Snap for 15614157 from eb736d608fd999817a2beb08a547a5822a51b320 to androidx-sqlite-release

Change-Id: I520a50f9e1489975af090b1824b6801b3515dd55
diff --git a/Android.bp b/Android.bp
index 2a6bf5c..5be4fd8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -58,13 +58,6 @@
     stl: "libc++",
 }
 
-cc_defaults {
-    name: "absl_notls_test_defaults",
-    host_supported: true,
-    stl: "libc++",
-    cflags: ["-DANDROID_DISABLE_TLS_FOR_LINKER=1"],
-}
-
 genrule {
     name: "absl_synchronization_hdrs",
     srcs: [
@@ -144,6 +137,7 @@
         "absl_base_tracing_internal",
         "absl_debugging_stacktrace",
         "absl_debugging_symbolize",
+        "absl_meta_type_traits",
         "absl_time",
     ],
     export_static_lib_headers: [
@@ -161,6 +155,7 @@
         "absl_base_tracing_internal",
         "absl_debugging_stacktrace",
         "absl_debugging_symbolize",
+        "absl_meta_type_traits",
         "absl_time",
     ],
 
@@ -202,6 +197,7 @@
         "absl_base_tracing_internal_notls",
         "absl_debugging_stacktrace_notls",
         "absl_debugging_symbolize_notls",
+        "absl_meta_type_traits_notls",
         "absl_time_notls",
     ],
     export_static_lib_headers: [
@@ -219,6 +215,7 @@
         "absl_base_tracing_internal_notls",
         "absl_debugging_stacktrace_notls",
         "absl_debugging_symbolize_notls",
+        "absl_meta_type_traits_notls",
         "absl_time_notls",
     ],
 
@@ -644,6 +641,7 @@
         "absl/time/internal/cctz/src/time_zone_libc.h",
         "absl/time/internal/cctz/src/time_zone_posix.h",
         "absl/time/internal/cctz/src/tzfile.h",
+        "absl/time/internal/cctz/src/time_zone_name_win.h",
     ],
     out: [
         "my_include_dir/absl/time/internal/cctz/include/cctz/time_zone.h",
@@ -655,6 +653,7 @@
         "my_include_dir/absl/time/internal/cctz/src/time_zone_libc.h",
         "my_include_dir/absl/time/internal/cctz/src/time_zone_posix.h",
         "my_include_dir/absl/time/internal/cctz/src/tzfile.h",
+        "my_include_dir/absl/time/internal/cctz/src/time_zone_name_win.h",
     ],
     export_include_dirs: ["my_include_dir"],
     cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
@@ -679,6 +678,7 @@
         "absl/time/internal/cctz/src/time_zone_lookup.cc",
         "absl/time/internal/cctz/src/time_zone_posix.cc",
         "absl/time/internal/cctz/src/zone_info_source.cc",
+        "absl/time/internal/cctz/src/time_zone_name_win.cc",
     ],
     generated_headers: ["absl_time_internal_cctz_time_zone_hdrs"],
     export_generated_headers: ["absl_time_internal_cctz_time_zone_hdrs"],
@@ -708,6 +708,7 @@
         "absl/time/internal/cctz/src/time_zone_lookup.cc",
         "absl/time/internal/cctz/src/time_zone_posix.cc",
         "absl/time/internal/cctz/src/zone_info_source.cc",
+        "absl/time/internal/cctz/src/time_zone_name_win.cc",
     ],
     generated_headers: ["absl_time_internal_cctz_time_zone_hdrs"],
     export_generated_headers: ["absl_time_internal_cctz_time_zone_hdrs"],
@@ -802,24 +803,20 @@
     defaults: ["absl_defaults"],
     visibility: ["//visibility:public"],
     srcs: [
-        "absl/strings/string_view.cc",
+
     ],
     generated_headers: ["absl_strings_string_view_hdrs"],
     export_generated_headers: ["absl_strings_string_view_hdrs"],
 
     whole_static_libs: [
-        "absl_base",
         "absl_base_config",
         "absl_base_core_headers",
         "absl_base_nullability",
-        "absl_base_throw_delegate",
     ],
     export_static_lib_headers: [
-        "absl_base",
         "absl_base_config",
         "absl_base_core_headers",
         "absl_base_nullability",
-        "absl_base_throw_delegate",
     ],
 
 }
@@ -829,327 +826,20 @@
     defaults: ["absl_notls_defaults"],
     visibility: ["//external/protobuf"],
     srcs: [
-        "absl/strings/string_view.cc",
+
     ],
     generated_headers: ["absl_strings_string_view_hdrs"],
     export_generated_headers: ["absl_strings_string_view_hdrs"],
 
     whole_static_libs: [
-        "absl_base_notls",
         "absl_base_config_notls",
         "absl_base_core_headers_notls",
         "absl_base_nullability_notls",
-        "absl_base_throw_delegate_notls",
     ],
     export_static_lib_headers: [
-        "absl_base_notls",
         "absl_base_config_notls",
         "absl_base_core_headers_notls",
         "absl_base_nullability_notls",
-        "absl_base_throw_delegate_notls",
-    ],
-
-}
-
-genrule {
-    name: "absl_base_throw_delegate_hdrs",
-    srcs: [
-        "absl/base/internal/throw_delegate.h",
-    ],
-    out: [
-        "my_include_dir/absl/base/internal/throw_delegate.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_base_throw_delegate",
-    defaults: ["absl_defaults"],
-
-    srcs: [
-        "absl/base/internal/throw_delegate.cc",
-    ],
-    generated_headers: ["absl_base_throw_delegate_hdrs"],
-    export_generated_headers: ["absl_base_throw_delegate_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config",
-        "absl_base_raw_logging_internal",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config",
-        "absl_base_raw_logging_internal",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_base_throw_delegate_notls",
-    defaults: ["absl_notls_defaults"],
-
-    srcs: [
-        "absl/base/internal/throw_delegate.cc",
-    ],
-    generated_headers: ["absl_base_throw_delegate_hdrs"],
-    export_generated_headers: ["absl_base_throw_delegate_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config_notls",
-        "absl_base_raw_logging_internal_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config_notls",
-        "absl_base_raw_logging_internal_notls",
-    ],
-
-}
-
-genrule {
-    name: "absl_base_raw_logging_internal_hdrs",
-    srcs: [
-        "absl/base/internal/raw_logging.h",
-    ],
-    out: [
-        "my_include_dir/absl/base/internal/raw_logging.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_base_raw_logging_internal",
-    defaults: ["absl_defaults"],
-
-    srcs: [
-        "absl/base/internal/raw_logging.cc",
-    ],
-    generated_headers: ["absl_base_raw_logging_internal_hdrs"],
-    export_generated_headers: ["absl_base_raw_logging_internal_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_atomic_hook",
-        "absl_base_config",
-        "absl_base_core_headers",
-        "absl_base_errno_saver",
-        "absl_base_log_severity",
-    ],
-    export_static_lib_headers: [
-        "absl_base_atomic_hook",
-        "absl_base_config",
-        "absl_base_core_headers",
-        "absl_base_errno_saver",
-        "absl_base_log_severity",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_base_raw_logging_internal_notls",
-    defaults: ["absl_notls_defaults"],
-
-    srcs: [
-        "absl/base/internal/raw_logging.cc",
-    ],
-    generated_headers: ["absl_base_raw_logging_internal_hdrs"],
-    export_generated_headers: ["absl_base_raw_logging_internal_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_atomic_hook_notls",
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-        "absl_base_errno_saver_notls",
-        "absl_base_log_severity_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_base_atomic_hook_notls",
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-        "absl_base_errno_saver_notls",
-        "absl_base_log_severity_notls",
-    ],
-
-}
-
-genrule {
-    name: "absl_base_log_severity_hdrs",
-    srcs: [
-        "absl/base/log_severity.h",
-    ],
-    out: [
-        "my_include_dir/absl/base/log_severity.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_base_log_severity",
-    defaults: ["absl_defaults"],
-    visibility: ["//visibility:public"],
-    srcs: [
-        "absl/base/log_severity.cc",
-    ],
-    generated_headers: ["absl_base_log_severity_hdrs"],
-    export_generated_headers: ["absl_base_log_severity_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config",
-        "absl_base_core_headers",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config",
-        "absl_base_core_headers",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_base_log_severity_notls",
-    defaults: ["absl_notls_defaults"],
-    visibility: ["//external/protobuf"],
-    srcs: [
-        "absl/base/log_severity.cc",
-    ],
-    generated_headers: ["absl_base_log_severity_hdrs"],
-    export_generated_headers: ["absl_base_log_severity_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-    ],
-
-}
-
-genrule {
-    name: "absl_base_errno_saver_hdrs",
-    srcs: [
-        "absl/base/internal/errno_saver.h",
-    ],
-    out: [
-        "my_include_dir/absl/base/internal/errno_saver.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_base_errno_saver",
-    defaults: ["absl_defaults"],
-
-    srcs: [
-
-    ],
-    generated_headers: ["absl_base_errno_saver_hdrs"],
-    export_generated_headers: ["absl_base_errno_saver_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_base_errno_saver_notls",
-    defaults: ["absl_notls_defaults"],
-
-    srcs: [
-
-    ],
-    generated_headers: ["absl_base_errno_saver_hdrs"],
-    export_generated_headers: ["absl_base_errno_saver_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config_notls",
-    ],
-
-}
-
-genrule {
-    name: "absl_base_atomic_hook_hdrs",
-    srcs: [
-        "absl/base/internal/atomic_hook.h",
-    ],
-    out: [
-        "my_include_dir/absl/base/internal/atomic_hook.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_base_atomic_hook",
-    defaults: ["absl_defaults"],
-
-    srcs: [
-
-    ],
-    generated_headers: ["absl_base_atomic_hook_hdrs"],
-    export_generated_headers: ["absl_base_atomic_hook_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config",
-        "absl_base_core_headers",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config",
-        "absl_base_core_headers",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_base_atomic_hook_notls",
-    defaults: ["absl_notls_defaults"],
-
-    srcs: [
-
-    ],
-    generated_headers: ["absl_base_atomic_hook_hdrs"],
-    export_generated_headers: ["absl_base_atomic_hook_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
     ],
 
 }
@@ -1158,11 +848,9 @@
     name: "absl_base_nullability_hdrs",
     srcs: [
         "absl/base/nullability.h",
-        "absl/base/internal/nullability_deprecated.h",
     ],
     out: [
         "my_include_dir/absl/base/nullability.h",
-        "my_include_dir/absl/base/internal/nullability_deprecated.h",
     ],
     export_include_dirs: ["my_include_dir"],
     cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
@@ -1185,11 +873,9 @@
 
     whole_static_libs: [
         "absl_base_config",
-        "absl_base_core_headers",
     ],
     export_static_lib_headers: [
         "absl_base_config",
-        "absl_base_core_headers",
     ],
 
 }
@@ -1206,388 +892,9 @@
 
     whole_static_libs: [
         "absl_base_config_notls",
-        "absl_base_core_headers_notls",
     ],
     export_static_lib_headers: [
         "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-    ],
-
-}
-
-genrule {
-    name: "absl_base_hdrs",
-    srcs: [
-        "absl/base/call_once.h",
-        "absl/base/casts.h",
-        "absl/base/internal/cycleclock.h",
-        "absl/base/internal/low_level_scheduling.h",
-        "absl/base/internal/per_thread_tls.h",
-        "absl/base/internal/spinlock.h",
-        "absl/base/internal/sysinfo.h",
-        "absl/base/internal/thread_identity.h",
-        "absl/base/internal/tsan_mutex_interface.h",
-        "absl/base/internal/unscaledcycleclock.h",
-    ],
-    out: [
-        "my_include_dir/absl/base/call_once.h",
-        "my_include_dir/absl/base/casts.h",
-        "my_include_dir/absl/base/internal/cycleclock.h",
-        "my_include_dir/absl/base/internal/low_level_scheduling.h",
-        "my_include_dir/absl/base/internal/per_thread_tls.h",
-        "my_include_dir/absl/base/internal/spinlock.h",
-        "my_include_dir/absl/base/internal/sysinfo.h",
-        "my_include_dir/absl/base/internal/thread_identity.h",
-        "my_include_dir/absl/base/internal/tsan_mutex_interface.h",
-        "my_include_dir/absl/base/internal/unscaledcycleclock.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_base",
-    defaults: ["absl_defaults"],
-    visibility: ["//visibility:public"],
-    srcs: [
-        "absl/base/internal/cycleclock.cc",
-        "absl/base/internal/spinlock.cc",
-        "absl/base/internal/sysinfo.cc",
-        "absl/base/internal/thread_identity.cc",
-        "absl/base/internal/unscaledcycleclock.cc",
-    ],
-    generated_headers: ["absl_base_hdrs"],
-    export_generated_headers: ["absl_base_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_atomic_hook",
-        "absl_base_base_internal",
-        "absl_base_config",
-        "absl_base_core_headers",
-        "absl_base_cycleclock_internal",
-        "absl_base_dynamic_annotations",
-        "absl_base_log_severity",
-        "absl_base_nullability",
-        "absl_base_raw_logging_internal",
-        "absl_base_spinlock_wait",
-        "absl_meta_type_traits",
-    ],
-    export_static_lib_headers: [
-        "absl_base_atomic_hook",
-        "absl_base_base_internal",
-        "absl_base_config",
-        "absl_base_core_headers",
-        "absl_base_cycleclock_internal",
-        "absl_base_dynamic_annotations",
-        "absl_base_log_severity",
-        "absl_base_nullability",
-        "absl_base_raw_logging_internal",
-        "absl_base_spinlock_wait",
-        "absl_meta_type_traits",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_base_notls",
-    defaults: ["absl_notls_defaults"],
-    visibility: ["//external/protobuf"],
-    srcs: [
-        "absl/base/internal/cycleclock.cc",
-        "absl/base/internal/spinlock.cc",
-        "absl/base/internal/sysinfo.cc",
-        "absl/base/internal/thread_identity.cc",
-        "absl/base/internal/unscaledcycleclock.cc",
-    ],
-    generated_headers: ["absl_base_hdrs"],
-    export_generated_headers: ["absl_base_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_atomic_hook_notls",
-        "absl_base_base_internal_notls",
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-        "absl_base_cycleclock_internal_notls",
-        "absl_base_dynamic_annotations_notls",
-        "absl_base_log_severity_notls",
-        "absl_base_nullability_notls",
-        "absl_base_raw_logging_internal_notls",
-        "absl_base_spinlock_wait_notls",
-        "absl_meta_type_traits_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_base_atomic_hook_notls",
-        "absl_base_base_internal_notls",
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-        "absl_base_cycleclock_internal_notls",
-        "absl_base_dynamic_annotations_notls",
-        "absl_base_log_severity_notls",
-        "absl_base_nullability_notls",
-        "absl_base_raw_logging_internal_notls",
-        "absl_base_spinlock_wait_notls",
-        "absl_meta_type_traits_notls",
-    ],
-
-}
-
-genrule {
-    name: "absl_base_spinlock_wait_hdrs",
-    srcs: [
-        "absl/base/internal/spinlock_wait.h",
-        "absl/base/internal/spinlock_akaros.inc",
-        "absl/base/internal/spinlock_linux.inc",
-        "absl/base/internal/spinlock_posix.inc",
-        "absl/base/internal/spinlock_win32.inc",
-    ],
-    out: [
-        "my_include_dir/absl/base/internal/spinlock_wait.h",
-        "my_include_dir/absl/base/internal/spinlock_akaros.inc",
-        "my_include_dir/absl/base/internal/spinlock_linux.inc",
-        "my_include_dir/absl/base/internal/spinlock_posix.inc",
-        "my_include_dir/absl/base/internal/spinlock_win32.inc",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_base_spinlock_wait",
-    defaults: ["absl_defaults"],
-
-    srcs: [
-        "absl/base/internal/spinlock_wait.cc",
-    ],
-    generated_headers: ["absl_base_spinlock_wait_hdrs"],
-    export_generated_headers: ["absl_base_spinlock_wait_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_base_internal",
-        "absl_base_core_headers",
-        "absl_base_errno_saver",
-    ],
-    export_static_lib_headers: [
-        "absl_base_base_internal",
-        "absl_base_core_headers",
-        "absl_base_errno_saver",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_base_spinlock_wait_notls",
-    defaults: ["absl_notls_defaults"],
-
-    srcs: [
-        "absl/base/internal/spinlock_wait.cc",
-    ],
-    generated_headers: ["absl_base_spinlock_wait_hdrs"],
-    export_generated_headers: ["absl_base_spinlock_wait_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_base_internal_notls",
-        "absl_base_core_headers_notls",
-        "absl_base_errno_saver_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_base_base_internal_notls",
-        "absl_base_core_headers_notls",
-        "absl_base_errno_saver_notls",
-    ],
-
-}
-
-genrule {
-    name: "absl_base_base_internal_hdrs",
-    srcs: [
-        "absl/base/internal/hide_ptr.h",
-        "absl/base/internal/identity.h",
-        "absl/base/internal/scheduling_mode.h",
-    ],
-    out: [
-        "my_include_dir/absl/base/internal/hide_ptr.h",
-        "my_include_dir/absl/base/internal/identity.h",
-        "my_include_dir/absl/base/internal/scheduling_mode.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_base_base_internal",
-    defaults: ["absl_defaults"],
-
-    srcs: [
-
-    ],
-    generated_headers: ["absl_base_base_internal_hdrs"],
-    export_generated_headers: ["absl_base_base_internal_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config",
-        "absl_meta_type_traits",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config",
-        "absl_meta_type_traits",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_base_base_internal_notls",
-    defaults: ["absl_notls_defaults"],
-
-    srcs: [
-
-    ],
-    generated_headers: ["absl_base_base_internal_hdrs"],
-    export_generated_headers: ["absl_base_base_internal_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config_notls",
-        "absl_meta_type_traits_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config_notls",
-        "absl_meta_type_traits_notls",
-    ],
-
-}
-
-genrule {
-    name: "absl_base_dynamic_annotations_hdrs",
-    srcs: [
-        "absl/base/dynamic_annotations.h",
-        "absl/base/internal/dynamic_annotations.h",
-    ],
-    out: [
-        "my_include_dir/absl/base/dynamic_annotations.h",
-        "my_include_dir/absl/base/internal/dynamic_annotations.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_base_dynamic_annotations",
-    defaults: ["absl_defaults"],
-    visibility: ["//visibility:public"],
-    srcs: [
-
-    ],
-    generated_headers: ["absl_base_dynamic_annotations_hdrs"],
-    export_generated_headers: ["absl_base_dynamic_annotations_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config",
-        "absl_base_core_headers",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config",
-        "absl_base_core_headers",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_base_dynamic_annotations_notls",
-    defaults: ["absl_notls_defaults"],
-    visibility: ["//external/protobuf"],
-    srcs: [
-
-    ],
-    generated_headers: ["absl_base_dynamic_annotations_hdrs"],
-    export_generated_headers: ["absl_base_dynamic_annotations_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-    ],
-
-}
-
-genrule {
-    name: "absl_base_cycleclock_internal_hdrs",
-    srcs: [
-        "absl/base/internal/cycleclock_config.h",
-        "absl/base/internal/unscaledcycleclock_config.h",
-    ],
-    out: [
-        "my_include_dir/absl/base/internal/cycleclock_config.h",
-        "my_include_dir/absl/base/internal/unscaledcycleclock_config.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_base_cycleclock_internal",
-    defaults: ["absl_defaults"],
-
-    srcs: [
-
-    ],
-    generated_headers: ["absl_base_cycleclock_internal_hdrs"],
-    export_generated_headers: ["absl_base_cycleclock_internal_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_base_internal",
-        "absl_base_config",
-    ],
-    export_static_lib_headers: [
-        "absl_base_base_internal",
-        "absl_base_config",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_base_cycleclock_internal_notls",
-    defaults: ["absl_notls_defaults"],
-
-    srcs: [
-
-    ],
-    generated_headers: ["absl_base_cycleclock_internal_hdrs"],
-    export_generated_headers: ["absl_base_cycleclock_internal_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_base_internal_notls",
-        "absl_base_config_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_base_base_internal_notls",
-        "absl_base_config_notls",
     ],
 
 }
@@ -1675,8 +982,10 @@
     export_generated_headers: ["absl_strings_hdrs"],
 
     whole_static_libs: [
+        "absl_strings_append_and_overwrite",
         "absl_strings_charset",
         "absl_strings_internal",
+        "absl_strings_resize_and_overwrite",
         "absl_strings_string_view",
         "absl_base",
         "absl_base_config",
@@ -1692,8 +1001,10 @@
         "absl_numeric_int128",
     ],
     export_static_lib_headers: [
+        "absl_strings_append_and_overwrite",
         "absl_strings_charset",
         "absl_strings_internal",
+        "absl_strings_resize_and_overwrite",
         "absl_strings_string_view",
         "absl_base",
         "absl_base_config",
@@ -1735,8 +1046,10 @@
     export_generated_headers: ["absl_strings_hdrs"],
 
     whole_static_libs: [
+        "absl_strings_append_and_overwrite_notls",
         "absl_strings_charset_notls",
         "absl_strings_internal_notls",
+        "absl_strings_resize_and_overwrite_notls",
         "absl_strings_string_view_notls",
         "absl_base_notls",
         "absl_base_config_notls",
@@ -1752,8 +1065,10 @@
         "absl_numeric_int128_notls",
     ],
     export_static_lib_headers: [
+        "absl_strings_append_and_overwrite_notls",
         "absl_strings_charset_notls",
         "absl_strings_internal_notls",
+        "absl_strings_resize_and_overwrite_notls",
         "absl_strings_string_view_notls",
         "absl_base_notls",
         "absl_base_config_notls",
@@ -2040,6 +1355,558 @@
 }
 
 genrule {
+    name: "absl_base_hdrs",
+    srcs: [
+        "absl/base/call_once.h",
+        "absl/base/casts.h",
+        "absl/base/internal/cycleclock.h",
+        "absl/base/internal/low_level_scheduling.h",
+        "absl/base/internal/per_thread_tls.h",
+        "absl/base/internal/spinlock.h",
+        "absl/base/internal/sysinfo.h",
+        "absl/base/internal/thread_identity.h",
+        "absl/base/internal/tsan_mutex_interface.h",
+        "absl/base/internal/unscaledcycleclock.h",
+    ],
+    out: [
+        "my_include_dir/absl/base/call_once.h",
+        "my_include_dir/absl/base/casts.h",
+        "my_include_dir/absl/base/internal/cycleclock.h",
+        "my_include_dir/absl/base/internal/low_level_scheduling.h",
+        "my_include_dir/absl/base/internal/per_thread_tls.h",
+        "my_include_dir/absl/base/internal/spinlock.h",
+        "my_include_dir/absl/base/internal/sysinfo.h",
+        "my_include_dir/absl/base/internal/thread_identity.h",
+        "my_include_dir/absl/base/internal/tsan_mutex_interface.h",
+        "my_include_dir/absl/base/internal/unscaledcycleclock.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_base",
+    defaults: ["absl_defaults"],
+    visibility: ["//visibility:public"],
+    srcs: [
+        "absl/base/casts.cc",
+        "absl/base/internal/cycleclock.cc",
+        "absl/base/internal/spinlock.cc",
+        "absl/base/internal/sysinfo.cc",
+        "absl/base/internal/thread_identity.cc",
+        "absl/base/internal/unscaledcycleclock.cc",
+    ],
+    generated_headers: ["absl_base_hdrs"],
+    export_generated_headers: ["absl_base_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_atomic_hook",
+        "absl_base_base_internal",
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_base_cycleclock_internal",
+        "absl_base_nullability",
+        "absl_base_raw_logging_internal",
+        "absl_base_spinlock_wait",
+        "absl_meta_type_traits",
+    ],
+    export_static_lib_headers: [
+        "absl_base_atomic_hook",
+        "absl_base_base_internal",
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_base_cycleclock_internal",
+        "absl_base_nullability",
+        "absl_base_raw_logging_internal",
+        "absl_base_spinlock_wait",
+        "absl_meta_type_traits",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_base_notls",
+    defaults: ["absl_notls_defaults"],
+    visibility: ["//external/protobuf"],
+    srcs: [
+        "absl/base/casts.cc",
+        "absl/base/internal/cycleclock.cc",
+        "absl/base/internal/spinlock.cc",
+        "absl/base/internal/sysinfo.cc",
+        "absl/base/internal/thread_identity.cc",
+        "absl/base/internal/unscaledcycleclock.cc",
+    ],
+    generated_headers: ["absl_base_hdrs"],
+    export_generated_headers: ["absl_base_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_atomic_hook_notls",
+        "absl_base_base_internal_notls",
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_cycleclock_internal_notls",
+        "absl_base_nullability_notls",
+        "absl_base_raw_logging_internal_notls",
+        "absl_base_spinlock_wait_notls",
+        "absl_meta_type_traits_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_atomic_hook_notls",
+        "absl_base_base_internal_notls",
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_cycleclock_internal_notls",
+        "absl_base_nullability_notls",
+        "absl_base_raw_logging_internal_notls",
+        "absl_base_spinlock_wait_notls",
+        "absl_meta_type_traits_notls",
+    ],
+
+}
+
+genrule {
+    name: "absl_base_spinlock_wait_hdrs",
+    srcs: [
+        "absl/base/internal/spinlock_wait.h",
+        "absl/base/internal/spinlock_akaros.inc",
+        "absl/base/internal/spinlock_linux.inc",
+        "absl/base/internal/spinlock_posix.inc",
+        "absl/base/internal/spinlock_win32.inc",
+    ],
+    out: [
+        "my_include_dir/absl/base/internal/spinlock_wait.h",
+        "my_include_dir/absl/base/internal/spinlock_akaros.inc",
+        "my_include_dir/absl/base/internal/spinlock_linux.inc",
+        "my_include_dir/absl/base/internal/spinlock_posix.inc",
+        "my_include_dir/absl/base/internal/spinlock_win32.inc",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_base_spinlock_wait",
+    defaults: ["absl_defaults"],
+
+    srcs: [
+        "absl/base/internal/spinlock_wait.cc",
+    ],
+    generated_headers: ["absl_base_spinlock_wait_hdrs"],
+    export_generated_headers: ["absl_base_spinlock_wait_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_base_internal",
+        "absl_base_core_headers",
+        "absl_base_errno_saver",
+    ],
+    export_static_lib_headers: [
+        "absl_base_base_internal",
+        "absl_base_core_headers",
+        "absl_base_errno_saver",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_base_spinlock_wait_notls",
+    defaults: ["absl_notls_defaults"],
+
+    srcs: [
+        "absl/base/internal/spinlock_wait.cc",
+    ],
+    generated_headers: ["absl_base_spinlock_wait_hdrs"],
+    export_generated_headers: ["absl_base_spinlock_wait_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_base_internal_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_errno_saver_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_base_internal_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_errno_saver_notls",
+    ],
+
+}
+
+genrule {
+    name: "absl_base_errno_saver_hdrs",
+    srcs: [
+        "absl/base/internal/errno_saver.h",
+    ],
+    out: [
+        "my_include_dir/absl/base/internal/errno_saver.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_base_errno_saver",
+    defaults: ["absl_defaults"],
+
+    srcs: [
+
+    ],
+    generated_headers: ["absl_base_errno_saver_hdrs"],
+    export_generated_headers: ["absl_base_errno_saver_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_base_errno_saver_notls",
+    defaults: ["absl_notls_defaults"],
+
+    srcs: [
+
+    ],
+    generated_headers: ["absl_base_errno_saver_hdrs"],
+    export_generated_headers: ["absl_base_errno_saver_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config_notls",
+    ],
+
+}
+
+genrule {
+    name: "absl_base_base_internal_hdrs",
+    srcs: [
+        "absl/base/internal/hide_ptr.h",
+        "absl/base/internal/scheduling_mode.h",
+    ],
+    out: [
+        "my_include_dir/absl/base/internal/hide_ptr.h",
+        "my_include_dir/absl/base/internal/scheduling_mode.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_base_base_internal",
+    defaults: ["absl_defaults"],
+
+    srcs: [
+
+    ],
+    generated_headers: ["absl_base_base_internal_hdrs"],
+    export_generated_headers: ["absl_base_base_internal_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config",
+        "absl_meta_type_traits",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config",
+        "absl_meta_type_traits",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_base_base_internal_notls",
+    defaults: ["absl_notls_defaults"],
+
+    srcs: [
+
+    ],
+    generated_headers: ["absl_base_base_internal_hdrs"],
+    export_generated_headers: ["absl_base_base_internal_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config_notls",
+        "absl_meta_type_traits_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config_notls",
+        "absl_meta_type_traits_notls",
+    ],
+
+}
+
+genrule {
+    name: "absl_base_raw_logging_internal_hdrs",
+    srcs: [
+        "absl/base/internal/raw_logging.h",
+    ],
+    out: [
+        "my_include_dir/absl/base/internal/raw_logging.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_base_raw_logging_internal",
+    defaults: ["absl_defaults"],
+
+    srcs: [
+        "absl/base/internal/raw_logging.cc",
+    ],
+    generated_headers: ["absl_base_raw_logging_internal_hdrs"],
+    export_generated_headers: ["absl_base_raw_logging_internal_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_atomic_hook",
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_base_errno_saver",
+        "absl_base_log_severity",
+    ],
+    export_static_lib_headers: [
+        "absl_base_atomic_hook",
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_base_errno_saver",
+        "absl_base_log_severity",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_base_raw_logging_internal_notls",
+    defaults: ["absl_notls_defaults"],
+
+    srcs: [
+        "absl/base/internal/raw_logging.cc",
+    ],
+    generated_headers: ["absl_base_raw_logging_internal_hdrs"],
+    export_generated_headers: ["absl_base_raw_logging_internal_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_atomic_hook_notls",
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_errno_saver_notls",
+        "absl_base_log_severity_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_atomic_hook_notls",
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_errno_saver_notls",
+        "absl_base_log_severity_notls",
+    ],
+
+}
+
+genrule {
+    name: "absl_base_log_severity_hdrs",
+    srcs: [
+        "absl/base/log_severity.h",
+    ],
+    out: [
+        "my_include_dir/absl/base/log_severity.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_base_log_severity",
+    defaults: ["absl_defaults"],
+    visibility: ["//visibility:public"],
+    srcs: [
+        "absl/base/log_severity.cc",
+    ],
+    generated_headers: ["absl_base_log_severity_hdrs"],
+    export_generated_headers: ["absl_base_log_severity_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config",
+        "absl_base_core_headers",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config",
+        "absl_base_core_headers",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_base_log_severity_notls",
+    defaults: ["absl_notls_defaults"],
+    visibility: ["//external/protobuf"],
+    srcs: [
+        "absl/base/log_severity.cc",
+    ],
+    generated_headers: ["absl_base_log_severity_hdrs"],
+    export_generated_headers: ["absl_base_log_severity_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+    ],
+
+}
+
+genrule {
+    name: "absl_base_atomic_hook_hdrs",
+    srcs: [
+        "absl/base/internal/atomic_hook.h",
+    ],
+    out: [
+        "my_include_dir/absl/base/internal/atomic_hook.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_base_atomic_hook",
+    defaults: ["absl_defaults"],
+
+    srcs: [
+
+    ],
+    generated_headers: ["absl_base_atomic_hook_hdrs"],
+    export_generated_headers: ["absl_base_atomic_hook_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config",
+        "absl_base_core_headers",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config",
+        "absl_base_core_headers",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_base_atomic_hook_notls",
+    defaults: ["absl_notls_defaults"],
+
+    srcs: [
+
+    ],
+    generated_headers: ["absl_base_atomic_hook_hdrs"],
+    export_generated_headers: ["absl_base_atomic_hook_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+    ],
+
+}
+
+genrule {
+    name: "absl_base_cycleclock_internal_hdrs",
+    srcs: [
+        "absl/base/internal/cycleclock_config.h",
+        "absl/base/internal/unscaledcycleclock_config.h",
+    ],
+    out: [
+        "my_include_dir/absl/base/internal/cycleclock_config.h",
+        "my_include_dir/absl/base/internal/unscaledcycleclock_config.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_base_cycleclock_internal",
+    defaults: ["absl_defaults"],
+
+    srcs: [
+
+    ],
+    generated_headers: ["absl_base_cycleclock_internal_hdrs"],
+    export_generated_headers: ["absl_base_cycleclock_internal_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_base_internal",
+        "absl_base_config",
+    ],
+    export_static_lib_headers: [
+        "absl_base_base_internal",
+        "absl_base_config",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_base_cycleclock_internal_notls",
+    defaults: ["absl_notls_defaults"],
+
+    srcs: [
+
+    ],
+    generated_headers: ["absl_base_cycleclock_internal_hdrs"],
+    export_generated_headers: ["absl_base_cycleclock_internal_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_base_internal_notls",
+        "absl_base_config_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_base_internal_notls",
+        "absl_base_config_notls",
+    ],
+
+}
+
+genrule {
     name: "absl_memory_hdrs",
     srcs: [
         "absl/memory/memory.h",
@@ -2099,6 +1966,65 @@
 }
 
 genrule {
+    name: "absl_base_throw_delegate_hdrs",
+    srcs: [
+        "absl/base/internal/throw_delegate.h",
+    ],
+    out: [
+        "my_include_dir/absl/base/internal/throw_delegate.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_base_throw_delegate",
+    defaults: ["absl_defaults"],
+
+    srcs: [
+        "absl/base/internal/throw_delegate.cc",
+    ],
+    generated_headers: ["absl_base_throw_delegate_hdrs"],
+    export_generated_headers: ["absl_base_throw_delegate_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config",
+        "absl_base_raw_logging_internal",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config",
+        "absl_base_raw_logging_internal",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_base_throw_delegate_notls",
+    defaults: ["absl_notls_defaults"],
+
+    srcs: [
+        "absl/base/internal/throw_delegate.cc",
+    ],
+    generated_headers: ["absl_base_throw_delegate_hdrs"],
+    export_generated_headers: ["absl_base_throw_delegate_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config_notls",
+        "absl_base_raw_logging_internal_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config_notls",
+        "absl_base_raw_logging_internal_notls",
+    ],
+
+}
+
+genrule {
     name: "absl_base_iterator_traits_internal_hdrs",
     srcs: [
         "absl/base/internal/iterator_traits.h",
@@ -2118,7 +2044,7 @@
 cc_library_static {
     name: "absl_base_iterator_traits_internal",
     defaults: ["absl_defaults"],
-    visibility: ["//visibility:public"],
+
     srcs: [
 
     ],
@@ -2139,7 +2065,7 @@
 cc_library_static {
     name: "absl_base_iterator_traits_internal_notls",
     defaults: ["absl_notls_defaults"],
-    visibility: ["//external/protobuf"],
+
     srcs: [
 
     ],
@@ -2158,6 +2084,134 @@
 }
 
 genrule {
+    name: "absl_strings_resize_and_overwrite_hdrs",
+    srcs: [
+        "absl/strings/resize_and_overwrite.h",
+    ],
+    out: [
+        "my_include_dir/absl/strings/resize_and_overwrite.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_strings_resize_and_overwrite",
+    defaults: ["absl_defaults"],
+    visibility: ["//visibility:public"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_strings_resize_and_overwrite_hdrs"],
+    export_generated_headers: ["absl_strings_resize_and_overwrite_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_base_dynamic_annotations",
+        "absl_base_throw_delegate",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_base_dynamic_annotations",
+        "absl_base_throw_delegate",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_strings_resize_and_overwrite_notls",
+    defaults: ["absl_notls_defaults"],
+    visibility: ["//external/protobuf"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_strings_resize_and_overwrite_hdrs"],
+    export_generated_headers: ["absl_strings_resize_and_overwrite_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_dynamic_annotations_notls",
+        "absl_base_throw_delegate_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_dynamic_annotations_notls",
+        "absl_base_throw_delegate_notls",
+    ],
+
+}
+
+genrule {
+    name: "absl_base_dynamic_annotations_hdrs",
+    srcs: [
+        "absl/base/dynamic_annotations.h",
+        "absl/base/internal/dynamic_annotations.h",
+    ],
+    out: [
+        "my_include_dir/absl/base/dynamic_annotations.h",
+        "my_include_dir/absl/base/internal/dynamic_annotations.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_base_dynamic_annotations",
+    defaults: ["absl_defaults"],
+    visibility: ["//visibility:public"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_base_dynamic_annotations_hdrs"],
+    export_generated_headers: ["absl_base_dynamic_annotations_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config",
+        "absl_base_core_headers",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config",
+        "absl_base_core_headers",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_base_dynamic_annotations_notls",
+    defaults: ["absl_notls_defaults"],
+    visibility: ["//external/protobuf"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_base_dynamic_annotations_hdrs"],
+    export_generated_headers: ["absl_base_dynamic_annotations_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+    ],
+
+}
+
+genrule {
     name: "absl_strings_internal_hdrs",
     srcs: [
         "absl/strings/internal/escaping.h",
@@ -2193,6 +2247,7 @@
     export_generated_headers: ["absl_strings_internal_hdrs"],
 
     whole_static_libs: [
+        "absl_strings_resize_and_overwrite",
         "absl_base_config",
         "absl_base_core_headers",
         "absl_base_endian",
@@ -2200,6 +2255,7 @@
         "absl_meta_type_traits",
     ],
     export_static_lib_headers: [
+        "absl_strings_resize_and_overwrite",
         "absl_base_config",
         "absl_base_core_headers",
         "absl_base_endian",
@@ -2222,6 +2278,7 @@
     export_generated_headers: ["absl_strings_internal_hdrs"],
 
     whole_static_libs: [
+        "absl_strings_resize_and_overwrite_notls",
         "absl_base_config_notls",
         "absl_base_core_headers_notls",
         "absl_base_endian_notls",
@@ -2229,6 +2286,7 @@
         "absl_meta_type_traits_notls",
     ],
     export_static_lib_headers: [
+        "absl_strings_resize_and_overwrite_notls",
         "absl_base_config_notls",
         "absl_base_core_headers_notls",
         "absl_base_endian_notls",
@@ -2298,6 +2356,73 @@
 }
 
 genrule {
+    name: "absl_strings_append_and_overwrite_hdrs",
+    srcs: [
+        "absl/strings/internal/append_and_overwrite.h",
+    ],
+    out: [
+        "my_include_dir/absl/strings/internal/append_and_overwrite.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_strings_append_and_overwrite",
+    defaults: ["absl_defaults"],
+
+    srcs: [
+
+    ],
+    generated_headers: ["absl_strings_append_and_overwrite_hdrs"],
+    export_generated_headers: ["absl_strings_append_and_overwrite_hdrs"],
+
+    whole_static_libs: [
+        "absl_strings_resize_and_overwrite",
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_base_throw_delegate",
+    ],
+    export_static_lib_headers: [
+        "absl_strings_resize_and_overwrite",
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_base_throw_delegate",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_strings_append_and_overwrite_notls",
+    defaults: ["absl_notls_defaults"],
+
+    srcs: [
+
+    ],
+    generated_headers: ["absl_strings_append_and_overwrite_hdrs"],
+    export_generated_headers: ["absl_strings_append_and_overwrite_hdrs"],
+
+    whole_static_libs: [
+        "absl_strings_resize_and_overwrite_notls",
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_throw_delegate_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_strings_resize_and_overwrite_notls",
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_throw_delegate_notls",
+    ],
+
+}
+
+genrule {
     name: "absl_debugging_symbolize_hdrs",
     srcs: [
         "absl/debugging/internal/symbolize.h",
@@ -2921,17 +3046,21 @@
     export_generated_headers: ["absl_debugging_stacktrace_hdrs"],
 
     whole_static_libs: [
+        "absl_debugging_borrowed_fixup_buffer",
         "absl_debugging_debugging_internal",
         "absl_base_config",
         "absl_base_core_headers",
         "absl_base_dynamic_annotations",
+        "absl_base_malloc_internal",
         "absl_base_raw_logging_internal",
     ],
     export_static_lib_headers: [
+        "absl_debugging_borrowed_fixup_buffer",
         "absl_debugging_debugging_internal",
         "absl_base_config",
         "absl_base_core_headers",
         "absl_base_dynamic_annotations",
+        "absl_base_malloc_internal",
         "absl_base_raw_logging_internal",
     ],
 
@@ -2948,23 +3077,786 @@
     export_generated_headers: ["absl_debugging_stacktrace_hdrs"],
 
     whole_static_libs: [
+        "absl_debugging_borrowed_fixup_buffer_notls",
         "absl_debugging_debugging_internal_notls",
         "absl_base_config_notls",
         "absl_base_core_headers_notls",
         "absl_base_dynamic_annotations_notls",
+        "absl_base_malloc_internal_notls",
         "absl_base_raw_logging_internal_notls",
     ],
     export_static_lib_headers: [
+        "absl_debugging_borrowed_fixup_buffer_notls",
         "absl_debugging_debugging_internal_notls",
         "absl_base_config_notls",
         "absl_base_core_headers_notls",
         "absl_base_dynamic_annotations_notls",
+        "absl_base_malloc_internal_notls",
         "absl_base_raw_logging_internal_notls",
     ],
 
 }
 
 genrule {
+    name: "absl_debugging_borrowed_fixup_buffer_hdrs",
+    srcs: [
+        "absl/debugging/internal/borrowed_fixup_buffer.h",
+    ],
+    out: [
+        "my_include_dir/absl/debugging/internal/borrowed_fixup_buffer.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_debugging_borrowed_fixup_buffer",
+    defaults: ["absl_defaults"],
+    visibility: ["//visibility:public"],
+    srcs: [
+        "absl/debugging/internal/borrowed_fixup_buffer.cc",
+    ],
+    generated_headers: ["absl_debugging_borrowed_fixup_buffer_hdrs"],
+    export_generated_headers: ["absl_debugging_borrowed_fixup_buffer_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_base_malloc_internal",
+        "absl_hash",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_base_malloc_internal",
+        "absl_hash",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_debugging_borrowed_fixup_buffer_notls",
+    defaults: ["absl_notls_defaults"],
+    visibility: ["//external/protobuf"],
+    srcs: [
+        "absl/debugging/internal/borrowed_fixup_buffer.cc",
+    ],
+    generated_headers: ["absl_debugging_borrowed_fixup_buffer_hdrs"],
+    export_generated_headers: ["absl_debugging_borrowed_fixup_buffer_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_malloc_internal_notls",
+        "absl_hash_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_malloc_internal_notls",
+        "absl_hash_notls",
+    ],
+
+}
+
+genrule {
+    name: "absl_hash_hdrs",
+    srcs: [
+        "absl/hash/hash.h",
+        "absl/hash/internal/hash.h",
+    ],
+    out: [
+        "my_include_dir/absl/hash/hash.h",
+        "my_include_dir/absl/hash/internal/hash.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_hash",
+    defaults: ["absl_defaults"],
+    visibility: ["//visibility:public"],
+    srcs: [
+        "absl/hash/internal/hash.cc",
+    ],
+    generated_headers: ["absl_hash_hdrs"],
+    export_generated_headers: ["absl_hash_hdrs"],
+
+    whole_static_libs: [
+        "absl_hash_city",
+        "absl_hash_weakly_mixed_integer",
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_base_endian",
+        "absl_base_prefetch",
+        "absl_container_fixed_array",
+        "absl_functional_function_ref",
+        "absl_meta_type_traits",
+        "absl_numeric_bits",
+        "absl_numeric_int128",
+        "absl_strings",
+        "absl_types_optional",
+        "absl_types_variant",
+        "absl_utility",
+    ],
+    export_static_lib_headers: [
+        "absl_hash_city",
+        "absl_hash_weakly_mixed_integer",
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_base_endian",
+        "absl_base_prefetch",
+        "absl_container_fixed_array",
+        "absl_functional_function_ref",
+        "absl_meta_type_traits",
+        "absl_numeric_bits",
+        "absl_numeric_int128",
+        "absl_strings",
+        "absl_types_optional",
+        "absl_types_variant",
+        "absl_utility",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_hash_notls",
+    defaults: ["absl_notls_defaults"],
+    visibility: ["//external/protobuf"],
+    srcs: [
+        "absl/hash/internal/hash.cc",
+    ],
+    generated_headers: ["absl_hash_hdrs"],
+    export_generated_headers: ["absl_hash_hdrs"],
+
+    whole_static_libs: [
+        "absl_hash_city_notls",
+        "absl_hash_weakly_mixed_integer_notls",
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_endian_notls",
+        "absl_base_prefetch_notls",
+        "absl_container_fixed_array_notls",
+        "absl_functional_function_ref_notls",
+        "absl_meta_type_traits_notls",
+        "absl_numeric_bits_notls",
+        "absl_numeric_int128_notls",
+        "absl_strings_notls",
+        "absl_types_optional_notls",
+        "absl_types_variant_notls",
+        "absl_utility_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_hash_city_notls",
+        "absl_hash_weakly_mixed_integer_notls",
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_endian_notls",
+        "absl_base_prefetch_notls",
+        "absl_container_fixed_array_notls",
+        "absl_functional_function_ref_notls",
+        "absl_meta_type_traits_notls",
+        "absl_numeric_bits_notls",
+        "absl_numeric_int128_notls",
+        "absl_strings_notls",
+        "absl_types_optional_notls",
+        "absl_types_variant_notls",
+        "absl_utility_notls",
+    ],
+
+}
+
+genrule {
+    name: "absl_types_variant_hdrs",
+    srcs: [
+        "absl/types/variant.h",
+    ],
+    out: [
+        "my_include_dir/absl/types/variant.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_types_variant",
+    defaults: ["absl_defaults"],
+    visibility: ["//visibility:public"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_types_variant_hdrs"],
+    export_generated_headers: ["absl_types_variant_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config",
+        "absl_utility",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config",
+        "absl_utility",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_types_variant_notls",
+    defaults: ["absl_notls_defaults"],
+    visibility: ["//external/protobuf"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_types_variant_hdrs"],
+    export_generated_headers: ["absl_types_variant_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config_notls",
+        "absl_utility_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config_notls",
+        "absl_utility_notls",
+    ],
+
+}
+
+genrule {
+    name: "absl_functional_function_ref_hdrs",
+    srcs: [
+        "absl/functional/function_ref.h",
+        "absl/functional/internal/function_ref.h",
+    ],
+    out: [
+        "my_include_dir/absl/functional/function_ref.h",
+        "my_include_dir/absl/functional/internal/function_ref.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_functional_function_ref",
+    defaults: ["absl_defaults"],
+    visibility: ["//visibility:public"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_functional_function_ref_hdrs"],
+    export_generated_headers: ["absl_functional_function_ref_hdrs"],
+
+    whole_static_libs: [
+        "absl_functional_any_invocable",
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_meta_type_traits",
+        "absl_utility",
+    ],
+    export_static_lib_headers: [
+        "absl_functional_any_invocable",
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_meta_type_traits",
+        "absl_utility",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_functional_function_ref_notls",
+    defaults: ["absl_notls_defaults"],
+    visibility: ["//external/protobuf"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_functional_function_ref_hdrs"],
+    export_generated_headers: ["absl_functional_function_ref_hdrs"],
+
+    whole_static_libs: [
+        "absl_functional_any_invocable_notls",
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_meta_type_traits_notls",
+        "absl_utility_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_functional_any_invocable_notls",
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_meta_type_traits_notls",
+        "absl_utility_notls",
+    ],
+
+}
+
+genrule {
+    name: "absl_functional_any_invocable_hdrs",
+    srcs: [
+        "absl/functional/any_invocable.h",
+        "absl/functional/internal/any_invocable.h",
+    ],
+    out: [
+        "my_include_dir/absl/functional/any_invocable.h",
+        "my_include_dir/absl/functional/internal/any_invocable.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_functional_any_invocable",
+    defaults: ["absl_defaults"],
+    visibility: ["//visibility:public"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_functional_any_invocable_hdrs"],
+    export_generated_headers: ["absl_functional_any_invocable_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_base_nullability",
+        "absl_meta_type_traits",
+        "absl_utility",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_base_nullability",
+        "absl_meta_type_traits",
+        "absl_utility",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_functional_any_invocable_notls",
+    defaults: ["absl_notls_defaults"],
+    visibility: ["//external/protobuf"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_functional_any_invocable_hdrs"],
+    export_generated_headers: ["absl_functional_any_invocable_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_nullability_notls",
+        "absl_meta_type_traits_notls",
+        "absl_utility_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_nullability_notls",
+        "absl_meta_type_traits_notls",
+        "absl_utility_notls",
+    ],
+
+}
+
+genrule {
+    name: "absl_container_fixed_array_hdrs",
+    srcs: [
+        "absl/container/fixed_array.h",
+    ],
+    out: [
+        "my_include_dir/absl/container/fixed_array.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_container_fixed_array",
+    defaults: ["absl_defaults"],
+    visibility: ["//visibility:public"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_container_fixed_array_hdrs"],
+    export_generated_headers: ["absl_container_fixed_array_hdrs"],
+
+    whole_static_libs: [
+        "absl_container_compressed_tuple",
+        "absl_algorithm",
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_base_dynamic_annotations",
+        "absl_base_iterator_traits_internal",
+        "absl_base_throw_delegate",
+        "absl_hash_weakly_mixed_integer",
+        "absl_memory",
+    ],
+    export_static_lib_headers: [
+        "absl_container_compressed_tuple",
+        "absl_algorithm",
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_base_dynamic_annotations",
+        "absl_base_iterator_traits_internal",
+        "absl_base_throw_delegate",
+        "absl_hash_weakly_mixed_integer",
+        "absl_memory",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_container_fixed_array_notls",
+    defaults: ["absl_notls_defaults"],
+    visibility: ["//external/protobuf"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_container_fixed_array_hdrs"],
+    export_generated_headers: ["absl_container_fixed_array_hdrs"],
+
+    whole_static_libs: [
+        "absl_container_compressed_tuple_notls",
+        "absl_algorithm_notls",
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_dynamic_annotations_notls",
+        "absl_base_iterator_traits_internal_notls",
+        "absl_base_throw_delegate_notls",
+        "absl_hash_weakly_mixed_integer_notls",
+        "absl_memory_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_container_compressed_tuple_notls",
+        "absl_algorithm_notls",
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_dynamic_annotations_notls",
+        "absl_base_iterator_traits_internal_notls",
+        "absl_base_throw_delegate_notls",
+        "absl_hash_weakly_mixed_integer_notls",
+        "absl_memory_notls",
+    ],
+
+}
+
+genrule {
+    name: "absl_hash_weakly_mixed_integer_hdrs",
+    srcs: [
+        "absl/hash/internal/weakly_mixed_integer.h",
+    ],
+    out: [
+        "my_include_dir/absl/hash/internal/weakly_mixed_integer.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_hash_weakly_mixed_integer",
+    defaults: ["absl_defaults"],
+
+    srcs: [
+
+    ],
+    generated_headers: ["absl_hash_weakly_mixed_integer_hdrs"],
+    export_generated_headers: ["absl_hash_weakly_mixed_integer_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_hash_weakly_mixed_integer_notls",
+    defaults: ["absl_notls_defaults"],
+
+    srcs: [
+
+    ],
+    generated_headers: ["absl_hash_weakly_mixed_integer_hdrs"],
+    export_generated_headers: ["absl_hash_weakly_mixed_integer_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config_notls",
+    ],
+
+}
+
+genrule {
+    name: "absl_algorithm_hdrs",
+    srcs: [
+        "absl/algorithm/algorithm.h",
+    ],
+    out: [
+        "my_include_dir/absl/algorithm/algorithm.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_algorithm",
+    defaults: ["absl_defaults"],
+    visibility: ["//visibility:public"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_algorithm_hdrs"],
+    export_generated_headers: ["absl_algorithm_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_algorithm_notls",
+    defaults: ["absl_notls_defaults"],
+    visibility: ["//external/protobuf"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_algorithm_hdrs"],
+    export_generated_headers: ["absl_algorithm_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config_notls",
+    ],
+
+}
+
+genrule {
+    name: "absl_container_compressed_tuple_hdrs",
+    srcs: [
+        "absl/container/internal/compressed_tuple.h",
+    ],
+    out: [
+        "my_include_dir/absl/container/internal/compressed_tuple.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_container_compressed_tuple",
+    defaults: ["absl_defaults"],
+    visibility: ["//visibility:public"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_container_compressed_tuple_hdrs"],
+    export_generated_headers: ["absl_container_compressed_tuple_hdrs"],
+
+    whole_static_libs: [
+        "absl_utility",
+    ],
+    export_static_lib_headers: [
+        "absl_utility",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_container_compressed_tuple_notls",
+    defaults: ["absl_notls_defaults"],
+    visibility: ["//external/protobuf"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_container_compressed_tuple_hdrs"],
+    export_generated_headers: ["absl_container_compressed_tuple_hdrs"],
+
+    whole_static_libs: [
+        "absl_utility_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_utility_notls",
+    ],
+
+}
+
+genrule {
+    name: "absl_base_prefetch_hdrs",
+    srcs: [
+        "absl/base/prefetch.h",
+    ],
+    out: [
+        "my_include_dir/absl/base/prefetch.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_base_prefetch",
+    defaults: ["absl_defaults"],
+    visibility: ["//visibility:public"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_base_prefetch_hdrs"],
+    export_generated_headers: ["absl_base_prefetch_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config",
+        "absl_base_core_headers",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config",
+        "absl_base_core_headers",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_base_prefetch_notls",
+    defaults: ["absl_notls_defaults"],
+    visibility: ["//external/protobuf"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_base_prefetch_hdrs"],
+    export_generated_headers: ["absl_base_prefetch_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+    ],
+
+}
+
+genrule {
+    name: "absl_hash_city_hdrs",
+    srcs: [
+        "absl/hash/internal/city.h",
+    ],
+    out: [
+        "my_include_dir/absl/hash/internal/city.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_hash_city",
+    defaults: ["absl_defaults"],
+    visibility: ["//visibility:public"],
+    srcs: [
+        "absl/hash/internal/city.cc",
+    ],
+    generated_headers: ["absl_hash_city_hdrs"],
+    export_generated_headers: ["absl_hash_city_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_base_endian",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_base_endian",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_hash_city_notls",
+    defaults: ["absl_notls_defaults"],
+    visibility: ["//external/protobuf"],
+    srcs: [
+        "absl/hash/internal/city.cc",
+    ],
+    generated_headers: ["absl_hash_city_hdrs"],
+    export_generated_headers: ["absl_hash_city_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_endian_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_base_endian_notls",
+    ],
+
+}
+
+genrule {
     name: "absl_base_tracing_internal_hdrs",
     srcs: [
         "absl/base/internal/tracing.h",
@@ -3170,6 +4062,58 @@
 }
 
 genrule {
+    name: "absl_status_status_matchers_hdrs",
+    srcs: [
+        "absl/status/status_matchers.h",
+        "absl/status/internal/status_matchers.h",
+    ],
+    out: [
+        "my_include_dir/absl/status/status_matchers.h",
+        "my_include_dir/absl/status/internal/status_matchers.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_test_library {
+    name: "absl_status_status_matchers",
+    defaults: ["absl_test_defaults"],
+    visibility: ["//visibility:public"],
+    srcs: [
+        "absl/status/internal/status_matchers.cc",
+    ],
+    generated_headers: ["absl_status_status_matchers_hdrs"],
+    export_generated_headers: ["absl_status_status_matchers_hdrs"],
+
+    whole_static_libs: [
+        "absl_status",
+        "absl_status_statusor",
+        "absl_base_config",
+        "absl_strings_string_view",
+    ],
+    export_static_lib_headers: [
+        "absl_status",
+        "absl_status_statusor",
+        "absl_base_config",
+        "absl_strings_string_view",
+    ],
+
+    static_libs: [
+        "libgmock",
+        "libgtest",
+    ],
+    shared: {
+        enabled: false,
+    },
+
+}
+
+genrule {
     name: "absl_status_statusor_hdrs",
     srcs: [
         "absl/status/statusor.h",
@@ -3271,65 +4215,6 @@
 }
 
 genrule {
-    name: "absl_types_variant_hdrs",
-    srcs: [
-        "absl/types/variant.h",
-    ],
-    out: [
-        "my_include_dir/absl/types/variant.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_types_variant",
-    defaults: ["absl_defaults"],
-    visibility: ["//visibility:public"],
-    srcs: [
-
-    ],
-    generated_headers: ["absl_types_variant_hdrs"],
-    export_generated_headers: ["absl_types_variant_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config",
-        "absl_utility",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config",
-        "absl_utility",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_types_variant_notls",
-    defaults: ["absl_notls_defaults"],
-    visibility: ["//external/protobuf"],
-    srcs: [
-
-    ],
-    generated_headers: ["absl_types_variant_hdrs"],
-    export_generated_headers: ["absl_types_variant_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config_notls",
-        "absl_utility_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config_notls",
-        "absl_utility_notls",
-    ],
-
-}
-
-genrule {
     name: "absl_strings_str_format_hdrs",
     srcs: [
         "absl/strings/str_format.h",
@@ -3486,116 +4371,6 @@
 }
 
 genrule {
-    name: "absl_hash_weakly_mixed_integer_hdrs",
-    srcs: [
-        "absl/hash/internal/weakly_mixed_integer.h",
-    ],
-    out: [
-        "my_include_dir/absl/hash/internal/weakly_mixed_integer.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_hash_weakly_mixed_integer",
-    defaults: ["absl_defaults"],
-
-    srcs: [
-
-    ],
-    generated_headers: ["absl_hash_weakly_mixed_integer_hdrs"],
-    export_generated_headers: ["absl_hash_weakly_mixed_integer_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_hash_weakly_mixed_integer_notls",
-    defaults: ["absl_notls_defaults"],
-
-    srcs: [
-
-    ],
-    generated_headers: ["absl_hash_weakly_mixed_integer_hdrs"],
-    export_generated_headers: ["absl_hash_weakly_mixed_integer_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config_notls",
-    ],
-
-}
-
-genrule {
-    name: "absl_algorithm_hdrs",
-    srcs: [
-        "absl/algorithm/algorithm.h",
-    ],
-    out: [
-        "my_include_dir/absl/algorithm/algorithm.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_algorithm",
-    defaults: ["absl_defaults"],
-    visibility: ["//visibility:public"],
-    srcs: [
-
-    ],
-    generated_headers: ["absl_algorithm_hdrs"],
-    export_generated_headers: ["absl_algorithm_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_algorithm_notls",
-    defaults: ["absl_notls_defaults"],
-    visibility: ["//external/protobuf"],
-    srcs: [
-
-    ],
-    generated_headers: ["absl_algorithm_hdrs"],
-    export_generated_headers: ["absl_algorithm_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config_notls",
-    ],
-
-}
-
-genrule {
     name: "absl_strings_str_format_internal_hdrs",
     srcs: [
         "absl/strings/internal/str_format/arg.h",
@@ -3782,140 +4557,6 @@
 }
 
 genrule {
-    name: "absl_functional_function_ref_hdrs",
-    srcs: [
-        "absl/functional/function_ref.h",
-        "absl/functional/internal/function_ref.h",
-    ],
-    out: [
-        "my_include_dir/absl/functional/function_ref.h",
-        "my_include_dir/absl/functional/internal/function_ref.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_functional_function_ref",
-    defaults: ["absl_defaults"],
-    visibility: ["//visibility:public"],
-    srcs: [
-
-    ],
-    generated_headers: ["absl_functional_function_ref_hdrs"],
-    export_generated_headers: ["absl_functional_function_ref_hdrs"],
-
-    whole_static_libs: [
-        "absl_functional_any_invocable",
-        "absl_base_core_headers",
-        "absl_meta_type_traits",
-    ],
-    export_static_lib_headers: [
-        "absl_functional_any_invocable",
-        "absl_base_core_headers",
-        "absl_meta_type_traits",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_functional_function_ref_notls",
-    defaults: ["absl_notls_defaults"],
-    visibility: ["//external/protobuf"],
-    srcs: [
-
-    ],
-    generated_headers: ["absl_functional_function_ref_hdrs"],
-    export_generated_headers: ["absl_functional_function_ref_hdrs"],
-
-    whole_static_libs: [
-        "absl_functional_any_invocable_notls",
-        "absl_base_core_headers_notls",
-        "absl_meta_type_traits_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_functional_any_invocable_notls",
-        "absl_base_core_headers_notls",
-        "absl_meta_type_traits_notls",
-    ],
-
-}
-
-genrule {
-    name: "absl_functional_any_invocable_hdrs",
-    srcs: [
-        "absl/functional/any_invocable.h",
-        "absl/functional/internal/any_invocable.h",
-    ],
-    out: [
-        "my_include_dir/absl/functional/any_invocable.h",
-        "my_include_dir/absl/functional/internal/any_invocable.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_functional_any_invocable",
-    defaults: ["absl_defaults"],
-    visibility: ["//visibility:public"],
-    srcs: [
-
-    ],
-    generated_headers: ["absl_functional_any_invocable_hdrs"],
-    export_generated_headers: ["absl_functional_any_invocable_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config",
-        "absl_base_core_headers",
-        "absl_meta_type_traits",
-        "absl_utility",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config",
-        "absl_base_core_headers",
-        "absl_meta_type_traits",
-        "absl_utility",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_functional_any_invocable_notls",
-    defaults: ["absl_notls_defaults"],
-    visibility: ["//external/protobuf"],
-    srcs: [
-
-    ],
-    generated_headers: ["absl_functional_any_invocable_hdrs"],
-    export_generated_headers: ["absl_functional_any_invocable_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-        "absl_meta_type_traits_notls",
-        "absl_utility_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-        "absl_meta_type_traits_notls",
-        "absl_utility_notls",
-    ],
-
-}
-
-genrule {
     name: "absl_container_inlined_vector_hdrs",
     srcs: [
         "absl/container/inlined_vector.h",
@@ -4078,148 +4719,6 @@
 }
 
 genrule {
-    name: "absl_container_compressed_tuple_hdrs",
-    srcs: [
-        "absl/container/internal/compressed_tuple.h",
-    ],
-    out: [
-        "my_include_dir/absl/container/internal/compressed_tuple.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_container_compressed_tuple",
-    defaults: ["absl_defaults"],
-    visibility: ["//visibility:public"],
-    srcs: [
-
-    ],
-    generated_headers: ["absl_container_compressed_tuple_hdrs"],
-    export_generated_headers: ["absl_container_compressed_tuple_hdrs"],
-
-    whole_static_libs: [
-        "absl_utility",
-    ],
-    export_static_lib_headers: [
-        "absl_utility",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_container_compressed_tuple_notls",
-    defaults: ["absl_notls_defaults"],
-    visibility: ["//external/protobuf"],
-    srcs: [
-
-    ],
-    generated_headers: ["absl_container_compressed_tuple_hdrs"],
-    export_generated_headers: ["absl_container_compressed_tuple_hdrs"],
-
-    whole_static_libs: [
-        "absl_utility_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_utility_notls",
-    ],
-
-}
-
-genrule {
-    name: "absl_container_fixed_array_hdrs",
-    srcs: [
-        "absl/container/fixed_array.h",
-    ],
-    out: [
-        "my_include_dir/absl/container/fixed_array.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_container_fixed_array",
-    defaults: ["absl_defaults"],
-    visibility: ["//visibility:public"],
-    srcs: [
-
-    ],
-    generated_headers: ["absl_container_fixed_array_hdrs"],
-    export_generated_headers: ["absl_container_fixed_array_hdrs"],
-
-    whole_static_libs: [
-        "absl_container_compressed_tuple",
-        "absl_algorithm",
-        "absl_base_config",
-        "absl_base_core_headers",
-        "absl_base_dynamic_annotations",
-        "absl_base_iterator_traits_internal",
-        "absl_base_throw_delegate",
-        "absl_hash_weakly_mixed_integer",
-        "absl_memory",
-    ],
-    export_static_lib_headers: [
-        "absl_container_compressed_tuple",
-        "absl_algorithm",
-        "absl_base_config",
-        "absl_base_core_headers",
-        "absl_base_dynamic_annotations",
-        "absl_base_iterator_traits_internal",
-        "absl_base_throw_delegate",
-        "absl_hash_weakly_mixed_integer",
-        "absl_memory",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_container_fixed_array_notls",
-    defaults: ["absl_notls_defaults"],
-    visibility: ["//external/protobuf"],
-    srcs: [
-
-    ],
-    generated_headers: ["absl_container_fixed_array_hdrs"],
-    export_generated_headers: ["absl_container_fixed_array_hdrs"],
-
-    whole_static_libs: [
-        "absl_container_compressed_tuple_notls",
-        "absl_algorithm_notls",
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-        "absl_base_dynamic_annotations_notls",
-        "absl_base_iterator_traits_internal_notls",
-        "absl_base_throw_delegate_notls",
-        "absl_hash_weakly_mixed_integer_notls",
-        "absl_memory_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_container_compressed_tuple_notls",
-        "absl_algorithm_notls",
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-        "absl_base_dynamic_annotations_notls",
-        "absl_base_iterator_traits_internal_notls",
-        "absl_base_throw_delegate_notls",
-        "absl_hash_weakly_mixed_integer_notls",
-        "absl_memory_notls",
-    ],
-
-}
-
-genrule {
     name: "absl_strings_has_ostream_operator_hdrs",
     srcs: [
         "absl/strings/has_ostream_operator.h",
@@ -4438,11 +4937,13 @@
     export_generated_headers: ["absl_strings_cord_hdrs"],
 
     whole_static_libs: [
+        "absl_strings_append_and_overwrite",
         "absl_strings_cord_internal",
         "absl_strings_cordz_info",
         "absl_strings_cordz_update_scope",
         "absl_strings_cordz_update_tracker",
         "absl_strings_internal",
+        "absl_strings_resize_and_overwrite",
         "absl_strings",
         "absl_base_config",
         "absl_base_core_headers",
@@ -4461,11 +4962,13 @@
         "absl_types_span",
     ],
     export_static_lib_headers: [
+        "absl_strings_append_and_overwrite",
         "absl_strings_cord_internal",
         "absl_strings_cordz_info",
         "absl_strings_cordz_update_scope",
         "absl_strings_cordz_update_tracker",
         "absl_strings_internal",
+        "absl_strings_resize_and_overwrite",
         "absl_strings",
         "absl_base_config",
         "absl_base_core_headers",
@@ -4498,11 +5001,13 @@
     export_generated_headers: ["absl_strings_cord_hdrs"],
 
     whole_static_libs: [
+        "absl_strings_append_and_overwrite_notls",
         "absl_strings_cord_internal_notls",
         "absl_strings_cordz_info_notls",
         "absl_strings_cordz_update_scope_notls",
         "absl_strings_cordz_update_tracker_notls",
         "absl_strings_internal_notls",
+        "absl_strings_resize_and_overwrite_notls",
         "absl_strings_notls",
         "absl_base_config_notls",
         "absl_base_core_headers_notls",
@@ -4521,11 +5026,13 @@
         "absl_types_span_notls",
     ],
     export_static_lib_headers: [
+        "absl_strings_append_and_overwrite_notls",
         "absl_strings_cord_internal_notls",
         "absl_strings_cordz_info_notls",
         "absl_strings_cordz_update_scope_notls",
         "absl_strings_cordz_update_tracker_notls",
         "absl_strings_internal_notls",
+        "absl_strings_resize_and_overwrite_notls",
         "absl_strings_notls",
         "absl_base_config_notls",
         "absl_base_core_headers_notls",
@@ -4772,65 +5279,6 @@
 }
 
 genrule {
-    name: "absl_base_prefetch_hdrs",
-    srcs: [
-        "absl/base/prefetch.h",
-    ],
-    out: [
-        "my_include_dir/absl/base/prefetch.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_base_prefetch",
-    defaults: ["absl_defaults"],
-    visibility: ["//visibility:public"],
-    srcs: [
-
-    ],
-    generated_headers: ["absl_base_prefetch_hdrs"],
-    export_generated_headers: ["absl_base_prefetch_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config",
-        "absl_base_core_headers",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config",
-        "absl_base_core_headers",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_base_prefetch_notls",
-    defaults: ["absl_notls_defaults"],
-    visibility: ["//external/protobuf"],
-    srcs: [
-
-    ],
-    generated_headers: ["absl_base_prefetch_hdrs"],
-    export_generated_headers: ["absl_base_prefetch_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-    ],
-
-}
-
-genrule {
     name: "absl_crc_non_temporal_memcpy_hdrs",
     srcs: [
         "absl/crc/internal/non_temporal_memcpy.h",
@@ -5262,6 +5710,7 @@
         "absl_base",
         "absl_base_config",
         "absl_base_core_headers",
+        "absl_base_no_destructor",
         "absl_base_raw_logging_internal",
         "absl_container_inlined_vector",
         "absl_debugging_stacktrace",
@@ -5278,6 +5727,7 @@
         "absl_base",
         "absl_base_config",
         "absl_base_core_headers",
+        "absl_base_no_destructor",
         "absl_base_raw_logging_internal",
         "absl_container_inlined_vector",
         "absl_debugging_stacktrace",
@@ -5307,6 +5757,7 @@
         "absl_base_notls",
         "absl_base_config_notls",
         "absl_base_core_headers_notls",
+        "absl_base_no_destructor_notls",
         "absl_base_raw_logging_internal_notls",
         "absl_container_inlined_vector_notls",
         "absl_debugging_stacktrace_notls",
@@ -5323,6 +5774,7 @@
         "absl_base_notls",
         "absl_base_config_notls",
         "absl_base_core_headers_notls",
+        "absl_base_no_destructor_notls",
         "absl_base_raw_logging_internal_notls",
         "absl_container_inlined_vector_notls",
         "absl_debugging_stacktrace_notls",
@@ -5737,12 +6189,14 @@
 
     whole_static_libs: [
         "absl_base_config",
+        "absl_hash",
         "absl_memory",
         "absl_meta_type_traits",
         "absl_utility",
     ],
     export_static_lib_headers: [
         "absl_base_config",
+        "absl_hash",
         "absl_memory",
         "absl_meta_type_traits",
         "absl_utility",
@@ -5762,12 +6216,14 @@
 
     whole_static_libs: [
         "absl_base_config_notls",
+        "absl_hash_notls",
         "absl_memory_notls",
         "absl_meta_type_traits_notls",
         "absl_utility_notls",
     ],
     export_static_lib_headers: [
         "absl_base_config_notls",
+        "absl_hash_notls",
         "absl_memory_notls",
         "absl_meta_type_traits_notls",
         "absl_utility_notls",
@@ -7718,45 +8174,6 @@
 
 }
 
-cc_test_library {
-    name: "absl_log_scoped_mock_log_notls",
-    defaults: ["absl_notls_test_defaults"],
-    visibility: ["//external/protobuf"],
-    srcs: [
-        "absl/log/scoped_mock_log.cc",
-    ],
-    generated_headers: ["absl_log_scoped_mock_log_hdrs"],
-    export_generated_headers: ["absl_log_scoped_mock_log_hdrs"],
-
-    whole_static_libs: [
-        "absl_log_log_entry_notls",
-        "absl_log_log_sink_notls",
-        "absl_log_log_sink_registry_notls",
-        "absl_base_config_notls",
-        "absl_base_log_severity_notls",
-        "absl_base_raw_logging_internal_notls",
-        "absl_strings_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_log_log_entry_notls",
-        "absl_log_log_sink_notls",
-        "absl_log_log_sink_registry_notls",
-        "absl_base_config_notls",
-        "absl_base_log_severity_notls",
-        "absl_base_raw_logging_internal_notls",
-        "absl_strings_notls",
-    ],
-
-    static_libs: [
-        "libgmock",
-        "libgtest",
-    ],
-    shared: {
-        enabled: false,
-    },
-
-}
-
 genrule {
     name: "absl_log_log_sink_registry_hdrs",
     srcs: [
@@ -8028,7 +8445,7 @@
     defaults: ["absl_defaults"],
     visibility: ["//visibility:public"],
     srcs: [
-
+        "absl/log/log_entry.cc",
     ],
     generated_headers: ["absl_log_log_entry_hdrs"],
     export_generated_headers: ["absl_log_log_entry_hdrs"],
@@ -8038,6 +8455,7 @@
         "absl_base_core_headers",
         "absl_base_log_severity",
         "absl_log_internal_config",
+        "absl_log_internal_proto",
         "absl_strings",
         "absl_time",
         "absl_types_span",
@@ -8047,6 +8465,7 @@
         "absl_base_core_headers",
         "absl_base_log_severity",
         "absl_log_internal_config",
+        "absl_log_internal_proto",
         "absl_strings",
         "absl_time",
         "absl_types_span",
@@ -8059,7 +8478,7 @@
     defaults: ["absl_notls_defaults"],
     visibility: ["//external/protobuf"],
     srcs: [
-
+        "absl/log/log_entry.cc",
     ],
     generated_headers: ["absl_log_log_entry_hdrs"],
     export_generated_headers: ["absl_log_log_entry_hdrs"],
@@ -8069,6 +8488,7 @@
         "absl_base_core_headers_notls",
         "absl_base_log_severity_notls",
         "absl_log_internal_config_notls",
+        "absl_log_internal_proto_notls",
         "absl_strings_notls",
         "absl_time_notls",
         "absl_types_span_notls",
@@ -8078,6 +8498,7 @@
         "absl_base_core_headers_notls",
         "absl_base_log_severity_notls",
         "absl_log_internal_config_notls",
+        "absl_log_internal_proto_notls",
         "absl_strings_notls",
         "absl_time_notls",
         "absl_types_span_notls",
@@ -8086,6 +8507,77 @@
 }
 
 genrule {
+    name: "absl_log_internal_proto_hdrs",
+    srcs: [
+        "absl/log/internal/proto.h",
+    ],
+    out: [
+        "my_include_dir/absl/log/internal/proto.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_log_internal_proto",
+    defaults: ["absl_defaults"],
+
+    srcs: [
+        "absl/log/internal/proto.cc",
+    ],
+    generated_headers: ["absl_log_internal_proto_hdrs"],
+    export_generated_headers: ["absl_log_internal_proto_hdrs"],
+
+    whole_static_libs: [
+        "absl_base",
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_strings",
+        "absl_types_span",
+    ],
+    export_static_lib_headers: [
+        "absl_base",
+        "absl_base_config",
+        "absl_base_core_headers",
+        "absl_strings",
+        "absl_types_span",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_log_internal_proto_notls",
+    defaults: ["absl_notls_defaults"],
+
+    srcs: [
+        "absl/log/internal/proto.cc",
+    ],
+    generated_headers: ["absl_log_internal_proto_hdrs"],
+    export_generated_headers: ["absl_log_internal_proto_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_notls",
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_strings_notls",
+        "absl_types_span_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_notls",
+        "absl_base_config_notls",
+        "absl_base_core_headers_notls",
+        "absl_strings_notls",
+        "absl_types_span_notls",
+    ],
+
+}
+
+genrule {
     name: "absl_log_internal_config_hdrs",
     srcs: [
         "absl/log/internal/config.h",
@@ -8378,253 +8870,6 @@
 }
 
 genrule {
-    name: "absl_hash_hdrs",
-    srcs: [
-        "absl/hash/hash.h",
-        "absl/hash/internal/hash.h",
-    ],
-    out: [
-        "my_include_dir/absl/hash/hash.h",
-        "my_include_dir/absl/hash/internal/hash.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_hash",
-    defaults: ["absl_defaults"],
-    visibility: ["//visibility:public"],
-    srcs: [
-        "absl/hash/internal/hash.cc",
-    ],
-    generated_headers: ["absl_hash_hdrs"],
-    export_generated_headers: ["absl_hash_hdrs"],
-
-    whole_static_libs: [
-        "absl_hash_city",
-        "absl_hash_low_level_hash",
-        "absl_hash_weakly_mixed_integer",
-        "absl_base_config",
-        "absl_base_core_headers",
-        "absl_base_endian",
-        "absl_container_fixed_array",
-        "absl_functional_function_ref",
-        "absl_meta_type_traits",
-        "absl_numeric_bits",
-        "absl_numeric_int128",
-        "absl_strings",
-        "absl_types_optional",
-        "absl_types_variant",
-        "absl_utility",
-    ],
-    export_static_lib_headers: [
-        "absl_hash_city",
-        "absl_hash_low_level_hash",
-        "absl_hash_weakly_mixed_integer",
-        "absl_base_config",
-        "absl_base_core_headers",
-        "absl_base_endian",
-        "absl_container_fixed_array",
-        "absl_functional_function_ref",
-        "absl_meta_type_traits",
-        "absl_numeric_bits",
-        "absl_numeric_int128",
-        "absl_strings",
-        "absl_types_optional",
-        "absl_types_variant",
-        "absl_utility",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_hash_notls",
-    defaults: ["absl_notls_defaults"],
-    visibility: ["//external/protobuf"],
-    srcs: [
-        "absl/hash/internal/hash.cc",
-    ],
-    generated_headers: ["absl_hash_hdrs"],
-    export_generated_headers: ["absl_hash_hdrs"],
-
-    whole_static_libs: [
-        "absl_hash_city_notls",
-        "absl_hash_low_level_hash_notls",
-        "absl_hash_weakly_mixed_integer_notls",
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-        "absl_base_endian_notls",
-        "absl_container_fixed_array_notls",
-        "absl_functional_function_ref_notls",
-        "absl_meta_type_traits_notls",
-        "absl_numeric_bits_notls",
-        "absl_numeric_int128_notls",
-        "absl_strings_notls",
-        "absl_types_optional_notls",
-        "absl_types_variant_notls",
-        "absl_utility_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_hash_city_notls",
-        "absl_hash_low_level_hash_notls",
-        "absl_hash_weakly_mixed_integer_notls",
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-        "absl_base_endian_notls",
-        "absl_container_fixed_array_notls",
-        "absl_functional_function_ref_notls",
-        "absl_meta_type_traits_notls",
-        "absl_numeric_bits_notls",
-        "absl_numeric_int128_notls",
-        "absl_strings_notls",
-        "absl_types_optional_notls",
-        "absl_types_variant_notls",
-        "absl_utility_notls",
-    ],
-
-}
-
-genrule {
-    name: "absl_hash_low_level_hash_hdrs",
-    srcs: [
-        "absl/hash/internal/low_level_hash.h",
-    ],
-    out: [
-        "my_include_dir/absl/hash/internal/low_level_hash.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_hash_low_level_hash",
-    defaults: ["absl_defaults"],
-
-    srcs: [
-        "absl/hash/internal/low_level_hash.cc",
-    ],
-    generated_headers: ["absl_hash_low_level_hash_hdrs"],
-    export_generated_headers: ["absl_hash_low_level_hash_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config",
-        "absl_base_core_headers",
-        "absl_base_endian",
-        "absl_base_prefetch",
-        "absl_numeric_int128",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config",
-        "absl_base_core_headers",
-        "absl_base_endian",
-        "absl_base_prefetch",
-        "absl_numeric_int128",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_hash_low_level_hash_notls",
-    defaults: ["absl_notls_defaults"],
-
-    srcs: [
-        "absl/hash/internal/low_level_hash.cc",
-    ],
-    generated_headers: ["absl_hash_low_level_hash_hdrs"],
-    export_generated_headers: ["absl_hash_low_level_hash_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-        "absl_base_endian_notls",
-        "absl_base_prefetch_notls",
-        "absl_numeric_int128_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-        "absl_base_endian_notls",
-        "absl_base_prefetch_notls",
-        "absl_numeric_int128_notls",
-    ],
-
-}
-
-genrule {
-    name: "absl_hash_city_hdrs",
-    srcs: [
-        "absl/hash/internal/city.h",
-    ],
-    out: [
-        "my_include_dir/absl/hash/internal/city.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_hash_city",
-    defaults: ["absl_defaults"],
-    visibility: ["//visibility:public"],
-    srcs: [
-        "absl/hash/internal/city.cc",
-    ],
-    generated_headers: ["absl_hash_city_hdrs"],
-    export_generated_headers: ["absl_hash_city_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config",
-        "absl_base_core_headers",
-        "absl_base_endian",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config",
-        "absl_base_core_headers",
-        "absl_base_endian",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_hash_city_notls",
-    defaults: ["absl_notls_defaults"],
-    visibility: ["//external/protobuf"],
-    srcs: [
-        "absl/hash/internal/city.cc",
-    ],
-    generated_headers: ["absl_hash_city_hdrs"],
-    export_generated_headers: ["absl_hash_city_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-        "absl_base_endian_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-        "absl_base_endian_notls",
-    ],
-
-}
-
-genrule {
     name: "absl_cleanup_hdrs",
     srcs: [
         "absl/cleanup/cleanup.h",
@@ -8822,12 +9067,12 @@
 }
 
 genrule {
-    name: "absl_log_hdrs",
+    name: "absl_log_log_streamer_hdrs",
     srcs: [
-        "absl/log/log.h",
+        "absl/log/log_streamer.h",
     ],
     out: [
-        "my_include_dir/absl/log/log.h",
+        "my_include_dir/absl/log/log_streamer.h",
     ],
     export_include_dirs: ["my_include_dir"],
     cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
@@ -8839,42 +9084,117 @@
 }
 
 cc_library_static {
-    name: "absl_log",
+    name: "absl_log_log_streamer",
     defaults: ["absl_defaults"],
     visibility: ["//visibility:public"],
     srcs: [
 
     ],
-    generated_headers: ["absl_log_hdrs"],
-    export_generated_headers: ["absl_log_hdrs"],
+    generated_headers: ["absl_log_log_streamer_hdrs"],
+    export_generated_headers: ["absl_log_log_streamer_hdrs"],
 
     whole_static_libs: [
-        "absl_log_vlog_is_on",
+        "absl_log_absl_log",
+        "absl_base_config",
+        "absl_base_log_severity",
+        "absl_strings",
+        "absl_strings_internal",
+        "absl_types_optional",
+        "absl_utility",
+    ],
+    export_static_lib_headers: [
+        "absl_log_absl_log",
+        "absl_base_config",
+        "absl_base_log_severity",
+        "absl_strings",
+        "absl_strings_internal",
+        "absl_types_optional",
+        "absl_utility",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_log_log_streamer_notls",
+    defaults: ["absl_notls_defaults"],
+    visibility: ["//external/protobuf"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_log_log_streamer_hdrs"],
+    export_generated_headers: ["absl_log_log_streamer_hdrs"],
+
+    whole_static_libs: [
+        "absl_log_absl_log_notls",
+        "absl_base_config_notls",
+        "absl_base_log_severity_notls",
+        "absl_strings_notls",
+        "absl_strings_internal_notls",
+        "absl_types_optional_notls",
+        "absl_utility_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_log_absl_log_notls",
+        "absl_base_config_notls",
+        "absl_base_log_severity_notls",
+        "absl_strings_notls",
+        "absl_strings_internal_notls",
+        "absl_types_optional_notls",
+        "absl_utility_notls",
+    ],
+
+}
+
+genrule {
+    name: "absl_log_absl_log_hdrs",
+    srcs: [
+        "absl/log/absl_log.h",
+    ],
+    out: [
+        "my_include_dir/absl/log/absl_log.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_log_absl_log",
+    defaults: ["absl_defaults"],
+    visibility: ["//visibility:public"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_log_absl_log_hdrs"],
+    export_generated_headers: ["absl_log_absl_log_hdrs"],
+
+    whole_static_libs: [
         "absl_log_internal_log_impl",
     ],
     export_static_lib_headers: [
-        "absl_log_vlog_is_on",
         "absl_log_internal_log_impl",
     ],
 
 }
 
 cc_library_static {
-    name: "absl_log_notls",
+    name: "absl_log_absl_log_notls",
     defaults: ["absl_notls_defaults"],
     visibility: ["//external/protobuf"],
     srcs: [
 
     ],
-    generated_headers: ["absl_log_hdrs"],
-    export_generated_headers: ["absl_log_hdrs"],
+    generated_headers: ["absl_log_absl_log_hdrs"],
+    export_generated_headers: ["absl_log_absl_log_hdrs"],
 
     whole_static_libs: [
-        "absl_log_vlog_is_on_notls",
         "absl_log_internal_log_impl_notls",
     ],
     export_static_lib_headers: [
-        "absl_log_vlog_is_on_notls",
         "absl_log_internal_log_impl_notls",
     ],
 
@@ -9446,77 +9766,6 @@
 }
 
 genrule {
-    name: "absl_log_internal_proto_hdrs",
-    srcs: [
-        "absl/log/internal/proto.h",
-    ],
-    out: [
-        "my_include_dir/absl/log/internal/proto.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_log_internal_proto",
-    defaults: ["absl_defaults"],
-
-    srcs: [
-        "absl/log/internal/proto.cc",
-    ],
-    generated_headers: ["absl_log_internal_proto_hdrs"],
-    export_generated_headers: ["absl_log_internal_proto_hdrs"],
-
-    whole_static_libs: [
-        "absl_base",
-        "absl_base_config",
-        "absl_base_core_headers",
-        "absl_strings",
-        "absl_types_span",
-    ],
-    export_static_lib_headers: [
-        "absl_base",
-        "absl_base_config",
-        "absl_base_core_headers",
-        "absl_strings",
-        "absl_types_span",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_log_internal_proto_notls",
-    defaults: ["absl_notls_defaults"],
-
-    srcs: [
-        "absl/log/internal/proto.cc",
-    ],
-    generated_headers: ["absl_log_internal_proto_hdrs"],
-    export_generated_headers: ["absl_log_internal_proto_hdrs"],
-
-    whole_static_libs: [
-        "absl_base_notls",
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-        "absl_strings_notls",
-        "absl_types_span_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_base_notls",
-        "absl_base_config_notls",
-        "absl_base_core_headers_notls",
-        "absl_strings_notls",
-        "absl_types_span_notls",
-    ],
-
-}
-
-genrule {
     name: "absl_log_internal_nullguard_hdrs",
     srcs: [
         "absl/log/internal/nullguard.h",
@@ -9860,6 +10109,65 @@
 }
 
 genrule {
+    name: "absl_log_hdrs",
+    srcs: [
+        "absl/log/log.h",
+    ],
+    out: [
+        "my_include_dir/absl/log/log.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_log",
+    defaults: ["absl_defaults"],
+    visibility: ["//visibility:public"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_log_hdrs"],
+    export_generated_headers: ["absl_log_hdrs"],
+
+    whole_static_libs: [
+        "absl_log_vlog_is_on",
+        "absl_log_internal_log_impl",
+    ],
+    export_static_lib_headers: [
+        "absl_log_vlog_is_on",
+        "absl_log_internal_log_impl",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_log_notls",
+    defaults: ["absl_notls_defaults"],
+    visibility: ["//external/protobuf"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_log_hdrs"],
+    export_generated_headers: ["absl_log_hdrs"],
+
+    whole_static_libs: [
+        "absl_log_vlog_is_on_notls",
+        "absl_log_internal_log_impl_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_log_vlog_is_on_notls",
+        "absl_log_internal_log_impl_notls",
+    ],
+
+}
+
+genrule {
     name: "absl_log_vlog_is_on_hdrs",
     srcs: [
         "absl/log/vlog_is_on.h",
@@ -10012,12 +10320,16 @@
         "absl_log",
         "absl_base_config",
         "absl_base_core_headers",
+        "absl_base_nullability",
+        "absl_base_nullability_traits_internal",
         "absl_strings",
     ],
     export_static_lib_headers: [
         "absl_log",
         "absl_base_config",
         "absl_base_core_headers",
+        "absl_base_nullability",
+        "absl_base_nullability_traits_internal",
         "absl_strings",
     ],
 
@@ -10037,18 +10349,81 @@
         "absl_log_notls",
         "absl_base_config_notls",
         "absl_base_core_headers_notls",
+        "absl_base_nullability_notls",
+        "absl_base_nullability_traits_internal_notls",
         "absl_strings_notls",
     ],
     export_static_lib_headers: [
         "absl_log_notls",
         "absl_base_config_notls",
         "absl_base_core_headers_notls",
+        "absl_base_nullability_notls",
+        "absl_base_nullability_traits_internal_notls",
         "absl_strings_notls",
     ],
 
 }
 
 genrule {
+    name: "absl_base_nullability_traits_internal_hdrs",
+    srcs: [
+        "absl/base/internal/nullability_traits.h",
+    ],
+    out: [
+        "my_include_dir/absl/base/internal/nullability_traits.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_base_nullability_traits_internal",
+    defaults: ["absl_defaults"],
+
+    srcs: [
+
+    ],
+    generated_headers: ["absl_base_nullability_traits_internal_hdrs"],
+    export_generated_headers: ["absl_base_nullability_traits_internal_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config",
+        "absl_base_nullability",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config",
+        "absl_base_nullability",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_base_nullability_traits_internal_notls",
+    defaults: ["absl_notls_defaults"],
+
+    srcs: [
+
+    ],
+    generated_headers: ["absl_base_nullability_traits_internal_hdrs"],
+    export_generated_headers: ["absl_base_nullability_traits_internal_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config_notls",
+        "absl_base_nullability_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config_notls",
+        "absl_base_nullability_notls",
+    ],
+
+}
+
+genrule {
     name: "absl_log_check_hdrs",
     srcs: [
         "absl/log/check.h",
@@ -10156,6 +10531,7 @@
         "absl_base_nullability",
         "absl_debugging_leak_check",
         "absl_strings",
+        "absl_strings_has_ostream_operator",
     ],
     export_static_lib_headers: [
         "absl_log_internal_nullguard",
@@ -10167,6 +10543,7 @@
         "absl_base_nullability",
         "absl_debugging_leak_check",
         "absl_strings",
+        "absl_strings_has_ostream_operator",
     ],
 
 }
@@ -10191,6 +10568,7 @@
         "absl_base_nullability_notls",
         "absl_debugging_leak_check_notls",
         "absl_strings_notls",
+        "absl_strings_has_ostream_operator_notls",
     ],
     export_static_lib_headers: [
         "absl_log_internal_nullguard_notls",
@@ -10202,6 +10580,7 @@
         "absl_base_nullability_notls",
         "absl_debugging_leak_check_notls",
         "absl_strings_notls",
+        "absl_strings_has_ostream_operator_notls",
     ],
 
 }
@@ -10236,14 +10615,12 @@
     whole_static_libs: [
         "absl_log_internal_check_op",
         "absl_log_internal_conditions",
-        "absl_log_internal_log_message",
         "absl_log_internal_strip",
         "absl_base_core_headers",
     ],
     export_static_lib_headers: [
         "absl_log_internal_check_op",
         "absl_log_internal_conditions",
-        "absl_log_internal_log_message",
         "absl_log_internal_strip",
         "absl_base_core_headers",
     ],
@@ -10263,14 +10640,12 @@
     whole_static_libs: [
         "absl_log_internal_check_op_notls",
         "absl_log_internal_conditions_notls",
-        "absl_log_internal_log_message_notls",
         "absl_log_internal_strip_notls",
         "absl_base_core_headers_notls",
     ],
     export_static_lib_headers: [
         "absl_log_internal_check_op_notls",
         "absl_log_internal_conditions_notls",
-        "absl_log_internal_log_message_notls",
         "absl_log_internal_strip_notls",
         "absl_base_core_headers_notls",
     ],
@@ -10278,61 +10653,6 @@
 }
 
 genrule {
-    name: "absl_log_absl_log_hdrs",
-    srcs: [
-        "absl/log/absl_log.h",
-    ],
-    out: [
-        "my_include_dir/absl/log/absl_log.h",
-    ],
-    export_include_dirs: ["my_include_dir"],
-    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
-        "cp --parents $(in) $(genDir)/temp && " +
-        // delete empty folders automatically created by soong
-        "rm -rf $(genDir)/my_include_dir/* && " +
-        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
-        "rm -rf $(genDir)/temp",
-}
-
-cc_library_static {
-    name: "absl_log_absl_log",
-    defaults: ["absl_defaults"],
-    visibility: ["//visibility:public"],
-    srcs: [
-
-    ],
-    generated_headers: ["absl_log_absl_log_hdrs"],
-    export_generated_headers: ["absl_log_absl_log_hdrs"],
-
-    whole_static_libs: [
-        "absl_log_internal_log_impl",
-    ],
-    export_static_lib_headers: [
-        "absl_log_internal_log_impl",
-    ],
-
-}
-
-cc_library_static {
-    name: "absl_log_absl_log_notls",
-    defaults: ["absl_notls_defaults"],
-    visibility: ["//external/protobuf"],
-    srcs: [
-
-    ],
-    generated_headers: ["absl_log_absl_log_hdrs"],
-    export_generated_headers: ["absl_log_absl_log_hdrs"],
-
-    whole_static_libs: [
-        "absl_log_internal_log_impl_notls",
-    ],
-    export_static_lib_headers: [
-        "absl_log_internal_log_impl_notls",
-    ],
-
-}
-
-genrule {
     name: "absl_log_absl_check_hdrs",
     srcs: [
         "absl/log/absl_check.h",
@@ -10388,6 +10708,165 @@
 }
 
 genrule {
+    name: "absl_hash_hash_testing_hdrs",
+    srcs: [
+        "absl/hash/hash_testing.h",
+    ],
+    out: [
+        "my_include_dir/absl/hash/hash_testing.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_test_library {
+    name: "absl_hash_hash_testing",
+    defaults: ["absl_test_defaults"],
+    visibility: ["//visibility:public"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_hash_hash_testing_hdrs"],
+    export_generated_headers: ["absl_hash_hash_testing_hdrs"],
+
+    whole_static_libs: [
+        "absl_hash_spy_hash_state",
+        "absl_meta_type_traits",
+        "absl_strings",
+        "absl_types_variant",
+    ],
+    export_static_lib_headers: [
+        "absl_hash_spy_hash_state",
+        "absl_meta_type_traits",
+        "absl_strings",
+        "absl_types_variant",
+    ],
+
+    static_libs: [
+        "libgmock",
+        "libgtest",
+    ],
+    shared: {
+        enabled: false,
+    },
+
+}
+
+genrule {
+    name: "absl_hash_spy_hash_state_hdrs",
+    srcs: [
+        "absl/hash/internal/spy_hash_state.h",
+    ],
+    out: [
+        "my_include_dir/absl/hash/internal/spy_hash_state.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_test_library {
+    name: "absl_hash_spy_hash_state",
+    defaults: ["absl_test_defaults"],
+
+    srcs: [
+
+    ],
+    generated_headers: ["absl_hash_spy_hash_state_hdrs"],
+    export_generated_headers: ["absl_hash_spy_hash_state_hdrs"],
+
+    whole_static_libs: [
+        "absl_hash",
+        "absl_hash_weakly_mixed_integer",
+        "absl_strings",
+        "absl_strings_str_format",
+    ],
+    export_static_lib_headers: [
+        "absl_hash",
+        "absl_hash_weakly_mixed_integer",
+        "absl_strings",
+        "absl_strings_str_format",
+    ],
+
+    static_libs: [
+        "libgmock",
+        "libgtest",
+    ],
+    shared: {
+        enabled: false,
+    },
+
+}
+
+genrule {
+    name: "absl_functional_overload_hdrs",
+    srcs: [
+        "absl/functional/overload.h",
+    ],
+    out: [
+        "my_include_dir/absl/functional/overload.h",
+    ],
+    export_include_dirs: ["my_include_dir"],
+    cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+        "cp --parents $(in) $(genDir)/temp && " +
+        // delete empty folders automatically created by soong
+        "rm -rf $(genDir)/my_include_dir/* && " +
+        "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+        "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+    name: "absl_functional_overload",
+    defaults: ["absl_defaults"],
+    visibility: ["//visibility:public"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_functional_overload_hdrs"],
+    export_generated_headers: ["absl_functional_overload_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config",
+        "absl_meta_type_traits",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config",
+        "absl_meta_type_traits",
+    ],
+
+}
+
+cc_library_static {
+    name: "absl_functional_overload_notls",
+    defaults: ["absl_notls_defaults"],
+    visibility: ["//external/protobuf"],
+    srcs: [
+
+    ],
+    generated_headers: ["absl_functional_overload_hdrs"],
+    export_generated_headers: ["absl_functional_overload_hdrs"],
+
+    whole_static_libs: [
+        "absl_base_config_notls",
+        "absl_meta_type_traits_notls",
+    ],
+    export_static_lib_headers: [
+        "absl_base_config_notls",
+        "absl_meta_type_traits_notls",
+    ],
+
+}
+
+genrule {
     name: "absl_functional_bind_front_hdrs",
     srcs: [
         "absl/functional/bind_front.h",
@@ -10600,14 +11079,12 @@
         "absl_algorithm",
         "absl_base_config",
         "absl_base_core_headers",
-        "absl_base_nullability",
         "absl_meta_type_traits",
     ],
     export_static_lib_headers: [
         "absl_algorithm",
         "absl_base_config",
         "absl_base_core_headers",
-        "absl_base_nullability",
         "absl_meta_type_traits",
     ],
 
@@ -10627,14 +11104,12 @@
         "absl_algorithm_notls",
         "absl_base_config_notls",
         "absl_base_core_headers_notls",
-        "absl_base_nullability_notls",
         "absl_meta_type_traits_notls",
     ],
     export_static_lib_headers: [
         "absl_algorithm_notls",
         "absl_base_config_notls",
         "absl_base_core_headers_notls",
-        "absl_base_nullability_notls",
         "absl_meta_type_traits_notls",
     ],
 
@@ -11032,6 +11507,7 @@
         "absl_container_hashtable_debug_hooks",
         "absl_container_hashtablez_sampler",
         "absl_container_raw_hash_set_resize_impl",
+        "absl_base",
         "absl_base_config",
         "absl_base_core_headers",
         "absl_base_dynamic_annotations",
@@ -11058,6 +11534,7 @@
         "absl_container_hashtable_debug_hooks",
         "absl_container_hashtablez_sampler",
         "absl_container_raw_hash_set_resize_impl",
+        "absl_base",
         "absl_base_config",
         "absl_base_core_headers",
         "absl_base_dynamic_annotations",
@@ -11097,6 +11574,7 @@
         "absl_container_hashtable_debug_hooks_notls",
         "absl_container_hashtablez_sampler_notls",
         "absl_container_raw_hash_set_resize_impl_notls",
+        "absl_base_notls",
         "absl_base_config_notls",
         "absl_base_core_headers_notls",
         "absl_base_dynamic_annotations_notls",
@@ -11123,6 +11601,7 @@
         "absl_container_hashtable_debug_hooks_notls",
         "absl_container_hashtablez_sampler_notls",
         "absl_container_raw_hash_set_resize_impl_notls",
+        "absl_base_notls",
         "absl_base_config_notls",
         "absl_base_core_headers_notls",
         "absl_base_dynamic_annotations_notls",
@@ -11515,10 +11994,12 @@
 
     whole_static_libs: [
         "absl_container_common_policy_traits",
+        "absl_container_container_memory",
         "absl_meta_type_traits",
     ],
     export_static_lib_headers: [
         "absl_container_common_policy_traits",
+        "absl_container_container_memory",
         "absl_meta_type_traits",
     ],
 
@@ -11536,10 +12017,12 @@
 
     whole_static_libs: [
         "absl_container_common_policy_traits_notls",
+        "absl_container_container_memory_notls",
         "absl_meta_type_traits_notls",
     ],
     export_static_lib_headers: [
         "absl_container_common_policy_traits_notls",
+        "absl_container_container_memory_notls",
         "absl_meta_type_traits_notls",
     ],
 
diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake
index f01021b..47d0efd 100644
--- a/CMake/AbseilDll.cmake
+++ b/CMake/AbseilDll.cmake
@@ -6,6 +6,7 @@
   "algorithm/container.h"
   "base/attributes.h"
   "base/call_once.h"
+  "base/casts.cc"
   "base/casts.h"
   "base/config.h"
   "base/const_init.h"
@@ -20,12 +21,11 @@
   "base/internal/endian.h"
   "base/internal/errno_saver.h"
   "base/internal/hide_ptr.h"
-  "base/internal/identity.h"
   "base/internal/iterator_traits.h"
   "base/internal/low_level_alloc.cc"
   "base/internal/low_level_alloc.h"
   "base/internal/low_level_scheduling.h"
-  "base/internal/nullability_deprecated.h"
+  "base/internal/nullability_traits.h"
   "base/internal/per_thread_tls.h"
   "base/internal/poison.cc"
   "base/internal/poison.h"
@@ -69,6 +69,7 @@
   "cleanup/internal/cleanup.h"
   "container/btree_map.h"
   "container/btree_set.h"
+  "container/chunked_queue.h"
   "container/hash_container_defaults.h"
   "container/fixed_array.h"
   "container/flat_hash_map.h"
@@ -76,6 +77,7 @@
   "container/inlined_vector.h"
   "container/internal/btree.h"
   "container/internal/btree_container.h"
+  "container/internal/chunked_queue.h"
   "container/internal/common.h"
   "container/internal/common_policy_traits.h"
   "container/internal/compressed_tuple.h"
@@ -96,6 +98,8 @@
   "container/internal/raw_hash_set.h"
   "container/internal/raw_hash_set_resize_impl.h"
   "container/internal/tracked.h"
+  "container/linked_hash_map.h"
+  "container/linked_hash_set.h"
   "container/node_hash_map.h"
   "container/node_hash_set.h"
   "crc/crc32c.cc"
@@ -129,6 +133,8 @@
   "debugging/internal/address_is_readable.h"
   "debugging/internal/addresses.h"
   "debugging/internal/bounded_utf8_length_sequence.h"
+  "debugging/internal/borrowed_fixup_buffer.h"
+  "debugging/internal/borrowed_fixup_buffer.cc"
   "debugging/internal/decode_rust_punycode.cc"
   "debugging/internal/decode_rust_punycode.h"
   "debugging/internal/demangle.cc"
@@ -160,8 +166,6 @@
   "hash/internal/hash.h"
   "hash/internal/hash.cc"
   "hash/internal/spy_hash_state.h"
-  "hash/internal/low_level_hash.h"
-  "hash/internal/low_level_hash.cc"
   "hash/internal/weakly_mixed_integer.h"
   "log/absl_check.h"
   "log/absl_log.h"
@@ -178,6 +182,7 @@
   "log/internal/conditions.cc"
   "log/internal/conditions.h"
   "log/internal/config.h"
+  "log/internal/container.h"
   "log/internal/fnmatch.h"
   "log/internal/fnmatch.cc"
   "log/internal/globals.cc"
@@ -204,6 +209,7 @@
   "log/initialize.cc"
   "log/initialize.h"
   "log/log.h"
+  "log/log_entry.cc"
   "log/log_entry.h"
   "log/log_sink.cc"
   "log/log_sink.h"
@@ -213,15 +219,20 @@
   "log/vlog_is_on.h"
   "memory/memory.h"
   "meta/type_traits.h"
+  "meta/internal/requires.h"
   "numeric/bits.h"
   "numeric/int128.cc"
   "numeric/int128.h"
   "numeric/internal/bits.h"
   "numeric/internal/representation.h"
+  "profiling/hashtable.cc"
+  "profiling/hashtable.h"
   "profiling/internal/exponential_biased.cc"
   "profiling/internal/exponential_biased.h"
   "profiling/internal/periodic_sampler.cc"
   "profiling/internal/periodic_sampler.h"
+  "profiling/internal/profile_builder.cc"
+  "profiling/internal/profile_builder.h"
   "profiling/internal/sample_recorder.h"
   "random/bernoulli_distribution.h"
   "random/beta_distribution.h"
@@ -291,6 +302,7 @@
   "strings/cord_buffer.h"
   "strings/escaping.cc"
   "strings/escaping.h"
+  "strings/internal/append_and_overwrite.h"
   "strings/internal/charconv_bigint.cc"
   "strings/internal/charconv_bigint.h"
   "strings/internal/charconv_parse.cc"
@@ -322,6 +334,9 @@
   "strings/internal/cordz_update_tracker.h"
   "strings/internal/damerau_levenshtein_distance.h"
   "strings/internal/damerau_levenshtein_distance.cc"
+  "strings/internal/generic_printer.cc"
+  "strings/internal/generic_printer.h"
+  "strings/internal/generic_printer_internal.h"
   "strings/internal/stl_type_traits.h"
   "strings/internal/string_constant.h"
   "strings/internal/stringify_sink.h"
@@ -340,8 +355,6 @@
   "strings/str_replace.h"
   "strings/str_split.cc"
   "strings/str_split.h"
-  "strings/string_view.cc"
-  "strings/string_view.h"
   "strings/strip.h"
   "strings/substitute.cc"
   "strings/substitute.h"
@@ -372,6 +385,7 @@
   "strings/internal/str_split_internal.h"
   "strings/internal/utf8.cc"
   "strings/internal/utf8.h"
+  "strings/resize_and_overwrite.h"
   "synchronization/barrier.cc"
   "synchronization/barrier.h"
   "synchronization/blocking_counter.cc"
@@ -440,9 +454,15 @@
   "types/variant.h"
   "utility/utility.h"
   "debugging/leak_check.cc"
+  "strings/string_view.h"
 )
 
-if(NOT MSVC)
+if(MSVC)
+  list(APPEND ABSL_INTERNAL_DLL_FILES
+    "time/internal/cctz/src/time_zone_name_win.cc"
+    "time/internal/cctz/src/time_zone_name_win.h"
+  )
+else()
   list(APPEND ABSL_INTERNAL_DLL_FILES
     "flags/commandlineflag.cc"
     "flags/commandlineflag.h"
@@ -719,8 +739,10 @@
 
 if(ABSL_INTERNAL_AT_LEAST_CXX20)
   set(ABSL_INTERNAL_CXX_STD_FEATURE cxx_std_20)
-else()
+elseif(ABSL_INTERNAL_AT_LEAST_CXX17)
   set(ABSL_INTERNAL_CXX_STD_FEATURE cxx_std_17)
+else()
+  message(FATAL_ERROR "The compiler defaults to or is configured for C++ < 17. C++ >= 17 is required and Abseil and all libraries that use Abseil must use the same C++ language standard")
 endif()
 
 function(absl_internal_dll_contains)
@@ -825,6 +847,9 @@
       ${_dll_libs}
       ${ABSL_DEFAULT_LINKOPTS}
       $<$<BOOL:${ANDROID}>:-llog>
+      $<$<BOOL:${MINGW}>:-ladvapi32>
+      $<$<BOOL:${MINGW}>:-ldbghelp>
+      $<$<BOOL:${MINGW}>:-lbcrypt>
   )
   set_target_properties(${_dll} PROPERTIES
     LINKER_LANGUAGE "CXX"
diff --git a/CMake/AbseilHelpers.cmake b/CMake/AbseilHelpers.cmake
index 624a3c7..61e1ae4 100644
--- a/CMake/AbseilHelpers.cmake
+++ b/CMake/AbseilHelpers.cmake
@@ -326,7 +326,12 @@
       )
 
     if (_build_type STREQUAL "dll")
-        set(ABSL_CC_LIB_DEPS abseil_dll)
+         if(${_in_dll})
+           set(ABSL_CC_LIB_DEPS abseil_dll)
+         endif()
+         if(${_in_test_dll})
+           set(ABSL_CC_LIB_DEPS abseil_test_dll)
+         endif()
     endif()
 
     target_link_libraries(${_NAME}
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8d3059d..26dc8e7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -23,8 +23,8 @@
   cmake_policy(SET CMP0141 NEW)
 endif (POLICY CMP0141)
 
-project(absl LANGUAGES CXX VERSION 20250512)
-set(ABSL_SOVERSION "2505.0.0")
+project(absl LANGUAGES CXX VERSION 20260107)
+set(ABSL_SOVERSION "2601.0.0")
 include(CTest)
 
 # Output directory is correct by default for most build setups. However, when
diff --git a/METADATA b/METADATA
index 8475b65..2500921 100644
--- a/METADATA
+++ b/METADATA
@@ -7,14 +7,15 @@
 third_party {
   license_type: NOTICE
   last_upgrade_date {
-    year: 2025
-    month: 7
-    day: 2
+    year: 2026
+    month: 2
+    day: 18
   }
   homepage: "https://abseil.io"
   identifier {
     type: "Git"
     value: "https://github.com/abseil/abseil-cpp"
-    version: "20250512.1"
+    version: "255c84dadd029fd8ad25c5efb5933e47beaa00c7"
+    closest_version: "20260107.1"
   }
 }
diff --git a/MODULE.bazel b/MODULE.bazel
index 48a65c7..7f542c9 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -16,7 +16,7 @@
 
 module(
     name = "abseil-cpp",
-    version = "20250512.1",
+    version = "20260107.1",
     compatibility_level = 1,
 )
 
@@ -25,13 +25,13 @@
                              dev_dependency = True)
 use_repo(cc_configure, "local_config_cc")
 
-bazel_dep(name = "rules_cc", version = "0.1.1")
-bazel_dep(name = "bazel_skylib", version = "1.7.1")
-bazel_dep(name = "platforms", version = "0.0.11")
+bazel_dep(name = "rules_cc", version = "0.2.9")
+bazel_dep(name = "bazel_skylib", version = "1.8.1")
+bazel_dep(name = "platforms", version = "1.0.0")
 
 bazel_dep(
     name = "google_benchmark",
-    version = "1.9.2",
+    version = "1.9.4",
     dev_dependency = True,
 )
 
diff --git a/absl/abseil.podspec.gen.py b/absl/abseil.podspec.gen.py
index e1afa21..e19f951 100755
--- a/absl/abseil.podspec.gen.py
+++ b/absl/abseil.podspec.gen.py
@@ -42,6 +42,7 @@
     'USER_HEADER_SEARCH_PATHS' => '$(inherited) "$(PODS_TARGET_SRCROOT)"',
     'USE_HEADERMAP' => 'NO',
     'ALWAYS_SEARCH_USER_PATHS' => 'NO',
+    'CLANG_CXX_LANGUAGE_STANDARD' => 'c++17',
   }
   s.ios.deployment_target = '12.0'
   s.osx.deployment_target = '10.13'
diff --git a/absl/algorithm/BUILD.bazel b/absl/algorithm/BUILD.bazel
index 0ec8b92..7d8350c 100644
--- a/absl/algorithm/BUILD.bazel
+++ b/absl/algorithm/BUILD.bazel
@@ -14,6 +14,8 @@
 # limitations under the License.
 #
 
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
@@ -67,7 +69,6 @@
         ":algorithm",
         "//absl/base:config",
         "//absl/base:core_headers",
-        "//absl/base:nullability",
         "//absl/meta:type_traits",
     ],
 )
diff --git a/absl/algorithm/CMakeLists.txt b/absl/algorithm/CMakeLists.txt
index f3dd138..cdd5d14 100644
--- a/absl/algorithm/CMakeLists.txt
+++ b/absl/algorithm/CMakeLists.txt
@@ -51,7 +51,6 @@
     absl::config
     absl::core_headers
     absl::meta
-    absl::nullability
   PUBLIC
 )
 
@@ -64,7 +63,6 @@
     ${ABSL_TEST_COPTS}
   DEPS
     absl::algorithm_container
-    absl::base
     absl::config
     absl::core_headers
     absl::memory
diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h
index 6f9c193..c0b8a10 100644
--- a/absl/algorithm/container.h
+++ b/absl/algorithm/container.h
@@ -53,7 +53,6 @@
 #include "absl/algorithm/algorithm.h"
 #include "absl/base/config.h"
 #include "absl/base/macros.h"
-#include "absl/base/nullability.h"
 #include "absl/meta/type_traits.h"
 
 namespace absl {
@@ -522,7 +521,8 @@
 // Container-based version of the <algorithm> `std::copy()` function to copy a
 // container's elements into an iterator.
 template <typename InputSequence, typename OutputIterator>
-OutputIterator c_copy(const InputSequence& input, OutputIterator output) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator
+c_copy(const InputSequence& input, OutputIterator output) {
   return std::copy(container_algorithm_internal::c_begin(input),
                    container_algorithm_internal::c_end(input), output);
 }
@@ -532,7 +532,8 @@
 // Container-based version of the <algorithm> `std::copy_n()` function to copy a
 // container's first N elements into an iterator.
 template <typename C, typename Size, typename OutputIterator>
-OutputIterator c_copy_n(const C& input, Size n, OutputIterator output) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator
+c_copy_n(const C& input, Size n, OutputIterator output) {
   return std::copy_n(container_algorithm_internal::c_begin(input), n, output);
 }
 
@@ -541,8 +542,8 @@
 // Container-based version of the <algorithm> `std::copy_if()` function to copy
 // a container's elements satisfying some condition into an iterator.
 template <typename InputSequence, typename OutputIterator, typename Pred>
-OutputIterator c_copy_if(const InputSequence& input, OutputIterator output,
-                         Pred&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator
+c_copy_if(const InputSequence& input, OutputIterator output, Pred&& pred) {
   return std::copy_if(container_algorithm_internal::c_begin(input),
                       container_algorithm_internal::c_end(input), output,
                       std::forward<Pred>(pred));
@@ -553,8 +554,8 @@
 // Container-based version of the <algorithm> `std::copy_backward()` function to
 // copy a container's elements in reverse order into an iterator.
 template <typename C, typename BidirectionalIterator>
-BidirectionalIterator c_copy_backward(const C& src,
-                                      BidirectionalIterator dest) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 BidirectionalIterator
+c_copy_backward(const C& src, BidirectionalIterator dest) {
   return std::copy_backward(container_algorithm_internal::c_begin(src),
                             container_algorithm_internal::c_end(src), dest);
 }
@@ -564,7 +565,8 @@
 // Container-based version of the <algorithm> `std::move()` function to move
 // a container's elements into an iterator.
 template <typename C, typename OutputIterator>
-OutputIterator c_move(C&& src, OutputIterator dest) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator c_move(C&& src,
+                                                          OutputIterator dest) {
   return std::move(container_algorithm_internal::c_begin(src),
                    container_algorithm_internal::c_end(src), dest);
 }
@@ -574,7 +576,8 @@
 // Container-based version of the <algorithm> `std::move_backward()` function to
 // move a container's elements into an iterator in reverse order.
 template <typename C, typename BidirectionalIterator>
-BidirectionalIterator c_move_backward(C&& src, BidirectionalIterator dest) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 BidirectionalIterator
+c_move_backward(C&& src, BidirectionalIterator dest) {
   return std::move_backward(container_algorithm_internal::c_begin(src),
                             container_algorithm_internal::c_end(src), dest);
 }
@@ -585,7 +588,9 @@
 // swap a container's elements with another container's elements. Swaps the
 // first N elements of `c1` and `c2`, where N = min(size(c1), size(c2)).
 template <typename C1, typename C2>
-container_algorithm_internal::ContainerIter<C2> c_swap_ranges(C1& c1, C2& c2) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+    container_algorithm_internal::ContainerIter<C2>
+    c_swap_ranges(C1& c1, C2& c2) {
   auto first1 = container_algorithm_internal::c_begin(c1);
   auto last1 = container_algorithm_internal::c_end(c1);
   auto first2 = container_algorithm_internal::c_begin(c2);
@@ -605,8 +610,8 @@
 // result in an iterator pointing to the last transformed element in the output
 // range.
 template <typename InputSequence, typename OutputIterator, typename UnaryOp>
-OutputIterator c_transform(const InputSequence& input, OutputIterator output,
-                           UnaryOp&& unary_op) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator c_transform(
+    const InputSequence& input, OutputIterator output, UnaryOp&& unary_op) {
   return std::transform(container_algorithm_internal::c_begin(input),
                         container_algorithm_internal::c_end(input), output,
                         std::forward<UnaryOp>(unary_op));
@@ -617,9 +622,9 @@
 // where N = min(size(c1), size(c2)).
 template <typename InputSequence1, typename InputSequence2,
           typename OutputIterator, typename BinaryOp>
-OutputIterator c_transform(const InputSequence1& input1,
-                           const InputSequence2& input2, OutputIterator output,
-                           BinaryOp&& binary_op) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator
+c_transform(const InputSequence1& input1, const InputSequence2& input2,
+            OutputIterator output, BinaryOp&& binary_op) {
   auto first1 = container_algorithm_internal::c_begin(input1);
   auto last1 = container_algorithm_internal::c_end(input1);
   auto first2 = container_algorithm_internal::c_begin(input2);
@@ -638,7 +643,9 @@
 // replace a container's elements of some value with a new value. The container
 // is modified in place.
 template <typename Sequence, typename T>
-void c_replace(Sequence& sequence, const T& old_value, const T& new_value) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_replace(Sequence& sequence,
+                                                   const T& old_value,
+                                                   const T& new_value) {
   std::replace(container_algorithm_internal::c_begin(sequence),
                container_algorithm_internal::c_end(sequence), old_value,
                new_value);
@@ -650,7 +657,8 @@
 // replace a container's elements of some value with a new value based on some
 // condition. The container is modified in place.
 template <typename C, typename Pred, typename T>
-void c_replace_if(C& c, Pred&& pred, T&& new_value) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_replace_if(C& c, Pred&& pred,
+                                                      T&& new_value) {
   std::replace_if(container_algorithm_internal::c_begin(c),
                   container_algorithm_internal::c_end(c),
                   std::forward<Pred>(pred), std::forward<T>(new_value));
@@ -662,8 +670,8 @@
 // replace a container's elements of some value with a new value  and return the
 // results within an iterator.
 template <typename C, typename OutputIterator, typename T>
-OutputIterator c_replace_copy(const C& c, OutputIterator result, T&& old_value,
-                              T&& new_value) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator c_replace_copy(
+    const C& c, OutputIterator result, T&& old_value, T&& new_value) {
   return std::replace_copy(container_algorithm_internal::c_begin(c),
                            container_algorithm_internal::c_end(c), result,
                            std::forward<T>(old_value),
@@ -676,8 +684,8 @@
 // to replace a container's elements of some value with a new value based on
 // some condition, and return the results within an iterator.
 template <typename C, typename OutputIterator, typename Pred, typename T>
-OutputIterator c_replace_copy_if(const C& c, OutputIterator result, Pred&& pred,
-                                 const T& new_value) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator c_replace_copy_if(
+    const C& c, OutputIterator result, Pred&& pred, const T& new_value) {
   return std::replace_copy_if(container_algorithm_internal::c_begin(c),
                               container_algorithm_internal::c_end(c), result,
                               std::forward<Pred>(pred), new_value);
@@ -688,7 +696,7 @@
 // Container-based version of the <algorithm> `std::fill()` function to fill a
 // container with some value.
 template <typename C, typename T>
-void c_fill(C& c, const T& value) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_fill(C& c, const T& value) {
   std::fill(container_algorithm_internal::c_begin(c),
             container_algorithm_internal::c_end(c), value);
 }
@@ -698,7 +706,8 @@
 // Container-based version of the <algorithm> `std::fill_n()` function to fill
 // the first N elements in a container with some value.
 template <typename C, typename Size, typename T>
-void c_fill_n(C& c, Size n, const T& value) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_fill_n(C& c, Size n,
+                                                  const T& value) {
   std::fill_n(container_algorithm_internal::c_begin(c), n, value);
 }
 
@@ -707,7 +716,7 @@
 // Container-based version of the <algorithm> `std::generate()` function to
 // assign a container's elements to the values provided by the given generator.
 template <typename C, typename Generator>
-void c_generate(C& c, Generator&& gen) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_generate(C& c, Generator&& gen) {
   std::generate(container_algorithm_internal::c_begin(c),
                 container_algorithm_internal::c_end(c),
                 std::forward<Generator>(gen));
@@ -719,8 +728,9 @@
 // assign a container's first N elements to the values provided by the given
 // generator.
 template <typename C, typename Size, typename Generator>
-container_algorithm_internal::ContainerIter<C> c_generate_n(C& c, Size n,
-                                                            Generator&& gen) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+    container_algorithm_internal::ContainerIter<C>
+    c_generate_n(C& c, Size n, Generator&& gen) {
   return std::generate_n(container_algorithm_internal::c_begin(c), n,
                          std::forward<Generator>(gen));
 }
@@ -736,8 +746,8 @@
 // copy a container's elements while removing any elements matching the given
 // `value`.
 template <typename C, typename OutputIterator, typename T>
-OutputIterator c_remove_copy(const C& c, OutputIterator result,
-                             const T& value) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator
+c_remove_copy(const C& c, OutputIterator result, const T& value) {
   return std::remove_copy(container_algorithm_internal::c_begin(c),
                           container_algorithm_internal::c_end(c), result,
                           value);
@@ -749,8 +759,8 @@
 // to copy a container's elements while removing any elements matching the given
 // condition.
 template <typename C, typename OutputIterator, typename Pred>
-OutputIterator c_remove_copy_if(const C& c, OutputIterator result,
-                                Pred&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator
+c_remove_copy_if(const C& c, OutputIterator result, Pred&& pred) {
   return std::remove_copy_if(container_algorithm_internal::c_begin(c),
                              container_algorithm_internal::c_end(c), result,
                              std::forward<Pred>(pred));
@@ -762,7 +772,8 @@
 // copy a container's elements while removing any elements containing duplicate
 // values.
 template <typename C, typename OutputIterator>
-OutputIterator c_unique_copy(const C& c, OutputIterator result) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator
+c_unique_copy(const C& c, OutputIterator result) {
   return std::unique_copy(container_algorithm_internal::c_begin(c),
                           container_algorithm_internal::c_end(c), result);
 }
@@ -770,8 +781,8 @@
 // Overload of c_unique_copy() for using a predicate evaluation other than
 // `==` for comparing uniqueness of the element values.
 template <typename C, typename OutputIterator, typename BinaryPredicate>
-OutputIterator c_unique_copy(const C& c, OutputIterator result,
-                             BinaryPredicate&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator
+c_unique_copy(const C& c, OutputIterator result, BinaryPredicate&& pred) {
   return std::unique_copy(container_algorithm_internal::c_begin(c),
                           container_algorithm_internal::c_end(c), result,
                           std::forward<BinaryPredicate>(pred));
@@ -782,7 +793,7 @@
 // Container-based version of the <algorithm> `std::reverse()` function to
 // reverse a container's elements.
 template <typename Sequence>
-void c_reverse(Sequence& sequence) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_reverse(Sequence& sequence) {
   std::reverse(container_algorithm_internal::c_begin(sequence),
                container_algorithm_internal::c_end(sequence));
 }
@@ -792,7 +803,8 @@
 // Container-based version of the <algorithm> `std::reverse()` function to
 // reverse a container's elements and write them to an iterator range.
 template <typename C, typename OutputIterator>
-OutputIterator c_reverse_copy(const C& sequence, OutputIterator result) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator
+c_reverse_copy(const C& sequence, OutputIterator result) {
   return std::reverse_copy(container_algorithm_internal::c_begin(sequence),
                            container_algorithm_internal::c_end(sequence),
                            result);
@@ -805,7 +817,8 @@
 // the first element in the container.
 template <typename C,
           typename Iterator = container_algorithm_internal::ContainerIter<C>>
-Iterator c_rotate(C& sequence, Iterator middle) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 Iterator c_rotate(C& sequence,
+                                                      Iterator middle) {
   return absl::rotate(container_algorithm_internal::c_begin(sequence), middle,
                       container_algorithm_internal::c_end(sequence));
 }
@@ -816,10 +829,10 @@
 // shift a container's elements leftward such that the `middle` element becomes
 // the first element in a new iterator range.
 template <typename C, typename OutputIterator>
-OutputIterator c_rotate_copy(
-    const C& sequence,
-    container_algorithm_internal::ContainerIter<const C> middle,
-    OutputIterator result) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator
+c_rotate_copy(const C& sequence,
+              container_algorithm_internal::ContainerIter<const C> middle,
+              OutputIterator result) {
   return std::rotate_copy(container_algorithm_internal::c_begin(sequence),
                           middle, container_algorithm_internal::c_end(sequence),
                           result);
@@ -861,7 +874,8 @@
 // to test whether all elements in the container for which `pred` returns `true`
 // precede those for which `pred` is `false`.
 template <typename C, typename Pred>
-bool c_is_partitioned(const C& c, Pred&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_is_partitioned(const C& c,
+                                                          Pred&& pred) {
   return std::is_partitioned(container_algorithm_internal::c_begin(c),
                              container_algorithm_internal::c_end(c),
                              std::forward<Pred>(pred));
@@ -874,7 +888,9 @@
 // which `pred` returns `true` precede all those for which it returns `false`,
 // returning an iterator to the first element of the second group.
 template <typename C, typename Pred>
-container_algorithm_internal::ContainerIter<C> c_partition(C& c, Pred&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+    container_algorithm_internal::ContainerIter<C>
+    c_partition(C& c, Pred&& pred) {
   return std::partition(container_algorithm_internal::c_begin(c),
                         container_algorithm_internal::c_end(c),
                         std::forward<Pred>(pred));
@@ -903,9 +919,9 @@
 
 template <typename C, typename OutputIterator1, typename OutputIterator2,
           typename Pred>
-std::pair<OutputIterator1, OutputIterator2> c_partition_copy(
-    const C& c, OutputIterator1 out_true, OutputIterator2 out_false,
-    Pred&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 std::pair<OutputIterator1, OutputIterator2>
+c_partition_copy(const C& c, OutputIterator1 out_true,
+                 OutputIterator2 out_false, Pred&& pred) {
   return std::partition_copy(container_algorithm_internal::c_begin(c),
                              container_algorithm_internal::c_end(c), out_true,
                              out_false, std::forward<Pred>(pred));
@@ -917,8 +933,9 @@
 // to return the first element of an already partitioned container for which
 // the given `pred` is not `true`.
 template <typename C, typename Pred>
-container_algorithm_internal::ContainerIter<C> c_partition_point(C& c,
-                                                                 Pred&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+    container_algorithm_internal::ContainerIter<C>
+    c_partition_point(C& c, Pred&& pred) {
   return std::partition_point(container_algorithm_internal::c_begin(c),
                               container_algorithm_internal::c_end(c),
                               std::forward<Pred>(pred));
@@ -933,7 +950,7 @@
 // Container-based version of the <algorithm> `std::sort()` function
 // to sort elements in ascending order of their values.
 template <typename C>
-void c_sort(C& c) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_sort(C& c) {
   std::sort(container_algorithm_internal::c_begin(c),
             container_algorithm_internal::c_end(c));
 }
@@ -941,7 +958,7 @@
 // Overload of c_sort() for performing a `comp` comparison other than the
 // default `operator<`.
 template <typename C, typename LessThan>
-void c_sort(C& c, LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_sort(C& c, LessThan&& comp) {
   std::sort(container_algorithm_internal::c_begin(c),
             container_algorithm_internal::c_end(c),
             std::forward<LessThan>(comp));
@@ -972,7 +989,7 @@
 // Container-based version of the <algorithm> `std::is_sorted()` function
 // to evaluate whether the given container is sorted in ascending order.
 template <typename C>
-bool c_is_sorted(const C& c) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_is_sorted(const C& c) {
   return std::is_sorted(container_algorithm_internal::c_begin(c),
                         container_algorithm_internal::c_end(c));
 }
@@ -980,7 +997,8 @@
 // c_is_sorted() overload for performing a `comp` comparison other than the
 // default `operator<`.
 template <typename C, typename LessThan>
-bool c_is_sorted(const C& c, LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_is_sorted(const C& c,
+                                                     LessThan&& comp) {
   return std::is_sorted(container_algorithm_internal::c_begin(c),
                         container_algorithm_internal::c_end(c),
                         std::forward<LessThan>(comp));
@@ -992,7 +1010,7 @@
 // to rearrange elements within a container such that elements before `middle`
 // are sorted in ascending order.
 template <typename RandomAccessContainer>
-void c_partial_sort(
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_partial_sort(
     RandomAccessContainer& sequence,
     container_algorithm_internal::ContainerIter<RandomAccessContainer> middle) {
   std::partial_sort(container_algorithm_internal::c_begin(sequence), middle,
@@ -1002,7 +1020,7 @@
 // Overload of c_partial_sort() for performing a `comp` comparison other than
 // the default `operator<`.
 template <typename RandomAccessContainer, typename LessThan>
-void c_partial_sort(
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_partial_sort(
     RandomAccessContainer& sequence,
     container_algorithm_internal::ContainerIter<RandomAccessContainer> middle,
     LessThan&& comp) {
@@ -1019,8 +1037,9 @@
 // At most min(result.last - result.first, sequence.last - sequence.first)
 // elements from the sequence will be stored in the result.
 template <typename C, typename RandomAccessContainer>
-container_algorithm_internal::ContainerIter<RandomAccessContainer>
-c_partial_sort_copy(const C& sequence, RandomAccessContainer& result) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+    container_algorithm_internal::ContainerIter<RandomAccessContainer>
+    c_partial_sort_copy(const C& sequence, RandomAccessContainer& result) {
   return std::partial_sort_copy(container_algorithm_internal::c_begin(sequence),
                                 container_algorithm_internal::c_end(sequence),
                                 container_algorithm_internal::c_begin(result),
@@ -1030,9 +1049,10 @@
 // Overload of c_partial_sort_copy() for performing a `comp` comparison other
 // than the default `operator<`.
 template <typename C, typename RandomAccessContainer, typename LessThan>
-container_algorithm_internal::ContainerIter<RandomAccessContainer>
-c_partial_sort_copy(const C& sequence, RandomAccessContainer& result,
-                    LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+    container_algorithm_internal::ContainerIter<RandomAccessContainer>
+    c_partial_sort_copy(const C& sequence, RandomAccessContainer& result,
+                        LessThan&& comp) {
   return std::partial_sort_copy(container_algorithm_internal::c_begin(sequence),
                                 container_algorithm_internal::c_end(sequence),
                                 container_algorithm_internal::c_begin(result),
@@ -1046,7 +1066,9 @@
 // to return the first element within a container that is not sorted in
 // ascending order as an iterator.
 template <typename C>
-container_algorithm_internal::ContainerIter<C> c_is_sorted_until(C& c) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+    container_algorithm_internal::ContainerIter<C>
+    c_is_sorted_until(C& c) {
   return std::is_sorted_until(container_algorithm_internal::c_begin(c),
                               container_algorithm_internal::c_end(c));
 }
@@ -1054,8 +1076,9 @@
 // Overload of c_is_sorted_until() for performing a `comp` comparison other than
 // the default `operator<`.
 template <typename C, typename LessThan>
-container_algorithm_internal::ContainerIter<C> c_is_sorted_until(
-    C& c, LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+    container_algorithm_internal::ContainerIter<C>
+    c_is_sorted_until(C& c, LessThan&& comp) {
   return std::is_sorted_until(container_algorithm_internal::c_begin(c),
                               container_algorithm_internal::c_end(c),
                               std::forward<LessThan>(comp));
@@ -1069,7 +1092,7 @@
 // any order, except that all preceding `nth` will be less than that element,
 // and all following `nth` will be greater than that element.
 template <typename RandomAccessContainer>
-void c_nth_element(
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_nth_element(
     RandomAccessContainer& sequence,
     container_algorithm_internal::ContainerIter<RandomAccessContainer> nth) {
   std::nth_element(container_algorithm_internal::c_begin(sequence), nth,
@@ -1079,7 +1102,7 @@
 // Overload of c_nth_element() for performing a `comp` comparison other than
 // the default `operator<`.
 template <typename RandomAccessContainer, typename LessThan>
-void c_nth_element(
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_nth_element(
     RandomAccessContainer& sequence,
     container_algorithm_internal::ContainerIter<RandomAccessContainer> nth,
     LessThan&& comp) {
@@ -1098,8 +1121,9 @@
 // to return an iterator pointing to the first element in a sorted container
 // which does not compare less than `value`.
 template <typename Sequence, typename T>
-container_algorithm_internal::ContainerIter<Sequence> c_lower_bound(
-    Sequence& sequence, const T& value) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+    container_algorithm_internal::ContainerIter<Sequence>
+    c_lower_bound(Sequence& sequence, const T& value) {
   return std::lower_bound(container_algorithm_internal::c_begin(sequence),
                           container_algorithm_internal::c_end(sequence), value);
 }
@@ -1107,8 +1131,9 @@
 // Overload of c_lower_bound() for performing a `comp` comparison other than
 // the default `operator<`.
 template <typename Sequence, typename T, typename LessThan>
-container_algorithm_internal::ContainerIter<Sequence> c_lower_bound(
-    Sequence& sequence, const T& value, LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+    container_algorithm_internal::ContainerIter<Sequence>
+    c_lower_bound(Sequence& sequence, const T& value, LessThan&& comp) {
   return std::lower_bound(container_algorithm_internal::c_begin(sequence),
                           container_algorithm_internal::c_end(sequence), value,
                           std::forward<LessThan>(comp));
@@ -1120,8 +1145,9 @@
 // to return an iterator pointing to the first element in a sorted container
 // which is greater than `value`.
 template <typename Sequence, typename T>
-container_algorithm_internal::ContainerIter<Sequence> c_upper_bound(
-    Sequence& sequence, const T& value) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+    container_algorithm_internal::ContainerIter<Sequence>
+    c_upper_bound(Sequence& sequence, const T& value) {
   return std::upper_bound(container_algorithm_internal::c_begin(sequence),
                           container_algorithm_internal::c_end(sequence), value);
 }
@@ -1129,8 +1155,9 @@
 // Overload of c_upper_bound() for performing a `comp` comparison other than
 // the default `operator<`.
 template <typename Sequence, typename T, typename LessThan>
-container_algorithm_internal::ContainerIter<Sequence> c_upper_bound(
-    Sequence& sequence, const T& value, LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+    container_algorithm_internal::ContainerIter<Sequence>
+    c_upper_bound(Sequence& sequence, const T& value, LessThan&& comp) {
   return std::upper_bound(container_algorithm_internal::c_begin(sequence),
                           container_algorithm_internal::c_end(sequence), value,
                           std::forward<LessThan>(comp));
@@ -1142,8 +1169,9 @@
 // to return an iterator pair pointing to the first and last elements in a
 // sorted container which compare equal to `value`.
 template <typename Sequence, typename T>
-container_algorithm_internal::ContainerIterPairType<Sequence, Sequence>
-c_equal_range(Sequence& sequence, const T& value) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+    container_algorithm_internal::ContainerIterPairType<Sequence, Sequence>
+    c_equal_range(Sequence& sequence, const T& value) {
   return std::equal_range(container_algorithm_internal::c_begin(sequence),
                           container_algorithm_internal::c_end(sequence), value);
 }
@@ -1151,8 +1179,9 @@
 // Overload of c_equal_range() for performing a `comp` comparison other than
 // the default `operator<`.
 template <typename Sequence, typename T, typename LessThan>
-container_algorithm_internal::ContainerIterPairType<Sequence, Sequence>
-c_equal_range(Sequence& sequence, const T& value, LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+    container_algorithm_internal::ContainerIterPairType<Sequence, Sequence>
+    c_equal_range(Sequence& sequence, const T& value, LessThan&& comp) {
   return std::equal_range(container_algorithm_internal::c_begin(sequence),
                           container_algorithm_internal::c_end(sequence), value,
                           std::forward<LessThan>(comp));
@@ -1164,7 +1193,8 @@
 // to test if any element in the sorted container contains a value equivalent to
 // 'value'.
 template <typename Sequence, typename T>
-bool c_binary_search(const Sequence& sequence, const T& value) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_binary_search(
+    const Sequence& sequence, const T& value) {
   return std::binary_search(container_algorithm_internal::c_begin(sequence),
                             container_algorithm_internal::c_end(sequence),
                             value);
@@ -1173,8 +1203,8 @@
 // Overload of c_binary_search() for performing a `comp` comparison other than
 // the default `operator<`.
 template <typename Sequence, typename T, typename LessThan>
-bool c_binary_search(const Sequence& sequence, const T& value,
-                     LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_binary_search(
+    const Sequence& sequence, const T& value, LessThan&& comp) {
   return std::binary_search(container_algorithm_internal::c_begin(sequence),
                             container_algorithm_internal::c_end(sequence),
                             value, std::forward<LessThan>(comp));
@@ -1189,7 +1219,8 @@
 // Container-based version of the <algorithm> `std::merge()` function
 // to merge two sorted containers into a single sorted iterator.
 template <typename C1, typename C2, typename OutputIterator>
-OutputIterator c_merge(const C1& c1, const C2& c2, OutputIterator result) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator
+c_merge(const C1& c1, const C2& c2, OutputIterator result) {
   return std::merge(container_algorithm_internal::c_begin(c1),
                     container_algorithm_internal::c_end(c1),
                     container_algorithm_internal::c_begin(c2),
@@ -1199,8 +1230,8 @@
 // Overload of c_merge() for performing a `comp` comparison other than
 // the default `operator<`.
 template <typename C1, typename C2, typename OutputIterator, typename LessThan>
-OutputIterator c_merge(const C1& c1, const C2& c2, OutputIterator result,
-                       LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator
+c_merge(const C1& c1, const C2& c2, OutputIterator result, LessThan&& comp) {
   return std::merge(container_algorithm_internal::c_begin(c1),
                     container_algorithm_internal::c_end(c1),
                     container_algorithm_internal::c_begin(c2),
@@ -1236,7 +1267,8 @@
 // to test whether a sorted container `c1` entirely contains another sorted
 // container `c2`.
 template <typename C1, typename C2>
-bool c_includes(const C1& c1, const C2& c2) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_includes(const C1& c1,
+                                                    const C2& c2) {
   return std::includes(container_algorithm_internal::c_begin(c1),
                        container_algorithm_internal::c_end(c1),
                        container_algorithm_internal::c_begin(c2),
@@ -1246,7 +1278,8 @@
 // Overload of c_includes() for performing a merge using a `comp` other than
 // `operator<`.
 template <typename C1, typename C2, typename LessThan>
-bool c_includes(const C1& c1, const C2& c2, LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_includes(const C1& c1, const C2& c2,
+                                                    LessThan&& comp) {
   return std::includes(container_algorithm_internal::c_begin(c1),
                        container_algorithm_internal::c_end(c1),
                        container_algorithm_internal::c_begin(c2),
@@ -1266,7 +1299,8 @@
           typename = typename std::enable_if<
               !container_algorithm_internal::IsUnorderedContainer<C2>::value,
               void>::type>
-OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator
+c_set_union(const C1& c1, const C2& c2, OutputIterator output) {
   return std::set_union(container_algorithm_internal::c_begin(c1),
                         container_algorithm_internal::c_end(c1),
                         container_algorithm_internal::c_begin(c2),
@@ -1282,8 +1316,8 @@
           typename = typename std::enable_if<
               !container_algorithm_internal::IsUnorderedContainer<C2>::value,
               void>::type>
-OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output,
-                           LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator c_set_union(
+    const C1& c1, const C2& c2, OutputIterator output, LessThan&& comp) {
   return std::set_union(container_algorithm_internal::c_begin(c1),
                         container_algorithm_internal::c_end(c1),
                         container_algorithm_internal::c_begin(c2),
@@ -1302,13 +1336,13 @@
           typename = typename std::enable_if<
               !container_algorithm_internal::IsUnorderedContainer<C2>::value,
               void>::type>
-OutputIterator c_set_intersection(const C1& c1, const C2& c2,
-                                  OutputIterator output) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator
+c_set_intersection(const C1& c1, const C2& c2, OutputIterator output) {
   // In debug builds, ensure that both containers are sorted with respect to the
   // default comparator. std::set_intersection requires the containers be sorted
   // using operator<.
-  assert(absl::c_is_sorted(c1));
-  assert(absl::c_is_sorted(c2));
+  ABSL_ASSERT(absl::c_is_sorted(c1));
+  ABSL_ASSERT(absl::c_is_sorted(c2));
   return std::set_intersection(container_algorithm_internal::c_begin(c1),
                                container_algorithm_internal::c_end(c1),
                                container_algorithm_internal::c_begin(c2),
@@ -1324,13 +1358,13 @@
           typename = typename std::enable_if<
               !container_algorithm_internal::IsUnorderedContainer<C2>::value,
               void>::type>
-OutputIterator c_set_intersection(const C1& c1, const C2& c2,
-                                  OutputIterator output, LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator c_set_intersection(
+    const C1& c1, const C2& c2, OutputIterator output, LessThan&& comp) {
   // In debug builds, ensure that both containers are sorted with respect to the
   // default comparator. std::set_intersection requires the containers be sorted
   // using the same comparator.
-  assert(absl::c_is_sorted(c1, comp));
-  assert(absl::c_is_sorted(c2, comp));
+  ABSL_ASSERT(absl::c_is_sorted(c1, comp));
+  ABSL_ASSERT(absl::c_is_sorted(c2, comp));
   return std::set_intersection(container_algorithm_internal::c_begin(c1),
                                container_algorithm_internal::c_end(c1),
                                container_algorithm_internal::c_begin(c2),
@@ -1350,8 +1384,8 @@
           typename = typename std::enable_if<
               !container_algorithm_internal::IsUnorderedContainer<C2>::value,
               void>::type>
-OutputIterator c_set_difference(const C1& c1, const C2& c2,
-                                OutputIterator output) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator
+c_set_difference(const C1& c1, const C2& c2, OutputIterator output) {
   return std::set_difference(container_algorithm_internal::c_begin(c1),
                              container_algorithm_internal::c_end(c1),
                              container_algorithm_internal::c_begin(c2),
@@ -1367,8 +1401,8 @@
           typename = typename std::enable_if<
               !container_algorithm_internal::IsUnorderedContainer<C2>::value,
               void>::type>
-OutputIterator c_set_difference(const C1& c1, const C2& c2,
-                                OutputIterator output, LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator c_set_difference(
+    const C1& c1, const C2& c2, OutputIterator output, LessThan&& comp) {
   return std::set_difference(container_algorithm_internal::c_begin(c1),
                              container_algorithm_internal::c_end(c1),
                              container_algorithm_internal::c_begin(c2),
@@ -1388,8 +1422,8 @@
           typename = typename std::enable_if<
               !container_algorithm_internal::IsUnorderedContainer<C2>::value,
               void>::type>
-OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
-                                          OutputIterator output) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator
+c_set_symmetric_difference(const C1& c1, const C2& c2, OutputIterator output) {
   return std::set_symmetric_difference(
       container_algorithm_internal::c_begin(c1),
       container_algorithm_internal::c_end(c1),
@@ -1406,9 +1440,8 @@
           typename = typename std::enable_if<
               !container_algorithm_internal::IsUnorderedContainer<C2>::value,
               void>::type>
-OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
-                                          OutputIterator output,
-                                          LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIterator c_set_symmetric_difference(
+    const C1& c1, const C2& c2, OutputIterator output, LessThan&& comp) {
   return std::set_symmetric_difference(
       container_algorithm_internal::c_begin(c1),
       container_algorithm_internal::c_end(c1),
@@ -1426,7 +1459,8 @@
 // Container-based version of the <algorithm> `std::push_heap()` function
 // to push a value onto a container heap.
 template <typename RandomAccessContainer>
-void c_push_heap(RandomAccessContainer& sequence) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_push_heap(
+    RandomAccessContainer& sequence) {
   std::push_heap(container_algorithm_internal::c_begin(sequence),
                  container_algorithm_internal::c_end(sequence));
 }
@@ -1434,7 +1468,8 @@
 // Overload of c_push_heap() for performing a push operation on a heap using a
 // `comp` other than `operator<`.
 template <typename RandomAccessContainer, typename LessThan>
-void c_push_heap(RandomAccessContainer& sequence, LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_push_heap(
+    RandomAccessContainer& sequence, LessThan&& comp) {
   std::push_heap(container_algorithm_internal::c_begin(sequence),
                  container_algorithm_internal::c_end(sequence),
                  std::forward<LessThan>(comp));
@@ -1445,7 +1480,8 @@
 // Container-based version of the <algorithm> `std::pop_heap()` function
 // to pop a value from a heap container.
 template <typename RandomAccessContainer>
-void c_pop_heap(RandomAccessContainer& sequence) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_pop_heap(
+    RandomAccessContainer& sequence) {
   std::pop_heap(container_algorithm_internal::c_begin(sequence),
                 container_algorithm_internal::c_end(sequence));
 }
@@ -1453,7 +1489,8 @@
 // Overload of c_pop_heap() for performing a pop operation on a heap using a
 // `comp` other than `operator<`.
 template <typename RandomAccessContainer, typename LessThan>
-void c_pop_heap(RandomAccessContainer& sequence, LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_pop_heap(
+    RandomAccessContainer& sequence, LessThan&& comp) {
   std::pop_heap(container_algorithm_internal::c_begin(sequence),
                 container_algorithm_internal::c_end(sequence),
                 std::forward<LessThan>(comp));
@@ -1464,7 +1501,8 @@
 // Container-based version of the <algorithm> `std::make_heap()` function
 // to make a container a heap.
 template <typename RandomAccessContainer>
-void c_make_heap(RandomAccessContainer& sequence) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_make_heap(
+    RandomAccessContainer& sequence) {
   std::make_heap(container_algorithm_internal::c_begin(sequence),
                  container_algorithm_internal::c_end(sequence));
 }
@@ -1472,7 +1510,8 @@
 // Overload of c_make_heap() for performing heap comparisons using a
 // `comp` other than `operator<`
 template <typename RandomAccessContainer, typename LessThan>
-void c_make_heap(RandomAccessContainer& sequence, LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_make_heap(
+    RandomAccessContainer& sequence, LessThan&& comp) {
   std::make_heap(container_algorithm_internal::c_begin(sequence),
                  container_algorithm_internal::c_end(sequence),
                  std::forward<LessThan>(comp));
@@ -1483,7 +1522,8 @@
 // Container-based version of the <algorithm> `std::sort_heap()` function
 // to sort a heap into ascending order (after which it is no longer a heap).
 template <typename RandomAccessContainer>
-void c_sort_heap(RandomAccessContainer& sequence) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_sort_heap(
+    RandomAccessContainer& sequence) {
   std::sort_heap(container_algorithm_internal::c_begin(sequence),
                  container_algorithm_internal::c_end(sequence));
 }
@@ -1491,7 +1531,8 @@
 // Overload of c_sort_heap() for performing heap comparisons using a
 // `comp` other than `operator<`
 template <typename RandomAccessContainer, typename LessThan>
-void c_sort_heap(RandomAccessContainer& sequence, LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_sort_heap(
+    RandomAccessContainer& sequence, LessThan&& comp) {
   std::sort_heap(container_algorithm_internal::c_begin(sequence),
                  container_algorithm_internal::c_end(sequence),
                  std::forward<LessThan>(comp));
@@ -1502,7 +1543,8 @@
 // Container-based version of the <algorithm> `std::is_heap()` function
 // to check whether the given container is a heap.
 template <typename RandomAccessContainer>
-bool c_is_heap(const RandomAccessContainer& sequence) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_is_heap(
+    const RandomAccessContainer& sequence) {
   return std::is_heap(container_algorithm_internal::c_begin(sequence),
                       container_algorithm_internal::c_end(sequence));
 }
@@ -1510,7 +1552,8 @@
 // Overload of c_is_heap() for performing heap comparisons using a
 // `comp` other than `operator<`
 template <typename RandomAccessContainer, typename LessThan>
-bool c_is_heap(const RandomAccessContainer& sequence, LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_is_heap(
+    const RandomAccessContainer& sequence, LessThan&& comp) {
   return std::is_heap(container_algorithm_internal::c_begin(sequence),
                       container_algorithm_internal::c_end(sequence),
                       std::forward<LessThan>(comp));
@@ -1521,8 +1564,9 @@
 // Container-based version of the <algorithm> `std::is_heap_until()` function
 // to find the first element in a given container which is not in heap order.
 template <typename RandomAccessContainer>
-container_algorithm_internal::ContainerIter<RandomAccessContainer>
-c_is_heap_until(RandomAccessContainer& sequence) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+    container_algorithm_internal::ContainerIter<RandomAccessContainer>
+    c_is_heap_until(RandomAccessContainer& sequence) {
   return std::is_heap_until(container_algorithm_internal::c_begin(sequence),
                             container_algorithm_internal::c_end(sequence));
 }
@@ -1530,8 +1574,9 @@
 // Overload of c_is_heap_until() for performing heap comparisons using a
 // `comp` other than `operator<`
 template <typename RandomAccessContainer, typename LessThan>
-container_algorithm_internal::ContainerIter<RandomAccessContainer>
-c_is_heap_until(RandomAccessContainer& sequence, LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+    container_algorithm_internal::ContainerIter<RandomAccessContainer>
+    c_is_heap_until(RandomAccessContainer& sequence, LessThan&& comp) {
   return std::is_heap_until(container_algorithm_internal::c_begin(sequence),
                             container_algorithm_internal::c_end(sequence),
                             std::forward<LessThan>(comp));
@@ -1626,8 +1671,8 @@
 // that capital letters ("A-Z") have ASCII values less than lowercase letters
 // ("a-z").
 template <typename Sequence1, typename Sequence2>
-bool c_lexicographical_compare(const Sequence1& sequence1,
-                               const Sequence2& sequence2) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_lexicographical_compare(
+    const Sequence1& sequence1, const Sequence2& sequence2) {
   return std::lexicographical_compare(
       container_algorithm_internal::c_begin(sequence1),
       container_algorithm_internal::c_end(sequence1),
@@ -1638,8 +1683,8 @@
 // Overload of c_lexicographical_compare() for performing a lexicographical
 // comparison using a `comp` operator instead of `operator<`.
 template <typename Sequence1, typename Sequence2, typename LessThan>
-bool c_lexicographical_compare(const Sequence1& sequence1,
-                               const Sequence2& sequence2, LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_lexicographical_compare(
+    const Sequence1& sequence1, const Sequence2& sequence2, LessThan&& comp) {
   return std::lexicographical_compare(
       container_algorithm_internal::c_begin(sequence1),
       container_algorithm_internal::c_end(sequence1),
@@ -1654,7 +1699,7 @@
 // to rearrange a container's elements into the next lexicographically greater
 // permutation.
 template <typename C>
-bool c_next_permutation(C& c) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_next_permutation(C& c) {
   return std::next_permutation(container_algorithm_internal::c_begin(c),
                                container_algorithm_internal::c_end(c));
 }
@@ -1662,7 +1707,8 @@
 // Overload of c_next_permutation() for performing a lexicographical
 // comparison using a `comp` operator instead of `operator<`.
 template <typename C, typename LessThan>
-bool c_next_permutation(C& c, LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_next_permutation(C& c,
+                                                            LessThan&& comp) {
   return std::next_permutation(container_algorithm_internal::c_begin(c),
                                container_algorithm_internal::c_end(c),
                                std::forward<LessThan>(comp));
@@ -1674,7 +1720,7 @@
 // to rearrange a container's elements into the next lexicographically lesser
 // permutation.
 template <typename C>
-bool c_prev_permutation(C& c) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_prev_permutation(C& c) {
   return std::prev_permutation(container_algorithm_internal::c_begin(c),
                                container_algorithm_internal::c_end(c));
 }
@@ -1682,7 +1728,8 @@
 // Overload of c_prev_permutation() for performing a lexicographical
 // comparison using a `comp` operator instead of `operator<`.
 template <typename C, typename LessThan>
-bool c_prev_permutation(C& c, LessThan&& comp) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_prev_permutation(C& c,
+                                                            LessThan&& comp) {
   return std::prev_permutation(container_algorithm_internal::c_begin(c),
                                container_algorithm_internal::c_end(c),
                                std::forward<LessThan>(comp));
@@ -1698,7 +1745,8 @@
 // to compute successive values of `value`, as if incremented with `++value`
 // after each element is written, and write them to the container.
 template <typename Sequence, typename T>
-void c_iota(Sequence& sequence, const T& value) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 void c_iota(Sequence& sequence,
+                                                const T& value) {
   std::iota(container_algorithm_internal::c_begin(sequence),
             container_algorithm_internal::c_end(sequence), value);
 }
@@ -1713,7 +1761,8 @@
 // absl::decay_t<T>. As a user of this function you can casually read
 // this as "returns T by value" and assume it does the right thing.
 template <typename Sequence, typename T>
-decay_t<T> c_accumulate(const Sequence& sequence, T&& init) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 decay_t<T> c_accumulate(
+    const Sequence& sequence, T&& init) {
   return std::accumulate(container_algorithm_internal::c_begin(sequence),
                          container_algorithm_internal::c_end(sequence),
                          std::forward<T>(init));
@@ -1722,8 +1771,8 @@
 // Overload of c_accumulate() for using a binary operations other than
 // addition for computing the accumulation.
 template <typename Sequence, typename T, typename BinaryOp>
-decay_t<T> c_accumulate(const Sequence& sequence, T&& init,
-                        BinaryOp&& binary_op) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 decay_t<T> c_accumulate(
+    const Sequence& sequence, T&& init, BinaryOp&& binary_op) {
   return std::accumulate(container_algorithm_internal::c_begin(sequence),
                          container_algorithm_internal::c_end(sequence),
                          std::forward<T>(init),
@@ -1739,8 +1788,8 @@
 // absl::decay_t<T>. As a user of this function you can casually read
 // this as "returns T by value" and assume it does the right thing.
 template <typename Sequence1, typename Sequence2, typename T>
-decay_t<T> c_inner_product(const Sequence1& factors1, const Sequence2& factors2,
-                           T&& sum) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 decay_t<T> c_inner_product(
+    const Sequence1& factors1, const Sequence2& factors2, T&& sum) {
   return std::inner_product(container_algorithm_internal::c_begin(factors1),
                             container_algorithm_internal::c_end(factors1),
                             container_algorithm_internal::c_begin(factors2),
@@ -1752,8 +1801,9 @@
 // the product between the two container's element pair).
 template <typename Sequence1, typename Sequence2, typename T,
           typename BinaryOp1, typename BinaryOp2>
-decay_t<T> c_inner_product(const Sequence1& factors1, const Sequence2& factors2,
-                           T&& sum, BinaryOp1&& op1, BinaryOp2&& op2) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 decay_t<T> c_inner_product(
+    const Sequence1& factors1, const Sequence2& factors2, T&& sum,
+    BinaryOp1&& op1, BinaryOp2&& op2) {
   return std::inner_product(container_algorithm_internal::c_begin(factors1),
                             container_algorithm_internal::c_end(factors1),
                             container_algorithm_internal::c_begin(factors2),
@@ -1767,8 +1817,8 @@
 // function to compute the difference between each element and the one preceding
 // it and write it to an iterator.
 template <typename InputSequence, typename OutputIt>
-OutputIt c_adjacent_difference(const InputSequence& input,
-                               OutputIt output_first) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIt
+c_adjacent_difference(const InputSequence& input, OutputIt output_first) {
   return std::adjacent_difference(container_algorithm_internal::c_begin(input),
                                   container_algorithm_internal::c_end(input),
                                   output_first);
@@ -1777,8 +1827,8 @@
 // Overload of c_adjacent_difference() for using a binary operation other than
 // subtraction to compute the adjacent difference.
 template <typename InputSequence, typename OutputIt, typename BinaryOp>
-OutputIt c_adjacent_difference(const InputSequence& input,
-                               OutputIt output_first, BinaryOp&& op) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIt c_adjacent_difference(
+    const InputSequence& input, OutputIt output_first, BinaryOp&& op) {
   return std::adjacent_difference(container_algorithm_internal::c_begin(input),
                                   container_algorithm_internal::c_end(input),
                                   output_first, std::forward<BinaryOp>(op));
@@ -1791,7 +1841,8 @@
 // to an iterator. The partial sum is the sum of all element values so far in
 // the sequence.
 template <typename InputSequence, typename OutputIt>
-OutputIt c_partial_sum(const InputSequence& input, OutputIt output_first) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIt
+c_partial_sum(const InputSequence& input, OutputIt output_first) {
   return std::partial_sum(container_algorithm_internal::c_begin(input),
                           container_algorithm_internal::c_end(input),
                           output_first);
@@ -1800,8 +1851,8 @@
 // Overload of c_partial_sum() for using a binary operation other than addition
 // to compute the "partial sum".
 template <typename InputSequence, typename OutputIt, typename BinaryOp>
-OutputIt c_partial_sum(const InputSequence& input, OutputIt output_first,
-                       BinaryOp&& op) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 OutputIt c_partial_sum(
+    const InputSequence& input, OutputIt output_first, BinaryOp&& op) {
   return std::partial_sum(container_algorithm_internal::c_begin(input),
                           container_algorithm_internal::c_end(input),
                           output_first, std::forward<BinaryOp>(op));
diff --git a/absl/algorithm/container_test.cc b/absl/algorithm/container_test.cc
index cb06335..347b41f 100644
--- a/absl/algorithm/container_test.cc
+++ b/absl/algorithm/container_test.cc
@@ -1408,6 +1408,824 @@
                 kArray.begin());
 }
 
+TEST(ConstexprTest, Copy) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArrayCopy = [] {
+    std::array<int, 3> array;
+    absl::c_copy(kArray, array.begin());
+    return array;
+  }();
+  static_assert(kArrayCopy == kArray);
+}
+
+TEST(ConstexprTest, CopyN) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArrayCopy = [] {
+    std::array<int, 2> array;
+    absl::c_copy_n(kArray, 2, array.begin());
+    return array;
+  }();
+  static_assert(kArrayCopy == std::array{1, 2});
+}
+
+TEST(ConstexprTest, CopyIf) {
+  static constexpr std::array kArray = {1, 2, 3, 4};
+  static constexpr auto kArrayCopy = [] {
+    std::array<int, 3> array;
+    absl::c_copy_if(kArray, array.begin(), [](int x) { return x > 1; });
+    return array;
+  }();
+  static_assert(kArrayCopy == std::array{2, 3, 4});
+}
+
+TEST(ConstexprTest, CopyBackward) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArrayCopy = [] {
+    std::array<int, 3> array;
+    absl::c_copy_backward(kArray, array.end());
+    return array;
+  }();
+  static_assert(kArrayCopy == kArray);
+}
+
+TEST(ConstexprTest, Move) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArrayMove = [] {
+    std::array<int, 3> array;
+    absl::c_move(kArray, array.begin());
+    return array;
+  }();
+  static_assert(kArrayMove == kArray);
+}
+
+TEST(ConstexprTest, MoveBackward) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArrayMove = [] {
+    std::array<int, 3> array;
+    absl::c_move_backward(kArray, array.end());
+    return array;
+  }();
+  static_assert(kArrayMove == kArray);
+}
+
+TEST(ConstexprTest, SwapRanges) {
+  static constexpr std::array kArray1 = {1, 2, 3};
+  static constexpr std::array kArray2 = {4, 5, 6};
+
+  static constexpr auto kSwapped = [] {
+    std::array arr1 = kArray1;
+    std::array arr2 = kArray2;
+    absl::c_swap_ranges(arr1, arr2);
+    return std::make_pair(arr1, arr2);
+  }();
+
+  static_assert(kSwapped.first == kArray2);
+  static_assert(kSwapped.second == kArray1);
+}
+
+TEST(ConstexprTest, Transform) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArrayTransform = [] {
+    std::array<int, 3> array;
+    absl::c_transform(kArray, array.begin(), [](int x) { return x + 1; });
+    return array;
+  }();
+  static_assert(kArrayTransform == std::array{2, 3, 4});
+}
+
+TEST(ConstexprTest, Replace) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArrayReplace = [] {
+    std::array array = kArray;
+    absl::c_replace(array, 1, 4);
+    return array;
+  }();
+  static_assert(kArrayReplace == std::array{4, 2, 3});
+}
+
+TEST(ConstexprTest, ReplaceIf) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArrayReplaceIf = [] {
+    std::array array = kArray;
+    absl::c_replace_if(array, [](int x) { return x == 1; }, 4);
+    return array;
+  }();
+  static_assert(kArrayReplaceIf == std::array{4, 2, 3});
+}
+
+TEST(ConstexprTest, ReplaceCopy) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArrayReplaceCopy = [] {
+    std::array<int, 3> array;
+    absl::c_replace_copy(kArray, array.begin(), 1, 4);
+    return array;
+  }();
+  static_assert(kArrayReplaceCopy == std::array{4, 2, 3});
+}
+
+TEST(ConstexprTest, ReplaceCopyIf) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArrayReplaceCopyIf = [] {
+    std::array<int, 3> array;
+    absl::c_replace_copy_if(
+        kArray, array.begin(), [](int x) { return x == 1; }, 4);
+    return array;
+  }();
+  static_assert(kArrayReplaceCopyIf == std::array{4, 2, 3});
+}
+
+TEST(ConstexprTest, Fill) {
+  static constexpr auto kArrayFill = [] {
+    std::array<int, 3> array;
+    absl::c_fill(array, 4);
+    return array;
+  }();
+  static_assert(kArrayFill == std::array{4, 4, 4});
+}
+
+TEST(ConstexprTest, FillN) {
+  static constexpr auto kArrayFillN = [] {
+    std::array array = {0, 0, 0};
+    absl::c_fill_n(array, 2, 4);
+    return array;
+  }();
+  static_assert(kArrayFillN == std::array{4, 4, 0});
+}
+
+TEST(ConstexprTest, Generate) {
+  static constexpr auto kArrayGenerate = [] {
+    std::array<int, 3> array;
+    absl::c_generate(array, []() { return 4; });
+    return array;
+  }();
+  static_assert(kArrayGenerate == std::array{4, 4, 4});
+}
+
+TEST(ConstexprTest, GenerateN) {
+  static constexpr auto kArrayGenerateN = [] {
+    std::array array = {0, 0, 0};
+    absl::c_generate_n(array, 2, []() { return 4; });
+    return array;
+  }();
+  static_assert(kArrayGenerateN == std::array{4, 4, 0});
+}
+
+TEST(ConstexprTest, RemoveCopy) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArrayRemoveCopy = [] {
+    std::array<int, 2> array;
+    absl::c_remove_copy(kArray, array.begin(), 1);
+    return array;
+  }();
+  static_assert(kArrayRemoveCopy == std::array{2, 3});
+}
+
+TEST(ConstexprTest, RemoveCopyIf) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArrayRemoveCopyIf = [] {
+    std::array<int, 2> array;
+    absl::c_remove_copy_if(kArray, array.begin(), [](int x) { return x == 1; });
+    return array;
+  }();
+  static_assert(kArrayRemoveCopyIf == std::array{2, 3});
+}
+
+TEST(ConstexprTest, UniqueCopy) {
+  static constexpr std::array kArray = {1, 2, 2, 3};
+  static constexpr auto kArrayUniqueCopy = [] {
+    std::array<int, 3> array;
+    absl::c_unique_copy(kArray, array.begin());
+    return array;
+  }();
+  static_assert(kArrayUniqueCopy == std::array{1, 2, 3});
+}
+
+TEST(ConstexprTest, UniqueCopyWithPredicate) {
+  static constexpr std::array kArray = {1, 2, 2, 3};
+  static constexpr auto kArrayUniqueCopy = [] {
+    std::array<int, 3> array;
+    absl::c_unique_copy(kArray, array.begin(), std::equal_to<>());
+    return array;
+  }();
+  static_assert(kArrayUniqueCopy == std::array{1, 2, 3});
+}
+
+TEST(ConstexprTest, Reverse) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArrayReverse = [] {
+    std::array array = kArray;
+    absl::c_reverse(array);
+    return array;
+  }();
+  static_assert(kArrayReverse == std::array{3, 2, 1});
+}
+
+TEST(ConstexprTest, ReverseCopy) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArrayReverseCopy = [] {
+    std::array<int, 3> array;
+    absl::c_reverse_copy(kArray, array.begin());
+    return array;
+  }();
+  static_assert(kArrayReverseCopy == std::array{3, 2, 1});
+}
+
+TEST(ConstexprTest, Rotate) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArrayRotate = [] {
+    std::array array = kArray;
+    absl::c_rotate(array, array.begin() + 1);
+    return array;
+  }();
+  static_assert(kArrayRotate == std::array{2, 3, 1});
+}
+
+TEST(ConstexprTest, RotateCopy) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArrayRotateCopy = [] {
+    std::array<int, 3> array;
+    absl::c_rotate_copy(kArray, kArray.begin() + 1, array.begin());
+    return array;
+  }();
+  static_assert(kArrayRotateCopy == std::array{2, 3, 1});
+}
+
+TEST(ConstexprTest, IsPartitioned) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static_assert(!absl::c_is_partitioned(kArray, [](int x) { return x > 1; }));
+
+  static constexpr std::array kPartitionedArray = {2, 3, 1};
+  static_assert(
+      absl::c_is_partitioned(kPartitionedArray, [](int x) { return x > 1; }));
+}
+
+TEST(ConstexprTest, Partition) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArrayPartition = [] {
+    std::array array = kArray;
+    absl::c_partition(array, [](int x) { return x > 1; });
+    return array;
+  }();
+  static_assert(
+      absl::c_is_partitioned(kArrayPartition, [](int x) { return x > 1; }));
+}
+
+TEST(ConstexprTest, PartitionCopy) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kPartitioned = [] {
+    std::array<int, 2> true_part;
+    std::array<int, 1> false_part;
+    absl::c_partition_copy(kArray, true_part.begin(), false_part.begin(),
+                           [](int x) { return x > 1; });
+    return std::make_pair(true_part, false_part);
+  }();
+  static_assert(kPartitioned.first == std::array{2, 3});
+  static_assert(kPartitioned.second == std::array{1});
+}
+
+TEST(ConstexprTest, PartitionPoint) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kPartitionPoint =
+      absl::c_partition_point(kArray, [](int x) { return x > 1; });
+  static_assert(kPartitionPoint == kArray.end());
+}
+
+TEST(ConstexprTest, Sort) {
+  static constexpr std::array kArray = {2, 1, 3};
+  static constexpr auto kArraySort = [] {
+    std::array array = kArray;
+    absl::c_sort(array);
+    return array;
+  }();
+  static_assert(kArraySort == std::array{1, 2, 3});
+}
+
+TEST(ConstexprTest, SortWithPredicate) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArraySort = [] {
+    std::array array = kArray;
+    absl::c_sort(array, std::greater<>());
+    return array;
+  }();
+  static_assert(kArraySort == std::array{3, 2, 1});
+}
+
+TEST(ConstexprTest, IsSorted) {
+  static constexpr std::array kSortedArray = {1, 2, 3};
+  static_assert(absl::c_is_sorted(kSortedArray));
+  static constexpr std::array kUnsortedArray = {1, 3, 2};
+  static_assert(!absl::c_is_sorted(kUnsortedArray));
+}
+
+TEST(ConstexprTest, IsSortedWithPredicate) {
+  static constexpr std::array kSortedArray = {3, 2, 1};
+  static_assert(absl::c_is_sorted(kSortedArray, std::greater<>()));
+  static constexpr std::array kUnsortedArray = {1, 3, 2};
+  static_assert(!absl::c_is_sorted(kUnsortedArray, std::greater<>()));
+}
+
+TEST(ConstexprTest, PartialSort) {
+  static constexpr std::array kArray = {3, 1, 4, 2};
+  static constexpr auto kArrayPartialSort = [] {
+    std::array array = kArray;
+    absl::c_partial_sort(array, array.begin() + 2);
+    return array;
+  }();
+  static_assert(kArrayPartialSort[0] == 1);
+  static_assert(kArrayPartialSort[1] == 2);
+}
+
+TEST(ConstexprTest, PartialSortWithPredicate) {
+  static constexpr std::array kArray = {3, 1, 4, 2};
+  static constexpr auto kArrayPartialSort = [] {
+    std::array array = kArray;
+    absl::c_partial_sort(array, array.begin() + 2, std::greater<>());
+    return array;
+  }();
+  static_assert(kArrayPartialSort[0] == 4);
+  static_assert(kArrayPartialSort[1] == 3);
+}
+
+TEST(ConstexprTest, PartialSortCopy) {
+  static constexpr std::array kArray = {3, 1, 4, 2};
+  static constexpr auto kArrayPartialSort = [] {
+    std::array<int, 4> array;
+    absl::c_partial_sort_copy(kArray, array);
+    return array;
+  }();
+  static_assert(kArrayPartialSort[0] == 1);
+  static_assert(kArrayPartialSort[1] == 2);
+}
+
+TEST(ConstexprTest, PartialSortCopyWithPredicate) {
+  static constexpr std::array kArray = {3, 1, 4, 2};
+  static constexpr auto kArrayPartialSort = [] {
+    std::array<int, 4> array;
+    absl::c_partial_sort_copy(kArray, array, std::greater<>());
+    return array;
+  }();
+  static_assert(kArrayPartialSort[0] == 4);
+  static_assert(kArrayPartialSort[1] == 3);
+}
+
+TEST(ConstexprTest, IsSortedUntil) {
+  static constexpr std::array kSortedArray = {1, 2, 3};
+  static_assert(absl::c_is_sorted_until(kSortedArray) == kSortedArray.end());
+  static constexpr std::array kUnsortedArray = {1, 3, 2};
+  static_assert(absl::c_is_sorted_until(kUnsortedArray) ==
+                kUnsortedArray.begin() + 2);
+}
+
+TEST(ConstexprTest, IsSortedUntilWithPredicate) {
+  static constexpr std::array kSortedArray = {3, 2, 1};
+  static_assert(absl::c_is_sorted_until(kSortedArray, std::greater<>()) ==
+                kSortedArray.end());
+  static constexpr std::array kUnsortedArray = {1, 3, 2};
+  static_assert(absl::c_is_sorted_until(kUnsortedArray, std::greater<>()) ==
+                kUnsortedArray.begin() + 1);
+}
+
+TEST(ConstexprTest, NthElement) {
+  static constexpr std::array kArray = {2, 1, 3, 4};
+  static constexpr auto kArrayNthElement = [] {
+    std::array array = kArray;
+    absl::c_nth_element(array, array.begin() + 2);
+    return array;
+  }();
+  static_assert(kArrayNthElement[2] == 3);
+  static_assert(kArrayNthElement[0] <= kArrayNthElement[2]);
+  static_assert(kArrayNthElement[1] <= kArrayNthElement[2]);
+  static_assert(kArrayNthElement[3] >= kArrayNthElement[2]);
+}
+
+TEST(ConstexprTest, NthElementWithPredicate) {
+  static constexpr std::array kArray = {1, 2, 3, 4};
+  static constexpr auto kArrayNthElement = [] {
+    std::array array = kArray;
+    absl::c_nth_element(array, array.begin() + 2, std::greater<>());
+    return array;
+  }();
+  static_assert(kArrayNthElement[2] == 2);
+  static_assert(std::greater<>()(kArrayNthElement[0], kArrayNthElement[2]) ||
+                kArrayNthElement[0] == kArrayNthElement[2]);
+  static_assert(std::greater<>()(kArrayNthElement[1], kArrayNthElement[2]) ||
+                kArrayNthElement[1] == kArrayNthElement[2]);
+  static_assert(std::greater<>()(kArrayNthElement[2], kArrayNthElement[3]) ||
+                kArrayNthElement[2] == kArrayNthElement[3]);
+}
+
+TEST(ConstexprTest, LowerBound) {
+  static constexpr std::array kArray = {1, 2, 3, 4};
+  static constexpr auto kLowerBound = absl::c_lower_bound(kArray, 2);
+  static_assert(kLowerBound == kArray.begin() + 1);
+}
+
+TEST(ConstexprTest, LowerBoundWithPredicate) {
+  static constexpr std::array kArray = {4, 3, 2, 1};
+  static constexpr auto kLowerBound =
+      absl::c_lower_bound(kArray, 2, std::greater<>());
+  static_assert(kLowerBound == kArray.begin() + 2);
+}
+
+TEST(ConstexprTest, UpperBound) {
+  static constexpr std::array kArray = {1, 2, 3, 4};
+  static constexpr auto kUpperBound = absl::c_upper_bound(kArray, 2);
+  static_assert(kUpperBound == kArray.begin() + 2);
+}
+
+TEST(ConstexprTest, UpperBoundWithPredicate) {
+  static constexpr std::array kArray = {4, 3, 2, 1};
+  static constexpr auto kUpperBound =
+      absl::c_upper_bound(kArray, 2, std::greater<>());
+  static_assert(kUpperBound == kArray.begin() + 3);
+}
+
+TEST(ConstexprTest, EqualRange) {
+  static constexpr std::array kArray = {1, 2, 3, 4};
+  static constexpr auto kEqualRange = absl::c_equal_range(kArray, 2);
+  static_assert(kEqualRange.first == kArray.begin() + 1);
+  static_assert(kEqualRange.second == kArray.begin() + 2);
+}
+
+TEST(ConstexprTest, EqualRangeWithPredicate) {
+  static constexpr std::array kArray = {4, 3, 2, 1};
+  static constexpr auto kEqualRange =
+      absl::c_equal_range(kArray, 2, std::greater<>());
+  static_assert(kEqualRange.first == kArray.begin() + 2);
+  static_assert(kEqualRange.second == kArray.begin() + 3);
+}
+
+TEST(ConstexprTest, BinarySearch) {
+  static constexpr std::array kArray = {1, 2, 3, 4};
+  static constexpr bool kBinarySearch = absl::c_binary_search(kArray, 2);
+  static_assert(kBinarySearch);
+}
+
+TEST(ConstexprTest, BinarySearchWithPredicate) {
+  static constexpr std::array kArray = {4, 3, 2, 1};
+  static constexpr bool kBinarySearch =
+      absl::c_binary_search(kArray, 2, std::greater<>());
+  static_assert(kBinarySearch);
+}
+
+TEST(ConstexprTest, Merge) {
+  static constexpr std::array kArray1 = {1, 2, 3};
+  static constexpr std::array kArray2 = {4, 5, 6};
+  static constexpr auto kArrayMerge = [] {
+    std::array<int, 6> array;
+    absl::c_merge(kArray1, kArray2, array.begin());
+    return array;
+  }();
+  static_assert(kArrayMerge == std::array{1, 2, 3, 4, 5, 6});
+}
+
+TEST(ConstexprTest, MergeWithPredicate) {
+  static constexpr std::array kArray1 = {3, 2, 1};
+  static constexpr std::array kArray2 = {6, 5, 4};
+  static constexpr auto kArrayMerge = [] {
+    std::array<int, 6> array;
+    absl::c_merge(kArray1, kArray2, array.begin(), std::greater<>());
+    return array;
+  }();
+  static_assert(kArrayMerge == std::array{6, 5, 4, 3, 2, 1});
+}
+
+TEST(ConstexprTest, Includes) {
+  static constexpr std::array kArray1 = {1, 2, 3, 4, 5, 6};
+  static constexpr std::array kArray2 = {2, 3, 5};
+  static constexpr bool kIncludes = absl::c_includes(kArray1, kArray2);
+  static_assert(kIncludes);
+}
+
+TEST(ConstexprTest, IncludesWithPredicate) {
+  static constexpr std::array kArray1 = {6, 5, 4, 3, 2, 1};
+  static constexpr std::array kArray2 = {5, 3, 2};
+  static constexpr bool kIncludes =
+      absl::c_includes(kArray1, kArray2, std::greater<>());
+  static_assert(kIncludes);
+}
+
+TEST(ConstexprTest, SetUnion) {
+  static constexpr std::array kArray1 = {1, 2, 3};
+  static constexpr std::array kArray2 = {1, 3, 4};
+  static constexpr auto kArraySetUnion = [] {
+    std::array<int, 4> array;
+    absl::c_set_union(kArray1, kArray2, array.begin());
+    return array;
+  }();
+  static_assert(kArraySetUnion == std::array{1, 2, 3, 4});
+}
+
+TEST(ConstexprTest, SetUnionWithPredicate) {
+  static constexpr std::array kArray1 = {3, 2, 1};
+  static constexpr std::array kArray2 = {4, 3, 1};
+  static constexpr auto kArraySetUnion = [] {
+    std::array<int, 4> array;
+    absl::c_set_union(kArray1, kArray2, array.begin(), std::greater<>());
+    return array;
+  }();
+  static_assert(kArraySetUnion == std::array{4, 3, 2, 1});
+}
+
+TEST(ConstexprTest, SetIntersection) {
+  static constexpr std::array kArray1 = {1, 2, 3};
+  static constexpr std::array kArray2 = {1, 3, 4};
+  static constexpr auto kArraySetIntersection = [] {
+    std::array<int, 2> array;
+    absl::c_set_intersection(kArray1, kArray2, array.begin());
+    return array;
+  }();
+  static_assert(kArraySetIntersection == std::array{1, 3});
+}
+
+TEST(ConstexprTest, SetIntersectionWithPredicate) {
+  static constexpr std::array kArray1 = {3, 2, 1};
+  static constexpr std::array kArray2 = {4, 3, 1};
+  static constexpr auto kArraySetIntersection = [] {
+    std::array<int, 2> array;
+    absl::c_set_intersection(kArray1, kArray2, array.begin(), std::greater<>());
+    return array;
+  }();
+  static_assert(kArraySetIntersection == std::array{3, 1});
+}
+
+TEST(ConstexprTest, SetDifference) {
+  static constexpr std::array kArray1 = {1, 2, 3};
+  static constexpr std::array kArray2 = {1, 3, 4};
+  static constexpr auto kArraySetDifference = [] {
+    std::array<int, 1> array;
+    absl::c_set_difference(kArray1, kArray2, array.begin());
+    return array;
+  }();
+  static_assert(kArraySetDifference == std::array{2});
+}
+
+TEST(ConstexprTest, SetDifferenceWithPredicate) {
+  static constexpr std::array kArray1 = {3, 2, 1};
+  static constexpr std::array kArray2 = {4, 3, 1};
+  static constexpr auto kArraySetDifference = [] {
+    std::array<int, 1> array;
+    absl::c_set_difference(kArray1, kArray2, array.begin(), std::greater<>());
+    return array;
+  }();
+  static_assert(kArraySetDifference == std::array{2});
+}
+
+TEST(ConstexprTest, SetSymmetricDifference) {
+  static constexpr std::array kArray1 = {1, 2, 3};
+  static constexpr std::array kArray2 = {1, 3, 4};
+  static constexpr auto kArraySetSymmetricDifference = [] {
+    std::array<int, 2> array;
+    absl::c_set_symmetric_difference(kArray1, kArray2, array.begin());
+    return array;
+  }();
+  static_assert(kArraySetSymmetricDifference == std::array{2, 4});
+}
+
+TEST(ConstexprTest, SetSymmetricDifferenceWithPredicate) {
+  static constexpr std::array kArray1 = {3, 2, 1};
+  static constexpr std::array kArray2 = {4, 3, 1};
+  static constexpr auto kArraySetSymmetricDifference = [] {
+    std::array<int, 2> array;
+    absl::c_set_symmetric_difference(kArray1, kArray2, array.begin(),
+                                     std::greater<>());
+    return array;
+  }();
+  static_assert(kArraySetSymmetricDifference == std::array{4, 2});
+}
+
+TEST(ConstexprTest, PushHeap) {
+  static constexpr auto kArray = [] {
+    std::array array = {1, 2, 3, 4};
+    absl::c_push_heap(array);
+    return array;
+  }();
+  static_assert(kArray[0] == 4);
+}
+
+TEST(ConstexprTest, PushHeapWithPredicate) {
+  static constexpr auto kArray = [] {
+    std::array array = {4, 3, 2, 1};
+    absl::c_push_heap(array, std::greater<>());
+    return array;
+  }();
+  static_assert(kArray[0] == 1);
+}
+
+TEST(ConstexprTest, PopHeap) {
+  static constexpr auto kArray = [] {
+    std::array array = {4, 3, 2, 1};
+    absl::c_pop_heap(array);
+    return array;
+  }();
+  static_assert(kArray[3] == 4);
+}
+
+TEST(ConstexprTest, PopHeapWithPredicate) {
+  static constexpr auto kArray = [] {
+    std::array array = {1, 2, 3, 4};
+    absl::c_pop_heap(array, std::greater<>());
+    return array;
+  }();
+  static_assert(kArray[3] == 1);
+}
+
+TEST(ConstexprTest, MakeHeap) {
+  static constexpr auto kArray = [] {
+    std::array array = {1, 2, 3, 4};
+    absl::c_make_heap(array);
+    return array;
+  }();
+  static_assert(absl::c_is_heap(kArray));
+}
+
+TEST(ConstexprTest, MakeHeapWithPredicate) {
+  static constexpr auto kArray = [] {
+    std::array array = {4, 3, 2, 1};
+    absl::c_make_heap(array, std::greater<>());
+    return array;
+  }();
+  static_assert(absl::c_is_heap(kArray, std::greater<>()));
+}
+
+TEST(ConstexprTest, SortHeap) {
+  static constexpr auto kArray = [] {
+    std::array array = {1, 2, 3, 4};
+    absl::c_make_heap(array);
+    absl::c_sort_heap(array);
+    return array;
+  }();
+  static_assert(kArray == std::array{1, 2, 3, 4});
+}
+
+TEST(ConstexprTest, SortHeapWithPredicate) {
+  static constexpr auto kArray = [] {
+    std::array array = {4, 3, 2, 1};
+    absl::c_make_heap(array, std::greater<>());
+    absl::c_sort_heap(array, std::greater<>());
+    return array;
+  }();
+  static_assert(kArray == std::array{4, 3, 2, 1});
+}
+
+TEST(ConstexprTest, IsHeap) {
+  static constexpr std::array kHeap = {4, 2, 3, 1};
+  static_assert(absl::c_is_heap(kHeap));
+  static constexpr std::array kNotHeap = {1, 2, 3, 4};
+  static_assert(!absl::c_is_heap(kNotHeap));
+}
+
+TEST(ConstexprTest, IsHeapWithPredicate) {
+  static constexpr std::array kHeap = {1, 2, 3, 4};
+  static_assert(absl::c_is_heap(kHeap, std::greater<>()));
+  static constexpr std::array kNotHeap = {4, 3, 2, 1};
+  static_assert(!absl::c_is_heap(kNotHeap, std::greater<>()));
+}
+
+TEST(ConstexprTest, IsHeapUntil) {
+  static constexpr std::array kHeap = {4, 2, 3, 1};
+  static_assert(absl::c_is_heap_until(kHeap) == kHeap.end());
+  static constexpr std::array kNotHeap = {4, 2, 3, 5};
+  static_assert(absl::c_is_heap_until(kNotHeap) == kNotHeap.begin() + 3);
+}
+
+TEST(ConstexprTest, IsHeapUntilWithPredicate) {
+  static constexpr std::array kHeap = {1, 2, 3, 4};
+  static_assert(absl::c_is_heap_until(kHeap, std::greater<>()) == kHeap.end());
+  static constexpr std::array kNotHeap = {1, 2, 3, 0};
+  static_assert(absl::c_is_heap_until(kNotHeap, std::greater<>()) ==
+                kNotHeap.begin() + 3);
+}
+
+TEST(ConstexprTest, LexicographicalCompare) {
+  static constexpr std::array kArray1 = {1, 2, 3};
+  static constexpr std::array kArray2 = {1, 2, 4};
+  static constexpr std::array kArray3 = {1, 2, 3};
+  static_assert(absl::c_lexicographical_compare(kArray1, kArray2));
+  static_assert(!absl::c_lexicographical_compare(kArray2, kArray1));
+  static_assert(!absl::c_lexicographical_compare(kArray1, kArray3));
+}
+
+TEST(ConstexprTest, LexicographicalCompareWithPredicate) {
+  static constexpr std::array kArray1 = {1, 2, 3};
+  static constexpr std::array kArray2 = {1, 2, 4};
+  static constexpr std::array kArray3 = {1, 2, 3};
+  static_assert(
+      !absl::c_lexicographical_compare(kArray1, kArray2, std::greater<>()));
+  static_assert(
+      absl::c_lexicographical_compare(kArray2, kArray1, std::greater<>()));
+  static_assert(
+      !absl::c_lexicographical_compare(kArray1, kArray3, std::greater<>()));
+}
+
+TEST(ConstexprTest, NextPermutation) {
+  static constexpr auto kArray = [] {
+    std::array array = {1, 2, 3};
+    absl::c_next_permutation(array);
+    return array;
+  }();
+  static_assert(kArray == std::array{1, 3, 2});
+}
+
+TEST(ConstexprTest, NextPermutationWithPredicate) {
+  static constexpr auto kArray = [] {
+    std::array array = {3, 2, 1};
+    absl::c_next_permutation(array, std::greater<>());
+    return array;
+  }();
+  static_assert(kArray == std::array{3, 1, 2});
+}
+
+TEST(ConstexprTest, PrevPermutation) {
+  static constexpr auto kArray = [] {
+    std::array array = {1, 3, 2};
+    absl::c_prev_permutation(array);
+    return array;
+  }();
+  static_assert(kArray == std::array{1, 2, 3});
+}
+
+TEST(ConstexprTest, PrevPermutationWithPredicate) {
+  static constexpr auto kArray = [] {
+    std::array array = {1, 2, 3};
+    absl::c_prev_permutation(array, std::greater<>());
+    return array;
+  }();
+  static_assert(kArray == std::array{1, 3, 2});
+}
+
+TEST(ConstexprTest, Iota) {
+  static constexpr auto kArray = [] {
+    std::array<int, 3> array;
+    absl::c_iota(array, 1);
+    return array;
+  }();
+  static_assert(kArray == std::array{1, 2, 3});
+}
+
+TEST(ConstexprTest, Accumulate) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static_assert(absl::c_accumulate(kArray, 0) == 6);
+}
+
+TEST(ConstexprTest, AccumulateWithPredicate) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static_assert(absl::c_accumulate(kArray, 1, std::multiplies<>()) == 6);
+}
+
+TEST(ConstexprTest, InnerProduct) {
+  static constexpr std::array kArray1 = {1, 2, 3};
+  static constexpr std::array kArray2 = {4, 5, 6};
+  static_assert(absl::c_inner_product(kArray1, kArray2, 0) == 32);
+}
+
+TEST(ConstexprTest, InnerProductWithPredicate) {
+  static constexpr std::array kArray1 = {1, 2, 3};
+  static constexpr std::array kArray2 = {4, 5, 6};
+  static_assert(absl::c_inner_product(kArray1, kArray2, 1, std::multiplies<>(),
+                                      std::plus<>()) == 315);
+}
+
+TEST(ConstexprTest, AdjacentDifference) {
+  static constexpr std::array kArray = {1, 2, 4};
+  static constexpr auto kArrayAdjacentDifference = [] {
+    std::array<int, 3> array;
+    absl::c_adjacent_difference(kArray, array.begin());
+    return array;
+  }();
+  static_assert(kArrayAdjacentDifference == std::array{1, 1, 2});
+}
+
+TEST(ConstexprTest, AdjacentDifferenceWithPredicate) {
+  static constexpr std::array kArray = {1, 2, 4};
+  static constexpr auto kArrayAdjacentDifference = [] {
+    std::array<int, 3> array;
+    absl::c_adjacent_difference(kArray, array.begin(), std::multiplies<>());
+    return array;
+  }();
+  static_assert(kArrayAdjacentDifference == std::array{1, 2, 8});
+}
+
+TEST(ConstexprTest, PartialSum) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArrayPartialSum = [] {
+    std::array<int, 3> array;
+    absl::c_partial_sum(kArray, array.begin());
+    return array;
+  }();
+  static_assert(kArrayPartialSum == std::array{1, 3, 6});
+}
+
+TEST(ConstexprTest, PartialSumWithPredicate) {
+  static constexpr std::array kArray = {1, 2, 3};
+  static constexpr auto kArrayPartialSum = [] {
+    std::array<int, 3> array;
+    absl::c_partial_sum(kArray, array.begin(), std::multiplies<>());
+    return array;
+  }();
+  static_assert(kArrayPartialSum == std::array{1, 2, 6});
+}
+
 #endif  // defined(ABSL_INTERNAL_CPLUSPLUS_LANG) &&
         //  ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
 
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index ef97b4e..1d27796 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -14,6 +14,9 @@
 # limitations under the License.
 #
 
+load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
@@ -82,13 +85,23 @@
 
 cc_library(
     name = "nullability",
-    srcs = ["internal/nullability_deprecated.h"],
     hdrs = ["nullability.h"],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [":config"],
+)
+
+cc_library(
+    name = "nullability_traits_internal",
+    hdrs = ["internal/nullability_traits.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
     deps = [
         ":config",
-        ":core_headers",
+        ":nullability",
     ],
 )
 
@@ -228,7 +241,6 @@
     name = "base_internal",
     hdrs = [
         "internal/hide_ptr.h",
-        "internal/identity.h",
         "internal/scheduling_mode.h",
     ],
     copts = ABSL_DEFAULT_COPTS,
@@ -245,6 +257,7 @@
 cc_library(
     name = "base",
     srcs = [
+        "casts.cc",
         "internal/cycleclock.cc",
         "internal/spinlock.cc",
         "internal/sysinfo.cc",
@@ -284,8 +297,6 @@
         ":config",
         ":core_headers",
         ":cycleclock_internal",
-        ":dynamic_annotations",
-        ":log_severity",
         ":nullability",
         ":raw_logging_internal",
         ":spinlock_wait",
@@ -591,6 +602,22 @@
 )
 
 cc_test(
+    name = "casts_test",
+    size = "small",
+    srcs = [
+        "casts_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":base",
+        ":config",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
+
+cc_test(
     name = "no_destructor_test",
     srcs = ["no_destructor_test.cc"],
     copts = ABSL_TEST_COPTS,
@@ -623,7 +650,6 @@
     name = "nullability_test",
     srcs = ["nullability_test.cc"],
     deps = [
-        ":core_headers",
         ":nullability",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
@@ -641,6 +667,18 @@
 )
 
 cc_test(
+    name = "nullability_traits_test",
+    srcs = ["internal/nullability_traits_test.cc"],
+    deps = [
+        ":config",
+        ":nullability",
+        ":nullability_traits_internal",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
+
+cc_test(
     name = "raw_logging_test",
     srcs = ["raw_logging_test.cc"],
     copts = ABSL_TEST_COPTS,
@@ -685,7 +723,6 @@
 
 cc_test(
     name = "thread_identity_test",
-    size = "small",
     srcs = ["internal/thread_identity_test.cc"],
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
@@ -721,6 +758,7 @@
     testonly = True,
     srcs = ["internal/scoped_set_env.cc"],
     hdrs = ["internal/scoped_set_env.h"],
+    copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl:__subpackages__",
@@ -925,6 +963,9 @@
     hdrs = ["internal/iterator_traits.h"],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
     deps = [
         ":config",
         "//absl/meta:type_traits",
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index 23942c0..84decab 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -72,11 +72,8 @@
     nullability
   HDRS
     "nullability.h"
-  SRCS
-    "internal/nullability_deprecated.h"
   DEPS
     absl::config
-    absl::core_headers
   COPTS
     ${ABSL_DEFAULT_COPTS}
 )
@@ -89,7 +86,6 @@
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
-    absl::core_headers
     absl::nullability
     GTest::gtest_main
 )
@@ -109,6 +105,34 @@
 # Internal-only target, do not depend on directly.
 absl_cc_library(
   NAME
+    nullability_traits_internal
+  HDRS
+    "internal/nullability_traits.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::config
+    absl::nullability
+  PUBLIC
+)
+
+absl_cc_test(
+  NAME
+    nullability_traits_test
+  SRCS
+    "internal/nullability_traits_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::config
+    absl::nullability
+    absl::nullability_traits_internal
+    GTest::gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+  NAME
     raw_logging_internal
   HDRS
     "internal/raw_logging.h"
@@ -214,7 +238,6 @@
     base_internal
   HDRS
     "internal/hide_ptr.h"
-    "internal/identity.h"
     "internal/scheduling_mode.h"
   COPTS
     ${ABSL_DEFAULT_COPTS}
@@ -240,6 +263,7 @@
     "internal/unscaledcycleclock.h"
     "internal/unscaledcycleclock_config.h"
   SRCS
+    "casts.cc"
     "internal/cycleclock.cc"
     "internal/spinlock.cc"
     "internal/sysinfo.cc"
@@ -396,6 +420,19 @@
 
 absl_cc_test(
   NAME
+    casts_test
+  SRCS
+    "casts_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::base
+    absl::core_headers
+    GTest::gtest_main
+)
+
+absl_cc_test(
+  NAME
     errno_saver_test
   SRCS
     "internal/errno_saver_test.cc"
diff --git a/absl/base/attributes.h b/absl/base/attributes.h
index d009f6d..2261747 100644
--- a/absl/base/attributes.h
+++ b/absl/base/attributes.h
@@ -277,6 +277,16 @@
 #define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED
 #endif
 
+// Android local modification: add attribute for disabling unsigned overflow
+// sanitization for code where it's intentional, to support vendor code that
+// enables it.
+#if ABSL_HAVE_ATTRIBUTE(no_sanitize)
+#define ABSL_ATTRIBUTE_NO_SANITIZE_UNSIGNED_OVERFLOW \
+  __attribute__((no_sanitize("unsigned-integer-overflow")))
+#else
+#define ABSL_ATTRIBUTE_NO_SANITIZE_UNSIGNED_OVERFLOW
+#endif
+
 // ABSL_ATTRIBUTE_NO_SANITIZE_CFI
 //
 // Tells the ControlFlowIntegrity sanitizer to not instrument a given function.
@@ -553,7 +563,7 @@
 //
 // Prevents the compiler from complaining about variables that appear unused.
 //
-// Deprecated: Use the standard C++17 `[[maybe_unused]` instead.
+// Deprecated: Use the standard C++17 `[[maybe_unused]]` instead.
 //
 // Due to differences in positioning requirements between the old, compiler
 // specific __attribute__ syntax and the now standard `[[maybe_unused]]`, this
@@ -580,7 +590,11 @@
 // Instructs the compiler not to use natural alignment for a tagged data
 // structure, but instead to reduce its alignment to 1.
 //
-// Therefore, DO NOT APPLY THIS ATTRIBUTE TO STRUCTS CONTAINING ATOMICS. Doing
+// Use of this attribute is HIGHLY DISCOURAGED. Taking the address of or
+// binding a reference to any unaligned member is UB, and it is very easy to
+// do so unintentionally when passing such members as function arguments.
+//
+// DO NOT APPLY THIS ATTRIBUTE TO STRUCTS CONTAINING ATOMICS. Doing
 // so can cause atomic variables to be mis-aligned and silently violate
 // atomicity on x86.
 //
diff --git a/absl/base/call_once_test.cc b/absl/base/call_once_test.cc
index 11d26c4..630e7ce 100644
--- a/absl/base/call_once_test.cc
+++ b/absl/base/call_once_test.cc
@@ -39,25 +39,25 @@
 
 // Function to be called from absl::call_once.  Waits for a notification.
 void WaitAndIncrement() {
-  counters_mu.Lock();
+  counters_mu.lock();
   ++call_once_invoke_count;
-  counters_mu.Unlock();
+  counters_mu.unlock();
 
   counters_mu.LockWhen(Condition(&done_blocking));
   ++call_once_finished_count;
-  counters_mu.Unlock();
+  counters_mu.unlock();
 }
 
 void ThreadBody() {
-  counters_mu.Lock();
+  counters_mu.lock();
   ++running_thread_count;
-  counters_mu.Unlock();
+  counters_mu.unlock();
 
   absl::call_once(once, WaitAndIncrement);
 
-  counters_mu.Lock();
+  counters_mu.lock();
   ++call_once_return_count;
-  counters_mu.Unlock();
+  counters_mu.unlock();
 }
 
 // Returns true if all threads are set up for the test.
@@ -89,17 +89,17 @@
   // Allow WaitAndIncrement to finish executing.  Once it does, the other
   // call_once waiters will be unblocked.
   done_blocking = true;
-  counters_mu.Unlock();
+  counters_mu.unlock();
 
   for (std::thread& thread : threads) {
     thread.join();
   }
 
-  counters_mu.Lock();
+  counters_mu.lock();
   EXPECT_EQ(call_once_invoke_count, 1);
   EXPECT_EQ(call_once_finished_count, 1);
   EXPECT_EQ(call_once_return_count, 10);
-  counters_mu.Unlock();
+  counters_mu.unlock();
 }
 
 }  // namespace
diff --git a/absl/base/casts.cc b/absl/base/casts.cc
new file mode 100644
index 0000000..d864a8c
--- /dev/null
+++ b/absl/base/casts.cc
@@ -0,0 +1,61 @@
+// Copyright 2025 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/casts.h"
+
+#include <cstdlib>
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/raw_logging.h"
+
+#ifdef ABSL_INTERNAL_HAS_CXA_DEMANGLE
+#include <cxxabi.h>
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+namespace base_internal {
+
+namespace {
+
+std::string DemangleCppString(const char* mangled) {
+  std::string out;
+  int status = 0;
+  char* demangled = nullptr;
+#ifdef ABSL_INTERNAL_HAS_CXA_DEMANGLE
+  demangled = abi::__cxa_demangle(mangled, nullptr, nullptr, &status);
+#endif
+  if (status == 0 && demangled != nullptr) {
+    out.append(demangled);
+    free(demangled);
+  } else {
+    out.append(mangled);
+  }
+  return out;
+}
+
+}  // namespace
+
+void BadDownCastCrash(const char* source_type, const char* target_type) {
+  ABSL_RAW_LOG(FATAL, "down cast from %s to %s failed",
+               DemangleCppString(source_type).c_str(),
+               DemangleCppString(target_type).c_str());
+}
+
+}  // namespace base_internal
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/base/casts.h b/absl/base/casts.h
index e0b11bb..480855a 100644
--- a/absl/base/casts.h
+++ b/absl/base/casts.h
@@ -33,8 +33,11 @@
 #include <bit>  // For std::bit_cast.
 #endif  // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
 
-#include "absl/base/internal/identity.h"
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
 #include "absl/base/macros.h"
+#include "absl/base/optimization.h"
+#include "absl/base/options.h"
 #include "absl/meta/type_traits.h"
 
 namespace absl {
@@ -90,9 +93,26 @@
 //
 // Such implicit cast chaining may be useful within template logic.
 template <typename To>
-constexpr To implicit_cast(typename absl::internal::type_identity_t<To> to) {
+constexpr std::enable_if_t<
+    !type_traits_internal::IsView<std::enable_if_t<
+        !std::is_reference_v<To>, std::remove_cv_t<To>>>::value,
+    To>
+implicit_cast(absl::type_identity_t<To> to) {
   return to;
 }
+template <typename To>
+constexpr std::enable_if_t<
+    type_traits_internal::IsView<std::enable_if_t<!std::is_reference_v<To>,
+                                                  std::remove_cv_t<To>>>::value,
+    To>
+implicit_cast(absl::type_identity_t<To> to ABSL_ATTRIBUTE_LIFETIME_BOUND) {
+  return to;
+}
+template <typename To>
+constexpr std::enable_if_t<std::is_reference_v<To>, To> implicit_cast(
+    absl::type_identity_t<To> to ABSL_ATTRIBUTE_LIFETIME_BOUND) {
+  return std::forward<absl::type_identity_t<To>>(to);
+}
 
 // bit_cast()
 //
@@ -174,6 +194,112 @@
 
 #endif  // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
 
+namespace base_internal {
+
+[[noreturn]] ABSL_ATTRIBUTE_NOINLINE void BadDownCastCrash(
+    const char* source_type, const char* target_type);
+
+template <typename To, typename From>
+inline void ValidateDownCast(From* f ABSL_ATTRIBUTE_UNUSED) {
+  // Assert only if RTTI is enabled and in debug mode or hardened asserts are
+  // enabled.
+#ifdef ABSL_INTERNAL_HAS_RTTI
+#if !defined(NDEBUG) || (ABSL_OPTION_HARDENED == 1 || ABSL_OPTION_HARDENED == 2)
+  // Suppress erroneous nonnull comparison warning on older GCC.
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnonnull-compare"
+#endif
+  if (ABSL_PREDICT_FALSE(f != nullptr && dynamic_cast<To>(f) == nullptr)) {
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+    absl::base_internal::BadDownCastCrash(
+        typeid(*f).name(), typeid(std::remove_pointer_t<To>).name());
+  }
+#endif
+#endif
+}
+
+}  // namespace base_internal
+
+// An "upcast", i.e. a conversion from a pointer to an object to a pointer to a
+// base subobject, always succeeds if the base is unambiguous and accessible,
+// and so it's fine to use implicit_cast.
+//
+// A "downcast", i.e. a conversion from a pointer to an object to a pointer
+// to a more-derived object that may contain the original object as a base
+// subobject, cannot safely be done using static_cast, because you do not
+// generally know whether the source object is really the base subobject of
+// a containing, more-derived object of the target type. Thus, when you
+// downcast in a polymorphic type hierarchy, you should use the following
+// function template.
+//
+// This function only returns null when the input is null. In debug mode, we
+// use dynamic_cast to double-check whether the downcast is legal (we die if
+// it's not). In normal mode, we do the efficient static_cast instead. Because
+// the process will die in debug mode, it's important to test to make sure the
+// cast is legal before calling this function!
+//
+// dynamic_cast should be avoided except as allowed by the style guide
+// (https://google.github.io/styleguide/cppguide.html#Run-Time_Type_Information__RTTI_).
+
+template <typename To, typename From>  // use like this: down_cast<T*>(foo);
+[[nodiscard]]
+inline To down_cast(From* f) {  // so we only accept pointers
+  static_assert(std::is_pointer<To>::value, "target type not a pointer");
+  // dynamic_cast allows casting to the same type or a more cv-qualified
+  // version of the same type without them being polymorphic.
+  if constexpr (!std::is_same<std::remove_cv_t<std::remove_pointer_t<To>>,
+                              std::remove_cv_t<From>>::value) {
+    static_assert(std::is_polymorphic<From>::value,
+                  "source type must be polymorphic");
+    static_assert(std::is_polymorphic<std::remove_pointer_t<To>>::value,
+                  "target type must be polymorphic");
+  }
+  static_assert(
+      std::is_convertible<std::remove_cv_t<std::remove_pointer_t<To>>*,
+                          std::remove_cv_t<From>*>::value,
+      "target type not derived from source type");
+
+  absl::base_internal::ValidateDownCast<To>(f);
+
+  return static_cast<To>(f);
+}
+
+// Overload of down_cast for references. Use like this:
+// absl::down_cast<T&>(foo). The code is slightly convoluted because we're still
+// using the pointer form of dynamic cast. (The reference form throws an
+// exception if it fails.)
+//
+// There's no need for a special const overload either for the pointer
+// or the reference form. If you call down_cast with a const T&, the
+// compiler will just bind From to const T.
+template <typename To, typename From>
+[[nodiscard]]
+inline To down_cast(From& f) {
+  static_assert(std::is_lvalue_reference<To>::value,
+                "target type not a reference");
+  // dynamic_cast allows casting to the same type or a more cv-qualified
+  // version of the same type without them being polymorphic.
+  if constexpr (!std::is_same<std::remove_cv_t<std::remove_reference_t<To>>,
+                              std::remove_cv_t<From>>::value) {
+    static_assert(std::is_polymorphic<From>::value,
+                  "source type must be polymorphic");
+    static_assert(std::is_polymorphic<std::remove_reference_t<To>>::value,
+                  "target type must be polymorphic");
+  }
+  static_assert(
+      std::is_convertible<std::remove_cv_t<std::remove_reference_t<To>>*,
+                          std::remove_cv_t<From>*>::value,
+      "target type not derived from source type");
+
+  absl::base_internal::ValidateDownCast<std::remove_reference_t<To>*>(
+      std::addressof(f));
+
+  return static_cast<To>(f);
+}
+
 ABSL_NAMESPACE_END
 }  // namespace absl
 
diff --git a/absl/base/casts_test.cc b/absl/base/casts_test.cc
new file mode 100644
index 0000000..772225e
--- /dev/null
+++ b/absl/base/casts_test.cc
@@ -0,0 +1,151 @@
+// Copyright 2025 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/casts.h"
+
+#include <type_traits>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "absl/base/options.h"
+
+namespace {
+
+struct BaseForImplicitCast {
+  explicit BaseForImplicitCast(int value) : x(value) {}
+  BaseForImplicitCast(const BaseForImplicitCast& other) = delete;
+  BaseForImplicitCast& operator=(const BaseForImplicitCast& other) = delete;
+  int x;
+};
+struct DerivedForImplicitCast : BaseForImplicitCast {
+  explicit DerivedForImplicitCast(int value) : BaseForImplicitCast(value) {}
+};
+
+static_assert(std::is_same_v<decltype(absl::implicit_cast<BaseForImplicitCast&>(
+                                 std::declval<DerivedForImplicitCast&>())),
+                             BaseForImplicitCast&>);
+static_assert(
+    std::is_same_v<decltype(absl::implicit_cast<const BaseForImplicitCast&>(
+                       std::declval<DerivedForImplicitCast>())),
+                   const BaseForImplicitCast&>);
+
+TEST(ImplicitCastTest, LValueReference) {
+  DerivedForImplicitCast derived(5);
+  EXPECT_EQ(&absl::implicit_cast<BaseForImplicitCast&>(derived), &derived);
+  EXPECT_EQ(&absl::implicit_cast<const BaseForImplicitCast&>(derived),
+            &derived);
+}
+
+TEST(ImplicitCastTest, RValueReference) {
+  DerivedForImplicitCast derived(5);
+  BaseForImplicitCast&& base =
+      absl::implicit_cast<BaseForImplicitCast&&>(std::move(derived));
+  EXPECT_EQ(&base, &derived);
+
+  const DerivedForImplicitCast cderived(6);
+  const BaseForImplicitCast&& cbase =
+      absl::implicit_cast<const BaseForImplicitCast&&>(std::move(cderived));
+  EXPECT_EQ(&cbase, &cderived);
+}
+
+class BaseForDownCast {
+ public:
+  virtual ~BaseForDownCast() = default;
+};
+
+class DerivedForDownCast : public BaseForDownCast {};
+class Derived2ForDownCast : public BaseForDownCast {};
+
+TEST(DownCastTest, Pointer) {
+  DerivedForDownCast derived;
+  BaseForDownCast* const base_ptr = &derived;
+
+  // Tests casting a BaseForDownCast* to a DerivedForDownCast*.
+  EXPECT_EQ(&derived, absl::down_cast<DerivedForDownCast*>(base_ptr));
+
+  // Tests casting a const BaseForDownCast* to a const DerivedForDownCast*.
+  const BaseForDownCast* const_base_ptr = base_ptr;
+  EXPECT_EQ(&derived,
+            absl::down_cast<const DerivedForDownCast*>(const_base_ptr));
+
+  // Tests casting a BaseForDownCast* to a const DerivedForDownCast*.
+  EXPECT_EQ(&derived, absl::down_cast<const DerivedForDownCast*>(base_ptr));
+
+  // Tests casting a BaseForDownCast* to a BaseForDownCast* (an identity cast).
+  EXPECT_EQ(base_ptr, absl::down_cast<BaseForDownCast*>(base_ptr));
+
+  // Tests down casting NULL.
+  EXPECT_EQ(nullptr,
+            (absl::down_cast<DerivedForDownCast*, BaseForDownCast>(nullptr)));
+
+  // Tests a bad downcast. We have to disguise the badness just enough
+  // that the compiler doesn't warn about it at compile time.
+  BaseForDownCast* base2 = new BaseForDownCast();
+#if GTEST_HAS_DEATH_TEST && (!defined(NDEBUG) || (ABSL_OPTION_HARDENED == 1 || \
+                                                  ABSL_OPTION_HARDENED == 2))
+  EXPECT_DEATH(static_cast<void>(absl::down_cast<DerivedForDownCast*>(base2)),
+               ".*down cast from .*BaseForDownCast.* to "
+               ".*DerivedForDownCast.* failed.*");
+#endif
+  delete base2;
+}
+
+TEST(DownCastTest, Reference) {
+  DerivedForDownCast derived;
+  BaseForDownCast& base_ref = derived;
+
+  // Tests casting a BaseForDownCast& to a DerivedForDownCast&.
+  // NOLINTNEXTLINE(runtime/casting)
+  EXPECT_EQ(&derived, &absl::down_cast<DerivedForDownCast&>(base_ref));
+
+  // Tests casting a const BaseForDownCast& to a const DerivedForDownCast&.
+  const BaseForDownCast& const_base_ref = base_ref;
+  // NOLINTNEXTLINE(runtime/casting)
+  EXPECT_EQ(&derived,
+            &absl::down_cast<const DerivedForDownCast&>(const_base_ref));
+
+  // Tests casting a BaseForDownCast& to a const DerivedForDownCast&.
+  // NOLINTNEXTLINE(runtime/casting)
+  EXPECT_EQ(&derived, &absl::down_cast<const DerivedForDownCast&>(base_ref));
+
+  // Tests casting a BaseForDownCast& to a BaseForDownCast& (an identity cast).
+  // NOLINTNEXTLINE(runtime/casting)
+  EXPECT_EQ(&base_ref, &absl::down_cast<BaseForDownCast&>(base_ref));
+
+  // Tests a bad downcast. We have to disguise the badness just enough
+  // that the compiler doesn't warn about it at compile time.
+  BaseForDownCast& base2 = *new BaseForDownCast();
+#if GTEST_HAS_DEATH_TEST && (!defined(NDEBUG) || (ABSL_OPTION_HARDENED == 1 || \
+                                                  ABSL_OPTION_HARDENED == 2))
+  EXPECT_DEATH(static_cast<void>(absl::down_cast<DerivedForDownCast&>(base2)),
+               ".*down cast from .*BaseForDownCast.* to "
+               ".*DerivedForDownCast.* failed.*");
+#endif
+  delete &base2;
+}
+
+TEST(DownCastTest, ErrorMessage) {
+  DerivedForDownCast derived;
+  BaseForDownCast& base = derived;
+  (void)base;
+
+#if GTEST_HAS_DEATH_TEST && (!defined(NDEBUG) || (ABSL_OPTION_HARDENED == 1 || \
+                                                  ABSL_OPTION_HARDENED == 2))
+  EXPECT_DEATH(static_cast<void>(absl::down_cast<Derived2ForDownCast&>(base)),
+               ".*down cast from .*DerivedForDownCast.* to "
+               ".*Derived2ForDownCast.* failed.*");
+#endif
+}
+
+}  // namespace
diff --git a/absl/base/config.h b/absl/base/config.h
index 8e5feb5..0de5b8c 100644
--- a/absl/base/config.h
+++ b/absl/base/config.h
@@ -117,7 +117,7 @@
 //
 // LTS releases can be obtained from
 // https://github.com/abseil/abseil-cpp/releases.
-#define ABSL_LTS_RELEASE_VERSION 20250512
+#define ABSL_LTS_RELEASE_VERSION 20260107
 #define ABSL_LTS_RELEASE_PATCH_LEVEL 1
 
 // Helper macro to convert a CPP variable to a string literal.
@@ -237,6 +237,8 @@
 #error ABSL_HAVE_TLS cannot be directly set
 #elif (defined(__linux__)) && (defined(__clang__) || defined(_GLIBCXX_HAVE_TLS))
 #define ABSL_HAVE_TLS 1
+#elif defined(__INTEL_LLVM_COMPILER)
+#define ABSL_HAVE_TLS 1
 #endif
 
 // ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
@@ -358,10 +360,10 @@
 //   Darwin (macOS and iOS)            __APPLE__
 //   Akaros (http://akaros.org)        __ros__
 //   Windows                           _WIN32
-//   NaCL                              __native_client__
 //   AsmJS                             __asmjs__
 //   WebAssembly (Emscripten)          __EMSCRIPTEN__
 //   Fuchsia                           __Fuchsia__
+//   WebAssembly (WASI)                _WASI_EMULATED_MMAN (implies __wasi__)
 //
 // Note that since Android defines both __ANDROID__ and __linux__, one
 // may probe for either Linux or Android by simply testing for __linux__.
@@ -372,12 +374,13 @@
 // POSIX.1-2001.
 #ifdef ABSL_HAVE_MMAP
 #error ABSL_HAVE_MMAP cannot be directly set
-#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) ||    \
-    defined(_AIX) || defined(__ros__) || defined(__native_client__) ||       \
-    defined(__asmjs__) || defined(__EMSCRIPTEN__) || defined(__Fuchsia__) || \
-    defined(__sun) || defined(__myriad2__) || defined(__HAIKU__) ||          \
-    defined(__OpenBSD__) || defined(__NetBSD__) || defined(__QNX__) ||       \
-    defined(__VXWORKS__) || defined(__hexagon__) || defined(__XTENSA__)
+#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
+    defined(_AIX) || defined(__ros__) || defined(__asmjs__) ||            \
+    defined(__EMSCRIPTEN__) || defined(__Fuchsia__) || defined(__sun) ||  \
+    defined(__myriad2__) || defined(__HAIKU__) || defined(__OpenBSD__) || \
+    defined(__NetBSD__) || defined(__QNX__) || defined(__VXWORKS__) ||    \
+    defined(__hexagon__) || defined(__XTENSA__) ||                        \
+    defined(_WASI_EMULATED_MMAN)
 #define ABSL_HAVE_MMAP 1
 #endif
 
@@ -453,8 +456,6 @@
 // WASI doesn't support signals
 #elif defined(__Fuchsia__)
 // Signals don't exist on fuchsia.
-#elif defined(__native_client__)
-// Signals don't exist on hexagon/QuRT
 #elif defined(__hexagon__)
 #else
 // other standard libraries
@@ -525,20 +526,11 @@
 #define ABSL_USES_STD_ANY 1
 #define ABSL_HAVE_STD_OPTIONAL 1
 #define ABSL_USES_STD_OPTIONAL 1
+#define ABSL_HAVE_STD_STRING_VIEW 1
+#define ABSL_USES_STD_STRING_VIEW 1
 #define ABSL_HAVE_STD_VARIANT 1
 #define ABSL_USES_STD_VARIANT 1
 
-// ABSL_HAVE_STD_STRING_VIEW
-//
-// Deprecated: always defined to 1.
-// std::string_view was added in C++17, which means all versions of C++
-// supported by Abseil have it.
-#ifdef ABSL_HAVE_STD_STRING_VIEW
-#error "ABSL_HAVE_STD_STRING_VIEW cannot be directly set."
-#else
-#define ABSL_HAVE_STD_STRING_VIEW 1
-#endif
-
 // ABSL_HAVE_STD_ORDERING
 //
 // Checks whether C++20 std::{partial,weak,strong}_ordering are available.
@@ -555,20 +547,6 @@
 #define ABSL_HAVE_STD_ORDERING 1
 #endif
 
-// ABSL_USES_STD_STRING_VIEW
-//
-// Indicates whether absl::string_view is an alias for std::string_view.
-#if !defined(ABSL_OPTION_USE_STD_STRING_VIEW)
-#error options.h is misconfigured.
-#elif ABSL_OPTION_USE_STD_STRING_VIEW == 0
-#undef ABSL_USES_STD_STRING_VIEW
-#elif ABSL_OPTION_USE_STD_STRING_VIEW == 1 || \
-    ABSL_OPTION_USE_STD_STRING_VIEW == 2
-#define ABSL_USES_STD_STRING_VIEW 1
-#else
-#error options.h is misconfigured.
-#endif
-
 // ABSL_USES_STD_ORDERING
 //
 // Indicates whether absl::{partial,weak,strong}_ordering are aliases for the
@@ -754,7 +732,7 @@
 #ifdef ABSL_INTERNAL_HAS_CXA_DEMANGLE
 #error ABSL_INTERNAL_HAS_CXA_DEMANGLE cannot be directly set
 #elif defined(OS_ANDROID) && (defined(__i386__) || defined(__x86_64__))
-#define ABSL_INTERNAL_HAS_CXA_DEMANGLE 0
+#undef ABSL_INTERNAL_HAS_CXA_DEMANGLE
 #elif defined(__GNUC__)
 #define ABSL_INTERNAL_HAS_CXA_DEMANGLE 1
 #elif defined(__clang__) && !defined(_MSC_VER)
diff --git a/absl/base/internal/dynamic_annotations.h b/absl/base/internal/dynamic_annotations.h
index b23c5ec..537a2fe 100644
--- a/absl/base/internal/dynamic_annotations.h
+++ b/absl/base/internal/dynamic_annotations.h
@@ -89,7 +89,7 @@
 #endif
 
 // Memory annotations are also made available to LLVM's Memory Sanitizer
-#if defined(ABSL_HAVE_MEMORY_SANITIZER) && !defined(__native_client__)
+#if defined(ABSL_HAVE_MEMORY_SANITIZER)
 #define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 1
 #endif
 
diff --git a/absl/base/internal/identity.h b/absl/base/internal/identity.h
deleted file mode 100644
index 365207b..0000000
--- a/absl/base/internal/identity.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2017 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.
-//
-
-#ifndef ABSL_BASE_INTERNAL_IDENTITY_H_
-#define ABSL_BASE_INTERNAL_IDENTITY_H_
-
-#include "absl/base/config.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace internal {
-
-// This is a back-fill of C++20's `std::type_identity`.
-template <typename T>
-struct type_identity {
-  typedef T type;
-};
-
-// This is a back-fill of C++20's `std::type_identity_t`.
-template <typename T>
-using type_identity_t = typename type_identity<T>::type;
-
-}  // namespace internal
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#endif  // ABSL_BASE_INTERNAL_IDENTITY_H_
diff --git a/absl/base/internal/iterator_traits.h b/absl/base/internal/iterator_traits.h
index 472c436..5fa4df8 100644
--- a/absl/base/internal/iterator_traits.h
+++ b/absl/base/internal/iterator_traits.h
@@ -61,6 +61,10 @@
     std::is_convertible<IteratorConcept<Iterator>, IteratorTag>;
 
 template <typename Iterator>
+using IsAtLeastInputIterator =
+    IsAtLeastIterator<std::input_iterator_tag, Iterator>;
+
+template <typename Iterator>
 using IsAtLeastForwardIterator =
     IsAtLeastIterator<std::forward_iterator_tag, Iterator>;
 
diff --git a/absl/base/internal/low_level_alloc.cc b/absl/base/internal/low_level_alloc.cc
index 158b609..a5bd71d 100644
--- a/absl/base/internal/low_level_alloc.cc
+++ b/absl/base/internal/low_level_alloc.cc
@@ -19,6 +19,9 @@
 
 #include "absl/base/internal/low_level_alloc.h"
 
+#include <stdint.h>
+
+#include <optional>
 #include <type_traits>
 
 #include "absl/base/call_once.h"
@@ -219,6 +222,32 @@
   uint32_t random ABSL_GUARDED_BY(mu);
 };
 
+// ---------------------------------------------------------------
+// An async-signal-safe arena for LowLevelAlloc
+static std::atomic<base_internal::LowLevelAlloc::Arena *> g_sig_safe_arena;
+
+base_internal::LowLevelAlloc::Arena *SigSafeArena() {
+  return g_sig_safe_arena.load(std::memory_order_acquire);
+}
+
+void InitSigSafeArena() {
+  if (SigSafeArena() == nullptr) {
+    uint32_t flags = 0;
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+    flags |= base_internal::LowLevelAlloc::kAsyncSignalSafe;
+#endif
+    base_internal::LowLevelAlloc::Arena *new_arena =
+        base_internal::LowLevelAlloc::NewArena(flags);
+    base_internal::LowLevelAlloc::Arena *old_value = nullptr;
+    if (!g_sig_safe_arena.compare_exchange_strong(old_value, new_arena,
+                                                  std::memory_order_release,
+                                                  std::memory_order_relaxed)) {
+      // We lost a race to allocate an arena; deallocate.
+      base_internal::LowLevelAlloc::DeleteArena(new_arena);
+    }
+  }
+}
+
 namespace {
 // Static storage space for the lazily-constructed, default global arena
 // instances.  We require this space because the whole point of LowLevelAlloc
@@ -289,11 +318,11 @@
       mask_valid_ = pthread_sigmask(SIG_BLOCK, &all, &mask_) == 0;
     }
 #endif
-    arena_->mu.Lock();
+    arena_->mu.lock();
   }
   ~ArenaLock() { ABSL_RAW_CHECK(left_, "haven't left Arena region"); }
   void Leave() ABSL_UNLOCK_FUNCTION() {
-    arena_->mu.Unlock();
+    arena_->mu.unlock();
 #ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
     if (mask_valid_) {
       const int err = pthread_sigmask(SIG_SETMASK, &mask_, nullptr);
@@ -544,7 +573,7 @@
       }
       // we unlock before mmap() both because mmap() may call a callback hook,
       // and because it may be slow.
-      arena->mu.Unlock();
+      arena->mu.unlock();
       // mmap generous 64K chunks to decrease
       // the chances/impact of fragmentation:
       size_t new_pages_size = RoundUp(req_rnd, arena->pagesize * 16);
@@ -583,7 +612,7 @@
 #endif
 #endif  // __linux__
 #endif  // _WIN32
-      arena->mu.Lock();
+      arena->mu.lock();
       s = reinterpret_cast<AllocList *>(new_pages);
       s->header.size = new_pages_size;
       // Pretend the block is allocated; call AddToFreelist() to free it.
diff --git a/absl/base/internal/low_level_alloc.h b/absl/base/internal/low_level_alloc.h
index c2f1f25..23218dd 100644
--- a/absl/base/internal/low_level_alloc.h
+++ b/absl/base/internal/low_level_alloc.h
@@ -120,6 +120,12 @@
   LowLevelAlloc();      // no instances
 };
 
+// Returns a global async-signal-safe arena for LowLevelAlloc.
+LowLevelAlloc::Arena *SigSafeArena();
+
+// Ensures the global async-signal-safe arena for LowLevelAlloc is initialized.
+void InitSigSafeArena();
+
 }  // namespace base_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/base/internal/nullability_deprecated.h b/absl/base/internal/nullability_deprecated.h
deleted file mode 100644
index 1174a96..0000000
--- a/absl/base/internal/nullability_deprecated.h
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2023 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.
-#ifndef ABSL_BASE_INTERNAL_NULLABILITY_DEPRECATED_H_
-#define ABSL_BASE_INTERNAL_NULLABILITY_DEPRECATED_H_
-
-#include "absl/base/attributes.h"
-#include "absl/base/config.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace nullability_internal {
-
-template <typename T>
-using NullableImpl
-#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
-    [[clang::annotate("Nullable")]]
-#endif
-// Don't add the _Nullable attribute in Objective-C compiles. Many Objective-C
-// projects enable the `-Wnullable-to-nonnull-conversion warning`, which is
-// liable to produce false positives.
-#if ABSL_HAVE_FEATURE(nullability_on_classes) && !defined(__OBJC__)
-    = T _Nullable;
-#else
-    = T;
-#endif
-
-template <typename T>
-using NonnullImpl
-#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
-    [[clang::annotate("Nonnull")]]
-#endif
-#if ABSL_HAVE_FEATURE(nullability_on_classes) && !defined(__OBJC__)
-    = T _Nonnull;
-#else
-    = T;
-#endif
-
-template <typename T>
-using NullabilityUnknownImpl
-#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
-    [[clang::annotate("Nullability_Unspecified")]]
-#endif
-#if ABSL_HAVE_FEATURE(nullability_on_classes) && !defined(__OBJC__)
-    = T _Null_unspecified;
-#else
-    = T;
-#endif
-
-}  // namespace nullability_internal
-
-// The following template aliases are deprecated forms of nullability
-// annotations. They have some limitations, for example, an incompatibility with
-// `auto*` pointers, as `auto` cannot be used in a template argument.
-//
-// It is important to note that these annotations are not distinct strong
-// *types*. They are alias templates defined to be equal to the underlying
-// pointer type. A pointer annotated `Nonnull<T*>`, for example, is simply a
-// pointer of type `T*`.
-//
-// Prefer the macro style annotations in `absl/base/nullability.h` instead.
-
-// absl::Nonnull, analogous to absl_nonnull
-//
-// Example:
-// absl::Nonnull<int*> foo;
-// Is equivalent to:
-// int* absl_nonnull foo;
-template <typename T>
-using Nonnull [[deprecated("Use `absl_nonnull`.")]] =
-    nullability_internal::NonnullImpl<T>;
-
-// absl::Nullable, analogous to absl_nullable
-//
-// Example:
-// absl::Nullable<int*> foo;
-// Is equivalent to:
-// int* absl_nullable foo;
-template <typename T>
-using Nullable [[deprecated("Use `absl_nullable`.")]] =
-    nullability_internal::NullableImpl<T>;
-
-// absl::NullabilityUnknown, analogous to absl_nullability_unknown
-//
-// Example:
-// absl::NullabilityUnknown<int*> foo;
-// Is equivalent to:
-// int* absl_nullability_unknown foo;
-template <typename T>
-using NullabilityUnknown [[deprecated("Use `absl_nullability_unknown`.")]] =
-    nullability_internal::NullabilityUnknownImpl<T>;
-
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#endif  // ABSL_BASE_INTERNAL_NULLABILITY_DEPRECATED_H_
diff --git a/absl/base/internal/nullability_traits.h b/absl/base/internal/nullability_traits.h
new file mode 100644
index 0000000..790ec90
--- /dev/null
+++ b/absl/base/internal/nullability_traits.h
@@ -0,0 +1,71 @@
+// Copyright 2025 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.
+
+#ifndef ABSL_BASE_INTERNAL_NULLABILITY_TRAITS_H_
+#define ABSL_BASE_INTERNAL_NULLABILITY_TRAITS_H_
+
+#include <type_traits>
+
+#include "absl/base/config.h"
+#include "absl/base/nullability.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// `value` is true if the type `T` is compatible with nullability annotations
+// (is a raw pointer, a smart pointer, or marked with
+// ABSL_NULLABILITY_COMPATIBLE). Prefer to use the higher-level
+// `AddNonnullIfCompatible` if that is sufficient.
+//
+// NOTE: This should not be used to detect if the compiler is Clang (since
+// Clang is the only compiler that supports nullability annotations).
+#if defined(__clang__) && !defined(__OBJC__) && \
+    ABSL_HAVE_FEATURE(nullability_on_classes)
+template <class T, class = void>
+struct IsNullabilityCompatibleType {
+  constexpr static bool value = false;
+};
+
+template <class T>
+struct IsNullabilityCompatibleType<T, std::void_t<absl_nullable T>> {
+  constexpr static bool value = true;
+};
+#else
+// False when absl_nullable is a no-op (for non-Clang compilers or Objective-C.)
+template <class T, class = void>
+struct IsNullabilityCompatibleType {
+  constexpr static bool value = false;
+};
+#endif
+
+// A trait to add `absl_nonnull` to a type if it is compatible with nullability
+// annotations.
+template <typename T, bool ShouldAdd = IsNullabilityCompatibleType<T>::value>
+struct AddNonnullIfCompatible;
+
+template <typename T>
+struct AddNonnullIfCompatible<T, false> {
+  using type = T;
+};
+template <typename T>
+struct AddNonnullIfCompatible<T, true> {
+  using type = absl_nonnull T;
+};
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_NULLABILITY_TRAITS_H_
diff --git a/absl/base/internal/nullability_traits_test.cc b/absl/base/internal/nullability_traits_test.cc
new file mode 100644
index 0000000..2451239
--- /dev/null
+++ b/absl/base/internal/nullability_traits_test.cc
@@ -0,0 +1,98 @@
+// Copyright 2025 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/nullability_traits.h"
+
+#include <memory>
+#include <type_traits>
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/base/nullability.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+namespace {
+
+struct NotSmartPtr {
+  int* x;
+};
+
+class ABSL_NULLABILITY_COMPATIBLE MySmartPtr : std::unique_ptr<int> {};
+
+// The IsNullabilityCompatibleType trait value can only be true when we define
+// `absl_nullable` (isn't a no-op).
+#if defined(__clang__) && !defined(__OBJC__) && \
+    ABSL_HAVE_FEATURE(nullability_on_classes)
+#define EXPECT_TRUE_IF_SUPPORTED EXPECT_TRUE
+#else
+#define EXPECT_TRUE_IF_SUPPORTED EXPECT_FALSE
+#endif
+
+TEST(NullabilityTraitsTest, IsNullabilityEligibleTypePrimitives) {
+  EXPECT_FALSE(IsNullabilityCompatibleType<int>::value);
+  EXPECT_FALSE(IsNullabilityCompatibleType<int*&>::value);
+
+  EXPECT_TRUE_IF_SUPPORTED(IsNullabilityCompatibleType<int*>::value);
+  EXPECT_TRUE_IF_SUPPORTED(IsNullabilityCompatibleType<int**>::value);
+  EXPECT_TRUE_IF_SUPPORTED(IsNullabilityCompatibleType<int* const>::value);
+  EXPECT_TRUE_IF_SUPPORTED(IsNullabilityCompatibleType<const int*>::value);
+  EXPECT_TRUE_IF_SUPPORTED(IsNullabilityCompatibleType<void (*)(int)>::value);
+}
+
+TEST(NullabilityTraitsTest, IsNullabilityCompatibleTypeAliases) {
+  using MyInt = int;
+  using MyIntPtr = int*;
+  EXPECT_FALSE(IsNullabilityCompatibleType<MyInt>::value);
+  EXPECT_TRUE_IF_SUPPORTED(IsNullabilityCompatibleType<MyIntPtr>::value);
+}
+
+TEST(NullabilityTraitsTest, IsNullabilityCompatibleTypeSmartPointers) {
+  EXPECT_TRUE_IF_SUPPORTED(
+      IsNullabilityCompatibleType<std::unique_ptr<int>>::value);
+  EXPECT_TRUE_IF_SUPPORTED(
+      IsNullabilityCompatibleType<std::shared_ptr<int>>::value);
+
+  EXPECT_FALSE(IsNullabilityCompatibleType<NotSmartPtr>::value);
+  EXPECT_TRUE_IF_SUPPORTED(IsNullabilityCompatibleType<NotSmartPtr*>::value);
+  EXPECT_TRUE_IF_SUPPORTED(IsNullabilityCompatibleType<MySmartPtr>::value);
+}
+
+#undef EXPECT_TRUE_IF_SUPPORTED
+
+TEST(NullabilityTraitsTest, AddNonnullIfCompatiblePassThroughPrimitives) {
+  EXPECT_TRUE((std::is_same_v<AddNonnullIfCompatible<int>::type, int>));
+  EXPECT_TRUE((std::is_same_v<AddNonnullIfCompatible<int*>::type, int*>));
+  EXPECT_TRUE(
+      (std::is_same_v<AddNonnullIfCompatible<int* const>::type, int* const>));
+}
+
+TEST(NullabilityTraitsTest, AddNonnullIfCompatiblePassThroughSmartPointers) {
+  EXPECT_TRUE(
+      (std::is_same_v<AddNonnullIfCompatible<std::unique_ptr<int>>::type,
+                      std::unique_ptr<int>>));
+  EXPECT_TRUE(
+      (std::is_same_v<AddNonnullIfCompatible<std::shared_ptr<int>>::type,
+                      std::shared_ptr<int>>));
+  EXPECT_TRUE(
+      (std::is_same_v<AddNonnullIfCompatible<NotSmartPtr>::type, NotSmartPtr>));
+  EXPECT_TRUE(
+      (std::is_same_v<AddNonnullIfCompatible<MySmartPtr>::type, MySmartPtr>));
+}
+
+}  // namespace
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/base/internal/poison.cc b/absl/base/internal/poison.cc
index b33d4c2..c639c96 100644
--- a/absl/base/internal/poison.cc
+++ b/absl/base/internal/poison.cc
@@ -57,19 +57,20 @@
 
 void* InitializePoisonedPointerInternal() {
   const size_t block_size = GetPageSize();
+  void* data = nullptr;
 #if defined(ABSL_HAVE_ADDRESS_SANITIZER)
-  void* data = malloc(block_size);
+  data = malloc(block_size);
   ASAN_POISON_MEMORY_REGION(data, block_size);
 #elif defined(ABSL_HAVE_MEMORY_SANITIZER)
-  void* data = malloc(block_size);
+  data = malloc(block_size);
   __msan_poison(data, block_size);
 #elif defined(ABSL_HAVE_MMAP)
-  void* data = DirectMmap(nullptr, block_size, PROT_NONE,
-                          MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  data = DirectMmap(nullptr, block_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
+                    -1, 0);
   if (data == MAP_FAILED) return GetBadPointerInternal();
 #elif defined(_WIN32)
-  void* data = VirtualAlloc(nullptr, block_size, MEM_RESERVE | MEM_COMMIT,
-                            PAGE_NOACCESS);
+  data = VirtualAlloc(nullptr, block_size, MEM_RESERVE | MEM_COMMIT,
+                      PAGE_NOACCESS);
   if (data == nullptr) return GetBadPointerInternal();
 #else
   return GetBadPointerInternal();
diff --git a/absl/base/internal/raw_logging.cc b/absl/base/internal/raw_logging.cc
index 35a08f0..8537f3e 100644
--- a/absl/base/internal/raw_logging.cc
+++ b/absl/base/internal/raw_logging.cc
@@ -41,9 +41,8 @@
 //
 // This preprocessor token is also defined in raw_io.cc.  If you need to copy
 // this, consider moving both to config.h instead.
-#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
-    defined(__hexagon__) || defined(__Fuchsia__) ||                     \
-    defined(__native_client__) || defined(__OpenBSD__) ||               \
+#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) ||     \
+    defined(__hexagon__) || defined(__Fuchsia__) || defined(__OpenBSD__) || \
     defined(__EMSCRIPTEN__) || defined(__ASYLO__)
 
 #include <unistd.h>
@@ -158,7 +157,7 @@
 #endif
 
 #ifdef ABSL_MIN_LOG_LEVEL
-  if (severity < static_cast<absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) &&
+  if (severity < static_cast<absl::LogSeverityAtLeast>(ABSL_MIN_LOG_LEVEL) &&
       severity < absl::LogSeverity::kFatal) {
     enabled = false;
   }
diff --git a/absl/base/internal/spinlock.cc b/absl/base/internal/spinlock.cc
index 430f775..41d2b48 100644
--- a/absl/base/internal/spinlock.cc
+++ b/absl/base/internal/spinlock.cc
@@ -16,15 +16,18 @@
 
 #include <algorithm>
 #include <atomic>
+#include <cstdint>
 #include <limits>
 
 #include "absl/base/attributes.h"
+#include "absl/base/call_once.h"
 #include "absl/base/config.h"
 #include "absl/base/internal/atomic_hook.h"
 #include "absl/base/internal/cycleclock.h"
+#include "absl/base/internal/scheduling_mode.h"
 #include "absl/base/internal/spinlock_wait.h"
 #include "absl/base/internal/sysinfo.h" /* For NumCPUs() */
-#include "absl/base/call_once.h"
+#include "absl/base/internal/tsan_mutex_interface.h"
 
 // Description of lock-word:
 //  31..00: [............................3][2][1][0]
@@ -58,7 +61,7 @@
 ABSL_NAMESPACE_BEGIN
 namespace base_internal {
 
-ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static base_internal::AtomicHook<void (*)(
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static AtomicHook<void (*)(
     const void *lock, int64_t wait_cycles)>
     submit_profile_data;
 
@@ -67,25 +70,24 @@
   submit_profile_data.Store(fn);
 }
 
-// Uncommon constructors.
-SpinLock::SpinLock(base_internal::SchedulingMode mode)
-    : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {
-  ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
-}
-
 // Monitor the lock to see if its value changes within some time period
-// (adaptive_spin_count loop iterations). The last value read from the lock
+// (adaptive_spin_count_ loop iterations). The last value read from the lock
 // is returned from the method.
+ABSL_CONST_INIT std::atomic<int> SpinLock::adaptive_spin_count_{0};
 uint32_t SpinLock::SpinLoop() {
   // We are already in the slow path of SpinLock, initialize the
   // adaptive_spin_count here.
-  ABSL_CONST_INIT static absl::once_flag init_adaptive_spin_count;
-  ABSL_CONST_INIT static int adaptive_spin_count = 0;
-  base_internal::LowLevelCallOnce(&init_adaptive_spin_count, []() {
-    adaptive_spin_count = base_internal::NumCPUs() > 1 ? 1000 : 1;
-  });
-
-  int c = adaptive_spin_count;
+  if (adaptive_spin_count_.load(std::memory_order_relaxed) == 0) {
+    int current_spin_count = 0;
+    int new_spin_count = NumCPUs() > 1 ? 1000 : 1;
+    // If this fails, the value will remain unchanged. We may not spin for the
+    // intended duration, but that is still safe. We will try again on the next
+    // call to SpinLoop.
+    adaptive_spin_count_.compare_exchange_weak(
+        current_spin_count, new_spin_count, std::memory_order_relaxed,
+        std::memory_order_relaxed);
+  }
+  int c = adaptive_spin_count_.load(std::memory_order_relaxed);
   uint32_t lock_value;
   do {
     lock_value = lockword_.load(std::memory_order_relaxed);
@@ -100,11 +102,11 @@
     return;
   }
 
-  base_internal::SchedulingMode scheduling_mode;
+  SchedulingMode scheduling_mode;
   if ((lock_value & kSpinLockCooperative) != 0) {
-    scheduling_mode = base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
+    scheduling_mode = SCHEDULE_COOPERATIVE_AND_KERNEL;
   } else {
-    scheduling_mode = base_internal::SCHEDULE_KERNEL_ONLY;
+    scheduling_mode = SCHEDULE_KERNEL_ONLY;
   }
 
   // The lock was not obtained initially, so this thread needs to wait for
@@ -134,7 +136,7 @@
         // new lock state will be the number of cycles this thread waited if
         // this thread obtains the lock.
         lock_value = TryLockInternal(lock_value, wait_cycles);
-        continue;   // Skip the delay at the end of the loop.
+        continue;  // Skip the delay at the end of the loop.
       } else if ((lock_value & kWaitTimeMask) == 0) {
         // The lock is still held, without a waiter being marked, but something
         // else about the lock word changed, causing our CAS to fail. For
@@ -150,8 +152,8 @@
     // synchronization there to avoid false positives.
     ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
     // Wait for an OS specific delay.
-    base_internal::SpinLockDelay(&lockword_, lock_value, ++lock_wait_call_count,
-                                 scheduling_mode);
+    SpinLockDelay(&lockword_, lock_value, ++lock_wait_call_count,
+                  scheduling_mode);
     ABSL_TSAN_MUTEX_POST_DIVERT(this, 0);
     // Spin again after returning from the wait routine to give this thread
     // some chance of obtaining the lock.
@@ -162,8 +164,8 @@
 }
 
 void SpinLock::SlowUnlock(uint32_t lock_value) {
-  base_internal::SpinLockWake(&lockword_,
-                              false);  // wake waiter if necessary
+  SpinLockWake(&lockword_,
+               false);  // wake waiter if necessary
 
   // If our acquisition was contended, collect contentionz profile info.  We
   // reserve a unitary wait time to represent that a waiter exists without our
diff --git a/absl/base/internal/spinlock.h b/absl/base/internal/spinlock.h
index 2a10896..d535093 100644
--- a/absl/base/internal/spinlock.h
+++ b/absl/base/internal/spinlock.h
@@ -19,7 +19,7 @@
 //   - for use by Abseil internal code that Mutex itself depends on
 //   - for async signal safety (see below)
 
-// SpinLock with a base_internal::SchedulingMode::SCHEDULE_KERNEL_ONLY is async
+// SpinLock with a SchedulingMode::SCHEDULE_KERNEL_ONLY is async
 // signal safe. If a spinlock is used within a signal handler, all code that
 // acquires the lock must ensure that the signal cannot arrive while they are
 // holding the lock. Typically, this is done by blocking the signal.
@@ -31,20 +31,24 @@
 
 #include <atomic>
 #include <cstdint>
+#include <mutex>
+#include <type_traits>
 
 #include "absl/base/attributes.h"
+#include "absl/base/config.h"
 #include "absl/base/const_init.h"
-#include "absl/base/dynamic_annotations.h"
 #include "absl/base/internal/low_level_scheduling.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/internal/scheduling_mode.h"
 #include "absl/base/internal/tsan_mutex_interface.h"
+#include "absl/base/macros.h"
 #include "absl/base/thread_annotations.h"
 
 namespace tcmalloc {
 namespace tcmalloc_internal {
 
 class AllocationGuardSpinLockHolder;
+class Static;
 
 }  // namespace tcmalloc_internal
 }  // namespace tcmalloc
@@ -55,17 +59,31 @@
 
 class ABSL_LOCKABLE ABSL_ATTRIBUTE_WARN_UNUSED SpinLock {
  public:
-  SpinLock() : lockword_(kSpinLockCooperative) {
-    ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
-  }
+  constexpr SpinLock() : lockword_(kSpinLockCooperative) { RegisterWithTsan(); }
 
   // Constructors that allow non-cooperative spinlocks to be created for use
   // inside thread schedulers.  Normal clients should not use these.
-  explicit SpinLock(base_internal::SchedulingMode mode);
+  constexpr explicit SpinLock(SchedulingMode mode)
+      : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {
+    RegisterWithTsan();
+  }
+
+#if ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(_WIN32)
+  // Constructor to inline users of the default scheduling mode.
+  //
+  // This only needs to exists for inliner runs, but doesn't work correctly in
+  // clang+windows builds, likely due to mangling differences.
+  ABSL_DEPRECATE_AND_INLINE()
+  constexpr explicit SpinLock(SchedulingMode mode)
+      __attribute__((enable_if(mode == SCHEDULE_COOPERATIVE_AND_KERNEL,
+                               "Cooperative use default constructor")))
+      : SpinLock() {}
+#endif
 
   // Constructor for global SpinLock instances.  See absl/base/const_init.h.
-  constexpr SpinLock(absl::ConstInitType, base_internal::SchedulingMode mode)
-      : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {}
+  ABSL_DEPRECATE_AND_INLINE()
+  constexpr SpinLock(absl::ConstInitType, SchedulingMode mode)
+      : SpinLock(mode) {}
 
   // For global SpinLock instances prefer trivial destructor when possible.
   // Default but non-trivial destructor in some build configurations causes an
@@ -77,7 +95,7 @@
 #endif
 
   // Acquire this SpinLock.
-  inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
+  inline void lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
     ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
     if (!TryLockImpl()) {
       SlowLock();
@@ -85,11 +103,14 @@
     ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
   }
 
+  ABSL_DEPRECATE_AND_INLINE()
+  inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { return lock(); }
+
   // Try to acquire this SpinLock without blocking and return true if the
   // acquisition was successful.  If the lock was not acquired, false is
-  // returned.  If this SpinLock is free at the time of the call, TryLock
-  // will return true with high probability.
-  [[nodiscard]] inline bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+  // returned.  If this SpinLock is free at the time of the call, try_lock will
+  // return true with high probability.
+  [[nodiscard]] inline bool try_lock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
     ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
     bool res = TryLockImpl();
     ABSL_TSAN_MUTEX_POST_LOCK(
@@ -98,15 +119,20 @@
     return res;
   }
 
+  ABSL_DEPRECATE_AND_INLINE()
+  [[nodiscard]] inline bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+    return try_lock();
+  }
+
   // Release this SpinLock, which must be held by the calling thread.
-  inline void Unlock() ABSL_UNLOCK_FUNCTION() {
+  inline void unlock() ABSL_UNLOCK_FUNCTION() {
     ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0);
     uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
     lock_value = lockword_.exchange(lock_value & kSpinLockCooperative,
                                     std::memory_order_release);
 
     if ((lock_value & kSpinLockDisabledScheduling) != 0) {
-      base_internal::SchedulingGuard::EnableRescheduling(true);
+      SchedulingGuard::EnableRescheduling(true);
     }
     if ((lock_value & kWaitTimeMask) != 0) {
       // Collect contentionz profile info, and speed the wakeup of any waiter.
@@ -117,6 +143,9 @@
     ABSL_TSAN_MUTEX_POST_UNLOCK(this, 0);
   }
 
+  ABSL_DEPRECATE_AND_INLINE()
+  inline void Unlock() ABSL_UNLOCK_FUNCTION() { unlock(); }
+
   // Determine if the lock is held.  When the lock is held by the invoking
   // thread, true will always be returned. Intended to be used as
   // CHECK(lock.IsHeld()).
@@ -146,6 +175,16 @@
   // Provide access to protected method above.  Use for testing only.
   friend struct SpinLockTest;
   friend class tcmalloc::tcmalloc_internal::AllocationGuardSpinLockHolder;
+  friend class tcmalloc::tcmalloc_internal::Static;
+
+  static int GetAdaptiveSpinCount() {
+    return adaptive_spin_count_.load(std::memory_order_relaxed);
+  }
+  static void SetAdaptiveSpinCount(int count) {
+    adaptive_spin_count_.store(count, std::memory_order_relaxed);
+  }
+
+  static std::atomic<int> adaptive_spin_count_;
 
  private:
   // lockword_ is used to store the following:
@@ -175,9 +214,16 @@
       ~(kSpinLockHeld | kSpinLockCooperative | kSpinLockDisabledScheduling);
 
   // Returns true if the provided scheduling mode is cooperative.
-  static constexpr bool IsCooperative(
-      base_internal::SchedulingMode scheduling_mode) {
-    return scheduling_mode == base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
+  static constexpr bool IsCooperative(SchedulingMode scheduling_mode) {
+    return scheduling_mode == SCHEDULE_COOPERATIVE_AND_KERNEL;
+  }
+
+  constexpr void RegisterWithTsan() {
+#if ABSL_HAVE_BUILTIN(__builtin_is_constant_evaluated)
+    if (!__builtin_is_constant_evaluated()) {
+      ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
+    }
+#endif
   }
 
   bool IsCooperative() const {
@@ -202,19 +248,18 @@
 
 // Corresponding locker object that arranges to acquire a spinlock for
 // the duration of a C++ scope.
-class ABSL_SCOPED_LOCKABLE [[nodiscard]] SpinLockHolder {
+class ABSL_SCOPED_LOCKABLE [[nodiscard]] SpinLockHolder
+    : public std::lock_guard<SpinLock> {
  public:
+  inline explicit SpinLockHolder(
+      SpinLock& l ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(l)
+      : std::lock_guard<SpinLock>(l) {}
+  ABSL_DEPRECATE_AND_INLINE()
   inline explicit SpinLockHolder(SpinLock* l) ABSL_EXCLUSIVE_LOCK_FUNCTION(l)
-      : lock_(l) {
-    l->Lock();
-  }
-  inline ~SpinLockHolder() ABSL_UNLOCK_FUNCTION() { lock_->Unlock(); }
+      : SpinLockHolder(*l) {}
 
-  SpinLockHolder(const SpinLockHolder&) = delete;
-  SpinLockHolder& operator=(const SpinLockHolder&) = delete;
-
- private:
-  SpinLock* lock_;
+  inline ~SpinLockHolder() ABSL_UNLOCK_FUNCTION() = default;
 };
 
 // Register a hook for profiling support.
@@ -243,7 +288,7 @@
   if ((lock_value & kSpinLockCooperative) == 0) {
     // For non-cooperative locks we must make sure we mark ourselves as
     // non-reschedulable before we attempt to CompareAndSwap.
-    if (base_internal::SchedulingGuard::DisableRescheduling()) {
+    if (SchedulingGuard::DisableRescheduling()) {
       sched_disabled_bit = kSpinLockDisabledScheduling;
     }
   }
@@ -252,7 +297,7 @@
           lock_value,
           kSpinLockHeld | lock_value | wait_cycles | sched_disabled_bit,
           std::memory_order_acquire, std::memory_order_relaxed)) {
-    base_internal::SchedulingGuard::EnableRescheduling(sched_disabled_bit != 0);
+    SchedulingGuard::EnableRescheduling(sched_disabled_bit != 0);
   }
 
   return lock_value;
diff --git a/absl/base/internal/spinlock_benchmark.cc b/absl/base/internal/spinlock_benchmark.cc
index 1790d96..c79f49f 100644
--- a/absl/base/internal/spinlock_benchmark.cc
+++ b/absl/base/internal/spinlock_benchmark.cc
@@ -35,7 +35,7 @@
   static absl::NoDestructor<absl::base_internal::SpinLock> spinlock(
       scheduling_mode);
   for (auto _ : state) {
-    if (spinlock->TryLock()) spinlock->Unlock();
+    if (spinlock->try_lock()) spinlock->unlock();
   }
 }
 
@@ -50,7 +50,7 @@
   static absl::NoDestructor<absl::base_internal::SpinLock> spinlock(
       scheduling_mode);
   for (auto _ : state) {
-    absl::base_internal::SpinLockHolder holder(spinlock.get());
+    absl::base_internal::SpinLockHolder holder(*spinlock.get());
   }
 }
 
diff --git a/absl/base/internal/strerror_test.cc b/absl/base/internal/strerror_test.cc
index e32d5b5..d12c537 100644
--- a/absl/base/internal/strerror_test.cc
+++ b/absl/base/internal/strerror_test.cc
@@ -39,7 +39,8 @@
 TEST(StrErrorTest, InvalidErrorCode) {
   errno = ERANGE;
   EXPECT_THAT(absl::base_internal::StrError(-1),
-              AnyOf(Eq("No error information"), Eq("Unknown error -1")));
+              AnyOf(Eq("No error information"), Eq("Unknown error -1"),
+                    Eq("Unknown error")));
   EXPECT_THAT(errno, Eq(ERANGE));
 }
 
diff --git a/absl/base/internal/sysinfo.cc b/absl/base/internal/sysinfo.cc
index 1937db3..a62dd31 100644
--- a/absl/base/internal/sysinfo.cc
+++ b/absl/base/internal/sysinfo.cc
@@ -456,15 +456,6 @@
 
 pid_t GetTID() { return static_cast<pid_t>(_lwp_self()); }
 
-#elif defined(__native_client__)
-
-pid_t GetTID() {
-  auto* thread = pthread_self();
-  static_assert(sizeof(pid_t) == sizeof(thread),
-                "In NaCL int expected to be the same size as a pointer");
-  return reinterpret_cast<pid_t>(thread);
-}
-
 #elif defined(__Fuchsia__)
 
 pid_t GetTID() {
diff --git a/absl/base/internal/sysinfo_test.cc b/absl/base/internal/sysinfo_test.cc
index c2b59aa..b4c75f5 100644
--- a/absl/base/internal/sysinfo_test.cc
+++ b/absl/base/internal/sysinfo_test.cc
@@ -39,12 +39,6 @@
 
 TEST(SysinfoTest, GetTID) {
   EXPECT_EQ(GetTID(), GetTID());  // Basic compile and equality test.
-#ifdef __native_client__
-  // Native Client has a race condition bug that leads to memory
-  // exhaustion when repeatedly creating and joining threads.
-  // https://bugs.chromium.org/p/nativeclient/issues/detail?id=1027
-  return;
-#endif
   // Test that TIDs are unique to each thread.
   // Uses a few loops to exercise implementations that reallocate IDs.
   for (int i = 0; i < 10; ++i) {
@@ -59,7 +53,7 @@
       threads.push_back(std::thread([&]() {
         pid_t id = GetTID();
         {
-          MutexLock lock(&mutex);
+          MutexLock lock(mutex);
           ASSERT_TRUE(tids.find(id) == tids.end());
           tids.insert(id);
         }
diff --git a/absl/base/internal/thread_identity_test.cc b/absl/base/internal/thread_identity_test.cc
index 5f17553..3ef2ffe 100644
--- a/absl/base/internal/thread_identity_test.cc
+++ b/absl/base/internal/thread_identity_test.cc
@@ -31,7 +31,7 @@
 namespace {
 
 ABSL_CONST_INIT static absl::base_internal::SpinLock map_lock(
-    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+    base_internal::SCHEDULE_KERNEL_ONLY);
 ABSL_CONST_INIT static int num_identities_reused ABSL_GUARDED_BY(map_lock);
 
 static const void* const kCheckNoIdentity = reinterpret_cast<void*>(1);
@@ -58,7 +58,7 @@
                    PerThreadSynch::kAlignment);
   EXPECT_EQ(identity, identity->per_thread_synch.thread_identity());
 
-  absl::base_internal::SpinLockHolder l(&map_lock);
+  absl::base_internal::SpinLockHolder l(map_lock);
   num_identities_reused++;
 }
 
@@ -90,7 +90,7 @@
   // We should have recycled ThreadIdentity objects above; while (external)
   // library threads allocating their own identities may preclude some
   // reuse, we should have sufficient repetitions to exclude this.
-  absl::base_internal::SpinLockHolder l(&map_lock);
+  absl::base_internal::SpinLockHolder l(map_lock);
   EXPECT_LT(kNumThreads, num_identities_reused);
 }
 
@@ -112,7 +112,7 @@
       threads.push_back(std::thread([&]() {
         for (int l = 0; l < kNumLockLoops; ++l) {
           for (int m = 0; m < kNumMutexes; ++m) {
-            MutexLock lock(&mutexes[m]);
+            MutexLock lock(mutexes[m]);
           }
         }
       }));
diff --git a/absl/base/internal/unscaledcycleclock.cc b/absl/base/internal/unscaledcycleclock.cc
index 68f9273..73e4145 100644
--- a/absl/base/internal/unscaledcycleclock.cc
+++ b/absl/base/internal/unscaledcycleclock.cc
@@ -62,7 +62,7 @@
 
 int64_t UnscaledCycleClock::Now() {
 #ifdef __GLIBC__
-  return __ppc_get_timebase();
+  return static_cast<int64_t>(__ppc_get_timebase());
 #else
 #ifdef __powerpc64__
   int64_t tbr;
@@ -85,6 +85,10 @@
 double UnscaledCycleClock::Frequency() {
 #ifdef __GLIBC__
   return __ppc_get_timebase_freq();
+#elif defined(__linux__)
+  // Fallback for musl + ppc64le: use constant timebase frequency (512 MHz)
+  // Must come after __GLIBC__.
+  return static_cast<double>(512000000);
 #elif defined(_AIX)
   // This is the same constant value as returned by
   // __ppc_get_timebase_freq().
diff --git a/absl/base/internal/unscaledcycleclock_config.h b/absl/base/internal/unscaledcycleclock_config.h
index 43a3dab..9a0841d 100644
--- a/absl/base/internal/unscaledcycleclock_config.h
+++ b/absl/base/internal/unscaledcycleclock_config.h
@@ -34,7 +34,7 @@
 // CycleClock that runs at atleast 1 MHz. We've found some Android
 // ARM64 devices where this is not the case, so we disable it by
 // default on Android ARM64.
-#if defined(__native_client__) || (defined(__APPLE__)) || \
+#if defined(__APPLE__) || \
     (defined(__ANDROID__) && defined(__aarch64__))
 #define ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT 0
 #else
diff --git a/absl/base/macros.h b/absl/base/macros.h
index ff89944..446a445 100644
--- a/absl/base/macros.h
+++ b/absl/base/macros.h
@@ -169,42 +169,65 @@
 #define ABSL_INTERNAL_RETHROW do {} while (false)
 #endif  // ABSL_HAVE_EXCEPTIONS
 
-// ABSL_DEPRECATE_AND_INLINE()
+// ABSL_REFACTOR_INLINE
 //
-// Marks a function or type alias as deprecated and tags it to be picked up for
-// automated refactoring by go/cpp-inliner. It can added to inline function
-// definitions or type aliases. It should only be used within a header file. It
-// differs from `ABSL_DEPRECATED` in the following ways:
+// Marks a function or type for automated refactoring by go/cpp-inliner. It can
+// be used on inline function definitions or type aliases in header files and
+// should be combined with the `[[deprecated]]` attribute.
+//
+// Using `ABSL_REFACTOR_INLINE` differs from using the `[[deprecated]]` alone in
+// the following ways:
 //
 // 1. New uses of the function or type will be discouraged via Tricorder
 //    warnings.
 // 2. If enabled via `METADATA`, automated changes will be sent out inlining the
 //    functions's body or replacing the type where it is used.
 //
-// For example:
+// Examples:
 //
-// ABSL_DEPRECATE_AND_INLINE() inline int OldFunc(int x) {
+// [[deprecated("Use NewFunc() instead")]] ABSL_REFACTOR_INLINE
+// inline int OldFunc(int x) {
 //   return NewFunc(x, 0);
 // }
 //
-// will mark `OldFunc` as deprecated, and the go/cpp-inliner service will
-// replace calls to `OldFunc(x)` with calls to `NewFunc(x, 0)`. Once all calls
-// to `OldFunc` have been replaced, `OldFunc` can be deleted.
+// using OldType [[deprecated("Use NewType instead")]] ABSL_REFACTOR_INLINE =
+//     NewType;
+//
+// will mark `OldFunc` and `OldType` as deprecated, and the go/cpp-inliner
+// service will replace calls to `OldFunc(x)` with calls to `NewFunc(x, 0)` and
+// `OldType` with `NewType`. Once all replacements have been completed, the old
+// function or type can be deleted.
 //
 // See go/cpp-inliner for more information.
 //
 // Note: go/cpp-inliner is Google-internal service for automated refactoring.
 // While open-source users do not have access to this service, the macro is
-// provided for compatibility, and so that users receive deprecation warnings.
-#if ABSL_HAVE_CPP_ATTRIBUTE(deprecated) && \
-    ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
-#define ABSL_DEPRECATE_AND_INLINE() [[deprecated, clang::annotate("inline-me")]]
-#elif ABSL_HAVE_CPP_ATTRIBUTE(deprecated)
-#define ABSL_DEPRECATE_AND_INLINE() [[deprecated]]
+// provided for compatibility.
+#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
+#define ABSL_REFACTOR_INLINE [[clang::annotate("inline-me")]]
 #else
-#define ABSL_DEPRECATE_AND_INLINE()
+#define ABSL_REFACTOR_INLINE
 #endif
 
+// ABSL_DEPRECATE_AND_INLINE()
+//
+// This is the original macro used by go/cpp-inliner that combines
+// [[deprecated]] and ABSL_REFACTOR_INLINE.
+//
+// Examples:
+//
+// ABSL_DEPRECATE_AND_INLINE() inline int OldFunc(int x) {
+//   return NewFunc(x, 0);
+// }
+//
+// using OldType ABSL_DEPRECATE_AND_INLINE() = NewType;
+//
+// The combination of `[[deprecated("Use X instead")]]` and
+// `ABSL_REFACTOR_INLINE` is preferred because it provides a more informative
+// deprecation message to developers, especially those that do not have access
+// to the automated refactoring capabilities of go/cpp-inliner.
+#define ABSL_DEPRECATE_AND_INLINE() [[deprecated]] ABSL_REFACTOR_INLINE
+
 // Requires the compiler to prove that the size of the given object is at least
 // the expected amount.
 #if ABSL_HAVE_ATTRIBUTE(diagnose_if) && ABSL_HAVE_BUILTIN(__builtin_object_size)
diff --git a/absl/base/nullability.h b/absl/base/nullability.h
index 3a5d6e8..facc642 100644
--- a/absl/base/nullability.h
+++ b/absl/base/nullability.h
@@ -81,7 +81,7 @@
 // const Employee* absl_nonnull e;
 //
 // // A non-null pointer to a const nullable pointer to an `Employee`.
-// Employee* absl_nullable const* absl_nonnull e = nullptr;
+// Employee* absl_nullable const* absl_nonnull e;
 //
 // // A non-null function pointer.
 // void (*absl_nonnull func)(int, double);
@@ -184,7 +184,6 @@
 #define ABSL_BASE_NULLABILITY_H_
 
 #include "absl/base/config.h"
-#include "absl/base/internal/nullability_deprecated.h"
 
 // ABSL_POINTERS_DEFAULT_NONNULL
 //
diff --git a/absl/base/nullability_test.cc b/absl/base/nullability_test.cc
index bccc388..bccf1af 100644
--- a/absl/base/nullability_test.cc
+++ b/absl/base/nullability_test.cc
@@ -14,16 +14,13 @@
 
 #include "absl/base/nullability.h"
 
-#include <cassert>
 #include <memory>
 #include <type_traits>
 #include <utility>
 
 #include "gtest/gtest.h"
-#include "absl/base/attributes.h"
 
 namespace {
-namespace macro_annotations {
 void funcWithNonnullArg(int* absl_nonnull /*arg*/) {}
 template <typename T>
 void funcWithDeducedNonnullArg(T* absl_nonnull /*arg*/) {}
@@ -90,117 +87,4 @@
   EXPECT_TRUE((std::is_same<absl_nullable T, T>::value));
   EXPECT_TRUE((std::is_same<absl_nullability_unknown T, T>::value));
 }
-}  // namespace macro_annotations
-
-// Allow testing of the deprecated type alias annotations.
-ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
-
-using ::absl::Nonnull;
-using ::absl::NullabilityUnknown;
-using ::absl::Nullable;
-namespace type_alias_annotations {
-
-void funcWithNonnullArg(Nonnull<int*> /*arg*/) {}
-template <typename T>
-void funcWithDeducedNonnullArg(Nonnull<T*> /*arg*/) {}
-
-TEST(NonnullTest, NonnullArgument) {
-  int var = 0;
-  funcWithNonnullArg(&var);
-  funcWithDeducedNonnullArg(&var);
-}
-
-Nonnull<int*> funcWithNonnullReturn() {
-  static int var = 0;
-  return &var;
-}
-
-TEST(NonnullTest, NonnullReturn) {
-  auto var = funcWithNonnullReturn();
-  (void)var;
-}
-
-TEST(PassThroughTest, PassesThroughRawPointerToInt) {
-  EXPECT_TRUE((std::is_same<Nonnull<int*>, int*>::value));
-  EXPECT_TRUE((std::is_same<Nullable<int*>, int*>::value));
-  EXPECT_TRUE((std::is_same<NullabilityUnknown<int*>, int*>::value));
-}
-
-TEST(PassThroughTest, PassesThroughRawPointerToVoid) {
-  EXPECT_TRUE((std::is_same<Nonnull<void*>, void*>::value));
-  EXPECT_TRUE((std::is_same<Nullable<void*>, void*>::value));
-  EXPECT_TRUE((std::is_same<NullabilityUnknown<void*>, void*>::value));
-}
-
-TEST(PassThroughTest, PassesThroughUniquePointerToInt) {
-  using T = std::unique_ptr<int>;
-  EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
-  EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
-  EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
-}
-
-TEST(PassThroughTest, PassesThroughSharedPointerToInt) {
-  using T = std::shared_ptr<int>;
-  EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
-  EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
-  EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
-}
-
-TEST(PassThroughTest, PassesThroughSharedPointerToVoid) {
-  using T = std::shared_ptr<void>;
-  EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
-  EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
-  EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
-}
-
-TEST(PassThroughTest, PassesThroughPointerToMemberObject) {
-  using T = decltype(&std::pair<int, int>::first);
-  EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
-  EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
-  EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
-}
-
-TEST(PassThroughTest, PassesThroughPointerToMemberFunction) {
-  using T = decltype(&std::unique_ptr<int>::reset);
-  EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
-  EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
-  EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
-}
-
-}  // namespace type_alias_annotations
-}  // namespace
-
-// Nullable ADL lookup test
-namespace util {
-// Helper for NullableAdlTest.  Returns true, denoting that argument-dependent
-// lookup found this implementation of DidAdlWin.  Must be in namespace
-// util itself, not a nested anonymous namespace.
-template <typename T>
-bool DidAdlWin(T*) {
-  return true;
-}
-
-// Because this type is defined in namespace util, an unqualified call to
-// DidAdlWin with a pointer to MakeAdlWin will find the above implementation.
-struct MakeAdlWin {};
-}  // namespace util
-
-namespace {
-// Returns false, denoting that ADL did not inspect namespace util.  If it
-// had, the better match (T*) above would have won out over the (...) here.
-bool DidAdlWin(...) { return false; }
-
-TEST(NullableAdlTest, NullableAddsNothingToArgumentDependentLookup) {
-  // Treatment: util::Nullable<int*> contributes nothing to ADL because
-  // int* itself doesn't.
-  EXPECT_FALSE(DidAdlWin((int*)nullptr));
-  EXPECT_FALSE(DidAdlWin((Nullable<int*>)nullptr));
-
-  // Control: Argument-dependent lookup does find the implementation in
-  // namespace util when the underlying pointee type resides there.
-  EXPECT_TRUE(DidAdlWin((util::MakeAdlWin*)nullptr));
-  EXPECT_TRUE(DidAdlWin((Nullable<util::MakeAdlWin*>)nullptr));
-}
-
-ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
 }  // namespace
diff --git a/absl/base/optimization.h b/absl/base/optimization.h
index 429ea9c..04678c4 100644
--- a/absl/base/optimization.h
+++ b/absl/base/optimization.h
@@ -53,9 +53,7 @@
 //     ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
 //     return result;
 //   }
-#if defined(__pnacl__)
-#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
-#elif defined(__clang__)
+#if defined(__clang__)
 // Clang will not tail call given inline volatile assembly.
 #define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
 #elif defined(__GNUC__)
diff --git a/absl/base/options.h b/absl/base/options.h
index cba75b9..4067d6a 100644
--- a/absl/base/options.h
+++ b/absl/base/options.h
@@ -73,32 +73,6 @@
 // Type Compatibility Options
 // -----------------------------------------------------------------------------
 
-// ABSL_OPTION_USE_STD_STRING_VIEW
-//
-// This option controls whether absl::string_view is implemented as an alias to
-// std::string_view, or as an independent implementation.
-//
-// A value of 0 means to use Abseil's implementation.  This requires only C++11
-// support, and is expected to work on every toolchain we support.
-//
-// A value of 1 means to use an alias to std::string_view.  This requires that
-// all code using Abseil is built in C++17 mode or later.
-//
-// A value of 2 means to detect the C++ version being used to compile Abseil,
-// and use an alias only if a working std::string_view is available.  This
-// option is useful when you are building your program from source.  It should
-// not be used otherwise -- for example, if you are distributing Abseil in a
-// binary package manager -- since in mode 2, absl::string_view will name a
-// different type, with a different mangled name and binary layout, depending on
-// the compiler flags passed by the end user.  For more info, see
-// https://abseil.io/about/design/dropin-types.
-//
-// User code should not inspect this macro.  To check in the preprocessor if
-// absl::string_view is a typedef of std::string_view, use the feature macro
-// ABSL_USES_STD_STRING_VIEW.
-
-#define ABSL_OPTION_USE_STD_STRING_VIEW 1
-
 // ABSL_OPTION_USE_STD_ORDERING
 //
 // This option controls whether absl::{partial,weak,strong}_ordering are
@@ -150,9 +124,9 @@
 
 #define ABSL_OPTION_USE_INLINE_NAMESPACE 1
 #ifdef ANDROID_DISABLE_TLS_FOR_LINKER
-#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_20250512_notls
+#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_20260107_notls
 #else
-#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_20250512
+#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_20260107
 #endif
 
 // ABSL_OPTION_HARDENED
diff --git a/absl/base/spinlock_test_common.cc b/absl/base/spinlock_test_common.cc
index e904715..6ac2e36 100644
--- a/absl/base/spinlock_test_common.cc
+++ b/absl/base/spinlock_test_common.cc
@@ -18,6 +18,7 @@
 
 #include <cstdint>
 #include <limits>
+#include <mutex>  // NOLINT(build/c++11)
 #include <random>
 #include <thread>  // NOLINT(build/c++11)
 #include <type_traits>
@@ -60,30 +61,47 @@
 static constexpr size_t kArrayLength = 10;
 static uint32_t values[kArrayLength];
 
-ABSL_CONST_INIT static SpinLock static_cooperative_spinlock(
-    absl::kConstInit, base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL);
+ABSL_CONST_INIT static SpinLock static_cooperative_spinlock;
 ABSL_CONST_INIT static SpinLock static_noncooperative_spinlock(
-    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+    base_internal::SCHEDULE_KERNEL_ONLY);
 
 // Simple integer hash function based on the public domain lookup2 hash.
 // http://burtleburtle.net/bob/c/lookup2.c
 static uint32_t Hash32(uint32_t a, uint32_t c) {
   uint32_t b = 0x9e3779b9UL;  // The golden ratio; an arbitrary value.
-  a -= b; a -= c; a ^= (c >> 13);
-  b -= c; b -= a; b ^= (a << 8);
-  c -= a; c -= b; c ^= (b >> 13);
-  a -= b; a -= c; a ^= (c >> 12);
-  b -= c; b -= a; b ^= (a << 16);
-  c -= a; c -= b; c ^= (b >> 5);
-  a -= b; a -= c; a ^= (c >> 3);
-  b -= c; b -= a; b ^= (a << 10);
-  c -= a; c -= b; c ^= (b >> 15);
+  a -= b;
+  a -= c;
+  a ^= (c >> 13);
+  b -= c;
+  b -= a;
+  b ^= (a << 8);
+  c -= a;
+  c -= b;
+  c ^= (b >> 13);
+  a -= b;
+  a -= c;
+  a ^= (c >> 12);
+  b -= c;
+  b -= a;
+  b ^= (a << 16);
+  c -= a;
+  c -= b;
+  c ^= (b >> 5);
+  a -= b;
+  a -= c;
+  a ^= (c >> 3);
+  b -= c;
+  b -= a;
+  b ^= (a << 10);
+  c -= a;
+  c -= b;
+  c ^= (b >> 15);
   return c;
 }
 
 static void TestFunction(uint32_t thread_salt, SpinLock* spinlock) {
   for (int i = 0; i < kIters; i++) {
-    SpinLockHolder h(spinlock);
+    SpinLockHolder h(*spinlock);
     for (size_t j = 0; j < kArrayLength; j++) {
       const size_t index = (j + thread_salt) % kArrayLength;
       values[index] = Hash32(values[index], thread_salt);
@@ -102,7 +120,7 @@
     thread.join();
   }
 
-  SpinLockHolder h(spinlock);
+  SpinLockHolder h(*spinlock);
   for (size_t i = 1; i < kArrayLength; i++) {
     EXPECT_EQ(values[0], values[i]);
   }
@@ -114,15 +132,13 @@
 
 TEST(SpinLock, StackNonCooperativeDisablesScheduling) {
   SpinLock spinlock(base_internal::SCHEDULE_KERNEL_ONLY);
-  spinlock.Lock();
+  SpinLockHolder l(spinlock);
   EXPECT_FALSE(base_internal::SchedulingGuard::ReschedulingIsAllowed());
-  spinlock.Unlock();
 }
 
 TEST(SpinLock, StaticNonCooperativeDisablesScheduling) {
-  static_noncooperative_spinlock.Lock();
+  SpinLockHolder l(static_noncooperative_spinlock);
   EXPECT_FALSE(base_internal::SchedulingGuard::ReschedulingIsAllowed());
-  static_noncooperative_spinlock.Unlock();
 }
 
 TEST(SpinLock, WaitCyclesEncoding) {
@@ -134,7 +150,7 @@
   // We should be able to encode up to (1^kMaxCycleBits - 1) without clamping
   // but the lower kProfileTimestampShift will be dropped.
   const int kMaxCyclesShift =
-    32 - kLockwordReservedShift + kProfileTimestampShift;
+      32 - kLockwordReservedShift + kProfileTimestampShift;
   const int64_t kMaxCycles = (int64_t{1} << kMaxCyclesShift) - 1;
 
   // These bits should be zero after encoding.
@@ -171,22 +187,22 @@
             SpinLockTest::DecodeWaitCycles(~kLockwordReservedMask));
 
   // Check that we cannot produce kSpinLockSleeper during encoding.
-  int64_t sleeper_cycles =
-      kSpinLockSleeper << (kProfileTimestampShift - kLockwordReservedShift);
+  int64_t sleeper_cycles = kSpinLockSleeper
+                           << (kProfileTimestampShift - kLockwordReservedShift);
   uint32_t sleeper_value =
       SpinLockTest::EncodeWaitCycles(start_time, start_time + sleeper_cycles);
   EXPECT_NE(sleeper_value, kSpinLockSleeper);
 
   // Test clamping
   uint32_t max_value =
-    SpinLockTest::EncodeWaitCycles(start_time, start_time + kMaxCycles);
+      SpinLockTest::EncodeWaitCycles(start_time, start_time + kMaxCycles);
   int64_t max_value_decoded = SpinLockTest::DecodeWaitCycles(max_value);
   int64_t expected_max_value_decoded = kMaxCycles & ~kProfileTimestampMask;
   EXPECT_EQ(expected_max_value_decoded, max_value_decoded);
 
   const int64_t step = (1 << kProfileTimestampShift);
-  uint32_t after_max_value =
-    SpinLockTest::EncodeWaitCycles(start_time, start_time + kMaxCycles + step);
+  uint32_t after_max_value = SpinLockTest::EncodeWaitCycles(
+      start_time, start_time + kMaxCycles + step);
   int64_t after_max_value_decoded =
       SpinLockTest::DecodeWaitCycles(after_max_value);
   EXPECT_EQ(expected_max_value_decoded, after_max_value_decoded);
@@ -204,7 +220,7 @@
 }
 
 TEST(SpinLockWithThreads, StackCooperativeSpinLock) {
-  SpinLock spinlock(base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL);
+  SpinLock spinlock;
   ThreadedTest(&spinlock);
 }
 
@@ -227,12 +243,12 @@
                                BlockingCounter* b) {
       locked->WaitForNotification();  // Wait for LockThenWait() to hold "s".
       b->DecrementCount();
-      SpinLockHolder l(spinlock);
+      SpinLockHolder l(*spinlock);
     }
 
     static void LockThenWait(Notification* locked, SpinLock* spinlock,
                              BlockingCounter* b) {
-      SpinLockHolder l(spinlock);
+      SpinLockHolder l(*spinlock);
       locked->Notify();
       b->Wait();
     }
@@ -255,30 +271,31 @@
     }
   };
 
-  SpinLock stack_cooperative_spinlock(
-      base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL);
+  int num_threads = base_internal::NumCPUs() * 2;
+  SpinLock stack_cooperative_spinlock;
   SpinLock stack_noncooperative_spinlock(base_internal::SCHEDULE_KERNEL_ONLY);
-  Helper::DeadlockTest(&stack_cooperative_spinlock,
-                       base_internal::NumCPUs() * 2);
-  Helper::DeadlockTest(&stack_noncooperative_spinlock,
-                       base_internal::NumCPUs() * 2);
-  Helper::DeadlockTest(&static_cooperative_spinlock,
-                       base_internal::NumCPUs() * 2);
-  Helper::DeadlockTest(&static_noncooperative_spinlock,
-                       base_internal::NumCPUs() * 2);
+  Helper::DeadlockTest(&stack_cooperative_spinlock, num_threads);
+  Helper::DeadlockTest(&stack_noncooperative_spinlock, num_threads);
+  Helper::DeadlockTest(&static_cooperative_spinlock, num_threads);
+  Helper::DeadlockTest(&static_noncooperative_spinlock, num_threads);
 }
 
 TEST(SpinLockTest, IsCooperative) {
   SpinLock default_constructor;
   EXPECT_TRUE(SpinLockTest::IsCooperative(default_constructor));
 
-  SpinLock cooperative(base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL);
+  SpinLock cooperative;
   EXPECT_TRUE(SpinLockTest::IsCooperative(cooperative));
 
   SpinLock kernel_only(base_internal::SCHEDULE_KERNEL_ONLY);
   EXPECT_FALSE(SpinLockTest::IsCooperative(kernel_only));
 }
 
+TEST(SpinLockTest, ScopedLock) {
+  SpinLock s;
+  std::scoped_lock l(s);
+}
+
 }  // namespace
 }  // namespace base_internal
 ABSL_NAMESPACE_END
diff --git a/absl/cleanup/BUILD.bazel b/absl/cleanup/BUILD.bazel
index d579781..5475439 100644
--- a/absl/cleanup/BUILD.bazel
+++ b/absl/cleanup/BUILD.bazel
@@ -12,6 +12,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
diff --git a/absl/cleanup/cleanup.h b/absl/cleanup/cleanup.h
index 311e482..632ec6e 100644
--- a/absl/cleanup/cleanup.h
+++ b/absl/cleanup/cleanup.h
@@ -19,6 +19,10 @@
 // `absl::Cleanup` implements the scope guard idiom, invoking the contained
 // callback's `operator()() &&` on scope exit.
 //
+// This class doesn't allocate or take any locks, and is safe to use in a signal
+// handler. Of course the callback with which it is constructed also must be
+// signal safe in order for this to be useful.
+//
 // Example:
 //
 // ```
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
index 61e816f..e90aaec 100644
--- a/absl/container/BUILD.bazel
+++ b/absl/container/BUILD.bazel
@@ -14,6 +14,9 @@
 # limitations under the License.
 #
 
+load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
@@ -305,7 +308,7 @@
 cc_test(
     name = "flat_hash_set_test",
     srcs = ["flat_hash_set_test.cc"],
-    copts = ABSL_TEST_COPTS + ["-DUNORDERED_SET_CXX17"],
+    copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     tags = ["no_test_loonix"],
     deps = [
@@ -385,7 +388,7 @@
 cc_test(
     name = "node_hash_set_test",
     srcs = ["node_hash_set_test.cc"],
-    copts = ABSL_TEST_COPTS + ["-DUNORDERED_SET_CXX17"],
+    copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     tags = ["no_test_loonix"],
     deps = [
@@ -410,6 +413,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         "//absl/base:config",
+        "//absl/hash",
         "//absl/memory",
         "//absl/meta:type_traits",
         "//absl/utility",
@@ -425,6 +429,7 @@
     deps = [
         ":container_memory",
         ":test_instance_tracker",
+        "//absl/base:config",
         "//absl/base:no_destructor",
         "//absl/meta:type_traits",
         "//absl/strings",
@@ -491,6 +496,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":hash_policy_testing",
+        "//absl/base:config",
         "//absl/base:no_destructor",
         "//absl/memory",
         "//absl/meta:type_traits",
@@ -530,6 +536,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":common_policy_traits",
+        ":container_memory",
         "//absl/meta:type_traits",
     ],
 )
@@ -697,6 +704,19 @@
     ],
 )
 
+cc_test(
+    name = "hashtable_control_bytes_test",
+    srcs = ["internal/hashtable_control_bytes_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":hashtable_control_bytes",
+        "//absl/base:config",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
+
 cc_library(
     name = "raw_hash_set_resize_impl",
     hdrs = ["internal/raw_hash_set_resize_impl.h"],
@@ -735,6 +755,7 @@
         ":hashtable_debug_hooks",
         ":hashtablez_sampler",
         ":raw_hash_set_resize_impl",
+        "//absl/base",
         "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:dynamic_annotations",
@@ -922,9 +943,13 @@
     hdrs = ["internal/unordered_map_constructor_test.h"],
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl/container:__pkg__",
+    ],
     deps = [
         ":hash_generator_testing",
         ":hash_policy_testing",
+        "//absl/base:config",
         "@googletest//:gtest",
     ],
 )
@@ -935,6 +960,9 @@
     hdrs = ["internal/unordered_map_lookup_test.h"],
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl/container:__pkg__",
+    ],
     deps = [
         ":hash_generator_testing",
         ":hash_policy_testing",
@@ -948,6 +976,9 @@
     hdrs = ["internal/unordered_map_modifiers_test.h"],
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl/container:__pkg__",
+    ],
     deps = [
         ":hash_generator_testing",
         ":hash_policy_testing",
@@ -961,9 +992,13 @@
     hdrs = ["internal/unordered_set_constructor_test.h"],
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl/container:__pkg__",
+    ],
     deps = [
         ":hash_generator_testing",
         ":hash_policy_testing",
+        "//absl/base:config",
         "//absl/meta:type_traits",
         "@googletest//:gtest",
     ],
@@ -975,6 +1010,9 @@
     hdrs = ["internal/unordered_set_members_test.h"],
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl/container:__pkg__",
+    ],
     deps = [
         "//absl/meta:type_traits",
         "@googletest//:gtest",
@@ -987,6 +1025,9 @@
     hdrs = ["internal/unordered_map_members_test.h"],
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl/container:__pkg__",
+    ],
     deps = [
         "//absl/meta:type_traits",
         "@googletest//:gtest",
@@ -999,6 +1040,9 @@
     hdrs = ["internal/unordered_set_lookup_test.h"],
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl/container:__pkg__",
+    ],
     deps = [
         ":hash_generator_testing",
         ":hash_policy_testing",
@@ -1012,6 +1056,9 @@
     hdrs = ["internal/unordered_set_modifiers_test.h"],
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl/container:__pkg__",
+    ],
     deps = [
         ":hash_generator_testing",
         ":hash_policy_testing",
@@ -1180,3 +1227,168 @@
         "@google_benchmark//:benchmark_main",
     ],
 )
+
+cc_library(
+    name = "heterogeneous_lookup_testing",
+    testonly = True,
+    hdrs = ["internal/heterogeneous_lookup_testing.h"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl/container:__pkg__",
+    ],
+    deps = [
+        "//absl/base:config",
+        "//absl/container:test_instance_tracker",
+        "@googletest//:gtest",
+    ],
+)
+
+cc_library(
+    name = "linked_hash_set",
+    hdrs = ["linked_hash_set.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":common",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/container:flat_hash_set",
+    ],
+)
+
+cc_test(
+    name = "linked_hash_set_test",
+    srcs = ["linked_hash_set_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":heterogeneous_lookup_testing",
+        ":linked_hash_set",
+        "//absl/base:config",
+        "//absl/container:hash_generator_testing",
+        "//absl/container:hash_policy_testing",
+        "//absl/container:test_instance_tracker",
+        "//absl/container:unordered_set_constructor_test",
+        "//absl/container:unordered_set_lookup_test",
+        "//absl/container:unordered_set_members_test",
+        "//absl/container:unordered_set_modifiers_test",
+        "//absl/strings:string_view",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
+
+cc_binary(
+    name = "linked_hash_set_benchmark",
+    testonly = True,
+    srcs = ["linked_hash_set_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":linked_hash_set",
+        "//absl/functional:function_ref",
+        "//absl/strings:str_format",
+        "//absl/strings:string_view",
+        "@google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_library(
+    name = "linked_hash_map",
+    hdrs = ["linked_hash_map.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":common",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/base:throw_delegate",
+        "//absl/container:flat_hash_set",
+    ],
+)
+
+cc_test(
+    name = "linked_hash_map_test",
+    srcs = ["linked_hash_map_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":heterogeneous_lookup_testing",
+        ":linked_hash_map",
+        "//absl/base:config",
+        "//absl/base:exception_testing",
+        "//absl/container:hash_generator_testing",
+        "//absl/container:hash_policy_testing",
+        "//absl/container:test_instance_tracker",
+        "//absl/container:unordered_map_constructor_test",
+        "//absl/container:unordered_map_lookup_test",
+        "//absl/container:unordered_map_members_test",
+        "//absl/container:unordered_map_modifiers_test",
+        "//absl/strings:string_view",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
+
+cc_binary(
+    name = "linked_hash_map_benchmark",
+    testonly = True,
+    srcs = ["linked_hash_map_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":linked_hash_map",
+        "//absl/functional:function_ref",
+        "//absl/strings:str_format",
+        "//absl/strings:string_view",
+        "@google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_library(
+    name = "chunked_queue",
+    srcs = ["internal/chunked_queue.h"],
+    hdrs = ["chunked_queue.h"],
+    deps = [
+        ":layout",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/base:iterator_traits_internal",
+    ],
+)
+
+cc_test(
+    name = "chunked_queue_test",
+    size = "small",
+    srcs = ["chunked_queue_test.cc"],
+    deps = [
+        ":chunked_queue",
+        ":test_allocator",
+        "//absl/base:core_headers",
+        "//absl/strings",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
+
+cc_binary(
+    name = "chunked_queue_benchmark",
+    testonly = True,
+    srcs = ["chunked_queue_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":chunked_queue",
+        "//absl/random",
+        "//absl/status",
+        "//absl/strings:cord",
+        "@google_benchmark//:benchmark_main",
+    ],
+)
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt
index d8cd7d0..365c6ea 100644
--- a/absl/container/CMakeLists.txt
+++ b/absl/container/CMakeLists.txt
@@ -349,7 +349,6 @@
     "flat_hash_set_test.cc"
   COPTS
     ${ABSL_TEST_COPTS}
-    "-DUNORDERED_SET_CXX17"
   DEPS
     absl::check
     absl::config
@@ -432,7 +431,6 @@
     "node_hash_set_test.cc"
   COPTS
     ${ABSL_TEST_COPTS}
-    "-DUNORDERED_SET_CXX17"
   DEPS
     absl::hash_generator_testing
     absl::hash_policy_testing
@@ -469,6 +467,7 @@
     ${ABSL_DEFAULT_COPTS}
   DEPS
     absl::config
+    absl::hash
     absl::memory
     absl::type_traits
     absl::utility
@@ -483,6 +482,7 @@
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
+    absl::config
     absl::container_memory
     absl::no_destructor
     absl::strings
@@ -539,6 +539,7 @@
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
+    absl::config
     absl::hash_policy_testing
     absl::memory
     absl::meta
@@ -583,6 +584,7 @@
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
+    absl::container_memory
     absl::common_policy_traits
     absl::meta
   PUBLIC
@@ -761,6 +763,19 @@
     absl::endian
 )
 
+absl_cc_test(
+  NAME
+    hashtable_control_bytes_test
+  SRCS
+    "internal/hashtable_control_bytes_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::config
+    absl::hashtable_control_bytes
+    GTest::gmock_main
+)
+
 # Internal-only target, do not depend on directly.
 absl_cc_library(
   NAME
@@ -772,6 +787,7 @@
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
+    absl::base
     absl::bits
     absl::common_policy_traits
     absl::compressed_tuple
@@ -933,6 +949,7 @@
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
+    absl::config
     absl::hash_generator_testing
     absl::hash_policy_testing
     GTest::gmock
@@ -992,6 +1009,7 @@
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
+    absl::config
     absl::hash_generator_testing
     absl::hash_policy_testing
     GTest::gmock
@@ -1087,3 +1105,135 @@
     absl::hashtablez_sampler
     GTest::gmock_main
 )
+
+absl_cc_library(
+  NAME
+    heterogeneous_lookup_testing
+  HDRS
+    "internal/heterogeneous_lookup_testing.h"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+    absl::config
+    absl::test_instance_tracker
+    GTest::gmock
+)
+
+absl_cc_library(
+  NAME
+    linked_hash_set
+  HDRS
+    "linked_hash_set.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+     absl::container_common
+     absl::config
+     absl::core_headers
+     absl::flat_hash_set
+)
+
+absl_cc_test(
+  NAME
+    linked_hash_set_test
+  SRCS
+    "linked_hash_set_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+    absl::linked_hash_set
+    absl::config
+    absl::heterogeneous_lookup_testing
+    absl::hash_generator_testing
+    absl::hash_policy_testing
+    absl::string_view
+    absl::test_instance_tracker
+    absl::unordered_set_constructor_test
+    absl::unordered_set_lookup_test
+    absl::unordered_set_members_test
+    absl::unordered_set_modifiers_test
+    GTest::gmock_main
+)
+
+absl_cc_library(
+  NAME
+    linked_hash_map
+  HDRS
+    "linked_hash_map.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+     absl::container_common
+     absl::config
+     absl::core_headers
+     absl::flat_hash_set
+     absl::throw_delegate
+)
+
+absl_cc_test(
+  NAME
+    linked_hash_map_test
+  SRCS
+    "linked_hash_map_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+    absl::linked_hash_map
+    absl::config
+    absl::exception_testing
+    absl::heterogeneous_lookup_testing
+    absl::hash_generator_testing
+    absl::hash_policy_testing
+    absl::string_view
+    absl::test_instance_tracker
+    absl::unordered_set_constructor_test
+    absl::unordered_set_lookup_test
+    absl::unordered_set_members_test
+    absl::unordered_set_modifiers_test
+    GTest::gmock_main
+)
+
+absl_cc_library(
+  NAME
+    chunked_queue
+  HDRS
+    "chunked_queue.h"
+    "internal/chunked_queue.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+     absl::config
+     absl::core_headers
+     absl::iterator_traits_internal
+     absl::layout
+)
+
+absl_cc_test(
+  NAME
+    chunked_queue_test
+  SRCS
+    "chunked_queue_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+    absl::chunked_queue
+    absl::config
+    absl::core_headers
+    absl::strings
+    absl::test_allocator
+    GTest::gmock_main
+)
diff --git a/absl/container/btree_map.h b/absl/container/btree_map.h
index 32a82ef..0746f72 100644
--- a/absl/container/btree_map.h
+++ b/absl/container/btree_map.h
@@ -57,18 +57,44 @@
 #ifndef ABSL_CONTAINER_BTREE_MAP_H_
 #define ABSL_CONTAINER_BTREE_MAP_H_
 
+#include <functional>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
 #include "absl/base/attributes.h"
 #include "absl/container/internal/btree.h"  // IWYU pragma: export
 #include "absl/container/internal/btree_container.h"  // IWYU pragma: export
+#include "absl/container/internal/common.h"
+#include "absl/container/internal/container_memory.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
 namespace container_internal {
 
+template <typename Key, typename Data, typename... Params>
+struct map_params_impl;
+
+template <typename Key, typename Data>
+struct btree_map_defaults {
+  using Compare = std::less<Key>;
+  using Alloc = std::allocator<std::pair<const Key, Data>>;
+  using TargetNodeSize = std::integral_constant<int, 256>;
+  using IsMulti = std::false_type;
+};
+
 template <typename Key, typename Data, typename Compare, typename Alloc,
           int TargetNodeSize, bool IsMulti>
-struct map_params;
+using map_params = typename ApplyWithoutDefaultSuffix<
+    map_params_impl,
+    TypeList<void, void, typename btree_map_defaults<Key, Data>::Compare,
+             typename btree_map_defaults<Key, Data>::Alloc,
+             typename btree_map_defaults<Key, Data>::TargetNodeSize,
+             typename btree_map_defaults<Key, Data>::IsMulti>,
+    TypeList<Key, Data, Compare, Alloc,
+             std::integral_constant<int, TargetNodeSize>,
+             std::integral_constant<bool, IsMulti>>>::type;
 
 }  // namespace container_internal
 
@@ -117,8 +143,8 @@
   //
   // * Copy assignment operator
   //
-  //  absl::btree_map<int, std::string> map4;
-  //  map4 = map3;
+  //   absl::btree_map<int, std::string> map4;
+  //   map4 = map3;
   //
   // * Move constructor
   //
@@ -555,8 +581,8 @@
   //
   // * Copy assignment operator
   //
-  //  absl::btree_multimap<int, std::string> map4;
-  //  map4 = map3;
+  //   absl::btree_multimap<int, std::string> map4;
+  //   map4 = map3;
   //
   // * Move constructor
   //
@@ -855,11 +881,20 @@
 
 // A parameters structure for holding the type parameters for a btree_map.
 // Compare and Alloc should be nothrow copy-constructible.
-template <typename Key, typename Data, typename Compare, typename Alloc,
-          int TargetNodeSize, bool IsMulti>
-struct map_params : common_params<Key, Compare, Alloc, TargetNodeSize, IsMulti,
-                                  /*IsMap=*/true, map_slot_policy<Key, Data>> {
-  using super_type = typename map_params::common_params;
+template <typename Key, typename Data, typename... Params>
+struct map_params_impl
+    : common_params<
+          Key,
+          GetFromListOr<typename btree_map_defaults<Key, Data>::Compare, 0,
+                        Params...>,
+          GetFromListOr<typename btree_map_defaults<Key, Data>::Alloc, 1,
+                        Params...>,
+          GetFromListOr<typename btree_map_defaults<Key, Data>::TargetNodeSize,
+                        2, Params...>::value,
+          GetFromListOr<typename btree_map_defaults<Key, Data>::IsMulti, 3,
+                        Params...>::value,
+          /*IsMap=*/true, map_slot_policy<Key, Data>> {
+  using super_type = typename map_params_impl::common_params;
   using mapped_type = Data;
   // This type allows us to move keys when it is safe to do so. It is safe
   // for maps in which value_type and mutable_value_type are layout compatible.
@@ -868,6 +903,21 @@
   using value_type = typename super_type::value_type;
   using init_type = typename super_type::init_type;
 
+  static_assert(
+      std::is_same_v<
+          map_params<
+              Key, Data,
+              GetFromListOr<typename btree_map_defaults<Key, Data>::Compare, 0,
+                            Params...>,
+              GetFromListOr<typename btree_map_defaults<Key, Data>::Alloc, 1,
+                            Params...>,
+              GetFromListOr<
+                  typename btree_map_defaults<Key, Data>::TargetNodeSize, 2,
+                  Params...>::value,
+              GetFromListOr<typename btree_map_defaults<Key, Data>::IsMulti, 3,
+                            Params...>::value>,
+          map_params_impl>);
+
   template <typename V>
   static auto key(const V &value ABSL_ATTRIBUTE_LIFETIME_BOUND)
       -> decltype((value.first)) {
diff --git a/absl/container/btree_set.h b/absl/container/btree_set.h
index 16181de..991cb89 100644
--- a/absl/container/btree_set.h
+++ b/absl/container/btree_set.h
@@ -56,9 +56,15 @@
 #ifndef ABSL_CONTAINER_BTREE_SET_H_
 #define ABSL_CONTAINER_BTREE_SET_H_
 
+#include <functional>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
 #include "absl/base/attributes.h"
 #include "absl/container/internal/btree.h"  // IWYU pragma: export
 #include "absl/container/internal/btree_container.h"  // IWYU pragma: export
+#include "absl/container/internal/common.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -68,9 +74,27 @@
 template <typename Key>
 struct set_slot_policy;
 
+template <typename Key, typename...Params>
+struct set_params_impl;
+
+template <typename Key>
+struct btree_set_defaults {
+  using Compare = std::less<Key>;
+  using Alloc = std::allocator<Key>;
+  using TargetNodeSize = std::integral_constant<int, 256>;
+  using IsMulti = std::false_type;
+};
+
 template <typename Key, typename Compare, typename Alloc, int TargetNodeSize,
           bool IsMulti>
-struct set_params;
+using set_params = typename ApplyWithoutDefaultSuffix<
+    set_params_impl,
+    TypeList<void, typename btree_set_defaults<Key>::Compare,
+             typename btree_set_defaults<Key>::Alloc,
+             typename btree_set_defaults<Key>::TargetNodeSize,
+             typename btree_set_defaults<Key>::IsMulti>,
+    TypeList<Key, Compare, Alloc, std::integral_constant<int, TargetNodeSize>,
+             std::integral_constant<bool, IsMulti>>>::type;
 
 }  // namespace container_internal
 
@@ -119,8 +143,8 @@
   //
   // * Copy assignment operator
   //
-  //  absl::btree_set<std::string> set4;
-  //  set4 = set3;
+  //   absl::btree_set<std::string> set4;
+  //   set4 = set3;
   //
   // * Move constructor
   //
@@ -475,8 +499,8 @@
   //
   // * Copy assignment operator
   //
-  //  absl::btree_multiset<std::string> set4;
-  //  set4 = set3;
+  //   absl::btree_multiset<std::string> set4;
+  //   set4 = set3;
   //
   // * Move constructor
   //
@@ -803,12 +827,34 @@
 
 // A parameters structure for holding the type parameters for a btree_set.
 // Compare and Alloc should be nothrow copy-constructible.
-template <typename Key, typename Compare, typename Alloc, int TargetNodeSize,
-          bool IsMulti>
-struct set_params : common_params<Key, Compare, Alloc, TargetNodeSize, IsMulti,
-                                  /*IsMap=*/false, set_slot_policy<Key>> {
+template <typename Key, typename... Params>
+struct set_params_impl
+    : common_params<
+          Key,
+          GetFromListOr<typename btree_set_defaults<Key>::Compare, 0,
+                        Params...>,
+          GetFromListOr<typename btree_set_defaults<Key>::Alloc, 1, Params...>,
+          GetFromListOr<typename btree_set_defaults<Key>::TargetNodeSize, 2,
+                        Params...>::value,
+          GetFromListOr<typename btree_set_defaults<Key>::IsMulti, 3,
+                        Params...>::value,
+          /*IsMap=*/false, set_slot_policy<Key>> {
   using value_type = Key;
-  using slot_type = typename set_params::common_params::slot_type;
+  using slot_type = typename set_params_impl::common_params::slot_type;
+
+  static_assert(
+      std::is_same_v<
+          set_params<
+              Key,
+              GetFromListOr<typename btree_set_defaults<Key>::Compare, 0,
+                            Params...>,
+              GetFromListOr<typename btree_set_defaults<Key>::Alloc, 1,
+                            Params...>,
+              GetFromListOr<typename btree_set_defaults<Key>::TargetNodeSize, 2,
+                            Params...>::value,
+              GetFromListOr<typename btree_set_defaults<Key>::IsMulti, 3,
+                            Params...>::value>,
+          set_params_impl>);
 
   template <typename V>
   static const V &key(const V &value) {
diff --git a/absl/container/btree_test.cc b/absl/container/btree_test.cc
index 1d2c2a6..0cf3ed3 100644
--- a/absl/container/btree_test.cc
+++ b/absl/container/btree_test.cc
@@ -2048,7 +2048,10 @@
 
 TEST(Btree, ExtractDoesntCauseExtraMoves) {
 #ifdef _MSC_VER
-  GTEST_SKIP() << "This test fails on MSVC.";
+  // This conditional is to avoid an unreachable code warning.
+  if (_MSC_VER > 0) {
+    GTEST_SKIP() << "This test fails on MSVC.";
+  }
 #endif
 
   using Set = absl::btree_set<MovableOnlyInstance>;
@@ -3541,6 +3544,109 @@
   TestBasicFunctionality(set_type());
 }
 
+// Alias whose only purpose is to have the same length as set_params for better
+// alignment in the test below.
+template <typename... T>
+using set_p_impl = set_params_impl<T...>;
+
+TEST(BtreeTest, SetParamsStripsDefaults) {
+  using K = int;
+  using DA = btree_set_defaults<int>::Compare;
+  using DB = btree_set_defaults<int>::Alloc;
+  using DC = btree_set_defaults<int>::TargetNodeSize;
+  using DD = btree_set_defaults<int>::IsMulti;
+
+  using XA = std::greater<int>;
+  struct XB {};
+  using XC = std::integral_constant<int, 100>;
+  using XD = std::true_type;
+
+  EXPECT_TRUE((std::is_same_v<set_params<K, XA, XB, XC{}, XD{}>,
+                              set_p_impl<K, XA, XB, XC, XD>>));
+  EXPECT_TRUE((std::is_same_v<set_params<K, XA, XB, XC{}, DD{}>,
+                              set_p_impl<K, XA, XB, XC>>));
+  EXPECT_TRUE((std::is_same_v<set_params<K, XA, XB, DC{}, XD{}>,
+                              set_p_impl<K, XA, XB, DC, XD>>));
+  EXPECT_TRUE((std::is_same_v<set_params<K, XA, XB, DC{}, DD{}>,
+                              set_p_impl<K, XA, XB>>));
+  EXPECT_TRUE((std::is_same_v<set_params<K, XA, DB, XC{}, XD{}>,
+                              set_p_impl<K, XA, DB, XC, XD>>));
+  EXPECT_TRUE((std::is_same_v<set_params<K, XA, DB, XC{}, DD{}>,
+                              set_p_impl<K, XA, DB, XC>>));
+  EXPECT_TRUE((std::is_same_v<set_params<K, XA, DB, DC{}, XD{}>,
+                              set_p_impl<K, XA, DB, DC, XD>>));
+  EXPECT_TRUE((std::is_same_v<set_params<K, XA, DB, DC{}, DD{}>,
+                              set_p_impl<K, XA>>));
+  EXPECT_TRUE((std::is_same_v<set_params<K, DA, XB, XC{}, XD{}>,
+                              set_p_impl<K, DA, XB, XC, XD>>));
+  EXPECT_TRUE((std::is_same_v<set_params<K, DA, XB, XC{}, DD{}>,
+                              set_p_impl<K, DA, XB, XC>>));
+  EXPECT_TRUE((std::is_same_v<set_params<K, DA, XB, DC{}, XD{}>,
+                              set_p_impl<K, DA, XB, DC, XD>>));
+  EXPECT_TRUE((std::is_same_v<set_params<K, DA, XB, DC{}, DD{}>,
+                              set_p_impl<K, DA, XB>>));
+  EXPECT_TRUE((std::is_same_v<set_params<K, DA, DB, XC{}, XD{}>,
+                              set_p_impl<K, DA, DB, XC, XD>>));
+  EXPECT_TRUE((std::is_same_v<set_params<K, DA, DB, XC{}, DD{}>,
+                              set_p_impl<K, DA, DB, XC>>));
+  EXPECT_TRUE((std::is_same_v<set_params<K, DA, DB, DC{}, XD{}>,
+                              set_p_impl<K, DA, DB, DC, XD>>));
+  EXPECT_TRUE((std::is_same_v<set_params<K, DA, DB, DC{}, DD{}>,
+                              set_p_impl<K>>));
+}
+
+// Alias whose only purpose is to have the same length as map_params for better
+// alignment in the test below.
+template <typename... T>
+using map_p_impl = map_params_impl<T...>;
+
+TEST(BtreeTest, MapParamsStripsDefaults) {
+  using K = int;
+  using V = double;
+  using DA = btree_map_defaults<int, double>::Compare;
+  using DB = btree_map_defaults<int, double>::Alloc;
+  using DC = btree_map_defaults<int, double>::TargetNodeSize;
+  using DD = btree_map_defaults<int, double>::IsMulti;
+
+  using XA = std::greater<int>;
+  struct XB {};
+  using XC = std::integral_constant<int, 100>;
+  using XD = std::true_type;
+
+  EXPECT_TRUE((std::is_same_v<map_params<K, V, XA, XB, XC{}, XD{}>,
+                              map_p_impl<K, V, XA, XB, XC, XD>>));
+  EXPECT_TRUE((std::is_same_v<map_params<K, V, XA, XB, XC{}, DD{}>,
+                              map_p_impl<K, V, XA, XB, XC>>));
+  EXPECT_TRUE((std::is_same_v<map_params<K, V, XA, XB, DC{}, XD{}>,
+                              map_p_impl<K, V, XA, XB, DC, XD>>));
+  EXPECT_TRUE((std::is_same_v<map_params<K, V, XA, XB, DC{}, DD{}>,
+                              map_p_impl<K, V, XA, XB>>));
+  EXPECT_TRUE((std::is_same_v<map_params<K, V, XA, DB, XC{}, XD{}>,
+                              map_p_impl<K, V, XA, DB, XC, XD>>));
+  EXPECT_TRUE((std::is_same_v<map_params<K, V, XA, DB, XC{}, DD{}>,
+                              map_p_impl<K, V, XA, DB, XC>>));
+  EXPECT_TRUE((std::is_same_v<map_params<K, V, XA, DB, DC{}, XD{}>,
+                              map_p_impl<K, V, XA, DB, DC, XD>>));
+  EXPECT_TRUE((std::is_same_v<map_params<K, V, XA, DB, DC{}, DD{}>,
+                              map_p_impl<K, V, XA>>));
+  EXPECT_TRUE((std::is_same_v<map_params<K, V, DA, XB, XC{}, XD{}>,
+                              map_p_impl<K, V, DA, XB, XC, XD>>));
+  EXPECT_TRUE((std::is_same_v<map_params<K, V, DA, XB, XC{}, DD{}>,
+                              map_p_impl<K, V, DA, XB, XC>>));
+  EXPECT_TRUE((std::is_same_v<map_params<K, V, DA, XB, DC{}, XD{}>,
+                              map_p_impl<K, V, DA, XB, DC, XD>>));
+  EXPECT_TRUE((std::is_same_v<map_params<K, V, DA, XB, DC{}, DD{}>,
+                              map_p_impl<K, V, DA, XB>>));
+  EXPECT_TRUE((std::is_same_v<map_params<K, V, DA, DB, XC{}, XD{}>,
+                              map_p_impl<K, V, DA, DB, XC, XD>>));
+  EXPECT_TRUE((std::is_same_v<map_params<K, V, DA, DB, XC{}, DD{}>,
+                              map_p_impl<K, V, DA, DB, XC>>));
+  EXPECT_TRUE((std::is_same_v<map_params<K, V, DA, DB, DC{}, XD{}>,
+                              map_p_impl<K, V, DA, DB, DC, XD>>));
+  EXPECT_TRUE((std::is_same_v<map_params<K, V, DA, DB, DC{}, DD{}>,
+                              map_p_impl<K, V>>));
+}
+
 }  // namespace
 }  // namespace container_internal
 ABSL_NAMESPACE_END
diff --git a/absl/container/chunked_queue.h b/absl/container/chunked_queue.h
new file mode 100644
index 0000000..d5b1184
--- /dev/null
+++ b/absl/container/chunked_queue.h
@@ -0,0 +1,755 @@
+// Copyright 2025 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: chunked_queue.h
+// -----------------------------------------------------------------------------
+//
+// `std::deque` provides random access and fast push/pop back/front. It is
+// implemented as an array of fixed blocks. It provides no control of block size
+// and implementations differ; libstdc++ tries to allocate blocks of ~512 bytes
+// and libc++ tries for blocks of ~4k bytes.
+//
+// `absl::chunked_queue` provides the same minus random access. It is
+// implemented as a double-linked list of fixed or variable sized blocks.
+//
+// `absl::chunked_queue` is useful when memory usage is paramount as it provides
+//  finegrained and configurable block sizing.
+//
+// The interface supported by this class is limited to:
+//
+//   empty()
+//   size()
+//   max_size()
+//   shrink_to_fit()
+//   resize()
+//   assign()
+//   push_back()
+//   emplace_back()
+//   pop_front()
+//   front()
+//   back()
+//   swap()
+//   clear()
+//   begin(), end()
+//   cbegin(), cend()
+//
+// === ADVANCED USAGE
+//
+// == clear()
+//
+// As an optimization clear() leaves the first block of the chunked_queue
+// allocated (but empty). So clear will not delete all memory of the container.
+// In order to do so, call shrink_to_fit() or swap the container with an empty
+// one.
+//
+//   absl::chunked_queue<int64> q = {1, 2, 3};
+//   q.clear();
+//   q.shrink_to_fit();
+//
+// == block size customization
+//
+// chunked_queue allows customization of the block size for each block. By
+// default the block size is set to 1 element and the size doubles for the next
+// block until it reaches the default max block size, which is 128 elements.
+//
+// = fixed size
+//
+// When only the first block size parameter is specified, it sets a fixed block
+// size for all blocks:
+//
+//   chunked_queue<T, 32>: 32 elements per block
+//
+// The smaller the block size, the less the memory usage for small queues at the
+// cost of performance. Caveat: For large queues, a smaller block size will
+// increase memory usage, and reduce performance.
+//
+// = variable size
+//
+// When both block size parameters are specified, they set the min and max block
+// sizes for the blocks. Initially the queue starts with the min block size and
+// as it grows, the size of each block grows until it reaches the max block
+// size.
+// New blocks are double the size of the tail block (so they at least
+// double the size of the queue).
+//
+//   chunked_queue<T, 4, 64>: first block 4 elements, second block 8 elements,
+//                            third block 16 elements, fourth block 32 elements,
+//                            all other blocks 64 elements
+//
+// One can specify a min and max such that small queues will not waste memory
+// and large queues will not have too many blocks.
+
+#ifndef ABSL_CONTAINER_CHUNKED_QUEUE_H_
+#define ABSL_CONTAINER_CHUNKED_QUEUE_H_
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <initializer_list>
+#include <iterator>
+#include <memory>
+#include <new>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/iterator_traits.h"
+#include "absl/base/macros.h"
+#include "absl/container/internal/chunked_queue.h"
+#include "absl/container/internal/layout.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+template <typename T, size_t BLo = 0, size_t BHi = BLo,
+          typename Allocator = std::allocator<T>>
+class chunked_queue {
+ public:
+  static constexpr size_t kBlockSizeMin = (BLo == 0 && BHi == 0) ? 1 : BLo;
+  static constexpr size_t kBlockSizeMax = (BLo == 0 && BHi == 0) ? 128 : BHi;
+
+ private:
+  static_assert(kBlockSizeMin > 0, "Min block size cannot be zero");
+  static_assert(kBlockSizeMin <= kBlockSizeMax, "Invalid block size bounds");
+
+  using Block = container_internal::ChunkedQueueBlock<T, Allocator>;
+  using AllocatorTraits = std::allocator_traits<Allocator>;
+
+  class iterator_common {
+   public:
+    friend bool operator==(const iterator_common& a, const iterator_common& b) {
+      return a.ptr == b.ptr;
+    }
+
+    friend bool operator!=(const iterator_common& a, const iterator_common& b) {
+      return !(a == b);
+    }
+
+   protected:
+    iterator_common() = default;
+    explicit iterator_common(Block* b)
+        : block(b), ptr(b->start()), limit(b->limit()) {}
+
+    void Incr() {
+      // If we do not have a next block, make ptr point one past the end of this
+      // block. If we do have a next block, make ptr point to the first element
+      // of the next block.
+      ++ptr;
+      if (ptr == limit && block->next()) *this = iterator_common(block->next());
+    }
+
+    void IncrBy(size_t n) {
+      while (ptr + n > limit) {
+        n -= limit - ptr;
+        *this = iterator_common(block->next());
+      }
+      ptr += n;
+    }
+
+    Block* block = nullptr;
+    T* ptr = nullptr;
+    T* limit = nullptr;
+  };
+
+  // CT can be either T or const T.
+  template <typename CT>
+  class basic_iterator : public iterator_common {
+   public:
+    using iterator_category = std::forward_iterator_tag;
+    using value_type = typename AllocatorTraits::value_type;
+    using difference_type = typename AllocatorTraits::difference_type;
+    using pointer =
+        typename std::conditional<std::is_const<CT>::value,
+                                  typename AllocatorTraits::const_pointer,
+                                  typename AllocatorTraits::pointer>::type;
+    using reference = CT&;
+
+    basic_iterator() = default;
+
+    // Copy ctor if CT is T.
+    // Otherwise it's a conversion of iterator to const_iterator.
+    basic_iterator(const basic_iterator<T>& it)  // NOLINT(runtime/explicit)
+        : iterator_common(it) {}
+
+    basic_iterator& operator=(const basic_iterator& other) = default;
+
+    reference operator*() const { return *this->ptr; }
+    pointer operator->() const { return this->ptr; }
+    basic_iterator& operator++() {
+      this->Incr();
+      return *this;
+    }
+    basic_iterator operator++(int) {
+      basic_iterator t = *this;
+      ++*this;
+      return t;
+    }
+
+   private:
+    explicit basic_iterator(Block* b) : iterator_common(b) {}
+
+    friend chunked_queue;
+  };
+
+ public:
+  using allocator_type = typename AllocatorTraits::allocator_type;
+  using value_type = typename AllocatorTraits::value_type;
+  using size_type = typename AllocatorTraits::size_type;
+  using difference_type = typename AllocatorTraits::difference_type;
+  using reference = value_type&;
+  using const_reference = const value_type&;
+  using iterator = basic_iterator<T>;
+  using const_iterator = basic_iterator<const T>;
+
+  // Constructs an empty queue.
+  chunked_queue() : chunked_queue(allocator_type()) {}
+
+  // Constructs an empty queue with a custom allocator.
+  explicit chunked_queue(const allocator_type& alloc)
+      : alloc_and_size_(alloc) {}
+
+  // Constructs a queue with `count` default-inserted elements.
+  explicit chunked_queue(size_type count,
+                         const allocator_type& alloc = allocator_type())
+      : alloc_and_size_(alloc) {
+    resize(count);
+  }
+
+  // Constructs a queue with `count` copies of `value`.
+  chunked_queue(size_type count, const T& value,
+                const allocator_type& alloc = allocator_type())
+      : alloc_and_size_(alloc) {
+    assign(count, value);
+  }
+
+  // Constructs a queue with the contents of the range [first, last).
+  template <typename Iter,
+            typename = std::enable_if_t<
+                base_internal::IsAtLeastInputIterator<Iter>::value>>
+  chunked_queue(Iter first, Iter last,
+                const allocator_type& alloc = allocator_type())
+      : alloc_and_size_(alloc) {
+    using Tag = typename std::iterator_traits<Iter>::iterator_category;
+    RangeInit(first, last, Tag());
+  }
+
+  // Constructs a queue with the contents of the initializer list `list`.
+  chunked_queue(std::initializer_list<T> list,
+                const allocator_type& alloc = allocator_type())
+      : chunked_queue(list.begin(), list.end(), alloc) {}
+
+  ~chunked_queue();
+
+  // Copy constructor.
+  chunked_queue(const chunked_queue& other)
+      : chunked_queue(other,
+                      AllocatorTraits::select_on_container_copy_construction(
+                          other.alloc_and_size_.allocator())) {}
+
+  // Copy constructor with specific allocator.
+  chunked_queue(const chunked_queue& other, const allocator_type& alloc)
+      : alloc_and_size_(alloc) {
+    for (const_reference item : other) {
+      push_back(item);
+    }
+  }
+
+  // Move constructor.
+  chunked_queue(chunked_queue&& other) noexcept
+      : head_(other.head_),
+        tail_(other.tail_),
+        alloc_and_size_(std::move(other.alloc_and_size_)) {
+    other.head_ = {};
+    other.tail_ = {};
+    other.alloc_and_size_.size = 0;
+  }
+
+  // Replaces contents with those from initializer list `il`.
+  chunked_queue& operator=(std::initializer_list<T> il) {
+    assign(il.begin(), il.end());
+    return *this;
+  }
+
+  // Copy assignment operator.
+  chunked_queue& operator=(const chunked_queue& other) {
+    if (this == &other) {
+      return *this;
+    }
+    if (AllocatorTraits::propagate_on_container_copy_assignment::value &&
+        (alloc_and_size_.allocator() != other.alloc_and_size_.allocator())) {
+      // Destroy all current elements and blocks with the current allocator,
+      // before switching this to use the allocator propagated from "other".
+      DestroyAndDeallocateAll();
+      alloc_and_size_ = AllocatorAndSize(other.alloc_and_size_.allocator());
+    }
+    assign(other.begin(), other.end());
+    return *this;
+  }
+
+  // Move assignment operator.
+  chunked_queue& operator=(chunked_queue&& other) noexcept;
+
+  // Returns true if the queue contains no elements.
+  bool empty() const { return alloc_and_size_.size == 0; }
+
+  // Returns the number of elements in the queue.
+  size_t size() const { return alloc_and_size_.size; }
+
+  // Returns the maximum number of elements the queue is able to hold.
+  size_type max_size() const noexcept {
+    return AllocatorTraits::max_size(alloc_and_size_.allocator());
+  }
+
+  // Resizes the container to contain `new_size` elements.
+  // If `new_size > size()`, additional default-inserted elements are appended.
+  // If `new_size < size()`, elements are removed from the end.
+  void resize(size_t new_size);
+
+  // Resizes the container to contain `new_size` elements.
+  // If `new_size > size()`, additional copies of `value` are appended.
+  // If `new_size < size()`, elements are removed from the end.
+  void resize(size_type new_size, const T& value) {
+    if (new_size > size()) {
+      size_t to_add = new_size - size();
+      for (size_t i = 0; i < to_add; ++i) {
+        push_back(value);
+      }
+    } else {
+      resize(new_size);
+    }
+  }
+
+  // Requests the removal of unused capacity.
+  void shrink_to_fit() {
+    // As an optimization clear() leaves the first block of the chunked_queue
+    // allocated (but empty). When empty, shrink_to_fit() deallocates the first
+    // block by swapping it a newly constructed container that has no first
+    // block.
+    if (empty()) {
+      chunked_queue(alloc_and_size_.allocator()).swap(*this);
+    }
+  }
+
+  // Replaces the contents with copies of those in the range [first, last).
+  template <typename Iter,
+            typename = std::enable_if_t<
+                base_internal::IsAtLeastInputIterator<Iter>::value>>
+  void assign(Iter first, Iter last) {
+    auto out = begin();
+    Block* prev_block = nullptr;
+
+    // Overwrite existing elements.
+    for (; out != end() && first != last; ++first) {
+      // Track the previous block so we can correctly update tail_ if we stop
+      // exactly at a block boundary.
+      if (out.ptr + 1 == out.block->limit()) {
+        prev_block = out.block;
+      }
+      *out = *first;
+      ++out;
+    }
+
+    // If we stopped exactly at the start of a block (meaning the previous block
+    // was full), we must ensure tail_ points to the end of the previous block,
+    // not the start of the current (now empty and to be deleted) block.
+    // This maintains the invariant required by back() which assumes tail_
+    // never points to the start of a block (unless it's the only block).
+    if (!empty() && out.block != nullptr && out.ptr == out.block->start() &&
+        prev_block != nullptr) {
+      // Delete the current block and all subsequent blocks.
+      //
+      // NOTE: Calling EraseAllFrom on an iterator that points to the limit of
+      // the previous block will not delete any element from the previous block.
+      iterator prev_block_end(prev_block);
+      prev_block_end.ptr = prev_block->limit();
+      EraseAllFrom(prev_block_end);
+
+      // Update tail_ to point to the end of the previous block.
+      tail_ = prev_block_end;
+      prev_block->set_next(nullptr);
+    } else {
+      // Standard erase from the current position to the end.
+      EraseAllFrom(out);
+    }
+
+    // Append any remaining new elements.
+    for (; first != last; ++first) {
+      push_back(*first);
+    }
+  }
+
+  // Replaces the contents with `count` copies of `value`.
+  void assign(size_type count, const T& value) {
+    clear();
+    for (size_type i = 0; i < count; ++i) {
+      push_back(value);
+    }
+  }
+
+  // Replaces the contents with the elements from the initializer list `il`.
+  void assign(std::initializer_list<T> il) { assign(il.begin(), il.end()); }
+
+  // Appends the given element value to the end of the container.
+  // Invalidates `end()` iterator. References to other elements remain valid.
+  void push_back(const T& val) { emplace_back(val); }
+  void push_back(T&& val) { emplace_back(std::move(val)); }
+
+  // Appends a new element to the end of the container.
+  // The element is constructed in-place with `args`.
+  // Returns a reference to the new element.
+  // Invalidates `end()` iterator. References to other elements remain valid.
+  template <typename... A>
+  T& emplace_back(A&&... args) {
+    T* storage = AllocateBack();
+    AllocatorTraits::construct(alloc_and_size_.allocator(), storage,
+                               std::forward<A>(args)...);
+    return *storage;
+  }
+
+  // Removes the first element of the container.
+  // Invalidates iterators to the removed element.
+  // REQUIRES: !empty()
+  void pop_front();
+
+  // Returns a reference to the first element in the container.
+  // REQUIRES: !empty()
+  T& front() {
+    ABSL_HARDENING_ASSERT(!empty());
+    return *head_;
+  }
+  const T& front() const {
+    ABSL_HARDENING_ASSERT(!empty());
+    return *head_;
+  }
+
+  // Returns a reference to the last element in the container.
+  // REQUIRES: !empty()
+  T& back() {
+    ABSL_HARDENING_ASSERT(!empty());
+    return *(&*tail_ - 1);
+  }
+  const T& back() const {
+    ABSL_HARDENING_ASSERT(!empty());
+    return *(&*tail_ - 1);
+  }
+
+  // Swaps the contents of this queue with `other`.
+  void swap(chunked_queue& other) noexcept {
+    using std::swap;
+    swap(head_, other.head_);
+    swap(tail_, other.tail_);
+    if (AllocatorTraits::propagate_on_container_swap::value) {
+      swap(alloc_and_size_, other.alloc_and_size_);
+    } else {
+      // Swap only the sizes; each object keeps its allocator.
+      //
+      // (It is undefined behavior to swap between two containers with unequal
+      // allocators if propagate_on_container_swap is false, so we don't have to
+      // handle that here like we do in the move-assignment operator.)
+      ABSL_HARDENING_ASSERT(get_allocator() == other.get_allocator());
+      swap(alloc_and_size_.size, other.alloc_and_size_.size);
+    }
+  }
+
+  // Erases all elements from the container.
+  // Note: Leaves one empty block allocated as an optimization.
+  // To free all memory, call shrink_to_fit() after calling clear().
+  void clear();
+
+  iterator begin() { return head_; }
+  iterator end() { return tail_; }
+
+  const_iterator begin() const { return head_; }
+  const_iterator end() const { return tail_; }
+
+  const_iterator cbegin() const { return head_; }
+  const_iterator cend() const { return tail_; }
+
+  // Returns the allocator associated with the container.
+  allocator_type get_allocator() const { return alloc_and_size_.allocator(); }
+
+ private:
+  // Empty base-class optimization: bundle storage for our allocator together
+  // with a field we had to store anyway (size), via inheriting from the
+  // allocator, so this allocator instance doesn't consume any storage
+  // when its type has no data members.
+  struct AllocatorAndSize : private allocator_type {
+    explicit AllocatorAndSize(const allocator_type& alloc)
+        : allocator_type(alloc) {}
+    const allocator_type& allocator() const { return *this; }
+    allocator_type& allocator() { return *this; }
+    size_t size = 0;
+  };
+
+  template <typename Iter>
+  void RangeInit(Iter first, Iter last, std::input_iterator_tag) {
+    while (first != last) {
+      AddTailBlock();
+      for (; first != last && tail_.ptr != tail_.limit;
+           ++alloc_and_size_.size, ++tail_.ptr, ++first) {
+        AllocatorTraits::construct(alloc_and_size_.allocator(), tail_.ptr,
+                                   *first);
+      }
+    }
+  }
+
+  void Construct(T* start, T* limit) {
+    ABSL_ASSERT(start <= limit);
+    for (; start != limit; ++start) {
+      AllocatorTraits::construct(alloc_and_size_.allocator(), start);
+    }
+  }
+
+  size_t Destroy(T* start, T* limit) {
+    ABSL_ASSERT(start <= limit);
+    const size_t n = limit - start;
+    for (; start != limit; ++start) {
+      AllocatorTraits::destroy(alloc_and_size_.allocator(), start);
+    }
+    return n;
+  }
+
+  T* block_begin(Block* b) const {
+    return b == head_.block ? head_.ptr : b->start();
+  }
+  T* block_end(Block* b) const {
+    // We have the choice of !b->next or b == tail_.block to determine if b is
+    // the tail or not. !b->next is usually faster because the caller of
+    // block_end() is most likely traversing the list of blocks so b->next is
+    // already fetched into some register.
+    return !b->next() ? tail_.ptr : b->limit();
+  }
+
+  void AddTailBlock();
+  size_t NewBlockSize() {
+    // Double the last block size and bound to [kBlockSizeMin, kBlockSizeMax].
+    if (!tail_.block) return kBlockSizeMin;
+    return (std::min)(kBlockSizeMax, 2 * tail_.block->size());
+  }
+
+  T* AllocateBack();
+  void EraseAllFrom(iterator i);
+
+  // Destroys any contained elements and destroys all allocated storage.
+  // (Like clear(), except this doesn't leave any empty blocks behind.)
+  void DestroyAndDeallocateAll();
+
+  // The set of elements in the queue is the following:
+  //
+  // (1) When we have just one block:
+  //      [head_.ptr .. tail_.ptr-1]
+  // (2) When we have multiple blocks:
+  //      [head_.ptr .. head_.limit-1]
+  //      ... concatenation of all elements from interior blocks ...
+  //      [tail_.ptr .. tail_.limit-1]
+  //
+  // Rep invariants:
+  // When have just one block:
+  //   head_.limit == tail_.limit == &head_.block->element[kBlockSize]
+  // Always:
+  //   head_.ptr <= head_.limit
+  //   tail_.ptr <= tail_.limit
+
+  iterator head_;
+  iterator tail_;
+  AllocatorAndSize alloc_and_size_;
+};
+
+template <typename T, size_t BLo, size_t BHi, typename Allocator>
+constexpr size_t chunked_queue<T, BLo, BHi, Allocator>::kBlockSizeMin;
+
+template <typename T, size_t BLo, size_t BHi, typename Allocator>
+constexpr size_t chunked_queue<T, BLo, BHi, Allocator>::kBlockSizeMax;
+
+template <typename T, size_t BLo, size_t BHi, typename Allocator>
+inline void swap(chunked_queue<T, BLo, BHi, Allocator>& a,
+                 chunked_queue<T, BLo, BHi, Allocator>& b) noexcept {
+  a.swap(b);
+}
+
+template <typename T, size_t BLo, size_t BHi, typename Allocator>
+chunked_queue<T, BLo, BHi, Allocator>&
+chunked_queue<T, BLo, BHi, Allocator>::operator=(
+    chunked_queue&& other) noexcept {
+  if (this == &other) {
+    return *this;
+  }
+  DestroyAndDeallocateAll();
+
+  if constexpr (AllocatorTraits::propagate_on_container_move_assignment::
+                    value) {
+    // Take over the storage of "other", along with its allocator.
+    head_ = other.head_;
+    tail_ = other.tail_;
+    alloc_and_size_ = std::move(other.alloc_and_size_);
+    other.head_ = {};
+    other.tail_ = {};
+    other.alloc_and_size_.size = 0;
+  } else if (get_allocator() == other.get_allocator()) {
+    // Take over the storage of "other", with which we share an allocator.
+    head_ = other.head_;
+    tail_ = other.tail_;
+    alloc_and_size_.size = other.alloc_and_size_.size;
+    other.head_ = {};
+    other.tail_ = {};
+    other.alloc_and_size_.size = 0;
+  } else {
+    // We cannot take over of the storage from "other", since it has a different
+    // allocator; we're stuck move-assigning elements individually.
+    for (auto& elem : other) {
+      push_back(std::move(elem));
+    }
+  }
+  return *this;
+}
+
+template <typename T, size_t BLo, size_t BHi, typename Allocator>
+inline chunked_queue<T, BLo, BHi, Allocator>::~chunked_queue() {
+  Block* b = head_.block;
+  while (b) {
+    Block* next = b->next();
+    Destroy(block_begin(b), block_end(b));
+    Block::Delete(b, &alloc_and_size_.allocator());
+    b = next;
+  }
+}
+
+template <typename T, size_t BLo, size_t BHi, typename Allocator>
+void chunked_queue<T, BLo, BHi, Allocator>::resize(size_t new_size) {
+  while (new_size > size()) {
+    ptrdiff_t to_add = new_size - size();
+    if (tail_.ptr == tail_.limit) {
+      AddTailBlock();
+    }
+    T* start = tail_.ptr;
+    T* limit = (std::min)(tail_.limit, start + to_add);
+    Construct(start, limit);
+    tail_.ptr = limit;
+    alloc_and_size_.size += limit - start;
+  }
+  if (size() == new_size) {
+    return;
+  }
+  ABSL_ASSERT(new_size < size());
+  auto new_end = begin();
+  new_end.IncrBy(new_size);
+  ABSL_ASSERT(new_end != end());
+  EraseAllFrom(new_end);
+}
+
+template <typename T, size_t BLo, size_t BHi, typename Allocator>
+inline void chunked_queue<T, BLo, BHi, Allocator>::AddTailBlock() {
+  ABSL_ASSERT(tail_.ptr == tail_.limit);
+  auto* b = Block::New(NewBlockSize(), &alloc_and_size_.allocator());
+  if (!head_.block) {
+    ABSL_ASSERT(!tail_.block);
+    head_ = iterator(b);
+  } else {
+    ABSL_ASSERT(tail_.block);
+    tail_.block->set_next(b);
+  }
+  tail_ = iterator(b);
+}
+
+template <typename T, size_t BLo, size_t BHi, typename Allocator>
+inline T* chunked_queue<T, BLo, BHi, Allocator>::AllocateBack() {
+  if (tail_.ptr == tail_.limit) {
+    AddTailBlock();
+  }
+  ++alloc_and_size_.size;
+  return tail_.ptr++;
+}
+
+template <typename T, size_t BLo, size_t BHi, typename Allocator>
+inline void chunked_queue<T, BLo, BHi, Allocator>::EraseAllFrom(iterator i) {
+  if (!i.block) {
+    return;
+  }
+  ABSL_ASSERT(i.ptr);
+  ABSL_ASSERT(i.limit);
+  alloc_and_size_.size -= Destroy(i.ptr, block_end(i.block));
+  Block* b = i.block->next();
+  while (b) {
+    Block* next = b->next();
+    alloc_and_size_.size -= Destroy(b->start(), block_end(b));
+    Block::Delete(b, &alloc_and_size_.allocator());
+    b = next;
+  }
+  tail_ = i;
+  tail_.block->set_next(nullptr);
+}
+
+template <typename T, size_t BLo, size_t BHi, typename Allocator>
+inline void chunked_queue<T, BLo, BHi, Allocator>::DestroyAndDeallocateAll() {
+  Block* b = head_.block;
+  while (b) {
+    Block* next = b->next();
+    Destroy(block_begin(b), block_end(b));
+    Block::Delete(b, &alloc_and_size_.allocator());
+    b = next;
+  }
+  head_ = iterator();
+  tail_ = iterator();
+  alloc_and_size_.size = 0;
+}
+
+template <typename T, size_t BLo, size_t BHi, typename Allocator>
+inline void chunked_queue<T, BLo, BHi, Allocator>::pop_front() {
+  ABSL_HARDENING_ASSERT(!empty());
+  ABSL_ASSERT(head_.block);
+  AllocatorTraits::destroy(alloc_and_size_.allocator(), head_.ptr);
+  ++head_.ptr;
+  --alloc_and_size_.size;
+  if (empty()) {
+    // Reset head and tail to the start of the (only) block.
+    ABSL_ASSERT(head_.block == tail_.block);
+    head_.ptr = tail_.ptr = head_.block->start();
+    return;
+  }
+  if (head_.ptr == head_.limit) {
+    Block* n = head_.block->next();
+    Block::Delete(head_.block, &alloc_and_size_.allocator());
+    head_ = iterator(n);
+  }
+}
+
+template <typename T, size_t BLo, size_t BHi, typename Allocator>
+void chunked_queue<T, BLo, BHi, Allocator>::clear() {
+  // NOTE: As an optimization we leave one block allocated.
+  Block* b = head_.block;
+  if (!b) {
+    ABSL_ASSERT(empty());
+    return;
+  }
+  while (b) {
+    Block* next = b->next();
+    Destroy(block_begin(b), block_end(b));
+    if (head_.block != b) {
+      Block::Delete(b, &alloc_and_size_.allocator());
+    }
+    b = next;
+  }
+  b = head_.block;
+  b->set_next(nullptr);
+  head_ = tail_ = iterator(b);
+  alloc_and_size_.size = 0;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_CHUNKED_QUEUE_H_
diff --git a/absl/container/chunked_queue_benchmark.cc b/absl/container/chunked_queue_benchmark.cc
new file mode 100644
index 0000000..ee4d3c1
--- /dev/null
+++ b/absl/container/chunked_queue_benchmark.cc
@@ -0,0 +1,386 @@
+// Copyright 2025 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 <cstddef>
+#include <cstdint>
+#include <deque>
+#include <forward_list>
+#include <list>
+#include <random>
+
+#include "absl/container/chunked_queue.h"
+#include "absl/random/random.h"
+#include "absl/status/status.h"
+#include "absl/strings/cord.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+// Queue implementation using std::forward_list. Used to benchmark
+// absl::chunked_queue against another plausable implementation.
+template <typename T>
+class forward_list_queue {
+ public:
+  using iterator = typename std::forward_list<T>::iterator;
+
+  forward_list_queue() = default;
+  ~forward_list_queue() = default;
+
+  template <typename... Args>
+  void emplace_back(Args&&... args) {
+    if (list_.empty()) {
+      list_.emplace_front(std::forward<Args>(args)...);
+      tail_ = list_.begin();
+    } else {
+      list_.emplace_after(tail_, std::forward<Args>(args)...);
+      ++tail_;
+    }
+  }
+
+  void push_back(const T& value) { emplace_back(value); }
+  iterator begin() { return list_.begin(); }
+  iterator end() { return list_.end(); }
+  T& front() { return list_.front(); }
+  const T& front() const { return list_.front(); }
+  void pop_front() { list_.pop_front(); }
+  bool empty() const { return list_.empty(); }
+  void clear() { list_.clear(); }
+
+ private:
+  std::forward_list<T> list_;
+  typename std::forward_list<T>::iterator tail_;
+};
+
+template <class T>
+using Deque = std::deque<T>;
+template <class T>
+using List = std::list<T>;
+template <class T>
+using FwdList = forward_list_queue<T>;
+template <class T>
+using Chunked = absl::chunked_queue<T>;
+template <class T>
+using ExpChunked = absl::chunked_queue<T, 2, 64>;
+
+class Element {
+ public:
+  Element() : Element(-1) {}
+  Element(int type) : type_(type) {}      // NOLINT
+  operator int() const { return type_; }  // NOLINT
+
+ private:
+  int type_;
+  absl::Cord item_;
+  absl::Status status_;
+};
+
+template <class Q>
+Q MakeQueue(int64_t num_elements) {
+  Q q;
+  for (int64_t i = 0; i < num_elements; i++) {
+    q.push_back(static_cast<int>(i));
+  }
+  return q;
+}
+
+void CustomArgs(benchmark::internal::Benchmark* b) {
+  b->Arg(1 << 4);
+  b->Arg(1 << 10);
+  b->Arg(1 << 17);
+}
+
+template <class Q>
+void BM_construct(benchmark::State& state) {
+  for (auto s : state) {
+    Q q;
+    benchmark::DoNotOptimize(q);
+  }
+}
+
+BENCHMARK_TEMPLATE(BM_construct, Deque<int64_t>);
+BENCHMARK_TEMPLATE(BM_construct, List<int64_t>);
+BENCHMARK_TEMPLATE(BM_construct, FwdList<int64_t>);
+BENCHMARK_TEMPLATE(BM_construct, Chunked<int64_t>);
+BENCHMARK_TEMPLATE(BM_construct, ExpChunked<int64_t>);
+BENCHMARK_TEMPLATE(BM_construct, Deque<Element>);
+BENCHMARK_TEMPLATE(BM_construct, List<Element>);
+BENCHMARK_TEMPLATE(BM_construct, FwdList<Element>);
+BENCHMARK_TEMPLATE(BM_construct, Chunked<Element>);
+BENCHMARK_TEMPLATE(BM_construct, ExpChunked<Element>);
+
+template <class Q>
+void BM_destroy(benchmark::State& state) {
+  const int64_t num_elements = state.range(0);
+
+  for (auto s : state) {
+    state.PauseTiming();
+    {
+      Q q = MakeQueue<Q>(num_elements);
+      benchmark::DoNotOptimize(q);
+      state.ResumeTiming();
+    }
+  }
+  state.SetItemsProcessed(state.iterations() * num_elements);
+}
+
+BENCHMARK_TEMPLATE(BM_destroy, Deque<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_destroy, List<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_destroy, FwdList<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_destroy, Chunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_destroy, ExpChunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_destroy, Deque<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_destroy, List<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_destroy, FwdList<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_destroy, Chunked<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_destroy, ExpChunked<Element>)->Apply(CustomArgs);
+
+template <class Q>
+void BM_push_back(benchmark::State& state) {
+  const int64_t num_elements = state.range(0);
+
+  state.SetItemsProcessed(state.max_iterations * num_elements);
+  for (auto s : state) {
+    state.PauseTiming();
+    Q q;
+    state.ResumeTiming();
+    for (int j = 0; j < num_elements; j++) q.push_back(j);
+    benchmark::DoNotOptimize(q);
+  }
+}
+
+BENCHMARK_TEMPLATE(BM_push_back, Deque<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_push_back, List<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_push_back, FwdList<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_push_back, Chunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_push_back, ExpChunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_push_back, Deque<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_push_back, List<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_push_back, FwdList<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_push_back, Chunked<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_push_back, ExpChunked<Element>)->Apply(CustomArgs);
+
+template <class Q>
+void BM_pop_front(benchmark::State& state) {
+  const int64_t num_elements = state.range(0);
+
+  state.SetItemsProcessed(state.max_iterations * num_elements);
+  for (auto s : state) {
+    state.PauseTiming();
+    Q q = MakeQueue<Q>(num_elements);
+    state.ResumeTiming();
+    for (int j = 0; j < num_elements; j++) q.pop_front();
+    benchmark::DoNotOptimize(q);
+  }
+}
+
+BENCHMARK_TEMPLATE(BM_pop_front, Deque<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_pop_front, List<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_pop_front, FwdList<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_pop_front, Chunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_pop_front, ExpChunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_pop_front, Deque<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_pop_front, List<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_pop_front, FwdList<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_pop_front, Chunked<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_pop_front, ExpChunked<Element>)->Apply(CustomArgs);
+
+template <class Q>
+void BM_clear(benchmark::State& state) {
+  const int64_t num_elements = state.range(0);
+
+  state.SetItemsProcessed(state.max_iterations * num_elements);
+  for (auto s : state) {
+    state.PauseTiming();
+    Q q = MakeQueue<Q>(num_elements);
+    state.ResumeTiming();
+    q.clear();
+    benchmark::DoNotOptimize(q);
+  }
+}
+
+BENCHMARK_TEMPLATE(BM_clear, Deque<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_clear, List<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_clear, FwdList<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_clear, Chunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_clear, ExpChunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_clear, Deque<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_clear, List<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_clear, FwdList<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_clear, Chunked<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_clear, ExpChunked<Element>)->Apply(CustomArgs);
+
+template <class Q>
+void BM_iter(benchmark::State& state) {
+  const int64_t num_elements = state.range(0);
+
+  state.SetItemsProcessed(state.max_iterations * num_elements);
+  for (auto s : state) {
+    state.PauseTiming();
+    Q q = MakeQueue<Q>(state.max_iterations);
+    int sum = 0;
+    state.ResumeTiming();
+    for (const auto& v : q) sum += v;
+    benchmark::DoNotOptimize(sum);
+  }
+}
+
+BENCHMARK_TEMPLATE(BM_iter, Deque<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_iter, List<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_iter, FwdList<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_iter, Chunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_iter, ExpChunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_iter, Deque<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_iter, List<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_iter, FwdList<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_iter, Chunked<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_iter, ExpChunked<Element>)->Apply(CustomArgs);
+
+template <class Q>
+void BM_resize_shrink(benchmark::State& state) {
+  const int64_t num_elements = state.range(0);
+
+  state.SetItemsProcessed(state.max_iterations * num_elements);
+  for (auto s : state) {
+    state.PauseTiming();
+    Q q = MakeQueue<Q>(num_elements * 2);
+    state.ResumeTiming();
+    q.resize(num_elements);
+    benchmark::DoNotOptimize(q);
+  }
+}
+
+// FwdList does not support resize.
+BENCHMARK_TEMPLATE(BM_resize_shrink, Deque<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_resize_shrink, List<int64_t>)->Apply(CustomArgs);
+// BENCHMARK_TEMPLATE(BM_resize_shrink, FwdList<int64>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_resize_shrink, Chunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_resize_shrink, ExpChunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_resize_shrink, Deque<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_resize_shrink, List<Element>)->Apply(CustomArgs);
+// BENCHMARK_TEMPLATE(BM_resize_shrink, FwdList<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_resize_shrink, Chunked<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_resize_shrink, ExpChunked<Element>)->Apply(CustomArgs);
+
+template <class Q>
+void BM_resize_grow(benchmark::State& state) {
+  const int64_t num_elements = state.range(0);
+
+  state.SetItemsProcessed(state.max_iterations * num_elements);
+  for (auto s : state) {
+    state.PauseTiming();
+    Q q = MakeQueue<Q>(num_elements);
+    state.ResumeTiming();
+    q.resize(static_cast<size_t>(num_elements) * 2);
+    benchmark::DoNotOptimize(q);
+  }
+}
+
+// FwdList does not support resize.
+BENCHMARK_TEMPLATE(BM_resize_grow, Deque<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_resize_grow, List<int64_t>)->Apply(CustomArgs);
+// BENCHMARK_TEMPLATE(BM_resize_grow, FwdList<int64>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_resize_grow, Chunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_resize_grow, ExpChunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_resize_grow, Deque<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_resize_grow, List<Element>)->Apply(CustomArgs);
+// BENCHMARK_TEMPLATE(BM_resize_grow, FwdList<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_resize_grow, Chunked<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_resize_grow, ExpChunked<Element>)->Apply(CustomArgs);
+
+template <class Q>
+void BM_assign_shrink(benchmark::State& state) {
+  const int64_t num_elements = state.range(0);
+
+  state.SetItemsProcessed(state.max_iterations * num_elements);
+  for (auto s : state) {
+    state.PauseTiming();
+    const Q src = MakeQueue<Q>(num_elements);
+    Q dst = MakeQueue<Q>(num_elements * 2);
+    state.ResumeTiming();
+    dst = src;
+    benchmark::DoNotOptimize(dst);
+  }
+}
+
+BENCHMARK_TEMPLATE(BM_assign_shrink, Deque<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_assign_shrink, List<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_assign_shrink, FwdList<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_assign_shrink, Chunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_assign_shrink, ExpChunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_assign_shrink, Deque<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_assign_shrink, List<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_assign_shrink, FwdList<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_assign_shrink, Chunked<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_assign_shrink, ExpChunked<Element>)->Apply(CustomArgs);
+
+template <class Q>
+void BM_assign_grow(benchmark::State& state) {
+  const int64_t num_elements = state.range(0);
+
+  state.SetItemsProcessed(state.max_iterations * num_elements);
+  for (auto s : state) {
+    state.PauseTiming();
+    const Q src = MakeQueue<Q>(num_elements * 2);
+    Q dst = MakeQueue<Q>(num_elements);
+    state.ResumeTiming();
+    dst = src;
+    benchmark::DoNotOptimize(dst);
+  }
+}
+
+BENCHMARK_TEMPLATE(BM_assign_grow, Deque<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_assign_grow, List<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_assign_grow, FwdList<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_assign_grow, Chunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_assign_grow, ExpChunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_assign_grow, Deque<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_assign_grow, List<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_assign_grow, FwdList<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_assign_grow, Chunked<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_assign_grow, ExpChunked<Element>)->Apply(CustomArgs);
+
+template <class Q>
+void BM_push_pop(benchmark::State& state) {
+  const int64_t num_elements = state.range(0);
+
+  state.SetItemsProcessed(state.max_iterations * num_elements);
+
+  std::mt19937 rnd;
+  for (auto s : state) {
+    state.PauseTiming();
+    Q q;
+    state.ResumeTiming();
+    for (int j = 0; j < num_elements; j++) {
+      if (q.empty() || absl::Bernoulli(rnd, 0.5)) {
+        q.push_back(state.iterations());
+      } else {
+        q.pop_front();
+      }
+    }
+    benchmark::DoNotOptimize(q);
+  }
+}
+
+BENCHMARK_TEMPLATE(BM_push_pop, Deque<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_push_pop, List<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_push_pop, FwdList<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_push_pop, Chunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_push_pop, ExpChunked<int64_t>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_push_pop, Deque<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_push_pop, List<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_push_pop, FwdList<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_push_pop, Chunked<Element>)->Apply(CustomArgs);
+BENCHMARK_TEMPLATE(BM_push_pop, ExpChunked<Element>)->Apply(CustomArgs);
+
+}  // namespace
diff --git a/absl/container/chunked_queue_test.cc b/absl/container/chunked_queue_test.cc
new file mode 100644
index 0000000..d394ec4
--- /dev/null
+++ b/absl/container/chunked_queue_test.cc
@@ -0,0 +1,768 @@
+// Copyright 2025 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/container/chunked_queue.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <deque>
+#include <forward_list>
+#include <iterator>
+#include <list>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/macros.h"
+#include "absl/container/internal/test_allocator.h"
+#include "absl/strings/str_cat.h"
+
+using ::testing::ElementsAre;
+using ::testing::Pair;
+using ::testing::Pointee;
+using ::testing::SizeIs;
+
+// Hide in a namespace to make sure swap is found via ADL.
+namespace adl_namespace {
+namespace {
+TEST(ChunkedQueueADLTest, Swap) {
+  absl::chunked_queue<int64_t> q1;
+  absl::chunked_queue<int64_t> q2;
+  q1.push_back(4);
+  q2.push_back(5);
+  q2.push_back(6);
+  swap(q1, q2);
+  EXPECT_THAT(q1, ElementsAre(5, 6));
+  EXPECT_THAT(q2, ElementsAre(4));
+}
+}  // namespace
+}  // namespace adl_namespace
+
+namespace {
+
+template <class T>
+using ChunkedQueueBlock =
+    absl::container_internal::ChunkedQueueBlock<T, std::allocator<T>>;
+
+TEST(Internal, elements_in_bytes) {
+  EXPECT_EQ(size_t{1}, ChunkedQueueBlock<int>::block_size_from_bytes(0));
+  EXPECT_EQ(size_t{1}, ChunkedQueueBlock<int>::block_size_from_bytes(
+                           sizeof(ChunkedQueueBlock<int>)));
+  EXPECT_EQ(size_t{1},
+            ChunkedQueueBlock<int>::block_size_from_bytes(sizeof(int)));
+  EXPECT_EQ(size_t{2}, ChunkedQueueBlock<int>::block_size_from_bytes(
+                           sizeof(ChunkedQueueBlock<int>) + 2 * sizeof(int)));
+}
+
+TEST(Internal, BlockSizedDelete) {
+  struct Item {
+    int i;
+    char c;
+  };
+  std::allocator<Item> allocator;
+  auto* block = ChunkedQueueBlock<Item>::New(3, &allocator);
+  ChunkedQueueBlock<Item>::Delete(block, &allocator);
+}
+
+template <size_t elem_size>
+void BlockSizeRounding() {
+  struct Elem {
+    char data[elem_size];
+  };
+  typedef ChunkedQueueBlock<Elem> Block;
+  for (size_t n = 1; n < 100; ++n) {
+    SCOPED_TRACE(n);
+    std::allocator<Elem> allocator;
+    Block* b = Block::New(n, &allocator);
+    EXPECT_GE(b->size(), n);
+    Block::Delete(b, &allocator);
+  }
+}
+
+TEST(Internal, BlockSizeRounding1) { BlockSizeRounding<1>(); }
+TEST(Internal, BlockSizeRounding17) { BlockSizeRounding<17>(); }
+TEST(Internal, BlockSizeRounding101) { BlockSizeRounding<101>(); }
+TEST(Internal, BlockSizeRounding528) { BlockSizeRounding<528>(); }
+
+TEST(ChunkedQueue, MinMaxBlockSize) {
+  absl::chunked_queue<int64_t, 1, 2> q = {1, 2, 3};
+  EXPECT_THAT(q, ElementsAre(1, 2, 3));
+}
+
+TEST(ChunkedQueue, Empty) {
+  absl::chunked_queue<int64_t> q;
+  EXPECT_TRUE(q.empty());
+  q.push_back(10);
+  EXPECT_FALSE(q.empty());
+  EXPECT_EQ(q.front(), 10);
+  EXPECT_EQ(q.back(), 10);
+  q.pop_front();
+  EXPECT_TRUE(q.empty());
+  q.clear();
+  EXPECT_TRUE(q.empty());
+}
+
+TEST(ChunkedQueue, CopyConstruct) {
+  absl::chunked_queue<int64_t> q;
+  q.push_back(1);
+  absl::chunked_queue<int64_t> r(q);
+  EXPECT_THAT(r, ElementsAre(1));
+  EXPECT_EQ(1, r.size());
+}
+
+TEST(ChunkedQueue, CopyConstructMultipleChunks) {
+  absl::chunked_queue<int64_t, 2> q;
+  q.push_back(1);
+  q.push_back(2);
+  q.push_back(3);
+  absl::chunked_queue<int64_t, 2> r(q);
+  EXPECT_THAT(r, ElementsAre(1, 2, 3));
+  EXPECT_EQ(3, r.size());
+}
+
+TEST(ChunkedQueue, BeginEndConstruct) {
+  std::vector<int64_t> src = {1, 2, 3, 4, 5};
+  absl::chunked_queue<int64_t, 2> q(src.begin(), src.end());
+  EXPECT_THAT(q, ElementsAre(1, 2, 3, 4, 5));
+  EXPECT_EQ(5, q.size());
+}
+
+TEST(ChunkedQueue, InitializerListConstruct) {
+  absl::chunked_queue<int64_t, 2> q = {1, 2, 3, 4, 5};
+  EXPECT_THAT(q, ElementsAre(1, 2, 3, 4, 5));
+  EXPECT_EQ(5, q.size());
+}
+
+TEST(ChunkedQueue, CountConstruct) {
+  absl::chunked_queue<int64_t> q(3);
+  EXPECT_THAT(q, ElementsAre(0, 0, 0));
+  EXPECT_EQ(3, q.size());
+}
+
+TEST(ChunkedQueue, CountValueConstruct) {
+  absl::chunked_queue<int64_t> q(3, 10);
+  EXPECT_THAT(q, ElementsAre(10, 10, 10));
+  EXPECT_EQ(3, q.size());
+}
+
+TEST(ChunkedQueue, InitializerListAssign) {
+  absl::chunked_queue<int64_t, 2> q;
+  q = {1, 2, 3, 4, 5};
+  EXPECT_THAT(q, ElementsAre(1, 2, 3, 4, 5));
+  EXPECT_EQ(5, q.size());
+}
+
+TEST(ChunkedQueue, CopyAssign) {
+  absl::chunked_queue<int64_t> q;
+  q.push_back(1);
+  absl::chunked_queue<int64_t> r = q;
+  EXPECT_THAT(r, ElementsAre(1));
+}
+
+TEST(ChunkedQueue, CopyAssignSelf) {
+  absl::chunked_queue<int64_t> q;
+  q.push_back(1);
+  q = *&q;  // Avoid -Wself-assign.
+  EXPECT_THAT(q, ElementsAre(1));
+  EXPECT_EQ(1, q.size());
+}
+
+TEST(ChunkedQueue, CopyAssignDestinationBigger) {
+  absl::chunked_queue<int64_t> q;
+  q.push_back(1);
+  absl::chunked_queue<int64_t> r;
+  r.push_back(9);
+  r.push_back(9);
+  r.push_back(9);
+  r = q;
+  EXPECT_THAT(r, ElementsAre(1));
+  EXPECT_EQ(1, r.size());
+}
+
+TEST(ChunkedQueue, CopyAssignSourceBiggerMultipleChunks) {
+  absl::chunked_queue<int64_t, 2> q;
+  q.push_back(1);
+  q.push_back(2);
+  q.push_back(3);
+  absl::chunked_queue<int64_t, 2> r;
+  r.push_back(9);
+  r = q;
+  EXPECT_THAT(r, ElementsAre(1, 2, 3));
+  EXPECT_EQ(3, r.size());
+}
+
+TEST(ChunkedQueue, CopyAssignDestinationBiggerMultipleChunks) {
+  absl::chunked_queue<int64_t, 2> q;
+  q.push_back(1);
+  absl::chunked_queue<int64_t, 2> r;
+  r.push_back(9);
+  r.push_back(9);
+  r.push_back(9);
+  r = q;
+  EXPECT_THAT(r, ElementsAre(1));
+  EXPECT_EQ(1, r.size());
+}
+
+TEST(ChunkedQueue, AssignCountValue) {
+  absl::chunked_queue<int64_t> q;
+  q.assign(3, 10);
+  EXPECT_THAT(q, ElementsAre(10, 10, 10));
+  EXPECT_EQ(3, q.size());
+
+  q.assign(2, 20);
+  EXPECT_THAT(q, ElementsAre(20, 20));
+  EXPECT_EQ(2, q.size());
+}
+
+TEST(ChunkedQueue, MoveConstruct) {
+  absl::chunked_queue<int64_t> q;
+  q.push_back(1);
+  absl::chunked_queue<int64_t> r(std::move(q));
+  EXPECT_THAT(r, ElementsAre(1));
+  EXPECT_EQ(1, r.size());
+}
+
+TEST(ChunkedQueue, MoveAssign) {
+  absl::chunked_queue<int64_t> q;
+  q.push_back(1);
+  absl::chunked_queue<int64_t> r;
+  r = std::move(q);
+  EXPECT_THAT(r, ElementsAre(1));
+  EXPECT_EQ(1, r.size());
+}
+
+TEST(ChunkedQueue, MoveAssignImmovable) {
+  struct Immovable {
+    Immovable() = default;
+
+    Immovable(const Immovable&) = delete;
+    Immovable& operator=(const Immovable&) = delete;
+    Immovable(Immovable&&) = delete;
+    Immovable& operator=(Immovable&&) = delete;
+  };
+  absl::chunked_queue<Immovable> q;
+  q.emplace_back();
+  absl::chunked_queue<Immovable> r;
+  r = std::move(q);
+  EXPECT_THAT(r, SizeIs(1));
+}
+
+TEST(ChunkedQueue, MoveAssignSelf) {
+  absl::chunked_queue<int64_t> q;
+  absl::chunked_queue<int64_t>& q2 = q;
+  q.push_back(1);
+  q = std::move(q2);
+  EXPECT_THAT(q, ElementsAre(1));
+  EXPECT_EQ(1, q.size());
+}
+
+TEST(ChunkedQueue, MoveAssignDestinationBigger) {
+  absl::chunked_queue<int64_t> q;
+  q.push_back(1);
+  absl::chunked_queue<int64_t> r;
+  r.push_back(9);
+  r.push_back(9);
+  r.push_back(9);
+  r = std::move(q);
+  EXPECT_THAT(r, ElementsAre(1));
+  EXPECT_EQ(1, r.size());
+}
+
+TEST(ChunkedQueue, MoveAssignDestinationBiggerMultipleChunks) {
+  absl::chunked_queue<int64_t, 2> q;
+  q.push_back(1);
+  absl::chunked_queue<int64_t, 2> r;
+  r.push_back(9);
+  r.push_back(9);
+  r.push_back(9);
+  r = std::move(q);
+  EXPECT_THAT(r, ElementsAre(1));
+  EXPECT_EQ(1, r.size());
+}
+
+TEST(ChunkedQueue, ConstFrontBack) {
+  absl::chunked_queue<int64_t> q;
+  q.push_back(10);
+  EXPECT_EQ(q.front(), 10);
+  EXPECT_EQ(q.back(), 10);
+  q.front() = 12;
+  EXPECT_EQ(q.front(), 12);
+  EXPECT_EQ(q.back(), 12);
+
+  const absl::chunked_queue<int64_t>& qref = q;
+  EXPECT_EQ(qref.front(), 12);
+  EXPECT_EQ(qref.back(), 12);
+
+  q.pop_front();
+
+  // Test at block bloundary and beyond
+  for (int i = 0; i < 64; ++i) q.push_back(i + 10);
+  EXPECT_EQ(q.front(), 10);
+  EXPECT_EQ(q.back(), 73);
+
+  for (int i = 64; i < 128; ++i) q.push_back(i + 10);
+  EXPECT_EQ(q.front(), 10);
+  EXPECT_EQ(q.back(), 137);
+  q.clear();
+  EXPECT_TRUE(q.empty());
+}
+
+TEST(ChunkedQueue, PushAndPop) {
+  absl::chunked_queue<int64_t> q;
+  EXPECT_TRUE(q.empty());
+  EXPECT_EQ(0, q.size());
+  for (int i = 0; i < 10000; i++) {
+    q.push_back(i);
+    EXPECT_EQ(q.front(), 0) << ": iteration " << i;
+    EXPECT_FALSE(q.empty());
+    EXPECT_EQ(i + 1, q.size());
+  }
+  for (int i = 0; i < 10000; i++) {
+    EXPECT_FALSE(q.empty());
+    EXPECT_EQ(10000 - i, q.size());
+    EXPECT_EQ(q.front(), i);
+    q.pop_front();
+  }
+  EXPECT_TRUE(q.empty());
+  EXPECT_EQ(0, q.size());
+}
+
+TEST(ChunkedQueue, Swap) {
+  absl::chunked_queue<int64_t> q1;
+  absl::chunked_queue<int64_t> q2;
+  q1.push_back(4);
+  q2.push_back(5);
+  q2.push_back(6);
+  q2.swap(q1);
+  EXPECT_EQ(2, q1.size());
+  EXPECT_EQ(5, q1.front());
+  EXPECT_EQ(1, q2.size());
+  EXPECT_EQ(4, q2.front());
+  q1.pop_front();
+  q1.swap(q2);
+  EXPECT_EQ(1, q1.size());
+  EXPECT_EQ(4, q1.front());
+  EXPECT_EQ(1, q2.size());
+  EXPECT_EQ(6, q2.front());
+  q1.pop_front();
+  q1.swap(q2);
+  EXPECT_EQ(1, q1.size());
+  EXPECT_EQ(6, q1.front());
+  EXPECT_EQ(0, q2.size());
+  q1.clear();
+  EXPECT_TRUE(q1.empty());
+}
+
+TEST(ChunkedQueue, ShrinkToFit) {
+  absl::chunked_queue<int64_t> q;
+  q.shrink_to_fit();  // Should work on empty
+  EXPECT_TRUE(q.empty());
+
+  q.push_back(1);
+  q.shrink_to_fit();  // Should work on non-empty
+  EXPECT_THAT(q, ElementsAre(1));
+
+  q.clear();
+  // We know clear leaves a block and shrink_to_fit should remove it.
+  // Hard to test internal memory state without mocks or inspection.
+  // But at least we verify it doesn't crash or corrupt.
+  q.shrink_to_fit();
+  EXPECT_TRUE(q.empty());
+}
+
+TEST(ChunkedQueue, ResizeExtends) {
+  absl::chunked_queue<int64_t> q;
+  q.resize(2);
+  EXPECT_THAT(q, ElementsAre(0, 0));
+  EXPECT_EQ(2, q.size());
+}
+
+TEST(ChunkedQueue, ResizeShrinks) {
+  absl::chunked_queue<int64_t> q;
+  q.push_back(1);
+  q.push_back(2);
+  q.resize(1);
+  EXPECT_THAT(q, ElementsAre(1));
+  EXPECT_EQ(1, q.size());
+}
+
+TEST(ChunkedQueue, ResizeExtendsMultipleBlocks) {
+  absl::chunked_queue<int64_t, 2> q;
+  q.resize(3);
+  EXPECT_THAT(q, ElementsAre(0, 0, 0));
+  EXPECT_EQ(3, q.size());
+}
+
+TEST(ChunkedQueue, ResizeShrinksMultipleBlocks) {
+  absl::chunked_queue<int64_t, 2> q;
+  q.push_back(1);
+  q.push_back(2);
+  q.push_back(3);
+  q.resize(1);
+  EXPECT_THAT(q, ElementsAre(1));
+  EXPECT_EQ(1, q.size());
+}
+
+TEST(ChunkedQueue, ResizeValue) {
+  absl::chunked_queue<int64_t> q;
+  q.resize(3, 10);
+  EXPECT_THAT(q, ElementsAre(10, 10, 10));
+  EXPECT_EQ(3, q.size());
+
+  q.resize(5, 20);
+  EXPECT_THAT(q, ElementsAre(10, 10, 10, 20, 20));
+  EXPECT_EQ(5, q.size());
+
+  q.resize(2, 30);
+  EXPECT_THAT(q, ElementsAre(10, 10));
+  EXPECT_EQ(2, q.size());
+}
+
+TEST(ChunkedQueue, MaxSize) {
+  absl::chunked_queue<int64_t> q;
+  EXPECT_GE(q.max_size(),
+            size_t{1} << (sizeof(size_t) * 8 - sizeof(int64_t) - 4));
+}
+
+TEST(ChunkedQueue, AssignExtends) {
+  absl::chunked_queue<int64_t, 2> q;
+  std::vector<int64_t> v = {1, 2, 3, 4, 5};
+  q.assign(v.begin(), v.end());
+  EXPECT_THAT(q, ElementsAre(1, 2, 3, 4, 5));
+  EXPECT_EQ(5, q.size());
+}
+
+TEST(ChunkedQueue, AssignShrinks) {
+  absl::chunked_queue<int64_t, 2> q = {1, 2, 3, 4, 5};
+  std::vector<int64_t> v = {1};
+  q.assign(v.begin(), v.end());
+  EXPECT_THAT(q, ElementsAre(1));
+  EXPECT_EQ(1, q.size());
+}
+
+TEST(ChunkedQueue, AssignBoundaryCondition) {
+  // Create a queue with fixed block size of 4.
+  // 3 blocks: [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]
+  absl::chunked_queue<int, 4> q = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
+
+  // Assign a range that fills exactly the first block (4 elements).
+  // This triggers the boundary condition where the assignment loop ends
+  // exactly at the limit of the first block.
+  std::vector<int> v = {101, 102, 103, 104};
+  q.assign(v.begin(), v.end());
+
+  EXPECT_EQ(q.size(), 4);
+  EXPECT_EQ(q.front(), 101);
+  // Verify back() is valid. If tail_ was incorrectly pointing to the start
+  // of the (now deleted) second block, this might access invalid memory
+  // or fail assertions.
+  EXPECT_EQ(q.back(), 104);
+
+  // Verify we can continue to push elements correctly.
+  q.push_back(105);
+  EXPECT_EQ(q.size(), 5);
+  EXPECT_EQ(q.back(), 105);
+}
+
+TEST(ChunkedQueue, Iterator) {
+  absl::chunked_queue<int64_t> q;
+  EXPECT_TRUE(q.begin() == q.end());
+
+  q.push_back(1);
+  absl::chunked_queue<int64_t>::const_iterator iter = q.begin();
+  ASSERT_FALSE(iter == q.end());
+  ASSERT_EQ(*iter, 1);
+  ++iter;
+  ASSERT_TRUE(iter == q.end());
+
+  q.push_back(2);
+  iter = q.begin();
+  ASSERT_EQ(*iter, 1);
+  ++iter;
+  absl::chunked_queue<int64_t>::const_iterator copy_iter = iter;
+  ASSERT_FALSE(copy_iter == q.end());
+  ASSERT_EQ(*copy_iter, 2);
+  ++copy_iter;
+  ASSERT_TRUE(copy_iter == q.end());
+
+  copy_iter = iter;
+  ASSERT_FALSE(iter == q.end());
+  ASSERT_EQ(*iter, 2);
+  ++iter;
+  ASSERT_TRUE(iter == q.end());
+
+  ASSERT_FALSE(copy_iter == q.end());
+  ASSERT_EQ(*copy_iter, 2);
+  ++copy_iter;
+  ASSERT_TRUE(copy_iter == q.end());
+}
+
+TEST(ChunkedQueue, IteratorDefaultConstructor) {
+  using ConstIter = absl::chunked_queue<int64_t>::const_iterator;
+  using Iter = absl::chunked_queue<int64_t>::iterator;
+  ConstIter const_iter;
+  EXPECT_TRUE(const_iter == ConstIter());
+  Iter iter;
+  EXPECT_TRUE(iter == Iter());
+}
+
+TEST(ChunkedQueue, IteratorConversion) {
+  using ConstIter = absl::chunked_queue<int64_t>::const_iterator;
+  using Iter = absl::chunked_queue<int64_t>::iterator;
+  EXPECT_FALSE((std::is_convertible<ConstIter, Iter>::value));
+  EXPECT_TRUE((std::is_convertible<Iter, ConstIter>::value));
+  absl::chunked_queue<int64_t> q;
+  ConstIter it1 = q.begin();
+  ConstIter it2 = q.cbegin();
+  Iter it3 = q.begin();
+  it1 = q.end();
+  it2 = q.cend();
+  it3 = q.end();
+  EXPECT_FALSE((std::is_assignable<Iter, ConstIter>::value));
+}
+
+struct TestEntry {
+  int x, y;
+};
+
+TEST(ChunkedQueue, Iterator2) {
+  absl::chunked_queue<TestEntry> q;
+  TestEntry e;
+  e.x = 1;
+  e.y = 2;
+  q.push_back(e);
+  e.x = 3;
+  e.y = 4;
+  q.push_back(e);
+
+  absl::chunked_queue<TestEntry>::const_iterator iter = q.begin();
+  EXPECT_EQ(iter->x, 1);
+  EXPECT_EQ(iter->y, 2);
+  ++iter;
+  EXPECT_EQ(iter->x, 3);
+  EXPECT_EQ(iter->y, 4);
+  ++iter;
+  EXPECT_TRUE(iter == q.end());
+}
+
+TEST(ChunkedQueue, Iterator_MultipleBlocks) {
+  absl::chunked_queue<int64_t> q;
+  for (int i = 0; i < 130; ++i) {
+    absl::chunked_queue<int64_t>::const_iterator iter = q.begin();
+    for (int j = 0; j < i; ++j) {
+      ASSERT_FALSE(iter == q.end());
+      EXPECT_EQ(*iter, j);
+      ++iter;
+    }
+    ASSERT_TRUE(iter == q.end());
+    q.push_back(i);
+  }
+
+  for (int i = 0; i < 130; ++i) {
+    absl::chunked_queue<int64_t>::const_iterator iter = q.begin();
+    for (int j = i; j < 130; ++j) {
+      ASSERT_FALSE(iter == q.end());
+      EXPECT_EQ(*iter, j);
+      ++iter;
+    }
+    q.pop_front();
+  }
+  EXPECT_TRUE(q.empty());
+  EXPECT_TRUE(q.begin() == q.end());
+}
+
+TEST(ChunkedQueue, Iterator_PopFrontInvalidate) {
+  absl::chunked_queue<int64_t> q;
+  for (int i = 0; i < 130; ++i) {
+    q.push_back(i);
+  }
+
+  auto iter = q.begin();
+  for (int i = 0; i < 130; ++i) {
+    auto prev = iter++;
+    ASSERT_FALSE(prev == q.end());
+    EXPECT_EQ(*prev, i);
+    q.pop_front();
+  }
+  ASSERT_TRUE(q.empty());
+}
+
+TEST(ChunkedQueue, Iterator_PushBackInvalidate) {
+  absl::chunked_queue<int64_t, 2> q;
+  q.push_back(0);
+  auto i = q.begin();
+  EXPECT_EQ(*i, 0);
+  q.push_back(1);
+  EXPECT_EQ(*++i, 1);
+  q.push_back(2);
+  EXPECT_EQ(*++i, 2);
+}
+
+struct MyType {
+  static int constructor_calls;
+  static int destructor_calls;
+
+  explicit MyType(int x) : val(x) { constructor_calls++; }
+  MyType(const MyType& t) : val(t.val) { constructor_calls++; }
+  ~MyType() { destructor_calls++; }
+
+  int val;
+};
+
+int MyType::constructor_calls = 0;
+int MyType::destructor_calls = 0;
+
+TEST(ChunkedQueue, ConstructorDestructorCalls) {
+  for (int i = 0; i < 100; i++) {
+    std::vector<MyType> vals;
+    for (int j = 0; j < i; j++) {
+      vals.push_back(MyType(j));
+    }
+    MyType::constructor_calls = 0;
+    MyType::destructor_calls = 0;
+    {
+      absl::chunked_queue<MyType> q;
+      for (int j = 0; j < i; j++) {
+        q.push_back(vals[j]);
+      }
+      if (i % 10 == 0) {
+        q.clear();
+      } else {
+        for (int j = 0; j < i; j++) {
+          EXPECT_EQ(q.front().val, j);
+          q.pop_front();
+        }
+      }
+    }
+    EXPECT_EQ(MyType::constructor_calls, i);
+    EXPECT_EQ(MyType::destructor_calls, i);
+  }
+}
+
+TEST(ChunkedQueue, MoveObjects) {
+  absl::chunked_queue<std::unique_ptr<int>> q;
+  q.push_back(std::make_unique<int>(10));
+  q.push_back(std::make_unique<int>(11));
+
+  EXPECT_EQ(10, *q.front());
+  q.pop_front();
+  EXPECT_EQ(11, *q.front());
+  q.pop_front();
+}
+
+TEST(ChunkedQueue, EmplaceBack1) {
+  absl::chunked_queue<std::pair<int, int>> q;
+  auto& v = q.emplace_back(1, 2);
+  EXPECT_THAT(v, Pair(1, 2));
+  EXPECT_THAT(q.front(), Pair(1, 2));
+  EXPECT_EQ(&v, &q.back());
+}
+
+TEST(ChunkedQueue, EmplaceBack2) {
+  absl::chunked_queue<std::pair<std::unique_ptr<int>, std::string>> q;
+  auto& v = q.emplace_back(std::make_unique<int>(11), "val12");
+  EXPECT_THAT(v, Pair(Pointee(11), "val12"));
+  EXPECT_THAT(q.front(), Pair(Pointee(11), "val12"));
+}
+
+TEST(ChunkedQueue, OveralignmentEmplaceBack) {
+  struct alignas(64) Overaligned {
+    int x;
+    int y;
+  };
+  absl::chunked_queue<Overaligned, 1, 8> q;
+  for (int i = 0; i < 10; ++i) {
+    auto& v = q.emplace_back(Overaligned{i, i});
+    EXPECT_EQ(reinterpret_cast<uintptr_t>(&v) % 64, 0);
+  }
+}
+
+TEST(ChunkedQueue, StatelessAllocatorDoesntAffectObjectSizes) {
+  // When a stateless allocator type is used -- such as when no explicit
+  // allocator type is given, and the stateless default is used -- it does not
+  // increase the object sizes from what they used to be before allocator
+  // support was added.  (In practice this verifies that allocator support makes
+  // use of the empty base-class optimization.)
+  //
+  // These "Mock*" structs model the data members of absl::chunked_queue<> and
+  // its internal ChunkedQueueBlock<> type, without any extra storage for
+  // allocator state.  (We use these to generate expected stateless-allocator
+  // object sizes in a portable way.)
+  struct MockQueue {
+    struct MockIterator {
+      void* block;
+      void* ptr;
+      void* limit;
+    };
+    MockIterator head;
+    MockIterator tail;
+    size_t size;
+  };
+  struct MockBlock {
+    void* next;
+    void* limit;
+  };
+  using TestQueueType = absl::chunked_queue<int64_t, 1, 16>;
+  EXPECT_EQ(sizeof(TestQueueType), sizeof(MockQueue));
+  EXPECT_EQ(sizeof(absl::container_internal::ChunkedQueueBlock<
+                   TestQueueType::value_type, TestQueueType::allocator_type>),
+            sizeof(MockBlock));
+}
+
+TEST(ChunkedQueue, DoesNotRoundBlockSizesUpWithNonDefaultAllocator) {
+  using OneByte = uint8_t;
+  using CustomAllocator = absl::container_internal::CountingAllocator<OneByte>;
+  using Block =
+      absl::container_internal::ChunkedQueueBlock<OneByte, CustomAllocator>;
+  int64_t allocator_live_bytes = 0;
+  CustomAllocator allocator(&allocator_live_bytes);
+  // Create a Block big enough to accomodate at least 1 OneByte.
+  Block* b = Block::New(1, &allocator);
+  ASSERT_TRUE(b != nullptr);
+  // With a non-default allocator in play, the resulting block should have
+  // capacity for exactly 1 element -- the implementation should not round the
+  // allocation size up, which may be inappropriate for non-default allocators.
+  //
+  // (Note that we don't always round up even with the default allocator in use,
+  // e.g. when compiling for ASAN analysis.)
+  EXPECT_EQ(b->size(), 1);
+  Block::Delete(b, &allocator);
+}
+
+TEST(ChunkedQueue, Hardening) {
+  bool hardened = false;
+  ABSL_HARDENING_ASSERT([&hardened]() {
+    hardened = true;
+    return true;
+  }());
+  if (!hardened) {
+    GTEST_SKIP() << "Not a hardened build";
+  }
+
+  absl::chunked_queue<int> q;
+  EXPECT_DEATH(q.front(), "");
+  EXPECT_DEATH(q.back(), "");
+  EXPECT_DEATH(q.pop_front(), "");
+
+  const absl::chunked_queue<int> cq;
+  EXPECT_DEATH(cq.front(), "");
+  EXPECT_DEATH(cq.back(), "");
+}
+
+}  // namespace
diff --git a/absl/container/fixed_array.h b/absl/container/fixed_array.h
index 6c238fc..d47b0e4 100644
--- a/absl/container/fixed_array.h
+++ b/absl/container/fixed_array.h
@@ -84,11 +84,9 @@
   static constexpr size_t kInlineBytesDefault = 256;
 
   using AllocatorTraits = std::allocator_traits<A>;
-  // std::iterator_traits isn't guaranteed to be SFINAE-friendly until C++17,
-  // but this seems to be mostly pedantic.
   template <typename Iterator>
-  using EnableIfForwardIterator = std::enable_if_t<
-      base_internal::IsAtLeastForwardIterator<Iterator>::value>;
+  using EnableIfInputIterator =
+      std::enable_if_t<base_internal::IsAtLeastInputIterator<Iterator>::value>;
   static constexpr bool NoexceptCopyable() {
     return std::is_nothrow_copy_constructible<StorageElement>::value &&
            absl::allocator_is_nothrow<allocator_type>::value;
@@ -161,8 +159,8 @@
 
   // Creates an array initialized with the elements from the input
   // range. The array's size will always be `std::distance(first, last)`.
-  // REQUIRES: Iterator must be a forward_iterator or better.
-  template <typename Iterator, EnableIfForwardIterator<Iterator>* = nullptr>
+  // REQUIRES: Iterator must be a input_iterator or better.
+  template <typename Iterator, EnableIfInputIterator<Iterator>* = nullptr>
   FixedArray(Iterator first, Iterator last,
              const allocator_type& a = allocator_type())
       : storage_(std::distance(first, last), a) {
@@ -392,8 +390,7 @@
 
   template <typename H>
   friend H AbslHashValue(H h, const FixedArray& v) {
-    return H::combine(H::combine_contiguous(std::move(h), v.data(), v.size()),
-                      hash_internal::WeaklyMixedInteger{v.size()});
+    return H::combine_contiguous(std::move(h), v.data(), v.size());
   }
 
  private:
diff --git a/absl/container/flat_hash_map.h b/absl/container/flat_hash_map.h
index bc86ced..7ce3353 100644
--- a/absl/container/flat_hash_map.h
+++ b/absl/container/flat_hash_map.h
@@ -115,25 +115,29 @@
 //   absl::flat_hash_map<std::string, std::string> ducks =
 //     {{"a", "huey"}, {"b", "dewey"}, {"c", "louie"}};
 //
-//  // Insert a new element into the flat hash map
-//  ducks.insert({"d", "donald"});
+//   // Insert a new element into the flat hash map
+//   ducks.insert({"d", "donald"});
 //
-//  // Force a rehash of the flat hash map
-//  ducks.rehash(0);
+//   // Force a rehash of the flat hash map
+//   ducks.rehash(0);
 //
-//  // Find the element with the key "b"
-//  std::string search_key = "b";
-//  auto result = ducks.find(search_key);
-//  if (result != ducks.end()) {
-//    std::cout << "Result: " << result->second << std::endl;
-//  }
-template <class K, class V, class Hash = DefaultHashContainerHash<K>,
-          class Eq = DefaultHashContainerEq<K>,
-          class Allocator = std::allocator<std::pair<const K, V>>>
+//   // Find the element with the key "b"
+//   std::string search_key = "b";
+//   auto result = ducks.find(search_key);
+//   if (result != ducks.end()) {
+//     std::cout << "Result: " << result->second << std::endl;
+//   }
+template <
+    class K, class V,
+    class Hash =
+        typename container_internal::FlatHashMapPolicy<K, V>::DefaultHash,
+    class Eq = typename container_internal::FlatHashMapPolicy<K, V>::DefaultEq,
+    class Allocator =
+        typename container_internal::FlatHashMapPolicy<K, V>::DefaultAlloc>
 class ABSL_ATTRIBUTE_OWNER flat_hash_map
-    : public absl::container_internal::raw_hash_map<
+    : public absl::container_internal::InstantiateRawHashMap<
           absl::container_internal::FlatHashMapPolicy<K, V>, Hash, Eq,
-          Allocator> {
+          Allocator>::type {
   using Base = typename flat_hash_map::raw_hash_map;
 
  public:
@@ -158,9 +162,9 @@
   //
   // * Copy assignment operator
   //
-  //  // Hash functor and Comparator are copied as well
-  //  absl::flat_hash_map<int, std::string> map4;
-  //  map4 = map3;
+  //   // Hash functor and Comparator are copied as well
+  //   absl::flat_hash_map<int, std::string> map4;
+  //   map4 = map3;
   //
   // * Move constructor
   //
@@ -462,7 +466,9 @@
   //
   // Sets the number of slots in the `flat_hash_map` to the number needed to
   // accommodate at least `count` total elements without exceeding the current
-  // maximum load factor, and may rehash the container if needed.
+  // maximum load factor, and may rehash the container if needed. After this
+  // returns, it is guaranteed that `count - size()` elements can be inserted
+  // into the `flat_hash_map` without another rehash.
   using Base::reserve;
 
   // flat_hash_map::at()
@@ -635,6 +641,10 @@
   using mapped_type = V;
   using init_type = std::pair</*non const*/ key_type, mapped_type>;
 
+  using DefaultHash = DefaultHashContainerHash<K>;
+  using DefaultEq = DefaultHashContainerEq<K>;
+  using DefaultAlloc = std::allocator<std::pair<const K, V>>;
+
   template <class Allocator, class... Args>
   static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
     slot_policy::construct(alloc, slot, std::forward<Args>(args)...);
@@ -660,10 +670,10 @@
                                                    std::forward<Args>(args)...);
   }
 
-  template <class Hash>
+  template <class Hash, bool kIsDefault>
   static constexpr HashSlotFn get_hash_slot_fn() {
     return memory_internal::IsLayoutCompatible<K, V>::value
-               ? &TypeErasedApplyToSlotFn<Hash, K>
+               ? &TypeErasedApplyToSlotFn<Hash, K, kIsDefault>
                : nullptr;
   }
 
diff --git a/absl/container/flat_hash_map_test.cc b/absl/container/flat_hash_map_test.cc
index 5c83c94..73f28c7 100644
--- a/absl/container/flat_hash_map_test.cc
+++ b/absl/container/flat_hash_map_test.cc
@@ -39,8 +39,7 @@
 ABSL_NAMESPACE_BEGIN
 namespace container_internal {
 namespace {
-using ::absl::container_internal::hash_internal::Enum;
-using ::absl::container_internal::hash_internal::EnumClass;
+
 using ::testing::_;
 using ::testing::IsEmpty;
 using ::testing::Pair;
@@ -116,15 +115,6 @@
 
 TEST(FlatHashMap, Relocatability) {
   static_assert(absl::is_trivially_relocatable<int>::value);
-#if ABSL_INTERNAL_CPLUSPLUS_LANG <= 202002L
-  // std::pair is not trivially copyable in C++23 in some standard
-  // library versions.
-  // See https://github.com/llvm/llvm-project/pull/95444 for instance.
-  // container_memory.h contains a workaround so what really matters
-  // is the transfer test below.
-  static_assert(
-      absl::is_trivially_relocatable<std::pair<const int, int>>::value);
-#endif
   static_assert(
       std::is_same<decltype(absl::container_internal::FlatHashMapPolicy<
                             int, int>::transfer<std::allocator<char>>(nullptr,
diff --git a/absl/container/flat_hash_set.h b/absl/container/flat_hash_set.h
index bf63eb5..a469fa0 100644
--- a/absl/container/flat_hash_set.h
+++ b/absl/container/flat_hash_set.h
@@ -114,22 +114,26 @@
 //   absl::flat_hash_set<std::string> ducks =
 //     {"huey", "dewey", "louie"};
 //
-//  // Insert a new element into the flat hash set
-//  ducks.insert("donald");
+//   // Insert a new element into the flat hash set
+//   ducks.insert("donald");
 //
-//  // Force a rehash of the flat hash set
-//  ducks.rehash(0);
+//   // Force a rehash of the flat hash set
+//   ducks.rehash(0);
 //
-//  // See if "dewey" is present
-//  if (ducks.contains("dewey")) {
-//    std::cout << "We found dewey!" << std::endl;
-//  }
-template <class T, class Hash = DefaultHashContainerHash<T>,
-          class Eq = DefaultHashContainerEq<T>,
-          class Allocator = std::allocator<T>>
+//   // See if "dewey" is present
+//   if (ducks.contains("dewey")) {
+//     std::cout << "We found dewey!" << std::endl;
+//   }
+template <
+    class T,
+    class Hash = typename container_internal::FlatHashSetPolicy<T>::DefaultHash,
+    class Eq = typename container_internal::FlatHashSetPolicy<T>::DefaultEq,
+    class Allocator =
+        typename container_internal::FlatHashSetPolicy<T>::DefaultAlloc>
 class ABSL_ATTRIBUTE_OWNER flat_hash_set
-    : public absl::container_internal::raw_hash_set<
-          absl::container_internal::FlatHashSetPolicy<T>, Hash, Eq, Allocator> {
+    : public absl::container_internal::InstantiateRawHashSet<
+          absl::container_internal::FlatHashSetPolicy<T>, Hash, Eq,
+          Allocator>::type {
   using Base = typename flat_hash_set::raw_hash_set;
 
  public:
@@ -154,9 +158,9 @@
   //
   // * Copy assignment operator
   //
-  //  // Hash functor and Comparator are copied as well
-  //  absl::flat_hash_set<std::string> set4;
-  //  set4 = set3;
+  //   // Hash functor and Comparator are copied as well
+  //   absl::flat_hash_set<std::string> set4;
+  //   set4 = set3;
   //
   // * Move constructor
   //
@@ -396,7 +400,9 @@
   //
   // Sets the number of slots in the `flat_hash_set` to the number needed to
   // accommodate at least `count` total elements without exceeding the current
-  // maximum load factor, and may rehash the container if needed.
+  // maximum load factor, and may rehash the container if needed. After this
+  // returns, it is guaranteed that `count - size()` elements can be inserted
+  // into the `flat_hash_set` without another rehash.
   using Base::reserve;
 
   // flat_hash_set::contains()
@@ -533,6 +539,10 @@
   using init_type = T;
   using constant_iterators = std::true_type;
 
+  using DefaultHash = DefaultHashContainerHash<T>;
+  using DefaultEq = DefaultHashContainerEq<T>;
+  using DefaultAlloc = std::allocator<T>;
+
   template <class Allocator, class... Args>
   static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
     absl::allocator_traits<Allocator>::construct(*alloc, slot,
@@ -558,9 +568,9 @@
 
   static size_t space_used(const T*) { return 0; }
 
-  template <class Hash>
+  template <class Hash, bool kIsDefault>
   static constexpr HashSlotFn get_hash_slot_fn() {
-    return &TypeErasedApplyToSlotFn<Hash, T>;
+    return &TypeErasedApplyToSlotFn<Hash, T, kIsDefault>;
   }
 };
 }  // namespace container_internal
diff --git a/absl/container/flat_hash_set_test.cc b/absl/container/flat_hash_set_test.cc
index bb90efa..9b6a6d1 100644
--- a/absl/container/flat_hash_set_test.cc
+++ b/absl/container/flat_hash_set_test.cc
@@ -43,8 +43,6 @@
 namespace container_internal {
 namespace {
 
-using ::absl::container_internal::hash_internal::Enum;
-using ::absl::container_internal::hash_internal::EnumClass;
 using ::testing::IsEmpty;
 using ::testing::Pointee;
 using ::testing::UnorderedElementsAre;
@@ -383,6 +381,20 @@
   EXPECT_THAT(s, UnorderedElementsAre(1, 2, 3));
 }
 
+TEST(FlatHashSet, IsDefaultHash) {
+  using absl::container_internal::hashtable_debug_internal::
+      HashtableDebugAccess;
+  EXPECT_EQ(HashtableDebugAccess<flat_hash_set<int>>::kIsDefaultHash, true);
+  EXPECT_EQ(HashtableDebugAccess<flat_hash_set<std::string>>::kIsDefaultHash,
+            true);
+
+  struct Hash {
+    size_t operator()(size_t i) const { return i; }
+  };
+  EXPECT_EQ((HashtableDebugAccess<flat_hash_set<size_t, Hash>>::kIsDefaultHash),
+            false);
+}
+
 }  // namespace
 }  // namespace container_internal
 ABSL_NAMESPACE_END
diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h
index f871b34..6b05d92 100644
--- a/absl/container/inlined_vector.h
+++ b/absl/container/inlined_vector.h
@@ -815,13 +815,11 @@
   // `InlinedVector::clear()`
   //
   // Destroys all elements in the inlined vector, setting the size to `0` and
-  // deallocating any held memory.
+  // preserving capacity.
   void clear() noexcept {
     inlined_vector_internal::DestroyAdapter<A>::DestroyElements(
         storage_.GetAllocator(), data(), size());
-    storage_.DeallocateIfAllocated();
-
-    storage_.SetInlinedSize(0);
+    storage_.SetSize(0);
   }
 
   // `InlinedVector::reserve(...)`
@@ -1008,9 +1006,17 @@
 // call this directly.
 template <typename H, typename T, size_t N, typename A>
 H AbslHashValue(H h, const absl::InlinedVector<T, N, A>& a) {
-  auto size = a.size();
-  return H::combine(H::combine_contiguous(std::move(h), a.data(), size),
-                    hash_internal::WeaklyMixedInteger{size});
+  return H::combine_contiguous(std::move(h), a.data(), a.size());
+}
+
+template <typename T, size_t N, typename A, typename Predicate>
+constexpr typename InlinedVector<T, N, A>::size_type erase_if(
+    InlinedVector<T, N, A>& v, Predicate pred) {
+  const auto it = std::remove_if(v.begin(), v.end(), std::move(pred));
+  const auto removed = static_cast<typename InlinedVector<T, N, A>::size_type>(
+      std::distance(it, v.end()));
+  v.erase(it, v.end());
+  return removed;
 }
 
 ABSL_NAMESPACE_END
diff --git a/absl/container/inlined_vector_test.cc b/absl/container/inlined_vector_test.cc
index ff0e77b..1e3ff82 100644
--- a/absl/container/inlined_vector_test.cc
+++ b/absl/container/inlined_vector_test.cc
@@ -51,6 +51,7 @@
 using testing::Each;
 using testing::ElementsAre;
 using testing::ElementsAreArray;
+using testing::IsEmpty;
 using testing::Eq;
 using testing::Gt;
 using testing::Pointee;
@@ -919,7 +920,9 @@
     SCOPED_TRACE(len);
     IntVec v;
     Fill(&v, len);
+    size_t capacity_before_clear = v.capacity();
     v.clear();
+    EXPECT_EQ(v.capacity(), capacity_before_clear);
     EXPECT_EQ(0u, v.size());
     EXPECT_EQ(v.begin(), v.end());
   }
@@ -2254,4 +2257,22 @@
             sizeof(MySpan<int>) / sizeof(int));
 }
 
+TEST(IntVec, EraseIf) {
+  IntVec v = {3, 1, 2, 0};
+  EXPECT_EQ(absl::erase_if(v, [](int i) { return i > 1; }), 2u);
+  EXPECT_THAT(v, ElementsAre(1, 0));
+}
+
+TEST(IntVec, EraseIfMatchesNone) {
+  IntVec v = {1, 2, 3};
+  EXPECT_EQ(absl::erase_if(v, [](int i) { return i > 10; }), 0u);;
+  EXPECT_THAT(v, ElementsAre(1, 2, 3));
+}
+
+TEST(IntVec, EraseIfMatchesAll) {
+  IntVec v = {1, 2, 3};
+  EXPECT_EQ(absl::erase_if(v, [](int i) { return i > 0; }), 3u);
+  EXPECT_THAT(v, IsEmpty());
+}
+
 }  // anonymous namespace
diff --git a/absl/container/internal/btree_container.h b/absl/container/internal/btree_container.h
index 21f00ae..e1649e3 100644
--- a/absl/container/internal/btree_container.h
+++ b/absl/container/internal/btree_container.h
@@ -640,12 +640,12 @@
   }
   template <class K = key_type, int = EnableIf<LifetimeBoundK<K, false>>()>
   mapped_type &operator[](key_arg<K> &&k) ABSL_ATTRIBUTE_LIFETIME_BOUND {
-    return try_emplace(std::forward<K>(k)).first->second;
+    return try_emplace(std::forward<key_arg<K>>(k)).first->second;
   }
   template <class K = key_type, int &..., EnableIf<LifetimeBoundK<K, true>> = 0>
   mapped_type &operator[](key_arg<K> &&k ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(
       this)) ABSL_ATTRIBUTE_LIFETIME_BOUND {
-    return this->template operator[]<K, 0>(std::forward<K>(k));
+    return this->template operator[]<K, 0>(std::forward<key_arg<K>>(k));
   }
 
   template <typename K = key_type>
@@ -672,27 +672,36 @@
   std::pair<iterator, bool> insert_or_assign_impl(K &&k, M &&obj) {
     const std::pair<iterator, bool> ret =
         this->tree_.insert_unique(k, std::forward<K>(k), std::forward<M>(obj));
-    if (!ret.second) ret.first->second = std::forward<M>(obj);
+    if (!ret.second) {
+      // NOLINTNEXTLINE(bugprone-use-after-move)
+      ret.first->second = std::forward<M>(obj);
+    }
     return ret;
   }
   template <class K, class M>
   iterator insert_or_assign_hint_impl(const_iterator hint, K &&k, M &&obj) {
     const std::pair<iterator, bool> ret = this->tree_.insert_hint_unique(
         iterator(hint), k, std::forward<K>(k), std::forward<M>(obj));
-    if (!ret.second) ret.first->second = std::forward<M>(obj);
+    if (!ret.second) {
+      // NOLINTNEXTLINE(bugprone-use-after-move)
+      ret.first->second = std::forward<M>(obj);
+    }
     return ret.first;
   }
 
   template <class K, class... Args>
   std::pair<iterator, bool> try_emplace_impl(K &&k, Args &&... args) {
     return this->tree_.insert_unique(
+        // NOLINTNEXTLINE(bugprone-use-after-move)
         k, std::piecewise_construct, std::forward_as_tuple(std::forward<K>(k)),
         std::forward_as_tuple(std::forward<Args>(args)...));
   }
   template <class K, class... Args>
   iterator try_emplace_hint_impl(const_iterator hint, K &&k, Args &&... args) {
     return this->tree_
-        .insert_hint_unique(iterator(hint), k, std::piecewise_construct,
+        .insert_hint_unique(iterator(hint),
+                            // NOLINTNEXTLINE(bugprone-use-after-move)
+                            k, std::piecewise_construct,
                             std::forward_as_tuple(std::forward<K>(k)),
                             std::forward_as_tuple(std::forward<Args>(args)...))
         .first;
diff --git a/absl/container/internal/chunked_queue.h b/absl/container/internal/chunked_queue.h
new file mode 100644
index 0000000..c3718ac
--- /dev/null
+++ b/absl/container/internal/chunked_queue.h
@@ -0,0 +1,173 @@
+// Copyright 2025 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.
+
+#ifndef ABSL_CONTAINER_INTERNAL_CHUNKED_QUEUE_H_
+#define ABSL_CONTAINER_INTERNAL_CHUNKED_QUEUE_H_
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <initializer_list>
+#include <iterator>
+#include <memory>
+#include <new>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/macros.h"
+#include "absl/container/internal/layout.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+// ChunkedQueueBlock defines a node in a forward list of uninitialized storage
+// of size T's. The user is responsible for constructing and destroying T's in
+// said storage.
+//
+// ChunkedQueueBlock::New(size) returns said node, with at least size_hint T's
+// of uninitialized storage.
+template <typename T, typename Allocator>
+class ChunkedQueueBlock {
+ private:
+  using ChunkedQueueBlockAllocator = typename std::allocator_traits<
+      Allocator>::template rebind_alloc<ChunkedQueueBlock>;
+  using ByteAllocator =
+      typename std::allocator_traits<Allocator>::template rebind_alloc<char>;
+
+ public:
+  // NB, instances of this must not be created or destroyed directly, only via
+  // the New() and Delete() methods.  (This notionally-private constructor is
+  // public only to allow access from allocator types used by New().)
+  explicit ChunkedQueueBlock(size_t size)
+      : next_(nullptr), limit_(start() + size) {}
+
+  // Must be deleted by ChunkedQueueBlock::Delete.
+  static ChunkedQueueBlock* New(size_t size_hint, Allocator* alloc) {  // NOLINT
+    ABSL_ASSERT(size_hint >= size_t{1});
+    size_t allocation_bytes = AllocSize(size_hint);
+    void* mem;
+    std::tie(mem, allocation_bytes) = Allocate(allocation_bytes, alloc);
+    const size_t element_count =
+        (allocation_bytes - start_offset()) / sizeof(T);
+    ChunkedQueueBlock* as_block = static_cast<ChunkedQueueBlock*>(mem);
+    ChunkedQueueBlockAllocator block_alloc(*alloc);
+    std::allocator_traits<ChunkedQueueBlockAllocator>::construct(
+        block_alloc, as_block, element_count);
+    return as_block;
+  }
+
+  static void Delete(ChunkedQueueBlock* ptr, Allocator* alloc) {
+    const size_t allocation_bytes = AllocSize(ptr->size());
+    ChunkedQueueBlockAllocator block_alloc(*alloc);
+    std::allocator_traits<ChunkedQueueBlockAllocator>::destroy(block_alloc,
+                                                               ptr);
+    if constexpr (std::is_same_v<ByteAllocator, std::allocator<char>>) {
+#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
+      if (alignment() > __STDCPP_DEFAULT_NEW_ALIGNMENT__) {
+        ::operator delete(ptr
+#ifdef __cpp_sized_deallocation
+                          ,
+                          allocation_bytes
+#endif
+                          ,
+                          std::align_val_t(alignment()));
+        return;
+      }
+#endif
+      ::operator delete(ptr);
+    } else {
+      void* mem = ptr;
+      ByteAllocator byte_alloc(*alloc);
+      std::allocator_traits<ByteAllocator>::deallocate(
+          byte_alloc, static_cast<char*>(mem), allocation_bytes);
+    }
+  }
+
+  ChunkedQueueBlock* next() const { return next_; }
+  void set_next(ChunkedQueueBlock* next) { next_ = next; }
+  T* start() {
+    return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(this) +
+                                start_offset());
+  }
+  T* limit() { return limit_; }
+  size_t size() { return limit() - start(); }
+
+  static constexpr size_t block_size_from_bytes(size_t bytes) {
+    return bytes <= static_cast<size_t>(start_offset())
+               ? size_t{1}
+               : elements_in_bytes(bytes - start_offset());
+  }
+
+ private:
+  ChunkedQueueBlock(const ChunkedQueueBlock&) = delete;
+  ChunkedQueueBlock& operator=(const ChunkedQueueBlock&) = delete;
+
+  // The byte size to allocate to ensure space for `min_element_count` elements.
+  static constexpr size_t AllocSize(size_t min_element_count) {
+    return absl::container_internal::Layout<ChunkedQueueBlock, T>(
+               1, min_element_count)
+        .AllocSize();
+  }
+
+  static constexpr ptrdiff_t start_offset() {
+    return absl::container_internal::Layout<ChunkedQueueBlock, T>(1, 1)
+        .template Offset<1>();
+  }
+
+  static constexpr size_t alignment() {
+    return absl::container_internal::Layout<ChunkedQueueBlock, T>(1, 1)
+        .Alignment();
+  }
+
+  static constexpr size_t elements_in_bytes(size_t bytes) {
+    return (bytes + sizeof(T) - 1) / sizeof(T);
+  }
+
+  static std::pair<void*, size_t> Allocate(size_t allocation_bytes,
+                                           Allocator* alloc) {
+    // If we're using the default allocator, then we can use new.
+    void* mem;
+    if constexpr (std::is_same_v<ByteAllocator, std::allocator<char>>) {
+      // Older GCC versions have an unused variable warning on `alloc` inside
+      // this constexpr branch.
+      static_cast<void>(alloc);
+#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
+      if (alignment() > __STDCPP_DEFAULT_NEW_ALIGNMENT__) {
+        // Align the allocation to respect alignof(T).
+        mem = ::operator new(allocation_bytes, std::align_val_t(alignment()));
+        return {mem, allocation_bytes};
+      }
+#endif
+      mem = ::operator new(allocation_bytes);
+    } else {
+      ByteAllocator byte_alloc(*alloc);
+      mem = std::allocator_traits<ByteAllocator>::allocate(byte_alloc,
+                                                           allocation_bytes);
+    }
+    return {mem, allocation_bytes};
+  }
+
+  ChunkedQueueBlock* next_;
+  T* limit_;
+};
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_CHUNKED_QUEUE_H_
diff --git a/absl/container/internal/common.h b/absl/container/internal/common.h
index 5ef6c56..3e263a3 100644
--- a/absl/container/internal/common.h
+++ b/absl/container/internal/common.h
@@ -15,7 +15,10 @@
 #ifndef ABSL_CONTAINER_INTERNAL_COMMON_H_
 #define ABSL_CONTAINER_INTERNAL_COMMON_H_
 
+#include <algorithm>
 #include <cassert>
+#include <cstddef>
+#include <tuple>
 #include <type_traits>
 
 #include "absl/meta/type_traits.h"
@@ -243,6 +246,54 @@
   NodeType node;
 };
 
+// Utilities to strip redundant template parameters from the underlying
+// implementation types.
+// We use a variadic pack (ie Params...) to specify required prefix of types for
+// non-default types, and then we use GetFromListOr to select the provided types
+// or the default ones otherwise.
+//
+// These default types do not contribute information for debugging and just
+// bloat the binary.
+// Removing the redundant tail types reduces mangled names and stringified
+// function names like __PRETTY_FUNCTION__.
+//
+// How to use:
+//  1. Define a template with `typename ...Params`
+//  2. Instantiate it via `ApplyWithoutDefaultSuffix<>` to only pass the minimal
+//     set of types.
+//  3. Inside the template use `GetFromListOr` to map back from the existing
+//     `Params` list to the actual types, filling the gaps when types are
+//     missing.
+
+template <typename Or, size_t N, typename... Params>
+using GetFromListOr = std::tuple_element_t<(std::min)(N, sizeof...(Params)),
+                                           std::tuple<Params..., Or>>;
+
+template <typename... T>
+struct TypeList {
+  template <template <typename...> class Template>
+  using Apply = Template<T...>;
+};
+
+// Evaluate to `Template<TPrefix...>` where the last type in the list (if any)
+// is different from the corresponding one in the default list.
+// Eg
+//   ApplyWithoutDefaultSuffix<Template, TypeList<a, b, c>, TypeList<a, X, c>>
+// evaluates to
+//   Template<a, X>
+template <template <typename...> class Template, typename D, typename T,
+          typename L = TypeList<>, typename = void>
+struct ApplyWithoutDefaultSuffix {
+  using type = typename L::template Apply<Template>;
+};
+template <template <typename...> class Template, typename D, typename... Ds,
+          typename T, typename... Ts, typename... L>
+struct ApplyWithoutDefaultSuffix<
+    Template, TypeList<D, Ds...>, TypeList<T, Ts...>, TypeList<L...>,
+    std::enable_if_t<!std::is_same_v<TypeList<D, Ds...>, TypeList<T, Ts...>>>>
+    : ApplyWithoutDefaultSuffix<Template, TypeList<Ds...>, TypeList<Ts...>,
+                       TypeList<L..., T>> {};
+
 }  // namespace container_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/container/internal/compressed_tuple.h b/absl/container/internal/compressed_tuple.h
index 6db0468..2dd8d6c 100644
--- a/absl/container/internal/compressed_tuple.h
+++ b/absl/container/internal/compressed_tuple.h
@@ -64,24 +64,24 @@
 template <typename D, size_t I>
 using ElemT = typename Elem<D, I>::type;
 
-// We can't use EBCO on other CompressedTuples because that would mean that we
-// derive from multiple Storage<> instantiations with the same I parameter,
-// and potentially from multiple identical Storage<> instantiations.  So anytime
-// we use type inheritance rather than encapsulation, we mark
-// CompressedTupleImpl, to make this easy to detect.
-struct uses_inheritance {};
 
 template <typename T>
 constexpr bool ShouldUseBase() {
   return std::is_class<T>::value && std::is_empty<T>::value &&
-         !std::is_final<T>::value &&
-         !std::is_base_of<uses_inheritance, T>::value;
+         !std::is_final<T>::value;
 }
 
+// Tag type used to disambiguate Storage types for different CompresseedTuples.
+// Without it, CompressedTuple<T, CompressedTuple<T>> would inherit from
+// Storage<T, 0> twice.
+template <typename... Ts>
+struct StorageTag;
+
 // The storage class provides two specializations:
 //  - For empty classes, it stores T as a base class.
 //  - For everything else, it stores T as a member.
-template <typename T, size_t I, bool UseBase = ShouldUseBase<T>()>
+// Tag should be set to StorageTag<Ts...>.
+template <typename T, size_t I, typename Tag, bool UseBase = ShouldUseBase<T>()>
 struct Storage {
   T value;
   constexpr Storage() = default;
@@ -94,8 +94,8 @@
   constexpr T&& get() && { return std::move(*this).value; }
 };
 
-template <typename T, size_t I>
-struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC Storage<T, I, true> : T {
+template <typename T, size_t I, typename Tag>
+struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC Storage<T, I, Tag, true> : T {
   constexpr Storage() = default;
 
   template <typename V>
@@ -111,30 +111,35 @@
 struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl;
 
 template <typename... Ts, size_t... I, bool ShouldAnyUseBase>
-struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl<
-    CompressedTuple<Ts...>, absl::index_sequence<I...>, ShouldAnyUseBase>
+struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
+    CompressedTupleImpl<CompressedTuple<Ts...>, absl::index_sequence<I...>,
+                        ShouldAnyUseBase>
     // We use the dummy identity function through std::integral_constant to
     // convince MSVC of accepting and expanding I in that context. Without it
     // you would get:
     //   error C3548: 'I': parameter pack cannot be used in this context
-    : uses_inheritance,
-      Storage<Ts, std::integral_constant<size_t, I>::value>... {
+    : Storage<Ts, std::integral_constant<size_t, I>::value,
+              StorageTag<Ts...>>... {
   constexpr CompressedTupleImpl() = default;
   template <typename... Vs>
   explicit constexpr CompressedTupleImpl(absl::in_place_t, Vs&&... args)
-      : Storage<Ts, I>(absl::in_place, std::forward<Vs>(args))... {}
+      : Storage<Ts, I, StorageTag<Ts...>>(absl::in_place,
+                                          std::forward<Vs>(args))... {}
   friend CompressedTuple<Ts...>;
 };
 
 template <typename... Ts, size_t... I>
-struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl<
-    CompressedTuple<Ts...>, absl::index_sequence<I...>, false>
+struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
+    CompressedTupleImpl<CompressedTuple<Ts...>, absl::index_sequence<I...>,
+                        false>
     // We use the dummy identity function as above...
-    : Storage<Ts, std::integral_constant<size_t, I>::value, false>... {
+    : Storage<Ts, std::integral_constant<size_t, I>::value, StorageTag<Ts...>,
+              false>... {
   constexpr CompressedTupleImpl() = default;
   template <typename... Vs>
   explicit constexpr CompressedTupleImpl(absl::in_place_t, Vs&&... args)
-      : Storage<Ts, I, false>(absl::in_place, std::forward<Vs>(args))... {}
+      : Storage<Ts, I, StorageTag<Ts...>, false>(absl::in_place,
+                                                 std::forward<Vs>(args))... {}
   friend CompressedTuple<Ts...>;
 };
 
@@ -183,9 +188,7 @@
 // Helper class to perform the Empty Base Class Optimization.
 // Ts can contain classes and non-classes, empty or not. For the ones that
 // are empty classes, we perform the CompressedTuple. If all types in Ts are
-// empty classes, then CompressedTuple<Ts...> is itself an empty class.  (This
-// does not apply when one or more of those empty classes is itself an empty
-// CompressedTuple.)
+// empty classes, then CompressedTuple<Ts...> is itself an empty class.
 //
 // To access the members, use member .get<N>() function.
 //
@@ -208,7 +211,8 @@
   using ElemT = internal_compressed_tuple::ElemT<CompressedTuple, I>;
 
   template <int I>
-  using StorageT = internal_compressed_tuple::Storage<ElemT<I>, I>;
+  using StorageT = internal_compressed_tuple::Storage<
+      ElemT<I>, I, internal_compressed_tuple::StorageTag<Ts...>>;
 
  public:
   // There seems to be a bug in MSVC dealing in which using '=default' here will
diff --git a/absl/container/internal/compressed_tuple_test.cc b/absl/container/internal/compressed_tuple_test.cc
index 01b334e..662f944 100644
--- a/absl/container/internal/compressed_tuple_test.cc
+++ b/absl/container/internal/compressed_tuple_test.cc
@@ -452,14 +452,15 @@
 }
 #endif
 
-// TODO(b/214288561): enable this test.
-TEST(CompressedTupleTest, DISABLED_NestedEbo) {
+TEST(CompressedTupleTest, NestedEbo) {
   struct Empty1 {};
   struct Empty2 {};
   CompressedTuple<Empty1, CompressedTuple<Empty2>, int> x;
   CompressedTuple<Empty1, Empty2, int> y;
-  // Currently fails with sizeof(x) == 8, sizeof(y) == 4.
   EXPECT_EQ(sizeof(x), sizeof(y));
+
+  using NestedEmpty = CompressedTuple<Empty1, CompressedTuple<Empty2>>;
+  EXPECT_TRUE(std::is_empty_v<NestedEmpty>);
 }
 
 }  // namespace
diff --git a/absl/container/internal/container_memory.h b/absl/container/internal/container_memory.h
index e7ac1db..47064a7 100644
--- a/absl/container/internal/container_memory.h
+++ b/absl/container/internal/container_memory.h
@@ -26,6 +26,7 @@
 #include <utility>
 
 #include "absl/base/config.h"
+#include "absl/hash/hash.h"
 #include "absl/memory/memory.h"
 #include "absl/meta/type_traits.h"
 #include "absl/utility/utility.h"
@@ -43,7 +44,12 @@
 namespace container_internal {
 
 template <size_t Alignment>
-struct alignas(Alignment) AlignedType {};
+struct alignas(Alignment) AlignedType {
+  // When alignment is sufficient for the allocated memory to store pointers,
+  // include a pointer member so that swisstable backing arrays end up in the
+  // pointer-containing partition for heap partitioning.
+  std::conditional_t<(Alignment < alignof(void*)), char, void*> pointer;
+};
 
 // Allocates at least n bytes aligned to the specified alignment.
 // Alignment must be a power of 2. It must be positive.
@@ -129,6 +135,7 @@
 template <class T, size_t... Is>
 auto TupleRefImpl(T&& t, absl::index_sequence<Is...>)
     -> decltype(std::forward_as_tuple(std::get<Is>(std::forward<T>(t))...)) {
+  // NOLINTNEXTLINE(bugprone-use-after-move)
   return std::forward_as_tuple(std::get<Is>(std::forward<T>(t))...);
 }
 
@@ -464,24 +471,87 @@
   }
 };
 
+// Suppress erroneous uninitialized memory errors on GCC. For example, GCC
+// thinks that the call to slot_array() in find_or_prepare_insert() is reading
+// uninitialized memory, but slot_array is only called there when the table is
+// non-empty and this memory is initialized when the table is non-empty.
+#if !defined(__clang__) && defined(__GNUC__)
+#define ABSL_SWISSTABLE_IGNORE_UNINITIALIZED(x)                    \
+  _Pragma("GCC diagnostic push")                                   \
+      _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")  \
+          _Pragma("GCC diagnostic ignored \"-Wuninitialized\"") x; \
+  _Pragma("GCC diagnostic pop")
+#define ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(x) \
+  ABSL_SWISSTABLE_IGNORE_UNINITIALIZED(return x)
+#else
+#define ABSL_SWISSTABLE_IGNORE_UNINITIALIZED(x) x
+#define ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(x) return x
+#endif
+
+// Variadic arguments hash function that ignore the rest of the arguments.
+// Useful for usage with policy traits.
+template <class Hash, bool kIsDefault>
+struct HashElement {
+  HashElement(const Hash& h, size_t s) : hash(h), seed(s) {}
+
+  template <class K, class... Args>
+  size_t operator()(const K& key, Args&&...) const {
+    if constexpr (kIsDefault) {
+      // TODO(b/384509507): resolve `no header providing
+      // "absl::hash_internal::SupportsHashWithSeed" is directly included`.
+      // Maybe we should make "internal/hash.h" be a separate library.
+      return absl::hash_internal::HashWithSeed().hash(hash, key, seed);
+    }
+    // NOLINTNEXTLINE(clang-diagnostic-sign-conversion)
+    return hash(key) ^ seed;
+  }
+  const Hash& hash;
+  size_t seed;
+};
+
+// No arguments function hash function for a specific key.
+template <class Hash, class Key, bool kIsDefault>
+struct HashKey {
+  HashKey(const Hash& h, const Key& k) : hash(h), key(k) {}
+
+  size_t operator()(size_t seed) const {
+    return HashElement<Hash, kIsDefault>{hash, seed}(key);
+  }
+  const Hash& hash;
+  const Key& key;
+};
+
+// Variadic arguments equality function that ignore the rest of the arguments.
+// Useful for usage with policy traits.
+template <class K1, class KeyEqual>
+struct EqualElement {
+  template <class K2, class... Args>
+  bool operator()(const K2& lhs, Args&&...) const {
+    ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(eq(lhs, rhs));
+  }
+  const K1& rhs;
+  const KeyEqual& eq;
+};
+
 // Type erased function for computing hash of the slot.
-using HashSlotFn = size_t (*)(const void* hash_fn, void* slot);
+using HashSlotFn = size_t (*)(const void* hash_fn, void* slot, size_t seed);
 
 // Type erased function to apply `Fn` to data inside of the `slot`.
 // The data is expected to have type `T`.
-template <class Fn, class T>
-size_t TypeErasedApplyToSlotFn(const void* fn, void* slot) {
+template <class Fn, class T, bool kIsDefault>
+size_t TypeErasedApplyToSlotFn(const void* fn, void* slot, size_t seed) {
   const auto* f = static_cast<const Fn*>(fn);
-  return (*f)(*static_cast<const T*>(slot));
+  return HashElement<Fn, kIsDefault>{*f, seed}(*static_cast<const T*>(slot));
 }
 
 // Type erased function to apply `Fn` to data inside of the `*slot_ptr`.
 // The data is expected to have type `T`.
-template <class Fn, class T>
-size_t TypeErasedDerefAndApplyToSlotFn(const void* fn, void* slot_ptr) {
+template <class Fn, class T, bool kIsDefault>
+size_t TypeErasedDerefAndApplyToSlotFn(const void* fn, void* slot_ptr,
+                                       size_t seed) {
   const auto* f = static_cast<const Fn*>(fn);
   const T* slot = *static_cast<const T**>(slot_ptr);
-  return (*f)(*slot);
+  return HashElement<Fn, kIsDefault>{*f, seed}(*slot);
 }
 
 }  // namespace container_internal
diff --git a/absl/container/internal/container_memory_test.cc b/absl/container/internal/container_memory_test.cc
index 7e4357d..946d1d3 100644
--- a/absl/container/internal/container_memory_test.cc
+++ b/absl/container/internal/container_memory_test.cc
@@ -25,6 +25,7 @@
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/base/config.h"
 #include "absl/base/no_destructor.h"
 #include "absl/container/internal/test_instance_tracker.h"
 #include "absl/meta/type_traits.h"
@@ -42,6 +43,16 @@
 using ::testing::Gt;
 using ::testing::Pair;
 
+#if ABSL_HAVE_BUILTIN(__builtin_infer_alloc_token)
+TEST(Memory, AlignedTypeAllocToken) {
+#if defined(__wasm__)
+  GTEST_SKIP() << "Fails on wasm due to lack of heap partitioning support.";
+#endif
+  EXPECT_GT(__builtin_infer_alloc_token(sizeof(AlignedType<alignof(void*)>)),
+            __builtin_infer_alloc_token(sizeof(int)));
+}
+#endif
+
 TEST(Memory, AlignmentLargerThanBase) {
   std::allocator<int8_t> alloc;
   void* mem = Allocate<2>(&alloc, 3);
@@ -300,16 +311,46 @@
 
 TEST(ApplyTest, TypeErasedApplyToSlotFn) {
   size_t x = 7;
+  size_t seed = 100;
   auto fn = [](size_t v) { return v * 2; };
-  EXPECT_EQ((TypeErasedApplyToSlotFn<decltype(fn), size_t>(&fn, &x)), 14);
+  EXPECT_EQ(
+      (TypeErasedApplyToSlotFn<decltype(fn), size_t, /*kIsDefault=*/false>(
+          &fn, &x, seed)),
+      (HashElement<decltype(fn), /*kIsDefault=*/false>(fn, seed)(x)));
 }
 
 TEST(ApplyTest, TypeErasedDerefAndApplyToSlotFn) {
   size_t x = 7;
+  size_t seed = 100;
   auto fn = [](size_t v) { return v * 2; };
   size_t* x_ptr = &x;
+  EXPECT_EQ((TypeErasedDerefAndApplyToSlotFn<decltype(fn), size_t,
+                                             /*kIsDefault=*/false>(&fn, &x_ptr,
+                                                                   seed)),
+            (HashElement<decltype(fn), /*kIsDefault=*/false>(fn, seed)(x)));
+}
+
+TEST(HashElement, DefaultHash) {
+  size_t x = 7;
+  size_t seed = 100;
+  struct HashWithSeed {
+    size_t operator()(size_t v) const { return v * 2; }
+    size_t hash_with_seed(size_t v, size_t seed) const {
+      return v * 2 + seed * 3;
+    }
+  } hash;
+  EXPECT_EQ((HashElement<HashWithSeed, /*kIsDefault=*/true>(hash, seed)(x)),
+            hash.hash_with_seed(x, seed));
+}
+
+TEST(HashElement, NonDefaultHash) {
+  size_t x = 7;
+  size_t seed = 100;
+  auto fn = [](size_t v) { return v * 2; };
   EXPECT_EQ(
-      (TypeErasedDerefAndApplyToSlotFn<decltype(fn), size_t>(&fn, &x_ptr)), 14);
+      (HashElement<decltype(fn), /*kIsDefault=*/false>(
+          fn, seed)(x)),
+      fn(x) ^ seed);
 }
 
 }  // namespace
diff --git a/absl/container/internal/hash_function_defaults.h b/absl/container/internal/hash_function_defaults.h
index c2a757b..eefecab 100644
--- a/absl/container/internal/hash_function_defaults.h
+++ b/absl/container/internal/hash_function_defaults.h
@@ -79,6 +79,18 @@
   size_t operator()(const absl::Cord& v) const {
     return absl::Hash<absl::Cord>{}(v);
   }
+
+ private:
+  friend struct absl::hash_internal::HashWithSeed;
+
+  size_t hash_with_seed(absl::string_view v, size_t seed) const {
+    return absl::hash_internal::HashWithSeed().hash(
+        absl::Hash<absl::string_view>{}, v, seed);
+  }
+  size_t hash_with_seed(const absl::Cord& v, size_t seed) const {
+    return absl::hash_internal::HashWithSeed().hash(absl::Hash<absl::Cord>{}, v,
+                                                    seed);
+  }
 };
 
 struct StringEq {
diff --git a/absl/container/internal/hash_generator_testing.cc b/absl/container/internal/hash_generator_testing.cc
index be20e21..4ae58da 100644
--- a/absl/container/internal/hash_generator_testing.cc
+++ b/absl/container/internal/hash_generator_testing.cc
@@ -26,7 +26,6 @@
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace container_internal {
-namespace hash_internal {
 
 std::string Generator<std::string>::operator()() const {
   absl::InsecureBitGen gen;
@@ -50,7 +49,6 @@
   return res;
 }
 
-}  // namespace hash_internal
 }  // namespace container_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/container/internal/hash_generator_testing.h b/absl/container/internal/hash_generator_testing.h
index 14c878e..4c5d87b 100644
--- a/absl/container/internal/hash_generator_testing.h
+++ b/absl/container/internal/hash_generator_testing.h
@@ -31,6 +31,7 @@
 #include <utility>
 #include <vector>
 
+#include "absl/base/config.h"
 #include "absl/container/internal/hash_policy_testing.h"
 #include "absl/memory/memory.h"
 #include "absl/meta/type_traits.h"
@@ -40,7 +41,6 @@
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace container_internal {
-namespace hash_internal {
 namespace generator_internal {
 
 template <class Container, class = void>
@@ -165,7 +165,6 @@
   }
 };
 
-}  // namespace hash_internal
 }  // namespace container_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/container/internal/hash_policy_testing.h b/absl/container/internal/hash_policy_testing.h
index e9f5757..86ea96a 100644
--- a/absl/container/internal/hash_policy_testing.h
+++ b/absl/container/internal/hash_policy_testing.h
@@ -170,18 +170,4 @@
 ABSL_NAMESPACE_END
 }  // namespace absl
 
-// ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS is false for glibcxx versions
-// where the unordered containers are missing certain constructors that
-// take allocator arguments. This test is defined ad-hoc for the platforms
-// we care about (notably Crosstool 17) because libstdcxx's useless
-// versioning scheme precludes a more principled solution.
-// From GCC-4.9 Changelog: (src: https://gcc.gnu.org/gcc-4.9/changes.html)
-// "the unordered associative containers in <unordered_map> and <unordered_set>
-// meet the allocator-aware container requirements;"
-#if defined(__GLIBCXX__) && __GLIBCXX__ <= 20140425
-#define ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS 0
-#else
-#define ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS 1
-#endif
-
 #endif  // ABSL_CONTAINER_INTERNAL_HASH_POLICY_TESTING_H_
diff --git a/absl/container/internal/hash_policy_traits.h b/absl/container/internal/hash_policy_traits.h
index cd6b42f..82eed2a 100644
--- a/absl/container/internal/hash_policy_traits.h
+++ b/absl/container/internal/hash_policy_traits.h
@@ -22,6 +22,7 @@
 #include <utility>
 
 #include "absl/container/internal/common_policy_traits.h"
+#include "absl/container/internal/container_memory.h"
 #include "absl/meta/type_traits.h"
 
 namespace absl {
@@ -145,9 +146,7 @@
     return P::value(elem);
   }
 
-  using HashSlotFn = size_t (*)(const void* hash_fn, void* slot);
-
-  template <class Hash>
+  template <class Hash, bool kIsDefault>
   static constexpr HashSlotFn get_hash_slot_fn() {
 // get_hash_slot_fn may return nullptr to signal that non type erased function
 // should be used. GCC warns against comparing function address with nullptr.
@@ -156,9 +155,9 @@
 // silent error: the address of * will never be NULL [-Werror=address]
 #pragma GCC diagnostic ignored "-Waddress"
 #endif
-    return Policy::template get_hash_slot_fn<Hash>() == nullptr
-               ? &hash_slot_fn_non_type_erased<Hash>
-               : Policy::template get_hash_slot_fn<Hash>();
+    return Policy::template get_hash_slot_fn<Hash, kIsDefault>() == nullptr
+               ? &hash_slot_fn_non_type_erased<Hash, kIsDefault>
+               : Policy::template get_hash_slot_fn<Hash, kIsDefault>();
 #if defined(__GNUC__) && !defined(__clang__)
 #pragma GCC diagnostic pop
 #endif
@@ -168,19 +167,12 @@
   static constexpr bool soo_enabled() { return soo_enabled_impl(Rank1{}); }
 
  private:
-  template <class Hash>
-  struct HashElement {
-    template <class K, class... Args>
-    size_t operator()(const K& key, Args&&...) const {
-      return h(key);
-    }
-    const Hash& h;
-  };
-
-  template <class Hash>
-  static size_t hash_slot_fn_non_type_erased(const void* hash_fn, void* slot) {
-    return Policy::apply(HashElement<Hash>{*static_cast<const Hash*>(hash_fn)},
-                         Policy::element(static_cast<slot_type*>(slot)));
+  template <class Hash, bool kIsDefault>
+  static size_t hash_slot_fn_non_type_erased(const void* hash_fn, void* slot,
+                                             size_t seed) {
+    return Policy::apply(
+        HashElement<Hash, kIsDefault>{*static_cast<const Hash*>(hash_fn), seed},
+        Policy::element(static_cast<slot_type*>(slot)));
   }
 
   // Use go/ranked-overloads for dispatching. Rank1 is preferred.
diff --git a/absl/container/internal/hash_policy_traits_test.cc b/absl/container/internal/hash_policy_traits_test.cc
index 2d2c7c2..03de132 100644
--- a/absl/container/internal/hash_policy_traits_test.cc
+++ b/absl/container/internal/hash_policy_traits_test.cc
@@ -45,7 +45,7 @@
   static std::function<int(int)> apply_impl;
   static std::function<Slot&(Slot*)> value;
 
-  template <class Hash>
+  template <class Hash, bool kIsDefault>
   static constexpr HashSlotFn get_hash_slot_fn() {
     return nullptr;
   }
@@ -99,7 +99,7 @@
     return fn(v);
   }
 
-  template <class Hash>
+  template <class Hash, bool kIsDefault>
   static constexpr HashSlotFn get_hash_slot_fn() {
     return nullptr;
   }
@@ -108,9 +108,9 @@
 size_t* PolicyNoHashFn::apply_called_count;
 
 struct PolicyCustomHashFn : PolicyNoHashFn {
-  template <class Hash>
+  template <class Hash, bool kIsDefault>
   static constexpr HashSlotFn get_hash_slot_fn() {
-    return &TypeErasedApplyToSlotFn<Hash, int>;
+    return &TypeErasedApplyToSlotFn<Hash, int, kIsDefault>;
   }
 };
 
@@ -120,9 +120,11 @@
 
   Hash hasher;
   Slot value = 7;
-  auto* fn = hash_policy_traits<PolicyNoHashFn>::get_hash_slot_fn<Hash>();
+  auto* fn = hash_policy_traits<PolicyNoHashFn>::get_hash_slot_fn<
+      Hash, /*kIsDefault=*/false>();
   EXPECT_NE(fn, nullptr);
-  EXPECT_EQ(fn(&hasher, &value), hasher(value));
+  EXPECT_EQ(fn(&hasher, &value, 100),
+            (HashElement<Hash, /*kIsDefault=*/false>(hasher, 100)(value)));
   EXPECT_EQ(apply_called_count, 1);
 }
 
@@ -132,9 +134,12 @@
 
   Hash hasher;
   Slot value = 7;
-  auto* fn = hash_policy_traits<PolicyCustomHashFn>::get_hash_slot_fn<Hash>();
-  EXPECT_EQ(fn, PolicyCustomHashFn::get_hash_slot_fn<Hash>());
-  EXPECT_EQ(fn(&hasher, &value), hasher(value));
+  auto* fn = hash_policy_traits<PolicyCustomHashFn>::get_hash_slot_fn<
+      Hash, /*kIsDefault=*/false>();
+  EXPECT_EQ(
+      fn, (PolicyCustomHashFn::get_hash_slot_fn<Hash, /*kIsDefault=*/false>()));
+  EXPECT_EQ(fn(&hasher, &value, 100),
+            (HashElement<Hash, /*kIsDefault=*/false>(hasher, 100)(value)));
   EXPECT_EQ(apply_called_count, 0);
 }
 
diff --git a/absl/container/internal/hashtable_control_bytes.h b/absl/container/internal/hashtable_control_bytes.h
index abaadc3..f0fd354 100644
--- a/absl/container/internal/hashtable_control_bytes.h
+++ b/absl/container/internal/hashtable_control_bytes.h
@@ -91,11 +91,6 @@
     return container_internal::TrailingZeros(mask_) >> Shift;
   }
 
-  // Returns the index of the highest *abstract* bit set in `self`.
-  uint32_t HighestBitSet() const {
-    return static_cast<uint32_t>((bit_width(mask_) - 1) >> Shift);
-  }
-
   // Returns the number of trailing zero *abstract* bits.
   uint32_t TrailingZeros() const {
     return container_internal::TrailingZeros(mask_) >> Shift;
@@ -217,6 +212,9 @@
 static_assert(ctrl_t::kDeleted == static_cast<ctrl_t>(-2),
               "ctrl_t::kDeleted must be -2 to make the implementation of "
               "ConvertSpecialToEmptyAndFullToDeleted efficient");
+static_assert(ctrl_t::kEmpty == static_cast<ctrl_t>(-128),
+              "ctrl_t::kEmpty must be -128 to use saturated subtraction in"
+              " ConvertSpecialToEmptyAndFullToDeleted");
 
 // Helpers for checking the state of a control byte.
 inline bool IsEmpty(ctrl_t c) { return c == ctrl_t::kEmpty; }
@@ -324,23 +322,25 @@
         _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl))));
   }
 
-  // Returns the number of trailing empty or deleted elements in the group.
-  uint32_t CountLeadingEmptyOrDeleted() const {
-    auto special = _mm_set1_epi8(static_cast<char>(ctrl_t::kSentinel));
-    return TrailingZeros(static_cast<uint32_t>(
-        _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)) + 1));
+  // Returns a bitmask representing the positions of full or sentinel slots.
+  // Note: for `is_small()` tables group may contain the "same" slot twice:
+  // original and mirrored.
+  NonIterableBitMaskType MaskFullOrSentinel() const {
+    auto special = _mm_set1_epi8(static_cast<char>(ctrl_t::kSentinel) - 1);
+    return NonIterableBitMaskType(static_cast<uint16_t>(
+        _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(ctrl, special))));
   }
 
   void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const {
+    // Take advantage of the fact that kEmpty is already the smallest signed
+    // char value, and using a saturated subtraction will not affect it.
+    // All special values have the MSB set, so after an AND with MSBS, we
+    // are left with -128 for special values and 0 for full. After applying
+    // subs 2, we arrive at the result of -128(kEmpty) for special and
+    // -2(kDeleted) for full.
     auto msbs = _mm_set1_epi8(static_cast<char>(-128));
-    auto x126 = _mm_set1_epi8(126);
-#ifdef ABSL_INTERNAL_HAVE_SSSE3
-    auto res = _mm_or_si128(_mm_shuffle_epi8(x126, ctrl), msbs);
-#else
-    auto zero = _mm_setzero_si128();
-    auto special_mask = _mm_cmpgt_epi8_fixed(zero, ctrl);
-    auto res = _mm_or_si128(msbs, _mm_andnot_si128(special_mask, x126));
-#endif
+    auto twos = _mm_set1_epi8(static_cast<char>(2));
+    auto res = _mm_subs_epi8(_mm_and_si128(msbs, ctrl), twos);
     _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), res);
   }
 
@@ -406,17 +406,13 @@
     return NonIterableBitMaskType(mask);
   }
 
-  uint32_t CountLeadingEmptyOrDeleted() const {
-    uint64_t mask =
-        vget_lane_u64(vreinterpret_u64_u8(vcle_s8(
-                          vdup_n_s8(static_cast<int8_t>(ctrl_t::kSentinel)),
-                          vreinterpret_s8_u8(ctrl))),
-                      0);
-    // Similar to MaskEmptyorDeleted() but we invert the logic to invert the
-    // produced bitfield. We then count number of trailing zeros.
-    // Clang and GCC optimize countr_zero to rbit+clz without any check for 0,
-    // so we should be fine.
-    return static_cast<uint32_t>(countr_zero(mask)) >> 3;
+  NonIterableBitMaskType MaskFullOrSentinel() const {
+    uint64_t mask = vget_lane_u64(
+        vreinterpret_u64_u8(
+            vcgt_s8(vreinterpret_s8_u8(ctrl),
+                    vdup_n_s8(static_cast<int8_t>(ctrl_t::kSentinel) - 1))),
+        0);
+    return NonIterableBitMaskType(mask);
   }
 
   void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const {
@@ -481,12 +477,8 @@
     return NonIterableBitMaskType((ctrl & ~(ctrl << 7)) & kMsbs8Bytes);
   }
 
-  uint32_t CountLeadingEmptyOrDeleted() const {
-    // ctrl | ~(ctrl >> 7) will have the lowest bit set to zero for kEmpty and
-    // kDeleted. We lower all other bits and count number of trailing zeros.
-    constexpr uint64_t bits = 0x0101010101010101ULL;
-    return static_cast<uint32_t>(countr_zero((ctrl | ~(ctrl >> 7)) & bits) >>
-                                 3);
+  auto MaskFullOrSentinel() const {
+    return NonIterableBitMaskType((~ctrl | (ctrl << 7)) & kMsbs8Bytes);
   }
 
   void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const {
diff --git a/absl/container/internal/hashtable_control_bytes_test.cc b/absl/container/internal/hashtable_control_bytes_test.cc
new file mode 100644
index 0000000..a4aa3a9
--- /dev/null
+++ b/absl/container/internal/hashtable_control_bytes_test.cc
@@ -0,0 +1,259 @@
+// Copyright 2025 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/container/internal/hashtable_control_bytes.h"
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+namespace {
+
+using ::testing::ElementsAre;
+using ::testing::ElementsAreArray;
+
+// Convenience function to static cast to ctrl_t.
+ctrl_t CtrlT(int i) { return static_cast<ctrl_t>(i); }
+
+TEST(BitMask, Smoke) {
+  EXPECT_FALSE((BitMask<uint8_t, 8>(0)));
+  EXPECT_TRUE((BitMask<uint8_t, 8>(5)));
+
+  EXPECT_THAT((BitMask<uint8_t, 8>(0)), ElementsAre());
+  EXPECT_THAT((BitMask<uint8_t, 8>(0x1)), ElementsAre(0));
+  EXPECT_THAT((BitMask<uint8_t, 8>(0x2)), ElementsAre(1));
+  EXPECT_THAT((BitMask<uint8_t, 8>(0x3)), ElementsAre(0, 1));
+  EXPECT_THAT((BitMask<uint8_t, 8>(0x4)), ElementsAre(2));
+  EXPECT_THAT((BitMask<uint8_t, 8>(0x5)), ElementsAre(0, 2));
+  EXPECT_THAT((BitMask<uint8_t, 8>(0x55)), ElementsAre(0, 2, 4, 6));
+  EXPECT_THAT((BitMask<uint8_t, 8>(0xAA)), ElementsAre(1, 3, 5, 7));
+}
+
+TEST(BitMask, WithShift_MatchPortable) {
+  // See the non-SSE version of Group for details on what this math is for.
+  uint64_t ctrl = 0x1716151413121110;
+  uint64_t hash = 0x12;
+  constexpr uint64_t lsbs = 0x0101010101010101ULL;
+  auto x = ctrl ^ (lsbs * hash);
+  uint64_t mask = (x - lsbs) & ~x & kMsbs8Bytes;
+  EXPECT_EQ(0x0000000080800000, mask);
+
+  BitMask<uint64_t, 8, 3> b(mask);
+  EXPECT_EQ(*b, 2);
+}
+
+constexpr uint64_t kSome8BytesMask = /*  */ 0x8000808080008000ULL;
+constexpr uint64_t kSome8BytesMaskAllOnes = 0xff00ffffff00ff00ULL;
+constexpr auto kSome8BytesMaskBits = std::array<int, 5>{1, 3, 4, 5, 7};
+
+TEST(BitMask, WithShift_FullMask) {
+  EXPECT_THAT((BitMask<uint64_t, 8, 3>(kMsbs8Bytes)),
+              ElementsAre(0, 1, 2, 3, 4, 5, 6, 7));
+  EXPECT_THAT(
+      (BitMask<uint64_t, 8, 3, /*NullifyBitsOnIteration=*/true>(kMsbs8Bytes)),
+      ElementsAre(0, 1, 2, 3, 4, 5, 6, 7));
+  EXPECT_THAT(
+      (BitMask<uint64_t, 8, 3, /*NullifyBitsOnIteration=*/true>(~uint64_t{0})),
+      ElementsAre(0, 1, 2, 3, 4, 5, 6, 7));
+}
+
+TEST(BitMask, WithShift_EmptyMask) {
+  EXPECT_THAT((BitMask<uint64_t, 8, 3>(0)), ElementsAre());
+  EXPECT_THAT((BitMask<uint64_t, 8, 3, /*NullifyBitsOnIteration=*/true>(0)),
+              ElementsAre());
+}
+
+TEST(BitMask, WithShift_SomeMask) {
+  EXPECT_THAT((BitMask<uint64_t, 8, 3>(kSome8BytesMask)),
+              ElementsAreArray(kSome8BytesMaskBits));
+  EXPECT_THAT((BitMask<uint64_t, 8, 3, /*NullifyBitsOnIteration=*/true>(
+                  kSome8BytesMask)),
+              ElementsAreArray(kSome8BytesMaskBits));
+  EXPECT_THAT((BitMask<uint64_t, 8, 3, /*NullifyBitsOnIteration=*/true>(
+                  kSome8BytesMaskAllOnes)),
+              ElementsAreArray(kSome8BytesMaskBits));
+}
+
+TEST(BitMask, WithShift_SomeMaskExtraBitsForNullify) {
+  // Verify that adding extra bits into non zero bytes is fine.
+  uint64_t extra_bits = 77;
+  for (int i = 0; i < 100; ++i) {
+    // Add extra bits, but keep zero bytes untouched.
+    uint64_t extra_mask = extra_bits & kSome8BytesMaskAllOnes;
+    EXPECT_THAT((BitMask<uint64_t, 8, 3, /*NullifyBitsOnIteration=*/true>(
+                    kSome8BytesMask | extra_mask)),
+                ElementsAreArray(kSome8BytesMaskBits))
+        << i << " " << extra_mask;
+    extra_bits = (extra_bits + 1) * 3;
+  }
+}
+
+TEST(BitMask, LeadingTrailing) {
+  EXPECT_EQ((BitMask<uint32_t, 16>(0x00001a40).LeadingZeros()), 3);
+  EXPECT_EQ((BitMask<uint32_t, 16>(0x00001a40).TrailingZeros()), 6);
+
+  EXPECT_EQ((BitMask<uint32_t, 16>(0x00000001).LeadingZeros()), 15);
+  EXPECT_EQ((BitMask<uint32_t, 16>(0x00000001).TrailingZeros()), 0);
+
+  EXPECT_EQ((BitMask<uint32_t, 16>(0x00008000).LeadingZeros()), 0);
+  EXPECT_EQ((BitMask<uint32_t, 16>(0x00008000).TrailingZeros()), 15);
+
+  EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000008080808000).LeadingZeros()), 3);
+  EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000008080808000).TrailingZeros()), 1);
+
+  EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000000000000080).LeadingZeros()), 7);
+  EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000000000000080).TrailingZeros()), 0);
+
+  EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x8000000000000000).LeadingZeros()), 0);
+  EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x8000000000000000).TrailingZeros()), 7);
+}
+
+template <class GroupTypeParam>
+class GroupTest : public testing::Test {};
+using GroupTypes =
+    ::testing::Types<Group, GroupPortableImpl, GroupFullEmptyOrDeleted>;
+TYPED_TEST_SUITE(GroupTest, GroupTypes);
+
+TYPED_TEST(GroupTest, Match) {
+  using GroupType = TypeParam;
+  if (GroupType::kWidth == 16) {
+    ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted,  CtrlT(3),
+                      ctrl_t::kEmpty, CtrlT(5), ctrl_t::kSentinel, CtrlT(7),
+                      CtrlT(7),       CtrlT(5), CtrlT(3),          CtrlT(1),
+                      CtrlT(1),       CtrlT(1), CtrlT(1),          CtrlT(1)};
+    EXPECT_THAT(GroupType{group}.Match(0), ElementsAre());
+    EXPECT_THAT(GroupType{group}.Match(1), ElementsAre(1, 11, 12, 13, 14, 15));
+    EXPECT_THAT(GroupType{group}.Match(3), ElementsAre(3, 10));
+    EXPECT_THAT(GroupType{group}.Match(5), ElementsAre(5, 9));
+    EXPECT_THAT(GroupType{group}.Match(7), ElementsAre(7, 8));
+  } else if (GroupType::kWidth == 8) {
+    ctrl_t group[] = {ctrl_t::kEmpty,    CtrlT(1), CtrlT(2),
+                      ctrl_t::kDeleted,  CtrlT(2), CtrlT(1),
+                      ctrl_t::kSentinel, CtrlT(1)};
+    EXPECT_THAT(GroupType{group}.Match(0), ElementsAre());
+    EXPECT_THAT(GroupType{group}.Match(1), ElementsAre(1, 5, 7));
+    EXPECT_THAT(GroupType{group}.Match(2), ElementsAre(2, 4));
+  } else {
+    FAIL() << "No test coverage for Group::kWidth==" << GroupType::kWidth;
+  }
+}
+
+TYPED_TEST(GroupTest, MaskEmpty) {
+  using GroupType = TypeParam;
+  if (GroupType::kWidth == 16) {
+    ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted,  CtrlT(3),
+                      ctrl_t::kEmpty, CtrlT(5), ctrl_t::kSentinel, CtrlT(7),
+                      CtrlT(7),       CtrlT(5), CtrlT(3),          CtrlT(1),
+                      CtrlT(1),       CtrlT(1), CtrlT(1),          CtrlT(1)};
+    EXPECT_THAT(GroupType{group}.MaskEmpty().LowestBitSet(), 0);
+  } else if (GroupType::kWidth == 8) {
+    ctrl_t group[] = {ctrl_t::kEmpty,    CtrlT(1), CtrlT(2),
+                      ctrl_t::kDeleted,  CtrlT(2), CtrlT(1),
+                      ctrl_t::kSentinel, CtrlT(1)};
+    EXPECT_THAT(GroupType{group}.MaskEmpty().LowestBitSet(), 0);
+  } else {
+    FAIL() << "No test coverage for Group::kWidth==" << GroupType::kWidth;
+  }
+}
+
+TYPED_TEST(GroupTest, MaskFull) {
+  using GroupType = TypeParam;
+  if (GroupType::kWidth == 16) {
+    ctrl_t group[] = {
+        ctrl_t::kEmpty, CtrlT(1),          ctrl_t::kDeleted,  CtrlT(3),
+        ctrl_t::kEmpty, CtrlT(5),          ctrl_t::kSentinel, CtrlT(7),
+        CtrlT(7),       CtrlT(5),          ctrl_t::kDeleted,  CtrlT(1),
+        CtrlT(1),       ctrl_t::kSentinel, ctrl_t::kEmpty,    CtrlT(1)};
+    EXPECT_THAT(GroupType{group}.MaskFull(),
+                ElementsAre(1, 3, 5, 7, 8, 9, 11, 12, 15));
+  } else if (GroupType::kWidth == 8) {
+    ctrl_t group[] = {ctrl_t::kEmpty,    CtrlT(1), ctrl_t::kEmpty,
+                      ctrl_t::kDeleted,  CtrlT(2), ctrl_t::kSentinel,
+                      ctrl_t::kSentinel, CtrlT(1)};
+    EXPECT_THAT(GroupType{group}.MaskFull(), ElementsAre(1, 4, 7));
+  } else {
+    FAIL() << "No test coverage for Group::kWidth==" << GroupType::kWidth;
+  }
+}
+
+TYPED_TEST(GroupTest, MaskNonFull) {
+  using GroupType = TypeParam;
+  if (GroupType::kWidth == 16) {
+    ctrl_t group[] = {
+        ctrl_t::kEmpty, CtrlT(1),          ctrl_t::kDeleted,  CtrlT(3),
+        ctrl_t::kEmpty, CtrlT(5),          ctrl_t::kSentinel, CtrlT(7),
+        CtrlT(7),       CtrlT(5),          ctrl_t::kDeleted,  CtrlT(1),
+        CtrlT(1),       ctrl_t::kSentinel, ctrl_t::kEmpty,    CtrlT(1)};
+    EXPECT_THAT(GroupType{group}.MaskNonFull(),
+                ElementsAre(0, 2, 4, 6, 10, 13, 14));
+  } else if (GroupType::kWidth == 8) {
+    ctrl_t group[] = {ctrl_t::kEmpty,    CtrlT(1), ctrl_t::kEmpty,
+                      ctrl_t::kDeleted,  CtrlT(2), ctrl_t::kSentinel,
+                      ctrl_t::kSentinel, CtrlT(1)};
+    EXPECT_THAT(GroupType{group}.MaskNonFull(), ElementsAre(0, 2, 3, 5, 6));
+  } else {
+    FAIL() << "No test coverage for Group::kWidth==" << GroupType::kWidth;
+  }
+}
+
+TYPED_TEST(GroupTest, MaskEmptyOrDeleted) {
+  using GroupType = TypeParam;
+  if (GroupType::kWidth == 16) {
+    ctrl_t group[] = {ctrl_t::kEmpty,   CtrlT(1), ctrl_t::kEmpty,    CtrlT(3),
+                      ctrl_t::kDeleted, CtrlT(5), ctrl_t::kSentinel, CtrlT(7),
+                      CtrlT(7),         CtrlT(5), CtrlT(3),          CtrlT(1),
+                      CtrlT(1),         CtrlT(1), CtrlT(1),          CtrlT(1)};
+    EXPECT_THAT(GroupType{group}.MaskEmptyOrDeleted().LowestBitSet(), 0);
+  } else if (GroupType::kWidth == 8) {
+    ctrl_t group[] = {ctrl_t::kEmpty,    CtrlT(1), CtrlT(2),
+                      ctrl_t::kDeleted,  CtrlT(2), CtrlT(1),
+                      ctrl_t::kSentinel, CtrlT(1)};
+    EXPECT_THAT(GroupType{group}.MaskEmptyOrDeleted().LowestBitSet(), 0);
+  } else {
+    FAIL() << "No test coverage for Group::kWidth==" << GroupType::kWidth;
+  }
+}
+
+TYPED_TEST(GroupTest, MaskFullOrSentinel) {
+  using GroupType = TypeParam;
+  if (GroupType::kWidth == 16) {
+    ctrl_t group[] = {
+        ctrl_t::kEmpty,   ctrl_t::kDeleted, ctrl_t::kEmpty,    CtrlT(3),
+        ctrl_t::kDeleted, CtrlT(5),         ctrl_t::kSentinel, ctrl_t::kEmpty,
+        ctrl_t::kEmpty,   ctrl_t::kDeleted, ctrl_t::kDeleted,  ctrl_t::kDeleted,
+        ctrl_t::kEmpty,   ctrl_t::kDeleted, ctrl_t::kDeleted,  ctrl_t::kDeleted,
+    };
+    EXPECT_THAT(GroupType{group}.MaskFullOrSentinel().LowestBitSet(), 3);
+  } else if (GroupType::kWidth == 8) {
+    ctrl_t group[] = {ctrl_t::kEmpty,   ctrl_t::kDeleted, CtrlT(2),
+                      ctrl_t::kDeleted, CtrlT(2),         ctrl_t::kSentinel,
+                      ctrl_t::kDeleted, ctrl_t::kEmpty};
+    EXPECT_THAT(GroupType{group}.MaskFullOrSentinel().LowestBitSet(), 2);
+  } else {
+    FAIL() << "No test coverage for Group::kWidth==" << GroupType::kWidth;
+  }
+}
+
+}  // namespace
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/container/internal/hashtablez_sampler.cc b/absl/container/internal/hashtablez_sampler.cc
index c0fce87..4f6e946 100644
--- a/absl/container/internal/hashtablez_sampler.cc
+++ b/absl/container/internal/hashtablez_sampler.cc
@@ -81,12 +81,12 @@
   capacity.store(0, std::memory_order_relaxed);
   size.store(0, std::memory_order_relaxed);
   num_erases.store(0, std::memory_order_relaxed);
+  num_insert_hits.store(0, std::memory_order_relaxed);
   num_rehashes.store(0, std::memory_order_relaxed);
   max_probe_length.store(0, std::memory_order_relaxed);
   total_probe_length.store(0, std::memory_order_relaxed);
   hashes_bitwise_or.store(0, std::memory_order_relaxed);
   hashes_bitwise_and.store(~size_t{}, std::memory_order_relaxed);
-  hashes_bitwise_xor.store(0, std::memory_order_relaxed);
   max_reserve.store(0, std::memory_order_relaxed);
 
   create_time = absl::Now();
@@ -94,8 +94,9 @@
   // The inliner makes hardcoded skip_count difficult (especially when combined
   // with LTO).  We use the ability to exclude stacks by regex when encoding
   // instead.
-  depth = absl::GetStackTrace(stack, HashtablezInfo::kMaxStackDepth,
-                              /* skip_count= */ 0);
+  depth = static_cast<unsigned>(
+      absl::GetStackTrace(stack, HashtablezInfo::kMaxStackDepth,
+                          /* skip_count= */ 0));
   inline_element_size = inline_element_size_value;
   key_size = key_size_value;
   value_size = value_size_value;
@@ -229,8 +230,8 @@
   }
 }
 
-void RecordInsertSlow(HashtablezInfo* info, size_t hash,
-                      size_t distance_from_desired) {
+void RecordInsertMissSlow(HashtablezInfo* info, size_t hash,
+                          size_t distance_from_desired) {
   // SwissTables probe in groups of 16, so scale this to count items probes and
   // not offset from desired.
   size_t probe_length = distance_from_desired;
@@ -242,7 +243,6 @@
 
   info->hashes_bitwise_and.fetch_and(hash, std::memory_order_relaxed);
   info->hashes_bitwise_or.fetch_or(hash, std::memory_order_relaxed);
-  info->hashes_bitwise_xor.fetch_xor(hash, std::memory_order_relaxed);
   info->max_probe_length.store(
       std::max(info->max_probe_length.load(std::memory_order_relaxed),
                probe_length),
diff --git a/absl/container/internal/hashtablez_sampler.h b/absl/container/internal/hashtablez_sampler.h
index 305dc85..6c20dc3 100644
--- a/absl/container/internal/hashtablez_sampler.h
+++ b/absl/container/internal/hashtablez_sampler.h
@@ -82,12 +82,12 @@
   std::atomic<size_t> capacity;
   std::atomic<size_t> size;
   std::atomic<size_t> num_erases;
+  std::atomic<size_t> num_insert_hits;
   std::atomic<size_t> num_rehashes;
   std::atomic<size_t> max_probe_length;
   std::atomic<size_t> total_probe_length;
   std::atomic<size_t> hashes_bitwise_or;
   std::atomic<size_t> hashes_bitwise_and;
-  std::atomic<size_t> hashes_bitwise_xor;
   std::atomic<size_t> max_reserve;
 
   // All of the fields below are set by `PrepareForSampling`, they must not be
@@ -97,7 +97,7 @@
   // the lock.
   static constexpr int kMaxStackDepth = 64;
   absl::Time create_time;
-  int32_t depth;
+  uint32_t depth;
   // The SOO capacity for this table in elements (not bytes). Note that sampled
   // tables are never SOO because we need to store the infoz handle on the heap.
   // Tables that would be SOO if not sampled should have: soo_capacity > 0 &&
@@ -111,6 +111,16 @@
 
 void RecordRehashSlow(HashtablezInfo* info, size_t total_probe_length);
 
+// This is inline to avoid calling convention overhead for an otherwise
+// lightweight operation.
+inline void RecordInsertHitSlow(HashtablezInfo* info) {
+  // We avoid fetch_add since no other thread should be mutating the table
+  // simultaneously without synchronization.
+  info->num_insert_hits.store(
+      info->num_insert_hits.load(std::memory_order_relaxed) + 1,
+      std::memory_order_relaxed);
+}
+
 void RecordReservationSlow(HashtablezInfo* info, size_t target_capacity);
 
 void RecordClearedReservationSlow(HashtablezInfo* info);
@@ -118,8 +128,8 @@
 void RecordStorageChangedSlow(HashtablezInfo* info, size_t size,
                               size_t capacity);
 
-void RecordInsertSlow(HashtablezInfo* info, size_t hash,
-                      size_t distance_from_desired);
+void RecordInsertMissSlow(HashtablezInfo* info, size_t hash,
+                          size_t distance_from_desired);
 
 void RecordEraseSlow(HashtablezInfo* info);
 
@@ -174,9 +184,9 @@
     RecordClearedReservationSlow(info_);
   }
 
-  inline void RecordInsert(size_t hash, size_t distance_from_desired) {
+  inline void RecordInsertMiss(size_t hash, size_t distance_from_desired) {
     if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
-    RecordInsertSlow(info_, hash, distance_from_desired);
+    RecordInsertMissSlow(info_, hash, distance_from_desired);
   }
 
   inline void RecordErase() {
@@ -184,6 +194,11 @@
     RecordEraseSlow(info_);
   }
 
+  inline void RecordInsertHit() {
+    if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
+    RecordInsertHitSlow(info_);
+  }
+
   friend inline void swap(HashtablezInfoHandle& lhs,
                           HashtablezInfoHandle& rhs) {
     std::swap(lhs.info_, rhs.info_);
@@ -207,8 +222,10 @@
   inline void RecordRehash(size_t /*total_probe_length*/) {}
   inline void RecordReservation(size_t /*target_capacity*/) {}
   inline void RecordClearedReservation() {}
-  inline void RecordInsert(size_t /*hash*/, size_t /*distance_from_desired*/) {}
+  inline void RecordInsertMiss(size_t /*hash*/,
+                               size_t /*distance_from_desired*/) {}
   inline void RecordErase() {}
+  inline void RecordInsertHit() {}
 
   friend inline void swap(HashtablezInfoHandle& /*lhs*/,
                           HashtablezInfoHandle& /*rhs*/) {}
diff --git a/absl/container/internal/hashtablez_sampler_test.cc b/absl/container/internal/hashtablez_sampler_test.cc
index 0de1e29..9391e94 100644
--- a/absl/container/internal/hashtablez_sampler_test.cc
+++ b/absl/container/internal/hashtablez_sampler_test.cc
@@ -90,7 +90,7 @@
   const size_t test_value_size = 13;
 
   HashtablezInfo info;
-  absl::MutexLock l(&info.init_mu);
+  absl::MutexLock l(info.init_mu);
   info.PrepareForSampling(test_stride, test_element_size,
                           /*key_size=*/test_key_size,
                           /*value_size=*/test_value_size,
@@ -99,12 +99,12 @@
   EXPECT_EQ(info.capacity.load(), 0);
   EXPECT_EQ(info.size.load(), 0);
   EXPECT_EQ(info.num_erases.load(), 0);
+  EXPECT_EQ(info.num_insert_hits.load(), 0);
   EXPECT_EQ(info.num_rehashes.load(), 0);
   EXPECT_EQ(info.max_probe_length.load(), 0);
   EXPECT_EQ(info.total_probe_length.load(), 0);
   EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
   EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{});
-  EXPECT_EQ(info.hashes_bitwise_xor.load(), 0);
   EXPECT_EQ(info.max_reserve.load(), 0);
   EXPECT_GE(info.create_time, test_start);
   EXPECT_EQ(info.weight, test_stride);
@@ -116,11 +116,11 @@
   info.capacity.store(1, std::memory_order_relaxed);
   info.size.store(1, std::memory_order_relaxed);
   info.num_erases.store(1, std::memory_order_relaxed);
+  info.num_insert_hits.store(1, std::memory_order_relaxed);
   info.max_probe_length.store(1, std::memory_order_relaxed);
   info.total_probe_length.store(1, std::memory_order_relaxed);
   info.hashes_bitwise_or.store(1, std::memory_order_relaxed);
   info.hashes_bitwise_and.store(1, std::memory_order_relaxed);
-  info.hashes_bitwise_xor.store(1, std::memory_order_relaxed);
   info.max_reserve.store(1, std::memory_order_relaxed);
   info.create_time = test_start - absl::Hours(20);
 
@@ -131,12 +131,12 @@
   EXPECT_EQ(info.capacity.load(), 0);
   EXPECT_EQ(info.size.load(), 0);
   EXPECT_EQ(info.num_erases.load(), 0);
+  EXPECT_EQ(info.num_insert_hits.load(), 0);
   EXPECT_EQ(info.num_rehashes.load(), 0);
   EXPECT_EQ(info.max_probe_length.load(), 0);
   EXPECT_EQ(info.total_probe_length.load(), 0);
   EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
   EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{});
-  EXPECT_EQ(info.hashes_bitwise_xor.load(), 0);
   EXPECT_EQ(info.max_reserve.load(), 0);
   EXPECT_EQ(info.weight, 2 * test_stride);
   EXPECT_EQ(info.inline_element_size, test_element_size);
@@ -148,7 +148,7 @@
 
 TEST(HashtablezInfoTest, RecordStorageChanged) {
   HashtablezInfo info;
-  absl::MutexLock l(&info.init_mu);
+  absl::MutexLock l(info.init_mu);
   const int64_t test_stride = 21;
   const size_t test_element_size = 19;
   const size_t test_key_size = 17;
@@ -166,9 +166,9 @@
   EXPECT_EQ(info.capacity.load(), 20);
 }
 
-TEST(HashtablezInfoTest, RecordInsert) {
+TEST(HashtablezInfoTest, RecordInsertMiss) {
   HashtablezInfo info;
-  absl::MutexLock l(&info.init_mu);
+  absl::MutexLock l(info.init_mu);
   const int64_t test_stride = 25;
   const size_t test_element_size = 23;
   const size_t test_key_size = 21;
@@ -179,21 +179,18 @@
                           /*value_size=*/test_value_size,
                           /*soo_capacity_value=*/0);
   EXPECT_EQ(info.max_probe_length.load(), 0);
-  RecordInsertSlow(&info, 0x0000FF00, 6 * kProbeLength);
+  RecordInsertMissSlow(&info, 0x0000FF00, 6 * kProbeLength);
   EXPECT_EQ(info.max_probe_length.load(), 6);
   EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000FF00);
   EXPECT_EQ(info.hashes_bitwise_or.load(), 0x0000FF00);
-  EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x0000FF00);
-  RecordInsertSlow(&info, 0x000FF000, 4 * kProbeLength);
+  RecordInsertMissSlow(&info, 0x000FF000, 4 * kProbeLength);
   EXPECT_EQ(info.max_probe_length.load(), 6);
   EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000F000);
   EXPECT_EQ(info.hashes_bitwise_or.load(), 0x000FFF00);
-  EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x000F0F00);
-  RecordInsertSlow(&info, 0x00FF0000, 12 * kProbeLength);
+  RecordInsertMissSlow(&info, 0x00FF0000, 12 * kProbeLength);
   EXPECT_EQ(info.max_probe_length.load(), 12);
   EXPECT_EQ(info.hashes_bitwise_and.load(), 0x00000000);
   EXPECT_EQ(info.hashes_bitwise_or.load(), 0x00FFFF00);
-  EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x00F00F00);
 }
 
 TEST(HashtablezInfoTest, RecordErase) {
@@ -203,14 +200,14 @@
   const size_t test_value_size = 25;
 
   HashtablezInfo info;
-  absl::MutexLock l(&info.init_mu);
+  absl::MutexLock l(info.init_mu);
   info.PrepareForSampling(test_stride, test_element_size,
                           /*key_size=*/test_key_size,
                           /*value_size=*/test_value_size,
                           /*soo_capacity_value=*/1);
   EXPECT_EQ(info.num_erases.load(), 0);
   EXPECT_EQ(info.size.load(), 0);
-  RecordInsertSlow(&info, 0x0000FF00, 6 * kProbeLength);
+  RecordInsertMissSlow(&info, 0x0000FF00, 6 * kProbeLength);
   EXPECT_EQ(info.size.load(), 1);
   RecordEraseSlow(&info);
   EXPECT_EQ(info.size.load(), 0);
@@ -221,22 +218,41 @@
   EXPECT_EQ(info.soo_capacity, 1);
 }
 
+TEST(HashtablezInfoTest, RecordInsertHit) {
+  const int64_t test_stride = 31;
+  const size_t test_element_size = 29;
+  const size_t test_key_size = 27;
+  const size_t test_value_size = 25;
+
+  HashtablezInfo info;
+  absl::MutexLock l(info.init_mu);
+  info.PrepareForSampling(test_stride, test_element_size,
+                          /*key_size=*/test_key_size,
+                          /*value_size=*/test_value_size,
+                          /*soo_capacity_value=*/1);
+  EXPECT_EQ(info.num_insert_hits.load(), 0);
+  RecordInsertHitSlow(&info);
+  EXPECT_EQ(info.num_insert_hits.load(), 1);
+  RecordInsertHitSlow(&info);
+  EXPECT_EQ(info.num_insert_hits.load(), 2);
+}
+
 TEST(HashtablezInfoTest, RecordRehash) {
   const int64_t test_stride = 33;
   const size_t test_element_size = 31;
   const size_t test_key_size = 29;
   const size_t test_value_size = 27;
   HashtablezInfo info;
-  absl::MutexLock l(&info.init_mu);
+  absl::MutexLock l(info.init_mu);
   info.PrepareForSampling(test_stride, test_element_size,
                           /*key_size=*/test_key_size,
                           /*value_size=*/test_value_size,
 
                           /*soo_capacity_value=*/0);
-  RecordInsertSlow(&info, 0x1, 0);
-  RecordInsertSlow(&info, 0x2, kProbeLength);
-  RecordInsertSlow(&info, 0x4, kProbeLength);
-  RecordInsertSlow(&info, 0x8, 2 * kProbeLength);
+  RecordInsertMissSlow(&info, 0x1, 0);
+  RecordInsertMissSlow(&info, 0x2, kProbeLength);
+  RecordInsertMissSlow(&info, 0x4, kProbeLength);
+  RecordInsertMissSlow(&info, 0x8, 2 * kProbeLength);
   EXPECT_EQ(info.size.load(), 4);
   EXPECT_EQ(info.total_probe_length.load(), 4);
 
@@ -259,7 +275,7 @@
 
 TEST(HashtablezInfoTest, RecordReservation) {
   HashtablezInfo info;
-  absl::MutexLock l(&info.init_mu);
+  absl::MutexLock l(info.init_mu);
   const int64_t test_stride = 35;
   const size_t test_element_size = 33;
   const size_t test_key_size = 31;
diff --git a/absl/container/internal/heterogeneous_lookup_testing.h b/absl/container/internal/heterogeneous_lookup_testing.h
new file mode 100644
index 0000000..b8cfae3
--- /dev/null
+++ b/absl/container/internal/heterogeneous_lookup_testing.h
@@ -0,0 +1,80 @@
+// Copyright 2025 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.
+
+#ifndef ABSL_CONTAINER_INTERNAL_HETEROGENEOUS_LOOKUP_TESTING_H_
+#define ABSL_CONTAINER_INTERNAL_HETEROGENEOUS_LOOKUP_TESTING_H_
+
+#include <cstddef>
+#include <ostream>
+
+#include "gmock/gmock.h"
+#include "absl/base/config.h"
+#include "absl/container/internal/test_instance_tracker.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+// An expensive class that is convertible to CheapType to demonstrate
+// heterogeneous lookups.
+class ExpensiveType : public absl::test_internal::CopyableMovableInstance {
+ public:
+  explicit ExpensiveType(int value)
+      : absl::test_internal::CopyableMovableInstance(value) {}
+
+  friend std::ostream& operator<<(std::ostream& os, const ExpensiveType& a) {
+    return os << a.value();
+  }
+};
+
+class CheapType {
+ public:
+  explicit CheapType(const int value) : value_(value) {}
+
+  explicit operator ExpensiveType() const { return ExpensiveType(value_); }
+
+  int value() const { return value_; }
+
+ private:
+  int value_;
+};
+
+struct HeterogeneousHash {
+  using is_transparent = void;
+  size_t operator()(const ExpensiveType& a) const { return a.value(); }
+  size_t operator()(const CheapType& a) const { return a.value(); }
+};
+
+struct HeterogeneousEqual {
+  using is_transparent = void;
+  bool operator()(const ExpensiveType& a, const ExpensiveType& b) const {
+    return a.value() == b.value();
+  }
+  bool operator()(const ExpensiveType& a, const CheapType& b) const {
+    return a.value() == b.value();
+  }
+  bool operator()(const CheapType& a, const ExpensiveType& b) const {
+    return a.value() == b.value();
+  }
+};
+
+MATCHER_P(HasExpensiveValue, n, "") {
+  return ::testing::ExplainMatchResult(n, arg.value(), result_listener);
+}
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_HETEROGENEOUS_LOOKUP_TESTING_H_
diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h
index b0d3f07..c7b709f 100644
--- a/absl/container/internal/inlined_vector.h
+++ b/absl/container/internal/inlined_vector.h
@@ -27,7 +27,6 @@
 
 #include "absl/base/attributes.h"
 #include "absl/base/config.h"
-#include "absl/base/internal/identity.h"
 #include "absl/base/macros.h"
 #include "absl/container/internal/compressed_tuple.h"
 #include "absl/memory/memory.h"
@@ -127,7 +126,7 @@
 };
 
 template <typename A, typename ValueAdapter>
-void ConstructElements(absl::internal::type_identity_t<A>& allocator,
+void ConstructElements(absl::type_identity_t<A>& allocator,
                        Pointer<A> construct_first, ValueAdapter& values,
                        SizeType<A> construct_size) {
   for (SizeType<A> i = 0; i < construct_size; ++i) {
@@ -796,16 +795,9 @@
                                    move_construction_values,
                                    move_construction.size());
 
-    for (Pointer<A>
-             destination = move_assignment.data() + move_assignment.size(),
-             last_destination = move_assignment.data(),
-             source = move_assignment_values + move_assignment.size();
-         ;) {
-      --destination;
-      --source;
-      if (destination < last_destination) break;
-      *destination = std::move(*source);
-    }
+    std::move_backward(move_assignment_values,
+                       move_assignment_values + move_assignment.size(),
+                       move_assignment.data() + move_assignment.size());
 
     AssignElements<A>(insert_assignment.data(), values,
                       insert_assignment.size());
diff --git a/absl/container/internal/raw_hash_map.h b/absl/container/internal/raw_hash_map.h
index b42a4f2..9338f16 100644
--- a/absl/container/internal/raw_hash_map.h
+++ b/absl/container/internal/raw_hash_map.h
@@ -31,8 +31,20 @@
 ABSL_NAMESPACE_BEGIN
 namespace container_internal {
 
-template <class Policy, class Hash, class Eq, class Alloc>
-class raw_hash_map : public raw_hash_set<Policy, Hash, Eq, Alloc> {
+template <class Policy, class... Params>
+class raw_hash_map;
+
+template <typename Policy, typename Hash, typename Eq, typename Alloc>
+struct InstantiateRawHashMap {
+  using type = typename ApplyWithoutDefaultSuffix<
+      raw_hash_map,
+      TypeList<int, typename Policy::DefaultHash, typename Policy::DefaultEq,
+               typename Policy::DefaultAlloc>,
+      TypeList<Policy, Hash, Eq, Alloc>>::type;
+};
+
+template <class Policy, class... Params>
+class raw_hash_map : public raw_hash_set<Policy, Params...> {
   // P is Policy. It's passed as a template argument to support maps that have
   // incomplete types as values, as in unordered_map<K, IncompleteType>.
   // MappedReference<> may be a non-reference type.
@@ -45,6 +57,10 @@
   using MappedConstReference = decltype(P::value(
       std::addressof(std::declval<typename raw_hash_map::const_reference>())));
 
+  using Hash = typename raw_hash_map::raw_hash_set::hasher;
+  using Eq = typename raw_hash_map::raw_hash_set::key_equal;
+  using Alloc = typename raw_hash_map::raw_hash_set::allocator_type;
+
   template <class K>
   using key_arg =
       typename KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>::
@@ -205,7 +221,8 @@
                 !std::is_convertible<K, const_iterator>::value, int>::type = 0>
   std::pair<iterator, bool> try_emplace(key_arg<K> &&k, Args &&...args)
       ABSL_ATTRIBUTE_LIFETIME_BOUND {
-    return try_emplace_impl(std::forward<K>(k), std::forward<Args>(args)...);
+    return try_emplace_impl(std::forward<key_arg<K>>(k),
+                            std::forward<Args>(args)...);
   }
 
   template <class K = key_type, class... Args,
@@ -215,7 +232,7 @@
   std::pair<iterator, bool> try_emplace(
       key_arg<K> &&k ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this),
       Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
-    return this->template try_emplace<K, 0>(std::forward<K>(k),
+    return this->template try_emplace<K, 0>(std::forward<key_arg<K>>(k),
                                             std::forward<Args>(args)...);
   }
 
@@ -241,14 +258,15 @@
             class... Args>
   iterator try_emplace(const_iterator, key_arg<K> &&k,
                        Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
-    return try_emplace(std::forward<K>(k), std::forward<Args>(args)...).first;
+    return try_emplace(std::forward<key_arg<K>>(k), std::forward<Args>(args)...)
+        .first;
   }
   template <class K = key_type, class... Args,
             EnableIf<LifetimeBoundK<K, true, K *>> = 0>
   iterator try_emplace(const_iterator hint,
                        key_arg<K> &&k ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this),
                        Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
-    return this->template try_emplace<K, 0>(hint, std::forward<K>(k),
+    return this->template try_emplace<K, 0>(hint, std::forward<key_arg<K>>(k),
                                             std::forward<Args>(args)...);
   }
 
@@ -264,7 +282,7 @@
                        const key_arg<K> &k
                            ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this),
                        Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
-    return this->template try_emplace<K, 0>(hint, std::forward<K>(k),
+    return this->template try_emplace<K, 0>(hint, k,
                                             std::forward<Args>(args)...);
   }
 
@@ -296,15 +314,15 @@
     // It is safe to use unchecked_deref here because try_emplace
     // will always return an iterator pointing to a valid item in the table,
     // since it inserts if nothing is found for the given key.
-    return Policy::value(
-        &this->unchecked_deref(try_emplace(std::forward<K>(key)).first));
+    return Policy::value(&this->unchecked_deref(
+        try_emplace(std::forward<key_arg<K>>(key)).first));
   }
   template <class K = key_type, class P = Policy, int &...,
             EnableIf<LifetimeBoundK<K, true, K *>> = 0>
   MappedReference<P> operator[](
       key_arg<K> &&key ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))
       ABSL_ATTRIBUTE_LIFETIME_BOUND {
-    return this->template operator[]<K, P, 0>(std::forward<K>(key));
+    return this->template operator[]<K, P, 0>(std::forward<key_arg<K>>(key));
   }
 
   template <class K = key_type, class P = Policy,
@@ -325,6 +343,13 @@
   }
 
  private:
+  static_assert(
+      std::is_same_v<
+          typename InstantiateRawHashMap<Policy, Hash, Eq, Alloc>::type,
+          raw_hash_map>,
+      "Redundant template parameters were passed. Use InstantiateRawHashMap<> "
+      "instead");
+
   template <class K, class V>
   std::pair<iterator, bool> insert_or_assign_impl(K&& k, V&& v)
       ABSL_ATTRIBUTE_LIFETIME_BOUND {
diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc
index 339e662..9955029 100644
--- a/absl/container/internal/raw_hash_set.cc
+++ b/absl/container/internal/raw_hash_set.cc
@@ -19,6 +19,9 @@
 #include <cstddef>
 #include <cstdint>
 #include <cstring>
+#include <memory>
+#include <tuple>
+#include <utility>
 
 #include "absl/base/attributes.h"
 #include "absl/base/config.h"
@@ -40,32 +43,13 @@
 // Represents a control byte corresponding to a full slot with arbitrary hash.
 constexpr ctrl_t ZeroCtrlT() { return static_cast<ctrl_t>(0); }
 
-// We have space for `growth_info` before a single block of control bytes. A
-// single block of empty control bytes for tables without any slots allocated.
-// This enables removing a branch in the hot path of find(). In order to ensure
-// that the control bytes are aligned to 16, we have 16 bytes before the control
-// bytes even though growth_info only needs 8.
-alignas(16) ABSL_CONST_INIT ABSL_DLL const ctrl_t kEmptyGroup[32] = {
-    ZeroCtrlT(),       ZeroCtrlT(),    ZeroCtrlT(),    ZeroCtrlT(),
-    ZeroCtrlT(),       ZeroCtrlT(),    ZeroCtrlT(),    ZeroCtrlT(),
-    ZeroCtrlT(),       ZeroCtrlT(),    ZeroCtrlT(),    ZeroCtrlT(),
-    ZeroCtrlT(),       ZeroCtrlT(),    ZeroCtrlT(),    ZeroCtrlT(),
-    ctrl_t::kSentinel, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
-    ctrl_t::kEmpty,    ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
-    ctrl_t::kEmpty,    ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
-    ctrl_t::kEmpty,    ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty};
+// A single control byte for default-constructed iterators. We leave it
+// uninitialized because reading this memory is a bug.
+ABSL_DLL ctrl_t kDefaultIterControl;
 
-// We need one full byte followed by a sentinel byte for iterator::operator++ to
-// work. We have a full group after kSentinel to be safe (in case operator++ is
-// changed to read a full group).
-ABSL_CONST_INIT ABSL_DLL const ctrl_t kSooControl[17] = {
-    ZeroCtrlT(),    ctrl_t::kSentinel, ZeroCtrlT(),    ctrl_t::kEmpty,
-    ctrl_t::kEmpty, ctrl_t::kEmpty,    ctrl_t::kEmpty, ctrl_t::kEmpty,
-    ctrl_t::kEmpty, ctrl_t::kEmpty,    ctrl_t::kEmpty, ctrl_t::kEmpty,
-    ctrl_t::kEmpty, ctrl_t::kEmpty,    ctrl_t::kEmpty, ctrl_t::kEmpty,
-    ctrl_t::kEmpty};
-static_assert(NumControlBytes(SooCapacity()) <= 17,
-              "kSooControl capacity too small");
+// We need one full byte followed by a sentinel byte for iterator::operator++.
+ABSL_CONST_INIT ABSL_DLL const ctrl_t kSooControl[2] = {ZeroCtrlT(),
+                                                        ctrl_t::kSentinel};
 
 namespace {
 
@@ -100,13 +84,13 @@
   return value ^ static_cast<size_t>(reinterpret_cast<uintptr_t>(&counter));
 }
 
-bool ShouldRehashForBugDetection(PerTableSeed seed, size_t capacity) {
+bool ShouldRehashForBugDetection(size_t capacity) {
   // Note: we can't use the abseil-random library because abseil-random
   // depends on swisstable. We want to return true with probability
   // `min(1, RehashProbabilityConstant() / capacity())`. In order to do this,
   // we probe based on a random hash and see if the offset is less than
   // RehashProbabilityConstant().
-  return probe(seed, capacity, absl::HashOf(RandomSeed())).offset() <
+  return probe(capacity, absl::HashOf(RandomSeed())).offset() <
          RehashProbabilityConstant();
 }
 
@@ -118,6 +102,21 @@
   return hash ^ seed.seed();
 }
 
+// Returns the offset of the new element after resize from capacity 1 to 3.
+size_t Resize1To3NewOffset(size_t hash, PerTableSeed seed) {
+  // After resize from capacity 1 to 3, we always have exactly the slot with
+  // index 1 occupied, so we need to insert either at index 0 or index 2.
+  static_assert(SooSlotIndex() == 1);
+  return SingleGroupTableH1(hash, seed) & 2;
+}
+
+// Returns the address of the ith slot in slots where each slot occupies
+// slot_size.
+inline void* SlotAddress(void* slot_array, size_t slot, size_t slot_size) {
+  return static_cast<void*>(static_cast<char*>(slot_array) +
+                            (slot * slot_size));
+}
+
 // Returns the address of the slot `i` iterations after `slot` assuming each
 // slot has the specified size.
 inline void* NextSlot(void* slot, size_t slot_size, size_t i = 1) {
@@ -133,6 +132,16 @@
 
 }  // namespace
 
+// Must be defined out-of-line to avoid MSVC error C2482 on some platforms,
+// which is caused by non-constexpr initialization.
+uint16_t HashtableSize::NextSeed() {
+  static_assert(PerTableSeed::kBitCount == 16);
+  thread_local uint16_t seed =
+      static_cast<uint16_t>(reinterpret_cast<uintptr_t>(&seed));
+  seed += uint16_t{0xad53};
+  return seed;
+}
+
 GenerationType* EmptyGeneration() {
   if (SwisstableGenerationsEnabled()) {
     constexpr size_t kNumEmptyGenerations = 1024;
@@ -144,66 +153,98 @@
 }
 
 bool CommonFieldsGenerationInfoEnabled::
-    should_rehash_for_bug_detection_on_insert(PerTableSeed seed,
-                                              size_t capacity) const {
+    should_rehash_for_bug_detection_on_insert(size_t capacity) const {
   if (reserved_growth_ == kReservedGrowthJustRanOut) return true;
   if (reserved_growth_ > 0) return false;
-  return ShouldRehashForBugDetection(seed, capacity);
+  return ShouldRehashForBugDetection(capacity);
 }
 
 bool CommonFieldsGenerationInfoEnabled::should_rehash_for_bug_detection_on_move(
-    PerTableSeed seed, size_t capacity) const {
-  return ShouldRehashForBugDetection(seed, capacity);
+    size_t capacity) const {
+  return ShouldRehashForBugDetection(capacity);
 }
 
 namespace {
 
-FindInfo find_first_non_full_from_h1(const ctrl_t* ctrl, size_t h1,
-                                     size_t capacity) {
-  auto seq = probe(h1, capacity);
-  if (IsEmptyOrDeleted(ctrl[seq.offset()])) {
-    return {seq.offset(), /*probe_length=*/0};
-  }
+// Probes an array of control bits using a probe sequence,
+// and returns the mask corresponding to the first group with a deleted or empty
+// slot.
+inline Group::NonIterableBitMaskType probe_till_first_non_full_group(
+    const ctrl_t* ctrl, probe_seq<Group::kWidth>& seq,
+    [[maybe_unused]] size_t capacity) {
   while (true) {
     GroupFullEmptyOrDeleted g{ctrl + seq.offset()};
     auto mask = g.MaskEmptyOrDeleted();
     if (mask) {
-      return {seq.offset(mask.LowestBitSet()), seq.index()};
+      return mask;
     }
     seq.next();
     ABSL_SWISSTABLE_ASSERT(seq.index() <= capacity && "full table!");
   }
 }
 
-// Whether a table is "small". A small table fits entirely into a probing
-// group, i.e., has a capacity < `Group::kWidth`.
+FindInfo find_first_non_full_from_h1(const ctrl_t* ctrl, size_t h1,
+                                     size_t capacity) {
+  auto seq = probe_h1(capacity, h1);
+  if (IsEmptyOrDeleted(ctrl[seq.offset()])) {
+    return {seq.offset(), /*probe_length=*/0};
+  }
+  auto mask = probe_till_first_non_full_group(ctrl, seq, capacity);
+  return {seq.offset(mask.LowestBitSet()), seq.index()};
+}
+
+// Probes an array of control bits using a probe sequence derived from `hash`,
+// and returns the offset corresponding to the first deleted or empty slot.
 //
-// In small mode we are able to use the whole capacity. The extra control
+// Behavior when the entire table is full is undefined.
+//
+// NOTE: this function must work with tables having both empty and deleted
+// slots in the same group. Such tables appear during `erase()`.
+FindInfo find_first_non_full(const CommonFields& common, size_t hash) {
+  return find_first_non_full_from_h1(common.control(), H1(hash),
+                                     common.capacity());
+}
+
+// Same as `find_first_non_full`, but returns the mask corresponding to the
+// first group with a deleted or empty slot.
+std::pair<FindInfo, Group::NonIterableBitMaskType> find_first_non_full_group(
+    const CommonFields& common, size_t hash) {
+  auto seq = probe(common, hash);
+  auto mask =
+      probe_till_first_non_full_group(common.control(), seq, common.capacity());
+  return {{seq.offset(), seq.index()}, mask};
+}
+
+// Whether a table fits in half a group. A half-group table fits entirely into a
+// probing group, i.e., has a capacity < `Group::kWidth`.
+//
+// In half-group mode we are able to use the whole capacity. The extra control
 // bytes give us at least one "empty" control byte to stop the iteration.
 // This is important to make 1 a valid capacity.
 //
-// In small mode only the first `capacity` control bytes after the sentinel
+// In half-group mode only the first `capacity` control bytes after the sentinel
 // are valid. The rest contain dummy ctrl_t::kEmpty values that do not
 // represent a real slot.
-constexpr bool is_small(size_t capacity) {
+constexpr bool is_half_group(size_t capacity) {
   return capacity < Group::kWidth - 1;
 }
 
 template <class Fn>
 void IterateOverFullSlotsImpl(const CommonFields& c, size_t slot_size, Fn cb) {
   const size_t cap = c.capacity();
+  ABSL_SWISSTABLE_ASSERT(!IsSmallCapacity(cap));
   const ctrl_t* ctrl = c.control();
   void* slot = c.slot_array();
-  if (is_small(cap)) {
-    // Mirrored/cloned control bytes in small table are also located in the
+  if (is_half_group(cap)) {
+    // Mirrored/cloned control bytes in half-group table are also located in the
     // first group (starting from position 0). We are taking group from position
     // `capacity` in order to avoid duplicates.
 
-    // Small tables capacity fits into portable group, where
+    // Half-group tables capacity fits into portable group, where
     // GroupPortableImpl::MaskFull is more efficient for the
     // capacity <= GroupPortableImpl::kWidth.
     ABSL_SWISSTABLE_ASSERT(cap <= GroupPortableImpl::kWidth &&
-                           "unexpectedly large small capacity");
+                           "unexpectedly large half-group capacity");
     static_assert(Group::kWidth >= GroupPortableImpl::kWidth,
                   "unexpected group width");
     // Group starts from kSentinel slot, so indices in the mask will
@@ -250,11 +291,6 @@
   ctrl[capacity] = ctrl_t::kSentinel;
 }
 
-FindInfo find_first_non_full(const CommonFields& common, size_t hash) {
-  return find_first_non_full_from_h1(common.control(), H1(hash, common.seed()),
-                                     common.capacity());
-}
-
 void IterateOverFullSlots(const CommonFields& c, size_t slot_size,
                           absl::FunctionRef<void(const ctrl_t*, void*)> cb) {
   IterateOverFullSlotsImpl(c, slot_size, cb);
@@ -300,6 +336,69 @@
   common.maybe_increment_generation_on_insert();
 }
 
+// Sets sanitizer poisoning for slot corresponding to control byte being set.
+inline void DoSanitizeOnSetCtrl(const CommonFields& c, size_t i, ctrl_t h,
+                                size_t slot_size) {
+  ABSL_SWISSTABLE_ASSERT(i < c.capacity());
+  auto* slot_i = static_cast<const char*>(c.slot_array()) + i * slot_size;
+  if (IsFull(h)) {
+    SanitizerUnpoisonMemoryRegion(slot_i, slot_size);
+  } else {
+    SanitizerPoisonMemoryRegion(slot_i, slot_size);
+  }
+}
+
+// Sets `ctrl[i]` to `h`.
+//
+// Unlike setting it directly, this function will perform bounds checks and
+// mirror the value to the cloned tail if necessary.
+inline void SetCtrl(const CommonFields& c, size_t i, ctrl_t h,
+                    size_t slot_size) {
+  ABSL_SWISSTABLE_ASSERT(!c.is_small());
+  DoSanitizeOnSetCtrl(c, i, h, slot_size);
+  ctrl_t* ctrl = c.control();
+  ctrl[i] = h;
+  ctrl[((i - NumClonedBytes()) & c.capacity()) +
+       (NumClonedBytes() & c.capacity())] = h;
+}
+// Overload for setting to an occupied `h2_t` rather than a special `ctrl_t`.
+inline void SetCtrl(const CommonFields& c, size_t i, h2_t h, size_t slot_size) {
+  SetCtrl(c, i, static_cast<ctrl_t>(h), slot_size);
+}
+
+// Like SetCtrl, but in a single group table, we can save some operations when
+// setting the cloned control byte.
+inline void SetCtrlInSingleGroupTable(const CommonFields& c, size_t i, ctrl_t h,
+                                      size_t slot_size) {
+  ABSL_SWISSTABLE_ASSERT(!c.is_small());
+  ABSL_SWISSTABLE_ASSERT(is_single_group(c.capacity()));
+  DoSanitizeOnSetCtrl(c, i, h, slot_size);
+  ctrl_t* ctrl = c.control();
+  ctrl[i] = h;
+  ctrl[i + c.capacity() + 1] = h;
+}
+// Overload for setting to an occupied `h2_t` rather than a special `ctrl_t`.
+inline void SetCtrlInSingleGroupTable(const CommonFields& c, size_t i, h2_t h,
+                                      size_t slot_size) {
+  SetCtrlInSingleGroupTable(c, i, static_cast<ctrl_t>(h), slot_size);
+}
+
+// Like SetCtrl, but in a table with capacity >= Group::kWidth - 1,
+// we can save some operations when setting the cloned control byte.
+inline void SetCtrlInLargeTable(const CommonFields& c, size_t i, ctrl_t h,
+                                size_t slot_size) {
+  ABSL_SWISSTABLE_ASSERT(c.capacity() >= Group::kWidth - 1);
+  DoSanitizeOnSetCtrl(c, i, h, slot_size);
+  ctrl_t* ctrl = c.control();
+  ctrl[i] = h;
+  ctrl[((i - NumClonedBytes()) & c.capacity()) + NumClonedBytes()] = h;
+}
+// Overload for setting to an occupied `h2_t` rather than a special `ctrl_t`.
+inline void SetCtrlInLargeTable(const CommonFields& c, size_t i, h2_t h,
+                                size_t slot_size) {
+  SetCtrlInLargeTable(c, i, static_cast<ctrl_t>(h), slot_size);
+}
+
 size_t DropDeletesWithoutResizeAndPrepareInsert(
     CommonFields& common, const PolicyFunctions& __restrict policy,
     size_t new_hash) {
@@ -347,7 +446,7 @@
       continue;
     }
     if (!IsDeleted(ctrl[i])) continue;
-    const size_t hash = (*hasher)(hash_fn, slot_ptr);
+    const size_t hash = (*hasher)(hash_fn, slot_ptr, common.seed().seed());
     const FindInfo target = find_first_non_full(common, hash);
     const size_t new_i = target.offset;
     total_probe_length += target.probe_length;
@@ -405,12 +504,12 @@
   ResetGrowthLeft(common);
   FindInfo find_info = find_first_non_full(common, new_hash);
   SetCtrlInLargeTable(common, find_info.offset, H2(new_hash), slot_size);
-  common.infoz().RecordInsert(new_hash, find_info.probe_length);
+  common.infoz().RecordInsertMiss(new_hash, find_info.probe_length);
   common.infoz().RecordRehash(total_probe_length);
   return find_info.offset;
 }
 
-static bool WasNeverFull(CommonFields& c, size_t index) {
+bool WasNeverFull(CommonFields& c, size_t index) {
   if (is_single_group(c.capacity())) {
     return true;
   }
@@ -434,6 +533,7 @@
   ctrl_t* ctrl = common.control();
   static constexpr size_t kTwoGroupCapacity = 2 * Group::kWidth - 1;
   if (ABSL_PREDICT_TRUE(capacity <= kTwoGroupCapacity)) {
+    if (IsSmallCapacity(capacity)) return;
     std::memset(ctrl, static_cast<int8_t>(ctrl_t::kEmpty), Group::kWidth);
     std::memset(ctrl + capacity, static_cast<int8_t>(ctrl_t::kEmpty),
                 Group::kWidth);
@@ -449,38 +549,11 @@
   SanitizerPoisonMemoryRegion(common.slot_array(), slot_size * capacity);
 }
 
-// Initializes control bytes for single element table.
-// Capacity of the table must be 1.
-ABSL_ATTRIBUTE_ALWAYS_INLINE inline void InitializeSingleElementControlBytes(
-    uint64_t h2, ctrl_t* new_ctrl) {
-  static constexpr uint64_t kEmptyXorSentinel =
-      static_cast<uint8_t>(ctrl_t::kEmpty) ^
-      static_cast<uint8_t>(ctrl_t::kSentinel);
-  static constexpr uint64_t kEmpty64 = static_cast<uint8_t>(ctrl_t::kEmpty);
-  // The first 8 bytes, where present slot positions are replaced with 0.
-  static constexpr uint64_t kFirstCtrlBytesWithZeroes =
-      k8EmptyBytes ^ kEmpty64 ^ (kEmptyXorSentinel << 8) ^ (kEmpty64 << 16);
-
-  // Fill the original 0th and mirrored 2nd bytes with the hash.
-  // Result will look like:
-  // HSHEEEEE
-  // Where H = h2, E = kEmpty, S = kSentinel.
-  const uint64_t first_ctrl_bytes =
-      (h2 | kFirstCtrlBytesWithZeroes) | (h2 << 16);
-  // Fill last bytes with kEmpty.
-  std::memset(new_ctrl + 1, static_cast<int8_t>(ctrl_t::kEmpty), Group::kWidth);
-  // Overwrite the first 3 bytes with HSH. Other bytes will not be changed.
-  absl::little_endian::Store64(new_ctrl, first_ctrl_bytes);
-}
-
-// Initializes control bytes for growing after SOO to the next capacity.
-// `soo_ctrl` is placed in the position `SooSlotIndex()`.
-// `new_hash` is placed in the position `new_offset`.
-// The table must be non-empty SOO.
-ABSL_ATTRIBUTE_ALWAYS_INLINE inline void
-InitializeThreeElementsControlBytesAfterSoo(ctrl_t soo_ctrl, size_t new_hash,
-                                            size_t new_offset,
-                                            ctrl_t* new_ctrl) {
+// Initializes control bytes for growing from capacity 1 to 3.
+// `orig_h2` is placed in the position `SooSlotIndex()`.
+// `new_h2` is placed in the position `new_offset`.
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline void InitializeThreeElementsControlBytes(
+    h2_t orig_h2, h2_t new_h2, size_t new_offset, ctrl_t* new_ctrl) {
   static constexpr size_t kNewCapacity = NextCapacity(SooCapacity());
   static_assert(kNewCapacity == 3);
   static_assert(is_single_group(kNewCapacity));
@@ -501,9 +574,9 @@
       (kEmptyXorSentinel << (8 * kNewCapacity)) ^
       (kEmpty64 << (8 * kMirroredSooSlotIndex));
 
-  const uint64_t soo_h2 = static_cast<uint64_t>(soo_ctrl);
-  const uint64_t new_h2_xor_empty = static_cast<uint64_t>(
-      H2(new_hash) ^ static_cast<uint8_t>(ctrl_t::kEmpty));
+  const uint64_t soo_h2 = static_cast<uint64_t>(orig_h2);
+  const uint64_t new_h2_xor_empty =
+      static_cast<uint64_t>(new_h2 ^ static_cast<uint8_t>(ctrl_t::kEmpty));
   // Fill the original and mirrored bytes for SOO slot.
   // Result will look like:
   // EHESEHEE
@@ -544,11 +617,24 @@
 
 }  // namespace
 
-void EraseMetaOnly(CommonFields& c, size_t index, size_t slot_size) {
-  ABSL_SWISSTABLE_ASSERT(IsFull(c.control()[index]) &&
-                         "erasing a dangling iterator");
+void EraseMetaOnlySmall(CommonFields& c, bool soo_enabled, size_t slot_size) {
+  ABSL_SWISSTABLE_ASSERT(c.is_small());
+  if (soo_enabled) {
+    c.set_empty_soo();
+    return;
+  }
   c.decrement_size();
   c.infoz().RecordErase();
+  SanitizerPoisonMemoryRegion(c.slot_array(), slot_size);
+}
+
+void EraseMetaOnlyLarge(CommonFields& c, const ctrl_t* ctrl, size_t slot_size) {
+  ABSL_SWISSTABLE_ASSERT(!c.is_small());
+  ABSL_SWISSTABLE_ASSERT(IsFull(*ctrl) && "erasing a dangling iterator");
+  c.decrement_size();
+  c.infoz().RecordErase();
+
+  size_t index = static_cast<size_t>(ctrl - c.control());
 
   if (WasNeverFull(c, index)) {
     SetCtrl(c, index, ctrl_t::kEmpty, slot_size);
@@ -599,15 +685,25 @@
   void* new_slots = common.slot_array();
   const void* hash_fn = policy.hash_fn(common);
   const size_t slot_size = policy.slot_size;
+  const size_t seed = common.seed().seed();
 
   const auto insert_slot = [&](void* slot) {
-    size_t hash = policy.hash_slot(hash_fn, slot);
-    auto target = find_first_non_full(common, hash);
-    SetCtrl(common, target.offset, H2(hash), slot_size);
+    size_t hash = policy.hash_slot(hash_fn, slot, seed);
+    FindInfo target;
+    if (common.is_small()) {
+      target = FindInfo{0, 0};
+    } else {
+      target = find_first_non_full(common, hash);
+      SetCtrl(common, target.offset, H2(hash), slot_size);
+    }
     policy.transfer_n(&common, SlotAddress(new_slots, target.offset, slot_size),
                       slot, 1);
     return target.probe_length;
   };
+  if (IsSmallCapacity(old_capacity)) {
+    if (common.size() == 1) insert_slot(old_slots);
+    return 0;
+  }
   size_t total_probe_length = 0;
   for (size_t i = 0; i < old_capacity; ++i) {
     if (IsFull(old_ctrl[i])) {
@@ -618,6 +714,75 @@
   return total_probe_length;
 }
 
+void ReportGrowthToInfozImpl(CommonFields& common, HashtablezInfoHandle infoz,
+                             size_t hash, size_t total_probe_length,
+                             size_t distance_from_desired) {
+  ABSL_SWISSTABLE_ASSERT(infoz.IsSampled());
+  infoz.RecordStorageChanged(common.size() - 1, common.capacity());
+  infoz.RecordRehash(total_probe_length);
+  infoz.RecordInsertMiss(hash, distance_from_desired);
+  common.set_has_infoz();
+  // TODO(b/413062340): we could potentially store infoz in place of the
+  // control pointer for the capacity 1 case.
+  common.set_infoz(infoz);
+}
+
+// Specialization to avoid passing two 0s from hot function.
+ABSL_ATTRIBUTE_NOINLINE void ReportSingleGroupTableGrowthToInfoz(
+    CommonFields& common, HashtablezInfoHandle infoz, size_t hash) {
+  ReportGrowthToInfozImpl(common, infoz, hash, /*total_probe_length=*/0,
+                          /*distance_from_desired=*/0);
+}
+
+ABSL_ATTRIBUTE_NOINLINE void ReportGrowthToInfoz(CommonFields& common,
+                                                 HashtablezInfoHandle infoz,
+                                                 size_t hash,
+                                                 size_t total_probe_length,
+                                                 size_t distance_from_desired) {
+  ReportGrowthToInfozImpl(common, infoz, hash, total_probe_length,
+                          distance_from_desired);
+}
+
+ABSL_ATTRIBUTE_NOINLINE void ReportResizeToInfoz(CommonFields& common,
+                                                 HashtablezInfoHandle infoz,
+                                                 size_t total_probe_length) {
+  ABSL_SWISSTABLE_ASSERT(infoz.IsSampled());
+  infoz.RecordStorageChanged(common.size(), common.capacity());
+  infoz.RecordRehash(total_probe_length);
+  common.set_has_infoz();
+  common.set_infoz(infoz);
+}
+
+struct BackingArrayPtrs {
+  ctrl_t* ctrl;
+  void* slots;
+};
+
+BackingArrayPtrs AllocBackingArray(CommonFields& common,
+                                   const PolicyFunctions& __restrict policy,
+                                   size_t new_capacity, bool has_infoz,
+                                   void* alloc) {
+  RawHashSetLayout layout(new_capacity, policy.slot_size, policy.slot_align,
+                          has_infoz);
+  // Perform a direct call in the common case to allow for profile-guided
+  // heap optimization (PGHO) to understand which allocation function is used.
+  constexpr size_t kDefaultAlignment = BackingArrayAlignment(alignof(size_t));
+  char* mem = static_cast<char*>(
+      ABSL_PREDICT_TRUE(
+          policy.alloc ==
+          (&AllocateBackingArray<kDefaultAlignment, std::allocator<char>>))
+          ? AllocateBackingArray<kDefaultAlignment, std::allocator<char>>(
+                alloc, layout.alloc_size())
+          : policy.alloc(alloc, layout.alloc_size()));
+  const GenerationType old_generation = common.generation();
+  common.set_generation_ptr(
+      reinterpret_cast<GenerationType*>(mem + layout.generation_offset()));
+  common.set_generation(NextGeneration(old_generation));
+
+  return {reinterpret_cast<ctrl_t*>(mem + layout.control_offset()),
+          mem + layout.slot_offset()};
+}
+
 template <ResizeNonSooMode kMode>
 void ResizeNonSooImpl(CommonFields& common,
                       const PolicyFunctions& __restrict policy,
@@ -625,26 +790,25 @@
   ABSL_SWISSTABLE_ASSERT(IsValidCapacity(new_capacity));
   ABSL_SWISSTABLE_ASSERT(new_capacity > policy.soo_capacity());
 
-  const size_t old_capacity = common.capacity();
-  [[maybe_unused]] ctrl_t* old_ctrl = common.control();
-  [[maybe_unused]] void* old_slots = common.slot_array();
+  [[maybe_unused]] const size_t old_capacity = common.capacity();
+  [[maybe_unused]] ctrl_t* old_ctrl;
+  [[maybe_unused]] void* old_slots;
+  if constexpr (kMode == ResizeNonSooMode::kGuaranteedAllocated) {
+    old_ctrl = common.control();
+    old_slots = common.slot_array();
+  }
 
   const size_t slot_size = policy.slot_size;
-  const size_t slot_align = policy.slot_align;
+  [[maybe_unused]] const size_t slot_align = policy.slot_align;
   const bool has_infoz = infoz.IsSampled();
+  void* alloc = policy.get_char_alloc(common);
 
   common.set_capacity(new_capacity);
-  RawHashSetLayout layout(new_capacity, slot_size, slot_align, has_infoz);
-  void* alloc = policy.get_char_alloc(common);
-  char* mem = static_cast<char*>(policy.alloc(alloc, layout.alloc_size()));
-  const GenerationType old_generation = common.generation();
-  common.set_generation_ptr(
-      reinterpret_cast<GenerationType*>(mem + layout.generation_offset()));
-  common.set_generation(NextGeneration(old_generation));
-
-  ctrl_t* new_ctrl = reinterpret_cast<ctrl_t*>(mem + layout.control_offset());
-  common.set_control</*kGenerateSeed=*/true>(new_ctrl);
-  common.set_slots(mem + layout.slot_offset());
+  const auto [new_ctrl, new_slots] =
+      AllocBackingArray(common, policy, new_capacity, has_infoz, alloc);
+  common.set_control(new_ctrl);
+  common.set_slots(new_slots);
+  common.generate_new_seed(has_infoz);
 
   size_t total_probe_length = 0;
   ResetCtrl(common, slot_size);
@@ -664,11 +828,8 @@
         CapacityToGrowth(new_capacity));
   }
 
-  if (has_infoz) {
-    common.set_has_infoz();
-    infoz.RecordStorageChanged(common.size(), new_capacity);
-    infoz.RecordRehash(total_probe_length);
-    common.set_infoz(infoz);
+  if (ABSL_PREDICT_FALSE(has_infoz)) {
+    ReportResizeToInfoz(common, infoz, total_probe_length);
   }
 }
 
@@ -697,23 +858,26 @@
 // It is rare to resize an SOO table with one element to a large size.
 // Requires: `c` contains SOO data.
 void InsertOldSooSlotAndInitializeControlBytes(
-    CommonFields& c, const PolicyFunctions& __restrict policy, size_t hash,
-    ctrl_t* new_ctrl, void* new_slots) {
+    CommonFields& c, const PolicyFunctions& __restrict policy, ctrl_t* new_ctrl,
+    void* new_slots, bool has_infoz) {
   ABSL_SWISSTABLE_ASSERT(c.size() == policy.soo_capacity());
   ABSL_SWISSTABLE_ASSERT(policy.soo_enabled);
   size_t new_capacity = c.capacity();
 
-  c.generate_new_seed();
-  size_t offset = probe(c.seed(), new_capacity, hash).offset();
+  c.generate_new_seed(has_infoz);
+
+  const size_t soo_slot_hash =
+      policy.hash_slot(policy.hash_fn(c), c.soo_data(), c.seed().seed());
+  size_t offset = probe(new_capacity, soo_slot_hash).offset();
   offset = offset == new_capacity ? 0 : offset;
   SanitizerPoisonMemoryRegion(new_slots, policy.slot_size * new_capacity);
   void* target_slot = SlotAddress(new_slots, offset, policy.slot_size);
   SanitizerUnpoisonMemoryRegion(target_slot, policy.slot_size);
   policy.transfer_n(&c, target_slot, c.soo_data(), 1);
-  c.set_control</*kGenerateSeed=*/false>(new_ctrl);
+  c.set_control(new_ctrl);
   c.set_slots(new_slots);
   ResetCtrl(c, policy.slot_size);
-  SetCtrl(c, offset, H2(hash), policy.slot_size);
+  SetCtrl(c, offset, H2(soo_slot_hash), policy.slot_size);
 }
 
 enum class ResizeFullSooTableSamplingMode {
@@ -739,9 +903,10 @@
                         ResizeFullSooTableSamplingMode sampling_mode) {
   AssertFullSoo(common, policy);
   const size_t slot_size = policy.slot_size;
-  const size_t slot_align = policy.slot_align;
+  void* alloc = policy.get_char_alloc(common);
 
   HashtablezInfoHandle infoz;
+  bool has_infoz = false;
   if (sampling_mode ==
       ResizeFullSooTableSamplingMode::kForceSampleNoResizeIfUnsampled) {
     if (ABSL_PREDICT_FALSE(policy.is_hashtablez_eligible)) {
@@ -749,33 +914,19 @@
                               policy.soo_capacity());
     }
 
-    if (!infoz.IsSampled()) {
-      return;
-    }
+    if (!infoz.IsSampled()) return;
+    has_infoz = true;
   }
 
-  const bool has_infoz = infoz.IsSampled();
-
   common.set_capacity(new_capacity);
 
-  RawHashSetLayout layout(new_capacity, slot_size, slot_align, has_infoz);
-  void* alloc = policy.get_char_alloc(common);
-  char* mem = static_cast<char*>(policy.alloc(alloc, layout.alloc_size()));
-  const GenerationType old_generation = common.generation();
-  common.set_generation_ptr(
-      reinterpret_cast<GenerationType*>(mem + layout.generation_offset()));
-  common.set_generation(NextGeneration(old_generation));
-
   // We do not set control and slots in CommonFields yet to avoid overriding
   // SOO data.
-  ctrl_t* new_ctrl = reinterpret_cast<ctrl_t*>(mem + layout.control_offset());
-  void* new_slots = mem + layout.slot_offset();
+  const auto [new_ctrl, new_slots] =
+      AllocBackingArray(common, policy, new_capacity, has_infoz, alloc);
 
-  const size_t soo_slot_hash =
-      policy.hash_slot(policy.hash_fn(common), common.soo_data());
-
-  InsertOldSooSlotAndInitializeControlBytes(common, policy, soo_slot_hash,
-                                            new_ctrl, new_slots);
+  InsertOldSooSlotAndInitializeControlBytes(common, policy, new_ctrl, new_slots,
+                                            has_infoz);
   ResetGrowthLeft(common);
   if (has_infoz) {
     common.set_has_infoz();
@@ -853,7 +1004,7 @@
     return;
   }
 
-  ABSL_SWISSTABLE_ASSERT(Group::kWidth == 16);
+  ABSL_SWISSTABLE_ASSERT(Group::kWidth == 16);  // NOLINT(misc-static-assert)
 
   // Fill the second half of the main control bytes with kEmpty.
   // For small capacity that may write into mirrored control bytes.
@@ -965,12 +1116,13 @@
   const void* hash_fn = policy.hash_fn(c);
   auto hash_slot = policy.hash_slot;
   auto transfer_n = policy.transfer_n;
+  const size_t seed = c.seed().seed();
   for (size_t old_index = start; old_index < old_capacity; ++old_index) {
     if (old_ctrl[old_index] != ctrl_t::kSentinel) {
       continue;
     }
     void* src_slot = SlotAddress(old_slots, old_index, slot_size);
-    const size_t hash = hash_slot(hash_fn, src_slot);
+    const size_t hash = hash_slot(hash_fn, src_slot, seed);
     const FindInfo target = find_first_non_full(c, hash);
     total_probe_length += target.probe_length;
     const size_t new_i = target.offset;
@@ -1224,6 +1376,79 @@
   }
 }
 
+void IncrementSmallSizeNonSoo(CommonFields& common,
+                              const PolicyFunctions& __restrict policy) {
+  ABSL_SWISSTABLE_ASSERT(common.is_small());
+  common.increment_size();
+  SanitizerUnpoisonMemoryRegion(common.slot_array(), policy.slot_size);
+}
+
+void IncrementSmallSize(CommonFields& common,
+                        const PolicyFunctions& __restrict policy) {
+  ABSL_SWISSTABLE_ASSERT(common.is_small());
+  if (policy.soo_enabled) {
+    common.set_full_soo();
+  } else {
+    IncrementSmallSizeNonSoo(common, policy);
+  }
+}
+
+std::pair<ctrl_t*, void*> Grow1To3AndPrepareInsert(
+    CommonFields& common, const PolicyFunctions& __restrict policy,
+    absl::FunctionRef<size_t(size_t)> get_hash) {
+  // TODO(b/413062340): Refactor to reuse more code with
+  // GrowSooTableToNextCapacityAndPrepareInsert.
+  ABSL_SWISSTABLE_ASSERT(common.capacity() == 1);
+  ABSL_SWISSTABLE_ASSERT(!common.empty());
+  ABSL_SWISSTABLE_ASSERT(!policy.soo_enabled);
+  constexpr size_t kOldCapacity = 1;
+  constexpr size_t kNewCapacity = NextCapacity(kOldCapacity);
+  ctrl_t* old_ctrl = common.control();
+  void* old_slots = common.slot_array();
+
+  const size_t slot_size = policy.slot_size;
+  const size_t slot_align = policy.slot_align;
+  void* alloc = policy.get_char_alloc(common);
+  HashtablezInfoHandle infoz = common.infoz();
+  const bool has_infoz = infoz.IsSampled();
+  common.set_capacity(kNewCapacity);
+
+  const auto [new_ctrl, new_slots] =
+      AllocBackingArray(common, policy, kNewCapacity, has_infoz, alloc);
+  common.set_control(new_ctrl);
+  common.set_slots(new_slots);
+  SanitizerPoisonMemoryRegion(new_slots, kNewCapacity * slot_size);
+
+  if (ABSL_PREDICT_TRUE(!has_infoz)) {
+    // When we're sampled, we already have a seed.
+    common.generate_new_seed(/*has_infoz=*/false);
+  }
+  const size_t new_hash = get_hash(common.seed().seed());
+  h2_t new_h2 = H2(new_hash);
+  size_t orig_hash =
+      policy.hash_slot(policy.hash_fn(common), old_slots, common.seed().seed());
+  size_t offset = Resize1To3NewOffset(new_hash, common.seed());
+  InitializeThreeElementsControlBytes(H2(orig_hash), new_h2, offset, new_ctrl);
+
+  void* old_element_target = NextSlot(new_slots, slot_size);
+  SanitizerUnpoisonMemoryRegion(old_element_target, slot_size);
+  policy.transfer_n(&common, old_element_target, old_slots, 1);
+
+  void* new_element_target_slot = SlotAddress(new_slots, offset, slot_size);
+  SanitizerUnpoisonMemoryRegion(new_element_target_slot, slot_size);
+
+  policy.dealloc(alloc, kOldCapacity, old_ctrl, slot_size, slot_align,
+                 has_infoz);
+  PrepareInsertCommon(common);
+  ABSL_SWISSTABLE_ASSERT(common.size() == 2);
+  GetGrowthInfoFromControl(new_ctrl).InitGrowthLeftNoDeleted(kNewCapacity - 2);
+
+  if (ABSL_PREDICT_FALSE(has_infoz)) {
+    ReportSingleGroupTableGrowthToInfoz(common, infoz, new_hash);
+  }
+  return {new_ctrl + offset, new_element_target_slot};
+}
+
 // Grows to next capacity and prepares insert for the given new_hash.
 // Returns the offset of the new element.
 size_t GrowToNextCapacityAndPrepareInsert(
@@ -1231,98 +1456,116 @@
     size_t new_hash) {
   ABSL_SWISSTABLE_ASSERT(common.growth_left() == 0);
   const size_t old_capacity = common.capacity();
-  ABSL_SWISSTABLE_ASSERT(old_capacity == 0 ||
-                         old_capacity > policy.soo_capacity());
+  ABSL_SWISSTABLE_ASSERT(old_capacity > policy.soo_capacity());
+  ABSL_SWISSTABLE_ASSERT(!IsSmallCapacity(old_capacity));
 
   const size_t new_capacity = NextCapacity(old_capacity);
-  ABSL_SWISSTABLE_ASSERT(IsValidCapacity(new_capacity));
-  ABSL_SWISSTABLE_ASSERT(new_capacity > policy.soo_capacity());
-
   ctrl_t* old_ctrl = common.control();
   void* old_slots = common.slot_array();
 
   common.set_capacity(new_capacity);
   const size_t slot_size = policy.slot_size;
   const size_t slot_align = policy.slot_align;
-  HashtablezInfoHandle infoz;
-  if (old_capacity > 0) {
-    infoz = common.infoz();
-  } else {
-    const bool should_sample =
-        policy.is_hashtablez_eligible && ShouldSampleNextTable();
-    if (ABSL_PREDICT_FALSE(should_sample)) {
-      infoz = ForcedTrySample(slot_size, policy.key_size, policy.value_size,
-                              policy.soo_capacity());
-    }
-  }
+  void* alloc = policy.get_char_alloc(common);
+  HashtablezInfoHandle infoz = common.infoz();
   const bool has_infoz = infoz.IsSampled();
 
-  RawHashSetLayout layout(new_capacity, slot_size, slot_align, has_infoz);
-  void* alloc = policy.get_char_alloc(common);
-  char* mem = static_cast<char*>(policy.alloc(alloc, layout.alloc_size()));
-  const GenerationType old_generation = common.generation();
-  common.set_generation_ptr(
-      reinterpret_cast<GenerationType*>(mem + layout.generation_offset()));
-  common.set_generation(NextGeneration(old_generation));
-
-  ctrl_t* new_ctrl = reinterpret_cast<ctrl_t*>(mem + layout.control_offset());
-  void* new_slots = mem + layout.slot_offset();
-  common.set_control</*kGenerateSeed=*/false>(new_ctrl);
+  const auto [new_ctrl, new_slots] =
+      AllocBackingArray(common, policy, new_capacity, has_infoz, alloc);
+  common.set_control(new_ctrl);
   common.set_slots(new_slots);
   SanitizerPoisonMemoryRegion(new_slots, new_capacity * slot_size);
 
   h2_t new_h2 = H2(new_hash);
   size_t total_probe_length = 0;
   FindInfo find_info;
-  if (old_capacity == 0) {
-    static_assert(NextCapacity(0) == 1);
-    InitializeSingleElementControlBytes(new_h2, new_ctrl);
-    common.generate_new_seed();
-    find_info = FindInfo{0, 0};
-    SanitizerUnpoisonMemoryRegion(new_slots, slot_size);
-  } else {
-    if (ABSL_PREDICT_TRUE(is_single_group(new_capacity))) {
-      GrowIntoSingleGroupShuffleControlBytes(old_ctrl, old_capacity, new_ctrl,
-                                             new_capacity);
-      // Single group tables have all slots full on resize. So we can transfer
-      // all slots without checking the control bytes.
-      ABSL_SWISSTABLE_ASSERT(common.size() == old_capacity);
-      auto* target = NextSlot(new_slots, slot_size);
-      SanitizerUnpoisonMemoryRegion(target, old_capacity * slot_size);
-      policy.transfer_n(&common, target, old_slots, old_capacity);
-      // We put the new element either at the beginning or at the end of the
-      // table with approximately equal probability.
-      size_t offset = SingleGroupTableH1(new_hash, common.seed()) & 1
-                          ? 0
-                          : new_capacity - 1;
+  if (ABSL_PREDICT_TRUE(is_single_group(new_capacity))) {
+    size_t offset;
+    GrowIntoSingleGroupShuffleControlBytes(old_ctrl, old_capacity, new_ctrl,
+                                           new_capacity);
+    // We put the new element either at the beginning or at the end of the
+    // table with approximately equal probability.
+    offset =
+        SingleGroupTableH1(new_hash, common.seed()) & 1 ? 0 : new_capacity - 1;
 
-      ABSL_SWISSTABLE_ASSERT(IsEmpty(new_ctrl[offset]));
-      SetCtrlInSingleGroupTable(common, offset, new_h2, policy.slot_size);
-      find_info = FindInfo{offset, 0};
-    } else {
-      total_probe_length =
-          GrowToNextCapacityDispatch(common, policy, old_ctrl, old_slots);
-      find_info = find_first_non_full(common, new_hash);
-      SetCtrlInLargeTable(common, find_info.offset, new_h2, policy.slot_size);
-    }
-    ABSL_SWISSTABLE_ASSERT(old_capacity > policy.soo_capacity());
-    (*policy.dealloc)(alloc, old_capacity, old_ctrl, slot_size, slot_align,
-                      has_infoz);
+    ABSL_SWISSTABLE_ASSERT(IsEmpty(new_ctrl[offset]));
+    SetCtrlInSingleGroupTable(common, offset, new_h2, policy.slot_size);
+    find_info = FindInfo{offset, 0};
+    // Single group tables have all slots full on resize. So we can transfer
+    // all slots without checking the control bytes.
+    ABSL_SWISSTABLE_ASSERT(common.size() == old_capacity);
+    void* target = NextSlot(new_slots, slot_size);
+    SanitizerUnpoisonMemoryRegion(target, old_capacity * slot_size);
+    policy.transfer_n(&common, target, old_slots, old_capacity);
+  } else {
+    total_probe_length =
+        GrowToNextCapacityDispatch(common, policy, old_ctrl, old_slots);
+    find_info = find_first_non_full(common, new_hash);
+    SetCtrlInLargeTable(common, find_info.offset, new_h2, policy.slot_size);
   }
+  ABSL_SWISSTABLE_ASSERT(old_capacity > policy.soo_capacity());
+  (*policy.dealloc)(alloc, old_capacity, old_ctrl, slot_size, slot_align,
+                    has_infoz);
   PrepareInsertCommon(common);
   ResetGrowthLeft(GetGrowthInfoFromControl(new_ctrl), new_capacity,
                   common.size());
 
   if (ABSL_PREDICT_FALSE(has_infoz)) {
-    common.set_has_infoz();
-    infoz.RecordStorageChanged(common.size() - 1, new_capacity);
-    infoz.RecordRehash(total_probe_length);
-    infoz.RecordInsert(new_hash, find_info.probe_length);
-    common.set_infoz(infoz);
+    ReportGrowthToInfoz(common, infoz, new_hash, total_probe_length,
+                        find_info.probe_length);
   }
   return find_info.offset;
 }
 
+}  // namespace
+
+std::pair<ctrl_t*, void*> PrepareInsertSmallNonSoo(
+    CommonFields& common, const PolicyFunctions& __restrict policy,
+    absl::FunctionRef<size_t(size_t)> get_hash) {
+  ABSL_SWISSTABLE_ASSERT(common.is_small());
+  ABSL_SWISSTABLE_ASSERT(!policy.soo_enabled);
+  if (common.capacity() == 1) {
+    if (common.empty()) {
+      IncrementSmallSizeNonSoo(common, policy);
+      return {SooControl(), common.slot_array()};
+    } else {
+      return Grow1To3AndPrepareInsert(common, policy, get_hash);
+    }
+  }
+
+  // Growing from 0 to 1 capacity.
+  ABSL_SWISSTABLE_ASSERT(common.capacity() == 0);
+  constexpr size_t kNewCapacity = 1;
+
+  common.set_capacity(kNewCapacity);
+  HashtablezInfoHandle infoz;
+  const bool should_sample =
+      policy.is_hashtablez_eligible && ShouldSampleNextTable();
+  if (ABSL_PREDICT_FALSE(should_sample)) {
+    infoz = ForcedTrySample(policy.slot_size, policy.key_size,
+                            policy.value_size, policy.soo_capacity());
+  }
+  const bool has_infoz = infoz.IsSampled();
+  void* alloc = policy.get_char_alloc(common);
+
+  const auto [new_ctrl, new_slots] =
+      AllocBackingArray(common, policy, kNewCapacity, has_infoz, alloc);
+  common.set_control(new_ctrl);
+  common.set_slots(new_slots);
+
+  static_assert(NextCapacity(0) == 1);
+  PrepareInsertCommon(common);
+
+  if (ABSL_PREDICT_FALSE(has_infoz)) {
+    common.generate_new_seed(/*has_infoz=*/true);
+    ReportSingleGroupTableGrowthToInfoz(common, infoz,
+                                        get_hash(common.seed().seed()));
+  }
+  return {SooControl(), new_slots};
+}
+
+namespace {
+
 // Called whenever the table needs to vacate empty slots either by removing
 // tombstones via rehash or growth to next capacity.
 ABSL_ATTRIBUTE_NOINLINE
@@ -1382,11 +1625,11 @@
   }
 }
 
-// Slow path for PrepareInsertNonSoo that is called when the table has deleted
+// Slow path for PrepareInsertLarge that is called when the table has deleted
 // slots or need to be resized or rehashed.
-size_t PrepareInsertNonSooSlow(CommonFields& common,
-                               const PolicyFunctions& __restrict policy,
-                               size_t hash) {
+size_t PrepareInsertLargeSlow(CommonFields& common,
+                              const PolicyFunctions& __restrict policy,
+                              size_t hash) {
   const GrowthInfo growth_info = common.growth_info();
   ABSL_SWISSTABLE_ASSERT(!growth_info.HasNoDeletedAndGrowthLeft());
   if (ABSL_PREDICT_TRUE(growth_info.HasNoGrowthLeftAndNoDeleted())) {
@@ -1404,7 +1647,7 @@
   PrepareInsertCommon(common);
   common.growth_info().OverwriteControlAsFull(common.control()[target.offset]);
   SetCtrlInLargeTable(common, target.offset, H2(hash), policy.slot_size);
-  common.infoz().RecordInsert(hash, target.probe_length);
+  common.infoz().RecordInsertMiss(hash, target.probe_length);
   return target.offset;
 }
 
@@ -1417,14 +1660,15 @@
 ABSL_ATTRIBUTE_NOINLINE size_t
 GrowEmptySooTableToNextCapacityForceSamplingAndPrepareInsert(
     CommonFields& common, const PolicyFunctions& __restrict policy,
-    size_t new_hash) {
+    absl::FunctionRef<size_t(size_t)> get_hash) {
   ResizeEmptyNonAllocatedTableImpl(common, policy, NextCapacity(SooCapacity()),
                                    /*force_infoz=*/true);
   PrepareInsertCommon(common);
   common.growth_info().OverwriteEmptyAsFull();
+  const size_t new_hash = get_hash(common.seed().seed());
   SetCtrlInSingleGroupTable(common, SooSlotIndex(), H2(new_hash),
                             policy.slot_size);
-  common.infoz().RecordInsert(new_hash, /*distance_from_desired=*/0);
+  common.infoz().RecordInsertMiss(new_hash, /*distance_from_desired=*/0);
   return SooSlotIndex();
 }
 
@@ -1471,6 +1715,17 @@
   common.infoz().RecordReservation(new_size);
 }
 
+// As `ResizeFullSooTableToNextCapacity`, except that we also force the SOO
+// table to be sampled. SOO tables need to switch from SOO to heap in order to
+// store the infoz. No-op if sampling is disabled or not possible.
+void GrowFullSooTableToNextCapacityForceSampling(
+    CommonFields& common, const PolicyFunctions& __restrict policy) {
+  AssertFullSoo(common, policy);
+  ResizeFullSooTable(
+      common, policy, NextCapacity(SooCapacity()),
+      ResizeFullSooTableSamplingMode::kForceSampleNoResizeIfUnsampled);
+}
+
 }  // namespace
 
 void* GetRefForEmptyClass(CommonFields& common) {
@@ -1501,46 +1756,38 @@
 template <size_t SooSlotMemcpySize, bool TransferUsesMemcpy>
 size_t GrowSooTableToNextCapacityAndPrepareInsert(
     CommonFields& common, const PolicyFunctions& __restrict policy,
-    size_t new_hash, ctrl_t soo_slot_ctrl) {
+    absl::FunctionRef<size_t(size_t)> get_hash, bool force_sampling) {
   AssertSoo(common, policy);
-  if (ABSL_PREDICT_FALSE(soo_slot_ctrl == ctrl_t::kEmpty)) {
+  if (ABSL_PREDICT_FALSE(force_sampling)) {
     // The table is empty, it is only used for forced sampling of SOO tables.
     return GrowEmptySooTableToNextCapacityForceSamplingAndPrepareInsert(
-        common, policy, new_hash);
+        common, policy, get_hash);
   }
   ABSL_SWISSTABLE_ASSERT(common.size() == policy.soo_capacity());
   static constexpr size_t kNewCapacity = NextCapacity(SooCapacity());
   const size_t slot_size = policy.slot_size;
-  const size_t slot_align = policy.slot_align;
+  void* alloc = policy.get_char_alloc(common);
   common.set_capacity(kNewCapacity);
 
   // Since the table is not empty, it will not be sampled.
   // The decision to sample was already made during the first insertion.
-  RawHashSetLayout layout(kNewCapacity, slot_size, slot_align,
-                          /*has_infoz=*/false);
-  void* alloc = policy.get_char_alloc(common);
-  char* mem = static_cast<char*>(policy.alloc(alloc, layout.alloc_size()));
-  const GenerationType old_generation = common.generation();
-  common.set_generation_ptr(
-      reinterpret_cast<GenerationType*>(mem + layout.generation_offset()));
-  common.set_generation(NextGeneration(old_generation));
-
+  //
   // We do not set control and slots in CommonFields yet to avoid overriding
   // SOO data.
-  ctrl_t* new_ctrl = reinterpret_cast<ctrl_t*>(mem + layout.control_offset());
-  void* new_slots = mem + layout.slot_offset();
+  const auto [new_ctrl, new_slots] = AllocBackingArray(
+      common, policy, kNewCapacity, /*has_infoz=*/false, alloc);
 
   PrepareInsertCommon(common);
   ABSL_SWISSTABLE_ASSERT(common.size() == 2);
   GetGrowthInfoFromControl(new_ctrl).InitGrowthLeftNoDeleted(kNewCapacity - 2);
-  common.generate_new_seed();
+  common.generate_new_seed(/*has_infoz=*/false);
+  const h2_t soo_slot_h2 = H2(policy.hash_slot(
+      policy.hash_fn(common), common.soo_data(), common.seed().seed()));
+  const size_t new_hash = get_hash(common.seed().seed());
 
-  // After resize from capacity 1 to 3, we always have exactly the slot with
-  // index 1 occupied, so we need to insert either at index 0 or index 2.
-  static_assert(SooSlotIndex() == 1);
-  const size_t offset = SingleGroupTableH1(new_hash, common.seed()) & 2;
-  InitializeThreeElementsControlBytesAfterSoo(soo_slot_ctrl, new_hash, offset,
-                                              new_ctrl);
+  const size_t offset = Resize1To3NewOffset(new_hash, common.seed());
+  InitializeThreeElementsControlBytes(soo_slot_h2, H2(new_hash), offset,
+                                      new_ctrl);
 
   SanitizerPoisonMemoryRegion(new_slots, slot_size * kNewCapacity);
   void* target_slot = SlotAddress(new_slots, SooSlotIndex(), slot_size);
@@ -1562,24 +1809,17 @@
     static_assert(SooSlotMemcpySize == 0);
     policy.transfer_n(&common, target_slot, common.soo_data(), 1);
   }
-  // Seed was already generated above.
-  common.set_control</*kGenerateSeed=*/false>(new_ctrl);
+  common.set_control(new_ctrl);
   common.set_slots(new_slots);
 
-  common.infoz().RecordInsert(new_hash, /*distance_from_desired=*/0);
+  // Full SOO table couldn't be sampled. If SOO table is sampled, it would
+  // have been resized to the next capacity.
+  ABSL_SWISSTABLE_ASSERT(!common.infoz().IsSampled());
   SanitizerUnpoisonMemoryRegion(SlotAddress(new_slots, offset, slot_size),
                                 slot_size);
   return offset;
 }
 
-void GrowFullSooTableToNextCapacityForceSampling(
-    CommonFields& common, const PolicyFunctions& __restrict policy) {
-  AssertFullSoo(common, policy);
-  ResizeFullSooTable(
-      common, policy, NextCapacity(SooCapacity()),
-      ResizeFullSooTableSamplingMode::kForceSampleNoResizeIfUnsampled);
-}
-
 void Rehash(CommonFields& common, const PolicyFunctions& __restrict policy,
             size_t n) {
   const size_t cap = common.capacity();
@@ -1612,7 +1852,7 @@
       }
       ABSL_SWISSTABLE_ASSERT(slot_size <= sizeof(HeapOrSoo));
       ABSL_SWISSTABLE_ASSERT(policy.slot_align <= alignof(HeapOrSoo));
-      HeapOrSoo tmp_slot(uninitialized_tag_t{});
+      HeapOrSoo tmp_slot;
       size_t begin_offset = FindFirstFullSlot(0, cap, common.control());
       policy.transfer_n(
           &common, &tmp_slot,
@@ -1655,19 +1895,22 @@
   ABSL_SWISSTABLE_ASSERT(size > 0);
   const size_t soo_capacity = policy.soo_capacity();
   const size_t slot_size = policy.slot_size;
-  if (size <= soo_capacity) {
-    ABSL_SWISSTABLE_ASSERT(size == 1);
-    common.set_full_soo();
+  const bool soo_enabled = policy.soo_enabled;
+  if (size == 1) {
+    if (!soo_enabled) ReserveTableToFitNewSize(common, policy, 1);
+    IncrementSmallSize(common, policy);
+    const size_t other_capacity = other.capacity();
     const void* other_slot =
-        other.capacity() <= soo_capacity
-            ? other.soo_data()
-            : SlotAddress(
-                  other.slot_array(),
-                  FindFirstFullSlot(0, other.capacity(), other.control()),
-                  slot_size);
-    copy_fn(common.soo_data(), other_slot);
+        other_capacity <= soo_capacity ? other.soo_data()
+        : other.is_small()
+            ? other.slot_array()
+            : SlotAddress(other.slot_array(),
+                          FindFirstFullSlot(0, other_capacity, other.control()),
+                          slot_size);
+    copy_fn(soo_enabled ? common.soo_data() : common.slot_array(), other_slot);
 
-    if (policy.is_hashtablez_eligible && ShouldSampleNextTable()) {
+    if (soo_enabled && policy.is_hashtablez_eligible &&
+        ShouldSampleNextTable()) {
       GrowFullSooTableToNextCapacityForceSampling(common, policy);
     }
     return;
@@ -1678,47 +1921,22 @@
   ABSL_SWISSTABLE_ASSERT(other.capacity() > soo_capacity);
   const size_t cap = common.capacity();
   ABSL_SWISSTABLE_ASSERT(cap > soo_capacity);
-  // Note about single group tables:
-  // 1. It is correct to have any order of elements.
-  // 2. Order has to be non deterministic.
-  // 3. We are assigning elements with arbitrary `shift` starting from
-  //    `capacity + shift` position.
-  // 4. `shift` must be coprime with `capacity + 1` in order to be able to use
-  //     modular arithmetic to traverse all positions, instead of cycling
-  //     through a subset of positions. Odd numbers are coprime with any
-  //     `capacity + 1` (2^N).
   size_t offset = cap;
-  const size_t shift = is_single_group(cap) ? (common.seed().seed() | 1) : 0;
   const void* hash_fn = policy.hash_fn(common);
   auto hasher = policy.hash_slot;
+  const size_t seed = common.seed().seed();
   IterateOverFullSlotsImpl(
-      other, slot_size, [&](const ctrl_t* that_ctrl, void* that_slot) {
-        if (shift == 0) {
-          // Big tables case. Position must be searched via probing.
-          // The table is guaranteed to be empty, so we can do faster than
-          // a full `insert`.
-          const size_t hash = (*hasher)(hash_fn, that_slot);
-          FindInfo target = find_first_non_full(common, hash);
-          infoz.RecordInsert(hash, target.probe_length);
-          offset = target.offset;
-        } else {
-          // Small tables case. Next position is computed via shift.
-          offset = (offset + shift) & cap;
-        }
-        const h2_t h2 = static_cast<h2_t>(*that_ctrl);
-        // We rely on the hash not changing for small tables.
-        ABSL_SWISSTABLE_ASSERT(
-            H2((*hasher)(hash_fn, that_slot)) == h2 &&
-            "hash function value changed unexpectedly during the copy");
-        SetCtrl(common, offset, h2, slot_size);
+      other, slot_size, [&](const ctrl_t*, void* that_slot) {
+        // The table is guaranteed to be empty, so we can do faster than
+        // a full `insert`.
+        const size_t hash = (*hasher)(hash_fn, that_slot, seed);
+        FindInfo target = find_first_non_full(common, hash);
+        infoz.RecordInsertMiss(hash, target.probe_length);
+        offset = target.offset;
+        SetCtrl(common, offset, H2(hash), slot_size);
         copy_fn(SlotAddress(common.slot_array(), offset, slot_size), that_slot);
         common.maybe_increment_generation_on_insert();
       });
-  if (shift != 0) {
-    // On small table copy we do not record individual inserts.
-    // RecordInsert requires hash, but it is unknown for small tables.
-    infoz.RecordStorageChanged(size, cap);
-  }
   common.increment_size(size);
   common.growth_info().OverwriteManyEmptyAsFull(size);
 }
@@ -1737,41 +1955,62 @@
   ABSL_SWISSTABLE_ASSERT(!common.empty() || cap > policy.soo_capacity());
   ABSL_SWISSTABLE_ASSERT(cap > 0);
   const size_t max_size_before_growth =
-      cap <= policy.soo_capacity() ? policy.soo_capacity()
-                                   : common.size() + common.growth_left();
+      IsSmallCapacity(cap) ? cap : common.size() + common.growth_left();
   if (new_size <= max_size_before_growth) {
     return;
   }
   ReserveAllocatedTable(common, policy, new_size);
 }
 
-size_t PrepareInsertNonSoo(CommonFields& common,
-                           const PolicyFunctions& __restrict policy,
-                           size_t hash, FindInfo target) {
-  const bool rehash_for_bug_detection =
-      common.should_rehash_for_bug_detection_on_insert() &&
-      // Required to allow use of ResizeAllocatedTable.
-      common.capacity() > 0;
-  if (rehash_for_bug_detection) {
-    // Move to a different heap allocation in order to detect bugs.
-    const size_t cap = common.capacity();
-    ResizeAllocatedTableWithSeedChange(
-        common, policy, common.growth_left() > 0 ? cap : NextCapacity(cap));
-    target = find_first_non_full(common, hash);
-  }
-
+namespace {
+size_t PrepareInsertLargeImpl(CommonFields& common,
+                              const PolicyFunctions& __restrict policy,
+                              size_t hash,
+                              Group::NonIterableBitMaskType mask_empty,
+                              FindInfo target_group) {
+  ABSL_SWISSTABLE_ASSERT(!common.is_small());
   const GrowthInfo growth_info = common.growth_info();
   // When there are no deleted slots in the table
   // and growth_left is positive, we can insert at the first
   // empty slot in the probe sequence (target).
   if (ABSL_PREDICT_FALSE(!growth_info.HasNoDeletedAndGrowthLeft())) {
-    return PrepareInsertNonSooSlow(common, policy, hash);
+    return PrepareInsertLargeSlow(common, policy, hash);
   }
   PrepareInsertCommon(common);
   common.growth_info().OverwriteEmptyAsFull();
-  SetCtrl(common, target.offset, H2(hash), policy.slot_size);
-  common.infoz().RecordInsert(hash, target.probe_length);
-  return target.offset;
+  target_group.offset += mask_empty.LowestBitSet();
+  target_group.offset &= common.capacity();
+  SetCtrl(common, target_group.offset, H2(hash), policy.slot_size);
+  common.infoz().RecordInsertMiss(hash, target_group.probe_length);
+  return target_group.offset;
+}
+}  // namespace
+
+size_t PrepareInsertLarge(CommonFields& common,
+                          const PolicyFunctions& __restrict policy, size_t hash,
+                          Group::NonIterableBitMaskType mask_empty,
+                          FindInfo target_group) {
+  // NOLINTNEXTLINE(misc-static-assert)
+  ABSL_SWISSTABLE_ASSERT(!SwisstableGenerationsEnabled());
+  return PrepareInsertLargeImpl(common, policy, hash, mask_empty, target_group);
+}
+
+size_t PrepareInsertLargeGenerationsEnabled(
+    CommonFields& common, const PolicyFunctions& policy, size_t hash,
+    Group::NonIterableBitMaskType mask_empty, FindInfo target_group,
+    absl::FunctionRef<size_t(size_t)> recompute_hash) {
+  // NOLINTNEXTLINE(misc-static-assert)
+  ABSL_SWISSTABLE_ASSERT(SwisstableGenerationsEnabled());
+  if (common.should_rehash_for_bug_detection_on_insert()) {
+    // Move to a different heap allocation in order to detect bugs.
+    const size_t cap = common.capacity();
+    ResizeAllocatedTableWithSeedChange(
+        common, policy, common.growth_left() > 0 ? cap : NextCapacity(cap));
+    hash = recompute_hash(common.seed().seed());
+    std::tie(target_group, mask_empty) =
+        find_first_non_full_group(common, hash);
+  }
+  return PrepareInsertLargeImpl(common, policy, hash, mask_empty, target_group);
 }
 
 namespace {
@@ -1808,35 +2047,44 @@
 // We need to instantiate ALL possible template combinations because we define
 // the function in the cc file.
 template size_t GrowSooTableToNextCapacityAndPrepareInsert<0, false>(
-    CommonFields&, const PolicyFunctions&, size_t, ctrl_t);
+    CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
+    bool);
 template size_t GrowSooTableToNextCapacityAndPrepareInsert<
-    OptimalMemcpySizeForSooSlotTransfer(1), true>(CommonFields&,
-                                                  const PolicyFunctions&,
-                                                  size_t, ctrl_t);
+    OptimalMemcpySizeForSooSlotTransfer(1), true>(
+    CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
+    bool);
 
 static_assert(VerifyOptimalMemcpySizeForSooSlotTransferRange(2, 3));
 template size_t GrowSooTableToNextCapacityAndPrepareInsert<
-    OptimalMemcpySizeForSooSlotTransfer(3), true>(CommonFields&,
-                                                  const PolicyFunctions&,
-                                                  size_t, ctrl_t);
+    OptimalMemcpySizeForSooSlotTransfer(3), true>(
+    CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
+    bool);
 
 static_assert(VerifyOptimalMemcpySizeForSooSlotTransferRange(4, 8));
 template size_t GrowSooTableToNextCapacityAndPrepareInsert<
-    OptimalMemcpySizeForSooSlotTransfer(8), true>(CommonFields&,
-                                                  const PolicyFunctions&,
-                                                  size_t, ctrl_t);
+    OptimalMemcpySizeForSooSlotTransfer(8), true>(
+    CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
+    bool);
 
 #if UINTPTR_MAX == UINT32_MAX
 static_assert(MaxSooSlotSize() == 8);
 #else
 static_assert(VerifyOptimalMemcpySizeForSooSlotTransferRange(9, 16));
 template size_t GrowSooTableToNextCapacityAndPrepareInsert<
-    OptimalMemcpySizeForSooSlotTransfer(16), true>(CommonFields&,
-                                                   const PolicyFunctions&,
-                                                   size_t, ctrl_t);
+    OptimalMemcpySizeForSooSlotTransfer(16), true>(
+    CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
+    bool);
 static_assert(MaxSooSlotSize() == 16);
 #endif
 
+template void* AllocateBackingArray<BackingArrayAlignment(alignof(size_t)),
+                                    std::allocator<char>>(void* alloc,
+                                                          size_t n);
+template void DeallocateBackingArray<BackingArrayAlignment(alignof(size_t)),
+                                     std::allocator<char>>(
+    void* alloc, size_t capacity, ctrl_t* ctrl, size_t slot_size,
+    size_t slot_align, bool had_infoz);
+
 }  // namespace container_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index f5e3fdf..d307e2d 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -150,11 +150,11 @@
 // To `insert`, we compose `unchecked_insert` with `find`. We compute `h(x)` and
 // perform a `find` to see if it's already present; if it is, we're done. If
 // it's not, we may decide the table is getting overcrowded (i.e. the load
-// factor is greater than 7/8 for big tables; `is_small()` tables use a max load
-// factor of 1); in this case, we allocate a bigger array, `unchecked_insert`
-// each element of the table into the new array (we know that no insertion here
-// will insert an already-present value), and discard the old backing array. At
-// this point, we may `unchecked_insert` the value `x`.
+// factor is greater than 7/8 for big tables; tables smaller than one probing
+// group use a max load factor of 1); in this case, we allocate a bigger array,
+// `unchecked_insert` each element of the table into the new array (we know that
+// no insertion here will insert an already-present value), and discard the old
+// backing array. At this point, we may `unchecked_insert` the value `x`.
 //
 // Below, `unchecked_insert` is partly implemented by `prepare_insert`, which
 // presents a viable, initialized slot pointee to the caller.
@@ -194,6 +194,7 @@
 #include <utility>
 
 #include "absl/base/attributes.h"
+#include "absl/base/casts.h"
 #include "absl/base/config.h"
 #include "absl/base/internal/endian.h"
 #include "absl/base/internal/iterator_traits.h"
@@ -282,10 +283,8 @@
   swap(lhs, rhs);
 }
 template <typename AllocType>
-void SwapAlloc(AllocType& lhs, AllocType& rhs,
+void SwapAlloc([[maybe_unused]] AllocType& lhs, [[maybe_unused]] AllocType& rhs,
                std::false_type /* propagate_on_container_swap */) {
-  (void)lhs;
-  (void)rhs;
   assert(lhs == rhs &&
          "It's UB to call swap with unequal non-propagating allocators.");
 }
@@ -369,19 +368,7 @@
         std::declval<Ts>()...))>,
     Policy, Hash, Eq, Ts...> : std::true_type {};
 
-// TODO(alkis): Switch to std::is_nothrow_swappable when gcc/clang supports it.
-template <class T>
-constexpr bool IsNoThrowSwappable(std::true_type = {} /* is_swappable */) {
-  using std::swap;
-  return noexcept(swap(std::declval<T&>(), std::declval<T&>()));
-}
-template <class T>
-constexpr bool IsNoThrowSwappable(std::false_type /* is_swappable */) {
-  return false;
-}
-
-// See definition comment for why this is size 32.
-ABSL_DLL extern const ctrl_t kEmptyGroup[32];
+ABSL_DLL extern ctrl_t kDefaultIterControl;
 
 // We use these sentinel capacity values in debug mode to indicate different
 // classes of bugs.
@@ -395,17 +382,14 @@
   kSelfMovedFrom,
 };
 
-// Returns a pointer to a control byte group that can be used by empty tables.
-inline ctrl_t* EmptyGroup() {
-  // Const must be cast away here; no uses of this function will actually write
-  // to it because it is only used for empty tables.
-  return const_cast<ctrl_t*>(kEmptyGroup + 16);
-}
+// Returns a pointer to a control byte that can be used by default-constructed
+// iterators. We don't expect this pointer to be dereferenced.
+inline ctrl_t* DefaultIterControl() { return &kDefaultIterControl; }
 
 // For use in SOO iterators.
 // TODO(b/289225379): we could potentially get rid of this by adding an is_soo
 // bit in iterators. This would add branches but reduce cache misses.
-ABSL_DLL extern const ctrl_t kSooControl[17];
+ABSL_DLL extern const ctrl_t kSooControl[2];
 
 // Returns a pointer to a full byte followed by a sentinel byte.
 inline ctrl_t* SooControl() {
@@ -452,29 +436,31 @@
   // The number of bits in the seed.
   // It is big enough to ensure non-determinism of iteration order.
   // We store the seed inside a uint64_t together with size and other metadata.
-  // Using 16 bits allows us to save one `and` instruction in H1 (we use movzwl
-  // instead of movq+and).
+  // Using 16 bits allows us to save one `and` instruction in H1 (we use
+  // sign-extended move instead of mov+and).
   static constexpr size_t kBitCount = 16;
+  static constexpr size_t kSignBit = uint64_t{1} << (kBitCount - 1);
 
-  // Returns the seed for the table. Only the lowest kBitCount are non zero.
-  size_t seed() const { return seed_; }
+  // Returns the seed for the table.
+  size_t seed() const {
+    // We use a sign-extended load to ensure high bits are non-zero.
+    int16_t seed_signed = absl::bit_cast<int16_t>(seed_);
+    auto seed_sign_extended =
+        static_cast<std::make_signed_t<size_t>>(seed_signed);
+    return absl::bit_cast<size_t>(seed_sign_extended);
+  }
 
  private:
   friend class HashtableSize;
-  explicit PerTableSeed(size_t seed) : seed_(seed) {}
+  explicit PerTableSeed(uint16_t seed) : seed_(seed) {
+    ABSL_SWISSTABLE_ASSERT((seed & kSignBit) != 0 || seed == 0);
+  }
 
-  const size_t seed_;
+  // The most significant bit of the seed is always 1 when there is a non-zero
+  // seed. This way, when sign-extended the seed has non-zero high bits.
+  const uint16_t seed_;
 };
 
-// Returns next per-table seed.
-inline uint16_t NextSeed() {
-  static_assert(PerTableSeed::kBitCount == 16);
-  thread_local uint16_t seed =
-      static_cast<uint16_t>(reinterpret_cast<uintptr_t>(&seed));
-  seed += uint16_t{0xad53};
-  return seed;
-}
-
 // The size and also has additionally
 // 1) one bit that stores whether we have infoz.
 // 2) PerTableSeed::kBitCount bits for the seed.
@@ -502,8 +488,14 @@
     return PerTableSeed(static_cast<size_t>(data_) & kSeedMask);
   }
 
-  void generate_new_seed() {
-    data_ = (data_ & ~kSeedMask) ^ uint64_t{NextSeed()};
+  void generate_new_seed() { set_seed(NextSeed()); }
+
+  // We need to use a constant seed when the table is sampled so that sampled
+  // hashes use the same seed and can e.g. identify stuck bits accurately.
+  void set_sampled_seed() { set_seed(PerTableSeed::kSignBit); }
+
+  bool is_sampled_seed() const {
+    return (data_ & kSeedMask) == PerTableSeed::kSignBit;
   }
 
   // Returns true if the table has infoz.
@@ -516,7 +508,13 @@
 
   void set_no_seed_for_testing() { data_ &= ~kSeedMask; }
 
+  // Returns next per-table seed.
+  static uint16_t NextSeed();
+
  private:
+  void set_seed(uint16_t seed) {
+    data_ = (data_ & ~kSeedMask) | (seed | PerTableSeed::kSignBit);
+  }
   static constexpr size_t kSizeShift = 64 - kSizeBitCount;
   static constexpr uint64_t kSizeOneNoMetadata = uint64_t{1} << kSizeShift;
   static constexpr uint64_t kMetadataMask = kSizeOneNoMetadata - 1;
@@ -527,15 +525,13 @@
   uint64_t data_;
 };
 
-// Extracts the H1 portion of a hash: 57 bits mixed with a per-table seed.
-inline size_t H1(size_t hash, PerTableSeed seed) {
-  return (hash >> 7) ^ seed.seed();
-}
+// H1 is just the low bits of the hash.
+inline size_t H1(size_t hash) { return hash; }
 
-// Extracts the H2 portion of a hash: the 7 bits not used for H1.
+// Extracts the H2 portion of a hash: the 7 most significant bits.
 //
 // These are used as an occupied control byte.
-inline h2_t H2(size_t hash) { return hash & 0x7F; }
+inline h2_t H2(size_t hash) { return hash >> (sizeof(size_t) * 8 - 7); }
 
 // When there is an insertion with no reserved growth, we rehash with
 // probability `min(1, RehashProbabilityConstant() / capacity())`. Using a
@@ -571,11 +567,9 @@
   // references. We rehash on the first insertion after reserved_growth_ reaches
   // 0 after a call to reserve. We also do a rehash with low probability
   // whenever reserved_growth_ is zero.
-  bool should_rehash_for_bug_detection_on_insert(PerTableSeed seed,
-                                                 size_t capacity) const;
+  bool should_rehash_for_bug_detection_on_insert(size_t capacity) const;
   // Similar to above, except that we don't depend on reserved_growth_.
-  bool should_rehash_for_bug_detection_on_move(PerTableSeed seed,
-                                               size_t capacity) const;
+  bool should_rehash_for_bug_detection_on_move(size_t capacity) const;
   void maybe_increment_generation_on_insert() {
     if (reserved_growth_ == kReservedGrowthJustRanOut) reserved_growth_ = 0;
 
@@ -628,12 +622,8 @@
   CommonFieldsGenerationInfoDisabled& operator=(
       CommonFieldsGenerationInfoDisabled&&) = default;
 
-  bool should_rehash_for_bug_detection_on_insert(PerTableSeed, size_t) const {
-    return false;
-  }
-  bool should_rehash_for_bug_detection_on_move(PerTableSeed, size_t) const {
-    return false;
-  }
+  bool should_rehash_for_bug_detection_on_insert(size_t) const { return false; }
+  bool should_rehash_for_bug_detection_on_move(size_t) const { return false; }
   void maybe_increment_generation_on_insert() {}
   void increment_generation() {}
   void reset_reserved_growth(size_t, size_t) {}
@@ -781,6 +771,9 @@
 // A valid capacity is a non-zero integer `2^m - 1`.
 constexpr bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; }
 
+// Whether a table is small enough that we don't need to hash any keys.
+constexpr bool IsSmallCapacity(size_t capacity) { return capacity <= 1; }
+
 // Returns the number of "cloned control bytes".
 //
 // This is the number of control bytes that are present both at the beginning
@@ -790,7 +783,7 @@
 
 // Returns the number of control bytes including cloned.
 constexpr size_t NumControlBytes(size_t capacity) {
-  return capacity + 1 + NumClonedBytes();
+  return IsSmallCapacity(capacity) ? 0 : capacity + 1 + NumClonedBytes();
 }
 
 // Computes the offset from the start of the backing allocation of control.
@@ -808,6 +801,9 @@
 // Helper class for computing offsets and allocation size of hash set fields.
 class RawHashSetLayout {
  public:
+  // TODO(b/413062340): maybe don't allocate growth info for capacity 1 tables.
+  // Doing so may require additional branches/complexity so it might not be
+  // worth it.
   explicit RawHashSetLayout(size_t capacity, size_t slot_size,
                             size_t slot_align, bool has_infoz)
       : control_offset_(ControlOffset(has_infoz)),
@@ -846,50 +842,30 @@
 
 struct HashtableFreeFunctionsAccess;
 
-// Suppress erroneous uninitialized memory errors on GCC. For example, GCC
-// thinks that the call to slot_array() in find_or_prepare_insert() is reading
-// uninitialized memory, but slot_array is only called there when the table is
-// non-empty and this memory is initialized when the table is non-empty.
-#if !defined(__clang__) && defined(__GNUC__)
-#define ABSL_SWISSTABLE_IGNORE_UNINITIALIZED(x)                    \
-  _Pragma("GCC diagnostic push")                                   \
-      _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")  \
-          _Pragma("GCC diagnostic ignored \"-Wuninitialized\"") x; \
-  _Pragma("GCC diagnostic pop")
-#define ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(x) \
-  ABSL_SWISSTABLE_IGNORE_UNINITIALIZED(return x)
-#else
-#define ABSL_SWISSTABLE_IGNORE_UNINITIALIZED(x) x
-#define ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(x) return x
-#endif
-
 // This allows us to work around an uninitialized memory warning when
 // constructing begin() iterators in empty hashtables.
+template <typename T>
 union MaybeInitializedPtr {
-  void* get() const { ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(p); }
-  void set(void* ptr) { p = ptr; }
+  T* get() const { ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(p); }
+  void set(T* ptr) { p = ptr; }
 
-  void* p;
+  T* p;
 };
 
 struct HeapPtrs {
-  explicit HeapPtrs(uninitialized_tag_t) {}
-  explicit HeapPtrs(ctrl_t* c) : control(c) {}
-
   // The control bytes (and, also, a pointer near to the base of the backing
   // array).
   //
-  // This contains `capacity + 1 + NumClonedBytes()` entries, even
-  // when the table is empty (hence EmptyGroup).
+  // This contains `capacity + 1 + NumClonedBytes()` entries.
   //
   // Note that growth_info is stored immediately before this pointer.
-  // May be uninitialized for SOO tables.
-  ctrl_t* control;
+  // May be uninitialized for small tables.
+  MaybeInitializedPtr<ctrl_t> control;
 
   // The beginning of the slots, located at `SlotOffset()` bytes after
   // `control`. May be uninitialized for empty tables.
   // Note: we can't use `slots` because Qt defines "slots" as a macro.
-  MaybeInitializedPtr slot_array;
+  MaybeInitializedPtr<void> slot_array;
 };
 
 // Returns the maximum size of the SOO slot.
@@ -898,19 +874,16 @@
 // Manages the backing array pointers or the SOO slot. When raw_hash_set::is_soo
 // is true, the SOO slot is stored in `soo_data`. Otherwise, we use `heap`.
 union HeapOrSoo {
-  explicit HeapOrSoo(uninitialized_tag_t) : heap(uninitialized_tag_t{}) {}
-  explicit HeapOrSoo(ctrl_t* c) : heap(c) {}
-
-  ctrl_t*& control() {
+  MaybeInitializedPtr<ctrl_t>& control() {
     ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(heap.control);
   }
-  ctrl_t* control() const {
+  MaybeInitializedPtr<ctrl_t> control() const {
     ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(heap.control);
   }
-  MaybeInitializedPtr& slot_array() {
+  MaybeInitializedPtr<void>& slot_array() {
     ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(heap.slot_array);
   }
-  MaybeInitializedPtr slot_array() const {
+  MaybeInitializedPtr<void> slot_array() const {
     ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(heap.slot_array);
   }
   void* get_soo_data() {
@@ -939,20 +912,13 @@
 class CommonFields : public CommonFieldsGenerationInfo {
  public:
   explicit CommonFields(soo_tag_t)
-      : capacity_(SooCapacity()),
-        size_(no_seed_empty_tag_t{}),
-        heap_or_soo_(uninitialized_tag_t{}) {}
+      : capacity_(SooCapacity()), size_(no_seed_empty_tag_t{}) {}
   explicit CommonFields(full_soo_tag_t)
-      : capacity_(SooCapacity()),
-        size_(full_soo_tag_t{}),
-        heap_or_soo_(uninitialized_tag_t{}) {}
+      : capacity_(SooCapacity()), size_(full_soo_tag_t{}) {}
   explicit CommonFields(non_soo_tag_t)
-      : capacity_(0),
-        size_(no_seed_empty_tag_t{}),
-        heap_or_soo_(EmptyGroup()) {}
+      : capacity_(0), size_(no_seed_empty_tag_t{}) {}
   // For use in swapping.
-  explicit CommonFields(uninitialized_tag_t)
-      : size_(uninitialized_tag_t{}), heap_or_soo_(uninitialized_tag_t{}) {}
+  explicit CommonFields(uninitialized_tag_t) : size_(uninitialized_tag_t{}) {}
 
   // Not copyable
   CommonFields(const CommonFields&) = delete;
@@ -979,31 +945,25 @@
   const void* soo_data() const { return heap_or_soo_.get_soo_data(); }
   void* soo_data() { return heap_or_soo_.get_soo_data(); }
 
-  ctrl_t* control() const { return heap_or_soo_.control(); }
+  ctrl_t* control() const {
+    ABSL_SWISSTABLE_ASSERT(capacity() > 0);
+    // Assume that the control bytes don't alias `this`.
+    ctrl_t* ctrl = heap_or_soo_.control().get();
+    [[maybe_unused]] size_t num_control_bytes = NumControlBytes(capacity());
+    ABSL_ASSUME(reinterpret_cast<uintptr_t>(ctrl + num_control_bytes) <=
+                    reinterpret_cast<uintptr_t>(this) ||
+                reinterpret_cast<uintptr_t>(this + 1) <=
+                    reinterpret_cast<uintptr_t>(ctrl));
+    ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(ctrl);
+  }
 
-  // When we set the control bytes, we also often want to generate a new seed.
-  // So we bundle these two operations together to make sure we don't forget to
-  // generate a new seed.
-  // The table will be invalidated if
-  // `kGenerateSeed && !empty() && !is_single_group(capacity())` because H1 is
-  // being changed. In such cases, we will need to rehash the table.
-  template <bool kGenerateSeed>
-  void set_control(ctrl_t* c) {
-    heap_or_soo_.control() = c;
-    if constexpr (kGenerateSeed) {
-      generate_new_seed();
-    }
-  }
-  void* backing_array_start() const {
-    // growth_info (and maybe infoz) is stored before control bytes.
-    ABSL_SWISSTABLE_ASSERT(
-        reinterpret_cast<uintptr_t>(control()) % alignof(size_t) == 0);
-    return control() - ControlOffset(has_infoz());
-  }
+  void set_control(ctrl_t* c) { heap_or_soo_.control().set(c); }
 
   // Note: we can't use slots() because Qt defines "slots" as a macro.
   void* slot_array() const { return heap_or_soo_.slot_array().get(); }
-  MaybeInitializedPtr slots_union() const { return heap_or_soo_.slot_array(); }
+  MaybeInitializedPtr<void> slots_union() const {
+    return heap_or_soo_.slot_array();
+  }
   void set_slots(void* s) { heap_or_soo_.slot_array().set(s); }
 
   // The number of filled slots.
@@ -1032,13 +992,20 @@
   }
   bool empty() const { return size_.empty(); }
 
-  // The seed used for the H1 part of the hash function.
+  // The seed used for the hash function.
   PerTableSeed seed() const { return size_.seed(); }
-  // Generates a new seed for the H1 part of the hash function.
-  // The table will be invalidated if
-  // `kGenerateSeed && !empty() && !is_single_group(capacity())` because H1 is
-  // being changed. In such cases, we will need to rehash the table.
-  void generate_new_seed() { size_.generate_new_seed(); }
+  // Generates a new seed the hash function.
+  // The table will be invalidated if `!empty()` because hash is being changed.
+  // In such cases, we will need to rehash the table.
+  void generate_new_seed(bool has_infoz) {
+    // Note: we can't use has_infoz() here because we set has_infoz later than
+    // we generate the seed.
+    if (ABSL_PREDICT_FALSE(has_infoz)) {
+      size_.set_sampled_seed();
+      return;
+    }
+    size_.generate_new_seed();
+  }
   void set_no_seed_for_testing() { size_.set_no_seed_for_testing(); }
 
   // The total number of available slots.
@@ -1049,6 +1016,7 @@
                            c > kAboveMaxValidCapacity);
     capacity_ = c;
   }
+  bool is_small() const { return IsSmallCapacity(capacity_); }
 
   // The number of slots we can still fill without needing to rehash.
   // This is stored in the heap allocation before the control bytes.
@@ -1057,6 +1025,7 @@
   size_t growth_left() const { return growth_info().GetGrowthLeft(); }
 
   GrowthInfo& growth_info() {
+    ABSL_SWISSTABLE_ASSERT(!is_small());
     return GetGrowthInfoFromControl(control());
   }
   GrowthInfo growth_info() const {
@@ -1064,16 +1033,26 @@
   }
 
   bool has_infoz() const { return size_.has_infoz(); }
-  void set_has_infoz() { size_.set_has_infoz(); }
+  void set_has_infoz() {
+    ABSL_SWISSTABLE_ASSERT(size_.is_sampled_seed());
+    size_.set_has_infoz();
+  }
+
+  HashtablezInfoHandle* infoz_ptr() const {
+    // growth_info is stored before control bytes.
+    ABSL_SWISSTABLE_ASSERT(
+        reinterpret_cast<uintptr_t>(control()) % alignof(size_t) == 0);
+    ABSL_SWISSTABLE_ASSERT(has_infoz());
+    return reinterpret_cast<HashtablezInfoHandle*>(
+        control() - ControlOffset(/*has_infoz=*/true));
+  }
 
   HashtablezInfoHandle infoz() {
-    return has_infoz()
-               ? *reinterpret_cast<HashtablezInfoHandle*>(backing_array_start())
-               : HashtablezInfoHandle();
+    return has_infoz() ? *infoz_ptr() : HashtablezInfoHandle();
   }
   void set_infoz(HashtablezInfoHandle infoz) {
     ABSL_SWISSTABLE_ASSERT(has_infoz());
-    *reinterpret_cast<HashtablezInfoHandle*>(backing_array_start()) = infoz;
+    *infoz_ptr() = infoz;
   }
 
   bool should_rehash_for_bug_detection_on_insert() const {
@@ -1084,11 +1063,11 @@
     // will end up rehashing anyways.
     if (growth_left() == 0) return false;
     return CommonFieldsGenerationInfo::
-        should_rehash_for_bug_detection_on_insert(seed(), capacity());
+        should_rehash_for_bug_detection_on_insert(capacity());
   }
   bool should_rehash_for_bug_detection_on_move() const {
     return CommonFieldsGenerationInfo::should_rehash_for_bug_detection_on_move(
-        seed(), capacity());
+        capacity());
   }
   void reset_reserved_growth(size_t reservation) {
     CommonFieldsGenerationInfo::reset_reserved_growth(reservation, size());
@@ -1159,7 +1138,7 @@
   HeapOrSoo heap_or_soo_;
 };
 
-template <class Policy, class Hash, class Eq, class Alloc>
+template <class Policy, class... Params>
 class raw_hash_set;
 
 // Returns the next valid capacity after `n`.
@@ -1223,6 +1202,10 @@
   // NormalizeCapacity(size).
   int leading_zeros = absl::countl_zero(size);
   constexpr size_t kLast3Bits = size_t{7} << (sizeof(size_t) * 8 - 3);
+  // max_size_for_next_capacity = max_load_factor * next_capacity
+  //                            = (7/8) * (~size_t{} >> leading_zeros)
+  //                            = (7/8*~size_t{}) >> leading_zeros
+  //                            = kLast3Bits >> leading_zeros
   size_t max_size_for_next_capacity = kLast3Bits >> leading_zeros;
   // Decrease shift if size is too big for the minimum capacity.
   leading_zeros -= static_cast<int>(size > max_size_for_next_capacity);
@@ -1267,7 +1250,7 @@
   if (ABSL_PREDICT_FALSE(ctrl == nullptr)) {
     ABSL_RAW_LOG(FATAL, "%s called on end() iterator.", operation);
   }
-  if (ABSL_PREDICT_FALSE(ctrl == EmptyGroup())) {
+  if (ABSL_PREDICT_FALSE(ctrl == DefaultIterControl())) {
     ABSL_RAW_LOG(FATAL, "%s called on default-constructed iterator.",
                  operation);
   }
@@ -1302,7 +1285,7 @@
                                        const GenerationType* generation_ptr) {
   if (!SwisstableDebugEnabled()) return;
   const bool ctrl_is_valid_for_comparison =
-      ctrl == nullptr || ctrl == EmptyGroup() || IsFull(*ctrl);
+      ctrl == nullptr || ctrl == DefaultIterControl() || IsFull(*ctrl);
   if (SwisstableGenerationsEnabled()) {
     if (ABSL_PREDICT_FALSE(generation != *generation_ptr)) {
       ABSL_RAW_LOG(FATAL,
@@ -1368,8 +1351,8 @@
     }
   };
 
-  const bool a_is_default = ctrl_a == EmptyGroup();
-  const bool b_is_default = ctrl_b == EmptyGroup();
+  const bool a_is_default = ctrl_a == DefaultIterControl();
+  const bool b_is_default = ctrl_b == DefaultIterControl();
   if (a_is_default && b_is_default) return;
   fail_if(a_is_default != b_is_default,
           "Comparing default-constructed hashtable iterator with a "
@@ -1377,13 +1360,6 @@
 
   if (SwisstableGenerationsEnabled()) {
     if (ABSL_PREDICT_TRUE(generation_ptr_a == generation_ptr_b)) return;
-    // Users don't need to know whether the tables are SOO so don't mention SOO
-    // in the debug message.
-    const bool a_is_soo = IsSooControl(ctrl_a);
-    const bool b_is_soo = IsSooControl(ctrl_b);
-    fail_if(a_is_soo != b_is_soo || (a_is_soo && b_is_soo),
-            "Comparing iterators from different hashtables.");
-
     const bool a_is_empty = IsEmptyGeneration(generation_ptr_a);
     const bool b_is_empty = IsEmptyGeneration(generation_ptr_b);
     fail_if(a_is_empty != b_is_empty,
@@ -1419,26 +1395,16 @@
 }
 
 // Begins a probing operation on `common.control`, using `hash`.
-inline probe_seq<Group::kWidth> probe(size_t h1, size_t capacity) {
+inline probe_seq<Group::kWidth> probe_h1(size_t capacity, size_t h1) {
   return probe_seq<Group::kWidth>(h1, capacity);
 }
-inline probe_seq<Group::kWidth> probe(PerTableSeed seed, size_t capacity,
-                                      size_t hash) {
-  return probe(H1(hash, seed), capacity);
+inline probe_seq<Group::kWidth> probe(size_t capacity, size_t hash) {
+  return probe_h1(capacity, H1(hash));
 }
 inline probe_seq<Group::kWidth> probe(const CommonFields& common, size_t hash) {
-  return probe(common.seed(), common.capacity(), hash);
+  return probe(common.capacity(), hash);
 }
 
-// Probes an array of control bits using a probe sequence derived from `hash`,
-// and returns the offset corresponding to the first deleted or empty slot.
-//
-// Behavior when the entire table is full is undefined.
-//
-// NOTE: this function must work with tables having both empty and deleted
-// slots in the same group. Such tables appear during `erase()`.
-FindInfo find_first_non_full(const CommonFields& common, size_t hash);
-
 constexpr size_t kProbedElementIndexSentinel = ~size_t{};
 
 // Implementation detail of transfer_unprobed_elements_to_next_capacity_fn.
@@ -1502,79 +1468,11 @@
                                                      ctrl_t* new_ctrl,
                                                      size_t new_capacity);
 
-// Sets sanitizer poisoning for slot corresponding to control byte being set.
-inline void DoSanitizeOnSetCtrl(const CommonFields& c, size_t i, ctrl_t h,
-                                size_t slot_size) {
-  ABSL_SWISSTABLE_ASSERT(i < c.capacity());
-  auto* slot_i = static_cast<const char*>(c.slot_array()) + i * slot_size;
-  if (IsFull(h)) {
-    SanitizerUnpoisonMemoryRegion(slot_i, slot_size);
-  } else {
-    SanitizerPoisonMemoryRegion(slot_i, slot_size);
-  }
-}
-
-// Sets `ctrl[i]` to `h`.
-//
-// Unlike setting it directly, this function will perform bounds checks and
-// mirror the value to the cloned tail if necessary.
-inline void SetCtrl(const CommonFields& c, size_t i, ctrl_t h,
-                    size_t slot_size) {
-  DoSanitizeOnSetCtrl(c, i, h, slot_size);
-  ctrl_t* ctrl = c.control();
-  ctrl[i] = h;
-  ctrl[((i - NumClonedBytes()) & c.capacity()) +
-       (NumClonedBytes() & c.capacity())] = h;
-}
-// Overload for setting to an occupied `h2_t` rather than a special `ctrl_t`.
-inline void SetCtrl(const CommonFields& c, size_t i, h2_t h, size_t slot_size) {
-  SetCtrl(c, i, static_cast<ctrl_t>(h), slot_size);
-}
-
-// Like SetCtrl, but in a single group table, we can save some operations when
-// setting the cloned control byte.
-inline void SetCtrlInSingleGroupTable(const CommonFields& c, size_t i, ctrl_t h,
-                                      size_t slot_size) {
-  ABSL_SWISSTABLE_ASSERT(is_single_group(c.capacity()));
-  DoSanitizeOnSetCtrl(c, i, h, slot_size);
-  ctrl_t* ctrl = c.control();
-  ctrl[i] = h;
-  ctrl[i + c.capacity() + 1] = h;
-}
-// Overload for setting to an occupied `h2_t` rather than a special `ctrl_t`.
-inline void SetCtrlInSingleGroupTable(const CommonFields& c, size_t i, h2_t h,
-                                      size_t slot_size) {
-  SetCtrlInSingleGroupTable(c, i, static_cast<ctrl_t>(h), slot_size);
-}
-
-// Like SetCtrl, but in a table with capacity >= Group::kWidth - 1,
-// we can save some operations when setting the cloned control byte.
-inline void SetCtrlInLargeTable(const CommonFields& c, size_t i, ctrl_t h,
-                                size_t slot_size) {
-  ABSL_SWISSTABLE_ASSERT(c.capacity() >= Group::kWidth - 1);
-  DoSanitizeOnSetCtrl(c, i, h, slot_size);
-  ctrl_t* ctrl = c.control();
-  ctrl[i] = h;
-  ctrl[((i - NumClonedBytes()) & c.capacity()) + NumClonedBytes()] = h;
-}
-// Overload for setting to an occupied `h2_t` rather than a special `ctrl_t`.
-inline void SetCtrlInLargeTable(const CommonFields& c, size_t i, h2_t h,
-                                size_t slot_size) {
-  SetCtrlInLargeTable(c, i, static_cast<ctrl_t>(h), slot_size);
-}
-
 // growth_info (which is a size_t) is stored with the backing array.
 constexpr size_t BackingArrayAlignment(size_t align_of_slot) {
   return (std::max)(align_of_slot, alignof(GrowthInfo));
 }
 
-// Returns the address of the ith slot in slots where each slot occupies
-// slot_size.
-inline void* SlotAddress(void* slot_array, size_t slot, size_t slot_size) {
-  return static_cast<void*>(static_cast<char*>(slot_array) +
-                            (slot * slot_size));
-}
-
 // Iterates over all full slots and calls `cb(const ctrl_t*, void*)`.
 // No insertion to the table is allowed during `cb` call.
 // Erasure is allowed only for the element passed to the callback.
@@ -1592,33 +1490,14 @@
   return std::is_same_v<CharAlloc, std::allocator<char>>;
 }
 
-template <bool kSooEnabled>
-bool ShouldSampleHashtablezInfoOnResize(bool force_sampling,
-                                        bool is_hashtablez_eligible,
-                                        size_t old_capacity, CommonFields& c) {
-  if (!is_hashtablez_eligible) return false;
-  // Force sampling is only allowed for SOO tables.
-  ABSL_SWISSTABLE_ASSERT(kSooEnabled || !force_sampling);
-  if (kSooEnabled && force_sampling) {
-    return true;
-  }
-  // In SOO, we sample on the first insertion so if this is an empty SOO case
-  // (e.g. when reserve is called), then we still need to sample.
-  if (kSooEnabled && old_capacity == SooCapacity() && c.empty()) {
-    return ShouldSampleNextTable();
-  }
-  if (!kSooEnabled && old_capacity == 0) {
-    return ShouldSampleNextTable();
-  }
-  return false;
-}
-
 // Allocates `n` bytes for a backing array.
 template <size_t AlignOfBackingArray, typename Alloc>
-ABSL_ATTRIBUTE_NOINLINE void* AllocateBackingArray(void* alloc, size_t n) {
+void* AllocateBackingArray(void* alloc, size_t n) {
   return Allocate<AlignOfBackingArray>(static_cast<Alloc*>(alloc), n);
 }
 
+// Note: we mark this function as ABSL_ATTRIBUTE_NOINLINE because we don't want
+// it to be inlined into e.g. the destructor to save code size.
 template <size_t AlignOfBackingArray, typename Alloc>
 ABSL_ATTRIBUTE_NOINLINE void DeallocateBackingArray(
     void* alloc, size_t capacity, ctrl_t* ctrl, size_t slot_size,
@@ -1647,7 +1526,7 @@
   void* (*hash_fn)(CommonFields& common);
 
   // Returns the hash of the pointed-to slot.
-  size_t (*hash_slot)(const void* hash_fn, void* slot);
+  HashSlotFn hash_slot;
 
   // Transfers the contents of `count` slots from src_slot to dst_slot.
   // We use ability to transfer several slots in single group table growth.
@@ -1802,23 +1681,20 @@
 
 // Resizes SOO table to the NextCapacity(SooCapacity()) and prepares insert for
 // the given new_hash. Returns the offset of the new element.
-// `soo_slot_ctrl` is the control byte of the SOO slot.
-// If soo_slot_ctrl is kEmpty
-//   1. The table must be empty.
-//   2. Table will be forced to be sampled.
 // All possible template combinations are defined in cc file to improve
 // compilation time.
 template <size_t SooSlotMemcpySize, bool TransferUsesMemcpy>
-size_t GrowSooTableToNextCapacityAndPrepareInsert(CommonFields& common,
-                                                  const PolicyFunctions& policy,
-                                                  size_t new_hash,
-                                                  ctrl_t soo_slot_ctrl);
+size_t GrowSooTableToNextCapacityAndPrepareInsert(
+    CommonFields& common, const PolicyFunctions& policy,
+    absl::FunctionRef<size_t(size_t)> get_hash, bool force_sampling);
 
-// As `ResizeFullSooTableToNextCapacity`, except that we also force the SOO
-// table to be sampled. SOO tables need to switch from SOO to heap in order to
-// store the infoz. No-op if sampling is disabled or not possible.
-void GrowFullSooTableToNextCapacityForceSampling(CommonFields& common,
-                                                 const PolicyFunctions& policy);
+// PrepareInsert for small tables (is_small()==true).
+// Returns the new control and the new slot.
+// Hash is only computed if the table is sampled or grew to large size
+// (is_small()==false).
+std::pair<ctrl_t*, void*> PrepareInsertSmallNonSoo(
+    CommonFields& common, const PolicyFunctions& policy,
+    absl::FunctionRef<size_t(size_t)> get_hash);
 
 // Resizes table with allocated slots and change the table seed.
 // Tables with SOO enabled must have capacity > policy.soo_capacity.
@@ -1833,8 +1709,9 @@
 void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy,
                        void* alloc, bool reuse, bool soo_enabled);
 
-// Type-erased version of raw_hash_set::erase_meta_only.
-void EraseMetaOnly(CommonFields& c, size_t index, size_t slot_size);
+// Type-erased versions of raw_hash_set::erase_meta_only_{small,large}.
+void EraseMetaOnlySmall(CommonFields& c, bool soo_enabled, size_t slot_size);
+void EraseMetaOnlyLarge(CommonFields& c, const ctrl_t* ctrl, size_t slot_size);
 
 // For trivially relocatable types we use memcpy directly. This allows us to
 // share the same function body for raw_hash_set instantiations that have the
@@ -1853,23 +1730,44 @@
 // empty class cases.
 void* GetRefForEmptyClass(CommonFields& common);
 
-// Given the hash of a value not currently in the table and the first empty
-// slot in the probe sequence, finds a viable slot index to insert it at.
+// Given the hash of a value not currently in the table and the first group with
+// an empty slot in the probe sequence, finds a viable slot index to insert it
+// at.
 //
 // In case there's no space left, the table can be resized or rehashed
 // (for tables with deleted slots, see FindInsertPositionWithGrowthOrRehash).
 //
 // In the case of absence of deleted slots and positive growth_left, the element
-// can be inserted in the provided `target` position.
+// can be inserted in one of the empty slots in the provided `target_group`.
 //
 // When the table has deleted slots (according to GrowthInfo), the target
 // position will be searched one more time using `find_first_non_full`.
 //
-// REQUIRES: Table is not SOO.
+// REQUIRES: `!common.is_small()`.
 // REQUIRES: At least one non-full slot available.
-// REQUIRES: `target` is a valid empty position to insert.
-size_t PrepareInsertNonSoo(CommonFields& common, const PolicyFunctions& policy,
-                           size_t hash, FindInfo target);
+// REQUIRES: `mask_empty` is a mask containing empty slots for the
+//           `target_group`.
+// REQUIRES: `target_group` is a starting position for the group that has
+//            at least one empty slot.
+size_t PrepareInsertLarge(CommonFields& common, const PolicyFunctions& policy,
+                          size_t hash, Group::NonIterableBitMaskType mask_empty,
+                          FindInfo target_group);
+
+// Same as above, but with generations enabled, we may end up changing the seed,
+// which means we need to be able to recompute the hash.
+size_t PrepareInsertLargeGenerationsEnabled(
+    CommonFields& common, const PolicyFunctions& policy, size_t hash,
+    Group::NonIterableBitMaskType mask_empty, FindInfo target_group,
+    absl::FunctionRef<size_t(size_t)> recompute_hash);
+
+template <typename Policy, typename Hash, typename Eq, typename Alloc>
+struct InstantiateRawHashSet {
+  using type = typename ApplyWithoutDefaultSuffix<
+      raw_hash_set,
+      TypeList<void, typename Policy::DefaultHash, typename Policy::DefaultEq,
+               typename Policy::DefaultAlloc>,
+      TypeList<Policy, Hash, Eq, Alloc>>::type;
+};
 
 // A SwissTable.
 //
@@ -1877,26 +1775,47 @@
 // the slots of the hashtable (see hash_policy_traits.h for the full interface
 // of policy).
 //
+// Params...: a variadic list of parameters that allows us to omit default
+//            types. This reduces the mangled name of the class and the size of
+//            debug strings like __PRETTY_FUNCTION__. Default types do not give
+//            any new information.
+//
 // Hash: a (possibly polymorphic) functor that hashes keys of the hashtable. The
 // functor should accept a key and return size_t as hash. For best performance
 // it is important that the hash function provides high entropy across all bits
 // of the hash.
+// This is the first element in `Params...` if it exists, or Policy::DefaultHash
+// otherwise.
 //
 // Eq: a (possibly polymorphic) functor that compares two keys for equality. It
 // should accept two (of possibly different type) keys and return a bool: true
 // if they are equal, false if they are not. If two keys compare equal, then
 // their hash values as defined by Hash MUST be equal.
+// This is the second element in `Params...` if it exists, or Policy::DefaultEq
+// otherwise.
 //
 // Allocator: an Allocator
 // [https://en.cppreference.com/w/cpp/named_req/Allocator] with which
 // the storage of the hashtable will be allocated and the elements will be
 // constructed and destroyed.
-template <class Policy, class Hash, class Eq, class Alloc>
+// This is the third element in `Params...` if it exists, or
+// Policy::DefaultAlloc otherwise.
+template <class Policy, class... Params>
 class raw_hash_set {
   using PolicyTraits = hash_policy_traits<Policy>;
+  using Hash = GetFromListOr<typename Policy::DefaultHash, 0, Params...>;
+  using Eq = GetFromListOr<typename Policy::DefaultEq, 1, Params...>;
+  using Alloc = GetFromListOr<typename Policy::DefaultAlloc, 2, Params...>;
   using KeyArgImpl =
       KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>;
 
+  static_assert(
+      std::is_same_v<
+          typename InstantiateRawHashSet<Policy, Hash, Eq, Alloc>::type,
+          raw_hash_set>,
+      "Redundant template parameters were passed. Use InstantiateRawHashSet<> "
+      "instead");
+
  public:
   using init_type = typename PolicyTraits::init_type;
   using key_type = typename PolicyTraits::key_type;
@@ -1924,6 +1843,10 @@
 
   using slot_type = typename PolicyTraits::slot_type;
 
+  constexpr static bool kIsDefaultHash =
+      std::is_same_v<hasher, absl::Hash<key_type>> ||
+      std::is_same_v<hasher, absl::container_internal::StringHash>;
+
   // TODO(b/289225379): we could add extra SOO space inside raw_hash_set
   // after CommonFields to allow inlining larger slot_types (e.g. std::string),
   // but it's a bit complicated if we want to support incomplete mapped_type in
@@ -1948,10 +1871,19 @@
   bool is_soo() const { return fits_in_soo(capacity()); }
   bool is_full_soo() const { return is_soo() && !empty(); }
 
+  bool is_small() const { return common().is_small(); }
+
   // Give an early error when key_type is not hashable/eq.
   auto KeyTypeCanBeHashed(const Hash& h, const key_type& k) -> decltype(h(k));
   auto KeyTypeCanBeEq(const Eq& eq, const key_type& k) -> decltype(eq(k, k));
 
+  // Try to be helpful when the hasher returns an unreasonable type.
+  using key_hash_result =
+      absl::remove_cvref_t<decltype(std::declval<const Hash&>()(
+          std::declval<const key_type&>()))>;
+  static_assert(sizeof(key_hash_result) >= sizeof(size_t),
+                "`Hash::operator()` should return a `size_t`");
+
   using AllocTraits = absl::allocator_traits<allocator_type>;
   using SlotAlloc = typename absl::allocator_traits<
       allocator_type>::template rebind_alloc<slot_type>;
@@ -2018,19 +1950,19 @@
 
     // PRECONDITION: not an end() iterator.
     reference operator*() const {
-      AssertIsFull(ctrl_, generation(), generation_ptr(), "operator*()");
+      assert_is_full("operator*()");
       return unchecked_deref();
     }
 
     // PRECONDITION: not an end() iterator.
     pointer operator->() const {
-      AssertIsFull(ctrl_, generation(), generation_ptr(), "operator->");
+      assert_is_full("operator->");
       return &operator*();
     }
 
     // PRECONDITION: not an end() iterator.
     iterator& operator++() {
-      AssertIsFull(ctrl_, generation(), generation_ptr(), "operator++");
+      assert_is_full("operator++");
       ++ctrl_;
       ++slot_;
       skip_empty_or_deleted();
@@ -2068,7 +2000,7 @@
     // This constructor is used in begin() to avoid an MSan
     // use-of-uninitialized-value error. Delegating from this constructor to
     // the previous one doesn't avoid the error.
-    iterator(ctrl_t* ctrl, MaybeInitializedPtr slot,
+    iterator(ctrl_t* ctrl, MaybeInitializedPtr<void> slot,
              const GenerationType* generation_ptr)
         : HashSetIteratorGenerationInfo(generation_ptr),
           ctrl_(ctrl),
@@ -2081,38 +2013,42 @@
     explicit iterator(const GenerationType* generation_ptr)
         : HashSetIteratorGenerationInfo(generation_ptr), ctrl_(nullptr) {}
 
+    void assert_is_full(const char* operation) const {
+      AssertIsFull(ctrl_, generation(), generation_ptr(), operation);
+    }
+
     // Fixes up `ctrl_` to point to a full or sentinel by advancing `ctrl_` and
     // `slot_` until they reach one.
     void skip_empty_or_deleted() {
       while (IsEmptyOrDeleted(*ctrl_)) {
-        uint32_t shift =
-            GroupFullEmptyOrDeleted{ctrl_}.CountLeadingEmptyOrDeleted();
-        ctrl_ += shift;
-        slot_ += shift;
+        ++ctrl_;
+        ++slot_;
       }
     }
 
-    ctrl_t* control() const { return ctrl_; }
-    slot_type* slot() const { return slot_; }
-
-    // We use EmptyGroup() for default-constructed iterators so that they can
-    // be distinguished from end iterators, which have nullptr ctrl_.
-    ctrl_t* ctrl_ = EmptyGroup();
-    // To avoid uninitialized member warnings, put slot_ in an anonymous union.
-    // The member is not initialized on singleton and end iterators.
-    union {
-      slot_type* slot_;
-    };
-
     // An equality check which skips ABSL Hardening iterator invalidation
     // checks.
     // Should be used when the lifetimes of the iterators are well-enough
     // understood to prove that they cannot be invalid.
-    bool unchecked_equals(const iterator& b) { return ctrl_ == b.control(); }
+    bool unchecked_equals(const iterator& b) const {
+      return ctrl_ == b.control();
+    }
 
     // Dereferences the iterator without ABSL Hardening iterator invalidation
     // checks.
     reference unchecked_deref() const { return PolicyTraits::element(slot_); }
+
+    ctrl_t* control() const { return ctrl_; }
+    slot_type* slot() const { return slot_; }
+
+    // We use DefaultIterControl() for default-constructed iterators so that
+    // they can be distinguished from end iterators, which have nullptr ctrl_.
+    ctrl_t* ctrl_ = DefaultIterControl();
+    // To avoid uninitialized member warnings, put slot_ in an anonymous union.
+    // The member is not initialized on singleton and end iterators.
+    union {
+      slot_type* slot_;
+    };
   };
 
   class const_iterator {
@@ -2153,14 +2089,13 @@
                    const GenerationType* gen)
         : inner_(const_cast<ctrl_t*>(ctrl), const_cast<slot_type*>(slot), gen) {
     }
+    bool unchecked_equals(const const_iterator& b) const {
+      return inner_.unchecked_equals(b.inner_);
+    }
     ctrl_t* control() const { return inner_.control(); }
     slot_type* slot() const { return inner_.slot(); }
 
     iterator inner_;
-
-    bool unchecked_equals(const const_iterator& b) {
-      return inner_.unchecked_equals(b.inner_);
-    }
   };
 
   using node_type = node_handle<Policy, hash_policy_traits<Policy>, Alloc>;
@@ -2345,7 +2280,7 @@
   }
 
   raw_hash_set& operator=(raw_hash_set&& that) noexcept(
-      absl::allocator_traits<allocator_type>::is_always_equal::value &&
+      AllocTraits::is_always_equal::value &&
       std::is_nothrow_move_assignable<hasher>::value &&
       std::is_nothrow_move_assignable<key_equal>::value) {
     // TODO(sbenza): We should only use the operations from the noexcept clause
@@ -2365,7 +2300,7 @@
 
   iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND {
     if (ABSL_PREDICT_FALSE(empty())) return end();
-    if (capacity() == 1) return single_iterator();
+    if (is_small()) return single_iterator();
     iterator it = {control(), common().slots_union(),
                    common().generation_ptr()};
     it.skip_empty_or_deleted();
@@ -2419,9 +2354,11 @@
     const size_t cap = capacity();
     if (cap == 0) {
       // Already guaranteed to be empty; so nothing to do.
-    } else if (is_soo()) {
-      if (!empty()) destroy(soo_slot());
-      common().set_empty_soo();
+    } else if (is_small()) {
+      if (!empty()) {
+        destroy(single_slot());
+        decrement_small_size();
+      }
     } else {
       destroy_slots();
       clear_backing_array(/*reuse=*/cap < 128);
@@ -2491,13 +2428,13 @@
   //   s.insert({"abc", 42});
   std::pair<iterator, bool> insert(init_type&& value)
       ABSL_ATTRIBUTE_LIFETIME_BOUND
-#if __cplusplus >= 202002L
+#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
     requires(!IsLifetimeBoundAssignmentFrom<init_type>::value)
 #endif
   {
     return emplace(std::move(value));
   }
-#if __cplusplus >= 202002L
+#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
   std::pair<iterator, bool> insert(
       init_type&& value ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))
       ABSL_ATTRIBUTE_LIFETIME_BOUND
@@ -2540,17 +2477,17 @@
 
   template <class InputIt>
   void insert(InputIt first, InputIt last) {
-    for (; first != last; ++first) emplace(*first);
+    insert_range(first, last);
   }
 
   template <class T, RequiresNotInit<T> = 0,
             std::enable_if_t<Insertable<const T&>::value, int> = 0>
   void insert(std::initializer_list<T> ilist) {
-    insert(ilist.begin(), ilist.end());
+    insert_range(ilist.begin(), ilist.end());
   }
 
   void insert(std::initializer_list<init_type> ilist) {
-    insert(ilist.begin(), ilist.end());
+    insert_range(ilist.begin(), ilist.end());
   }
 
   insert_return_type insert(node_type&& node) ABSL_ATTRIBUTE_LIFETIME_BOUND {
@@ -2697,14 +2634,11 @@
   // This overload is necessary because otherwise erase<K>(const K&) would be
   // a better match if non-const iterator is passed as an argument.
   void erase(iterator it) {
+    ABSL_SWISSTABLE_ASSERT(capacity() > 0);
     AssertNotDebugCapacity();
-    AssertIsFull(it.control(), it.generation(), it.generation_ptr(), "erase()");
+    it.assert_is_full("erase()");
     destroy(it.slot());
-    if (is_soo()) {
-      common().set_empty_soo();
-    } else {
-      erase_meta_only(it);
-    }
+    erase_meta_only(it);
   }
 
   iterator erase(const_iterator first,
@@ -2714,9 +2648,9 @@
     // capacity() > 0 as a precondition.
     if (empty()) return end();
     if (first == last) return last.inner_;
-    if (is_soo()) {
-      destroy(soo_slot());
-      common().set_empty_soo();
+    if (is_small()) {
+      destroy(single_slot());
+      erase_meta_only_small();
       return end();
     }
     if (first == begin() && last == end()) {
@@ -2736,8 +2670,11 @@
 
   // Moves elements from `src` into `this`.
   // If the element already exists in `this`, it is left unmodified in `src`.
-  template <typename H, typename E>
-  void merge(raw_hash_set<Policy, H, E, Alloc>& src) {  // NOLINT
+  template <
+      typename... Params2,
+      typename = std::enable_if_t<std::is_same_v<
+          Alloc, typename raw_hash_set<Policy, Params2...>::allocator_type>>>
+  void merge(raw_hash_set<Policy, Params2...>& src) {  // NOLINT
     AssertNotDebugCapacity();
     src.AssertNotDebugCapacity();
     assert(this != &src);
@@ -2748,34 +2685,33 @@
           .second;
     };
 
-    if (src.is_soo()) {
+    if (src.is_small()) {
       if (src.empty()) return;
-      if (insert_slot(src.soo_slot())) src.common().set_empty_soo();
+      if (insert_slot(src.single_slot()))
+        src.erase_meta_only_small();
       return;
     }
     for (auto it = src.begin(), e = src.end(); it != e;) {
       auto next = std::next(it);
-      if (insert_slot(it.slot())) src.erase_meta_only(it);
+      if (insert_slot(it.slot())) src.erase_meta_only_large(it);
       it = next;
     }
   }
 
-  template <typename H, typename E>
-  void merge(raw_hash_set<Policy, H, E, Alloc>&& src) {
+  template <
+      typename... Params2,
+      typename = std::enable_if_t<std::is_same_v<
+          Alloc, typename raw_hash_set<Policy, Params2...>::allocator_type>>>
+  void merge(raw_hash_set<Policy, Params2...>&& src) {  // NOLINT
     merge(src);
   }
 
   node_type extract(const_iterator position) {
     AssertNotDebugCapacity();
-    AssertIsFull(position.control(), position.inner_.generation(),
-                 position.inner_.generation_ptr(), "extract()");
+    position.inner_.assert_is_full("extract()");
     allocator_type alloc(char_alloc_ref());
     auto node = CommonAccess::Transfer<node_type>(alloc, position.slot());
-    if (is_soo()) {
-      common().set_empty_soo();
-    } else {
-      erase_meta_only(position);
-    }
+    erase_meta_only(position);
     return node;
   }
 
@@ -2787,9 +2723,9 @@
   }
 
   void swap(raw_hash_set& that) noexcept(
-      IsNoThrowSwappable<hasher>() && IsNoThrowSwappable<key_equal>() &&
-      IsNoThrowSwappable<allocator_type>(
-          typename AllocTraits::propagate_on_container_swap{})) {
+      AllocTraits::is_always_equal::value &&
+      std::is_nothrow_swappable<hasher>::value &&
+      std::is_nothrow_swappable<key_equal>::value) {
     AssertNotDebugCapacity();
     that.AssertNotDebugCapacity();
     using std::swap;
@@ -2828,12 +2764,12 @@
   // NOTE: This is a very low level operation and should not be used without
   // specific benchmarks indicating its importance.
   template <class K = key_type>
-  void prefetch(const key_arg<K>& key) const {
+  void prefetch([[maybe_unused]] const key_arg<K>& key) const {
     if (capacity() == DefaultCapacity()) return;
-    (void)key;
     // Avoid probing if we won't be able to prefetch the addresses received.
 #ifdef ABSL_HAVE_PREFETCH
     prefetch_heap_block();
+    if (is_small()) return;
     auto seq = probe(common(), hash_of(key));
     PrefetchToLocalCache(control() + seq.offset());
     PrefetchToLocalCache(slot_array() + seq.offset());
@@ -2851,7 +2787,7 @@
   template <class K = key_type>
   iterator find(const key_arg<K>& key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     AssertOnFind(key);
-    if (capacity() <= 1) return find_small(key);
+    if (is_small()) return find_small(key);
     prefetch_heap_block();
     return find_large(key, hash_of(key));
   }
@@ -2960,24 +2896,6 @@
     const raw_hash_set& s;
   };
 
-  struct HashElement {
-    template <class K, class... Args>
-    size_t operator()(const K& key, Args&&...) const {
-      return h(key);
-    }
-    const hasher& h;
-  };
-
-  template <class K1>
-  struct EqualElement {
-    template <class K2, class... Args>
-    bool operator()(const K2& lhs, Args&&...) const {
-      ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(eq(lhs, rhs));
-    }
-    const K1& rhs;
-    const key_equal& eq;
-  };
-
   struct EmplaceDecomposable {
     template <class K, class... Args>
     std::pair<iterator, bool> operator()(const K& key, Args&&... args) const {
@@ -3031,18 +2949,13 @@
   // SOO functionality.
   template <class K = key_type>
   iterator find_small(const key_arg<K>& key) {
-    ABSL_SWISSTABLE_ASSERT(capacity() <= 1);
-    return empty() || !PolicyTraits::apply(
-                          EqualElement<K>{key, eq_ref()},
-                          PolicyTraits::element(single_slot()))
-               ? end()
-               : single_iterator();
+    ABSL_SWISSTABLE_ASSERT(is_small());
+    return empty() || !equal_to(key, single_slot()) ? end() : single_iterator();
   }
 
   template <class K = key_type>
   iterator find_large(const key_arg<K>& key, size_t hash) {
-    ABSL_SWISSTABLE_ASSERT(capacity() > 1);
-    ABSL_SWISSTABLE_ASSERT(!is_soo());
+    ABSL_SWISSTABLE_ASSERT(!is_small());
     auto seq = probe(common(), hash);
     const h2_t h2 = H2(hash);
     const ctrl_t* ctrl = control();
@@ -3052,9 +2965,7 @@
 #endif
       Group g{ctrl + seq.offset()};
       for (uint32_t i : g.Match(h2)) {
-        if (ABSL_PREDICT_TRUE(PolicyTraits::apply(
-                EqualElement<K>{key, eq_ref()},
-                PolicyTraits::element(slot_array() + seq.offset(i)))))
+        if (ABSL_PREDICT_TRUE(equal_to(key, slot_array() + seq.offset(i))))
           return iterator_at(seq.offset(i));
       }
       if (ABSL_PREDICT_TRUE(g.MaskEmpty())) return end();
@@ -3079,7 +2990,7 @@
   }
 
   void destroy_slots() {
-    ABSL_SWISSTABLE_ASSERT(!is_soo());
+    ABSL_SWISSTABLE_ASSERT(!is_small());
     if (PolicyTraits::template destroy_is_trivial<Alloc>()) return;
     auto destroy_slot = [&](const ctrl_t*, void* slot) {
       this->destroy(static_cast<slot_type*>(slot));
@@ -3111,13 +3022,14 @@
       return;
     }
     if (capacity() == 0) return;
-    if (is_soo()) {
+    if (is_small()) {
       if (!empty()) {
-        ABSL_SWISSTABLE_IGNORE_UNINITIALIZED(destroy(soo_slot()));
+        ABSL_SWISSTABLE_IGNORE_UNINITIALIZED(destroy(single_slot()));
       }
-      return;
+      if constexpr (SooEnabled()) return;
+    } else {
+      destroy_slots();
     }
-    destroy_slots();
     dealloc();
   }
 
@@ -3126,23 +3038,41 @@
   // This merely updates the pertinent control byte. This can be used in
   // conjunction with Policy::transfer to move the object to another place.
   void erase_meta_only(const_iterator it) {
-    ABSL_SWISSTABLE_ASSERT(!is_soo());
-    EraseMetaOnly(common(), static_cast<size_t>(it.control() - control()),
-                  sizeof(slot_type));
+    if (is_small()) {
+      erase_meta_only_small();
+      return;
+    }
+    erase_meta_only_large(it);
+  }
+  void erase_meta_only_small() {
+    EraseMetaOnlySmall(common(), SooEnabled(), sizeof(slot_type));
+  }
+  void erase_meta_only_large(const_iterator it) {
+    EraseMetaOnlyLarge(common(), it.control(), sizeof(slot_type));
   }
 
   template <class K>
-  size_t hash_of(const K& key) const {
-    return hash_ref()(key);
-  }
-  size_t hash_of(slot_type* slot) const {
-    return PolicyTraits::apply(HashElement{hash_ref()},
+  ABSL_ATTRIBUTE_ALWAYS_INLINE bool equal_to(const K& key,
+                                             slot_type* slot) const {
+    return PolicyTraits::apply(EqualElement<K, key_equal>{key, eq_ref()},
                                PolicyTraits::element(slot));
   }
+  template <class K>
+  ABSL_ATTRIBUTE_ALWAYS_INLINE size_t hash_of(const K& key) const {
+    return HashElement<hasher, kIsDefaultHash>{hash_ref(),
+                                               common().seed().seed()}(key);
+  }
+  ABSL_ATTRIBUTE_ALWAYS_INLINE size_t hash_of(slot_type* slot) const {
+    return PolicyTraits::apply(
+        HashElement<hasher, kIsDefaultHash>{hash_ref(), common().seed().seed()},
+        PolicyTraits::element(slot));
+  }
 
   // Casting directly from e.g. char* to slot_type* can cause compilation errors
   // on objective-C. This function converts to void* first, avoiding the issue.
-  static slot_type* to_slot(void* buf) { return static_cast<slot_type*>(buf); }
+  static ABSL_ATTRIBUTE_ALWAYS_INLINE slot_type* to_slot(void* buf) {
+    return static_cast<slot_type*>(buf);
+  }
 
   // Requires that lhs does not have a full SOO slot.
   static void move_common(bool rhs_is_full_soo, CharAlloc& rhs_alloc,
@@ -3178,8 +3108,7 @@
                 std::move(tmp));
   }
 
-  void annotate_for_bug_detection_on_move(
-      [[maybe_unused]] raw_hash_set& that) {
+  void annotate_for_bug_detection_on_move([[maybe_unused]] raw_hash_set& that) {
     // We only enable moved-from validation when generations are enabled (rather
     // than using NDEBUG) to avoid issues in which NDEBUG is enabled in some
     // translation units but not in others.
@@ -3250,58 +3179,98 @@
 
   template <class K>
   std::pair<iterator, bool> find_or_prepare_insert_soo(const K& key) {
-    ctrl_t soo_slot_ctrl;
+    ABSL_SWISSTABLE_ASSERT(is_soo());
+    bool force_sampling;
     if (empty()) {
       if (!should_sample_soo()) {
         common().set_full_soo();
-        return {soo_iterator(), true};
+        return {single_iterator(), true};
       }
-      soo_slot_ctrl = ctrl_t::kEmpty;
-    } else if (PolicyTraits::apply(EqualElement<K>{key, eq_ref()},
-                                   PolicyTraits::element(soo_slot()))) {
-      return {soo_iterator(), false};
+      force_sampling = true;
+    } else if (equal_to(key, single_slot())) {
+      return {single_iterator(), false};
     } else {
-      soo_slot_ctrl = static_cast<ctrl_t>(H2(hash_of(soo_slot())));
+      force_sampling = false;
     }
+    ABSL_SWISSTABLE_ASSERT(capacity() == 1);
     constexpr bool kUseMemcpy =
         PolicyTraits::transfer_uses_memcpy() && SooEnabled();
     size_t index = GrowSooTableToNextCapacityAndPrepareInsert<
         kUseMemcpy ? OptimalMemcpySizeForSooSlotTransfer(sizeof(slot_type)) : 0,
-        kUseMemcpy>(common(), GetPolicyFunctions(), hash_of(key),
-                    soo_slot_ctrl);
+        kUseMemcpy>(common(), GetPolicyFunctions(),
+                    HashKey<hasher, K, kIsDefaultHash>{hash_ref(), key},
+                    force_sampling);
     return {iterator_at(index), true};
   }
 
   template <class K>
-  std::pair<iterator, bool> find_or_prepare_insert_non_soo(const K& key) {
+  std::pair<iterator, bool> find_or_prepare_insert_small(const K& key) {
+    ABSL_SWISSTABLE_ASSERT(is_small());
+    if constexpr (SooEnabled()) {
+      return find_or_prepare_insert_soo(key);
+    }
+    if (!empty()) {
+      if (equal_to(key, single_slot())) {
+        common().infoz().RecordInsertHit();
+        return {single_iterator(), false};
+      }
+    }
+    return {iterator_at_ptr(PrepareInsertSmallNonSoo(
+                common(), GetPolicyFunctions(),
+                HashKey<hasher, K, kIsDefaultHash>{hash_ref(), key})),
+            true};
+  }
+
+  template <class K>
+  std::pair<iterator, bool> find_or_prepare_insert_large(const K& key) {
     ABSL_SWISSTABLE_ASSERT(!is_soo());
     prefetch_heap_block();
     const size_t hash = hash_of(key);
     auto seq = probe(common(), hash);
     const h2_t h2 = H2(hash);
     const ctrl_t* ctrl = control();
-    while (true) {
+    size_t index;
+    bool inserted;
+    // We use a lambda function to be able to exit from the nested loop without
+    // duplicating generated code for the return statement (e.g. iterator_at).
+    [&]() ABSL_ATTRIBUTE_ALWAYS_INLINE {
+      while (true) {
 #ifndef ABSL_HAVE_MEMORY_SANITIZER
-      absl::PrefetchToLocalCache(slot_array() + seq.offset());
+        absl::PrefetchToLocalCache(slot_array() + seq.offset());
 #endif
-      Group g{ctrl + seq.offset()};
-      for (uint32_t i : g.Match(h2)) {
-        if (ABSL_PREDICT_TRUE(PolicyTraits::apply(
-                EqualElement<K>{key, eq_ref()},
-                PolicyTraits::element(slot_array() + seq.offset(i)))))
-          return {iterator_at(seq.offset(i)), false};
+        Group g{ctrl + seq.offset()};
+        for (uint32_t i : g.Match(h2)) {
+          if (ABSL_PREDICT_TRUE(equal_to(key, slot_array() + seq.offset(i)))) {
+            index = seq.offset(i);
+            inserted = false;
+            common().infoz().RecordInsertHit();
+            return;
+          }
+        }
+        auto mask_empty = g.MaskEmpty();
+        if (ABSL_PREDICT_TRUE(mask_empty)) {
+          size_t target_group_offset = seq.offset();
+          index = SwisstableGenerationsEnabled()
+                      ? PrepareInsertLargeGenerationsEnabled(
+                            common(), GetPolicyFunctions(), hash, mask_empty,
+                            FindInfo{target_group_offset, seq.index()},
+                            HashKey<hasher, K, kIsDefaultHash>{hash_ref(), key})
+                      : PrepareInsertLarge(
+                            common(), GetPolicyFunctions(), hash, mask_empty,
+                            FindInfo{target_group_offset, seq.index()});
+          inserted = true;
+          return;
+        }
+        seq.next();
+        ABSL_SWISSTABLE_ASSERT(seq.index() <= capacity() && "full table!");
       }
-      auto mask_empty = g.MaskEmpty();
-      if (ABSL_PREDICT_TRUE(mask_empty)) {
-        size_t target = seq.offset(mask_empty.LowestBitSet());
-        return {iterator_at(PrepareInsertNonSoo(common(), GetPolicyFunctions(),
-                                                hash,
-                                                FindInfo{target, seq.index()})),
-                true};
-      }
-      seq.next();
-      ABSL_SWISSTABLE_ASSERT(seq.index() <= capacity() && "full table!");
-    }
+    }();
+    return {iterator_at(index), inserted};
+  }
+
+  template <class InputIt>
+  void insert_range(InputIt first, InputIt last) {
+    for (; first != last; ++first) emplace(*first);
   }
 
  protected:
@@ -3363,23 +3332,18 @@
 
     const size_t hash_of_arg = hash_of(key);
     const auto assert_consistent = [&](const ctrl_t*, void* slot) {
-      const value_type& element =
-          PolicyTraits::element(static_cast<slot_type*>(slot));
-      const bool is_key_equal =
-          PolicyTraits::apply(EqualElement<K>{key, eq_ref()}, element);
+      const bool is_key_equal = equal_to(key, to_slot(slot));
       if (!is_key_equal) return;
 
-      const size_t hash_of_slot =
-          PolicyTraits::apply(HashElement{hash_ref()}, element);
       [[maybe_unused]] const bool is_hash_equal =
-          hash_of_arg == hash_of_slot;
+          hash_of_arg == hash_of(to_slot(slot));
       assert((!is_key_equal || is_hash_equal) &&
              "eq(k1, k2) must imply that hash(k1) == hash(k2). "
              "hash/eq functors are inconsistent.");
     };
 
-    if (is_soo()) {
-      assert_consistent(/*unused*/ nullptr, soo_slot());
+    if (is_small()) {
+      assert_consistent(/*unused*/ nullptr, single_slot());
       return;
     }
     // We only do validation for small tables so that it's constant time.
@@ -3393,8 +3357,8 @@
   template <class K>
   std::pair<iterator, bool> find_or_prepare_insert(const K& key) {
     AssertOnFind(key);
-    if (is_soo()) return find_or_prepare_insert_soo(key);
-    return find_or_prepare_insert_non_soo(key);
+    if (is_small()) return find_or_prepare_insert_small(key);
+    return find_or_prepare_insert_large(key);
   }
 
   // Constructs the value in the space pointed by the iterator. This only works
@@ -3409,9 +3373,9 @@
   void emplace_at(iterator iter, Args&&... args) {
     construct(iter.slot(), std::forward<Args>(args)...);
 
-    // When capacity is 1, find calls find_small and if size is 0, then it will
+    // When is_small, find calls find_small and if size is 0, then it will
     // return an end iterator. This can happen in the raw_hash_set copy ctor.
-    assert((capacity() == 1 ||
+    assert((is_small() ||
             PolicyTraits::apply(FindElement{*this}, *iter) == iter) &&
            "constructed value does not match the lookup key");
   }
@@ -3422,6 +3386,10 @@
   const_iterator iterator_at(size_t i) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return const_cast<raw_hash_set*>(this)->iterator_at(i);
   }
+  iterator iterator_at_ptr(std::pair<ctrl_t*, void*> ptrs)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return {ptrs.first, to_slot(ptrs.second), common().generation_ptr()};
+  }
 
   reference unchecked_deref(iterator it) { return it.unchecked_deref(); }
 
@@ -3439,16 +3407,13 @@
   //
   // See `CapacityToGrowth()`.
   size_t growth_left() const {
-    ABSL_SWISSTABLE_ASSERT(!is_soo());
     return common().growth_left();
   }
 
   GrowthInfo& growth_info() {
-    ABSL_SWISSTABLE_ASSERT(!is_soo());
     return common().growth_info();
   }
   GrowthInfo growth_info() const {
-    ABSL_SWISSTABLE_ASSERT(!is_soo());
     return common().growth_info();
   }
 
@@ -3482,22 +3447,22 @@
     ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(
         const_cast<raw_hash_set*>(this)->soo_slot());
   }
-  iterator soo_iterator() {
-    return {SooControl(), soo_slot(), common().generation_ptr()};
-  }
-  const_iterator soo_iterator() const {
-    return const_cast<raw_hash_set*>(this)->soo_iterator();
-  }
   slot_type* single_slot() {
-    ABSL_SWISSTABLE_ASSERT(capacity() <= 1);
+    ABSL_SWISSTABLE_ASSERT(is_small());
     return SooEnabled() ? soo_slot() : slot_array();
   }
   const slot_type* single_slot() const {
     return const_cast<raw_hash_set*>(this)->single_slot();
   }
+  void decrement_small_size() {
+    ABSL_SWISSTABLE_ASSERT(is_small());
+    SooEnabled() ? common().set_empty_soo() : common().decrement_size();
+    if (!SooEnabled()) {
+      SanitizerPoisonObject(single_slot());
+    }
+  }
   iterator single_iterator() {
-    return {SooEnabled() ? SooControl() : control(), single_slot(),
-            common().generation_ptr()};
+    return {SooControl(), single_slot(), common().generation_ptr()};
   }
   const_iterator single_iterator() const {
     return const_cast<raw_hash_set*>(this)->single_iterator();
@@ -3554,8 +3519,6 @@
     ctrl_t* new_ctrl = common.control();
     slot_type* new_slots = set->slot_array();
 
-    const PerTableSeed seed = common.seed();
-
     for (size_t group_index = 0; group_index < old_capacity;
          group_index += Group::kWidth) {
       GroupFullEmptyOrDeleted old_g(old_ctrl + group_index);
@@ -3571,7 +3534,7 @@
         // TODO(b/382423690): try to avoid entire hash calculation since we need
         // only one new bit of h1.
         size_t hash = set->hash_of(old_slot);
-        size_t h1 = H1(hash, seed);
+        size_t h1 = H1(hash);
         h2_t h2 = H2(hash);
         size_t new_index = TryFindNewIndexWithoutProbing(
             h1, old_index, old_capacity, new_ctrl, new_capacity);
@@ -3614,7 +3577,7 @@
         // for standard layout and alignof(Hash) <= alignof(CommonFields).
         std::is_empty_v<hasher> ? &GetRefForEmptyClass
                                 : &raw_hash_set::get_hash_ref_fn,
-        PolicyTraits::template get_hash_slot_fn<hasher>(),
+        PolicyTraits::template get_hash_slot_fn<hasher, kIsDefaultHash>(),
         PolicyTraits::transfer_uses_memcpy()
             ? TransferNRelocatable<sizeof(slot_type)>
             : &raw_hash_set::transfer_n_slots_fn,
@@ -3642,15 +3605,15 @@
     if (c->empty()) {
       return 0;
     }
-    if (c->is_soo()) {
-      auto it = c->soo_iterator();
+    if (c->is_small()) {
+      auto it = c->single_iterator();
       if (!pred(*it)) {
         ABSL_SWISSTABLE_ASSERT(c->size() == 1 &&
                                "hash table was modified unexpectedly");
         return 0;
       }
       c->destroy(it.slot());
-      c->common().set_empty_soo();
+      c->erase_meta_only_small();
       return 1;
     }
     [[maybe_unused]] const size_t original_size_for_assert = c->size();
@@ -3662,8 +3625,7 @@
           auto* slot = static_cast<SlotType*>(slot_void);
           if (pred(Set::PolicyTraits::element(slot))) {
             c->destroy(slot);
-            EraseMetaOnly(c->common(), static_cast<size_t>(ctrl - c->control()),
-                          sizeof(*slot));
+            EraseMetaOnlyLarge(c->common(), ctrl, sizeof(*slot));
             ++num_deleted;
           }
         });
@@ -3680,8 +3642,8 @@
     if (c->empty()) {
       return;
     }
-    if (c->is_soo()) {
-      cb(*c->soo_iterator());
+    if (c->is_small()) {
+      cb(*c->single_iterator());
       return;
     }
     using SlotType = typename Set::slot_type;
@@ -3696,19 +3658,19 @@
 };
 
 // Erases all elements that satisfy the predicate `pred` from the container `c`.
-template <typename P, typename H, typename E, typename A, typename Predicate>
-typename raw_hash_set<P, H, E, A>::size_type EraseIf(
-    Predicate& pred, raw_hash_set<P, H, E, A>* c) {
+template <typename P, typename... Params, typename Predicate>
+typename raw_hash_set<P, Params...>::size_type EraseIf(
+    Predicate& pred, raw_hash_set<P, Params...>* c) {
   return HashtableFreeFunctionsAccess::EraseIf(pred, c);
 }
 
 // Calls `cb` for all elements in the container `c`.
-template <typename P, typename H, typename E, typename A, typename Callback>
-void ForEach(Callback& cb, raw_hash_set<P, H, E, A>* c) {
+template <typename P, typename... Params, typename Callback>
+void ForEach(Callback& cb, raw_hash_set<P, Params...>* c) {
   return HashtableFreeFunctionsAccess::ForEach(cb, c);
 }
-template <typename P, typename H, typename E, typename A, typename Callback>
-void ForEach(Callback& cb, const raw_hash_set<P, H, E, A>* c) {
+template <typename P, typename... Params, typename Callback>
+void ForEach(Callback& cb, const raw_hash_set<P, Params...>* c) {
   return HashtableFreeFunctionsAccess::ForEach(cb, c);
 }
 
@@ -3718,9 +3680,11 @@
   using Traits = typename Set::PolicyTraits;
   using Slot = typename Traits::slot_type;
 
+  constexpr static bool kIsDefaultHash = Set::kIsDefaultHash;
+
   static size_t GetNumProbes(const Set& set,
                              const typename Set::key_type& key) {
-    if (set.is_soo()) return 0;
+    if (set.is_small()) return 0;
     size_t num_probes = 0;
     const size_t hash = set.hash_of(key);
     auto seq = probe(set.common(), hash);
@@ -3729,10 +3693,7 @@
     while (true) {
       container_internal::Group g{ctrl + seq.offset()};
       for (uint32_t i : g.Match(h2)) {
-        if (Traits::apply(
-                typename Set::template EqualElement<typename Set::key_type>{
-                    key, set.eq_ref()},
-                Traits::element(set.slot_array() + seq.offset(i))))
+        if (set.equal_to(key, set.slot_array() + seq.offset(i)))
           return num_probes;
         ++num_probes;
       }
@@ -3765,18 +3726,31 @@
 // Extern template instantiations reduce binary size and linker input size.
 // Function definition is in raw_hash_set.cc.
 extern template size_t GrowSooTableToNextCapacityAndPrepareInsert<0, false>(
-    CommonFields&, const PolicyFunctions&, size_t, ctrl_t);
+    CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
+    bool);
 extern template size_t GrowSooTableToNextCapacityAndPrepareInsert<1, true>(
-    CommonFields&, const PolicyFunctions&, size_t, ctrl_t);
+    CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
+    bool);
 extern template size_t GrowSooTableToNextCapacityAndPrepareInsert<4, true>(
-    CommonFields&, const PolicyFunctions&, size_t, ctrl_t);
+    CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
+    bool);
 extern template size_t GrowSooTableToNextCapacityAndPrepareInsert<8, true>(
-    CommonFields&, const PolicyFunctions&, size_t, ctrl_t);
+    CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
+    bool);
 #if UINTPTR_MAX == UINT64_MAX
 extern template size_t GrowSooTableToNextCapacityAndPrepareInsert<16, true>(
-    CommonFields&, const PolicyFunctions&, size_t, ctrl_t);
+    CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
+    bool);
 #endif
 
+extern template void* AllocateBackingArray<
+    BackingArrayAlignment(alignof(size_t)), std::allocator<char>>(void* alloc,
+                                                                  size_t n);
+extern template void DeallocateBackingArray<
+    BackingArrayAlignment(alignof(size_t)), std::allocator<char>>(
+    void* alloc, size_t capacity, ctrl_t* ctrl, size_t slot_size,
+    size_t slot_align, bool had_infoz);
+
 }  // namespace container_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/container/internal/raw_hash_set_allocator_test.cc b/absl/container/internal/raw_hash_set_allocator_test.cc
index 7e7a506..c4bff60 100644
--- a/absl/container/internal/raw_hash_set_allocator_test.cc
+++ b/absl/container/internal/raw_hash_set_allocator_test.cc
@@ -142,6 +142,10 @@
   using init_type = Tracked<int32_t>;
   using key_type = int32_t;
 
+  using DefaultHash = void;
+  using DefaultEq = void;
+  using DefaultAlloc = void;
+
   template <class allocator_type, class... Args>
   static void construct(allocator_type* alloc, slot_type* slot,
                         Args&&... args) {
@@ -180,7 +184,7 @@
 
   static slot_type& element(slot_type* slot) { return *slot; }
 
-  template <class Hash>
+  template <class Hash, bool kIsDefault>
   static constexpr HashSlotFn get_hash_slot_fn() {
     return nullptr;
   }
@@ -436,13 +440,14 @@
 }
 
 TEST_F(PropagateOnAll, Swap) {
-  auto it = t1.insert(0).first;
+  t1.insert(0);
   Table u(0, a2);
   u.swap(t1);
   EXPECT_EQ(a1, u.get_allocator());
   EXPECT_EQ(a2, t1.get_allocator());
   EXPECT_EQ(1, a1.num_allocs());
   EXPECT_EQ(0, a2.num_allocs());
+  auto it = u.begin();
   EXPECT_EQ(0, it->num_moves());
   EXPECT_EQ(0, it->num_copies());
 }
diff --git a/absl/container/internal/raw_hash_set_benchmark.cc b/absl/container/internal/raw_hash_set_benchmark.cc
index ac94877..589f4f5 100644
--- a/absl/container/internal/raw_hash_set_benchmark.cc
+++ b/absl/container/internal/raw_hash_set_benchmark.cc
@@ -51,6 +51,10 @@
   using key_type = int64_t;
   using init_type = int64_t;
 
+  using DefaultHash = void;
+  using DefaultEq = void;
+  using DefaultAlloc = void;
+
   static void construct(void*, int64_t* slot, int64_t v) { *slot = v; }
   static void destroy(void*, int64_t*) {}
   static void transfer(void*, int64_t* new_slot, int64_t* old_slot) {
@@ -64,7 +68,7 @@
     return std::forward<F>(f)(x, x);
   }
 
-  template <class Hash>
+  template <class Hash, bool kIsDefault>
   static constexpr HashSlotFn get_hash_slot_fn() {
     return nullptr;
   }
@@ -97,6 +101,10 @@
   using key_type = std::string;
   using init_type = std::pair<std::string, std::string>;
 
+  using DefaultHash = void;
+  using DefaultEq = void;
+  using DefaultAlloc = void;
+
   template <class allocator_type, class... Args>
   static void construct(allocator_type* alloc, slot_type* slot, Args... args) {
     std::allocator_traits<allocator_type>::construct(
@@ -127,7 +135,7 @@
                       PairArgs(std::forward<Args>(args)...));
   }
 
-  template <class Hash>
+  template <class Hash, bool kIsDefault>
   static constexpr HashSlotFn get_hash_slot_fn() {
     return nullptr;
   }
@@ -519,17 +527,6 @@
 }
 BENCHMARK(BM_Group_MaskNonFull);
 
-void BM_Group_CountLeadingEmptyOrDeleted(benchmark::State& state) {
-  std::array<ctrl_t, Group::kWidth> group;
-  Iota(group.begin(), group.end(), -2);
-  Group g{group.data()};
-  for (auto _ : state) {
-    ::benchmark::DoNotOptimize(g);
-    ::benchmark::DoNotOptimize(g.CountLeadingEmptyOrDeleted());
-  }
-}
-BENCHMARK(BM_Group_CountLeadingEmptyOrDeleted);
-
 void BM_Group_MatchFirstEmptyOrDeleted(benchmark::State& state) {
   std::array<ctrl_t, Group::kWidth> group;
   Iota(group.begin(), group.end(), -2);
diff --git a/absl/container/internal/raw_hash_set_probe_benchmark.cc b/absl/container/internal/raw_hash_set_probe_benchmark.cc
index e56648f..7165558 100644
--- a/absl/container/internal/raw_hash_set_probe_benchmark.cc
+++ b/absl/container/internal/raw_hash_set_probe_benchmark.cc
@@ -15,8 +15,14 @@
 // Generates probe length statistics for many combinations of key types and key
 // distributions, all using the default hash function for swisstable.
 
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <limits>
 #include <memory>
 #include <regex>  // NOLINT
+#include <string>
+#include <utility>
 #include <vector>
 
 #include "absl/base/no_destructor.h"
@@ -52,6 +58,10 @@
   using key_type = T;
   using init_type = T;
 
+  using DefaultHash = void;
+  using DefaultEq = void;
+  using DefaultAlloc = void;
+
   template <class allocator_type, class Arg>
   static void construct(allocator_type* alloc, slot_type* slot,
                         const Arg& arg) {
@@ -71,7 +81,7 @@
     return std::forward<F>(f)(arg, arg);
   }
 
-  template <class Hash>
+  template <class Hash, bool kIsDefault>
   static constexpr auto get_hash_slot_fn() {
     return nullptr;
   }
@@ -227,24 +237,6 @@
   return reinterpret_cast<Ptr<Align>*>(v);
 }
 
-struct IntIdentity {
-  uint64_t i;
-  friend bool operator==(IntIdentity a, IntIdentity b) { return a.i == b.i; }
-  IntIdentity operator++(int) { return IntIdentity{i++}; }
-};
-
-template <int Align>
-struct PtrIdentity {
-  explicit PtrIdentity(uintptr_t val = PointerForAlignment<Align>()) : i(val) {}
-  uintptr_t i;
-  friend bool operator==(PtrIdentity a, PtrIdentity b) { return a.i == b.i; }
-  PtrIdentity operator++(int) {
-    PtrIdentity p(i);
-    i += Align;
-    return p;
-  }
-};
-
 enum class StringSize { kSmall, kMedium, kLarge, kExtraLarge };
 constexpr char kStringFormat[] = "%s/name-%07d-of-9999999.txt";
 
@@ -270,20 +262,6 @@
   }
 };
 
-template <>
-struct DefaultHash<IntIdentity> {
-  struct type {
-    size_t operator()(IntIdentity t) const { return t.i; }
-  };
-};
-
-template <int Align>
-struct DefaultHash<PtrIdentity<Align>> {
-  struct type {
-    size_t operator()(PtrIdentity<Align> t) const { return t.i; }
-  };
-};
-
 template <class T>
 struct Sequential {
   T operator()() const { return current++; }
@@ -389,20 +367,6 @@
   }
 };
 
-template <class Dist>
-struct Random<IntIdentity, Dist> {
-  IntIdentity operator()() const {
-    return IntIdentity{Random<uint64_t, Dist>{}()};
-  }
-};
-
-template <class Dist, int Align>
-struct Random<PtrIdentity<Align>, Dist> {
-  PtrIdentity<Align> operator()() const {
-    return PtrIdentity<Align>{Random<uintptr_t, Dist>{}() * Align};
-  }
-};
-
 template <class Dist, StringSize size>
 struct Random<String<size>, Dist> {
   std::string operator()() const {
@@ -423,18 +387,12 @@
 
 std::string Name(uint32_t*) { return "u32"; }
 std::string Name(uint64_t*) { return "u64"; }
-std::string Name(IntIdentity*) { return "IntIdentity"; }
 
 template <int Align>
 std::string Name(Ptr<Align>**) {
   return absl::StrCat("Ptr", Align);
 }
 
-template <int Align>
-std::string Name(PtrIdentity<Align>*) {
-  return absl::StrCat("PtrIdentity", Align);
-}
-
 template <StringSize size>
 std::string Name(String<size>*) {
   switch (size) {
@@ -558,15 +516,10 @@
 
   std::vector<Result> results;
   RunForType<uint64_t>(results);
-  RunForType<IntIdentity>(results);
   RunForType<Ptr<8>*>(results);
   RunForType<Ptr<16>*>(results);
   RunForType<Ptr<32>*>(results);
   RunForType<Ptr<64>*>(results);
-  RunForType<PtrIdentity<8>>(results);
-  RunForType<PtrIdentity<16>>(results);
-  RunForType<PtrIdentity<32>>(results);
-  RunForType<PtrIdentity<64>>(results);
   RunForType<std::pair<uint32_t, uint32_t>>(results);
   RunForType<String<StringSize::kSmall>>(results);
   RunForType<String<StringSize::kMedium>>(results);
@@ -603,9 +556,11 @@
           // Check the regex again. We might had have enabled only one of the
           // stats for the benchmark.
           if (!CanRunBenchmark(name)) return;
+          // Report at least 1, because benchy drops results with zero.
+          double reported_value = std::max(1e9 * result.ratios.*val, 1.0);
           absl::PrintF("    %s{\n", comma);
-          absl::PrintF("      \"cpu_time\": %f,\n", 1e9 * result.ratios.*val);
-          absl::PrintF("      \"real_time\": %f,\n", 1e9 * result.ratios.*val);
+          absl::PrintF("      \"cpu_time\": %f,\n", reported_value);
+          absl::PrintF("      \"real_time\": %f,\n", reported_value);
           absl::PrintF("      \"iterations\": 1,\n");
           absl::PrintF("      \"name\": \"%s\",\n", name);
           absl::PrintF("      \"time_unit\": \"ns\"\n");
diff --git a/absl/container/internal/raw_hash_set_resize_impl.h b/absl/container/internal/raw_hash_set_resize_impl.h
index 149d9e8..ed48d96 100644
--- a/absl/container/internal/raw_hash_set_resize_impl.h
+++ b/absl/container/internal/raw_hash_set_resize_impl.h
@@ -52,7 +52,6 @@
   static constexpr IntType kMaxNewBits = kMaxOldBits + 1;
   static constexpr IntType kMaxNewCapacity = (IntType{1} << kMaxNewBits) - 1;
 
-  static constexpr IntType kH2Shift = (kTotalBits - kH2Bits);
   static_assert(kMaxNewBits + kMaxOldBits + kH2Bits == kTotalBits);
 
   ProbedItemImpl() = default;
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc
index 9a323c4..0b5ad8f 100644
--- a/absl/container/internal/raw_hash_set_test.cc
+++ b/absl/container/internal/raw_hash_set_test.cc
@@ -54,8 +54,6 @@
 #include "absl/container/internal/hash_function_defaults.h"
 #include "absl/container/internal/hash_policy_testing.h"
 #include "absl/random/random.h"
-// TODO(b/382423690): Separate tests that depend only on
-// hashtable_control_bytes.
 #include "absl/container/internal/hashtable_control_bytes.h"
 #include "absl/container/internal/hashtable_debug.h"
 #include "absl/container/internal/hashtablez_sampler.h"
@@ -96,7 +94,6 @@
 namespace {
 
 using ::testing::ElementsAre;
-using ::testing::ElementsAreArray;
 using ::testing::Eq;
 using ::testing::Ge;
 using ::testing::Lt;
@@ -279,28 +276,53 @@
   EXPECT_EQ(15 * 2 + 1, NormalizeCapacity(15 + 2));
 }
 
-TEST(Util, GrowthAndCapacity) {
-  // Verify that GrowthToCapacity gives the minimum capacity that has enough
-  // growth.
+TEST(Util, SizeToCapacitySmallValues) {
   EXPECT_EQ(SizeToCapacity(0), 0);
   EXPECT_EQ(SizeToCapacity(1), 1);
   EXPECT_EQ(SizeToCapacity(2), 3);
   EXPECT_EQ(SizeToCapacity(3), 3);
+  EXPECT_EQ(SizeToCapacity(4), 7);
+  EXPECT_EQ(SizeToCapacity(5), 7);
+  EXPECT_EQ(SizeToCapacity(6), 7);
+  if (Group::kWidth == 16) {
+    EXPECT_EQ(SizeToCapacity(7), 7);
+    EXPECT_EQ(SizeToCapacity(14), 15);
+  } else {
+    EXPECT_EQ(SizeToCapacity(7), 15);
+  }
+}
+
+TEST(Util, CapacityToGrowthSmallValues) {
+  EXPECT_EQ(CapacityToGrowth(1), 1);
+  EXPECT_EQ(CapacityToGrowth(3), 3);
+  if (Group::kWidth == 16) {
+    EXPECT_EQ(CapacityToGrowth(7), 7);
+  } else {
+    EXPECT_EQ(CapacityToGrowth(7), 6);
+  }
+  EXPECT_EQ(CapacityToGrowth(15), 14);
+  EXPECT_EQ(CapacityToGrowth(31), 28);
+  EXPECT_EQ(CapacityToGrowth(63), 56);
+}
+
+TEST(Util, GrowthAndCapacity) {
+  // Verify that GrowthToCapacity gives the minimum capacity that has enough
+  // growth.
   for (size_t growth = 1; growth < 10000; ++growth) {
     SCOPED_TRACE(growth);
     size_t capacity = SizeToCapacity(growth);
     ASSERT_TRUE(IsValidCapacity(capacity));
     // The capacity is large enough for `growth`.
-    EXPECT_THAT(CapacityToGrowth(capacity), Ge(growth));
+    ASSERT_THAT(CapacityToGrowth(capacity), Ge(growth));
     // For (capacity+1) < kWidth, growth should equal capacity.
     if (capacity + 1 < Group::kWidth) {
-      EXPECT_THAT(CapacityToGrowth(capacity), Eq(capacity));
+      ASSERT_THAT(CapacityToGrowth(capacity), Eq(capacity));
     } else {
-      EXPECT_THAT(CapacityToGrowth(capacity), Lt(capacity));
+      ASSERT_THAT(CapacityToGrowth(capacity), Lt(capacity));
     }
     if (growth != 0 && capacity > 1) {
       // There is no smaller capacity that works.
-      EXPECT_THAT(CapacityToGrowth(capacity / 2), Lt(growth));
+      ASSERT_THAT(CapacityToGrowth(capacity / 2), Lt(growth)) << capacity;
     }
   }
 
@@ -308,9 +330,9 @@
        capacity = 2 * capacity + 1) {
     SCOPED_TRACE(capacity);
     size_t growth = CapacityToGrowth(capacity);
-    EXPECT_THAT(growth, Lt(capacity));
-    EXPECT_EQ(SizeToCapacity(growth), capacity);
-    EXPECT_EQ(NormalizeCapacity(SizeToCapacity(growth)), capacity);
+    ASSERT_THAT(growth, Lt(capacity));
+    ASSERT_EQ(SizeToCapacity(growth), capacity);
+    ASSERT_EQ(NormalizeCapacity(SizeToCapacity(growth)), capacity);
   }
 }
 
@@ -329,203 +351,6 @@
   EXPECT_THAT(offsets, ElementsAre(0, 16, 48, 96, 32, 112, 80, 64));
 }
 
-TEST(BitMask, Smoke) {
-  EXPECT_FALSE((BitMask<uint8_t, 8>(0)));
-  EXPECT_TRUE((BitMask<uint8_t, 8>(5)));
-
-  EXPECT_THAT((BitMask<uint8_t, 8>(0)), ElementsAre());
-  EXPECT_THAT((BitMask<uint8_t, 8>(0x1)), ElementsAre(0));
-  EXPECT_THAT((BitMask<uint8_t, 8>(0x2)), ElementsAre(1));
-  EXPECT_THAT((BitMask<uint8_t, 8>(0x3)), ElementsAre(0, 1));
-  EXPECT_THAT((BitMask<uint8_t, 8>(0x4)), ElementsAre(2));
-  EXPECT_THAT((BitMask<uint8_t, 8>(0x5)), ElementsAre(0, 2));
-  EXPECT_THAT((BitMask<uint8_t, 8>(0x55)), ElementsAre(0, 2, 4, 6));
-  EXPECT_THAT((BitMask<uint8_t, 8>(0xAA)), ElementsAre(1, 3, 5, 7));
-}
-
-TEST(BitMask, WithShift_MatchPortable) {
-  // See the non-SSE version of Group for details on what this math is for.
-  uint64_t ctrl = 0x1716151413121110;
-  uint64_t hash = 0x12;
-  constexpr uint64_t lsbs = 0x0101010101010101ULL;
-  auto x = ctrl ^ (lsbs * hash);
-  uint64_t mask = (x - lsbs) & ~x & kMsbs8Bytes;
-  EXPECT_EQ(0x0000000080800000, mask);
-
-  BitMask<uint64_t, 8, 3> b(mask);
-  EXPECT_EQ(*b, 2);
-}
-
-constexpr uint64_t kSome8BytesMask = /*  */ 0x8000808080008000ULL;
-constexpr uint64_t kSome8BytesMaskAllOnes = 0xff00ffffff00ff00ULL;
-constexpr auto kSome8BytesMaskBits = std::array<int, 5>{1, 3, 4, 5, 7};
-
-
-TEST(BitMask, WithShift_FullMask) {
-  EXPECT_THAT((BitMask<uint64_t, 8, 3>(kMsbs8Bytes)),
-              ElementsAre(0, 1, 2, 3, 4, 5, 6, 7));
-  EXPECT_THAT(
-      (BitMask<uint64_t, 8, 3, /*NullifyBitsOnIteration=*/true>(kMsbs8Bytes)),
-      ElementsAre(0, 1, 2, 3, 4, 5, 6, 7));
-  EXPECT_THAT(
-      (BitMask<uint64_t, 8, 3, /*NullifyBitsOnIteration=*/true>(~uint64_t{0})),
-      ElementsAre(0, 1, 2, 3, 4, 5, 6, 7));
-}
-
-TEST(BitMask, WithShift_EmptyMask) {
-  EXPECT_THAT((BitMask<uint64_t, 8, 3>(0)), ElementsAre());
-  EXPECT_THAT((BitMask<uint64_t, 8, 3, /*NullifyBitsOnIteration=*/true>(0)),
-              ElementsAre());
-}
-
-TEST(BitMask, WithShift_SomeMask) {
-  EXPECT_THAT((BitMask<uint64_t, 8, 3>(kSome8BytesMask)),
-              ElementsAreArray(kSome8BytesMaskBits));
-  EXPECT_THAT((BitMask<uint64_t, 8, 3, /*NullifyBitsOnIteration=*/true>(
-                  kSome8BytesMask)),
-              ElementsAreArray(kSome8BytesMaskBits));
-  EXPECT_THAT((BitMask<uint64_t, 8, 3, /*NullifyBitsOnIteration=*/true>(
-                  kSome8BytesMaskAllOnes)),
-              ElementsAreArray(kSome8BytesMaskBits));
-}
-
-TEST(BitMask, WithShift_SomeMaskExtraBitsForNullify) {
-  // Verify that adding extra bits into non zero bytes is fine.
-  uint64_t extra_bits = 77;
-  for (int i = 0; i < 100; ++i) {
-    // Add extra bits, but keep zero bytes untouched.
-    uint64_t extra_mask = extra_bits & kSome8BytesMaskAllOnes;
-    EXPECT_THAT((BitMask<uint64_t, 8, 3, /*NullifyBitsOnIteration=*/true>(
-                    kSome8BytesMask | extra_mask)),
-                ElementsAreArray(kSome8BytesMaskBits))
-        << i << " " << extra_mask;
-    extra_bits = (extra_bits + 1) * 3;
-  }
-}
-
-TEST(BitMask, LeadingTrailing) {
-  EXPECT_EQ((BitMask<uint32_t, 16>(0x00001a40).LeadingZeros()), 3);
-  EXPECT_EQ((BitMask<uint32_t, 16>(0x00001a40).TrailingZeros()), 6);
-
-  EXPECT_EQ((BitMask<uint32_t, 16>(0x00000001).LeadingZeros()), 15);
-  EXPECT_EQ((BitMask<uint32_t, 16>(0x00000001).TrailingZeros()), 0);
-
-  EXPECT_EQ((BitMask<uint32_t, 16>(0x00008000).LeadingZeros()), 0);
-  EXPECT_EQ((BitMask<uint32_t, 16>(0x00008000).TrailingZeros()), 15);
-
-  EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000008080808000).LeadingZeros()), 3);
-  EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000008080808000).TrailingZeros()), 1);
-
-  EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000000000000080).LeadingZeros()), 7);
-  EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000000000000080).TrailingZeros()), 0);
-
-  EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x8000000000000000).LeadingZeros()), 0);
-  EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x8000000000000000).TrailingZeros()), 7);
-}
-
-TEST(Group, EmptyGroup) {
-  for (h2_t h = 0; h != 128; ++h) EXPECT_FALSE(Group{EmptyGroup()}.Match(h));
-}
-
-TEST(Group, Match) {
-  if (Group::kWidth == 16) {
-    ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted,  CtrlT(3),
-                      ctrl_t::kEmpty, CtrlT(5), ctrl_t::kSentinel, CtrlT(7),
-                      CtrlT(7),       CtrlT(5), CtrlT(3),          CtrlT(1),
-                      CtrlT(1),       CtrlT(1), CtrlT(1),          CtrlT(1)};
-    EXPECT_THAT(Group{group}.Match(0), ElementsAre());
-    EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 11, 12, 13, 14, 15));
-    EXPECT_THAT(Group{group}.Match(3), ElementsAre(3, 10));
-    EXPECT_THAT(Group{group}.Match(5), ElementsAre(5, 9));
-    EXPECT_THAT(Group{group}.Match(7), ElementsAre(7, 8));
-  } else if (Group::kWidth == 8) {
-    ctrl_t group[] = {ctrl_t::kEmpty,    CtrlT(1), CtrlT(2),
-                      ctrl_t::kDeleted,  CtrlT(2), CtrlT(1),
-                      ctrl_t::kSentinel, CtrlT(1)};
-    EXPECT_THAT(Group{group}.Match(0), ElementsAre());
-    EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 5, 7));
-    EXPECT_THAT(Group{group}.Match(2), ElementsAre(2, 4));
-  } else {
-    FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
-  }
-}
-
-TEST(Group, MaskEmpty) {
-  if (Group::kWidth == 16) {
-    ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted,  CtrlT(3),
-                      ctrl_t::kEmpty, CtrlT(5), ctrl_t::kSentinel, CtrlT(7),
-                      CtrlT(7),       CtrlT(5), CtrlT(3),          CtrlT(1),
-                      CtrlT(1),       CtrlT(1), CtrlT(1),          CtrlT(1)};
-    EXPECT_THAT(Group{group}.MaskEmpty().LowestBitSet(), 0);
-    EXPECT_THAT(Group{group}.MaskEmpty().HighestBitSet(), 4);
-  } else if (Group::kWidth == 8) {
-    ctrl_t group[] = {ctrl_t::kEmpty,    CtrlT(1), CtrlT(2),
-                      ctrl_t::kDeleted,  CtrlT(2), CtrlT(1),
-                      ctrl_t::kSentinel, CtrlT(1)};
-    EXPECT_THAT(Group{group}.MaskEmpty().LowestBitSet(), 0);
-    EXPECT_THAT(Group{group}.MaskEmpty().HighestBitSet(), 0);
-  } else {
-    FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
-  }
-}
-
-TEST(Group, MaskFull) {
-  if (Group::kWidth == 16) {
-    ctrl_t group[] = {
-        ctrl_t::kEmpty, CtrlT(1),          ctrl_t::kDeleted,  CtrlT(3),
-        ctrl_t::kEmpty, CtrlT(5),          ctrl_t::kSentinel, CtrlT(7),
-        CtrlT(7),       CtrlT(5),          ctrl_t::kDeleted,  CtrlT(1),
-        CtrlT(1),       ctrl_t::kSentinel, ctrl_t::kEmpty,    CtrlT(1)};
-    EXPECT_THAT(Group{group}.MaskFull(),
-                ElementsAre(1, 3, 5, 7, 8, 9, 11, 12, 15));
-  } else if (Group::kWidth == 8) {
-    ctrl_t group[] = {ctrl_t::kEmpty,    CtrlT(1), ctrl_t::kEmpty,
-                      ctrl_t::kDeleted,  CtrlT(2), ctrl_t::kSentinel,
-                      ctrl_t::kSentinel, CtrlT(1)};
-    EXPECT_THAT(Group{group}.MaskFull(), ElementsAre(1, 4, 7));
-  } else {
-    FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
-  }
-}
-
-TEST(Group, MaskNonFull) {
-  if (Group::kWidth == 16) {
-    ctrl_t group[] = {
-        ctrl_t::kEmpty, CtrlT(1),          ctrl_t::kDeleted,  CtrlT(3),
-        ctrl_t::kEmpty, CtrlT(5),          ctrl_t::kSentinel, CtrlT(7),
-        CtrlT(7),       CtrlT(5),          ctrl_t::kDeleted,  CtrlT(1),
-        CtrlT(1),       ctrl_t::kSentinel, ctrl_t::kEmpty,    CtrlT(1)};
-    EXPECT_THAT(Group{group}.MaskNonFull(),
-                ElementsAre(0, 2, 4, 6, 10, 13, 14));
-  } else if (Group::kWidth == 8) {
-    ctrl_t group[] = {ctrl_t::kEmpty,    CtrlT(1), ctrl_t::kEmpty,
-                      ctrl_t::kDeleted,  CtrlT(2), ctrl_t::kSentinel,
-                      ctrl_t::kSentinel, CtrlT(1)};
-    EXPECT_THAT(Group{group}.MaskNonFull(), ElementsAre(0, 2, 3, 5, 6));
-  } else {
-    FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
-  }
-}
-
-TEST(Group, MaskEmptyOrDeleted) {
-  if (Group::kWidth == 16) {
-    ctrl_t group[] = {ctrl_t::kEmpty,   CtrlT(1), ctrl_t::kEmpty,    CtrlT(3),
-                      ctrl_t::kDeleted, CtrlT(5), ctrl_t::kSentinel, CtrlT(7),
-                      CtrlT(7),         CtrlT(5), CtrlT(3),          CtrlT(1),
-                      CtrlT(1),         CtrlT(1), CtrlT(1),          CtrlT(1)};
-    EXPECT_THAT(Group{group}.MaskEmptyOrDeleted().LowestBitSet(), 0);
-    EXPECT_THAT(Group{group}.MaskEmptyOrDeleted().HighestBitSet(), 4);
-  } else if (Group::kWidth == 8) {
-    ctrl_t group[] = {ctrl_t::kEmpty,    CtrlT(1), CtrlT(2),
-                      ctrl_t::kDeleted,  CtrlT(2), CtrlT(1),
-                      ctrl_t::kSentinel, CtrlT(1)};
-    EXPECT_THAT(Group{group}.MaskEmptyOrDeleted().LowestBitSet(), 0);
-    EXPECT_THAT(Group{group}.MaskEmptyOrDeleted().HighestBitSet(), 3);
-  } else {
-    FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
-  }
-}
-
 TEST(Batch, DropDeletes) {
   constexpr size_t kCapacity = 63;
   constexpr size_t kGroupWidth = container_internal::Group::kWidth;
@@ -551,36 +376,16 @@
   }
 }
 
-TEST(Group, CountLeadingEmptyOrDeleted) {
-  const std::vector<ctrl_t> empty_examples = {ctrl_t::kEmpty, ctrl_t::kDeleted};
-  const std::vector<ctrl_t> full_examples = {
-      CtrlT(0), CtrlT(1), CtrlT(2),   CtrlT(3),
-      CtrlT(5), CtrlT(9), CtrlT(127), ctrl_t::kSentinel};
-
-  for (ctrl_t empty : empty_examples) {
-    std::vector<ctrl_t> e(Group::kWidth, empty);
-    EXPECT_EQ(Group::kWidth, Group{e.data()}.CountLeadingEmptyOrDeleted());
-    for (ctrl_t full : full_examples) {
-      for (size_t i = 0; i != Group::kWidth; ++i) {
-        std::vector<ctrl_t> f(Group::kWidth, empty);
-        f[i] = full;
-        EXPECT_EQ(i, Group{f.data()}.CountLeadingEmptyOrDeleted());
-      }
-      std::vector<ctrl_t> f(Group::kWidth, empty);
-      f[Group::kWidth * 2 / 3] = full;
-      f[Group::kWidth / 2] = full;
-      EXPECT_EQ(Group::kWidth / 2,
-                Group{f.data()}.CountLeadingEmptyOrDeleted());
-    }
-  }
-}
-
 template <class T, bool kTransferable = false, bool kSoo = false>
 struct ValuePolicy {
   using slot_type = T;
   using key_type = T;
   using init_type = T;
 
+  using DefaultHash = hash_default_hash<T>;
+  using DefaultEq = std::equal_to<T>;
+  using DefaultAlloc = std::allocator<T>;
+
   template <class Allocator, class... Args>
   static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
     absl::allocator_traits<Allocator>::construct(*alloc, slot,
@@ -610,7 +415,7 @@
         std::forward<F>(f), std::forward<Args>(args)...);
   }
 
-  template <class Hash>
+  template <class Hash, bool kIsDefault>
   static constexpr HashSlotFn get_hash_slot_fn() {
     return nullptr;
   }
@@ -728,6 +533,10 @@
   using key_type = std::string;
   using init_type = std::pair<std::string, std::string>;
 
+  using DefaultHash = void;
+  using DefaultEq = void;
+  using DefaultAlloc = void;
+
   template <class allocator_type, class... Args>
   static void construct(allocator_type* alloc, slot_type* slot, Args... args) {
     std::allocator_traits<allocator_type>::construct(
@@ -758,7 +567,7 @@
                       PairArgs(std::forward<Args>(args)...));
   }
 
-  template <class Hash>
+  template <class Hash, bool kIsDefault>
   static constexpr HashSlotFn get_hash_slot_fn() {
     return nullptr;
   }
@@ -780,9 +589,9 @@
 
 template <typename T, bool kTransferable = false, bool kSoo = false,
           class Alloc = std::allocator<T>>
-struct ValueTable
-    : raw_hash_set<ValuePolicy<T, kTransferable, kSoo>, hash_default_hash<T>,
-                   std::equal_to<T>, Alloc> {
+struct ValueTable : InstantiateRawHashSet<ValuePolicy<T, kTransferable, kSoo>,
+                                          hash_default_hash<T>,
+                                          std::equal_to<T>, Alloc>::type {
   using Base = typename ValueTable::raw_hash_set;
   using Base::Base;
 };
@@ -981,6 +790,34 @@
                        std::equal_to<absl::string_view>, std::allocator<int>>));
 }
 
+TEST(InstantiateRawHashSetTest, VerifyTypes) {
+  using P = ValuePolicy<int>;
+  using DA = typename P::DefaultHash;
+  using DB = typename P::DefaultEq;
+  using DC = typename P::DefaultAlloc;
+
+  struct A {};
+  struct B {};
+  struct C {};
+
+  EXPECT_TRUE((std::is_same_v<InstantiateRawHashSet<P, A, B, C>::type,
+                              raw_hash_set<P, A, B, C>>));
+  EXPECT_TRUE((std::is_same_v<InstantiateRawHashSet<P, A, B, DC>::type,
+                              raw_hash_set<P, A, B>>));
+  EXPECT_TRUE((std::is_same_v<InstantiateRawHashSet<P, A, DB, C>::type,
+                              raw_hash_set<P, A, DB, C>>));
+  EXPECT_TRUE((std::is_same_v<InstantiateRawHashSet<P, A, DB, DC>::type,
+                              raw_hash_set<P, A>>));
+  EXPECT_TRUE((std::is_same_v<InstantiateRawHashSet<P, DA, B, C>::type,
+                              raw_hash_set<P, DA, B, C>>));
+  EXPECT_TRUE((std::is_same_v<InstantiateRawHashSet<P, DA, B, DC>::type,
+                              raw_hash_set<P, DA, B>>));
+  EXPECT_TRUE((std::is_same_v<InstantiateRawHashSet<P, DA, DB, C>::type,
+                              raw_hash_set<P, DA, DB, C>>));
+  EXPECT_TRUE((std::is_same_v<InstantiateRawHashSet<P, DA, DB, DC>::type,
+                              raw_hash_set<P>>));
+}
+
 template <class TableType>
 class SooTest : public testing::Test {};
 
@@ -1184,7 +1021,7 @@
     t.insert(i);
     ASSERT_EQ(t.size(), i + 1);
     for (int j = 0; j < i + 1; ++j) {
-      EXPECT_TRUE(t.find(j) != t.end());
+      ASSERT_TRUE(t.find(j) != t.end());
       EXPECT_EQ(*t.find(j), j);
     }
   }
@@ -1207,7 +1044,7 @@
           t.reserve(target_size);
         }
         for (size_t i = 0; i < source_size; ++i) {
-          EXPECT_TRUE(t.find(static_cast<int>(i)) != t.end());
+          ASSERT_TRUE(t.find(static_cast<int>(i)) != t.end());
           EXPECT_EQ(*t.find(static_cast<int>(i)), static_cast<int>(i));
         }
       }
@@ -1232,7 +1069,7 @@
             << "rehash(0) must resize to the minimum capacity";
       }
       for (size_t i = 0; i < inserted_count; ++i) {
-        EXPECT_TRUE(t.find(static_cast<int>(i)) != t.end());
+        ASSERT_TRUE(t.find(static_cast<int>(i)) != t.end());
         EXPECT_EQ(*t.find(static_cast<int>(i)), static_cast<int>(i));
       }
     }
@@ -1283,6 +1120,9 @@
 
   t.clear();
   EXPECT_FALSE(t.contains(0));
+
+  EXPECT_TRUE(t.insert(0).second);
+  EXPECT_TRUE(t.contains(0));
 }
 
 int decompose_constructed;
@@ -1340,6 +1180,10 @@
   using key_type = DecomposeType;
   using init_type = DecomposeType;
 
+  using DefaultHash = void;
+  using DefaultEq = void;
+  using DefaultAlloc = void;
+
   template <typename T>
   static void construct(void*, DecomposeType* slot, T&& v) {
     ::new (slot) DecomposeType(std::forward<T>(v));
@@ -1352,7 +1196,7 @@
     return std::forward<F>(f)(x, x);
   }
 
-  template <class Hash>
+  template <class Hash, bool kIsDefault>
   static constexpr HashSlotFn get_hash_slot_fn() {
     return nullptr;
   }
@@ -2083,8 +1927,6 @@
 
 TEST(Table, GrowthInfoDeletedBit) {
   BadTable t;
-  EXPECT_TRUE(
-      RawHashSetTestOnlyAccess::GetCommon(t).growth_info().HasNoDeleted());
   int64_t init_count = static_cast<int64_t>(
       CapacityToGrowth(NormalizeCapacity(Group::kWidth + 1)));
   for (int64_t i = 0; i < init_count; ++i) {
@@ -2470,12 +2312,10 @@
 }
 
 TEST(Table, NoThrowSwappable) {
-  ASSERT_TRUE(
-      container_internal::IsNoThrowSwappable<absl::Hash<absl::string_view>>());
-  ASSERT_TRUE(container_internal::IsNoThrowSwappable<
-              std::equal_to<absl::string_view>>());
-  ASSERT_TRUE(container_internal::IsNoThrowSwappable<std::allocator<int>>());
-  EXPECT_TRUE(container_internal::IsNoThrowSwappable<StringTable>());
+  ASSERT_TRUE(std::is_nothrow_swappable<absl::Hash<absl::string_view>>());
+  ASSERT_TRUE(std::is_nothrow_swappable<std::equal_to<absl::string_view>>());
+  ASSERT_TRUE(std::is_nothrow_swappable<std::allocator<int>>());
+  EXPECT_TRUE(std::is_nothrow_swappable<StringTable>());
 }
 
 TEST(Table, HeterogeneousLookup) {
@@ -2604,6 +2444,19 @@
   EXPECT_THAT(t2, UnorderedElementsAre(Pair("0", "~0")));
 }
 
+TEST(Table, MergeSmall) {
+  StringTable t1, t2;
+  t1.emplace("1", "1");
+  t2.emplace("2", "2");
+
+  EXPECT_THAT(t1, UnorderedElementsAre(Pair("1", "1")));
+  EXPECT_THAT(t2, UnorderedElementsAre(Pair("2", "2")));
+
+  t2.merge(t1);
+  EXPECT_EQ(t1.size(), 0);
+  EXPECT_THAT(t2, UnorderedElementsAre(Pair("1", "1"), Pair("2", "2")));
+}
+
 TEST(Table, IteratorEmplaceConstructibleRequirement) {
   struct Value {
     explicit Value(absl::string_view view) : value(view) {}
@@ -2617,8 +2470,9 @@
     }
   };
 
-  struct Table : raw_hash_set<ValuePolicy<Value>, H, std::equal_to<Value>,
-                              std::allocator<Value>> {
+  struct Table
+      : InstantiateRawHashSet<ValuePolicy<Value>, H, std::equal_to<Value>,
+                              std::allocator<Value>>::type {
     using Base = typename Table::raw_hash_set;
     using Base::Base;
   };
@@ -2690,6 +2544,24 @@
   EXPECT_FALSE(node);  // NOLINT(bugprone-use-after-move)
 }
 
+TEST(Nodes, ExtractInsertSmall) {
+  constexpr char k0[] = "Very long string zero.";
+  StringTable t = {{k0, ""}};
+  EXPECT_THAT(t, UnorderedElementsAre(Pair(k0, "")));
+
+  auto node = t.extract(k0);
+  EXPECT_EQ(t.size(), 0);
+  EXPECT_TRUE(node);
+  EXPECT_FALSE(node.empty());
+
+  StringTable t2;
+  StringTable::insert_return_type res = t2.insert(std::move(node));
+  EXPECT_TRUE(res.inserted);
+  EXPECT_THAT(*res.position, Pair(k0, ""));
+  EXPECT_FALSE(res.node);
+  EXPECT_THAT(t2, UnorderedElementsAre(Pair(k0, "")));
+}
+
 TYPED_TEST(SooTest, HintInsert) {
   TypeParam t = {1, 2, 3};
   auto node = t.extract(1);
@@ -2729,7 +2601,7 @@
 // in seed.
 void GenerateIrrelevantSeeds(int cnt) {
   for (int i = cnt % 17; i > 0; --i) {
-    NextSeed();
+    HashtableSize::NextSeed();
   }
 }
 
@@ -2828,12 +2700,12 @@
 
   NonSooIntTable t;
   // Extra simple "regexp" as regexp support is highly varied across platforms.
-  EXPECT_DEATH_IF_SUPPORTED(t.erase(t.end()),
-                            "erase.* called on end.. iterator.");
+  EXPECT_DEATH_IF_SUPPORTED(++t.end(), "operator.* called on end.. iterator.");
   typename NonSooIntTable::iterator iter;
   EXPECT_DEATH_IF_SUPPORTED(
       ++iter, "operator.* called on default-constructed iterator.");
   t.insert(0);
+  t.insert(1);
   iter = t.begin();
   t.erase(iter);
   const char* const kErasedDeathMessage =
@@ -2959,6 +2831,7 @@
   absl::flat_hash_set<const HashtablezInfo*> preexisting_info(10);
   absl::flat_hash_map<size_t, int> observed_checksums(10);
   absl::flat_hash_map<ssize_t, int> reservations(10);
+  absl::flat_hash_map<std::pair<size_t, size_t>, int> hit_misses(10);
 
   start_size += sampler.Iterate([&](const HashtablezInfo& info) {
     preexisting_info.insert(&info);
@@ -2971,6 +2844,8 @@
 
     const bool do_reserve = (i % 10 > 5);
     const bool do_rehash = !do_reserve && (i % 10 > 0);
+    const bool do_first_insert_hit = i % 2 == 0;
+    const bool do_second_insert_hit = i % 4 == 0;
 
     if (do_reserve) {
       // Don't reserve on all tables.
@@ -2978,7 +2853,14 @@
     }
 
     tables.back().insert(1);
+    if (do_first_insert_hit) {
+      tables.back().insert(1);
+      tables.back().insert(1);
+    }
     tables.back().insert(i % 5);
+    if (do_second_insert_hit) {
+      tables.back().insert(i % 5);
+    }
 
     if (do_rehash) {
       // Rehash some other tables.
@@ -2989,9 +2871,11 @@
   end_size += sampler.Iterate([&](const HashtablezInfo& info) {
     ++end_size;
     if (preexisting_info.contains(&info)) return;
-    observed_checksums[info.hashes_bitwise_xor.load(
-        std::memory_order_relaxed)]++;
     reservations[info.max_reserve.load(std::memory_order_relaxed)]++;
+    hit_misses[std::make_pair(
+        info.num_insert_hits.load(std::memory_order_relaxed),
+        info.size.load(std::memory_order_relaxed))]++;
+
     EXPECT_EQ(info.inline_element_size, sizeof(typename TypeParam::value_type));
     EXPECT_EQ(info.key_size, sizeof(typename TypeParam::key_type));
     EXPECT_EQ(info.value_size, sizeof(typename TypeParam::value_type));
@@ -3006,12 +2890,8 @@
   // Expect that we sampled at the requested sampling rate of ~1%.
   EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()),
               0.01, 0.005);
-  EXPECT_EQ(observed_checksums.size(), 5);
-  for (const auto& [_, count] : observed_checksums) {
-    EXPECT_NEAR((100 * count) / static_cast<double>(tables.size()), 0.2, 0.05);
-  }
 
-  EXPECT_EQ(reservations.size(), 10);
+  ASSERT_EQ(reservations.size(), 10);
   for (const auto& [reservation, count] : reservations) {
     EXPECT_GE(reservation, 0);
     EXPECT_LT(reservation, 100);
@@ -3019,6 +2899,21 @@
     EXPECT_NEAR((100 * count) / static_cast<double>(tables.size()), 0.1, 0.05)
         << reservation;
   }
+
+  EXPECT_THAT(hit_misses, testing::SizeIs(6));
+  const double sampled_tables = end_size - start_size;
+  // i % 20: { 1, 11 }
+  EXPECT_NEAR((hit_misses[{1, 1}] / sampled_tables), 0.10, 0.02);
+  // i % 20: { 6 }
+  EXPECT_NEAR((hit_misses[{3, 1}] / sampled_tables), 0.05, 0.02);
+  // i % 20: { 0, 4, 8, 12 }
+  EXPECT_NEAR((hit_misses[{3, 2}] / sampled_tables), 0.20, 0.02);
+  // i % 20: { 2, 10, 14, 18 }
+  EXPECT_NEAR((hit_misses[{2, 2}] / sampled_tables), 0.20, 0.02);
+  // i % 20: { 16 }
+  EXPECT_NEAR((hit_misses[{4, 1}] / sampled_tables), 0.05, 0.02);
+  // i % 20: { 3, 5, 7, 9, 13, 15, 17, 19 }
+  EXPECT_NEAR((hit_misses[{0, 2}] / sampled_tables), 0.40, 0.02);
 }
 
 std::vector<const HashtablezInfo*> SampleSooMutation(
@@ -3644,11 +3539,13 @@
   EXPECT_DEATH_IF_SUPPORTED(void(t1.end() == default_constructed_iter),
                             "Invalid iterator comparison.*default-constructed");
   t1.insert(0);
+  t1.insert(1);
   EXPECT_DEATH_IF_SUPPORTED(void(t1.begin() == t2.end()),
                             "Invalid iterator comparison.*empty hashtable");
   EXPECT_DEATH_IF_SUPPORTED(void(t1.begin() == default_constructed_iter),
                             "Invalid iterator comparison.*default-constructed");
   t2.insert(0);
+  t2.insert(1);
   EXPECT_DEATH_IF_SUPPORTED(void(t1.begin() == t2.end()),
                             "Invalid iterator comparison.*end.. iterator");
   EXPECT_DEATH_IF_SUPPORTED(void(t1.begin() == t2.begin()),
@@ -3687,40 +3584,47 @@
     GTEST_SKIP() << "Only run under NDEBUG: `assert` statements may cause "
                     "redundant hashing.";
   }
+  // When the table is sampled, we need to hash on the first insertion.
+  DisableSampling();
 
   using Table = CountedHashIntTable;
   auto HashCount = [](const Table& t) { return t.hash_function().count; };
   {
     Table t;
+    t.find(0);
     EXPECT_EQ(HashCount(t), 0);
   }
   {
     Table t;
     t.insert(1);
-    EXPECT_EQ(HashCount(t), 1);
+    t.find(1);
+    EXPECT_EQ(HashCount(t), 0);
     t.erase(1);
-    EXPECT_LE(HashCount(t), 2);
+    EXPECT_EQ(HashCount(t), 0);
+    t.insert(1);
+    t.insert(2);
+    EXPECT_EQ(HashCount(t), 2);
   }
   {
     Table t;
     t.insert(3);
-    EXPECT_EQ(HashCount(t), 1);
+    EXPECT_EQ(HashCount(t), 0);
     auto node = t.extract(3);
-    EXPECT_LE(HashCount(t), 2);
+    EXPECT_EQ(HashCount(t), 0);
     t.insert(std::move(node));
-    EXPECT_LE(HashCount(t), 3);
+    EXPECT_EQ(HashCount(t), 0);
   }
   {
     Table t;
     t.emplace(5);
-    EXPECT_EQ(HashCount(t), 1);
+    EXPECT_EQ(HashCount(t), 0);
   }
   {
     Table src;
     src.insert(7);
     Table dst;
     dst.merge(src);
-    EXPECT_EQ(HashCount(dst), 1);
+    EXPECT_EQ(HashCount(dst), 0);
   }
 }
 
@@ -3731,9 +3635,7 @@
   auto fail_if_any = [](const ctrl_t*, void* i) {
     FAIL() << "expected no slots " << **static_cast<SlotType*>(i);
   };
-  container_internal::IterateOverFullSlots(
-      RawHashSetTestOnlyAccess::GetCommon(t), sizeof(SlotType), fail_if_any);
-  for (size_t i = 0; i < 256; ++i) {
+  for (size_t i = 2; i < 256; ++i) {
     t.reserve(i);
     container_internal::IterateOverFullSlots(
         RawHashSetTestOnlyAccess::GetCommon(t), sizeof(SlotType), fail_if_any);
@@ -3745,7 +3647,9 @@
   using SlotType = NonSooIntTableSlotType;
 
   std::vector<int64_t> expected_slots;
-  for (int64_t idx = 0; idx < 128; ++idx) {
+  t.insert(0);
+  expected_slots.push_back(0);
+  for (int64_t idx = 1; idx < 128; ++idx) {
     t.insert(idx);
     expected_slots.push_back(idx);
 
@@ -4226,8 +4130,8 @@
 // 5. Finally we will catch up and go to overflow codepath.
 TEST(Table, GrowExtremelyLargeTable) {
   constexpr size_t kTargetCapacity =
-#if defined(__wasm__) || defined(__asmjs__)
-      NextCapacity(ProbedItem4Bytes::kMaxNewCapacity);  // OOMs on WASM.
+#if defined(__wasm__) || defined(__asmjs__) || defined(__i386__)
+      NextCapacity(ProbedItem4Bytes::kMaxNewCapacity);  // OOMs on WASM, 32-bit.
 #else
       NextCapacity(ProbedItem8Bytes::kMaxNewCapacity);
 #endif
@@ -4240,7 +4144,7 @@
   CommonFields& common = RawHashSetTestOnlyAccess::GetCommon(t);
   // Set 0 seed so that H1 is always 0.
   common.set_no_seed_for_testing();
-  ASSERT_EQ(H1(t.hash_function()(75), common.seed()), 0);
+  ASSERT_EQ(H1(t.hash_function()(75)), 0);
   uint8_t inserted_till = 210;
   for (uint8_t i = 0; i < inserted_till; ++i) {
     t.insert(i);
@@ -4264,6 +4168,16 @@
   EXPECT_EQ(t.capacity(), kTargetCapacity);
 }
 
+// Test that after calling generate_new_seed(), the high bits of the returned
+// seed are non-zero.
+TEST(PerTableSeed, HighBitsAreNonZero) {
+  HashtableSize hs(no_seed_empty_tag_t{});
+  for (int i = 0; i < 100; ++i) {
+    hs.generate_new_seed();
+    ASSERT_GT(hs.seed().seed() >> 16, 0);
+  }
+}
+
 }  // namespace
 }  // namespace container_internal
 ABSL_NAMESPACE_END
diff --git a/absl/container/internal/unordered_map_constructor_test.h b/absl/container/internal/unordered_map_constructor_test.h
index 7e84dc2..1076aea 100644
--- a/absl/container/internal/unordered_map_constructor_test.h
+++ b/absl/container/internal/unordered_map_constructor_test.h
@@ -21,6 +21,7 @@
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/base/config.h"
 #include "absl/container/internal/hash_generator_testing.h"
 #include "absl/container/internal/hash_policy_testing.h"
 
@@ -85,28 +86,8 @@
   EXPECT_GE(m.bucket_count(), 123);
 }
 
-template <typename T>
-struct is_std_unordered_map : std::false_type {};
-
-template <typename... T>
-struct is_std_unordered_map<std::unordered_map<T...>> : std::true_type {};
-
-#if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17)
-using has_cxx14_std_apis = std::true_type;
-#else
-using has_cxx14_std_apis = std::false_type;
-#endif
-
-template <typename T>
-using expect_cxx14_apis =
-    absl::disjunction<absl::negation<is_std_unordered_map<T>>,
-                      has_cxx14_std_apis>;
-
 template <typename TypeParam>
-void BucketCountAllocTest(std::false_type) {}
-
-template <typename TypeParam>
-void BucketCountAllocTest(std::true_type) {
+void BucketCountAllocTest() {
   using A = typename TypeParam::allocator_type;
   A alloc(0);
   TypeParam m(123, alloc);
@@ -117,14 +98,11 @@
 }
 
 TYPED_TEST_P(ConstructorTest, BucketCountAlloc) {
-  BucketCountAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+  BucketCountAllocTest<TypeParam>();
 }
 
 template <typename TypeParam>
-void BucketCountHashAllocTest(std::false_type) {}
-
-template <typename TypeParam>
-void BucketCountHashAllocTest(std::true_type) {
+void BucketCountHashAllocTest() {
   using H = typename TypeParam::hasher;
   using A = typename TypeParam::allocator_type;
   H hasher;
@@ -138,25 +116,11 @@
 }
 
 TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) {
-  BucketCountHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+  BucketCountHashAllocTest<TypeParam>();
 }
 
-#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
-using has_alloc_std_constructors = std::true_type;
-#else
-using has_alloc_std_constructors = std::false_type;
-#endif
-
-template <typename T>
-using expect_alloc_constructors =
-    absl::disjunction<absl::negation<is_std_unordered_map<T>>,
-                      has_alloc_std_constructors>;
-
 template <typename TypeParam>
-void AllocTest(std::false_type) {}
-
-template <typename TypeParam>
-void AllocTest(std::true_type) {
+void AllocTest() {
   using A = typename TypeParam::allocator_type;
   A alloc(0);
   TypeParam m(alloc);
@@ -165,12 +129,10 @@
   EXPECT_THAT(m, ::testing::UnorderedElementsAre());
 }
 
-TYPED_TEST_P(ConstructorTest, Alloc) {
-  AllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
-}
+TYPED_TEST_P(ConstructorTest, Alloc) { AllocTest<TypeParam>(); }
 
 TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashEqualAlloc) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using H = typename TypeParam::hasher;
   using E = typename TypeParam::key_equal;
   using A = typename TypeParam::allocator_type;
@@ -178,8 +140,7 @@
   E equal;
   A alloc(0);
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::UniqueGenerator<T>());
+  std::generate_n(std::back_inserter(values), 10, UniqueGenerator<T>());
   TypeParam m(values.begin(), values.end(), 123, hasher, equal, alloc);
   EXPECT_EQ(m.hash_function(), hasher);
   EXPECT_EQ(m.key_eq(), equal);
@@ -189,16 +150,12 @@
 }
 
 template <typename TypeParam>
-void InputIteratorBucketAllocTest(std::false_type) {}
-
-template <typename TypeParam>
-void InputIteratorBucketAllocTest(std::true_type) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+void InputIteratorBucketAllocTest() {
+  using T = GeneratedType<TypeParam>;
   using A = typename TypeParam::allocator_type;
   A alloc(0);
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::UniqueGenerator<T>());
+  std::generate_n(std::back_inserter(values), 10, UniqueGenerator<T>());
   TypeParam m(values.begin(), values.end(), 123, alloc);
   EXPECT_EQ(m.get_allocator(), alloc);
   EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
@@ -206,22 +163,18 @@
 }
 
 TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) {
-  InputIteratorBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+  InputIteratorBucketAllocTest<TypeParam>();
 }
 
 template <typename TypeParam>
-void InputIteratorBucketHashAllocTest(std::false_type) {}
-
-template <typename TypeParam>
-void InputIteratorBucketHashAllocTest(std::true_type) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+void InputIteratorBucketHashAllocTest() {
+  using T = GeneratedType<TypeParam>;
   using H = typename TypeParam::hasher;
   using A = typename TypeParam::allocator_type;
   H hasher;
   A alloc(0);
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::UniqueGenerator<T>());
+  std::generate_n(std::back_inserter(values), 10, UniqueGenerator<T>());
   TypeParam m(values.begin(), values.end(), 123, hasher, alloc);
   EXPECT_EQ(m.hash_function(), hasher);
   EXPECT_EQ(m.get_allocator(), alloc);
@@ -230,18 +183,18 @@
 }
 
 TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) {
-  InputIteratorBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+  InputIteratorBucketHashAllocTest<TypeParam>();
 }
 
 TYPED_TEST_P(ConstructorTest, CopyConstructor) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using H = typename TypeParam::hasher;
   using E = typename TypeParam::key_equal;
   using A = typename TypeParam::allocator_type;
   H hasher;
   E equal;
   A alloc(0);
-  hash_internal::UniqueGenerator<T> gen;
+  UniqueGenerator<T> gen;
   TypeParam m(123, hasher, equal, alloc);
   for (size_t i = 0; i != 10; ++i) m.insert(gen());
   TypeParam n(m);
@@ -252,18 +205,15 @@
 }
 
 template <typename TypeParam>
-void CopyConstructorAllocTest(std::false_type) {}
-
-template <typename TypeParam>
-void CopyConstructorAllocTest(std::true_type) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+void CopyConstructorAllocTest() {
+  using T = GeneratedType<TypeParam>;
   using H = typename TypeParam::hasher;
   using E = typename TypeParam::key_equal;
   using A = typename TypeParam::allocator_type;
   H hasher;
   E equal;
   A alloc(0);
-  hash_internal::UniqueGenerator<T> gen;
+  UniqueGenerator<T> gen;
   TypeParam m(123, hasher, equal, alloc);
   for (size_t i = 0; i != 10; ++i) m.insert(gen());
   TypeParam n(m, A(11));
@@ -274,20 +224,20 @@
 }
 
 TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) {
-  CopyConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
+  CopyConstructorAllocTest<TypeParam>();
 }
 
 // TODO(alkis): Test non-propagating allocators on copy constructors.
 
 TYPED_TEST_P(ConstructorTest, MoveConstructor) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using H = typename TypeParam::hasher;
   using E = typename TypeParam::key_equal;
   using A = typename TypeParam::allocator_type;
   H hasher;
   E equal;
   A alloc(0);
-  hash_internal::UniqueGenerator<T> gen;
+  UniqueGenerator<T> gen;
   TypeParam m(123, hasher, equal, alloc);
   for (size_t i = 0; i != 10; ++i) m.insert(gen());
   TypeParam t(m);
@@ -299,18 +249,15 @@
 }
 
 template <typename TypeParam>
-void MoveConstructorAllocTest(std::false_type) {}
-
-template <typename TypeParam>
-void MoveConstructorAllocTest(std::true_type) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+void MoveConstructorAllocTest() {
+  using T = GeneratedType<TypeParam>;
   using H = typename TypeParam::hasher;
   using E = typename TypeParam::key_equal;
   using A = typename TypeParam::allocator_type;
   H hasher;
   E equal;
   A alloc(0);
-  hash_internal::UniqueGenerator<T> gen;
+  UniqueGenerator<T> gen;
   TypeParam m(123, hasher, equal, alloc);
   for (size_t i = 0; i != 10; ++i) m.insert(gen());
   TypeParam t(m);
@@ -322,14 +269,14 @@
 }
 
 TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) {
-  MoveConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
+  MoveConstructorAllocTest<TypeParam>();
 }
 
 // TODO(alkis): Test non-propagating allocators on move constructors.
 
 TYPED_TEST_P(ConstructorTest, InitializerListBucketHashEqualAlloc) {
-  using T = hash_internal::GeneratedType<TypeParam>;
-  hash_internal::UniqueGenerator<T> gen;
+  using T = GeneratedType<TypeParam>;
+  UniqueGenerator<T> gen;
   std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
   using H = typename TypeParam::hasher;
   using E = typename TypeParam::key_equal;
@@ -346,13 +293,10 @@
 }
 
 template <typename TypeParam>
-void InitializerListBucketAllocTest(std::false_type) {}
-
-template <typename TypeParam>
-void InitializerListBucketAllocTest(std::true_type) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+void InitializerListBucketAllocTest() {
+  using T = GeneratedType<TypeParam>;
   using A = typename TypeParam::allocator_type;
-  hash_internal::UniqueGenerator<T> gen;
+  UniqueGenerator<T> gen;
   std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
   A alloc(0);
   TypeParam m(values, 123, alloc);
@@ -362,20 +306,17 @@
 }
 
 TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) {
-  InitializerListBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+  InitializerListBucketAllocTest<TypeParam>();
 }
 
 template <typename TypeParam>
-void InitializerListBucketHashAllocTest(std::false_type) {}
-
-template <typename TypeParam>
-void InitializerListBucketHashAllocTest(std::true_type) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+void InitializerListBucketHashAllocTest() {
+  using T = GeneratedType<TypeParam>;
   using H = typename TypeParam::hasher;
   using A = typename TypeParam::allocator_type;
   H hasher;
   A alloc(0);
-  hash_internal::UniqueGenerator<T> gen;
+  UniqueGenerator<T> gen;
   std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
   TypeParam m(values, 123, hasher, alloc);
   EXPECT_EQ(m.hash_function(), hasher);
@@ -385,18 +326,18 @@
 }
 
 TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) {
-  InitializerListBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+  InitializerListBucketHashAllocTest<TypeParam>();
 }
 
 TYPED_TEST_P(ConstructorTest, Assignment) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using H = typename TypeParam::hasher;
   using E = typename TypeParam::key_equal;
   using A = typename TypeParam::allocator_type;
   H hasher;
   E equal;
   A alloc(0);
-  hash_internal::UniqueGenerator<T> gen;
+  UniqueGenerator<T> gen;
   TypeParam m({gen(), gen(), gen()}, 123, hasher, equal, alloc);
   TypeParam n;
   n = m;
@@ -409,14 +350,14 @@
 // (it depends on traits).
 
 TYPED_TEST_P(ConstructorTest, MoveAssignment) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using H = typename TypeParam::hasher;
   using E = typename TypeParam::key_equal;
   using A = typename TypeParam::allocator_type;
   H hasher;
   E equal;
   A alloc(0);
-  hash_internal::UniqueGenerator<T> gen;
+  UniqueGenerator<T> gen;
   TypeParam m({gen(), gen(), gen()}, 123, hasher, equal, alloc);
   TypeParam t(m);
   TypeParam n;
@@ -427,8 +368,8 @@
 }
 
 TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerList) {
-  using T = hash_internal::GeneratedType<TypeParam>;
-  hash_internal::UniqueGenerator<T> gen;
+  using T = GeneratedType<TypeParam>;
+  UniqueGenerator<T> gen;
   std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
   TypeParam m;
   m = values;
@@ -436,8 +377,8 @@
 }
 
 TYPED_TEST_P(ConstructorTest, AssignmentOverwritesExisting) {
-  using T = hash_internal::GeneratedType<TypeParam>;
-  hash_internal::UniqueGenerator<T> gen;
+  using T = GeneratedType<TypeParam>;
+  UniqueGenerator<T> gen;
   TypeParam m({gen(), gen(), gen()});
   TypeParam n({gen()});
   n = m;
@@ -445,8 +386,8 @@
 }
 
 TYPED_TEST_P(ConstructorTest, MoveAssignmentOverwritesExisting) {
-  using T = hash_internal::GeneratedType<TypeParam>;
-  hash_internal::UniqueGenerator<T> gen;
+  using T = GeneratedType<TypeParam>;
+  UniqueGenerator<T> gen;
   TypeParam m({gen(), gen(), gen()});
   TypeParam t(m);
   TypeParam n({gen()});
@@ -455,8 +396,8 @@
 }
 
 TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerListOverwritesExisting) {
-  using T = hash_internal::GeneratedType<TypeParam>;
-  hash_internal::UniqueGenerator<T> gen;
+  using T = GeneratedType<TypeParam>;
+  UniqueGenerator<T> gen;
   std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
   TypeParam m;
   m = values;
@@ -464,8 +405,8 @@
 }
 
 TYPED_TEST_P(ConstructorTest, AssignmentOnSelf) {
-  using T = hash_internal::GeneratedType<TypeParam>;
-  hash_internal::UniqueGenerator<T> gen;
+  using T = GeneratedType<TypeParam>;
+  UniqueGenerator<T> gen;
   std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
   TypeParam m(values);
   m = *&m;  // Avoid -Wself-assign
diff --git a/absl/container/internal/unordered_map_lookup_test.h b/absl/container/internal/unordered_map_lookup_test.h
index 3713cd9..ba037c0 100644
--- a/absl/container/internal/unordered_map_lookup_test.h
+++ b/absl/container/internal/unordered_map_lookup_test.h
@@ -30,10 +30,9 @@
 TYPED_TEST_SUITE_P(LookupTest);
 
 TYPED_TEST_P(LookupTest, At) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(values), 10, Generator<T>());
   TypeParam m(values.begin(), values.end());
   for (const auto& p : values) {
     const auto& val = m.at(p.first);
@@ -42,11 +41,10 @@
 }
 
 TYPED_TEST_P(LookupTest, OperatorBracket) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using V = typename TypeParam::mapped_type;
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(values), 10, Generator<T>());
   TypeParam m;
   for (const auto& p : values) {
     auto& val = m[p.first];
@@ -58,10 +56,9 @@
 }
 
 TYPED_TEST_P(LookupTest, Count) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(values), 10, Generator<T>());
   TypeParam m;
   for (const auto& p : values)
     EXPECT_EQ(0, m.count(p.first)) << ::testing::PrintToString(p.first);
@@ -72,10 +69,9 @@
 
 TYPED_TEST_P(LookupTest, Find) {
   using std::get;
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(values), 10, Generator<T>());
   TypeParam m;
   for (const auto& p : values)
     EXPECT_TRUE(m.end() == m.find(p.first))
@@ -90,10 +86,9 @@
 
 TYPED_TEST_P(LookupTest, EqualRange) {
   using std::get;
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(values), 10, Generator<T>());
   TypeParam m;
   for (const auto& p : values) {
     auto r = m.equal_range(p.first);
diff --git a/absl/container/internal/unordered_map_members_test.h b/absl/container/internal/unordered_map_members_test.h
index 7d48cdb..e9f4979 100644
--- a/absl/container/internal/unordered_map_members_test.h
+++ b/absl/container/internal/unordered_map_members_test.h
@@ -36,10 +36,10 @@
   EXPECT_TRUE((std::is_same<std::pair<const typename TypeParam::key_type,
                                       typename TypeParam::mapped_type>,
                             typename TypeParam::value_type>()));
-  EXPECT_TRUE((absl::conjunction<
-               absl::negation<std::is_signed<typename TypeParam::size_type>>,
+  EXPECT_TRUE((std::conjunction<
+               std::negation<std::is_signed<typename TypeParam::size_type>>,
                std::is_integral<typename TypeParam::size_type>>()));
-  EXPECT_TRUE((absl::conjunction<
+  EXPECT_TRUE((std::conjunction<
                std::is_signed<typename TypeParam::difference_type>,
                std::is_integral<typename TypeParam::difference_type>>()));
   EXPECT_TRUE((std::is_convertible<
diff --git a/absl/container/internal/unordered_map_modifiers_test.h b/absl/container/internal/unordered_map_modifiers_test.h
index 4d9ab30..a0b01a0 100644
--- a/absl/container/internal/unordered_map_modifiers_test.h
+++ b/absl/container/internal/unordered_map_modifiers_test.h
@@ -32,10 +32,9 @@
 TYPED_TEST_SUITE_P(ModifiersTest);
 
 TYPED_TEST_P(ModifiersTest, Clear) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(values), 10, Generator<T>());
   TypeParam m(values.begin(), values.end());
   ASSERT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
   m.clear();
@@ -44,63 +43,61 @@
 }
 
 TYPED_TEST_P(ModifiersTest, Insert) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using V = typename TypeParam::mapped_type;
-  T val = hash_internal::Generator<T>()();
+  T val = Generator<T>()();
   TypeParam m;
   auto p = m.insert(val);
   EXPECT_TRUE(p.second);
   EXPECT_EQ(val, *p.first);
-  T val2 = {val.first, hash_internal::Generator<V>()()};
+  T val2 = {val.first, Generator<V>()()};
   p = m.insert(val2);
   EXPECT_FALSE(p.second);
   EXPECT_EQ(val, *p.first);
 }
 
 TYPED_TEST_P(ModifiersTest, InsertHint) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using V = typename TypeParam::mapped_type;
-  T val = hash_internal::Generator<T>()();
+  T val = Generator<T>()();
   TypeParam m;
   auto it = m.insert(m.end(), val);
   EXPECT_TRUE(it != m.end());
   EXPECT_EQ(val, *it);
-  T val2 = {val.first, hash_internal::Generator<V>()()};
+  T val2 = {val.first, Generator<V>()()};
   it = m.insert(it, val2);
   EXPECT_TRUE(it != m.end());
   EXPECT_EQ(val, *it);
 }
 
 TYPED_TEST_P(ModifiersTest, InsertRange) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(values), 10, Generator<T>());
   TypeParam m;
   m.insert(values.begin(), values.end());
   ASSERT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
 }
 
 TYPED_TEST_P(ModifiersTest, InsertWithinCapacity) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using V = typename TypeParam::mapped_type;
-  T val = hash_internal::Generator<T>()();
+  T val = Generator<T>()();
   TypeParam m;
   m.reserve(10);
   const size_t original_capacity = m.bucket_count();
   m.insert(val);
   EXPECT_EQ(m.bucket_count(), original_capacity);
-  T val2 = {val.first, hash_internal::Generator<V>()()};
+  T val2 = {val.first, Generator<V>()()};
   m.insert(val2);
   EXPECT_EQ(m.bucket_count(), original_capacity);
 }
 
 TYPED_TEST_P(ModifiersTest, InsertRangeWithinCapacity) {
 #if !defined(__GLIBCXX__)
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> base_values;
-  std::generate_n(std::back_inserter(base_values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(base_values), 10, Generator<T>());
   std::vector<T> values;
   while (values.size() != 100) {
     std::copy_n(base_values.begin(), 10, std::back_inserter(values));
@@ -114,106 +111,98 @@
 }
 
 TYPED_TEST_P(ModifiersTest, InsertOrAssign) {
-#ifdef UNORDERED_MAP_CXX17
   using std::get;
   using K = typename TypeParam::key_type;
   using V = typename TypeParam::mapped_type;
-  K k = hash_internal::Generator<K>()();
-  V val = hash_internal::Generator<V>()();
+  K k = Generator<K>()();
+  V val = Generator<V>()();
   TypeParam m;
   auto p = m.insert_or_assign(k, val);
   EXPECT_TRUE(p.second);
   EXPECT_EQ(k, get<0>(*p.first));
   EXPECT_EQ(val, get<1>(*p.first));
-  V val2 = hash_internal::Generator<V>()();
+  V val2 = Generator<V>()();
   p = m.insert_or_assign(k, val2);
   EXPECT_FALSE(p.second);
   EXPECT_EQ(k, get<0>(*p.first));
   EXPECT_EQ(val2, get<1>(*p.first));
-#endif
 }
 
 TYPED_TEST_P(ModifiersTest, InsertOrAssignHint) {
-#ifdef UNORDERED_MAP_CXX17
   using std::get;
   using K = typename TypeParam::key_type;
   using V = typename TypeParam::mapped_type;
-  K k = hash_internal::Generator<K>()();
-  V val = hash_internal::Generator<V>()();
+  K k = Generator<K>()();
+  V val = Generator<V>()();
   TypeParam m;
   auto it = m.insert_or_assign(m.end(), k, val);
   EXPECT_TRUE(it != m.end());
   EXPECT_EQ(k, get<0>(*it));
   EXPECT_EQ(val, get<1>(*it));
-  V val2 = hash_internal::Generator<V>()();
+  V val2 = Generator<V>()();
   it = m.insert_or_assign(it, k, val2);
   EXPECT_EQ(k, get<0>(*it));
   EXPECT_EQ(val2, get<1>(*it));
-#endif
 }
 
 TYPED_TEST_P(ModifiersTest, Emplace) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using V = typename TypeParam::mapped_type;
-  T val = hash_internal::Generator<T>()();
+  T val = Generator<T>()();
   TypeParam m;
   // TODO(alkis): We need a way to run emplace in a more meaningful way. Perhaps
   // with test traits/policy.
   auto p = m.emplace(val);
   EXPECT_TRUE(p.second);
   EXPECT_EQ(val, *p.first);
-  T val2 = {val.first, hash_internal::Generator<V>()()};
+  T val2 = {val.first, Generator<V>()()};
   p = m.emplace(val2);
   EXPECT_FALSE(p.second);
   EXPECT_EQ(val, *p.first);
 }
 
 TYPED_TEST_P(ModifiersTest, EmplaceHint) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using V = typename TypeParam::mapped_type;
-  T val = hash_internal::Generator<T>()();
+  T val = Generator<T>()();
   TypeParam m;
   // TODO(alkis): We need a way to run emplace in a more meaningful way. Perhaps
   // with test traits/policy.
   auto it = m.emplace_hint(m.end(), val);
   EXPECT_EQ(val, *it);
-  T val2 = {val.first, hash_internal::Generator<V>()()};
+  T val2 = {val.first, Generator<V>()()};
   it = m.emplace_hint(it, val2);
   EXPECT_EQ(val, *it);
 }
 
 TYPED_TEST_P(ModifiersTest, TryEmplace) {
-#ifdef UNORDERED_MAP_CXX17
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using V = typename TypeParam::mapped_type;
-  T val = hash_internal::Generator<T>()();
+  T val = Generator<T>()();
   TypeParam m;
   // TODO(alkis): We need a way to run emplace in a more meaningful way. Perhaps
   // with test traits/policy.
   auto p = m.try_emplace(val.first, val.second);
   EXPECT_TRUE(p.second);
   EXPECT_EQ(val, *p.first);
-  T val2 = {val.first, hash_internal::Generator<V>()()};
+  T val2 = {val.first, Generator<V>()()};
   p = m.try_emplace(val2.first, val2.second);
   EXPECT_FALSE(p.second);
   EXPECT_EQ(val, *p.first);
-#endif
 }
 
 TYPED_TEST_P(ModifiersTest, TryEmplaceHint) {
-#ifdef UNORDERED_MAP_CXX17
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using V = typename TypeParam::mapped_type;
-  T val = hash_internal::Generator<T>()();
+  T val = Generator<T>()();
   TypeParam m;
   // TODO(alkis): We need a way to run emplace in a more meaningful way. Perhaps
   // with test traits/policy.
   auto it = m.try_emplace(m.end(), val.first, val.second);
   EXPECT_EQ(val, *it);
-  T val2 = {val.first, hash_internal::Generator<V>()()};
+  T val2 = {val.first, Generator<V>()()};
   it = m.try_emplace(it, val2.first, val2.second);
   EXPECT_EQ(val, *it);
-#endif
 }
 
 template <class V>
@@ -236,11 +225,10 @@
 };
 
 TYPED_TEST_P(ModifiersTest, Erase) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using std::get;
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(values), 10, Generator<T>());
   TypeParam m(values.begin(), values.end());
   ASSERT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
   auto& first = *m.begin();
@@ -255,10 +243,9 @@
 }
 
 TYPED_TEST_P(ModifiersTest, EraseRange) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(values), 10, Generator<T>());
   TypeParam m(values.begin(), values.end());
   ASSERT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
   auto it = m.erase(m.begin(), m.end());
@@ -267,10 +254,9 @@
 }
 
 TYPED_TEST_P(ModifiersTest, EraseKey) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(values), 10, Generator<T>());
   TypeParam m(values.begin(), values.end());
   ASSERT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
   EXPECT_EQ(1, m.erase(values[0].first));
@@ -280,11 +266,11 @@
 }
 
 TYPED_TEST_P(ModifiersTest, Swap) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> v1;
   std::vector<T> v2;
-  std::generate_n(std::back_inserter(v1), 5, hash_internal::Generator<T>());
-  std::generate_n(std::back_inserter(v2), 5, hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(v1), 5, Generator<T>());
+  std::generate_n(std::back_inserter(v2), 5, Generator<T>());
   TypeParam m1(v1.begin(), v1.end());
   TypeParam m2(v2.begin(), v2.end());
   EXPECT_THAT(items(m1), ::testing::UnorderedElementsAreArray(v1));
@@ -327,20 +313,18 @@
 // Test that we do not move from rvalue arguments if an insertion does not
 // happen.
 TYPED_TEST_P(UniquePtrModifiersTest, TryEmplace) {
-#ifdef UNORDERED_MAP_CXX17
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using V = typename TypeParam::mapped_type;
-  T val = hash_internal::Generator<T>()();
+  T val = Generator<T>()();
   TypeParam m;
   auto p = m.try_emplace(val.first, std::move(val.second));
   EXPECT_TRUE(p.second);
   // A moved from std::unique_ptr is guaranteed to be nullptr.
   EXPECT_EQ(val.second, nullptr);
-  T val2 = {val.first, hash_internal::Generator<V>()()};
+  T val2 = {val.first, Generator<V>()()};
   p = m.try_emplace(val2.first, std::move(val2.second));
   EXPECT_FALSE(p.second);
   EXPECT_NE(val2.second, nullptr);
-#endif
 }
 
 REGISTER_TYPED_TEST_SUITE_P(UniquePtrModifiersTest, TryEmplace);
diff --git a/absl/container/internal/unordered_set_constructor_test.h b/absl/container/internal/unordered_set_constructor_test.h
index af1116e..7038a0c 100644
--- a/absl/container/internal/unordered_set_constructor_test.h
+++ b/absl/container/internal/unordered_set_constructor_test.h
@@ -21,6 +21,7 @@
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/base/config.h"
 #include "absl/container/internal/hash_generator_testing.h"
 #include "absl/container/internal/hash_policy_testing.h"
 #include "absl/meta/type_traits.h"
@@ -94,28 +95,8 @@
   EXPECT_GE(cm.bucket_count(), 123);
 }
 
-template <typename T>
-struct is_std_unordered_set : std::false_type {};
-
-template <typename... T>
-struct is_std_unordered_set<std::unordered_set<T...>> : std::true_type {};
-
-#if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17)
-using has_cxx14_std_apis = std::true_type;
-#else
-using has_cxx14_std_apis = std::false_type;
-#endif
-
-template <typename T>
-using expect_cxx14_apis =
-    absl::disjunction<absl::negation<is_std_unordered_set<T>>,
-                      has_cxx14_std_apis>;
-
 template <typename TypeParam>
-void BucketCountAllocTest(std::false_type) {}
-
-template <typename TypeParam>
-void BucketCountAllocTest(std::true_type) {
+void BucketCountAllocTest() {
   using A = typename TypeParam::allocator_type;
   A alloc(0);
   TypeParam m(123, alloc);
@@ -126,14 +107,11 @@
 }
 
 TYPED_TEST_P(ConstructorTest, BucketCountAlloc) {
-  BucketCountAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+  BucketCountAllocTest<TypeParam>();
 }
 
 template <typename TypeParam>
-void BucketCountHashAllocTest(std::false_type) {}
-
-template <typename TypeParam>
-void BucketCountHashAllocTest(std::true_type) {
+void BucketCountHashAllocTest() {
   using H = typename TypeParam::hasher;
   using A = typename TypeParam::allocator_type;
   H hasher;
@@ -147,25 +125,11 @@
 }
 
 TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) {
-  BucketCountHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+  BucketCountHashAllocTest<TypeParam>();
 }
 
-#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
-using has_alloc_std_constructors = std::true_type;
-#else
-using has_alloc_std_constructors = std::false_type;
-#endif
-
-template <typename T>
-using expect_alloc_constructors =
-    absl::disjunction<absl::negation<is_std_unordered_set<T>>,
-                      has_alloc_std_constructors>;
-
 template <typename TypeParam>
-void AllocTest(std::false_type) {}
-
-template <typename TypeParam>
-void AllocTest(std::true_type) {
+void AllocTest() {
   using A = typename TypeParam::allocator_type;
   A alloc(0);
   TypeParam m(alloc);
@@ -174,12 +138,10 @@
   EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
 }
 
-TYPED_TEST_P(ConstructorTest, Alloc) {
-  AllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
-}
+TYPED_TEST_P(ConstructorTest, Alloc) { AllocTest<TypeParam>(); }
 
 TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashEqualAlloc) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using H = typename TypeParam::hasher;
   using E = typename TypeParam::key_equal;
   using A = typename TypeParam::allocator_type;
@@ -187,8 +149,7 @@
   E equal;
   A alloc(0);
   std::vector<T> values;
-  for (size_t i = 0; i != 10; ++i)
-    values.push_back(hash_internal::Generator<T>()());
+  for (size_t i = 0; i != 10; ++i) values.push_back(Generator<T>()());
   TypeParam m(values.begin(), values.end(), 123, hasher, equal, alloc);
   EXPECT_EQ(m.hash_function(), hasher);
   EXPECT_EQ(m.key_eq(), equal);
@@ -198,16 +159,12 @@
 }
 
 template <typename TypeParam>
-void InputIteratorBucketAllocTest(std::false_type) {}
-
-template <typename TypeParam>
-void InputIteratorBucketAllocTest(std::true_type) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+void InputIteratorBucketAllocTest() {
+  using T = GeneratedType<TypeParam>;
   using A = typename TypeParam::allocator_type;
   A alloc(0);
   std::vector<T> values;
-  for (size_t i = 0; i != 10; ++i)
-    values.push_back(hash_internal::Generator<T>()());
+  for (size_t i = 0; i != 10; ++i) values.push_back(Generator<T>()());
   TypeParam m(values.begin(), values.end(), 123, alloc);
   EXPECT_EQ(m.get_allocator(), alloc);
   EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
@@ -215,22 +172,18 @@
 }
 
 TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) {
-  InputIteratorBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+  InputIteratorBucketAllocTest<TypeParam>();
 }
 
 template <typename TypeParam>
-void InputIteratorBucketHashAllocTest(std::false_type) {}
-
-template <typename TypeParam>
-void InputIteratorBucketHashAllocTest(std::true_type) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+void InputIteratorBucketHashAllocTest() {
+  using T = GeneratedType<TypeParam>;
   using H = typename TypeParam::hasher;
   using A = typename TypeParam::allocator_type;
   H hasher;
   A alloc(0);
   std::vector<T> values;
-  for (size_t i = 0; i != 10; ++i)
-    values.push_back(hash_internal::Generator<T>()());
+  for (size_t i = 0; i != 10; ++i) values.push_back(Generator<T>()());
   TypeParam m(values.begin(), values.end(), 123, hasher, alloc);
   EXPECT_EQ(m.hash_function(), hasher);
   EXPECT_EQ(m.get_allocator(), alloc);
@@ -239,11 +192,11 @@
 }
 
 TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) {
-  InputIteratorBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+  InputIteratorBucketHashAllocTest<TypeParam>();
 }
 
 TYPED_TEST_P(ConstructorTest, CopyConstructor) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using H = typename TypeParam::hasher;
   using E = typename TypeParam::key_equal;
   using A = typename TypeParam::allocator_type;
@@ -251,7 +204,7 @@
   E equal;
   A alloc(0);
   TypeParam m(123, hasher, equal, alloc);
-  for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator<T>()());
+  for (size_t i = 0; i != 10; ++i) m.insert(Generator<T>()());
   TypeParam n(m);
   EXPECT_EQ(m.hash_function(), n.hash_function());
   EXPECT_EQ(m.key_eq(), n.key_eq());
@@ -261,11 +214,8 @@
 }
 
 template <typename TypeParam>
-void CopyConstructorAllocTest(std::false_type) {}
-
-template <typename TypeParam>
-void CopyConstructorAllocTest(std::true_type) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+void CopyConstructorAllocTest() {
+  using T = GeneratedType<TypeParam>;
   using H = typename TypeParam::hasher;
   using E = typename TypeParam::key_equal;
   using A = typename TypeParam::allocator_type;
@@ -273,7 +223,7 @@
   E equal;
   A alloc(0);
   TypeParam m(123, hasher, equal, alloc);
-  for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator<T>()());
+  for (size_t i = 0; i != 10; ++i) m.insert(Generator<T>()());
   TypeParam n(m, A(11));
   EXPECT_EQ(m.hash_function(), n.hash_function());
   EXPECT_EQ(m.key_eq(), n.key_eq());
@@ -282,13 +232,13 @@
 }
 
 TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) {
-  CopyConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
+  CopyConstructorAllocTest<TypeParam>();
 }
 
 // TODO(alkis): Test non-propagating allocators on copy constructors.
 
 TYPED_TEST_P(ConstructorTest, MoveConstructor) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using H = typename TypeParam::hasher;
   using E = typename TypeParam::key_equal;
   using A = typename TypeParam::allocator_type;
@@ -296,7 +246,7 @@
   E equal;
   A alloc(0);
   TypeParam m(123, hasher, equal, alloc);
-  for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator<T>()());
+  for (size_t i = 0; i != 10; ++i) m.insert(Generator<T>()());
   TypeParam t(m);
   TypeParam n(std::move(t));
   EXPECT_EQ(m.hash_function(), n.hash_function());
@@ -306,11 +256,8 @@
 }
 
 template <typename TypeParam>
-void MoveConstructorAllocTest(std::false_type) {}
-
-template <typename TypeParam>
-void MoveConstructorAllocTest(std::true_type) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+void MoveConstructorAllocTest() {
+  using T = GeneratedType<TypeParam>;
   using H = typename TypeParam::hasher;
   using E = typename TypeParam::key_equal;
   using A = typename TypeParam::allocator_type;
@@ -318,7 +265,7 @@
   E equal;
   A alloc(0);
   TypeParam m(123, hasher, equal, alloc);
-  for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator<T>()());
+  for (size_t i = 0; i != 10; ++i) m.insert(Generator<T>()());
   TypeParam t(m);
   TypeParam n(std::move(t), A(1));
   EXPECT_EQ(m.hash_function(), n.hash_function());
@@ -328,14 +275,14 @@
 }
 
 TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) {
-  MoveConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
+  MoveConstructorAllocTest<TypeParam>();
 }
 
 // TODO(alkis): Test non-propagating allocators on move constructors.
 
 TYPED_TEST_P(ConstructorTest, InitializerListBucketHashEqualAlloc) {
-  using T = hash_internal::GeneratedType<TypeParam>;
-  hash_internal::Generator<T> gen;
+  using T = GeneratedType<TypeParam>;
+  Generator<T> gen;
   std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
   using H = typename TypeParam::hasher;
   using E = typename TypeParam::key_equal;
@@ -352,13 +299,10 @@
 }
 
 template <typename TypeParam>
-void InitializerListBucketAllocTest(std::false_type) {}
-
-template <typename TypeParam>
-void InitializerListBucketAllocTest(std::true_type) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+void InitializerListBucketAllocTest() {
+  using T = GeneratedType<TypeParam>;
   using A = typename TypeParam::allocator_type;
-  hash_internal::Generator<T> gen;
+  Generator<T> gen;
   std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
   A alloc(0);
   TypeParam m(values, 123, alloc);
@@ -368,20 +312,17 @@
 }
 
 TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) {
-  InitializerListBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+  InitializerListBucketAllocTest<TypeParam>();
 }
 
 template <typename TypeParam>
-void InitializerListBucketHashAllocTest(std::false_type) {}
-
-template <typename TypeParam>
-void InitializerListBucketHashAllocTest(std::true_type) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+void InitializerListBucketHashAllocTest() {
+  using T = GeneratedType<TypeParam>;
   using H = typename TypeParam::hasher;
   using A = typename TypeParam::allocator_type;
   H hasher;
   A alloc(0);
-  hash_internal::Generator<T> gen;
+  Generator<T> gen;
   std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
   TypeParam m(values, 123, hasher, alloc);
   EXPECT_EQ(m.hash_function(), hasher);
@@ -391,18 +332,18 @@
 }
 
 TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) {
-  InitializerListBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+  InitializerListBucketHashAllocTest<TypeParam>();
 }
 
 TYPED_TEST_P(ConstructorTest, CopyAssignment) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using H = typename TypeParam::hasher;
   using E = typename TypeParam::key_equal;
   using A = typename TypeParam::allocator_type;
   H hasher;
   E equal;
   A alloc(0);
-  hash_internal::Generator<T> gen;
+  Generator<T> gen;
   TypeParam m({gen(), gen(), gen()}, 123, hasher, equal, alloc);
   TypeParam n;
   n = m;
@@ -415,14 +356,14 @@
 // (it depends on traits).
 
 TYPED_TEST_P(ConstructorTest, MoveAssignment) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   using H = typename TypeParam::hasher;
   using E = typename TypeParam::key_equal;
   using A = typename TypeParam::allocator_type;
   H hasher;
   E equal;
   A alloc(0);
-  hash_internal::Generator<T> gen;
+  Generator<T> gen;
   TypeParam m({gen(), gen(), gen()}, 123, hasher, equal, alloc);
   TypeParam t(m);
   TypeParam n;
@@ -433,8 +374,8 @@
 }
 
 TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerList) {
-  using T = hash_internal::GeneratedType<TypeParam>;
-  hash_internal::Generator<T> gen;
+  using T = GeneratedType<TypeParam>;
+  Generator<T> gen;
   std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
   TypeParam m;
   m = values;
@@ -442,8 +383,8 @@
 }
 
 TYPED_TEST_P(ConstructorTest, AssignmentOverwritesExisting) {
-  using T = hash_internal::GeneratedType<TypeParam>;
-  hash_internal::Generator<T> gen;
+  using T = GeneratedType<TypeParam>;
+  Generator<T> gen;
   TypeParam m({gen(), gen(), gen()});
   TypeParam n({gen()});
   n = m;
@@ -451,8 +392,8 @@
 }
 
 TYPED_TEST_P(ConstructorTest, MoveAssignmentOverwritesExisting) {
-  using T = hash_internal::GeneratedType<TypeParam>;
-  hash_internal::Generator<T> gen;
+  using T = GeneratedType<TypeParam>;
+  Generator<T> gen;
   TypeParam m({gen(), gen(), gen()});
   TypeParam t(m);
   TypeParam n({gen()});
@@ -461,8 +402,8 @@
 }
 
 TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerListOverwritesExisting) {
-  using T = hash_internal::GeneratedType<TypeParam>;
-  hash_internal::Generator<T> gen;
+  using T = GeneratedType<TypeParam>;
+  Generator<T> gen;
   std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
   TypeParam m;
   m = values;
@@ -470,8 +411,8 @@
 }
 
 TYPED_TEST_P(ConstructorTest, AssignmentOnSelf) {
-  using T = hash_internal::GeneratedType<TypeParam>;
-  hash_internal::Generator<T> gen;
+  using T = GeneratedType<TypeParam>;
+  Generator<T> gen;
   std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
   TypeParam m(values);
   m = *&m;  // Avoid -Wself-assign.
diff --git a/absl/container/internal/unordered_set_lookup_test.h b/absl/container/internal/unordered_set_lookup_test.h
index b35f766..dc63118 100644
--- a/absl/container/internal/unordered_set_lookup_test.h
+++ b/absl/container/internal/unordered_set_lookup_test.h
@@ -30,10 +30,9 @@
 TYPED_TEST_SUITE_P(LookupTest);
 
 TYPED_TEST_P(LookupTest, Count) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(values), 10, Generator<T>());
   TypeParam m;
   for (const auto& v : values)
     EXPECT_EQ(0, m.count(v)) << ::testing::PrintToString(v);
@@ -43,10 +42,9 @@
 }
 
 TYPED_TEST_P(LookupTest, Find) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(values), 10, Generator<T>());
   TypeParam m;
   for (const auto& v : values)
     EXPECT_TRUE(m.end() == m.find(v)) << ::testing::PrintToString(v);
@@ -65,10 +63,9 @@
 }
 
 TYPED_TEST_P(LookupTest, EqualRange) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(values), 10, Generator<T>());
   TypeParam m;
   for (const auto& v : values) {
     auto r = m.equal_range(v);
diff --git a/absl/container/internal/unordered_set_members_test.h b/absl/container/internal/unordered_set_members_test.h
index 4c5e104..b416fef 100644
--- a/absl/container/internal/unordered_set_members_test.h
+++ b/absl/container/internal/unordered_set_members_test.h
@@ -35,10 +35,10 @@
 TYPED_TEST_P(MembersTest, Typedefs) {
   EXPECT_TRUE((std::is_same<typename TypeParam::key_type,
                             typename TypeParam::value_type>()));
-  EXPECT_TRUE((absl::conjunction<
-               absl::negation<std::is_signed<typename TypeParam::size_type>>,
+  EXPECT_TRUE((std::conjunction<
+               std::negation<std::is_signed<typename TypeParam::size_type>>,
                std::is_integral<typename TypeParam::size_type>>()));
-  EXPECT_TRUE((absl::conjunction<
+  EXPECT_TRUE((std::conjunction<
                std::is_signed<typename TypeParam::difference_type>,
                std::is_integral<typename TypeParam::difference_type>>()));
   EXPECT_TRUE((std::is_convertible<
diff --git a/absl/container/internal/unordered_set_modifiers_test.h b/absl/container/internal/unordered_set_modifiers_test.h
index d8864bb..b647642 100644
--- a/absl/container/internal/unordered_set_modifiers_test.h
+++ b/absl/container/internal/unordered_set_modifiers_test.h
@@ -30,10 +30,9 @@
 TYPED_TEST_SUITE_P(ModifiersTest);
 
 TYPED_TEST_P(ModifiersTest, Clear) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(values), 10, Generator<T>());
   TypeParam m(values.begin(), values.end());
   ASSERT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
   m.clear();
@@ -42,8 +41,8 @@
 }
 
 TYPED_TEST_P(ModifiersTest, Insert) {
-  using T = hash_internal::GeneratedType<TypeParam>;
-  T val = hash_internal::Generator<T>()();
+  using T = GeneratedType<TypeParam>;
+  T val = Generator<T>()();
   TypeParam m;
   auto p = m.insert(val);
   EXPECT_TRUE(p.second);
@@ -53,8 +52,8 @@
 }
 
 TYPED_TEST_P(ModifiersTest, InsertHint) {
-  using T = hash_internal::GeneratedType<TypeParam>;
-  T val = hash_internal::Generator<T>()();
+  using T = GeneratedType<TypeParam>;
+  T val = Generator<T>()();
   TypeParam m;
   auto it = m.insert(m.end(), val);
   EXPECT_TRUE(it != m.end());
@@ -65,18 +64,17 @@
 }
 
 TYPED_TEST_P(ModifiersTest, InsertRange) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(values), 10, Generator<T>());
   TypeParam m;
   m.insert(values.begin(), values.end());
   ASSERT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
 }
 
 TYPED_TEST_P(ModifiersTest, InsertWithinCapacity) {
-  using T = hash_internal::GeneratedType<TypeParam>;
-  T val = hash_internal::Generator<T>()();
+  using T = GeneratedType<TypeParam>;
+  T val = Generator<T>()();
   TypeParam m;
   m.reserve(10);
   const size_t original_capacity = m.bucket_count();
@@ -88,10 +86,9 @@
 
 TYPED_TEST_P(ModifiersTest, InsertRangeWithinCapacity) {
 #if !defined(__GLIBCXX__)
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> base_values;
-  std::generate_n(std::back_inserter(base_values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(base_values), 10, Generator<T>());
   std::vector<T> values;
   while (values.size() != 100) {
     values.insert(values.end(), base_values.begin(), base_values.end());
@@ -105,8 +102,8 @@
 }
 
 TYPED_TEST_P(ModifiersTest, Emplace) {
-  using T = hash_internal::GeneratedType<TypeParam>;
-  T val = hash_internal::Generator<T>()();
+  using T = GeneratedType<TypeParam>;
+  T val = Generator<T>()();
   TypeParam m;
   // TODO(alkis): We need a way to run emplace in a more meaningful way. Perhaps
   // with test traits/policy.
@@ -119,8 +116,8 @@
 }
 
 TYPED_TEST_P(ModifiersTest, EmplaceHint) {
-  using T = hash_internal::GeneratedType<TypeParam>;
-  T val = hash_internal::Generator<T>()();
+  using T = GeneratedType<TypeParam>;
+  T val = Generator<T>()();
   TypeParam m;
   // TODO(alkis): We need a way to run emplace in a more meaningful way. Perhaps
   // with test traits/policy.
@@ -150,10 +147,9 @@
 };
 
 TYPED_TEST_P(ModifiersTest, Erase) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(values), 10, Generator<T>());
   TypeParam m(values.begin(), values.end());
   ASSERT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
   std::vector<T> values2;
@@ -167,10 +163,9 @@
 }
 
 TYPED_TEST_P(ModifiersTest, EraseRange) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(values), 10, Generator<T>());
   TypeParam m(values.begin(), values.end());
   ASSERT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
   auto it = m.erase(m.begin(), m.end());
@@ -179,10 +174,9 @@
 }
 
 TYPED_TEST_P(ModifiersTest, EraseKey) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> values;
-  std::generate_n(std::back_inserter(values), 10,
-                  hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(values), 10, Generator<T>());
   TypeParam m(values.begin(), values.end());
   ASSERT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
   EXPECT_EQ(1, m.erase(values[0]));
@@ -192,11 +186,11 @@
 }
 
 TYPED_TEST_P(ModifiersTest, Swap) {
-  using T = hash_internal::GeneratedType<TypeParam>;
+  using T = GeneratedType<TypeParam>;
   std::vector<T> v1;
   std::vector<T> v2;
-  std::generate_n(std::back_inserter(v1), 5, hash_internal::Generator<T>());
-  std::generate_n(std::back_inserter(v2), 5, hash_internal::Generator<T>());
+  std::generate_n(std::back_inserter(v1), 5, Generator<T>());
+  std::generate_n(std::back_inserter(v2), 5, Generator<T>());
   TypeParam m1(v1.begin(), v1.end());
   TypeParam m2(v2.begin(), v2.end());
   EXPECT_THAT(keys(m1), ::testing::UnorderedElementsAreArray(v1));
diff --git a/absl/container/linked_hash_map.h b/absl/container/linked_hash_map.h
new file mode 100644
index 0000000..e42a1f7
--- /dev/null
+++ b/absl/container/linked_hash_map.h
@@ -0,0 +1,666 @@
+// Copyright 2025 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: linked_hash_map.h
+// -----------------------------------------------------------------------------
+//
+// This is a simple insertion-ordered map. It provides O(1) amortized
+// insertions and lookups, as well as iteration over the map in the insertion
+// order.
+//
+// This class is thread-compatible.
+//
+// Iterators point into the list and should be stable in the face of
+// mutations, except for an iterator pointing to an element that was just
+// deleted.
+//
+// This class supports heterogeneous lookups.
+
+#ifndef ABSL_CONTAINER_LINKED_HASH_MAP_H_
+#define ABSL_CONTAINER_LINKED_HASH_MAP_H_
+
+#include <cassert>
+#include <cstddef>
+#include <initializer_list>
+#include <list>
+#include <memory>
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/base/optimization.h"
+#include "absl/container/flat_hash_set.h"
+#include "absl/container/internal/common.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+template <typename Key, typename Value,
+          typename KeyHash = typename absl::flat_hash_set<Key>::hasher,
+          typename KeyEq =
+              typename absl::flat_hash_set<Key, KeyHash>::key_equal,
+          typename Alloc = std::allocator<std::pair<const Key, Value>>>
+class linked_hash_map {
+  using KeyArgImpl = absl::container_internal::KeyArg<
+      absl::container_internal::IsTransparent<KeyEq>::value &&
+      absl::container_internal::IsTransparent<KeyHash>::value>;
+
+ public:
+  using key_type = Key;
+  using mapped_type = Value;
+  using hasher = KeyHash;
+  using key_equal = KeyEq;
+  using value_type = std::pair<const key_type, mapped_type>;
+  using allocator_type = Alloc;
+  using difference_type = ptrdiff_t;
+
+ private:
+  template <class K>
+  using key_arg = typename KeyArgImpl::template type<K, key_type>;
+
+  using ListType = std::list<value_type, Alloc>;
+
+  template <class Fn>
+  class Wrapped {
+    template <typename K>
+    static const K& ToKey(const K& k) {
+      return k;
+    }
+    static const key_type& ToKey(typename ListType::const_iterator it) {
+      return it->first;
+    }
+    static const key_type& ToKey(typename ListType::iterator it) {
+      return it->first;
+    }
+
+    Fn fn_;
+
+    friend linked_hash_map;
+
+   public:
+    using is_transparent = void;
+
+    Wrapped() = default;
+    explicit Wrapped(Fn fn) : fn_(std::move(fn)) {}
+
+    template <class... Args>
+    auto operator()(Args&&... args) const
+        -> decltype(this->fn_(ToKey(args)...)) {
+      return fn_(ToKey(args)...);
+    }
+  };
+  using SetType =
+      absl::flat_hash_set<typename ListType::iterator, Wrapped<hasher>,
+                          Wrapped<key_equal>, Alloc>;
+
+  class NodeHandle {
+   public:
+    using key_type = linked_hash_map::key_type;
+    using mapped_type = linked_hash_map::mapped_type;
+    using allocator_type = linked_hash_map::allocator_type;
+
+    constexpr NodeHandle() noexcept = default;
+    NodeHandle(NodeHandle&& nh) noexcept = default;
+    ~NodeHandle() = default;
+    NodeHandle& operator=(NodeHandle&& node) noexcept = default;
+    bool empty() const noexcept { return list_.empty(); }
+    explicit operator bool() const noexcept { return !empty(); }
+    allocator_type get_allocator() const { return list_.get_allocator(); }
+    const key_type& key() const { return list_.front().first; }
+    mapped_type& mapped() { return list_.front().second; }
+    void swap(NodeHandle& nh) noexcept { list_.swap(nh.list_); }
+
+   private:
+    friend linked_hash_map;
+
+    explicit NodeHandle(ListType list) : list_(std::move(list)) {}
+    ListType list_;
+  };
+
+  template <class Iterator, class NodeType>
+  struct InsertReturnType {
+    Iterator position;
+    bool inserted;
+    NodeType node;
+  };
+
+ public:
+  using iterator = typename ListType::iterator;
+  using const_iterator = typename ListType::const_iterator;
+  using reverse_iterator = typename ListType::reverse_iterator;
+  using const_reverse_iterator = typename ListType::const_reverse_iterator;
+  using reference = typename ListType::reference;
+  using const_reference = typename ListType::const_reference;
+  using size_type = typename ListType::size_type;
+  using pointer = typename std::allocator_traits<allocator_type>::pointer;
+  using const_pointer =
+      typename std::allocator_traits<allocator_type>::const_pointer;
+  using node_type = NodeHandle;
+  using insert_return_type = InsertReturnType<iterator, node_type>;
+
+  linked_hash_map() {}
+
+  explicit linked_hash_map(size_t bucket_count, const hasher& hash = hasher(),
+                           const key_equal& eq = key_equal(),
+                           const allocator_type& alloc = allocator_type())
+      : set_(bucket_count, Wrapped<hasher>(hash), Wrapped<key_equal>(eq),
+             alloc),
+        list_(alloc) {}
+
+  linked_hash_map(size_t bucket_count, const hasher& hash,
+                  const allocator_type& alloc)
+      : linked_hash_map(bucket_count, hash, key_equal(), alloc) {}
+
+  linked_hash_map(size_t bucket_count, const allocator_type& alloc)
+      : linked_hash_map(bucket_count, hasher(), key_equal(), alloc) {}
+
+  explicit linked_hash_map(const allocator_type& alloc)
+      : linked_hash_map(0, hasher(), key_equal(), alloc) {}
+
+  template <class InputIt>
+  linked_hash_map(InputIt first, InputIt last, size_t bucket_count = 0,
+                  const hasher& hash = hasher(),
+                  const key_equal& eq = key_equal(),
+                  const allocator_type& alloc = allocator_type())
+      : linked_hash_map(bucket_count, hash, eq, alloc) {
+    insert(first, last);
+  }
+
+  template <class InputIt>
+  linked_hash_map(InputIt first, InputIt last, size_t bucket_count,
+                  const hasher& hash, const allocator_type& alloc)
+      : linked_hash_map(first, last, bucket_count, hash, key_equal(), alloc) {}
+
+  template <class InputIt>
+  linked_hash_map(InputIt first, InputIt last, size_t bucket_count,
+                  const allocator_type& alloc)
+      : linked_hash_map(first, last, bucket_count, hasher(), key_equal(),
+                        alloc) {}
+
+  template <class InputIt>
+  linked_hash_map(InputIt first, InputIt last, const allocator_type& alloc)
+      : linked_hash_map(first, last, /*bucket_count=*/0, hasher(), key_equal(),
+                        alloc) {}
+
+  linked_hash_map(std::initializer_list<value_type> init,
+                  size_t bucket_count = 0, const hasher& hash = hasher(),
+                  const key_equal& eq = key_equal(),
+                  const allocator_type& alloc = allocator_type())
+      : linked_hash_map(init.begin(), init.end(), bucket_count, hash, eq,
+                        alloc) {}
+
+  linked_hash_map(std::initializer_list<value_type> init, size_t bucket_count,
+                  const hasher& hash, const allocator_type& alloc)
+      : linked_hash_map(init, bucket_count, hash, key_equal(), alloc) {}
+
+  linked_hash_map(std::initializer_list<value_type> init, size_t bucket_count,
+                  const allocator_type& alloc)
+      : linked_hash_map(init, bucket_count, hasher(), key_equal(), alloc) {}
+
+  linked_hash_map(std::initializer_list<value_type> init,
+                  const allocator_type& alloc)
+      : linked_hash_map(init, /*bucket_count=*/0, hasher(), key_equal(),
+                        alloc) {}
+
+  linked_hash_map(const linked_hash_map& other)
+      : linked_hash_map(other.bucket_count(), other.hash_function(),
+                        other.key_eq(), other.get_allocator()) {
+    CopyFrom(other);
+  }
+
+  linked_hash_map(const linked_hash_map& other, const allocator_type& alloc)
+      : linked_hash_map(other.bucket_count(), other.hash_function(),
+                        other.key_eq(), alloc) {
+    CopyFrom(other);
+  }
+
+  linked_hash_map(linked_hash_map&& other) noexcept
+      : set_(std::move(other.set_)), list_(std::move(other.list_)) {
+    // Since the list and set must agree for other to end up "valid",
+    // explicitly clear them.
+    other.set_.clear();
+    other.list_.clear();
+  }
+
+  linked_hash_map(linked_hash_map&& other, const allocator_type& alloc)
+      : linked_hash_map(0, other.hash_function(), other.key_eq(), alloc) {
+    if (get_allocator() == other.get_allocator()) {
+      *this = std::move(other);
+    } else {
+      CopyFrom(std::move(other));
+    }
+  }
+
+  linked_hash_map& operator=(const linked_hash_map& other) {
+    if (this != &other) {
+      // Make a new set, with other's hash/eq/alloc.
+      set_ = SetType(other.bucket_count(), other.set_.hash_function(),
+                     other.set_.key_eq(), other.get_allocator());
+      // Copy the list, with other's allocator.
+      list_ = ListType(other.get_allocator());
+      CopyFrom(other);
+    }
+    return *this;
+  }
+
+  linked_hash_map& operator=(linked_hash_map&& other) noexcept {
+    if (this != &other) {
+      // underlying containers will handle progagate_on_container_move details
+      set_ = std::move(other.set_);
+      list_ = std::move(other.list_);
+      other.set_.clear();
+      other.list_.clear();
+    }
+    return *this;
+  }
+
+  linked_hash_map& operator=(std::initializer_list<value_type> values) {
+    clear();
+    insert(values.begin(), values.end());
+    return *this;
+  }
+
+  // Derive size_ from set_, as list::size might be O(N).
+  size_type size() const { return set_.size(); }
+  size_type max_size() const noexcept { return ~size_type{}; }
+  bool empty() const { return set_.empty(); }
+
+  // Iteration is list-like, in insertion order.
+  // These are all forwarded.
+  iterator begin() { return list_.begin(); }
+  iterator end() { return list_.end(); }
+  const_iterator begin() const { return list_.begin(); }
+  const_iterator end() const { return list_.end(); }
+  const_iterator cbegin() const { return list_.cbegin(); }
+  const_iterator cend() const { return list_.cend(); }
+  reverse_iterator rbegin() { return list_.rbegin(); }
+  reverse_iterator rend() { return list_.rend(); }
+  const_reverse_iterator rbegin() const { return list_.rbegin(); }
+  const_reverse_iterator rend() const { return list_.rend(); }
+  const_reverse_iterator crbegin() const { return list_.crbegin(); }
+  const_reverse_iterator crend() const { return list_.crend(); }
+  reference front() { return list_.front(); }
+  reference back() { return list_.back(); }
+  const_reference front() const { return list_.front(); }
+  const_reference back() const { return list_.back(); }
+
+  void pop_front() { erase(begin()); }
+  void pop_back() { erase(std::prev(end())); }
+
+  ABSL_ATTRIBUTE_REINITIALIZES void clear() {
+    set_.clear();
+    list_.clear();
+  }
+
+  void reserve(size_t n) { set_.reserve(n); }
+  size_t capacity() const { return set_.capacity(); }
+  size_t bucket_count() const { return set_.bucket_count(); }
+  float load_factor() const { return set_.load_factor(); }
+
+  hasher hash_function() const { return set_.hash_function().fn_; }
+  key_equal key_eq() const { return set_.key_eq().fn_; }
+  allocator_type get_allocator() const { return list_.get_allocator(); }
+
+  template <class K = key_type>
+  size_type erase(const key_arg<K>& key) {
+    auto found = set_.find(key);
+    if (found == set_.end()) return 0;
+    auto list_it = *found;
+    // Erase set entry first since it refers to the list element.
+    set_.erase(found);
+    list_.erase(list_it);
+    return 1;
+  }
+
+  iterator erase(const_iterator position) {
+    auto found = set_.find(position);
+    assert(*found == position);
+    set_.erase(found);
+    return list_.erase(position);
+  }
+
+  iterator erase(iterator position) {
+    return erase(static_cast<const_iterator>(position));
+  }
+
+  iterator erase(iterator first, iterator last) {
+    while (first != last) first = erase(first);
+    return first;
+  }
+
+  iterator erase(const_iterator first, const_iterator last) {
+    while (first != last) first = erase(first);
+    if (first == end()) return end();
+    return *set_.find(first);
+  }
+
+  template <class K = key_type>
+  iterator find(const key_arg<K>& key) {
+    auto found = set_.find(key);
+    if (found == set_.end()) return end();
+    return *found;
+  }
+
+  template <class K = key_type>
+  const_iterator find(const key_arg<K>& key) const {
+    auto found = set_.find(key);
+    if (found == set_.end()) return end();
+    return *found;
+  }
+
+  template <class K = key_type>
+  size_type count(const key_arg<K>& key) const {
+    return contains(key) ? 1 : 0;
+  }
+  template <class K = key_type>
+  bool contains(const key_arg<K>& key) const {
+    return set_.contains(key);
+  }
+
+  template <class K = key_type>
+  mapped_type& at(const key_arg<K>& key) {
+    auto it = find(key);
+    if (ABSL_PREDICT_FALSE(it == end())) {
+      absl::base_internal::ThrowStdOutOfRange("absl::linked_hash_map::at");
+    }
+    return it->second;
+  }
+
+  template <class K = key_type>
+  const mapped_type& at(const key_arg<K>& key) const {
+    return const_cast<linked_hash_map*>(this)->at(key);
+  }
+
+  template <class K = key_type>
+  std::pair<iterator, iterator> equal_range(const key_arg<K>& key) {
+    auto iter = set_.find(key);
+    if (iter == set_.end()) return {end(), end()};
+    return {*iter, std::next(*iter)};
+  }
+
+  template <class K = key_type>
+  std::pair<const_iterator, const_iterator> equal_range(
+      const key_arg<K>& key) const {
+    auto iter = set_.find(key);
+    if (iter == set_.end()) return {end(), end()};
+    return {*iter, std::next(*iter)};
+  }
+
+  template <class K = key_type>
+  mapped_type& operator[](const key_arg<K>& key) {
+    return LazyEmplaceInternal(key).first->second;
+  }
+
+  template <class K = key_type, K* = nullptr>
+  mapped_type& operator[](key_arg<K>&& key) {
+    return LazyEmplaceInternal(std::forward<key_arg<K>>(key)).first->second;
+  }
+
+  std::pair<iterator, bool> insert(const value_type& v) {
+    return InsertInternal(v);
+  }
+  std::pair<iterator, bool> insert(value_type&& v) {
+    return InsertInternal(std::move(v));
+  }
+
+  iterator insert(const_iterator, const value_type& v) {
+    return insert(v).first;
+  }
+  iterator insert(const_iterator, value_type&& v) {
+    return insert(std::move(v)).first;
+  }
+
+  void insert(std::initializer_list<value_type> ilist) {
+    insert(ilist.begin(), ilist.end());
+  }
+
+  template <class InputIt>
+  void insert(InputIt first, InputIt last) {
+    for (; first != last; ++first) insert(*first);
+  }
+
+  insert_return_type insert(node_type&& node) {
+    if (node.empty()) return {end(), false, node_type()};
+    if (auto [set_itr, inserted] = set_.emplace(node.list_.begin()); inserted) {
+      list_.splice(list_.end(), node.list_);
+      return {*set_itr, true, node_type()};
+    } else {
+      return {*set_itr, false, std::move(node)};
+    }
+  }
+
+  iterator insert(const_iterator, node_type&& node) {
+    return insert(std::move(node)).first;
+  }
+
+  // The last two template parameters ensure that both arguments are rvalues
+  // (lvalue arguments are handled by the overloads below). This is necessary
+  // for supporting bitfield arguments.
+  //
+  //   union { int n : 1; };
+  //   linked_hash_map<int, int> m;
+  //   m.insert_or_assign(n, n);
+  template <class K = key_type, class V = mapped_type, K* = nullptr,
+            V* = nullptr>
+  std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, V&& v) {
+    return InsertOrAssignInternal(std::forward<key_arg<K>>(k),
+                                  std::forward<V>(v));
+  }
+
+  template <class K = key_type, class V = mapped_type, K* = nullptr>
+  std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, const V& v) {
+    return InsertOrAssignInternal(std::forward<key_arg<K>>(k), v);
+  }
+
+  template <class K = key_type, class V = mapped_type, V* = nullptr>
+  std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, V&& v) {
+    return InsertOrAssignInternal(k, std::forward<V>(v));
+  }
+
+  template <class K = key_type, class V = mapped_type>
+  std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, const V& v) {
+    return InsertOrAssignInternal(k, v);
+  }
+
+  template <class K = key_type, class V = mapped_type, K* = nullptr,
+            V* = nullptr>
+  iterator insert_or_assign(const_iterator, key_arg<K>&& k, V&& v) {
+    return insert_or_assign(std::forward<key_arg<K>>(k), std::forward<V>(v))
+        .first;
+  }
+
+  template <class K = key_type, class V = mapped_type, K* = nullptr>
+  iterator insert_or_assign(const_iterator, key_arg<K>&& k, const V& v) {
+    return insert_or_assign(std::forward<key_arg<K>>(k), v).first;
+  }
+
+  template <class K = key_type, class V = mapped_type, V* = nullptr>
+  iterator insert_or_assign(const_iterator, const key_arg<K>& k, V&& v) {
+    return insert_or_assign(k, std::forward<V>(v)).first;
+  }
+
+  template <class K = key_type, class V = mapped_type>
+  iterator insert_or_assign(const_iterator, const key_arg<K>& k, const V& v) {
+    return insert_or_assign(k, v).first;
+  }
+
+  template <typename... Args>
+  std::pair<iterator, bool> emplace(Args&&... args) {
+    ListType node_donor;
+    auto list_iter =
+        node_donor.emplace(node_donor.end(), std::forward<Args>(args)...);
+    auto ins = set_.insert(list_iter);
+    if (!ins.second) return {*ins.first, false};
+    list_.splice(list_.end(), node_donor, list_iter);
+    return {list_iter, true};
+  }
+
+  template <class K = key_type, class... Args, K* = nullptr>
+  iterator try_emplace(const_iterator, key_arg<K>&& k, Args&&... args) {
+    return try_emplace(std::forward<key_arg<K>>(k), std::forward<Args>(args)...)
+        .first;
+  }
+
+  template <typename... Args>
+  iterator emplace_hint(const_iterator, Args&&... args) {
+    return emplace(std::forward<Args>(args)...).first;
+  }
+
+  template <class K = key_type, typename... Args, K* = nullptr>
+  std::pair<iterator, bool> try_emplace(key_arg<K>&& key, Args&&... args) {
+    return LazyEmplaceInternal(std::forward<key_arg<K>>(key),
+                               std::forward<Args>(args)...);
+  }
+
+  template <typename H, typename E>
+  void merge(linked_hash_map<Key, Value, H, E, Alloc>& src) {
+    auto itr = src.list_.begin();
+    while (itr != src.list_.end()) {
+      if (contains(itr->first)) {
+        ++itr;
+      } else {
+        insert(src.extract(itr++));
+      }
+    }
+  }
+
+  template <typename H, typename E>
+  void merge(linked_hash_map<Key, Value, H, E, Alloc>&& src) {
+    merge(src);
+  }
+
+  node_type extract(const_iterator position) {
+    set_.erase(position->first);
+    ListType extracted_node_list;
+    extracted_node_list.splice(extracted_node_list.end(), list_, position);
+    return node_type(std::move(extracted_node_list));
+  }
+
+  template <class K = key_type,
+            std::enable_if_t<!std::is_same_v<K, iterator>, int> = 0>
+  node_type extract(const key_arg<K>& key) {
+    auto node = set_.extract(key);
+    if (node.empty()) return node_type();
+    ListType extracted_node_list;
+    extracted_node_list.splice(extracted_node_list.end(), list_, node.value());
+    return node_type(std::move(extracted_node_list));
+  }
+
+  template <typename H, typename E>
+  void splice(const_iterator, linked_hash_map<Key, Value, H, E, Alloc>& list,
+              const_iterator it) {
+    if (&list == this) {
+      list_.splice(list_.end(), list.list_, it);
+    } else {
+      insert(list.extract(it));
+    }
+  }
+
+  template <class K = key_type, typename... Args>
+  std::pair<iterator, bool> try_emplace(const key_arg<K>& key, Args&&... args) {
+    return LazyEmplaceInternal(key, std::forward<Args>(args)...);
+  }
+
+  template <class K = key_type, typename... Args>
+  iterator try_emplace(const_iterator, const key_arg<K>& key, Args&&... args) {
+    return LazyEmplaceInternal(key, std::forward<Args>(args)...).first;
+  }
+
+  void swap(linked_hash_map& other) noexcept {
+    using std::swap;
+    swap(set_, other.set_);
+    swap(list_, other.list_);
+  }
+
+  friend bool operator==(const linked_hash_map& a, const linked_hash_map& b) {
+    if (a.size() != b.size()) return false;
+    const linked_hash_map* outer = &a;
+    const linked_hash_map* inner = &b;
+    if (outer->capacity() > inner->capacity()) std::swap(outer, inner);
+    for (const value_type& elem : *outer) {
+      auto it = inner->find(elem.first);
+      if (it == inner->end()) return false;
+      if (it->second != elem.second) return false;
+    }
+
+    return true;
+  }
+
+  friend bool operator!=(const linked_hash_map& a, const linked_hash_map& b) {
+    return !(a == b);
+  }
+
+  void rehash(size_t n) { set_.rehash(n); }
+
+ private:
+  template <typename Other>
+  void CopyFrom(Other&& other) {
+    for (auto& elem : other.list_) {
+      set_.insert(list_.insert(list_.end(), std::move(elem)));
+    }
+    assert(set_.size() == list_.size());
+  }
+
+  template <typename U>
+  std::pair<iterator, bool> InsertInternal(U&& pair) {  // NOLINT(build/c++11)
+    bool constructed = false;
+    auto set_iter = set_.lazy_emplace(pair.first, [&](const auto& ctor) {
+      constructed = true;
+      ctor(list_.emplace(list_.end(), std::forward<U>(pair)));
+    });
+    return {*set_iter, constructed};
+  }
+
+  template <class K, class V>
+  std::pair<iterator, bool> InsertOrAssignInternal(K&& k, V&& v) {
+    auto [it, inserted] =
+        LazyEmplaceInternal(std::forward<K>(k), std::forward<V>(v));
+    if (!inserted) {
+      // NOLINTNEXTLINE(bugprone-use-after-move)
+      it->second = std::forward<V>(v);
+    }
+    return {it, inserted};
+  }
+
+  template <typename K, typename... Args>
+  std::pair<iterator, bool> LazyEmplaceInternal(K&& key, Args&&... args) {
+    bool constructed = false;
+    auto set_iter = set_.lazy_emplace(
+        key, [this, &constructed, &key, &args...](const auto& ctor) {
+          auto list_iter =
+              list_.emplace(list_.end(), std::piecewise_construct,
+                            std::forward_as_tuple(std::forward<K>(key)),
+                            std::forward_as_tuple(std::forward<Args>(args)...));
+          constructed = true;
+          ctor(list_iter);
+        });
+    return {*set_iter, constructed};
+  }
+
+  // The set component, used for speedy lookups.
+  SetType set_;
+
+  // The list component, used for maintaining insertion order.
+  ListType list_;
+};
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_LINKED_HASH_MAP_H_
diff --git a/absl/container/linked_hash_map_benchmark.cc b/absl/container/linked_hash_map_benchmark.cc
new file mode 100644
index 0000000..5a0db38
--- /dev/null
+++ b/absl/container/linked_hash_map_benchmark.cc
@@ -0,0 +1,140 @@
+// Copyright 2025 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 <algorithm>
+#include <cstddef>
+#include <string>
+#include <vector>
+
+#include "absl/container/linked_hash_map.h"
+#include "absl/functional/function_ref.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/string_view.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+struct BenchmarkData {
+  std::vector<std::string> sample;
+  size_t str_bytes = 0;
+  explicit BenchmarkData(int size,
+                         absl::FunctionRef<std::string(int)> factory) {
+    sample.reserve(size);
+    for (int i = 0; i < size; ++i) {
+      sample.push_back(factory(i));
+      str_bytes += sample.back().size();
+    }
+  }
+};
+
+void BenchmarkTryEmplaceStrings(benchmark::State& state,
+                                absl::FunctionRef<std::string(int)> factory) {
+  BenchmarkData data(state.range(0), factory);
+
+  // Make a batch around 1Mi bytes.
+  const size_t batch_size =
+      std::max(size_t{1}, size_t{1000000} / data.str_bytes);
+  std::vector<absl::linked_hash_map<std::string, int>> sets(batch_size);
+
+  while (state.KeepRunningBatch(batch_size)) {
+    state.PauseTiming();
+    for (auto& set : sets) set.clear();
+    state.ResumeTiming();
+    for (auto& set : sets) {
+      for (const auto& str : data.sample) {
+        benchmark::DoNotOptimize(set.try_emplace(str));
+      }
+    }
+  }
+
+  state.SetItemsProcessed(state.iterations() * state.range(0));
+  state.SetBytesProcessed(state.iterations() * data.str_bytes);
+}
+
+void BenchmarkInsertOrAssignStrings(
+    benchmark::State& state, absl::FunctionRef<std::string(int)> factory) {
+  BenchmarkData data(state.range(0), factory);
+
+  // Make a batch around 1Mi bytes.
+  const size_t batch_size = std::max(size_t{1}, 1000000 / data.str_bytes);
+  std::vector<absl::linked_hash_map<std::string, int>> sets(batch_size);
+
+  while (state.KeepRunningBatch(batch_size)) {
+    state.PauseTiming();
+    for (auto& set : sets) set.clear();
+    state.ResumeTiming();
+    for (auto& set : sets) {
+      for (const auto& str : data.sample) {
+        benchmark::DoNotOptimize(set.insert_or_assign(str, 0));
+      }
+    }
+  }
+
+  state.SetItemsProcessed(state.iterations() * state.range(0));
+  state.SetBytesProcessed(state.iterations() * data.str_bytes);
+}
+
+constexpr absl::string_view kFormatShort = "%10d";
+constexpr absl::string_view kFormatLong =
+    "a longer string that exceeds the SSO %10d";
+
+void BM_TryEmplaceShortStrings_Hit(benchmark::State& state) {
+  BenchmarkTryEmplaceStrings(
+      state, [](int i) { return absl::StrFormat(kFormatShort, i); });
+}
+BENCHMARK(BM_TryEmplaceShortStrings_Hit)->Range(1, 1 << 16);
+
+void BM_TryEmplaceLongStrings_Hit(benchmark::State& state) {
+  BenchmarkTryEmplaceStrings(
+      state, [](int i) { return absl::StrFormat(kFormatLong, i); });
+}
+BENCHMARK(BM_TryEmplaceLongStrings_Hit)->Range(1, 1 << 16);
+
+void BM_TryEmplaceShortStrings_Miss(benchmark::State& state) {
+  BenchmarkTryEmplaceStrings(
+      state, [](int i) { return absl::StrFormat(kFormatShort, i % 20); });
+}
+BENCHMARK(BM_TryEmplaceShortStrings_Miss)->Range(1, 1 << 16);
+
+void BM_TryEmplaceLongStrings_Miss(benchmark::State& state) {
+  BenchmarkTryEmplaceStrings(
+      state, [](int i) { return absl::StrFormat(kFormatLong, i % 20); });
+}
+BENCHMARK(BM_TryEmplaceLongStrings_Miss)->Range(1, 1 << 16);
+
+void BM_InsertOrAssignShortStrings_Hit(benchmark::State& state) {
+  BenchmarkInsertOrAssignStrings(
+      state, [](int i) { return absl::StrFormat(kFormatShort, i); });
+}
+BENCHMARK(BM_InsertOrAssignShortStrings_Hit)->Range(1, 1 << 16);
+
+void BM_InsertOrAssignLongStrings_Hit(benchmark::State& state) {
+  BenchmarkInsertOrAssignStrings(
+      state, [](int i) { return absl::StrFormat(kFormatLong, i); });
+}
+BENCHMARK(BM_InsertOrAssignLongStrings_Hit)->Range(1, 1 << 16);
+
+void BM_InsertOrAssignShortStrings_Miss(benchmark::State& state) {
+  BenchmarkInsertOrAssignStrings(
+      state, [](int i) { return absl::StrFormat(kFormatShort, i % 20); });
+}
+BENCHMARK(BM_InsertOrAssignShortStrings_Miss)->Range(1, 1 << 16);
+
+void BM_InsertOrAssignLongStrings_Miss(benchmark::State& state) {
+  BenchmarkInsertOrAssignStrings(
+      state, [](int i) { return absl::StrFormat(kFormatLong, i % 20); });
+}
+BENCHMARK(BM_InsertOrAssignLongStrings_Miss)->Range(1, 1 << 16);
+
+}  // namespace
diff --git a/absl/container/linked_hash_map_test.cc b/absl/container/linked_hash_map_test.cc
new file mode 100644
index 0000000..9f530d7
--- /dev/null
+++ b/absl/container/linked_hash_map_test.cc
@@ -0,0 +1,987 @@
+// Copyright 2025 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/container/linked_hash_map.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/exception_testing.h"
+#include "absl/container/internal/hash_generator_testing.h"
+#include "absl/container/internal/hash_policy_testing.h"
+#include "absl/container/internal/heterogeneous_lookup_testing.h"
+#include "absl/container/internal/test_instance_tracker.h"
+#include "absl/container/internal/unordered_map_constructor_test.h"
+#include "absl/container/internal/unordered_map_lookup_test.h"
+#include "absl/container/internal/unordered_map_members_test.h"
+#include "absl/container/internal/unordered_map_modifiers_test.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+namespace {
+
+using ::testing::ElementsAre;
+using ::testing::Pair;
+using ::testing::Pointee;
+
+template <class K, class V>
+using Map = linked_hash_map<K, V, StatefulTestingHash, StatefulTestingEqual,
+                            Alloc<std::pair<const K, V>>>;
+
+static_assert(!std::is_standard_layout<NonStandardLayout>(), "");
+
+using MapTypes =
+    ::testing::Types<Map<int, int>, Map<std::string, int>,
+                     Map<Enum, std::string>, Map<EnumClass, int>,
+                     Map<int, NonStandardLayout>, Map<NonStandardLayout, int>>;
+
+INSTANTIATE_TYPED_TEST_SUITE_P(LinkedHashMap, ConstructorTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(LinkedHashMap, LookupTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(LinkedHashMap, MembersTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(LinkedHashMap, ModifiersTest, MapTypes);
+
+// Tests that the range constructor works.
+TEST(LinkedHashMapTest, RangeConstruct) {
+  const std::pair<int, int> items[] = {{1, 2}, {2, 3}, {3, 4}};
+  EXPECT_THAT((linked_hash_map<int, int>(std::begin(items), std::end(items))),
+              ElementsAre(Pair(1, 2), Pair(2, 3), Pair(3, 4)));
+}
+
+// Tests that copying works.
+TEST(LinkedHashMapTest, Copy) {
+  linked_hash_map<int, int> m{{2, 12}, {3, 13}};
+  auto copy = m;
+
+  EXPECT_TRUE(copy.contains(2));
+  auto found = copy.find(2);
+  ASSERT_TRUE(found != copy.end());
+  for (auto iter = copy.begin(); iter != copy.end(); ++iter) {
+    if (iter == found) return;
+  }
+  FAIL() << "Copied map's find method returned an invalid iterator.";
+}
+
+// Tests that assignment works.
+TEST(LinkedHashMapTest, Assign) {
+  linked_hash_map<int, int> m{{2, 12}, {3, 13}};
+  linked_hash_map<int, int> n{{4, 14}};
+
+  n = m;
+  EXPECT_TRUE(n.contains(2));
+  auto found = n.find(2);
+  ASSERT_TRUE(found != n.end());
+  for (auto iter = n.begin(); iter != n.end(); ++iter) {
+    if (iter == found) return;
+  }
+  FAIL() << "Assigned map's find method returned an invalid iterator.";
+}
+
+// Tests that self-assignment works.
+TEST(LinkedHashMapTest, SelfAssign) {
+  linked_hash_map<int, int> a{{1, 1}, {2, 2}, {3, 3}};
+  auto& a_ref = a;
+  a = a_ref;
+  EXPECT_THAT(a, ElementsAre(Pair(1, 1), Pair(2, 2), Pair(3, 3)));
+}
+
+// Tests that move constructor works.
+TEST(LinkedHashMapTest, Move) {
+  // Use unique_ptr as an example of a non-copyable type.
+  linked_hash_map<int, std::unique_ptr<int>> m;
+  m[2] = std::make_unique<int>(12);
+  m[3] = std::make_unique<int>(13);
+  linked_hash_map<int, std::unique_ptr<int>> n = std::move(m);
+  EXPECT_THAT(n, ElementsAre(Pair(2, Pointee(12)), Pair(3, Pointee(13))));
+}
+
+// Tests that self-moving works.
+TEST(LinkedHashMapTest, SelfMove) {
+  linked_hash_map<int, int> a{{1, 1}, {2, 2}, {3, 3}};
+  auto& a_ref = a;
+  a = std::move(a_ref);
+  EXPECT_THAT(a, ElementsAre(Pair(1, 1), Pair(2, 2), Pair(3, 3)));
+}
+
+TEST(LinkedHashMapTest, CanInsertMoveOnly) {
+  linked_hash_map<int, std::unique_ptr<int>> m;
+  struct Data {
+    int k, v;
+  };
+  const Data data[] = {{1, 123}, {3, 345}, {2, 234}, {4, 456}};
+  for (const auto& kv : data)
+    m.insert({kv.k, std::make_unique<int>(int{kv.v})});
+  EXPECT_TRUE(m.contains(2));
+  auto found = m.find(2);
+  ASSERT_TRUE(found != m.end());
+  EXPECT_EQ(234, *found->second);
+}
+
+TEST(LinkedHashMapTest, CanEmplaceMoveOnly) {
+  linked_hash_map<int, std::unique_ptr<int>> m;
+  struct Data {
+    int k, v;
+  };
+  const Data data[] = {{1, 123}, {3, 345}, {2, 234}, {4, 456}};
+  for (const auto& kv : data) {
+    m.emplace(std::piecewise_construct, std::make_tuple(kv.k),
+              std::make_tuple(new int{kv.v}));
+  }
+  EXPECT_TRUE(m.contains(2));
+  auto found = m.find(2);
+  ASSERT_TRUE(found != m.end());
+  EXPECT_EQ(234, *found->second);
+}
+
+struct NoCopy {
+  explicit NoCopy(int x) : x(x) {}
+  NoCopy(const NoCopy&) = delete;
+  NoCopy& operator=(const NoCopy&) = delete;
+  NoCopy(NoCopy&&) = delete;
+  NoCopy& operator=(NoCopy&&) = delete;
+  int x;
+};
+
+TEST(LinkedHashMapTest, CanEmplaceNoMoveNoCopy) {
+  linked_hash_map<int, NoCopy> m;
+  struct Data {
+    int k, v;
+  };
+  const Data data[] = {{1, 123}, {3, 345}, {2, 234}, {4, 456}};
+  for (const auto& kv : data) {
+    m.emplace(std::piecewise_construct, std::make_tuple(kv.k),
+              std::make_tuple(kv.v));
+  }
+  EXPECT_TRUE(m.contains(2));
+  auto found = m.find(2);
+  ASSERT_TRUE(found != m.end());
+  EXPECT_EQ(234, found->second.x);
+}
+
+TEST(LinkedHashMapTest, ConstKeys) {
+  linked_hash_map<int, int> m;
+  m.insert(std::make_pair(1, 2));
+  // Test that keys are const in iteration.
+  std::pair<const int, int>& p = *m.begin();
+  EXPECT_EQ(1, p.first);
+}
+
+// Tests that iteration from begin() to end() works
+TEST(LinkedHashMapTest, Iteration) {
+  linked_hash_map<int, int> m;
+  EXPECT_TRUE(m.begin() == m.end());
+
+  m.insert(std::make_pair(2, 12));
+  m.insert(std::make_pair(1, 11));
+  m.insert(std::make_pair(3, 13));
+
+  linked_hash_map<int, int>::iterator i = m.begin();
+  ASSERT_TRUE(m.begin() == i);
+  ASSERT_TRUE(m.end() != i);
+  EXPECT_EQ(2, i->first);
+  EXPECT_EQ(12, i->second);
+
+  ++i;
+  ASSERT_TRUE(m.end() != i);
+  EXPECT_EQ(1, i->first);
+  EXPECT_EQ(11, i->second);
+
+  ++i;
+  ASSERT_TRUE(m.end() != i);
+  EXPECT_EQ(3, i->first);
+  EXPECT_EQ(13, i->second);
+
+  ++i;  // Should be the end of the line.
+  ASSERT_TRUE(m.end() == i);
+}
+
+// Tests that reverse iteration from rbegin() to rend() works
+TEST(LinkedHashMapTest, ReverseIteration) {
+  linked_hash_map<int, int> m;
+  EXPECT_TRUE(m.rbegin() == m.rend());
+
+  m.insert(std::make_pair(2, 12));
+  m.insert(std::make_pair(1, 11));
+  m.insert(std::make_pair(3, 13));
+
+  linked_hash_map<int, int>::reverse_iterator i = m.rbegin();
+  ASSERT_TRUE(m.rbegin() == i);
+  ASSERT_TRUE(m.rend() != i);
+  EXPECT_EQ(3, i->first);
+  EXPECT_EQ(13, i->second);
+
+  ++i;
+  ASSERT_TRUE(m.rend() != i);
+  EXPECT_EQ(1, i->first);
+  EXPECT_EQ(11, i->second);
+
+  ++i;
+  ASSERT_TRUE(m.rend() != i);
+  EXPECT_EQ(2, i->first);
+  EXPECT_EQ(12, i->second);
+
+  ++i;  // Should be the end of the line.
+  ASSERT_TRUE(m.rend() == i);
+}
+
+// Tests that clear() works
+TEST(LinkedHashMapTest, Clear) {
+  linked_hash_map<int, int> m;
+  m.insert(std::make_pair(2, 12));
+  m.insert(std::make_pair(1, 11));
+  m.insert(std::make_pair(3, 13));
+
+  ASSERT_EQ(3, m.size());
+
+  m.clear();
+
+  EXPECT_EQ(0, m.size());
+
+  m.clear();  // Make sure we can call it on an empty map.
+
+  EXPECT_EQ(0, m.size());
+}
+
+// Tests that size() works.
+TEST(LinkedHashMapTest, Size) {
+  linked_hash_map<int, int> m;
+  EXPECT_EQ(0, m.size());
+  m.insert(std::make_pair(2, 12));
+  EXPECT_EQ(1, m.size());
+  m.insert(std::make_pair(1, 11));
+  EXPECT_EQ(2, m.size());
+  m.insert(std::make_pair(3, 13));
+  EXPECT_EQ(3, m.size());
+  m.clear();
+  EXPECT_EQ(0, m.size());
+}
+
+// Tests empty()
+TEST(LinkedHashMapTest, Empty) {
+  linked_hash_map<int, int> m;
+  ASSERT_TRUE(m.empty());
+  m.insert(std::make_pair(2, 12));
+  ASSERT_FALSE(m.empty());
+  m.clear();
+  ASSERT_TRUE(m.empty());
+}
+
+TEST(LinkedHashMapTest, Erase) {
+  linked_hash_map<int, int> m;
+  ASSERT_EQ(0, m.size());
+  EXPECT_EQ(0, m.erase(2));  // Nothing to erase yet
+
+  m.insert(std::make_pair(2, 12));
+  ASSERT_EQ(1, m.size());
+  EXPECT_EQ(1, m.erase(2));
+  EXPECT_EQ(0, m.size());
+
+  EXPECT_EQ(0, m.erase(2));  // Make sure nothing bad happens if we repeat.
+  EXPECT_EQ(0, m.size());
+}
+
+TEST(LinkedHashMapTest, Erase2) {
+  linked_hash_map<int, int> m;
+  ASSERT_EQ(0, m.size());
+  EXPECT_EQ(0, m.erase(2));  // Nothing to erase yet
+
+  m.insert(std::make_pair(2, 12));
+  m.insert(std::make_pair(1, 11));
+  m.insert(std::make_pair(3, 13));
+  m.insert(std::make_pair(4, 14));
+  ASSERT_EQ(4, m.size());
+
+  // Erase middle two
+  EXPECT_EQ(1, m.erase(1));
+  EXPECT_EQ(1, m.erase(3));
+
+  EXPECT_EQ(2, m.size());
+
+  // Make sure we can still iterate over everything that's left.
+  linked_hash_map<int, int>::iterator it = m.begin();
+  ASSERT_TRUE(it != m.end());
+  EXPECT_EQ(12, it->second);
+  ++it;
+  ASSERT_TRUE(it != m.end());
+  EXPECT_EQ(14, it->second);
+  ++it;
+  ASSERT_TRUE(it == m.end());
+
+  EXPECT_EQ(0, m.erase(1));  // Make sure nothing bad happens if we repeat.
+  ASSERT_EQ(2, m.size());
+
+  EXPECT_EQ(1, m.erase(2));
+  EXPECT_EQ(1, m.erase(4));
+  ASSERT_EQ(0, m.size());
+
+  EXPECT_EQ(0, m.erase(1));  // Make sure nothing bad happens if we repeat.
+  ASSERT_EQ(0, m.size());
+}
+
+// Test that erase(iter,iter) and erase(iter) compile and work.
+TEST(LinkedHashMapTest, Erase3) {
+  linked_hash_map<int, int> m;
+
+  m.insert(std::make_pair(1, 11));
+  m.insert(std::make_pair(2, 12));
+  m.insert(std::make_pair(3, 13));
+  m.insert(std::make_pair(4, 14));
+
+  // Erase middle two
+  linked_hash_map<int, int>::iterator it2 = m.find(2);
+  linked_hash_map<int, int>::iterator it4 = m.find(4);
+  EXPECT_EQ(m.erase(it2, it4), m.find(4));
+  EXPECT_EQ(2, m.size());
+
+  // Make sure we can still iterate over everything that's left.
+  linked_hash_map<int, int>::iterator it = m.begin();
+  ASSERT_TRUE(it != m.end());
+  EXPECT_EQ(11, it->second);
+  ++it;
+  ASSERT_TRUE(it != m.end());
+  EXPECT_EQ(14, it->second);
+  ++it;
+  ASSERT_TRUE(it == m.end());
+
+  // Erase first one using an iterator.
+  EXPECT_EQ(m.erase(m.begin()), m.find(4));
+
+  // Only the last element should be left.
+  it = m.begin();
+  ASSERT_TRUE(it != m.end());
+  EXPECT_EQ(14, it->second);
+  ++it;
+  ASSERT_TRUE(it == m.end());
+}
+
+// Test all types of insertion
+TEST(LinkedHashMapTest, Insertion) {
+  linked_hash_map<int, int> m;
+  ASSERT_EQ(0, m.size());
+  std::pair<linked_hash_map<int, int>::iterator, bool> result;
+
+  result = m.insert(std::make_pair(2, 12));
+  ASSERT_EQ(1, m.size());
+  EXPECT_TRUE(result.second);
+  EXPECT_EQ(2, result.first->first);
+  EXPECT_EQ(12, result.first->second);
+
+  result = m.insert(std::make_pair(1, 11));
+  ASSERT_EQ(2, m.size());
+  EXPECT_TRUE(result.second);
+  EXPECT_EQ(1, result.first->first);
+  EXPECT_EQ(11, result.first->second);
+
+  result = m.insert(std::make_pair(3, 13));
+  linked_hash_map<int, int>::iterator result_iterator = result.first;
+  ASSERT_EQ(3, m.size());
+  EXPECT_TRUE(result.second);
+  EXPECT_EQ(3, result.first->first);
+  EXPECT_EQ(13, result.first->second);
+
+  result = m.insert(std::make_pair(3, 13));
+  EXPECT_EQ(3, m.size());
+  EXPECT_FALSE(result.second) << "No insertion should have occurred.";
+  EXPECT_TRUE(result_iterator == result.first)
+      << "Duplicate insertion should have given us the original iterator.";
+
+  std::vector<std::pair<int, int>> v = {{3, 13}, {4, 14}, {5, 15}};
+  m.insert(v.begin(), v.end());
+  // Expect 4 and 5 inserted, 3 not inserted.
+  EXPECT_EQ(5, m.size());
+  EXPECT_EQ(14, m.at(4));
+  EXPECT_EQ(15, m.at(5));
+}
+
+static std::pair<const int, int> Pair(int i, int j) { return {i, j}; }
+
+// Test front accessors.
+TEST(LinkedHashMapTest, Front) {
+  linked_hash_map<int, int> m;
+
+  m.insert(std::make_pair(2, 12));
+  m.insert(std::make_pair(1, 11));
+  m.insert(std::make_pair(3, 13));
+
+  EXPECT_EQ(3, m.size());
+  EXPECT_EQ(Pair(2, 12), m.front());
+  m.pop_front();
+  EXPECT_EQ(2, m.size());
+  EXPECT_EQ(Pair(1, 11), m.front());
+  m.pop_front();
+  EXPECT_EQ(1, m.size());
+  EXPECT_EQ(Pair(3, 13), m.front());
+  m.pop_front();
+  EXPECT_TRUE(m.empty());
+}
+
+// Test back accessors.
+TEST(LinkedHashMapTest, Back) {
+  linked_hash_map<int, int> m;
+
+  m.insert(std::make_pair(2, 12));
+  m.insert(std::make_pair(1, 11));
+  m.insert(std::make_pair(3, 13));
+
+  EXPECT_EQ(3, m.size());
+  EXPECT_EQ(Pair(3, 13), m.back());
+  m.pop_back();
+  EXPECT_EQ(2, m.size());
+  EXPECT_EQ(Pair(1, 11), m.back());
+  m.pop_back();
+  EXPECT_EQ(1, m.size());
+  EXPECT_EQ(Pair(2, 12), m.back());
+  m.pop_back();
+  EXPECT_TRUE(m.empty());
+}
+
+TEST(LinkedHashMapTest, Find) {
+  linked_hash_map<int, int> m;
+
+  EXPECT_TRUE(m.end() == m.find(1))
+      << "We shouldn't find anything in an empty map.";
+
+  m.insert(std::make_pair(2, 12));
+  EXPECT_TRUE(m.end() == m.find(1))
+      << "We shouldn't find an element that doesn't exist in the map.";
+
+  std::pair<linked_hash_map<int, int>::iterator, bool> result =
+      m.insert(std::make_pair(1, 11));
+  ASSERT_TRUE(result.second);
+  ASSERT_TRUE(m.end() != result.first);
+  EXPECT_TRUE(result.first == m.find(1))
+      << "We should have found an element we know exists in the map.";
+  EXPECT_EQ(11, result.first->second);
+
+  // Check that a follow-up insertion doesn't affect our original
+  m.insert(std::make_pair(3, 13));
+  linked_hash_map<int, int>::iterator it = m.find(1);
+  ASSERT_TRUE(m.end() != it);
+  EXPECT_EQ(11, it->second);
+
+  m.clear();
+  EXPECT_TRUE(m.end() == m.find(1))
+      << "We shouldn't find anything in a map that we've cleared.";
+}
+
+TEST(LinkedHashMapTest, Contains) {
+  linked_hash_map<int, int> m;
+
+  EXPECT_FALSE(m.contains(1)) << "An empty map shouldn't contain anything.";
+
+  m.insert(std::make_pair(2, 12));
+  EXPECT_FALSE(m.contains(1))
+      << "The map shouldn't contain an element that doesn't exist.";
+
+  m.insert(std::make_pair(1, 11));
+  EXPECT_TRUE(m.contains(1))
+      << "The map should contain an element that we know exists.";
+
+  m.clear();
+  EXPECT_FALSE(m.contains(1))
+      << "A map that we've cleared shouldn't contain anything.";
+}
+
+TEST(LinkedHashMapTest, At) {
+  linked_hash_map<int, int> m = {{1, 2}};
+  EXPECT_EQ(2, m.at(1));
+  ABSL_BASE_INTERNAL_EXPECT_FAIL(m.at(3), std::out_of_range,
+                                 "linked_hash_map::at");
+
+  const linked_hash_map<int, int> cm = {{1, 2}};
+  EXPECT_EQ(2, cm.at(1));
+  ABSL_BASE_INTERNAL_EXPECT_FAIL(cm.at(3), std::out_of_range,
+                                 "linked_hash_map::at");
+}
+
+TEST(LinkedHashMapTest, Swap) {
+  linked_hash_map<int, int> m1;
+  linked_hash_map<int, int> m2;
+  m1.insert(std::make_pair(1, 1));
+  m1.insert(std::make_pair(2, 2));
+  m2.insert(std::make_pair(3, 3));
+  ASSERT_EQ(2, m1.size());
+  ASSERT_EQ(1, m2.size());
+  m1.swap(m2);
+  ASSERT_EQ(1, m1.size());
+  ASSERT_EQ(2, m2.size());
+}
+
+TEST(LinkedHashMapTest, SelfSwap) {
+  linked_hash_map<int, int> a{{1, 1}, {2, 2}, {3, 3}};
+  using std::swap;
+  swap(a, a);
+  EXPECT_THAT(a, ElementsAre(Pair(1, 1), Pair(2, 2), Pair(3, 3)));
+}
+
+TEST(LinkedHashMapTest, InitializerList) {
+  linked_hash_map<int, int> m{{1, 2}, {3, 4}};
+  ASSERT_EQ(2, m.size());
+  EXPECT_TRUE(m.contains(1));
+  linked_hash_map<int, int>::iterator it = m.find(1);
+  ASSERT_TRUE(m.end() != it);
+  EXPECT_EQ(2, it->second);
+  EXPECT_TRUE(m.contains(3));
+  it = m.find(3);
+  ASSERT_TRUE(m.end() != it);
+  EXPECT_EQ(4, it->second);
+}
+
+TEST(LinkedHashMapTest, CustomHashAndEquality) {
+  struct CustomIntHash {
+    size_t operator()(int x) const { return x; }
+  };
+  struct CustomIntEq {
+    bool operator()(int x, int y) const { return x == y; }
+  };
+  linked_hash_map<int, int, CustomIntHash, CustomIntEq> m;
+  m.insert(std::make_pair(1, 1));
+  EXPECT_TRUE(m.contains(1));
+  EXPECT_EQ(1, m[1]);
+}
+
+TEST(LinkedHashMapTest, EqualRange) {
+  linked_hash_map<int, int> m{{3, 11}, {1, 13}};
+  const auto& const_m = m;
+
+  EXPECT_THAT(m.equal_range(2), testing::Pair(m.end(), m.end()));
+  EXPECT_THAT(const_m.equal_range(2),
+              testing::Pair(const_m.end(), const_m.end()));
+
+  EXPECT_THAT(m.equal_range(1), testing::Pair(m.find(1), ++m.find(1)));
+  EXPECT_THAT(const_m.equal_range(1),
+              testing::Pair(const_m.find(1), ++const_m.find(1)));
+}
+
+TEST(LinkedHashMapTest, ReserveWorks) {
+  linked_hash_map<int, int> m;
+  EXPECT_EQ(0, m.size());
+  EXPECT_EQ(0.0, m.load_factor());
+  m.reserve(10);
+  EXPECT_LE(10, m.capacity());
+  EXPECT_EQ(0, m.size());
+  EXPECT_EQ(0.0, m.load_factor());
+  m.emplace(1, 1);
+  m.emplace(2, 2);
+  EXPECT_LE(10, m.capacity());
+  EXPECT_EQ(2, m.size());
+  EXPECT_LT(0.0, m.load_factor());
+}
+
+// We require key types to have hash and equals.
+class CopyableMovableType
+    : public absl::test_internal::CopyableMovableInstance {
+ public:
+  using CopyableMovableInstance::CopyableMovableInstance;
+
+  bool operator==(const CopyableMovableType& o) const {
+    return value() == o.value();
+  }
+
+  template <typename H>
+  friend H AbslHashValue(H h, const CopyableMovableType& c) {
+    return H::combine(std::move(h), c.value());
+  }
+};
+
+TEST(LinkedHashMapTest, RValueOperatorAt) {
+  absl::test_internal::InstanceTracker tracker;
+
+  linked_hash_map<CopyableMovableType, int> map;
+  map[CopyableMovableType(1)] = 1;
+  EXPECT_EQ(tracker.copies(), 0);
+  CopyableMovableType c(2);
+  map[std::move(c)] = 2;
+  EXPECT_EQ(tracker.copies(), 0);
+  EXPECT_THAT(map, ElementsAre(Pair(CopyableMovableType(1), 1),
+                               Pair(CopyableMovableType(2), 2)));
+}
+
+TEST(LinkedHashMapTest, HeterogeneousTests) {
+  absl::test_internal::InstanceTracker tracker;
+
+  using MapType = linked_hash_map<ExpensiveType, int, HeterogeneousHash,
+                                  HeterogeneousEqual>;
+  MapType map;
+  ExpensiveType one(1);
+  map[one] = 1;
+  // Two instances: 'one' var and an instance in the map.
+  EXPECT_EQ(2, tracker.instances());
+  EXPECT_EQ(1, tracker.copies());
+  EXPECT_EQ(0, tracker.moves());
+
+  tracker.ResetCopiesMovesSwaps();
+  map[one] = 5;
+  // No construction since key==1 exists.
+  EXPECT_EQ(2, tracker.instances());
+  EXPECT_EQ(0, tracker.copies());
+  EXPECT_EQ(0, tracker.moves());
+
+  tracker.ResetCopiesMovesSwaps();
+  map[CheapType(1)] = 10;
+  // No construction since key==1 exists.
+  EXPECT_EQ(2, tracker.instances());
+  EXPECT_EQ(0, tracker.copies());
+  EXPECT_EQ(0, tracker.moves());
+
+  tracker.ResetCopiesMovesSwaps();
+  map[CheapType(2)] = 20;
+  // Construction since key==2 doesn't exist in the map.
+  EXPECT_EQ(3, tracker.instances());
+  EXPECT_EQ(0, tracker.copies());
+  EXPECT_EQ(0, tracker.moves());
+  EXPECT_THAT(map, ElementsAre(Pair(HasExpensiveValue(1), 10),
+                               Pair(HasExpensiveValue(2), 20)));
+
+  // find
+  auto itr = map.find(CheapType(1));
+  tracker.ResetCopiesMovesSwaps();
+  ASSERT_NE(itr, map.end());
+  EXPECT_EQ(10, itr->second);
+  // contains
+  EXPECT_TRUE(map.contains(CheapType(2)));
+  // count
+  EXPECT_EQ(1, map.count(CheapType(2)));
+  // equal_range
+  auto eq_itr_pair = map.equal_range(CheapType(2));
+  ASSERT_NE(eq_itr_pair.first, map.end());
+  EXPECT_EQ(20, eq_itr_pair.first->second);
+  // No construction for find, contains, count or equal_range.
+  EXPECT_EQ(3, tracker.instances());
+  EXPECT_EQ(0, tracker.copies());
+  EXPECT_EQ(0, tracker.moves());
+
+  // insert
+  auto three = MapType::value_type(CheapType(3), 30);
+  tracker.ResetCopiesMovesSwaps();
+  map.insert(three);
+  // Two instances: 'three' var and an instance in the map.
+  EXPECT_EQ(5, tracker.instances());
+  EXPECT_EQ(1, tracker.copies());
+  EXPECT_EQ(0, tracker.moves());
+
+  tracker.ResetCopiesMovesSwaps();
+  map.insert(three);
+  // No additional construction since key==3 exists.
+  EXPECT_EQ(5, tracker.instances());
+  EXPECT_EQ(0, tracker.copies());
+  EXPECT_EQ(0, tracker.moves());
+  EXPECT_THAT(map, ElementsAre(Pair(HasExpensiveValue(1), 10),
+                               Pair(HasExpensiveValue(2), 20),
+                               Pair(HasExpensiveValue(3), 30)));
+
+  // Test std::move() using operator[] and insert().
+  ExpensiveType four(4);
+  tracker.ResetCopiesMovesSwaps();
+  map[std::move(four)] = 40;
+  // Two constructions (regular and move).
+  EXPECT_EQ(7, tracker.instances());
+  EXPECT_EQ(0, tracker.copies());
+  EXPECT_EQ(1, tracker.moves());
+
+  auto five = MapType::value_type(CheapType(5), 50);
+  tracker.ResetCopiesMovesSwaps();
+  map.insert(std::move(five));
+  // Two constructions (regular and move).
+  EXPECT_EQ(9, tracker.instances());
+  EXPECT_EQ(1, tracker.copies());
+  EXPECT_EQ(0, tracker.moves());
+  EXPECT_THAT(map, ElementsAre(Pair(HasExpensiveValue(1), 10),
+                               Pair(HasExpensiveValue(2), 20),
+                               Pair(HasExpensiveValue(3), 30),
+                               Pair(HasExpensiveValue(4), 40),
+                               Pair(HasExpensiveValue(5), 50)));
+
+  // Insert using std::pair.
+  tracker.ResetCopiesMovesSwaps();
+  map.insert(std::make_pair(ExpensiveType(6), 60));
+  EXPECT_EQ(10, tracker.instances());
+  EXPECT_EQ(1, tracker.copies());
+  EXPECT_EQ(2, tracker.moves());
+
+  // Heterogeneous erase.
+  map.erase(CheapType(1));
+  // No construction and instance reduced by one.
+  tracker.ResetCopiesMovesSwaps();
+  EXPECT_EQ(9, tracker.instances());
+  EXPECT_EQ(0, tracker.copies());
+  EXPECT_EQ(0, tracker.moves());
+  EXPECT_THAT(map, ElementsAre(Pair(HasExpensiveValue(2), 20),
+                               Pair(HasExpensiveValue(3), 30),
+                               Pair(HasExpensiveValue(4), 40),
+                               Pair(HasExpensiveValue(5), 50),
+                               Pair(HasExpensiveValue(6), 60)));
+}
+
+TEST(LinkedHashMapTest, HeterogeneousStringViewLookup) {
+  linked_hash_map<std::string, int> map;
+  map["foo"] = 1;
+  map["bar"] = 2;
+  map["blah"] = 3;
+
+  {
+    absl::string_view lookup("foo");
+    auto itr = map.find(lookup);
+    ASSERT_NE(itr, map.end());
+    EXPECT_EQ(1, itr->second);
+  }
+
+  // Not found.
+  {
+    absl::string_view lookup("foobar");
+    EXPECT_EQ(map.end(), map.find(lookup));
+  }
+
+  {
+    absl::string_view lookup("blah");
+    auto itr = map.find(lookup);
+    ASSERT_NE(itr, map.end());
+    EXPECT_EQ(3, itr->second);
+  }
+}
+
+TEST(LinkedHashMapTest, UniversalReferenceWorks) {
+  linked_hash_map<std::string, int> map;
+  std::string s = "very very very very very long string";
+  map[s] = 1;
+  EXPECT_EQ(s, "very very very very very long string");
+}
+
+TEST(LinkedHashMap, ExtractInsert) {
+  linked_hash_map<int, int> m = {{1, 7}, {2, 9}};
+  auto node = m.extract(1);
+  EXPECT_TRUE(node);
+  EXPECT_EQ(node.key(), 1);
+  EXPECT_EQ(node.mapped(), 7);
+  EXPECT_THAT(m, ElementsAre(Pair(2, 9)));
+  EXPECT_FALSE(m.contains(1));
+  EXPECT_TRUE(m.contains(2));
+
+  node.mapped() = 17;
+  m.insert(std::move(node));
+  EXPECT_FALSE(node);
+  EXPECT_THAT(m, ElementsAre(Pair(2, 9), Pair(1, 17)));
+  EXPECT_TRUE(m.contains(2));
+  EXPECT_TRUE(m.contains(1));
+
+  node = m.extract(m.find(1));
+  EXPECT_TRUE(node);
+  EXPECT_EQ(node.key(), 1);
+  EXPECT_EQ(node.mapped(), 17);
+  EXPECT_THAT(m, ElementsAre(Pair(2, 9)));
+}
+
+TEST(LinkedHashMap, Merge) {
+  linked_hash_map<int, int> m = {{1, 7}, {3, 6}};
+  linked_hash_map<int, int> src = {{1, 10}, {2, 9}, {4, 16}};
+
+  m.merge(src);
+
+  EXPECT_THAT(m, ElementsAre(Pair(1, 7), Pair(3, 6), Pair(2, 9), Pair(4, 16)));
+  EXPECT_THAT(src, ElementsAre(Pair(1, 10)));
+  for (int i : {2, 9, 4}) {
+    EXPECT_FALSE(src.contains(i));
+  }
+}
+
+TEST(LinkedHashMap, Splice) {
+  linked_hash_map<int, int> m = {{1, 7}, {3, 6}};
+  linked_hash_map<int, int> src = {{1, 10}, {2, 9}, {4, 16}};
+  m.splice(m.end(), m, m.begin());
+
+  EXPECT_THAT(m, ElementsAre(Pair(3, 6), Pair(1, 7)));
+
+  m.splice(m.end(), src, ++src.begin());
+  EXPECT_THAT(m, ElementsAre(Pair(3, 6), Pair(1, 7), Pair(2, 9)));
+  EXPECT_THAT(src, ElementsAre(Pair(1, 10), Pair(4, 16)));
+}
+
+TEST(LinkedHashMap, EraseRange) {
+  linked_hash_map<int, int> map = {{1, 1},  {2, 4},  {3, 9},  {4, 16}, {5, 25},
+                                   {6, 36}, {7, 49}, {8, 64}, {9, 81}};
+  auto start = map.find(3);
+  auto end = map.find(8);
+  auto itr = map.erase(start, end);
+  ASSERT_NE(itr, map.end());
+  EXPECT_THAT(*itr, Pair(8, 64));
+  EXPECT_THAT(map,
+              ElementsAre(Pair(1, 1), Pair(2, 4), Pair(8, 64), Pair(9, 81)));
+  for (int i : {1, 2, 8, 9}) {
+    EXPECT_TRUE(map.contains(i));
+  }
+  for (int i : {3, 4, 5, 6, 7}) {
+    EXPECT_FALSE(map.contains(i));
+  }
+}
+
+TEST(LinkedHashMap, InsertInitializerList) {
+  linked_hash_map<int, int> m;
+  m.insert({{1, 7}, {2, 9}, {3, 29}});
+  EXPECT_THAT(m, ElementsAre(Pair(1, 7), Pair(2, 9), Pair(3, 29)));
+}
+
+TEST(LinkedHashMap, InsertOrAssign) {
+  linked_hash_map<int, int> m;
+  {
+    auto [itr, elem_inserted] = m.insert_or_assign(10, 20);
+    EXPECT_THAT(*itr, Pair(10, 20));
+    EXPECT_EQ(elem_inserted, true);
+  }
+  {
+    auto [itr, elem_inserted] = m.insert_or_assign(10, 30);
+    EXPECT_THAT(*itr, Pair(10, 30));
+    EXPECT_EQ(elem_inserted, false);
+  }
+}
+
+TEST(LinkedHashMap, TryEmplace) {
+  linked_hash_map<int, std::pair<int, std::string>> m;
+  {
+    auto [itr, elem_inserted] = m.try_emplace(10, 20, "string");
+    EXPECT_THAT(*itr, Pair(10, Pair(20, "string")));
+    EXPECT_EQ(elem_inserted, true);
+  }
+  {
+    absl::test_internal::InstanceTracker tracker;
+    std::string s = "some string";
+    auto [itr, elem_inserted] = m.try_emplace(10, 2, std::move(s));
+    EXPECT_THAT(*itr, Pair(10, Pair(20, "string")));
+    EXPECT_EQ(elem_inserted, false);
+    EXPECT_THAT(tracker.moves(), 0);
+  }
+}
+
+TEST(LinkedHashMapTest, TryEmplace) {
+  linked_hash_map<int, std::tuple<int, std::string, std::unique_ptr<float>>>
+      map;
+  auto result = map.try_emplace(3, 2, "foo", new float(1.0));
+  EXPECT_TRUE(result.second);
+  EXPECT_EQ(std::get<0>(result.first->second), 2);
+  EXPECT_EQ(std::get<1>(result.first->second), "foo");
+  EXPECT_EQ(*std::get<2>(result.first->second), 1.0);
+
+  // Ptr should not be moved.
+  auto ptr = std::make_unique<float>(3.0);
+  auto result2 = map.try_emplace(3, 22, "foo-bar", std::move(ptr));
+  EXPECT_FALSE(result2.second);
+  EXPECT_EQ(std::get<0>(result.first->second), 2);
+  EXPECT_EQ(std::get<1>(result.first->second), "foo");
+  EXPECT_EQ(*std::get<2>(result.first->second), 1.0);
+  EXPECT_NE(ptr.get(), nullptr);
+}
+
+struct CountedHash {
+  explicit CountedHash(int* count) : count(count) {}
+  size_t operator()(int value) const {
+    ++(*count);
+    return value;
+  }
+  int* count = nullptr;
+};
+
+// Makes a map too big for small object optimization.  Counts the number of
+// hashes in `count`, but leaves `count` set to 0.
+linked_hash_map<int, std::string, CountedHash> MakeNonSmallMap(int* count) {
+  const int kFirstKey = -1000;
+  linked_hash_map<int, std::string, CountedHash> m(0, CountedHash(count));
+  for (int i = kFirstKey; i < kFirstKey + 100; ++i) {
+    m[i] = "foo";
+  }
+  *count = 0;
+  return m;
+}
+
+constexpr bool BuildHasDebugModeRehashes() {
+#if !defined(NDEBUG) || defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
+    defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER)
+  return true;
+#else
+  return false;
+#endif
+}
+
+TEST(LinkedHashMapTest, HashCountInOptBuilds) {
+  if (BuildHasDebugModeRehashes()) {
+    GTEST_SKIP() << "Only run under NDEBUG: `assert` statements and sanitizer "
+                    "rehashing may cause redundant hashing.";
+  }
+
+  using Map = linked_hash_map<int, std::string, CountedHash>;
+  {
+    int count = 0;
+    Map m = MakeNonSmallMap(&count);
+    m.insert({1, "foo"});
+    EXPECT_EQ(count, 1);
+    m.erase(1);
+    EXPECT_EQ(count, 2);
+  }
+  {
+    int count = 0;
+    Map m = MakeNonSmallMap(&count);
+    m[2] = "bar";
+    EXPECT_EQ(count, 1);
+  }
+  {
+    int count = 0;
+    Map m = MakeNonSmallMap(&count);
+    m.insert({3, "baz"});
+    EXPECT_EQ(count, 1);
+    auto node = m.extract(3);
+    EXPECT_EQ(count, 2);
+    m.insert(std::move(node));
+    EXPECT_EQ(count, 3);
+  }
+  {
+    int count = 0;
+    Map m = MakeNonSmallMap(&count);
+    m.insert_or_assign(4, "qux");
+    EXPECT_EQ(count, 1);
+  }
+  {
+    int count = 0;
+    Map m = MakeNonSmallMap(&count);
+    m.emplace(5, "vog");
+    EXPECT_EQ(count, 1);
+  }
+  {
+    int count = 0;
+    Map m = MakeNonSmallMap(&count);
+    m.try_emplace(6, 'x', 42);
+    EXPECT_EQ(count, 1);
+  }
+  {
+    int src_count = 0, dst_count = 0;
+    Map src = MakeNonSmallMap(&src_count);
+    Map dst = MakeNonSmallMap(&dst_count);
+    src[7] = "siete";
+    dst.merge(src);
+    EXPECT_LE(src_count, 200);
+    EXPECT_LE(dst_count, 200);
+  }
+}
+
+}  // namespace
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/container/linked_hash_set.h b/absl/container/linked_hash_set.h
new file mode 100644
index 0000000..1b5d578
--- /dev/null
+++ b/absl/container/linked_hash_set.h
@@ -0,0 +1,527 @@
+// Copyright 2025 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: linked_hash_set.h
+// -----------------------------------------------------------------------------
+//
+// This is a simple insertion-ordered set. It provides O(1) amortized
+// insertions and lookups, as well as iteration over the set in the insertion
+// order.
+//
+// This class is thread-compatible.
+//
+// Iterators point into the list and should be stable in the face of
+// mutations, except for an iterator pointing to an element that was just
+// deleted.
+//
+// This class supports heterogeneous lookups.
+
+#ifndef ABSL_CONTAINER_LINKED_HASH_SET_H_
+#define ABSL_CONTAINER_LINKED_HASH_SET_H_
+
+#include <cassert>
+#include <cstddef>
+#include <initializer_list>
+#include <list>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/container/flat_hash_set.h"
+#include "absl/container/internal/common.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+template <
+    typename Key, typename KeyHash = typename absl::flat_hash_set<Key>::hasher,
+    typename KeyEq = typename absl::flat_hash_set<Key, KeyHash>::key_equal,
+    typename Alloc = std::allocator<Key>>
+class linked_hash_set {
+  using KeyArgImpl = absl::container_internal::KeyArg<
+      absl::container_internal::IsTransparent<KeyEq>::value &&
+      absl::container_internal::IsTransparent<KeyHash>::value>;
+
+ public:
+  using key_type = Key;
+  using hasher = KeyHash;
+  using key_equal = KeyEq;
+  using value_type = key_type;
+  using allocator_type = Alloc;
+  using difference_type = ptrdiff_t;
+
+ private:
+  template <class K>
+  using key_arg = typename KeyArgImpl::template type<K, key_type>;
+
+  using ListType = std::list<key_type, Alloc>;
+
+  template <class Fn>
+  class Wrapped {
+    template <typename K>
+    static const K& ToKey(const K& k) {
+      return k;
+    }
+    static const key_type& ToKey(typename ListType::const_iterator it) {
+      return *it;
+    }
+    static const key_type& ToKey(typename ListType::iterator it) { return *it; }
+
+    Fn fn_;
+
+    friend linked_hash_set;
+
+   public:
+    using is_transparent = void;
+
+    Wrapped() = default;
+    explicit Wrapped(Fn fn) : fn_(std::move(fn)) {}
+
+    template <class... Args>
+    auto operator()(Args&&... args) const
+        -> decltype(this->fn_(ToKey(args)...)) {
+      return fn_(ToKey(args)...);
+    }
+  };
+  using SetType =
+      absl::flat_hash_set<typename ListType::iterator, Wrapped<hasher>,
+                          Wrapped<key_equal>, Alloc>;
+
+  class NodeHandle {
+   public:
+    using allocator_type = linked_hash_set::allocator_type;
+    using value_type = linked_hash_set::value_type;
+
+    constexpr NodeHandle() noexcept = default;
+    NodeHandle(NodeHandle&& nh) noexcept = default;
+    ~NodeHandle() = default;
+    NodeHandle& operator=(NodeHandle&& node) noexcept = default;
+    bool empty() const noexcept { return list_.empty(); }
+    explicit operator bool() const noexcept { return !empty(); }
+    allocator_type get_allocator() const { return list_.get_allocator(); }
+    value_type& value() { return list_.front(); }
+    void swap(NodeHandle& nh) noexcept { list_.swap(nh.list_); }
+
+   private:
+    friend linked_hash_set;
+
+    explicit NodeHandle(ListType list) : list_(std::move(list)) {}
+    ListType list_;
+  };
+
+  template <class Iterator, class NodeType>
+  struct InsertReturnType {
+    Iterator position;
+    bool inserted;
+    NodeType node;
+  };
+
+ public:
+  using iterator = typename ListType::const_iterator;
+  using const_iterator = typename ListType::const_iterator;
+  using reverse_iterator = typename ListType::const_reverse_iterator;
+  using const_reverse_iterator = typename ListType::const_reverse_iterator;
+  using reference = typename ListType::reference;
+  using const_reference = typename ListType::const_reference;
+  using pointer = typename std::allocator_traits<allocator_type>::pointer;
+  using const_pointer =
+      typename std::allocator_traits<allocator_type>::const_pointer;
+  using size_type = typename ListType::size_type;
+  using node_type = NodeHandle;
+  using insert_return_type = InsertReturnType<iterator, node_type>;
+
+  linked_hash_set() {}
+
+  explicit linked_hash_set(size_t bucket_count, const hasher& hash = hasher(),
+                           const key_equal& eq = key_equal(),
+                           const allocator_type& alloc = allocator_type())
+      : set_(bucket_count, Wrapped<hasher>(hash), Wrapped<key_equal>(eq),
+             alloc),
+        list_(alloc) {}
+
+  linked_hash_set(size_t bucket_count, const hasher& hash,
+                  const allocator_type& alloc)
+      : linked_hash_set(bucket_count, hash, key_equal(), alloc) {}
+
+  linked_hash_set(size_t bucket_count, const allocator_type& alloc)
+      : linked_hash_set(bucket_count, hasher(), key_equal(), alloc) {}
+
+  explicit linked_hash_set(const allocator_type& alloc)
+      : linked_hash_set(0, hasher(), key_equal(), alloc) {}
+
+  template <class InputIt>
+  linked_hash_set(InputIt first, InputIt last, size_t bucket_count = 0,
+                  const hasher& hash = hasher(),
+                  const key_equal& eq = key_equal(),
+                  const allocator_type& alloc = allocator_type())
+      : linked_hash_set(bucket_count, hash, eq, alloc) {
+    insert(first, last);
+  }
+
+  template <class InputIter>
+  linked_hash_set(InputIter first, InputIter last, size_t bucket_count,
+                  const hasher& hash, const allocator_type& alloc)
+      : linked_hash_set(first, last, bucket_count, hash, key_equal(), alloc) {}
+
+  template <class InputIter>
+  linked_hash_set(InputIter first, InputIter last, size_t bucket_count,
+                  const allocator_type& alloc)
+      : linked_hash_set(first, last, bucket_count, hasher(), key_equal(),
+                        alloc) {}
+
+  template <class InputIt>
+  linked_hash_set(InputIt first, InputIt last, const allocator_type& alloc)
+      : linked_hash_set(first, last, /*bucket_count=*/0, hasher(), key_equal(),
+                        alloc) {}
+
+  linked_hash_set(std::initializer_list<key_type> init, size_t bucket_count = 0,
+                  const hasher& hash = hasher(),
+                  const key_equal& eq = key_equal(),
+                  const allocator_type& alloc = allocator_type())
+      : linked_hash_set(init.begin(), init.end(), bucket_count, hash, eq,
+                        alloc) {}
+
+  linked_hash_set(std::initializer_list<key_type> init, size_t bucket_count,
+                  const allocator_type& alloc)
+      : linked_hash_set(init, bucket_count, hasher(), key_equal(), alloc) {}
+
+  linked_hash_set(std::initializer_list<key_type> init, size_t bucket_count,
+                  const hasher& hash, const allocator_type& alloc)
+      : linked_hash_set(init, bucket_count, hash, key_equal(), alloc) {}
+
+  linked_hash_set(std::initializer_list<key_type> init,
+                  const allocator_type& alloc)
+      : linked_hash_set(init, /*bucket_count=*/0, hasher(), key_equal(),
+                        alloc) {}
+
+  linked_hash_set(const linked_hash_set& other)
+      : linked_hash_set(other.bucket_count(), other.hash_function(),
+                        other.key_eq(), other.get_allocator()) {
+    CopyFrom(other);
+  }
+
+  linked_hash_set(const linked_hash_set& other, const allocator_type& alloc)
+      : linked_hash_set(other.bucket_count(), other.hash_function(),
+                        other.key_eq(), alloc) {
+    CopyFrom(other);
+  }
+
+  linked_hash_set(linked_hash_set&& other) noexcept
+      : set_(std::move(other.set_)), list_(std::move(other.list_)) {
+    // Since the list and set must agree for other to end up "valid",
+    // explicitly clear them.
+    other.set_.clear();
+    other.list_.clear();
+  }
+
+  linked_hash_set(linked_hash_set&& other, const allocator_type& alloc)
+      : linked_hash_set(0, other.hash_function(), other.key_eq(), alloc) {
+    if (get_allocator() == other.get_allocator()) {
+      *this = std::move(other);
+    } else {
+      CopyFrom(std::move(other));
+    }
+  }
+
+  linked_hash_set& operator=(const linked_hash_set& other) {
+    if (this != &other) {
+      // Make a new set, with other's hash/eq/alloc.
+      set_ = SetType(other.bucket_count(), other.set_.hash_function(),
+                     other.set_.key_eq(), other.get_allocator());
+      // Copy the list, with other's allocator.
+      list_ = ListType(other.get_allocator());
+      CopyFrom(other);
+    }
+    return *this;
+  }
+
+  linked_hash_set& operator=(linked_hash_set&& other) noexcept {
+    if (this != &other) {
+      set_ = std::move(other.set_);
+      list_ = std::move(other.list_);
+      other.set_.clear();
+      other.list_.clear();
+    }
+    return *this;
+  }
+
+  linked_hash_set& operator=(std::initializer_list<key_type> values) {
+    clear();
+    insert(values.begin(), values.end());
+    return *this;
+  }
+
+  // Derive size from set_, as list::size might be O(N).
+  size_type size() const { return set_.size(); }
+  size_type max_size() const noexcept { return ~size_type{}; }
+  bool empty() const { return set_.empty(); }
+
+  // Iteration is list-like, in insertion order.
+  // These are all forwarded.
+  iterator begin() { return list_.begin(); }
+  iterator end() { return list_.end(); }
+  const_iterator begin() const { return list_.begin(); }
+  const_iterator end() const { return list_.end(); }
+  const_iterator cbegin() const { return list_.cbegin(); }
+  const_iterator cend() const { return list_.cend(); }
+  reverse_iterator rbegin() { return list_.rbegin(); }
+  reverse_iterator rend() { return list_.rend(); }
+  const_reverse_iterator rbegin() const { return list_.rbegin(); }
+  const_reverse_iterator rend() const { return list_.rend(); }
+  const_reverse_iterator crbegin() const { return list_.crbegin(); }
+  const_reverse_iterator crend() const { return list_.crend(); }
+  reference front() { return list_.front(); }
+  reference back() { return list_.back(); }
+  const_reference front() const { return list_.front(); }
+  const_reference back() const { return list_.back(); }
+
+  void pop_front() { erase(begin()); }
+  void pop_back() { erase(std::prev(end())); }
+
+  ABSL_ATTRIBUTE_REINITIALIZES void clear() {
+    set_.clear();
+    list_.clear();
+  }
+
+  void reserve(size_t n) { set_.reserve(n); }
+  size_t bucket_count() const { return set_.bucket_count(); }
+  size_t capacity() const { return set_.capacity(); }
+  float load_factor() const { return set_.load_factor(); }
+
+  hasher hash_function() const { return set_.hash_function().fn_; }
+  key_equal key_eq() const { return set_.key_eq().fn_; }
+  allocator_type get_allocator() const { return list_.get_allocator(); }
+
+  template <typename K = key_type>
+  size_type erase(const key_arg<K>& key) {
+    auto found = set_.find(key);
+    if (found == set_.end()) return 0;
+    auto list_it = *found;
+    // Erase set entry first since it refers to the list element.
+    set_.erase(found);
+    list_.erase(list_it);
+    return 1;
+  }
+
+  iterator erase(const_iterator position) {
+    auto found = set_.find(position);
+    assert(*found == position);
+    set_.erase(found);
+    return list_.erase(position);
+  }
+
+  iterator erase(const_iterator first, const_iterator last) {
+    while (first != last) first = erase(first);
+    return first;
+  }
+
+  template <typename K = key_type>
+  iterator find(const key_arg<K>& key) {
+    auto found = set_.find(key);
+    if (found == set_.end()) return end();
+    return *found;
+  }
+
+  template <typename K = key_type>
+  const_iterator find(const key_arg<K>& key) const {
+    auto found = set_.find(key);
+    if (found == set_.end()) return end();
+    return *found;
+  }
+
+  template <typename K = key_type>
+  size_t count(const key_arg<K>& key) const {
+    return contains(key) ? 1 : 0;
+  }
+  template <typename K = key_type>
+  bool contains(const key_arg<K>& key) const {
+    return set_.contains(key);
+  }
+
+  template <typename K = key_type>
+  std::pair<iterator, iterator> equal_range(const key_arg<K>& key) {
+    auto iter = set_.find(key);
+    if (iter == set_.end()) return {end(), end()};
+    return {*iter, std::next(*iter)};
+  }
+
+  template <typename K = key_type>
+  std::pair<const_iterator, const_iterator> equal_range(
+      const key_arg<K>& key) const {
+    auto iter = set_.find(key);
+    if (iter == set_.end()) return {end(), end()};
+    return {*iter, std::next(*iter)};
+  }
+
+  template <typename K = key_type>
+  std::pair<iterator, bool> insert(const key_arg<K>& k) {
+    return InsertInternal(list_.end(), k);
+  }
+  template <typename K = key_type, K* = nullptr>
+  std::pair<iterator, bool> insert(key_arg<K>&& k) {
+    return InsertInternal(list_.end(), std::move(k));
+  }
+
+  template <typename K = key_type,
+            std::enable_if_t<
+                !std::is_convertible_v<const key_arg<K>&, const_iterator> &&
+                    !std::is_convertible_v<const key_arg<K>&, iterator>,
+                int> = 0>
+  iterator insert(const_iterator hint, const key_arg<K>& k) {
+    return InsertInternal(hint, k).first;
+  }
+  template <
+      typename K = key_type, K* = nullptr,
+      std::enable_if_t<!std::is_convertible_v<key_arg<K>&&, const_iterator> &&
+                           !std::is_convertible_v<key_arg<K>&&, iterator>,
+                       int> = 0>
+  iterator insert(const_iterator hint, key_arg<K>&& k) {
+    return InsertInternal(hint, std::move(k)).first;
+  }
+
+  void insert(std::initializer_list<key_type> ilist) {
+    insert(ilist.begin(), ilist.end());
+  }
+
+  template <class InputIt>
+  void insert(InputIt first, InputIt last) {
+    for (; first != last; ++first) insert(*first);
+  }
+
+  insert_return_type insert(node_type&& node) {
+    if (node.empty()) return {end(), false, node_type()};
+    if (auto [set_itr, inserted] = set_.emplace(node.list_.begin()); inserted) {
+      list_.splice(list_.end(), node.list_);
+      return {*set_itr, true, node_type()};
+    } else {
+      return {*set_itr, false, std::move(node)};
+    }
+  }
+
+  iterator insert(const_iterator, node_type&& node) {
+    return insert(std::move(node)).first;
+  }
+
+  template <typename... Args>
+  std::pair<iterator, bool> emplace(Args&&... args) {
+    return EmplaceInternal(list_.end(), std::forward<Args>(args)...);
+  }
+
+  template <typename... Args>
+  iterator emplace_hint(const_iterator hint, Args&&... args) {
+    return EmplaceInternal(hint, std::forward<Args>(args)...).first;
+  }
+
+  template <typename H, typename E>
+  void merge(linked_hash_set<Key, H, E, Alloc>& src) {
+    auto itr = src.list_.begin();
+    while (itr != src.list_.end()) {
+      if (contains(*itr)) {
+        ++itr;
+      } else {
+        insert(src.extract(itr++));
+      }
+    }
+  }
+
+  template <typename H, typename E>
+  void merge(linked_hash_set<Key, H, E, Alloc>&& src) {
+    merge(src);
+  }
+
+  node_type extract(const_iterator position) {
+    set_.erase(position);
+    ListType extracted_node_list;
+    extracted_node_list.splice(extracted_node_list.end(), list_, position);
+    return node_type(std::move(extracted_node_list));
+  }
+
+  template <class K = key_type, typename std::enable_if_t<
+                                    !std::is_same<K, iterator>::value, int> = 0>
+  node_type extract(const key_arg<K>& key) {
+    auto node = set_.extract(key);
+    if (node.empty()) return node_type();
+    ListType extracted_node_list;
+    extracted_node_list.splice(extracted_node_list.end(), list_, node.value());
+    return node_type(std::move(extracted_node_list));
+  }
+
+  void swap(linked_hash_set& other) noexcept {
+    using std::swap;
+    swap(set_, other.set_);
+    swap(list_, other.list_);
+  }
+
+  friend bool operator==(const linked_hash_set& a, const linked_hash_set& b) {
+    if (a.size() != b.size()) return false;
+    const linked_hash_set* outer = &a;
+    const linked_hash_set* inner = &b;
+    if (outer->capacity() > inner->capacity()) std::swap(outer, inner);
+    for (const value_type& elem : *outer)
+      if (!inner->contains(elem)) return false;
+    return true;
+  }
+
+  friend bool operator!=(const linked_hash_set& a, const linked_hash_set& b) {
+    return !(a == b);
+  }
+
+  void rehash(size_t n) { set_.rehash(n); }
+
+ private:
+  template <typename Other>
+  void CopyFrom(Other&& other) {
+    for (auto& elem : other.list_) {
+      set_.insert(list_.insert(list_.end(), std::move(elem)));
+    }
+    assert(set_.size() == list_.size());
+  }
+
+  template <typename... Args>
+  std::pair<iterator, bool> EmplaceInternal(const_iterator hint,
+                                            Args&&... args) {
+    ListType node_donor;
+    auto list_iter =
+        node_donor.emplace(node_donor.end(), std::forward<Args>(args)...);
+    auto ins = set_.insert(list_iter);
+    if (!ins.second) return {*ins.first, false};
+    list_.splice(hint, node_donor, list_iter);
+    return {list_iter, true};
+  }
+
+  template <typename U>
+  std::pair<iterator, bool> InsertInternal(const_iterator hint,
+                                           U&& key) {  // NOLINT(build/c++11)
+    bool constructed = false;
+    auto set_iter = set_.lazy_emplace(key, [&](const auto& ctor) {
+      constructed = true;
+      ctor(list_.emplace(hint, std::forward<U>(key)));
+    });
+    return {*set_iter, constructed};
+  }
+
+  // The set component, used for speedy lookups.
+  SetType set_;
+
+  // The list component, used for maintaining insertion order.
+  ListType list_;
+};
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_LINKED_HASH_SET_H_
diff --git a/absl/container/linked_hash_set_benchmark.cc b/absl/container/linked_hash_set_benchmark.cc
new file mode 100644
index 0000000..e790e7d
--- /dev/null
+++ b/absl/container/linked_hash_set_benchmark.cc
@@ -0,0 +1,84 @@
+// Copyright 2025 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 <algorithm>
+#include <cstddef>
+#include <string>
+#include <vector>
+
+#include "absl/container/linked_hash_set.h"
+#include "absl/functional/function_ref.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/string_view.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+void BenchmarkInsertStrings(benchmark::State& state,
+                            absl::FunctionRef<std::string(int)> factory) {
+  std::vector<std::string> sample;
+  size_t str_bytes = 0;
+  for (int i = 0; i < state.range(0); ++i) {
+    sample.push_back(factory(i));
+    str_bytes += sample.back().size();
+  }
+
+  // Make a batch around 1Mi bytes.
+  const size_t batch_size = std::max(size_t{1}, size_t{1000000} / str_bytes);
+  std::vector<absl::linked_hash_set<std::string>> sets(batch_size);
+
+  while (state.KeepRunningBatch(batch_size)) {
+    state.PauseTiming();
+    for (auto& set : sets) set.clear();
+    state.ResumeTiming();
+    for (auto& set : sets) {
+      for (const auto& str : sample) {
+        benchmark::DoNotOptimize(set.insert(str));
+      }
+    }
+  }
+
+  state.SetItemsProcessed(state.iterations() * state.range(0));
+  state.SetBytesProcessed(state.iterations() * str_bytes);
+}
+
+constexpr absl::string_view kFormatShort = "%10d";
+constexpr absl::string_view kFormatLong =
+    "a longer string that exceeds the SSO %10d";
+
+void BM_InsertShortStrings_Hit(benchmark::State& state) {
+  BenchmarkInsertStrings(
+      state, [](int i) { return absl::StrFormat(kFormatShort, i); });
+}
+BENCHMARK(BM_InsertShortStrings_Hit)->Range(1, 1 << 16);
+
+void BM_InsertLongStrings_Hit(benchmark::State& state) {
+  BenchmarkInsertStrings(state,
+                         [](int i) { return absl::StrFormat(kFormatLong, i); });
+}
+BENCHMARK(BM_InsertLongStrings_Hit)->Range(1, 1 << 16);
+
+void BM_InsertShortStrings_Miss(benchmark::State& state) {
+  BenchmarkInsertStrings(
+      state, [](int i) { return absl::StrFormat(kFormatShort, i % 20); });
+}
+BENCHMARK(BM_InsertShortStrings_Miss)->Range(1, 1 << 16);
+
+void BM_InsertLongStrings_Miss(benchmark::State& state) {
+  BenchmarkInsertStrings(
+      state, [](int i) { return absl::StrFormat(kFormatLong, i % 20); });
+}
+BENCHMARK(BM_InsertLongStrings_Miss)->Range(1, 1 << 16);
+
+}  // namespace
diff --git a/absl/container/linked_hash_set_test.cc b/absl/container/linked_hash_set_test.cc
new file mode 100644
index 0000000..9a3af62
--- /dev/null
+++ b/absl/container/linked_hash_set_test.cc
@@ -0,0 +1,947 @@
+// Copyright 2025 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/container/linked_hash_set.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/container/internal/hash_generator_testing.h"
+#include "absl/container/internal/hash_policy_testing.h"
+#include "absl/container/internal/heterogeneous_lookup_testing.h"
+#include "absl/container/internal/test_instance_tracker.h"
+#include "absl/container/internal/unordered_set_constructor_test.h"
+#include "absl/container/internal/unordered_set_lookup_test.h"
+#include "absl/container/internal/unordered_set_members_test.h"
+#include "absl/container/internal/unordered_set_modifiers_test.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+namespace {
+
+using ::testing::ElementsAre;
+using ::testing::ElementsAreArray;
+using ::testing::Pointee;
+
+template <class T>
+using Set =
+    linked_hash_set<T, StatefulTestingHash, StatefulTestingEqual, Alloc<T>>;
+
+using SetTypes =
+    ::testing::Types<Set<int>, Set<std::string>, Set<Enum>, Set<EnumClass>>;
+
+INSTANTIATE_TYPED_TEST_SUITE_P(LinkedHashSet, ConstructorTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(LinkedHashSet, LookupTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(LinkedHashSet, MembersTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(LinkedHashSet, ModifiersTest, SetTypes);
+
+// Tests that the range constructor works.
+TEST(LinkedHashSetTest, RangeConstruct) {
+  const auto items = {1, 2, 3};
+  EXPECT_THAT(linked_hash_set<int>(items.begin(), items.end()),
+              ElementsAre(1, 2, 3));
+}
+
+// Tests that copying works.
+TEST(LinkedHashSetTest, Copy) {
+  linked_hash_set<int> m{4, 8, 15, 16, 23, 42};
+  auto copy = m;
+
+  auto found = copy.find(8);
+  ASSERT_TRUE(found != copy.end());
+  for (auto iter = copy.begin(); iter != copy.end(); ++iter) {
+    if (iter == found) return;
+  }
+  FAIL() << "Copied set's find method returned an invalid iterator.";
+}
+
+// Tests that assignment works.
+TEST(LinkedHashSetTest, Assign) {
+  linked_hash_set<int> m{2, 3};
+  linked_hash_set<int> n{4};
+
+  n = m;
+  EXPECT_TRUE(n.contains(2));
+  auto found = n.find(2);
+  ASSERT_TRUE(found != n.end());
+  for (auto iter = n.begin(); iter != n.end(); ++iter) {
+    if (iter == found) return;
+  }
+  FAIL() << "Assigned set's find method returned an invalid iterator.";
+}
+
+// Tests that self-assignment works.
+TEST(LinkedHashSetTest, SelfAssign) {
+  linked_hash_set<int> a{1, 2, 3};
+  auto& a_ref = a;
+  a = a_ref;
+
+  EXPECT_TRUE(a.contains(2));
+  auto found = a.find(2);
+  ASSERT_TRUE(found != a.end());
+  for (auto iter = a.begin(); iter != a.end(); ++iter) {
+    if (iter == found) return;
+  }
+  FAIL() << "Assigned set's find method returned an invalid iterator.";
+}
+
+// Tests that move constructor works.
+TEST(LinkedHashSetTest, Move) {
+  // Use unique_ptr as an example of a non-copyable type.
+  linked_hash_set<std::unique_ptr<int>> m;
+  m.insert(std::make_unique<int>(2));
+  m.insert(std::make_unique<int>(3));
+  linked_hash_set<std::unique_ptr<int>> n = std::move(m);
+  EXPECT_THAT(n, ElementsAre(Pointee(2), Pointee(3)));
+}
+
+// Tests that self-moving works.
+TEST(LinkedHashSetTest, SelfMove) {
+  linked_hash_set<int> a{1, 2, 3};
+  auto& a_ref = a;
+  a = std::move(a_ref);
+  EXPECT_THAT(a, ElementsAre(1, 2, 3));
+}
+
+struct IntUniquePtrHash {
+  size_t operator()(const std::unique_ptr<int>& p) const {
+    return static_cast<size_t>(*p);
+  }
+};
+
+struct IntUniquePtrEq {
+  size_t operator()(const std::unique_ptr<int>& a,
+                    const std::unique_ptr<int>& b) const {
+    return *a == *b;
+  }
+};
+
+// Pretty artificial for a set, but unique_ptr is a convenient move-only type.
+TEST(LinkedHashSetTest, CanInsertMoveOnly) {
+  linked_hash_set<std::unique_ptr<int>, IntUniquePtrHash, IntUniquePtrEq> s;
+  std::vector<int> data = {4, 8, 15, 16, 23, 42};
+  for (int x : data) s.insert(std::make_unique<int>(x));
+  EXPECT_EQ(s.size(), data.size());
+  for (const std::unique_ptr<int>& elt : s) {
+    EXPECT_TRUE(s.contains(elt));
+    EXPECT_TRUE(s.find(elt) != s.end());
+  }
+}
+
+TEST(LinkedHashSetTest, CanMoveMoveOnly) {
+  linked_hash_set<std::unique_ptr<int>, IntUniquePtrHash, IntUniquePtrEq> s;
+  std::vector<int> data = {4, 8, 15, 16, 23, 42};
+  for (int x : data) s.insert(std::make_unique<int>(x));
+  linked_hash_set<std::unique_ptr<int>, IntUniquePtrHash, IntUniquePtrEq> ss =
+      std::move(s);
+  EXPECT_EQ(ss.size(), data.size());
+}
+
+TEST(LinkedHashSetTest, CanEmplaceMoveOnly) {
+  linked_hash_set<std::unique_ptr<int>, IntUniquePtrHash, IntUniquePtrEq> s;
+  std::vector<int> data = {4, 8, 15, 16, 23, 42};
+  for (const int x : data) {
+    s.emplace(new int{x});
+  }
+  EXPECT_EQ(s.size(), data.size());
+  for (const std::unique_ptr<int>& elt : s) {
+    EXPECT_TRUE(s.contains(elt));
+    EXPECT_TRUE(s.find(elt) != s.end());
+  }
+}
+
+TEST(LinkedHashSetTest, CanInsertTransparent) {
+  linked_hash_set<std::string> s;
+  s.insert(absl::string_view("foo"));
+  s.insert(absl::string_view("bar"));
+  s.insert(absl::string_view("foo"));
+  EXPECT_THAT(s, ElementsAre("foo", "bar"));
+}
+
+// Tests that iteration from begin() to end() works
+TEST(LinkedHashSetTest, Iteration) {
+  linked_hash_set<int> m;
+  EXPECT_TRUE(m.begin() == m.end());
+
+  m.insert(2);
+  m.insert(1);
+  m.insert(3);
+
+  linked_hash_set<int>::iterator i = m.begin();
+  ASSERT_TRUE(m.begin() == i);
+  ASSERT_TRUE(m.end() != i);
+  EXPECT_EQ(2, *i);
+
+  ++i;
+  ASSERT_TRUE(m.end() != i);
+  EXPECT_EQ(1, *i);
+
+  ++i;
+  ASSERT_TRUE(m.end() != i);
+  EXPECT_EQ(3, *i);
+
+  ++i;
+  ASSERT_TRUE(m.end() == i);
+}
+
+// Tests that reverse iteration from rbegin() to rend() works
+TEST(LinkedHashSetTest, ReverseIteration) {
+  linked_hash_set<int> m;
+  EXPECT_TRUE(m.rbegin() == m.rend());
+
+  m.insert(2);
+  m.insert(1);
+  m.insert(3);
+
+  linked_hash_set<int>::reverse_iterator i = m.rbegin();
+  ASSERT_TRUE(m.rbegin() == i);
+  ASSERT_TRUE(m.rend() != i);
+  EXPECT_EQ(3, *i);
+
+  ++i;
+  ASSERT_TRUE(m.rend() != i);
+  EXPECT_EQ(1, *i);
+
+  ++i;
+  ASSERT_TRUE(m.rend() != i);
+  EXPECT_EQ(2, *i);
+
+  ++i;
+  ASSERT_TRUE(m.rend() == i);
+}
+
+// Tests that clear() works
+TEST(LinkedHashSetTest, Clear) {
+  linked_hash_set<int> m{2, 1, 3};
+  ASSERT_EQ(3, m.size());
+
+  m.clear();
+  EXPECT_EQ(0, m.size());
+  EXPECT_FALSE(m.contains(1));
+  EXPECT_TRUE(m.find(1) == m.end());
+
+  // Make sure we can call it on an empty set.
+  m.clear();
+  EXPECT_EQ(0, m.size());
+}
+
+// Tests that size() works.
+TEST(LinkedHashSetTest, Size) {
+  linked_hash_set<int> m;
+  EXPECT_EQ(0, m.size());
+  m.insert(2);
+  EXPECT_EQ(1, m.size());
+  m.insert(11);
+  EXPECT_EQ(2, m.size());
+  m.insert(0);
+  EXPECT_EQ(3, m.size());
+  m.insert(0);
+  EXPECT_EQ(3, m.size());
+  m.clear();
+  EXPECT_EQ(0, m.size());
+}
+
+// Tests empty()
+TEST(LinkedHashSetTest, Empty) {
+  linked_hash_set<int> m;
+  ASSERT_TRUE(m.empty());
+  m.insert(2);
+  ASSERT_FALSE(m.empty());
+  m.clear();
+  ASSERT_TRUE(m.empty());
+}
+
+TEST(LinkedHashSetTest, Erase) {
+  linked_hash_set<int> m;
+  ASSERT_EQ(0, m.size());
+  EXPECT_EQ(0, m.erase(2));  // Nothing to erase yet
+
+  m.insert(2);
+  ASSERT_EQ(1, m.size());
+  EXPECT_EQ(1, m.erase(2));
+  EXPECT_EQ(0, m.size());
+  EXPECT_TRUE(m.empty());
+
+  EXPECT_EQ(0, m.erase(2));  // Make sure nothing bad happens if we repeat.
+  EXPECT_EQ(0, m.size());
+  EXPECT_TRUE(m.empty());
+}
+
+TEST(LinkedHashSetTest, Erase2) {
+  linked_hash_set<int> m;
+  ASSERT_EQ(0, m.size());
+  EXPECT_EQ(0, m.erase(2));  // Nothing to erase yet
+
+  m.insert(2);
+  m.insert(1);
+  m.insert(3);
+  m.insert(4);
+  ASSERT_EQ(4, m.size());
+
+  // Erase middle two
+  EXPECT_EQ(1, m.erase(1));
+  EXPECT_EQ(1, m.erase(3));
+
+  EXPECT_EQ(2, m.size());
+
+  // Make sure we can still iterate over everything that's left.
+  linked_hash_set<int>::iterator it = m.begin();
+  ASSERT_TRUE(it != m.end());
+  EXPECT_EQ(2, *it);
+  ++it;
+  ASSERT_TRUE(it != m.end());
+  EXPECT_EQ(4, *it);
+  ++it;
+  ASSERT_TRUE(it == m.end());
+
+  EXPECT_EQ(0, m.erase(1));  // Make sure nothing bad happens if we repeat.
+  ASSERT_EQ(2, m.size());
+
+  EXPECT_EQ(1, m.erase(2));
+  EXPECT_EQ(1, m.erase(4));
+  ASSERT_EQ(0, m.size());
+  EXPECT_TRUE(m.empty());
+
+  EXPECT_EQ(0, m.erase(1));  // Make sure nothing bad happens if we repeat.
+  ASSERT_EQ(0, m.size());
+  EXPECT_TRUE(m.empty());
+}
+
+// Test that erase(iter,iter) and erase(iter) compile and work.
+TEST(LinkedHashSetTest, Erase3) {
+  linked_hash_set<int> m;
+
+  m.insert(1);
+  m.insert(2);
+  m.insert(3);
+  m.insert(4);
+
+  // Erase middle two
+  linked_hash_set<int>::iterator it2 = m.find(2);
+  linked_hash_set<int>::iterator it4 = m.find(4);
+  EXPECT_EQ(m.erase(it2, it4), m.find(4));
+  EXPECT_FALSE(m.contains(2));
+  EXPECT_TRUE(m.find(2) == m.end());
+  EXPECT_FALSE(m.contains(3));
+  EXPECT_TRUE(m.find(3) == m.end());
+  EXPECT_EQ(2, m.size());
+
+  // Make sure we can still iterate over everything that's left.
+  linked_hash_set<int>::iterator it = m.begin();
+  ASSERT_TRUE(it != m.end());
+  EXPECT_EQ(1, *it);
+  ++it;
+  ASSERT_TRUE(it != m.end());
+  EXPECT_EQ(4, *it);
+  ++it;
+  ASSERT_TRUE(it == m.end());
+
+  // Erase first one using an iterator.
+  EXPECT_EQ(m.erase(m.begin()), m.find(4));
+  EXPECT_FALSE(m.contains(1));
+  EXPECT_TRUE(m.find(1) == m.end());
+
+  // Only the last element should be left.
+  EXPECT_TRUE(m.contains(4));
+  it = m.begin();
+  ASSERT_TRUE(it != m.end());
+  EXPECT_EQ(4, *it);
+  ++it;
+  ASSERT_TRUE(it == m.end());
+}
+
+// Test all types of insertion
+TEST(LinkedHashSetTest, Insertion) {
+  linked_hash_set<int> m;
+  ASSERT_EQ(0, m.size());
+  std::pair<linked_hash_set<int>::iterator, bool> result;
+
+  result = m.insert(2);
+  ASSERT_EQ(1, m.size());
+  EXPECT_TRUE(result.second);
+  EXPECT_EQ(2, *result.first);
+  EXPECT_TRUE(m.contains(2));
+  EXPECT_TRUE(m.find(2) != m.end());
+
+  result = m.insert(1);
+  ASSERT_EQ(2, m.size());
+  EXPECT_TRUE(result.second);
+  EXPECT_EQ(1, *result.first);
+  EXPECT_TRUE(m.contains(1));
+  EXPECT_TRUE(m.find(1) != m.end());
+
+  result = m.insert(3);
+  linked_hash_set<int>::iterator result_iterator = result.first;
+  ASSERT_EQ(3, m.size());
+  EXPECT_TRUE(result.second);
+  EXPECT_EQ(3, *result.first);
+  EXPECT_TRUE(m.contains(3));
+  EXPECT_TRUE(m.find(3) != m.end());
+
+  result = m.insert(3);
+  EXPECT_EQ(3, m.size());
+  EXPECT_FALSE(result.second) << "No insertion should have occurred.";
+  EXPECT_TRUE(result_iterator == result.first)
+      << "Duplicate insertion should have given us the original iterator.";
+  EXPECT_TRUE(m.contains(3));
+  EXPECT_TRUE(m.find(3) != m.end());
+
+  std::vector<int> v = {3, 4, 5};
+  m.insert(v.begin(), v.end());
+  // Expect 4 and 5 inserted, 3 not inserted.
+  EXPECT_EQ(5, m.size());
+  EXPECT_TRUE(m.contains(4));
+  EXPECT_NE(m.find(4), m.end());
+  EXPECT_TRUE(m.contains(5));
+  EXPECT_NE(m.find(5), m.end());
+}
+
+TEST(LinkedHashSetTest, HintedInsertionMoveable) {
+  linked_hash_set<int> m = {1, 3};
+  m.insert(m.find(3), 2);
+  EXPECT_THAT(m, ElementsAre(1, 2, 3));
+}
+
+TEST(LinkedHashSetTest, HintedInsertionReference) {
+  linked_hash_set<int> m = {1, 3};
+  const int val = 2;
+  m.insert(m.find(3), val);
+  EXPECT_THAT(m, ElementsAre(1, 2, 3));
+}
+
+TEST(LinkedHashSetTest, HintedEmplaceMoveable) {
+  linked_hash_set<int> m = {1, 3};
+  m.emplace_hint(m.find(3), 2);
+  EXPECT_THAT(m, ElementsAre(1, 2, 3));
+}
+
+TEST(LinkedHashSetTest, HintedEmplaceReference) {
+  linked_hash_set<int> m = {1, 3};
+  const int val = 2;
+  m.emplace_hint(m.find(3), val);
+  EXPECT_THAT(m, ElementsAre(1, 2, 3));
+}
+
+// Test front accessors.
+TEST(LinkedHashSetTest, Front) {
+  linked_hash_set<int> m;
+
+  m.insert(222);
+  m.insert(111);
+  m.insert(333);
+
+  EXPECT_EQ(3, m.size());
+  EXPECT_EQ(222, m.front());
+  m.pop_front();
+  EXPECT_EQ(2, m.size());
+  EXPECT_EQ(111, m.front());
+  m.pop_front();
+  EXPECT_EQ(1, m.size());
+  EXPECT_EQ(333, m.front());
+  m.pop_front();
+  EXPECT_TRUE(m.empty());
+}
+
+// Test back accessors.
+TEST(LinkedHashSetTest, Back) {
+  linked_hash_set<int> m;
+
+  m.insert(222);
+  m.insert(111);
+  m.insert(333);
+
+  EXPECT_EQ(3, m.size());
+  EXPECT_EQ(333, m.back());
+  m.pop_back();
+  EXPECT_EQ(2, m.size());
+  EXPECT_EQ(111, m.back());
+  m.pop_back();
+  EXPECT_EQ(1, m.size());
+  EXPECT_EQ(222, m.back());
+  m.pop_back();
+  EXPECT_TRUE(m.empty());
+}
+
+TEST(LinkedHashSetTest, Find) {
+  linked_hash_set<int> m;
+
+  EXPECT_TRUE(m.end() == m.find(1))
+      << "We shouldn't find anything in an empty set.";
+
+  m.insert(2);
+  EXPECT_TRUE(m.end() == m.find(1))
+      << "We shouldn't find an element that doesn't exist in the set.";
+
+  std::pair<linked_hash_set<int>::iterator, bool> result = m.insert(1);
+  ASSERT_TRUE(result.second);
+  ASSERT_TRUE(m.end() != result.first);
+  EXPECT_TRUE(result.first == m.find(1))
+      << "We should have found an element we know exists in the set.";
+  EXPECT_EQ(1, *result.first);
+
+  // Check that a follow-up insertion doesn't affect our original
+  m.insert(3);
+  linked_hash_set<int>::iterator it = m.find(1);
+  ASSERT_TRUE(m.end() != it);
+  EXPECT_EQ(1, *it);
+
+  m.clear();
+  EXPECT_TRUE(m.end() == m.find(1))
+      << "We shouldn't find anything in a set that we've cleared.";
+}
+
+TEST(LinkedHashSetTest, Contains) {
+  linked_hash_set<int> m;
+
+  EXPECT_FALSE(m.contains(1)) << "The empty set shouldn't contain anything.";
+
+  m.insert(2);
+  EXPECT_FALSE(m.contains(1))
+      << "contains() should not return true for an element that doesn't exist "
+      << "in the set.";
+
+  m.insert(1);
+  EXPECT_TRUE(m.contains(1))
+      << "contains() should return true for an element we know exists in the "
+      << "set.";
+
+  m.clear();
+  EXPECT_FALSE(m.contains(1))
+      << "A set that we've cleared shouldn't contain anything.";
+}
+
+TEST(LinkedHashSetTest, Swap) {
+  linked_hash_set<int> m1;
+  linked_hash_set<int> m2;
+  m1.insert(1);
+  m1.insert(2);
+  m2.insert(3);
+  ASSERT_EQ(2, m1.size());
+  ASSERT_EQ(1, m2.size());
+  m1.swap(m2);
+  ASSERT_EQ(1, m1.size());
+  ASSERT_EQ(2, m2.size());
+}
+
+TEST(LinkedHashSetTest, SelfSwap) {
+  linked_hash_set<int> a{1, 2, 3};
+  using std::swap;
+  swap(a, a);
+  EXPECT_THAT(a, ElementsAre(1, 2, 3));
+}
+
+TEST(LinkedHashSetTest, InitializerList) {
+  linked_hash_set<int> m{1, 3};
+  ASSERT_EQ(2, m.size());
+  EXPECT_TRUE(m.contains(1));
+  linked_hash_set<int>::iterator it = m.find(1);
+  ASSERT_TRUE(m.end() != it);
+  EXPECT_EQ(1, *it);
+  it = m.find(3);
+  EXPECT_TRUE(m.contains(3));
+  ASSERT_TRUE(m.end() != it);
+  EXPECT_EQ(3, *it);
+}
+
+TEST(LinkedHashSetTest, CustomHashAndEquality) {
+  struct CustomIntHash {
+    size_t operator()(int x) const { return 0; }
+  };
+  struct CustomIntEq {
+    bool operator()(int x, int y) const { return abs(x) == abs(y); }
+  };
+  linked_hash_set<int, CustomIntHash, CustomIntEq> m;
+  m.insert(1);
+  EXPECT_EQ(1, m.size());
+  m.insert(2);
+  EXPECT_EQ(2, m.size());
+  EXPECT_FALSE(m.insert(-2).second);
+  EXPECT_EQ(2, m.size());
+  EXPECT_TRUE(m.contains(-1));
+  EXPECT_TRUE(m.find(-1) != m.end());
+}
+
+TEST(LinkedHashSetTest, EqualRange) {
+  linked_hash_set<int> m{3, 1};
+  const auto& const_m = m;
+
+  EXPECT_THAT(m.equal_range(2), testing::Pair(m.end(), m.end()));
+  EXPECT_THAT(const_m.equal_range(2),
+              testing::Pair(const_m.end(), const_m.end()));
+
+  EXPECT_THAT(m.equal_range(1), testing::Pair(m.find(1), ++m.find(1)));
+  EXPECT_THAT(const_m.equal_range(1),
+              testing::Pair(const_m.find(1), ++const_m.find(1)));
+}
+
+TEST(LinkedHashSetTest, ReserveWorks) {
+  linked_hash_set<int> m;
+  EXPECT_EQ(0, m.size());
+  EXPECT_EQ(0.0, m.load_factor());
+  m.reserve(10);
+  EXPECT_LE(10, m.capacity());
+  EXPECT_EQ(0, m.size());
+  EXPECT_EQ(0.0, m.load_factor());
+  m.insert(1);
+  m.insert(2);
+  EXPECT_LE(10, m.capacity());
+  EXPECT_EQ(2, m.size());
+  EXPECT_LT(0.0, m.load_factor());
+}
+
+TEST(LinkedHashSetTest, HeterogeneousTests) {
+  absl::test_internal::InstanceTracker tracker;
+
+  linked_hash_set<ExpensiveType, HeterogeneousHash, HeterogeneousEqual> set;
+  ExpensiveType one(1);
+  tracker.ResetCopiesMovesSwaps();
+  set.insert(one);
+  // Two instances: 'one' var and an instance in the set.
+  EXPECT_EQ(2, tracker.instances());
+  EXPECT_EQ(1, tracker.copies());
+  EXPECT_EQ(0, tracker.moves());
+
+  tracker.ResetCopiesMovesSwaps();
+  set.insert(one);
+  // No construction since key==1 exists.
+  EXPECT_EQ(2, tracker.instances());
+  EXPECT_EQ(0, tracker.copies());
+  EXPECT_EQ(0, tracker.moves());
+
+  tracker.ResetCopiesMovesSwaps();
+  set.emplace(CheapType(1));
+  // No construction since key==1 exists.
+  EXPECT_EQ(2, tracker.instances());
+  EXPECT_EQ(0, tracker.copies());
+  EXPECT_EQ(0, tracker.moves());
+
+  tracker.ResetCopiesMovesSwaps();
+  set.emplace(CheapType(2));
+  // Construction since key==2 doesn't exist in the set.
+  EXPECT_EQ(3, tracker.instances());
+  EXPECT_EQ(0, tracker.copies());
+  EXPECT_EQ(0, tracker.moves());
+  EXPECT_THAT(set, ElementsAre(HasExpensiveValue(1), HasExpensiveValue(2)));
+
+  // find
+  tracker.ResetCopiesMovesSwaps();
+  auto itr = set.find(CheapType(1));
+  ASSERT_NE(itr, set.end());
+  EXPECT_EQ(1, itr->value());
+  // contains
+  EXPECT_TRUE(set.contains(CheapType(2)));
+  // count
+  EXPECT_EQ(1, set.count(CheapType(2)));
+  // equal_range
+  auto eq_itr_pair = set.equal_range(CheapType(2));
+  ASSERT_NE(eq_itr_pair.first, set.end());
+  EXPECT_EQ(2, eq_itr_pair.first->value());
+  // No construction for find, contains, count or equal_range.
+  EXPECT_EQ(3, tracker.instances());
+  EXPECT_EQ(0, tracker.copies());
+  EXPECT_EQ(0, tracker.moves());
+
+  // emplace
+  tracker.ResetCopiesMovesSwaps();
+  set.emplace(3);
+  // Just one construction.
+  EXPECT_EQ(4, tracker.instances());
+  EXPECT_EQ(0, tracker.copies());
+  EXPECT_EQ(0, tracker.moves());
+
+  tracker.ResetCopiesMovesSwaps();
+  set.emplace(3);
+  // No additional construction since key==3 exists.
+  EXPECT_EQ(4, tracker.instances());
+  EXPECT_EQ(0, tracker.copies());
+  EXPECT_EQ(0, tracker.moves());
+  EXPECT_THAT(set, ElementsAre(HasExpensiveValue(1), HasExpensiveValue(2),
+                               HasExpensiveValue(3)));
+
+  // Test std::move() using insert().
+  ExpensiveType four(4);
+  tracker.ResetCopiesMovesSwaps();
+  set.insert(std::move(four));
+  // Two constructions (regular and move).
+  EXPECT_EQ(6, tracker.instances());
+  EXPECT_EQ(0, tracker.copies());
+  EXPECT_EQ(1, tracker.moves());
+
+  EXPECT_THAT(set, ElementsAre(HasExpensiveValue(1), HasExpensiveValue(2),
+                               HasExpensiveValue(3), HasExpensiveValue(4)));
+
+  tracker.ResetCopiesMovesSwaps();
+  set.erase(CheapType(1));
+  // No construction and instance reduced by one.
+  EXPECT_EQ(5, tracker.instances());
+  EXPECT_EQ(0, tracker.copies());
+  EXPECT_EQ(0, tracker.moves());
+  EXPECT_THAT(set, ElementsAre(HasExpensiveValue(2), HasExpensiveValue(3),
+                               HasExpensiveValue(4)));
+}
+
+TEST(LinkedHashSetTest, HeterogeneousStringViewLookup) {
+  linked_hash_set<std::string> set;
+  set.insert("foo");
+  set.insert("bar");
+  set.insert("blah");
+
+  {
+    absl::string_view lookup("foo");
+    auto itr = set.find(lookup);
+    ASSERT_NE(itr, set.end());
+    EXPECT_EQ("foo", *itr);
+  }
+
+  // Not found.
+  {
+    absl::string_view lookup("foobar");
+    EXPECT_EQ(set.end(), set.find(lookup));
+  }
+
+  {
+    absl::string_view lookup("blah");
+    auto itr = set.find(lookup);
+    ASSERT_NE(itr, set.end());
+    EXPECT_EQ("blah", *itr);
+  }
+}
+
+TEST(LinkedHashSetTest, EmplaceString) {
+  std::vector<std::string> v = {"a", "b"};
+  linked_hash_set<absl::string_view> hs(v.begin(), v.end());
+  EXPECT_THAT(hs, ElementsAreArray(v));
+}
+
+TEST(LinkedHashSetTest, BitfieldArgument) {
+  union {
+    int n : 1;
+  };
+  n = 0;
+  linked_hash_set<int> s = {n};
+  s.insert(n);
+  s.insert(s.end(), n);
+  s.insert({n});
+  s.erase(n);
+  s.count(n);
+  s.find(n);
+  s.contains(n);
+  s.equal_range(n);
+}
+
+TEST(LinkedHashSetTest, MergeExtractInsert) {
+  struct Hash {
+    size_t operator()(const std::unique_ptr<int>& p) const { return *p; }
+  };
+  struct Eq {
+    bool operator()(const std::unique_ptr<int>& a,
+                    const std::unique_ptr<int>& b) const {
+      return *a == *b;
+    }
+  };
+  linked_hash_set<std::unique_ptr<int>, Hash, Eq> set1, set2;
+  set1.insert(std::make_unique<int>(7));
+  set1.insert(std::make_unique<int>(17));
+
+  set2.insert(std::make_unique<int>(7));
+  set2.insert(std::make_unique<int>(19));
+
+  EXPECT_THAT(set1, ElementsAre(Pointee(7), Pointee(17)));
+  EXPECT_THAT(set2, ElementsAre(Pointee(7), Pointee(19)));
+
+  set1.merge(set2);
+
+  EXPECT_THAT(set1, ElementsAre(Pointee(7), Pointee(17), Pointee(19)));
+  EXPECT_THAT(set2, ElementsAre(Pointee(7)));
+
+  auto node = set1.extract(std::make_unique<int>(7));
+  EXPECT_TRUE(node);
+  EXPECT_THAT(node.value(), Pointee(7));
+  EXPECT_THAT(set1, ElementsAre(Pointee(17), Pointee(19)));
+
+  auto insert_result = set2.insert(std::move(node));
+  EXPECT_FALSE(node);
+  EXPECT_FALSE(insert_result.inserted);
+  EXPECT_TRUE(insert_result.node);
+  EXPECT_THAT(insert_result.node.value(), Pointee(7));
+  EXPECT_EQ(**insert_result.position, 7);
+  EXPECT_NE(insert_result.position->get(), insert_result.node.value().get());
+  EXPECT_THAT(set2, ElementsAre(Pointee(7)));
+
+  node = set1.extract(std::make_unique<int>(17));
+  EXPECT_TRUE(node);
+  EXPECT_THAT(node.value(), Pointee(17));
+  EXPECT_THAT(set1, ElementsAre(Pointee(19)));
+
+  node.value() = std::make_unique<int>(23);
+
+  insert_result = set2.insert(std::move(node));
+  EXPECT_FALSE(node);
+  EXPECT_TRUE(insert_result.inserted);
+  EXPECT_FALSE(insert_result.node);
+  EXPECT_EQ(**insert_result.position, 23);
+  EXPECT_THAT(set2, ElementsAre(Pointee(7), Pointee(23)));
+}
+
+TEST(LinkedHashSet, ExtractInsert) {
+  linked_hash_set<int> s = {1, 7, 2, 9};
+  auto node = s.extract(1);
+  EXPECT_TRUE(node);
+  EXPECT_EQ(node.value(), 1);
+  EXPECT_THAT(s, ElementsAre(7, 2, 9));
+  EXPECT_FALSE(s.contains(1));
+
+  node.value() = 17;
+  s.insert(std::move(node));
+  EXPECT_FALSE(node);
+  EXPECT_THAT(s, ElementsAre(7, 2, 9, 17));
+  EXPECT_TRUE(s.contains(17));
+
+  node = s.extract(s.find(9));
+  EXPECT_TRUE(node);
+  EXPECT_EQ(node.value(), 9);
+  EXPECT_THAT(s, ElementsAre(7, 2, 17));
+  EXPECT_FALSE(s.contains(9));
+}
+
+TEST(LinkedHashSet, Merge) {
+  linked_hash_set<int> m = {1, 7, 3, 6, 10};
+  linked_hash_set<int> src = {1, 2, 9, 10, 4, 16};
+
+  m.merge(src);
+
+  EXPECT_THAT(m, ElementsAre(1, 7, 3, 6, 10, 2, 9, 4, 16));
+  for (int i : {1, 7, 3, 6, 10, 2, 9, 4, 16}) {
+    EXPECT_TRUE(m.contains(i));
+  }
+  EXPECT_THAT(src, ElementsAre(1, 10));
+  for (int i : {1, 10}) {
+    EXPECT_TRUE(src.contains(i));
+  }
+  for (int i : {2, 9, 4, 16}) {
+    EXPECT_FALSE(src.contains(i));
+  }
+}
+
+TEST(LinkedHashSet, EraseRange) {
+  linked_hash_set<int> set = {1, 2, 3, 4, 5, 25, 36, 7, 8, 9, 81};
+  auto start = set.find(3);
+  auto end = set.find(8);
+  auto itr = set.erase(start, end);
+  ASSERT_NE(itr, set.end());
+  EXPECT_THAT(*itr, 8);
+  EXPECT_THAT(set, ElementsAre(1, 2, 8, 9, 81));
+  for (int i : {1, 2, 8, 9, 81}) {
+    EXPECT_TRUE(set.contains(i));
+  }
+  for (int i : {3, 4, 5, 25, 36, 7}) {
+    EXPECT_FALSE(set.contains(i));
+  }
+}
+
+TEST(LinkedHashSet, InsertInitializerList) {
+  linked_hash_set<int> set;
+  set.insert({1, 7, 2, 9, 3, 29});
+  EXPECT_THAT(set, ElementsAre(1, 7, 2, 9, 3, 29));
+  for (int i : {1, 7, 2, 9, 3, 29}) {
+    EXPECT_TRUE(set.contains(i));
+  }
+}
+
+struct CountedHash {
+  explicit CountedHash(int* count) : count(count) {}
+  size_t operator()(int value) const {
+    ++(*count);
+    return value;
+  }
+  int* count = nullptr;
+};
+
+// Makes a set too big for small object optimization.  Counts the number of
+// hashes in `count`, but leaves `count` set to 0.
+linked_hash_set<int, CountedHash> MakeNonSmallSet(int* count) {
+  const int kFirstKey = -1000;
+  linked_hash_set<int, CountedHash> s(0, CountedHash(count));
+  for (int i = kFirstKey; i < kFirstKey + 100; ++i) {
+    s.insert(i);
+  }
+  *count = 0;
+  return s;
+}
+
+constexpr bool BuildHasDebugModeRehashes() {
+#if !defined(NDEBUG) || defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
+    defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER)
+  return true;
+#else
+  return false;
+#endif
+}
+
+TEST(LinkedHashSetTest, HashCountInOptBuilds) {
+  if (BuildHasDebugModeRehashes()) {
+    GTEST_SKIP() << "Only run under NDEBUG: `assert` statements and sanitizer "
+                    "rehashing may cause redundant hashing.";
+  }
+
+  using Set = linked_hash_set<int, CountedHash>;
+  {
+    int count = 0;
+    Set s = MakeNonSmallSet(&count);
+    s.insert(1);
+    EXPECT_EQ(count, 1);
+    s.erase(1);
+    EXPECT_EQ(count, 2);
+  }
+  {
+    int count = 0;
+    Set s = MakeNonSmallSet(&count);
+    s.insert(3);
+    EXPECT_EQ(count, 1);
+    auto node = s.extract(3);
+    EXPECT_EQ(count, 2);
+    s.insert(std::move(node));
+    EXPECT_EQ(count, 3);
+  }
+  {
+    int count = 0;
+    Set s = MakeNonSmallSet(&count);
+    s.emplace(5);
+    EXPECT_EQ(count, 1);
+  }
+  {
+    int src_count = 0, dst_count = 0;
+    Set src = MakeNonSmallSet(&src_count);
+    Set dst = MakeNonSmallSet(&dst_count);
+    src.insert(7);
+    dst.merge(src);
+    EXPECT_LE(src_count, 200);
+    EXPECT_LE(dst_count, 200);
+  }
+}
+
+}  // namespace
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/container/node_hash_map.h b/absl/container/node_hash_map.h
index 8aed18b..580a044 100644
--- a/absl/container/node_hash_map.h
+++ b/absl/container/node_hash_map.h
@@ -110,25 +110,30 @@
 //   absl::node_hash_map<std::string, std::string> ducks =
 //     {{"a", "huey"}, {"b", "dewey"}, {"c", "louie"}};
 //
-//  // Insert a new element into the node hash map
-//  ducks.insert({"d", "donald"}};
+//   // Insert a new element into the node hash map
+//   ducks.insert({"d", "donald"}};
 //
-//  // Force a rehash of the node hash map
-//  ducks.rehash(0);
+//   // Force a rehash of the node hash map
+//   ducks.rehash(0);
 //
-//  // Find the element with the key "b"
-//  std::string search_key = "b";
-//  auto result = ducks.find(search_key);
-//  if (result != ducks.end()) {
-//    std::cout << "Result: " << result->second << std::endl;
-//  }
-template <class Key, class Value, class Hash = DefaultHashContainerHash<Key>,
-          class Eq = DefaultHashContainerEq<Key>,
-          class Alloc = std::allocator<std::pair<const Key, Value>>>
+//   // Find the element with the key "b"
+//   std::string search_key = "b";
+//   auto result = ducks.find(search_key);
+//   if (result != ducks.end()) {
+//     std::cout << "Result: " << result->second << std::endl;
+//   }
+template <
+    class Key, class Value,
+    class Hash =
+        typename container_internal::NodeHashMapPolicy<Key, Value>::DefaultHash,
+    class Eq =
+        typename container_internal::NodeHashMapPolicy<Key, Value>::DefaultEq,
+    class Alloc = typename container_internal::NodeHashMapPolicy<
+        Key, Value>::DefaultAlloc>
 class ABSL_ATTRIBUTE_OWNER node_hash_map
-    : public absl::container_internal::raw_hash_map<
+    : public absl::container_internal::InstantiateRawHashMap<
           absl::container_internal::NodeHashMapPolicy<Key, Value>, Hash, Eq,
-          Alloc> {
+          Alloc>::type {
   using Base = typename node_hash_map::raw_hash_map;
 
  public:
@@ -153,9 +158,9 @@
   //
   // * Copy assignment operator
   //
-  //  // Hash functor and Comparator are copied as well
-  //  absl::node_hash_map<int, std::string> map4;
-  //  map4 = map3;
+  //   // Hash functor and Comparator are copied as well
+  //   absl::node_hash_map<int, std::string> map4;
+  //   map4 = map3;
   //
   // * Move constructor
   //
@@ -455,7 +460,9 @@
   //
   // Sets the number of slots in the `node_hash_map` to the number needed to
   // accommodate at least `count` total elements without exceeding the current
-  // maximum load factor, and may rehash the container if needed.
+  // maximum load factor, and may rehash the container if needed. After this
+  // returns, it is guaranteed that `count - size()` elements can be inserted
+  // into the `node_hash_map` without another rehash.
   using Base::reserve;
 
   // node_hash_map::at()
@@ -627,6 +634,10 @@
   using mapped_type = Value;
   using init_type = std::pair</*non const*/ key_type, mapped_type>;
 
+  using DefaultHash = DefaultHashContainerHash<Key>;
+  using DefaultEq = DefaultHashContainerEq<Key>;
+  using DefaultAlloc = std::allocator<std::pair<const Key, Value>>;
+
   template <class Allocator, class... Args>
   static value_type* new_element(Allocator* alloc, Args&&... args) {
     using PairAlloc = typename absl::allocator_traits<
@@ -663,10 +674,10 @@
   static Value& value(value_type* elem) { return elem->second; }
   static const Value& value(const value_type* elem) { return elem->second; }
 
-  template <class Hash>
+  template <class Hash, bool kIsDefault>
   static constexpr HashSlotFn get_hash_slot_fn() {
     return memory_internal::IsLayoutCompatible<Key, Value>::value
-               ? &TypeErasedDerefAndApplyToSlotFn<Hash, Key>
+               ? &TypeErasedDerefAndApplyToSlotFn<Hash, Key, kIsDefault>
                : nullptr;
   }
 };
diff --git a/absl/container/node_hash_set.h b/absl/container/node_hash_set.h
index 6240e2d..f69c6ab 100644
--- a/absl/container/node_hash_set.h
+++ b/absl/container/node_hash_set.h
@@ -108,21 +108,26 @@
 //   absl::node_hash_set<std::string> ducks =
 //     {"huey", "dewey", "louie"};
 //
-//  // Insert a new element into the node hash set
-//  ducks.insert("donald");
+//   // Insert a new element into the node hash set
+//   ducks.insert("donald");
 //
-//  // Force a rehash of the node hash set
-//  ducks.rehash(0);
+//   // Force a rehash of the node hash set
+//   ducks.rehash(0);
 //
-//  // See if "dewey" is present
-//  if (ducks.contains("dewey")) {
-//    std::cout << "We found dewey!" << std::endl;
-//  }
-template <class T, class Hash = DefaultHashContainerHash<T>,
-          class Eq = DefaultHashContainerEq<T>, class Alloc = std::allocator<T>>
+//   // See if "dewey" is present
+//   if (ducks.contains("dewey")) {
+//     std::cout << "We found dewey!" << std::endl;
+//   }
+template <
+    class T,
+    class Hash = typename container_internal::NodeHashSetPolicy<T>::DefaultHash,
+    class Eq = typename container_internal::NodeHashSetPolicy<T>::DefaultEq,
+    class Alloc =
+        typename container_internal::NodeHashSetPolicy<T>::DefaultAlloc>
 class ABSL_ATTRIBUTE_OWNER node_hash_set
-    : public absl::container_internal::raw_hash_set<
-          absl::container_internal::NodeHashSetPolicy<T>, Hash, Eq, Alloc> {
+    : public absl::container_internal::InstantiateRawHashSet<
+          absl::container_internal::NodeHashSetPolicy<T>, Hash, Eq,
+          Alloc>::type {
   using Base = typename node_hash_set::raw_hash_set;
 
  public:
@@ -147,9 +152,9 @@
   //
   // * Copy assignment operator
   //
-  //  // Hash functor and Comparator are copied as well
-  //  absl::node_hash_set<std::string> set4;
-  //  set4 = set3;
+  //   // Hash functor and Comparator are copied as well
+  //   absl::node_hash_set<std::string> set4;
+  //   set4 = set3;
   //
   // * Move constructor
   //
@@ -390,7 +395,9 @@
   //
   // Sets the number of slots in the `node_hash_set` to the number needed to
   // accommodate at least `count` total elements without exceeding the current
-  // maximum load factor, and may rehash the container if needed.
+  // maximum load factor, and may rehash the container if needed. After this
+  // returns, it is guaranteed that `count - size()` elements can be inserted
+  // into the `node_hash_set` without another rehash.
   using Base::reserve;
 
   // node_hash_set::contains()
@@ -527,6 +534,10 @@
   using init_type = T;
   using constant_iterators = std::true_type;
 
+  using DefaultHash = DefaultHashContainerHash<T>;
+  using DefaultEq = DefaultHashContainerEq<T>;
+  using DefaultAlloc = std::allocator<T>;
+
   template <class Allocator, class... Args>
   static T* new_element(Allocator* alloc, Args&&... args) {
     using ValueAlloc =
@@ -557,9 +568,9 @@
 
   static size_t element_space_used(const T*) { return sizeof(T); }
 
-  template <class Hash>
+  template <class Hash, bool kIsDefault>
   static constexpr HashSlotFn get_hash_slot_fn() {
-    return &TypeErasedDerefAndApplyToSlotFn<Hash, T>;
+    return &TypeErasedDerefAndApplyToSlotFn<Hash, T, kIsDefault>;
   }
 };
 }  // namespace container_internal
diff --git a/absl/container/node_hash_set_test.cc b/absl/container/node_hash_set_test.cc
index e616ac1..e1f5bd9 100644
--- a/absl/container/node_hash_set_test.cc
+++ b/absl/container/node_hash_set_test.cc
@@ -35,8 +35,7 @@
 ABSL_NAMESPACE_BEGIN
 namespace container_internal {
 namespace {
-using ::absl::container_internal::hash_internal::Enum;
-using ::absl::container_internal::hash_internal::EnumClass;
+
 using ::testing::IsEmpty;
 using ::testing::Pointee;
 using ::testing::UnorderedElementsAre;
diff --git a/absl/copts/GENERATED_AbseilCopts.cmake b/absl/copts/GENERATED_AbseilCopts.cmake
index 7d8af92..b08c34c 100644
--- a/absl/copts/GENERATED_AbseilCopts.cmake
+++ b/absl/copts/GENERATED_AbseilCopts.cmake
@@ -10,6 +10,46 @@
     "/D_CRT_SECURE_NO_WARNINGS"
     "/D_SCL_SECURE_NO_WARNINGS"
     "/D_ENABLE_EXTENDED_ALIGNED_STORAGE"
+    "-Wmost"
+    "-Wextra"
+    "-Wc++98-compat-extra-semi"
+    "-Wcast-qual"
+    "-Wconversion"
+    "-Wdeprecated-pragma"
+    "-Wfloat-overflow-conversion"
+    "-Wfloat-zero-conversion"
+    "-Wfor-loop-analysis"
+    "-Wformat-security"
+    "-Wgnu-redeclared-enum"
+    "-Winfinite-recursion"
+    "-Winvalid-constexpr"
+    "-Wliteral-conversion"
+    "-Wmissing-declarations"
+    "-Wnullability-completeness"
+    "-Woverlength-strings"
+    "-Wpointer-arith"
+    "-Wself-assign"
+    "-Wshadow-all"
+    "-Wshorten-64-to-32"
+    "-Wsign-conversion"
+    "-Wstring-conversion"
+    "-Wtautological-overlap-compare"
+    "-Wtautological-unsigned-zero-compare"
+    "-Wthread-safety"
+    "-Wundef"
+    "-Wuninitialized"
+    "-Wunreachable-code"
+    "-Wunused-comparison"
+    "-Wunused-local-typedefs"
+    "-Wunused-result"
+    "-Wvla"
+    "-Wwrite-strings"
+    "-Wno-float-conversion"
+    "-Wno-implicit-float-conversion"
+    "-Wno-implicit-int-float-conversion"
+    "-Wno-unknown-warning-option"
+    "-Wno-unused-command-line-argument"
+    "-DNOMINMAX"
 )
 
 list(APPEND ABSL_CLANG_CL_TEST_FLAGS
@@ -19,6 +59,43 @@
     "/D_CRT_SECURE_NO_WARNINGS"
     "/D_SCL_SECURE_NO_WARNINGS"
     "/D_ENABLE_EXTENDED_ALIGNED_STORAGE"
+    "-Wmost"
+    "-Wextra"
+    "-Wc++98-compat-extra-semi"
+    "-Wcast-qual"
+    "-Wconversion"
+    "-Wdeprecated-pragma"
+    "-Wfloat-overflow-conversion"
+    "-Wfloat-zero-conversion"
+    "-Wfor-loop-analysis"
+    "-Wformat-security"
+    "-Wgnu-redeclared-enum"
+    "-Winfinite-recursion"
+    "-Winvalid-constexpr"
+    "-Wliteral-conversion"
+    "-Wmissing-declarations"
+    "-Woverlength-strings"
+    "-Wpointer-arith"
+    "-Wself-assign"
+    "-Wshadow-all"
+    "-Wstring-conversion"
+    "-Wtautological-overlap-compare"
+    "-Wtautological-unsigned-zero-compare"
+    "-Wthread-safety"
+    "-Wundef"
+    "-Wuninitialized"
+    "-Wunreachable-code"
+    "-Wunused-comparison"
+    "-Wunused-local-typedefs"
+    "-Wunused-result"
+    "-Wvla"
+    "-Wwrite-strings"
+    "-Wno-float-conversion"
+    "-Wno-implicit-float-conversion"
+    "-Wno-implicit-int-float-conversion"
+    "-Wno-unknown-warning-option"
+    "-Wno-unused-command-line-argument"
+    "-DNOMINMAX"
     "-Wno-deprecated-declarations"
     "-Wno-implicit-int-conversion"
     "-Wno-missing-prototypes"
@@ -84,6 +161,7 @@
 
 list(APPEND ABSL_LLVM_FLAGS
     "-Wall"
+    "-Wmost"
     "-Wextra"
     "-Wc++98-compat-extra-semi"
     "-Wcast-qual"
@@ -121,11 +199,13 @@
     "-Wno-implicit-float-conversion"
     "-Wno-implicit-int-float-conversion"
     "-Wno-unknown-warning-option"
+    "-Wno-unused-command-line-argument"
     "-DNOMINMAX"
 )
 
 list(APPEND ABSL_LLVM_TEST_FLAGS
     "-Wall"
+    "-Wmost"
     "-Wextra"
     "-Wc++98-compat-extra-semi"
     "-Wcast-qual"
@@ -160,6 +240,7 @@
     "-Wno-implicit-float-conversion"
     "-Wno-implicit-int-float-conversion"
     "-Wno-unknown-warning-option"
+    "-Wno-unused-command-line-argument"
     "-DNOMINMAX"
     "-Wno-deprecated-declarations"
     "-Wno-implicit-int-conversion"
diff --git a/absl/copts/GENERATED_copts.bzl b/absl/copts/GENERATED_copts.bzl
index 23896e9..8c1d7a0 100644
--- a/absl/copts/GENERATED_copts.bzl
+++ b/absl/copts/GENERATED_copts.bzl
@@ -11,6 +11,46 @@
     "/D_CRT_SECURE_NO_WARNINGS",
     "/D_SCL_SECURE_NO_WARNINGS",
     "/D_ENABLE_EXTENDED_ALIGNED_STORAGE",
+    "-Wmost",
+    "-Wextra",
+    "-Wc++98-compat-extra-semi",
+    "-Wcast-qual",
+    "-Wconversion",
+    "-Wdeprecated-pragma",
+    "-Wfloat-overflow-conversion",
+    "-Wfloat-zero-conversion",
+    "-Wfor-loop-analysis",
+    "-Wformat-security",
+    "-Wgnu-redeclared-enum",
+    "-Winfinite-recursion",
+    "-Winvalid-constexpr",
+    "-Wliteral-conversion",
+    "-Wmissing-declarations",
+    "-Wnullability-completeness",
+    "-Woverlength-strings",
+    "-Wpointer-arith",
+    "-Wself-assign",
+    "-Wshadow-all",
+    "-Wshorten-64-to-32",
+    "-Wsign-conversion",
+    "-Wstring-conversion",
+    "-Wtautological-overlap-compare",
+    "-Wtautological-unsigned-zero-compare",
+    "-Wthread-safety",
+    "-Wundef",
+    "-Wuninitialized",
+    "-Wunreachable-code",
+    "-Wunused-comparison",
+    "-Wunused-local-typedefs",
+    "-Wunused-result",
+    "-Wvla",
+    "-Wwrite-strings",
+    "-Wno-float-conversion",
+    "-Wno-implicit-float-conversion",
+    "-Wno-implicit-int-float-conversion",
+    "-Wno-unknown-warning-option",
+    "-Wno-unused-command-line-argument",
+    "-DNOMINMAX",
 ]
 
 ABSL_CLANG_CL_TEST_FLAGS = [
@@ -20,6 +60,43 @@
     "/D_CRT_SECURE_NO_WARNINGS",
     "/D_SCL_SECURE_NO_WARNINGS",
     "/D_ENABLE_EXTENDED_ALIGNED_STORAGE",
+    "-Wmost",
+    "-Wextra",
+    "-Wc++98-compat-extra-semi",
+    "-Wcast-qual",
+    "-Wconversion",
+    "-Wdeprecated-pragma",
+    "-Wfloat-overflow-conversion",
+    "-Wfloat-zero-conversion",
+    "-Wfor-loop-analysis",
+    "-Wformat-security",
+    "-Wgnu-redeclared-enum",
+    "-Winfinite-recursion",
+    "-Winvalid-constexpr",
+    "-Wliteral-conversion",
+    "-Wmissing-declarations",
+    "-Woverlength-strings",
+    "-Wpointer-arith",
+    "-Wself-assign",
+    "-Wshadow-all",
+    "-Wstring-conversion",
+    "-Wtautological-overlap-compare",
+    "-Wtautological-unsigned-zero-compare",
+    "-Wthread-safety",
+    "-Wundef",
+    "-Wuninitialized",
+    "-Wunreachable-code",
+    "-Wunused-comparison",
+    "-Wunused-local-typedefs",
+    "-Wunused-result",
+    "-Wvla",
+    "-Wwrite-strings",
+    "-Wno-float-conversion",
+    "-Wno-implicit-float-conversion",
+    "-Wno-implicit-int-float-conversion",
+    "-Wno-unknown-warning-option",
+    "-Wno-unused-command-line-argument",
+    "-DNOMINMAX",
     "-Wno-deprecated-declarations",
     "-Wno-implicit-int-conversion",
     "-Wno-missing-prototypes",
@@ -85,6 +162,7 @@
 
 ABSL_LLVM_FLAGS = [
     "-Wall",
+    "-Wmost",
     "-Wextra",
     "-Wc++98-compat-extra-semi",
     "-Wcast-qual",
@@ -122,11 +200,13 @@
     "-Wno-implicit-float-conversion",
     "-Wno-implicit-int-float-conversion",
     "-Wno-unknown-warning-option",
+    "-Wno-unused-command-line-argument",
     "-DNOMINMAX",
 ]
 
 ABSL_LLVM_TEST_FLAGS = [
     "-Wall",
+    "-Wmost",
     "-Wextra",
     "-Wc++98-compat-extra-semi",
     "-Wcast-qual",
@@ -161,6 +241,7 @@
     "-Wno-implicit-float-conversion",
     "-Wno-implicit-int-float-conversion",
     "-Wno-unknown-warning-option",
+    "-Wno-unused-command-line-argument",
     "-DNOMINMAX",
     "-Wno-deprecated-declarations",
     "-Wno-implicit-int-conversion",
diff --git a/absl/copts/copts.py b/absl/copts/copts.py
index 8cf8f31..c1d1f4a 100644
--- a/absl/copts/copts.py
+++ b/absl/copts/copts.py
@@ -41,8 +41,13 @@
     "-Wno-unused-private-field",
 ]
 
-ABSL_LLVM_FLAGS = [
-    "-Wall",
+# https://github.com/llvm/llvm-project/issues/102982
+# A list of LLVM base flags without -Wall. This is because clang-cl
+# translates -Wall to -Weverything on Windows, mimicking MSVCs
+# behavior. On most other platforms, -Wall is just a set of very good
+# default flags.
+ABSL_LLVM_BASE_FLAGS = [
+    "-Wmost",
     "-Wextra",
     "-Wc++98-compat-extra-semi",
     "-Wcast-qual",
@@ -84,10 +89,13 @@
     # Disable warnings on unknown warning flags (when warning flags are
     # unknown on older compiler versions)
     "-Wno-unknown-warning-option",
+    "-Wno-unused-command-line-argument",
     # Don't define min and max macros (Build on Windows using clang)
     "-DNOMINMAX",
 ]
 
+ABSL_LLVM_FLAGS = ["-Wall"] + ABSL_LLVM_BASE_FLAGS
+
 ABSL_LLVM_TEST_ADDITIONAL_FLAGS = [
     "-Wno-deprecated-declarations",
     "-Wno-implicit-int-conversion",
@@ -163,9 +171,15 @@
     "ABSL_LLVM_TEST_FLAGS": GccStyleFilterAndCombine(
         ABSL_LLVM_FLAGS, ABSL_LLVM_TEST_ADDITIONAL_FLAGS
     ),
-    "ABSL_CLANG_CL_FLAGS": MSVC_BIG_WARNING_FLAGS + MSVC_DEFINES,
+    "ABSL_CLANG_CL_FLAGS": (
+        MSVC_BIG_WARNING_FLAGS + MSVC_DEFINES + ABSL_LLVM_BASE_FLAGS
+    ),
     "ABSL_CLANG_CL_TEST_FLAGS": (
-        MSVC_BIG_WARNING_FLAGS + MSVC_DEFINES + ABSL_LLVM_TEST_ADDITIONAL_FLAGS
+        MSVC_BIG_WARNING_FLAGS
+        + MSVC_DEFINES
+        + GccStyleFilterAndCombine(
+            ABSL_LLVM_BASE_FLAGS, ABSL_LLVM_TEST_ADDITIONAL_FLAGS
+        )
     ),
     "ABSL_MSVC_FLAGS": (
         MSVC_BIG_WARNING_FLAGS + MSVC_WARNING_FLAGS + MSVC_DEFINES
diff --git a/absl/crc/BUILD.bazel b/absl/crc/BUILD.bazel
index b659a7e..22c3cbf 100644
--- a/absl/crc/BUILD.bazel
+++ b/absl/crc/BUILD.bazel
@@ -12,6 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
diff --git a/absl/crc/crc32c_test.cc b/absl/crc/crc32c_test.cc
index df0afb3..eed5a6c 100644
--- a/absl/crc/crc32c_test.cc
+++ b/absl/crc/crc32c_test.cc
@@ -15,11 +15,14 @@
 #include "absl/crc/crc32c.h"
 
 #include <algorithm>
+#include <array>
 #include <cstddef>
 #include <cstdint>
 #include <cstring>
+#include <limits>
 #include <sstream>
 #include <string>
+#include <tuple>
 
 #include "gtest/gtest.h"
 #include "absl/crc/internal/crc32c.h"
@@ -101,6 +104,33 @@
   }
 }
 
+// Test ExtendCrc32cByZeroes() for the full range of the size_t length,
+// including every bit. This is important because ExtendCrc32cByZeroes() is
+// implemented using an array of constants, where each entry in the array is
+// used only when a particular bit in the size_t length is set. This test
+// verifies that every entry in that array is correct.
+TEST(CRC32C, ExtendByZeroesAllLengthBits) {
+  absl::crc32c_t base_crc = absl::crc32c_t{0xc99465aa};
+  const std::array<std::tuple<uint64_t, absl::crc32c_t>, 5> kTestCases = {{
+      {0, absl::crc32c_t(0xc99465aa)},
+      {std::numeric_limits<uint32_t>::max(), absl::crc32c_t(0x9b1d5aaa)},
+      {0x12345678, absl::crc32c_t(0xcf0e9553)},
+      {std::numeric_limits<uint64_t>::max(), absl::crc32c_t(0xf5bff489)},
+      {0x12345678abcdefff, absl::crc32c_t(0xaa1ffb0b)},
+  }};
+  for (const auto &test_case : kTestCases) {
+    uint64_t length = std::get<0>(test_case);
+    absl::crc32c_t expected_value = std::get<1>(test_case);
+    SCOPED_TRACE(length);
+    if (length > std::numeric_limits<size_t>::max()) {
+      // On 32-bit platforms, 64-bit lengths cannot be used or tested.
+      continue;
+    }
+    EXPECT_EQ(absl::ExtendCrc32cByZeroes(base_crc, static_cast<size_t>(length)),
+              expected_value);
+  }
+}
+
 TEST(CRC32C, UnextendByZeroes) {
   constexpr size_t kExtendByValues[] = {2, 200, 20000, 200000, 20000000};
   constexpr size_t kUnextendByValues[] = {0, 100, 10000, 100000, 10000000};
diff --git a/absl/crc/internal/cpu_detect.cc b/absl/crc/internal/cpu_detect.cc
index c59f773..a697601 100644
--- a/absl/crc/internal/cpu_detect.cc
+++ b/absl/crc/internal/cpu_detect.cc
@@ -145,6 +145,14 @@
               }
             case 0x5e:  // Skylake (client)
               return CpuType::kIntelSkylake;
+            case 0x6a:  // Ice Lake
+              return CpuType::kIntelIcelake;
+            case 0x8f:  // Sapphire Rapids
+              return CpuType::kIntelSapphirerapids;
+            case 0xcf:  // Emerald Rapids
+              return CpuType::kIntelEmeraldrapids;
+            case 0xad:  // Granite Rapids
+              return CpuType::kIntelGraniterapidsap;
             default:
               return CpuType::kUnknown;
           }
@@ -210,6 +218,14 @@
           return CpuType::kUnknown;
       }
       break;
+    case 0x1A:
+      switch (model_num) {
+        case 0x2:
+          return CpuType::kAmdTurin;
+        default:
+          return CpuType::kUnknown;
+      }
+      break;
     default:
       return CpuType::kUnknown;
   }
@@ -259,6 +275,7 @@
           case 0xd40: return CpuType::kArmNeoverseV1;
           case 0xd49: return CpuType::kArmNeoverseN2;
           case 0xd4f: return CpuType::kArmNeoverseV2;
+          case 0xd8e: return CpuType::kArmNeoverseN3;
           default:
             return CpuType::kUnknown;
         }
diff --git a/absl/crc/internal/cpu_detect.h b/absl/crc/internal/cpu_detect.h
index 01e1959..e76a802 100644
--- a/absl/crc/internal/cpu_detect.h
+++ b/absl/crc/internal/cpu_detect.h
@@ -30,10 +30,15 @@
   kAmdNaples,
   kAmdMilan,
   kAmdGenoa,
+  kAmdTurin,
   kAmdRyzenV3000,
   kIntelCascadelakeXeon,
   kIntelSkylakeXeon,
   kIntelBroadwell,
+  kIntelIcelake,
+  kIntelSapphirerapids,
+  kIntelEmeraldrapids,
+  kIntelGraniterapidsap,
   kIntelSkylake,
   kIntelIvybridge,
   kIntelSandybridge,
@@ -42,7 +47,8 @@
   kArmNeoverseV1,
   kAmpereSiryn,
   kArmNeoverseN2,
-  kArmNeoverseV2
+  kArmNeoverseV2,
+  kArmNeoverseN3,
 };
 
 // Returns the type of host CPU this code is running on.  Returns kUnknown if
diff --git a/absl/crc/internal/crc_memcpy_x86_arm_combined.cc b/absl/crc/internal/crc_memcpy_x86_arm_combined.cc
index 38f61e9..247b3aa 100644
--- a/absl/crc/internal/crc_memcpy_x86_arm_combined.cc
+++ b/absl/crc/internal/crc_memcpy_x86_arm_combined.cc
@@ -422,6 +422,11 @@
       };
     // INTEL_SANDYBRIDGE performs better with SSE than AVX.
     case CpuType::kIntelSandybridge:
+    // Use SIMD memcpy on ARM cores.
+    case CpuType::kArmNeoverseN1:
+    case CpuType::kArmNeoverseN2:
+    case CpuType::kArmNeoverseV1:
+    case CpuType::kArmNeoverseV2:
       return {
           /*.temporal=*/new AcceleratedCrcMemcpyEngine<3, 0>(),
           /*.non_temporal=*/new CrcNonTemporalMemcpyEngine(),
diff --git a/absl/crc/internal/crc_x86_arm_combined.cc b/absl/crc/internal/crc_x86_arm_combined.cc
index 3194bec..ebd9c3f 100644
--- a/absl/crc/internal/crc_x86_arm_combined.cc
+++ b/absl/crc/internal/crc_x86_arm_combined.cc
@@ -100,47 +100,67 @@
 
 namespace {
 
-uint32_t multiply(uint32_t a, uint32_t b) {
-  V128 power = V128_From64WithZeroFill(a);
-  V128 crc = V128_From64WithZeroFill(b);
-  V128 res = V128_PMulLow(power, crc);
+// Does polynomial multiplication a * b * x^33 mod G.
+//
+// One of the multiplicands needs to have an extra factor of x^-33 to cancel out
+// the extra factor of x^33. The extra factor of x^33 comes from:
+//
+// - x^1 from the carry-less multiplication, due to the
+//   "least-significant-bit-first" convention of CRC-32C.
+//
+// - x^32 from using CRC32_u64() to reduce the carry-less product to 32 bits.
+//
+// Both could be avoided, but at the cost of extra instructions. It's more
+// efficient to just drop a factor of x^33 from one of the multiplicands.
+uint32_t MultiplyWithExtraX33(uint32_t a, uint32_t b) {
+  V128 a_vec = V128_From64WithZeroFill(a);
+  V128 b_vec = V128_From64WithZeroFill(b);
+  V128 res = V128_PMulLow(a_vec, b_vec);
 
-  // Combine crc values.
-  //
-  // Adding res to itself is equivalent to multiplying by 2,
-  // or shifting left by 1. Addition is used as not all compilers
-  // are able to generate optimal code without this hint.
-  // https://godbolt.org/z/rr3fMnf39
-  res = V128_Add64(res, res);
-  return static_cast<uint32_t>(V128_Extract32<1>(res)) ^
-         CRC32_u32(0, static_cast<uint32_t>(V128_Low64(res)));
+  return CRC32_u64(0, static_cast<uint64_t>(V128_Low64(res)));
 }
 
-// Powers of crc32c polynomial, for faster ExtendByZeros.
-// Verified against folly:
-// folly/hash/detail/Crc32CombineDetail.cpp
+// The number of low-order bits that ComputeZeroConstant() drops from the
+// length, i.e. treats as zeroes
+constexpr int kNumDroppedBits = 4;
+
+// Precomputed constants for faster ExtendByZeroes(). This was generated by
+// gen_crc32c_consts.py. The entry at index i is x^(2^(i + 3 + kNumDroppedBits)
+// - 33) mod G. That is x^-33 times the polynomial by which the CRC value needs
+// to be multiplied to extend it by 2^(i + 3 + kNumDroppedBits) zero bits, or
+// equivalently 2^(i + kNumDroppedBits) zero bytes. The extra factor of x^-33
+// cancels out the extra factor of x^33 that MultiplyWithExtraX33() introduces.
 constexpr uint32_t kCRC32CPowers[] = {
-    0x82f63b78, 0x6ea2d55c, 0x18b8ea18, 0x510ac59a, 0xb82be955, 0xb8fdb1e7,
-    0x88e56f72, 0x74c360a4, 0xe4172b16, 0x0d65762a, 0x35d73a62, 0x28461564,
-    0xbf455269, 0xe2ea32dc, 0xfe7740e6, 0xf946610b, 0x3c204f8f, 0x538586e3,
-    0x59726915, 0x734d5309, 0xbc1ac763, 0x7d0722cc, 0xd289cabe, 0xe94ca9bc,
-    0x05b74f3f, 0xa51e1f42, 0x40000000, 0x20000000, 0x08000000, 0x00800000,
-    0x00008000, 0x82f63b78, 0x6ea2d55c, 0x18b8ea18, 0x510ac59a, 0xb82be955,
-    0xb8fdb1e7, 0x88e56f72, 0x74c360a4, 0xe4172b16, 0x0d65762a, 0x35d73a62,
-    0x28461564, 0xbf455269, 0xe2ea32dc, 0xfe7740e6, 0xf946610b, 0x3c204f8f,
-    0x538586e3, 0x59726915, 0x734d5309, 0xbc1ac763, 0x7d0722cc, 0xd289cabe,
-    0xe94ca9bc, 0x05b74f3f, 0xa51e1f42, 0x40000000, 0x20000000, 0x08000000,
-    0x00800000, 0x00008000,
+    0x493c7d27, 0xba4fc28e, 0x9e4addf8, 0x0d3b6092, 0xb9e02b86, 0xdd7e3b0c,
+    0x170076fa, 0xa51b6135, 0x82f89c77, 0x54a86326, 0x1dc403cc, 0x5ae703ab,
+    0xc5013a36, 0xac2ac6dd, 0x9b4615a9, 0x688d1c61, 0xf6af14e6, 0xb6ffe386,
+    0xb717425b, 0x478b0d30, 0x54cc62e5, 0x7b2102ee, 0x8a99adef, 0xa7568c8f,
+    0xd610d67e, 0x6b086b3f, 0xd94f3c0b, 0xbf818109, 0x780d5a4d, 0x05ec76f1,
+    0x00000001, 0x493c7d27, 0xba4fc28e, 0x9e4addf8, 0x0d3b6092, 0xb9e02b86,
+    0xdd7e3b0c, 0x170076fa, 0xa51b6135, 0x82f89c77, 0x54a86326, 0x1dc403cc,
+    0x5ae703ab, 0xc5013a36, 0xac2ac6dd, 0x9b4615a9, 0x688d1c61, 0xf6af14e6,
+    0xb6ffe386, 0xb717425b, 0x478b0d30, 0x54cc62e5, 0x7b2102ee, 0x8a99adef,
+    0xa7568c8f, 0xd610d67e, 0x6b086b3f, 0xd94f3c0b, 0xbf818109, 0x780d5a4d,
 };
+// There must be an entry for each non-dropped bit in the size_t length.
+static_assert(std::size(kCRC32CPowers) >= sizeof(size_t) * 8 - kNumDroppedBits);
 
 }  // namespace
 
-// Compute a magic constant, so that multiplying by it is the same as
-// extending crc by length zeros.
+// Compute a magic constant, so that multiplying by it is the same as extending
+// crc by length zeros. The lowest kNumDroppedBits of the length are ignored and
+// treated as zeroes; the caller is assumed to handle any nonzero bits there.
+#if defined(NDEBUG) && ABSL_HAVE_CPP_ATTRIBUTE(clang::no_sanitize)
+// The array accesses in this are safe: `length >= size_t{1} <<
+// kNumDroppedBits`, so `countr_zero(length >> kNumDroppedBits) < sizeof(size_t)
+// * 8 - kNumDroppedBits`, and `length & (length - 1)` cannot introduce bits
+// `>= sizeof(size_t) * 8 - kNumDroppedBits`. The compiler cannot prove this, so
+// manually disable bounds checking.
+[[clang::no_sanitize("array-bounds")]]
+#endif
 uint32_t CRC32AcceleratedX86ARMCombined::ComputeZeroConstant(
     size_t length) const {
-  // Lowest 2 bits are handled separately in ExtendByZeroes
-  length >>= 2;
+  length >>= kNumDroppedBits;
 
   int index = absl::countr_zero(length);
   uint32_t prev = kCRC32CPowers[index];
@@ -149,7 +169,7 @@
   while (length) {
     // For each bit of length, extend by 2**n zeros.
     index = absl::countr_zero(length);
-    prev = multiply(prev, kCRC32CPowers[index]);
+    prev = MultiplyWithExtraX33(prev, kCRC32CPowers[index]);
     length &= length - 1;
   }
   return prev;
@@ -159,22 +179,13 @@
                                                     size_t length) const {
   uint32_t val = *crc;
   // Don't bother with multiplication for small length.
-  switch (length & 3) {
-    case 0:
-      break;
-    case 1:
-      val = CRC32_u8(val, 0);
-      break;
-    case 2:
-      val = CRC32_u16(val, 0);
-      break;
-    case 3:
-      val = CRC32_u8(val, 0);
-      val = CRC32_u16(val, 0);
-      break;
-  }
-  if (length > 3) {
-    val = multiply(val, ComputeZeroConstant(length));
+  if (length & 1) val = CRC32_u8(val, 0);
+  if (length & 2) val = CRC32_u16(val, 0);
+  if (length & 4) val = CRC32_u32(val, 0);
+  if (length & 8) val = CRC32_u64(val, 0);
+  static_assert(kNumDroppedBits == 4);
+  if (length >= size_t{1} << kNumDroppedBits) {
+    val = MultiplyWithExtraX33(val, ComputeZeroConstant(length));
   }
   *crc = val;
 }
@@ -306,6 +317,46 @@
     return crc;
   }
 
+  // Same as Process64BytesCRC, but just interleaved for 2 streams.
+  ABSL_ATTRIBUTE_ALWAYS_INLINE void Process64BytesCRC2Streams(
+      const uint8_t* p0, const uint8_t* p1, uint64_t* crc) const {
+    uint64_t crc0 = crc[0];
+    uint64_t crc1 = crc[1];
+    for (int i = 0; i < 8; i++) {
+      crc0 = CRC32_u64(static_cast<uint32_t>(crc0),
+                       absl::little_endian::Load64(p0));
+      crc1 = CRC32_u64(static_cast<uint32_t>(crc1),
+                       absl::little_endian::Load64(p1));
+      p0 += 8;
+      p1 += 8;
+    }
+    crc[0] = crc0;
+    crc[1] = crc1;
+  }
+
+  // Same as Process64BytesCRC, but just interleaved for 3 streams.
+  ABSL_ATTRIBUTE_ALWAYS_INLINE void Process64BytesCRC3Streams(
+      const uint8_t* p0, const uint8_t* p1, const uint8_t* p2,
+      uint64_t* crc) const {
+    uint64_t crc0 = crc[0];
+    uint64_t crc1 = crc[1];
+    uint64_t crc2 = crc[2];
+    for (int i = 0; i < 8; i++) {
+      crc0 = CRC32_u64(static_cast<uint32_t>(crc0),
+                       absl::little_endian::Load64(p0));
+      crc1 = CRC32_u64(static_cast<uint32_t>(crc1),
+                       absl::little_endian::Load64(p1));
+      crc2 = CRC32_u64(static_cast<uint32_t>(crc2),
+                       absl::little_endian::Load64(p2));
+      p0 += 8;
+      p1 += 8;
+      p2 += 8;
+    }
+    crc[0] = crc0;
+    crc[1] = crc1;
+    crc[2] = crc2;
+  }
+
   // Constants generated by './scripts/gen-crc-consts.py x86_pclmul
   // crc32_lsb_0x82f63b78' from the Linux kernel.
   alignas(16) static constexpr uint64_t kFoldAcross512Bits[2] = {
@@ -339,7 +390,8 @@
 class CRC32AcceleratedX86ARMCombinedMultipleStreams
     : public CRC32AcceleratedX86ARMCombinedMultipleStreamsBase {
   ABSL_ATTRIBUTE_HOT
-  void Extend(uint32_t* crc, const void* bytes, size_t length) const override {
+  void Extend(uint32_t* crc, const void* bytes,
+              const size_t length) const override {
     static_assert(num_crc_streams >= 1 && num_crc_streams <= kMaxStreams,
                   "Invalid number of crc streams");
     static_assert(num_pclmul_streams >= 0 && num_pclmul_streams <= kMaxStreams,
@@ -349,47 +401,15 @@
     uint32_t l = *crc;
     uint64_t l64;
 
-    // We have dedicated instruction for 1,2,4 and 8 bytes.
-    if (length & 8) {
-      ABSL_INTERNAL_STEP8(l, p);
-      length &= ~size_t{8};
-    }
-    if (length & 4) {
-      ABSL_INTERNAL_STEP4(l, p);
-      length &= ~size_t{4};
-    }
-    if (length & 2) {
-      ABSL_INTERNAL_STEP2(l, p);
-      length &= ~size_t{2};
-    }
-    if (length & 1) {
-      ABSL_INTERNAL_STEP1(l, p);
-      length &= ~size_t{1};
-    }
-    if (length == 0) {
-      *crc = l;
-      return;
-    }
-    // length is now multiple of 16.
-
     // For small blocks just run simple loop, because cost of combining multiple
     // streams is significant.
-    if (strategy != CutoffStrategy::Unroll64CRC) {
-      if (length < kSmallCutoff) {
-        while (length >= 16) {
-          ABSL_INTERNAL_STEP8(l, p);
-          ABSL_INTERNAL_STEP8(l, p);
-          length -= 16;
-        }
-        *crc = l;
-        return;
-      }
-    }
-
-    // For medium blocks we run 3 crc streams and combine them as described in
-    // Intel paper above. Running 4th stream doesn't help, because crc
-    // instruction has latency 3 and throughput 1.
-    if (length < kMediumCutoff) {
+    if (strategy != CutoffStrategy::Unroll64CRC && (length < kSmallCutoff)) {
+      // fallthrough; Use the same strategy as we do for processing the
+      // remaining bytes after any other strategy.
+    }  else if (length < kMediumCutoff) {
+      // For medium blocks we run 3 crc streams and combine them as described in
+      // Intel paper above. Running 4th stream doesn't help, because crc
+      // instruction has latency 3 and throughput 1.
       l64 = l;
       if (strategy == CutoffStrategy::Fold3) {
         uint64_t l641 = 0;
@@ -438,6 +458,7 @@
           p += 64;
         }
       }
+      l = static_cast<uint32_t>(l64);
     } else {
       // There is a lot of data, we can ignore combine costs and run all
       // requested streams (num_crc_streams + num_pclmul_streams),
@@ -471,9 +492,19 @@
       uint64_t l64_pclmul[kMaxStreams] = {0};
 
       // Peel first iteration, because PCLMULQDQ stream, needs setup.
-      for (size_t i = 0; i < num_crc_streams; i++) {
-        l64_crc[i] = Process64BytesCRC(crc_streams[i], l64_crc[i]);
-        crc_streams[i] += 16 * 4;
+      if (num_crc_streams == 1) {
+        l64_crc[0] = Process64BytesCRC(crc_streams[0], l64_crc[0]);
+        crc_streams[0] += 16 * 4;
+      } else if (num_crc_streams == 2) {
+        Process64BytesCRC2Streams(crc_streams[0], crc_streams[1], l64_crc);
+        crc_streams[0] += 16 * 4;
+        crc_streams[1] += 16 * 4;
+      } else {
+        Process64BytesCRC3Streams(crc_streams[0], crc_streams[1],
+                                  crc_streams[2], l64_crc);
+        crc_streams[0] += 16 * 4;
+        crc_streams[1] += 16 * 4;
+        crc_streams[2] += 16 * 4;
       }
 
       V128 partialCRC[kMaxStreams][4];
@@ -511,24 +542,28 @@
         // }
         // But unrolling and interleaving PCLMULQDQ and CRC blocks manually
         // gives ~2% performance boost.
-        l64_crc[0] = Process64BytesCRC(crc_streams[0], l64_crc[0]);
-        crc_streams[0] += 16 * 4;
+        if (num_crc_streams == 1) {
+          l64_crc[0] = Process64BytesCRC(crc_streams[0], l64_crc[0]);
+          crc_streams[0] += 16 * 4;
+        } else if (num_crc_streams == 2) {
+          Process64BytesCRC2Streams(crc_streams[0], crc_streams[1], l64_crc);
+          crc_streams[0] += 16 * 4;
+          crc_streams[1] += 16 * 4;
+        } else {
+          Process64BytesCRC3Streams(crc_streams[0], crc_streams[1],
+                                    crc_streams[2], l64_crc);
+          crc_streams[0] += 16 * 4;
+          crc_streams[1] += 16 * 4;
+          crc_streams[2] += 16 * 4;
+        }
         if (num_pclmul_streams > 0) {
           Process64BytesPclmul(pclmul_streams[0], partialCRC[0]);
           pclmul_streams[0] += 16 * 4;
         }
-        if (num_crc_streams > 1) {
-          l64_crc[1] = Process64BytesCRC(crc_streams[1], l64_crc[1]);
-          crc_streams[1] += 16 * 4;
-        }
         if (num_pclmul_streams > 1) {
           Process64BytesPclmul(pclmul_streams[1], partialCRC[1]);
           pclmul_streams[1] += 16 * 4;
         }
-        if (num_crc_streams > 2) {
-          l64_crc[2] = Process64BytesCRC(crc_streams[2], l64_crc[2]);
-          crc_streams[2] += 16 * 4;
-        }
         if (num_pclmul_streams > 2) {
           Process64BytesPclmul(pclmul_streams[2], partialCRC[2]);
           pclmul_streams[2] += 16 * 4;
@@ -542,14 +577,15 @@
       }
 
       // Combine all streams into single result.
+      static_assert(64 % (1 << kNumDroppedBits) == 0);
       uint32_t magic = ComputeZeroConstant(bs * 64);
       l64 = l64_crc[0];
       for (size_t i = 1; i < num_crc_streams; i++) {
-        l64 = multiply(static_cast<uint32_t>(l64), magic);
+        l64 = MultiplyWithExtraX33(static_cast<uint32_t>(l64), magic);
         l64 ^= l64_crc[i];
       }
       for (size_t i = 0; i < num_pclmul_streams; i++) {
-        l64 = multiply(static_cast<uint32_t>(l64), magic);
+        l64 = MultiplyWithExtraX33(static_cast<uint32_t>(l64), magic);
         l64 ^= l64_pclmul[i];
       }
 
@@ -559,15 +595,26 @@
       } else {
         p = crc_streams[num_crc_streams - 1];
       }
+      l = static_cast<uint32_t>(l64);
     }
-    l = static_cast<uint32_t>(l64);
 
+    uint64_t remaining_bytes = static_cast<uint64_t>(e - p);
+    // Process the remaining bytes.
     while ((e - p) >= 16) {
       ABSL_INTERNAL_STEP8(l, p);
       ABSL_INTERNAL_STEP8(l, p);
     }
-    // Process the last few bytes
-    while (p != e) {
+
+    if (remaining_bytes & 8) {
+      ABSL_INTERNAL_STEP8(l, p);
+    }
+    if (remaining_bytes & 4) {
+      ABSL_INTERNAL_STEP4(l, p);
+    }
+    if (remaining_bytes & 2) {
+      ABSL_INTERNAL_STEP2(l, p);
+    }
+    if (remaining_bytes & 1) {
       ABSL_INTERNAL_STEP1(l, p);
     }
 
@@ -593,6 +640,8 @@
     case CpuType::kAmdRome:
     case CpuType::kAmdNaples:
     case CpuType::kAmdMilan:
+    case CpuType::kAmdGenoa:
+    case CpuType::kAmdTurin:
       return new CRC32AcceleratedX86ARMCombinedMultipleStreams<
           3, 1, CutoffStrategy::Fold3>();
     // PCLMULQDQ is fast, use combined PCLMULQDQ + CRC implementation.
@@ -600,6 +649,10 @@
     case CpuType::kIntelSkylakeXeon:
     case CpuType::kIntelBroadwell:
     case CpuType::kIntelSkylake:
+    case CpuType::kIntelIcelake:
+    case CpuType::kIntelSapphirerapids:
+    case CpuType::kIntelEmeraldrapids:
+    case CpuType::kIntelGraniterapidsap:
       return new CRC32AcceleratedX86ARMCombinedMultipleStreams<
           3, 2, CutoffStrategy::Fold3>();
     // PCLMULQDQ is slow, don't use it.
@@ -611,6 +664,7 @@
     case CpuType::kArmNeoverseN1:
     case CpuType::kArmNeoverseN2:
     case CpuType::kArmNeoverseV1:
+    case CpuType::kArmNeoverseN3:
       return new CRC32AcceleratedX86ARMCombinedMultipleStreams<
           1, 1, CutoffStrategy::Unroll64CRC>();
     case CpuType::kAmpereSiryn:
diff --git a/absl/crc/internal/gen_crc32c_consts.py b/absl/crc/internal/gen_crc32c_consts.py
new file mode 100755
index 0000000..f78ae30
--- /dev/null
+++ b/absl/crc/internal/gen_crc32c_consts.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python3
+#
+# Copyright 2025 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.
+
+"""This script generates kCRC32CPowers[]."""
+
+
+def poly_mul(a, b):
+  """Polynomial multiplication: a * b."""
+  product = 0
+  for i in range(b.bit_length()):
+    if (b & (1 << i)) != 0:
+      product ^= a << i
+  return product
+
+
+def poly_div(a, b):
+  """Polynomial division: floor(a / b)."""
+  q = 0
+  while a.bit_length() >= b.bit_length():
+    q ^= 1 << (a.bit_length() - b.bit_length())
+    a ^= b << (a.bit_length() - b.bit_length())
+  return q
+
+
+def poly_reduce(a, b):
+  """Polynomial reduction: a mod b."""
+  return a ^ poly_mul(poly_div(a, b), b)
+
+
+def poly_exp(a, b, g):
+  """Polynomial exponentiation: a^b mod g."""
+  if b == 1:
+    return poly_reduce(a, g)
+  c = poly_exp(a, b // 2, g)
+  c = poly_mul(c, c)
+  if b % 2 != 0:
+    c = poly_mul(c, a)
+  return poly_reduce(c, g)
+
+
+def bitreflect(a, num_bits):
+  """Reflects the bits of the given integer."""
+  if a.bit_length() > num_bits:
+    raise ValueError(f'Integer has more than {num_bits} bits')
+  return sum(((a >> i) & 1) << (num_bits - 1 - i) for i in range(num_bits))
+
+
+G = 0x11EDC6F41  # The CRC-32C reducing polynomial, in the "natural" bit order
+CRC_BITS = 32  # The degree of G, i.e. the 32 in "CRC-32C"
+LSB_FIRST = True  # CRC-32C is a least-significant-bit-first CRC
+NUM_SIZE_BITS = 64  # The maximum number of bits in the length (size_t)
+NUM_DROPPED_BITS = 4  # The number of bits dropped from the length
+LOG2_BITS_PER_BYTE = 3  # log2 of the number of bits in a byte, i.e. log2(8)
+X = 2  # The polynomial 'x', in the "natural" bit order
+
+
+def print_crc32c_powers():
+  """Generates kCRC32CPowers[].
+
+  kCRC32CPowers[] is an array of length NUM_SIZE_BITS - NUM_DROPPED_BITS,
+  whose i'th entry is x^(2^(i + LOG2_BITS_PER_BYTE + NUM_DROPPED_BITS) -
+  CRC_BITS - 1) mod G. See kCRC32CPowers[] in the C++ source for more info.
+  """
+  for i in range(NUM_SIZE_BITS - NUM_DROPPED_BITS):
+    poly = poly_exp(
+        X,
+        2 ** (i + LOG2_BITS_PER_BYTE + NUM_DROPPED_BITS)
+        - CRC_BITS
+        - (1 if LSB_FIRST else 0),
+        G,
+    )
+    poly = bitreflect(poly, CRC_BITS)
+    print(f'0x{poly:0{2*CRC_BITS//8}x}, ', end='')
+
+
+if __name__ == '__main__':
+  print_crc32c_powers()
diff --git a/absl/crc/internal/non_temporal_arm_intrinsics.h b/absl/crc/internal/non_temporal_arm_intrinsics.h
index 9e5ccfc..a0d2f08 100644
--- a/absl/crc/internal/non_temporal_arm_intrinsics.h
+++ b/absl/crc/internal/non_temporal_arm_intrinsics.h
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+// SKIP_ABSL_INLINE_NAMESPACE_CHECK
+
 #ifndef ABSL_CRC_INTERNAL_NON_TEMPORAL_ARM_INTRINSICS_H_
 #define ABSL_CRC_INTERNAL_NON_TEMPORAL_ARM_INTRINSICS_H_
 
@@ -21,7 +23,7 @@
 #include <arm_neon.h>
 
 typedef int64x2_t __m128i; /* 128-bit vector containing integers */
-#define vreinterpretq_m128i_s32(x) vreinterpretq_s64_s32(x)
+#define vreinterpretq_m128i_s64(x) (x)
 #define vreinterpretq_s64_m128i(x) (x)
 
 // Guarantees that every preceding store is globally visible before any
@@ -44,7 +46,7 @@
 // https://msdn.microsoft.com/zh-cn/library/f4k12ae8(v=vs.90).aspx
 static inline __attribute__((always_inline)) __m128i _mm_loadu_si128(
     const __m128i *p) {
-  return vreinterpretq_m128i_s32(vld1q_s32((const int32_t *)p));
+  return vreinterpretq_m128i_s64(vld1q_s64((const int64_t*)p));
 }
 
 // Stores the data in a to the address p without polluting the caches.  If the
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel
index cd0f1de..aad5e28 100644
--- a/absl/debugging/BUILD.bazel
+++ b/absl/debugging/BUILD.bazel
@@ -14,6 +14,9 @@
 # limitations under the License.
 #
 
+load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
@@ -33,6 +36,33 @@
 licenses(["notice"])
 
 cc_library(
+    name = "borrowed_fixup_buffer",
+    srcs = ["internal/borrowed_fixup_buffer.cc"],
+    hdrs = ["internal/borrowed_fixup_buffer.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/base:malloc_internal",
+        "//absl/hash",
+    ],
+)
+
+cc_test(
+    name = "borrowed_fixup_buffer_test",
+    srcs = ["internal/borrowed_fixup_buffer_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":borrowed_fixup_buffer",
+        "//absl/base:config",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
+
+cc_library(
     name = "stacktrace",
     srcs = [
         "internal/stacktrace_aarch64-inl.inc",
@@ -51,10 +81,12 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        ":borrowed_fixup_buffer",
         ":debugging_internal",
         "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:dynamic_annotations",
+        "//absl/base:malloc_internal",
         "//absl/base:raw_logging_internal",
     ],
 )
@@ -65,9 +97,11 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        ":borrowed_fixup_buffer",
         ":stacktrace",
         "//absl/base:config",
         "//absl/base:core_headers",
+        "//absl/base:errno_saver",
         "//absl/types:span",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
@@ -443,6 +477,7 @@
         ":stacktrace",
         "//absl/base:config",
         "//absl/base:core_headers",
+        "//absl/cleanup",
         "@google_benchmark//:benchmark_main",
     ],
 )
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt
index 60b138a..ab3a795 100644
--- a/absl/debugging/CMakeLists.txt
+++ b/absl/debugging/CMakeLists.txt
@@ -18,6 +18,38 @@
 
 absl_cc_library(
   NAME
+    borrowed_fixup_buffer
+  SRCS
+    "internal/borrowed_fixup_buffer.cc"
+  HDRS
+    "internal/borrowed_fixup_buffer.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+    absl::config
+    absl::core_headers
+    absl::hash
+    absl::malloc_internal
+  PUBLIC
+)
+
+absl_cc_test(
+  NAME
+    borrowed_fixup_buffer_test
+  SRCS
+    "internal/borrowed_fixup_buffer_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::borrowed_fixup_buffer
+    absl::config
+    GTest::gmock_main
+)
+
+absl_cc_library(
+  NAME
     stacktrace
   HDRS
     "stacktrace.h"
@@ -38,10 +70,12 @@
   LINKOPTS
     $<$<BOOL:${EXECINFO_LIBRARY}>:${EXECINFO_LIBRARY}>
   DEPS
+    absl::borrowed_fixup_buffer
     absl::debugging_internal
     absl::config
     absl::core_headers
     absl::dynamic_annotations
+    absl::malloc_internal
     absl::raw_logging_internal
   PUBLIC
 )
@@ -57,6 +91,7 @@
     absl::stacktrace
     absl::config
     absl::core_headers
+    absl::errno_saver
     absl::span
     GTest::gmock_main
 )
diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc
index d31f5a1..16609f1 100644
--- a/absl/debugging/failure_signal_handler.cc
+++ b/absl/debugging/failure_signal_handler.cc
@@ -157,8 +157,8 @@
 #ifdef ABSL_HAVE_SIGALTSTACK
 
 static bool SetupAlternateStackOnce() {
-#if defined(__wasm__) || defined(__asjms__)
-  const size_t page_mask = getpagesize() - 1;
+#if defined(__wasm__) || defined(__asmjs__)
+  const size_t page_mask = static_cast<size_t>(getpagesize()) - 1;
 #else
   const size_t page_mask = static_cast<size_t>(sysconf(_SC_PAGESIZE)) - 1;
 #endif
diff --git a/absl/debugging/internal/borrowed_fixup_buffer.cc b/absl/debugging/internal/borrowed_fixup_buffer.cc
new file mode 100644
index 0000000..507a0a2
--- /dev/null
+++ b/absl/debugging/internal/borrowed_fixup_buffer.cc
@@ -0,0 +1,118 @@
+// Copyright 2025 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/debugging/internal/borrowed_fixup_buffer.h"
+
+#include <assert.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <atomic>
+#include <iterator>
+#include <utility>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/low_level_alloc.h"
+#include "absl/hash/hash.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace internal_stacktrace {
+
+// A buffer for holding fix-up information for stack traces of common sizes_.
+struct BorrowedFixupBuffer::FixupStackBuffer {
+  static constexpr size_t kMaxStackElements = 128;  // Can be reduced if needed
+  std::atomic_flag in_use{};
+  uintptr_t frames[kMaxStackElements];
+  int sizes[kMaxStackElements];
+
+  ABSL_CONST_INIT static FixupStackBuffer g_instances[kNumStaticBuffers];
+};
+
+ABSL_CONST_INIT BorrowedFixupBuffer::FixupStackBuffer
+    BorrowedFixupBuffer::FixupStackBuffer::g_instances[kNumStaticBuffers] = {};
+
+BorrowedFixupBuffer::~BorrowedFixupBuffer() {
+  if (borrowed_) {
+    std::move(*this).Unlock();
+  } else {
+    base_internal::LowLevelAlloc::Free(frames_);
+  }
+}
+
+BorrowedFixupBuffer::BorrowedFixupBuffer(size_t length)
+    : borrowed_(0 < length && length <= FixupStackBuffer::kMaxStackElements
+                    ? TryLock()
+                    : nullptr) {
+  if (borrowed_) {
+    InitViaBorrow();
+  } else {
+    InitViaAllocation(length);
+  }
+}
+
+void BorrowedFixupBuffer::InitViaBorrow() {
+  assert(borrowed_);
+  frames_ = borrowed_->frames;
+  sizes_ = borrowed_->sizes;
+}
+
+void BorrowedFixupBuffer::InitViaAllocation(size_t length) {
+  static_assert(alignof(decltype(*frames_)) >= alignof(decltype(*sizes_)),
+                "contiguous layout assumes decreasing alignment, otherwise "
+                "padding may be needed in the middle");
+  assert(!borrowed_);
+
+  base_internal::InitSigSafeArena();
+  void* buf = base_internal::LowLevelAlloc::AllocWithArena(
+      length * (sizeof(*frames_) + sizeof(*sizes_)),
+      base_internal::SigSafeArena());
+
+  if (buf == nullptr) {
+    frames_ = nullptr;
+    sizes_ = nullptr;
+    return;
+  }
+
+  frames_ = new (buf) uintptr_t[length];
+  sizes_ = new (static_cast<void*>(static_cast<unsigned char*>(buf) +
+                                   length * sizeof(*frames_))) int[length];
+}
+
+[[nodiscard]] BorrowedFixupBuffer::FixupStackBuffer*
+BorrowedFixupBuffer::TryLock() {
+  constexpr size_t kNumSlots = std::size(FixupStackBuffer::g_instances);
+  const size_t i = absl::Hash<const void*>()(this) % kNumSlots;
+  for (size_t k = 0; k < kNumSlots; ++k) {
+    auto* instance = &FixupStackBuffer::g_instances[(i + k) % kNumSlots];
+    // Use memory_order_acquire to ensure that no reads and writes on the
+    // borrowed buffer are reordered before the borrowing.
+    if (!instance->in_use.test_and_set(std::memory_order_acquire)) {
+      return instance;
+    }
+  }
+  return nullptr;
+}
+
+void BorrowedFixupBuffer::Unlock() && {
+  // Use memory_order_release to ensure that no reads and writes on the borrowed
+  // buffer are reordered after the borrowing.
+  borrowed_->in_use.clear(std::memory_order_release);
+}
+
+}  // namespace internal_stacktrace
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/debugging/internal/borrowed_fixup_buffer.h b/absl/debugging/internal/borrowed_fixup_buffer.h
new file mode 100644
index 0000000..a8f00c8
--- /dev/null
+++ b/absl/debugging/internal/borrowed_fixup_buffer.h
@@ -0,0 +1,71 @@
+// Copyright 2025 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.
+
+#ifndef ABSL_DEBUGGING_INTERNAL_BORROWED_FIXUP_BUFFER_H_
+#define ABSL_DEBUGGING_INTERNAL_BORROWED_FIXUP_BUFFER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace internal_stacktrace {
+
+// An RAII type that temporarily acquires a buffer for stack trace fix-ups from
+// a pool of preallocated buffers, or attempts to allocate a new buffer if no
+// such buffer is available.
+// When destroyed, returns the buffer to the pool if it borrowed successfully,
+// otherwise deallocates any previously allocated buffer.
+class BorrowedFixupBuffer {
+ public:
+  static constexpr size_t kNumStaticBuffers = 64;
+  ~BorrowedFixupBuffer();
+
+  // The number of frames to allocate space for. Note that allocations can fail.
+  explicit BorrowedFixupBuffer(size_t length);
+
+  uintptr_t* frames() const { return frames_; }
+  int* sizes() const { return sizes_; }
+
+ private:
+  struct FixupStackBuffer;
+
+  uintptr_t* frames_;
+  int* sizes_;
+
+  // The borrowed pre-existing buffer, if any (if we haven't allocated our own)
+  FixupStackBuffer* const borrowed_;
+
+  void InitViaBorrow();
+  void InitViaAllocation(size_t length);
+
+  // Attempts to opportunistically borrow a small buffer in a thread- and
+  // signal-safe manner. Returns nullptr on failure.
+  [[nodiscard]] FixupStackBuffer* TryLock();
+
+  // Returns the borrowed buffer.
+  void Unlock() &&;
+
+  BorrowedFixupBuffer(const BorrowedFixupBuffer&) = delete;
+  BorrowedFixupBuffer& operator=(const BorrowedFixupBuffer&) = delete;
+};
+
+}  // namespace internal_stacktrace
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_BORROWED_FIXUP_BUFFER_H_
diff --git a/absl/debugging/internal/borrowed_fixup_buffer_test.cc b/absl/debugging/internal/borrowed_fixup_buffer_test.cc
new file mode 100644
index 0000000..a856c5d
--- /dev/null
+++ b/absl/debugging/internal/borrowed_fixup_buffer_test.cc
@@ -0,0 +1,97 @@
+// Copyright 2025 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/debugging/internal/borrowed_fixup_buffer.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <functional>
+#include <memory>
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace internal_stacktrace {
+namespace {
+
+TEST(BorrowedFixupBuffer, ProperReuse) {
+  uintptr_t first_borrowed_frame = 0;
+  uintptr_t first_borrowed_size = 0;
+
+  // Ensure that we borrow the same buffer each time, indicating proper reuse.
+  // Disable loop unrolling. We need all iterations to match exactly, to coax
+  // reuse of the the same underlying buffer.
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC unroll 1  // <= 1 disables unrolling
+#endif
+  for (int i = 0; i < 100; ++i) {
+    BorrowedFixupBuffer buf0(0);
+    EXPECT_EQ(buf0.frames(), nullptr);
+    EXPECT_EQ(buf0.sizes(), nullptr);
+
+    BorrowedFixupBuffer buf1(1);
+    EXPECT_NE(buf1.frames(), nullptr);
+    EXPECT_NE(buf1.sizes(), nullptr);
+    if (first_borrowed_frame == 0) {
+      first_borrowed_frame = reinterpret_cast<uintptr_t>(buf1.frames());
+    } else {
+      EXPECT_EQ(reinterpret_cast<uintptr_t>(buf1.frames()),
+                first_borrowed_frame);
+    }
+    if (first_borrowed_size == 0) {
+      first_borrowed_size = reinterpret_cast<uintptr_t>(buf1.sizes());
+    } else {
+      EXPECT_EQ(reinterpret_cast<uintptr_t>(buf1.sizes()), first_borrowed_size);
+    }
+
+    BorrowedFixupBuffer buf2(2);
+    EXPECT_NE(buf2.frames(), buf1.frames());
+    EXPECT_NE(buf2.sizes(), buf1.sizes());
+    EXPECT_NE(buf2.frames(), nullptr);
+    EXPECT_NE(buf2.sizes(), nullptr);
+  }
+}
+
+TEST(BorrowedFixupBuffer, NoOverlap) {
+  using BufferPtr = std::unique_ptr<BorrowedFixupBuffer>;
+  static constexpr std::less<const void*> less;
+  static constexpr size_t kBufLen = 5;
+  static constexpr size_t kNumBuffers =
+      BorrowedFixupBuffer::kNumStaticBuffers * 37 + 1;
+
+  auto bufs = std::make_unique<BufferPtr[]>(kNumBuffers);
+  for (size_t i = 0; i < kNumBuffers; ++i) {
+    bufs[i] = std::make_unique<BorrowedFixupBuffer>(kBufLen);
+  }
+
+  std::sort(bufs.get(), bufs.get() + kNumBuffers,
+            [](const BufferPtr& a, const BufferPtr& b) {
+              return less(a->frames(), b->frames());
+            });
+
+  // Verify there are no overlaps
+  for (size_t i = 1; i < kNumBuffers; ++i) {
+    EXPECT_FALSE(less(bufs[i]->frames(), bufs[i - 1]->frames() + kBufLen));
+    EXPECT_FALSE(less(bufs[i]->sizes(), bufs[i - 1]->sizes() + kBufLen));
+  }
+}
+
+}  // namespace
+}  // namespace internal_stacktrace
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/debugging/internal/demangle.cc b/absl/debugging/internal/demangle.cc
index 5f62ebb..a8d7511 100644
--- a/absl/debugging/internal/demangle.cc
+++ b/absl/debugging/internal/demangle.cc
@@ -28,7 +28,7 @@
 #include "absl/base/config.h"
 #include "absl/debugging/internal/demangle_rust.h"
 
-#if ABSL_INTERNAL_HAS_CXA_DEMANGLE
+#ifdef ABSL_INTERNAL_HAS_CXA_DEMANGLE
 #include <cxxabi.h>
 #endif
 
@@ -2941,7 +2941,7 @@
   std::string out;
   int status = 0;
   char* demangled = nullptr;
-#if ABSL_INTERNAL_HAS_CXA_DEMANGLE
+#ifdef ABSL_INTERNAL_HAS_CXA_DEMANGLE
   demangled = abi::__cxa_demangle(mangled, nullptr, nullptr, &status);
 #endif
   if (status == 0 && demangled != nullptr) {
diff --git a/absl/debugging/internal/demangle_test.cc b/absl/debugging/internal/demangle_test.cc
index 2012184..1731197 100644
--- a/absl/debugging/internal/demangle_test.cc
+++ b/absl/debugging/internal/demangle_test.cc
@@ -1936,11 +1936,11 @@
   return g_demangle_result;
 }
 
-// Demangle stack consumption should be within 8kB for simple mangled names
+// Demangle stack consumption should be within 9kB for simple mangled names
 // with some level of nesting. With alternate signal stack we have 64K,
 // but some signal handlers run on thread stack, and could have arbitrarily
 // little space left (so we don't want to make this number too large).
-const int kStackConsumptionUpperLimit = 8192;
+const int kStackConsumptionUpperLimit = 9670;
 
 // Returns a mangled name nested to the given depth.
 static std::string NestedMangledName(int depth) {
diff --git a/absl/debugging/internal/elf_mem_image.h b/absl/debugging/internal/elf_mem_image.h
index 1fac29c..c8a1036 100644
--- a/absl/debugging/internal/elf_mem_image.h
+++ b/absl/debugging/internal/elf_mem_image.h
@@ -32,10 +32,10 @@
 #error ABSL_HAVE_ELF_MEM_IMAGE cannot be directly set
 #endif
 
-#if defined(__ELF__) && !defined(__OpenBSD__) && !defined(__QNX__) && \
-    !defined(__native_client__) && !defined(__asmjs__) &&             \
-    !defined(__wasm__) && !defined(__HAIKU__) && !defined(__sun) &&   \
-    !defined(__VXWORKS__) && !defined(__hexagon__) && !defined(__XTENSA__)
+#if defined(__ELF__) && !defined(__OpenBSD__) && !defined(__QNX__) &&    \
+    !defined(__asmjs__) && !defined(__wasm__) && !defined(__HAIKU__) &&  \
+    !defined(__sun) && !defined(__VXWORKS__) && !defined(__hexagon__) && \
+    !defined(__XTENSA__)
 #define ABSL_HAVE_ELF_MEM_IMAGE 1
 #endif
 
diff --git a/absl/debugging/internal/examine_stack.cc b/absl/debugging/internal/examine_stack.cc
index 3dd6ba1..cc24ebd 100644
--- a/absl/debugging/internal/examine_stack.cc
+++ b/absl/debugging/internal/examine_stack.cc
@@ -149,6 +149,10 @@
   debug_stack_trace_hook = hook;
 }
 
+SymbolizeUrlEmitterLegacy GetDebugStackTraceHookLegacy() {
+  return debug_stack_trace_hook;
+}
+
 SymbolizeUrlEmitter GetDebugStackTraceHook() { return debug_stack_trace_hook; }
 
 // Returns the program counter from signal context, nullptr if
diff --git a/absl/debugging/internal/examine_stack.h b/absl/debugging/internal/examine_stack.h
index 190af87..2094d62 100644
--- a/absl/debugging/internal/examine_stack.h
+++ b/absl/debugging/internal/examine_stack.h
@@ -32,12 +32,19 @@
 // `hook` may be called from a signal handler.
 typedef void (*SymbolizeUrlEmitter)(void* const stack[], int depth,
                                     OutputWriter* writer, void* writer_arg);
+typedef void (*SymbolizeUrlEmitterLegacy)(void* const stack[], int depth,
+                                          OutputWriter* writer,
+                                          void* writer_arg);
 
 // Registration of SymbolizeUrlEmitter for use inside of a signal handler.
 // This is inherently unsafe and must be signal safe code.
 void RegisterDebugStackTraceHook(SymbolizeUrlEmitter hook);
 SymbolizeUrlEmitter GetDebugStackTraceHook();
 
+// Currently exact copy of above. Needed for the 3-CL dance due to
+// TCMallocDebugStackTraceHook dependency on this API.
+SymbolizeUrlEmitterLegacy GetDebugStackTraceHookLegacy();
+
 // Returns the program counter from signal context, or nullptr if
 // unknown. `vuc` is a ucontext_t*. We use void* to avoid the use of
 // ucontext_t on non-POSIX systems.
diff --git a/absl/debugging/internal/stacktrace_aarch64-inl.inc b/absl/debugging/internal/stacktrace_aarch64-inl.inc
index 1746b5d..bbdce77 100644
--- a/absl/debugging/internal/stacktrace_aarch64-inl.inc
+++ b/absl/debugging/internal/stacktrace_aarch64-inl.inc
@@ -123,7 +123,7 @@
       // earlier in the stack than the old_frame_pointer, then use it. If it is
       // later, then we have already unwound through it and it needs no special
       // handling.
-      if (pre_signal_frame_pointer >= old_frame_pointer) {
+      if (pre_signal_frame_pointer > old_frame_pointer) {
         new_frame_pointer = pre_signal_frame_pointer;
       }
     }
diff --git a/absl/debugging/internal/stacktrace_config.h b/absl/debugging/internal/stacktrace_config.h
index 8f84a87..6fce5e9 100644
--- a/absl/debugging/internal/stacktrace_config.h
+++ b/absl/debugging/internal/stacktrace_config.h
@@ -42,11 +42,14 @@
 #define ABSL_STACKTRACE_INL_HEADER \
   "absl/debugging/internal/stacktrace_emscripten-inl.inc"
 
+// Android local modification: ignore __ANDROID_API__, use a weak symbol
+// instead. This code must compile with API lower than 33, but we want to
+// provide backtracing if supported by the OS at runtime.
 #elif defined(__ANDROID__)
-#if defined(ABSL_HAVE_THREAD_LOCAL)
+#ifdef ABSL_HAVE_THREAD_LOCAL
 #define ABSL_STACKTRACE_INL_HEADER \
   "absl/debugging/internal/stacktrace_generic-inl.inc"
-#endif
+#endif  // defined(ABSL_HAVE_THREAD_LOCAL)
 
 #elif defined(__linux__) && !defined(__ANDROID__)
 
diff --git a/absl/debugging/internal/stacktrace_emscripten-inl.inc b/absl/debugging/internal/stacktrace_emscripten-inl.inc
index 2f39c70..9f87006 100644
--- a/absl/debugging/internal/stacktrace_emscripten-inl.inc
+++ b/absl/debugging/internal/stacktrace_emscripten-inl.inc
@@ -52,13 +52,6 @@
 // Waiting until static initializers run seems to be late enough.
 // This file is included into stacktrace.cc so this will only run once.
 ABSL_ATTRIBUTE_UNUSED static int stacktraces_enabler = []() {
-  // Check if we can even create stacktraces. If not, bail early and leave
-  // disable_stacktraces set as-is.
-  // clang-format off
-  if (!EM_ASM_INT({ return (typeof wasmOffsetConverter !== 'undefined'); })) {
-    return 0;
-  }
-  // clang-format on
   disable_stacktraces.store(false, std::memory_order_relaxed);
   return 0;
 }();
diff --git a/absl/debugging/internal/stacktrace_powerpc-inl.inc b/absl/debugging/internal/stacktrace_powerpc-inl.inc
index f82ca8f..ade4edf 100644
--- a/absl/debugging/internal/stacktrace_powerpc-inl.inc
+++ b/absl/debugging/internal/stacktrace_powerpc-inl.inc
@@ -223,8 +223,9 @@
         }
         if (sizes != nullptr) {
           if (next_sp > sp) {
-            sizes[n] = absl::debugging_internal::StripPointerMetadata(next_sp) -
-                       absl::debugging_internal::StripPointerMetadata(sp);
+            sizes[n] = static_cast<int>(
+                absl::debugging_internal::StripPointerMetadata(next_sp) -
+                absl::debugging_internal::StripPointerMetadata(sp));
           } else {
             // A frame-size of 0 is used to indicate unknown frame size.
             sizes[n] = 0;
diff --git a/absl/debugging/internal/stacktrace_riscv-inl.inc b/absl/debugging/internal/stacktrace_riscv-inl.inc
index f9919c6..7ae7fef 100644
--- a/absl/debugging/internal/stacktrace_riscv-inl.inc
+++ b/absl/debugging/internal/stacktrace_riscv-inl.inc
@@ -162,7 +162,8 @@
               absl::debugging_internal::StripPointerMetadata(frame_pointer);
         }
         if (sizes != nullptr) {
-          sizes[n] = ComputeStackFrameSize(frame_pointer, next_frame_pointer);
+          sizes[n] = static_cast<int>(
+              ComputeStackFrameSize(frame_pointer, next_frame_pointer));
         }
       }
       n++;
diff --git a/absl/debugging/internal/stacktrace_x86-inl.inc b/absl/debugging/internal/stacktrace_x86-inl.inc
index 96b128e..27ee32a 100644
--- a/absl/debugging/internal/stacktrace_x86-inl.inc
+++ b/absl/debugging/internal/stacktrace_x86-inl.inc
@@ -245,6 +245,7 @@
   }
 #endif
 
+  const size_t page_size = static_cast<size_t>(getpagesize());
   const uintptr_t old_fp_u = reinterpret_cast<uintptr_t>(old_fp);
   const uintptr_t new_fp_u = reinterpret_cast<uintptr_t>(new_fp);
 
@@ -261,19 +262,19 @@
   // it's supposed to.
   if (STRICT_UNWINDING &&
       (!WITH_CONTEXT || uc == nullptr || new_fp_u != GetFP(uc))) {
-    // With the stack growing downwards, older stack frame must be
-    // at a greater address that the current one.
-    if (new_fp_u <= old_fp_u) return nullptr;
-
+    // With the stack growing downwards, older stack frame should be
+    // at a greater address that the current one. However if we get multiple
+    // signals handled on altstack the new frame pointer might return to the
+    // main stack, but be different than the value from the most recent
+    // ucontext.
     // If we get a very large frame size, it may be an indication that we
     // guessed frame pointers incorrectly and now risk a paging fault
     // dereferencing a wrong frame pointer. Or maybe not because large frames
     // are possible as well. The main stack is assumed to be readable,
     // so we assume the large frame is legit if we know the real stack bounds
     // and are within the stack.
-    if (new_fp_u - old_fp_u > kMaxFrameBytes) {
-      if (stack_high < kUnknownStackEnd &&
-          static_cast<size_t>(getpagesize()) < stack_low) {
+    if (new_fp_u <= old_fp_u || new_fp_u - old_fp_u > kMaxFrameBytes) {
+      if (stack_high < kUnknownStackEnd && page_size < stack_low) {
         // Stack bounds are known.
         if (!(stack_low < new_fp_u && new_fp_u <= stack_high)) {
           // new_fp_u is not within the known stack.
@@ -310,7 +311,12 @@
   if (new_fp_u >= 0xffffe000) return nullptr;
 #endif
 #if !defined(_WIN32)
-  if (!STRICT_UNWINDING) {
+  const uintptr_t old_fp_page = old_fp_u & ~(page_size - 1);
+  const uintptr_t new_fp_page = new_fp_u & ~(page_size - 1);
+  if (old_fp_page == new_fp_page && (new_fp_u & (sizeof(void*) - 1)) == 0) {
+    // We dereferenced the old_fp above, so it is safe to dereference
+    // new_fp if it's on the same page as the old_fp and is aligned.
+  } else if (!STRICT_UNWINDING) {
     // Lax sanity checks cause a crash in 32-bit tcmalloc/crash_reason_test
     // on AMD-based machines with VDSO-enabled kernels.
     // Make an extra sanity check to insure new_fp is readable.
diff --git a/absl/debugging/internal/symbolize.h b/absl/debugging/internal/symbolize.h
index 5593fde..509f426 100644
--- a/absl/debugging/internal/symbolize.h
+++ b/absl/debugging/internal/symbolize.h
@@ -28,8 +28,8 @@
 
 #ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
 #error ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE cannot be directly set
-#elif defined(__ELF__) && defined(__GLIBC__) && !defined(__native_client__) \
-      && !defined(__asmjs__) && !defined(__wasm__)
+#elif defined(__ELF__) && defined(__GLIBC__) && !defined(__asmjs__) \
+      && !defined(__wasm__)
 #define ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE 1
 
 #include <elf.h>
diff --git a/absl/debugging/internal/vdso_support.cc b/absl/debugging/internal/vdso_support.cc
index 8a588ea..f7e2a44 100644
--- a/absl/debugging/internal/vdso_support.cc
+++ b/absl/debugging/internal/vdso_support.cc
@@ -17,6 +17,7 @@
 // VDSOSupport -- a class representing kernel VDSO (if present).
 
 #include "absl/debugging/internal/vdso_support.h"
+#include "absl/base/attributes.h"
 
 #ifdef ABSL_HAVE_VDSO_SUPPORT     // defined in vdso_support.h
 
@@ -190,6 +191,9 @@
 // This function must be very fast, and may be called from very
 // low level (e.g. tcmalloc). Hence I avoid things like
 // GoogleOnceInit() and ::operator new.
+// The destination in VDSO is unknown to CFI and VDSO does not set MSAN
+// shadow for the return value.
+ABSL_ATTRIBUTE_NO_SANITIZE_CFI
 ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
 int GetCPU() {
   unsigned cpu;
diff --git a/absl/debugging/stacktrace.cc b/absl/debugging/stacktrace.cc
index f71e80c..1a770af 100644
--- a/absl/debugging/stacktrace.cc
+++ b/absl/debugging/stacktrace.cc
@@ -38,6 +38,7 @@
 
 #include <stddef.h>
 #include <stdint.h>
+#include <stdlib.h>
 
 #include <algorithm>
 #include <atomic>
@@ -46,46 +47,23 @@
 #include "absl/base/config.h"
 #include "absl/base/optimization.h"
 #include "absl/base/port.h"
+#include "absl/debugging/internal/borrowed_fixup_buffer.h"
 #include "absl/debugging/internal/stacktrace_config.h"
 
-#ifdef ABSL_INTERNAL_HAVE_ALLOCA
-#error ABSL_INTERNAL_HAVE_ALLOCA cannot be directly set
-#endif
-
-#ifdef _WIN32
-#include <malloc.h>
-#define ABSL_INTERNAL_HAVE_ALLOCA 1
-#else
-#ifdef __has_include
-#if __has_include(<alloca.h>)
-#include <alloca.h>
-#define ABSL_INTERNAL_HAVE_ALLOCA 1
-#elif !defined(alloca)
-static void* alloca(size_t) noexcept { return nullptr; }
-#endif
-#endif
-#endif
-
-#ifdef ABSL_INTERNAL_HAVE_ALLOCA
-static constexpr bool kHaveAlloca = true;
-#else
-static constexpr bool kHaveAlloca = false;
-#endif
-
 #if defined(ABSL_STACKTRACE_INL_HEADER)
 #include ABSL_STACKTRACE_INL_HEADER
 #else
-# error Cannot calculate stack trace: will need to write for your environment
+#error Cannot calculate stack trace: will need to write for your environment
 
-# include "absl/debugging/internal/stacktrace_aarch64-inl.inc"
-# include "absl/debugging/internal/stacktrace_arm-inl.inc"
-# include "absl/debugging/internal/stacktrace_emscripten-inl.inc"
-# include "absl/debugging/internal/stacktrace_generic-inl.inc"
-# include "absl/debugging/internal/stacktrace_powerpc-inl.inc"
-# include "absl/debugging/internal/stacktrace_riscv-inl.inc"
-# include "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
-# include "absl/debugging/internal/stacktrace_win32-inl.inc"
-# include "absl/debugging/internal/stacktrace_x86-inl.inc"
+#include "absl/debugging/internal/stacktrace_aarch64-inl.inc"
+#include "absl/debugging/internal/stacktrace_arm-inl.inc"
+#include "absl/debugging/internal/stacktrace_emscripten-inl.inc"
+#include "absl/debugging/internal/stacktrace_generic-inl.inc"
+#include "absl/debugging/internal/stacktrace_powerpc-inl.inc"
+#include "absl/debugging/internal/stacktrace_riscv-inl.inc"
+#include "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
+#include "absl/debugging/internal/stacktrace_win32-inl.inc"
+#include "absl/debugging/internal/stacktrace_x86-inl.inc"
 #endif
 
 namespace absl {
@@ -97,25 +75,63 @@
 
 template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
 ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(void** result, uintptr_t* frames,
-                                               int* sizes, int max_depth,
+                                               int* sizes, size_t max_depth,
                                                int skip_count, const void* uc,
-                                               int* min_dropped_frames) {
+                                               int* min_dropped_frames,
+                                               bool unwind_with_fixup = true) {
+  unwind_with_fixup =
+      unwind_with_fixup && internal_stacktrace::ShouldFixUpStack();
+
+#ifdef _WIN32
+  if (unwind_with_fixup) {
+    // TODO(b/434184677): Fixups are flaky and not supported on Windows
+    unwind_with_fixup = false;
+#ifndef NDEBUG
+    abort();
+#endif
+  }
+#endif
+
+  // Some implementations of FixUpStack may need to be passed frame
+  // information from Unwind, even if the caller doesn't need that
+  // information. We allocate the necessary buffers for such implementations
+  // here.
+  const internal_stacktrace::BorrowedFixupBuffer fixup_buffer(
+      unwind_with_fixup ? max_depth : 0);
+  if (frames == nullptr) {
+    frames = fixup_buffer.frames();
+  }
+  if (sizes == nullptr) {
+    sizes = fixup_buffer.sizes();
+  }
+
   Unwinder g = custom.load(std::memory_order_acquire);
-  int size;
+  size_t size;
   // Add 1 to skip count for the unwinder function itself
   ++skip_count;
   if (g != nullptr) {
-    size = (*g)(result, sizes, max_depth, skip_count, uc, min_dropped_frames);
+    size = static_cast<size_t>((*g)(result, sizes, static_cast<int>(max_depth),
+                                    skip_count, uc, min_dropped_frames));
     // Frame pointers aren't returned by existing hooks, so clear them.
     if (frames != nullptr) {
       std::fill(frames, frames + size, uintptr_t());
     }
   } else {
-    size = UnwindImpl<IS_STACK_FRAMES, IS_WITH_CONTEXT>(
-        result, frames, sizes, max_depth, skip_count, uc, min_dropped_frames);
+    size = static_cast<size_t>(
+        unwind_with_fixup
+            ? UnwindImpl<true, IS_WITH_CONTEXT>(
+                  result, frames, sizes, static_cast<int>(max_depth),
+                  skip_count, uc, min_dropped_frames)
+            : UnwindImpl<IS_STACK_FRAMES, IS_WITH_CONTEXT>(
+                  result, frames, sizes, static_cast<int>(max_depth),
+                  skip_count, uc, min_dropped_frames));
   }
+  if (unwind_with_fixup) {
+    internal_stacktrace::FixUpStack(result, frames, sizes, max_depth, size);
+  }
+
   ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
-  return size;
+  return static_cast<int>(size);
 }
 
 }  // anonymous namespace
@@ -123,15 +139,8 @@
 ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
 internal_stacktrace::GetStackFrames(void** result, uintptr_t* frames,
                                     int* sizes, int max_depth, int skip_count) {
-  if (internal_stacktrace::ShouldFixUpStack()) {
-    size_t depth = static_cast<size_t>(Unwind<true, true>(
-        result, frames, sizes, max_depth, skip_count, nullptr, nullptr));
-    internal_stacktrace::FixUpStack(result, frames, sizes,
-                                    static_cast<size_t>(max_depth), depth);
-    return static_cast<int>(depth);
-  }
-
-  return Unwind<true, false>(result, frames, sizes, max_depth, skip_count,
+  return Unwind<true, false>(result, frames, sizes,
+                             static_cast<size_t>(max_depth), skip_count,
                              nullptr, nullptr);
 }
 
@@ -140,56 +149,32 @@
                                                int* sizes, int max_depth,
                                                int skip_count, const void* uc,
                                                int* min_dropped_frames) {
-  if (internal_stacktrace::ShouldFixUpStack()) {
-    size_t depth = static_cast<size_t>(Unwind<true, true>(
-        result, frames, sizes, max_depth, skip_count, uc, min_dropped_frames));
-    internal_stacktrace::FixUpStack(result, frames, sizes,
-                                    static_cast<size_t>(max_depth), depth);
-    return static_cast<int>(depth);
-  }
-
-  return Unwind<true, true>(result, frames, sizes, max_depth, skip_count, uc,
+  return Unwind<true, true>(result, frames, sizes,
+                            static_cast<size_t>(max_depth), skip_count, uc,
                             min_dropped_frames);
 }
 
+ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
+internal_stacktrace::GetStackTraceNoFixup(void** result, int max_depth,
+                                          int skip_count) {
+  return Unwind<false, false>(result, nullptr, nullptr,
+                              static_cast<size_t>(max_depth), skip_count,
+                              nullptr, nullptr, /*unwind_with_fixup=*/false);
+}
+
 ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackTrace(
     void** result, int max_depth, int skip_count) {
-  if (internal_stacktrace::ShouldFixUpStack()) {
-    if constexpr (kHaveAlloca) {
-      const size_t nmax = static_cast<size_t>(max_depth);
-      uintptr_t* frames =
-          static_cast<uintptr_t*>(alloca(nmax * sizeof(*frames)));
-      int* sizes = static_cast<int*>(alloca(nmax * sizeof(*sizes)));
-      size_t depth = static_cast<size_t>(Unwind<true, false>(
-          result, frames, sizes, max_depth, skip_count, nullptr, nullptr));
-      internal_stacktrace::FixUpStack(result, frames, sizes, nmax, depth);
-      return static_cast<int>(depth);
-    }
-  }
-
-  return Unwind<false, false>(result, nullptr, nullptr, max_depth, skip_count,
+  return Unwind<false, false>(result, nullptr, nullptr,
+                              static_cast<size_t>(max_depth), skip_count,
                               nullptr, nullptr);
 }
 
 ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
 GetStackTraceWithContext(void** result, int max_depth, int skip_count,
                          const void* uc, int* min_dropped_frames) {
-  if (internal_stacktrace::ShouldFixUpStack()) {
-    if constexpr (kHaveAlloca) {
-      const size_t nmax = static_cast<size_t>(max_depth);
-      uintptr_t* frames =
-          static_cast<uintptr_t*>(alloca(nmax * sizeof(*frames)));
-      int* sizes = static_cast<int*>(alloca(nmax * sizeof(*sizes)));
-      size_t depth = static_cast<size_t>(
-          Unwind<true, true>(result, frames, sizes, max_depth, skip_count, uc,
-                             min_dropped_frames));
-      internal_stacktrace::FixUpStack(result, frames, sizes, nmax, depth);
-      return static_cast<int>(depth);
-    }
-  }
-
-  return Unwind<false, true>(result, nullptr, nullptr, max_depth, skip_count,
-                             uc, min_dropped_frames);
+  return Unwind<false, true>(result, nullptr, nullptr,
+                             static_cast<size_t>(max_depth), skip_count, uc,
+                             min_dropped_frames);
 }
 
 void SetStackUnwinder(Unwinder w) {
diff --git a/absl/debugging/stacktrace.h b/absl/debugging/stacktrace.h
index 8777172..79f7651 100644
--- a/absl/debugging/stacktrace.h
+++ b/absl/debugging/stacktrace.h
@@ -69,6 +69,9 @@
                                      int* sizes, int max_depth, int skip_count,
                                      const void* uc, int* min_dropped_frames);
 
+// As above, but skips fix-ups for efficiency.
+extern int GetStackTraceNoFixup(void** result, int max_depth, int skip_count);
+
 // Same as `absl::DefaultStackUnwinder`, but with an optional `frames` parameter
 // to allow callers to receive the raw stack frame addresses.
 // This is internal for now; do not depend on this externally.
diff --git a/absl/debugging/stacktrace_benchmark.cc b/absl/debugging/stacktrace_benchmark.cc
index 9360baf..eef9850 100644
--- a/absl/debugging/stacktrace_benchmark.cc
+++ b/absl/debugging/stacktrace_benchmark.cc
@@ -12,12 +12,25 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <stddef.h>
+#include <stdint.h>
+
 #include "absl/base/attributes.h"
 #include "absl/base/config.h"
 #include "absl/base/optimization.h"
+#include "absl/cleanup/cleanup.h"
 #include "absl/debugging/stacktrace.h"
 #include "benchmark/benchmark.h"
 
+static bool g_enable_fixup = false;
+
+#if ABSL_HAVE_ATTRIBUTE_WEAK
+// Override these weak symbols if possible.
+bool absl::internal_stacktrace::ShouldFixUpStack() { return g_enable_fixup; }
+void absl::internal_stacktrace::FixUpStack(void**, uintptr_t*, int*, size_t,
+                                           size_t&) {}
+#endif
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace {
@@ -42,14 +55,24 @@
   func(state, --x, depth);
 }
 
+template <bool EnableFixup>
 void BM_GetStackTrace(benchmark::State& state) {
+  const Cleanup restore_state(
+      [prev = g_enable_fixup]() { g_enable_fixup = prev; });
+  g_enable_fixup = EnableFixup;
   int depth = state.range(0);
   for (auto s : state) {
     func(state, depth, depth);
   }
 }
 
-BENCHMARK(BM_GetStackTrace)->DenseRange(10, kMaxStackDepth, 10);
+#if ABSL_HAVE_ATTRIBUTE_WEAK
+auto& BM_GetStackTraceWithFixup = BM_GetStackTrace<true>;
+BENCHMARK(BM_GetStackTraceWithFixup)->DenseRange(10, kMaxStackDepth, 10);
+#endif
+
+auto& BM_GetStackTraceWithoutFixup = BM_GetStackTrace<false>;
+BENCHMARK(BM_GetStackTraceWithoutFixup)->DenseRange(10, kMaxStackDepth, 10);
 }  // namespace
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/debugging/stacktrace_test.cc b/absl/debugging/stacktrace_test.cc
index 4477d84..177db64 100644
--- a/absl/debugging/stacktrace_test.cc
+++ b/absl/debugging/stacktrace_test.cc
@@ -18,17 +18,23 @@
 #include <stdint.h>
 
 #include <algorithm>
+#include <cerrno>
+#include <csignal>
+#include <cstring>
+#include <memory>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "absl/base/attributes.h"
 #include "absl/base/config.h"
+#include "absl/base/internal/errno_saver.h"
 #include "absl/base/optimization.h"
 #include "absl/types/span.h"
 
 static int g_should_fixup_calls = 0;
 static int g_fixup_calls = 0;
 static bool g_enable_fixup = false;
+static uintptr_t g_last_fixup_frame_address = 0;
 
 #if ABSL_HAVE_ATTRIBUTE_WEAK
 bool absl::internal_stacktrace::ShouldFixUpStack() {
@@ -38,6 +44,11 @@
 
 void absl::internal_stacktrace::FixUpStack(void**, uintptr_t*, int*, size_t,
                                            size_t&) {
+  const void* frame_address = nullptr;
+#if ABSL_HAVE_BUILTIN(__builtin_frame_address)
+  frame_address = __builtin_frame_address(0);
+#endif
+  g_last_fixup_frame_address = reinterpret_cast<uintptr_t>(frame_address);
   ++g_fixup_calls;
 }
 #endif
@@ -82,11 +93,29 @@
 
 // This is a separate function to avoid inlining.
 ABSL_ATTRIBUTE_NOINLINE static void FixupNoFixupEquivalenceNoInline() {
-#if defined(__riscv)
-  GTEST_SKIP() << "Skipping test on RISC-V due to pre-existing failure";
+#if !ABSL_HAVE_ATTRIBUTE_WEAK
+  const char* kSkipReason = "Need weak symbol support";
+#elif defined(__riscv)
+  const char* kSkipReason =
+      "Skipping test on RISC-V due to pre-existing failure";
+#elif defined(_WIN32)
+  // TODO(b/434184677): Add support for fixups on Windows if needed
+  const char* kSkipReason =
+      "Skipping test on Windows due to lack of support for fixups";
+#else
+  const char* kSkipReason = nullptr;
 #endif
 
-#if ABSL_HAVE_ATTRIBUTE_WEAK
+  // This conditional is to avoid an unreachable code warning.
+  if (kSkipReason != nullptr) {
+    GTEST_SKIP() << kSkipReason;
+  }
+
+  bool can_rely_on_frame_pointers = false;
+  if (!can_rely_on_frame_pointers) {
+    GTEST_SKIP() << "Frame pointers are required, but not guaranteed in OSS";
+  }
+
   // This test is known not to pass on MSVC (due to weak symbols)
 
   const Cleanup restore_state([enable_fixup = g_enable_fixup,
@@ -206,15 +235,122 @@
       ContainerEq(absl::MakeSpan(b.frames, static_cast<size_t>(b.depth))));
   EXPECT_GT(g_should_fixup_calls, 0);
   EXPECT_GE(g_should_fixup_calls, g_fixup_calls);
-
-  // ==========================================================================
-#else
-  GTEST_SKIP() << "Need weak symbol support";
-#endif
 }
 
 TEST(StackTrace, FixupNoFixupEquivalence) { FixupNoFixupEquivalenceNoInline(); }
 
+TEST(StackTrace, FixupLowStackUsage) {
+#if !ABSL_HAVE_ATTRIBUTE_WEAK
+  const char* kSkipReason = "Skipping test on MSVC due to weak symbols";
+#elif defined(_WIN32)
+  // TODO(b/434184677): Add support for fixups on Windows if needed
+  const char* kSkipReason =
+      "Skipping test on Windows due to lack of support for fixups";
+#else
+  const char* kSkipReason = nullptr;
+#endif
+
+  // This conditional is to avoid an unreachable code warning.
+  if (kSkipReason != nullptr) {
+    GTEST_SKIP() << kSkipReason;
+  }
+
+  const Cleanup restore_state([enable_fixup = g_enable_fixup,
+                               fixup_calls = g_fixup_calls,
+                               should_fixup_calls = g_should_fixup_calls]() {
+    g_enable_fixup = enable_fixup;
+    g_fixup_calls = fixup_calls;
+    g_should_fixup_calls = should_fixup_calls;
+  });
+
+  g_enable_fixup = true;
+
+  // Request a ton of stack frames, regardless of how many are actually used.
+  // It's fine to request more frames than we have, since functions preallocate
+  // memory before discovering how high the stack really is, and we're really
+  // just trying to make sure the preallocations don't overflow the stack.
+  //
+  // Note that we loop in order to cover all sides of any branches in the
+  // implementation that switch allocation behavior (e.g., from stack to heap)
+  // and to ensure that no sides allocate too much stack space.
+  constexpr size_t kPageSize = 4096;
+  for (size_t depth = 2; depth < (1 << 20); depth += depth / 2) {
+    const auto stack = std::make_unique<void*[]>(depth);
+    const auto frames = std::make_unique<int[]>(depth);
+
+    absl::GetStackFrames(stack.get(), frames.get(), static_cast<int>(depth), 0);
+    const void* frame_address = nullptr;
+#if ABSL_HAVE_BUILTIN(__builtin_frame_address)
+    frame_address = __builtin_frame_address(0);
+#endif
+    size_t stack_usage =
+        reinterpret_cast<uintptr_t>(frame_address) - g_last_fixup_frame_address;
+    EXPECT_LT(stack_usage, kPageSize);
+  }
+}
+
+TEST(StackTrace, CustomUnwinderPerformsFixup) {
+#if !ABSL_HAVE_ATTRIBUTE_WEAK
+  const char* kSkipReason = "Need weak symbol support";
+#elif defined(_WIN32)
+  // TODO(b/434184677): Add support for fixups on Windows if needed
+  const char* kSkipReason =
+      "Skipping test on Windows due to lack of support for fixups";
+#else
+  const char* kSkipReason = nullptr;
+#endif
+
+  // This conditional is to avoid an unreachable code warning.
+  if (kSkipReason != nullptr) {
+    GTEST_SKIP() << kSkipReason;
+  }
+
+  constexpr int kSkip = 1;  // Skip our own frame, whose return PCs won't match
+  constexpr auto kStackCount = 1;
+
+  absl::SetStackUnwinder(absl::DefaultStackUnwinder);
+  const Cleanup restore_state([enable_fixup = g_enable_fixup,
+                               fixup_calls = g_fixup_calls,
+                               should_fixup_calls = g_should_fixup_calls]() {
+    absl::SetStackUnwinder(nullptr);
+    g_enable_fixup = enable_fixup;
+    g_fixup_calls = fixup_calls;
+    g_should_fixup_calls = should_fixup_calls;
+  });
+
+  StackTrace trace;
+
+  g_enable_fixup = true;
+  g_should_fixup_calls = 0;
+  g_fixup_calls = 0;
+  absl::GetStackTrace(trace.result, kSkip, kStackCount);
+  EXPECT_GT(g_should_fixup_calls, 0);
+  EXPECT_GT(g_fixup_calls, 0);
+
+  g_enable_fixup = true;
+  g_should_fixup_calls = 0;
+  g_fixup_calls = 0;
+  absl::GetStackFrames(trace.result, trace.sizes, kSkip, kStackCount);
+  EXPECT_GT(g_should_fixup_calls, 0);
+  EXPECT_GT(g_fixup_calls, 0);
+
+  g_enable_fixup = true;
+  g_should_fixup_calls = 0;
+  g_fixup_calls = 0;
+  absl::GetStackTraceWithContext(trace.result, kSkip, kStackCount, nullptr,
+                                 nullptr);
+  EXPECT_GT(g_should_fixup_calls, 0);
+  EXPECT_GT(g_fixup_calls, 0);
+
+  g_enable_fixup = true;
+  g_should_fixup_calls = 0;
+  g_fixup_calls = 0;
+  absl::GetStackFramesWithContext(trace.result, trace.sizes, kSkip, kStackCount,
+                                  nullptr, nullptr);
+  EXPECT_GT(g_should_fixup_calls, 0);
+  EXPECT_GT(g_fixup_calls, 0);
+}
+
 #if ABSL_HAVE_BUILTIN(__builtin_frame_address)
 struct FrameInfo {
   const void* return_address;
@@ -295,4 +431,75 @@
 }
 #endif
 
+// This test is Linux specific.
+#if defined(__linux__)
+const void* g_return_address = nullptr;
+bool g_sigusr2_raised = false;
+
+void SigUsr2Handler(int, siginfo_t*, void* uc) {
+  absl::base_internal::ErrnoSaver errno_saver;
+  // Many platforms don't support this by default.
+  bool support_is_expected = false;
+  constexpr int kMaxStackDepth = 64;
+  void* result[kMaxStackDepth];
+  int depth =
+      absl::GetStackTraceWithContext(result, kMaxStackDepth, 0, uc, nullptr);
+  // Verify we can unwind past the nested signal handlers.
+  if (support_is_expected) {
+    EXPECT_THAT(absl::MakeSpan(result, static_cast<size_t>(depth)),
+                Contains(g_return_address).Times(1));
+  }
+  depth = absl::GetStackTrace(result, kMaxStackDepth, 0);
+  if (support_is_expected) {
+    EXPECT_THAT(absl::MakeSpan(result, static_cast<size_t>(depth)),
+                Contains(g_return_address).Times(1));
+  }
+  g_sigusr2_raised = true;
+}
+
+void SigUsr1Handler(int, siginfo_t*, void*) {
+  raise(SIGUSR2);
+  ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
+}
+
+ABSL_ATTRIBUTE_NOINLINE void RaiseSignal() {
+  g_return_address = __builtin_return_address(0);
+  raise(SIGUSR1);
+  ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
+}
+
+ABSL_ATTRIBUTE_NOINLINE void TestNestedSignal() {
+  constexpr size_t kAltstackSize = 1 << 14;
+  // Allocate altstack on regular stack to make sure it'll have a higher
+  // address than some of the regular stack frames.
+  char space[kAltstackSize];
+  stack_t altstack;
+  stack_t old_stack;
+  altstack.ss_sp = space;
+  altstack.ss_size = kAltstackSize;
+  altstack.ss_flags = 0;
+  ASSERT_EQ(sigaltstack(&altstack, &old_stack), 0) << strerror(errno);
+  struct sigaction act;
+  struct sigaction oldusr1act;
+  struct sigaction oldusr2act;
+  act.sa_sigaction = SigUsr1Handler;
+  act.sa_flags = SA_SIGINFO | SA_ONSTACK;
+  sigemptyset(&act.sa_mask);
+  ASSERT_EQ(sigaction(SIGUSR1, &act, &oldusr1act), 0) << strerror(errno);
+  act.sa_sigaction = SigUsr2Handler;
+  ASSERT_EQ(sigaction(SIGUSR2, &act, &oldusr2act), 0) << strerror(errno);
+  RaiseSignal();
+  ASSERT_EQ(sigaltstack(&old_stack, nullptr), 0) << strerror(errno);
+  ASSERT_EQ(sigaction(SIGUSR1, &oldusr1act, nullptr), 0) << strerror(errno);
+  ASSERT_EQ(sigaction(SIGUSR2, &oldusr2act, nullptr), 0) << strerror(errno);
+  ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
+}
+
+TEST(StackTrace, NestedSignal) {
+  // Verify we can unwind past the nested signal handlers.
+  TestNestedSignal();
+  EXPECT_TRUE(g_sigusr2_raised);
+}
+#endif
+
 }  // namespace
diff --git a/absl/debugging/symbolize_elf.inc b/absl/debugging/symbolize_elf.inc
index 9836c93..0317bbc 100644
--- a/absl/debugging/symbolize_elf.inc
+++ b/absl/debugging/symbolize_elf.inc
@@ -167,22 +167,22 @@
 // We are using SpinLock and not a Mutex here, because we may be called
 // from inside Mutex::Lock itself, and it prohibits recursive calls.
 // This happens in e.g. base/stacktrace_syscall_unittest.
-// Moreover, we are using only TryLock(), if the decorator list
+// Moreover, we are using only try_lock(), if the decorator list
 // is being modified (is busy), we skip all decorators, and possibly
 // loose some info. Sorry, that's the best we could do.
 ABSL_CONST_INIT absl::base_internal::SpinLock g_decorators_mu(
-    absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY);
+    absl::base_internal::SCHEDULE_KERNEL_ONLY);
 
 const int kMaxFileMappingHints = 8;
 int g_num_file_mapping_hints;
 FileMappingHint g_file_mapping_hints[kMaxFileMappingHints];
 // Protects g_file_mapping_hints.
 ABSL_CONST_INIT absl::base_internal::SpinLock g_file_mapping_mu(
-    absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY);
+    absl::base_internal::SCHEDULE_KERNEL_ONLY);
 
 // Async-signal-safe function to zero a buffer.
 // memset() is not guaranteed to be async-signal-safe.
-static void SafeMemZero(void* p, size_t size) {
+static void SafeMemZero(void *p, size_t size) {
   unsigned char *c = static_cast<unsigned char *>(p);
   while (size--) {
     *c++ = 0;
@@ -233,29 +233,6 @@
 };
 
 // ---------------------------------------------------------------
-// An async-signal-safe arena for LowLevelAlloc
-static std::atomic<base_internal::LowLevelAlloc::Arena *> g_sig_safe_arena;
-
-static base_internal::LowLevelAlloc::Arena *SigSafeArena() {
-  return g_sig_safe_arena.load(std::memory_order_acquire);
-}
-
-static void InitSigSafeArena() {
-  if (SigSafeArena() == nullptr) {
-    base_internal::LowLevelAlloc::Arena *new_arena =
-        base_internal::LowLevelAlloc::NewArena(
-            base_internal::LowLevelAlloc::kAsyncSignalSafe);
-    base_internal::LowLevelAlloc::Arena *old_value = nullptr;
-    if (!g_sig_safe_arena.compare_exchange_strong(old_value, new_arena,
-                                                  std::memory_order_release,
-                                                  std::memory_order_relaxed)) {
-      // We lost a race to allocate an arena; deallocate.
-      base_internal::LowLevelAlloc::DeleteArena(new_arena);
-    }
-  }
-}
-
-// ---------------------------------------------------------------
 // An AddrMap is a vector of ObjFile, using SigSafeArena() for allocation.
 
 class AddrMap {
@@ -287,7 +264,7 @@
     size_t new_allocated = allocated_ * 2 + 50;
     ObjFile *new_obj_ =
         static_cast<ObjFile *>(base_internal::LowLevelAlloc::AllocWithArena(
-            new_allocated * sizeof(*new_obj_), SigSafeArena()));
+            new_allocated * sizeof(*new_obj_), base_internal::SigSafeArena()));
     if (obj_) {
       memcpy(new_obj_, obj_, allocated_ * sizeof(*new_obj_));
       base_internal::LowLevelAlloc::Free(obj_);
@@ -335,8 +312,9 @@
  private:
   char *CopyString(const char *s) {
     size_t len = strlen(s);
-    char *dst = static_cast<char *>(
-        base_internal::LowLevelAlloc::AllocWithArena(len + 1, SigSafeArena()));
+    char *dst =
+        static_cast<char *>(base_internal::LowLevelAlloc::AllocWithArena(
+            len + 1, base_internal::SigSafeArena()));
     ABSL_RAW_CHECK(dst != nullptr, "out of memory");
     memcpy(dst, s, len + 1);
     return dst;
@@ -441,14 +419,14 @@
 // Return (and set null) g_cached_symbolized_state if it is not null.
 // Otherwise return a new symbolizer.
 static Symbolizer *AllocateSymbolizer() {
-  InitSigSafeArena();
+  base_internal::InitSigSafeArena();
   Symbolizer *symbolizer =
       g_cached_symbolizer.exchange(nullptr, std::memory_order_acquire);
   if (symbolizer != nullptr) {
     return symbolizer;
   }
   return new (base_internal::LowLevelAlloc::AllocWithArena(
-      SymbolizerSize(), SigSafeArena())) Symbolizer();
+      SymbolizerSize(), base_internal::SigSafeArena())) Symbolizer();
 }
 
 // Set g_cached_symbolize_state to s if it is null, otherwise
@@ -1469,14 +1447,15 @@
       constexpr int interesting = PF_X | PF_R;
 #endif
 
-      if (phdr.p_type != PT_LOAD
-          || (phdr.p_flags & interesting) != interesting) {
+      if (phdr.p_type != PT_LOAD ||
+          (phdr.p_flags & interesting) != interesting) {
         // Not a LOAD segment, not executable code, and not a function
         // descriptor.
         continue;
       }
       if (num_interesting_load_segments < obj->phdr.size()) {
-        memcpy(&obj->phdr[num_interesting_load_segments++], &phdr, sizeof(phdr));
+        memcpy(&obj->phdr[num_interesting_load_segments++], &phdr,
+               sizeof(phdr));
       } else {
         ABSL_RAW_LOG(
             WARNING, "%s: too many interesting LOAD segments: %zu >= %zu",
@@ -1525,7 +1504,8 @@
             ABSL_RAW_CHECK(p.p_type == PT_NULL, "unexpected p_type");
             break;
           }
-          if (pc < reinterpret_cast<void *>(start_addr + p.p_vaddr + p.p_memsz)) {
+          if (pc <
+              reinterpret_cast<void *>(start_addr + p.p_vaddr + p.p_memsz)) {
             phdr = &p;
             break;
           }
@@ -1569,7 +1549,7 @@
 #endif
   }
 
-  if (g_decorators_mu.TryLock()) {
+  if (g_decorators_mu.try_lock()) {
     if (g_num_decorators > 0) {
       SymbolDecoratorArgs decorator_args = {
           pc,       relocation,       fd,     symbol_buf_, sizeof(symbol_buf_),
@@ -1579,7 +1559,7 @@
         g_decorators[i].fn(&decorator_args);
       }
     }
-    g_decorators_mu.Unlock();
+    g_decorators_mu.unlock();
   }
   if (symbol_buf_[0] == '\0') {
     return nullptr;
@@ -1625,17 +1605,17 @@
 }
 
 bool RemoveAllSymbolDecorators(void) {
-  if (!g_decorators_mu.TryLock()) {
+  if (!g_decorators_mu.try_lock()) {
     // Someone else is using decorators. Get out.
     return false;
   }
   g_num_decorators = 0;
-  g_decorators_mu.Unlock();
+  g_decorators_mu.unlock();
   return true;
 }
 
 bool RemoveSymbolDecorator(int ticket) {
-  if (!g_decorators_mu.TryLock()) {
+  if (!g_decorators_mu.try_lock()) {
     // Someone else is using decorators. Get out.
     return false;
   }
@@ -1649,14 +1629,14 @@
       break;
     }
   }
-  g_decorators_mu.Unlock();
+  g_decorators_mu.unlock();
   return true;  // Decorator is known to be removed.
 }
 
 int InstallSymbolDecorator(SymbolDecorator decorator, void *arg) {
   static int ticket = 0;
 
-  if (!g_decorators_mu.TryLock()) {
+  if (!g_decorators_mu.try_lock()) {
     // Someone else is using decorators. Get out.
     return -2;
   }
@@ -1667,18 +1647,18 @@
     g_decorators[g_num_decorators] = {decorator, arg, ticket++};
     ++g_num_decorators;
   }
-  g_decorators_mu.Unlock();
+  g_decorators_mu.unlock();
   return ret;
 }
 
-bool RegisterFileMappingHint(const void *start, const void *end, uint64_t offset,
-                             const char *filename) {
+bool RegisterFileMappingHint(const void *start, const void *end,
+                             uint64_t offset, const char *filename) {
   SAFE_ASSERT(start <= end);
   SAFE_ASSERT(filename != nullptr);
 
-  InitSigSafeArena();
+  base_internal::InitSigSafeArena();
 
-  if (!g_file_mapping_mu.TryLock()) {
+  if (!g_file_mapping_mu.try_lock()) {
     return false;
   }
 
@@ -1688,8 +1668,9 @@
   } else {
     // TODO(ckennelly): Move this into a string copy routine.
     size_t len = strlen(filename);
-    char *dst = static_cast<char *>(
-        base_internal::LowLevelAlloc::AllocWithArena(len + 1, SigSafeArena()));
+    char *dst =
+        static_cast<char *>(base_internal::LowLevelAlloc::AllocWithArena(
+            len + 1, base_internal::SigSafeArena()));
     ABSL_RAW_CHECK(dst != nullptr, "out of memory");
     memcpy(dst, filename, len + 1);
 
@@ -1700,13 +1681,13 @@
     hint.filename = dst;
   }
 
-  g_file_mapping_mu.Unlock();
+  g_file_mapping_mu.unlock();
   return ret;
 }
 
 bool GetFileMappingHint(const void **start, const void **end, uint64_t *offset,
                         const char **filename) {
-  if (!g_file_mapping_mu.TryLock()) {
+  if (!g_file_mapping_mu.try_lock()) {
     return false;
   }
   bool found = false;
@@ -1729,7 +1710,7 @@
       break;
     }
   }
-  g_file_mapping_mu.Unlock();
+  g_file_mapping_mu.unlock();
   return found;
 }
 
@@ -1765,7 +1746,8 @@
 }  // namespace absl
 
 extern "C" bool AbslInternalGetFileMappingHint(const void **start,
-                                               const void **end, uint64_t *offset,
+                                               const void **end,
+                                               uint64_t *offset,
                                                const char **filename) {
   return absl::debugging_internal::GetFileMappingHint(start, end, offset,
                                                       filename);
diff --git a/absl/debugging/symbolize_emscripten.inc b/absl/debugging/symbolize_emscripten.inc
index f6da0ac..5756325 100644
--- a/absl/debugging/symbolize_emscripten.inc
+++ b/absl/debugging/symbolize_emscripten.inc
@@ -26,33 +26,20 @@
 
 extern "C" {
 const char* emscripten_pc_get_function(const void* pc);
+void* emscripten_stack_snapshot();
 }
 
-// clang-format off
-EM_JS(bool, HaveOffsetConverter, (),
-      { return typeof wasmOffsetConverter !== 'undefined'; });
-// clang-format on
-
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
-void InitializeSymbolizer(const char*) {
-  if (!HaveOffsetConverter()) {
-    ABSL_RAW_LOG(INFO,
-                 "Symbolization unavailable. Rebuild with -sWASM=1 "
-                 "and -sUSE_OFFSET_CONVERTER=1.");
-  }
-}
+void InitializeSymbolizer(const char*) {}
 
 bool Symbolize(const void* pc, char* out, int out_size) {
-  // Check if we have the offset converter necessary for pc_get_function.
-  // Without it, the program will abort().
-  if (!HaveOffsetConverter()) {
-    return false;
-  }
   if (pc == nullptr || out_size <= 0) {
     return false;
   }
+  // Need to capture a snapshot first.
+  emscripten_stack_snapshot();
   const char* func_name = emscripten_pc_get_function(pc);
   if (func_name == nullptr) {
     return false;
diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc
index 69b0a26..2dd5da5 100644
--- a/absl/debugging/symbolize_test.cc
+++ b/absl/debugging/symbolize_test.cc
@@ -107,8 +107,6 @@
 #endif
 
 #if !defined(__EMSCRIPTEN__)
-static void *GetPCFromFnPtr(void *ptr) { return ptr; }
-
 // Used below to hopefully inhibit some compiler/linker optimizations
 // that may remove kHpageTextPadding, kPadding0, and kPadding1 from
 // the binary.
@@ -119,12 +117,6 @@
 const char kHpageTextPadding[kHpageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(
         .text) = "";
 
-#else
-static void *GetPCFromFnPtr(void *ptr) {
-  return EM_ASM_PTR(
-      { return wasmOffsetConverter.convert(wasmTable.get($0).name, 0); }, ptr);
-}
-
 #endif  // !defined(__EMSCRIPTEN__)
 
 static char try_symbolize_buffer[4096];
@@ -174,12 +166,10 @@
 
 TEST(Symbolize, Cached) {
   // Compilers should give us pointers to them.
-  EXPECT_STREQ("nonstatic_func",
-               TrySymbolize(GetPCFromFnPtr((void *)(&nonstatic_func))));
+  EXPECT_STREQ("nonstatic_func", TrySymbolize((void*)(&nonstatic_func)));
   // The name of an internal linkage symbol is not specified; allow either a
   // mangled or an unmangled name here.
-  const char *static_func_symbol =
-      TrySymbolize(GetPCFromFnPtr((void *)(&static_func)));
+  const char* static_func_symbol = TrySymbolize((void*)(&static_func));
   EXPECT_TRUE(strcmp("static_func", static_func_symbol) == 0 ||
               strcmp("static_func()", static_func_symbol) == 0);
 
@@ -189,50 +179,38 @@
 TEST(Symbolize, Truncation) {
   constexpr char kNonStaticFunc[] = "nonstatic_func";
   EXPECT_STREQ("nonstatic_func",
-               TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)),
+               TrySymbolizeWithLimit((void*)(&nonstatic_func),
                                      strlen(kNonStaticFunc) + 1));
   EXPECT_STREQ("nonstatic_...",
-               TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)),
+               TrySymbolizeWithLimit((void*)(&nonstatic_func),
                                      strlen(kNonStaticFunc) + 0));
   EXPECT_STREQ("nonstatic...",
-               TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)),
+               TrySymbolizeWithLimit((void*)(&nonstatic_func),
                                      strlen(kNonStaticFunc) - 1));
-  EXPECT_STREQ("n...", TrySymbolizeWithLimit(
-                           GetPCFromFnPtr((void *)(&nonstatic_func)), 5));
-  EXPECT_STREQ("...", TrySymbolizeWithLimit(
-                          GetPCFromFnPtr((void *)(&nonstatic_func)), 4));
-  EXPECT_STREQ("..", TrySymbolizeWithLimit(
-                         GetPCFromFnPtr((void *)(&nonstatic_func)), 3));
-  EXPECT_STREQ(
-      ".", TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)), 2));
-  EXPECT_STREQ(
-      "", TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)), 1));
-  EXPECT_EQ(nullptr, TrySymbolizeWithLimit(
-                         GetPCFromFnPtr((void *)(&nonstatic_func)), 0));
+  EXPECT_STREQ("n...", TrySymbolizeWithLimit((void*)(&nonstatic_func), 5));
+  EXPECT_STREQ("...", TrySymbolizeWithLimit((void*)(&nonstatic_func), 4));
+  EXPECT_STREQ("..", TrySymbolizeWithLimit((void*)(&nonstatic_func), 3));
+  EXPECT_STREQ(".", TrySymbolizeWithLimit((void*)(&nonstatic_func), 2));
+  EXPECT_STREQ("", TrySymbolizeWithLimit((void*)(&nonstatic_func), 1));
+  EXPECT_EQ(nullptr, TrySymbolizeWithLimit((void*)(&nonstatic_func), 0));
 }
 
 TEST(Symbolize, SymbolizeWithDemangling) {
   Foo::func(100);
 #ifdef __EMSCRIPTEN__
   // Emscripten's online symbolizer is more precise with arguments.
-  EXPECT_STREQ("Foo::func(int)",
-               TrySymbolize(GetPCFromFnPtr((void *)(&Foo::func))));
+  EXPECT_STREQ("Foo::func(int)", TrySymbolize((void*)(&Foo::func)));
 #else
-  EXPECT_STREQ("Foo::func()",
-               TrySymbolize(GetPCFromFnPtr((void *)(&Foo::func))));
+  EXPECT_STREQ("Foo::func()", TrySymbolize((void*)(&Foo::func)));
 #endif
 }
 
 TEST(Symbolize, SymbolizeSplitTextSections) {
-  EXPECT_STREQ("unlikely_func()",
-               TrySymbolize(GetPCFromFnPtr((void *)(&unlikely_func))));
-  EXPECT_STREQ("hot_func()", TrySymbolize(GetPCFromFnPtr((void *)(&hot_func))));
-  EXPECT_STREQ("startup_func()",
-               TrySymbolize(GetPCFromFnPtr((void *)(&startup_func))));
-  EXPECT_STREQ("exit_func()",
-               TrySymbolize(GetPCFromFnPtr((void *)(&exit_func))));
-  EXPECT_STREQ("regular_func()",
-               TrySymbolize(GetPCFromFnPtr((void *)(&regular_func))));
+  EXPECT_STREQ("unlikely_func()", TrySymbolize((void*)(&unlikely_func)));
+  EXPECT_STREQ("hot_func()", TrySymbolize((void*)(&hot_func)));
+  EXPECT_STREQ("startup_func()", TrySymbolize((void*)(&startup_func)));
+  EXPECT_STREQ("exit_func()", TrySymbolize((void*)(&exit_func)));
+  EXPECT_STREQ("regular_func()", TrySymbolize((void*)(&regular_func)));
 }
 
 // Tests that verify that Symbolize stack footprint is within some limit.
@@ -630,5 +608,12 @@
 #endif
 #endif
 
+#if !defined(__EMSCRIPTEN__)
+  // All of these test cases rely on symbolizing function pointers.
+  // On most platforms, function pointers directly map to PC.
+  // In WebAssembly, function pointers are indices into the function table
+  // and there is no longer a mapping from function index back into the
+  // file offset for symbolization.
   return RUN_ALL_TESTS();
+#endif  // !defined(__EMSCRIPTEN__)
 }
diff --git a/absl/debugging/symbolize_win32.inc b/absl/debugging/symbolize_win32.inc
index 589890f..eaeefb9 100644
--- a/absl/debugging/symbolize_win32.inc
+++ b/absl/debugging/symbolize_win32.inc
@@ -15,7 +15,6 @@
 // See "Retrieving Symbol Information by Address":
 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx
 
-#include <ntstatus.h>
 #include <windows.h>
 #include <winternl.h>
 
@@ -58,10 +57,9 @@
     // NTSTATUS (0xC0000004), which can happen when a module load occurs during
     // the SymInitialize call. In this case, we should try calling SymInitialize
     // again.
+    constexpr DWORD kStatusInfoLengthMismatch = DWORD{0xC0000004};
     syminitialize_error = GetLastError();
-    // Both NTSTATUS and DWORD are 32-bit numbers, which makes the cast safe.
-    if (syminitialize_error !=
-        static_cast<DWORD>(STATUS_INFO_LENGTH_MISMATCH)) {
+    if (syminitialize_error != kStatusInfoLengthMismatch) {
       break;
     }
   }
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel
index 620af2b..f928609 100644
--- a/absl/flags/BUILD.bazel
+++ b/absl/flags/BUILD.bazel
@@ -14,6 +14,9 @@
 # limitations under the License.
 #
 
+load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
@@ -165,6 +168,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl/flags:__pkg__",
+        "//absl/flags/rust:__pkg__",
     ],
     deps = [
         ":commandlineflag",
diff --git a/absl/flags/declare.h b/absl/flags/declare.h
index 8d2a856..a0b12bb 100644
--- a/absl/flags/declare.h
+++ b/absl/flags/declare.h
@@ -59,10 +59,19 @@
 
 // Internal implementation of ABSL_DECLARE_FLAG to allow macro expansion of its
 // arguments. Clients must use ABSL_DECLARE_FLAG instead.
+//
+// The non-MSVC implementation declares the flag twice. This is to allow
+// applying attributes to the second declaration. However, this causes a
+// compile error (C4273) in MSVC if a `__declspec` is prepended to the macro.
+#if defined(_MSC_VER)
+#define ABSL_DECLARE_FLAG_INTERNAL(type, name) \
+  extern absl::Flag<type> FLAGS_##name
+#else
 #define ABSL_DECLARE_FLAG_INTERNAL(type, name)               \
   extern absl::Flag<type> FLAGS_##name;                      \
   namespace absl /* block flags in namespaces */ {}          \
   /* second redeclaration is to allow applying attributes */ \
   extern absl::Flag<type> FLAGS_##name
+#endif  // _MSC_VER
 
 #endif  // ABSL_FLAGS_DECLARE_H_
diff --git a/absl/flags/flag.h b/absl/flags/flag.h
index e052d5f..4c328e3 100644
--- a/absl/flags/flag.h
+++ b/absl/flags/flag.h
@@ -241,7 +241,8 @@
     /* default value argument. That keeps temporaries alive */               \
     /* long enough for NonConst to work correctly.          */               \
     static constexpr absl::string_view Value(                                \
-        absl::string_view absl_flag_help = ABSL_FLAG_IMPL_FLAGHELP(txt)) {   \
+        absl::string_view absl_flag_help ABSL_ATTRIBUTE_LIFETIME_BOUND  =     \
+            ABSL_FLAG_IMPL_FLAGHELP(txt)) {                                  \
       return absl_flag_help;                                                 \
     }                                                                        \
     static std::string NonConst() { return std::string(Value()); }           \
diff --git a/absl/flags/internal/commandlineflag.h b/absl/flags/internal/commandlineflag.h
index daef4e3..e2c4c82 100644
--- a/absl/flags/internal/commandlineflag.h
+++ b/absl/flags/internal/commandlineflag.h
@@ -58,7 +58,7 @@
   virtual ~FlagStateInterface();
 
   // Restores the flag originated this object to the saved state.
-  virtual void Restore() const = 0;
+  virtual void Restore() && = 0;
 };
 
 }  // namespace flags_internal
diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc
index 37f6ef1..8e89425 100644
--- a/absl/flags/internal/flag.cc
+++ b/absl/flags/internal/flag.cc
@@ -26,6 +26,7 @@
 #include <memory>
 #include <string>
 #include <typeinfo>
+#include <utility>
 #include <vector>
 
 #include "absl/base/attributes.h"
@@ -73,8 +74,8 @@
 // need to acquire these locks themselves.
 class MutexRelock {
  public:
-  explicit MutexRelock(absl::Mutex& mu) : mu_(mu) { mu_.Unlock(); }
-  ~MutexRelock() { mu_.Lock(); }
+  explicit MutexRelock(absl::Mutex& mu) : mu_(mu) { mu_.unlock(); }
+  ~MutexRelock() { mu_.lock(); }
 
   MutexRelock(const MutexRelock&) = delete;
   MutexRelock& operator=(const MutexRelock&) = delete;
@@ -88,9 +89,9 @@
 // we move the memory to the freelist where it lives indefinitely, so it can
 // still be safely accessed. This also prevents leak checkers from complaining
 // about the leaked memory that can no longer be accessed through any pointer.
-absl::Mutex* FreelistMutex() {
+absl::Mutex& FreelistMutex() {
   static absl::NoDestructor<absl::Mutex> mutex;
-  return mutex.get();
+  return *mutex;
 }
 ABSL_CONST_INIT std::vector<void*>* s_freelist ABSL_GUARDED_BY(FreelistMutex())
     ABSL_PT_GUARDED_BY(FreelistMutex()) = nullptr;
@@ -139,8 +140,8 @@
   friend class FlagImpl;
 
   // Restores the flag to the saved state.
-  void Restore() const override {
-    if (!flag_impl_.RestoreState(*this)) return;
+  void Restore() && override {
+    if (!std::move(flag_impl_).RestoreState(*this)) return;
 
     ABSL_INTERNAL_LOG(INFO,
                       absl::StrCat("Restore saved value of ", flag_impl_.Name(),
@@ -248,12 +249,12 @@
   seq_lock_.MarkInitialized();
 }
 
-absl::Mutex* FlagImpl::DataGuard() const {
+absl::Mutex& FlagImpl::DataGuard() const {
   absl::call_once(const_cast<FlagImpl*>(this)->init_control_, &FlagImpl::Init,
                   const_cast<FlagImpl*>(this));
 
   // data_guard_ is initialized inside Init.
-  return reinterpret_cast<absl::Mutex*>(&data_guard_);
+  return *reinterpret_cast<absl::Mutex*>(&data_guard_);
 }
 
 void FlagImpl::AssertValidType(FlagFastTypeId rhs_type_id,
@@ -375,7 +376,7 @@
 }
 
 std::string FlagImpl::CurrentValue() const {
-  auto* guard = DataGuard();  // Make sure flag initialized
+  auto& guard = DataGuard();  // Make sure flag initialized
   switch (ValueStorageKind()) {
     case FlagValueStorageKind::kValueAndInitBit:
     case FlagValueStorageKind::kOneWordAtomic: {
@@ -429,8 +430,8 @@
   // and it also can be different by the time the callback invocation is
   // completed. Requires that *primary_lock be held in exclusive mode; it may be
   // released and reacquired by the implementation.
-  MutexRelock relock(*DataGuard());
-  absl::MutexLock lock(&callback_->guard);
+  MutexRelock relock(DataGuard());
+  absl::MutexLock lock(callback_->guard);
   cb();
 }
 
@@ -535,7 +536,7 @@
 }
 
 void FlagImpl::Read(void* dst) const {
-  auto* guard = DataGuard();  // Make sure flag initialized
+  auto& guard = DataGuard();  // Make sure flag initialized
   switch (ValueStorageKind()) {
     case FlagValueStorageKind::kValueAndInitBit:
     case FlagValueStorageKind::kOneWordAtomic: {
@@ -567,14 +568,14 @@
 int64_t FlagImpl::ReadOneWord() const {
   assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic ||
          ValueStorageKind() == FlagValueStorageKind::kValueAndInitBit);
-  auto* guard = DataGuard();  // Make sure flag initialized
+  auto& guard = DataGuard();  // Make sure flag initialized
   (void)guard;
   return OneWordValue().load(std::memory_order_acquire);
 }
 
 bool FlagImpl::ReadOneBool() const {
   assert(ValueStorageKind() == FlagValueStorageKind::kValueAndInitBit);
-  auto* guard = DataGuard();  // Make sure flag initialized
+  auto& guard = DataGuard();  // Make sure flag initialized
   (void)guard;
   return absl::bit_cast<FlagValueAndInitBit<bool>>(
              OneWordValue().load(std::memory_order_acquire))
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index b61a247..cab9d16 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -601,17 +601,17 @@
         data_guard_{} {}
 
   // Constant access methods
-  int64_t ReadOneWord() const ABSL_LOCKS_EXCLUDED(*DataGuard());
-  bool ReadOneBool() const ABSL_LOCKS_EXCLUDED(*DataGuard());
-  void Read(void* dst) const override ABSL_LOCKS_EXCLUDED(*DataGuard());
-  void Read(bool* value) const ABSL_LOCKS_EXCLUDED(*DataGuard()) {
+  int64_t ReadOneWord() const ABSL_LOCKS_EXCLUDED(DataGuard());
+  bool ReadOneBool() const ABSL_LOCKS_EXCLUDED(DataGuard());
+  void Read(void* dst) const override ABSL_LOCKS_EXCLUDED(DataGuard());
+  void Read(bool* value) const ABSL_LOCKS_EXCLUDED(DataGuard()) {
     *value = ReadOneBool();
   }
   template <typename T,
             absl::enable_if_t<flags_internal::StorageKind<T>() ==
                                   FlagValueStorageKind::kOneWordAtomic,
                               int> = 0>
-  void Read(T* value) const ABSL_LOCKS_EXCLUDED(*DataGuard()) {
+  void Read(T* value) const ABSL_LOCKS_EXCLUDED(DataGuard()) {
     int64_t v = ReadOneWord();
     std::memcpy(value, static_cast<const void*>(&v), sizeof(T));
   }
@@ -619,17 +619,17 @@
             typename std::enable_if<flags_internal::StorageKind<T>() ==
                                         FlagValueStorageKind::kValueAndInitBit,
                                     int>::type = 0>
-  void Read(T* value) const ABSL_LOCKS_EXCLUDED(*DataGuard()) {
+  void Read(T* value) const ABSL_LOCKS_EXCLUDED(DataGuard()) {
     *value = absl::bit_cast<FlagValueAndInitBit<T>>(ReadOneWord()).value;
   }
 
   // Mutating access methods
-  void Write(const void* src) ABSL_LOCKS_EXCLUDED(*DataGuard());
+  void Write(const void* src) ABSL_LOCKS_EXCLUDED(DataGuard());
 
   // Interfaces to operate on callbacks.
   void SetCallback(const FlagCallbackFunc mutation_callback)
-      ABSL_LOCKS_EXCLUDED(*DataGuard());
-  void InvokeCallback() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
+      ABSL_LOCKS_EXCLUDED(DataGuard());
+  void InvokeCallback() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(DataGuard());
 
   // Used in read/write operations to validate source/target has correct type.
   // For example if flag is declared as absl::Flag<int> FLAGS_foo, a call to
@@ -646,11 +646,11 @@
   friend class FlagState;
 
   // Ensures that `data_guard_` is initialized and returns it.
-  absl::Mutex* DataGuard() const
+  absl::Mutex& DataGuard() const
       ABSL_LOCK_RETURNED(reinterpret_cast<absl::Mutex*>(data_guard_));
   // Returns heap allocated value of type T initialized with default value.
   std::unique_ptr<void, DynValueDeleter> MakeInitValue() const
-      ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(DataGuard());
   // Flag initialization called via absl::call_once.
   void Init();
 
@@ -676,16 +676,15 @@
   // returns new value. Otherwise returns nullptr.
   std::unique_ptr<void, DynValueDeleter> TryParse(absl::string_view value,
                                                   std::string& err) const
-      ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(DataGuard());
   // Stores the flag value based on the pointer to the source.
   void StoreValue(const void* src, ValueSource source)
-      ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(DataGuard());
 
   // Copy the flag data, protected by `seq_lock_` into `dst`.
   //
   // REQUIRES: ValueStorageKind() == kSequenceLocked.
-  void ReadSequenceLockedData(void* dst) const
-      ABSL_LOCKS_EXCLUDED(*DataGuard());
+  void ReadSequenceLockedData(void* dst) const ABSL_LOCKS_EXCLUDED(DataGuard());
 
   FlagHelpKind HelpSourceKind() const {
     return static_cast<FlagHelpKind>(help_source_kind_);
@@ -694,7 +693,7 @@
     return static_cast<FlagValueStorageKind>(value_storage_kind_);
   }
   FlagDefaultKind DefaultKind() const
-      ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()) {
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(DataGuard()) {
     return static_cast<FlagDefaultKind>(def_kind_);
   }
 
@@ -705,30 +704,30 @@
   std::string Help() const override;
   FlagFastTypeId TypeId() const override;
   bool IsSpecifiedOnCommandLine() const override
-      ABSL_LOCKS_EXCLUDED(*DataGuard());
-  std::string DefaultValue() const override ABSL_LOCKS_EXCLUDED(*DataGuard());
-  std::string CurrentValue() const override ABSL_LOCKS_EXCLUDED(*DataGuard());
+      ABSL_LOCKS_EXCLUDED(DataGuard());
+  std::string DefaultValue() const override ABSL_LOCKS_EXCLUDED(DataGuard());
+  std::string CurrentValue() const override ABSL_LOCKS_EXCLUDED(DataGuard());
   bool ValidateInputValue(absl::string_view value) const override
-      ABSL_LOCKS_EXCLUDED(*DataGuard());
+      ABSL_LOCKS_EXCLUDED(DataGuard());
   void CheckDefaultValueParsingRoundtrip() const override
-      ABSL_LOCKS_EXCLUDED(*DataGuard());
+      ABSL_LOCKS_EXCLUDED(DataGuard());
 
-  int64_t ModificationCount() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
+  int64_t ModificationCount() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(DataGuard());
 
   // Interfaces to save and restore flags to/from persistent state.
   // Returns current flag state or nullptr if flag does not support
   // saving and restoring a state.
   std::unique_ptr<FlagStateInterface> SaveState() override
-      ABSL_LOCKS_EXCLUDED(*DataGuard());
+      ABSL_LOCKS_EXCLUDED(DataGuard());
 
   // Restores the flag state to the supplied state object. If there is
   // nothing to restore returns false. Otherwise returns true.
   bool RestoreState(const FlagState& flag_state)
-      ABSL_LOCKS_EXCLUDED(*DataGuard());
+      ABSL_LOCKS_EXCLUDED(DataGuard());
 
   bool ParseFrom(absl::string_view value, FlagSettingMode set_mode,
                  ValueSource source, std::string& error) override
-      ABSL_LOCKS_EXCLUDED(*DataGuard());
+      ABSL_LOCKS_EXCLUDED(DataGuard());
 
   // Immutable flag's state.
 
@@ -758,9 +757,9 @@
   // locks.
   uint8_t def_kind_ : 2;
   // Has this flag's value been modified?
-  bool modified_ : 1 ABSL_GUARDED_BY(*DataGuard());
+  bool modified_ : 1 ABSL_GUARDED_BY(DataGuard());
   // Has this flag been specified on command line.
-  bool on_command_line_ : 1 ABSL_GUARDED_BY(*DataGuard());
+  bool on_command_line_ : 1 ABSL_GUARDED_BY(DataGuard());
 
   // Unique tag for absl::call_once call to initialize this flag.
   absl::once_flag init_control_;
@@ -769,7 +768,7 @@
   flags_internal::SequenceLock seq_lock_;
 
   // Optional flag's callback and absl::Mutex to guard the invocations.
-  FlagCallback* callback_ ABSL_GUARDED_BY(*DataGuard());
+  FlagCallback* callback_ ABSL_GUARDED_BY(DataGuard());
   // Either a pointer to the function generating the default value based on the
   // value specified in ABSL_FLAG or pointer to the dynamically set default
   // value via SetCommandLineOptionWithMode. def_kind_ is used to distinguish
diff --git a/absl/flags/internal/program_name.cc b/absl/flags/internal/program_name.cc
index fb06643..23185c6 100644
--- a/absl/flags/internal/program_name.cc
+++ b/absl/flags/internal/program_name.cc
@@ -29,9 +29,9 @@
 ABSL_NAMESPACE_BEGIN
 namespace flags_internal {
 
-static absl::Mutex* ProgramNameMutex() {
+static absl::Mutex& ProgramNameMutex() {
   static absl::NoDestructor<absl::Mutex> mutex;
-  return mutex.get();
+  return *mutex;
 }
 ABSL_CONST_INIT static std::string* program_name ABSL_GUARDED_BY(
     ProgramNameMutex()) ABSL_PT_GUARDED_BY(ProgramNameMutex()) = nullptr;
diff --git a/absl/flags/internal/usage.cc b/absl/flags/internal/usage.cc
index fc68b03..3c44271 100644
--- a/absl/flags/internal/usage.cc
+++ b/absl/flags/internal/usage.cc
@@ -434,9 +434,9 @@
 
 namespace {
 
-absl::Mutex* HelpAttributesMutex() {
+absl::Mutex& HelpAttributesMutex() {
   static absl::NoDestructor<absl::Mutex> mutex;
-  return mutex.get();
+  return *mutex;
 }
 ABSL_CONST_INIT std::string* match_substr ABSL_GUARDED_BY(HelpAttributesMutex())
     ABSL_PT_GUARDED_BY(HelpAttributesMutex()) = nullptr;
diff --git a/absl/flags/marshalling.cc b/absl/flags/marshalling.cc
index ca4a130..acdc880 100644
--- a/absl/flags/marshalling.cc
+++ b/absl/flags/marshalling.cc
@@ -45,22 +45,7 @@
 // AbslParseFlag specializations for boolean type.
 
 bool AbslParseFlag(absl::string_view text, bool* dst, std::string*) {
-  const char* kTrue[] = {"1", "t", "true", "y", "yes"};
-  const char* kFalse[] = {"0", "f", "false", "n", "no"};
-  static_assert(sizeof(kTrue) == sizeof(kFalse), "true_false_equal");
-
-  text = absl::StripAsciiWhitespace(text);
-
-  for (size_t i = 0; i < ABSL_ARRAYSIZE(kTrue); ++i) {
-    if (absl::EqualsIgnoreCase(text, kTrue[i])) {
-      *dst = true;
-      return true;
-    } else if (absl::EqualsIgnoreCase(text, kFalse[i])) {
-      *dst = false;
-      return true;
-    }
-  }
-  return false;  // didn't match a legal input
+  return SimpleAtob(absl::StripAsciiWhitespace(text), dst);
 }
 
 // --------------------------------------------------------------------
diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc
index c87cacd..4961930 100644
--- a/absl/flags/parse.cc
+++ b/absl/flags/parse.cc
@@ -64,9 +64,9 @@
 namespace flags_internal {
 namespace {
 
-absl::Mutex* ProcessingChecksMutex() {
+absl::Mutex& ProcessingChecksMutex() {
   static absl::NoDestructor<absl::Mutex> mutex;
-  return mutex.get();
+  return *mutex;
 }
 
 ABSL_CONST_INIT bool flagfile_needs_processing
@@ -76,9 +76,9 @@
 ABSL_CONST_INIT bool tryfromenv_needs_processing
     ABSL_GUARDED_BY(ProcessingChecksMutex()) = false;
 
-absl::Mutex* SpecifiedFlagsMutex() {
+absl::Mutex& SpecifiedFlagsMutex() {
   static absl::NoDestructor<absl::Mutex> mutex;
-  return mutex.get();
+  return *mutex;
 }
 
 ABSL_CONST_INIT std::vector<const CommandLineFlag*>* specified_flags
@@ -206,8 +206,10 @@
 
   std::string line;
   bool success = true;
+  int line_number = 0;
 
   while (std::getline(flag_file, line)) {
+    line_number++;
     absl::string_view stripped = absl::StripLeadingAsciiWhitespace(line);
 
     if (stripped.empty() || stripped[0] == '#') {
@@ -229,8 +231,8 @@
     }
 
     flags_internal::ReportUsageError(
-        absl::StrCat("Unexpected line in the flagfile ", flag_file_name, ": ",
-                     line),
+        absl::StrCat("Unexpected line ", line_number, " in the flagfile ",
+                     flag_file_name),
         true);
 
     success = false;
diff --git a/absl/flags/parse_test.cc b/absl/flags/parse_test.cc
index 9997069..08eb81a 100644
--- a/absl/flags/parse_test.cc
+++ b/absl/flags/parse_test.cc
@@ -827,7 +827,7 @@
                       flagfile_flag),
   };
   EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args5),
-               "Unexpected line in the flagfile .*: \\*bin\\*");
+               "Unexpected line 2 in the flagfile .*");
 }
 
 // --------------------------------------------------------------------
diff --git a/absl/flags/reflection.cc b/absl/flags/reflection.cc
index b8b4a2e..fb64a65 100644
--- a/absl/flags/reflection.cc
+++ b/absl/flags/reflection.cc
@@ -19,6 +19,7 @@
 
 #include <atomic>
 #include <string>
+#include <utility>
 
 #include "absl/base/config.h"
 #include "absl/base/no_destructor.h"
@@ -53,8 +54,11 @@
   // Store a flag in this registry. Takes ownership of *flag.
   void RegisterFlag(CommandLineFlag& flag, const char* filename);
 
-  void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION(lock_) { lock_.Lock(); }
-  void Unlock() ABSL_UNLOCK_FUNCTION(lock_) { lock_.Unlock(); }
+  void lock() ABSL_EXCLUSIVE_LOCK_FUNCTION(lock_) { lock_.lock(); }
+  inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION(lock_) { lock(); }
+
+  void unlock() ABSL_UNLOCK_FUNCTION(lock_) { lock_.unlock(); }
+  inline void Unlock() ABSL_UNLOCK_FUNCTION(lock_) { unlock(); }
 
   // Returns the flag object for the specified name, or nullptr if not found.
   // Will emit a warning if a 'retired' flag is specified.
@@ -87,8 +91,8 @@
 
 class FlagRegistryLock {
  public:
-  explicit FlagRegistryLock(FlagRegistry& fr) : fr_(fr) { fr_.Lock(); }
-  ~FlagRegistryLock() { fr_.Unlock(); }
+  explicit FlagRegistryLock(FlagRegistry& fr) : fr_(fr) { fr_.lock(); }
+  ~FlagRegistryLock() { fr_.unlock(); }
 
  private:
   FlagRegistry& fr_;
@@ -317,9 +321,9 @@
   }
 
   // Restores the saved flag states into the flag registry.
-  void RestoreToRegistry() {
+  void RestoreToRegistry() && {
     for (const auto& flag_state : backup_registry_) {
-      flag_state->Restore();
+      std::move(*flag_state).Restore();
     }
   }
 
@@ -337,7 +341,7 @@
 FlagSaver::~FlagSaver() {
   if (!impl_) return;
 
-  impl_->RestoreToRegistry();
+  std::move(*impl_).RestoreToRegistry();
   delete impl_;
 }
 
diff --git a/absl/flags/usage.cc b/absl/flags/usage.cc
index 267a503..e42b454 100644
--- a/absl/flags/usage.cc
+++ b/absl/flags/usage.cc
@@ -40,7 +40,7 @@
 // --------------------------------------------------------------------
 // Sets the "usage" message to be used by help reporting routines.
 void SetProgramUsageMessage(absl::string_view new_usage_message) {
-  absl::MutexLock l(&flags_internal::usage_message_guard);
+  absl::MutexLock l(flags_internal::usage_message_guard);
 
   if (flags_internal::program_usage_message != nullptr) {
     ABSL_INTERNAL_LOG(FATAL, "SetProgramUsageMessage() called twice.");
@@ -55,7 +55,7 @@
 // Note: We able to return string_view here only because calling
 // SetProgramUsageMessage twice is prohibited.
 absl::string_view ProgramUsageMessage() {
-  absl::MutexLock l(&flags_internal::usage_message_guard);
+  absl::MutexLock l(flags_internal::usage_message_guard);
 
   return flags_internal::program_usage_message != nullptr
              ? absl::string_view(*flags_internal::program_usage_message)
diff --git a/absl/flags/usage_config.cc b/absl/flags/usage_config.cc
index 5922c5e..bbc020d 100644
--- a/absl/flags/usage_config.cc
+++ b/absl/flags/usage_config.cc
@@ -105,9 +105,9 @@
 
 // --------------------------------------------------------------------
 
-absl::Mutex* CustomUsageConfigMutex() {
+absl::Mutex& CustomUsageConfigMutex() {
   static absl::NoDestructor<absl::Mutex> mutex;
-  return mutex.get();
+  return *mutex;
 }
 ABSL_CONST_INIT FlagsUsageConfig* custom_usage_config
     ABSL_GUARDED_BY(CustomUsageConfigMutex())
diff --git a/absl/functional/BUILD.bazel b/absl/functional/BUILD.bazel
index aeed3b6..b7aa31f 100644
--- a/absl/functional/BUILD.bazel
+++ b/absl/functional/BUILD.bazel
@@ -14,6 +14,9 @@
 # limitations under the License.
 #
 
+load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
@@ -41,6 +44,7 @@
     deps = [
         "//absl/base:config",
         "//absl/base:core_headers",
+        "//absl/base:nullability",
         "//absl/meta:type_traits",
         "//absl/utility",
     ],
@@ -58,6 +62,7 @@
         ":any_invocable",
         "//absl/base:config",
         "//absl/base:core_headers",
+        "//absl/base:nullability",
         "//absl/meta:type_traits",
         "//absl/utility",
         "@googletest//:gtest",
@@ -99,8 +104,10 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":any_invocable",
+        "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/meta:type_traits",
+        "//absl/utility",
     ],
 )
 
@@ -112,8 +119,10 @@
     deps = [
         ":any_invocable",
         ":function_ref",
+        "//absl/base:config",
         "//absl/container:test_instance_tracker",
         "//absl/memory",
+        "//absl/utility",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
     ],
diff --git a/absl/functional/CMakeLists.txt b/absl/functional/CMakeLists.txt
index 91939db..07f3dc0 100644
--- a/absl/functional/CMakeLists.txt
+++ b/absl/functional/CMakeLists.txt
@@ -24,6 +24,7 @@
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
+    absl::base
     absl::config
     absl::core_headers
     absl::type_traits
@@ -41,6 +42,7 @@
     ${ABSL_TEST_COPTS}
   DEPS
     absl::any_invocable
+    absl::base
     absl::config
     absl::core_headers
     absl::type_traits
@@ -85,9 +87,11 @@
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
+    absl::config
     absl::core_headers
     absl::any_invocable
     absl::meta
+    absl::utility
   PUBLIC
 )
 
@@ -99,9 +103,11 @@
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
+    absl::config
     absl::function_ref
     absl::memory
     absl::test_instance_tracker
+    absl::utility
     GTest::gmock_main
 )
 
diff --git a/absl/functional/any_invocable.h b/absl/functional/any_invocable.h
index 43ea9af..6dd72b6 100644
--- a/absl/functional/any_invocable.h
+++ b/absl/functional/any_invocable.h
@@ -39,7 +39,9 @@
 #include <type_traits>
 #include <utility>
 
+#include "absl/base/attributes.h"
 #include "absl/base/config.h"
+#include "absl/base/nullability.h"
 #include "absl/functional/internal/any_invocable.h"
 #include "absl/meta/type_traits.h"
 #include "absl/utility/utility.h"
@@ -158,7 +160,8 @@
 //   AnyInvocable<void()> empty;
 //   empty();  // WARNING: Undefined behavior!
 template <class Sig>
-class AnyInvocable : private internal_any_invocable::Impl<Sig> {
+class ABSL_NULLABILITY_COMPATIBLE ABSL_ATTRIBUTE_OWNER AnyInvocable
+    : private internal_any_invocable::Impl<Sig> {
  private:
   static_assert(
       std::is_function<Sig>::value,
@@ -169,6 +172,7 @@
  public:
   // The return type of Sig
   using result_type = typename Impl::result_type;
+  using absl_internal_is_view = std::false_type;
 
   // Constructors
 
@@ -295,22 +299,22 @@
 
   // Equality operators
 
-  // Returns `true` if `*this` is empty.
+  // Returns `true` if `f` is empty.
   friend bool operator==(const AnyInvocable& f, std::nullptr_t) noexcept {
     return !f.HasValue();
   }
 
-  // Returns `true` if `*this` is empty.
+  // Returns `true` if `f` is empty.
   friend bool operator==(std::nullptr_t, const AnyInvocable& f) noexcept {
     return !f.HasValue();
   }
 
-  // Returns `false` if `*this` is empty.
+  // Returns `false` if `f` is empty.
   friend bool operator!=(const AnyInvocable& f, std::nullptr_t) noexcept {
     return f.HasValue();
   }
 
-  // Returns `false` if `*this` is empty.
+  // Returns `false` if `f` is empty.
   friend bool operator!=(std::nullptr_t, const AnyInvocable& f) noexcept {
     return f.HasValue();
   }
diff --git a/absl/functional/any_invocable_test.cc b/absl/functional/any_invocable_test.cc
index 6ad6323..7ddfcab 100644
--- a/absl/functional/any_invocable_test.cc
+++ b/absl/functional/any_invocable_test.cc
@@ -15,13 +15,17 @@
 #include "absl/functional/any_invocable.h"
 
 #include <cstddef>
+#include <cstdlib>
+#include <functional>
 #include <initializer_list>
+#include <iterator>
 #include <memory>
 #include <numeric>
 #include <type_traits>
 
 #include "gtest/gtest.h"
 #include "absl/base/config.h"
+#include "absl/base/nullability.h"
 #include "absl/meta/type_traits.h"
 #include "absl/utility/utility.h"
 
@@ -652,8 +656,8 @@
 TYPED_TEST_P(AnyInvTestBasic, MoveConstructionFromEmpty) {
   using AnyInvType = typename TypeParam::AnyInvType;
 
-  AnyInvType source_fun;
-  AnyInvType fun(std::move(source_fun));
+  absl_nullable AnyInvType source_fun;
+  absl_nullable AnyInvType fun(std::move(source_fun));
 
   EXPECT_FALSE(static_cast<bool>(fun));
 
diff --git a/absl/functional/function_ref.h b/absl/functional/function_ref.h
index f1d087a..3882eb0 100644
--- a/absl/functional/function_ref.h
+++ b/absl/functional/function_ref.h
@@ -47,12 +47,14 @@
 #define ABSL_FUNCTIONAL_FUNCTION_REF_H_
 
 #include <cassert>
-#include <functional>
 #include <type_traits>
+#include <utility>
 
 #include "absl/base/attributes.h"
+#include "absl/base/config.h"
 #include "absl/functional/internal/function_ref.h"
 #include "absl/meta/type_traits.h"
+#include "absl/utility/utility.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -83,42 +85,80 @@
 //   bool Visitor(absl::FunctionRef<void(my_proto&, absl::string_view)>
 //                  callback);
 template <typename R, typename... Args>
-class FunctionRef<R(Args...)> {
- private:
+class ABSL_ATTRIBUTE_VIEW FunctionRef<R(Args...)> {
+ protected:
   // Used to disable constructors for objects that are not compatible with the
   // signature of this FunctionRef.
-  template <typename F, typename FR = std::invoke_result_t<F, Args&&...>>
+  template <typename F, typename... U>
   using EnableIfCompatible =
-      typename std::enable_if<std::is_void<R>::value ||
-                              std::is_convertible<FR, R>::value>::type;
+      std::enable_if_t<std::is_invocable_r<R, F, U..., Args...>::value>;
 
- public:
-  // Constructs a FunctionRef from any invocable type.
-  template <typename F, typename = EnableIfCompatible<const F&>>
-  // NOLINTNEXTLINE(runtime/explicit)
-  FunctionRef(const F& f ABSL_ATTRIBUTE_LIFETIME_BOUND)
-      : invoker_(&absl::functional_internal::InvokeObject<F, R, Args...>) {
+  // Internal constructor to supersede the copying constructor
+  template <typename F>
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  FunctionRef(std::in_place_t, F&& f ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
+      : invoker_(&absl::functional_internal::InvokeObject<F&, R, Args...>) {
     absl::functional_internal::AssertNonNull(f);
     ptr_.obj = &f;
   }
 
+ public:
+  // Constructs a FunctionRef from any invocable type.
+  template <typename F,
+            typename = EnableIfCompatible<std::enable_if_t<
+                !std::is_same_v<FunctionRef, absl::remove_cvref_t<F>>, F&>>>
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  FunctionRef(F&& f ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
+      : FunctionRef(std::in_place, std::forward<F>(f)) {}
+
   // Overload for function pointers. This eliminates a level of indirection that
   // would happen if the above overload was used (it lets us store the pointer
   // instead of a pointer to a pointer).
   //
   // This overload is also used for references to functions, since references to
   // functions can decay to function pointers implicitly.
-  template <
-      typename F, typename = EnableIfCompatible<F*>,
-      absl::functional_internal::EnableIf<absl::is_function<F>::value> = 0>
-  FunctionRef(F* f)  // NOLINT(runtime/explicit)
+  template <typename F, typename = EnableIfCompatible<F*>,
+            absl::functional_internal::EnableIf<std::is_function_v<F>> = 0>
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  FunctionRef(F* f ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
       : invoker_(&absl::functional_internal::InvokeFunction<F*, R, Args...>) {
     assert(f != nullptr);
     ptr_.fun = reinterpret_cast<decltype(ptr_.fun)>(f);
   }
 
-  FunctionRef& operator=(const FunctionRef& rhs) = default;
-  FunctionRef(const FunctionRef& rhs) = default;
+#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+  // Similar to the other overloads, but passes the address of a known callable
+  // `F` at compile time. This allows calling arbitrary functions while avoiding
+  // an indirection.
+  // Needs C++20 as `nontype_t` needs C++20 for `auto` template parameters.
+  template <auto F, typename = EnableIfCompatible<decltype(F)>>
+  FunctionRef(nontype_t<F>) noexcept  // NOLINT(google-explicit-constructor)
+      : invoker_(&absl::functional_internal::InvokeFunction<decltype(F), F, R,
+                                                            Args...>) {}
+
+  template <
+      auto F, typename Obj,
+      typename = EnableIfCompatible<decltype(F), std::remove_reference_t<Obj>&>,
+      absl::functional_internal::EnableIf<!std::is_rvalue_reference_v<Obj&&>> =
+          0>
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  FunctionRef(nontype_t<F>, Obj&& obj ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
+      : invoker_(&absl::functional_internal::InvokeObject<Obj&, decltype(F), F,
+                                                          R, Args...>) {
+    ptr_.obj = std::addressof(obj);
+  }
+
+  template <auto F, typename Obj,
+            typename = EnableIfCompatible<decltype(F), Obj*>>
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  FunctionRef(nontype_t<F>, Obj* obj ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
+      : invoker_(&absl::functional_internal::InvokePtr<Obj, decltype(F), F, R,
+                                                       Args...>) {
+    ptr_.obj = obj;
+  }
+#endif
+
+  using absl_internal_is_view = std::true_type;
 
   // Call the underlying object.
   R operator()(Args... args) const {
@@ -133,11 +173,76 @@
 // Allow const qualified function signatures. Since FunctionRef requires
 // constness anyway we can just make this a no-op.
 template <typename R, typename... Args>
-class FunctionRef<R(Args...) const> : public FunctionRef<R(Args...)> {
+class ABSL_ATTRIBUTE_VIEW
+    FunctionRef<R(Args...) const> : private FunctionRef<R(Args...)> {
+  using Base = FunctionRef<R(Args...)>;
+
+  template <typename F, typename... U>
+  using EnableIfCompatible =
+      typename Base::template EnableIfCompatible<F, U...>;
+
  public:
-  using FunctionRef<R(Args...)>::FunctionRef;
+  template <
+      typename F,
+      typename = EnableIfCompatible<std::enable_if_t<
+          !std::is_same_v<FunctionRef, absl::remove_cvref_t<F>>, const F&>>>
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  FunctionRef(const F& f ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
+      : Base(std::in_place_t(), f) {}
+
+  template <typename F, typename = EnableIfCompatible<F*>,
+            absl::functional_internal::EnableIf<std::is_function_v<F>> = 0>
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  FunctionRef(F* f ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept : Base(f) {}
+
+#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+  template <auto F, typename = EnableIfCompatible<decltype(F)>>
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  FunctionRef(nontype_t<F> arg) noexcept : Base(arg) {}
+
+  template <auto F, typename Obj,
+            typename = EnableIfCompatible<decltype(F),
+                                          const std::remove_reference_t<Obj>&>,
+            absl::functional_internal::EnableIf<
+                !std::is_rvalue_reference_v<Obj&&>> = 0>
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  FunctionRef(nontype_t<F> arg,
+              Obj&& obj ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
+      : Base(arg, std::forward<Obj>(obj)) {}
+
+  template <auto F, typename Obj,
+            typename = EnableIfCompatible<decltype(F), const Obj*>>
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  FunctionRef(nontype_t<F> arg,
+              const Obj* obj ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
+      : Base(arg, obj) {}
+#endif
+
+  using absl_internal_is_view = std::true_type;
+
+  using Base::operator();
 };
 
+template <class F>
+FunctionRef(F*) -> FunctionRef<F>;
+
+#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+template <auto Func>
+FunctionRef(nontype_t<Func>)
+    -> FunctionRef<std::remove_pointer_t<decltype(Func)>>;
+
+template <class M, class T, M T::* Func, class U>
+FunctionRef(nontype_t<Func>, U&&)
+    -> FunctionRef<std::enable_if_t<std::is_member_pointer_v<M T::*>, M>>;
+
+template <class M, class T, M T::* Func, class U>
+FunctionRef(nontype_t<Func>, U&&) -> FunctionRef<std::enable_if_t<
+    std::is_object_v<M>, std::invoke_result_t<decltype(Func), U&>()>>;
+
+template <class R, class T, class... Args, R (*Func)(T, Args...), class U>
+FunctionRef(nontype_t<Func>, U&&) -> FunctionRef<R(Args...)>;
+#endif
+
 ABSL_NAMESPACE_END
 }  // namespace absl
 
diff --git a/absl/functional/function_ref_test.cc b/absl/functional/function_ref_test.cc
index 98d11f7..97aa3d5 100644
--- a/absl/functional/function_ref_test.cc
+++ b/absl/functional/function_ref_test.cc
@@ -16,27 +16,37 @@
 
 #include <functional>
 #include <memory>
+#include <type_traits>
+#include <utility>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "absl/container/internal/test_instance_tracker.h"
 #include "absl/functional/any_invocable.h"
 #include "absl/memory/memory.h"
+#include "absl/utility/utility.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace {
 
-void RunFun(FunctionRef<void()> f) { f(); }
-
-TEST(FunctionRefTest, Lambda) {
-  bool ran = false;
-  RunFun([&] { ran = true; });
-  EXPECT_TRUE(ran);
-}
+struct Class {
+  int Func() { return 42; }
+  int CFunc() const { return 43; }
+};
 
 int Function() { return 1337; }
 
+template <typename T>
+T Dereference(const T* v) {
+  return *v;
+}
+
+template <typename T>
+T Copy(const T& v) {
+  return v;
+}
+
 TEST(FunctionRefTest, Function1) {
   FunctionRef<int()> ref(&Function);
   EXPECT_EQ(1337, ref());
@@ -251,11 +261,11 @@
       std::is_same<Invoker<void, Trivial>, void (*)(VoidPtr, Trivial)>::value,
       "Small trivial types should be passed by value");
   static_assert(std::is_same<Invoker<void, LargeTrivial>,
-                             void (*)(VoidPtr, LargeTrivial &&)>::value,
+                             void (*)(VoidPtr, LargeTrivial&&)>::value,
                 "Large trivial types should be passed by rvalue reference");
   static_assert(
       std::is_same<Invoker<void, CopyableMovableInstance>,
-                   void (*)(VoidPtr, CopyableMovableInstance &&)>::value,
+                   void (*)(VoidPtr, CopyableMovableInstance&&)>::value,
       "Types with copy/move ctor should be passed by rvalue reference");
 
   // References are passed as references.
@@ -268,7 +278,7 @@
       "Reference types should be preserved");
   static_assert(
       std::is_same<Invoker<void, CopyableMovableInstance&&>,
-                   void (*)(VoidPtr, CopyableMovableInstance &&)>::value,
+                   void (*)(VoidPtr, CopyableMovableInstance&&)>::value,
       "Reference types should be preserved");
 
   // Make sure the address of an object received by reference is the same as the
@@ -298,6 +308,109 @@
   ref(obj);
 }
 
+TEST(FunctionRefTest, CorrectConstQualifiers) {
+  struct S {
+    int operator()() { return 42; }
+    int operator()() const { return 1337; }
+  };
+  S s;
+  EXPECT_EQ(42, FunctionRef<int()>(s)());
+  EXPECT_EQ(1337, FunctionRef<int() const>(s)());
+  EXPECT_EQ(1337, FunctionRef<int()>(std::as_const(s))());
+  EXPECT_EQ(1337, FunctionRef<int() const>(std::as_const(s))());
+}
+
+TEST(FunctionRefTest, Lambdas) {
+  // Stateless lambdas implicitly convert to function pointers, so their
+  // mutability is irrelevant.
+  EXPECT_TRUE(FunctionRef<bool()>([]() /*const*/ { return true; })());
+  EXPECT_TRUE(FunctionRef<bool()>([]() mutable { return true; })());
+  EXPECT_TRUE(FunctionRef<bool() const>([]() /*const*/ { return true; })());
+#if defined(__clang__) || (ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L && \
+                           defined(_MSC_VER) && !defined(__EDG__))
+  // MSVC has problems compiling the following code pre-C++20:
+  //   const auto f = []() mutable {};
+  //   f();
+  // EDG's MSVC-compatible mode (which Visual C++ uses for Intellisense)
+  // exhibits the bug in C++20 as well. So we don't support them.
+  EXPECT_TRUE(FunctionRef<bool() const>([]() mutable { return true; })());
+#endif
+
+  // Stateful lambdas are not implicitly convertible to function pointers, so
+  // a const stateful lambda is not mutably callable.
+  EXPECT_TRUE(FunctionRef<bool()>([v = true]() /*const*/ { return v; })());
+  EXPECT_TRUE(FunctionRef<bool()>([v = true]() mutable { return v; })());
+  EXPECT_TRUE(
+      FunctionRef<bool() const>([v = true]() /*const*/ { return v; })());
+  const auto func = [v = true]() mutable { return v; };
+  static_assert(
+      !std::is_convertible_v<decltype(func), FunctionRef<bool() const>>);
+}
+
+#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+static_assert(std::is_same_v<decltype(FunctionRef(nontype<&Class::Func>,
+                                                  std::declval<Class&>())),
+                             FunctionRef<int()>>);
+static_assert(std::is_same_v<decltype(FunctionRef(nontype<&Class::CFunc>,
+                                                  std::declval<Class&>())),
+                             FunctionRef<int() const>>);
+
+static_assert(std::is_same_v<decltype(FunctionRef(nontype<&Class::Func>,
+                                                  std::declval<Class*>())),
+                             FunctionRef<int()>>);
+static_assert(std::is_same_v<decltype(FunctionRef(nontype<&Class::CFunc>,
+                                                  std::declval<Class*>())),
+                             FunctionRef<int() const>>);
+
+TEST(FunctionRefTest, NonTypeParameterWithTemporaries) {
+  static_assert(!std::is_constructible_v<FunctionRef<int()>,
+                                         nontype_t<&Class::Func>, Class&&>);
+  static_assert(
+      !std::is_constructible_v<FunctionRef<int()>, nontype_t<&Class::Func>,
+                               const Class&&>);
+  static_assert(!std::is_constructible_v<FunctionRef<int() const>,
+                                         nontype_t<&Class::CFunc>, Class&&>);
+  static_assert(
+      !std::is_constructible_v<FunctionRef<int() const>,
+                               nontype_t<&Class::CFunc>, const Class&&>);
+}
+
+TEST(FunctionRefTest, NonTypeParameterWithDeductionGuides) {
+  EXPECT_EQ(1337, FunctionRef(nontype<&Function>)());
+  EXPECT_EQ(42, FunctionRef(nontype<&Copy<int>>,
+                            std::integral_constant<int, 42>::value)());
+  EXPECT_EQ(42, FunctionRef(nontype<&Dereference<int>>,
+                            &std::integral_constant<int, 42>::value)());
+
+  Class c;
+  EXPECT_EQ(42, FunctionRef<int()>(nontype<&Class::Func>, c)());
+  EXPECT_EQ(43, FunctionRef<int() const>(nontype<&Class::CFunc>, c)());
+
+  EXPECT_EQ(42, FunctionRef<int()>(nontype<&Class::Func>, &c)());
+  EXPECT_EQ(43, FunctionRef<int() const>(nontype<&Class::CFunc>, &c)());
+}
+#endif
+
+TEST(FunctionRefTest, OptionalArguments) {
+  struct S {
+    int operator()(int = 0) const { return 1337; }
+  };
+  S s;
+  EXPECT_EQ(1337, FunctionRef<int()>(s)());
+}
+
+TEST(FunctionRefTest, NonConstToConstConversion) {
+  // The const-qualified version might inherit from the non-const version.
+  // We want to make sure that this doesn't introduce a bug when an instance of
+  // the base (non-const) class is forwarded through the derived (const) class.
+  // This has the potential to trigger the copy constructor, thus incorrectly
+  // producing a copy rather than another indirection.
+  absl::FunctionRef<int()> a = +[]() { return 1; };
+  absl::FunctionRef<int() const> b = a;
+  a = +[]() { return 2; };
+  EXPECT_EQ(b(), 2);
+}
+
 }  // namespace
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/functional/internal/any_invocable.h b/absl/functional/internal/any_invocable.h
index 167d947..597c210 100644
--- a/absl/functional/internal/any_invocable.h
+++ b/absl/functional/internal/any_invocable.h
@@ -66,6 +66,7 @@
 #include "absl/base/attributes.h"
 #include "absl/base/config.h"
 #include "absl/base/macros.h"
+#include "absl/base/nullability.h"
 #include "absl/base/optimization.h"
 #include "absl/meta/type_traits.h"
 #include "absl/utility/utility.h"
@@ -75,7 +76,7 @@
 
 // Defined in functional/any_invocable.h
 template <class Sig>
-class AnyInvocable;
+class ABSL_NULLABILITY_COMPATIBLE AnyInvocable;
 
 namespace internal_any_invocable {
 
@@ -158,10 +159,18 @@
 // A discriminator when calling the "manager" function that describes operation
 // type-erased operation should be invoked.
 //
+// "dispose" specifies that the manager should perform a destroy.
+//
 // "relocate_from_to" specifies that the manager should perform a move.
 //
-// "dispose" specifies that the manager should perform a destroy.
-enum class FunctionToCall : bool { relocate_from_to, dispose };
+// "relocate_from_to_and_query_rust" is identical to "relocate_from_to" for C++
+// managers, but instructs Rust managers to perform a special operation that
+// can be detected by the caller.
+enum class FunctionToCall : unsigned char {
+  dispose,
+  relocate_from_to,
+  relocate_from_to_and_query_rust,
+};
 
 // The portion of `AnyInvocable` state that contains either a pointer to the
 // target object or the object itself in local storage
@@ -242,6 +251,7 @@
 
   switch (operation) {
     case FunctionToCall::relocate_from_to:
+    case FunctionToCall::relocate_from_to_and_query_rust:
       // NOTE: Requires that the left-hand operand is already empty.
       ::new (static_cast<void*>(&to->storage)) T(std::move(from_object));
       ABSL_FALLTHROUGH_INTENDED;
@@ -276,6 +286,7 @@
                                  TypeErasedState* const to) noexcept {
   switch (operation) {
     case FunctionToCall::relocate_from_to:
+    case FunctionToCall::relocate_from_to_and_query_rust:
       // NOTE: Requires that the left-hand operand is already empty.
       to->remote = from->remote;
       return;
@@ -302,6 +313,7 @@
 
   switch (operation) {
     case FunctionToCall::relocate_from_to:
+    case FunctionToCall::relocate_from_to_and_query_rust:
       // NOTE: Requires that the left-hand operand is already empty.
       to->remote.target = from->remote.target;
       return;
diff --git a/absl/functional/internal/function_ref.h b/absl/functional/internal/function_ref.h
index 27d45b8..543b30f 100644
--- a/absl/functional/internal/function_ref.h
+++ b/absl/functional/internal/function_ref.h
@@ -72,14 +72,52 @@
 // static_cast<R> handles the case the return type is void.
 template <typename Obj, typename R, typename... Args>
 R InvokeObject(VoidPtr ptr, typename ForwardT<Args>::type... args) {
-  auto o = static_cast<const Obj*>(ptr.obj);
-  return static_cast<R>(std::invoke(*o, std::forward<Args>(args)...));
+  using T = std::remove_reference_t<Obj>;
+  return static_cast<R>(std::invoke(
+      std::forward<Obj>(*const_cast<T*>(static_cast<const T*>(ptr.obj))),
+      std::forward<typename ForwardT<Args>::type>(args)...));
+}
+
+template <typename Obj, typename Fun, Fun F, typename R, typename... Args>
+R InvokeObject(VoidPtr ptr, typename ForwardT<Args>::type... args) {
+  using T = std::remove_reference_t<Obj>;
+  Obj&& obj =
+      std::forward<Obj>(*const_cast<T*>(static_cast<const T*>(ptr.obj)));
+  // Avoid std::invoke() since the callee is a known function at compile time
+  if constexpr (std::is_member_function_pointer_v<Fun>) {
+    return static_cast<R>((std::forward<Obj>(obj).*F)(
+        std::forward<typename ForwardT<Args>::type>(args)...));
+  } else {
+    return static_cast<R>(
+        F(std::forward<Obj>(obj),
+          std::forward<typename ForwardT<Args>::type>(args)...));
+  }
+}
+
+template <typename T, typename Fun, Fun F, typename R, typename... Args>
+R InvokePtr(VoidPtr ptr, typename ForwardT<Args>::type... args) {
+  T* obj = const_cast<T*>(static_cast<const T*>(ptr.obj));
+  // Avoid std::invoke() since the callee is a known function at compile time
+  if constexpr (std::is_member_function_pointer_v<Fun>) {
+    return static_cast<R>(
+        (obj->*F)(std::forward<typename ForwardT<Args>::type>(args)...));
+  } else {
+    return static_cast<R>(
+        F(obj, std::forward<typename ForwardT<Args>::type>(args)...));
+  }
 }
 
 template <typename Fun, typename R, typename... Args>
 R InvokeFunction(VoidPtr ptr, typename ForwardT<Args>::type... args) {
   auto f = reinterpret_cast<Fun>(ptr.fun);
-  return static_cast<R>(std::invoke(f, std::forward<Args>(args)...));
+  return static_cast<R>(
+      std::invoke(f, std::forward<typename ForwardT<Args>::type>(args)...));
+}
+
+template <typename Fun, Fun F, typename R, typename... Args>
+R InvokeFunction(VoidPtr, typename ForwardT<Args>::type... args) {
+  return static_cast<R>(
+      F(std::forward<typename ForwardT<Args>::type>(args)...));
 }
 
 template <typename Sig>
@@ -98,7 +136,7 @@
 void AssertNonNull(const F&) {}
 
 template <typename F, typename C>
-void AssertNonNull(F C::*f) {
+void AssertNonNull(F C::* f) {
   assert(f != nullptr);
   (void)f;
 }
diff --git a/absl/hash/BUILD.bazel b/absl/hash/BUILD.bazel
index b2ffcd0..187689f 100644
--- a/absl/hash/BUILD.bazel
+++ b/absl/hash/BUILD.bazel
@@ -14,6 +14,9 @@
 # limitations under the License.
 #
 
+load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
@@ -43,11 +46,11 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":city",
-        ":low_level_hash",
         ":weakly_mixed_integer",
         "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:endian",
+        "//absl/base:prefetch",
         "//absl/container:fixed_array",
         "//absl/functional:function_ref",
         "//absl/meta:type_traits",
@@ -76,6 +79,7 @@
 
 cc_test(
     name = "hash_test",
+    size = "large",
     srcs = [
         "hash_test.cc",
         "internal/hash_test.h",
@@ -186,22 +190,6 @@
 )
 
 cc_library(
-    name = "low_level_hash",
-    srcs = ["internal/low_level_hash.cc"],
-    hdrs = ["internal/low_level_hash.h"],
-    copts = ABSL_DEFAULT_COPTS,
-    linkopts = ABSL_DEFAULT_LINKOPTS,
-    visibility = ["//visibility:private"],
-    deps = [
-        "//absl/base:config",
-        "//absl/base:core_headers",
-        "//absl/base:endian",
-        "//absl/base:prefetch",
-        "//absl/numeric:int128",
-    ],
-)
-
-cc_library(
     name = "weakly_mixed_integer",
     hdrs = ["internal/weakly_mixed_integer.h"],
     copts = ABSL_DEFAULT_COPTS,
@@ -223,7 +211,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = ["//visibility:private"],
     deps = [
-        ":low_level_hash",
+        ":hash",
         "//absl/strings",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt
index 6996d93..b439e4c 100644
--- a/absl/hash/CMakeLists.txt
+++ b/absl/hash/CMakeLists.txt
@@ -38,7 +38,6 @@
     absl::optional
     absl::variant
     absl::utility
-    absl::low_level_hash
     absl::weakly_mixed_integer
   PUBLIC
 )
@@ -156,24 +155,6 @@
 # Internal-only target, do not depend on directly.
 absl_cc_library(
   NAME
-    low_level_hash
-  HDRS
-    "internal/low_level_hash.h"
-  SRCS
-    "internal/low_level_hash.cc"
-  COPTS
-    ${ABSL_DEFAULT_COPTS}
-  DEPS
-    absl::config
-    absl::core_headers
-    absl::endian
-    absl::int128
-    absl::prefetch
-)
-
-# Internal-only target, do not depend on directly.
-absl_cc_library(
-  NAME
     weakly_mixed_integer
   HDRS
     "internal/weakly_mixed_integer.h"
@@ -191,7 +172,7 @@
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
-    absl::low_level_hash
+    absl::hash
     absl::strings
     GTest::gmock_main
 )
diff --git a/absl/hash/hash_benchmark.cc b/absl/hash/hash_benchmark.cc
index 73b037d..b39ef75 100644
--- a/absl/hash/hash_benchmark.cc
+++ b/absl/hash/hash_benchmark.cc
@@ -338,6 +338,16 @@
 }();
 }  // namespace
 
+struct PodPairInt64 {
+  int64_t a;
+  int64_t b;
+
+  template <typename H>
+  friend H AbslHashValue(H h, const PodPairInt64& p) {
+    return H::combine(std::move(h), p.a, p.b);
+  }
+};
+
 template <class T>
 struct PodRand {
   static_assert(std::is_pod<T>::value, "");
@@ -378,6 +388,7 @@
 
 MAKE_LATENCY_BENCHMARK(AbslHash, Int32, PodRand<int32_t>)
 MAKE_LATENCY_BENCHMARK(AbslHash, Int64, PodRand<int64_t>)
+MAKE_LATENCY_BENCHMARK(AbslHash, PairInt64, PodRand<PodPairInt64>)
 MAKE_LATENCY_BENCHMARK(AbslHash, String3, StringRand<3>)
 MAKE_LATENCY_BENCHMARK(AbslHash, String5, StringRand<5>)
 MAKE_LATENCY_BENCHMARK(AbslHash, String9, StringRand<9>)
diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc
index 7582f54..89e0470 100644
--- a/absl/hash/hash_test.cc
+++ b/absl/hash/hash_test.cc
@@ -58,17 +58,17 @@
 
 namespace {
 
+using ::absl::Hash;
+using ::absl::container_internal::hashtable_debug_internal::
+    HashtableDebugAccess;
+using ::absl::hash_internal::SpyHashState;
 using ::absl::hash_test_internal::is_hashable;
 using ::absl::hash_test_internal::TypeErasedContainer;
 using ::absl::hash_test_internal::TypeErasedValue;
-using ::testing::SizeIs;
 
 template <typename T>
 using TypeErasedVector = TypeErasedContainer<std::vector<T>>;
 
-using absl::Hash;
-using absl::hash_internal::SpyHashState;
-
 template <typename T>
 class HashValueIntTest : public testing::Test {
 };
@@ -171,6 +171,9 @@
   constexpr size_t kLog2NumValues = 5;
   constexpr size_t kNumValues = 1 << kLog2NumValues;
 
+  int64_t test_count = 0;
+  int64_t total_stuck_bit_count = 0;
+
   for (size_t align = 1; align < kTotalSize / kNumValues;
        align < 8 ? align += 1 : align < 1024 ? align += 8 : align += 32) {
     SCOPED_TRACE(align);
@@ -188,9 +191,17 @@
     // Limit the scope to the bits we would be using for Swisstable.
     constexpr size_t kMask = (1 << (kLog2NumValues + 7)) - 1;
     size_t stuck_bits = (~bits_or | bits_and) & kMask;
-    // Test that there are at most 3 stuck bits.
-    EXPECT_LE(absl::popcount(stuck_bits), 3) << "0x" << std::hex << stuck_bits;
+    int stuck_bit_count = absl::popcount(stuck_bits);
+    size_t max_stuck_bits = 5;
+    EXPECT_LE(stuck_bit_count, max_stuck_bits)
+        << "0x" << std::hex << stuck_bits;
+
+    total_stuck_bit_count += stuck_bit_count;
+    ++test_count;
   }
+  // Test that average across alignments are at most 0.2 stuck bits.
+  // As of 2025-05-30 test is also passing with 0.07 stuck bits.
+  EXPECT_LE(total_stuck_bit_count, 0.2 * test_count);
 }
 
 TEST(HashValueTest, PointerToMember) {
@@ -1224,4 +1235,86 @@
             absl::Hash<AutoReturnTypeUser>{}(AutoReturnTypeUser{1, s}));
 }
 
+TEST(HashOf, DoubleSignCollision) {
+  // These values differ only in their most significant bit.
+  EXPECT_NE(absl::HashOf(-1.0), absl::HashOf(1.0));
+}
+
+// Test for collisions in short strings if PrecombineLengthMix is low quality.
+TEST(PrecombineLengthMix, ShortStringCollision) {
+#if defined(__wasm__)
+  GTEST_SKIP() << "Fails flakily on wasm due to no ASLR and 32-bit size_t.";
+#endif
+  std::string s1 = "00";
+  std::string s2 = "000";
+  constexpr char kMinChar = 0;
+  constexpr char kMaxChar = 32;
+  for (s1[0] = kMinChar; s1[0] < kMaxChar; ++s1[0]) {
+    for (s1[1] = kMinChar; s1[1] < kMaxChar; ++s1[1]) {
+      for (s2[0] = kMinChar; s2[0] < kMaxChar; ++s2[0]) {
+        for (s2[1] = kMinChar; s2[1] < kMaxChar; ++s2[1]) {
+          for (s2[2] = kMinChar; s2[2] < kMaxChar; ++s2[2]) {
+            ASSERT_NE(absl::HashOf(s1), absl::HashOf(s2))
+                << "s1[0]: " << static_cast<int>(s1[0])
+                << "; s1[1]: " << static_cast<int>(s1[1])
+                << "; s2[0]: " << static_cast<int>(s2[0])
+                << "; s2[1]: " << static_cast<int>(s2[1])
+                << "; s2[2]: " << static_cast<int>(s2[2]);
+          }
+        }
+      }
+    }
+  }
+}
+
+// Test that we don't cause excessive collisions on the hash table for
+// doubles in the range [-1024, 1024]. See cl/773069881 for more information.
+TEST(SwisstableCollisions, DoubleRange) {
+  absl::flat_hash_set<double> set;
+  for (double t = -1024.0; t < 1024.0; t += 1.0) {
+    set.insert(t);
+    ASSERT_LT(HashtableDebugAccess<decltype(set)>::GetNumProbes(set, t), 64)
+        << t;
+  }
+}
+
+// Test that for each pair of adjacent bytes in a string, if there's only
+// entropy in those two bytes, then we don't have excessive collisions.
+TEST(SwisstableCollisions, LowEntropyStrings) {
+  constexpr char kMinChar = 0;
+  constexpr char kMaxChar = 64;
+  // These sizes cover the different hashing cases.
+  for (size_t size : {8u, 16u, 32u, 64u, 128u}) {
+    for (size_t b = 0; b < size - 1; ++b) {
+      absl::flat_hash_set<std::string> set;
+      std::string s(size, '\0');
+      for (char c1 = kMinChar; c1 < kMaxChar; ++c1) {
+        for (char c2 = kMinChar; c2 < kMaxChar; ++c2) {
+          s[b] = c1;
+          s[b + 1] = c2;
+          set.insert(s);
+          ASSERT_LT(HashtableDebugAccess<decltype(set)>::GetNumProbes(set, s),
+                    64)
+              << "size: " << size << "; bit: " << b;
+        }
+      }
+    }
+  }
+}
+
+// Test that we don't have excessive collisions when keys are consecutive
+// integers rotated by N bits.
+TEST(SwisstableCollisions, LowEntropyInts) {
+  constexpr int kSizeTBits = sizeof(size_t) * 8;
+  for (int bit = 0; bit < kSizeTBits; ++bit) {
+    absl::flat_hash_set<size_t> set;
+    for (size_t i = 0; i < 128 * 1024; ++i) {
+      size_t v = absl::rotl(i, bit);
+      set.insert(v);
+      ASSERT_LT(HashtableDebugAccess<decltype(set)>::GetNumProbes(set, v), 48)
+          << bit << " " << i;
+    }
+  }
+}
+
 }  // namespace
diff --git a/absl/hash/internal/hash.cc b/absl/hash/internal/hash.cc
index 9abace5..23caae9 100644
--- a/absl/hash/internal/hash.cc
+++ b/absl/hash/internal/hash.cc
@@ -14,52 +14,299 @@
 
 #include "absl/hash/internal/hash.h"
 
+#include <cassert>
 #include <cstddef>
 #include <cstdint>
 #include <type_traits>
 
 #include "absl/base/attributes.h"
 #include "absl/base/config.h"
-#include "absl/hash/internal/low_level_hash.h"
+#include "absl/base/internal/unaligned_access.h"
+#include "absl/base/optimization.h"
+#include "absl/base/prefetch.h"
+#include "absl/hash/internal/city.h"
+
+#ifdef ABSL_AES_INTERNAL_HAVE_X86_SIMD
+#error ABSL_AES_INTERNAL_HAVE_X86_SIMD cannot be directly set
+#elif defined(__SSE4_2__) && defined(__AES__)
+#define ABSL_AES_INTERNAL_HAVE_X86_SIMD
+#endif
+
+
+#ifdef ABSL_AES_INTERNAL_HAVE_X86_SIMD
+#include <smmintrin.h>
+#include <wmmintrin.h>
+#include <xmmintrin.h>
+#endif  // ABSL_AES_INTERNAL_HAVE_X86_SIMD
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace hash_internal {
 
-uint64_t MixingHashState::CombineLargeContiguousImpl32(
-    uint64_t state, const unsigned char* first, size_t len) {
+namespace {
+
+void PrefetchFutureDataToLocalCache(const uint8_t* ptr) {
+  PrefetchToLocalCache(ptr + 5 * ABSL_CACHELINE_SIZE);
+}
+
+#ifdef ABSL_AES_INTERNAL_HAVE_X86_SIMD
+uint64_t Mix4x16Vectors(__m128i a, __m128i b, __m128i c, __m128i d) {
+  // res128 = encrypt(a + c, d) + decrypt(b - d, a)
+  auto res128 = _mm_add_epi64(_mm_aesenc_si128(_mm_add_epi64(a, c), d),
+                              _mm_aesdec_si128(_mm_sub_epi64(b, d), a));
+  auto x64 = static_cast<uint64_t>(_mm_cvtsi128_si64(res128));
+  auto y64 = static_cast<uint64_t>(_mm_extract_epi64(res128, 1));
+  return x64 ^ y64;
+}
+
+uint64_t LowLevelHash33To64(uint64_t seed, const uint8_t* ptr, size_t len) {
+  assert(len > 32);
+  assert(len <= 64);
+  __m128i state =
+      _mm_set_epi64x(static_cast<int64_t>(seed), static_cast<int64_t>(len));
+  auto a = _mm_loadu_si128(reinterpret_cast<const __m128i*>(ptr));
+  auto b = _mm_loadu_si128(reinterpret_cast<const __m128i*>(ptr + 16));
+  auto* last32_ptr = ptr + len - 32;
+  auto c = _mm_loadu_si128(reinterpret_cast<const __m128i*>(last32_ptr));
+  auto d = _mm_loadu_si128(reinterpret_cast<const __m128i*>(last32_ptr + 16));
+
+  // Bits of the second argument to _mm_aesdec_si128/_mm_aesenc_si128 are
+  // XORed with the state argument after encryption.
+  // We use each value as the first argument to shuffle all the bits around.
+  // We do not add any salt to the state or loaded data, instead we vary
+  // instructions used to mix bits _mm_aesdec_si128/_mm_aesenc_si128 and
+  // _mm_add_epi64/_mm_sub_epi64.
+  // _mm_add_epi64/_mm_sub_epi64 are combined to one instruction with data
+  // loading like `vpaddq  xmm1, xmm0, xmmword ptr [rdi]`.
+  auto na = _mm_aesdec_si128(_mm_add_epi64(state, a), state);
+  auto nb = _mm_aesdec_si128(_mm_sub_epi64(state, b), state);
+  auto nc = _mm_aesenc_si128(_mm_add_epi64(state, c), state);
+  auto nd = _mm_aesenc_si128(_mm_sub_epi64(state, d), state);
+
+  // We perform another round of encryption to mix bits between two halves of
+  // the input.
+  return Mix4x16Vectors(na, nb, nc, nd);
+}
+
+[[maybe_unused]] ABSL_ATTRIBUTE_NOINLINE uint64_t
+LowLevelHashLenGt64(uint64_t seed, const void* data, size_t len) {
+  assert(len > 64);
+  const uint8_t* ptr = static_cast<const uint8_t*>(data);
+  const uint8_t* last_32_ptr = ptr + len - 32;
+
+  // If we have more than 64 bytes, we're going to handle chunks of 64
+  // bytes at a time. We're going to build up four separate hash states
+  // which we will then hash together. This avoids short dependency chains.
+  __m128i state0 =
+      _mm_set_epi64x(static_cast<int64_t>(seed), static_cast<int64_t>(len));
+  __m128i state1 = state0;
+  __m128i state2 = state1;
+  __m128i state3 = state2;
+
+  // Mixing two 128-bit vectors at a time with corresponding states.
+  // All variables are mixed slightly differently to avoid hash collision
+  // due to trivial byte rotation.
+  // We combine state and data with _mm_add_epi64/_mm_sub_epi64 before applying
+  // AES encryption to make hash function dependent on the order of the blocks.
+  // See comments in LowLevelHash33To64 for more considerations.
+  auto mix_ab = [&state0,
+                 &state1](const uint8_t* p) ABSL_ATTRIBUTE_ALWAYS_INLINE {
+    // i128 a = *p;
+    // i128 b = *(p + 16);
+    // state0 = decrypt(state0 + a, state0);
+    // state1 = decrypt(state1 - b, state1);
+    auto a = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p));
+    auto b = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p + 16));
+    state0 = _mm_aesdec_si128(_mm_add_epi64(state0, a), state0);
+    state1 = _mm_aesdec_si128(_mm_sub_epi64(state1, b), state1);
+  };
+  auto mix_cd = [&state2,
+                 &state3](const uint8_t* p) ABSL_ATTRIBUTE_ALWAYS_INLINE {
+    // i128 c = *p;
+    // i128 d = *(p + 16);
+    // state2 = encrypt(state2 + c, state2);
+    // state3 = encrypt(state3 - d, state3);
+    auto c = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p));
+    auto d = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p + 16));
+    state2 = _mm_aesenc_si128(_mm_add_epi64(state2, c), state2);
+    state3 = _mm_aesenc_si128(_mm_sub_epi64(state3, d), state3);
+  };
+
+  do {
+    PrefetchFutureDataToLocalCache(ptr);
+    mix_ab(ptr);
+    mix_cd(ptr + 32);
+
+    ptr += 64;
+    len -= 64;
+  } while (len > 64);
+
+  // We now have a data `ptr` with at most 64 bytes.
+  if (len > 32) {
+    mix_ab(ptr);
+  }
+  mix_cd(last_32_ptr);
+
+  return Mix4x16Vectors(state0, state1, state2, state3);
+}
+#else
+uint64_t Mix32Bytes(const uint8_t* ptr, uint64_t current_state) {
+  uint64_t a = absl::base_internal::UnalignedLoad64(ptr);
+  uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8);
+  uint64_t c = absl::base_internal::UnalignedLoad64(ptr + 16);
+  uint64_t d = absl::base_internal::UnalignedLoad64(ptr + 24);
+
+  uint64_t cs0 = Mix(a ^ kStaticRandomData[1], b ^ current_state);
+  uint64_t cs1 = Mix(c ^ kStaticRandomData[2], d ^ current_state);
+  return cs0 ^ cs1;
+}
+
+uint64_t LowLevelHash33To64(uint64_t seed, const uint8_t* ptr, size_t len) {
+  assert(len > 32);
+  assert(len <= 64);
+  uint64_t current_state = seed ^ kStaticRandomData[0] ^ len;
+  const uint8_t* last_32_ptr = ptr + len - 32;
+  return Mix32Bytes(last_32_ptr, Mix32Bytes(ptr, current_state));
+}
+
+[[maybe_unused]] ABSL_ATTRIBUTE_NOINLINE uint64_t
+LowLevelHashLenGt64(uint64_t seed, const void* data, size_t len) {
+  assert(len > 64);
+  const uint8_t* ptr = static_cast<const uint8_t*>(data);
+  uint64_t current_state = seed ^ kStaticRandomData[0] ^ len;
+  const uint8_t* last_32_ptr = ptr + len - 32;
+  // If we have more than 64 bytes, we're going to handle chunks of 64
+  // bytes at a time. We're going to build up four separate hash states
+  // which we will then hash together. This avoids short dependency chains.
+  uint64_t duplicated_state0 = current_state;
+  uint64_t duplicated_state1 = current_state;
+  uint64_t duplicated_state2 = current_state;
+
+  do {
+    PrefetchFutureDataToLocalCache(ptr);
+
+    uint64_t a = absl::base_internal::UnalignedLoad64(ptr);
+    uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8);
+    uint64_t c = absl::base_internal::UnalignedLoad64(ptr + 16);
+    uint64_t d = absl::base_internal::UnalignedLoad64(ptr + 24);
+    uint64_t e = absl::base_internal::UnalignedLoad64(ptr + 32);
+    uint64_t f = absl::base_internal::UnalignedLoad64(ptr + 40);
+    uint64_t g = absl::base_internal::UnalignedLoad64(ptr + 48);
+    uint64_t h = absl::base_internal::UnalignedLoad64(ptr + 56);
+
+    current_state = Mix(a ^ kStaticRandomData[1], b ^ current_state);
+    duplicated_state0 = Mix(c ^ kStaticRandomData[2], d ^ duplicated_state0);
+
+    duplicated_state1 = Mix(e ^ kStaticRandomData[3], f ^ duplicated_state1);
+    duplicated_state2 = Mix(g ^ kStaticRandomData[4], h ^ duplicated_state2);
+
+    ptr += 64;
+    len -= 64;
+  } while (len > 64);
+
+  current_state = (current_state ^ duplicated_state0) ^
+                  (duplicated_state1 + duplicated_state2);
+  // We now have a data `ptr` with at most 64 bytes and the current state
+  // of the hashing state machine stored in current_state.
+  if (len > 32) {
+    current_state = Mix32Bytes(ptr, current_state);
+  }
+
+  // We now have a data `ptr` with at most 32 bytes and the current state
+  // of the hashing state machine stored in current_state. But we can
+  // safely read from `ptr + len - 32`.
+  return Mix32Bytes(last_32_ptr, current_state);
+}
+#endif  // ABSL_AES_INTERNAL_HAVE_X86_SIMD
+
+[[maybe_unused]] uint64_t LowLevelHashLenGt32(uint64_t seed, const void* data,
+                                              size_t len) {
+  assert(len > 32);
+  if (ABSL_PREDICT_FALSE(len > 64)) {
+    return LowLevelHashLenGt64(seed, data, len);
+  }
+  return LowLevelHash33To64(seed, static_cast<const uint8_t*>(data), len);
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline uint64_t HashBlockOn32Bit(
+    uint64_t state, const unsigned char* data, size_t len) {
+  // TODO(b/417141985): expose and use CityHash32WithSeed.
+  // Note: we can't use PrecombineLengthMix here because len can be up to 1024.
+  return CombineRawImpl(
+      state + len,
+      hash_internal::CityHash32(reinterpret_cast<const char*>(data), len));
+}
+
+ABSL_ATTRIBUTE_NOINLINE uint64_t
+SplitAndCombineOn32Bit(uint64_t state, const unsigned char* first, size_t len) {
   while (len >= PiecewiseChunkSize()) {
-    state = Mix(
-        state ^ hash_internal::CityHash32(reinterpret_cast<const char*>(first),
-                                          PiecewiseChunkSize()),
-        kMul);
+    state = HashBlockOn32Bit(state, first, PiecewiseChunkSize());
     len -= PiecewiseChunkSize();
     first += PiecewiseChunkSize();
   }
+  // Do not call CombineContiguousImpl for empty range since it is modifying
+  // state.
+  if (len == 0) {
+    return state;
+  }
   // Handle the remainder.
   return CombineContiguousImpl(state, first, len,
                                std::integral_constant<int, 4>{});
 }
 
-uint64_t MixingHashState::CombineLargeContiguousImpl64(
-    uint64_t state, const unsigned char* first, size_t len) {
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline uint64_t HashBlockOn64Bit(
+    uint64_t state, const unsigned char* data, size_t len) {
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  return LowLevelHashLenGt32(state, data, len);
+#else
+  return hash_internal::CityHash64WithSeed(reinterpret_cast<const char*>(data),
+                                           len, state);
+#endif
+}
+
+ABSL_ATTRIBUTE_NOINLINE uint64_t
+SplitAndCombineOn64Bit(uint64_t state, const unsigned char* first, size_t len) {
   while (len >= PiecewiseChunkSize()) {
-    state = Mix(state ^ Hash64(first, PiecewiseChunkSize()), kMul);
+    state = HashBlockOn64Bit(state, first, PiecewiseChunkSize());
     len -= PiecewiseChunkSize();
     first += PiecewiseChunkSize();
   }
+  // Do not call CombineContiguousImpl for empty range since it is modifying
+  // state.
+  if (len == 0) {
+    return state;
+  }
   // Handle the remainder.
   return CombineContiguousImpl(state, first, len,
                                std::integral_constant<int, 8>{});
 }
 
-ABSL_CONST_INIT const void* const MixingHashState::kSeed = &kSeed;
+}  // namespace
 
-uint64_t MixingHashState::LowLevelHashImpl(const unsigned char* data,
-                                           size_t len) {
-  return LowLevelHashLenGt32(data, len, Seed(), &kStaticRandomData[0]);
+uint64_t CombineLargeContiguousImplOn32BitLengthGt8(uint64_t state,
+                                                    const unsigned char* first,
+                                                    size_t len) {
+  assert(len > 8);
+  assert(sizeof(size_t) == 4);  // NOLINT(misc-static-assert)
+  if (ABSL_PREDICT_TRUE(len <= PiecewiseChunkSize())) {
+    return HashBlockOn32Bit(state, first, len);
+  }
+  return SplitAndCombineOn32Bit(state, first, len);
 }
 
+uint64_t CombineLargeContiguousImplOn64BitLengthGt32(uint64_t state,
+                                                     const unsigned char* first,
+                                                     size_t len) {
+  assert(len > 32);
+  assert(sizeof(size_t) == 8);  // NOLINT(misc-static-assert)
+  if (ABSL_PREDICT_TRUE(len <= PiecewiseChunkSize())) {
+    return HashBlockOn64Bit(state, first, len);
+  }
+  return SplitAndCombineOn64Bit(state, first, len);
+}
+
+ABSL_CONST_INIT const void* const MixingHashState::kSeed = &kSeed;
+
 }  // namespace hash_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h
index eb53823..15d3d5b 100644
--- a/absl/hash/internal/hash.h
+++ b/absl/hash/internal/hash.h
@@ -89,10 +89,46 @@
 #include "absl/types/variant.h"
 #include "absl/utility/utility.h"
 
-#if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L
+#if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L && \
+    !defined(__XTENSA__)
 #include <filesystem>  // NOLINT
 #endif
 
+// 32-bit builds with SSE 4.2 do not have _mm_crc32_u64, so the
+// __x86_64__ condition is necessary.
+#if defined(__SSE4_2__) && defined(__x86_64__)
+
+#include <x86intrin.h>
+#define ABSL_HASH_INTERNAL_HAS_CRC32
+#define ABSL_HASH_INTERNAL_CRC32_U64 _mm_crc32_u64
+#define ABSL_HASH_INTERNAL_CRC32_U32 _mm_crc32_u32
+#define ABSL_HASH_INTERNAL_CRC32_U8 _mm_crc32_u8
+
+// 32-bit builds with AVX do not have _mm_crc32_u64, so the _M_X64 condition is
+// necessary.
+#elif defined(_MSC_VER) && !defined(__clang__) && defined(__AVX__) && \
+    defined(_M_X64)
+
+// MSVC AVX (/arch:AVX) implies SSE 4.2.
+#include <intrin.h>
+#define ABSL_HASH_INTERNAL_HAS_CRC32
+#define ABSL_HASH_INTERNAL_CRC32_U64 _mm_crc32_u64
+#define ABSL_HASH_INTERNAL_CRC32_U32 _mm_crc32_u32
+#define ABSL_HASH_INTERNAL_CRC32_U8 _mm_crc32_u8
+
+#elif defined(__ARM_FEATURE_CRC32)
+
+#include <arm_acle.h>
+#define ABSL_HASH_INTERNAL_HAS_CRC32
+// Casting to uint32_t to be consistent with x86 intrinsic (_mm_crc32_u64
+// accepts crc as 64 bit integer).
+#define ABSL_HASH_INTERNAL_CRC32_U64(crc, data) \
+  __crc32cd(static_cast<uint32_t>(crc), data)
+#define ABSL_HASH_INTERNAL_CRC32_U32 __crc32cw
+#define ABSL_HASH_INTERNAL_CRC32_U8 __crc32cb
+
+#endif
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
@@ -104,8 +140,6 @@
 // returns the size of these chunks.
 constexpr size_t PiecewiseChunkSize() { return 1024; }
 
-// PiecewiseCombiner
-//
 // PiecewiseCombiner is an internal-only helper class for hashing a piecewise
 // buffer of `char` or `unsigned char` as though it were contiguous.  This class
 // provides two methods:
@@ -126,12 +160,10 @@
 //    return combiner.finalize(std::move(state));
 class PiecewiseCombiner {
  public:
-  PiecewiseCombiner() : position_(0) {}
+  PiecewiseCombiner() = default;
   PiecewiseCombiner(const PiecewiseCombiner&) = delete;
   PiecewiseCombiner& operator=(const PiecewiseCombiner&) = delete;
 
-  // PiecewiseCombiner::add_buffer()
-  //
   // Appends the given range of bytes to the sequence to be hashed, which may
   // modify the provided hash state.
   template <typename H>
@@ -142,8 +174,6 @@
                       reinterpret_cast<const unsigned char*>(data), size);
   }
 
-  // PiecewiseCombiner::finalize()
-  //
   // Finishes combining the hash sequence, which may may modify the provided
   // hash state.
   //
@@ -156,21 +186,19 @@
 
  private:
   unsigned char buf_[PiecewiseChunkSize()];
-  size_t position_;
+  size_t position_ = 0;
+  bool added_something_ = false;
 };
 
-// is_hashable()
-//
 // Trait class which returns true if T is hashable by the absl::Hash framework.
 // Used for the AbslHashValue implementations for composite types below.
 template <typename T>
 struct is_hashable;
 
-// HashStateBase
-//
-// An internal implementation detail that contains common implementation details
-// for all of the "hash state objects" objects generated by Abseil.  This is not
-// a public API; users should not create classes that inherit from this.
+// HashStateBase is an internal implementation detail that contains common
+// implementation details for all of the "hash state objects" objects generated
+// by Abseil.  This is not a public API; users should not create classes that
+// inherit from this.
 //
 // A hash state object is the template argument `H` passed to `AbslHashValue`.
 // It represents an intermediate state in the computation of an unspecified hash
@@ -235,8 +263,6 @@
 template <typename H>
 class HashStateBase {
  public:
-  // HashStateBase::combine()
-  //
   // Combines an arbitrary number of values into a hash state, returning the
   // updated state.
   //
@@ -256,8 +282,6 @@
   static H combine(H state, const T& value, const Ts&... values);
   static H combine(H state) { return state; }
 
-  // HashStateBase::combine_contiguous()
-  //
   // Combines a contiguous array of `size` elements into a hash state, returning
   // the updated state.
   //
@@ -297,8 +321,6 @@
   };
 };
 
-// is_uniquely_represented
-//
 // `is_uniquely_represented<T>` is a trait class that indicates whether `T`
 // is uniquely represented.
 //
@@ -333,8 +355,6 @@
 template <typename T, typename Enable = void>
 struct is_uniquely_represented : std::false_type {};
 
-// is_uniquely_represented<unsigned char>
-//
 // unsigned char is a synonym for "byte", so it is guaranteed to be
 // uniquely represented.
 template <>
@@ -349,9 +369,6 @@
     Integral, typename std::enable_if<std::is_integral<Integral>::value>::type>
     : std::true_type {};
 
-// is_uniquely_represented<bool>
-//
-//
 template <>
 struct is_uniquely_represented<bool> : std::false_type {};
 
@@ -373,8 +390,15 @@
   }
 };
 
-// hash_bytes()
-//
+// For use in `raw_hash_set` to pass a seed to the hash function.
+struct HashWithSeed {
+  template <typename Hasher, typename T>
+  size_t hash(const Hasher& hasher, const T& value, size_t seed) const {
+    // NOLINTNEXTLINE(clang-diagnostic-sign-conversion)
+    return hasher.hash_with_seed(value, seed);
+  }
+};
+
 // Convenience function that combines `hash_state` with the byte representation
 // of `value`.
 template <typename H, typename T,
@@ -422,8 +446,10 @@
 template <typename H, typename B>
 typename std::enable_if<std::is_same<B, bool>::value, H>::type AbslHashValue(
     H hash_state, B value) {
+  // We use ~size_t{} instead of 1 so that all bits are different between
+  // true/false instead of only 1.
   return H::combine(std::move(hash_state),
-                    static_cast<unsigned char>(value ? 1 : 0));
+                    static_cast<size_t>(value ? ~size_t{} : 0));
 }
 
 // AbslHashValue() for hashing enum values
@@ -502,10 +528,10 @@
                                                              T ptr) {
   auto v = reinterpret_cast<uintptr_t>(ptr);
   // Due to alignment, pointers tend to have low bits as zero, and the next few
-  // bits follow a pattern since they are also multiples of some base value. The
-  // byte swap in WeakMix helps ensure we still have good entropy in low bits.
-  // Mix pointers twice to ensure we have good entropy in low bits.
-  return H::combine(std::move(hash_state), v, v);
+  // bits follow a pattern since they are also multiples of some base value.
+  // The PointerAlignment test verifies that our mixing is good enough to handle
+  // these cases.
+  return H::combine(std::move(hash_state), v);
 }
 
 // AbslHashValue() for hashing nullptr_t
@@ -559,8 +585,6 @@
   return H::combine(std::move(hash_state), p.first, p.second);
 }
 
-// hash_tuple()
-//
 // Helper function for hashing a tuple. The third argument should
 // be an index_sequence running from 0 to tuple_size<Tuple> - 1.
 template <typename H, typename Tuple, size_t... Is>
@@ -619,9 +643,7 @@
 // `eq()` member isn't equivalent to `==` on the underlying character type.
 template <typename H>
 H AbslHashValue(H hash_state, absl::string_view str) {
-  return H::combine(
-      H::combine_contiguous(std::move(hash_state), str.data(), str.size()),
-      WeaklyMixedInteger{str.size()});
+  return H::combine_contiguous(std::move(hash_state), str.data(), str.size());
 }
 
 // Support std::wstring, std::u16string and std::u32string.
@@ -632,9 +654,7 @@
 H AbslHashValue(
     H hash_state,
     const std::basic_string<Char, std::char_traits<Char>, Alloc>& str) {
-  return H::combine(
-      H::combine_contiguous(std::move(hash_state), str.data(), str.size()),
-      WeaklyMixedInteger{str.size()});
+  return H::combine_contiguous(std::move(hash_state), str.data(), str.size());
 }
 
 // Support std::wstring_view, std::u16string_view and std::u32string_view.
@@ -643,16 +663,15 @@
                                        std::is_same<Char, char16_t>::value ||
                                        std::is_same<Char, char32_t>::value>>
 H AbslHashValue(H hash_state, std::basic_string_view<Char> str) {
-  return H::combine(
-      H::combine_contiguous(std::move(hash_state), str.data(), str.size()),
-      WeaklyMixedInteger{str.size()});
+  return H::combine_contiguous(std::move(hash_state), str.data(), str.size());
 }
 
 #if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L && \
     (!defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) ||        \
      __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 130000) &&       \
     (!defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) ||         \
-     __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101500)
+     __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101500) &&        \
+    (!defined(__XTENSA__))
 
 #define ABSL_INTERNAL_STD_FILESYSTEM_PATH_HASH_AVAILABLE 1
 
@@ -727,9 +746,8 @@
 typename std::enable_if<is_hashable<T>::value && !std::is_same<T, bool>::value,
                         H>::type
 AbslHashValue(H hash_state, const std::vector<T, Allocator>& vector) {
-  return H::combine(H::combine_contiguous(std::move(hash_state), vector.data(),
-                                          vector.size()),
-                    WeaklyMixedInteger{vector.size()});
+  return H::combine_contiguous(std::move(hash_state), vector.data(),
+                               vector.size());
 }
 
 // AbslHashValue special cases for hashing std::vector<bool>
@@ -888,7 +906,6 @@
   return H::combine(std::move(hash_state), opt.has_value());
 }
 
-// VariantVisitor
 template <typename H>
 struct VariantVisitor {
   H&& hash_state;
@@ -937,8 +954,6 @@
 
 // -----------------------------------------------------------------------------
 
-// hash_range_or_bytes()
-//
 // Mixes all values in the range [data, data+size) into the hash state.
 // This overload accepts only uniquely-represented types, and hashes them by
 // hashing the entire range of bytes.
@@ -949,16 +964,264 @@
   return H::combine_contiguous(std::move(hash_state), bytes, sizeof(T) * size);
 }
 
-// hash_range_or_bytes()
 template <typename H, typename T>
 typename std::enable_if<!is_uniquely_represented<T>::value, H>::type
 hash_range_or_bytes(H hash_state, const T* data, size_t size) {
   for (const auto end = data + size; data < end; ++data) {
     hash_state = H::combine(std::move(hash_state), *data);
   }
-  return hash_state;
+  return H::combine(std::move(hash_state),
+                    hash_internal::WeaklyMixedInteger{size});
 }
 
+inline constexpr uint64_t kMul = uint64_t{0x79d5f9e0de1e8cf5};
+
+// Random data taken from the hexadecimal digits of Pi's fractional component.
+// https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number
+ABSL_CACHELINE_ALIGNED inline constexpr uint64_t kStaticRandomData[] = {
+    0x243f'6a88'85a3'08d3, 0x1319'8a2e'0370'7344, 0xa409'3822'299f'31d0,
+    0x082e'fa98'ec4e'6c89, 0x4528'21e6'38d0'1377,
+};
+
+// Extremely weak mixture of length that is mixed into the state before
+// combining the data. It is used only for small strings. This also ensures that
+// we have high entropy in all bits of the state.
+inline uint64_t PrecombineLengthMix(uint64_t state, size_t len) {
+  ABSL_ASSUME(len + sizeof(uint64_t) <= sizeof(kStaticRandomData));
+  uint64_t data = absl::base_internal::UnalignedLoad64(
+      reinterpret_cast<const unsigned char*>(&kStaticRandomData[0]) + len);
+  return state ^ data;
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline uint64_t Mix(uint64_t lhs, uint64_t rhs) {
+  // Though the 128-bit product needs multiple instructions on non-x86-64
+  // platforms, it is still a good balance between speed and hash quality.
+  absl::uint128 m = lhs;
+  m *= rhs;
+  return Uint128High64(m) ^ Uint128Low64(m);
+}
+
+// Suppress erroneous array bounds errors on GCC.
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+#endif
+inline uint32_t Read4(const unsigned char* p) {
+  return absl::base_internal::UnalignedLoad32(p);
+}
+inline uint64_t Read8(const unsigned char* p) {
+  return absl::base_internal::UnalignedLoad64(p);
+}
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+// Reads 9 to 16 bytes from p.
+// The first 8 bytes are in .first, and the rest of the bytes are in .second
+// along with duplicated bytes from .first if len<16.
+inline std::pair<uint64_t, uint64_t> Read9To16(const unsigned char* p,
+                                               size_t len) {
+  return {Read8(p), Read8(p + len - 8)};
+}
+
+// Reads 4 to 8 bytes from p.
+// Bytes are permuted and some input bytes may be duplicated in output.
+inline uint64_t Read4To8(const unsigned char* p, size_t len) {
+  // If `len < 8`, we duplicate bytes. We always put low memory at the end.
+  // E.g., on little endian platforms:
+  // `ABCD` will be read as `ABCDABCD`.
+  // `ABCDE` will be read as `BCDEABCD`.
+  // `ABCDEF` will be read as `CDEFABCD`.
+  // `ABCDEFG` will be read as `DEFGABCD`.
+  // `ABCDEFGH` will be read as `EFGHABCD`.
+  // We also do not care about endianness. On big-endian platforms, bytes will
+  // be permuted differently. We always shift low memory by 32, because that
+  // can be pipelined earlier. Reading high memory requires computing
+  // `p + len - 4`.
+  uint64_t most_significant =
+      static_cast<uint64_t>(absl::base_internal::UnalignedLoad32(p)) << 32;
+  uint64_t least_significant =
+      absl::base_internal::UnalignedLoad32(p + len - 4);
+  return most_significant | least_significant;
+}
+
+// Reads 1 to 3 bytes from p. Some input bytes may be duplicated in output.
+inline uint32_t Read1To3(const unsigned char* p, size_t len) {
+  // The trick used by this implementation is to avoid branches.
+  // We always read three bytes by duplicating.
+  // E.g.,
+  // `A` is read as `AAA`.
+  // `AB` is read as `ABB`.
+  // `ABC` is read as `ABC`.
+  // We always shift `p[0]` so that it can be pipelined better.
+  // Other bytes require extra computation to find indices.
+  uint32_t mem0 = (static_cast<uint32_t>(p[0]) << 16) | p[len - 1];
+  uint32_t mem1 = static_cast<uint32_t>(p[len / 2]) << 8;
+  return mem0 | mem1;
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline uint64_t CombineRawImpl(uint64_t state,
+                                                            uint64_t value) {
+  return Mix(state ^ value, kMul);
+}
+
+// Slow dispatch path for calls to CombineContiguousImpl with a size argument
+// larger than inlined size. Has the same effect as calling
+// CombineContiguousImpl() repeatedly with the chunk stride size.
+uint64_t CombineLargeContiguousImplOn32BitLengthGt8(uint64_t state,
+                                                    const unsigned char* first,
+                                                    size_t len);
+uint64_t CombineLargeContiguousImplOn64BitLengthGt32(uint64_t state,
+                                                     const unsigned char* first,
+                                                     size_t len);
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline uint64_t CombineSmallContiguousImpl(
+    uint64_t state, const unsigned char* first, size_t len) {
+  ABSL_ASSUME(len <= 8);
+  uint64_t v;
+  if (len >= 4) {
+    v = Read4To8(first, len);
+  } else if (len > 0) {
+    v = Read1To3(first, len);
+  } else {
+    // Empty string must modify the state.
+    v = 0x57;
+  }
+  return CombineRawImpl(state, v);
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline uint64_t CombineContiguousImpl9to16(
+    uint64_t state, const unsigned char* first, size_t len) {
+  ABSL_ASSUME(len >= 9);
+  ABSL_ASSUME(len <= 16);
+  // Note: any time one half of the mix function becomes zero it will fail to
+  // incorporate any bits from the other half. However, there is exactly 1 in
+  // 2^64 values for each side that achieve this, and only when the size is
+  // exactly 16 -- for smaller sizes there is an overlapping byte that makes
+  // this impossible unless the seed is *also* incredibly unlucky.
+  auto p = Read9To16(first, len);
+  return Mix(state ^ p.first, kMul ^ p.second);
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline uint64_t CombineContiguousImpl17to32(
+    uint64_t state, const unsigned char* first, size_t len) {
+  ABSL_ASSUME(len >= 17);
+  ABSL_ASSUME(len <= 32);
+  // Do two mixes of overlapping 16-byte ranges in parallel to minimize
+  // latency.
+  const uint64_t m0 =
+      Mix(Read8(first) ^ kStaticRandomData[1], Read8(first + 8) ^ state);
+
+  const unsigned char* tail_16b_ptr = first + (len - 16);
+  const uint64_t m1 = Mix(Read8(tail_16b_ptr) ^ kStaticRandomData[3],
+                          Read8(tail_16b_ptr + 8) ^ state);
+  return m0 ^ m1;
+}
+
+// Implementation of the base case for combine_contiguous where we actually
+// mix the bytes into the state.
+// Dispatch to different implementations of combine_contiguous depending
+// on the value of `sizeof(size_t)`.
+inline uint64_t CombineContiguousImpl(
+    uint64_t state, const unsigned char* first, size_t len,
+    std::integral_constant<int, 4> /* sizeof_size_t */) {
+  // For large values we use CityHash, for small ones we use custom low latency
+  // hash.
+  if (len <= 8) {
+    return CombineSmallContiguousImpl(PrecombineLengthMix(state, len), first,
+                                      len);
+  }
+  return CombineLargeContiguousImplOn32BitLengthGt8(state, first, len);
+}
+
+#ifdef ABSL_HASH_INTERNAL_HAS_CRC32
+inline uint64_t CombineContiguousImpl(
+    uint64_t state, const unsigned char* first, size_t len,
+    std::integral_constant<int, 8> /* sizeof_size_t */) {
+  if (ABSL_PREDICT_FALSE(len > 32)) {
+    return CombineLargeContiguousImplOn64BitLengthGt32(state, first, len);
+  }
+  // `mul` is the salt that is used for final mixing. It is important to fill
+  // high 32 bits because CRC wipes out high 32 bits.
+  // `rotr` is important to mix `len` into high 32 bits.
+  uint64_t mul = absl::rotr(kMul, static_cast<int>(len));
+  // Only low 32 bits of each uint64_t are used in CRC32 so we use gbswap_64 to
+  // move high 32 bits to low 32 bits. It has slightly smaller binary size than
+  // `>> 32`. `state + 8 * len` is a single instruction on both x86 and ARM, so
+  // we use it to better mix length. Although only the low 32 bits of the pair
+  // elements are used, we use pair<uint64_t, uint64_t> for better generated
+  // code.
+  std::pair<uint64_t, uint64_t> crcs = {state + 8 * len,
+                                        absl::gbswap_64(state)};
+
+  // All CRC operations here directly read bytes from the memory.
+  // Single fused instructions are used, like `crc32 rcx, qword ptr [rsi]`.
+  // On x86, llvm-mca reports latency `R + 2` for such fused instructions, while
+  // `R + 3` for two separate `mov` + `crc` instructions. `R` is the latency of
+  // reading the memory. Fused instructions also reduce register pressure
+  // allowing surrounding code to be more efficient when this code is inlined.
+  if (len > 8) {
+    crcs = {ABSL_HASH_INTERNAL_CRC32_U64(crcs.first, Read8(first)),
+            ABSL_HASH_INTERNAL_CRC32_U64(crcs.second, Read8(first + len - 8))};
+    if (len > 16) {
+      // We compute the second round of dependent CRC32 operations.
+      crcs = {ABSL_HASH_INTERNAL_CRC32_U64(crcs.first, Read8(first + len - 16)),
+              ABSL_HASH_INTERNAL_CRC32_U64(crcs.second, Read8(first + 8))};
+    }
+  } else {
+    if (len >= 4) {
+      // We use CRC for 4 bytes to benefit from the fused instruction and better
+      // hash quality.
+      // Using `xor` or `add` may reduce latency for this case, but would
+      // require more registers, more instructions and will have worse hash
+      // quality.
+      crcs = {ABSL_HASH_INTERNAL_CRC32_U32(static_cast<uint32_t>(crcs.first),
+                                           Read4(first)),
+              ABSL_HASH_INTERNAL_CRC32_U32(static_cast<uint32_t>(crcs.second),
+                                           Read4(first + len - 4))};
+    } else if (len >= 1) {
+      // We mix three bytes all into different output registers.
+      // This way, we do not need shifting of these bytes (so they don't overlap
+      // with each other).
+      crcs = {ABSL_HASH_INTERNAL_CRC32_U8(static_cast<uint32_t>(crcs.first),
+                                          first[0]),
+              ABSL_HASH_INTERNAL_CRC32_U8(static_cast<uint32_t>(crcs.second),
+                                          first[len - 1])};
+      // Middle byte is mixed weaker. It is a new byte only for len == 3.
+      // Mixing is independent from CRC operations so it is scheduled ASAP.
+      mul += first[len / 2];
+    }
+  }
+  // `mul` is mixed into both sides of `Mix` to guarantee non-zero values for
+  // both multiplicands. Using Mix instead of just multiplication here improves
+  // hash quality, especially for short strings.
+  return Mix(mul - crcs.first, crcs.second - mul);
+}
+#else
+inline uint64_t CombineContiguousImpl(
+    uint64_t state, const unsigned char* first, size_t len,
+    std::integral_constant<int, 8> /* sizeof_size_t */) {
+  // For large values we use LowLevelHash or CityHash depending on the platform,
+  // for small ones we use custom low latency hash.
+  if (len <= 8) {
+    return CombineSmallContiguousImpl(PrecombineLengthMix(state, len), first,
+                                      len);
+  }
+  if (len <= 16) {
+    return CombineContiguousImpl9to16(PrecombineLengthMix(state, len), first,
+                                      len);
+  }
+  if (len <= 32) {
+    return CombineContiguousImpl17to32(PrecombineLengthMix(state, len), first,
+                                       len);
+  }
+  // We must not mix length into the state here because calling
+  // CombineContiguousImpl twice with PiecewiseChunkSize() must be equivalent
+  // to calling CombineLargeContiguousImpl once with 2 * PiecewiseChunkSize().
+  return CombineLargeContiguousImplOn64BitLengthGt32(state, first, len);
+}
+#endif  // ABSL_HASH_INTERNAL_HAS_CRC32
+
 #if defined(ABSL_INTERNAL_LEGACY_HASH_NAMESPACE) && \
     ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
 #define ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 1
@@ -966,8 +1229,6 @@
 #define ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 0
 #endif
 
-// HashSelect
-//
 // Type trait to select the appropriate hash implementation to use.
 // HashSelect::type<T> will give the proper hash implementation, to be invoked
 // as:
@@ -1064,26 +1325,7 @@
 struct is_hashable
     : std::integral_constant<bool, HashSelect::template Apply<T>::value> {};
 
-// MixingHashState
 class ABSL_DLL MixingHashState : public HashStateBase<MixingHashState> {
-  // absl::uint128 is not an alias or a thin wrapper around the intrinsic.
-  // We use the intrinsic when available to improve performance.
-#ifdef ABSL_HAVE_INTRINSIC_INT128
-  using uint128 = __uint128_t;
-#else   // ABSL_HAVE_INTRINSIC_INT128
-  using uint128 = absl::uint128;
-#endif  // ABSL_HAVE_INTRINSIC_INT128
-
-  // Random data taken from the hexadecimal digits of Pi's fractional component.
-  // https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number
-  ABSL_CACHELINE_ALIGNED static constexpr uint64_t kStaticRandomData[] = {
-      0x243f'6a88'85a3'08d3, 0x1319'8a2e'0370'7344, 0xa409'3822'299f'31d0,
-      0x082e'fa98'ec4e'6c89, 0x4528'21e6'38d0'1377,
-  };
-
-  static constexpr uint64_t kMul =
-   uint64_t{0xdcb22ca68cb134ed};
-
   template <typename T>
   using IntegralFastPath =
       conjunction<std::is_integral<T>, is_uniquely_represented<T>,
@@ -1094,8 +1336,6 @@
   MixingHashState(MixingHashState&&) = default;
   MixingHashState& operator=(MixingHashState&&) = default;
 
-  // MixingHashState::combine_contiguous()
-  //
   // Fundamental base case for hash recursion: mixes the given range of bytes
   // into the hash state.
   static MixingHashState combine_contiguous(MixingHashState hash_state,
@@ -1107,35 +1347,63 @@
   }
   using MixingHashState::HashStateBase::combine_contiguous;
 
-  // MixingHashState::hash()
-  //
+  template <typename T>
+  static size_t hash(const T& value) {
+    return hash_with_seed(value, Seed());
+  }
+
   // For performance reasons in non-opt mode, we specialize this for
   // integral types.
   // Otherwise we would be instantiating and calling dozens of functions for
   // something that is just one multiplication and a couple xor's.
   // The result should be the same as running the whole algorithm, but faster.
   template <typename T, absl::enable_if_t<IntegralFastPath<T>::value, int> = 0>
-  static size_t hash(T value) {
+  static size_t hash_with_seed(T value, size_t seed) {
     return static_cast<size_t>(
-        WeakMix(Seed(), static_cast<std::make_unsigned_t<T>>(value)));
+        CombineRawImpl(seed, static_cast<std::make_unsigned_t<T>>(value)));
   }
 
-  // Overload of MixingHashState::hash()
   template <typename T, absl::enable_if_t<!IntegralFastPath<T>::value, int> = 0>
-  static size_t hash(const T& value) {
-    return static_cast<size_t>(combine(MixingHashState{}, value).state_);
+  static size_t hash_with_seed(const T& value, size_t seed) {
+    return static_cast<size_t>(combine(MixingHashState{seed}, value).state_);
   }
 
  private:
-  // Invoked only once for a given argument; that plus the fact that this is
-  // move-only ensures that there is only one non-moved-from object.
-  MixingHashState() : state_(Seed()) {}
-
   friend class MixingHashState::HashStateBase;
   template <typename H>
   friend H absl::hash_internal::hash_weakly_mixed_integer(H,
                                                           WeaklyMixedInteger);
+  // Allow the HashState type-erasure implementation to invoke
+  // RunCombinedUnordered() directly.
+  friend class absl::HashState;
+  friend struct CombineRaw;
 
+  // For use in Seed().
+  static const void* const kSeed;
+
+  // Invoked only once for a given argument; that plus the fact that this is
+  // move-only ensures that there is only one non-moved-from object.
+  MixingHashState() : state_(Seed()) {}
+
+  // Workaround for MSVC bug.
+  // We make the type copyable to fix the calling convention, even though we
+  // never actually copy it. Keep it private to not affect the public API of the
+  // type.
+  MixingHashState(const MixingHashState&) = default;
+
+  explicit MixingHashState(uint64_t state) : state_(state) {}
+
+  // Combines a raw value from e.g. integrals/floats/pointers/etc. This allows
+  // us to be consistent with IntegralFastPath when combining raw types, but
+  // optimize Read1To3 and Read4To8 differently for the string case.
+  static MixingHashState combine_raw(MixingHashState hash_state,
+                                     uint64_t value) {
+    return MixingHashState(CombineRawImpl(hash_state.state_, value));
+  }
+
+  // Android local modification: disable unsigned integer overflow sanitizer
+  // here to support enabling it in the clients.
+  ABSL_ATTRIBUTE_NO_SANITIZE_UNSIGNED_OVERFLOW
   static MixingHashState combine_weakly_mixed_integer(
       MixingHashState hash_state, WeaklyMixedInteger value) {
     // Some transformation for the value is needed to make an empty
@@ -1164,195 +1432,6 @@
     return MixingHashState::combine(std::move(state), unordered_state);
   }
 
-  // Allow the HashState type-erasure implementation to invoke
-  // RunCombinedUnordered() directly.
-  friend class absl::HashState;
-  friend struct CombineRaw;
-
-  // Workaround for MSVC bug.
-  // We make the type copyable to fix the calling convention, even though we
-  // never actually copy it. Keep it private to not affect the public API of the
-  // type.
-  MixingHashState(const MixingHashState&) = default;
-
-  explicit MixingHashState(uint64_t state) : state_(state) {}
-
-  // Combines a raw value from e.g. integrals/floats/pointers/etc. This allows
-  // us to be consistent with IntegralFastPath when combining raw types, but
-  // optimize Read1To3 and Read4To8 differently for the string case.
-  static MixingHashState combine_raw(MixingHashState hash_state,
-                                     uint64_t value) {
-    return MixingHashState(WeakMix(hash_state.state_, value));
-  }
-
-  // Implementation of the base case for combine_contiguous where we actually
-  // mix the bytes into the state.
-  // Dispatch to different implementations of the combine_contiguous depending
-  // on the value of `sizeof(size_t)`.
-  static uint64_t CombineContiguousImpl(uint64_t state,
-                                        const unsigned char* first, size_t len,
-                                        std::integral_constant<int, 4>
-                                        /* sizeof_size_t */);
-  static uint64_t CombineContiguousImpl(uint64_t state,
-                                        const unsigned char* first, size_t len,
-                                        std::integral_constant<int, 8>
-                                        /* sizeof_size_t */);
-
-  ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t CombineSmallContiguousImpl(
-      uint64_t state, const unsigned char* first, size_t len) {
-    ABSL_ASSUME(len <= 8);
-    uint64_t v;
-    if (len >= 4) {
-      v = Read4To8(first, len);
-    } else if (len > 0) {
-      v = Read1To3(first, len);
-    } else {
-      // Empty ranges have no effect.
-      return state;
-    }
-    return WeakMix(state, v);
-  }
-
-  ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t CombineContiguousImpl9to16(
-      uint64_t state, const unsigned char* first, size_t len) {
-    ABSL_ASSUME(len >= 9);
-    ABSL_ASSUME(len <= 16);
-    // Note: any time one half of the mix function becomes zero it will fail to
-    // incorporate any bits from the other half. However, there is exactly 1 in
-    // 2^64 values for each side that achieve this, and only when the size is
-    // exactly 16 -- for smaller sizes there is an overlapping byte that makes
-    // this impossible unless the seed is *also* incredibly unlucky.
-    auto p = Read9To16(first, len);
-    return Mix(state ^ p.first, kMul ^ p.second);
-  }
-
-  ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t CombineContiguousImpl17to32(
-      uint64_t state, const unsigned char* first, size_t len) {
-    ABSL_ASSUME(len >= 17);
-    ABSL_ASSUME(len <= 32);
-    // Do two mixes of overlapping 16-byte ranges in parallel to minimize
-    // latency.
-    const uint64_t m0 =
-        Mix(Read8(first) ^ kStaticRandomData[1], Read8(first + 8) ^ state);
-
-    const unsigned char* tail_16b_ptr = first + (len - 16);
-    const uint64_t m1 = Mix(Read8(tail_16b_ptr) ^ kStaticRandomData[3],
-                            Read8(tail_16b_ptr + 8) ^ state);
-    return m0 ^ m1;
-  }
-
-  // Slow dispatch path for calls to CombineContiguousImpl with a size argument
-  // larger than PiecewiseChunkSize().  Has the same effect as calling
-  // CombineContiguousImpl() repeatedly with the chunk stride size.
-  static uint64_t CombineLargeContiguousImpl32(uint64_t state,
-                                               const unsigned char* first,
-                                               size_t len);
-  static uint64_t CombineLargeContiguousImpl64(uint64_t state,
-                                               const unsigned char* first,
-                                               size_t len);
-
-  // Reads 9 to 16 bytes from p.
-  // The least significant 8 bytes are in .first, and the rest of the bytes are
-  // in .second along with duplicated bytes from .first if len<16.
-  static std::pair<uint64_t, uint64_t> Read9To16(const unsigned char* p,
-                                                 size_t len) {
-    uint64_t low_mem = Read8(p);
-    uint64_t high_mem = Read8(p + len - 8);
-#ifdef ABSL_IS_LITTLE_ENDIAN
-    uint64_t most_significant = high_mem;
-    uint64_t least_significant = low_mem;
-#else
-    uint64_t most_significant = low_mem;
-    uint64_t least_significant = high_mem;
-#endif
-    return {least_significant, most_significant};
-  }
-
-  // Reads 8 bytes from p.
-  static uint64_t Read8(const unsigned char* p) {
-    // Suppress erroneous array bounds errors on GCC.
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Warray-bounds"
-#endif
-    return absl::base_internal::UnalignedLoad64(p);
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-  }
-
-  // Reads 4 to 8 bytes from p. Some input bytes may be duplicated in output.
-  static uint64_t Read4To8(const unsigned char* p, size_t len) {
-    // If `len < 8`, we duplicate bytes in the middle.
-    // E.g.:
-    // `ABCD` will be read as `ABCDABCD`.
-    // `ABCDE` will be read as `ABCDBCDE`.
-    // `ABCDEF` will be read as `ABCDCDEF`.
-    // `ABCDEFG` will be read as `ABCDDEFG`.
-    // We also do not care about endianness. On big-endian platforms, bytes will
-    // be shuffled (it's fine). We always shift low memory by 32, because that
-    // can be pipelined earlier. Reading high memory requires computing
-    // `p + len - 4`.
-    uint64_t most_significant =
-        static_cast<uint64_t>(absl::base_internal::UnalignedLoad32(p)) << 32;
-    uint64_t least_significant =
-        absl::base_internal::UnalignedLoad32(p + len - 4);
-    return most_significant | least_significant;
-  }
-
-  // Reads 1 to 3 bytes from p. Some input bytes may be duplicated in output.
-  static uint32_t Read1To3(const unsigned char* p, size_t len) {
-    // The trick used by this implementation is to avoid branches.
-    // We always read three bytes by duplicating.
-    // E.g.,
-    // `A` is read as `AAA`.
-    // `AB` is read as `ABB`.
-    // `ABC` is read as `ABC`.
-    // We always shift `p[0]` so that it can be pipelined better.
-    // Other bytes require extra computation to find indices.
-    uint32_t mem0 = (static_cast<uint32_t>(p[0]) << 16) | p[len - 1];
-    uint32_t mem1 = static_cast<uint32_t>(p[len / 2]) << 8;
-    return mem0 | mem1;
-  }
-
-  ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t Mix(uint64_t lhs, uint64_t rhs) {
-    // For 32 bit platforms we are trying to use all 64 lower bits.
-    if constexpr (sizeof(size_t) < 8) {
-      uint64_t m = lhs * rhs;
-      return m ^ (m >> 32);
-    }
-    // Though the 128-bit product on AArch64 needs two instructions, it is
-    // still a good balance between speed and hash quality.
-    uint128 m = lhs;
-    m *= rhs;
-    return Uint128High64(m) ^ Uint128Low64(m);
-  }
-
-  // Slightly lower latency than Mix, but with lower quality. The byte swap
-  // helps ensure that low bits still have high quality.
-  ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t WeakMix(uint64_t lhs,
-                                                       uint64_t rhs) {
-    const uint64_t n = lhs ^ rhs;
-    // WeakMix doesn't work well on 32-bit platforms so just use Mix.
-    if constexpr (sizeof(size_t) < 8) return Mix(n, kMul);
-    return absl::gbswap_64(n * kMul);
-  }
-
-  // An extern to avoid bloat on a direct call to LowLevelHash() with fixed
-  // values for both the seed and salt parameters.
-  static uint64_t LowLevelHashImpl(const unsigned char* data, size_t len);
-
-  ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t Hash64(const unsigned char* data,
-                                                      size_t len) {
-#ifdef ABSL_HAVE_INTRINSIC_INT128
-    return LowLevelHashImpl(data, len);
-#else
-    return hash_internal::CityHash64(reinterpret_cast<const char*>(data), len);
-#endif
-  }
-
-  // Seed()
-  //
   // A non-deterministic seed.
   //
   // The current purpose of this seed is to generate non-deterministic results
@@ -1367,64 +1446,18 @@
   //
   // On other platforms this is still going to be non-deterministic but most
   // probably per-build and not per-process.
-  ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t Seed() {
-#if (!defined(__clang__) || __clang_major__ > 11) && \
-    (!defined(__apple_build_version__) ||            \
-     __apple_build_version__ >= 19558921)  // Xcode 12
-    return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(&kSeed));
-#else
-    // Workaround the absence of
-    // https://github.com/llvm/llvm-project/commit/bc15bf66dcca76cc06fe71fca35b74dc4d521021.
-    return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(kSeed));
-#endif
+  ABSL_ATTRIBUTE_ALWAYS_INLINE static size_t Seed() {
+    // Android local modification: use an address of a function in libc instead
+    // of a local constant, so that the result is the same even if this code is
+    // linked multiple times in the same process. See b/436318577.
+    return static_cast<size_t>(reinterpret_cast<uintptr_t>(&strcmp));
   }
-  static const void* const kSeed;
 
   uint64_t state_;
 };
 
-// MixingHashState::CombineContiguousImpl()
-inline uint64_t MixingHashState::CombineContiguousImpl(
-    uint64_t state, const unsigned char* first, size_t len,
-    std::integral_constant<int, 4> /* sizeof_size_t */) {
-  // For large values we use CityHash, for small ones we just use a
-  // multiplicative hash.
-  if (len <= 8) {
-    return CombineSmallContiguousImpl(state, first, len);
-  }
-  if (ABSL_PREDICT_TRUE(len <= PiecewiseChunkSize())) {
-    return Mix(state ^ hash_internal::CityHash32(
-                           reinterpret_cast<const char*>(first), len),
-               kMul);
-  }
-  return CombineLargeContiguousImpl32(state, first, len);
-}
-
-// Overload of MixingHashState::CombineContiguousImpl()
-inline uint64_t MixingHashState::CombineContiguousImpl(
-    uint64_t state, const unsigned char* first, size_t len,
-    std::integral_constant<int, 8> /* sizeof_size_t */) {
-  // For large values we use LowLevelHash or CityHash depending on the platform,
-  // for small ones we just use a multiplicative hash.
-  if (len <= 8) {
-    return CombineSmallContiguousImpl(state, first, len);
-  }
-  if (len <= 16) {
-    return CombineContiguousImpl9to16(state, first, len);
-  }
-  if (len <= 32) {
-    return CombineContiguousImpl17to32(state, first, len);
-  }
-  if (ABSL_PREDICT_TRUE(len <= PiecewiseChunkSize())) {
-    return Mix(state ^ Hash64(first, len), kMul);
-  }
-  return CombineLargeContiguousImpl64(state, first, len);
-}
-
 struct AggregateBarrier {};
 
-// HashImpl
-
 // Add a private base class to make sure this type is not an aggregate.
 // Aggregates can be aggregate initialized even if the default constructor is
 // deleted.
@@ -1439,6 +1472,13 @@
   size_t operator()(const T& value) const {
     return MixingHashState::hash(value);
   }
+
+ private:
+  friend struct HashWithSeed;
+
+  size_t hash_with_seed(const T& value, size_t seed) const {
+    return MixingHashState::hash_with_seed(value, seed);
+  }
 };
 
 template <typename T>
@@ -1453,14 +1493,12 @@
                     values...);
 }
 
-// HashStateBase::combine_contiguous()
 template <typename H>
 template <typename T>
 H HashStateBase<H>::combine_contiguous(H state, const T* data, size_t size) {
   return hash_internal::hash_range_or_bytes(std::move(state), data, size);
 }
 
-// HashStateBase::combine_unordered()
 template <typename H>
 template <typename I>
 H HashStateBase<H>::combine_unordered(H state, I begin, I end) {
@@ -1468,7 +1506,6 @@
                                 CombineUnorderedCallback<I>{begin, end});
 }
 
-// HashStateBase::PiecewiseCombiner::add_buffer()
 template <typename H>
 H PiecewiseCombiner::add_buffer(H state, const unsigned char* data,
                                 size_t size) {
@@ -1478,7 +1515,7 @@
     position_ += size;
     return state;
   }
-
+  added_something_ = true;
   // If the buffer is partially filled we need to complete the buffer
   // and hash it.
   if (position_ != 0) {
@@ -1501,10 +1538,14 @@
   return state;
 }
 
-// HashStateBase::PiecewiseCombiner::finalize()
 template <typename H>
 H PiecewiseCombiner::finalize(H state) {
-  // Hash the remainder left in the buffer, which may be empty
+  // Do not call combine_contiguous with empty remainder since it is modifying
+  // state.
+  if (added_something_ && position_ == 0) {
+    return state;
+  }
+  // We still call combine_contiguous for the entirely empty buffer.
   return H::combine_contiguous(std::move(state), buf_, position_);
 }
 
@@ -1512,4 +1553,9 @@
 ABSL_NAMESPACE_END
 }  // namespace absl
 
+#undef ABSL_HASH_INTERNAL_HAS_CRC32
+#undef ABSL_HASH_INTERNAL_CRC32_U64
+#undef ABSL_HASH_INTERNAL_CRC32_U32
+#undef ABSL_HASH_INTERNAL_CRC32_U8
+
 #endif  // ABSL_HASH_INTERNAL_HASH_H_
diff --git a/absl/hash/internal/low_level_hash.cc b/absl/hash/internal/low_level_hash.cc
deleted file mode 100644
index 1a107ec..0000000
--- a/absl/hash/internal/low_level_hash.cc
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2020 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/hash/internal/low_level_hash.h"
-
-#include <cassert>
-#include <cstddef>
-#include <cstdint>
-
-#include "absl/base/config.h"
-#include "absl/base/internal/unaligned_access.h"
-#include "absl/base/optimization.h"
-#include "absl/base/prefetch.h"
-#include "absl/numeric/int128.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace hash_internal {
-namespace {
-uint64_t Mix(uint64_t v0, uint64_t v1) {
-  absl::uint128 p = v0;
-  p *= v1;
-  return absl::Uint128Low64(p) ^ absl::Uint128High64(p);
-}
-uint64_t Mix32Bytes(const uint8_t* ptr, uint64_t current_state,
-                    const uint64_t salt[5]) {
-  uint64_t a = absl::base_internal::UnalignedLoad64(ptr);
-  uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8);
-  uint64_t c = absl::base_internal::UnalignedLoad64(ptr + 16);
-  uint64_t d = absl::base_internal::UnalignedLoad64(ptr + 24);
-
-  uint64_t cs0 = Mix(a ^ salt[1], b ^ current_state);
-  uint64_t cs1 = Mix(c ^ salt[2], d ^ current_state);
-  return cs0 ^ cs1;
-}
-}  // namespace
-
-uint64_t LowLevelHashLenGt32(const void* data, size_t len, uint64_t seed,
-                             const uint64_t salt[5]) {
-  assert(len > 32);
-  const uint8_t* ptr = static_cast<const uint8_t*>(data);
-  uint64_t current_state = seed ^ salt[0] ^ len;
-  const uint8_t* last_32_ptr = ptr + len - 32;
-
-  if (len > 64) {
-    // If we have more than 64 bytes, we're going to handle chunks of 64
-    // bytes at a time. We're going to build up four separate hash states
-    // which we will then hash together. This avoids short dependency chains.
-    uint64_t duplicated_state0 = current_state;
-    uint64_t duplicated_state1 = current_state;
-    uint64_t duplicated_state2 = current_state;
-
-    do {
-      // Always prefetch the next cacheline.
-      PrefetchToLocalCache(ptr + ABSL_CACHELINE_SIZE);
-
-      uint64_t a = absl::base_internal::UnalignedLoad64(ptr);
-      uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8);
-      uint64_t c = absl::base_internal::UnalignedLoad64(ptr + 16);
-      uint64_t d = absl::base_internal::UnalignedLoad64(ptr + 24);
-      uint64_t e = absl::base_internal::UnalignedLoad64(ptr + 32);
-      uint64_t f = absl::base_internal::UnalignedLoad64(ptr + 40);
-      uint64_t g = absl::base_internal::UnalignedLoad64(ptr + 48);
-      uint64_t h = absl::base_internal::UnalignedLoad64(ptr + 56);
-
-      current_state = Mix(a ^ salt[1], b ^ current_state);
-      duplicated_state0 = Mix(c ^ salt[2], d ^ duplicated_state0);
-
-      duplicated_state1 = Mix(e ^ salt[3], f ^ duplicated_state1);
-      duplicated_state2 = Mix(g ^ salt[4], h ^ duplicated_state2);
-
-      ptr += 64;
-      len -= 64;
-    } while (len > 64);
-
-    current_state = (current_state ^ duplicated_state0) ^
-                    (duplicated_state1 + duplicated_state2);
-  }
-
-  // We now have a data `ptr` with at most 64 bytes and the current state
-  // of the hashing state machine stored in current_state.
-  if (len > 32) {
-    current_state = Mix32Bytes(ptr, current_state, salt);
-  }
-
-  // We now have a data `ptr` with at most 32 bytes and the current state
-  // of the hashing state machine stored in current_state. But we can
-  // safely read from `ptr + len - 32`.
-  return Mix32Bytes(last_32_ptr, current_state, salt);
-}
-
-}  // namespace hash_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
diff --git a/absl/hash/internal/low_level_hash.h b/absl/hash/internal/low_level_hash.h
deleted file mode 100644
index 49e9ec4..0000000
--- a/absl/hash/internal/low_level_hash.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2020 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.
-//
-// This file provides the Google-internal implementation of LowLevelHash.
-//
-// LowLevelHash is a fast hash function for hash tables, the fastest we've
-// currently (late 2020) found that passes the SMHasher tests. The algorithm
-// relies on intrinsic 128-bit multiplication for speed. This is not meant to be
-// secure - just fast.
-//
-// It is closely based on a version of wyhash, but does not maintain or
-// guarantee future compatibility with it.
-
-#ifndef ABSL_HASH_INTERNAL_LOW_LEVEL_HASH_H_
-#define ABSL_HASH_INTERNAL_LOW_LEVEL_HASH_H_
-
-#include <stdint.h>
-#include <stdlib.h>
-
-#include "absl/base/config.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace hash_internal {
-
-// Hash function for a byte array. A 64-bit seed and a set of five 64-bit
-// integers are hashed into the result. The length must be greater than 32.
-//
-// To allow all hashable types (including string_view and Span) to depend on
-// this algorithm, we keep the API low-level, with as few dependencies as
-// possible.
-uint64_t LowLevelHashLenGt32(const void* data, size_t len, uint64_t seed,
-                             const uint64_t salt[5]);
-
-}  // namespace hash_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#endif  // ABSL_HASH_INTERNAL_LOW_LEVEL_HASH_H_
diff --git a/absl/hash/internal/low_level_hash_test.cc b/absl/hash/internal/low_level_hash_test.cc
index d370dc7..d054337 100644
--- a/absl/hash/internal/low_level_hash_test.cc
+++ b/absl/hash/internal/low_level_hash_test.cc
@@ -12,29 +12,26 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "absl/hash/internal/low_level_hash.h"
-
-#include <cinttypes>
+#include <cstddef>
 #include <cstdint>
+#include <string>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/hash/hash.h"
 #include "absl/strings/escaping.h"
+#include "absl/strings/string_view.h"
 
 #define UPDATE_GOLDEN 0
 
 namespace {
 
-static const uint64_t kSalt[5] = {0xa0761d6478bd642f, 0xe7037ed1a0b428dbl,
-                                  0x8ebc6af09c88c6e3, 0x589965cc75374cc3l,
-                                  0x1d8e4e27c47d124f};
-
 TEST(LowLevelHashTest, VerifyGolden) {
-  constexpr size_t kNumGoldenOutputs = 94;
+  constexpr size_t kNumGoldenOutputs = 95;
   static struct {
     absl::string_view base64_data;
     uint64_t seed;
-  } cases[] = {
+  } cases[kNumGoldenOutputs] = {
       {"VprUGNH+5NnNRaORxgH/ySrZFQFDL+4VAodhfBNinmn8cg==",
        uint64_t{0x531858a40bfa7ea1}},
       {"gc1xZaY+q0nPcUvOOnWnT3bqfmT/geth/f7Dm2e/DemMfk4=",
@@ -361,54 +358,100 @@
        uint64_t{0xc9ae5c8759b4877a}},
   };
 
-#if defined(ABSL_IS_BIG_ENDIAN)
+#if defined(ABSL_IS_BIG_ENDIAN) || !defined(ABSL_HAVE_INTRINSIC_INT128) || \
+    UINTPTR_MAX != UINT64_MAX
   constexpr uint64_t kGolden[kNumGoldenOutputs] = {};
-  GTEST_SKIP() << "We only maintain golden data for little endian systems.";
+  // This conditional is to avoid an unreachable code warning.
+  bool skip = true;
+  if (skip) {
+    GTEST_SKIP()
+        << "We only maintain golden data for little endian 64 bit systems with "
+           "128 bit intristics.";
+  }
+#elif defined(__SSE4_2__) && defined(__AES__)
+  constexpr uint64_t kGolden[kNumGoldenOutputs] = {
+      0xd6bdb2c9ba5e55f2, 0xffd3e23d4115a8ae, 0x2c3218ef486127de,
+      0x554fa7f3a262b886, 0x06304cbf82e312d3, 0x490b3fb5af80622c,
+      0x7398a90b8cc59c5d, 0x65fb3168b98030ab, 0xd4564363c53617bb,
+      0x0545c26351925fe7, 0xc30700723b634bf4, 0xfb23a140a76dbe94,
+      0x2fa1467fe218a47c, 0x92e05ec3a7b966eb, 0x6112b56e5624dd50,
+      0x8760801365f9d722, 0x41f7187b61db0e5e, 0x7fe9188a1f5f50ad,
+      0x25800bd4c2002ef1, 0x91fecd33a78ef0aa, 0x93986ad71e983613,
+      0xe4c78173c7ea537b, 0x0bbdc2bcabdb50b1, 0xd9aa134df2d87623,
+      0x6c4907c9477a9409, 0xc3e418a5dbda52e5, 0x4d24f3e9d0dda93a,
+      0xcdb565a363dbe45f, 0xa95f228c8ee57478, 0x6b8f00bab5130227,
+      0x2d05a0f44818b67a, 0xd6bf7d990b5f44cb, 0xa3608bdb4712861a,
+      0xf20c33e5e355330b, 0xbc86e1b13130180d, 0x0848221b397b839a,
+      0x17cc0acf44a7e210, 0xc18c6dc584fe0f62, 0x896c7858a59f991d,
+      0xeab1e6d7d2856ed7, 0x7e4b2d99c23edc51, 0x9aeeeb7fa46e7cf0,
+      0x161b9f2e3611790f, 0x5f82aae18d971b36, 0x8d0dd9965881e162,
+      0x56700ea26285895a, 0xcd919c86c29a053e, 0x3e5d589282d9a722,
+      0x92caee9f48a66604, 0x7e1a2fd9b06f14b0, 0xce1d5293f95b0178,
+      0x8101361290e70a11, 0x570e3e9c9eafc1c6, 0x77b6241926a7a568,
+      0x313e5cb34f346699, 0xab8ebeab0514b82b, 0x6e0a43763a310408,
+      0x761b76ec22b2e440, 0x4238c84a9ec00528, 0xb9ea1f6d4d5552af,
+      0xd21f8f110b9dc060, 0xb3d3842b69ac3689, 0xd0a88aa1dcf59869,
+      0xf3f69f637b123403, 0xf5f34b1068cac7da, 0xe69a08d604774abf,
+      0x57648d3a73332437, 0x9762947f5013d00d, 0x35c5d734a0015922,
+      0xbee2fe5a104ce209, 0xedb060efa6efca34, 0x5ccf0f4786d97bc2,
+      0x1ef8ed72e80d7bef, 0x58522deb49c5e30f, 0xde97cd2a6f8bd13b,
+      0x3fae37c6f9855d09, 0xea99ae786feca261, 0x8c6d1d46670b0943,
+      0x84658b2a232c7bfb, 0x7058b7a7968de394, 0x0d44fba68e25aa8f,
+      0xc7f687020f8eb00b, 0xbf9671e1196153d6, 0x1009be891b7f83e7,
+      0x4f9457fb4aa12865, 0x30a49d9563643b32, 0x0302e2c5b46d5a3a,
+      0x77553f42fb0bfbf7, 0x26b95e89f0077110, 0x76ce68ebe01191ba,
+      0x724110fb509e4376, 0xebe74b016b5cfb88, 0x3b0fe11dcf175fc9,
+      0x20b737b9c0490538, 0x0db21c429b45fd17,
+  };
 #else
   constexpr uint64_t kGolden[kNumGoldenOutputs] = {
-      0x59b1542b0ff6b7b8, 0x3fb979d297096db9, 0xb391802c536343a9,
-      0x94e0f7e4331081c4, 0x234d95e49e3ce30e, 0xca6351a3e568ed17,
-      0xa62fcf7fa334293d, 0xb03111035f546067, 0x97b8c861e013d558,
-      0xb6683803d9387949, 0xce5d907e0b3cb6a1, 0xab7466fae53ed201,
-      0x8f13ca3f1cac3edd, 0xa2684a99cd909a2a, 0x03194f86b9440843,
-      0xab3a745d96f75a66, 0xef2448606760ec3d, 0xd999e03247d5d5c5,
-      0x4a25ab345d53f926, 0xa511b829ce9fc919, 0x4b76517f8e806cbf,
-      0x006efd7ee09ff8d4, 0x790a4978bd0170a1, 0xc14f6e4b2dff057e,
-      0xe0d2f4ae7c836d09, 0x4e2038a491ed939d, 0x23fd6f408e9598e0,
-      0xa91cf8f1d92bcb08, 0x555cdec06df49d58, 0xe7d3e14bd6a8f3bd,
-      0x4fdd25c1e75c009a, 0x3dffb8acf1ffbd17, 0x56946f33ed73a705,
-      0x154c633d7690f3b0, 0x3e96f8e9a58a04e0, 0xb0279b244d3ccf9c,
-      0x8571e87c882b2142, 0x9d9ada45132e7b41, 0xd5667655533f1dec,
-      0x70607ace4ec36463, 0x691418d2eb63116c, 0xa70179d8e7142980,
-      0xf8388d756bea25a7, 0xe5127c736d9826de, 0x7f1c95f9b6b656b6,
-      0x66ab835b7bf4c7b3, 0xc03423b9a6db9728, 0xe88415a2b416b76d,
-      0x8afd8c14d0b56c36, 0xe9a252b3ba217dad, 0x710150f5cd87a9ff,
-      0xd66b147837fad9ae, 0x1af5f8ffbaa717a7, 0xe01f88d7a9a8ac17,
-      0xd67870a7251fde72, 0xf32b837f845a676b, 0x0827717b1ffe59f7,
-      0x80307212ca7645fb, 0xf0d22af71ea57c80, 0x459373765f2c114b,
-      0x54d26109fab9cbaf, 0xc603da4e257b93db, 0x57fa334b5689d7d5,
-      0x41cd1b2a8a91f620, 0xe1d6e7cd0fb015af, 0x8608e9035eb9d795,
-      0x45c7b9fae739fee1, 0x9f5ae4f7a6b597ee, 0xfb771b6e0017757d,
-      0x8dac6d29cfd8d027, 0x3c9ba4fb62ce6508, 0xa971fad8243844a7,
-      0xd2126f49b2ea3b64, 0x5dd78fe7ac436861, 0xfe4004a6bb3494a8,
-      0xe7c01cc63d770d7c, 0xa117075b8c801d37, 0xdf1dfe75f0e73069,
-      0x7285b39700cefb98, 0x5e97ea1aa9a670eb, 0xe21872db2b9137a3,
-      0x12630b02c6ca405e, 0xfe1f2d802151f97a, 0xb53b0ed3dea4fb02,
-      0xc6d5ed56d1dbf9fd, 0xe5b92b558a5c70cb, 0xccd6eedf97277d08,
-      0x08582fff2e1494ed, 0xa41f2b3d17f1c4c7, 0x29ec07e5ef950f3d,
-      0x96aba32565a97084, 0xf26870eca10cebcd, 0xbe1432feb4d33361,
-      0x21993a779845e6eb,
+      0x669da02f8d009e0f, 0xceb19bf2255445cd, 0x0e746992d6d43a7c,
+      0x41ed623b9dcc5fde, 0x187a5a30d7c72edc, 0x949ae2a9c1eb925a,
+      0x7e9c76a7b7c35e68, 0x4f96bf15b8309ff6, 0x26c0c1fde233732e,
+      0xb0453f72aa151615, 0xf24b621a9ce9fece, 0x99ed798408687b5f,
+      0x3b13ec1221423b66, 0xc67cf148a28afe59, 0x22f7e0173f92e3fa,
+      0x14186c5fda6683a0, 0x97d608caa2603b2c, 0xfde3b0bbba24ffa9,
+      0xb7068eb48c472c77, 0x9e34d72866b9fda0, 0xbbb99c884cdef88e,
+      0x81d3e01f472a8a1a, 0xf84f506b3b60366d, 0xfe3f42f01300db37,
+      0xe385712a51c1f836, 0x41dfd5e394245c79, 0x60855dbedadb900a,
+      0xbdb4c0aa38567476, 0x9748802e8eec02cc, 0x5ced256d257f88de,
+      0x55acccdf9a80f155, 0xa64b55b071afbbea, 0xa205bfe6c724ce4d,
+      0x69dd26ca8ac21744, 0xef80e2ff2f6a9bc0, 0xde266c0baa202c20,
+      0xfa3463080ac74c50, 0x379d968a40125c2b, 0x4cbbd0a7b3c7d648,
+      0xc92afd93f4c665d2, 0x6e28f5adb7ae38dc, 0x7c689c9c237be35e,
+      0xaea41b29bd9d0f73, 0x832cef631d77e59f, 0x70cac8e87bc37dd3,
+      0x8e8c98bbde68e764, 0xd6117aeb3ddedded, 0xd796ab808e766240,
+      0x8953d0ea1a7d9814, 0xa212eba4281b391c, 0x21a555a8939ce597,
+      0x809d31660f6d81a8, 0x2356524b20ab400f, 0x5bc611e1e49d0478,
+      0xba9c065e2f385ce2, 0xb0a0fd12f4e83899, 0x14d076a35b1ff2ca,
+      0x8acd0bb8cf9a93c0, 0xe62e8ec094039ee4, 0x38a536a7072bdc61,
+      0xca256297602524f8, 0xfc62ebfb3530caeb, 0x8d8b0c05520569f6,
+      0xbbaca65cf154c59d, 0x3739b5ada7e338d3, 0xdb9ea31f47365340,
+      0x410b5c9c1da56755, 0x7e0abc03dbd10283, 0x136f87be70ed442e,
+      0x6b727d4feddbe1e9, 0x074ebb21183b01df, 0x3fe92185b1985484,
+      0xc5d8efd3c68305ca, 0xd9bada21b17e272e, 0x64d73133e1360f83,
+      0xeb8563aa993e21f9, 0xe5e8da50cceab28f, 0x7a6f92eb3223d2f3,
+      0xbdaf98370ea9b31b, 0x1682a84457f077bc, 0x4abd2d33b6e3be37,
+      0xb35bc81a7c9d4c04, 0x3e5bde3fb7cfe63d, 0xff3abe6e2ffec974,
+      0xb8116dd26cf6feec, 0x7a77a6e4ed0cf081, 0xb71eec2d5a184316,
+      0x6fa932f77b4da817, 0x795f79b33909b2c4, 0x1b8755ef6b5eb34e,
+      0x2255b72d7d6b2d79, 0xf2bdafafa90bd50a, 0x442a578f02cb1fc8,
+      0xc25aefe55ecf83db, 0x3114c056f9c5a676,
   };
 #endif
 
+  auto hash_fn = [](absl::string_view s, uint64_t state) {
+    return absl::hash_internal::CombineLargeContiguousImplOn64BitLengthGt32(
+        state, reinterpret_cast<const unsigned char*>(s.data()), s.size());
+  };
+
 #if UPDATE_GOLDEN
   (void)kGolden;  // Silence warning.
   for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
     std::string str;
     ASSERT_TRUE(absl::Base64Unescape(cases[i].base64_data, &str));
     ASSERT_GT(str.size(), 32);
-    uint64_t h = absl::hash_internal::LowLevelHashLenGt32(
-        str.data(), str.size(), cases[i].seed, kSalt);
+    uint64_t h = hash_fn(str, cases[i].seed);
     printf("0x%016" PRIx64 ", ", h);
     if (i % 3 == 2) {
       printf("\n");
@@ -423,9 +466,7 @@
     std::string str;
     ASSERT_TRUE(absl::Base64Unescape(cases[i].base64_data, &str));
     ASSERT_GT(str.size(), 32);
-    EXPECT_EQ(absl::hash_internal::LowLevelHashLenGt32(str.data(), str.size(),
-                                                       cases[i].seed, kSalt),
-              kGolden[i]);
+    EXPECT_EQ(hash_fn(str, cases[i].seed), kGolden[i]);
   }
 #endif
 }
diff --git a/absl/hash/internal/spy_hash_state.h b/absl/hash/internal/spy_hash_state.h
index e403113..823e1e9 100644
--- a/absl/hash/internal/spy_hash_state.h
+++ b/absl/hash/internal/spy_hash_state.h
@@ -151,6 +151,9 @@
   static SpyHashStateImpl combine_contiguous(SpyHashStateImpl hash_state,
                                              const unsigned char* begin,
                                              size_t size) {
+    if (size == 0) {
+      return SpyHashStateImpl::combine_raw(std::move(hash_state), 0);
+    }
     const size_t large_chunk_stride = PiecewiseChunkSize();
     // Combining a large contiguous buffer must have the same effect as
     // doing it piecewise by the stride length, followed by the (possibly
@@ -165,6 +168,7 @@
     if (size > 0) {
       hash_state.hash_representation_.emplace_back(
           reinterpret_cast<const char*>(begin), size);
+      hash_state = SpyHashStateImpl::combine_raw(std::move(hash_state), size);
     }
     return hash_state;
   }
@@ -224,8 +228,9 @@
 
   // Combines raw data from e.g. integrals/floats/pointers/etc.
   static SpyHashStateImpl combine_raw(SpyHashStateImpl state, uint64_t value) {
-    const unsigned char* data = reinterpret_cast<const unsigned char*>(&value);
-    return SpyHashStateImpl::combine_contiguous(std::move(state), data, 8);
+    state.hash_representation_.emplace_back(
+        reinterpret_cast<const char*>(&value), 8);
+    return state;
   }
 
   // This is true if SpyHashStateImpl<T> has been passed to a call of
diff --git a/absl/log/BUILD.bazel b/absl/log/BUILD.bazel
index 62ece45..5bc7150 100644
--- a/absl/log/BUILD.bazel
+++ b/absl/log/BUILD.bazel
@@ -14,6 +14,8 @@
 # limitations under the License.
 #
 
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
@@ -78,6 +80,8 @@
         ":log",
         "//absl/base:config",
         "//absl/base:core_headers",
+        "//absl/base:nullability",
+        "//absl/base:nullability_traits_internal",
         "//absl/strings",
     ],
 )
@@ -152,6 +156,7 @@
 
 cc_library(
     name = "log_entry",
+    srcs = ["log_entry.cc"],
     hdrs = ["log_entry.h"],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
@@ -160,6 +165,7 @@
         "//absl/base:core_headers",
         "//absl/base:log_severity",
         "//absl/log/internal:config",
+        "//absl/log/internal:proto",
         "//absl/strings",
         "//absl/time",
         "//absl/types:span",
diff --git a/absl/log/CMakeLists.txt b/absl/log/CMakeLists.txt
index 130897f..9d097ab 100644
--- a/absl/log/CMakeLists.txt
+++ b/absl/log/CMakeLists.txt
@@ -28,7 +28,6 @@
     absl::core_headers
     absl::log_internal_check_op
     absl::log_internal_conditions
-    absl::log_internal_message
     absl::log_internal_strip
 )
 
@@ -47,6 +46,7 @@
     absl::base
     absl::config
     absl::core_headers
+    absl::has_ostream_operator
     absl::leak_check
     absl::log_internal_nullguard
     absl::log_internal_nullstream
@@ -466,6 +466,8 @@
     absl::config
     absl::core_headers
     absl::log
+    absl::nullability
+    absl::nullability_traits_internal
     absl::strings
   PUBLIC
 )
@@ -560,6 +562,8 @@
 absl_cc_library(
   NAME
     log_entry
+  SRCS
+    "log_entry.cc"
   HDRS
     "log_entry.h"
   COPTS
@@ -570,6 +574,7 @@
     absl::config
     absl::core_headers
     absl::log_internal_config
+    absl::log_internal_proto
     absl::log_severity
     absl::span
     absl::strings
@@ -1199,3 +1204,36 @@
     absl::log_internal_fnmatch
     GTest::gmock_main
 )
+
+absl_cc_library(
+  NAME
+    log_internal_container
+  HDRS
+    "internal/container.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+    absl::config
+    absl::requires_internal
+    absl::strings
+)
+
+absl_cc_test(
+  NAME
+    internal_container_test
+  SRCS
+    "internal/container_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+    absl::config
+    absl::log_internal_container
+    absl::span
+    absl::strings
+    absl::str_format
+    GTest::gmock_main
+)
diff --git a/absl/log/check_test_impl.inc b/absl/log/check_test_impl.inc
index 7a0000e..47af1dd 100644
--- a/absl/log/check_test_impl.inc
+++ b/absl/log/check_test_impl.inc
@@ -13,6 +13,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+// SKIP_ABSL_INLINE_NAMESPACE_CHECK
+
 #ifndef ABSL_LOG_CHECK_TEST_IMPL_H_
 #define ABSL_LOG_CHECK_TEST_IMPL_H_
 
@@ -22,6 +24,8 @@
 #error ABSL_TEST_CHECK must be defined for these tests to work.
 #endif
 
+#include <cstdint>
+#include <limits>
 #include <ostream>
 #include <string>
 
@@ -40,6 +44,7 @@
 
 using ::testing::AllOf;
 using ::testing::AnyOf;
+using ::testing::ContainsRegex;
 using ::testing::HasSubstr;
 using ::testing::Not;
 
@@ -238,6 +243,72 @@
   ABSL_TEST_CHECK_LT(1, 2);
 }
 
+TEST(CHECKTest, TestBinaryChecksWithStringComparison) {
+  const std::string a = "a";
+  ABSL_TEST_CHECK_EQ(a, "a");
+  ABSL_TEST_CHECK_NE(a, "b");
+  ABSL_TEST_CHECK_GE(a, a);
+  ABSL_TEST_CHECK_GE("b", a);
+  ABSL_TEST_CHECK_LE(a, "a");
+  ABSL_TEST_CHECK_LE(a, "b");
+  ABSL_TEST_CHECK_GT("b", a);
+  ABSL_TEST_CHECK_LT(a, "b");
+}
+
+TEST(CHECKDeathTest, CheckWithCharStarAndStringPrintsTheCharStar) {
+  std::string str = "B";
+
+  // When the comparison happens as strings, then we print the CharT* as a
+  // string.
+  EXPECT_DEATH(ABSL_TEST_CHECK_EQ("A", str),
+               R"re(Check failed: \"A\" == str \(A vs. B\))re");
+}
+
+#if defined(GTEST_USES_SIMPLE_RE) && GTEST_USES_SIMPLE_RE
+#define POINTER_VALUE_RE R"re(\w*)re"
+#else
+#define POINTER_VALUE_RE R"re((0x)*[0-9a-fA-F]*)re"
+#endif
+
+#define POINTER_VS_POINTER_RE(lhs, rhs) "\\(" lhs " vs. " rhs "\\)"
+
+template <typename CharT>
+void TestCharStarComparison() {
+  // When the comparison happens as pointers, we only print the pointer and not
+  // interpret it as a C-String because it might not be.
+  // Leave the CharTs uninitialized to trigger ASan/MSan failures if we actually
+  // read the pointers.
+  CharT* p1 = new CharT;
+  CharT* p2 = new CharT;
+  EXPECT_DEATH(ABSL_TEST_CHECK_EQ(p1, p2),
+               R"re(Check failed: p1 == p2 )re" POINTER_VS_POINTER_RE(
+                   POINTER_VALUE_RE, POINTER_VALUE_RE));
+  CharT as_array[10];
+  EXPECT_DEATH(ABSL_TEST_CHECK_EQ(p1, as_array),
+               R"re(Check failed: p1 == as_array )re" POINTER_VS_POINTER_RE(
+                   POINTER_VALUE_RE, POINTER_VALUE_RE));
+
+  const void* as_void = as_array;
+  EXPECT_DEATH(ABSL_TEST_CHECK_EQ(as_void, p2),
+               R"re(Check failed: as_void == p2 )re" POINTER_VS_POINTER_RE(
+                   POINTER_VALUE_RE, POINTER_VALUE_RE));
+
+  delete p1;
+  delete p2;
+}
+
+TEST(CHECKDeathTest, CheckWithCharStarStringification) {
+  TestCharStarComparison<char>();
+  TestCharStarComparison<signed char>();
+  TestCharStarComparison<unsigned char>();
+  TestCharStarComparison<wchar_t>();
+#if defined(__cpp_char8_t)
+  TestCharStarComparison<char8_t>();
+#endif
+  TestCharStarComparison<char16_t>();
+  TestCharStarComparison<char32_t>();
+}
+
 // For testing using CHECK*() on anonymous enums.
 enum { CASE_A, CASE_B };
 
@@ -262,6 +333,25 @@
   ABSL_TEST_CHECK_NE(nullptr, p_not_null);
 }
 
+struct ExampleTypeThatHasNoStreamOperator {
+  bool x;
+
+  bool operator==(const ExampleTypeThatHasNoStreamOperator& other) const {
+    return x == other.x;
+  }
+  bool operator==(const bool& other) const { return x == other; }
+};
+
+TEST(CHECKDeathTest, TestBinaryChecksWithUnprintable) {
+  ExampleTypeThatHasNoStreamOperator a{true};
+  ExampleTypeThatHasNoStreamOperator b{false};
+  ABSL_TEST_CHECK_EQ(a, a);
+  EXPECT_DEATH(ABSL_TEST_CHECK_EQ(a, b), "Check failed: a == b");
+  ABSL_TEST_CHECK_EQ(a, true);
+  EXPECT_DEATH(ABSL_TEST_CHECK_EQ(a, false),
+               "Check failed: a == false \\(UNPRINTABLE vs. 0\\)");
+}
+
 #if GTEST_HAS_DEATH_TEST
 
 // Test logging of various char-typed values by failing CHECK*().
@@ -303,9 +393,11 @@
 
   a = "xx";
   EXPECT_DEATH(ABSL_TEST_CHECK_EQ(a, b),
-               "Check failed: a == b \\(xx vs. \\(null\\)\\)");
+               R"re(Check failed: a == b )re" POINTER_VS_POINTER_RE(
+                   POINTER_VALUE_RE, "\\(null\\)"));
   EXPECT_DEATH(ABSL_TEST_CHECK_EQ(b, a),
-               "Check failed: b == a \\(\\(null\\) vs. xx\\)");
+               R"re(Check failed: b == a )re" POINTER_VS_POINTER_RE(
+                   "\\(null\\)", POINTER_VALUE_RE));
 
   std::nullptr_t n{};
   EXPECT_DEATH(ABSL_TEST_CHECK_NE(n, nullptr),
@@ -638,9 +730,8 @@
   EXPECT_DEATH(
       ABSL_TEST_CHECK_EQ(p, nullptr),
       AnyOf(
-        HasSubstr("Check failed: p == nullptr (0000000000001234 vs. (null))"),
-        HasSubstr("Check failed: p == nullptr (0x1234 vs. (null))")
-      ));
+          HasSubstr("Check failed: p == nullptr (0000000000001234 vs. (null))"),
+          HasSubstr("Check failed: p == nullptr (0x1234 vs. (null))")));
 }
 
 // An uncopyable object with operator<<.
@@ -670,6 +761,273 @@
       HasSubstr("Check failed: v1 == v2 (Uncopyable{1} vs. Uncopyable{2})"));
 }
 
+enum class ScopedEnum { kValue1 = 1, kValue2 = 2 };
+
+TEST(CHECKTest, TestScopedEnumComparisonChecks) {
+  ABSL_TEST_CHECK_EQ(ScopedEnum::kValue1, ScopedEnum::kValue1);
+  ABSL_TEST_CHECK_NE(ScopedEnum::kValue1, ScopedEnum::kValue2);
+  ABSL_TEST_CHECK_LT(ScopedEnum::kValue1, ScopedEnum::kValue2);
+  ABSL_TEST_CHECK_LE(ScopedEnum::kValue1, ScopedEnum::kValue2);
+  ABSL_TEST_CHECK_GT(ScopedEnum::kValue2, ScopedEnum::kValue1);
+  ABSL_TEST_CHECK_GE(ScopedEnum::kValue2, ScopedEnum::kValue2);
+  ABSL_TEST_DCHECK_EQ(ScopedEnum::kValue1, ScopedEnum::kValue1);
+  ABSL_TEST_DCHECK_NE(ScopedEnum::kValue1, ScopedEnum::kValue2);
+  ABSL_TEST_DCHECK_LT(ScopedEnum::kValue1, ScopedEnum::kValue2);
+  ABSL_TEST_DCHECK_LE(ScopedEnum::kValue1, ScopedEnum::kValue2);
+  ABSL_TEST_DCHECK_GT(ScopedEnum::kValue2, ScopedEnum::kValue1);
+  ABSL_TEST_DCHECK_GE(ScopedEnum::kValue2, ScopedEnum::kValue2);
+
+  // Check that overloads work correctly with references as well.
+  const ScopedEnum x = ScopedEnum::kValue1;
+  const ScopedEnum& x_ref = x;
+  ABSL_TEST_CHECK_EQ(x, x_ref);
+  ABSL_TEST_CHECK_EQ(x_ref, x_ref);
+}
+
+#if GTEST_HAS_DEATH_TEST
+TEST(CHECKDeathTest, TestScopedEnumCheckFailureMessagePrintsIntegerValues) {
+  const auto e1 = ScopedEnum::kValue1;
+  const auto e2 = ScopedEnum::kValue2;
+  EXPECT_DEATH(ABSL_TEST_CHECK_EQ(e1, e2),
+               ContainsRegex(R"re(Check failed:.*\(1 vs. 2\))re"));
+  EXPECT_DEATH(ABSL_TEST_CHECK_NE(e1, e1),
+               ContainsRegex(R"re(Check failed:.*\(1 vs. 1\))re"));
+  EXPECT_DEATH(ABSL_TEST_CHECK_GT(e1, e1),
+               ContainsRegex(R"re(Check failed:.*\(1 vs. 1\))re"));
+  EXPECT_DEATH(ABSL_TEST_CHECK_GE(e1, e2),
+               ContainsRegex(R"re(Check failed:.*\(1 vs. 2\))re"));
+  EXPECT_DEATH(ABSL_TEST_CHECK_LT(e2, e2),
+               ContainsRegex(R"re(Check failed:.*\(2 vs. 2\))re"));
+  EXPECT_DEATH(ABSL_TEST_CHECK_LE(e2, e1),
+               ContainsRegex(R"re(Check failed:.*\(2 vs. 1\))re"));
+
+  const auto& e1_ref = e1;
+  EXPECT_DEATH(ABSL_TEST_CHECK_NE(e1_ref, e1),
+               ContainsRegex(R"re(Check failed:.*\(1 vs. 1\))re"));
+  EXPECT_DEATH(ABSL_TEST_CHECK_NE(e1_ref, e1_ref),
+               ContainsRegex(R"re(Check failed:.*\(1 vs. 1\))re"));
+  EXPECT_DEATH(ABSL_TEST_CHECK_EQ(e2, e1_ref),
+               ContainsRegex(R"re(Check failed:.*\(2 vs. 1\))re"));
+
+#ifndef NDEBUG
+  EXPECT_DEATH(ABSL_TEST_DCHECK_EQ(e2, e1),
+               ContainsRegex(R"re(Check failed:.*\(2 vs. 1\))re"));
+#else
+  // DHECK_EQ is not evaluated in non-debug mode.
+  ABSL_TEST_DCHECK_EQ(e2, e1);
+#endif  // NDEBUG
+}
+#endif  // GTEST_HAS_DEATH_TEST
+
+enum class ScopedInt8Enum : int8_t {
+  kValue1 = 1,
+  kValue2 = 66  // Printable ascii value 'B'.
+};
+
+TEST(CHECKDeathTest, TestScopedInt8EnumCheckFailureMessagePrintsCharValues) {
+  const auto e1 = ScopedInt8Enum::kValue1;
+  const auto e2 = ScopedInt8Enum::kValue2;
+  EXPECT_DEATH(
+      ABSL_TEST_CHECK_EQ(e1, e2),
+      ContainsRegex(R"re(Check failed:.*\(signed char value 1 vs. 'B'\))re"));
+  EXPECT_DEATH(
+      ABSL_TEST_CHECK_NE(e1, e1),
+      ContainsRegex(
+          R"re(Check failed:.*\(signed char value 1 vs. signed char value 1\))re"));
+  EXPECT_DEATH(
+      ABSL_TEST_CHECK_GT(e1, e1),
+      ContainsRegex(
+          R"re(Check failed:.*\(signed char value 1 vs. signed char value 1\))re"));
+  EXPECT_DEATH(
+      ABSL_TEST_CHECK_GE(e1, e2),
+      ContainsRegex(R"re(Check failed:.*\(signed char value 1 vs. 'B'\))re"));
+  EXPECT_DEATH(ABSL_TEST_CHECK_LT(e2, e2),
+               ContainsRegex(R"re(Check failed:.*\('B' vs. 'B'\))re"));
+  EXPECT_DEATH(
+      ABSL_TEST_CHECK_LE(e2, e1),
+      ContainsRegex(R"re(Check failed:.*\('B' vs. signed char value 1\))re"));
+}
+
+enum class ScopedUnsignedEnum : uint16_t {
+  kValue1 = std::numeric_limits<uint16_t>::min(),
+  kValue2 = std::numeric_limits<uint16_t>::max()
+};
+
+TEST(CHECKDeathTest,
+     TestScopedUnsignedEnumCheckFailureMessagePrintsCorrectValues) {
+  const auto e1 = ScopedUnsignedEnum::kValue1;
+  const auto e2 = ScopedUnsignedEnum::kValue2;
+  EXPECT_DEATH(ABSL_TEST_CHECK_EQ(e1, e2),
+               ContainsRegex(R"re(Check failed:.*\(0 vs. 65535\))re"));
+  EXPECT_DEATH(ABSL_TEST_CHECK_NE(e1, e1),
+               ContainsRegex(R"re(Check failed:.*\(0 vs. 0\))re"));
+  EXPECT_DEATH(ABSL_TEST_CHECK_GT(e1, e1),
+               ContainsRegex(R"re(Check failed:.*\(0 vs. 0\))re"));
+  EXPECT_DEATH(ABSL_TEST_CHECK_GE(e1, e2),
+               ContainsRegex(R"re(Check failed:.*\(0 vs. 65535\))re"));
+  EXPECT_DEATH(ABSL_TEST_CHECK_LT(e1, e1),
+               ContainsRegex(R"re(Check failed:.*\(0 vs. 0\))re"));
+  EXPECT_DEATH(ABSL_TEST_CHECK_LE(e2, e1),
+               ContainsRegex(R"re(Check failed:.*\(65535 vs. 0\))re"));
+}
+
+enum class ScopedInt64Enum : int64_t {
+  kMin = std::numeric_limits<int64_t>::min(),
+  kMax = std::numeric_limits<int64_t>::max(),
+};
+
+// Tests that int64-backed enums are printed correctly even for very large and
+// very small values.
+TEST(CHECKDeathTest, TestScopedInt64EnumCheckFailureMessage) {
+  const auto min = ScopedInt64Enum::kMin;
+  const auto max = ScopedInt64Enum::kMax;
+  EXPECT_DEATH(
+      ABSL_TEST_CHECK_EQ(max, min),
+      ContainsRegex(
+          "Check failed:.*9223372036854775807 vs. -9223372036854775808"));
+  EXPECT_DEATH(
+      ABSL_TEST_CHECK_NE(max, max),
+      ContainsRegex(
+          "Check failed:.*9223372036854775807 vs. 9223372036854775807"));
+  EXPECT_DEATH(
+      ABSL_TEST_CHECK_GT(min, min),
+      ContainsRegex(
+          "Check failed:.*-9223372036854775808 vs. -9223372036854775808"));
+  EXPECT_DEATH(
+      ABSL_TEST_CHECK_GE(min, max),
+      ContainsRegex(
+          R"(Check failed:.*-9223372036854775808 vs. 9223372036854775807)"));
+  EXPECT_DEATH(
+      ABSL_TEST_CHECK_LT(max, max),
+      ContainsRegex(
+          R"(Check failed:.*9223372036854775807 vs. 9223372036854775807)"));
+  EXPECT_DEATH(
+      ABSL_TEST_CHECK_LE(max, min),
+      ContainsRegex(
+          R"(Check failed:.*9223372036854775807 vs. -9223372036854775808)"));
+}
+
+enum class ScopedBoolEnum : bool {
+  kFalse,
+  kTrue,
+};
+
+TEST(CHECKDeathTest, TestScopedBoolEnumCheckFailureMessagePrintsCorrectValues) {
+  const auto t = ScopedBoolEnum::kTrue;
+  const auto f = ScopedBoolEnum::kFalse;
+  EXPECT_DEATH(ABSL_TEST_CHECK_EQ(t, f),
+               ContainsRegex(R"re(Check failed:.*\(1 vs. 0\))re"));
+  EXPECT_DEATH(ABSL_TEST_CHECK_NE(f, f),
+               ContainsRegex(R"re(Check failed:.*\(0 vs. 0\))re"));
+  EXPECT_DEATH(ABSL_TEST_CHECK_GT(f, f),
+               ContainsRegex(R"re(Check failed:.*\(0 vs. 0\))re"));
+  EXPECT_DEATH(ABSL_TEST_CHECK_GE(f, t),
+               ContainsRegex(R"re(Check failed:.*\(0 vs. 1\))re"));
+  EXPECT_DEATH(ABSL_TEST_CHECK_LT(t, t),
+               ContainsRegex(R"re(Check failed:.*\(1 vs. 1\))re"));
+  EXPECT_DEATH(ABSL_TEST_CHECK_LE(t, f),
+               ContainsRegex(R"re(Check failed:.*\(1 vs. 0\))re"));
+}
+
+enum class ScopedEnumWithAbslStringify {
+  kValue1 = 1,
+  kValue2 = 2,
+  kValue3 = 3
+};
+
+template <typename Sink>
+void AbslStringify(Sink& sink, ScopedEnumWithAbslStringify v) {
+  switch (v) {
+    case ScopedEnumWithAbslStringify::kValue1:
+      sink.Append("AbslStringify: kValue1");
+      break;
+    case ScopedEnumWithAbslStringify::kValue2:
+      sink.Append("AbslStringify: kValue2");
+      break;
+    case ScopedEnumWithAbslStringify::kValue3:
+      sink.Append("AbslStringify: kValue3");
+      break;
+  }
+}
+
+#if GTEST_HAS_DEATH_TEST
+TEST(CHECKDeathTest, TestScopedEnumUsesAbslStringify) {
+  EXPECT_DEATH(ABSL_TEST_CHECK_EQ(ScopedEnumWithAbslStringify::kValue1,
+                                  ScopedEnumWithAbslStringify::kValue2),
+               ContainsRegex("Check failed:.*AbslStringify: kValue1 vs. "
+                             "AbslStringify: kValue2"));
+}
+#endif  // GTEST_HAS_DEATH_TEST
+
+enum class ScopedEnumWithOutputOperator {
+  kValue1 = 1,
+  kValue2 = 2,
+};
+
+std::ostream& operator<<(std::ostream& os, ScopedEnumWithOutputOperator v) {
+  switch (v) {
+    case ScopedEnumWithOutputOperator::kValue1:
+      os << "OutputOperator: kValue1";
+      break;
+    case ScopedEnumWithOutputOperator::kValue2:
+      os << "OutputOperator: kValue2";
+      break;
+  }
+  return os;
+}
+
+#if GTEST_HAS_DEATH_TEST
+TEST(CHECKDeathTest, TestOutputOperatorIsUsedForScopedEnum) {
+  EXPECT_DEATH(ABSL_TEST_CHECK_EQ(ScopedEnumWithOutputOperator::kValue1,
+                                  ScopedEnumWithOutputOperator::kValue2),
+               ContainsRegex("Check failed:.*OutputOperator: kValue1 vs. "
+                             "OutputOperator: kValue2"));
+}
+#endif  // GTEST_HAS_DEATH_TEST
+
+enum class ScopedEnumWithAbslStringifyAndOutputOperator {
+  kValue1 = 1,
+  kValue2 = 2,
+};
+
+template <typename Sink>
+void AbslStringify(Sink& sink, ScopedEnumWithAbslStringifyAndOutputOperator v) {
+  switch (v) {
+    case ScopedEnumWithAbslStringifyAndOutputOperator::kValue1:
+      sink.Append("AbslStringify: kValue1");
+      break;
+    case ScopedEnumWithAbslStringifyAndOutputOperator::kValue2:
+      sink.Append("AbslStringify: kValue2");
+      break;
+  }
+}
+
+std::ostream& operator<<(std::ostream& os,
+                         ScopedEnumWithAbslStringifyAndOutputOperator v) {
+  switch (v) {
+    case ScopedEnumWithAbslStringifyAndOutputOperator::kValue1:
+      os << "OutputOperator: kValue1";
+      break;
+    case ScopedEnumWithAbslStringifyAndOutputOperator::kValue2:
+      os << "OutputOperator: kValue2";
+      break;
+  }
+  return os;
+}
+
+#if GTEST_HAS_DEATH_TEST
+
+// Test that, if operator<< and AbslStringify are both defined for a scoped
+// enum, streaming takes precedence over AbslStringify.
+TEST(CHECKDeathTest, TestScopedEnumPrefersOutputOperatorOverAbslStringify) {
+  EXPECT_DEATH(
+      ABSL_TEST_CHECK_EQ(ScopedEnumWithAbslStringifyAndOutputOperator::kValue1,
+                         ScopedEnumWithAbslStringifyAndOutputOperator::kValue2),
+      ContainsRegex("Check failed:.*OutputOperator: kValue1 vs. "
+                    "OutputOperator: kValue2"));
+}
+#endif  // GTEST_HAS_DEATH_TEST
+
 }  // namespace absl_log_internal
 
 // NOLINTEND(misc-definitions-in-headers)
diff --git a/absl/log/die_if_null.cc b/absl/log/die_if_null.cc
index 19c6a28..0d0b78e 100644
--- a/absl/log/die_if_null.cc
+++ b/absl/log/die_if_null.cc
@@ -15,6 +15,7 @@
 #include "absl/log/die_if_null.h"
 
 #include "absl/base/config.h"
+#include "absl/base/nullability.h"
 #include "absl/log/log.h"
 #include "absl/strings/str_cat.h"
 
@@ -22,7 +23,8 @@
 ABSL_NAMESPACE_BEGIN
 namespace log_internal {
 
-void DieBecauseNull(const char* file, int line, const char* exprtext) {
+void DieBecauseNull(const char* absl_nonnull file, int line,
+                    const char* absl_nonnull exprtext) {
   LOG(FATAL).AtLocation(file, line)
       << absl::StrCat("Check failed: '", exprtext, "' Must be non-null");
 }
diff --git a/absl/log/die_if_null.h b/absl/log/die_if_null.h
index 8597976..ac7dbe6 100644
--- a/absl/log/die_if_null.h
+++ b/absl/log/die_if_null.h
@@ -23,10 +23,13 @@
 
 #include <stdint.h>
 
+#include <type_traits>
 #include <utility>
 
 #include "absl/base/attributes.h"
 #include "absl/base/config.h"
+#include "absl/base/internal/nullability_traits.h"
+#include "absl/base/nullability.h"
 #include "absl/base/optimization.h"
 
 // ABSL_DIE_IF_NULL()
@@ -56,12 +59,30 @@
 // generates less code than its implementation would if inlined, for a slight
 // code size reduction each time `ABSL_DIE_IF_NULL` is called.
 [[noreturn]] ABSL_ATTRIBUTE_NOINLINE void DieBecauseNull(
-    const char* file, int line, const char* exprtext);
+    const char* absl_nonnull file, int line, const char* absl_nonnull exprtext);
 
 // Helper for `ABSL_DIE_IF_NULL`.
+
+// Since we use `remove_reference_t` before `AddNonnullIfCompatible`, we need
+// to explicitly have overloads for both lvalue reference and rvalue reference
+// arguments and returns.
 template <typename T>
-[[nodiscard]] T DieIfNull(const char* file, int line, const char* exprtext,
-                          T&& t) {
+[[nodiscard]] typename absl::base_internal::AddNonnullIfCompatible<
+    std::remove_reference_t<T>>::type&
+DieIfNull(const char* absl_nonnull file, int line,
+          const char* absl_nonnull exprtext, T& t) {
+  if (ABSL_PREDICT_FALSE(t == nullptr)) {
+    // Call a non-inline helper function for a small code size improvement.
+    DieBecauseNull(file, line, exprtext);
+  }
+  return t;
+}
+
+template <typename T>
+[[nodiscard]] typename absl::base_internal::AddNonnullIfCompatible<
+    std::remove_reference_t<T>>::type&&
+DieIfNull(const char* absl_nonnull file, int line,
+          const char* absl_nonnull exprtext, T&& t) {
   if (ABSL_PREDICT_FALSE(t == nullptr)) {
     // Call a non-inline helper function for a small code size improvement.
     DieBecauseNull(file, line, exprtext);
diff --git a/absl/log/flags_test.cc b/absl/log/flags_test.cc
index 1080ea1..f5a2b51 100644
--- a/absl/log/flags_test.cc
+++ b/absl/log/flags_test.cc
@@ -93,6 +93,7 @@
 TEST_F(LogFlagsTest, EmptyBacktraceAtFlag) {
   absl::SetMinLogLevel(absl::LogSeverityAtLeast::kInfo);
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(test_sink, Send(TextMessage(Not(HasSubstr("(stacktrace:")))));
 
@@ -104,6 +105,7 @@
 TEST_F(LogFlagsTest, BacktraceAtNonsense) {
   absl::SetMinLogLevel(absl::LogSeverityAtLeast::kInfo);
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(test_sink, Send(TextMessage(Not(HasSubstr("(stacktrace:")))));
 
@@ -117,6 +119,7 @@
   const int log_line = __LINE__ + 1;
   auto do_log = [] { LOG(INFO) << "hello world"; };
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(test_sink, Send(TextMessage(Not(HasSubstr("(stacktrace:")))));
 
@@ -131,6 +134,7 @@
   const int log_line = __LINE__ + 1;
   auto do_log = [] { LOG(INFO) << "hello world"; };
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(test_sink, Send(TextMessage(Not(HasSubstr("(stacktrace:")))));
 
@@ -145,6 +149,7 @@
   const int log_line = __LINE__ + 1;
   auto do_log = [] { LOG(INFO) << "hello world"; };
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(test_sink, Send(TextMessage(Not(HasSubstr("(stacktrace:")))));
 
@@ -158,6 +163,7 @@
   const int log_line = __LINE__ + 1;
   auto do_log = [] { LOG(INFO) << "hello world"; };
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(test_sink, Send(TextMessage(Not(HasSubstr("(stacktrace:")))));
 
@@ -172,6 +178,7 @@
   const int log_line = __LINE__ + 1;
   auto do_log = [] { LOG(INFO) << "hello world"; };
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   testing::InSequence seq;
   EXPECT_CALL(test_sink, Send(TextMessage(HasSubstr("(stacktrace:"))));
diff --git a/absl/log/internal/BUILD.bazel b/absl/log/internal/BUILD.bazel
index 953b690..32ae277 100644
--- a/absl/log/internal/BUILD.bazel
+++ b/absl/log/internal/BUILD.bazel
@@ -14,6 +14,9 @@
 # limitations under the License.
 #
 
+load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
@@ -56,7 +59,6 @@
     deps = [
         ":check_op",
         ":conditions",
-        ":log_message",
         ":strip",
         "//absl/base:core_headers",
     ],
@@ -79,6 +81,7 @@
         "//absl/base:nullability",
         "//absl/debugging:leak_check",
         "//absl/strings",
+        "//absl/strings:has_ostream_operator",
     ],
 )
 
@@ -545,3 +548,34 @@
         "@google_benchmark//:benchmark_main",
     ],
 )
+
+cc_library(
+    name = "container",
+    hdrs = ["container.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
+    deps = [
+        "//absl/base:config",
+        "//absl/meta:requires",
+        "//absl/strings",
+    ],
+)
+
+cc_test(
+    name = "container_test",
+    srcs = ["container_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":container",
+        "//absl/base:config",
+        "//absl/strings",
+        "//absl/strings:str_format",
+        "//absl/types:span",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
diff --git a/absl/log/internal/check_impl.h b/absl/log/internal/check_impl.h
index 00f25f8..dc2e214 100644
--- a/absl/log/internal/check_impl.h
+++ b/absl/log/internal/check_impl.h
@@ -12,13 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+// SKIP_ABSL_INLINE_NAMESPACE_CHECK
+
 #ifndef ABSL_LOG_INTERNAL_CHECK_IMPL_H_
 #define ABSL_LOG_INTERNAL_CHECK_IMPL_H_
 
 #include "absl/base/optimization.h"
 #include "absl/log/internal/check_op.h"
 #include "absl/log/internal/conditions.h"
-#include "absl/log/internal/log_message.h"
 #include "absl/log/internal/strip.h"
 
 // CHECK
diff --git a/absl/log/internal/check_op.cc b/absl/log/internal/check_op.cc
index 23db63b..be8ceaf 100644
--- a/absl/log/internal/check_op.cc
+++ b/absl/log/internal/check_op.cc
@@ -101,6 +101,10 @@
   }
 }
 
+std::ostream& operator<<(std::ostream& os, UnprintableWrapper) {
+  return os << "UNPRINTABLE";
+}
+
 // Helper functions for string comparisons.
 #define DEFINE_CHECK_STROP_IMPL(name, func, expected)                          \
   const char* absl_nullable Check##func##expected##Impl(                       \
diff --git a/absl/log/internal/check_op.h b/absl/log/internal/check_op.h
index 7253402..9bf908e 100644
--- a/absl/log/internal/check_op.h
+++ b/absl/log/internal/check_op.h
@@ -40,15 +40,16 @@
 #include "absl/log/internal/nullstream.h"
 #include "absl/log/internal/strip.h"
 #include "absl/strings/has_absl_stringify.h"
+#include "absl/strings/has_ostream_operator.h"
 #include "absl/strings/string_view.h"
 
 // `ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL` wraps string literals that
 // should be stripped when `ABSL_MIN_LOG_LEVEL` exceeds `kFatal`.
 #ifdef ABSL_MIN_LOG_LEVEL
-#define ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(literal)         \
-  (::absl::LogSeverity::kFatal >=                               \
-           static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) \
-       ? (literal)                                              \
+#define ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(literal)                \
+  (::absl::LogSeverity::kFatal >=                                      \
+           static_cast<::absl::LogSeverityAtLeast>(ABSL_MIN_LOG_LEVEL) \
+       ? (literal)                                                     \
        : "")
 #else
 #define ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(literal) (literal)
@@ -133,41 +134,39 @@
 //   string literal and abort without doing any streaming.  We don't need to
 //   strip the call to stringify the non-ok `Status` as long as we don't log it;
 //   dropping the `Status`'s message text is out of scope.
-#define ABSL_LOG_INTERNAL_CHECK_OK(val, val_text)                          \
-  for (::std::pair<const ::absl::Status* absl_nonnull,                     \
-                   const char* absl_nullable>                              \
-           absl_log_internal_check_ok_goo;                                 \
-       absl_log_internal_check_ok_goo.first =                              \
-           ::absl::log_internal::AsStatus(val),                            \
-       absl_log_internal_check_ok_goo.second =                             \
-           ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok())   \
-               ? nullptr                                                   \
-               : ::absl::status_internal::MakeCheckFailString(             \
-                     absl_log_internal_check_ok_goo.first,                 \
-                     ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val_text       \
-                                                            " is OK")),    \
-       !ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok());)    \
-    ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, true)                     \
-  ABSL_LOG_INTERNAL_CHECK(::absl::implicit_cast<const char* absl_nonnull>( \
-                              absl_log_internal_check_ok_goo.second))      \
+#define ABSL_LOG_INTERNAL_CHECK_OK(val, val_text)                         \
+  for (::std::pair<const ::absl::Status* absl_nonnull,                    \
+                   const char* absl_nonnull>                              \
+           absl_log_internal_check_ok_goo;                                \
+       absl_log_internal_check_ok_goo.first =                             \
+           ::absl::log_internal::AsStatus(val),                           \
+       absl_log_internal_check_ok_goo.second =                            \
+           ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok())  \
+               ? "" /* Don't use nullptr, to keep the annotation happy */ \
+               : ::absl::status_internal::MakeCheckFailString(            \
+                     absl_log_internal_check_ok_goo.first,                \
+                     ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val_text      \
+                                                            " is OK")),   \
+       !ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok());)   \
+    ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, true)                    \
+  ABSL_LOG_INTERNAL_CHECK(absl_log_internal_check_ok_goo.second)          \
       .InternalStream()
-#define ABSL_LOG_INTERNAL_QCHECK_OK(val, val_text)                          \
-  for (::std::pair<const ::absl::Status* absl_nonnull,                      \
-                   const char* absl_nullable>                               \
-           absl_log_internal_qcheck_ok_goo;                                 \
-       absl_log_internal_qcheck_ok_goo.first =                              \
-           ::absl::log_internal::AsStatus(val),                             \
-       absl_log_internal_qcheck_ok_goo.second =                             \
-           ABSL_PREDICT_TRUE(absl_log_internal_qcheck_ok_goo.first->ok())   \
-               ? nullptr                                                    \
-               : ::absl::status_internal::MakeCheckFailString(              \
-                     absl_log_internal_qcheck_ok_goo.first,                 \
-                     ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val_text        \
-                                                            " is OK")),     \
-       !ABSL_PREDICT_TRUE(absl_log_internal_qcheck_ok_goo.first->ok());)    \
-    ABSL_LOG_INTERNAL_CONDITION_QFATAL(STATELESS, true)                     \
-  ABSL_LOG_INTERNAL_QCHECK(::absl::implicit_cast<const char* absl_nonnull>( \
-                               absl_log_internal_qcheck_ok_goo.second))     \
+#define ABSL_LOG_INTERNAL_QCHECK_OK(val, val_text)                        \
+  for (::std::pair<const ::absl::Status* absl_nonnull,                    \
+                   const char* absl_nonnull>                              \
+           absl_log_internal_qcheck_ok_goo;                               \
+       absl_log_internal_qcheck_ok_goo.first =                            \
+           ::absl::log_internal::AsStatus(val),                           \
+       absl_log_internal_qcheck_ok_goo.second =                           \
+           ABSL_PREDICT_TRUE(absl_log_internal_qcheck_ok_goo.first->ok()) \
+               ? "" /* Don't use nullptr, to keep the annotation happy */ \
+               : ::absl::status_internal::MakeCheckFailString(            \
+                     absl_log_internal_qcheck_ok_goo.first,               \
+                     ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val_text      \
+                                                            " is OK")),   \
+       !ABSL_PREDICT_TRUE(absl_log_internal_qcheck_ok_goo.first->ok());)  \
+    ABSL_LOG_INTERNAL_CONDITION_QFATAL(STATELESS, true)                   \
+  ABSL_LOG_INTERNAL_QCHECK(absl_log_internal_qcheck_ok_goo.second)        \
       .InternalStream()
 
 namespace absl {
@@ -226,6 +225,14 @@
 void MakeCheckOpValueString(std::ostream& os, unsigned char v);
 void MakeCheckOpValueString(std::ostream& os, const void* absl_nullable p);
 
+// A wrapper for types that have no operator<<.
+struct UnprintableWrapper {
+  template <typename T>
+  explicit UnprintableWrapper(const T&) {}
+
+  friend std::ostream& operator<<(std::ostream& os, UnprintableWrapper);
+};
+
 namespace detect_specialization {
 
 // MakeCheckOpString is being specialized for every T and U pair that is being
@@ -300,12 +307,11 @@
 
 // This overload triggers when the call is ambiguous.
 // It means that T is either one from this list or printed as one from this
-// list. Eg an enum that decays to `int` for printing.
+// list. Eg an unscoped enum that decays to `int` for printing.
 // We ask the overload set to give us the type we want to convert it to.
 template <typename T>
-decltype(detect_specialization::operator<<(std::declval<std::ostream&>(),
-                                           std::declval<const T&>()))
-Detect(char);
+decltype(detect_specialization::operator<<(
+    std::declval<std::ostream&>(), std::declval<const T&>())) Detect(char);
 
 // A sink for AbslStringify which redirects everything to a std::ostream.
 class StringifySink {
@@ -346,10 +352,76 @@
 std::enable_if_t<HasAbslStringify<T>::value,
                  StringifyToStreamWrapper<T>>
 Detect(...);  // Ellipsis has lowest preference when int passed.
-}  // namespace detect_specialization
+
+// This overload triggers when T is neither possible to print nor an enum.
+template <typename T>
+std::enable_if_t<std::negation_v<std::disjunction<
+                     std::is_convertible<T, int>, std::is_enum<T>,
+                     std::is_pointer<T>, std::is_same<T, std::nullptr_t>,
+                     HasOstreamOperator<T>, HasAbslStringify<T>>>,
+                 UnprintableWrapper>
+Detect(...);
+
+// Equivalent to the updated std::underlying_type from C++20, which is no
+// longer undefined behavior for non-enum types.
+template <typename T, typename EnableT = void>
+struct UnderlyingType {};
 
 template <typename T>
-using CheckOpStreamType = decltype(detect_specialization::Detect<T>(0));
+struct UnderlyingType<T, std::enable_if_t<std::is_enum_v<T>>> {
+  using type = std::underlying_type_t<T>;
+};
+template <typename T>
+using UnderlyingTypeT = typename UnderlyingType<T>::type;
+
+// This overload triggers when T is a scoped enum that has not defined an output
+// stream operator (operator<<) or AbslStringify. It causes the enum value to be
+// converted to a type that can be streamed. For consistency with other enums, a
+// scoped enum backed by a bool or char is converted to its underlying type, and
+// one backed by another integer is converted to (u)int64_t.
+template <typename T>
+std::enable_if_t<
+    std::conjunction_v<std::is_enum<T>,
+                       std::negation<std::is_convertible<T, int>>,
+                       std::negation<HasOstreamOperator<T>>,
+                       std::negation<HasAbslStringify<T>>>,
+    std::conditional_t<std::is_same_v<UnderlyingTypeT<T>, bool> ||
+                           std::is_same_v<UnderlyingTypeT<T>, char> ||
+                           std::is_same_v<UnderlyingTypeT<T>, signed char> ||
+                           std::is_same_v<UnderlyingTypeT<T>, unsigned char>,
+                       UnderlyingTypeT<T>,
+                       std::conditional_t<std::is_signed_v<UnderlyingTypeT<T>>,
+                                          int64_t, uint64_t>>>
+Detect(...);
+
+template <typename T>
+using Detected = decltype(Detect<T>(0));
+}  // namespace detect_specialization
+
+// If the comparison will happen as pointers, decay `char*` arguments to `void*`
+// when printing them. There is no evidence that they are a NULL terminated
+// C-String so printing them as such could lead to UB, and more importantly we
+// compared pointers so showing the pointers is a better result.
+template <typename T>
+constexpr bool IsCharStarOrVoidStar() {
+  if constexpr (std::is_reference_v<T>) {
+    return IsCharStarOrVoidStar<std::remove_reference_t<T>>();
+  } else if constexpr (std::is_array_v<T>) {
+    return IsCharStarOrVoidStar<std::decay_t<T>>();
+  } else {
+    using U = std::remove_const_t<std::remove_pointer_t<T>>;
+    return std::is_pointer_v<T> &&
+        (std::is_same_v<char, U> || std::is_same_v<unsigned char, U> ||
+         std::is_same_v<signed char, U> || std::is_void_v<U>);
+  }
+}
+
+template <typename T1, typename T2,
+          typename U1 = detect_specialization::Detected<T1>,
+          typename U2 = detect_specialization::Detected<T2>>
+using CheckOpStreamType =
+    std::conditional_t<IsCharStarOrVoidStar<U1>() && IsCharStarOrVoidStar<U2>(),
+                       const void*, U1>;
 
 // Build the error message string.  Specify no inlining for code size.
 template <typename T1, typename T2>
@@ -359,10 +431,16 @@
 template <typename T1, typename T2>
 const char* absl_nonnull MakeCheckOpString(T1 v1, T2 v2,
                                            const char* absl_nonnull exprtext) {
-  CheckOpMessageBuilder comb(exprtext);
-  MakeCheckOpValueString(comb.ForVar1(), v1);
-  MakeCheckOpValueString(comb.ForVar2(), v2);
-  return comb.NewString();
+  if constexpr (std::is_same_v<CheckOpStreamType<T1, T2>, UnprintableWrapper> &&
+                std::is_same_v<CheckOpStreamType<T2, T1>, UnprintableWrapper>) {
+    // No sense printing " (UNPRINTABLE vs. UNPRINTABLE)"
+    return exprtext;
+  } else {
+    CheckOpMessageBuilder comb(exprtext);
+    MakeCheckOpValueString(comb.ForVar1(), v1);
+    MakeCheckOpValueString(comb.ForVar2(), v2);
+    return comb.NewString();
+  }
 }
 
 // Add a few commonly used instantiations as extern to reduce size of objects
@@ -393,7 +471,7 @@
 #ifdef ABSL_MIN_LOG_LEVEL
 #define ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT(U1, U2, v1, v2, exprtext) \
   ((::absl::LogSeverity::kFatal >=                                       \
-    static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL))                \
+    static_cast<::absl::LogSeverityAtLeast>(ABSL_MIN_LOG_LEVEL))         \
        ? MakeCheckOpString<U1, U2>(v1, v2, exprtext)                     \
        : "")
 #else
@@ -409,8 +487,8 @@
   template <typename T1, typename T2>                                      \
   inline constexpr const char* absl_nullable name##Impl(                   \
       const T1& v1, const T2& v2, const char* absl_nonnull exprtext) {     \
-    using U1 = CheckOpStreamType<T1>;                                      \
-    using U2 = CheckOpStreamType<T2>;                                      \
+    using U1 = CheckOpStreamType<T1, T2>;                                  \
+    using U2 = CheckOpStreamType<T2, T1>;                                  \
     return ABSL_PREDICT_TRUE(v1 op v2)                                     \
                ? nullptr                                                   \
                : ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT(U1, U2, U1(v1),    \
diff --git a/absl/log/internal/conditions.h b/absl/log/internal/conditions.h
index 6fb74b1..3325a31 100644
--- a/absl/log/internal/conditions.h
+++ b/absl/log/internal/conditions.h
@@ -108,46 +108,49 @@
 #ifdef ABSL_MIN_LOG_LEVEL
 #define ABSL_LOG_INTERNAL_CONDITION_INFO(type, condition) \
   ABSL_LOG_INTERNAL_##type##_CONDITION(                   \
-      (condition) && ::absl::LogSeverity::kInfo >=        \
-                         static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL))
+      (condition) &&                                      \
+      ::absl::LogSeverity::kInfo >=                       \
+          static_cast<::absl::LogSeverityAtLeast>(ABSL_MIN_LOG_LEVEL))
 #define ABSL_LOG_INTERNAL_CONDITION_WARNING(type, condition) \
   ABSL_LOG_INTERNAL_##type##_CONDITION(                      \
-      (condition) && ::absl::LogSeverity::kWarning >=        \
-                         static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL))
+      (condition) &&                                         \
+      ::absl::LogSeverity::kWarning >=                       \
+          static_cast<::absl::LogSeverityAtLeast>(ABSL_MIN_LOG_LEVEL))
 #define ABSL_LOG_INTERNAL_CONDITION_ERROR(type, condition) \
   ABSL_LOG_INTERNAL_##type##_CONDITION(                    \
-      (condition) && ::absl::LogSeverity::kError >=        \
-                         static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL))
+      (condition) &&                                       \
+      ::absl::LogSeverity::kError >=                       \
+          static_cast<::absl::LogSeverityAtLeast>(ABSL_MIN_LOG_LEVEL))
 #define ABSL_LOG_INTERNAL_CONDITION_DO_NOT_SUBMIT(type, condition) \
   ABSL_LOG_INTERNAL_CONDITION_ERROR(type, condition)
 // NOTE: Use ternary operators instead of short-circuiting to mitigate
 // https://bugs.llvm.org/show_bug.cgi?id=51928.
 #define ABSL_LOG_INTERNAL_CONDITION_FATAL(type, condition)                 \
   ABSL_LOG_INTERNAL_##type##_CONDITION(                                    \
-      ((condition)                                                         \
-           ? (::absl::LogSeverity::kFatal >=                               \
-                      static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) \
-                  ? true                                                   \
-                  : (::absl::log_internal::AbortQuietly(), false))         \
-           : false))
+      ((condition) ? (::absl::LogSeverity::kFatal >=                       \
+                              static_cast<::absl::LogSeverityAtLeast>(     \
+                                  ABSL_MIN_LOG_LEVEL)                      \
+                          ? true                                           \
+                          : (::absl::log_internal::AbortQuietly(), false)) \
+                   : false))
 // NOTE: Use ternary operators instead of short-circuiting to mitigate
 // https://bugs.llvm.org/show_bug.cgi?id=51928.
-#define ABSL_LOG_INTERNAL_CONDITION_QFATAL(type, condition)                \
-  ABSL_LOG_INTERNAL_##type##_CONDITION(                                    \
-      ((condition)                                                         \
-           ? (::absl::LogSeverity::kFatal >=                               \
-                      static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) \
-                  ? true                                                   \
-                  : (::absl::log_internal::ExitQuietly(), false))          \
-           : false))
-#define ABSL_LOG_INTERNAL_CONDITION_DFATAL(type, condition)             \
-  ABSL_LOG_INTERNAL_##type##_CONDITION(                                 \
-      (ABSL_ASSUME(absl::kLogDebugFatal == absl::LogSeverity::kError || \
-                   absl::kLogDebugFatal == absl::LogSeverity::kFatal),  \
-       (condition) &&                                                   \
-           (::absl::kLogDebugFatal >=                                   \
-                static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) || \
-            (::absl::kLogDebugFatal == ::absl::LogSeverity::kFatal &&   \
+#define ABSL_LOG_INTERNAL_CONDITION_QFATAL(type, condition)               \
+  ABSL_LOG_INTERNAL_##type##_CONDITION(                                   \
+      ((condition) ? (::absl::LogSeverity::kFatal >=                      \
+                              static_cast<::absl::LogSeverityAtLeast>(    \
+                                  ABSL_MIN_LOG_LEVEL)                     \
+                          ? true                                          \
+                          : (::absl::log_internal::ExitQuietly(), false)) \
+                   : false))
+#define ABSL_LOG_INTERNAL_CONDITION_DFATAL(type, condition)                    \
+  ABSL_LOG_INTERNAL_##type##_CONDITION(                                        \
+      (ABSL_ASSUME(absl::kLogDebugFatal == absl::LogSeverity::kError ||        \
+                   absl::kLogDebugFatal == absl::LogSeverity::kFatal),         \
+       (condition) &&                                                          \
+           (::absl::kLogDebugFatal >=                                          \
+                static_cast<::absl::LogSeverityAtLeast>(ABSL_MIN_LOG_LEVEL) || \
+            (::absl::kLogDebugFatal == ::absl::LogSeverity::kFatal &&          \
              (::absl::log_internal::AbortQuietly(), false)))))
 
 #define ABSL_LOG_INTERNAL_CONDITION_LEVEL(severity)                            \
@@ -157,13 +160,13 @@
              ::absl::NormalizeLogSeverity(severity);                           \
          absl_log_internal_severity_loop; absl_log_internal_severity_loop = 0) \
   ABSL_LOG_INTERNAL_CONDITION_LEVEL_IMPL
-#define ABSL_LOG_INTERNAL_CONDITION_LEVEL_IMPL(type, condition)          \
-  ABSL_LOG_INTERNAL_##type##_CONDITION((                                  \
-      (condition) &&                                                     \
-          (absl_log_internal_severity >=                                 \
-               static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) ||   \
-           (absl_log_internal_severity == ::absl::LogSeverity::kFatal && \
-            (::absl::log_internal::AbortQuietly(), false)))))
+#define ABSL_LOG_INTERNAL_CONDITION_LEVEL_IMPL(type, condition)            \
+  ABSL_LOG_INTERNAL_##type##_CONDITION(                                    \
+      ((condition) &&                                                      \
+       (absl_log_internal_severity >=                                      \
+            static_cast<::absl::LogSeverityAtLeast>(ABSL_MIN_LOG_LEVEL) || \
+        (absl_log_internal_severity == ::absl::LogSeverity::kFatal &&      \
+         (::absl::log_internal::AbortQuietly(), false)))))
 #else  // ndef ABSL_MIN_LOG_LEVEL
 #define ABSL_LOG_INTERNAL_CONDITION_INFO(type, condition) \
   ABSL_LOG_INTERNAL_##type##_CONDITION(condition)
diff --git a/absl/log/internal/container.h b/absl/log/internal/container.h
new file mode 100644
index 0000000..1144652
--- /dev/null
+++ b/absl/log/internal/container.h
@@ -0,0 +1,312 @@
+// Copyright 2025 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.
+//
+// The typical use looks like this:
+//
+//   LOG(INFO) << LogContainer(container);
+//
+// By default, LogContainer() uses the LogShortUpTo100 policy: comma-space
+// separation, no newlines, and with limit of 100 items.
+//
+// Policies can be specified:
+//
+//   LOG(INFO) << LogContainer(container, LogMultiline());
+//
+// The above example will print the container using newlines between elements,
+// enclosed in [] braces.
+//
+// See below for further details on policies.
+
+#ifndef ABSL_LOG_INTERNAL_CONTAINER_H_
+#define ABSL_LOG_INTERNAL_CONTAINER_H_
+
+#include <cstdint>
+#include <limits>
+#include <ostream>
+#include <sstream>
+#include <string>
+#include <type_traits>
+
+#include "absl/base/config.h"
+#include "absl/meta/internal/requires.h"
+#include "absl/strings/str_cat.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace log_internal {
+
+// Several policy classes below determine how LogRangeToStream will
+// format a range of items.  A Policy class should have these methods:
+//
+// Called to print an individual container element.
+//   void Log(ostream &out, const ElementT &element) const;
+//
+// Called before printing the set of elements:
+//   void LogOpening(ostream &out) const;
+//
+// Called after printing the set of elements:
+//   void LogClosing(ostream &out) const;
+//
+// Called before printing the first element:
+//   void LogFirstSeparator(ostream &out) const;
+//
+// Called before printing the remaining elements:
+//   void LogSeparator(ostream &out) const;
+//
+// Returns the maximum number of elements to print:
+//   int64 MaxElements() const;
+//
+// Called to print an indication that MaximumElements() was reached:
+//   void LogEllipsis(ostream &out) const;
+
+namespace internal {
+
+struct LogBase {
+  template <typename ElementT>
+  void Log(std::ostream &out, const ElementT &element) const {  // NOLINT
+    // Fallback to `AbslStringify` if the type does not have `operator<<`.
+    if constexpr (meta_internal::Requires<std::ostream, ElementT>(
+                      [](auto&& x, auto&& y) -> decltype(x << y) {})) {
+      out << element;
+    } else {
+      out << absl::StrCat(element);
+    }
+  }
+  void LogEllipsis(std::ostream &out) const {  // NOLINT
+    out << "...";
+  }
+};
+
+struct LogShortBase : public LogBase {
+  void LogOpening(std::ostream &out) const { out << "["; }        // NOLINT
+  void LogClosing(std::ostream &out) const { out << "]"; }        // NOLINT
+  void LogFirstSeparator(std::ostream &out) const { out << ""; }  // NOLINT
+  void LogSeparator(std::ostream &out) const { out << ", "; }     // NOLINT
+};
+
+struct LogMultilineBase : public LogBase {
+  void LogOpening(std::ostream &out) const { out << "["; }          // NOLINT
+  void LogClosing(std::ostream &out) const { out << "\n]"; }        // NOLINT
+  void LogFirstSeparator(std::ostream &out) const { out << "\n"; }  // NOLINT
+  void LogSeparator(std::ostream &out) const { out << "\n"; }       // NOLINT
+};
+
+struct LogLegacyBase : public LogBase {
+  void LogOpening(std::ostream &out) const { out << ""; }         // NOLINT
+  void LogClosing(std::ostream &out) const { out << ""; }         // NOLINT
+  void LogFirstSeparator(std::ostream &out) const { out << ""; }  // NOLINT
+  void LogSeparator(std::ostream &out) const { out << " "; }      // NOLINT
+};
+
+}  // namespace internal
+
+// LogShort uses [] braces and separates items with comma-spaces.  For
+// example "[1, 2, 3]".
+struct LogShort : public internal::LogShortBase {
+  int64_t MaxElements() const { return (std::numeric_limits<int64_t>::max)(); }
+};
+
+// LogShortUpToN(max_elements) formats the same as LogShort but prints no more
+// than the max_elements elements.
+class LogShortUpToN : public internal::LogShortBase {
+ public:
+  explicit LogShortUpToN(int64_t max_elements) : max_elements_(max_elements) {}
+  int64_t MaxElements() const { return max_elements_; }
+
+ private:
+  int64_t max_elements_;
+};
+
+// LogShortUpTo100 formats the same as LogShort but prints no more
+// than 100 elements.
+struct LogShortUpTo100 : public LogShortUpToN {
+  LogShortUpTo100() : LogShortUpToN(100) {}
+};
+
+// LogMultiline uses [] braces and separates items with
+// newlines.  For example "[
+// 1
+// 2
+// 3
+// ]".
+struct LogMultiline : public internal::LogMultilineBase {
+  int64_t MaxElements() const { return (std::numeric_limits<int64_t>::max)(); }
+};
+
+// LogMultilineUpToN(max_elements) formats the same as LogMultiline but
+// prints no more than max_elements elements.
+class LogMultilineUpToN : public internal::LogMultilineBase {
+ public:
+  explicit LogMultilineUpToN(int64_t max_elements)
+      : max_elements_(max_elements) {}
+  int64_t MaxElements() const { return max_elements_; }
+
+ private:
+  int64_t max_elements_;
+};
+
+// LogMultilineUpTo100 formats the same as LogMultiline but
+// prints no more than 100 elements.
+struct LogMultilineUpTo100 : public LogMultilineUpToN {
+  LogMultilineUpTo100() : LogMultilineUpToN(100) {}
+};
+
+// The legacy behavior of LogSequence() does not use braces and
+// separates items with spaces.  For example "1 2 3".
+struct LogLegacyUpTo100 : public internal::LogLegacyBase {
+  int64_t MaxElements() const { return 100; }
+};
+struct LogLegacy : public internal::LogLegacyBase {
+  int64_t MaxElements() const { return (std::numeric_limits<int64_t>::max)(); }
+};
+
+// The default policy for new code.
+typedef LogShortUpTo100 LogDefault;
+
+// LogRangeToStream should be used to define operator<< for
+// STL and STL-like containers.  For example, see stl_logging.h.
+template <typename IteratorT, typename PolicyT>
+inline void LogRangeToStream(std::ostream &out,  // NOLINT
+                             IteratorT begin, IteratorT end,
+                             const PolicyT &policy) {
+  policy.LogOpening(out);
+  for (int64_t i = 0; begin != end && i < policy.MaxElements(); ++i, ++begin) {
+    if (i == 0) {
+      policy.LogFirstSeparator(out);
+    } else {
+      policy.LogSeparator(out);
+    }
+    policy.Log(out, *begin);
+  }
+  if (begin != end) {
+    policy.LogSeparator(out);
+    policy.LogEllipsis(out);
+  }
+  policy.LogClosing(out);
+}
+
+namespace detail {
+
+// RangeLogger is a helper class for LogRange and LogContainer; do not use it
+// directly.  This object captures iterators into the argument of the LogRange
+// and LogContainer functions, so its lifetime should be confined to a single
+// logging statement.  Objects of this type should not be assigned to local
+// variables.
+template <typename IteratorT, typename PolicyT>
+class RangeLogger {
+ public:
+  RangeLogger(const IteratorT &begin, const IteratorT &end,
+              const PolicyT &policy)
+      : begin_(begin), end_(end), policy_(policy) {}
+
+  friend std::ostream &operator<<(std::ostream &out, const RangeLogger &range) {
+    LogRangeToStream<IteratorT, PolicyT>(out, range.begin_, range.end_,
+                                         range.policy_);
+    return out;
+  }
+
+  // operator<< above is generally recommended. However, some situations may
+  // require a string, so a convenience str() method is provided as well.
+  std::string str() const {
+    std::stringstream ss;
+    ss << *this;
+    return ss.str();
+  }
+
+ private:
+  IteratorT begin_;
+  IteratorT end_;
+  PolicyT policy_;
+};
+
+template <typename E>
+class EnumLogger {
+ public:
+  explicit EnumLogger(E e) : e_(e) {}
+
+  friend std::ostream &operator<<(std::ostream &out, const EnumLogger &v) {
+    using I = typename std::underlying_type<E>::type;
+    return out << static_cast<I>(v.e_);
+  }
+
+ private:
+  E e_;
+};
+
+}  // namespace detail
+
+// Log a range using "policy".  For example:
+//
+//   LOG(INFO) << LogRange(start_pos, end_pos, LogMultiline());
+//
+// The above example will print the range using newlines between
+// elements, enclosed in [] braces.
+template <typename IteratorT, typename PolicyT>
+detail::RangeLogger<IteratorT, PolicyT> LogRange(const IteratorT &begin,
+                                                 const IteratorT &end,
+                                                 const PolicyT &policy) {
+  return detail::RangeLogger<IteratorT, PolicyT>(begin, end, policy);
+}
+
+// Log a range.  For example:
+//
+//   LOG(INFO) << LogRange(start_pos, end_pos);
+//
+// By default, Range() uses the LogShortUpTo100 policy: comma-space
+// separation, no newlines, and with limit of 100 items.
+template <typename IteratorT>
+detail::RangeLogger<IteratorT, LogDefault> LogRange(const IteratorT &begin,
+                                                    const IteratorT &end) {
+  return LogRange(begin, end, LogDefault());
+}
+
+// Log a container using "policy".  For example:
+//
+//   LOG(INFO) << LogContainer(container, LogMultiline());
+//
+// The above example will print the container using newlines between
+// elements, enclosed in [] braces.
+template <typename ContainerT, typename PolicyT>
+auto LogContainer(const ContainerT& container, const PolicyT& policy)
+    -> decltype(LogRange(container.begin(), container.end(), policy)) {
+  return LogRange(container.begin(), container.end(), policy);
+}
+
+// Log a container.  For example:
+//
+//   LOG(INFO) << LogContainer(container);
+//
+// By default, Container() uses the LogShortUpTo100 policy: comma-space
+// separation, no newlines, and with limit of 100 items.
+template <typename ContainerT>
+auto LogContainer(const ContainerT& container)
+    -> decltype(LogContainer(container, LogDefault())) {
+  return LogContainer(container, LogDefault());
+}
+
+// Log a (possibly scoped) enum.  For example:
+//
+//   enum class Color { kRed, kGreen, kBlue };
+//   LOG(INFO) << LogEnum(kRed);
+template <typename E>
+detail::EnumLogger<E> LogEnum(E e) {
+  static_assert(std::is_enum<E>::value, "must be an enum");
+  return detail::EnumLogger<E>(e);
+}
+
+}  // namespace log_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_LOG_INTERNAL_CONTAINER_H_
diff --git a/absl/log/internal/container_test.cc b/absl/log/internal/container_test.cc
new file mode 100644
index 0000000..0a5a058
--- /dev/null
+++ b/absl/log/internal/container_test.cc
@@ -0,0 +1,254 @@
+// Copyright 2025 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/log/internal/container.h"
+
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <ostream>
+#include <set>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/str_join.h"
+#include "absl/types/span.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace log_internal {
+namespace {
+
+class ContainerLoggingTest : public ::testing::Test {
+ protected:
+  ContainerLoggingTest() : stream_(new std::stringstream) {}
+  std::ostream& stream() { return *stream_; }
+  std::string logged() {
+    std::string r = stream_->str();
+    stream_ = std::make_unique<std::stringstream>();
+    return r;
+  }
+
+ private:
+  std::unique_ptr<std::stringstream> stream_;
+};
+
+TEST_F(ContainerLoggingTest, ShortRange) {
+  std::vector<std::string> words = {"hi", "hello"};
+  LogRangeToStream(stream(), words.begin(), words.end(), LogMultiline());
+  EXPECT_EQ("[\nhi\nhello\n]", logged());
+}
+
+TEST_F(ContainerLoggingTest, LegacyRange) {
+  std::vector<int> lengths = {1, 2};
+  LogRangeToStream(stream(), lengths.begin(), lengths.end(),
+                   LogLegacyUpTo100());
+  EXPECT_EQ("1 2", logged());
+}
+
+TEST_F(ContainerLoggingTest, ToString) {
+  std::vector<int> lengths = {1, 2, 3, 4, 5};
+  EXPECT_EQ(LogContainer(lengths).str(), "[1, 2, 3, 4, 5]");
+}
+
+class UserDefFriend {
+ public:
+  explicit UserDefFriend(int i) : i_(i) {}
+
+ private:
+  friend std::ostream& operator<<(std::ostream& str, const UserDefFriend& i) {
+    return str << i.i_;
+  }
+  int i_;
+};
+
+TEST_F(ContainerLoggingTest, RangeOfUserDefined) {
+  std::vector<UserDefFriend> ints = {UserDefFriend(1), UserDefFriend(2),
+                                     UserDefFriend(3)};
+  LogRangeToStream(stream(), ints.begin(), ints.begin() + 1, LogDefault());
+  LogRangeToStream(stream(), ints.begin() + 1, ints.begin() + 2,
+                   LogMultiline());
+  LogRangeToStream(stream(), ints.begin() + 2, ints.begin() + 3, LogDefault());
+  LogRangeToStream(stream(), ints.begin(), ints.begin(), LogMultiline());
+
+  EXPECT_EQ("[1][\n2\n][3][\n]", logged());
+}
+
+TEST_F(ContainerLoggingTest, FullContainer) {
+  std::vector<int> ints;
+  std::vector<int> ints100;
+  std::vector<int> ints123;
+  int64_t max_elements = 123;
+  std::string expected1;
+  std::string expected2;
+  std::string expected3;
+  std::string expected4;
+  std::string expected5;
+  std::string expected6;
+  std::string expected7;
+  std::string expected8;
+  std::string expected9;
+  for (int i = 0; i < 1000; ++i) {
+    ints.push_back(i);
+    if (i < 100) {
+      ints100.push_back(i);
+    }
+    if (i < max_elements) {
+      ints123.push_back(i);
+    }
+  }
+  expected1 = "[\n" + absl::StrJoin(ints, "\n") + "\n]";
+  expected2 = "[" + absl::StrJoin(ints, ", ") + "]";
+  expected3 = "[\n" + absl::StrJoin(ints100, "\n") + "\n...\n]";
+  expected4 = "[" + absl::StrJoin(ints100, ", ") + ", ...]";
+  expected5 = absl::StrJoin(ints100, " ") + " ...";
+  expected6 = "[\n" + absl::StrJoin(ints, "\n") + "\n]";
+  expected7 = "[\n" + absl::StrJoin(ints123, "\n") + "\n...\n]";
+  expected8 = "[" + absl::StrJoin(ints, ", ") + "]";
+  expected9 = "[" + absl::StrJoin(ints123, ", ") + ", ...]";
+
+  LogRangeToStream(stream(), ints.begin(), ints.end(), LogMultiline());
+  EXPECT_EQ(expected1, logged());
+  LogRangeToStream(stream(), ints.begin(), ints.end(), LogShort());
+  EXPECT_EQ(expected2, logged());
+  LogRangeToStream(stream(), ints.begin(), ints.end(), LogMultilineUpTo100());
+  EXPECT_EQ(expected3, logged());
+  LogRangeToStream(stream(), ints.begin(), ints.end(), LogShortUpTo100());
+  EXPECT_EQ(expected4, logged());
+  LogRangeToStream(stream(), ints.begin(), ints.end(), LogLegacyUpTo100());
+  EXPECT_EQ(expected5, logged());
+
+  LogRangeToStream(stream(), ints.begin(), ints.end(),
+                   LogMultilineUpToN(ints.size()));
+  EXPECT_EQ(expected6, logged());
+  LogRangeToStream(stream(), ints.begin(), ints.end(),
+                   LogMultilineUpToN(max_elements));
+  EXPECT_EQ(expected7, logged());
+  LogRangeToStream(stream(), ints.begin(), ints.end(),
+                   LogShortUpToN(ints.size()));
+  EXPECT_EQ(expected8, logged());
+  LogRangeToStream(stream(), ints.begin(), ints.end(),
+                   LogShortUpToN(max_elements));
+  EXPECT_EQ(expected9, logged());
+}
+
+TEST_F(ContainerLoggingTest, LogContainer) {
+  std::set<int> ints = {1, 2, 3};
+  stream() << LogContainer(ints, LogMultiline());
+  EXPECT_EQ("[\n1\n2\n3\n]", logged());
+
+  stream() << LogContainer(ints);
+  EXPECT_EQ("[1, 2, 3]", logged());
+
+  stream() << LogContainer(std::vector<int>(ints.begin(), ints.end()),
+                           LogLegacyUpTo100());
+  EXPECT_EQ("1 2 3", logged());
+}
+
+TEST_F(ContainerLoggingTest, LogMutableSpan) {
+  std::vector<int> ints = {1, 2, 3};
+  absl::Span<int> int_span(ints);
+  stream() << LogContainer(int_span);
+  EXPECT_EQ("[1, 2, 3]", logged());
+}
+
+TEST_F(ContainerLoggingTest, LogRange) {
+  std::set<int> ints = {1, 2, 3};
+  stream() << LogRange(ints.begin(), ints.end(), LogMultiline());
+  EXPECT_EQ("[\n1\n2\n3\n]", logged());
+
+  stream() << LogRange(ints.begin(), ints.end());
+  EXPECT_EQ("[1, 2, 3]", logged());
+}
+
+// Some class with a custom Stringify
+class C {
+ public:
+  explicit C(int x) : x_(x) {}
+
+ private:
+  // This is intentionally made private for the purposes of the test;
+  //` AbslStringify` isn't meant to be called directly, and instead invoked
+  // via `StrCat` and friends.
+  template <typename Sink>
+  friend void AbslStringify(Sink& sink, const C& p) {
+    absl::Format(&sink, "C(%d)", p.x_);
+  }
+
+  int x_;
+};
+
+TEST_F(ContainerLoggingTest, LogContainerWithCustomStringify) {
+  std::vector<C> c = {C(1), C(2), C(3)};
+  stream() << LogContainer(c);
+  EXPECT_EQ("[C(1), C(2), C(3)]", logged());
+}
+
+class LogEnumTest : public ContainerLoggingTest {
+ protected:
+  enum Unscoped { kUnscoped0, kUnscoped1, kUnscoped2 };
+
+  enum StreamableUnscoped {
+    kStreamableUnscoped0,
+    kStreamableUnscoped1,
+    kStreamableUnscoped2
+  };
+
+  enum class Scoped { k0, k1, k2 };
+
+  enum class StreamableScoped { k0, k1, k2 };
+
+  friend std::ostream& operator<<(std::ostream& os, StreamableUnscoped v) {
+    return os << LogEnum(v);
+  }
+
+  friend std::ostream& operator<<(std::ostream& os, StreamableScoped v) {
+    return os << LogEnum(v);
+  }
+};
+
+TEST_F(LogEnumTest, Unscoped) {
+  stream() << LogEnum(kUnscoped0) << "," << LogEnum(kUnscoped1) << ","
+           << LogEnum(kUnscoped2);
+  EXPECT_EQ("0,1,2", logged());
+}
+
+TEST_F(LogEnumTest, StreamableUnscoped) {
+  stream() << kStreamableUnscoped0 << "," << kStreamableUnscoped1 << ","
+           << kStreamableUnscoped2;
+  EXPECT_EQ("0,1,2", logged());
+}
+
+TEST_F(LogEnumTest, Scoped) {
+  stream() << LogEnum(Scoped::k0) << "," << LogEnum(Scoped::k1) << ","
+           << LogEnum(Scoped::k2);
+  EXPECT_EQ("0,1,2", logged());
+}
+
+TEST_F(LogEnumTest, StreamableScoped) {
+  // Test using LogEnum to implement an operator<<.
+  stream() << StreamableScoped::k0 << "," << StreamableScoped::k1 << ","
+           << StreamableScoped::k2;
+  EXPECT_EQ("0,1,2", logged());
+}
+
+}  // namespace
+}  // namespace log_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/log/internal/log_impl.h b/absl/log/internal/log_impl.h
index a67f2f3..2fe73de 100644
--- a/absl/log/internal/log_impl.h
+++ b/absl/log/internal/log_impl.h
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+// SKIP_ABSL_INLINE_NAMESPACE_CHECK
+
 #ifndef ABSL_LOG_INTERNAL_LOG_IMPL_H_
 #define ABSL_LOG_INTERNAL_LOG_IMPL_H_
 
@@ -23,260 +25,256 @@
 // ABSL_LOG()
 #define ABSL_LOG_INTERNAL_LOG_IMPL(severity)             \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, true) \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream()
+      ABSL_LOG_INTERNAL_LOG##severity.InternalStream()
 
 // ABSL_PLOG()
-#define ABSL_LOG_INTERNAL_PLOG_IMPL(severity)              \
-  ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, true)   \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \
+#define ABSL_LOG_INTERNAL_PLOG_IMPL(severity)            \
+  ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, true) \
+      ABSL_LOG_INTERNAL_LOG##severity.InternalStream()   \
           .WithPerror()
 
 // ABSL_DLOG()
 #ifndef NDEBUG
 #define ABSL_LOG_INTERNAL_DLOG_IMPL(severity)            \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, true) \
-      ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+      ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 #else
 #define ABSL_LOG_INTERNAL_DLOG_IMPL(severity)             \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, false) \
-      ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+      ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 #endif
 
 // The `switch` ensures that this expansion is the beginning of a statement (as
 // opposed to an expression). The use of both `case 0` and `default` is to
 // suppress a compiler warning.
-#define ABSL_LOG_INTERNAL_VLOG_IMPL(verbose_level)                         \
-  switch (const int absl_logging_internal_verbose_level = (verbose_level)) \
-  case 0:                                                                  \
-  default:                                                                 \
-    ABSL_LOG_INTERNAL_LOG_IF_IMPL(                                         \
-        _INFO, ABSL_VLOG_IS_ON(absl_logging_internal_verbose_level))       \
-        .WithVerbosity(absl_logging_internal_verbose_level)
+#define ABSL_LOG_INTERNAL_VLOG_IMPL(verbose_level)                     \
+  switch (const int absl_log_internal_verbose_level = (verbose_level)) \
+  case 0:                                                              \
+  default:                                                             \
+    ABSL_LOG_INTERNAL_LOG_IF_IMPL(                                     \
+        _INFO, ABSL_VLOG_IS_ON(absl_log_internal_verbose_level))       \
+        .WithVerbosity(absl_log_internal_verbose_level)
 
 #ifndef NDEBUG
-#define ABSL_LOG_INTERNAL_DVLOG_IMPL(verbose_level)                        \
-  switch (const int absl_logging_internal_verbose_level = (verbose_level)) \
-  case 0:                                                                  \
-  default:                                                                 \
-    ABSL_LOG_INTERNAL_DLOG_IF_IMPL(                                         \
-        _INFO, ABSL_VLOG_IS_ON(absl_logging_internal_verbose_level))       \
-        .WithVerbosity(absl_logging_internal_verbose_level)
+#define ABSL_LOG_INTERNAL_DVLOG_IMPL(verbose_level)                    \
+  switch (const int absl_log_internal_verbose_level = (verbose_level)) \
+  case 0:                                                              \
+  default:                                                             \
+    ABSL_LOG_INTERNAL_DLOG_IF_IMPL(                                    \
+        _INFO, ABSL_VLOG_IS_ON(absl_log_internal_verbose_level))       \
+        .WithVerbosity(absl_log_internal_verbose_level)
 #else
-#define ABSL_LOG_INTERNAL_DVLOG_IMPL(verbose_level)                           \
-  switch (const int absl_logging_internal_verbose_level = (verbose_level))    \
-  case 0:                                                                     \
-  default:                                                                    \
-    ABSL_LOG_INTERNAL_DLOG_IF_IMPL(                                            \
-        _INFO, false && ABSL_VLOG_IS_ON(absl_logging_internal_verbose_level)) \
-        .WithVerbosity(absl_logging_internal_verbose_level)
+#define ABSL_LOG_INTERNAL_DVLOG_IMPL(verbose_level)                       \
+  switch (const int absl_log_internal_verbose_level = (verbose_level))    \
+  case 0:                                                                 \
+  default:                                                                \
+    ABSL_LOG_INTERNAL_DLOG_IF_IMPL(                                       \
+        _INFO, false && ABSL_VLOG_IS_ON(absl_log_internal_verbose_level)) \
+        .WithVerbosity(absl_log_internal_verbose_level)
 #endif
 
 #define ABSL_LOG_INTERNAL_LOG_IF_IMPL(severity, condition)    \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, condition) \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream()
+      ABSL_LOG_INTERNAL_LOG##severity.InternalStream()
 #define ABSL_LOG_INTERNAL_PLOG_IF_IMPL(severity, condition)   \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, condition) \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream()    \
+      ABSL_LOG_INTERNAL_LOG##severity.InternalStream()        \
           .WithPerror()
 
 #ifndef NDEBUG
 #define ABSL_LOG_INTERNAL_DLOG_IF_IMPL(severity, condition)   \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, condition) \
-      ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+      ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 #else
 #define ABSL_LOG_INTERNAL_DLOG_IF_IMPL(severity, condition)              \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, false && (condition)) \
-      ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+      ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 #endif
 
 // ABSL_LOG_EVERY_N
 #define ABSL_LOG_INTERNAL_LOG_EVERY_N_IMPL(severity, n)            \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(EveryN, n) \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream()
+      ABSL_LOG_INTERNAL_LOG##severity.InternalStream()
 
 // ABSL_LOG_FIRST_N
 #define ABSL_LOG_INTERNAL_LOG_FIRST_N_IMPL(severity, n)            \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(FirstN, n) \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream()
+      ABSL_LOG_INTERNAL_LOG##severity.InternalStream()
 
 // ABSL_LOG_EVERY_POW_2
 #define ABSL_LOG_INTERNAL_LOG_EVERY_POW_2_IMPL(severity)           \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(EveryPow2) \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream()
+      ABSL_LOG_INTERNAL_LOG##severity.InternalStream()
 
 // ABSL_LOG_EVERY_N_SEC
 #define ABSL_LOG_INTERNAL_LOG_EVERY_N_SEC_IMPL(severity, n_seconds)           \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(EveryNSec, n_seconds) \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream()
+      ABSL_LOG_INTERNAL_LOG##severity.InternalStream()
 
 #define ABSL_LOG_INTERNAL_PLOG_EVERY_N_IMPL(severity, n)           \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(EveryN, n) \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream()         \
+      ABSL_LOG_INTERNAL_LOG##severity.InternalStream()             \
           .WithPerror()
 
 #define ABSL_LOG_INTERNAL_PLOG_FIRST_N_IMPL(severity, n)           \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(FirstN, n) \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream()         \
+      ABSL_LOG_INTERNAL_LOG##severity.InternalStream()             \
           .WithPerror()
 
 #define ABSL_LOG_INTERNAL_PLOG_EVERY_POW_2_IMPL(severity)          \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(EveryPow2) \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream()         \
+      ABSL_LOG_INTERNAL_LOG##severity.InternalStream()             \
           .WithPerror()
 
 #define ABSL_LOG_INTERNAL_PLOG_EVERY_N_SEC_IMPL(severity, n_seconds)          \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(EveryNSec, n_seconds) \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream()                    \
+      ABSL_LOG_INTERNAL_LOG##severity.InternalStream()                        \
           .WithPerror()
 
 #ifndef NDEBUG
 #define ABSL_LOG_INTERNAL_DLOG_EVERY_N_IMPL(severity, n) \
   ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true)       \
-  (EveryN, n) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+  (EveryN, n) ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 
 #define ABSL_LOG_INTERNAL_DLOG_FIRST_N_IMPL(severity, n) \
   ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true)       \
-  (FirstN, n) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+  (FirstN, n) ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 
 #define ABSL_LOG_INTERNAL_DLOG_EVERY_POW_2_IMPL(severity) \
   ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true)        \
-  (EveryPow2) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+  (EveryPow2) ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 
 #define ABSL_LOG_INTERNAL_DLOG_EVERY_N_SEC_IMPL(severity, n_seconds) \
   ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true)                   \
-  (EveryNSec, n_seconds) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+  (EveryNSec, n_seconds) ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 
 #else  // def NDEBUG
 #define ABSL_LOG_INTERNAL_DLOG_EVERY_N_IMPL(severity, n) \
   ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false)      \
-  (EveryN, n) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+  (EveryN, n) ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 
 #define ABSL_LOG_INTERNAL_DLOG_FIRST_N_IMPL(severity, n) \
   ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false)      \
-  (FirstN, n) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+  (FirstN, n) ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 
 #define ABSL_LOG_INTERNAL_DLOG_EVERY_POW_2_IMPL(severity) \
   ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false)       \
-  (EveryPow2) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+  (EveryPow2) ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 
 #define ABSL_LOG_INTERNAL_DLOG_EVERY_N_SEC_IMPL(severity, n_seconds) \
   ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false)                  \
-  (EveryNSec, n_seconds) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+  (EveryNSec, n_seconds) ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 #endif  // def NDEBUG
 
-#define ABSL_LOG_INTERNAL_VLOG_EVERY_N_IMPL(verbose_level, n)                \
-  switch (const int absl_logging_internal_verbose_level = (verbose_level))   \
-  case 0:                                                                    \
-  default:                                                                   \
-    ABSL_LOG_INTERNAL_CONDITION_INFO(                                        \
-        STATEFUL, ABSL_VLOG_IS_ON(absl_logging_internal_verbose_level))      \
-  (EveryN, n) ABSL_LOGGING_INTERNAL_LOG_INFO.InternalStream().WithVerbosity( \
-      absl_logging_internal_verbose_level)
+#define ABSL_LOG_INTERNAL_VLOG_EVERY_N_IMPL(verbose_level, n)            \
+  switch (const int absl_log_internal_verbose_level = (verbose_level))   \
+  case 0:                                                                \
+  default:                                                               \
+    ABSL_LOG_INTERNAL_CONDITION_INFO(                                    \
+        STATEFUL, ABSL_VLOG_IS_ON(absl_log_internal_verbose_level))      \
+  (EveryN, n) ABSL_LOG_INTERNAL_LOG_INFO.InternalStream().WithVerbosity( \
+      absl_log_internal_verbose_level)
 
-#define ABSL_LOG_INTERNAL_VLOG_FIRST_N_IMPL(verbose_level, n)                \
-  switch (const int absl_logging_internal_verbose_level = (verbose_level))   \
-  case 0:                                                                    \
-  default:                                                                   \
-    ABSL_LOG_INTERNAL_CONDITION_INFO(                                        \
-        STATEFUL, ABSL_VLOG_IS_ON(absl_logging_internal_verbose_level))      \
-  (FirstN, n) ABSL_LOGGING_INTERNAL_LOG_INFO.InternalStream().WithVerbosity( \
-      absl_logging_internal_verbose_level)
+#define ABSL_LOG_INTERNAL_VLOG_FIRST_N_IMPL(verbose_level, n)            \
+  switch (const int absl_log_internal_verbose_level = (verbose_level))   \
+  case 0:                                                                \
+  default:                                                               \
+    ABSL_LOG_INTERNAL_CONDITION_INFO(                                    \
+        STATEFUL, ABSL_VLOG_IS_ON(absl_log_internal_verbose_level))      \
+  (FirstN, n) ABSL_LOG_INTERNAL_LOG_INFO.InternalStream().WithVerbosity( \
+      absl_log_internal_verbose_level)
 
-#define ABSL_LOG_INTERNAL_VLOG_EVERY_POW_2_IMPL(verbose_level)               \
-  switch (const int absl_logging_internal_verbose_level = (verbose_level))   \
-  case 0:                                                                    \
-  default:                                                                   \
-    ABSL_LOG_INTERNAL_CONDITION_INFO(                                        \
-        STATEFUL, ABSL_VLOG_IS_ON(absl_logging_internal_verbose_level))      \
-  (EveryPow2) ABSL_LOGGING_INTERNAL_LOG_INFO.InternalStream().WithVerbosity( \
-      absl_logging_internal_verbose_level)
+#define ABSL_LOG_INTERNAL_VLOG_EVERY_POW_2_IMPL(verbose_level)           \
+  switch (const int absl_log_internal_verbose_level = (verbose_level))   \
+  case 0:                                                                \
+  default:                                                               \
+    ABSL_LOG_INTERNAL_CONDITION_INFO(                                    \
+        STATEFUL, ABSL_VLOG_IS_ON(absl_log_internal_verbose_level))      \
+  (EveryPow2) ABSL_LOG_INTERNAL_LOG_INFO.InternalStream().WithVerbosity( \
+      absl_log_internal_verbose_level)
 
-#define ABSL_LOG_INTERNAL_VLOG_EVERY_N_SEC_IMPL(verbose_level, n_seconds)  \
-  switch (const int absl_logging_internal_verbose_level = (verbose_level)) \
-  case 0:                                                                  \
-  default:                                                                 \
-    ABSL_LOG_INTERNAL_CONDITION_INFO(                                      \
-        STATEFUL, ABSL_VLOG_IS_ON(absl_logging_internal_verbose_level))    \
-  (EveryNSec, n_seconds) ABSL_LOGGING_INTERNAL_LOG_INFO.InternalStream()   \
-      .WithVerbosity(absl_logging_internal_verbose_level)
+#define ABSL_LOG_INTERNAL_VLOG_EVERY_N_SEC_IMPL(verbose_level, n_seconds) \
+  switch (const int absl_log_internal_verbose_level = (verbose_level))    \
+  case 0:                                                                 \
+  default:                                                                \
+    ABSL_LOG_INTERNAL_CONDITION_INFO(                                     \
+        STATEFUL, ABSL_VLOG_IS_ON(absl_log_internal_verbose_level))       \
+  (EveryNSec, n_seconds) ABSL_LOG_INTERNAL_LOG_INFO.InternalStream()      \
+      .WithVerbosity(absl_log_internal_verbose_level)
 
 #define ABSL_LOG_INTERNAL_LOG_IF_EVERY_N_IMPL(severity, condition, n)   \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryN, n) \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream()
+      ABSL_LOG_INTERNAL_LOG##severity.InternalStream()
 
 #define ABSL_LOG_INTERNAL_LOG_IF_FIRST_N_IMPL(severity, condition, n)   \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(FirstN, n) \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream()
+      ABSL_LOG_INTERNAL_LOG##severity.InternalStream()
 
 #define ABSL_LOG_INTERNAL_LOG_IF_EVERY_POW_2_IMPL(severity, condition)  \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryPow2) \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream()
+      ABSL_LOG_INTERNAL_LOG##severity.InternalStream()
 
-#define ABSL_LOG_INTERNAL_LOG_IF_EVERY_N_SEC_IMPL(severity, condition,  \
-                                                  n_seconds)            \
-  ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryNSec, \
-                                                             n_seconds) \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream()
+#define ABSL_LOG_INTERNAL_LOG_IF_EVERY_N_SEC_IMPL(severity, condition, \
+                                                  n_seconds)           \
+  ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(          \
+      EveryNSec, n_seconds) ABSL_LOG_INTERNAL_LOG##severity.InternalStream()
 
 #define ABSL_LOG_INTERNAL_PLOG_IF_EVERY_N_IMPL(severity, condition, n)  \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryN, n) \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream()              \
+      ABSL_LOG_INTERNAL_LOG##severity.InternalStream()                  \
           .WithPerror()
 
 #define ABSL_LOG_INTERNAL_PLOG_IF_FIRST_N_IMPL(severity, condition, n)  \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(FirstN, n) \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream()              \
+      ABSL_LOG_INTERNAL_LOG##severity.InternalStream()                  \
           .WithPerror()
 
 #define ABSL_LOG_INTERNAL_PLOG_IF_EVERY_POW_2_IMPL(severity, condition) \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryPow2) \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream()              \
+      ABSL_LOG_INTERNAL_LOG##severity.InternalStream()                  \
           .WithPerror()
 
-#define ABSL_LOG_INTERNAL_PLOG_IF_EVERY_N_SEC_IMPL(severity, condition, \
-                                                   n_seconds)           \
-  ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryNSec, \
-                                                             n_seconds) \
-      ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream()              \
-          .WithPerror()
+#define ABSL_LOG_INTERNAL_PLOG_IF_EVERY_N_SEC_IMPL(severity, condition,      \
+                                                   n_seconds)                \
+  ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(                \
+      EveryNSec, n_seconds) ABSL_LOG_INTERNAL_LOG##severity.InternalStream() \
+      .WithPerror()
 
 #ifndef NDEBUG
 #define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_IMPL(severity, condition, n)  \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryN, n) \
-      ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+      ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 
 #define ABSL_LOG_INTERNAL_DLOG_IF_FIRST_N_IMPL(severity, condition, n)  \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(FirstN, n) \
-      ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+      ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 
 #define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_POW_2_IMPL(severity, condition) \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryPow2) \
-      ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+      ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 
 #define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_SEC_IMPL(severity, condition, \
                                                    n_seconds)           \
-  ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryNSec, \
-                                                             n_seconds) \
-      ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+  ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(           \
+      EveryNSec, n_seconds) ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 
 #else  // def NDEBUG
 #define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_IMPL(severity, condition, n)   \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, false && (condition))( \
-      EveryN, n) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+      EveryN, n) ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 
 #define ABSL_LOG_INTERNAL_DLOG_IF_FIRST_N_IMPL(severity, condition, n)   \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, false && (condition))( \
-      FirstN, n) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+      FirstN, n) ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 
 #define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_POW_2_IMPL(severity, condition)  \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, false && (condition))( \
-      EveryPow2) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+      EveryPow2) ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 
 #define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_SEC_IMPL(severity, condition,  \
                                                    n_seconds)            \
   ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, false && (condition))( \
-      EveryNSec, n_seconds)                                              \
-      ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream()
+      EveryNSec, n_seconds) ABSL_LOG_INTERNAL_DLOG##severity.InternalStream()
 #endif  // def NDEBUG
 
 #endif  // ABSL_LOG_INTERNAL_LOG_IMPL_H_
diff --git a/absl/log/internal/log_message.cc b/absl/log/internal/log_message.cc
index 3aed3a2..52ab3d9 100644
--- a/absl/log/internal/log_message.cc
+++ b/absl/log/internal/log_message.cc
@@ -150,7 +150,7 @@
 }  // namespace
 
 struct LogMessage::LogMessageData final {
-  LogMessageData(const char* absl_nonnull file, int line,
+  LogMessageData(absl::string_view file, int line,
                  absl::LogSeverity severity, absl::Time timestamp);
   LogMessageData(const LogMessageData&) = delete;
   LogMessageData& operator=(const LogMessageData&) = delete;
@@ -202,7 +202,7 @@
   void FinalizeEncodingAndFormat();
 };
 
-LogMessage::LogMessageData::LogMessageData(const char* absl_nonnull file,
+LogMessage::LogMessageData::LogMessageData(absl::string_view file,
                                            int line, absl::LogSeverity severity,
                                            absl::Time timestamp)
     : extra_sinks_only(false), manipulated(nullptr) {
@@ -275,6 +275,9 @@
 
 LogMessage::LogMessage(const char* absl_nonnull file, int line,
                        absl::LogSeverity severity)
+  : LogMessage(absl::string_view(file), line, severity) {}
+LogMessage::LogMessage(absl::string_view file, int line,
+                       absl::LogSeverity severity)
     : data_(absl::make_unique<LogMessageData>(file, line, severity,
                                               absl::Now())) {
   data_->first_fatal = false;
diff --git a/absl/log/internal/log_message.h b/absl/log/internal/log_message.h
index 1aaf05e..5b6eed3 100644
--- a/absl/log/internal/log_message.h
+++ b/absl/log/internal/log_message.h
@@ -64,9 +64,13 @@
   struct WarningTag {};
   struct ErrorTag {};
 
-  // Used for `LOG`.
+  // Used for `LOG`.  Taking `const char *` instead of `string_view` keeps
+  // callsites a little bit smaller at the cost of doing `strlen` at runtime.
   LogMessage(const char* absl_nonnull file, int line,
              absl::LogSeverity severity) ABSL_ATTRIBUTE_COLD;
+  // Used for FFI integrations that don't have a NUL-terminated string.
+  LogMessage(absl::string_view file, int line,
+             absl::LogSeverity severity) ABSL_ATTRIBUTE_COLD;
   // These constructors are slightly smaller/faster to call; the severity is
   // curried into the function pointer.
   LogMessage(const char* absl_nonnull file, int line,
diff --git a/absl/log/internal/log_sink_set.cc b/absl/log/internal/log_sink_set.cc
index 3d5c699..c4c7e5f 100644
--- a/absl/log/internal/log_sink_set.cc
+++ b/absl/log/internal/log_sink_set.cc
@@ -192,7 +192,7 @@
         absl::log_internal::WriteToStderr(
             entry.text_message_with_prefix_and_newline(), entry.log_severity());
       } else {
-        absl::ReaderMutexLock global_sinks_lock(&guard_);
+        absl::ReaderMutexLock global_sinks_lock(guard_);
         ThreadIsLoggingStatus() = true;
         // Ensure the "thread is logging" status is reverted upon leaving the
         // scope even in case of exceptions.
@@ -205,7 +205,7 @@
 
   void AddLogSink(absl::LogSink* sink) ABSL_LOCKS_EXCLUDED(guard_) {
     {
-      absl::WriterMutexLock global_sinks_lock(&guard_);
+      absl::WriterMutexLock global_sinks_lock(guard_);
       auto pos = std::find(sinks_.begin(), sinks_.end(), sink);
       if (pos == sinks_.end()) {
         sinks_.push_back(sink);
@@ -217,7 +217,7 @@
 
   void RemoveLogSink(absl::LogSink* sink) ABSL_LOCKS_EXCLUDED(guard_) {
     {
-      absl::WriterMutexLock global_sinks_lock(&guard_);
+      absl::WriterMutexLock global_sinks_lock(guard_);
       auto pos = std::find(sinks_.begin(), sinks_.end(), sink);
       if (pos != sinks_.end()) {
         sinks_.erase(pos);
@@ -235,7 +235,7 @@
       guard_.AssertReaderHeld();
       FlushLogSinksLocked();
     } else {
-      absl::ReaderMutexLock global_sinks_lock(&guard_);
+      absl::ReaderMutexLock global_sinks_lock(guard_);
       // In case if LogSink::Flush overload decides to log
       ThreadIsLoggingStatus() = true;
       // Ensure the "thread is logging" status is reverted upon leaving the
diff --git a/absl/log/internal/strip.h b/absl/log/internal/strip.h
index 60ef878..6fd857b 100644
--- a/absl/log/internal/strip.h
+++ b/absl/log/internal/strip.h
@@ -26,57 +26,56 @@
 #include "absl/log/internal/log_message.h"
 #include "absl/log/internal/nullstream.h"
 
-// `ABSL_LOGGING_INTERNAL_LOG_*` evaluates to a temporary `LogMessage` object or
+// `ABSL_LOG_INTERNAL_LOG_*` evaluates to a temporary `LogMessage` object or
 // to a related object with a compatible API but different behavior.  This set
 // of defines comes in three flavors: vanilla, plus two variants that strip some
 // logging in subtly different ways for subtly different reasons (see below).
 #if defined(STRIP_LOG) && STRIP_LOG
 
-#define ABSL_LOGGING_INTERNAL_LOG_INFO ::absl::log_internal::NullStream()
-#define ABSL_LOGGING_INTERNAL_LOG_WARNING ::absl::log_internal::NullStream()
-#define ABSL_LOGGING_INTERNAL_LOG_ERROR ::absl::log_internal::NullStream()
-#define ABSL_LOGGING_INTERNAL_LOG_FATAL ::absl::log_internal::NullStreamFatal()
-#define ABSL_LOGGING_INTERNAL_LOG_QFATAL ::absl::log_internal::NullStreamFatal()
-#define ABSL_LOGGING_INTERNAL_LOG_DFATAL \
+#define ABSL_LOG_INTERNAL_LOG_INFO ::absl::log_internal::NullStream()
+#define ABSL_LOG_INTERNAL_LOG_WARNING ::absl::log_internal::NullStream()
+#define ABSL_LOG_INTERNAL_LOG_ERROR ::absl::log_internal::NullStream()
+#define ABSL_LOG_INTERNAL_LOG_FATAL ::absl::log_internal::NullStreamFatal()
+#define ABSL_LOG_INTERNAL_LOG_QFATAL ::absl::log_internal::NullStreamFatal()
+#define ABSL_LOG_INTERNAL_LOG_DFATAL \
   ::absl::log_internal::NullStreamMaybeFatal(::absl::kLogDebugFatal)
-#define ABSL_LOGGING_INTERNAL_LOG_LEVEL(severity) \
+#define ABSL_LOG_INTERNAL_LOG_LEVEL(severity) \
   ::absl::log_internal::NullStreamMaybeFatal(absl_log_internal_severity)
 
 // Fatal `DLOG`s expand a little differently to avoid being `[[noreturn]]`.
-#define ABSL_LOGGING_INTERNAL_DLOG_FATAL \
+#define ABSL_LOG_INTERNAL_DLOG_FATAL \
   ::absl::log_internal::NullStreamMaybeFatal(::absl::LogSeverity::kFatal)
-#define ABSL_LOGGING_INTERNAL_DLOG_QFATAL \
+#define ABSL_LOG_INTERNAL_DLOG_QFATAL \
   ::absl::log_internal::NullStreamMaybeFatal(::absl::LogSeverity::kFatal)
 
-#define ABSL_LOG_INTERNAL_CHECK(failure_message) ABSL_LOGGING_INTERNAL_LOG_FATAL
-#define ABSL_LOG_INTERNAL_QCHECK(failure_message) \
-  ABSL_LOGGING_INTERNAL_LOG_QFATAL
+#define ABSL_LOG_INTERNAL_CHECK(failure_message) ABSL_LOG_INTERNAL_LOG_FATAL
+#define ABSL_LOG_INTERNAL_QCHECK(failure_message) ABSL_LOG_INTERNAL_LOG_QFATAL
 
 #else  // !defined(STRIP_LOG) || !STRIP_LOG
 
-#define ABSL_LOGGING_INTERNAL_LOG_INFO \
-  ::absl::log_internal::LogMessage(    \
+#define ABSL_LOG_INTERNAL_LOG_INFO  \
+  ::absl::log_internal::LogMessage( \
       __FILE__, __LINE__, ::absl::log_internal::LogMessage::InfoTag{})
-#define ABSL_LOGGING_INTERNAL_LOG_WARNING \
-  ::absl::log_internal::LogMessage(       \
+#define ABSL_LOG_INTERNAL_LOG_WARNING \
+  ::absl::log_internal::LogMessage(   \
       __FILE__, __LINE__, ::absl::log_internal::LogMessage::WarningTag{})
-#define ABSL_LOGGING_INTERNAL_LOG_ERROR \
-  ::absl::log_internal::LogMessage(     \
+#define ABSL_LOG_INTERNAL_LOG_ERROR \
+  ::absl::log_internal::LogMessage( \
       __FILE__, __LINE__, ::absl::log_internal::LogMessage::ErrorTag{})
-#define ABSL_LOGGING_INTERNAL_LOG_FATAL \
+#define ABSL_LOG_INTERNAL_LOG_FATAL \
   ::absl::log_internal::LogMessageFatal(__FILE__, __LINE__)
-#define ABSL_LOGGING_INTERNAL_LOG_QFATAL \
+#define ABSL_LOG_INTERNAL_LOG_QFATAL \
   ::absl::log_internal::LogMessageQuietlyFatal(__FILE__, __LINE__)
-#define ABSL_LOGGING_INTERNAL_LOG_DFATAL \
+#define ABSL_LOG_INTERNAL_LOG_DFATAL \
   ::absl::log_internal::LogMessage(__FILE__, __LINE__, ::absl::kLogDebugFatal)
-#define ABSL_LOGGING_INTERNAL_LOG_LEVEL(severity)      \
+#define ABSL_LOG_INTERNAL_LOG_LEVEL(severity)          \
   ::absl::log_internal::LogMessage(__FILE__, __LINE__, \
                                    absl_log_internal_severity)
 
 // Fatal `DLOG`s expand a little differently to avoid being `[[noreturn]]`.
-#define ABSL_LOGGING_INTERNAL_DLOG_FATAL \
+#define ABSL_LOG_INTERNAL_DLOG_FATAL \
   ::absl::log_internal::LogMessageDebugFatal(__FILE__, __LINE__)
-#define ABSL_LOGGING_INTERNAL_DLOG_QFATAL \
+#define ABSL_LOG_INTERNAL_DLOG_QFATAL \
   ::absl::log_internal::LogMessageQuietlyDebugFatal(__FILE__, __LINE__)
 
 // These special cases dispatch to special-case constructors that allow us to
@@ -89,12 +88,12 @@
 #endif  // !defined(STRIP_LOG) || !STRIP_LOG
 
 // This part of a non-fatal `DLOG`s expands the same as `LOG`.
-#define ABSL_LOGGING_INTERNAL_DLOG_INFO ABSL_LOGGING_INTERNAL_LOG_INFO
-#define ABSL_LOGGING_INTERNAL_DLOG_WARNING ABSL_LOGGING_INTERNAL_LOG_WARNING
-#define ABSL_LOGGING_INTERNAL_DLOG_ERROR ABSL_LOGGING_INTERNAL_LOG_ERROR
-#define ABSL_LOGGING_INTERNAL_DLOG_DFATAL ABSL_LOGGING_INTERNAL_LOG_DFATAL
-#define ABSL_LOGGING_INTERNAL_DLOG_LEVEL ABSL_LOGGING_INTERNAL_LOG_LEVEL
+#define ABSL_LOG_INTERNAL_DLOG_INFO ABSL_LOG_INTERNAL_LOG_INFO
+#define ABSL_LOG_INTERNAL_DLOG_WARNING ABSL_LOG_INTERNAL_LOG_WARNING
+#define ABSL_LOG_INTERNAL_DLOG_ERROR ABSL_LOG_INTERNAL_LOG_ERROR
+#define ABSL_LOG_INTERNAL_DLOG_DFATAL ABSL_LOG_INTERNAL_LOG_DFATAL
+#define ABSL_LOG_INTERNAL_DLOG_LEVEL ABSL_LOG_INTERNAL_LOG_LEVEL
 
-#define ABSL_LOGGING_INTERNAL_LOG_DO_NOT_SUBMIT ABSL_LOGGING_INTERNAL_LOG_ERROR
+#define ABSL_LOG_INTERNAL_LOG_DO_NOT_SUBMIT ABSL_LOG_INTERNAL_LOG_ERROR
 
 #endif  // ABSL_LOG_INTERNAL_STRIP_H_
diff --git a/absl/log/internal/vlog_config.cc b/absl/log/internal/vlog_config.cc
index f7c61be..e9b4827 100644
--- a/absl/log/internal/vlog_config.cc
+++ b/absl/log/internal/vlog_config.cc
@@ -45,13 +45,25 @@
 namespace log_internal {
 
 namespace {
-bool ModuleIsPath(absl::string_view module_pattern) {
+
 #ifdef _WIN32
-  return module_pattern.find_first_of("/\\") != module_pattern.npos;
+constexpr char kPathSeparators[] = "/\\";
 #else
-  return module_pattern.find('/') != module_pattern.npos;
+constexpr char kPathSeparators[] = "/";
 #endif
+
+bool ModuleIsPath(absl::string_view module_pattern) {
+  return module_pattern.find_first_of(kPathSeparators) != module_pattern.npos;
 }
+
+absl::string_view Basename(absl::string_view file) {
+  auto sep = file.find_last_of(kPathSeparators);
+  if (sep != file.npos) {
+    file.remove_prefix(sep + 1);
+  }
+  return file;
+}
+
 }  // namespace
 
 bool VLogSite::SlowIsEnabled(int stale_v, int level) {
@@ -90,16 +102,16 @@
 // To avoid problems with the heap checker which calls into `VLOG`, `mutex` must
 // be a `SpinLock` that prevents fiber scheduling instead of a `Mutex`.
 ABSL_CONST_INIT absl::base_internal::SpinLock mutex(
-    absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY);
+    absl::base_internal::SCHEDULE_KERNEL_ONLY);
 
 // `GetUpdateSitesMutex()` serializes updates to all of the sites (i.e. those in
 // `site_list_head`) themselves.
-absl::Mutex* GetUpdateSitesMutex() {
+absl::Mutex& GetUpdateSitesMutex() {
   // Chromium requires no global destructors, so we can't use the
   // absl::kConstInit idiom since absl::Mutex as a non-trivial destructor.
   static absl::NoDestructor<absl::Mutex> update_sites_mutex ABSL_ACQUIRED_AFTER(
       mutex);
-  return update_sites_mutex.get();
+  return *update_sites_mutex;
 }
 
 ABSL_CONST_INIT int global_v ABSL_GUARDED_BY(mutex) = 0;
@@ -129,21 +141,9 @@
   // parsing flags).  We can't allocate in `VLOG`, so we treat null as empty
   // here and press on.
   if (!infos || infos->empty()) return current_global_v;
-  // Get basename for file
-  absl::string_view basename = file;
-  {
-    const size_t sep = basename.rfind('/');
-    if (sep != basename.npos) {
-      basename.remove_prefix(sep + 1);
-#ifdef _WIN32
-    } else {
-      const size_t sep = basename.rfind('\\');
-      if (sep != basename.npos) basename.remove_prefix(sep + 1);
-#endif
-    }
-  }
 
-  absl::string_view stem = file, stem_basename = basename;
+  absl::string_view stem = file;
+  absl::string_view stem_basename = Basename(stem);
   {
     const size_t sep = stem_basename.find('.');
     if (sep != stem_basename.npos) {
@@ -159,10 +159,10 @@
       // If there are any slashes in the pattern, try to match the full
       // name.
       if (FNMatch(info.module_pattern, stem)) {
-        return info.vlog_level == kUseFlag ? current_global_v : info.vlog_level;
+        return info.vlog_level;
       }
     } else if (FNMatch(info.module_pattern, stem_basename)) {
-      return info.vlog_level == kUseFlag ? current_global_v : info.vlog_level;
+      return info.vlog_level;
     }
   }
 
@@ -222,7 +222,7 @@
 }  // namespace
 
 int VLogLevel(absl::string_view file) ABSL_LOCKS_EXCLUDED(mutex) {
-  absl::base_internal::SpinLockHolder l(&mutex);
+  absl::base_internal::SpinLockHolder l(mutex);
   return VLogLevel(file, vmodule_info, global_v);
 }
 
@@ -267,7 +267,7 @@
   // have to wait on all updates in order to acquire `mutex` and initialize
   // themselves.
   absl::MutexLock ul(GetUpdateSitesMutex());
-  mutex.Unlock();
+  mutex.unlock();
   VLogSite* n = site_list_head.load(std::memory_order_seq_cst);
   // Because sites are added to the list in the order they are executed, there
   // tend to be clusters of entries with the same file.
@@ -299,7 +299,7 @@
     if (!absl::SimpleAtoi(glob_level.substr(eq + 1), &level)) continue;
     glob_levels.emplace_back(glob, level);
   }
-  mutex.Lock();  // Unlocked by UpdateVLogSites().
+  mutex.lock();  // unlocked by UpdateVLogSites().
   get_vmodule_info().clear();
   for (const auto& it : glob_levels) {
     const absl::string_view glob = it.first;
@@ -311,10 +311,10 @@
 
 int UpdateGlobalVLogLevel(int v)
     ABSL_LOCKS_EXCLUDED(mutex, GetUpdateSitesMutex()) {
-  mutex.Lock();  // Unlocked by UpdateVLogSites().
+  mutex.lock();  // unlocked by UpdateVLogSites().
   const int old_global_v = global_v;
   if (v == global_v) {
-    mutex.Unlock();
+    mutex.unlock();
     return old_global_v;
   }
   global_v = v;
@@ -324,7 +324,7 @@
 
 int PrependVModule(absl::string_view module_pattern, int log_level)
     ABSL_LOCKS_EXCLUDED(mutex, GetUpdateSitesMutex()) {
-  mutex.Lock();  // Unlocked by UpdateVLogSites().
+  mutex.lock();  // unlocked by UpdateVLogSites().
   int old_v = PrependVModuleLocked(module_pattern, log_level);
   UpdateVLogSites();
   return old_v;
diff --git a/absl/log/internal/vlog_config.h b/absl/log/internal/vlog_config.h
index 84e817a..da020f8 100644
--- a/absl/log/internal/vlog_config.h
+++ b/absl/log/internal/vlog_config.h
@@ -48,7 +48,6 @@
 
 int RegisterAndInitialize(VLogSite* absl_nonnull v);
 void UpdateVLogSites();
-constexpr int kUseFlag = (std::numeric_limits<int16_t>::min)();
 
 // Represents a unique callsite for a `VLOG()` or `VLOG_IS_ON()` call.
 //
diff --git a/absl/log/log.h b/absl/log/log.h
index f1cab9d..371c32f 100644
--- a/absl/log/log.h
+++ b/absl/log/log.h
@@ -247,11 +247,11 @@
 // However, simply testing whether verbose logging is enabled can be expensive.
 // If you don't intend to enable verbose logging in non-debug builds, consider
 // using `DVLOG` instead.
-#define VLOG(severity) ABSL_LOG_INTERNAL_VLOG_IMPL(severity)
+#define VLOG(verbose_level) ABSL_LOG_INTERNAL_VLOG_IMPL(verbose_level)
 
 // `DVLOG` behaves like `VLOG` in debug mode (i.e. `#ifndef NDEBUG`).
 // Otherwise, it compiles away and does nothing.
-#define DVLOG(severity) ABSL_LOG_INTERNAL_DVLOG_IMPL(severity)
+#define DVLOG(verbose_level) ABSL_LOG_INTERNAL_DVLOG_IMPL(verbose_level)
 
 // `LOG_IF` and friends add a second argument which specifies a condition.  If
 // the condition is false, nothing is logged.
diff --git a/absl/log/log_basic_test_impl.inc b/absl/log/log_basic_test_impl.inc
index c4b4e24..3f007dc 100644
--- a/absl/log/log_basic_test_impl.inc
+++ b/absl/log/log_basic_test_impl.inc
@@ -94,6 +94,7 @@
   absl::log_internal::ScopedMinLogLevel scoped_min_log_level(GetParam());
 
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int log_line = __LINE__ + 1;
   auto do_log = [] { ABSL_TEST_LOG(INFO) << "hello world"; };
@@ -125,6 +126,7 @@
   absl::log_internal::ScopedMinLogLevel scoped_min_log_level(GetParam());
 
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int log_line = __LINE__ + 1;
   auto do_log = [] { ABSL_TEST_LOG(WARNING) << "hello world"; };
@@ -156,6 +158,7 @@
   absl::log_internal::ScopedMinLogLevel scoped_min_log_level(GetParam());
 
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int log_line = __LINE__ + 1;
   auto do_log = [] { ABSL_TEST_LOG(ERROR) << "hello world"; };
@@ -187,6 +190,7 @@
   absl::log_internal::ScopedMinLogLevel scoped_min_log_level(GetParam());
 
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int log_line = __LINE__ + 1;
   auto do_log = [] { ABSL_TEST_LOG(DO_NOT_SUBMIT) << "hello world"; };
@@ -233,6 +237,7 @@
       {
         absl::ScopedMockLog test_sink(
             absl::MockLogDefault::kDisallowUnexpected);
+        EXPECT_CALL(test_sink, Send).Times(0);
 
         EXPECT_CALL(test_sink, Send)
             .Times(AnyNumber())
@@ -299,6 +304,7 @@
       {
         absl::ScopedMockLog test_sink(
             absl::MockLogDefault::kDisallowUnexpected);
+        EXPECT_CALL(test_sink, Send).Times(0);
 
         EXPECT_CALL(test_sink, Send)
             .Times(AnyNumber())
@@ -336,6 +342,7 @@
   absl::log_internal::ScopedMinLogLevel scoped_min_log_level(GetParam());
 
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int log_line = __LINE__ + 1;
   auto do_log = [] { ABSL_TEST_LOG(DFATAL) << "hello world"; };
@@ -375,6 +382,7 @@
       {
         absl::ScopedMockLog test_sink(
             absl::MockLogDefault::kDisallowUnexpected);
+        EXPECT_CALL(test_sink, Send).Times(0);
 
         EXPECT_CALL(test_sink, Send)
             .Times(AnyNumber())
@@ -456,6 +464,7 @@
   for (auto severity : {absl::LogSeverity::kInfo, absl::LogSeverity::kWarning,
                         absl::LogSeverity::kError}) {
     absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+    EXPECT_CALL(test_sink, Send).Times(0);
 
     const int log_line = __LINE__ + 2;
     auto do_log = [severity] {
@@ -506,6 +515,7 @@
       {
         absl::ScopedMockLog test_sink(
             absl::MockLogDefault::kDisallowUnexpected);
+        EXPECT_CALL(test_sink, Send).Times(0);
 
         EXPECT_CALL(test_sink, Send)
             .Times(AnyNumber())
@@ -567,6 +577,7 @@
   }
 
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(test_sink, Send(LogSeverity(Eq(absl::LogSeverity::kInfo))));
 
@@ -583,6 +594,7 @@
   }
 
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(test_sink, Send(LogSeverity(Eq(absl::LogSeverity::kError))));
 
diff --git a/absl/log/log_entry.cc b/absl/log/log_entry.cc
new file mode 100644
index 0000000..358b8f5
--- /dev/null
+++ b/absl/log/log_entry.cc
@@ -0,0 +1,263 @@
+// Copyright 2025 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/log/log_entry.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <iomanip>
+#include <ios>
+#include <ostream>
+
+#include "absl/base/config.h"
+#include "absl/log/internal/proto.h"
+#include "absl/strings/escaping.h"
+#include "absl/strings/string_view.h"
+#include "absl/time/time.h"
+#include "absl/types/span.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace {
+// message `logging.proto.Event`
+enum EventTag : uint8_t {
+  kFileName = 2,
+  kFileLine = 3,
+  kTimeNsecs = 4,
+  kSeverity = 5,
+  kThreadId = 6,
+  kValue = 7,
+  kSequenceNumber = 9,
+  kThreadName = 10,
+};
+
+// message `logging.proto.Value`
+enum ValueTag : uint8_t {
+  kString = 1,
+  kStringLiteral = 6,
+};
+
+// enum `logging.proto.Severity`
+enum Severity : int {
+  FINEST = 300,
+  FINER = 400,
+  FINE = 500,
+  VERBOSE_0 = 600,
+  CONFIG = 700,
+  INFO = 800,
+  NOTICE = 850,
+  WARNING = 900,
+  ERROR = 950,
+  SEVERE = 1000,
+  FATAL = 1100,
+};
+
+void PrintEscapedRangeTo(const absl::string_view str,
+                         const absl::string_view substr, std::ostream* os) {
+  const absl::string_view head =
+      str.substr(0, static_cast<size_t>(substr.data() - str.data()));
+  const char old_fill = os->fill();
+  const auto old_flags = os->flags();
+  *os << std::right
+      << std::setw(static_cast<int>(absl::CHexEscape(head).size())) << "";
+  switch (substr.size()) {
+    case 0:
+      *os << "\\";
+      break;
+    case 1:
+      *os << "^";
+      break;
+    default:
+      *os << "[" << std::setw(static_cast<int>(absl::CHexEscape(substr).size()))
+          << std::setfill('-') << ")";
+      break;
+  }
+  os->fill(old_fill);
+  os->flags(old_flags);
+}
+}  // namespace
+void PrintTo(const LogEntry& entry, std::ostream* os) {
+  auto text_message_with_prefix_and_newline_and_nul = absl::string_view(
+      entry.text_message_with_prefix_and_newline_and_nul_.data(),
+      entry.text_message_with_prefix_and_newline_and_nul_.size());
+  *os << "LogEntry {\n"
+      << "  source_filename: \"" << absl::CHexEscape(entry.source_filename())
+      << "\"\n"
+      << "  source_basename: \"" << absl::CHexEscape(entry.source_basename())
+      << "\"\n"
+      << "  source_line: " << entry.source_line() << "\n"
+      << "  prefix: " << std::boolalpha << entry.prefix() << "\n"
+      << "  log_severity: " << entry.log_severity() << "\n"
+      << "  verbosity: " << entry.verbosity();
+  if (entry.verbosity() == absl::LogEntry::kNoVerbosityLevel) {
+    *os << " (kNoVerbosityLevel)";
+  }
+  *os << "\n"
+      << "  timestamp: " << entry.timestamp() << "\n"
+      << "  tid: " << entry.tid() << "\n"
+      << "  text_message_with_prefix_and_newline_and_nul_: \""
+      << absl::CHexEscape(text_message_with_prefix_and_newline_and_nul)
+      << "\"\n"
+      << "  text_message_with_prefix_and_newline:           ";
+  PrintEscapedRangeTo(text_message_with_prefix_and_newline_and_nul,
+                      entry.text_message_with_prefix_and_newline(), os);
+  *os << "\n"
+      << "  text_message_with_prefix:                       ";
+  PrintEscapedRangeTo(text_message_with_prefix_and_newline_and_nul,
+                      entry.text_message_with_prefix(), os);
+  *os << "\n"
+      << "  text_message_with_newline:                      ";
+  PrintEscapedRangeTo(text_message_with_prefix_and_newline_and_nul,
+                      entry.text_message_with_newline(), os);
+  *os << "\n"
+      << "  text_message:                                   ";
+  PrintEscapedRangeTo(text_message_with_prefix_and_newline_and_nul,
+                      entry.text_message(), os);
+  *os << "\n"
+      << "  text_message_with_prefix_and_newline_c_str:     ";
+  PrintEscapedRangeTo(
+      text_message_with_prefix_and_newline_and_nul,
+      // NOLINTNEXTLINE(bugprone-string-constructor)
+      absl::string_view(entry.text_message_with_prefix_and_newline_c_str(), 0),
+      os);
+  *os << "\n"
+      << "  encoded_message (raw): \""
+      << absl::CHexEscape(entry.encoded_message()) << "\"\n"
+      << "  encoded_message {\n";
+  absl::Span<const char> event = entry.encoded_message();
+  log_internal::ProtoField field;
+  while (field.DecodeFrom(&event)) {
+    switch (field.tag()) {
+      case EventTag::kFileName:
+        *os << "    file_name: \"" << absl::CHexEscape(field.string_value())
+            << "\"\n";
+        break;
+      case EventTag::kFileLine:
+        *os << "    file_line: " << field.int32_value() << "\n";
+        break;
+      case EventTag::kTimeNsecs:
+        *os << "    time_nsecs: " << field.int64_value() << " ("
+            << absl::FromUnixNanos(field.int64_value()) << ")\n";
+        break;
+      case EventTag::kSeverity:
+        *os << "    severity: " << field.int32_value();
+        switch (field.int32_value()) {
+          case Severity::FINEST:
+            *os << " (FINEST)";
+            break;
+          case Severity::FINER:
+            *os << " (FINER)";
+            break;
+          case Severity::FINE:
+            *os << " (FINE)";
+            break;
+          case Severity::VERBOSE_0:
+            *os << " (VERBOSE_0)";
+            break;
+          case Severity::CONFIG:
+            *os << " (CONFIG)";
+            break;
+          case Severity::INFO:
+            *os << " (INFO)";
+            break;
+          case Severity::NOTICE:
+            *os << " (NOTICE)";
+            break;
+          case Severity::WARNING:
+            *os << " (WARNING)";
+            break;
+          case Severity::ERROR:
+            *os << " (ERROR)";
+            break;
+          case Severity::SEVERE:
+            *os << " (SEVERE)";
+            break;
+          case Severity::FATAL:
+            *os << " (FATAL)";
+            break;
+        }
+        *os << "\n";
+        break;
+      case EventTag::kThreadId:
+        *os << "    thread_id: " << field.int64_value() << "\n";
+        break;
+      case EventTag::kValue: {
+        *os << "    value {\n";
+        auto value = field.bytes_value();
+        while (field.DecodeFrom(&value)) {
+          switch (field.tag()) {
+            case ValueTag::kString:
+              *os << "      str: \"" << absl::CHexEscape(field.string_value())
+                  << "\"\n";
+              break;
+            case ValueTag::kStringLiteral:
+              *os << "      literal: \""
+                  << absl::CHexEscape(field.string_value()) << "\"\n";
+              break;
+            default:
+              *os << "      unknown field " << field.tag();
+              switch (field.type()) {
+                case log_internal::WireType::kVarint:
+                  *os << " (VARINT): " << std::hex << std::showbase
+                      << field.uint64_value() << std::dec << "\n";
+                  break;
+                case log_internal::WireType::k64Bit:
+                  *os << " (I64): " << std::hex << std::showbase
+                      << field.uint64_value() << std::dec << "\n";
+                  break;
+                case log_internal::WireType::kLengthDelimited:
+                  *os << " (LEN): \"" << absl::CHexEscape(field.string_value())
+                      << "\"\n";
+                  break;
+                case log_internal::WireType::k32Bit:
+                  *os << " (I32): " << std::hex << std::showbase
+                      << field.uint32_value() << std::dec << "\n";
+                  break;
+              }
+              break;
+          }
+        }
+        *os << "    }\n";
+        break;
+      }
+      default:
+        *os << "    unknown field " << field.tag();
+        switch (field.type()) {
+          case log_internal::WireType::kVarint:
+            *os << " (VARINT): " << std::hex << std::showbase
+                << field.uint64_value() << std::dec << "\n";
+            break;
+          case log_internal::WireType::k64Bit:
+            *os << " (I64): " << std::hex << std::showbase
+                << field.uint64_value() << std::dec << "\n";
+            break;
+          case log_internal::WireType::kLengthDelimited:
+            *os << " (LEN): \"" << absl::CHexEscape(field.string_value())
+                << "\"\n";
+            break;
+          case log_internal::WireType::k32Bit:
+            *os << " (I32): " << std::hex << std::showbase
+                << field.uint32_value() << std::dec << "\n";
+            break;
+        }
+        break;
+    }
+  }
+  *os << "  }\n"
+      << "  stacktrace: \"" << absl::CHexEscape(entry.stacktrace()) << "\"\n"
+      << "}";
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/log/log_entry.h b/absl/log/log_entry.h
index 7a55dfe..c566856 100644
--- a/absl/log/log_entry.h
+++ b/absl/log/log_entry.h
@@ -25,6 +25,7 @@
 #define ABSL_LOG_LOG_ENTRY_H_
 
 #include <cstddef>
+#include <ostream>
 #include <string>
 
 #include "absl/base/attributes.h"
@@ -213,6 +214,7 @@
 
   friend class log_internal::LogEntryTestPeer;
   friend class log_internal::LogMessage;
+  friend void PrintTo(const absl::LogEntry& entry, std::ostream* os);
 };
 
 ABSL_NAMESPACE_END
diff --git a/absl/log/log_format_test.cc b/absl/log/log_format_test.cc
index 6b7d1e5..9f1cc6b 100644
--- a/absl/log/log_format_test.cc
+++ b/absl/log/log_format_test.cc
@@ -73,6 +73,7 @@
 
 TEST(LogFormatTest, NoMessage) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int log_line = __LINE__ + 1;
   auto do_log = [] { LOG(INFO); };
@@ -95,6 +96,7 @@
 
 TYPED_TEST(CharLogFormatTest, Printable) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const TypeParam value = 'x';
   auto comparison_stream = ComparisonStream();
@@ -112,6 +114,7 @@
 
 TYPED_TEST(CharLogFormatTest, Unprintable) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   constexpr auto value = static_cast<TypeParam>(0xeeu);
   auto comparison_stream = ComparisonStream();
@@ -130,6 +133,7 @@
 
 TEST(WideCharLogFormatTest, Printable) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("€")),
                                     ENCODED_MESSAGE(HasValues(
@@ -142,6 +146,7 @@
 
 TEST(WideCharLogFormatTest, Unprintable) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   // Using NEL (Next Line) Unicode character (U+0085).
   // It is encoded as "\xC2\x85" in UTF-8.
@@ -163,6 +168,7 @@
 
 TYPED_TEST(UnsignedIntLogFormatTest, Positive) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const TypeParam value = 224;
   auto comparison_stream = ComparisonStream();
@@ -181,6 +187,7 @@
 
 TYPED_TEST(UnsignedIntLogFormatTest, BitfieldPositive) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const struct {
     TypeParam bits : 6;
@@ -206,6 +213,7 @@
 
 TYPED_TEST(SignedIntLogFormatTest, Positive) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const TypeParam value = 224;
   auto comparison_stream = ComparisonStream();
@@ -224,6 +232,7 @@
 
 TYPED_TEST(SignedIntLogFormatTest, Negative) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const TypeParam value = -112;
   auto comparison_stream = ComparisonStream();
@@ -242,6 +251,7 @@
 
 TYPED_TEST(SignedIntLogFormatTest, BitfieldPositive) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const struct {
     TypeParam bits : 6;
@@ -261,6 +271,7 @@
 
 TYPED_TEST(SignedIntLogFormatTest, BitfieldNegative) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const struct {
     TypeParam bits : 6;
@@ -305,6 +316,7 @@
 
 TYPED_TEST(UnsignedEnumLogFormatTest, Positive) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const TypeParam value = static_cast<TypeParam>(224);
   auto comparison_stream = ComparisonStream();
@@ -323,6 +335,7 @@
 
 TYPED_TEST(UnsignedEnumLogFormatTest, BitfieldPositive) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const struct {
     TypeParam bits : 6;
@@ -365,6 +378,7 @@
 
 TYPED_TEST(SignedEnumLogFormatTest, Positive) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const TypeParam value = static_cast<TypeParam>(224);
   auto comparison_stream = ComparisonStream();
@@ -383,6 +397,7 @@
 
 TYPED_TEST(SignedEnumLogFormatTest, Negative) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const TypeParam value = static_cast<TypeParam>(-112);
   auto comparison_stream = ComparisonStream();
@@ -401,6 +416,7 @@
 
 TYPED_TEST(SignedEnumLogFormatTest, BitfieldPositive) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const struct {
     TypeParam bits : 6;
@@ -420,6 +436,7 @@
 
 TYPED_TEST(SignedEnumLogFormatTest, BitfieldNegative) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const struct {
     TypeParam bits : 6;
@@ -441,6 +458,7 @@
 
 TEST(FloatLogFormatTest, Positive) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const float value = 6.02e23f;
   auto comparison_stream = ComparisonStream();
@@ -458,6 +476,7 @@
 
 TEST(FloatLogFormatTest, Negative) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const float value = -6.02e23f;
   auto comparison_stream = ComparisonStream();
@@ -475,6 +494,7 @@
 
 TEST(FloatLogFormatTest, NegativeExponent) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const float value = 6.02e-23f;
   auto comparison_stream = ComparisonStream();
@@ -492,6 +512,7 @@
 
 TEST(DoubleLogFormatTest, Positive) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const double value = 6.02e23;
   auto comparison_stream = ComparisonStream();
@@ -509,6 +530,7 @@
 
 TEST(DoubleLogFormatTest, Negative) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const double value = -6.02e23;
   auto comparison_stream = ComparisonStream();
@@ -526,6 +548,7 @@
 
 TEST(DoubleLogFormatTest, NegativeExponent) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const double value = 6.02e-23;
   auto comparison_stream = ComparisonStream();
@@ -548,6 +571,7 @@
 
 TYPED_TEST(FloatingPointLogFormatTest, Zero) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const TypeParam value = 0.0;
   auto comparison_stream = ComparisonStream();
@@ -565,6 +589,7 @@
 
 TYPED_TEST(FloatingPointLogFormatTest, Integer) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const TypeParam value = 1.0;
   auto comparison_stream = ComparisonStream();
@@ -582,6 +607,7 @@
 
 TYPED_TEST(FloatingPointLogFormatTest, Infinity) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const TypeParam value = std::numeric_limits<TypeParam>::infinity();
   auto comparison_stream = ComparisonStream();
@@ -600,6 +626,7 @@
 
 TYPED_TEST(FloatingPointLogFormatTest, NegativeInfinity) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const TypeParam value = -std::numeric_limits<TypeParam>::infinity();
   auto comparison_stream = ComparisonStream();
@@ -618,6 +645,7 @@
 
 TYPED_TEST(FloatingPointLogFormatTest, NaN) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const TypeParam value = std::numeric_limits<TypeParam>::quiet_NaN();
   auto comparison_stream = ComparisonStream();
@@ -635,6 +663,7 @@
 
 TYPED_TEST(FloatingPointLogFormatTest, NegativeNaN) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const TypeParam value =
       std::copysign(std::numeric_limits<TypeParam>::quiet_NaN(), -1.0);
@@ -671,6 +700,7 @@
 
 TYPED_TEST(VoidPtrLogFormatTest, Null) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const TypeParam value = nullptr;
   auto comparison_stream = ComparisonStream();
@@ -688,6 +718,7 @@
 
 TYPED_TEST(VoidPtrLogFormatTest, NonNull) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const TypeParam value = reinterpret_cast<TypeParam>(0xdeadbeefULL);
   auto comparison_stream = ComparisonStream();
@@ -715,6 +746,7 @@
 
 TYPED_TEST(VolatilePtrLogFormatTest, Null) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const TypeParam value = nullptr;
   auto comparison_stream = ComparisonStream();
@@ -742,6 +774,7 @@
 
 TYPED_TEST(VolatilePtrLogFormatTest, NonNull) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const TypeParam value = reinterpret_cast<TypeParam>(0xdeadbeefLL);
   auto comparison_stream = ComparisonStream();
@@ -777,6 +810,7 @@
 
 TYPED_TEST(CharPtrLogFormatTest, Null) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   // Streaming `([cv] char *)nullptr` into a `std::ostream` is UB, and some C++
   // standard library implementations choose to crash.  We take measures to log
@@ -797,6 +831,7 @@
 
 TYPED_TEST(CharPtrLogFormatTest, NonNull) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   TypeParam data[] = {'v', 'a', 'l', 'u', 'e', '\0'};
   TypeParam* const value = data;
@@ -821,6 +856,7 @@
 
 TYPED_TEST(WideCharPtrLogFormatTest, Null) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   TypeParam* const value = nullptr;
 
@@ -834,6 +870,7 @@
 
 TYPED_TEST(WideCharPtrLogFormatTest, NonNull) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   TypeParam data[] = {'v', 'a', 'l', 'u', 'e', '\0'};
   TypeParam* const value = data;
@@ -848,6 +885,7 @@
 
 TEST(BoolLogFormatTest, True) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const bool value = true;
   auto comparison_stream = ComparisonStream();
@@ -866,6 +904,7 @@
 
 TEST(BoolLogFormatTest, False) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const bool value = false;
   auto comparison_stream = ComparisonStream();
@@ -884,6 +923,7 @@
 
 TEST(LogFormatTest, StringLiteral) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   auto comparison_stream = ComparisonStream();
   comparison_stream << "value";
@@ -900,6 +940,7 @@
 
 TEST(LogFormatTest, WideStringLiteral) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("value")),
                                     ENCODED_MESSAGE(HasValues(ElementsAre(
@@ -911,6 +952,7 @@
 
 TEST(LogFormatTest, CharArray) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   char value[] = "value";
   auto comparison_stream = ComparisonStream();
@@ -929,6 +971,7 @@
 
 TEST(LogFormatTest, WideCharArray) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   wchar_t value[] = L"value";
 
@@ -967,6 +1010,7 @@
 
 TYPED_TEST(WideStringLogFormatTest, NonLiterals) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   TypeParam value = ABSL_LOG_INTERNAL_WIDE_LITERAL;
   absl::string_view utf8_value = GetUtf8TestString();
@@ -981,6 +1025,7 @@
 
 TEST(WideStringLogFormatTest, StringView) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   std::wstring_view value = ABSL_LOG_INTERNAL_WIDE_LITERAL;
   absl::string_view utf8_value = GetUtf8TestString();
@@ -995,6 +1040,7 @@
 
 TEST(WideStringLogFormatTest, Literal) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   absl::string_view utf8_value = GetUtf8TestString();
 
@@ -1011,6 +1057,7 @@
 
 TYPED_TEST(WideStringLogFormatTest, IsolatedLowSurrogatesAreReplaced) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   TypeParam value = L"AAA \xDC00 BBB";
   // NOLINTNEXTLINE(readability/utf8)
@@ -1027,6 +1074,7 @@
 TYPED_TEST(WideStringLogFormatTest,
            DISABLED_IsolatedHighSurrogatesAreReplaced) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   TypeParam value = L"AAA \xD800 BBB";
   // NOLINTNEXTLINE(readability/utf8)
@@ -1044,6 +1092,7 @@
 TYPED_TEST(WideStringLogFormatTest,
            DISABLED_ConsecutiveHighSurrogatesAreReplaced) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   TypeParam value = L"AAA \xD800\xD800 BBB";
   // NOLINTNEXTLINE(readability/utf8)
@@ -1061,6 +1110,7 @@
 TYPED_TEST(WideStringLogFormatTest,
            DISABLED_HighHighLowSurrogateSequencesAreReplaced) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   TypeParam value = L"AAA \xD800\xD800\xDC00 BBB";
   // NOLINTNEXTLINE(readability/utf8)
@@ -1078,6 +1128,7 @@
 TYPED_TEST(WideStringLogFormatTest,
            DISABLED_TrailingHighSurrogatesAreReplaced) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   TypeParam value = L"AAA \xD800";
   // NOLINTNEXTLINE(readability/utf8)
@@ -1094,6 +1145,7 @@
 
 TYPED_TEST(WideStringLogFormatTest, EmptyWideString) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   TypeParam value = L"";
 
@@ -1121,6 +1173,7 @@
 
 TEST(LogFormatTest, Custom) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   CustomClass value;
   auto comparison_stream = ComparisonStream();
@@ -1147,6 +1200,7 @@
 
 TEST(LogFormatTest, CustomNonCopyable) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   CustomClassNonCopyable value;
   auto comparison_stream = ComparisonStream();
@@ -1174,6 +1228,7 @@
 
 TEST(LogFormatTest, AbslStringifyExample) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   Point p;
 
@@ -1205,6 +1260,7 @@
 
 TEST(LogFormatTest, CustomWithAbslStringifyAndOstream) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   PointWithAbslStringifiyAndOstream p;
 
@@ -1228,6 +1284,7 @@
 
 TEST(LogFormatTest, AbslStringifyStreamsNothing) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   PointStreamsNothing p;
 
@@ -1254,6 +1311,7 @@
 
 TEST(LogFormatTest, AbslStringifyMultipleAppend) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   PointMultipleAppend p;
 
@@ -1269,6 +1327,7 @@
 
 TEST(ManipulatorLogFormatTest, BoolAlphaTrue) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const bool value = true;
   auto comparison_stream = ComparisonStream();
@@ -1293,6 +1352,7 @@
 
 TEST(ManipulatorLogFormatTest, BoolAlphaFalse) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const bool value = false;
   auto comparison_stream = ComparisonStream();
@@ -1317,6 +1377,7 @@
 
 TEST(ManipulatorLogFormatTest, ShowPoint) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const double value = 77.0;
   auto comparison_stream = ComparisonStream();
@@ -1341,6 +1402,7 @@
 
 TEST(ManipulatorLogFormatTest, ShowPos) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int value = 77;
   auto comparison_stream = ComparisonStream();
@@ -1364,6 +1426,7 @@
 
 TEST(ManipulatorLogFormatTest, UppercaseFloat) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const double value = 7.7e7;
   auto comparison_stream = ComparisonStream();
@@ -1388,6 +1451,7 @@
 
 TEST(ManipulatorLogFormatTest, Hex) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int value = 0x77;
   auto comparison_stream = ComparisonStream();
@@ -1405,6 +1469,7 @@
 
 TEST(ManipulatorLogFormatTest, Oct) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int value = 077;
   auto comparison_stream = ComparisonStream();
@@ -1423,6 +1488,7 @@
 
 TEST(ManipulatorLogFormatTest, Dec) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int value = 77;
   auto comparison_stream = ComparisonStream();
@@ -1440,6 +1506,7 @@
 
 TEST(ManipulatorLogFormatTest, ShowbaseHex) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int value = 0x77;
   auto comparison_stream = ComparisonStream();
@@ -1466,6 +1533,7 @@
 
 TEST(ManipulatorLogFormatTest, ShowbaseOct) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int value = 077;
   auto comparison_stream = ComparisonStream();
@@ -1491,6 +1559,7 @@
 
 TEST(ManipulatorLogFormatTest, UppercaseHex) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int value = 0xbeef;
   auto comparison_stream = ComparisonStream();
@@ -1518,6 +1587,7 @@
 
 TEST(ManipulatorLogFormatTest, FixedFloat) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const double value = 7.7e7;
   auto comparison_stream = ComparisonStream();
@@ -1535,6 +1605,7 @@
 
 TEST(ManipulatorLogFormatTest, ScientificFloat) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const double value = 7.7e7;
   auto comparison_stream = ComparisonStream();
@@ -1558,6 +1629,7 @@
 #else
 TEST(ManipulatorLogFormatTest, FixedAndScientificFloat) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const double value = 7.7e7;
   auto comparison_stream = ComparisonStream();
@@ -1591,6 +1663,7 @@
 #else
 TEST(ManipulatorLogFormatTest, HexfloatFloat) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const double value = 7.7e7;
   auto comparison_stream = ComparisonStream();
@@ -1612,6 +1685,7 @@
 
 TEST(ManipulatorLogFormatTest, DefaultFloatFloat) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const double value = 7.7e7;
   auto comparison_stream = ComparisonStream();
@@ -1629,6 +1703,7 @@
 
 TEST(ManipulatorLogFormatTest, Ends) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   auto comparison_stream = ComparisonStream();
   comparison_stream << std::ends;
@@ -1645,6 +1720,7 @@
 
 TEST(ManipulatorLogFormatTest, Endl) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   auto comparison_stream = ComparisonStream();
   comparison_stream << std::endl;
@@ -1662,6 +1738,7 @@
 
 TEST(ManipulatorLogFormatTest, SetIosFlags) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int value = 0x77;
   auto comparison_stream = ComparisonStream();
@@ -1691,6 +1768,7 @@
 
 TEST(ManipulatorLogFormatTest, SetBase) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int value = 0x77;
   auto comparison_stream = ComparisonStream();
@@ -1715,6 +1793,7 @@
 
 TEST(ManipulatorLogFormatTest, SetPrecision) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const double value = 6.022140857e23;
   auto comparison_stream = ComparisonStream();
@@ -1736,6 +1815,7 @@
 
 TEST(ManipulatorLogFormatTest, SetPrecisionOverflow) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const double value = 6.022140857e23;
   auto comparison_stream = ComparisonStream();
@@ -1753,6 +1833,7 @@
 
 TEST(ManipulatorLogFormatTest, SetW) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int value = 77;
   auto comparison_stream = ComparisonStream();
@@ -1774,6 +1855,7 @@
 
 TEST(ManipulatorLogFormatTest, Left) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int value = -77;
   auto comparison_stream = ComparisonStream();
@@ -1791,6 +1873,7 @@
 
 TEST(ManipulatorLogFormatTest, Right) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int value = -77;
   auto comparison_stream = ComparisonStream();
@@ -1808,6 +1891,7 @@
 
 TEST(ManipulatorLogFormatTest, Internal) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int value = -77;
   auto comparison_stream = ComparisonStream();
@@ -1825,6 +1909,7 @@
 
 TEST(ManipulatorLogFormatTest, SetFill) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   const int value = 77;
   auto comparison_stream = ComparisonStream();
@@ -1851,6 +1936,7 @@
 
 TEST(ManipulatorLogFormatTest, FromCustom) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   FromCustomClass value;
   auto comparison_stream = ComparisonStream();
@@ -1873,6 +1959,7 @@
 
 TEST(ManipulatorLogFormatTest, CustomClassStreamsNothing) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   StreamsNothing value;
   auto comparison_stream = ComparisonStream();
@@ -1900,6 +1987,7 @@
 
 TEST(ManipulatorLogFormatTest, IOManipsDoNotAffectAbslStringify) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   PointPercentV p;
 
@@ -1915,6 +2003,7 @@
 
 TEST(StructuredLoggingOverflowTest, TruncatesStrings) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   // This message is too long and should be truncated to some unspecified size
   // no greater than the buffer size but not too much less either.  It should be
@@ -1937,6 +2026,7 @@
 
 TEST(StructuredLoggingOverflowTest, TruncatesWideStrings) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   // This message is too long and should be truncated to some unspecified size
   // no greater than the buffer size but not too much less either.  It should be
@@ -1967,6 +2057,7 @@
 
 TEST(StructuredLoggingOverflowTest, TruncatesInsertionOperators) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   // This message is too long and should be truncated to some unspecified size
   // no greater than the buffer size but not too much less either.  It should be
@@ -2018,6 +2109,7 @@
   // sizes.  To put any data in the field we need a fifth byte.
   {
     absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+    EXPECT_CALL(test_sink, Send).Times(0);
     EXPECT_CALL(test_sink,
                 Send(AllOf(ENCODED_MESSAGE(HasOneStrThat(
                                AllOf(SizeIs(longest_fit), Each(Eq('x'))))),
@@ -2028,6 +2120,7 @@
   }
   {
     absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+    EXPECT_CALL(test_sink, Send).Times(0);
     EXPECT_CALL(test_sink,
                 Send(AllOf(ENCODED_MESSAGE(HasOneStrThat(
                                AllOf(SizeIs(longest_fit - 1), Each(Eq('x'))))),
@@ -2038,6 +2131,7 @@
   }
   {
     absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+    EXPECT_CALL(test_sink, Send).Times(0);
     EXPECT_CALL(test_sink,
                 Send(AllOf(ENCODED_MESSAGE(HasOneStrThat(
                                AllOf(SizeIs(longest_fit - 2), Each(Eq('x'))))),
@@ -2048,6 +2142,7 @@
   }
   {
     absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+    EXPECT_CALL(test_sink, Send).Times(0);
     EXPECT_CALL(test_sink,
                 Send(AllOf(ENCODED_MESSAGE(HasOneStrThat(
                                AllOf(SizeIs(longest_fit - 3), Each(Eq('x'))))),
@@ -2058,6 +2153,7 @@
   }
   {
     absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+    EXPECT_CALL(test_sink, Send).Times(0);
     EXPECT_CALL(test_sink,
                 Send(AllOf(ENCODED_MESSAGE(HasOneStrAndOneLiteralThat(
                                AllOf(SizeIs(longest_fit - 4), Each(Eq('x'))),
@@ -2070,6 +2166,7 @@
   }
   {
     absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+    EXPECT_CALL(test_sink, Send).Times(0);
     EXPECT_CALL(
         test_sink,
         Send(AllOf(ENCODED_MESSAGE(HasOneStrAndOneLiteralThat(
@@ -2087,6 +2184,7 @@
   // sizes.  To put any data in the field we need a fifth byte.
   {
     absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+    EXPECT_CALL(test_sink, Send).Times(0);
     EXPECT_CALL(test_sink,
                 Send(AllOf(ENCODED_MESSAGE(HasOneStrThat(
                                AllOf(SizeIs(longest_fit), Each(Eq('x'))))),
@@ -2097,6 +2195,7 @@
   }
   {
     absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+    EXPECT_CALL(test_sink, Send).Times(0);
     EXPECT_CALL(test_sink,
                 Send(AllOf(ENCODED_MESSAGE(HasOneStrThat(
                                AllOf(SizeIs(longest_fit - 1), Each(Eq('x'))))),
@@ -2108,6 +2207,7 @@
   }
   {
     absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+    EXPECT_CALL(test_sink, Send).Times(0);
     EXPECT_CALL(test_sink,
                 Send(AllOf(ENCODED_MESSAGE(HasOneStrThat(
                                AllOf(SizeIs(longest_fit - 2), Each(Eq('x'))))),
@@ -2119,6 +2219,7 @@
   }
   {
     absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+    EXPECT_CALL(test_sink, Send).Times(0);
     EXPECT_CALL(test_sink,
                 Send(AllOf(ENCODED_MESSAGE(HasOneStrThat(
                                AllOf(SizeIs(longest_fit - 3), Each(Eq('x'))))),
@@ -2130,6 +2231,7 @@
   }
   {
     absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+    EXPECT_CALL(test_sink, Send).Times(0);
     EXPECT_CALL(test_sink,
                 Send(AllOf(ENCODED_MESSAGE(HasOneStrThat(
                                AllOf(SizeIs(longest_fit - 4), Each(Eq('x'))))),
@@ -2143,6 +2245,7 @@
   }
   {
     absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+    EXPECT_CALL(test_sink, Send).Times(0);
     EXPECT_CALL(
         test_sink,
         Send(AllOf(ENCODED_MESSAGE(HasTwoStrsThat(
diff --git a/absl/log/log_modifier_methods_test.cc b/absl/log/log_modifier_methods_test.cc
index 4cee0c0..7893557 100644
--- a/absl/log/log_modifier_methods_test.cc
+++ b/absl/log/log_modifier_methods_test.cc
@@ -60,6 +60,7 @@
 
 TEST(TailCallsModifiesTest, AtLocationFileLine) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(
       test_sink,
@@ -89,6 +90,7 @@
 
 TEST(TailCallsModifiesTest, NoPrefix) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(test_sink, Send(AllOf(Prefix(IsFalse()), TextPrefix(IsEmpty()),
                                     TextMessageWithPrefix(Eq("hello world")))));
@@ -99,6 +101,7 @@
 
 TEST(TailCallsModifiesTest, NoPrefixNoMessageNoShirtNoShoesNoService) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(test_sink,
               Send(AllOf(Prefix(IsFalse()), TextPrefix(IsEmpty()),
@@ -110,6 +113,7 @@
 
 TEST(TailCallsModifiesTest, WithVerbosity) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(test_sink, Send(Verbosity(Eq(2))));
 
@@ -119,6 +123,7 @@
 
 TEST(TailCallsModifiesTest, WithVerbosityNoVerbosity) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(test_sink,
               Send(Verbosity(Eq(absl::LogEntry::kNoVerbosityLevel))));
@@ -130,6 +135,7 @@
 
 TEST(TailCallsModifiesTest, WithTimestamp) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(test_sink, Send(Timestamp(Eq(absl::UnixEpoch()))));
 
@@ -139,6 +145,7 @@
 
 TEST(TailCallsModifiesTest, WithThreadID) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(test_sink,
               Send(AllOf(ThreadID(Eq(absl::LogEntry::tid_t{1234})))));
@@ -157,6 +164,7 @@
   } forwarding_sink;
 
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(
       test_sink,
@@ -185,6 +193,7 @@
 
 TEST(TailCallsModifiesTest, WithPerror) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(
       test_sink,
@@ -211,6 +220,7 @@
       {
         absl::ScopedMockLog test_sink(
             absl::MockLogDefault::kDisallowUnexpected);
+        EXPECT_CALL(test_sink, Send).Times(0);
 
         auto do_log = [&test_sink] {
           LOG(QFATAL).ToSinkOnly(&test_sink.UseAsLocalSink()) << "hello world";
diff --git a/absl/log/log_streamer_test.cc b/absl/log/log_streamer_test.cc
index 4fe88e9..f226fef 100644
--- a/absl/log/log_streamer_test.cc
+++ b/absl/log/log_streamer_test.cc
@@ -66,6 +66,7 @@
 
 TEST(LogStreamerTest, LogInfoStreamer) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(
       test_sink,
@@ -87,6 +88,7 @@
 
 TEST(LogStreamerTest, LogWarningStreamer) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(
       test_sink,
@@ -109,6 +111,7 @@
 
 TEST(LogStreamerTest, LogErrorStreamer) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(
       test_sink,
@@ -133,6 +136,7 @@
   EXPECT_EXIT(
       {
         absl::ScopedMockLog test_sink;
+        EXPECT_CALL(test_sink, Send).Times(0);
 
         EXPECT_CALL(test_sink, Send)
             .Times(AnyNumber())
@@ -164,6 +168,7 @@
 #ifdef NDEBUG
 TEST(LogStreamerTest, LogDebugFatalStreamer) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(
       test_sink,
@@ -188,6 +193,7 @@
   EXPECT_EXIT(
       {
         absl::ScopedMockLog test_sink;
+        EXPECT_CALL(test_sink, Send).Times(0);
 
         EXPECT_CALL(test_sink, Send)
             .Times(AnyNumber())
@@ -218,6 +224,7 @@
 
 TEST(LogStreamerTest, LogStreamer) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(
       test_sink,
@@ -244,6 +251,7 @@
   EXPECT_EXIT(
       {
         absl::ScopedMockLog test_sink;
+        EXPECT_CALL(test_sink, Send).Times(0);
 
         EXPECT_CALL(test_sink, Send)
             .Times(AnyNumber())
@@ -275,6 +283,7 @@
 
 TEST(LogStreamerTest, PassedByReference) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(
       test_sink,
@@ -291,6 +300,7 @@
 
 TEST(LogStreamerTest, StoredAsLocal) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   auto streamer = absl::LogInfoStreamer("path/file.cc", 1234);
   WriteToStream("foo", &streamer.stream());
@@ -328,6 +338,7 @@
 
 TEST(LogStreamerTest, LogsEmptyLine) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(test_sink, Send(AllOf(SourceFilename(Eq("path/file.cc")),
                                     SourceLine(Eq(1234)), TextMessage(Eq("")),
@@ -345,8 +356,7 @@
   EXPECT_EXIT(
       {
         absl::ScopedMockLog test_sink;
-
-        EXPECT_CALL(test_sink, Log)
+        EXPECT_CALL(test_sink, Send)
             .Times(AnyNumber())
             .WillRepeatedly(DeathTestUnexpectedLogging());
 
@@ -368,6 +378,7 @@
 
 TEST(LogStreamerTest, MoveConstruction) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   EXPECT_CALL(
       test_sink,
@@ -389,6 +400,7 @@
 
 TEST(LogStreamerTest, MoveAssignment) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   testing::InSequence seq;
   EXPECT_CALL(
@@ -423,6 +435,7 @@
 
 TEST(LogStreamerTest, CorrectDefaultFlags) {
   absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+  EXPECT_CALL(test_sink, Send).Times(0);
 
   // The `boolalpha` and `showbase` flags should be set by default, to match
   // `LOG`.
diff --git a/absl/log/scoped_mock_log.h b/absl/log/scoped_mock_log.h
index a383066..9700873 100644
--- a/absl/log/scoped_mock_log.h
+++ b/absl/log/scoped_mock_log.h
@@ -160,7 +160,13 @@
   // from the log message text, log message path and log message severity.
   //
   // If no expectations are specified for this mock, the default action is to
-  // forward the call to the `Log` mock.
+  // forward the call to the `Log` mock.  Tests using `Send` are advised to call
+  //
+  //   `EXPECT_CALL(sink, Send).Times(0);`
+  //
+  // prior to specifying other expectations to suppress forwarding to `Log`.
+  // That way, unexpected calls show up as calls to `Send` with complete data
+  // and metadata for easier debugging.
   MOCK_METHOD(void, Send, (const absl::LogEntry&));
 
   // Implements the mock method:
diff --git a/absl/log/structured_test.cc b/absl/log/structured_test.cc
index 9fe0756..cde8199 100644
--- a/absl/log/structured_test.cc
+++ b/absl/log/structured_test.cc
@@ -50,6 +50,7 @@
   stream << LoggingDefaults << absl::LogAsLiteral(not_a_literal);
 
   absl::ScopedMockLog sink;
+  EXPECT_CALL(sink, Send).Times(0);
 
   EXPECT_CALL(sink, Send(AllOf(TextMessage(MatchesOstream(stream)),
                                TextMessage(Eq("hello world")),
diff --git a/absl/memory/BUILD.bazel b/absl/memory/BUILD.bazel
index d50a502..81e12fa 100644
--- a/absl/memory/BUILD.bazel
+++ b/absl/memory/BUILD.bazel
@@ -14,6 +14,8 @@
 # limitations under the License.
 #
 
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
diff --git a/absl/meta/BUILD.bazel b/absl/meta/BUILD.bazel
index d01cb8a..26468c6 100644
--- a/absl/meta/BUILD.bazel
+++ b/absl/meta/BUILD.bazel
@@ -14,6 +14,8 @@
 # limitations under the License.
 #
 
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
@@ -33,6 +35,57 @@
 licenses(["notice"])
 
 cc_library(
+    name = "constexpr_testing",
+    testonly = 1,
+    hdrs = ["internal/constexpr_testing.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
+    deps = [
+        "//absl/base:config",
+    ],
+)
+
+cc_test(
+    name = "constexpr_testing_test",
+    srcs = ["internal/constexpr_testing_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":constexpr_testing",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
+
+cc_library(
+    name = "requires",
+    hdrs = ["internal/requires.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
+    deps = [
+        "//absl/base:config",
+    ],
+)
+
+cc_test(
+    name = "requires_test",
+    srcs = ["internal/requires_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":requires",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
+
+cc_library(
     name = "type_traits",
     hdrs = ["type_traits.h"],
     copts = ABSL_DEFAULT_COPTS,
diff --git a/absl/meta/CMakeLists.txt b/absl/meta/CMakeLists.txt
index d509114..c98c360 100644
--- a/absl/meta/CMakeLists.txt
+++ b/absl/meta/CMakeLists.txt
@@ -16,6 +16,52 @@
 
 absl_cc_library(
   NAME
+    constexpr_testing_internal
+  HDRS
+    "internal/constexpr_testing.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::config
+)
+
+absl_cc_test(
+  NAME
+    constexpr_testing_test
+  SRCS
+    "internal/constexpr_testing_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::constexpr_testing_internal
+    GTest::gmock_main
+)
+
+absl_cc_library(
+  NAME
+    requires_internal
+  HDRS
+    "internal/requires.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::config
+)
+
+absl_cc_test(
+  NAME
+    requires_test
+  SRCS
+    "internal/requires_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::requires_internal
+    GTest::gmock_main
+)
+
+absl_cc_library(
+  NAME
     type_traits
   HDRS
     "type_traits.h"
diff --git a/absl/meta/internal/constexpr_testing.h b/absl/meta/internal/constexpr_testing.h
new file mode 100644
index 0000000..eddf64b
--- /dev/null
+++ b/absl/meta/internal/constexpr_testing.h
@@ -0,0 +1,73 @@
+// Copyright 2025 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.
+
+#ifndef ABSL_META_INTERNAL_CONSTEXPR_TESTING_H_
+#define ABSL_META_INTERNAL_CONSTEXPR_TESTING_H_
+
+#include <type_traits>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace meta_internal {
+
+// HasConstexprEvaluation([] { ... }) will evaluate to `true` if the
+// lambda can be evaluated in a constant expression and `false`
+// otherwise.
+// The return type of the lambda is not relevant, as long as the whole
+// evaluation works in a constant expression.
+template <typename F>
+constexpr bool HasConstexprEvaluation(F f);
+
+/// Implementation details below ///
+
+namespace internal_constexpr_evaluation {
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wuninitialized"
+#endif
+// This will give a constexpr instance of `F`.
+// This works for captureless lambdas because they have no state and the copy
+// constructor does not look at the input reference.
+template <typename F>
+constexpr F default_instance = default_instance<F>;
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+template <typename F>
+constexpr std::integral_constant<bool, (default_instance<F>(), true)> Tester(
+    int) {
+  return {};
+}
+
+template <typename S>
+constexpr std::false_type Tester(char) {
+  return {};
+}
+
+}  // namespace internal_constexpr_evaluation
+
+template <typename F>
+constexpr bool HasConstexprEvaluation(F) {
+  return internal_constexpr_evaluation::Tester<F>(0);
+}
+
+}  // namespace meta_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_META_INTERNAL_CONSTEXPR_TESTING_H_
diff --git a/absl/meta/internal/constexpr_testing_test.cc b/absl/meta/internal/constexpr_testing_test.cc
new file mode 100644
index 0000000..50c8c53
--- /dev/null
+++ b/absl/meta/internal/constexpr_testing_test.cc
@@ -0,0 +1,40 @@
+// Copyright 2025 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/meta/internal/constexpr_testing.h"
+
+#include <map>
+#include <string_view>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+TEST(ConstexprTesting, Basic) {
+  using absl::meta_internal::HasConstexprEvaluation;
+
+  EXPECT_TRUE(HasConstexprEvaluation([] {}));
+  static constexpr int const_global = 7;
+  EXPECT_TRUE(HasConstexprEvaluation([] { return const_global; }));
+  EXPECT_TRUE(HasConstexprEvaluation([] { return 0; }));
+  EXPECT_TRUE(HasConstexprEvaluation([] { return std::string_view{}; }));
+
+  static int nonconst_global;
+  EXPECT_FALSE(HasConstexprEvaluation([] { return nonconst_global; }));
+  EXPECT_FALSE(HasConstexprEvaluation([] { std::abort(); }));
+  EXPECT_FALSE(HasConstexprEvaluation([] { return std::map<int, int>(); }));
+}
+
+}  // namespace
diff --git a/absl/meta/internal/requires.h b/absl/meta/internal/requires.h
new file mode 100644
index 0000000..2166e99
--- /dev/null
+++ b/absl/meta/internal/requires.h
@@ -0,0 +1,67 @@
+// Copyright 2017 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.
+
+#ifndef ABSL_META_INTERNAL_REQUIRES_H_
+#define ABSL_META_INTERNAL_REQUIRES_H_
+
+#include <type_traits>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace meta_internal {
+
+// C++17 port of the C++20 `requires` expressions.
+// It allows easy inline test of properties of types in template code.
+// https://en.cppreference.com/w/cpp/language/constraints#Requires_expressions
+//
+// Example usage:
+//
+// if constexpr (Requires<T>([](auto&& x) -> decltype(x.foo()) {})) {
+//   // T has foo()
+//   return t.foo();
+// } else if constexpr (Requires<T>([](auto&& x) -> decltype(Bar(x)) {})) {
+//   // Can call Bar with T
+//   return Bar(t);
+// } else if constexpr (Requires<T, U>(
+//     // Can test expression with multiple inputs
+//     [](auto&& x, auto&& y) -> decltype(x + y) {})) {
+//   return t + t2;
+// }
+//
+// The `Requires` function takes a list of types and a generic lambda where all
+// arguments are of type `auto&&`. The lambda is never actually invoked and the
+// body must be empty.
+// When used this way, `Requires` returns whether the expression inside
+// `decltype` is well-formed, when the lambda parameters have the types that
+// are specified by the corresponding template arguments.
+//
+// NOTE: C++17 does not allow lambdas in template parameters, which means that
+// code like the following is _not_ valid in C++17:
+//
+//  template <typename T,
+//            typename = std::enable_if_t<gtl::Requires<T>(
+//              [] (auto&& v) -> decltype(<expr>) {})>>
+//
+template <typename... T, typename F>
+constexpr bool Requires(F) {
+  return std::is_invocable_v<F, T...>;
+}
+
+}  // namespace meta_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_META_INTERNAL_REQUIRES_H_
diff --git a/absl/meta/internal/requires_test.cc b/absl/meta/internal/requires_test.cc
new file mode 100644
index 0000000..046d8f3
--- /dev/null
+++ b/absl/meta/internal/requires_test.cc
@@ -0,0 +1,66 @@
+// Copyright 2017 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/meta/internal/requires.h"
+
+#include <string>
+#include <vector>
+
+#include "gtest/gtest.h"
+
+namespace {
+
+TEST(RequiresTest, SimpleLambdasWork) {
+  static_assert(absl::meta_internal::Requires([] {}));
+  static_assert(absl::meta_internal::Requires<int>([](auto&&) {}));
+  static_assert(
+      absl::meta_internal::Requires<int, char>([](auto&&, auto&&) {}));
+}
+
+template <typename T>
+inline constexpr bool has_cstr =
+    absl::meta_internal::Requires<T>([](auto&& x) -> decltype(x.c_str()) {});
+
+template <typename T, typename U>
+inline constexpr bool have_plus = absl::meta_internal::Requires<T, U>(
+    [](auto&& x, auto&& y) -> decltype(x + y) {});
+
+TEST(RequiresTest, CanTestProperties) {
+  static_assert(has_cstr<std::string>);
+  static_assert(!has_cstr<std::vector<int>>);
+
+  static_assert(have_plus<int, double>);
+  static_assert(have_plus<std::string, std::string>);
+  static_assert(!have_plus<std::string, double>);
+}
+
+TEST(RequiresTest, WorksWithUnmovableTypes) {
+  struct S {
+    S(const S&) = delete;
+    int foo() { return 0; }
+  };
+  static_assert(
+      absl::meta_internal::Requires<S>([](auto&& x) -> decltype(x.foo()) {}));
+  static_assert(
+      !absl::meta_internal::Requires<S>([](auto&& x) -> decltype(x.bar()) {}));
+}
+
+TEST(RequiresTest, WorksWithArrays) {
+  static_assert(
+      absl::meta_internal::Requires<int[2]>([](auto&& x) -> decltype(x[1]) {}));
+  static_assert(
+      !absl::meta_internal::Requires<int[2]>([](auto&& x) -> decltype(-x) {}));
+}
+
+}  // namespace
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h
index 02c1e63..59eb38b 100644
--- a/absl/meta/type_traits.h
+++ b/absl/meta/type_traits.h
@@ -40,6 +40,7 @@
 #include <string>
 #include <string_view>
 #include <type_traits>
+#include <utility>
 #include <vector>
 
 #include "absl/base/attributes.h"
@@ -168,6 +169,28 @@
 using remove_cvref_t = typename remove_cvref<T>::type;
 #endif
 
+#if defined(__cpp_lib_type_identity) && __cpp_lib_type_identity >= 201806L
+template <typename T>
+using type_identity = std::type_identity<T>;
+
+template <typename T>
+using type_identity_t = std::type_identity_t<T>;
+#else
+// type_identity
+//
+// Back-fill of C++20's `std::type_identity`.
+template <typename T>
+struct type_identity {
+  typedef T type;
+};
+
+// type_identity_t
+//
+// Back-fill of C++20's `std::type_identity_t`.
+template <typename T>
+using type_identity_t = typename type_identity<T>::type;
+#endif
+
 namespace type_traits_internal {
 
 #if (defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703L) || \
@@ -451,7 +474,7 @@
 
 // Detects if a class's definition has declared itself to be an owner by
 // declaring
-//   using absl_internal_is_view = std::true_type;
+//   using absl_internal_is_view = std::false_type;
 // as a member.
 // Types that don't want either must either omit this declaration entirely, or
 // (if e.g. inheriting from a base class) define the member to something that
@@ -479,6 +502,17 @@
 template <typename T>
 struct IsOwner : IsOwnerImpl<T> {};
 
+// This allows incomplete types to be used for associative containers, and also
+// expands the set of types we can handle to include std::pair.
+template <typename T1, typename T2>
+struct IsOwner<std::pair<T1, T2>>
+    : std::integral_constant<
+          bool, std::conditional_t<std::is_reference_v<T1>, std::false_type,
+                                   IsOwner<std::remove_cv_t<T1>>>::value &&
+                    std::conditional_t<std::is_reference_v<T2>, std::false_type,
+                                       IsOwner<std::remove_cv_t<T2>>>::value> {
+};
+
 template <typename T, typename Traits, typename Alloc>
 struct IsOwner<std::basic_string<T, Traits, Alloc>> : std::true_type {};
 
@@ -513,6 +547,13 @@
 struct IsView : std::integral_constant<bool, std::is_pointer<T>::value ||
                                                  IsViewImpl<T>::value> {};
 
+// This allows incomplete types to be used for associative containers, and also
+// expands the set of types we can handle to include std::pair.
+template <typename T1, typename T2>
+struct IsView<std::pair<T1, T2>>
+    : std::integral_constant<bool, IsView<std::remove_cv_t<T1>>::value &&
+                                       IsView<std::remove_cv_t<T2>>::value> {};
+
 template <typename Char, typename Traits>
 struct IsView<std::basic_string_view<Char, Traits>> : std::true_type {};
 
diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc
index 3d55a00..9a8262d 100644
--- a/absl/meta/type_traits_test.cc
+++ b/absl/meta/type_traits_test.cc
@@ -36,6 +36,9 @@
     absl::conjunction<absl::type_traits_internal::IsOwner<T>,
                       absl::negation<absl::type_traits_internal::IsView<T>>>;
 
+static_assert(
+    IsOwnerAndNotView<std::pair<std::vector<int>, std::string>>::value,
+    "pair of owners is an owner, not a view");
 static_assert(IsOwnerAndNotView<std::vector<int>>::value,
               "vector is an owner, not a view");
 static_assert(IsOwnerAndNotView<std::string>::value,
@@ -134,6 +137,17 @@
                             int[2]>::value));
 }
 
+TEST(TypeTraitsTest, TestTypeIdentity) {
+  EXPECT_TRUE((std::is_same_v<typename absl::type_identity<int>::type, int>));
+  EXPECT_TRUE((std::is_same_v<absl::type_identity_t<int>, int>));
+  EXPECT_TRUE((std::is_same_v<typename absl::type_identity<int&>::type, int&>));
+  EXPECT_TRUE((std::is_same_v<absl::type_identity_t<int&>, int&>));
+
+  EXPECT_FALSE(
+      (std::is_same_v<typename absl::type_identity<int64_t>::type, int32_t>));
+  EXPECT_FALSE((std::is_same_v<absl::type_identity_t<int64_t>, int32_t>));
+}
+
 struct TypeA {};
 struct TypeB {};
 struct TypeC {};
diff --git a/absl/numeric/BUILD.bazel b/absl/numeric/BUILD.bazel
index f455d1e..edfe6b6 100644
--- a/absl/numeric/BUILD.bazel
+++ b/absl/numeric/BUILD.bazel
@@ -12,6 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
diff --git a/absl/numeric/bits_test.cc b/absl/numeric/bits_test.cc
index 3b71ccc..e2c6409 100644
--- a/absl/numeric/bits_test.cc
+++ b/absl/numeric/bits_test.cc
@@ -27,15 +27,36 @@
 namespace {
 
 template <typename IntT>
+class UnsignedIntegerTypesTest : public ::testing::Test {};
+template <typename IntT>
 class IntegerTypesTest : public ::testing::Test {};
 
+using UnsignedIntegerTypes =
+    ::testing::Types<uint8_t, uint16_t, uint32_t, uint64_t>;
 using OneByteIntegerTypes = ::testing::Types<
     unsigned char,
     uint8_t
     >;
 
+TYPED_TEST_SUITE(UnsignedIntegerTypesTest, UnsignedIntegerTypes);
 TYPED_TEST_SUITE(IntegerTypesTest, OneByteIntegerTypes);
 
+TYPED_TEST(UnsignedIntegerTypesTest, ReturnTypes) {
+  using UIntType = TypeParam;
+
+  static_assert(std::is_same_v<decltype(byteswap(UIntType{0})), UIntType>);
+  static_assert(std::is_same_v<decltype(rotl(UIntType{0}, 0)), UIntType>);
+  static_assert(std::is_same_v<decltype(rotr(UIntType{0}, 0)), UIntType>);
+  static_assert(std::is_same_v<decltype(countl_zero(UIntType{0})), int>);
+  static_assert(std::is_same_v<decltype(countl_one(UIntType{0})), int>);
+  static_assert(std::is_same_v<decltype(countr_zero(UIntType{0})), int>);
+  static_assert(std::is_same_v<decltype(countr_one(UIntType{0})), int>);
+  static_assert(std::is_same_v<decltype(popcount(UIntType{0})), int>);
+  static_assert(std::is_same_v<decltype(bit_ceil(UIntType{0})), UIntType>);
+  static_assert(std::is_same_v<decltype(bit_floor(UIntType{0})), UIntType>);
+  static_assert(std::is_same_v<decltype(bit_width(UIntType{0})), int>);
+}
+
 TYPED_TEST(IntegerTypesTest, HandlesTypes) {
   using UIntType = TypeParam;
 
@@ -130,6 +151,9 @@
   EXPECT_EQ(rotl(uint32_t{0x12345678UL}, -4), uint32_t{0x81234567UL});
   EXPECT_EQ(rotl(uint64_t{0x12345678ABCDEF01ULL}, -4),
             uint64_t{0x112345678ABCDEF0ULL});
+
+  EXPECT_EQ(rotl(uint32_t{1234}, std::numeric_limits<int>::min()),
+            uint32_t{1234});
 }
 
 TEST(Rotate, Right) {
@@ -169,6 +193,9 @@
   EXPECT_EQ(rotr(uint32_t{0x12345678UL}, -4), uint32_t{0x23456781UL});
   EXPECT_EQ(rotr(uint64_t{0x12345678ABCDEF01ULL}, -4),
             uint64_t{0x2345678ABCDEF011ULL});
+
+  EXPECT_EQ(rotl(uint32_t{1234}, std::numeric_limits<int>::min()),
+            uint32_t{1234});
 }
 
 TEST(Rotate, Symmetry) {
diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h
index ae736b2..32603b0 100644
--- a/absl/numeric/int128.h
+++ b/absl/numeric/int128.h
@@ -164,9 +164,9 @@
   constexpr explicit operator __int128() const;
   constexpr explicit operator unsigned __int128() const;
 #endif  // ABSL_HAVE_INTRINSIC_INT128
-  explicit operator float() const;
-  explicit operator double() const;
-  explicit operator long double() const;
+  constexpr explicit operator float() const;
+  constexpr explicit operator double() const;
+  constexpr explicit operator long double() const;
 
   // Trivial copy constructor, assignment operator and destructor.
 
@@ -357,14 +357,18 @@
   constexpr int128(unsigned long v);       // NOLINT(runtime/int)
   constexpr int128(long long v);           // NOLINT(runtime/int)
   constexpr int128(unsigned long long v);  // NOLINT(runtime/int)
+  constexpr explicit int128(uint128 v);
 #ifdef ABSL_HAVE_INTRINSIC_INT128
   constexpr int128(__int128 v);  // NOLINT(runtime/explicit)
   constexpr explicit int128(unsigned __int128 v);
-#endif  // ABSL_HAVE_INTRINSIC_INT128
-  constexpr explicit int128(uint128 v);
+  constexpr explicit int128(float v);
+  constexpr explicit int128(double v);
+  constexpr explicit int128(long double v);
+#else
   explicit int128(float v);
   explicit int128(double v);
   explicit int128(long double v);
+#endif  // ABSL_HAVE_INTRINSIC_INT128
 
   // Assignment operators from arithmetic types
   int128& operator=(int v);
@@ -401,9 +405,9 @@
   constexpr explicit operator __int128() const;
   constexpr explicit operator unsigned __int128() const;
 #endif  // ABSL_HAVE_INTRINSIC_INT128
-  explicit operator float() const;
-  explicit operator double() const;
-  explicit operator long double() const;
+  constexpr explicit operator float() const;
+  constexpr explicit operator double() const;
+  constexpr explicit operator long double() const;
 
   // Trivial copy constructor, assignment operator and destructor.
 
@@ -609,9 +613,15 @@
 constexpr uint128 operator>>(uint128 lhs, int amount);
 constexpr uint128 operator+(uint128 lhs, uint128 rhs);
 constexpr uint128 operator-(uint128 lhs, uint128 rhs);
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+constexpr uint128 operator*(uint128 lhs, uint128 rhs);
+constexpr uint128 operator/(uint128 lhs, uint128 rhs);
+constexpr uint128 operator%(uint128 lhs, uint128 rhs);
+#else   // ABSL_HAVE_INTRINSIC_INT128
 uint128 operator*(uint128 lhs, uint128 rhs);
 uint128 operator/(uint128 lhs, uint128 rhs);
 uint128 operator%(uint128 lhs, uint128 rhs);
+#endif  // ABSL_HAVE_INTRINSIC_INT128
 
 inline uint128& uint128::operator<<=(int amount) {
   *this = *this << amount;
@@ -788,18 +798,18 @@
 
 // Conversion operators to floating point types.
 
-inline uint128::operator float() const {
+constexpr uint128::operator float() const {
   // Note: This method might return Inf.
   constexpr float pow_2_64 = 18446744073709551616.0f;
   return static_cast<float>(lo_) + static_cast<float>(hi_) * pow_2_64;
 }
 
-inline uint128::operator double() const {
+constexpr uint128::operator double() const {
   constexpr double pow_2_64 = 18446744073709551616.0;
   return static_cast<double>(lo_) + static_cast<double>(hi_) * pow_2_64;
 }
 
-inline uint128::operator long double() const {
+constexpr uint128::operator long double() const {
   constexpr long double pow_2_64 = 18446744073709551616.0L;
   return static_cast<long double>(lo_) +
          static_cast<long double>(hi_) * pow_2_64;
@@ -1021,19 +1031,15 @@
 #endif
 }
 
+#if !defined(ABSL_HAVE_INTRINSIC_INT128)
 inline uint128 operator*(uint128 lhs, uint128 rhs) {
-#if defined(ABSL_HAVE_INTRINSIC_INT128)
-  // TODO(strel) Remove once alignment issues are resolved and unsigned __int128
-  // can be used for uint128 storage.
-  return static_cast<unsigned __int128>(lhs) *
-         static_cast<unsigned __int128>(rhs);
-#elif defined(_MSC_VER) && defined(_M_X64) && !defined(_M_ARM64EC)
+#if defined(_MSC_VER) && defined(_M_X64) && !defined(_M_ARM64EC)
   uint64_t carry;
   uint64_t low = _umul128(Uint128Low64(lhs), Uint128Low64(rhs), &carry);
   return MakeUint128(Uint128Low64(lhs) * Uint128High64(rhs) +
                          Uint128High64(lhs) * Uint128Low64(rhs) + carry,
                      low);
-#else   // ABSL_HAVE_INTRINSIC128
+#else   // _MSC_VER
   uint64_t a32 = Uint128Low64(lhs) >> 32;
   uint64_t a00 = Uint128Low64(lhs) & 0xffffffff;
   uint64_t b32 = Uint128Low64(rhs) >> 32;
@@ -1045,16 +1051,24 @@
   result += uint128(a32 * b00) << 32;
   result += uint128(a00 * b32) << 32;
   return result;
-#endif  // ABSL_HAVE_INTRINSIC128
+#endif  // _MSC_VER
 }
+#endif  // ABSL_HAVE_INTRINSIC_INT128
 
 #if defined(ABSL_HAVE_INTRINSIC_INT128)
-inline uint128 operator/(uint128 lhs, uint128 rhs) {
+constexpr uint128 operator*(uint128 lhs, uint128 rhs) {
+  // TODO(strel) Remove once alignment issues are resolved and unsigned __int128
+  // can be used for uint128 storage.
+  return static_cast<unsigned __int128>(lhs) *
+         static_cast<unsigned __int128>(rhs);
+}
+
+constexpr uint128 operator/(uint128 lhs, uint128 rhs) {
   return static_cast<unsigned __int128>(lhs) /
          static_cast<unsigned __int128>(rhs);
 }
 
-inline uint128 operator%(uint128 lhs, uint128 rhs) {
+constexpr uint128 operator%(uint128 lhs, uint128 rhs) {
   return static_cast<unsigned __int128>(lhs) %
          static_cast<unsigned __int128>(rhs);
 }
@@ -1112,9 +1126,15 @@
 constexpr int128 operator-(int128 v);
 constexpr int128 operator+(int128 lhs, int128 rhs);
 constexpr int128 operator-(int128 lhs, int128 rhs);
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+constexpr int128 operator*(int128 lhs, int128 rhs);
+constexpr int128 operator/(int128 lhs, int128 rhs);
+constexpr int128 operator%(int128 lhs, int128 rhs);
+#else
 int128 operator*(int128 lhs, int128 rhs);
 int128 operator/(int128 lhs, int128 rhs);
 int128 operator%(int128 lhs, int128 rhs);
+#endif  // ABSL_HAVE_INTRINSIC_INT128
 constexpr int128 operator|(int128 lhs, int128 rhs);
 constexpr int128 operator&(int128 lhs, int128 rhs);
 constexpr int128 operator^(int128 lhs, int128 rhs);
diff --git a/absl/numeric/int128_have_intrinsic.inc b/absl/numeric/int128_have_intrinsic.inc
index 216115a..dea1d21 100644
--- a/absl/numeric/int128_have_intrinsic.inc
+++ b/absl/numeric/int128_have_intrinsic.inc
@@ -73,17 +73,11 @@
 
 constexpr int128::int128(unsigned __int128 v) : v_{static_cast<__int128>(v)} {}
 
-inline int128::int128(float v) {
-  v_ = static_cast<__int128>(v);
-}
+constexpr int128::int128(float v) : v_{static_cast<__int128>(v)} {}
 
-inline int128::int128(double v) {
-  v_ = static_cast<__int128>(v);
-}
+constexpr int128::int128(double v) : v_{static_cast<__int128>(v)} {}
 
-inline int128::int128(long double v) {
-  v_ = static_cast<__int128>(v);
-}
+constexpr int128::int128(long double v) : v_{static_cast<__int128>(v)} {}
 
 constexpr int128::int128(uint128 v) : v_{static_cast<__int128>(v)} {}
 
@@ -119,9 +113,7 @@
   return static_cast<unsigned short>(v_);            // NOLINT(runtime/int)
 }
 
-constexpr int128::operator int() const {
-  return static_cast<int>(v_);
-}
+constexpr int128::operator int() const { return static_cast<int>(v_); }
 
 constexpr int128::operator unsigned int() const {
   return static_cast<unsigned int>(v_);
@@ -153,17 +145,17 @@
 // conversions. In that case, we do the conversion with a similar implementation
 // to the conversion operators in int128_no_intrinsic.inc.
 #if defined(__clang__) && !defined(__ppc64__)
-inline int128::operator float() const { return static_cast<float>(v_); }
+constexpr int128::operator float() const { return static_cast<float>(v_); }
 
-inline int128::operator double() const { return static_cast<double>(v_); }
+constexpr int128::operator double() const { return static_cast<double>(v_); }
 
-inline int128::operator long double() const {
+constexpr int128::operator long double() const {
   return static_cast<long double>(v_);
 }
 
-#else  // Clang on PowerPC
+#else   // Clang on PowerPC
 
-inline int128::operator float() const {
+constexpr int128::operator float() const {
   // We must convert the absolute value and then negate as needed, because
   // floating point types are typically sign-magnitude. Otherwise, the
   // difference between the high and low 64 bits when interpreted as two's
@@ -177,7 +169,7 @@
                    static_cast<float>(Int128High64(*this)) * pow_2_64;
 }
 
-inline int128::operator double() const {
+constexpr int128::operator double() const {
   // See comment in int128::operator float() above.
   constexpr double pow_2_64 = 18446744073709551616.0;
   return v_ < 0 && *this != Int128Min()
@@ -186,7 +178,7 @@
                    static_cast<double>(Int128High64(*this)) * pow_2_64;
 }
 
-inline int128::operator long double() const {
+constexpr int128::operator long double() const {
   // See comment in int128::operator float() above.
   constexpr long double pow_2_64 = 18446744073709551616.0L;
   return v_ < 0 && *this != Int128Min()
@@ -254,17 +246,19 @@
   return static_cast<__int128>(lhs) - static_cast<__int128>(rhs);
 }
 
-inline int128 operator*(int128 lhs, int128 rhs) {
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+constexpr int128 operator*(int128 lhs, int128 rhs) {
   return static_cast<__int128>(lhs) * static_cast<__int128>(rhs);
 }
 
-inline int128 operator/(int128 lhs, int128 rhs) {
+constexpr int128 operator/(int128 lhs, int128 rhs) {
   return static_cast<__int128>(lhs) / static_cast<__int128>(rhs);
 }
 
-inline int128 operator%(int128 lhs, int128 rhs) {
+constexpr int128 operator%(int128 lhs, int128 rhs) {
   return static_cast<__int128>(lhs) % static_cast<__int128>(rhs);
 }
+#endif  // ABSL_HAVE_INTRINSIC_INT128
 
 inline int128 int128::operator++(int) {
   int128 tmp(*this);
diff --git a/absl/numeric/int128_no_intrinsic.inc b/absl/numeric/int128_no_intrinsic.inc
index a7cdcea..48bec2c 100644
--- a/absl/numeric/int128_no_intrinsic.inc
+++ b/absl/numeric/int128_no_intrinsic.inc
@@ -132,7 +132,7 @@
   return static_cast<unsigned long long>(lo_);           // NOLINT(runtime/int)
 }
 
-inline int128::operator float() const {
+constexpr int128::operator float() const {
   // We must convert the absolute value and then negate as needed, because
   // floating point types are typically sign-magnitude. Otherwise, the
   // difference between the high and low 64 bits when interpreted as two's
@@ -142,20 +142,18 @@
   constexpr float pow_2_64 = 18446744073709551616.0f;
   return hi_ < 0 && *this != Int128Min()
              ? -static_cast<float>(-*this)
-             : static_cast<float>(lo_) +
-                   static_cast<float>(hi_) * pow_2_64;
+             : static_cast<float>(lo_) + static_cast<float>(hi_) * pow_2_64;
 }
 
-inline int128::operator double() const {
+constexpr int128::operator double() const {
   // See comment in int128::operator float() above.
   constexpr double pow_2_64 = 18446744073709551616.0;
   return hi_ < 0 && *this != Int128Min()
              ? -static_cast<double>(-*this)
-             : static_cast<double>(lo_) +
-                   static_cast<double>(hi_) * pow_2_64;
+             : static_cast<double>(lo_) + static_cast<double>(hi_) * pow_2_64;
 }
 
-inline int128::operator long double() const {
+constexpr int128::operator long double() const {
   // See comment in int128::operator float() above.
   constexpr long double pow_2_64 = 18446744073709551616.0L;
   return hi_ < 0 && *this != Int128Min()
diff --git a/absl/numeric/int128_test.cc b/absl/numeric/int128_test.cc
index 13a0e7f..77ee63c 100644
--- a/absl/numeric/int128_test.cc
+++ b/absl/numeric/int128_test.cc
@@ -350,7 +350,7 @@
   c = a * b;
   EXPECT_EQ(absl::MakeUint128(0x530EDA741C71D4C3, 0xBF25975319080000), c);
   EXPECT_EQ(0, c - b * a);
-  EXPECT_EQ(a*a - b*b, (a+b) * (a-b));
+  EXPECT_EQ(a * a - b * b, (a + b) * (a - b));
 
   // Verified with dc.
   a = absl::MakeUint128(0x0123456789abcdef, 0xfedcba9876543210);
@@ -358,7 +358,7 @@
   c = a * b;
   EXPECT_EQ(absl::MakeUint128(0x97a87f4f261ba3f2, 0x342d0bbf48948200), c);
   EXPECT_EQ(0, c - b * a);
-  EXPECT_EQ(a*a - b*b, (a+b) * (a-b));
+  EXPECT_EQ(a * a - b * b, (a + b) * (a - b));
 }
 
 TEST(Uint128, AliasTests) {
@@ -462,6 +462,26 @@
   EXPECT_EQ(zero, absl::uint128(0));
   EXPECT_EQ(one, absl::uint128(1));
   EXPECT_EQ(minus_two, absl::MakeUint128(-1, -2));
+
+  constexpr double f = static_cast<float>(absl::uint128(123));
+  EXPECT_EQ(f, 123.0f);
+
+  constexpr double d = static_cast<double>(absl::uint128(123));
+  EXPECT_EQ(d, 123.0);
+
+  constexpr long double ld = static_cast<long double>(absl::uint128(123));
+  EXPECT_EQ(ld, 123.0);
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  constexpr absl::uint128 division = absl::uint128(10) / absl::uint128(2);
+  EXPECT_EQ(division, absl::uint128(5));
+
+  constexpr absl::uint128 modulus = absl::int128(10) % absl::int128(3);
+  EXPECT_EQ(modulus, absl::uint128(1));
+
+  constexpr absl::uint128 multiplication = absl::uint128(10) * absl::uint128(3);
+  EXPECT_EQ(multiplication, absl::uint128(30));
+#endif  // ABSL_HAVE_INTRINSIC_INT128
 }
 
 TEST(Uint128, NumericLimitsTest) {
@@ -522,7 +542,6 @@
   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(values));
 }
 
-
 TEST(Int128Uint128, ConversionTest) {
   absl::int128 nonnegative_signed_values[] = {
       0,
@@ -540,8 +559,7 @@
   }
 
   absl::int128 negative_values[] = {
-      -1, -0x1234567890abcdef,
-      absl::MakeInt128(-0x5544332211ffeedd, 0),
+      -1, -0x1234567890abcdef, absl::MakeInt128(-0x5544332211ffeedd, 0),
       -absl::MakeInt128(0x76543210fedcba98, 0xabcdef0123456789)};
   for (absl::int128 value : negative_values) {
     EXPECT_EQ(absl::uint128(-value), -absl::uint128(value));
@@ -769,6 +787,35 @@
   EXPECT_EQ(minus_two, absl::MakeInt128(-1, -2));
   EXPECT_GT(max, one);
   EXPECT_LT(min, minus_two);
+
+  constexpr double f = static_cast<float>(absl::int128(123));
+  EXPECT_EQ(f, 123.0f);
+
+  constexpr double d = static_cast<double>(absl::int128(123));
+  EXPECT_EQ(d, 123.0);
+
+  constexpr long double ld = static_cast<long double>(absl::int128(123));
+  EXPECT_EQ(ld, 123.0);
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  constexpr absl::int128 f_int128(static_cast<float>(123.0));
+  EXPECT_EQ(f_int128, absl::int128(123));
+
+  constexpr absl::int128 d_int128(static_cast<double>(123.0));
+  EXPECT_EQ(d_int128, absl::int128(123));
+
+  constexpr absl::int128 ld_int128(static_cast<long double>(123.0));
+  EXPECT_EQ(ld_int128, absl::int128(123));
+
+  constexpr absl::int128 division = absl::int128(10) / absl::int128(2);
+  EXPECT_EQ(division, absl::int128(5));
+
+  constexpr absl::int128 modulus = absl::int128(10) % absl::int128(3);
+  EXPECT_EQ(modulus, absl::int128(1));
+
+  constexpr absl::int128 multiplication = absl::int128(10) * absl::int128(3);
+  EXPECT_EQ(multiplication, absl::int128(30));
+#endif  // ABSL_HAVE_INTRINSIC_INT128
 }
 
 TEST(Int128, ComparisonTest) {
diff --git a/absl/numeric/internal/bits.h b/absl/numeric/internal/bits.h
index e1d18b8..e681544 100644
--- a/absl/numeric/internal/bits.h
+++ b/absl/numeric/internal/bits.h
@@ -77,8 +77,28 @@
   static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
                 "T must have a power-of-2 size");
 
-  return static_cast<T>(x >> (s & (std::numeric_limits<T>::digits - 1))) |
-         static_cast<T>(x << ((-s) & (std::numeric_limits<T>::digits - 1)));
+  // Rotate by s mod the number of digits to avoid unnecessary rotations.
+  //
+  // A negative s represents a left rotation instead of a right rotation.
+  // We compute it as an equivalent complementary right rotation by leveraging
+  // its two's complement representation.
+  //
+  // For example, suppose we rotate a 3-bit number by -2.
+  // In that case:
+  //   * s = 0b11111111111111111111111111111110
+  //   * n = 8
+  //   * r = (0b11111111111111111111111111111110 & 0b111) = 0b110
+  //
+  // Instead of rotating by 2 to the left, we rotate by 6 to the right, which
+  // is equivalent.
+  const int n = std::numeric_limits<T>::digits;
+  const int r = s & (n - 1);
+
+  if (r == 0) {
+    return x;
+  } else {
+    return (x >> r) | (x << (n - r));
+  }
 }
 
 template <class T>
@@ -88,8 +108,16 @@
   static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
                 "T must have a power-of-2 size");
 
-  return static_cast<T>(x << (s & (std::numeric_limits<T>::digits - 1))) |
-         static_cast<T>(x >> ((-s) & (std::numeric_limits<T>::digits - 1)));
+  // Rotate by s mod the number of digits to avoid unnecessary rotations.
+  // See comment in RotateRight for a detailed explanation of the logic below.
+  const int n = std::numeric_limits<T>::digits;
+  const int r = s & (n - 1);
+
+  if (r == 0) {
+    return x;
+  } else {
+    return (x << r) | (x >> (n - r));
+  }
 }
 
 ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int
diff --git a/absl/profiling/BUILD.bazel b/absl/profiling/BUILD.bazel
index ee4800d..00571b2 100644
--- a/absl/profiling/BUILD.bazel
+++ b/absl/profiling/BUILD.bazel
@@ -12,6 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
@@ -49,6 +52,7 @@
 cc_test(
     name = "sample_recorder_test",
     srcs = ["internal/sample_recorder_test.cc"],
+    copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     tags = [
         "no_test_wasm",
@@ -69,6 +73,7 @@
     name = "exponential_biased",
     srcs = ["internal/exponential_biased.cc"],
     hdrs = ["internal/exponential_biased.h"],
+    copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl:__subpackages__",
@@ -139,3 +144,45 @@
         "@google_benchmark//:benchmark_main",
     ],
 )
+
+cc_library(
+    name = "profile_builder",
+    srcs = ["internal/profile_builder.cc"],
+    hdrs = ["internal/profile_builder.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
+    deps = [
+        "//absl/base",
+        "//absl/base:config",
+        "//absl/base:raw_logging_internal",
+        "//absl/container:btree",
+        "//absl/container:flat_hash_map",
+        "//absl/strings",
+        "//absl/strings:str_format",
+        "//absl/types:span",
+    ],
+)
+
+cc_library(
+    name = "hashtable",
+    srcs = ["hashtable.cc"],
+    hdrs = ["hashtable.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
+    deps = [
+        ":profile_builder",
+        "//absl/base:config",
+        "//absl/container:hashtablez_sampler",
+        "//absl/status:statusor",
+        "//absl/strings",
+        "//absl/strings:string_view",
+        "//absl/time",
+        "//absl/types:span",
+    ],
+)
diff --git a/absl/profiling/CMakeLists.txt b/absl/profiling/CMakeLists.txt
index 84b8b3b..6441dae 100644
--- a/absl/profiling/CMakeLists.txt
+++ b/absl/profiling/CMakeLists.txt
@@ -92,3 +92,41 @@
     GTest::gmock_main
 )
 
+# Internal-only target, do not depend on directly
+absl_cc_library(
+  NAME
+    profile_builder
+  HDRS
+    "internal/profile_builder.h"
+  SRCS
+    "internal/profile_builder.cc"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::config
+    absl::core_headers
+    absl::raw_logging_internal
+    absl::flat_hash_map
+    absl::btree
+    absl::strings
+    absl::str_format
+    absl::span
+)
+
+absl_cc_library(
+  NAME
+    hashtable_profiler
+  HDRS
+    "hashtable.h"
+  SRCS
+    "hashtable.cc"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::profile_builder
+    absl::config
+    absl::core_headers
+    absl::strings
+    absl::span
+    absl::hashtablez_sampler
+)
diff --git a/absl/profiling/hashtable.cc b/absl/profiling/hashtable.cc
new file mode 100644
index 0000000..7c1a839
--- /dev/null
+++ b/absl/profiling/hashtable.cc
@@ -0,0 +1,135 @@
+// Copyright 2025 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/profiling/hashtable.h"
+
+#include <atomic>
+#include <cstddef>
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/base/config.h"
+#include "absl/container/internal/hashtablez_sampler.h"
+#include "absl/profiling/internal/profile_builder.h"
+#include "absl/status/statusor.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "absl/types/span.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+StatusOr<std::string> MarshalHashtableProfile() {
+  return debugging_internal::MarshalHashtableProfile(
+      container_internal::GlobalHashtablezSampler(), Now());
+}
+
+namespace debugging_internal {
+
+static void DroppedHashtableSample() {}
+
+StatusOr<std::string> MarshalHashtableProfile(
+    container_internal::HashtablezSampler& sampler, Time now) {
+  static constexpr absl::string_view kDropFrames =
+      "(::)?absl::container_internal::.*|"
+      "(::)?absl::(flat|node)_hash_(map|set).*";
+
+  ProfileBuilder builder;
+  StringId drop_frames_id = builder.InternString(kDropFrames);
+  builder.set_drop_frames_id(drop_frames_id);
+  builder.AddSampleType(builder.InternString("capacity"),
+                        builder.InternString("count"));
+  builder.set_default_sample_type_id(builder.InternString("capacity"));
+
+  const auto capacity_id = builder.InternString("capacity");
+  const auto size_id = builder.InternString("size");
+  const auto num_erases_id = builder.InternString("num_erases");
+  const auto num_insert_hits_id = builder.InternString("num_insert_hits");
+  const auto num_rehashes_id = builder.InternString("num_rehashes");
+  const auto max_probe_length_id = builder.InternString("max_probe_length");
+  const auto total_probe_length_id = builder.InternString("total_probe_length");
+  const auto stuck_bits_id = builder.InternString("stuck_bits");
+  const auto inline_element_size_id =
+      builder.InternString("inline_element_size");
+  const auto key_size_id = builder.InternString("key_size");
+  const auto value_size_id = builder.InternString("value_size");
+  const auto soo_capacity_id = builder.InternString("soo_capacity");
+  const auto table_age_id = builder.InternString("table_age");
+  const auto max_reserve_id = builder.InternString("max_reserve");
+
+  size_t dropped =
+      sampler.Iterate([&](const container_internal::HashtablezInfo& info) {
+        const size_t capacity = info.capacity.load(std::memory_order_relaxed);
+        std::vector<std::pair<StringId, int64_t>> labels;
+
+        auto add_label = [&](StringId tag, uint64_t value) {
+          if (value == 0) {
+            return;
+          }
+          labels.emplace_back(tag, static_cast<int64_t>(value));
+        };
+
+        add_label(capacity_id, capacity);
+        add_label(size_id, info.size.load(std::memory_order_relaxed));
+        add_label(num_erases_id,
+                  info.num_erases.load(std::memory_order_relaxed));
+        // TODO(b/436909492): Revisit whether this value is useful.
+        add_label(num_insert_hits_id,
+                  info.num_insert_hits.load(std::memory_order_relaxed));
+        add_label(num_rehashes_id,
+                  info.num_rehashes.load(std::memory_order_relaxed));
+        add_label(max_probe_length_id,
+                  info.max_probe_length.load(std::memory_order_relaxed));
+        add_label(total_probe_length_id,
+                  info.total_probe_length.load(std::memory_order_relaxed));
+        add_label(stuck_bits_id,
+                  (info.hashes_bitwise_and.load(std::memory_order_relaxed) |
+                   ~info.hashes_bitwise_or.load(std::memory_order_relaxed)));
+        add_label(inline_element_size_id, info.inline_element_size);
+        add_label(key_size_id, info.key_size);
+        add_label(value_size_id, info.value_size);
+        add_label(soo_capacity_id, info.soo_capacity);
+        add_label(
+            table_age_id,
+            static_cast<uint64_t>(ToInt64Microseconds(now - info.create_time)));
+        add_label(max_reserve_id,
+                  info.max_reserve.load(std::memory_order_relaxed));
+        builder.AddSample(static_cast<int64_t>(capacity) * info.weight,
+                          MakeSpan(info.stack, info.depth), labels);
+      });
+
+  if (dropped > 0) {
+    // If we dropped samples, we don't have information for them, including
+    // their sizes.  The non-zero weight allows it to be noticed in the profile
+    // and examined more closely.
+    //
+    // We compensate for the fixup done by AddSample by adjusting the address
+    // here.
+    const void* kFakeStack[] = {
+      absl::bit_cast<void*>(
+          reinterpret_cast<uintptr_t>(&DroppedHashtableSample)+1)};
+    builder.AddSample(static_cast<int64_t>(dropped), kFakeStack, {});
+  }
+  builder.AddCurrentMappings();
+  return std::move(builder).Emit();
+}
+
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/profiling/hashtable.h b/absl/profiling/hashtable.h
new file mode 100644
index 0000000..9e490dc
--- /dev/null
+++ b/absl/profiling/hashtable.h
@@ -0,0 +1,40 @@
+// Copyright 2025 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.
+
+#ifndef ABSL_PROFILING_HASHTABLE_H_
+#define ABSL_PROFILING_HASHTABLE_H_
+
+#include <cstdint>
+#include <string>
+
+#include "absl/container/internal/hashtablez_sampler.h"
+#include "absl/status/statusor.h"
+#include "absl/strings/string_view.h"
+#include "absl/time/time.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+absl::StatusOr<std::string> MarshalHashtableProfile();
+
+namespace debugging_internal {
+
+absl::StatusOr<std::string> MarshalHashtableProfile(
+    container_internal::HashtablezSampler& sampler, absl::Time now);
+
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_PROFILING_HASHTABLE_H_
diff --git a/absl/profiling/internal/profile_builder.cc b/absl/profiling/internal/profile_builder.cc
new file mode 100644
index 0000000..1ca0d3b
--- /dev/null
+++ b/absl/profiling/internal/profile_builder.cc
@@ -0,0 +1,463 @@
+// Copyright 2025 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/profiling/internal/profile_builder.h"
+
+#ifdef __linux__
+#include <elf.h>
+#include <link.h>
+#endif  // __linux__
+
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/base/casts.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/escaping.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/types/span.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+
+namespace {
+
+// This file contains a simplified implementation of the pprof profile builder,
+// which avoids a dependency on protobuf.
+//
+// The canonical profile proto definition is at
+// https://github.com/google/pprof/blob/master/proto/profile.proto
+//
+// Wire-format encoding is a simple sequence of (tag, value) pairs. The tag
+// is a varint-encoded integer, where the low 3 bits are the wire type, and the
+// high bits are the field number.
+//
+// For the fields we care about, we'll be using the following wire types:
+//
+// Wire Type 0: Varint-encoded integer.
+// Wire Type 2: Length-delimited. Used for strings and sub-messages.
+enum class WireType {
+  kVarint = 0,
+  kLengthDelimited = 2,
+};
+
+#ifdef __linux__
+// Returns the Phdr of the first segment of the given type.
+const ElfW(Phdr) * GetFirstSegment(const dl_phdr_info* const info,
+                                   const ElfW(Word) segment_type) {
+  for (int i = 0; i < info->dlpi_phnum; ++i) {
+    if (info->dlpi_phdr[i].p_type == segment_type) {
+      return &info->dlpi_phdr[i];
+    }
+  }
+  return nullptr;
+}
+
+// Return DT_SONAME for the given image.  If there is no PT_DYNAMIC or if
+// PT_DYNAMIC does not contain DT_SONAME, return nullptr.
+static const char* GetSoName(const dl_phdr_info* const info) {
+  const ElfW(Phdr)* const pt_dynamic = GetFirstSegment(info, PT_DYNAMIC);
+  if (pt_dynamic == nullptr) {
+    return nullptr;
+  }
+  const ElfW(Dyn)* dyn =
+      reinterpret_cast<ElfW(Dyn)*>(info->dlpi_addr + pt_dynamic->p_vaddr);
+  const ElfW(Dyn)* dt_strtab = nullptr;
+  const ElfW(Dyn)* dt_strsz = nullptr;
+  const ElfW(Dyn)* dt_soname = nullptr;
+  for (; dyn->d_tag != DT_NULL; ++dyn) {
+    if (dyn->d_tag == DT_SONAME) {
+      dt_soname = dyn;
+    } else if (dyn->d_tag == DT_STRTAB) {
+      dt_strtab = dyn;
+    } else if (dyn->d_tag == DT_STRSZ) {
+      dt_strsz = dyn;
+    }
+  }
+  if (dt_soname == nullptr) {
+    return nullptr;
+  }
+  ABSL_RAW_CHECK(dt_strtab != nullptr, "Unexpected nullptr");
+  ABSL_RAW_CHECK(dt_strsz != nullptr, "Unexpected nullptr");
+  const char* const strtab = reinterpret_cast<char*>(
+      info->dlpi_addr + static_cast<ElfW(Word)>(dt_strtab->d_un.d_val));
+  ABSL_RAW_CHECK(dt_soname->d_un.d_val < dt_strsz->d_un.d_val,
+                 "Unexpected order");
+  return strtab + dt_soname->d_un.d_val;
+}
+
+// Helper function to get the build ID of a shared object.
+std::string GetBuildId(const dl_phdr_info* const info) {
+  std::string result;
+
+  // pt_note contains entries (of type ElfW(Nhdr)) starting at
+  //   info->dlpi_addr + pt_note->p_vaddr
+  // with length
+  //   pt_note->p_memsz
+  //
+  // The length of each entry is given by
+  //   Align(sizeof(ElfW(Nhdr)) + nhdr->n_namesz) + Align(nhdr->n_descsz)
+  for (int i = 0; i < info->dlpi_phnum; ++i) {
+    const ElfW(Phdr)* pt_note = &info->dlpi_phdr[i];
+    if (pt_note->p_type != PT_NOTE) continue;
+
+    const char* note =
+        reinterpret_cast<char*>(info->dlpi_addr + pt_note->p_vaddr);
+    const char* const last = note + pt_note->p_filesz;
+    const ElfW(Xword) align = pt_note->p_align;
+    while (note < last) {
+      const ElfW(Nhdr)* const nhdr = reinterpret_cast<const ElfW(Nhdr)*>(note);
+      if (note + sizeof(*nhdr) > last) {
+        // Corrupt PT_NOTE
+        break;
+      }
+
+      // Both the start and end of the descriptor are aligned by sh_addralign
+      // (= p_align).
+      const ElfW(Xword) desc_start =
+          (sizeof(*nhdr) + nhdr->n_namesz + align - 1) & -align;
+      const ElfW(Xword) size =
+          desc_start + ((nhdr->n_descsz + align - 1) & -align);
+
+      // Beware of wrap-around.
+      if (nhdr->n_namesz >= static_cast<ElfW(Word)>(-align) ||
+          nhdr->n_descsz >= static_cast<ElfW(Word)>(-align) ||
+          desc_start < sizeof(*nhdr) || size < desc_start ||
+          size > static_cast<ElfW(Xword)>(last - note)) {
+        // Corrupt PT_NOTE
+        break;
+      }
+
+      if (nhdr->n_type == NT_GNU_BUILD_ID) {
+        const char* const note_name = note + sizeof(*nhdr);
+        // n_namesz is the length of note_name.
+        if (nhdr->n_namesz == 4 && memcmp(note_name, "GNU\0", 4) == 0) {
+          if (!result.empty()) {
+            // Repeated build-ids.  Ignore them.
+            return "";
+          }
+          result = absl::BytesToHexString(
+              absl::string_view(note + desc_start, nhdr->n_descsz));
+        }
+      }
+      note += size;
+    }
+  }
+
+  return result;
+}
+#endif  // __linux__
+
+// A varint-encoded integer.
+struct Varint {
+  explicit Varint(uint64_t v) : value(v) {}
+  explicit Varint(StringId v) : value(static_cast<uint64_t>(v)) {}
+  explicit Varint(LocationId v) : value(static_cast<uint64_t>(v)) {}
+  explicit Varint(MappingId v) : value(static_cast<uint64_t>(v)) {}
+
+  uint64_t value;
+
+  template <typename Sink>
+  friend void AbslStringify(Sink& sink, const Varint& v) {
+    char buf[10];
+    char* p = buf;
+    uint64_t u = v.value;
+    while (u >= 0x80) {
+      *p++ = static_cast<char>((u & 0x7f) | 0x80);
+      u >>= 7;
+    }
+    *p++ = static_cast<char>(u);
+    sink.Append(absl::string_view(buf, static_cast<size_t>(p - buf)));
+  }
+};
+
+struct Tag {
+  int field_number;
+  WireType wire_type;
+
+  template <typename Sink>
+  friend void AbslStringify(Sink& sink, const Tag& t) {
+    absl::Format(&sink, "%v",
+                 Varint((static_cast<uint64_t>(t.field_number) << 3) |
+                        static_cast<uint64_t>(t.wire_type)));
+  }
+};
+
+struct LengthDelimited {
+  int field_number;
+  absl::string_view value;
+
+  template <typename Sink>
+  friend void AbslStringify(Sink& sink, const LengthDelimited& ld) {
+    absl::Format(&sink, "%v%v%v",
+                 Tag{ld.field_number, WireType::kLengthDelimited},
+                 Varint(ld.value.size()), ld.value);
+  }
+};
+
+struct VarintField {
+  int field_number;
+  Varint value;
+
+  template <typename Sink>
+  friend void AbslStringify(Sink& sink, const VarintField& vf) {
+    absl::Format(&sink, "%v%v", Tag{vf.field_number, WireType::kVarint},
+                 vf.value);
+  }
+};
+
+}  // namespace
+
+StringId ProfileBuilder::InternString(absl::string_view str) {
+  if (str.empty()) return StringId(0);
+  return string_table_.emplace(str, StringId(string_table_.size()))
+      .first->second;
+}
+
+LocationId ProfileBuilder::InternLocation(const void* address) {
+  return location_table_
+      .emplace(absl::bit_cast<uintptr_t>(address),
+               LocationId(location_table_.size() + 1))
+      .first->second;
+}
+
+void ProfileBuilder::AddSample(
+    int64_t value, absl::Span<const void* const> stack,
+    absl::Span<const std::pair<StringId, int64_t>> labels) {
+  std::string sample_proto;
+  absl::StrAppend(
+      &sample_proto,
+      VarintField{SampleProto::kValue, Varint(static_cast<uint64_t>(value))});
+
+  for (const void* addr : stack) {
+    // Profile addresses are raw stack unwind addresses, so they should be
+    // adjusted by -1 to land inside the call instruction (although potentially
+    // misaligned).
+    absl::StrAppend(
+        &sample_proto,
+        VarintField{SampleProto::kLocationId,
+                    Varint(InternLocation(absl::bit_cast<const void*>(
+                        absl::bit_cast<uintptr_t>(addr) - 1)))});
+  }
+
+  for (const auto& label : labels) {
+    std::string label_proto =
+        absl::StrCat(VarintField{LabelProto::kKey, Varint(label.first)},
+                     VarintField{LabelProto::kNum,
+                                 Varint(static_cast<uint64_t>(label.second))});
+    absl::StrAppend(&sample_proto,
+                    LengthDelimited{SampleProto::kLabel, label_proto});
+  }
+  samples_.push_back(std::move(sample_proto));
+}
+
+void ProfileBuilder::AddSampleType(StringId type, StringId unit) {
+  std::string sample_type_proto =
+      absl::StrCat(VarintField{ValueTypeProto::kType, Varint(type)},
+                   VarintField{ValueTypeProto::kUnit, Varint(unit)});
+  sample_types_.push_back(std::move(sample_type_proto));
+}
+
+MappingId ProfileBuilder::AddMapping(uintptr_t memory_start,
+                                     uintptr_t memory_limit,
+                                     uintptr_t file_offset,
+                                     absl::string_view filename,
+                                     absl::string_view build_id) {
+  size_t index = mappings_.size() + 1;
+  auto [it, inserted] = mapping_table_.emplace(memory_start, index);
+  if (!inserted) {
+    return static_cast<MappingId>(it->second);
+  }
+
+  Mapping m;
+  m.start = memory_start;
+  m.limit = memory_limit;
+  m.offset = file_offset;
+  m.filename = std::string(filename);
+  m.build_id = std::string(build_id);
+
+  mappings_.push_back(std::move(m));
+  return static_cast<MappingId>(index);
+}
+
+std::string ProfileBuilder::Emit() && {
+  std::string profile_proto;
+  for (const auto& sample_type : sample_types_) {
+    absl::StrAppend(&profile_proto,
+                    LengthDelimited{ProfileProto::kSampleType, sample_type});
+  }
+  for (const auto& sample : samples_) {
+    absl::StrAppend(&profile_proto,
+                    LengthDelimited{ProfileProto::kSample, sample});
+  }
+
+  // Build mapping table.
+  for (size_t i = 0, n = mappings_.size(); i < n; ++i) {
+    const auto& mapping = mappings_[i];
+    std::string mapping_proto = absl::StrCat(
+        VarintField{MappingProto::kId, Varint(static_cast<uint64_t>(i + 1))},
+        VarintField{MappingProto::kMemoryStart, Varint(mapping.start)},
+        VarintField{MappingProto::kMemoryLimit, Varint(mapping.limit)},
+        VarintField{MappingProto::kFileOffset, Varint(mapping.offset)},
+        VarintField{MappingProto::kFilename,
+                    Varint(InternString(mapping.filename))},
+        VarintField{MappingProto::kBuildId,
+                    Varint(InternString(mapping.build_id))});
+
+    absl::StrAppend(&profile_proto,
+                    LengthDelimited{ProfileProto::kMapping, mapping_proto});
+  }
+
+  // Build location table.
+  for (const auto& [address, id] : location_table_) {
+    std::string location =
+        absl::StrCat(VarintField{LocationProto::kId, Varint(id)},
+                     VarintField{LocationProto::kAddress, Varint(address)});
+
+    if (!mappings_.empty()) {
+      // Find the mapping ID.
+      auto it = mapping_table_.upper_bound(address);
+      if (it != mapping_table_.begin()) {
+        --it;
+      }
+
+      // If *it contains address, add mapping to location.
+      const size_t mapping_index = it->second;
+      const Mapping& mapping = mappings_[mapping_index - 1];
+
+      if (it->first <= address && address < mapping.limit) {
+        absl::StrAppend(
+            &location,
+            VarintField{LocationProto::kMappingId,
+                        Varint(static_cast<uint64_t>(mapping_index))});
+      }
+    }
+
+    absl::StrAppend(&profile_proto,
+                    LengthDelimited{ProfileProto::kLocation, location});
+  }
+
+  std::string string_table_proto;
+  std::vector<absl::string_view> sorted_strings(string_table_.size());
+  for (const auto& p : string_table_) {
+    sorted_strings[static_cast<size_t>(p.second)] = p.first;
+  }
+  for (const auto& s : sorted_strings) {
+    absl::StrAppend(&string_table_proto,
+                    LengthDelimited{ProfileProto::kStringTable, s});
+  }
+  absl::StrAppend(&profile_proto, VarintField{ProfileProto::kDropFrames,
+                                              Varint(drop_frames_id_)});
+  absl::StrAppend(&profile_proto,
+                  VarintField{ProfileProto::kComment, Varint(comment_id_)});
+  absl::StrAppend(&profile_proto, VarintField{ProfileProto::kDefaultSampleType,
+                                              Varint(default_sample_type_id_)});
+  return absl::StrCat(string_table_proto, profile_proto);
+}
+
+void ProfileBuilder::set_drop_frames_id(StringId drop_frames_id) {
+  drop_frames_id_ = drop_frames_id;
+}
+
+void ProfileBuilder::set_comment_id(StringId comment_id) {
+  comment_id_ = comment_id;
+}
+
+void ProfileBuilder::set_default_sample_type_id(
+    StringId default_sample_type_id) {
+  default_sample_type_id_ = default_sample_type_id;
+}
+
+void ProfileBuilder::AddCurrentMappings() {
+#ifdef __linux__
+  dl_iterate_phdr(
+      +[](dl_phdr_info* info, size_t, void* data) {
+        auto& builder = *reinterpret_cast<ProfileBuilder*>(data);
+
+        // Skip dummy entry introduced since glibc 2.18.
+        if (info->dlpi_phdr == nullptr && info->dlpi_phnum == 0) {
+          return 0;
+        }
+
+        const bool is_main_executable = builder.mappings_.empty();
+
+        // Evaluate all the loadable segments.
+        for (int i = 0; i < info->dlpi_phnum; ++i) {
+          if (info->dlpi_phdr[i].p_type != PT_LOAD) {
+            continue;
+          }
+          const ElfW(Phdr)* pt_load = &info->dlpi_phdr[i];
+
+          ABSL_RAW_CHECK(pt_load != nullptr, "Unexpected nullptr");
+
+          // Extract data.
+          const size_t memory_start = info->dlpi_addr + pt_load->p_vaddr;
+          const size_t memory_limit = memory_start + pt_load->p_memsz;
+          const size_t file_offset = pt_load->p_offset;
+
+          // Storage for path to executable as dlpi_name isn't populated for the
+          // main executable.  +1 to allow for the null terminator that readlink
+          // does not add.
+          char self_filename[PATH_MAX + 1];
+          const char* filename = info->dlpi_name;
+          if (filename == nullptr || filename[0] == '\0') {
+            // This is either the main executable or the VDSO.  The main
+            // executable is always the first entry processed by callbacks.
+            if (is_main_executable) {
+              // This is the main executable.
+              ssize_t ret = readlink("/proc/self/exe", self_filename,
+                                     sizeof(self_filename) - 1);
+              if (ret >= 0 &&
+                  static_cast<size_t>(ret) < sizeof(self_filename)) {
+                self_filename[ret] = '\0';
+                filename = self_filename;
+              }
+            } else {
+              // This is the VDSO.
+              filename = GetSoName(info);
+            }
+          }
+
+          char resolved_path[PATH_MAX];
+          absl::string_view resolved_filename;
+          if (realpath(filename, resolved_path)) {
+            resolved_filename = resolved_path;
+          } else {
+            resolved_filename = filename;
+          }
+
+          const std::string build_id = GetBuildId(info);
+
+          // Add to profile.
+          builder.AddMapping(memory_start, memory_limit, file_offset,
+                             resolved_filename, build_id);
+        }
+        // Keep going.
+        return 0;
+      },
+      this);
+#endif  // __linux__
+}
+
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/profiling/internal/profile_builder.h b/absl/profiling/internal/profile_builder.h
new file mode 100644
index 0000000..45075e6
--- /dev/null
+++ b/absl/profiling/internal/profile_builder.h
@@ -0,0 +1,138 @@
+// Copyright 2025 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.
+
+#ifndef ABSL_PROFILING_INTERNAL_PROFILE_BUILDER_H_
+#define ABSL_PROFILING_INTERNAL_PROFILE_BUILDER_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "absl/container/btree_map.h"
+#include "absl/container/flat_hash_map.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/span.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+
+// Field numbers for perftools.profiles.Profile.
+// https://github.com/google/pprof/blob/master/proto/profile.proto
+struct ProfileProto {
+  static constexpr int kSampleType = 1;
+  static constexpr int kSample = 2;
+  static constexpr int kMapping = 3;
+  static constexpr int kLocation = 4;
+  static constexpr int kStringTable = 6;
+  static constexpr int kDropFrames = 7;
+  static constexpr int kComment = 13;
+  static constexpr int kDefaultSampleType = 14;
+};
+
+struct ValueTypeProto {
+  static constexpr int kType = 1;
+  static constexpr int kUnit = 2;
+};
+
+struct SampleProto {
+  static constexpr int kLocationId = 1;
+  static constexpr int kValue = 2;
+  static constexpr int kLabel = 3;
+};
+
+struct LabelProto {
+  static constexpr int kKey = 1;
+  static constexpr int kStr = 2;
+  static constexpr int kNum = 3;
+  static constexpr int kNumUnit = 4;
+};
+
+struct MappingProto {
+  static constexpr int kId = 1;
+  static constexpr int kMemoryStart = 2;
+  static constexpr int kMemoryLimit = 3;
+  static constexpr int kFileOffset = 4;
+  static constexpr int kFilename = 5;
+  static constexpr int kBuildId = 6;
+};
+
+struct LocationProto {
+  static constexpr int kId = 1;
+  static constexpr int kMappingId = 2;
+  static constexpr int kAddress = 3;
+};
+
+enum class StringId : size_t {};
+enum class LocationId : size_t {};
+enum class MappingId : size_t {};
+
+// A helper class to build a profile protocol buffer.
+class ProfileBuilder {
+ public:
+  struct Mapping {
+    uint64_t start;
+    uint64_t limit;
+    uint64_t offset;
+    std::string filename;
+    std::string build_id;
+  };
+
+  StringId InternString(absl::string_view str);
+
+  LocationId InternLocation(const void* address);
+
+  void AddSample(int64_t value, absl::Span<const void* const> stack,
+                 absl::Span<const std::pair<StringId, int64_t>> labels);
+
+  void AddSampleType(StringId type, StringId unit);
+
+  // Adds the current process mappings to the profile.
+  void AddCurrentMappings();
+
+  // Adds a single mapping to the profile and to lookup cache and returns the
+  // resulting ID.
+  MappingId AddMapping(uintptr_t memory_start, uintptr_t memory_limit,
+                       uintptr_t file_offset, absl::string_view filename,
+                       absl::string_view build_id);
+
+  std::string Emit() &&;
+
+  void set_drop_frames_id(StringId drop_frames_id);
+  void set_comment_id(StringId comment_id);
+  void set_default_sample_type_id(StringId default_sample_type_id);
+
+ private:
+  absl::flat_hash_map<std::string, StringId> string_table_{{"", StringId(0)}};
+  absl::flat_hash_map<uintptr_t, LocationId> location_table_;
+  // mapping_table_ stores the start address of each mapping in mapping_
+  // to its index.
+  absl::btree_map<uintptr_t, size_t> mapping_table_;
+  std::vector<Mapping> mappings_;
+
+  std::vector<std::string> sample_types_;
+  std::vector<std::string> samples_;
+
+  StringId drop_frames_id_{};
+  StringId comment_id_{};
+  StringId default_sample_type_id_{};
+};
+
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_PROFILING_INTERNAL_PROFILE_BUILDER_H_
diff --git a/absl/profiling/internal/sample_recorder.h b/absl/profiling/internal/sample_recorder.h
index 371f6c4..88a4b27 100644
--- a/absl/profiling/internal/sample_recorder.h
+++ b/absl/profiling/internal/sample_recorder.h
@@ -75,7 +75,7 @@
 
   // Iterates over all the registered `StackInfo`s.  Returning the number of
   // samples that have been dropped.
-  int64_t Iterate(const std::function<void(const T& stack)>& f);
+  size_t Iterate(const std::function<void(const T& stack)>& f);
 
   size_t GetMaxSamples() const;
   void SetMaxSamples(size_t max);
@@ -130,7 +130,7 @@
 template <typename T>
 SampleRecorder<T>::SampleRecorder()
     : dropped_samples_(0), size_estimate_(0), all_(nullptr), dispose_(nullptr) {
-  absl::MutexLock l(&graveyard_.init_mu);
+  absl::MutexLock l(graveyard_.init_mu);
   graveyard_.dead = &graveyard_;
 }
 
@@ -159,8 +159,8 @@
     dispose(*sample);
   }
 
-  absl::MutexLock graveyard_lock(&graveyard_.init_mu);
-  absl::MutexLock sample_lock(&sample->init_mu);
+  absl::MutexLock graveyard_lock(graveyard_.init_mu);
+  absl::MutexLock sample_lock(sample->init_mu);
   sample->dead = graveyard_.dead;
   graveyard_.dead = sample;
 }
@@ -168,7 +168,7 @@
 template <typename T>
 template <typename... Targs>
 T* SampleRecorder<T>::PopDead(Targs... args) {
-  absl::MutexLock graveyard_lock(&graveyard_.init_mu);
+  absl::MutexLock graveyard_lock(graveyard_.init_mu);
 
   // The list is circular, so eventually it collapses down to
   //   graveyard_.dead == &graveyard_
@@ -176,7 +176,7 @@
   T* sample = graveyard_.dead;
   if (sample == &graveyard_) return nullptr;
 
-  absl::MutexLock sample_lock(&sample->init_mu);
+  absl::MutexLock sample_lock(sample->init_mu);
   graveyard_.dead = sample->dead;
   sample->dead = nullptr;
   sample->PrepareForSampling(std::forward<Targs>(args)...);
@@ -198,7 +198,7 @@
     // Resurrection failed.  Hire a new warlock.
     sample = new T();
     {
-      absl::MutexLock sample_lock(&sample->init_mu);
+      absl::MutexLock sample_lock(sample->init_mu);
       // If flag initialization happens to occur (perhaps in another thread)
       // while in this block, it will lock `graveyard_` which is usually always
       // locked before any sample. This will appear as a lock inversion.
@@ -222,11 +222,11 @@
 }
 
 template <typename T>
-int64_t SampleRecorder<T>::Iterate(
+size_t SampleRecorder<T>::Iterate(
     const std::function<void(const T& stack)>& f) {
   T* s = all_.load(std::memory_order_acquire);
   while (s != nullptr) {
-    absl::MutexLock l(&s->init_mu);
+    absl::MutexLock l(s->init_mu);
     if (s->dead == nullptr) {
       f(*s);
     }
diff --git a/absl/random/BUILD.bazel b/absl/random/BUILD.bazel
index 887ab0f..8986211 100644
--- a/absl/random/BUILD.bazel
+++ b/absl/random/BUILD.bazel
@@ -16,6 +16,9 @@
 
 # ABSL random-number generation libraries.
 
+load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
diff --git a/absl/random/internal/BUILD.bazel b/absl/random/internal/BUILD.bazel
index 994fb5c..1a3fef8 100644
--- a/absl/random/internal/BUILD.bazel
+++ b/absl/random/internal/BUILD.bazel
@@ -15,6 +15,9 @@
 #
 
 load("@bazel_skylib//lib:selects.bzl", "selects")
+load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 
 # Internal-only implementation classes for Abseil Random
 load(
@@ -799,6 +802,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     tags = [
         "benchmark",
+        "no_test_ios_sim_arm64",
         "no_test_ios_x86_64",
         "no_test_loonix",  # Crashing.
         "no_test_wasm",
diff --git a/absl/random/internal/entropy_pool.cc b/absl/random/internal/entropy_pool.cc
index fa47d0d..1386700 100644
--- a/absl/random/internal/entropy_pool.cc
+++ b/absl/random/internal/entropy_pool.cc
@@ -55,7 +55,7 @@
       RandenTraits::kCapacityBytes / sizeof(uint32_t);
 
   void Init(absl::Span<const uint32_t> data) {
-    SpinLockHolder l(&mu_);  // Always uncontested.
+    SpinLockHolder l(mu_);  // Always uncontested.
     std::copy(data.begin(), data.end(), std::begin(state_));
     next_ = kState;
   }
@@ -84,7 +84,7 @@
 };
 
 void RandenPoolEntry::Fill(uint8_t* out, size_t bytes) {
-  SpinLockHolder l(&mu_);
+  SpinLockHolder l(mu_);
   while (bytes > 0) {
     MaybeRefill();
     size_t remaining = available() * sizeof(state_[0]);
diff --git a/absl/random/internal/entropy_pool_test.cc b/absl/random/internal/entropy_pool_test.cc
index 89ea72f..7739f19 100644
--- a/absl/random/internal/entropy_pool_test.cc
+++ b/absl/random/internal/entropy_pool_test.cc
@@ -44,7 +44,7 @@
       threads.emplace_back([&]() {
         std::vector<result_type> v(kValuesPerThread);
         GetEntropyFromRandenPool(v.data(), sizeof(result_type) * v.size());
-        absl::MutexLock l(&mu);
+        absl::MutexLock l(mu);
         data.push_back(std::move(v));
       });
     }
diff --git a/absl/random/internal/fastmath_test.cc b/absl/random/internal/fastmath_test.cc
index 0d6f9dc..0b9ae5e 100644
--- a/absl/random/internal/fastmath_test.cc
+++ b/absl/random/internal/fastmath_test.cc
@@ -16,12 +16,10 @@
 
 #include "gtest/gtest.h"
 
-#if defined(__native_client__) || defined(__EMSCRIPTEN__)
-// NACL has a less accurate implementation of std::log2 than most of
+#if defined(__EMSCRIPTEN__)
+// Emscripten has a less accurate implementation of std::log2 than most of
 // the other platforms. For some values which should have integral results,
-// sometimes NACL returns slightly larger values.
-//
-// The MUSL libc used by emscripten also has a similar bug.
+// sometimes Emscripten returns slightly larger values.
 #define ABSL_RANDOM_INACCURATE_LOG2
 #endif
 
diff --git a/absl/random/internal/nonsecure_base_test.cc b/absl/random/internal/nonsecure_base_test.cc
index 6b6f2d5..6e3e712 100644
--- a/absl/random/internal/nonsecure_base_test.cc
+++ b/absl/random/internal/nonsecure_base_test.cc
@@ -214,7 +214,7 @@
 
         std::vector<result_type> v(kValuesPerThread);
         std::generate(v.begin(), v.end(), [&]() { return gen(); });
-        absl::MutexLock l(&mu);
+        absl::MutexLock l(mu);
         data.push_back(std::move(v));
       });
     }
diff --git a/absl/random/internal/platform.h b/absl/random/internal/platform.h
index bd2993e..a6fde4b 100644
--- a/absl/random/internal/platform.h
+++ b/absl/random/internal/platform.h
@@ -35,7 +35,6 @@
 //   Darwin (macOS and iOS)            __APPLE__
 //   Akaros (http://akaros.org)        __ros__
 //   Windows                           _WIN32
-//   NaCL                              __native_client__
 //   AsmJS                             __asmjs__
 //   WebAssembly                       __wasm__
 //   Fuchsia                           __Fuchsia__
@@ -125,12 +124,6 @@
 
 #endif
 
-// NaCl does not allow AES.
-#if defined(__native_client__)
-#undef ABSL_HAVE_ACCELERATED_AES
-#define ABSL_HAVE_ACCELERATED_AES 0
-#endif
-
 // ABSL_RANDOM_INTERNAL_AES_DISPATCH indicates whether the currently active
 // platform has, or should use run-time dispatch for selecting the
 // accelerated Randen implementation.
@@ -162,10 +155,4 @@
 #define ABSL_RANDOM_INTERNAL_AES_DISPATCH 1
 #endif
 
-// NaCl does not allow dispatch.
-#if defined(__native_client__)
-#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH
-#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 0
-#endif
-
 #endif  // ABSL_RANDOM_INTERNAL_PLATFORM_H_
diff --git a/absl/random/internal/randen_engine_test.cc b/absl/random/internal/randen_engine_test.cc
index a94f491..122d90b 100644
--- a/absl/random/internal/randen_engine_test.cc
+++ b/absl/random/internal/randen_engine_test.cc
@@ -632,7 +632,6 @@
   //
   // linux, optimized ~5ns
   // ppc, optimized ~7ns
-  // nacl (slow), ~1100ns
   //
   // `kCount` is chosen below so that, in debug builds and without hardware
   // acceleration, the test (assuming ~1us per call) should finish in ~0.1s
diff --git a/absl/random/internal/seed_material.cc b/absl/random/internal/seed_material.cc
index 8099ec7..b6380c8 100644
--- a/absl/random/internal/seed_material.cc
+++ b/absl/random/internal/seed_material.cc
@@ -41,12 +41,7 @@
 #include "absl/types/optional.h"
 #include "absl/types/span.h"
 
-#if defined(__native_client__)
-
-#include <nacl/nacl_random.h>
-#define ABSL_RANDOM_USE_NACL_SECURE_RANDOM 1
-
-#elif defined(_WIN32)
+#if defined(_WIN32)
 
 #include <windows.h>
 #define ABSL_RANDOM_USE_BCRYPT 1
@@ -109,27 +104,6 @@
   return BCRYPT_SUCCESS(ret);
 }
 
-#elif defined(ABSL_RANDOM_USE_NACL_SECURE_RANDOM)
-
-// On NaCL use nacl_secure_random to acquire bytes.
-bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) {
-  auto buffer = reinterpret_cast<uint8_t*>(values.data());
-  size_t buffer_size = sizeof(uint32_t) * values.size();
-
-  uint8_t* output_ptr = buffer;
-  while (buffer_size > 0) {
-    size_t nread = 0;
-    const int error = nacl_secure_random(output_ptr, buffer_size, &nread);
-    if (error != 0 || nread > buffer_size) {
-      ABSL_RAW_LOG(ERROR, "Failed to read secure_random seed data: %d", error);
-      return false;
-    }
-    output_ptr += nread;
-    buffer_size -= nread;
-  }
-  return true;
-}
-
 #elif defined(__Fuchsia__)
 
 bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) {
diff --git a/absl/random/mock_distributions_test.cc b/absl/random/mock_distributions_test.cc
index 622aff7..93af3f9 100644
--- a/absl/random/mock_distributions_test.cc
+++ b/absl/random/mock_distributions_test.cc
@@ -69,10 +69,11 @@
       .WillOnce(Return(0.001));
   EXPECT_EQ(absl::Gaussian<double>(gen, 0.0, 1.0), 0.001);
 
-  EXPECT_NE(absl::LogUniform<int>(gen, 0, 1000000, 2), 2040);
-  EXPECT_CALL(absl::MockLogUniform<int>(), Call(gen, 0, 1000000, 2))
-      .WillOnce(Return(2040));
-  EXPECT_EQ(absl::LogUniform<int>(gen, 0, 1000000, 2), 2040);
+  const int kHigh = (1 << 30) - 1;
+  EXPECT_NE(absl::LogUniform<int>(gen, 0, kHigh, 2), kHigh);
+  EXPECT_CALL(absl::MockLogUniform<int>(), Call(gen, 0, kHigh, 2))
+      .WillOnce(Return(kHigh));
+  EXPECT_EQ(absl::LogUniform<int>(gen, 0, kHigh, 2), kHigh);
 }
 
 TEST(MockDistributions, UniformUInt128BoundariesAreAllowed) {
diff --git a/absl/status/BUILD.bazel b/absl/status/BUILD.bazel
index b61abeb..394222f 100644
--- a/absl/status/BUILD.bazel
+++ b/absl/status/BUILD.bazel
@@ -17,6 +17,9 @@
 # It will expand later to have utilities around `Status` like `StatusOr`,
 # `StatusBuilder` and macros.
 
+load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
@@ -189,3 +192,20 @@
         "@googletest//:gtest_main",
     ],
 )
+
+cc_test(
+    name = "status_matchers_with_unqualified_macros_test",
+    size = "small",
+    srcs = ["status_matchers_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    local_defines = ["ABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS"],
+    deps = [
+        ":status",
+        ":status_matchers",
+        ":statusor",
+        "//absl/strings",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
diff --git a/absl/status/CMakeLists.txt b/absl/status/CMakeLists.txt
index e140365..d0d134c 100644
--- a/absl/status/CMakeLists.txt
+++ b/absl/status/CMakeLists.txt
@@ -141,3 +141,19 @@
     absl::status_matchers
     GTest::gmock_main
 )
+
+absl_cc_test(
+  NAME
+    status_matchers_with_unqualified_macros_test
+  SRCS
+   "status_matchers_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEFINES
+    "ABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS"
+  DEPS
+    absl::status
+    absl::statusor
+    absl::status_matchers
+    GTest::gmock_main
+)
diff --git a/absl/status/internal/status_internal.h b/absl/status/internal/status_internal.h
index 45b90f3..35a9f9b 100644
--- a/absl/status/internal/status_internal.h
+++ b/absl/status/internal/status_internal.h
@@ -38,9 +38,11 @@
 // TODO(b/176172494): ABSL_MUST_USE_RESULT should expand to the more strict
 // [[nodiscard]]. For now, just use [[nodiscard]] directly when it is available.
 #if ABSL_HAVE_CPP_ATTRIBUTE(nodiscard)
-class [[nodiscard]] ABSL_ATTRIBUTE_TRIVIAL_ABI Status;
+class [[nodiscard]] ABSL_ATTRIBUTE_TRIVIAL_ABI
+    Status;
 #else
-class ABSL_MUST_USE_RESULT ABSL_ATTRIBUTE_TRIVIAL_ABI Status;
+class ABSL_MUST_USE_RESULT ABSL_ATTRIBUTE_TRIVIAL_ABI
+    Status;
 #endif
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/status/internal/status_matchers.h b/absl/status/internal/status_matchers.h
index 0750622..d11742b 100644
--- a/absl/status/internal/status_matchers.h
+++ b/absl/status/internal/status_matchers.h
@@ -69,8 +69,8 @@
   bool MatchAndExplain(
       StatusOrType actual_value,
       ::testing::MatchResultListener* result_listener) const override {
-    if (!GetStatus(actual_value).ok()) {
-      *result_listener << "which has status " << GetStatus(actual_value);
+    if (!actual_value.ok()) {
+      *result_listener << "which has status " << actual_value.status();
       return false;
     }
 
diff --git a/absl/status/internal/statusor_internal.h b/absl/status/internal/statusor_internal.h
index e986611..8a4e2f5 100644
--- a/absl/status/internal/statusor_internal.h
+++ b/absl/status/internal/statusor_internal.h
@@ -29,7 +29,8 @@
 ABSL_NAMESPACE_BEGIN
 
 template <typename T>
-class ABSL_MUST_USE_RESULT StatusOr;
+class ABSL_MUST_USE_RESULT
+    StatusOr;
 
 namespace internal_statusor {
 
@@ -46,6 +47,16 @@
 struct HasConversionOperatorToStatusOr<T, U, decltype(test<T, U>(0))>
     : std::true_type {};
 
+// Detects whether `T` is equality-comparable.
+template <typename T, typename = void>
+struct IsEqualityComparable : std::false_type {};
+
+template <typename T>
+struct IsEqualityComparable<
+    T, std::enable_if_t<std::is_convertible<
+           decltype(std::declval<T>() == std::declval<T>()),
+           bool>::value>> : std::true_type {};
+
 // Detects whether `T` is constructible or convertible from `StatusOr<U>`.
 template <typename T, typename U>
 using IsConstructibleOrConvertibleFromStatusOr =
@@ -80,17 +91,34 @@
 struct IsDirectInitializationAmbiguous<T, absl::StatusOr<V>>
     : public IsConstructibleOrConvertibleFromStatusOr<T, V> {};
 
+// Checks whether the conversion from U to T can be done without dangling
+// temporaries.
+// REQUIRES: T and U are references.
+template <typename T, typename U>
+using IsReferenceConversionValid = absl::conjunction<  //
+    std::is_reference<T>, std::is_reference<U>,
+    // The references are convertible. This checks for
+    // lvalue/rvalue compatibility.
+    std::is_convertible<U, T>,
+    // The pointers are convertible. This checks we don't have
+    // a temporary.
+    std::is_convertible<std::remove_reference_t<U>*,
+                        std::remove_reference_t<T>*>>;
+
 // Checks against the constraints of the direction initialization, i.e. when
 // `StatusOr<T>::StatusOr(U&&)` should participate in overload resolution.
 template <typename T, typename U>
 using IsDirectInitializationValid = absl::disjunction<
     // Short circuits if T is basically U.
-    std::is_same<T, absl::remove_cvref_t<U>>,
-    absl::negation<absl::disjunction<
-        std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>,
-        std::is_same<absl::Status, absl::remove_cvref_t<U>>,
-        std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>,
-        IsDirectInitializationAmbiguous<T, U>>>>;
+    std::is_same<T, absl::remove_cvref_t<U>>,  //
+    std::conditional_t<
+        std::is_reference_v<T>,  //
+        IsReferenceConversionValid<T, U>,
+        absl::negation<absl::disjunction<
+            std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>,
+            std::is_same<absl::Status, absl::remove_cvref_t<U>>,
+            std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>,
+            IsDirectInitializationAmbiguous<T, U>>>>>;
 
 // This trait detects whether `StatusOr<T>::operator=(U&&)` is ambiguous, which
 // is equivalent to whether all the following conditions are met:
@@ -130,7 +158,9 @@
 template <bool Explicit, typename T, typename U, bool Lifetimebound>
 using IsConstructionValid = absl::conjunction<
     Equality<Lifetimebound,
-             type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
+             absl::disjunction<
+                 std::is_reference<T>,
+                 type_traits_internal::IsLifetimeBoundAssignment<T, U>>>,
     IsDirectInitializationValid<T, U&&>, std::is_constructible<T, U&&>,
     Equality<!Explicit, std::is_convertible<U&&, T>>,
     absl::disjunction<
@@ -146,8 +176,13 @@
 template <typename T, typename U, bool Lifetimebound>
 using IsAssignmentValid = absl::conjunction<
     Equality<Lifetimebound,
-             type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
-    std::is_constructible<T, U&&>, std::is_assignable<T&, U&&>,
+             absl::disjunction<
+                 std::is_reference<T>,
+                 type_traits_internal::IsLifetimeBoundAssignment<T, U>>>,
+    std::conditional_t<std::is_reference_v<T>,
+                       IsReferenceConversionValid<T, U&&>,
+                       absl::conjunction<std::is_constructible<T, U&&>,
+                                         std::is_assignable<T&, U&&>>>,
     absl::disjunction<
         std::is_same<T, absl::remove_cvref_t<U>>,
         absl::conjunction<
@@ -168,6 +203,9 @@
           typename UQ>
 using IsConstructionFromStatusOrValid = absl::conjunction<
     absl::negation<std::is_same<T, U>>,
+    // If `T` is a reference, then U must be a compatible one.
+    absl::disjunction<absl::negation<std::is_reference<T>>,
+                      IsReferenceConversionValid<T, U>>,
     Equality<Lifetimebound,
              type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
     std::is_constructible<T, UQ>,
@@ -183,6 +221,16 @@
     absl::negation<IsConstructibleOrConvertibleOrAssignableFromStatusOr<
         T, absl::remove_cvref_t<U>>>>;
 
+template <typename T, typename U, bool Lifetimebound>
+using IsValueOrValid = absl::conjunction<
+    // If `T` is a reference, then U must be a compatible one.
+    absl::disjunction<absl::negation<std::is_reference<T>>,
+                      IsReferenceConversionValid<T, U>>,
+    Equality<Lifetimebound,
+             absl::disjunction<
+                 std::is_reference<T>,
+                 type_traits_internal::IsLifetimeBoundAssignment<T, U>>>>;
+
 class Helper {
  public:
   // Move type-agnostic error handling to the .cc.
@@ -199,6 +247,26 @@
   new (p) T(std::forward<Args>(args)...);
 }
 
+template <typename T>
+class Reference {
+ public:
+  constexpr explicit Reference(T ref ABSL_ATTRIBUTE_LIFETIME_BOUND)
+      : payload_(std::addressof(ref)) {}
+
+  Reference(const Reference&) = default;
+  Reference& operator=(const Reference&) = default;
+  Reference& operator=(T value) {
+    payload_ = std::addressof(value);
+    return *this;
+  }
+
+  operator T() const { return static_cast<T>(*payload_); }  // NOLINT
+  T get() const { return *this; }
+
+ private:
+  std::remove_reference_t<T>* absl_nonnull payload_;
+};
+
 // Helper base class to hold the data and all operations.
 // We move all this to a base class to allow mixing with the appropriate
 // TraitsBase specialization.
@@ -207,6 +275,14 @@
   template <typename U>
   friend class StatusOrData;
 
+  decltype(auto) MaybeMoveData() {
+    if constexpr (std::is_reference_v<T>) {
+      return data_.get();
+    } else {
+      return std::move(data_);
+    }
+  }
+
  public:
   StatusOrData() = delete;
 
@@ -221,7 +297,7 @@
 
   StatusOrData(StatusOrData&& other) noexcept {
     if (other.ok()) {
-      MakeValue(std::move(other.data_));
+      MakeValue(other.MaybeMoveData());
       MakeStatus();
     } else {
       MakeStatus(std::move(other.status_));
@@ -241,7 +317,7 @@
   template <typename U>
   explicit StatusOrData(StatusOrData<U>&& other) {
     if (other.ok()) {
-      MakeValue(std::move(other.data_));
+      MakeValue(other.MaybeMoveData());
       MakeStatus();
     } else {
       MakeStatus(std::move(other.status_));
@@ -254,13 +330,6 @@
     MakeStatus();
   }
 
-  explicit StatusOrData(const T& value) : data_(value) {
-    MakeStatus();
-  }
-  explicit StatusOrData(T&& value) : data_(std::move(value)) {
-    MakeStatus();
-  }
-
   template <typename U,
             absl::enable_if_t<std::is_constructible<absl::Status, U&&>::value,
                               int> = 0>
@@ -280,7 +349,7 @@
   StatusOrData& operator=(StatusOrData&& other) {
     if (this == &other) return *this;
     if (other.ok())
-      Assign(std::move(other.data_));
+      Assign(other.MaybeMoveData());
     else
       AssignStatus(std::move(other.status_));
     return *this;
@@ -289,7 +358,9 @@
   ~StatusOrData() {
     if (ok()) {
       status_.~Status();
-      data_.~T();
+      if constexpr (!std::is_trivially_destructible_v<T>) {
+        data_.~T();
+      }
     } else {
       status_.~Status();
     }
@@ -330,11 +401,13 @@
     // When T is const, we need some non-const object we can cast to void* for
     // the placement new. dummy_ is that object.
     Dummy dummy_;
-    T data_;
+    std::conditional_t<std::is_reference_v<T>, Reference<T>, T> data_;
   };
 
   void Clear() {
-    if (ok()) data_.~T();
+    if constexpr (!std::is_trivially_destructible_v<T>) {
+      if (ok()) data_.~T();
+    }
   }
 
   void EnsureOk() const {
@@ -349,7 +422,8 @@
   // argument.
   template <typename... Arg>
   void MakeValue(Arg&&... arg) {
-    internal_statusor::PlacementNew<T>(&dummy_, std::forward<Arg>(arg)...);
+    internal_statusor::PlacementNew<decltype(data_)>(&dummy_,
+                                                     std::forward<Arg>(arg)...);
   }
 
   // Construct the status (ie. status_) through placement new with the passed
@@ -359,6 +433,94 @@
     internal_statusor::PlacementNew<Status>(&status_,
                                             std::forward<Args>(args)...);
   }
+
+  template <typename U>
+  T ValueOrImpl(U&& default_value) const& {
+    if (ok()) {
+      return data_;
+    }
+    return std::forward<U>(default_value);
+  }
+
+  template <typename U>
+  T ValueOrImpl(U&& default_value) && {
+    if (ok()) {
+      return std::move(data_);
+    }
+    return std::forward<U>(default_value);
+  }
+};
+
+[[noreturn]] void ThrowBadStatusOrAccess(absl::Status status);
+
+template <typename T>
+struct OperatorBase {
+  auto& self() const { return static_cast<const StatusOr<T>&>(*this); }
+  auto& self() { return static_cast<StatusOr<T>&>(*this); }
+
+  const T& operator*() const& ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    self().EnsureOk();
+    return self().data_;
+  }
+  T& operator*() & ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    self().EnsureOk();
+    return self().data_;
+  }
+  const T&& operator*() const&& ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    self().EnsureOk();
+    return std::move(self().data_);
+  }
+  T&& operator*() && ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    self().EnsureOk();
+    return std::move(self().data_);
+  }
+
+  const T& value() const& ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    if (!self().ok()) internal_statusor::ThrowBadStatusOrAccess(self().status_);
+    return self().data_;
+  }
+  T& value() & ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    if (!self().ok()) internal_statusor::ThrowBadStatusOrAccess(self().status_);
+    return self().data_;
+  }
+  const T&& value() const&& ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    if (!self().ok()) {
+      internal_statusor::ThrowBadStatusOrAccess(std::move(self().status_));
+    }
+    return std::move(self().data_);
+  }
+  T&& value() && ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    if (!self().ok()) {
+      internal_statusor::ThrowBadStatusOrAccess(std::move(self().status_));
+    }
+    return std::move(self().data_);
+  }
+
+  const T* absl_nonnull operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return std::addressof(**this);
+  }
+  T* absl_nonnull operator->() ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return std::addressof(**this);
+  }
+};
+
+template <typename T>
+struct OperatorBase<T&> {
+  auto& self() const { return static_cast<const StatusOr<T&>&>(*this); }
+
+  T& operator*() const {
+    self().EnsureOk();
+    return self().data_;
+  }
+
+  T& value() const {
+    if (!self().ok()) internal_statusor::ThrowBadStatusOrAccess(self().status_);
+    return self().data_;
+  }
+
+  T* absl_nonnull operator->() const {
+    return std::addressof(**this);
+  }
 };
 
 // Helper base classes to allow implicitly deleted constructors and assignment
@@ -401,8 +563,9 @@
   MoveCtorBase& operator=(MoveCtorBase&&) = default;
 };
 
-template <typename T, bool = std::is_copy_constructible<T>::value&&
-                          std::is_copy_assignable<T>::value>
+template <typename T, bool = (std::is_copy_constructible<T>::value &&
+                              std::is_copy_assignable<T>::value) ||
+                             std::is_reference_v<T>>
 struct CopyAssignBase {
   CopyAssignBase() = default;
   CopyAssignBase(const CopyAssignBase&) = default;
@@ -420,8 +583,9 @@
   CopyAssignBase& operator=(CopyAssignBase&&) = default;
 };
 
-template <typename T, bool = std::is_move_constructible<T>::value&&
-                          std::is_move_assignable<T>::value>
+template <typename T, bool = (std::is_move_constructible<T>::value &&
+                              std::is_move_assignable<T>::value) ||
+                             std::is_reference_v<T>>
 struct MoveAssignBase {
   MoveAssignBase() = default;
   MoveAssignBase(const MoveAssignBase&) = default;
@@ -439,8 +603,6 @@
   MoveAssignBase& operator=(MoveAssignBase&&) = delete;
 };
 
-[[noreturn]] void ThrowBadStatusOrAccess(absl::Status status);
-
 // Used to introduce jitter into the output of printing functions for
 // `StatusOr` (i.e. `AbslStringify` and `operator<<`).
 class StringifyRandom {
diff --git a/absl/status/status.cc b/absl/status/status.cc
index 963dab6..f219933 100644
--- a/absl/status/status.cc
+++ b/absl/status/status.cc
@@ -47,6 +47,10 @@
     "absl::Status assumes it can use the bottom 2 bits of a StatusRep*.");
 
 std::string StatusCodeToString(StatusCode code) {
+  return std::string(absl::StatusCodeToStringView(code));
+}
+
+absl::string_view StatusCodeToStringView(StatusCode code) {
   switch (code) {
     case StatusCode::kOk:
       return "OK";
diff --git a/absl/status/status.h b/absl/status/status.h
index 4516822..b26d072 100644
--- a/absl/status/status.h
+++ b/absl/status/status.h
@@ -284,6 +284,11 @@
 // Returns the name for the status code, or "" if it is an unknown value.
 std::string StatusCodeToString(StatusCode code);
 
+// StatusCodeToStringView()
+//
+// Same as StatusCodeToString(), but returns a string_view.
+absl::string_view StatusCodeToStringView(StatusCode code);
+
 // operator<<
 //
 // Streams StatusCodeToString(code) to `os`.
diff --git a/absl/status/status_matchers.h b/absl/status/status_matchers.h
index 837660e..03e5f49 100644
--- a/absl/status/status_matchers.h
+++ b/absl/status/status_matchers.h
@@ -20,6 +20,24 @@
 //
 // Defines the following utilities:
 //
+//   =================
+//   ABSL_EXPECT_OK(s)
+//
+//   ABSL_ASSERT_OK(s)
+//   =================
+//   Convenience macros for `EXPECT_THAT(s, IsOk())`, where `s` is either
+//   a `Status` or a `StatusOr<T>`.
+//
+//   There are no EXPECT_NOT_OK/ASSERT_NOT_OK macros since they would not
+//   provide much value (when they fail, they would just print the OK status
+//   which conveys no more information than `EXPECT_FALSE(s.ok())`. You can
+//   of course use `EXPECT_THAT(s, Not(IsOk()))` if you prefer _THAT style.
+//
+//   If you want to check for particular errors, better alternatives are:
+//   EXPECT_THAT(s, StatusIs(expected_error));
+//   EXPECT_THAT(s, StatusIs(_, _, HasSubstr("expected error")));
+//
+//
 //   ===============
 //   `IsOkAndHolds(m)`
 //   ===============
@@ -76,6 +94,13 @@
 namespace absl_testing {
 ABSL_NAMESPACE_BEGIN
 
+// Macros for testing the results of functions that return absl::Status or
+// absl::StatusOr<T> (for any type T).
+#define ABSL_EXPECT_OK(expression) \
+  EXPECT_THAT(expression, ::absl_testing::IsOk())
+#define ABSL_ASSERT_OK(expression) \
+  ASSERT_THAT(expression, ::absl_testing::IsOk())
+
 // Returns a gMock matcher that matches a StatusOr<> whose status is
 // OK and whose value matches the inner matcher.
 template <typename InnerMatcherT>
@@ -112,6 +137,29 @@
   return status_internal::IsOkMatcher();
 }
 
+// By defining ABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS, this library also
+// provides unqualified versions of macros
+//
+// Unqualified macro names are likely to collide with those other projects, and
+// so are not recommended.  Further, this is true of any transitive dependency
+// of Abseil; it is impossible to be confident no downstream library will not
+// also define these macros itself nor depend on a different library that also
+// defines them.
+//
+// To enable this, define `ABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS`
+// preferably at the command line, e.g.
+// `-DABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS` or
+// `local_defines = ["ABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS"]` if using
+// Bazel.
+//
+// These are turned on by default inside Google's internal codebase where their
+// use is historically ubiquitous.  Other OSS Google projects should use the
+// qualified versions or the `EXPECT_THAT(..., IsOk())` form.
+#ifdef ABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS
+#define EXPECT_OK(expression) ABSL_EXPECT_OK(expression)
+#define ASSERT_OK(expression) ABSL_ASSERT_OK(expression)
+#endif  // ABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS
+
 ABSL_NAMESPACE_END
 }  // namespace absl_testing
 
diff --git a/absl/status/status_matchers_test.cc b/absl/status/status_matchers_test.cc
index b8ccaa4..8656b2d 100644
--- a/absl/status/status_matchers_test.cc
+++ b/absl/status/status_matchers_test.cc
@@ -18,6 +18,7 @@
 #include "absl/status/status_matchers.h"
 
 #include <string>
+#include <vector>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest-spi.h"
@@ -31,9 +32,39 @@
 using ::absl_testing::IsOk;
 using ::absl_testing::IsOkAndHolds;
 using ::absl_testing::StatusIs;
+using ::testing::ElementsAre;
 using ::testing::Eq;
 using ::testing::Gt;
 using ::testing::MatchesRegex;
+using ::testing::Not;
+using ::testing::Ref;
+
+TEST(StatusMatcherTest, AbslExpectAssertOk) {
+  ABSL_EXPECT_OK(absl::OkStatus());
+  ABSL_ASSERT_OK(absl::OkStatus());
+  EXPECT_NONFATAL_FAILURE(ABSL_EXPECT_OK(absl::InternalError("Smigla error")),
+                          "Smigla error");
+  EXPECT_FATAL_FAILURE(ABSL_ASSERT_OK(absl::InternalError("Smigla error")),
+                       "Smigla error");
+}
+
+TEST(StatusMatcherTest, ExpectAssertOk) {
+#ifdef ABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS
+  EXPECT_OK(absl::OkStatus());
+  ASSERT_OK(absl::OkStatus());
+  EXPECT_NONFATAL_FAILURE(EXPECT_OK(absl::InternalError("Smigla error")),
+                          "Smigla error");
+  EXPECT_FATAL_FAILURE(ASSERT_OK(absl::InternalError("Smigla error")),
+                       "Smigla error");
+#else
+#ifdef EXPECT_OK
+  static_assert(false, "EXPECT_OK defined despite being turned off.");
+#endif  // EXPECT_OK
+#ifdef ASSERT_OK
+  static_assert(false, "ASSERT_OK defined despite being turned off.");
+#endif  // ASSERT_OK
+#endif  // ABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS
+}
 
 TEST(StatusMatcherTest, StatusIsOk) { EXPECT_THAT(absl::OkStatus(), IsOk()); }
 
@@ -158,4 +189,23 @@
       "ungueltig");
 }
 
+TEST(StatusMatcherTest, ReferencesWork) {
+  int i = 17;
+  int j = 19;
+  EXPECT_THAT(absl::StatusOr<int&>(i), IsOkAndHolds(17));
+  EXPECT_THAT(absl::StatusOr<int&>(i), Not(IsOkAndHolds(19)));
+  EXPECT_THAT(absl::StatusOr<const int&>(i), IsOkAndHolds(17));
+
+  // Reference testing works as expected.
+  EXPECT_THAT(absl::StatusOr<int&>(i), IsOkAndHolds(Ref(i)));
+  EXPECT_THAT(absl::StatusOr<int&>(i), Not(IsOkAndHolds(Ref(j))));
+
+  // Try a more complex one.
+  std::vector<std::string> vec = {"A", "B", "C"};
+  EXPECT_THAT(absl::StatusOr<std::vector<std::string>&>(vec),
+              IsOkAndHolds(ElementsAre("A", "B", "C")));
+  EXPECT_THAT(absl::StatusOr<std::vector<std::string>&>(vec),
+              Not(IsOkAndHolds(ElementsAre("A", "X", "C"))));
+}
+
 }  // namespace
diff --git a/absl/status/status_test.cc b/absl/status/status_test.cc
index c3327ad..f6ac0c0 100644
--- a/absl/status/status_test.cc
+++ b/absl/status/status_test.cc
@@ -39,6 +39,7 @@
   std::ostringstream oss;
   oss << code;
   EXPECT_EQ(oss.str(), absl::StatusCodeToString(code));
+  EXPECT_EQ(oss.str(), absl::StatusCodeToStringView(code));
 }
 
 // This structure holds the details for testing a single error code,
diff --git a/absl/status/statusor.h b/absl/status/statusor.h
index 6142a2f..52294ee 100644
--- a/absl/status/statusor.h
+++ b/absl/status/statusor.h
@@ -45,8 +45,8 @@
 #include <utility>
 
 #include "absl/base/attributes.h"
-#include "absl/base/nullability.h"
 #include "absl/base/call_once.h"
+#include "absl/base/nullability.h"
 #include "absl/meta/type_traits.h"
 #include "absl/status/internal/statusor_internal.h"
 #include "absl/status/status.h"
@@ -189,14 +189,22 @@
 //    return Foo(arg);
 //  }
 template <typename T>
-class StatusOr : private internal_statusor::StatusOrData<T>,
+class StatusOr : private internal_statusor::OperatorBase<T>,
+                 private internal_statusor::StatusOrData<T>,
                  private internal_statusor::CopyCtorBase<T>,
                  private internal_statusor::MoveCtorBase<T>,
                  private internal_statusor::CopyAssignBase<T>,
                  private internal_statusor::MoveAssignBase<T> {
+#ifndef SWIG
+  static_assert(!std::is_rvalue_reference_v<T>,
+                "rvalue references are not yet supported.");
+#endif  // SWIG
+
   template <typename U>
   friend class StatusOr;
 
+  friend internal_statusor::OperatorBase<T>;
+
   typedef internal_statusor::StatusOrData<T> Base;
 
  public:
@@ -397,7 +405,7 @@
             typename std::enable_if<
                 internal_statusor::IsAssignmentValid<T, U, true>::value,
                 int>::type = 0>
-  StatusOr& operator=(U&& v ABSL_ATTRIBUTE_LIFETIME_BOUND) {
+  StatusOr& operator=(U&& v ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this)) {
     this->Assign(std::forward<U>(v));
     return *this;
   }
@@ -493,10 +501,7 @@
   //
   // The `std::move` on statusor instead of on the whole expression enables
   // warnings about possible uses of the statusor object after the move.
-  const T& value() const& ABSL_ATTRIBUTE_LIFETIME_BOUND;
-  T& value() & ABSL_ATTRIBUTE_LIFETIME_BOUND;
-  const T&& value() const&& ABSL_ATTRIBUTE_LIFETIME_BOUND;
-  T&& value() && ABSL_ATTRIBUTE_LIFETIME_BOUND;
+  using StatusOr::OperatorBase::value;
 
   // StatusOr<T>:: operator*()
   //
@@ -508,10 +513,7 @@
   // `absl::StatusOr<T>`. Alternatively, see the `value()` member function for a
   // similar API that guarantees crashing or throwing an exception if there is
   // no current value.
-  const T& operator*() const& ABSL_ATTRIBUTE_LIFETIME_BOUND;
-  T& operator*() & ABSL_ATTRIBUTE_LIFETIME_BOUND;
-  const T&& operator*() const&& ABSL_ATTRIBUTE_LIFETIME_BOUND;
-  T&& operator*() && ABSL_ATTRIBUTE_LIFETIME_BOUND;
+  using StatusOr::OperatorBase::operator*;
 
   // StatusOr<T>::operator->()
   //
@@ -520,8 +522,7 @@
   // REQUIRES: `this->ok() == true`, otherwise the behavior is undefined.
   //
   // Use `this->ok()` to verify that there is a current value.
-  const T* absl_nonnull operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND;
-  T* absl_nonnull operator->() ABSL_ATTRIBUTE_LIFETIME_BOUND;
+  using StatusOr::OperatorBase::operator->;
 
   // StatusOr<T>::value_or()
   //
@@ -536,10 +537,34 @@
   //
   // Unlike with `value`, calling `std::move()` on the result of `value_or` will
   // still trigger a copy.
-  template <typename U>
-  T value_or(U&& default_value) const&;
-  template <typename U>
-  T value_or(U&& default_value) &&;
+  template <
+      typename U,
+      std::enable_if_t<internal_statusor::IsValueOrValid<T, U&&, false>::value,
+                       int> = 0>
+  T value_or(U&& default_value) const& {
+    return this->ValueOrImpl(std::forward<U>(default_value));
+  }
+  template <
+      typename U,
+      std::enable_if_t<internal_statusor::IsValueOrValid<T, U&&, false>::value,
+                       int> = 0>
+  T value_or(U&& default_value) && {
+    return std::move(*this).ValueOrImpl(std::forward<U>(default_value));
+  }
+  template <
+      typename U,
+      std::enable_if_t<internal_statusor::IsValueOrValid<T, U&&, true>::value,
+                       int> = 0>
+  T value_or(U&& default_value ABSL_ATTRIBUTE_LIFETIME_BOUND) const& {
+    return this->ValueOrImpl(std::forward<U>(default_value));
+  }
+  template <
+      typename U,
+      std::enable_if_t<internal_statusor::IsValueOrValid<T, U&&, true>::value,
+                       int> = 0>
+  T value_or(U&& default_value ABSL_ATTRIBUTE_LIFETIME_BOUND) && {
+    return std::move(*this).ValueOrImpl(std::forward<U>(default_value));
+  }
 
   // StatusOr<T>::IgnoreError()
   //
@@ -607,7 +632,9 @@
 // operator==()
 //
 // This operator checks the equality of two `absl::StatusOr<T>` objects.
-template <typename T>
+template <typename T,
+          std::enable_if_t<internal_statusor::IsEqualityComparable<T>::value,
+                           int> = 0>
 bool operator==(const StatusOr<T>& lhs, const StatusOr<T>& rhs) {
   if (lhs.ok() && rhs.ok()) return *lhs == *rhs;
   return lhs.status() == rhs.status();
@@ -616,7 +643,9 @@
 // operator!=()
 //
 // This operator checks the inequality of two `absl::StatusOr<T>` objects.
-template <typename T>
+template <typename T,
+          std::enable_if_t<internal_statusor::IsEqualityComparable<T>::value,
+                           int> = 0>
 bool operator!=(const StatusOr<T>& lhs, const StatusOr<T>& rhs) {
   return !(lhs == rhs);
 }
@@ -704,88 +733,6 @@
 }
 
 template <typename T>
-const T& StatusOr<T>::value() const& {
-  if (!this->ok()) internal_statusor::ThrowBadStatusOrAccess(this->status_);
-  return this->data_;
-}
-
-template <typename T>
-T& StatusOr<T>::value() & {
-  if (!this->ok()) internal_statusor::ThrowBadStatusOrAccess(this->status_);
-  return this->data_;
-}
-
-template <typename T>
-const T&& StatusOr<T>::value() const&& {
-  if (!this->ok()) {
-    internal_statusor::ThrowBadStatusOrAccess(std::move(this->status_));
-  }
-  return std::move(this->data_);
-}
-
-template <typename T>
-T&& StatusOr<T>::value() && {
-  if (!this->ok()) {
-    internal_statusor::ThrowBadStatusOrAccess(std::move(this->status_));
-  }
-  return std::move(this->data_);
-}
-
-template <typename T>
-const T& StatusOr<T>::operator*() const& {
-  this->EnsureOk();
-  return this->data_;
-}
-
-template <typename T>
-T& StatusOr<T>::operator*() & {
-  this->EnsureOk();
-  return this->data_;
-}
-
-template <typename T>
-const T&& StatusOr<T>::operator*() const&& {
-  this->EnsureOk();
-  return std::move(this->data_);
-}
-
-template <typename T>
-T&& StatusOr<T>::operator*() && {
-  this->EnsureOk();
-  return std::move(this->data_);
-}
-
-template <typename T>
-const T* absl_nonnull StatusOr<T>::operator->() const {
-  this->EnsureOk();
-  return &this->data_;
-}
-
-template <typename T>
-T* absl_nonnull StatusOr<T>::operator->() {
-  this->EnsureOk();
-  return &this->data_;
-}
-
-template <typename T>
-template <typename U>
-T StatusOr<T>::value_or(U&& default_value) const& {
-  if (ok()) {
-    return this->data_;
-  }
-  return std::forward<U>(default_value);
-}
-
-template <typename T>
-template <typename U>
-T StatusOr<T>::value_or(U&& default_value) && {
-  if (ok()) {
-    return std::move(this->data_);
-  }
-  return std::forward<U>(default_value);
-}
-
-template <typename T>
 void StatusOr<T>::IgnoreError() const {
   // no-op
 }
diff --git a/absl/status/statusor_test.cc b/absl/status/statusor_test.cc
index 17a3384..26d4235 100644
--- a/absl/status/statusor_test.cc
+++ b/absl/status/statusor_test.cc
@@ -16,6 +16,7 @@
 
 #include <array>
 #include <cstddef>
+#include <cstdint>
 #include <initializer_list>
 #include <map>
 #include <memory>
@@ -1799,4 +1800,325 @@
   EXPECT_THAT(absl::StrCat(print_me), error_matcher);
 }
 
+TEST(StatusOr, SupportsReferenceTypes) {
+  int i = 1;
+  absl::StatusOr<int&> s = i;
+  EXPECT_EQ(&i, &*s);
+  *s = 10;
+  EXPECT_EQ(i, 10);
+}
+
+TEST(StatusOr, ReferenceFromStatus) {
+  int i = 10;
+  absl::StatusOr<int&> s = i;
+  s = absl::InternalError("foo");
+  EXPECT_EQ(s.status().message(), "foo");
+
+  absl::StatusOr<int&> s2 = absl::InternalError("foo2");
+  EXPECT_EQ(s2.status().message(), "foo2");
+}
+
+TEST(StatusOr, SupportReferenceValueConstructor) {
+  int i = 1;
+  absl::StatusOr<int&> s = i;
+  absl::StatusOr<const int&> cs = i;
+  absl::StatusOr<const int&> cs2 = std::move(i);  // `T&&` to `const T&` is ok.
+
+  EXPECT_EQ(&i, &*s);
+  EXPECT_EQ(&i, &*cs);
+
+  Derived d;
+  absl::StatusOr<const Base1&> b = d;
+  EXPECT_EQ(&d, &*b);
+
+  // We disallow constructions that cause temporaries.
+  EXPECT_FALSE((std::is_constructible_v<absl::StatusOr<const int&>, double>));
+  EXPECT_FALSE(
+      (std::is_constructible_v<absl::StatusOr<const int&>, const double&>));
+  EXPECT_FALSE(
+      (std::is_constructible_v<absl::StatusOr<const absl::string_view&>,
+                               std::string>));
+
+  // We disallow constructions with wrong reference.
+  EXPECT_FALSE((std::is_constructible_v<absl::StatusOr<int&>, int&&>));
+  EXPECT_FALSE((std::is_constructible_v<absl::StatusOr<int&>, const int&>));
+}
+
+TEST(StatusOr, SupportReferenceConvertingConstructor) {
+  int i = 1;
+  absl::StatusOr<int&> s = i;
+  absl::StatusOr<const int&> cs = s;
+
+  EXPECT_EQ(&i, &*s);
+  EXPECT_EQ(&i, &*cs);
+
+  // The other direction is not allowed.
+  EXPECT_FALSE((std::is_constructible_v<absl::StatusOr<int&>,
+                                        absl::StatusOr<const int&>>));
+
+  Derived d;
+  absl::StatusOr<const Base1&> b = absl::StatusOr<const Derived&>(d);
+  EXPECT_EQ(&d, &*b);
+
+  // The other direction is not allowed.
+  EXPECT_FALSE((std::is_constructible_v<absl::StatusOr<const Derived&>,
+                                        absl::StatusOr<const Base1&>>));
+
+  // We disallow conversions that cause temporaries.
+  EXPECT_FALSE((std::is_constructible_v<absl::StatusOr<const int&>,
+                                        absl::StatusOr<int>>));
+  EXPECT_FALSE((std::is_constructible_v<absl::StatusOr<const int&>,
+                                        absl::StatusOr<double>>));
+  EXPECT_FALSE((std::is_constructible_v<absl::StatusOr<const int&>,
+                                        absl::StatusOr<const double&>>));
+  EXPECT_FALSE((std::is_constructible_v<absl::StatusOr<const double&>,
+                                        absl::StatusOr<const int&>>));
+  EXPECT_FALSE(
+      (std::is_constructible_v<absl::StatusOr<const absl::string_view&>,
+                               absl::StatusOr<std::string>>));
+
+  // We disallow constructions with wrong reference.
+  EXPECT_FALSE((std::is_constructible_v<absl::StatusOr<int&>,
+                                        absl::StatusOr<const int&>>));
+}
+
+TEST(StatusOr, SupportReferenceValueAssignment) {
+  int i = 1;
+  absl::StatusOr<int&> s = i;
+  absl::StatusOr<const int&> cs;
+  cs = i;
+  absl::StatusOr<const int&> cs2;
+  cs2 = std::move(i);  // `T&&` to `const T&` is ok.
+
+  EXPECT_EQ(&i, &*s);
+  EXPECT_EQ(&i, &*cs);
+
+  Derived d;
+  absl::StatusOr<const Base1&> b;
+  b = d;
+  EXPECT_EQ(&d, &*b);
+
+  // We disallow constructions that cause temporaries.
+  EXPECT_FALSE((std::is_assignable_v<absl::StatusOr<const int&>, double>));
+  EXPECT_FALSE(
+      (std::is_assignable_v<absl::StatusOr<const int&>, const double&>));
+  EXPECT_FALSE((std::is_assignable_v<absl::StatusOr<const absl::string_view&>,
+                                     std::string>));
+
+  // We disallow constructions with wrong reference.
+  EXPECT_FALSE((std::is_assignable_v<absl::StatusOr<int&>, int&&>));
+  EXPECT_FALSE((std::is_assignable_v<absl::StatusOr<int&>, const int&>));
+}
+
+TEST(StatusOr, SupportReferenceConvertingAssignment) {
+  int i = 1;
+  absl::StatusOr<int&> s;
+  s = i;
+  absl::StatusOr<const int&> cs;
+  cs = s;
+
+  EXPECT_EQ(&i, &*s);
+  EXPECT_EQ(&i, &*cs);
+
+  // The other direction is not allowed.
+  EXPECT_FALSE(
+      (std::is_assignable_v<absl::StatusOr<int&>, absl::StatusOr<const int&>>));
+
+  Derived d;
+  absl::StatusOr<const Base1&> b;
+  b = absl::StatusOr<const Derived&>(d);
+  EXPECT_EQ(&d, &*b);
+
+  // The other direction is not allowed.
+  EXPECT_FALSE((std::is_assignable_v<absl::StatusOr<const Derived&>,
+                                     absl::StatusOr<const Base1&>>));
+
+  // We disallow conversions that cause temporaries.
+  EXPECT_FALSE((std::is_assignable_v<absl::StatusOr<const int&>,
+                                     absl::StatusOr<const double&>>));
+  EXPECT_FALSE((std::is_assignable_v<absl::StatusOr<const int&>,
+                                     absl::StatusOr<double>>));
+  EXPECT_FALSE((std::is_assignable_v<absl::StatusOr<const absl::string_view&>,
+                                     absl::StatusOr<std::string>>));
+
+  // We disallow constructions with wrong reference.
+  EXPECT_FALSE(
+      (std::is_assignable_v<absl::StatusOr<int&>, absl::StatusOr<const int&>>));
+}
+
+TEST(StatusOr, SupportReferenceToNonReferenceConversions) {
+  int i = 17;
+  absl::StatusOr<int&> si = i;
+  absl::StatusOr<float> sf = si;
+  EXPECT_THAT(sf, IsOkAndHolds(17.));
+
+  i = 20;
+  sf = si;
+  EXPECT_THAT(sf, IsOkAndHolds(20.));
+
+  EXPECT_THAT(absl::StatusOr<int64_t>(absl::StatusOr<int&>(i)),
+              IsOkAndHolds(20));
+  EXPECT_THAT(absl::StatusOr<int64_t>(absl::StatusOr<const int&>(i)),
+              IsOkAndHolds(20));
+
+  std::string str = "str";
+  absl::StatusOr<std::string> sos = absl::StatusOr<std::string&>(str);
+  EXPECT_THAT(sos, IsOkAndHolds("str"));
+  str = "str2";
+  EXPECT_THAT(sos, IsOkAndHolds("str"));
+  sos = absl::StatusOr<std::string&>(str);
+  EXPECT_THAT(sos, IsOkAndHolds("str2"));
+
+  absl::StatusOr<absl::string_view> sosv = absl::StatusOr<std::string&>(str);
+  EXPECT_THAT(sosv, IsOkAndHolds("str2"));
+  str = "str3";
+  sosv = absl::StatusOr<std::string&>(str);
+  EXPECT_THAT(sosv, IsOkAndHolds("str3"));
+
+  absl::string_view view = "view";
+  // This way it is constructible, but not convertible because
+  // string_view->string is explicit
+  EXPECT_THAT(
+      absl::StatusOr<std::string>(absl::StatusOr<absl::string_view&>(view)),
+      IsOkAndHolds("view"));
+#if defined(ABSL_USES_STD_STRING_VIEW)
+  // The assignment doesn't work with normal absl::string_view because
+  // std::string doesn't know about it.
+  sos = absl::StatusOr<absl::string_view&>(view);
+  EXPECT_THAT(sos, IsOkAndHolds("view"));
+#endif
+
+  EXPECT_FALSE((std::is_convertible_v<absl::StatusOr<absl::string_view&>,
+                                      absl::StatusOr<std::string>>));
+}
+
+TEST(StatusOr, ReferenceOperatorStarAndArrow) {
+  std::string str = "Foo";
+  absl::StatusOr<std::string&> s = str;
+  s->assign("Bar");
+  EXPECT_EQ(str, "Bar");
+
+  *s = "Baz";
+  EXPECT_EQ(str, "Baz");
+
+  const absl::StatusOr<std::string&> cs = str;
+  // Even if the StatusOr is const, the reference it gives is non-const so we
+  // can still assign.
+  *cs = "Finally";
+  EXPECT_EQ(str, "Finally");
+
+  cs->clear();
+  EXPECT_EQ(cs.value(), str);
+  EXPECT_EQ(str, "");
+}
+
+TEST(StatusOr, ReferenceValueOr) {
+  int i = 17;
+  absl::StatusOr<int&> si = i;
+
+  int other = 20;
+  EXPECT_EQ(&i, &si.value_or(other));
+
+  si = absl::UnknownError("");
+  EXPECT_EQ(&other, &si.value_or(other));
+
+  absl::StatusOr<const int&> csi = i;
+  EXPECT_EQ(&i, &csi.value_or(1));
+
+  const auto value_or_call = [](auto&& sor, auto&& v)
+      -> decltype(std::forward<decltype(sor)>(sor).value_or(
+          std::forward<decltype(v)>(v))) {};
+  using Probe = decltype(value_or_call);
+  // Just to verify that Probe works as expected in the good cases.
+  EXPECT_TRUE((std::is_invocable_v<Probe, absl::StatusOr<const int&>, int&&>));
+  // Causes temporary conversion.
+  EXPECT_FALSE(
+      (std::is_invocable_v<Probe, absl::StatusOr<const int&>, double&&>));
+  // Const invalid.
+  EXPECT_FALSE((std::is_invocable_v<Probe, absl::StatusOr<int&>, const int&>));
+}
+
+TEST(StatusOr, ReferenceAssignmentFromStatusOr) {
+  std::vector<int> v = {1, 2, 3};
+  absl::StatusOr<int&> si = v[0];
+  absl::StatusOr<int&> si2 = v[1];
+
+  EXPECT_THAT(v, ElementsAre(1, 2, 3));
+  EXPECT_THAT(si, IsOkAndHolds(1));
+  EXPECT_THAT(si2, IsOkAndHolds(2));
+
+  // This rebinds the reference.
+  si = si2;
+  EXPECT_THAT(v, ElementsAre(1, 2, 3));
+  EXPECT_THAT(si, IsOkAndHolds(2));
+  EXPECT_THAT(si2, IsOkAndHolds(2));
+  EXPECT_EQ(&*si, &*si2);
+}
+
+TEST(StatusOr, ReferenceAssignFromReference) {
+  std::vector<int> v = {1, 2, 3};
+  absl::StatusOr<int&> si = v[0];
+
+  EXPECT_THAT(v, ElementsAre(1, 2, 3));
+  EXPECT_THAT(si, IsOkAndHolds(1));
+
+  // This rebinds the reference.
+  si = v[2];
+  EXPECT_THAT(v, ElementsAre(1, 2, 3));
+  EXPECT_THAT(si, IsOkAndHolds(3));
+  EXPECT_EQ(&*si, &v[2]);
+}
+
+TEST(StatusOr, ReferenceIsNotLifetimeBoundForStarValue) {
+  int i = 0;
+
+  // op*/value should not be LIFETIME_BOUND because the ref is not limited to
+  // the lifetime of the StatusOr.
+  int& r = *absl::StatusOr<int&>(i);
+  EXPECT_EQ(&r, &i);
+  int& r2 = absl::StatusOr<int&>(i).value();
+  EXPECT_EQ(&r2, &i);
+
+  struct S {
+    int i;
+  };
+  S s;
+  // op-> should also not be LIFETIME_BOUND for refs.
+  int& r3 = absl::StatusOr<S&>(s)->i;
+  EXPECT_EQ(&r3, &s.i);
+}
+
+template <typename Expected, typename T>
+void TestReferenceDeref() {
+  static_assert(std::is_same_v<Expected, decltype(*std::declval<T>())>);
+  static_assert(std::is_same_v<Expected, decltype(std::declval<T>().value())>);
+}
+
+TEST(StatusOr, ReferenceTypeIsMaintainedOnDeref) {
+  TestReferenceDeref<int&, absl::StatusOr<int&>&>();
+  TestReferenceDeref<int&, absl::StatusOr<int&>&&>();
+  TestReferenceDeref<int&, const absl::StatusOr<int&>&>();
+  TestReferenceDeref<int&, const absl::StatusOr<int&>&&>();
+
+  TestReferenceDeref<const int&, absl::StatusOr<const int&>&>();
+  TestReferenceDeref<const int&, absl::StatusOr<const int&>&&>();
+  TestReferenceDeref<const int&, const absl::StatusOr<const int&>&>();
+  TestReferenceDeref<const int&, const absl::StatusOr<const int&>&&>();
+
+  struct Struct {
+    int value;
+  };
+  EXPECT_TRUE(
+      (std::is_same_v<
+          int&, decltype((std::declval<absl::StatusOr<Struct&>>()->value))>));
+  EXPECT_TRUE(
+      (std::is_same_v<
+          int&,
+          decltype((std::declval<const absl::StatusOr<Struct&>>()->value))>));
+  EXPECT_TRUE(
+      (std::is_same_v<
+          const int&,
+          decltype((std::declval<absl::StatusOr<const Struct&>>()->value))>));
+}
+
 }  // namespace
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
index bb152ac..a1e5021 100644
--- a/absl/strings/BUILD.bazel
+++ b/absl/strings/BUILD.bazel
@@ -13,6 +13,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
@@ -33,16 +36,13 @@
 
 cc_library(
     name = "string_view",
-    srcs = ["string_view.cc"],
     hdrs = ["string_view.h"],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
-        "//absl/base",
         "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:nullability",
-        "//absl/base:throw_delegate",
     ],
 )
 
@@ -97,8 +97,10 @@
         "string_view.h",
     ],
     deps = [
+        ":append_and_overwrite",
         ":charset",
         ":internal",
+        ":resize_and_overwrite",
         ":string_view",
         "//absl/base",
         "//absl/base:config",
@@ -131,6 +133,7 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        ":resize_and_overwrite",
         "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:endian",
@@ -139,6 +142,60 @@
     ],
 )
 
+cc_library(
+    name = "resize_and_overwrite",
+    hdrs = ["resize_and_overwrite.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/base:dynamic_annotations",
+        "//absl/base:throw_delegate",
+    ],
+)
+
+cc_test(
+    name = "resize_and_overwrite_test",
+    srcs = ["resize_and_overwrite_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":resize_and_overwrite",
+        "//absl/base:dynamic_annotations",
+        "//absl/log:absl_check",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
+
+cc_library(
+    name = "append_and_overwrite",
+    hdrs = ["internal/append_and_overwrite.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":resize_and_overwrite",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/base:throw_delegate",
+    ],
+)
+
+cc_test(
+    name = "append_and_overwrite_test",
+    srcs = ["internal/append_and_overwrite_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":append_and_overwrite",
+        "//absl/log:absl_check",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
+
 cc_test(
     name = "match_test",
     size = "small",
@@ -350,23 +407,6 @@
     ],
 )
 
-cc_binary(
-    name = "string_view_benchmark",
-    testonly = True,
-    srcs = ["string_view_benchmark.cc"],
-    copts = ABSL_TEST_COPTS,
-    tags = ["benchmark"],
-    visibility = ["//visibility:private"],
-    deps = [
-        ":string_view",
-        ":strings",
-        "//absl/base:core_headers",
-        "//absl/base:raw_logging_internal",
-        "//absl/random",
-        "@google_benchmark//:benchmark_main",
-    ],
-)
-
 cc_test(
     name = "string_view_test",
     size = "small",
@@ -594,11 +634,13 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        ":append_and_overwrite",
         ":cord_internal",
         ":cordz_info",
         ":cordz_update_scope",
         ":cordz_update_tracker",
         ":internal",
+        ":resize_and_overwrite",
         ":strings",
         "//absl/base:config",
         "//absl/base:core_headers",
@@ -651,6 +693,7 @@
         "//absl/base",
         "//absl/base:config",
         "//absl/base:core_headers",
+        "//absl/base:no_destructor",
         "//absl/base:raw_logging_internal",
         "//absl/container:inlined_vector",
         "//absl/debugging:stacktrace",
@@ -1092,12 +1135,12 @@
     name = "resize_uninitialized_test",
     size = "small",
     srcs = [
-        "internal/resize_uninitialized.h",
         "internal/resize_uninitialized_test.cc",
     ],
     copts = ABSL_TEST_COPTS,
     visibility = ["//visibility:private"],
     deps = [
+        ":internal",
         "//absl/base:core_headers",
         "//absl/meta:type_traits",
         "@googletest//:gtest",
@@ -1462,6 +1505,7 @@
     testonly = True,
     srcs = ["internal/pow10_helper.cc"],
     hdrs = ["internal/pow10_helper.h"],
+    copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = ["//visibility:private"],
     deps = ["//absl/base:config"],
@@ -1507,3 +1551,43 @@
         "@googletest//:gtest_main",
     ],
 )
+
+cc_library(
+    name = "generic_printer",
+    srcs = [
+        "internal/generic_printer.cc",
+        "internal/generic_printer_internal.h",
+    ],
+    hdrs = ["internal/generic_printer.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
+    deps = [
+        ":str_format",
+        ":strings",
+        "//absl/base:config",
+        "//absl/log/internal:container",
+        "//absl/meta:requires",
+    ],
+)
+
+cc_test(
+    name = "generic_printer_test",
+    srcs = ["internal/generic_printer_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":generic_printer",
+        ":strings",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/container:flat_hash_map",
+        "//absl/log",
+        "//absl/status",
+        "//absl/status:statusor",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt
index 547ef26..a03943d 100644
--- a/absl/strings/CMakeLists.txt
+++ b/absl/strings/CMakeLists.txt
@@ -19,16 +19,12 @@
     string_view
   HDRS
     "string_view.h"
-  SRCS
-    "string_view.cc"
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
-    absl::base
     absl::config
     absl::core_headers
     absl::nullability
-    absl::throw_delegate
   PUBLIC
 )
 
@@ -76,7 +72,9 @@
     ${ABSL_DEFAULT_COPTS}
   DEPS
     absl::string_view
+    absl::strings_append_and_overwrite
     absl::strings_internal
+    absl::strings_resize_and_overwrite
     absl::base
     absl::bits
     absl::charset
@@ -138,9 +136,65 @@
     absl::core_headers
     absl::endian
     absl::raw_logging_internal
+    absl::strings_resize_and_overwrite
     absl::type_traits
 )
 
+absl_cc_library(
+  NAME
+    strings_resize_and_overwrite
+  HDRS
+    "resize_and_overwrite.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::config
+    absl::core_headers
+    absl::dynamic_annotations
+    absl::throw_delegate
+)
+
+absl_cc_test(
+  NAME
+    strings_resize_and_overwrite_test
+  SRCS
+    "resize_and_overwrite_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::strings_resize_and_overwrite
+    absl::absl_check
+    absl::dynamic_annotations
+    GTest::gmock_main
+)
+
+absl_cc_library(
+  NAME
+    strings_append_and_overwrite
+  HDRS
+    "internal/append_and_overwrite.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::config
+    absl::core_headers
+    absl::strings_resize_and_overwrite
+    absl::throw_delegate
+)
+
+absl_cc_test(
+  NAME
+    strings_append_and_overwrite_test
+  SRCS
+    "internal/append_and_overwrite_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::strings_resize_and_overwrite
+    absl::absl_check
+    GTest::gmock_main
+)
+
 absl_cc_test(
   NAME
     match_test
@@ -337,11 +391,11 @@
   NAME
     resize_uninitialized_test
   SRCS
-    "internal/resize_uninitialized.h"
     "internal/resize_uninitialized_test.cc"
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
+    absl::strings_internal
     absl::base
     absl::core_headers
     absl::type_traits
@@ -663,7 +717,7 @@
   SRCS
     "internal/pow10_helper.cc"
   COPTS
-    ${ABSL_TEST_COPTS}
+    ${ABSL_DEFAULT_COPTS}
   DEPS
     absl::config
   TESTONLY
@@ -845,6 +899,7 @@
     absl::cordz_statistics
     absl::cordz_update_tracker
     absl::core_headers
+    absl::no_destructor
     absl::inlined_vector
     absl::span
     absl::raw_logging_internal
@@ -1000,6 +1055,8 @@
     absl::raw_logging_internal
     absl::span
     absl::strings
+    absl::strings_append_and_overwrite
+    absl::strings_resize_and_overwrite
     absl::type_traits
     absl::weakly_mixed_integer
   PUBLIC
@@ -1199,3 +1256,40 @@
     absl::strings
     GTest::gmock_main
 )
+
+absl_cc_library(
+  NAME
+    generic_printer_internal
+  SRCS
+    "internal/generic_printer.cc"
+    "internal/generic_printer_internal.h"
+  HDRS
+    "internal/generic_printer.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::config
+    absl::strings
+    absl::str_format
+    absl::log_internal_container
+    absl::requires_internal
+)
+
+absl_cc_test(
+  NAME
+    generic_printer_test
+  SRCS
+    "internal/generic_printer_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::base
+    absl::config
+    absl::flat_hash_map
+    absl::generic_printer_internal
+    absl::log
+    absl::status
+    absl::statusor
+    absl::strings
+    GTest::gmock_main
+)
diff --git a/absl/strings/ascii.h b/absl/strings/ascii.h
index ca0747e..6a75b1f 100644
--- a/absl/strings/ascii.h
+++ b/absl/strings/ascii.h
@@ -61,6 +61,7 @@
 #include "absl/base/config.h"
 #include "absl/base/nullability.h"
 #include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/resize_and_overwrite.h"
 #include "absl/strings/string_view.h"
 
 namespace absl {
@@ -190,8 +191,10 @@
 // Creates a lowercase string from a given absl::string_view.
 [[nodiscard]] inline std::string AsciiStrToLower(absl::string_view s) {
   std::string result;
-  strings_internal::STLStringResizeUninitialized(&result, s.size());
-  ascii_internal::AsciiStrToLower(&result[0], s.data(), s.size());
+  StringResizeAndOverwrite(result, s.size(), [s](char* buf, size_t buf_size) {
+    ascii_internal::AsciiStrToLower(buf, s.data(), s.size());
+    return buf_size;
+  });
   return result;
 }
 
@@ -219,8 +222,10 @@
 // Creates an uppercase string from a given absl::string_view.
 [[nodiscard]] inline std::string AsciiStrToUpper(absl::string_view s) {
   std::string result;
-  strings_internal::STLStringResizeUninitialized(&result, s.size());
-  ascii_internal::AsciiStrToUpper(&result[0], s.data(), s.size());
+  StringResizeAndOverwrite(result, s.size(), [s](char* buf, size_t buf_size) {
+    ascii_internal::AsciiStrToUpper(buf, s.data(), s.size());
+    return buf_size;
+  });
   return result;
 }
 
diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc
index e53f914..d3014f3 100644
--- a/absl/strings/cord.cc
+++ b/absl/strings/cord.cc
@@ -44,14 +44,15 @@
 #include "absl/functional/function_ref.h"
 #include "absl/strings/cord_buffer.h"
 #include "absl/strings/escaping.h"
+#include "absl/strings/internal/append_and_overwrite.h"
 #include "absl/strings/internal/cord_data_edge.h"
 #include "absl/strings/internal/cord_internal.h"
 #include "absl/strings/internal/cord_rep_btree.h"
 #include "absl/strings/internal/cord_rep_crc.h"
 #include "absl/strings/internal/cord_rep_flat.h"
 #include "absl/strings/internal/cordz_update_tracker.h"
-#include "absl/strings/internal/resize_uninitialized.h"
 #include "absl/strings/match.h"
+#include "absl/strings/resize_and_overwrite.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
 #include "absl/strings/strip.h"
@@ -161,8 +162,10 @@
 // --------------------------------------------------------------------
 // Cord::InlineRep functions
 
-inline void Cord::InlineRep::set_data(const char* absl_nonnull data, size_t n) {
+inline void Cord::InlineRep::set_data(const char* absl_nullable data,
+                                      size_t n) {
   static_assert(kMaxInline == 15, "set_data is hard-coded for a length of 15");
+  assert(data != nullptr || n == 0);
   data_.set_inline_data(data, n);
 }
 
@@ -1053,18 +1056,20 @@
   if (!src.contents_.is_tree()) {
     src.contents_.CopyTo(dst);
   } else {
-    absl::strings_internal::STLStringResizeUninitialized(dst, src.size());
-    src.CopyToArraySlowPath(&(*dst)[0]);
+    StringResizeAndOverwrite(*dst, src.size(),
+                             [&src](char* buf, size_t buf_size) {
+                               src.CopyToArraySlowPath(buf);
+                               return buf_size;
+                             });
   }
 }
 
 void AppendCordToString(const Cord& src, std::string* absl_nonnull dst) {
-  const size_t cur_dst_size = dst->size();
-  const size_t new_dst_size = cur_dst_size + src.size();
-  absl::strings_internal::STLStringResizeUninitializedAmortized(dst,
-                                                                new_dst_size);
-  char* append_ptr = &(*dst)[cur_dst_size];
-  src.CopyToArrayImpl(append_ptr);
+  strings_internal::StringAppendAndOverwrite(
+      *dst, src.size(), [&src](char* buf, size_t buf_size) {
+        src.CopyToArrayImpl(buf);
+        return buf_size;
+      });
 }
 
 void Cord::CopyToArraySlowPath(char* absl_nonnull dst) const {
diff --git a/absl/strings/cord.h b/absl/strings/cord.h
index 7afa419..fa6eb8a 100644
--- a/absl/strings/cord.h
+++ b/absl/strings/cord.h
@@ -755,7 +755,7 @@
   // NOTE: This routine is reasonably efficient. It is roughly
   // logarithmic based on the number of chunks that make up the cord. Still,
   // if you need to iterate over the contents of a cord, you should
-  // use a CharIterator/ChunkIterator rather than call operator[] or Get()
+  // use a CharIterator/ChunkIterator rather than call operator[]
   // repeatedly in a loop.
   char operator[](size_t i) const;
 
@@ -921,7 +921,7 @@
     // Returns nullptr if holding pointer
     const char* absl_nullable data() const;
     // Discards pointer, if any
-    void set_data(const char* absl_nonnull data, size_t n);
+    void set_data(const char* absl_nullable data, size_t n);
     char* absl_nonnull set_data(size_t n);  // Write data to the result
     // Returns nullptr if holding bytes
     absl::cord_internal::CordRep* absl_nullable tree() const;
@@ -1098,8 +1098,7 @@
       hash_state = combiner.add_buffer(std::move(hash_state), chunk.data(),
                                        chunk.size());
     });
-    return H::combine(combiner.finalize(std::move(hash_state)),
-                      hash_internal::WeaklyMixedInteger{size()});
+    return combiner.finalize(std::move(hash_state));
   }
 
   friend class CrcCord;
diff --git a/absl/strings/escaping.cc b/absl/strings/escaping.cc
index e551c66..228e527 100644
--- a/absl/strings/escaping.cc
+++ b/absl/strings/escaping.cc
@@ -28,13 +28,15 @@
 #include "absl/base/internal/endian.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/internal/unaligned_access.h"
+#include "absl/base/macros.h"
 #include "absl/base/nullability.h"
 #include "absl/strings/ascii.h"
 #include "absl/strings/charset.h"
+#include "absl/strings/internal/append_and_overwrite.h"
 #include "absl/strings/internal/escaping.h"
-#include "absl/strings/internal/resize_uninitialized.h"
 #include "absl/strings/internal/utf8.h"
 #include "absl/strings/numbers.h"
+#include "absl/strings/resize_and_overwrite.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
 
@@ -76,30 +78,31 @@
 //
 //    Unescapes C escape sequences and is the reverse of CEscape().
 //
-//    If `src` is valid, stores the unescaped string `dst`, and returns
-//    true. Otherwise returns false and optionally stores the error
-//    description in `error`. Set `error` to nullptr to disable error
-//    reporting.
+//    If `src` is valid, stores the unescaped string in `dst` and the length of
+//    unescaped string in `dst_size`, and returns true. Otherwise returns false
+//    and optionally stores the error description in `error`. Set `error` to
+//    nullptr to disable error reporting.
 //
-//    `src` and `dst` may use the same underlying buffer.
+//    `src` and `dst` may use the same underlying buffer (but keep in mind
+//    that if this returns an error, it will leave both `src` and `dst` in
+//    an unspecified state because they are using the same underlying buffer.)
+//    `dst` must have at least as much space as `src`.
 // ----------------------------------------------------------------------
 
 bool CUnescapeInternal(absl::string_view src, bool leave_nulls_escaped,
-                       std::string* absl_nonnull dst,
+                       char* absl_nonnull dst, size_t* absl_nonnull dst_size,
                        std::string* absl_nullable error) {
-  strings_internal::STLStringResizeUninitialized(dst, src.size());
-
   absl::string_view::size_type p = 0;  // Current src position.
-  std::string::size_type d = 0;        // Current dst position.
+  size_t d = 0;                        // Current dst position.
 
   // When unescaping in-place, skip any prefix that does not have escaping.
-  if (src.data() == dst->data()) {
+  if (src.data() == dst) {
     while (p < src.size() && src[p] != '\\') p++, d++;
   }
 
   while (p < src.size()) {
     if (src[p] != '\\') {
-      (*dst)[d++] = src[p++];
+      dst[d++] = src[p++];
     } else {
       if (++p >= src.size()) {  // skip past the '\\'
         if (error != nullptr) {
@@ -108,17 +111,19 @@
         return false;
       }
       switch (src[p]) {
-        case 'a':  (*dst)[d++] = '\a';  break;
-        case 'b':  (*dst)[d++] = '\b';  break;
-        case 'f':  (*dst)[d++] = '\f';  break;
-        case 'n':  (*dst)[d++] = '\n';  break;
-        case 'r':  (*dst)[d++] = '\r';  break;
-        case 't':  (*dst)[d++] = '\t';  break;
-        case 'v':  (*dst)[d++] = '\v';  break;
-        case '\\': (*dst)[d++] = '\\';  break;
-        case '?':  (*dst)[d++] = '\?';  break;
-        case '\'': (*dst)[d++] = '\'';  break;
-        case '"':  (*dst)[d++] = '\"';  break;
+          // clang-format off
+        case 'a':  dst[d++] = '\a';  break;
+        case 'b':  dst[d++] = '\b';  break;
+        case 'f':  dst[d++] = '\f';  break;
+        case 'n':  dst[d++] = '\n';  break;
+        case 'r':  dst[d++] = '\r';  break;
+        case 't':  dst[d++] = '\t';  break;
+        case 'v':  dst[d++] = '\v';  break;
+        case '\\': dst[d++] = '\\';  break;
+        case '?':  dst[d++] = '\?';  break;
+        case '\'': dst[d++] = '\'';  break;
+        case '"':  dst[d++] = '\"';  break;
+        // clang-format on
         case '0':
         case '1':
         case '2':
@@ -145,13 +150,13 @@
           }
           if ((ch == 0) && leave_nulls_escaped) {
             // Copy the escape sequence for the null character
-            (*dst)[d++] = '\\';
+            dst[d++] = '\\';
             while (octal_start <= p) {
-              (*dst)[d++] = src[octal_start++];
+              dst[d++] = src[octal_start++];
             }
             break;
           }
-          (*dst)[d++] = static_cast<char>(ch);
+          dst[d++] = static_cast<char>(ch);
           break;
         }
         case 'x':
@@ -185,13 +190,13 @@
           }
           if ((ch == 0) && leave_nulls_escaped) {
             // Copy the escape sequence for the null character
-            (*dst)[d++] = '\\';
+            dst[d++] = '\\';
             while (hex_start <= p) {
-              (*dst)[d++] = src[hex_start++];
+              dst[d++] = src[hex_start++];
             }
             break;
           }
-          (*dst)[d++] = static_cast<char>(ch);
+          dst[d++] = static_cast<char>(ch);
           break;
         }
         case 'u': {
@@ -218,16 +223,16 @@
           }
           if ((rune == 0) && leave_nulls_escaped) {
             // Copy the escape sequence for the null character
-            (*dst)[d++] = '\\';
+            dst[d++] = '\\';
             while (hex_start <= p) {
-              (*dst)[d++] = src[hex_start++];
+              dst[d++] = src[hex_start++];
             }
             break;
           }
           if (IsSurrogate(rune, src.substr(hex_start, 5), error)) {
             return false;
           }
-          d += strings_internal::EncodeUTF8Char(dst->data() + d, rune);
+          d += strings_internal::EncodeUTF8Char(dst + d, rune);
           break;
         }
         case 'U': {
@@ -267,17 +272,17 @@
           }
           if ((rune == 0) && leave_nulls_escaped) {
             // Copy the escape sequence for the null character
-            (*dst)[d++] = '\\';
+            dst[d++] = '\\';
             // U00000000
             while (hex_start <= p) {
-              (*dst)[d++] = src[hex_start++];
+              dst[d++] = src[hex_start++];
             }
             break;
           }
           if (IsSurrogate(rune, src.substr(hex_start, 9), error)) {
             return false;
           }
-          d += strings_internal::EncodeUTF8Char(dst->data() + d, rune);
+          d += strings_internal::EncodeUTF8Char(dst + d, rune);
           break;
         }
         default: {
@@ -291,7 +296,7 @@
     }
   }
 
-  dst->erase(d);
+  *dst_size = d;
   return true;
 }
 
@@ -441,22 +446,22 @@
 
   // We keep 3 slop bytes so that we can call `little_endian::Store32`
   // invariably regardless of the length of the escaped character.
-  constexpr size_t slop_bytes = 3;
+  constexpr size_t kSlopBytes = 3;
   size_t cur_dest_len = dest->size();
-  size_t new_dest_len = cur_dest_len + escaped_len + slop_bytes;
-  ABSL_INTERNAL_CHECK(new_dest_len > cur_dest_len, "std::string size overflow");
-  strings_internal::AppendUninitializedTraits<std::string>::Append(
-      dest, escaped_len + slop_bytes);
-  char* append_ptr = &(*dest)[cur_dest_len];
-
-  for (char c : src) {
-    unsigned char uc = static_cast<unsigned char>(c);
-    size_t char_len = kCEscapedLen[uc];
-    uint32_t little_endian_uint32 = kCEscapedLittleEndianUint32Array[uc];
-    little_endian::Store32(append_ptr, little_endian_uint32);
-    append_ptr += char_len;
-  }
-  dest->resize(new_dest_len - slop_bytes);
+  size_t append_buf_len = cur_dest_len + escaped_len + kSlopBytes;
+  ABSL_INTERNAL_CHECK(append_buf_len > cur_dest_len,
+                      "std::string size overflow");
+  strings_internal::StringAppendAndOverwrite(
+      *dest, append_buf_len, [src, escaped_len](char* append_ptr, size_t) {
+        for (char c : src) {
+          unsigned char uc = static_cast<unsigned char>(c);
+          size_t char_len = kCEscapedLen[uc];
+          uint32_t little_endian_uint32 = kCEscapedLittleEndianUint32Array[uc];
+          little_endian::Store32(append_ptr, little_endian_uint32);
+          append_ptr += char_len;
+        }
+        return escaped_len;
+      });
 }
 
 // Reverses the mapping in Base64EscapeInternal; see that method's
@@ -807,27 +812,22 @@
   // 4 characters.  Any leftover chars are added directly for good measure.
   const size_t dest_len = 3 * (slen / 4) + (slen % 4);
 
-  strings_internal::STLStringResizeUninitialized(dest, dest_len);
-
-  // We are getting the destination buffer by getting the beginning of the
-  // string and converting it into a char *.
-  size_t len;
-  const bool ok =
-      Base64UnescapeInternal(src, slen, &(*dest)[0], dest_len, unbase64, &len);
-  if (!ok) {
-    dest->clear();
-    return false;
-  }
-
-  // could be shorter if there was padding
-  assert(len <= dest_len);
-  dest->erase(len);
-
-  return true;
+  bool ok;
+  StringResizeAndOverwrite(
+      *dest, dest_len, [src, slen, unbase64, &ok](char* buf, size_t buf_size) {
+        size_t len;
+        ok = Base64UnescapeInternal(src, slen, buf, buf_size, unbase64, &len);
+        if (!ok) {
+          len = 0;
+        }
+        assert(len <= buf_size);  // Could be shorter if there was padding.
+        return len;
+      });
+  return ok;
 }
 
 /* clang-format off */
-constexpr std::array<char, 256> kHexValueLenient = {
+constexpr std::array<uint8_t, 256> kHexValueLenient = {
     0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -846,7 +846,7 @@
     0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 };
 
-constexpr std::array<signed char, 256> kHexValueStrict = {
+constexpr std::array<int8_t, 256> kHexValueStrict = {
     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
@@ -874,19 +874,15 @@
                               size_t num) {
   for (size_t i = 0; i < num; i++) {
     to[i] = static_cast<char>(kHexValueLenient[from[i * 2] & 0xFF] << 4) +
-            (kHexValueLenient[from[i * 2 + 1] & 0xFF]);
+            static_cast<char>(kHexValueLenient[from[i * 2 + 1] & 0xFF]);
   }
 }
 
-// This is a templated function so that T can be either a char* or a
-// std::string.
-template <typename T>
-void BytesToHexStringInternal(const unsigned char* absl_nullable src, T dest,
-                              size_t num) {
-  auto dest_ptr = &dest[0];
-  for (auto src_ptr = src; src_ptr != (src + num); ++src_ptr, dest_ptr += 2) {
+void BytesToHexStringInternal(const unsigned char* absl_nullable src,
+                              char* dest, size_t num) {
+  for (auto src_ptr = src; src_ptr != (src + num); ++src_ptr, dest += 2) {
     const char* hex_p = &numbers_internal::kHexTable[*src_ptr * 2];
-    std::copy(hex_p, hex_p + 2, dest_ptr);
+    std::copy(hex_p, hex_p + 2, dest);
   }
 }
 
@@ -897,9 +893,35 @@
 //
 // See CUnescapeInternal() for implementation details.
 // ----------------------------------------------------------------------
+
 bool CUnescape(absl::string_view source, std::string* absl_nonnull dest,
                std::string* absl_nullable error) {
-  return CUnescapeInternal(source, kUnescapeNulls, dest, error);
+  bool success;
+
+  // `CUnescape()` allows for in-place unescaping, which means `source` may
+  // alias `*dest`.  However, absl::StringResizeAndOverwrite() invalidates all
+  // iterators, pointers, and references into the string, regardless whether
+  // reallocation occurs. Therefore we need to avoid calling
+  // absl::StringResizeAndOverwrite() when `source.data() ==
+  // dest->data()`. Comparing the sizes is sufficient to cover this case.
+  if (dest->size() >= source.size()) {
+    size_t dest_size = 0;
+    success = CUnescapeInternal(source, kUnescapeNulls, dest->data(),
+                                &dest_size, error);
+    ABSL_ASSERT(dest_size <= dest->size());
+    dest->erase(dest_size);
+  } else {
+    StringResizeAndOverwrite(
+        *dest, source.size(),
+        [source, error, &success](char* buf, size_t buf_size) {
+          size_t dest_size = 0;
+          success =
+              CUnescapeInternal(source, kUnescapeNulls, buf, &dest_size, error);
+          ABSL_ASSERT(dest_size <= buf_size);
+          return dest_size;
+        });
+  }
+  return success;
 }
 
 std::string CEscape(absl::string_view src) {
@@ -966,19 +988,25 @@
     return false;
   }
 
-  absl::strings_internal::STLStringResizeUninitialized(&output, num_bytes);
-  auto hex_p = hex.cbegin();
-  for (std::string::iterator bin_p = output.begin(); bin_p != output.end();
-       ++bin_p) {
-    int h1 = absl::kHexValueStrict[static_cast<size_t>(*hex_p++)];
-    int h2 = absl::kHexValueStrict[static_cast<size_t>(*hex_p++)];
-    if (h1 == -1 || h2 == -1) {
-      output.resize(static_cast<size_t>(bin_p - output.begin()));
-      return false;
-    }
-    *bin_p = static_cast<char>((h1 << 4) + h2);
-  }
+  StringResizeAndOverwrite(
+      output, num_bytes, [hex](char* buf, size_t buf_size) {
+        auto hex_p = hex.cbegin();
+        for (size_t i = 0; i < buf_size; ++i) {
+          int h1 = absl::kHexValueStrict[static_cast<size_t>(
+              static_cast<uint8_t>(*hex_p++))];
+          int h2 = absl::kHexValueStrict[static_cast<size_t>(
+              static_cast<uint8_t>(*hex_p++))];
+          if (h1 == -1 || h2 == -1) {
+            return size_t{0};
+          }
+          buf[i] = static_cast<char>((h1 << 4) + h2);
+        }
+        return buf_size;
+      });
 
+  if (output.size() != num_bytes) {
+    return false;
+  }
   *bytes = std::move(output);
   return true;
 }
@@ -986,16 +1014,22 @@
 std::string HexStringToBytes(absl::string_view from) {
   std::string result;
   const auto num = from.size() / 2;
-  strings_internal::STLStringResizeUninitialized(&result, num);
-  absl::HexStringToBytesInternal<std::string&>(from.data(), result, num);
+  StringResizeAndOverwrite(result, num, [from](char* buf, size_t buf_size) {
+    absl::HexStringToBytesInternal<char*>(from.data(), buf, buf_size);
+    return buf_size;
+  });
   return result;
 }
 
 std::string BytesToHexString(absl::string_view from) {
   std::string result;
-  strings_internal::STLStringResizeUninitialized(&result, 2 * from.size());
-  absl::BytesToHexStringInternal<std::string&>(
-      reinterpret_cast<const unsigned char*>(from.data()), result, from.size());
+  StringResizeAndOverwrite(
+      result, 2 * from.size(), [from](char* buf, size_t buf_size) {
+        absl::BytesToHexStringInternal(
+            reinterpret_cast<const unsigned char*>(from.data()), buf,
+            from.size());
+        return buf_size;
+      });
   return result;
 }
 
diff --git a/absl/strings/escaping_test.cc b/absl/strings/escaping_test.cc
index 4786c88..08618aa 100644
--- a/absl/strings/escaping_test.cc
+++ b/absl/strings/escaping_test.cc
@@ -733,6 +733,10 @@
   bytes = "abc";
   EXPECT_TRUE(absl::HexStringToBytes("", &bytes));
   EXPECT_EQ("", bytes);  // Results in empty output.
+
+  // Ensure there is no sign extension bug on a signed char.
+  hex.assign("\xC8" "b", 2);
+  EXPECT_FALSE(absl::HexStringToBytes(hex, &bytes));
 }
 
 TEST(HexAndBack, HexStringToBytes_and_BytesToHexString) {
diff --git a/absl/strings/internal/append_and_overwrite.h b/absl/strings/internal/append_and_overwrite.h
new file mode 100644
index 0000000..9dec73b
--- /dev/null
+++ b/absl/strings/internal/append_and_overwrite.h
@@ -0,0 +1,93 @@
+// Copyright 2025 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.
+
+#ifndef ABSL_STRINGS_INTERNAL_APPEND_AND_OVERWRITE_H_
+#define ABSL_STRINGS_INTERNAL_APPEND_AND_OVERWRITE_H_
+
+#include "absl/base/config.h"
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
+#include "absl/strings/resize_and_overwrite.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+// An internal-only variant similar to `absl::StringResizeAndOverwrite()`
+// optimized for repeated appends to a string that uses exponential growth so
+// that the amortized complexity of increasing the string size by a small amount
+// is O(1), in contrast to O(str.size()) in the case of precise growth. Use of
+// this function is subtle; see https://reviews.llvm.org/D102727 to understand
+// the tradeoffs.
+//
+// Appends at most `append_n` characters to `str`, using the user-provided
+// operation `append_op` to modify the possibly indeterminate
+// contents. `append_op` must return the length of the buffer appended to `str`.
+//
+// Invalidates all iterators, pointers, and references into `str`, regardless
+// of whether reallocation occurs.
+//
+// `append_op(value_type* buf, size_t buf_size)` is allowed to write
+// `value_type{}` to `buf[buf_size]`, which facilitiates interoperation with
+// functions that write a trailing NUL.
+template <typename T, typename Op>
+void StringAppendAndOverwrite(T& str, typename T::size_type append_n,
+                              Op append_op) {
+  if (ABSL_PREDICT_FALSE(append_n > str.max_size() - str.size())) {
+    absl::base_internal::ThrowStdLengthError(
+        "absl::strings_internal::StringAppendAndOverwrite");
+  }
+
+  auto old_size = str.size();
+  auto resize = old_size + append_n;
+
+  if (resize > str.capacity()) {
+    // Make sure to always grow by at least a factor of 2x.
+    const auto min_growth = str.capacity();
+    if (ABSL_PREDICT_FALSE(str.capacity() > str.max_size() - min_growth)) {
+      resize = str.max_size();
+    } else if (resize < str.capacity() + min_growth) {
+      resize = str.capacity() + min_growth;
+    }
+  } else {
+    resize = str.capacity();
+  }
+
+  // Avoid calling StringResizeAndOverwrite() here since it does an MSAN
+  // verification on the entire string. StringResizeAndOverwriteImpl() is
+  // StringResizeAndOverwrite() without the MSAN verification.
+  StringResizeAndOverwriteImpl(
+      str, resize,
+      [old_size, append_n, do_append = std::move(append_op)](
+          typename T::value_type* data_ptr, typename T::size_type) mutable {
+        auto num_appended =
+            std::move(do_append)(data_ptr + old_size, append_n);
+        ABSL_HARDENING_ASSERT(num_appended >= 0 && num_appended <= append_n);
+        return old_size + num_appended;
+      });
+
+#if defined(ABSL_HAVE_MEMORY_SANITIZER)
+  // Only check the region appended to. Checking the entire string would cause
+  // pathological quadratic verfication on repeated small appends.
+  __msan_check_mem_is_initialized(str.data() + old_size, str.size() - old_size);
+#endif
+}
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+
+#endif  // ABSL_STRINGS_INTERNAL_APPEND_AND_OVERWRITE_H_
diff --git a/absl/strings/internal/append_and_overwrite_test.cc b/absl/strings/internal/append_and_overwrite_test.cc
new file mode 100644
index 0000000..aa9c7a1
--- /dev/null
+++ b/absl/strings/internal/append_and_overwrite_test.cc
@@ -0,0 +1,95 @@
+// Copyright 2025 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/strings/internal/append_and_overwrite.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "absl/log/absl_check.h"
+
+namespace {
+
+struct AppendAndOverwriteParam {
+  size_t initial_size;
+  size_t append_capacity;
+  size_t append_size;
+};
+
+using StringAppendAndOverwriteTest =
+    ::testing::TestWithParam<AppendAndOverwriteParam>;
+
+TEST_P(StringAppendAndOverwriteTest, StringAppendAndOverwrite) {
+  const auto& param = GetParam();
+  std::string s(param.initial_size, 'a');
+  absl::strings_internal::StringAppendAndOverwrite(
+      s, param.append_capacity, [&](char* p, size_t n) {
+        ABSL_CHECK_EQ(n, param.append_capacity);
+        std::fill_n(p, param.append_size, 'b');
+        p[param.append_size] = '\0';
+        return param.append_size;
+      });
+
+  std::string expected =
+      std::string(param.initial_size, 'a') +
+      std::string(param.append_size,
+                  'b');
+
+  EXPECT_EQ(s, expected);
+  EXPECT_EQ(s.c_str()[s.size()], '\0');
+}
+
+// clang-format off
+INSTANTIATE_TEST_SUITE_P(StringAppendAndOverwriteTestSuite,
+                         StringAppendAndOverwriteTest,
+                         ::testing::ValuesIn<AppendAndOverwriteParam>({
+                             {0,  10,  5},
+                             {10, 10, 10},
+                             {10, 15, 15},
+                             {10, 20, 15},
+                             {10, 40, 40},
+                             {10, 50, 40},
+                             {30, 35, 35},
+                             {30, 45, 35},
+                             {10, 30, 15},
+                         }));
+// clang-format on
+
+TEST(StringAppendAndOverwrite, AmortizedComplexity) {
+  std::string str;
+  std::string expected;
+  size_t prev_cap = str.capacity();
+  int cap_increase_count = 0;
+  for (int i = 0; i < 1000; ++i) {
+    char c = static_cast<char>('a' + (i % 26));
+    absl::strings_internal::StringAppendAndOverwrite(
+        str, 1, [c](char* buf, size_t buf_size) {
+          ABSL_CHECK_EQ(buf_size, 1);
+          buf[0] = c;
+          return size_t{1};
+        });
+    expected.push_back(c);
+    EXPECT_EQ(str, expected);
+    size_t new_cap = str.capacity();
+    if (new_cap > prev_cap) {
+      ++cap_increase_count;
+    }
+    prev_cap = new_cap;
+  }
+  EXPECT_LT(cap_increase_count, 50);
+}
+
+}  // namespace
diff --git a/absl/strings/internal/cord_internal.h b/absl/strings/internal/cord_internal.h
index cf1f703..6637561 100644
--- a/absl/strings/internal/cord_internal.h
+++ b/absl/strings/internal/cord_internal.h
@@ -381,6 +381,8 @@
     this->releaser_invoker = &Release;
   }
 
+  const Releaser* releaser() const { return &this->template get<0>(); }
+
   ~CordRepExternalImpl() {
     InvokeReleaser(Rank1{}, std::move(this->template get<0>()),
                    absl::string_view(base, length));
@@ -915,8 +917,6 @@
 
 inline void CordRep::Unref(CordRep* rep) {
   assert(rep != nullptr);
-  // Expect refcount to be 0. Avoiding the cost of an atomic decrement should
-  // typically outweigh the cost of an extra branch checking for ref == 1.
   if (ABSL_PREDICT_FALSE(!rep->refcount.DecrementExpectHighRefcount())) {
     Destroy(rep);
   }
diff --git a/absl/strings/internal/cord_rep_btree_test.cc b/absl/strings/internal/cord_rep_btree_test.cc
index 840acf9..0950617 100644
--- a/absl/strings/internal/cord_rep_btree_test.cc
+++ b/absl/strings/internal/cord_rep_btree_test.cc
@@ -1230,16 +1230,16 @@
 
     if (api != 3) {
       // Does not contain contents
-      EXPECT_THAT(str, Not(AnyOf((HasSubstr("data = \"Hello world\""),
-                                  HasSubstr("data = \"Hello external\""),
-                                  HasSubstr("data = \"ello w\""),
-                                  HasSubstr("data = \"llo ext\"")))));
+      EXPECT_THAT(str, Not(AnyOf(HasSubstr("data = \"Hello world\""),
+                                 HasSubstr("data = \"Hello external\""),
+                                 HasSubstr("data = \"ello w\""),
+                                 HasSubstr("data = \"llo ext\""))));
     } else {
       // Contains contents
-      EXPECT_THAT(str, AllOf((HasSubstr("data = \"Hello world\""),
-                              HasSubstr("data = \"Hello external\""),
-                              HasSubstr("data = \"ello w\""),
-                              HasSubstr("data = \"llo ext\""))));
+      EXPECT_THAT(str, AllOf(HasSubstr("data = \"Hello world\""),
+                             HasSubstr("data = \"Hello external\""),
+                             HasSubstr("data = \"ello w\""),
+                             HasSubstr("data = \"llo ext\"")));
     }
   }
 
diff --git a/absl/strings/internal/cord_rep_flat.h b/absl/strings/internal/cord_rep_flat.h
index 27c4b21..bf999fb 100644
--- a/absl/strings/internal/cord_rep_flat.h
+++ b/absl/strings/internal/cord_rep_flat.h
@@ -20,6 +20,7 @@
 #include <cstdint>
 #include <memory>
 
+#include "absl/base/attributes.h"
 #include "absl/base/config.h"
 #include "absl/base/macros.h"
 #include "absl/strings/internal/cord_internal.h"
@@ -75,6 +76,9 @@
 
 // RoundUp logically performs `((n + m - 1) / m) * m` to round up to the nearest
 // multiple of `m`, optimized for the invariant that `m` is a power of 2.
+// Android local modification: disable unsigned integer overflow sanitizer here
+// to support enabling it in the clients.
+ABSL_ATTRIBUTE_NO_SANITIZE_UNSIGNED_OVERFLOW
 constexpr size_t RoundUp(size_t n, size_t m) {
   return (n + m - 1) & (0 - m);
 }
diff --git a/absl/strings/internal/cordz_handle.cc b/absl/strings/internal/cordz_handle.cc
index 53d5f52..a4f47f0 100644
--- a/absl/strings/internal/cordz_handle.cc
+++ b/absl/strings/internal/cordz_handle.cc
@@ -54,7 +54,7 @@
 CordzHandle::CordzHandle(bool is_snapshot) : is_snapshot_(is_snapshot) {
   Queue& global_queue = GlobalQueue();
   if (is_snapshot) {
-    MutexLock lock(&global_queue.mutex);
+    MutexLock lock(global_queue.mutex);
     CordzHandle* dq_tail = global_queue.dq_tail.load(std::memory_order_acquire);
     if (dq_tail != nullptr) {
       dq_prev_ = dq_tail;
@@ -69,7 +69,7 @@
   if (is_snapshot_) {
     std::vector<CordzHandle*> to_delete;
     {
-      MutexLock lock(&global_queue.mutex);
+      MutexLock lock(global_queue.mutex);
       CordzHandle* next = dq_next_;
       if (dq_prev_ == nullptr) {
         // We were head of the queue, delete every CordzHandle until we reach
@@ -103,7 +103,7 @@
   if (handle) {
     Queue& queue = GlobalQueue();
     if (!handle->SafeToDelete()) {
-      MutexLock lock(&queue.mutex);
+      MutexLock lock(queue.mutex);
       CordzHandle* dq_tail = queue.dq_tail.load(std::memory_order_acquire);
       if (dq_tail != nullptr) {
         handle->dq_prev_ = dq_tail;
@@ -119,7 +119,7 @@
 std::vector<const CordzHandle*> CordzHandle::DiagnosticsGetDeleteQueue() {
   std::vector<const CordzHandle*> handles;
   Queue& global_queue = GlobalQueue();
-  MutexLock lock(&global_queue.mutex);
+  MutexLock lock(global_queue.mutex);
   CordzHandle* dq_tail = global_queue.dq_tail.load(std::memory_order_acquire);
   for (const CordzHandle* p = dq_tail; p; p = p->dq_prev_) {
     handles.push_back(p);
@@ -134,7 +134,7 @@
   if (handle->is_snapshot_) return false;
   bool snapshot_found = false;
   Queue& global_queue = GlobalQueue();
-  MutexLock lock(&global_queue.mutex);
+  MutexLock lock(global_queue.mutex);
   for (const CordzHandle* p = global_queue.dq_tail; p; p = p->dq_prev_) {
     if (p == handle) return !snapshot_found;
     if (p == this) snapshot_found = true;
@@ -151,7 +151,7 @@
   }
 
   Queue& global_queue = GlobalQueue();
-  MutexLock lock(&global_queue.mutex);
+  MutexLock lock(global_queue.mutex);
   for (const CordzHandle* p = dq_next_; p != nullptr; p = p->dq_next_) {
     if (!p->is_snapshot()) {
       handles.push_back(p);
diff --git a/absl/strings/internal/cordz_info.cc b/absl/strings/internal/cordz_info.cc
index 4baaecd..38fb473 100644
--- a/absl/strings/internal/cordz_info.cc
+++ b/absl/strings/internal/cordz_info.cc
@@ -17,7 +17,8 @@
 #include <cstdint>
 
 #include "absl/base/config.h"
-#include "absl/base/internal/spinlock.h"
+#include "absl/base/const_init.h"
+#include "absl/base/no_destructor.h"
 #include "absl/container/inlined_vector.h"
 #include "absl/debugging/stacktrace.h"
 #include "absl/strings/internal/cord_internal.h"
@@ -34,8 +35,6 @@
 ABSL_NAMESPACE_BEGIN
 namespace cord_internal {
 
-ABSL_CONST_INIT CordzInfo::List CordzInfo::global_list_{absl::kConstInit};
-
 namespace {
 
 // CordRepAnalyzer performs the analysis of a cord.
@@ -221,24 +220,32 @@
 
 }  // namespace
 
+CordzInfo::List* CordzInfo::GlobalList() {
+  static absl::NoDestructor<CordzInfo::List> list;
+  return list.get();
+}
+
 CordzInfo* CordzInfo::Head(const CordzSnapshot& snapshot) {
   ABSL_ASSERT(snapshot.is_snapshot());
 
-  // We can do an 'unsafe' load of 'head', as we are guaranteed that the
-  // instance it points to is kept alive by the provided CordzSnapshot, so we
-  // can simply return the current value using an acquire load.
+  // We obtain the lock here as we must synchronize the first call into the list
+  // with any concurrent 'Untrack()` operation to avoid any read in the list to
+  // reorder before the observation of the thread 'untracking a cord' of the
+  // delete queue being empty or not. After this all next observations are safe
+  // as we have established all subsequent untracks will be queued for delete.
   // We do enforce in DEBUG builds that the 'head' value is present in the
-  // delete queue: ODR violations may lead to 'snapshot' and 'global_list_'
+  // delete queue: ODR violations may lead to 'snapshot' and 'global_list'
   // being in different libraries / modules.
-  CordzInfo* head = global_list_.head.load(std::memory_order_acquire);
-  ABSL_ASSERT(snapshot.DiagnosticsHandleIsSafeToInspect(head));
-  return head;
+  auto global_list = GlobalList();
+  absl::MutexLock l(global_list->mutex);
+  ABSL_ASSERT(snapshot.DiagnosticsHandleIsSafeToInspect(global_list->head));
+  return global_list->head;
 }
 
 CordzInfo* CordzInfo::Next(const CordzSnapshot& snapshot) const {
   ABSL_ASSERT(snapshot.is_snapshot());
 
-  // Similar to the 'Head()' function, we do not need a mutex here.
+  // We do not need a lock here. See also comments in Head().
   CordzInfo* next = ci_next_.load(std::memory_order_acquire);
   ABSL_ASSERT(snapshot.DiagnosticsHandleIsSafeToInspect(this));
   ABSL_ASSERT(snapshot.DiagnosticsHandleIsSafeToInspect(next));
@@ -327,22 +334,21 @@
 }
 
 void CordzInfo::Track() {
-  SpinLockHolder l(&list_->mutex);
-
-  CordzInfo* const head = list_->head.load(std::memory_order_acquire);
+  absl::MutexLock l(list_->mutex);
+  CordzInfo* const head = list_->head;
   if (head != nullptr) {
     head->ci_prev_.store(this, std::memory_order_release);
   }
   ci_next_.store(head, std::memory_order_release);
-  list_->head.store(this, std::memory_order_release);
+  list_->head = this;
 }
 
 void CordzInfo::Untrack() {
   ODRCheck();
   {
-    SpinLockHolder l(&list_->mutex);
+    absl::MutexLock l(list_->mutex);
 
-    CordzInfo* const head = list_->head.load(std::memory_order_acquire);
+    CordzInfo* const head = list_->head;
     CordzInfo* const next = ci_next_.load(std::memory_order_acquire);
     CordzInfo* const prev = ci_prev_.load(std::memory_order_acquire);
 
@@ -356,7 +362,7 @@
       prev->ci_next_.store(next, std::memory_order_release);
     } else {
       ABSL_ASSERT(head == this);
-      list_->head.store(next, std::memory_order_release);
+      list_->head = next;
     }
   }
 
@@ -370,7 +376,7 @@
 
   // We are likely part of a snapshot, extend the life of the CordRep
   {
-    absl::MutexLock lock(&mutex_);
+    absl::MutexLock lock(mutex_);
     if (rep_) CordRep::Ref(rep_);
   }
   CordzHandle::Delete(this);
@@ -378,14 +384,14 @@
 
 void CordzInfo::Lock(MethodIdentifier method)
     ABSL_EXCLUSIVE_LOCK_FUNCTION(mutex_) {
-  mutex_.Lock();
+  mutex_.lock();
   update_tracker_.LossyAdd(method);
   assert(rep_);
 }
 
 void CordzInfo::Unlock() ABSL_UNLOCK_FUNCTION(mutex_) {
   bool tracked = rep_ != nullptr;
-  mutex_.Unlock();
+  mutex_.unlock();
   if (!tracked) {
     Untrack();
   }
diff --git a/absl/strings/internal/cordz_info.h b/absl/strings/internal/cordz_info.h
index aa92a8f..c03f2f2 100644
--- a/absl/strings/internal/cordz_info.h
+++ b/absl/strings/internal/cordz_info.h
@@ -20,8 +20,8 @@
 #include <functional>
 
 #include "absl/base/config.h"
+#include "absl/base/const_init.h"
 #include "absl/base/internal/raw_logging.h"
-#include "absl/base/internal/spinlock.h"
 #include "absl/base/thread_annotations.h"
 #include "absl/strings/internal/cord_internal.h"
 #include "absl/strings/internal/cordz_functions.h"
@@ -121,12 +121,10 @@
   CordzInfo& operator=(const CordzInfo&) = delete;
 
   // Retrieves the oldest existing CordzInfo.
-  static CordzInfo* Head(const CordzSnapshot& snapshot)
-      ABSL_NO_THREAD_SAFETY_ANALYSIS;
+  static CordzInfo* Head(const CordzSnapshot& snapshot);
 
   // Retrieves the next oldest existing CordzInfo older than 'this' instance.
-  CordzInfo* Next(const CordzSnapshot& snapshot) const
-      ABSL_NO_THREAD_SAFETY_ANALYSIS;
+  CordzInfo* Next(const CordzSnapshot& snapshot) const;
 
   // Locks this instance for the update identified by `method`.
   // Increases the count for `method` in `update_tracker`.
@@ -185,20 +183,15 @@
   int64_t sampling_stride() const { return sampling_stride_; }
 
  private:
-  using SpinLock = absl::base_internal::SpinLock;
-  using SpinLockHolder = ::absl::base_internal::SpinLockHolder;
-
   // Global cordz info list. CordzInfo stores a pointer to the global list
   // instance to harden against ODR violations.
   struct List {
-    constexpr explicit List(absl::ConstInitType)
-        : mutex(absl::kConstInit,
-                absl::base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL) {}
-
-    SpinLock mutex;
-    std::atomic<CordzInfo*> head ABSL_GUARDED_BY(mutex){nullptr};
+    absl::Mutex mutex;
+    CordzInfo* head ABSL_GUARDED_BY(mutex){nullptr};
   };
 
+  static List* GlobalList();
+
   static constexpr size_t kMaxStackDepth = 64;
 
   explicit CordzInfo(CordRep* rep, const CordzInfo* src,
@@ -223,7 +216,7 @@
 
   void ODRCheck() const {
 #ifndef NDEBUG
-    ABSL_RAW_CHECK(list_ == &global_list_, "ODR violation in Cord");
+    ABSL_RAW_CHECK(list_ == GlobalList(), "ODR violation in Cord");
 #endif
   }
 
@@ -233,12 +226,11 @@
   static void MaybeTrackCordImpl(InlineData& cord, const InlineData& src,
                                  MethodIdentifier method);
 
-  ABSL_CONST_INIT static List global_list_;
-  List* const list_ = &global_list_;
+  List* const list_ = GlobalList();
 
   // ci_prev_ and ci_next_ require the global list mutex to be held.
   // Unfortunately we can't use thread annotations such that the thread safety
-  // analysis understands that list_ and global_list_ are one and the same.
+  // analysis understands that list_ and GlobalList() are one and the same.
   std::atomic<CordzInfo*> ci_prev_{nullptr};
   std::atomic<CordzInfo*> ci_next_{nullptr};
 
@@ -296,7 +288,7 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wthread-safety-negative"
 inline CordRep* CordzInfo::RefCordRep() const ABSL_LOCKS_EXCLUDED(mutex_) {
-  MutexLock lock(&mutex_);
+  MutexLock lock(mutex_);
   return rep_ ? CordRep::Ref(rep_) : nullptr;
 }
 #pragma clang diagnostic pop
diff --git a/absl/strings/internal/escaping.h b/absl/strings/internal/escaping.h
index 2186f77..b71fb7e 100644
--- a/absl/strings/internal/escaping.h
+++ b/absl/strings/internal/escaping.h
@@ -17,7 +17,7 @@
 
 #include <cassert>
 
-#include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/resize_and_overwrite.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -42,12 +42,14 @@
                           bool do_padding, const char* base64_chars) {
   const size_t calc_escaped_size =
       CalculateBase64EscapedLenInternal(szsrc, do_padding);
-  STLStringResizeUninitialized(dest, calc_escaped_size);
-
-  const size_t escaped_len = Base64EscapeInternal(
-      src, szsrc, &(*dest)[0], dest->size(), base64_chars, do_padding);
-  assert(calc_escaped_size == escaped_len);
-  dest->erase(escaped_len);
+  StringResizeAndOverwrite(
+      *dest, calc_escaped_size,
+      [src, szsrc, base64_chars, do_padding](char* buf, size_t buf_size) {
+        const size_t escaped_len = Base64EscapeInternal(
+            src, szsrc, buf, buf_size, base64_chars, do_padding);
+        assert(escaped_len == buf_size);
+        return escaped_len;
+      });
 }
 
 }  // namespace strings_internal
diff --git a/absl/strings/internal/generic_printer.cc b/absl/strings/internal/generic_printer.cc
new file mode 100644
index 0000000..16ca228
--- /dev/null
+++ b/absl/strings/internal/generic_printer.cc
@@ -0,0 +1,107 @@
+// Copyright 2025 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/strings/internal/generic_printer.h"
+
+#include <cstddef>
+#include <cstdlib>
+#include <ostream>
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/escaping.h"
+#include "absl/strings/str_format.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace internal_generic_printer {
+
+// Out-of-line helper for PrintAsStringWithEscaping.
+std::ostream& PrintEscapedString(std::ostream& os, absl::string_view v) {
+  return os << "\"" << absl::CHexEscape(v) << "\"";
+}
+
+// Retuns a string representation of 'v', shortened if possible.
+template <class T, class F>
+std::string TryShorten(T v, F strtox) {
+  std::string printed =
+      absl::StrFormat("%.*g", std::numeric_limits<T>::max_digits10 / 2, v);
+  T parsed = strtox(printed.data());
+  if (parsed != v) {
+    printed =
+        absl::StrFormat("%.*g", std::numeric_limits<T>::max_digits10 + 1, v);
+  }
+  return printed;
+}
+
+// Out-of-line helpers for floating point values. These don't necessarily
+// ensure that values are precise, but rather that they are wide enough to
+// represent distinct values. go/c++17std/numeric.limits.members.html
+std::ostream& PrintPreciseFP(std::ostream& os, float v) {
+  return os << TryShorten(v, [](const char* buf) {
+           char* unused;
+           return std::strtof(buf, &unused);
+         }) << "f";
+}
+std::ostream& PrintPreciseFP(std::ostream& os, double v) {
+  return os << TryShorten(v, [](const char* buf) {
+           char* unused;
+           return std::strtod(buf, &unused);
+         });
+}
+std::ostream& PrintPreciseFP(std::ostream& os, long double v) {
+  return os << TryShorten(v, [](const char* buf) {
+           char* unused;
+           return std::strtold(buf, &unused);
+         }) << "L";
+}
+
+// Prints a nibble of 'v' in hexadecimal.
+inline char hexnib(int v) {
+  return static_cast<char>((v < 10 ? '0' : ('a' - 10)) + v);
+}
+
+template <typename T>
+static std::ostream& PrintCharImpl(std::ostream& os, T v) {
+  // Specialization for chars: print as 'c' if printable, otherwise
+  // hex-escaped.
+  return (absl::ascii_isprint(static_cast<unsigned char>(v))
+              ? (os << (v == '\'' ? "'\\" : "'") << v)
+              : (os << "'\\x" << hexnib((v >> 4) & 0xf) << hexnib(v & 0xf)))
+         << "' (0x" << hexnib((v >> 4) & 0xf) << hexnib(v & 0xf) << " "
+         << static_cast<int>(v) << ")";
+}
+
+std::ostream& PrintChar(std::ostream& os, char c) {
+  return PrintCharImpl(os, c);
+}
+
+std::ostream& PrintChar(std::ostream& os, signed char c) {
+  return PrintCharImpl(os, c);
+}
+
+std::ostream& PrintChar(std::ostream& os, unsigned char c) {
+  return PrintCharImpl(os, c);
+}
+
+std::ostream& PrintByte(std::ostream& os, std::byte b) {
+  auto v = std::to_integer<int>(b);
+  os << "0x" << hexnib((v >> 4) & 0xf) << hexnib(v & 0xf);
+  return os;
+}
+
+}  // namespace internal_generic_printer
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/strings/internal/generic_printer.h b/absl/strings/internal/generic_printer.h
new file mode 100644
index 0000000..ed60155
--- /dev/null
+++ b/absl/strings/internal/generic_printer.h
@@ -0,0 +1,115 @@
+// Copyright 2025 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.
+
+#ifndef ABSL_STRINGS_INTERNAL_GENERIC_PRINTER_H_
+#define ABSL_STRINGS_INTERNAL_GENERIC_PRINTER_H_
+
+#include "absl/strings/internal/generic_printer_internal.h"  // IWYU pragma: export
+
+// Helpers for printing objects in generic code.
+//
+// These functions help with streaming in generic code. It may be desirable, for
+// example, to log values from generic functions; however, operator<< may not be
+// overloaded for all types.
+//
+// The helpers in this library use, in order of precedence:
+//
+//  1. std::string and std::string_view are quoted and escaped. (The specific
+//     format is not guaranteed to be stable.)
+//  2. A defined AbslStringify() method.
+//  3. absl::log_internal::LogContainer, if the object is a STL container.
+//  4. For std::tuple, std::pair, and std::optional, recursively calls
+//     GenericPrint for each element.
+//  5. Floating point values are printed with enough precision for round-trip.
+//  6. char values are quoted, with non-printable values escaped, and the
+//     char's numeric value is included.
+//  7. A defined operator<< overload (which should be found by ADL).
+//  8. A defined DebugString() const method.
+//  9. A fallback value with basic information otherwise.
+//
+// Note that the fallback value means that if no formatting conversion is
+// defined, you will not see a compile-time error. This also means that
+// GenericPrint() can safely be used in generic template contexts, and can
+// format any types needed (even though the output will vary).
+//
+// Example usage:
+//
+//   // All values after GenericPrint() are formatted:
+//   LOG(INFO) << GenericPrint()
+//             << int_var         // <- printed normally
+//             << float_var       // <- sufficient precision for round-trip
+//             << " unchanged literal text ";
+//
+//   // Just one value is formatted:
+//   LOG(INFO) << GenericPrint(string("this is quoted and escaped\t\n"))
+//             << GenericPrint("but not this, ");
+//             << string("and not this.");
+//
+// To make a type loggable with GenericPrint, prefer defining operator<< as a
+// friend function. For example:
+//
+//   class TypeToLog {
+//    public:
+//     string ToString() const;  // Many types already implement this.
+//                               // Define out-of-line if it is complex.
+//     friend std::ostream& operator<<(std::ostream& os, const TypeToLog& v) {
+//       return os << v.ToString();  // OK to define in-line instead, if simple.
+//     }
+//   };
+//
+// (Defining operator<< as an inline friend free function allows it to be found
+// by Argument-Dependent Lookup, or ADL, which is the mechanism typically used
+// for operator overload resolution. An inline friend function is the tightest
+// scope possible for overloading the left-hand side of an operator.)
+
+#include <ostream>
+#include <utility>
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+// Helper for logging values in generic code.
+//
+// Example usage:
+//
+//   template <typename T>
+//   void GenericFunction() {
+//     T v1, v2;
+//     VLOG(1) << GenericPrint() << v1 << v2;  // GenericPrint everything
+//     VLOG(1) << GenericPrint(v1) << v2;  // GenericPrint just v1
+//   }
+//
+inline constexpr internal_generic_printer::GenericPrintAdapterFactory
+    GenericPrint{};
+
+// Generic printer type: this class can be used, for example, as a template
+// argument to allow users to provide alternative printing strategies.
+//
+// For example, to allow callers to provide a custom strategy:
+//
+//   template <typename T, typename PrinterT = GenericPrinter<T>>
+//   void GenericFunction() {
+//     T value;
+//     VLOG(1) << PrinterT{value};
+//   }
+//
+template <typename T>
+using GenericPrinter = internal_generic_printer::GenericPrinter<T>;
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_GENERIC_PRINTER_H_
diff --git a/absl/strings/internal/generic_printer_internal.h b/absl/strings/internal/generic_printer_internal.h
new file mode 100644
index 0000000..1a2d0bd
--- /dev/null
+++ b/absl/strings/internal/generic_printer_internal.h
@@ -0,0 +1,423 @@
+// Copyright 2025 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.
+
+#ifndef ABSL_STRINGS_INTERNAL_GENERIC_PRINTER_INTERNAL_H_
+#define ABSL_STRINGS_INTERNAL_GENERIC_PRINTER_INTERNAL_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <optional>
+#include <ostream>
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+#include <variant>
+#include <vector>
+
+#include "absl/base/config.h"
+#include "absl/log/internal/container.h"
+#include "absl/meta/internal/requires.h"
+#include "absl/strings/has_absl_stringify.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+
+// NOTE: we do not want to expand the dependencies of this library. All
+// compatibility detection must be done in a generic way, without having to
+// include the headers of other libraries.
+
+// Internal implementation details: see generic_printer.h.
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace internal_generic_printer {
+
+template <typename T>
+std::ostream& GenericPrintImpl(std::ostream& os, const T& v);
+
+// Scope blocker: we must always use ADL in our predicates below.
+struct Anonymous;
+std::ostream& operator<<(const Anonymous&, const Anonymous&) = delete;
+
+// Logging policy for LogContainer. Our SFINAE overload will not fail
+// if the contained type cannot be printed, so make sure to circle back to
+// GenericPrinter.
+struct ContainerLogPolicy {
+  void LogOpening(std::ostream& os) const { os << "["; }
+  void LogClosing(std::ostream& os) const { os << "]"; }
+  void LogFirstSeparator(std::ostream& os) const { os << ""; }
+  void LogSeparator(std::ostream& os) const { os << ", "; }
+  int64_t MaxElements() const { return 15; }
+  template <typename T>
+  void Log(std::ostream& os, const T& element) const {
+    internal_generic_printer::GenericPrintImpl(os, element);
+  }
+  void LogEllipsis(std::ostream& os) const { os << "..."; }
+};
+
+// Out-of-line helper for PrintAsStringWithEscaping.
+std::ostream& PrintEscapedString(std::ostream& os, absl::string_view v);
+
+// Trait to recognize a string, possibly with a custom allocator.
+template <class T>
+inline constexpr bool is_any_string = false;
+template <class A>
+inline constexpr bool
+    is_any_string<std::basic_string<char, std::char_traits<char>, A>> = true;
+
+// Trait to recognize a supported pointer. Below are documented reasons why
+// raw pointers and std::shared_ptr are not currently supported.
+// See also http://b/239459272#comment9 and the discussion in the comment
+// threads of cl/485200996.
+//
+// The tl;dr:
+// 1. Pointers that logically represent an object (or nullptr) are safe to print
+//    out.
+// 2. Pointers that may represent some other concept (delineating memory bounds,
+//    overridden managed-memory deleters to mimic RAII, ...) may be unsafe to
+//    print out.
+//
+// raw pointers:
+//  - A pointer one-past the last element of an array
+//  - Non-null but non-dereferenceable: https://gcc.godbolt.org/z/sqsqGvKbP
+//
+// `std::shared_ptr`:
+//  - "Aliasing" / similar to raw pointers: https://gcc.godbolt.org/z/YbWPzvhae
+template <class T, class = void>
+inline constexpr bool is_supported_ptr = false;
+// `std::unique_ptr` has the same theoretical risks as raw pointers, but those
+// risks are far less likely (typically requiring a custom deleter), and the
+// benefits of supporting unique_ptr outweigh the costs.
+//  - Note: `std::unique_ptr<T[]>` cannot safely be and is not dereferenced.
+template <class A, class... Deleter>
+inline constexpr bool is_supported_ptr<std::unique_ptr<A, Deleter...>> = true;
+// `ArenaSafeUniquePtr` is at least as safe as `std::unique_ptr`.
+template <class T>
+inline constexpr bool is_supported_ptr<
+    T,
+    // Check for `ArenaSafeUniquePtr` without having to include its header here.
+    // This does match any type named `ArenaSafeUniquePtr`, regardless of the
+    // namespace it is defined in, but it's pretty plausible that any such type
+    // would be a fork.
+    decltype(T().~ArenaSafeUniquePtr())> = true;
+
+// Specialization for floats: print floating point types using their
+// max_digits10 precision. This ensures each distinct underlying values
+// can be represented uniquely, even though it's not (strictly speaking)
+// the most precise representation.
+std::ostream& PrintPreciseFP(std::ostream& os, float v);
+std::ostream& PrintPreciseFP(std::ostream& os, double v);
+std::ostream& PrintPreciseFP(std::ostream& os, long double v);
+
+std::ostream& PrintChar(std::ostream& os, char c);
+std::ostream& PrintChar(std::ostream& os, signed char c);
+std::ostream& PrintChar(std::ostream& os, unsigned char c);
+
+std::ostream& PrintByte(std::ostream& os, std::byte b);
+
+template <class... Ts>
+std::ostream& PrintTuple(std::ostream& os, const std::tuple<Ts...>& tuple) {
+  absl::string_view sep = "";
+  const auto print_one = [&](const auto& v) {
+    os << sep;
+    (GenericPrintImpl)(os, v);
+    sep = ", ";
+  };
+  os << "<";
+  std::apply([&](const auto&... v) { (print_one(v), ...); }, tuple);
+  os << ">";
+  return os;
+}
+
+template <typename T, typename U>
+std::ostream& PrintPair(std::ostream& os, const std::pair<T, U>& p) {
+  os << "<";
+  (GenericPrintImpl)(os, p.first);
+  os << ", ";
+  (GenericPrintImpl)(os, p.second);
+  os << ">";
+  return os;
+}
+
+template <typename T>
+std::ostream& PrintOptionalLike(std::ostream& os, const T& v) {
+  if (v.has_value()) {
+    os << "<";
+    (GenericPrintImpl)(os, *v);
+    os << ">";
+  } else {
+    (GenericPrintImpl)(os, std::nullopt);
+  }
+  return os;
+}
+
+template <typename... Ts>
+std::ostream& PrintVariant(std::ostream& os, const std::variant<Ts...>& v) {
+  os << "(";
+  os << "'(index = " << v.index() << ")' ";
+
+  // NOTE(derekbailey): This may throw a std::bad_variant_access if the variant
+  // is "valueless", which only occurs if exceptions are thrown. This is
+  // non-relevant when not using exceptions, but it is worth mentioning if that
+  // invariant is ever changed.
+  std::visit([&](const auto& arg) { (GenericPrintImpl)(os, arg); }, v);
+  os << ")";
+  return os;
+}
+
+template <typename StatusOrLike>
+std::ostream& PrintStatusOrLike(std::ostream& os, const StatusOrLike& v) {
+  os << "<";
+  if (v.ok()) {
+    os << "OK: ";
+    (GenericPrintImpl)(os, *v);
+  } else {
+    (GenericPrintImpl)(os, v.status());
+  }
+  os << ">";
+  return os;
+}
+
+template <typename SmartPointer>
+std::ostream& PrintSmartPointerContents(std::ostream& os,
+                                        const SmartPointer& v) {
+  os << "<";
+  if (v == nullptr) {
+    (GenericPrintImpl)(os, nullptr);
+  } else {
+    // Cast to void* so that every type (e.g. `char*`) is printed as an address.
+    os << absl::implicit_cast<const void*>(v.get()) << " pointing to ";
+
+    if constexpr (meta_internal::Requires<SmartPointer>(
+                      [](auto&& p) -> decltype(p[0]) {})) {
+      // e.g. std::unique_ptr<int[]>, which only has operator[]
+      os << "an array";
+    } else if constexpr (std::is_object_v<
+                             typename SmartPointer::element_type>) {
+      (GenericPrintImpl)(os, *v);
+    } else {
+      // e.g. std::unique_ptr<void, MyCustomDeleter>
+      os << "a non-object type";
+    }
+  }
+  os << ">";
+  return os;
+}
+
+template <typename T>
+std::ostream& GenericPrintImpl(std::ostream& os, const T& v) {
+  if constexpr (is_any_string<T> || std::is_same_v<T, absl::string_view>) {
+    // Specialization for strings: prints with plausible quoting and escaping.
+    return PrintEscapedString(os, v);
+  } else if constexpr (absl::HasAbslStringify<T>::value) {
+    // If someone has specified `AbslStringify`, we should prefer that.
+    return os << absl::StrCat(v);
+  } else if constexpr (meta_internal::Requires<const T>(
+                           [&](auto&& w)
+                               -> decltype((
+                                   PrintTuple)(std::declval<std::ostream&>(),
+                                               w)) {})) {
+    // For tuples, use `< elem0, ..., elemN >`.
+    return (PrintTuple)(os, v);
+
+  } else if constexpr (meta_internal::Requires<const T>(
+                           [&](auto&& w)
+                               -> decltype((
+                                   PrintPair)(std::declval<std::ostream&>(),
+                                              w)) {})) {
+    // For pairs, use `< first, second >`.
+    return (PrintPair)(os, v);
+
+  } else if constexpr (meta_internal::Requires<const T>(
+                           [&](auto&& w)
+                               -> decltype((
+                                   PrintVariant)(std::declval<std::ostream&>(),
+                                                 w)) {})) {
+    // For std::variant, use `std::visit(v)`
+    return (PrintVariant)(os, v);
+  } else if constexpr (is_supported_ptr<T>) {
+    return (PrintSmartPointerContents)(os, v);
+  } else if constexpr (meta_internal::Requires<const T>(
+                           [&](auto&& w) -> decltype(w.ok(), w.status(), *w) {
+                           })) {
+    return (PrintStatusOrLike)(os, v);
+  } else if constexpr (meta_internal::Requires<const T>(
+                           [&](auto&& w) -> decltype(w.has_value(), *w) {})) {
+    return (PrintOptionalLike)(os, v);
+  } else if constexpr (std::is_same_v<T, std::nullopt_t>) {
+    // Specialization for nullopt.
+    return os << "nullopt";
+
+  } else if constexpr (std::is_same_v<T, std::nullptr_t>) {
+    // Specialization for nullptr.
+    return os << "nullptr";
+
+  } else if constexpr (std::is_floating_point_v<T>) {
+    // For floating point print with enough precision for a roundtrip.
+    return PrintPreciseFP(os, v);
+
+  } else if constexpr (std::is_same_v<T, char> ||
+                       std::is_same_v<T, signed char> ||
+                       std::is_same_v<T, unsigned char>) {
+    // Chars are printed as the char (if a printable char) and the integral
+    // representation in hex and decimal.
+    return PrintChar(os, v);
+
+  } else if constexpr (std::is_same_v<T, std::byte>) {
+    return PrintByte(os, v);
+
+  } else if constexpr (std::is_same_v<T, bool> ||
+                       std::is_same_v<T,
+                                      typename std::vector<bool>::reference> ||
+                       std::is_same_v<
+                           T, typename std::vector<bool>::const_reference>) {
+    return os << (v ? "true" : "false");
+
+  } else if constexpr (meta_internal::Requires<const T>(
+                           [&](auto&& w)
+                               -> decltype(ProtobufInternalGetEnumDescriptor(
+                                   w)) {})) {
+    os << static_cast<std::underlying_type_t<T>>(v);
+    if (auto* desc =
+            ProtobufInternalGetEnumDescriptor(T{})->FindValueByNumber(v)) {
+      os << "(" << desc->name() << ")";
+    }
+    return os;
+  } else if constexpr (!std::is_enum_v<T> &&
+                       meta_internal::Requires<const T>(
+                           [&](auto&& w) -> decltype(absl::StrCat(w)) {})) {
+    return os << absl::StrCat(v);
+
+  } else if constexpr (meta_internal::Requires<const T>(
+                           [&](auto&& w)
+                               -> decltype(std::declval<std::ostream&>()
+                                           << log_internal::LogContainer(w)) {
+                           })) {
+    // For containers, use `[ elem0, ..., elemN ]` with a max of 15.
+    return os << log_internal::LogContainer(v, ContainerLogPolicy());
+
+  } else if constexpr (meta_internal::Requires<const T>(
+                           [&](auto&& w)
+                               -> decltype(std::declval<std::ostream&>() << w) {
+                           })) {
+    // Streaming
+    return os << v;
+
+  } else if constexpr (meta_internal::Requires<const T>(
+                           [&](auto&& w)
+                               -> decltype(std::declval<std::ostream&>()
+                                           << w.DebugString()) {})) {
+    // DebugString
+    return os << v.DebugString();
+
+  } else if constexpr (std::is_enum_v<T>) {
+    // In case the underlying type is some kind of char, we have to recurse.
+    return GenericPrintImpl(os, static_cast<std::underlying_type_t<T>>(v));
+
+  } else {
+    // Default: we don't have anything to stream the value.
+    return os << "[unprintable value of size " << sizeof(T) << " @" << &v
+              << "]";
+  }
+}
+
+// GenericPrinter always has a valid operator<<. It defers to the disjuction
+// above.
+template <typename T>
+class GenericPrinter {
+ public:
+  explicit GenericPrinter(const T& value) : value_(value) {}
+
+ private:
+  friend std::ostream& operator<<(std::ostream& os, const GenericPrinter& gp) {
+    return internal_generic_printer::GenericPrintImpl(os, gp.value_);
+  }
+  const T& value_;
+};
+
+struct GenericPrintStreamAdapter {
+  template <class StreamT>
+  struct Impl {
+    // Stream operator: this object will adapt to the underlying stream type,
+    // but only if the Impl is an rvalue. For example, this works:
+    //   std::cout << GenericPrint() << foo;
+    // but not:
+    //   auto adapter = (std::cout << GenericPrint());
+    //   adapter << foo;
+    template <typename T>
+    Impl&& operator<<(const T& value) && {
+      os << internal_generic_printer::GenericPrinter<T>(value);
+      return std::move(*this);
+    }
+
+    // Inhibit using a stack variable for the adapter:
+    template <typename T>
+    Impl& operator<<(const T& value) & = delete;
+
+    // Detects a Flush() method, for LogMessage compatibility.
+    template <typename T>
+    class HasFlushMethod {
+     private:
+      template <typename C>
+      static std::true_type Test(decltype(&C::Flush));
+      template <typename C>
+      static std::false_type Test(...);
+
+     public:
+      static constexpr bool value = decltype(Test<T>(nullptr))::value;
+    };
+
+    // LogMessage compatibility requires a Flush() method.
+    void Flush() {
+      if constexpr (HasFlushMethod<StreamT>::value) {
+        os.Flush();
+      }
+    }
+
+    StreamT& os;
+  };
+
+  // If Impl is evaluated on the RHS of an 'operator&&', and 'lhs && Impl.os'
+  // implicitly converts to void, then it's fine for Impl to do so, too. This
+  // will create precisely as many objects as 'lhs && Impl.os', so we should
+  // both observe any side effects, and avoid observing multiple side
+  // effects. (See absl::log_internal::Voidify for an example of why this might
+  // be useful.)
+  template <typename LHS, typename RHS>
+  friend auto operator&&(LHS&& lhs, Impl<RHS>&& rhs)
+      -> decltype(lhs && rhs.os) {
+    return lhs && rhs.os;
+  }
+
+  template <class StreamT>
+  friend Impl<StreamT> operator<<(StreamT& os, GenericPrintStreamAdapter&&) {
+    return Impl<StreamT>{os};
+  }
+};
+
+struct GenericPrintAdapterFactory {
+  internal_generic_printer::GenericPrintStreamAdapter operator()() const {
+    return internal_generic_printer::GenericPrintStreamAdapter{};
+  }
+  template <typename T>
+  internal_generic_printer::GenericPrinter<T> operator()(const T& value) const {
+    return internal_generic_printer::GenericPrinter<T>{value};
+  }
+};
+
+}  // namespace internal_generic_printer
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_GENERIC_PRINTER_INTERNAL_H_
diff --git a/absl/strings/internal/generic_printer_test.cc b/absl/strings/internal/generic_printer_test.cc
new file mode 100644
index 0000000..4093228
--- /dev/null
+++ b/absl/strings/internal/generic_printer_test.cc
@@ -0,0 +1,685 @@
+// Copyright 2025 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/strings/internal/generic_printer.h"
+
+#include <array>
+#include <cstdint>
+#include <limits>
+#include <map>
+#include <memory>
+#include <optional>
+#include <ostream>
+#include <sstream>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <variant>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/container/flat_hash_map.h"
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/substitute.h"
+
+namespace generic_logging_test {
+struct NotStreamable {};
+}  // namespace generic_logging_test
+
+static std::ostream& operator<<(std::ostream& os,
+                                const generic_logging_test::NotStreamable&) {
+  return os << "This overload should NOT be found by GenericPrint.";
+}
+
+// Types to test selection logic for streamable and non-streamable types.
+namespace generic_logging_test {
+struct Streamable {
+  int x;
+  friend std::ostream& operator<<(std::ostream& os, const Streamable& l) {
+    return os << "Streamable{" << l.x << "}";
+  }
+};
+}  // namespace generic_logging_test
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+namespace {
+
+using ::testing::AllOf;
+using ::testing::AnyOf;
+using ::testing::ContainsRegex;
+using ::testing::EndsWith;
+using ::testing::Eq;
+using ::testing::HasSubstr;
+using ::testing::MatchesRegex;
+
+struct AbslStringifiable {
+  template <typename S>
+  friend void AbslStringify(S& sink, const AbslStringifiable&) {
+    sink.Append("AbslStringifiable!");
+  }
+};
+
+auto IsUnprintable() {
+#ifdef GTEST_USES_SIMPLE_RE
+  return HasSubstr("unprintable value of size");
+#else
+  return ContainsRegex(
+      "\\[unprintable value of size [0-9]+ @(0x)?[0-9a-fA-F]+\\]");
+#endif
+}
+
+auto HasExactlyNInstancesOf(int n, absl::string_view me) {
+#ifdef GTEST_USES_SIMPLE_RE
+  (void)n;
+  return HasSubstr(me);
+#else
+  absl::string_view value_m_times = "(.*$0){$1}.*";
+
+  return AllOf(MatchesRegex(absl::Substitute(value_m_times, me, n)),
+               Not(MatchesRegex(absl::Substitute(value_m_times, me, n + 1))));
+#endif
+}
+
+template <typename T>
+std::string GenericPrintToString(const T& v) {
+  std::stringstream ss;
+  ss << GenericPrint(v);
+  {
+    std::stringstream ss2;
+    ss2 << GenericPrint() << v;
+    EXPECT_EQ(ss.str(), ss2.str());
+  }
+  return ss.str();
+}
+
+TEST(GenericPrinterTest, Bool) {
+  EXPECT_EQ("true", GenericPrintToString(true));
+  EXPECT_EQ("false", GenericPrintToString(false));
+}
+
+TEST(GenericPrinterTest, VectorOfBool) {
+  std::vector<bool> v{true, false, true};
+  const auto& cv = v;
+  EXPECT_EQ("[true, false, true]", GenericPrintToString(v));
+  EXPECT_EQ("true", GenericPrintToString(v[0]));
+  EXPECT_EQ("true", GenericPrintToString(cv[0]));
+}
+
+TEST(GenericPrinterTest, CharLiterals) {
+  EXPECT_EQ(R"(a"\b)", GenericPrintToString(R"(a"\b)"));
+}
+
+TEST(GenericPrinterTest, Builtin) {
+  EXPECT_EQ("123", GenericPrintToString(123));
+}
+
+TEST(GenericPrinterTest, AbslStringifiable) {
+  EXPECT_EQ("AbslStringifiable!", GenericPrintToString(AbslStringifiable{}));
+}
+
+TEST(GenericPrinterTest, Nullptr) {
+  EXPECT_EQ("nullptr", GenericPrintToString(nullptr));
+}
+
+TEST(GenericPrinterTest, Chars) {
+  EXPECT_EQ(R"('\x0a' (0x0a 10))", GenericPrintToString('\x0a'));
+  EXPECT_EQ(R"(' ' (0x20 32))", GenericPrintToString(' '));
+  EXPECT_EQ(R"('~' (0x7e 126))", GenericPrintToString('~'));
+  EXPECT_EQ(R"('\'' (0x27 39))", GenericPrintToString('\''));
+}
+
+TEST(GenericPrinterTest, SignedChars) {
+  EXPECT_EQ(R"('\x0a' (0x0a 10))",
+            GenericPrintToString(static_cast<signed char>('\x0a')));
+  EXPECT_EQ(R"(' ' (0x20 32))",
+            GenericPrintToString(static_cast<signed char>(' ')));
+  EXPECT_EQ(R"('~' (0x7e 126))",
+            GenericPrintToString(static_cast<signed char>('~')));
+  EXPECT_EQ(R"('\'' (0x27 39))",
+            GenericPrintToString(static_cast<signed char>('\'')));
+}
+
+TEST(GenericPrinterTest, UnsignedChars) {
+  EXPECT_EQ(R"('\x0a' (0x0a 10))",
+            GenericPrintToString(static_cast<unsigned char>('\x0a')));
+  EXPECT_EQ(R"(' ' (0x20 32))",
+            GenericPrintToString(static_cast<unsigned char>(' ')));
+  EXPECT_EQ(R"('~' (0x7e 126))",
+            GenericPrintToString(static_cast<unsigned char>('~')));
+  EXPECT_EQ(R"('\'' (0x27 39))",
+            GenericPrintToString(static_cast<unsigned char>('\'')));
+}
+
+TEST(GenericPrinterTest, Bytes) {
+  EXPECT_EQ("0x00", GenericPrintToString(static_cast<std::byte>(0)));
+  EXPECT_EQ("0x7f", GenericPrintToString(static_cast<std::byte>(0x7F)));
+  EXPECT_EQ("0xff", GenericPrintToString(static_cast<std::byte>(0xFF)));
+}
+
+TEST(GenericPrinterTest, Strings) {
+  const std::string expected_quotes = R"("a\"\\b")";
+  EXPECT_EQ(expected_quotes, GenericPrintToString(std::string(R"(a"\b)")));
+  const std::string expected_nonprintable = R"("\x00\xcd\n\xab")";
+  EXPECT_EQ(expected_nonprintable,
+            GenericPrintToString(absl::string_view("\0\315\n\xAB", 4)));
+}
+
+TEST(GenericPrinterTest, PreciseFloat) {
+  // Instead of testing exactly how the values are formatted, just check that
+  // they are distinct.
+
+  // Ensure concise output for exact values:
+  EXPECT_EQ("1f", GenericPrintToString(1.f));
+  EXPECT_EQ("1.1f", GenericPrintToString(1.1f));
+
+  // Plausible real-world values:
+  float f = 10.0000095f;
+  EXPECT_NE(GenericPrintToString(f), GenericPrintToString(10.0000105f));
+  // Smallest increment for a real-world value:
+  EXPECT_NE(GenericPrintToString(f),
+            GenericPrintToString(std::nextafter(f, 11)));
+  // The two smallest (finite) values possible:
+  EXPECT_NE(GenericPrintToString(std::numeric_limits<float>::lowest()),
+            GenericPrintToString(
+                std::nextafter(std::numeric_limits<float>::lowest(), 1)));
+  // Ensure the value has the correct type suffix:
+  EXPECT_THAT(GenericPrintToString(0.f), EndsWith("f"));
+}
+
+TEST(GenericPrinterTest, PreciseDouble) {
+  EXPECT_EQ("1", GenericPrintToString(1.));
+  EXPECT_EQ("1.1", GenericPrintToString(1.1));
+  double d = 10.000000000000002;
+  EXPECT_NE(GenericPrintToString(d), GenericPrintToString(10.000000000000004));
+  EXPECT_NE(GenericPrintToString(d),
+            GenericPrintToString(std::nextafter(d, 11)));
+  EXPECT_NE(GenericPrintToString(std::numeric_limits<double>::lowest()),
+            GenericPrintToString(
+                std::nextafter(std::numeric_limits<double>::lowest(), 1)));
+  EXPECT_THAT(GenericPrintToString(0.), EndsWith("0"));
+}
+
+TEST(GenericPrinterTest, PreciseLongDouble) {
+  EXPECT_EQ("1L", GenericPrintToString(1.L));
+  EXPECT_EQ("1.1L", GenericPrintToString(1.1L));
+  long double ld = 10.0000000000000000000000000000002;
+  EXPECT_NE(GenericPrintToString(ld),
+            GenericPrintToString(10.0000000000000000000000000000004));
+  EXPECT_NE(GenericPrintToString(ld),
+            GenericPrintToString(std::nextafter(ld, 11)));
+  EXPECT_NE(GenericPrintToString(std::numeric_limits<long double>::lowest()),
+            GenericPrintToString(
+                std::nextafter(std::numeric_limits<long double>::lowest(), 1)));
+  EXPECT_THAT(GenericPrintToString(0.L), EndsWith("L"));
+}
+
+TEST(GenericPrinterTest, StreamableLvalue) {
+  generic_logging_test::Streamable x{234};
+  EXPECT_EQ("Streamable{234}", GenericPrintToString(x));
+}
+
+TEST(GenericPrinterTest, StreamableXvalue) {
+  EXPECT_EQ("Streamable{345}",
+            GenericPrintToString(generic_logging_test::Streamable{345}));
+}
+
+TEST(GenericPrinterTest, NotStreamableWithoutGenericPrint) {
+  ::generic_logging_test::NotStreamable x;
+  std::stringstream ss;
+  ::operator<<(ss, x);
+  EXPECT_EQ(ss.str(), "This overload should NOT be found by GenericPrint.");
+}
+
+TEST(GenericPrinterTest, NotStreamableLvalue) {
+  generic_logging_test::NotStreamable x;
+  EXPECT_THAT(GenericPrintToString(x), IsUnprintable());
+}
+
+TEST(GenericPrinterTest, NotStreamableXvalue) {
+  EXPECT_THAT(GenericPrintToString(generic_logging_test::NotStreamable{}),
+              IsUnprintable());
+}
+
+TEST(GenericPrinterTest, DebugString) {
+  struct WithDebugString {
+    std::string val;
+    std::string DebugString() const {
+      return absl::StrCat("WithDebugString{", val, "}");
+    }
+  };
+  EXPECT_EQ("WithDebugString{foo}",
+            GenericPrintToString(WithDebugString{"foo"}));
+}
+
+TEST(GenericPrinterTest, Vector) {
+  std::vector<int> v = {4, 5, 6};
+  EXPECT_THAT(GenericPrintToString(v), MatchesRegex(".*4,? 5,? 6.*"));
+}
+
+TEST(GenericPrinterTest, StreamableVector) {
+  std::vector<generic_logging_test::Streamable> v = {{7}, {8}, {9}};
+  EXPECT_THAT(GenericPrintToString(v),
+              MatchesRegex(".*Streamable.7.,? Streamable.8.,? Streamable.9.*"));
+}
+
+TEST(GenericPrinterTest, Map) {
+  absl::flat_hash_map<
+      std::string, absl::flat_hash_map<std::string, std::pair<double, double>>>
+      v = {{"A", {{"B", {.5, .25}}}}};
+
+  EXPECT_THAT(GenericPrintToString(v), R"([<"A", [<"B", <0.5, 0.25>>]>])");
+
+  std::map<std::string, std::map<std::string, std::pair<double, double>>> v2 = {
+      {"A", {{"B", {.5, .25}}}}};
+
+  EXPECT_THAT(GenericPrintToString(v2), R"([<"A", [<"B", <0.5, 0.25>>]>])");
+}
+
+TEST(GenericPrinterTest, StreamAdapter) {
+  std::stringstream ss;
+  static_assert(
+      std::is_same<
+          typename std::remove_reference<decltype(ss << GenericPrint())>::type,
+          internal_generic_printer::GenericPrintStreamAdapter::Impl<
+              std::stringstream>>::value,
+      "expected ostream << GenericPrint() to yield adapter impl");
+
+  ss << GenericPrint() << "again, " << "back-up, " << "cue, "
+     << "double-u, " << "eye, "
+     << "four: " << generic_logging_test::NotStreamable{};
+  EXPECT_THAT(
+      ss.str(),
+      MatchesRegex(
+          "again, back-up, cue, double-u, eye, four: .unprintable value.*"));
+}
+
+TEST(GenericPrinterTest, NotStreamableVector) {
+  std::vector<generic_logging_test::NotStreamable> v = {{}, {}, {}};
+#ifdef GTEST_USES_SIMPLE_RE
+  EXPECT_THAT(GenericPrintToString(v), HasSubstr("unprintable"));
+#else
+  EXPECT_THAT(GenericPrintToString(v), MatchesRegex(".*(unprintable.*){3}.*"));
+#endif
+}
+
+struct CustomContainer : public std::array<int, 4> {
+  template <typename Sink>
+  friend void AbslStringify(Sink& sink, const CustomContainer& c) {
+    absl::Format(&sink, "%d %d", c[0], c[1]);
+  }
+};
+
+// Checks that AbslStringify (go/totw/215) is respected for container-like
+// types.
+TEST(GenericPrinterTest, ContainerLikeCustomLogging) {
+  CustomContainer c = {1, 2, 3, 4};
+  EXPECT_EQ(GenericPrintToString(c), "1 2");
+}
+
+// Test helper: this function demonstrates customizable printing logic:
+// 'GenericPrinter<T>' can be nominated as a default template argument.
+template <typename T, typename Printer = GenericPrinter<T>>
+std::string SpecializablePrint(const T& v) {
+  std::stringstream ss;
+  ss << Printer{v};
+  return ss.str();
+}
+
+TEST(GenericPrinterTest, DefaultPrinter) {
+  EXPECT_EQ("123", SpecializablePrint(123));
+}
+
+// Example of custom printing logic. This doesn't actually test anything in
+// GenericPrinter, but it's a working example of customizing printing logic (as
+// opposed to the comments in generic_printer.h).
+struct CustomPrinter {
+  explicit CustomPrinter(int) {}
+  friend std::ostream& operator<<(std::ostream& os, CustomPrinter&&) {
+    return os << "custom printer";
+  }
+};
+
+TEST(GenericPrinterTest, CustomPrinter) {
+  EXPECT_EQ("custom printer", (SpecializablePrint<int, CustomPrinter>(123)));
+}
+
+TEST(GenricPrinterTest, Nullopt) {
+  EXPECT_EQ("nullopt", GenericPrintToString(std::nullopt));
+}
+
+TEST(GenericPrinterTest, Optional) {
+  EXPECT_EQ("nullopt", GenericPrintToString(std::optional<int>()));
+  EXPECT_EQ("nullopt", GenericPrintToString(std::optional<int>(std::nullopt)));
+  EXPECT_EQ("<3>", GenericPrintToString(std::make_optional(3)));
+  EXPECT_EQ("<Streamable{3}>", GenericPrintToString(std::make_optional(
+                                   generic_logging_test::Streamable{3})));
+}
+
+TEST(GenericPrinterTest, Tuple) {
+  EXPECT_EQ("<1, two, 3>", GenericPrintToString(std::make_tuple(1, "two", 3)));
+}
+
+TEST(GenericPrinterTest, EmptyTuple) {
+  EXPECT_EQ("<>", GenericPrintToString(std::make_tuple()));
+}
+
+TEST(GenericPrinterTest, TupleWithStreamableMember) {
+  EXPECT_EQ("<1, two, Streamable{3}>",
+            GenericPrintToString(std::make_tuple(
+                1, "two", generic_logging_test::Streamable{3})));
+}
+
+TEST(GenericPrinterTest, Variant) {
+  EXPECT_EQ(R"(('(index = 0)' "cow"))",
+            GenericPrintToString(std::variant<std::string, float>("cow")));
+
+  EXPECT_EQ("('(index = 1)' 1.1f)",
+            GenericPrintToString(std::variant<std::string, float>(1.1F)));
+}
+
+TEST(GenericPrinterTest, VariantMonostate) {
+  EXPECT_THAT(GenericPrintToString(std::variant<std::monostate, std::string>()),
+              IsUnprintable());
+}
+
+TEST(GenericPrinterTest, VariantNonStreamable) {
+  EXPECT_EQ(R"(('(index = 0)' "cow"))",
+            GenericPrintToString(
+                std::variant<std::string, generic_logging_test::NotStreamable>(
+                    "cow")));
+
+  EXPECT_THAT(
+      GenericPrintToString(
+          std::variant<std::string, generic_logging_test::NotStreamable>(
+              generic_logging_test::NotStreamable{})),
+      IsUnprintable());
+}
+
+TEST(GenericPrinterTest, VariantNestedVariant) {
+  EXPECT_EQ(
+      "('(index = 1)' ('(index = 1)' 1.1f))",
+      GenericPrintToString(std::variant<std::string, std::variant<int, float>>(
+          std::variant<int, float>(1.1F))));
+}
+
+TEST(GenericPrinterTest, VariantInPlace) {
+  EXPECT_EQ("('(index = 0)' 17)", GenericPrintToString(std::variant<int, int>(
+                                      std::in_place_index<0>, 17)));
+
+  EXPECT_EQ("('(index = 1)' 17)", GenericPrintToString(std::variant<int, int>(
+                                      std::in_place_index<1>, 17)));
+}
+
+TEST(GenericPrinterTest, StatusOrLikeOkPrintsValue) {
+  EXPECT_EQ(R"(<OK: "cow">)",
+            GenericPrintToString(absl::StatusOr<std::string>("cow")));
+
+  EXPECT_EQ(R"(<OK: 1.1f>)", GenericPrintToString(absl::StatusOr<float>(1.1F)));
+}
+
+TEST(GenericPrinterTest, StatusOrLikeNonOkPrintsStatus) {
+  EXPECT_THAT(
+      GenericPrintToString(absl::StatusOr<float>(
+          absl::InvalidArgumentError("my error message"))),
+      AllOf(HasSubstr("my error message"), HasSubstr("INVALID_ARGUMENT")));
+
+  EXPECT_THAT(GenericPrintToString(
+                  absl::StatusOr<int>(absl::AbortedError("other message"))),
+              AllOf(HasSubstr("other message"), HasSubstr("ABORTED")));
+}
+
+TEST(GenericPrinterTest, StatusOrLikeNonStreamableValueUnprintable) {
+  EXPECT_THAT(
+      GenericPrintToString(absl::StatusOr<generic_logging_test::NotStreamable>(
+          generic_logging_test::NotStreamable{})),
+      IsUnprintable());
+}
+
+TEST(GenericPrinterTest, StatusOrLikeNonStreamableErrorStillPrintable) {
+  EXPECT_THAT(
+      GenericPrintToString(absl::StatusOr<generic_logging_test::NotStreamable>(
+          absl::AbortedError("other message"))),
+      AllOf(HasSubstr("other message"), HasSubstr("ABORTED")));
+}
+
+TEST(GenericPrinterTest, IsSupportedPointer) {
+  using internal_generic_printer::is_supported_ptr;
+
+  EXPECT_TRUE(is_supported_ptr<std::unique_ptr<std::string>>);
+  EXPECT_TRUE(is_supported_ptr<std::unique_ptr<int[]>>);
+  EXPECT_TRUE((is_supported_ptr<std::unique_ptr<void, void (*)(void*)>>));
+
+  EXPECT_FALSE(is_supported_ptr<int*>);
+  EXPECT_FALSE(is_supported_ptr<std::shared_ptr<int>>);
+  EXPECT_FALSE(is_supported_ptr<std::weak_ptr<int>>);
+}
+
+TEST(GenericPrinterTest, SmartPointerPrintsNullptrForAllNullptrs) {
+  std::unique_ptr<std::string> up;
+
+  EXPECT_EQ("<nullptr>", GenericPrintToString(up));
+}
+
+TEST(GenericPrinterTest, SmartPointerPrintsValueIfNonNull) {
+  EXPECT_THAT(GenericPrintToString(std::make_unique<int>(5)),
+              HasSubstr("pointing to 5"));
+}
+
+TEST(GenericPrinterTest, SmartPointerPrintsAddressOfPointee) {
+  auto i = std::make_unique<int>(5);
+  auto c = std::make_unique<char>('z');
+  char memory[] = "abcdefg";
+  auto cp = std::make_unique<char*>(memory);
+
+  EXPECT_THAT(GenericPrintToString(i),
+              AnyOf(Eq(absl::StrFormat("<%016X pointing to 5>",
+                                       reinterpret_cast<intptr_t>(&*i))),
+                    Eq(absl::StrFormat("<%#x pointing to 5>",
+                                       reinterpret_cast<intptr_t>(&*i)))));
+
+  EXPECT_THAT(
+      GenericPrintToString(c),
+      AnyOf(HasSubstr(absl::StrFormat("<%016X pointing to 'z'",
+                                      reinterpret_cast<intptr_t>(&*c))),
+            HasSubstr(absl::StrFormat("<%#x pointing to 'z'",
+                                      reinterpret_cast<intptr_t>(&*c)))));
+
+  EXPECT_THAT(GenericPrintToString(cp),
+              AnyOf(Eq(absl::StrFormat("<%016X pointing to abcdefg>",
+                                       reinterpret_cast<intptr_t>(&*cp))),
+                    Eq(absl::StrFormat("<%#x pointing to abcdefg>",
+                                       reinterpret_cast<intptr_t>(&*cp)))));
+}
+
+TEST(GenericPrinterTest, SmartPointerToArrayOnlyPrintsAddressAndHelpText) {
+  auto empty = std::make_unique<int[]>(0);
+  auto nonempty = std::make_unique<int[]>(5);
+  nonempty[0] = 12345;
+  nonempty[4] = 54321;
+  // NOTE: ArenaSafeUniquePtr is not meant to support array-type template
+  // parameters, so we skip testing that here.
+  // http://g/c-users/J-AEFrFHssY/UMMFzCkdBAAJ, b/265984185.
+
+  EXPECT_THAT(
+      GenericPrintToString(nonempty),
+      AllOf(AnyOf(HasSubstr(absl::StrFormat(
+                      "%016X", reinterpret_cast<intptr_t>(nonempty.get()))),
+                  HasSubstr(absl::StrFormat(
+                      "%#x", reinterpret_cast<intptr_t>(nonempty.get())))),
+            HasSubstr("array"), Not(HasSubstr("to 54321")),
+            Not(HasSubstr("to 12345"))));
+
+  EXPECT_THAT(
+      GenericPrintToString(empty),
+      AllOf(AnyOf(HasSubstr(absl::StrFormat(
+                      "%016X", reinterpret_cast<intptr_t>(empty.get()))),
+                  HasSubstr(absl::StrFormat(
+                      "%#x", reinterpret_cast<intptr_t>(empty.get())))),
+            HasSubstr("array")));
+}
+
+TEST(GenericPrinterTest, SmartPointerToNonObjectType) {
+  auto int_ptr_deleter = [](void* data) {
+    int* p = static_cast<int*>(data);
+    delete p;
+  };
+
+  std::unique_ptr<void, decltype(int_ptr_deleter)> void_ptr(new int(959),
+                                                            int_ptr_deleter);
+
+  EXPECT_THAT(GenericPrintToString(void_ptr),
+              HasSubstr("pointing to a non-object type"));
+}
+
+TEST(GenericPrinterTest, PrintsCustomDeleterSmartPointer) {
+  // Delete `p` (if not nullptr) only on the 4th time the deleter is used.
+  auto four_deleter = [](std::string* p) {
+    static int counter = 0;
+    if (p == nullptr) return;  // skip calls to moved-from destructors.
+    if (++counter >= 4) delete p;
+  };
+
+  // Have four `unique_ptr`s "manage" the same string-pointer, with only the
+  // final (4th) call to the deleter deleting the string pointer.
+  auto* unique_string = new std::string("unique string");
+  std::vector<std::unique_ptr<std::string, decltype(four_deleter)>> test_ptrs;
+  for (int i = 0; i < 4; ++i) {
+    test_ptrs.emplace_back(unique_string, four_deleter);
+  }
+
+  EXPECT_THAT(GenericPrintToString(test_ptrs),
+              HasExactlyNInstancesOf(4, "unique string"));
+}
+
+// Ensure that GenericPrint is robust to recursion when a type's operator<<
+// calls into GenericPrint internally.
+struct CustomRecursive {
+  std::unique_ptr<CustomRecursive> next;
+  int val = 0;
+
+  friend std::ostream& operator<<(std::ostream& os, const CustomRecursive& cr) {
+    return os << "custom print: next = " << GenericPrintToString(cr.next);
+  }
+};
+
+TEST(GenericPrinterTest, DISABLED_CustomPrintOverloadRecursionDetected) {
+  auto r1 = std::make_unique<CustomRecursive>();
+  r1->val = 1;
+  auto& r2 = r1->next = std::make_unique<CustomRecursive>();
+  r2->val = 2;
+  r2->next = std::move(r1);
+
+  EXPECT_THAT(GenericPrintToString(*r2),
+              AllOf(HasExactlyNInstancesOf(2, "custom print"),
+                    HasExactlyNInstancesOf(1, "<recursive>")));
+
+  r2->next = nullptr;  // break the cycle
+}
+// <end DISABLED_ test section>
+
+enum CStyleEnum { kValue0, kValue1 };
+TEST(GenericPrinterTest, Enum) {
+  EXPECT_EQ("1", GenericPrintToString(kValue1));
+}
+
+enum class CppStyleEnum { kValue0, kValue1, kValue2 };
+TEST(GenericPrinterTest, EnumClass) {
+  EXPECT_EQ("2", GenericPrintToString(CppStyleEnum::kValue2));
+}
+
+enum class CharBasedEnum : char { kValueA = 'A', kValue1 = '\x01' };
+TEST(GenericPrinterTest, CharBasedEnum) {
+  EXPECT_EQ("'A' (0x41 65)", GenericPrintToString(CharBasedEnum::kValueA));
+  EXPECT_EQ("'\\x01' (0x01 1)", GenericPrintToString(CharBasedEnum::kValue1));
+}
+
+enum class WideBasedEnum : uint64_t {
+  kValue = std::numeric_limits<uint64_t>::max()
+};
+TEST(GenericPrinterTest, WideBasedEnum) {
+  EXPECT_EQ(absl::StrCat(std::numeric_limits<uint64_t>::max()),
+            GenericPrintToString(WideBasedEnum::kValue));
+}
+
+enum CStyleEnumWithStringify { kValueA = 0, kValueB = 2 };
+template <typename Sink>
+void AbslStringify(Sink& sink, CStyleEnumWithStringify e) {
+  switch (e) {
+    case CStyleEnumWithStringify::kValueA:
+      sink.Append("A");
+      return;
+    case CStyleEnumWithStringify::kValueB:
+      sink.Append("B");
+      return;
+  }
+  sink.Append("??");
+}
+TEST(GenericPrinterTest, CStyleEnumWithStringify) {
+  EXPECT_EQ("A", GenericPrintToString(CStyleEnumWithStringify::kValueA));
+  EXPECT_EQ("??",
+            GenericPrintToString(static_cast<CStyleEnumWithStringify>(1)));
+}
+
+enum class CppStyleEnumWithStringify { kValueA, kValueB, kValueC };
+template <typename Sink>
+void AbslStringify(Sink& sink, CppStyleEnumWithStringify e) {
+  switch (e) {
+    case CppStyleEnumWithStringify::kValueA:
+      sink.Append("A");
+      return;
+    case CppStyleEnumWithStringify::kValueB:
+      sink.Append("B");
+      return;
+    case CppStyleEnumWithStringify::kValueC:
+      sink.Append("C");
+      return;
+  }
+  sink.Append("??");
+}
+TEST(GenericPrinterTest, CppStyleEnumWithStringify) {
+  EXPECT_EQ("A", GenericPrintToString(CppStyleEnumWithStringify::kValueA));
+  EXPECT_EQ("??",
+            GenericPrintToString(static_cast<CppStyleEnumWithStringify>(17)));
+}
+
+enum class CharBasedEnumWithStringify : char { kValueA = 'A', kValueB = 'B' };
+template <typename Sink>
+void AbslStringify(Sink& sink, CharBasedEnumWithStringify e) {
+  switch (e) {
+    case CharBasedEnumWithStringify::kValueA:
+      sink.Append("charA");
+      return;
+    case CharBasedEnumWithStringify::kValueB:
+      sink.Append("charB");
+      return;
+  }
+  sink.Append("??");
+}
+TEST(GenericPrinterTest, CharBasedEnumWithStringify) {
+  EXPECT_EQ("charA", GenericPrintToString(CharBasedEnumWithStringify::kValueA));
+  EXPECT_EQ("??",
+            GenericPrintToString(static_cast<CharBasedEnumWithStringify>('W')));
+}
+
+}  // namespace
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/strings/internal/resize_uninitialized.h b/absl/strings/internal/resize_uninitialized.h
index 49859dc..7e55e5a 100644
--- a/absl/strings/internal/resize_uninitialized.h
+++ b/absl/strings/internal/resize_uninitialized.h
@@ -68,18 +68,6 @@
   ResizeUninitializedTraits<string_type>::Resize(s, new_size);
 }
 
-// Used to ensure exponential growth so that the amortized complexity of
-// increasing the string size by a small amount is O(1), in contrast to
-// O(str->size()) in the case of precise growth.
-template <typename string_type>
-void STLStringReserveAmortized(string_type* s, size_t new_size) {
-  const size_t cap = s->capacity();
-  if (new_size > cap) {
-    // Make sure to always grow by at least a factor of 2x.
-    s->reserve((std::max)(new_size, 2 * cap));
-  }
-}
-
 // In this type trait, we look for an __append_default_init member function, and
 // we use it if available, otherwise, we use append.
 template <typename string_type, typename = void>
diff --git a/absl/strings/internal/str_format/checker.h b/absl/strings/internal/str_format/checker.h
index eab6ab9..ee3df26 100644
--- a/absl/strings/internal/str_format/checker.h
+++ b/absl/strings/internal/str_format/checker.h
@@ -28,11 +28,9 @@
 // We disable format checker under vscode intellisense compilation.
 // See https://github.com/microsoft/vscode-cpptools/issues/3683 for
 // more details.
-#if ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(__native_client__) && \
-    !defined(__INTELLISENSE__)
+#if ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(__INTELLISENSE__)
 #define ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 1
-#endif  // ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(__native_client__) &&
-        // !defined(__INTELLISENSE__)
+#endif  // ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(__INTELLISENSE__)
 #endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
 
 namespace absl {
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc
index e4fa44e..f340df4 100644
--- a/absl/strings/internal/str_format/convert_test.cc
+++ b/absl/strings/internal/str_format/convert_test.cc
@@ -284,6 +284,11 @@
   return native_traits;
 }
 
+bool IsNativeHexFloatConversion(char f) { return f == 'a' || f == 'A'; }
+bool IsNativeFloatConversion(char f) {
+  return f == 'f' || f == 'F' || f == 'e' || f == 'E' || f == 'a' || f == 'A';
+}
+
 class FormatConvertTest : public ::testing::Test { };
 
 template <typename T>
@@ -799,20 +804,19 @@
                    'e', 'E'}) {
       std::string fmt_str = std::string(fmt) + f;
 
-      if (fmt == absl::string_view("%.5000") && f != 'f' && f != 'F' &&
-          f != 'a' && f != 'A') {
+      if (fmt == absl::string_view("%.5000") && !IsNativeFloatConversion(f)) {
         // This particular test takes way too long with snprintf.
         // Disable for the case we are not implementing natively.
         continue;
       }
 
-      if ((f == 'a' || f == 'A') &&
+      if (IsNativeHexFloatConversion(f) &&
           !native_traits.hex_float_has_glibc_rounding) {
         continue;
       }
 
       if (!native_traits.hex_float_prefers_denormal_repr &&
-          (f == 'a' || f == 'A') &&
+          IsNativeHexFloatConversion(f) &&
           std::fpclassify(tested_float) == FP_SUBNORMAL) {
         continue;
       }
@@ -1059,6 +1063,17 @@
             "0.000000000000000000000000000000000002"
             "25694915357879201529997415146671170141"
             "1837869002408041296803276054561138153076171875");
+
+  // Scientific exponent cases
+  // Round to even with all zeros after round digit
+  EXPECT_EQ(format("%0.13e", 1671075773261250), "1.6710757732612e+15");
+
+  // Rounding where precision is in first digit run
+  EXPECT_EQ(format("%0.1e", -1.93437090148818698e-297), "-1.9e-297");
+  EXPECT_EQ(format("%0.1e", -9.92255780642280927e-298), "-9.9e-298");
+
+  // Rounding large negative exponent first digit
+  EXPECT_EQ(format("%0.1e", -8.956e-294), "-9.0e-294");
 }
 
 TEST_F(FormatConvertTest, DoubleRoundA) {
@@ -1317,14 +1332,13 @@
                    'e', 'E'}) {
       std::string fmt_str = std::string(fmt) + 'L' + f;
 
-      if (fmt == absl::string_view("%.5000") && f != 'f' && f != 'F' &&
-          f != 'a' && f != 'A') {
+      if (fmt == absl::string_view("%.5000") && !IsNativeFloatConversion(f)) {
         // This particular test takes way too long with snprintf.
         // Disable for the case we are not implementing natively.
         continue;
       }
 
-      if (f == 'a' || f == 'A') {
+      if (IsNativeHexFloatConversion(f)) {
         if (!native_traits.hex_float_has_glibc_rounding ||
             !native_traits.hex_float_optimizes_leading_digit_bit_count) {
           continue;
diff --git a/absl/strings/internal/str_format/float_conversion.cc b/absl/strings/internal/str_format/float_conversion.cc
index aa31998..bcef275 100644
--- a/absl/strings/internal/str_format/float_conversion.cc
+++ b/absl/strings/internal/str_format/float_conversion.cc
@@ -20,7 +20,10 @@
 #include <array>
 #include <cassert>
 #include <cmath>
+#include <cstdint>
+#include <cstring>
 #include <limits>
+#include <optional>
 #include <string>
 
 #include "absl/base/attributes.h"
@@ -31,7 +34,9 @@
 #include "absl/numeric/bits.h"
 #include "absl/numeric/int128.h"
 #include "absl/numeric/internal/representation.h"
+#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"
 
@@ -451,6 +456,71 @@
   return p;
 }
 
+struct FractionalDigitPrinterResult {
+  char* end;
+  size_t skipped_zeros;
+  bool nonzero_remainder;
+};
+
+FractionalDigitPrinterResult PrintFractionalDigitsScientific(
+    uint64_t v, char* start, int exp, size_t precision, bool skip_zeros) {
+  char* p = start;
+  v <<= (64 - exp);
+
+  size_t skipped_zeros = 0;
+  while (v != 0 && precision > 0) {
+    char carry = MultiplyBy10WithCarry(&v, 0);
+    if (skip_zeros) {
+      if (carry == 0) {
+        ++skipped_zeros;
+        continue;
+      }
+      skip_zeros = false;
+    }
+    *p++ = carry + '0';
+    --precision;
+  }
+  return {p, skipped_zeros, v != 0};
+}
+
+FractionalDigitPrinterResult PrintFractionalDigitsScientific(
+    uint128 v, char* start, int exp, size_t precision, bool skip_zeros) {
+  char* p = start;
+  v <<= (128 - exp);
+  auto high = static_cast<uint64_t>(v >> 64);
+  auto low = static_cast<uint64_t>(v);
+
+  size_t skipped_zeros = 0;
+  while (precision > 0 && low != 0) {
+    char carry = MultiplyBy10WithCarry(&low, 0);
+    carry = MultiplyBy10WithCarry(&high, carry);
+    if (skip_zeros) {
+      if (carry == 0) {
+        ++skipped_zeros;
+        continue;
+      }
+      skip_zeros = false;
+    }
+    *p++ = carry + '0';
+    --precision;
+  }
+
+  while (precision > 0 && high != 0) {
+    char carry = MultiplyBy10WithCarry(&high, 0);
+    if (skip_zeros) {
+      if (carry == 0) {
+        ++skipped_zeros;
+        continue;
+      }
+      skip_zeros = false;
+    }
+    *p++ = carry + '0';
+    --precision;
+  }
+
+  return {p, skipped_zeros, high != 0 || low != 0};
+}
+
 struct FormatState {
   char sign_char;
   size_t precision;
@@ -1333,6 +1403,427 @@
   sink->Append(right_spaces, ' ');
 }
 
+template <typename Int>
+void FormatE(Int mantissa, int exp, bool uppercase, const FormatState& state) {
+  if (exp > 0) {
+    const int total_bits =
+        static_cast<int>(sizeof(Int) * 8) - LeadingZeros(mantissa) + exp;
+    if (total_bits > 128) {
+      FormatEPositiveExpSlow(mantissa, exp, uppercase, state);
+      return;
+    }
+  } else {
+    if (ABSL_PREDICT_FALSE(exp < -128)) {
+      FormatENegativeExpSlow(mantissa, exp, uppercase, state);
+      return;
+    }
+  }
+  FormatEFast(mantissa, exp, uppercase, state);
+}
+
+// Guaranteed to fit into 128 bits at this point
+template <typename Int>
+void FormatEFast(Int v, int exp, bool uppercase, const FormatState& state) {
+  if (!v) {
+    absl::string_view mantissa_str = state.ShouldPrintDot() ? "0." : "0";
+    FinalPrint(state, mantissa_str, 0, state.precision,
+               uppercase ? "E+00" : "e+00");
+    return;
+  }
+  constexpr int kInputBits = sizeof(Int) * 8;
+  constexpr int kMaxFractionalDigits = 128;
+  constexpr int kBufferSize = 2 +                    // '.' + rounding
+                              kMaxFixedPrecision +   // Integral
+                              kMaxFractionalDigits;  // Fractional
+  const int total_bits = kInputBits - LeadingZeros(v) + exp;
+  char buffer[kBufferSize];
+  char* integral_start = buffer + 2;
+  char* integral_end = buffer + 2 + kMaxFixedPrecision;
+  char* final_start;
+  char* final_end;
+  bool zero_integral = false;
+  int scientific_exp = 0;
+  size_t digits_printed = 0;
+  size_t trailing_zeros = 0;
+  bool has_more_non_zero = false;
+
+  auto check_integral_zeros =
+      [](char* const begin, char* const end,
+         const size_t precision, size_t digits_processed) -> bool {
+    // When considering rounding to even, we care about the digits after the
+    // round digit which means the total digits to move from the start is
+    // precision + 2 since the first digit we print before the decimal point
+    // is not a part of precision.
+    size_t digit_upper_bound = precision + 2;
+    if (digits_processed > digit_upper_bound) {
+      return std::any_of(begin + digit_upper_bound, end,
+                         [](char c) { return c != '0'; });
+    }
+    return false;
+  };
+
+  if (exp >= 0) {
+    integral_end = total_bits <= 64 ? numbers_internal::FastIntToBuffer(
+                               static_cast<uint64_t>(v) << exp, integral_start)
+                         : numbers_internal::FastIntToBuffer(
+                               static_cast<uint128>(v) << exp, integral_start);
+    *integral_end = '0';
+    final_start = integral_start;
+    // Integral is guaranteed to be non-zero at this point.
+    scientific_exp = static_cast<int>(integral_end - integral_start) - 1;
+    digits_printed = static_cast<size_t>(integral_end - integral_start);
+    final_end = integral_end;
+    has_more_non_zero = check_integral_zeros(integral_start, integral_end,
+                                             state.precision, digits_printed);
+  } else {
+    exp = -exp;
+    if (exp < kInputBits) {
+      integral_end =
+          numbers_internal::FastIntToBuffer(v >> exp, integral_start);
+    }
+    *integral_end = '0';
+    // We didn't move integral_start and it gets set to 0 in
+    zero_integral = exp >= kInputBits || v >> exp == 0;
+    if (!zero_integral) {
+      digits_printed = static_cast<size_t>(integral_end - integral_start);
+      has_more_non_zero = check_integral_zeros(integral_start, integral_end,
+                                               state.precision, digits_printed);
+      final_end = integral_end;
+    }
+    // Print fractional digits
+    char* fractional_start = integral_end;
+
+    size_t digits_to_print = (state.precision + 1) >= digits_printed
+                                 ? state.precision + 1 - digits_printed
+                                 : 0;
+    bool print_extra = digits_printed <= state.precision + 1;
+    auto [fractional_end, skipped_zeros, has_nonzero_rem] =
+        exp <= 64 ? PrintFractionalDigitsScientific(
+                        v, fractional_start, exp, digits_to_print + print_extra,
+                        zero_integral)
+                  : PrintFractionalDigitsScientific(
+                        static_cast<uint128>(v), fractional_start, exp,
+                        digits_to_print + print_extra, zero_integral);
+    final_end = fractional_end;
+    *fractional_end = '0';
+    has_more_non_zero |= has_nonzero_rem;
+    digits_printed += static_cast<size_t>(fractional_end - fractional_start);
+    if (zero_integral) {
+      scientific_exp = -1 * static_cast<int>(skipped_zeros + 1);
+    } else {
+      scientific_exp = static_cast<int>(integral_end - integral_start) - 1;
+    }
+    // Don't do any rounding here, we will do it ourselves.
+    final_start = zero_integral ? fractional_start : integral_start;
+  }
+
+  // For rounding
+  if (digits_printed >= state.precision + 1) {
+    final_start[-1] = '0';
+    char* round_digit_ptr = final_start + 1 + state.precision;
+    if (*round_digit_ptr > '5') {
+      RoundUp(round_digit_ptr - 1);
+    } else if (*round_digit_ptr == '5') {
+      if (has_more_non_zero) {
+        RoundUp(round_digit_ptr - 1);
+      } else {
+        RoundToEven(round_digit_ptr - 1);
+      }
+    }
+    final_end = round_digit_ptr;
+    if (final_start[-1] == '1') {
+      --final_start;
+      ++scientific_exp;
+      --final_end;
+    }
+  } else {
+    // Need to pad with zeros.
+    trailing_zeros = state.precision - (digits_printed - 1);
+  }
+
+  if (state.precision > 0 || state.ShouldPrintDot()) {
+    final_start[-1] = *final_start;
+    *final_start = '.';
+    --final_start;
+  }
+
+  // We need to add 2 to the buffer size for the +/- sign and the e
+  constexpr size_t kExpBufferSize = numbers_internal::kFastToBufferSize + 2;
+  char exp_buffer[kExpBufferSize];
+  char* exp_ptr_start = exp_buffer;
+  char* exp_ptr = exp_ptr_start;
+  *exp_ptr++ = uppercase ? 'E' : 'e';
+  if (scientific_exp >= 0) {
+    *exp_ptr++ = '+';
+  } else {
+    *exp_ptr++ = '-';
+    scientific_exp = -scientific_exp;
+  }
+
+  if (scientific_exp < 10) {
+    *exp_ptr++ = '0';
+  }
+  exp_ptr = numbers_internal::FastIntToBuffer(scientific_exp, exp_ptr);
+  FinalPrint(state,
+             absl::string_view(final_start,
+                               static_cast<size_t>(final_end - final_start)),
+             0, trailing_zeros,
+             absl::string_view(exp_ptr_start,
+                               static_cast<size_t>(exp_ptr - exp_ptr_start)));
+}
+
+void FormatENegativeExpSlow(uint128 mantissa, int exp, bool uppercase,
+                            const FormatState& state) {
+  assert(exp < 0);
+
+  FractionalDigitGenerator::RunConversion(
+      mantissa, -exp,
+      [&](FractionalDigitGenerator digit_gen) {
+        int first_digit = 0;
+        size_t nines = 0;
+        int num_leading_zeros = 0;
+        while (digit_gen.HasMoreDigits()) {
+          auto digits = digit_gen.GetDigits();
+          if (digits.digit_before_nine != 0) {
+            first_digit = digits.digit_before_nine;
+            nines = digits.num_nines;
+            break;
+          } else if (digits.num_nines > 0) {
+            // This also means the first digit is 0
+            first_digit = 9;
+            nines = digits.num_nines - 1;
+            num_leading_zeros++;
+            break;
+          }
+          num_leading_zeros++;
+        }
+
+        bool change_to_zeros = false;
+        if (nines >= state.precision || state.precision == 0) {
+          bool round_up = false;
+          if (nines == state.precision) {
+            round_up = digit_gen.IsGreaterThanHalf();
+          } else {
+            round_up = nines > 0 || digit_gen.IsGreaterThanHalf();
+          }
+          if (round_up) {
+            first_digit = (first_digit == 9 ? 1 : first_digit + 1);
+            num_leading_zeros -= (first_digit == 1);
+            change_to_zeros = true;
+          }
+        }
+        int scientific_exp = -(num_leading_zeros + 1);
+        assert(scientific_exp < 0);
+        char exp_buffer[numbers_internal::kFastToBufferSize];
+        char* exp_start = exp_buffer;
+        *exp_start++ = '-';
+        if (scientific_exp > -10) {
+          *exp_start++ = '0';
+        }
+        scientific_exp *= -1;
+        char* exp_end =
+            numbers_internal::FastIntToBuffer(scientific_exp, exp_start);
+        const size_t total_digits =
+            1                                   // First digit
+            + (state.ShouldPrintDot() ? 1 : 0)  // Decimal point
+            + state.precision                   // Digits after decimal
+            + 1                                 // 'e' or 'E'
+            + static_cast<size_t>(exp_end - exp_buffer);  // Exponent digits
+
+        const auto padding = ExtraWidthToPadding(
+            total_digits + (state.sign_char != '\0' ? 1 : 0), state);
+        state.sink->Append(padding.left_spaces, ' ');
+
+        if (state.sign_char != '\0') {
+          state.sink->Append(1, state.sign_char);
+        }
+
+        state.sink->Append(1, static_cast<char>(first_digit + '0'));
+        if (state.ShouldPrintDot()) {
+          state.sink->Append(1, '.');
+        }
+        size_t digits_to_go = state.precision;
+        size_t nines_to_print = std::min(nines, digits_to_go);
+        state.sink->Append(nines_to_print, change_to_zeros ? '0' : '9');
+        digits_to_go -= nines_to_print;
+        while (digits_to_go > 0 && digit_gen.HasMoreDigits()) {
+          auto digits = digit_gen.GetDigits();
+
+          if (digits.num_nines + 1 < digits_to_go) {
+            state.sink->Append(1, digits.digit_before_nine + '0');
+            state.sink->Append(digits.num_nines, '9');
+            digits_to_go -= digits.num_nines + 1;
+          } else {
+            bool round_up = false;
+            if (digits.num_nines + 1 > digits_to_go) {
+              round_up = true;
+            } else if (digit_gen.IsGreaterThanHalf()) {
+              round_up = true;
+            } else if (digit_gen.IsExactlyHalf()) {
+              round_up =
+                  digits.num_nines != 0 || digits.digit_before_nine % 2 == 1;
+            }
+            if (round_up) {
+              state.sink->Append(1, digits.digit_before_nine + '1');
+              --digits_to_go;
+            } else {
+              state.sink->Append(1, digits.digit_before_nine + '0');
+              state.sink->Append(digits_to_go - 1, '9');
+              digits_to_go = 0;
+            }
+            break;
+          }
+        }
+        state.sink->Append(digits_to_go, '0');
+        state.sink->Append(1, uppercase ? 'E' : 'e');
+        state.sink->Append(absl::string_view(
+            exp_buffer, static_cast<size_t>(exp_end - exp_buffer)));
+        state.sink->Append(padding.right_spaces, ' ');
+      });
+}
+
+std::optional<int> GetOneDigit(BinaryToDecimal& btd,
+                               absl::string_view& digits_view) {
+  if (digits_view.empty()) {
+    if (!btd.AdvanceDigits()) return std::nullopt;
+    digits_view = btd.CurrentDigits();
+  }
+  char d = digits_view.front();
+  digits_view.remove_prefix(1);
+  return d - '0';
+}
+
+struct DigitRun {
+  std::optional<int> digit;
+  size_t nines;
+};
+
+DigitRun GetDigits(BinaryToDecimal& btd, absl::string_view& digits_view) {
+  auto peek_digit = [&]() -> std::optional<int> {
+    if (digits_view.empty()) {
+      if (!btd.AdvanceDigits()) return std::nullopt;
+      digits_view = btd.CurrentDigits();
+    }
+    return digits_view.front() - '0';
+  };
+
+  auto digit_before_nines = GetOneDigit(btd, digits_view);
+  if (!digit_before_nines.has_value()) return {std::nullopt, 0};
+
+  auto next_digit = peek_digit();
+  size_t num_nines = 0;
+  while (next_digit == 9) {
+    // consume the 9
+    GetOneDigit(btd, digits_view);
+    ++num_nines;
+    next_digit = peek_digit();
+  }
+  return digit_before_nines == 9
+             ? DigitRun{std::nullopt, num_nines + 1}
+             : DigitRun{digit_before_nines, num_nines};
+}
+
+void FormatEPositiveExpSlow(uint128 mantissa, int exp, bool uppercase,
+                            const FormatState& state) {
+  BinaryToDecimal::RunConversion(
+      mantissa, exp, [&](BinaryToDecimal btd) {
+        int scientific_exp = static_cast<int>(btd.TotalDigits() - 1);
+        absl::string_view digits_view = btd.CurrentDigits();
+
+        size_t digits_to_go = state.precision + 1;
+        auto [first_digit_opt, nines] = GetDigits(btd, digits_view);
+        if (!first_digit_opt.has_value() && nines == 0) {
+          return;
+        }
+
+        int first_digit = first_digit_opt.value_or(9);
+        if (!first_digit_opt) {
+          --nines;
+        }
+
+        // At this point we are guaranteed to have some sort of first digit
+        bool change_to_zeros = false;
+        if (nines + 1 >= digits_to_go) {
+          // Everything we need to print is in the first DigitRun
+          auto next_digit_opt = GetDigits(btd, digits_view).digit;
+          if (nines == state.precision) {
+            change_to_zeros = next_digit_opt.value_or(0) > 4;
+          } else {
+            change_to_zeros = true;
+          }
+          if (change_to_zeros) {
+            if (first_digit != 9) {
+              first_digit = first_digit + 1;
+            } else {
+              first_digit = 1;
+              ++scientific_exp;
+            }
+          }
+        }
+
+        char exp_buffer[numbers_internal::kFastToBufferSize];
+        char* exp_buffer_end =
+            numbers_internal::FastIntToBuffer(scientific_exp, exp_buffer);
+        const size_t total_digits_out =
+            1 + state.ShouldPrintDot() + state.precision + 2 +
+            (static_cast<size_t>(exp_buffer_end - exp_buffer));
+
+        const auto padding = ExtraWidthToPadding(
+            total_digits_out + (state.sign_char != '\0' ? 1 : 0), state);
+
+        state.sink->Append(padding.left_spaces, ' ');
+        if (state.sign_char != '\0') {
+          state.sink->Append(1, state.sign_char);
+        }
+        state.sink->Append(1, static_cast<char>(first_digit + '0'));
+        --digits_to_go;
+        if (state.precision > 0 || state.ShouldPrintDot()) {
+          state.sink->Append(1, '.');
+        }
+        state.sink->Append(std::min(digits_to_go, nines),
+                           change_to_zeros ? '0' : '9');
+        digits_to_go -= std::min(digits_to_go, nines);
+        while (digits_to_go > 0) {
+          auto [digit_opt, curr_nines] = GetDigits(btd, digits_view);
+          if (!digit_opt.has_value()) break;
+          int digit = *digit_opt;
+          if (curr_nines + 1 < digits_to_go) {
+            state.sink->Append(1, static_cast<char>(digit + '0'));
+            state.sink->Append(curr_nines, '9');
+            digits_to_go -= curr_nines + 1;
+          } else {
+            bool need_round_up = false;
+            auto next_digit_opt = GetDigits(btd, digits_view).digit;
+            if (digits_to_go == 1) {
+              need_round_up = curr_nines > 0 || next_digit_opt > 4;
+            } else if (digits_to_go == curr_nines + 1) {
+              // Only round if next digit is > 4
+              need_round_up = next_digit_opt.value_or(0) > 4;
+            } else {
+              // we know we need to round since nine is after precision ends
+              need_round_up = true;
+            }
+            state.sink->Append(1,
+                               static_cast<char>(digit + need_round_up + '0'));
+            state.sink->Append(digits_to_go - 1, need_round_up ? '0' : '9');
+            digits_to_go = 0;
+          }
+        }
+
+        if (digits_to_go > 0) {
+          state.sink->Append(digits_to_go, '0');
+        }
+        state.sink->Append(1, uppercase ? 'E' : 'e');
+        state.sink->Append(1, scientific_exp >= 0 ? '+' : '-');
+        if (scientific_exp < 10) {
+          state.sink->Append(1, '0');
+        }
+        state.sink->Append(absl::string_view(
+            exp_buffer, static_cast<size_t>(exp_buffer_end - exp_buffer)));
+        state.sink->Append(padding.right_spaces, ' ');
+      });
+}
+
 template <typename Float>
 bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv,
                  FormatSinkImpl *sink) {
@@ -1371,14 +1862,10 @@
     return true;
   } else if (c == FormatConversionCharInternal::e ||
              c == FormatConversionCharInternal::E) {
-    if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
-                                               &exp)) {
-      return FallbackToSnprintf(v, conv, sink);
-    }
-    if (!conv.has_alt_flag() && buffer.back() == '.') buffer.pop_back();
-    PrintExponent(
-        exp, FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e',
-        &buffer);
+    FormatE(decomposed.mantissa, decomposed.exponent,
+            FormatConversionCharIsUpper(conv.conversion_char()),
+            {sign_char, precision, conv, sink});
+    return true;
   } else if (c == FormatConversionCharInternal::g ||
              c == FormatConversionCharInternal::G) {
     precision = std::max(precision, size_t{1}) - 1;
diff --git a/absl/strings/internal/str_join_internal.h b/absl/strings/internal/str_join_internal.h
index 31fcf6d..5f9df0e 100644
--- a/absl/strings/internal/str_join_internal.h
+++ b/absl/strings/internal/str_join_internal.h
@@ -47,6 +47,7 @@
 #include "absl/base/internal/raw_logging.h"
 #include "absl/strings/internal/ostringstream.h"
 #include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/resize_and_overwrite.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
 
@@ -249,23 +250,25 @@
       constexpr uint64_t kMaxSize =
           uint64_t{(std::numeric_limits<size_t>::max)()};
       ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
-      STLStringResizeUninitialized(&result, static_cast<size_t>(result_size));
 
-      // Joins strings
-      char* result_buf = &*result.begin();
-
-      memcpy(result_buf, start_value.data(), start_value.size());
-      result_buf += start_value.size();
-      for (Iterator it = start; ++it != end;) {
-        memcpy(result_buf, s.data(), s.size());
-        result_buf += s.size();
-        auto&& value = *it;
-        memcpy(result_buf, value.data(), value.size());
-        result_buf += value.size();
-      }
+      StringResizeAndOverwrite(
+          result, static_cast<size_t>(result_size),
+          [&start, &end, &start_value, s](char* result_buf,
+                                          size_t result_buf_size) {
+            // Joins strings
+            memcpy(result_buf, start_value.data(), start_value.size());
+            result_buf += start_value.size();
+            for (Iterator it = start; ++it != end;) {
+              memcpy(result_buf, s.data(), s.size());
+              result_buf += s.size();
+              auto&& value = *it;
+              memcpy(result_buf, value.data(), value.size());
+              result_buf += value.size();
+            }
+            return result_buf_size;
+          });
     }
   }
-
   return result;
 }
 
diff --git a/absl/strings/internal/str_split_internal.h b/absl/strings/internal/str_split_internal.h
index ed1f117..31f1d65 100644
--- a/absl/strings/internal/str_split_internal.h
+++ b/absl/strings/internal/str_split_internal.h
@@ -30,6 +30,7 @@
 #define ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_
 
 #include <array>
+#include <cassert>
 #include <cstddef>
 #include <initializer_list>
 #include <iterator>
@@ -58,8 +59,12 @@
 class ConvertibleToStringView {
  public:
   ConvertibleToStringView(const char* s)  // NOLINT(runtime/explicit)
-      : value_(s) {}
-  ConvertibleToStringView(char* s) : value_(s) {}  // NOLINT(runtime/explicit)
+      : value_(s) {
+    assert(s != nullptr);
+  }
+  ConvertibleToStringView(char* s) : value_(s) {  // NOLINT(runtime/explicit)
+    assert(s != nullptr);
+  }
   ConvertibleToStringView(absl::string_view s)     // NOLINT(runtime/explicit)
       : value_(s) {}
   ConvertibleToStringView(const std::string& s)  // NOLINT(runtime/explicit)
diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc
index a83fd2c..b6a8e42 100644
--- a/absl/strings/numbers.cc
+++ b/absl/strings/numbers.cc
@@ -50,11 +50,15 @@
 bool SimpleAtof(absl::string_view str, float* absl_nonnull out) {
   *out = 0.0;
   str = StripAsciiWhitespace(str);
+  if (str.empty()) {
+    // absl::from_chars doesn't accept empty strings.
+    return false;
+  }
   // std::from_chars doesn't accept an initial +, but SimpleAtof does, so if one
   // is present, skip it, while avoiding accepting "+-0" as valid.
-  if (!str.empty() && str[0] == '+') {
+  if (str[0] == '+') {
     str.remove_prefix(1);
-    if (!str.empty() && str[0] == '-') {
+    if (str.empty() || str[0] == '-') {
       return false;
     }
   }
@@ -81,11 +85,15 @@
 bool SimpleAtod(absl::string_view str, double* absl_nonnull out) {
   *out = 0.0;
   str = StripAsciiWhitespace(str);
+  if (str.empty()) {
+    // absl::from_chars doesn't accept empty strings.
+    return false;
+  }
   // std::from_chars doesn't accept an initial +, but SimpleAtod does, so if one
   // is present, skip it, while avoiding accepting "+-0" as valid.
-  if (!str.empty() && str[0] == '+') {
+  if (str[0] == '+') {
     str.remove_prefix(1);
-    if (!str.empty() && str[0] == '-') {
+    if (str.empty() || str[0] == '-') {
       return false;
     }
   }
@@ -234,6 +242,18 @@
   return tens;
 }
 
+
+// Encodes v to buffer as 16 digits padded with leading zeros.
+// Pre-condition: v must be < 10^16.
+inline char* EncodePadded16(uint64_t v, char* absl_nonnull buffer) {
+  constexpr uint64_t k1e8 = 100000000;
+  uint32_t hi = static_cast<uint32_t>(v / k1e8);
+  uint32_t lo = static_cast<uint32_t>(v % k1e8);
+  little_endian::Store64(buffer, PrepareEightDigits(hi) + kEightZeroBytes);
+  little_endian::Store64(buffer + 8, PrepareEightDigits(lo) + kEightZeroBytes);
+  return buffer + 16;
+}
+
 inline ABSL_ATTRIBUTE_ALWAYS_INLINE char* absl_nonnull EncodeFullU32(
     uint32_t n, char* absl_nonnull out_str) {
   if (n < 10) {
@@ -257,19 +277,19 @@
   return out_str + sizeof(bottom);
 }
 
-inline ABSL_ATTRIBUTE_ALWAYS_INLINE char* EncodeFullU64(uint64_t i,
-                                                        char* buffer) {
+inline ABSL_ATTRIBUTE_ALWAYS_INLINE char* absl_nonnull EncodeFullU64(
+    uint64_t i, char* absl_nonnull buffer) {
   if (i <= std::numeric_limits<uint32_t>::max()) {
     return EncodeFullU32(static_cast<uint32_t>(i), buffer);
   }
   uint32_t mod08;
   if (i < 1'0000'0000'0000'0000ull) {
     uint32_t div08 = static_cast<uint32_t>(i / 100'000'000ull);
-    mod08 =  static_cast<uint32_t>(i % 100'000'000ull);
+    mod08 = static_cast<uint32_t>(i % 100'000'000ull);
     buffer = EncodeFullU32(div08, buffer);
   } else {
     uint64_t div08 = i / 100'000'000ull;
-    mod08 =  static_cast<uint32_t>(i % 100'000'000ull);
+    mod08 = static_cast<uint32_t>(i % 100'000'000ull);
     uint32_t div016 = static_cast<uint32_t>(div08 / 100'000'000ull);
     uint32_t div08mod08 = static_cast<uint32_t>(div08 % 100'000'000ull);
     uint64_t mid_result = PrepareEightDigits(div08mod08) + kEightZeroBytes;
@@ -282,6 +302,30 @@
   return buffer + sizeof(mod_result);
 }
 
+inline ABSL_ATTRIBUTE_ALWAYS_INLINE char* absl_nonnull EncodeFullU128(
+    uint128 i, char* absl_nonnull buffer) {
+  if (absl::Uint128High64(i) == 0) {
+    return EncodeFullU64(absl::Uint128Low64(i), buffer);
+  }
+  // We divide the number into 16-digit chunks because `EncodePadded16` is
+  // optimized to handle 16 digits at a time (as two 8-digit chunks).
+  constexpr uint64_t k1e16 = uint64_t{10'000'000'000'000'000};
+  uint128 high = i / k1e16;
+  uint64_t low = absl::Uint128Low64(i % k1e16);
+  uint64_t mid = absl::Uint128Low64(high % k1e16);
+  high /= k1e16;
+
+  if (high == 0) {
+    buffer = EncodeFullU64(mid, buffer);
+    buffer = EncodePadded16(low, buffer);
+  } else {
+    buffer = EncodeFullU64(absl::Uint128Low64(high), buffer);
+    buffer = EncodePadded16(mid, buffer);
+    buffer = EncodePadded16(low, buffer);
+  }
+  return buffer;
+}
+
 }  // namespace
 
 void numbers_internal::PutTwoDigits(uint32_t i, char* absl_nonnull buf) {
@@ -337,6 +381,25 @@
   return buffer;
 }
 
+char* absl_nonnull numbers_internal::FastIntToBuffer(
+    uint128 i, char* absl_nonnull buffer) {
+  buffer = EncodeFullU128(i, buffer);
+  *buffer = '\0';
+  return buffer;
+}
+
+char* absl_nonnull numbers_internal::FastIntToBuffer(
+    int128 i, char* absl_nonnull buffer) {
+  uint128 u = static_cast<uint128>(i);
+  if (i < 0) {
+    *buffer++ = '-';
+    u = -u;
+  }
+  buffer = EncodeFullU128(u, buffer);
+  *buffer = '\0';
+  return buffer;
+}
+
 // Given a 128-bit number expressed as a pair of uint64_t, high half first,
 // return that number multiplied by the given 32-bit value.  If the result is
 // too large to fit in a 128-bit number, divide it by 2 until it fits.
diff --git a/absl/strings/numbers.h b/absl/strings/numbers.h
index 9c67974..fa552af 100644
--- a/absl/strings/numbers.h
+++ b/absl/strings/numbers.h
@@ -174,8 +174,9 @@
 bool safe_strtou128_base(absl::string_view text,
                          absl::uint128* absl_nonnull value, int base);
 
-static const int kFastToBufferSize = 32;
-static const int kSixDigitsToBufferSize = 16;
+inline constexpr int kFastToBuffer128Size = 41;
+inline constexpr int kFastToBufferSize = 32;
+inline constexpr int kSixDigitsToBufferSize = 16;
 
 // Helper function for fast formatting of floating-point values.
 // The result is the same as printf's "%g", a.k.a. "%.6g"; that is, six
@@ -188,7 +189,8 @@
 // WARNING: These functions may write more characters than necessary, because
 // they are intended for speed. All functions take an output buffer
 // as an argument and return a pointer to the last byte they wrote, which is the
-// terminating '\0'. At most `kFastToBufferSize` bytes are written.
+// terminating '\0'. The maximum size written is `kFastToBufferSize` for 64-bit
+// integers or less, and `kFastToBuffer128Size` for 128-bit integers.
 char* absl_nonnull FastIntToBuffer(int32_t i, char* absl_nonnull buffer)
     ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize);
 char* absl_nonnull FastIntToBuffer(uint32_t n, char* absl_nonnull out_str)
@@ -197,25 +199,36 @@
     ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize);
 char* absl_nonnull FastIntToBuffer(uint64_t i, char* absl_nonnull buffer)
     ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize);
+char* absl_nonnull FastIntToBuffer(int128 i, char* absl_nonnull buffer)
+    ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBuffer128Size);
+char* absl_nonnull FastIntToBuffer(uint128 i, char* absl_nonnull buffer)
+    ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBuffer128Size);
 
-// For enums and integer types that are not an exact match for the types above,
-// use templates to call the appropriate one of the four overloads above.
+// For enums and integer types that are up to 128 bits and are not an exact
+// match for the types above, use templates to call the appropriate one of the
+// four overloads above.
 template <typename int_type>
-char* absl_nonnull FastIntToBuffer(int_type i, char* absl_nonnull buffer)
-    ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize) {
-  static_assert(sizeof(i) <= 64 / 8,
-                "FastIntToBuffer works only with 64-bit-or-less integers.");
+char* absl_nonnull FastIntToBuffer(int_type i,
+                                          char* absl_nonnull buffer)
+    ABSL_INTERNAL_NEED_MIN_SIZE(
+        buffer, (sizeof(int_type) > 8 ? kFastToBuffer128Size
+                                      : kFastToBufferSize)) {
   // These conditions are constexpr bools to suppress MSVC warning C4127.
   constexpr bool kIsSigned = is_signed<int_type>();
   constexpr bool kUse64Bit = sizeof(i) > 32 / 8;
+  constexpr bool kUse128Bit = sizeof(i) > 64 / 8;
   if (kIsSigned) {
-    if (kUse64Bit) {
+    if constexpr (kUse128Bit) {
+      return FastIntToBuffer(static_cast<int128>(i), buffer);
+    } else if constexpr (kUse64Bit) {
       return FastIntToBuffer(static_cast<int64_t>(i), buffer);
     } else {
       return FastIntToBuffer(static_cast<int32_t>(i), buffer);
     }
   } else {
-    if (kUse64Bit) {
+    if constexpr (kUse128Bit) {
+      return FastIntToBuffer(static_cast<uint128>(i), buffer);
+    } else if constexpr (kUse64Bit) {
       return FastIntToBuffer(static_cast<uint64_t>(i), buffer);
     } else {
       return FastIntToBuffer(static_cast<uint32_t>(i), buffer);
diff --git a/absl/strings/numbers_test.cc b/absl/strings/numbers_test.cc
index 1a82087..2eaa8c7 100644
--- a/absl/strings/numbers_test.cc
+++ b/absl/strings/numbers_test.cc
@@ -159,6 +159,8 @@
 
 typedef MyInteger<int64_t> MyInt64;
 typedef MyInteger<uint64_t> MyUInt64;
+typedef MyInteger<absl::uint128> MyUInt128;
+typedef MyInteger<absl::int128> MyInt128;
 
 void CheckInt32(int32_t x) {
   char buffer[absl::numbers_internal::kFastToBufferSize];
@@ -212,6 +214,32 @@
   EXPECT_EQ(expected, std::string(&buffer[1], my_actual)) << " Input " << x;
 }
 
+void CheckUInt128(absl::uint128 x) {
+  char buffer[absl::numbers_internal::kFastToBuffer128Size];
+  char* actual = absl::numbers_internal::FastIntToBuffer(x, buffer);
+  std::string s;
+  absl::strings_internal::OStringStream strm(&s);
+  strm << x;
+  EXPECT_EQ(s, std::string(buffer, actual)) << " Input " << s;
+
+  char* my_actual =
+      absl::numbers_internal::FastIntToBuffer(MyUInt128(x), buffer);
+  EXPECT_EQ(s, std::string(buffer, my_actual)) << " Input " << s;
+}
+
+void CheckInt128(absl::int128 x) {
+  char buffer[absl::numbers_internal::kFastToBuffer128Size];
+  char* actual = absl::numbers_internal::FastIntToBuffer(x, buffer);
+  std::string s;
+  absl::strings_internal::OStringStream strm(&s);
+  strm << x;
+  EXPECT_EQ(s, std::string(buffer, actual)) << " Input " << s;
+
+  char* my_actual =
+      absl::numbers_internal::FastIntToBuffer(MyInt128(x), buffer);
+  EXPECT_EQ(s, std::string(buffer, my_actual)) << " Input " << s;
+}
+
 void CheckHex64(uint64_t v) {
   char expected[16 + 1];
   std::string actual = absl::StrCat(absl::Hex(v, absl::kZeroPad16));
@@ -251,6 +279,34 @@
   CheckUInt64(uint64_t{1000000000000000000});
   CheckUInt64(uint64_t{1199999999999999999});
   CheckUInt64(std::numeric_limits<uint64_t>::max());
+  CheckUInt128(0);
+  CheckUInt128(1);
+  CheckUInt128(9);
+  CheckUInt128(10);
+  CheckUInt128(99);
+  CheckUInt128(100);
+  CheckUInt128(std::numeric_limits<uint64_t>::max());
+  CheckUInt128(absl::uint128(std::numeric_limits<uint64_t>::max()) + 1);
+  CheckUInt128(absl::MakeUint128(1, 0));
+  absl::uint128 k1e16 = 10000000000000000ULL;
+  CheckUInt128(k1e16 - 1);
+  CheckUInt128(k1e16);
+  CheckUInt128(k1e16 + 1);
+  CheckUInt128(k1e16 * k1e16 - 1);
+  CheckUInt128(k1e16 * k1e16);
+  CheckUInt128(k1e16 * k1e16 + 1);
+  CheckUInt128(absl::Uint128Max() - 1);
+  CheckUInt128(absl::Uint128Max());
+
+  CheckInt128(0);
+  CheckInt128(1);
+  CheckInt128(-1);
+  CheckInt128(10);
+  CheckInt128(-10);
+  CheckInt128(absl::Int128Max());
+  CheckInt128(absl::Int128Min());
+  CheckInt128(absl::MakeInt128(-1, 1));
+  CheckInt128(absl::MakeInt128(-1, std::numeric_limits<uint64_t>::max()));
 
   for (int i = 0; i < 10000; i++) {
     CheckHex64(i);
@@ -451,6 +507,20 @@
   VerifySimpleAtoiGood<std::string::size_type>(42, 42);
 }
 
+TEST(NumbersTest, AtodEmpty) {
+  double d;
+  EXPECT_FALSE(absl::SimpleAtod("", &d));
+  // Empty string_view takes a different code path from "".
+  EXPECT_FALSE(absl::SimpleAtod({}, &d));
+}
+
+TEST(NumbersTest, AtofEmpty) {
+  float f;
+  EXPECT_FALSE(absl::SimpleAtof("", &f));
+  // Empty string_view takes a different code path from "".
+  EXPECT_FALSE(absl::SimpleAtof({}, &f));
+}
+
 TEST(NumbersTest, Atod) {
   // DBL_TRUE_MIN and FLT_TRUE_MIN were not mandated in <cfloat> before C++17.
 #if !defined(DBL_TRUE_MIN)
diff --git a/absl/strings/resize_and_overwrite.h b/absl/strings/resize_and_overwrite.h
new file mode 100644
index 0000000..04c12d2
--- /dev/null
+++ b/absl/strings/resize_and_overwrite.h
@@ -0,0 +1,194 @@
+// Copyright 2025 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: resize_and_overwrite.h
+// -----------------------------------------------------------------------------
+//
+// This file contains a polyfill for C++23's
+// std::basic_string<CharT,Traits,Allocator>::resize_and_overwrite
+//
+// The polyfill takes the form of a free function:
+
+// template<typename T, typename Op>
+// void StringResizeAndOverwrite(T& str, typename T::size_type count, Op op);
+//
+// This avoids the cost of initializing a suitably-sized std::string when it is
+// intended to be used as a char array, for example, to be populated by a
+// C-style API.
+//
+// Example usage:
+//
+// std::string IntToString(int n) {
+//   std::string result;
+//   constexpr size_t kMaxIntChars = 10;
+//   absl::StringResizeAndOverwrite(
+//       result, kMaxIntChars, [n](char* buffer, size_t buffer_size) {
+//         return snprintf(buffer, buffer_size, "%d", n);
+//       });
+//   return result;
+//  }
+//
+// https://en.cppreference.com/w/cpp/string/basic_string/resize_and_overwrite.html
+// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1072r10.html
+
+#ifndef ABSL_STRINGS_RESIZE_AND_OVERWRITE_H_
+#define ABSL_STRINGS_RESIZE_AND_OVERWRITE_H_
+
+#include <cstddef>
+#include <string>  // IWYU pragma: keep
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/config.h"
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
+
+#if defined(__cpp_lib_string_resize_and_overwrite) && \
+    __cpp_lib_string_resize_and_overwrite >= 202110L
+#define ABSL_INTERNAL_HAS_RESIZE_AND_OVERWRITE 1
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+namespace strings_internal {
+
+#ifndef ABSL_INTERNAL_HAS_RESIZE_AND_OVERWRITE
+
+inline size_t ProbeResizeAndOverwriteOp(char*, size_t) { return 0; }
+
+// Prior to C++23, Google's libc++ backports resize_and_overwrite as
+// __google_nonstandard_backport_resize_and_overwrite
+template <typename T, typename = void>
+struct has__google_nonstandard_backport_resize_and_overwrite : std::false_type {
+};
+
+template <typename T>
+struct has__google_nonstandard_backport_resize_and_overwrite<
+    T,
+    std::void_t<
+        decltype(std::declval<T&>()
+                     .__google_nonstandard_backport_resize_and_overwrite(
+                         std::declval<size_t>(), ProbeResizeAndOverwriteOp))>>
+    : std::true_type {};
+
+// Prior to C++23, the version of libstdc++ that shipped with GCC >= 14
+// has __resize_and_overwrite.
+template <typename T, typename = void>
+struct has__resize_and_overwrite : std::false_type {};
+
+template <typename T>
+struct has__resize_and_overwrite<
+    T, std::void_t<decltype(std::declval<T&>().__resize_and_overwrite(
+           std::declval<size_t>(), ProbeResizeAndOverwriteOp))>>
+    : std::true_type {};
+
+// libc++ used  __resize_default_init to achieve uninitialized string resizes
+// before removing it September 2025, in favor of resize_and_overwrite.
+// https://github.com/llvm/llvm-project/commit/92f5d8df361bb1bb6dea88f86faeedfd295ab970
+template <typename T, typename = void>
+struct has__resize_default_init : std::false_type {};
+
+template <typename T>
+struct has__resize_default_init<
+    T, std::void_t<decltype(std::declval<T&>().__resize_default_init(42))>>
+    : std::true_type {};
+
+// Prior to C++23, some versions of MSVC have _Resize_and_overwrite.
+template <typename T, typename = void>
+struct has_Resize_and_overwrite : std::false_type {};
+
+template <typename T>
+struct has_Resize_and_overwrite<
+    T, std::void_t<decltype(std::declval<T&>()._Resize_and_overwrite(
+           std::declval<size_t>(), ProbeResizeAndOverwriteOp))>>
+    : std::true_type {};
+
+#endif  // ifndef ABSL_INTERNAL_HAS_RESIZE_AND_OVERWRITE
+
+// A less-efficient fallback implementation that uses resize().
+template <typename T, typename Op>
+void StringResizeAndOverwriteFallback(T& str, typename T::size_type n, Op op) {
+  if (ABSL_PREDICT_FALSE(n > str.max_size())) {
+    absl::base_internal::ThrowStdLengthError("absl::StringResizeAndOverwrite");
+  }
+#ifdef ABSL_HAVE_MEMORY_SANITIZER
+  auto old_size = str.size();
+#endif
+  str.resize(n);
+#ifdef ABSL_HAVE_MEMORY_SANITIZER
+  if (old_size < n) {
+    ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(str.data() + old_size, n - old_size);
+  }
+#endif
+  auto new_size = std::move(op)(str.data(), n);
+  ABSL_HARDENING_ASSERT(new_size >= 0 && new_size <= n);
+  ABSL_HARDENING_ASSERT(str.data()[n] == typename T::value_type{});
+  str.erase(static_cast<typename T::size_type>(new_size));
+}
+
+template <typename T, typename Op>
+void StringResizeAndOverwriteImpl(T& str, typename T::size_type n, Op op) {
+#ifdef ABSL_INTERNAL_HAS_RESIZE_AND_OVERWRITE
+  str.resize_and_overwrite(n, std::move(op));
+#else
+  if constexpr (strings_internal::
+                    has__google_nonstandard_backport_resize_and_overwrite<
+                        T>::value) {
+    str.__google_nonstandard_backport_resize_and_overwrite(n, std::move(op));
+  } else if constexpr (strings_internal::has__resize_and_overwrite<T>::value) {
+    str.__resize_and_overwrite(n, std::move(op));
+  } else if constexpr (strings_internal::has__resize_default_init<T>::value) {
+    str.__resize_default_init(n);
+    str.__resize_default_init(
+        static_cast<typename T::size_type>(std::move(op)(str.data(), n)));
+  } else if constexpr (strings_internal::has_Resize_and_overwrite<T>::value) {
+    str._Resize_and_overwrite(n, std::move(op));
+  } else {
+    strings_internal::StringResizeAndOverwriteFallback(str, n, std::move(op));
+  }
+#endif
+}
+
+}  // namespace strings_internal
+
+// Resizes `str` to contain at most `n` characters, using the user-provided
+// operation `op` to modify the possibly indeterminate contents. `op` must
+// return the finalized length of `str`.
+//
+// Invalidates all iterators, pointers, and references into `str`, regardless
+// of whether reallocation occurs.
+//
+// `op(value_type* buf, size_t buf_size)` is allowed to write `value_type{}` to
+// `buf[buf_size]`, which facilitiates interoperation with functions that write
+// a trailing NUL. Please note that this requirement is more strict than
+// `basic_string::resize_and_overwrite()`, which allows writing an abitrary
+// value to `buf[buf_size]`.
+template <typename T, typename Op>
+void StringResizeAndOverwrite(T& str, typename T::size_type n, Op op) {
+  strings_internal::StringResizeAndOverwriteImpl(str, n, std::move(op));
+#if defined(ABSL_HAVE_MEMORY_SANITIZER)
+  __msan_check_mem_is_initialized(str.data(), str.size());
+#endif
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#undef ABSL_INTERNAL_HAS_RESIZE_AND_OVERWRITE
+
+#endif  // ABSL_STRINGS_RESIZE_AND_OVERWRITE_H_
diff --git a/absl/strings/resize_and_overwrite_test.cc b/absl/strings/resize_and_overwrite_test.cc
new file mode 100644
index 0000000..1070dec
--- /dev/null
+++ b/absl/strings/resize_and_overwrite_test.cc
@@ -0,0 +1,154 @@
+// Copyright 2025 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/strings/resize_and_overwrite.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "absl/base/dynamic_annotations.h"
+#include "absl/log/absl_check.h"
+
+namespace {
+
+struct ResizeAndOverwriteParam {
+  size_t initial_size;
+  size_t requested_capacity;
+  size_t final_size;
+};
+
+using StringResizeAndOverwriteTest =
+    ::testing::TestWithParam<ResizeAndOverwriteParam>;
+
+TEST_P(StringResizeAndOverwriteTest, StringResizeAndOverwrite) {
+  const auto& param = GetParam();
+  std::string s(param.initial_size, 'a');
+  absl::StringResizeAndOverwrite(
+      s, param.requested_capacity, [&](char* p, size_t n) {
+        ABSL_CHECK_EQ(n, param.requested_capacity);
+        if (param.final_size >= param.initial_size) {
+          // Append case.
+          std::fill(p + param.initial_size, p + param.final_size, 'b');
+        } else if (param.final_size > 0) {
+          // Truncate case.
+          p[param.final_size - 1] = 'b';
+        }
+        p[param.final_size] = '\0';
+        return param.final_size;
+      });
+
+  std::string expected;
+  if (param.final_size >= param.initial_size) {
+    // Append case.
+    expected = std::string(param.initial_size, 'a') +
+               std::string(param.final_size - param.initial_size, 'b');
+  } else if (param.final_size > 0) {
+    // Truncate case.
+    expected = std::string(param.final_size - 1, 'a') + std::string("b");
+  }
+
+  EXPECT_EQ(s, expected);
+  EXPECT_EQ(s.c_str()[param.final_size], '\0');
+}
+
+TEST_P(StringResizeAndOverwriteTest, StringResizeAndOverwriteFallback) {
+  const auto& param = GetParam();
+  std::string s(param.initial_size, 'a');
+  absl::strings_internal::StringResizeAndOverwriteFallback(
+      s, param.requested_capacity, [&](char* p, size_t n) {
+        ABSL_CHECK_EQ(n, param.requested_capacity);
+        if (param.final_size >= param.initial_size) {
+          // Append case.
+          std::fill(p + param.initial_size, p + param.final_size, 'b');
+        } else if (param.final_size > 0) {
+          // Truncate case.
+          p[param.final_size - 1] = 'b';
+        }
+        p[param.final_size] = '\0';
+        return param.final_size;
+      });
+
+  std::string expected;
+  if (param.final_size >= param.initial_size) {
+    // Append case.
+    expected = std::string(param.initial_size, 'a') +
+               std::string(param.final_size - param.initial_size, 'b');
+  } else if (param.final_size > 0) {
+    // Truncate case.
+    expected = std::string(param.final_size - 1, 'a') + std::string("b");
+  }
+
+  EXPECT_EQ(s, expected);
+  EXPECT_EQ(s.c_str()[param.final_size], '\0');
+}
+
+#ifdef ABSL_HAVE_MEMORY_SANITIZER
+constexpr bool kMSan = true;
+#else
+constexpr bool kMSan = false;
+#endif
+
+TEST_P(StringResizeAndOverwriteTest, Initialized) {
+  if (!kMSan) {
+    GTEST_SKIP() << "Skipping test without MSan.";
+  }
+
+  const auto& param = GetParam();
+  std::string s(param.initial_size, 'a');
+
+  auto op = [&]() {
+    absl::StringResizeAndOverwrite(s, param.requested_capacity,
+                                   [&](char*, size_t) {
+                                     // Fail to initialize the buffer in full.
+                                     return param.final_size;
+                                   });
+  };
+
+  if (param.initial_size < param.final_size) {
+#ifndef NDEBUG
+    EXPECT_DEATH_IF_SUPPORTED(op(),
+                              "MemorySanitizer: use-of-uninitialized-value");
+#endif
+  } else {
+    // The string is fully initialized from the initial constructor, or we skip
+    // the check in optimized builds.
+    op();
+  }
+}
+
+// clang-format off
+INSTANTIATE_TEST_SUITE_P(StringResizeAndOverwriteTestSuite,
+                         StringResizeAndOverwriteTest,
+                         ::testing::ValuesIn<ResizeAndOverwriteParam>({
+                             // Append cases.
+                             {0,  10,  5},
+                             {10, 10, 10},
+                             {10, 15, 15},
+                             {10, 20, 15},
+                             {10, 40, 40},
+                             {10, 50, 40},
+                             {30, 35, 35},
+                             {30, 45, 35},
+                             {10, 30, 15},
+                             // Truncate cases.
+                             {15, 15, 10},
+                             {40, 40, 35},
+                             {40, 30, 10},
+                             {10, 15, 0},
+                         }));
+// clang-format on
+
+}  // namespace
diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc
index 1f3cfbf..546b8ae 100644
--- a/absl/strings/str_cat.cc
+++ b/absl/strings/str_cat.cc
@@ -26,7 +26,8 @@
 #include "absl/base/config.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/nullability.h"
-#include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/internal/append_and_overwrite.h"
+#include "absl/strings/resize_and_overwrite.h"
 #include "absl/strings/string_view.h"
 
 namespace absl {
@@ -52,11 +53,6 @@
   return after;
 }
 
-inline void STLStringAppendUninitializedAmortized(std::string* dest,
-                                                  size_t to_append) {
-  strings_internal::AppendUninitializedTraits<std::string>::Append(dest,
-                                                                   to_append);
-}
 }  // namespace
 
 std::string StrCat(const AlphaNum& a, const AlphaNum& b) {
@@ -67,13 +63,14 @@
   const uint64_t result_size =
       static_cast<uint64_t>(a.size()) + static_cast<uint64_t>(b.size());
   ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
-  absl::strings_internal::STLStringResizeUninitialized(
-      &result, static_cast<size_t>(result_size));
-  char* const begin = &result[0];
-  char* out = begin;
-  out = Append(out, a);
-  out = Append(out, b);
-  assert(out == begin + result.size());
+  absl::StringResizeAndOverwrite(result, static_cast<size_t>(result_size),
+                                 [&a, &b](char* const begin, size_t buf_size) {
+                                   char* out = begin;
+                                   out = Append(out, a);
+                                   out = Append(out, b);
+                                   assert(out == begin + buf_size);
+                                   return buf_size;
+                                 });
   return result;
 }
 
@@ -86,14 +83,16 @@
                                static_cast<uint64_t>(b.size()) +
                                static_cast<uint64_t>(c.size());
   ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
-  strings_internal::STLStringResizeUninitialized(
-      &result, static_cast<size_t>(result_size));
-  char* const begin = &result[0];
-  char* out = begin;
-  out = Append(out, a);
-  out = Append(out, b);
-  out = Append(out, c);
-  assert(out == begin + result.size());
+  absl::StringResizeAndOverwrite(
+      result, static_cast<size_t>(result_size),
+      [&a, &b, &c](char* const begin, size_t buf_size) {
+        char* out = begin;
+        out = Append(out, a);
+        out = Append(out, b);
+        out = Append(out, c);
+        assert(out == begin + buf_size);
+        return buf_size;
+      });
   return result;
 }
 
@@ -103,20 +102,21 @@
   // Use uint64_t to prevent size_t overflow. We assume it is not possible for
   // in memory strings to overflow a uint64_t.
   constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
-  const uint64_t result_size = static_cast<uint64_t>(a.size()) +
-                               static_cast<uint64_t>(b.size()) +
-                               static_cast<uint64_t>(c.size()) +
-                               static_cast<uint64_t>(d.size());
+  const uint64_t result_size =
+      static_cast<uint64_t>(a.size()) + static_cast<uint64_t>(b.size()) +
+      static_cast<uint64_t>(c.size()) + static_cast<uint64_t>(d.size());
   ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
-  strings_internal::STLStringResizeUninitialized(
-      &result, static_cast<size_t>(result_size));
-  char* const begin = &result[0];
-  char* out = begin;
-  out = Append(out, a);
-  out = Append(out, b);
-  out = Append(out, c);
-  out = Append(out, d);
-  assert(out == begin + result.size());
+  absl::StringResizeAndOverwrite(
+      result, static_cast<size_t>(result_size),
+      [&a, &b, &c, &d](char* const begin, size_t buf_size) {
+        char* out = begin;
+        out = Append(out, a);
+        out = Append(out, b);
+        out = Append(out, c);
+        out = Append(out, d);
+        assert(out == begin + buf_size);
+        return buf_size;
+      });
   return result;
 }
 
@@ -133,19 +133,19 @@
     total_size += piece.size();
   }
   ABSL_INTERNAL_CHECK(total_size <= kMaxSize, "size_t overflow");
-  strings_internal::STLStringResizeUninitialized(
-      &result, static_cast<size_t>(total_size));
-
-  char* const begin = &result[0];
-  char* out = begin;
-  for (absl::string_view piece : pieces) {
-    const size_t this_size = piece.size();
-    if (this_size != 0) {
-      memcpy(out, piece.data(), this_size);
-      out += this_size;
-    }
-  }
-  assert(out == begin + result.size());
+  absl::StringResizeAndOverwrite(result, static_cast<size_t>(total_size),
+                                 [&pieces](char* const begin, size_t buf_size) {
+                                   char* out = begin;
+                                   for (absl::string_view piece : pieces) {
+                                     const size_t this_size = piece.size();
+                                     if (this_size != 0) {
+                                       memcpy(out, piece.data(), this_size);
+                                       out += this_size;
+                                     }
+                                   }
+                                   assert(out == begin + buf_size);
+                                   return buf_size;
+                                 });
   return result;
 }
 
@@ -160,49 +160,51 @@
 
 void AppendPieces(std::string* absl_nonnull dest,
                   std::initializer_list<absl::string_view> pieces) {
-  size_t old_size = dest->size();
   size_t to_append = 0;
   for (absl::string_view piece : pieces) {
     ASSERT_NO_OVERLAP(*dest, piece);
     to_append += piece.size();
   }
-  STLStringAppendUninitializedAmortized(dest, to_append);
-
-  char* const begin = &(*dest)[0];
-  char* out = begin + old_size;
-  for (absl::string_view piece : pieces) {
-    const size_t this_size = piece.size();
-    if (this_size != 0) {
-      memcpy(out, piece.data(), this_size);
-      out += this_size;
-    }
-  }
-  assert(out == begin + dest->size());
+  StringAppendAndOverwrite(*dest, to_append,
+                           [&pieces](char* const buf, size_t buf_size) {
+                             char* out = buf;
+                             for (absl::string_view piece : pieces) {
+                               const size_t this_size = piece.size();
+                               if (this_size != 0) {
+                                 memcpy(out, piece.data(), this_size);
+                                 out += this_size;
+                               }
+                             }
+                             assert(out == buf + buf_size);
+                             return buf_size;
+                           });
 }
 
 }  // namespace strings_internal
 
 void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a) {
   ASSERT_NO_OVERLAP(*dest, a);
-  std::string::size_type old_size = dest->size();
-  STLStringAppendUninitializedAmortized(dest, a.size());
-  char* const begin = &(*dest)[0];
-  char* out = begin + old_size;
-  out = Append(out, a);
-  assert(out == begin + dest->size());
+  strings_internal::StringAppendAndOverwrite(
+      *dest, a.size(), [&a](char* const buf, size_t buf_size) {
+        char* out = buf;
+        out = Append(out, a);
+        assert(out == buf + buf_size);
+        return buf_size;
+      });
 }
 
 void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a,
                const AlphaNum& b) {
   ASSERT_NO_OVERLAP(*dest, a);
   ASSERT_NO_OVERLAP(*dest, b);
-  std::string::size_type old_size = dest->size();
-  STLStringAppendUninitializedAmortized(dest, a.size() + b.size());
-  char* const begin = &(*dest)[0];
-  char* out = begin + old_size;
-  out = Append(out, a);
-  out = Append(out, b);
-  assert(out == begin + dest->size());
+  strings_internal::StringAppendAndOverwrite(
+      *dest, a.size() + b.size(), [&a, &b](char* const buf, size_t buf_size) {
+        char* out = buf;
+        out = Append(out, a);
+        out = Append(out, b);
+        assert(out == buf + buf_size);
+        return buf_size;
+      });
 }
 
 void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a,
@@ -210,14 +212,16 @@
   ASSERT_NO_OVERLAP(*dest, a);
   ASSERT_NO_OVERLAP(*dest, b);
   ASSERT_NO_OVERLAP(*dest, c);
-  std::string::size_type old_size = dest->size();
-  STLStringAppendUninitializedAmortized(dest, a.size() + b.size() + c.size());
-  char* const begin = &(*dest)[0];
-  char* out = begin + old_size;
-  out = Append(out, a);
-  out = Append(out, b);
-  out = Append(out, c);
-  assert(out == begin + dest->size());
+  strings_internal::StringAppendAndOverwrite(
+      *dest, a.size() + b.size() + c.size(),
+      [&a, &b, &c](char* const buf, size_t buf_size) {
+        char* out = buf;
+        out = Append(out, a);
+        out = Append(out, b);
+        out = Append(out, c);
+        assert(out == buf + buf_size);
+        return buf_size;
+      });
 }
 
 void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a,
@@ -226,16 +230,17 @@
   ASSERT_NO_OVERLAP(*dest, b);
   ASSERT_NO_OVERLAP(*dest, c);
   ASSERT_NO_OVERLAP(*dest, d);
-  std::string::size_type old_size = dest->size();
-  STLStringAppendUninitializedAmortized(
-      dest, a.size() + b.size() + c.size() + d.size());
-  char* const begin = &(*dest)[0];
-  char* out = begin + old_size;
-  out = Append(out, a);
-  out = Append(out, b);
-  out = Append(out, c);
-  out = Append(out, d);
-  assert(out == begin + dest->size());
+  strings_internal::StringAppendAndOverwrite(
+      *dest, a.size() + b.size() + c.size() + d.size(),
+      [&a, &b, &c, &d](char* const buf, size_t buf_size) {
+        char* out = buf;
+        out = Append(out, a);
+        out = Append(out, b);
+        out = Append(out, c);
+        out = Append(out, d);
+        assert(out == buf + buf_size);
+        return buf_size;
+      });
 }
 
 ABSL_NAMESPACE_END
diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h
index 84db0f6..48eb6f9 100644
--- a/absl/strings/str_cat.h
+++ b/absl/strings/str_cat.h
@@ -109,6 +109,7 @@
 #include "absl/strings/internal/resize_uninitialized.h"
 #include "absl/strings/internal/stringify_sink.h"
 #include "absl/strings/numbers.h"
+#include "absl/strings/resize_and_overwrite.h"
 #include "absl/strings/string_view.h"
 
 #if !defined(ABSL_USES_STD_STRING_VIEW)
@@ -471,23 +472,27 @@
   // with 22 bytes (including NULL at the end).
   constexpr size_t kMaxDigits10 = 22;
   std::string result;
-  strings_internal::STLStringResizeUninitialized(&result, kMaxDigits10);
-  char* start = &result[0];
-  // note: this can be optimized to not write last zero.
-  char* end = numbers_internal::FastIntToBuffer(i, start);
-  auto size = static_cast<size_t>(end - start);
-  assert((size < result.size()) &&
-         "StrCat(Integer) does not fit into kMaxDigits10");
-  result.erase(size);
+  StringResizeAndOverwrite(
+      result, kMaxDigits10, [i](char* start, size_t buf_size) {
+        // Note: This can be optimized to not write last zero.
+        char* end = numbers_internal::FastIntToBuffer(i, start);
+        auto size = static_cast<size_t>(end - start);
+        ABSL_ASSERT(size < buf_size);
+        return size;
+      });
   return result;
 }
+
 template <typename Float>
 std::string FloatToString(Float f) {
   std::string result;
-  strings_internal::STLStringResizeUninitialized(
-      &result, numbers_internal::kSixDigitsToBufferSize);
-  char* start = &result[0];
-  result.erase(numbers_internal::SixDigitsToBuffer(f, start));
+  StringResizeAndOverwrite(result, numbers_internal::kSixDigitsToBufferSize,
+                           [f](char* start, size_t buf_size) {
+                             size_t size =
+                                 numbers_internal::SixDigitsToBuffer(f, start);
+                             ABSL_ASSERT(size < buf_size);
+                             return size;
+                           });
   return result;
 }
 
diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc
index 969e1f9..a4c877a 100644
--- a/absl/strings/str_format_test.cc
+++ b/absl/strings/str_format_test.cc
@@ -65,8 +65,8 @@
     "",
     "a",
     "%80d",
-#if !defined(_MSC_VER) && !defined(__ANDROID__) && !defined(__native_client__)
-    // MSVC, NaCL and Android don't support positional syntax.
+#if !defined(_MSC_VER) && !defined(__ANDROID__)
+    // MSVC and Android don't support positional syntax.
     "complicated multipart %% %1$d format %1$0999d",
 #endif  // _MSC_VER
   };
@@ -266,8 +266,8 @@
     "a",
     "%80d",
     "%d %u %c %s %f %g",
-#if !defined(_MSC_VER) && !defined(__ANDROID__) && !defined(__native_client__)
-    // MSVC, NaCL and Android don't support positional syntax.
+#if !defined(_MSC_VER) && !defined(__ANDROID__)
+    // MSVC and Android don't support positional syntax.
     "complicated multipart %% %1$d format %1$080d",
 #endif  // _MSC_VER
   };
@@ -516,14 +516,11 @@
   EXPECT_EQ(result, 17);
   EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
 
-  // The `output` parameter is annotated nonnull, but we want to test that
-  // it is never written to if the size is zero.
-  // Use a variable instead of passing nullptr directly to avoid a `-Wnonnull`
-  // warning.
-  char* null_output = nullptr;
-  result =
-      SNPrintF(null_output, 0, "Just checking the %s of the output.", "size");
+  // Test that the buffer is never written to if the size is zero.
+  buffer[0] = '\0';
+  result = SNPrintF(buffer, 0, "Just checking the %s of the output.", "size");
   EXPECT_EQ(result, 37);
+  EXPECT_EQ(buffer[0], '\0');
 }
 
 TEST_F(FormatEntryPointTest, SNPrintFWithV) {
@@ -551,14 +548,11 @@
 
   std::string size = "size";
 
-  // The `output` parameter is annotated nonnull, but we want to test that
-  // it is never written to if the size is zero.
-  // Use a variable instead of passing nullptr directly to avoid a `-Wnonnull`
-  // warning.
-  char* null_output = nullptr;
-  result =
-      SNPrintF(null_output, 0, "Just checking the %v of the output.", size);
+  // Test that the buffer is never written to if the size is zero.
+  buffer[0] = '\0';
+  result = SNPrintF(buffer, 0, "Just checking the %v of the output.", size);
   EXPECT_EQ(result, 37);
+  EXPECT_EQ(buffer[0], '\0');
 }
 
 TEST(StrFormat, BehavesAsDocumented) {
diff --git a/absl/strings/str_split.h b/absl/strings/str_split.h
index 7e8e31c..29fa4f7 100644
--- a/absl/strings/str_split.h
+++ b/absl/strings/str_split.h
@@ -127,7 +127,7 @@
   absl::string_view Find(absl::string_view text, size_t pos) const;
 
  private:
-  const std::string delimiter_;
+  std::string delimiter_;
 };
 
 // ByAsciiWhitespace
@@ -277,7 +277,7 @@
 class MaxSplitsImpl {
  public:
   MaxSplitsImpl(Delimiter delimiter, int limit)
-      : delimiter_(delimiter), limit_(limit), count_(0) {}
+      : delimiter_(std::move(delimiter)), limit_(limit), count_(0) {}
   absl::string_view Find(absl::string_view text, size_t pos) {
     if (count_++ == limit_) {
       return absl::string_view(text.data() + text.size(),
@@ -382,7 +382,7 @@
 //   // v[0] == " a ", v[1] == " ", v[2] == "b"
 struct SkipWhitespace {
   bool operator()(absl::string_view sp) const {
-    sp = absl::StripAsciiWhitespace(sp);
+    sp = absl::StripLeadingAsciiWhitespace(sp);
     return !sp.empty();
   }
 };
diff --git a/absl/strings/str_split_test.cc b/absl/strings/str_split_test.cc
index b083975..c17c472 100644
--- a/absl/strings/str_split_test.cc
+++ b/absl/strings/str_split_test.cc
@@ -216,7 +216,7 @@
     std::multimap<std::string, std::string> m =
         absl::StrSplit("a,1,b,2,a,3", ',');
     EXPECT_EQ(3, m.size());
-    auto it = m.find("a");
+    auto it = m.lower_bound("a");
     EXPECT_EQ("1", it->second);
     ++it;
     EXPECT_EQ("3", it->second);
diff --git a/absl/strings/string_view.cc b/absl/strings/string_view.cc
deleted file mode 100644
index 33bd1bb..0000000
--- a/absl/strings/string_view.cc
+++ /dev/null
@@ -1,257 +0,0 @@
-// Copyright 2017 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/strings/string_view.h"
-
-#ifndef ABSL_USES_STD_STRING_VIEW
-
-#include <algorithm>
-#include <climits>
-#include <cstring>
-#include <ostream>
-
-#include "absl/base/nullability.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-
-namespace {
-
-// This is significantly faster for case-sensitive matches with very
-// few possible matches.
-const char* absl_nullable memmatch(const char* absl_nullable phaystack,
-                                   size_t haylen,
-                                   const char* absl_nullable pneedle,
-                                   size_t neelen) {
-  if (0 == neelen) {
-    return phaystack;  // even if haylen is 0
-  }
-  if (haylen < neelen) return nullptr;
-
-  const char* match;
-  const char* hayend = phaystack + haylen - neelen + 1;
-  // A static cast is used here as memchr returns a const void *, and pointer
-  // arithmetic is not allowed on pointers to void.
-  while (
-      (match = static_cast<const char*>(memchr(
-           phaystack, pneedle[0], static_cast<size_t>(hayend - phaystack))))) {
-    if (memcmp(match, pneedle, neelen) == 0)
-      return match;
-    else
-      phaystack = match + 1;
-  }
-  return nullptr;
-}
-
-void WritePadding(std::ostream& o, size_t pad) {
-  char fill_buf[32];
-  memset(fill_buf, o.fill(), sizeof(fill_buf));
-  while (pad) {
-    size_t n = std::min(pad, sizeof(fill_buf));
-    o.write(fill_buf, static_cast<std::streamsize>(n));
-    pad -= n;
-  }
-}
-
-class LookupTable {
- public:
-  // For each character in wanted, sets the index corresponding
-  // to the ASCII code of that character. This is used by
-  // the find_.*_of methods below to tell whether or not a character is in
-  // the lookup table in constant time.
-  explicit LookupTable(string_view wanted) {
-    for (char c : wanted) {
-      table_[Index(c)] = true;
-    }
-  }
-  bool operator[](char c) const { return table_[Index(c)]; }
-
- private:
-  static unsigned char Index(char c) { return static_cast<unsigned char>(c); }
-  bool table_[UCHAR_MAX + 1] = {};
-};
-
-}  // namespace
-
-std::ostream& operator<<(std::ostream& o, string_view piece) {
-  std::ostream::sentry sentry(o);
-  if (sentry) {
-    size_t lpad = 0;
-    size_t rpad = 0;
-    if (static_cast<size_t>(o.width()) > piece.size()) {
-      size_t pad = static_cast<size_t>(o.width()) - piece.size();
-      if ((o.flags() & o.adjustfield) == o.left) {
-        rpad = pad;
-      } else {
-        lpad = pad;
-      }
-    }
-    if (lpad) WritePadding(o, lpad);
-    o.write(piece.data(), static_cast<std::streamsize>(piece.size()));
-    if (rpad) WritePadding(o, rpad);
-    o.width(0);
-  }
-  return o;
-}
-
-string_view::size_type string_view::find(string_view s,
-                                         size_type pos) const noexcept {
-  if (empty() || pos > length_) {
-    if (empty() && pos == 0 && s.empty()) return 0;
-    return npos;
-  }
-  const char* result = memmatch(ptr_ + pos, length_ - pos, s.ptr_, s.length_);
-  return result ? static_cast<size_type>(result - ptr_) : npos;
-}
-
-string_view::size_type string_view::find(char c, size_type pos) const noexcept {
-  if (empty() || pos >= length_) {
-    return npos;
-  }
-  const char* result =
-      static_cast<const char*>(memchr(ptr_ + pos, c, length_ - pos));
-  return result != nullptr ? static_cast<size_type>(result - ptr_) : npos;
-}
-
-string_view::size_type string_view::rfind(string_view s,
-                                          size_type pos) const noexcept {
-  if (length_ < s.length_) return npos;
-  if (s.empty()) return std::min(length_, pos);
-  const char* last = ptr_ + std::min(length_ - s.length_, pos) + s.length_;
-  const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
-  return result != last ? static_cast<size_type>(result - ptr_) : npos;
-}
-
-// Search range is [0..pos] inclusive.  If pos == npos, search everything.
-string_view::size_type string_view::rfind(char c,
-                                          size_type pos) const noexcept {
-  // Note: memrchr() is not available on Windows.
-  if (empty()) return npos;
-  for (size_type i = std::min(pos, length_ - 1);; --i) {
-    if (ptr_[i] == c) {
-      return i;
-    }
-    if (i == 0) break;
-  }
-  return npos;
-}
-
-string_view::size_type string_view::find_first_of(
-    string_view s, size_type pos) const noexcept {
-  if (empty() || s.empty()) {
-    return npos;
-  }
-  // Avoid the cost of LookupTable() for a single-character search.
-  if (s.length_ == 1) return find_first_of(s.ptr_[0], pos);
-  LookupTable tbl(s);
-  for (size_type i = pos; i < length_; ++i) {
-    if (tbl[ptr_[i]]) {
-      return i;
-    }
-  }
-  return npos;
-}
-
-string_view::size_type string_view::find_first_not_of(
-    string_view s, size_type pos) const noexcept {
-  if (empty()) return npos;
-  // Avoid the cost of LookupTable() for a single-character search.
-  if (s.length_ == 1) return find_first_not_of(s.ptr_[0], pos);
-  LookupTable tbl(s);
-  for (size_type i = pos; i < length_; ++i) {
-    if (!tbl[ptr_[i]]) {
-      return i;
-    }
-  }
-  return npos;
-}
-
-string_view::size_type string_view::find_first_not_of(
-    char c, size_type pos) const noexcept {
-  if (empty()) return npos;
-  for (; pos < length_; ++pos) {
-    if (ptr_[pos] != c) {
-      return pos;
-    }
-  }
-  return npos;
-}
-
-string_view::size_type string_view::find_last_of(string_view s,
-                                                 size_type pos) const noexcept {
-  if (empty() || s.empty()) return npos;
-  // Avoid the cost of LookupTable() for a single-character search.
-  if (s.length_ == 1) return find_last_of(s.ptr_[0], pos);
-  LookupTable tbl(s);
-  for (size_type i = std::min(pos, length_ - 1);; --i) {
-    if (tbl[ptr_[i]]) {
-      return i;
-    }
-    if (i == 0) break;
-  }
-  return npos;
-}
-
-string_view::size_type string_view::find_last_not_of(
-    string_view s, size_type pos) const noexcept {
-  if (empty()) return npos;
-  size_type i = std::min(pos, length_ - 1);
-  if (s.empty()) return i;
-  // Avoid the cost of LookupTable() for a single-character search.
-  if (s.length_ == 1) return find_last_not_of(s.ptr_[0], pos);
-  LookupTable tbl(s);
-  for (;; --i) {
-    if (!tbl[ptr_[i]]) {
-      return i;
-    }
-    if (i == 0) break;
-  }
-  return npos;
-}
-
-string_view::size_type string_view::find_last_not_of(
-    char c, size_type pos) const noexcept {
-  if (empty()) return npos;
-  size_type i = std::min(pos, length_ - 1);
-  for (;; --i) {
-    if (ptr_[i] != c) {
-      return i;
-    }
-    if (i == 0) break;
-  }
-  return npos;
-}
-
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#else
-
-// https://github.com/abseil/abseil-cpp/issues/1465
-// CMake builds on Apple platforms error when libraries are empty.
-// Our CMake configuration can avoid this error on header-only libraries,
-// but since this library is conditionally empty, including a single
-// variable is an easy workaround.
-#ifdef __APPLE__
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace strings_internal {
-extern const char kAvoidEmptyStringViewLibraryWarning;
-const char kAvoidEmptyStringViewLibraryWarning = 0;
-}  // namespace strings_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
-#endif  // __APPLE__
-
-#endif  // ABSL_USES_STD_STRING_VIEW
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h
index 9a1933b..9daa149 100644
--- a/absl/strings/string_view.h
+++ b/absl/strings/string_view.h
@@ -1,4 +1,3 @@
-//
 // Copyright 2017 The Abseil Authors.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,736 +16,31 @@
 // File: string_view.h
 // -----------------------------------------------------------------------------
 //
-// This file contains the definition of the `absl::string_view` class. A
-// `string_view` points to a contiguous span of characters, often part or all of
-// another `std::string`, double-quoted string literal, character array, or even
-// another `string_view`.
-//
-// This `absl::string_view` abstraction is designed to be a drop-in
-// replacement for the C++17 `std::string_view` abstraction.
+// Historical note: Abseil once provided an implementation of
+// `absl::string_view` as a polyfill for `std::string_view` prior to C++17. Now
+// that C++17 is required, `absl::string_view` is an alias for
+// `std::string_view`
+
 #ifndef ABSL_STRINGS_STRING_VIEW_H_
 #define ABSL_STRINGS_STRING_VIEW_H_
 
-#include <algorithm>
-#include <cassert>
-#include <cstddef>
-#include <cstring>
-#include <iosfwd>
-#include <iterator>
-#include <limits>
-#include <string>
+#include <string_view>
 
 #include "absl/base/attributes.h"
-#include "absl/base/nullability.h"
 #include "absl/base/config.h"
-#include "absl/base/internal/throw_delegate.h"
-#include "absl/base/macros.h"
-#include "absl/base/optimization.h"
-#include "absl/base/port.h"
-
-#ifdef ABSL_USES_STD_STRING_VIEW
-
-#include <string_view>  // IWYU pragma: export
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-using string_view = std::string_view;
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#else  // ABSL_USES_STD_STRING_VIEW
-
-#if ABSL_HAVE_BUILTIN(__builtin_memcmp) ||        \
-    (defined(__GNUC__) && !defined(__clang__)) || \
-    (defined(_MSC_VER) && _MSC_VER >= 1928)
-#define ABSL_INTERNAL_STRING_VIEW_MEMCMP __builtin_memcmp
-#else  // ABSL_HAVE_BUILTIN(__builtin_memcmp)
-#define ABSL_INTERNAL_STRING_VIEW_MEMCMP memcmp
-#endif  // ABSL_HAVE_BUILTIN(__builtin_memcmp)
+#include "absl/base/nullability.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
-// absl::string_view
-//
-// A `string_view` provides a lightweight view into the string data provided by
-// a `std::string`, double-quoted string literal, character array, or even
-// another `string_view`. A `string_view` does *not* own the string to which it
-// points, and that data cannot be modified through the view.
-//
-// You can use `string_view` as a function or method parameter anywhere a
-// parameter can receive a double-quoted string literal, `const char*`,
-// `std::string`, or another `absl::string_view` argument with no need to copy
-// the string data. Systematic use of `string_view` within function arguments
-// reduces data copies and `strlen()` calls.
-//
-// Because of its small size, prefer passing `string_view` by value:
-//
-//   void MyFunction(absl::string_view arg);
-//
-// If circumstances require, you may also pass one by const reference:
-//
-//   void MyFunction(const absl::string_view& arg);  // not preferred
-//
-// Passing by value generates slightly smaller code for many architectures.
-//
-// In either case, the source data of the `string_view` must outlive the
-// `string_view` itself.
-//
-// A `string_view` is also suitable for local variables if you know that the
-// lifetime of the underlying object is longer than the lifetime of your
-// `string_view` variable. However, beware of binding a `string_view` to a
-// temporary value:
-//
-//   // BAD use of string_view: lifetime problem
-//   absl::string_view sv = obj.ReturnAString();
-//
-//   // GOOD use of string_view: str outlives sv
-//   std::string str = obj.ReturnAString();
-//   absl::string_view sv = str;
-//
-// Due to lifetime issues, a `string_view` is sometimes a poor choice for a
-// return value and usually a poor choice for a data member. If you do use a
-// `string_view` this way, it is your responsibility to ensure that the object
-// pointed to by the `string_view` outlives the `string_view`.
-//
-// A `string_view` may represent a whole string or just part of a string. For
-// example, when splitting a string, `std::vector<absl::string_view>` is a
-// natural data type for the output.
-//
-// For another example, a Cord is a non-contiguous, potentially very
-// long string-like object.  The Cord class has an interface that iteratively
-// provides string_view objects that point to the successive pieces of a Cord
-// object.
-//
-// When constructed from a source which is NUL-terminated, the `string_view`
-// itself will not include the NUL-terminator unless a specific size (including
-// the NUL) is passed to the constructor. As a result, common idioms that work
-// on NUL-terminated strings do not work on `string_view` objects. If you write
-// code that scans a `string_view`, you must check its length rather than test
-// for nul, for example. Note, however, that nuls may still be embedded within
-// a `string_view` explicitly.
-//
-// You may create a null `string_view` in two ways:
-//
-//   absl::string_view sv;
-//   absl::string_view sv(nullptr, 0);
-//
-// For the above, `sv.data() == nullptr`, `sv.length() == 0`, and
-// `sv.empty() == true`. Also, if you create a `string_view` with a non-null
-// pointer then `sv.data() != nullptr`. Thus, you can use `string_view()` to
-// signal an undefined value that is different from other `string_view` values
-// in a similar fashion to how `const char* p1 = nullptr;` is different from
-// `const char* p2 = "";`. However, in practice, it is not recommended to rely
-// on this behavior.
-//
-// Be careful not to confuse a null `string_view` with an empty one. A null
-// `string_view` is an empty `string_view`, but some empty `string_view`s are
-// not null. Prefer checking for emptiness over checking for null.
-//
-// There are many ways to create an empty string_view:
-//
-//   const char* nullcp = nullptr;
-//   // string_view.size() will return 0 in all cases.
-//   absl::string_view();
-//   absl::string_view(nullcp, 0);
-//   absl::string_view("");
-//   absl::string_view("", 0);
-//   absl::string_view("abcdef", 0);
-//   absl::string_view("abcdef" + 6, 0);
-//
-// All empty `string_view` objects whether null or not, are equal:
-//
-//   absl::string_view() == absl::string_view("", 0)
-//   absl::string_view(nullptr, 0) == absl::string_view("abcdef"+6, 0)
-class ABSL_ATTRIBUTE_VIEW string_view {
- public:
-  using traits_type = std::char_traits<char>;
-  using value_type = char;
-  using pointer = char* absl_nullable;
-  using const_pointer = const char* absl_nullable;
-  using reference = char&;
-  using const_reference = const char&;
-  using const_iterator = const char* absl_nullable;
-  using iterator = const_iterator;
-  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
-  using reverse_iterator = const_reverse_iterator;
-  using size_type = size_t;
-  using difference_type = std::ptrdiff_t;
-  using absl_internal_is_view = std::true_type;
-
-  static constexpr size_type npos = static_cast<size_type>(-1);
-
-  // Null `string_view` constructor
-  constexpr string_view() noexcept : ptr_(nullptr), length_(0) {}
-
-  // Implicit constructors
-
-  template <typename Allocator>
-  string_view(  // NOLINT(runtime/explicit)
-      const std::basic_string<char, std::char_traits<char>, Allocator>& str
-          ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
-      // This is implemented in terms of `string_view(p, n)` so `str.size()`
-      // doesn't need to be reevaluated after `ptr_` is set.
-      // The length check is also skipped since it is unnecessary and causes
-      // code bloat.
-      : string_view(str.data(), str.size(), SkipCheckLengthTag{}) {}
-
-  // Implicit constructor of a `string_view` from NUL-terminated `str`. When
-  // accepting possibly null strings, use `absl::NullSafeStringView(str)`
-  // instead (see below).
-  // The length check is skipped since it is unnecessary and causes code bloat.
-  constexpr string_view(  // NOLINT(runtime/explicit)
-      const char* absl_nonnull str)
-      : ptr_(str), length_(str ? StrlenInternal(str) : 0) {}
-
-  // Constructor of a `string_view` from a `const char*` and length.
-  constexpr string_view(const char* absl_nullable data, size_type len)
-      : ptr_(data), length_(CheckLengthInternal(len)) {}
-
-  constexpr string_view(const string_view&) noexcept = default;
-  string_view& operator=(const string_view&) noexcept = default;
-
-  // Iterators
-
-  // string_view::begin()
-  //
-  // Returns an iterator pointing to the first character at the beginning of the
-  // `string_view`, or `end()` if the `string_view` is empty.
-  constexpr const_iterator begin() const noexcept { return ptr_; }
-
-  // string_view::end()
-  //
-  // Returns an iterator pointing just beyond the last character at the end of
-  // the `string_view`. This iterator acts as a placeholder; attempting to
-  // access it results in undefined behavior.
-  constexpr const_iterator end() const noexcept { return ptr_ + length_; }
-
-  // string_view::cbegin()
-  //
-  // Returns a const iterator pointing to the first character at the beginning
-  // of the `string_view`, or `end()` if the `string_view` is empty.
-  constexpr const_iterator cbegin() const noexcept { return begin(); }
-
-  // string_view::cend()
-  //
-  // Returns a const iterator pointing just beyond the last character at the end
-  // of the `string_view`. This pointer acts as a placeholder; attempting to
-  // access its element results in undefined behavior.
-  constexpr const_iterator cend() const noexcept { return end(); }
-
-  // string_view::rbegin()
-  //
-  // Returns a reverse iterator pointing to the last character at the end of the
-  // `string_view`, or `rend()` if the `string_view` is empty.
-  const_reverse_iterator rbegin() const noexcept {
-    return const_reverse_iterator(end());
-  }
-
-  // string_view::rend()
-  //
-  // Returns a reverse iterator pointing just before the first character at the
-  // beginning of the `string_view`. This pointer acts as a placeholder;
-  // attempting to access its element results in undefined behavior.
-  const_reverse_iterator rend() const noexcept {
-    return const_reverse_iterator(begin());
-  }
-
-  // string_view::crbegin()
-  //
-  // Returns a const reverse iterator pointing to the last character at the end
-  // of the `string_view`, or `crend()` if the `string_view` is empty.
-  const_reverse_iterator crbegin() const noexcept { return rbegin(); }
-
-  // string_view::crend()
-  //
-  // Returns a const reverse iterator pointing just before the first character
-  // at the beginning of the `string_view`. This pointer acts as a placeholder;
-  // attempting to access its element results in undefined behavior.
-  const_reverse_iterator crend() const noexcept { return rend(); }
-
-  // Capacity Utilities
-
-  // string_view::size()
-  //
-  // Returns the number of characters in the `string_view`.
-  constexpr size_type size() const noexcept { return length_; }
-
-  // string_view::length()
-  //
-  // Returns the number of characters in the `string_view`. Alias for `size()`.
-  constexpr size_type length() const noexcept { return size(); }
-
-  // string_view::max_size()
-  //
-  // Returns the maximum number of characters the `string_view` can hold.
-  constexpr size_type max_size() const noexcept { return kMaxSize; }
-
-  // string_view::empty()
-  //
-  // Checks if the `string_view` is empty (refers to no characters).
-  constexpr bool empty() const noexcept { return length_ == 0; }
-
-  // string_view::operator[]
-  //
-  // Returns the ith element of the `string_view` using the array operator.
-  // Note that this operator does not perform any bounds checking.
-  constexpr const_reference operator[](size_type i) const {
-    ABSL_HARDENING_ASSERT(i < size());
-    return ptr_[i];
-  }
-
-  // string_view::at()
-  //
-  // Returns the ith element of the `string_view`. Bounds checking is performed,
-  // and an exception of type `std::out_of_range` will be thrown on invalid
-  // access.
-  constexpr const_reference at(size_type i) const {
-    if (ABSL_PREDICT_FALSE(i >= size())) {
-      base_internal::ThrowStdOutOfRange("absl::string_view::at");
-    }
-    return ptr_[i];
-  }
-
-  // string_view::front()
-  //
-  // Returns the first element of a `string_view`.
-  constexpr const_reference front() const {
-    ABSL_HARDENING_ASSERT(!empty());
-    return ptr_[0];
-  }
-
-  // string_view::back()
-  //
-  // Returns the last element of a `string_view`.
-  constexpr const_reference back() const {
-    ABSL_HARDENING_ASSERT(!empty());
-    return ptr_[size() - 1];
-  }
-
-  // string_view::data()
-  //
-  // Returns a pointer to the underlying character array (which is of course
-  // stored elsewhere). Note that `string_view::data()` may contain embedded nul
-  // characters, but the returned buffer may or may not be NUL-terminated;
-  // therefore, do not pass `data()` to a routine that expects a NUL-terminated
-  // string.
-  constexpr const_pointer data() const noexcept { return ptr_; }
-
-  // Modifiers
-
-  // string_view::remove_prefix()
-  //
-  // Removes the first `n` characters from the `string_view`. Note that the
-  // underlying string is not changed, only the view.
-  constexpr void remove_prefix(size_type n) {
-    ABSL_HARDENING_ASSERT(n <= length_);
-    ptr_ += n;
-    length_ -= n;
-  }
-
-  // string_view::remove_suffix()
-  //
-  // Removes the last `n` characters from the `string_view`. Note that the
-  // underlying string is not changed, only the view.
-  constexpr void remove_suffix(size_type n) {
-    ABSL_HARDENING_ASSERT(n <= length_);
-    length_ -= n;
-  }
-
-  // string_view::swap()
-  //
-  // Swaps this `string_view` with another `string_view`.
-  constexpr void swap(string_view& s) noexcept {
-    auto t = *this;
-    *this = s;
-    s = t;
-  }
-
-  // Explicit conversion operators
-
-  // Converts to `std::basic_string`.
-  template <typename A>
-  explicit operator std::basic_string<char, traits_type, A>() const {
-    if (!data()) return {};
-    return std::basic_string<char, traits_type, A>(data(), size());
-  }
-
-  // string_view::copy()
-  //
-  // Copies the contents of the `string_view` at offset `pos` and length `n`
-  // into `buf`.
-  size_type copy(char* buf, size_type n, size_type pos = 0) const {
-    if (ABSL_PREDICT_FALSE(pos > length_)) {
-      base_internal::ThrowStdOutOfRange("absl::string_view::copy");
-    }
-    size_type rlen = (std::min)(length_ - pos, n);
-    if (rlen > 0) {
-      const char* start = ptr_ + pos;
-      traits_type::copy(buf, start, rlen);
-    }
-    return rlen;
-  }
-
-  // string_view::substr()
-  //
-  // Returns a "substring" of the `string_view` (at offset `pos` and length
-  // `n`) as another string_view. This function throws `std::out_of_bounds` if
-  // `pos > size`.
-  // Use absl::ClippedSubstr if you need a truncating substr operation.
-  constexpr string_view substr(size_type pos = 0, size_type n = npos) const {
-    if (ABSL_PREDICT_FALSE(pos > length_)) {
-      base_internal::ThrowStdOutOfRange("absl::string_view::substr");
-    }
-    return string_view(ptr_ + pos, (std::min)(n, length_ - pos));
-  }
-
-  // string_view::compare()
-  //
-  // Performs a lexicographical comparison between this `string_view` and
-  // another `string_view` `x`, returning a negative value if `*this` is less
-  // than `x`, 0 if `*this` is equal to `x`, and a positive value if `*this`
-  // is greater than `x`.
-  constexpr int compare(string_view x) const noexcept {
-    return CompareImpl(length_, x.length_,
-                       (std::min)(length_, x.length_) == 0
-                           ? 0
-                           : ABSL_INTERNAL_STRING_VIEW_MEMCMP(
-                                 ptr_, x.ptr_, (std::min)(length_, x.length_)));
-  }
-
-  // Overload of `string_view::compare()` for comparing a substring of the
-  // 'string_view` and another `absl::string_view`.
-  constexpr int compare(size_type pos1, size_type count1, string_view v) const {
-    return substr(pos1, count1).compare(v);
-  }
-
-  // Overload of `string_view::compare()` for comparing a substring of the
-  // `string_view` and a substring of another `absl::string_view`.
-  constexpr int compare(size_type pos1, size_type count1, string_view v,
-                        size_type pos2, size_type count2) const {
-    return substr(pos1, count1).compare(v.substr(pos2, count2));
-  }
-
-  // Overload of `string_view::compare()` for comparing a `string_view` and a
-  // a different C-style string `s`.
-  constexpr int compare(const char* absl_nonnull s) const {
-    return compare(string_view(s));
-  }
-
-  // Overload of `string_view::compare()` for comparing a substring of the
-  // `string_view` and a different string C-style string `s`.
-  constexpr int compare(size_type pos1, size_type count1,
-                        const char* absl_nonnull s) const {
-    return substr(pos1, count1).compare(string_view(s));
-  }
-
-  // Overload of `string_view::compare()` for comparing a substring of the
-  // `string_view` and a substring of a different C-style string `s`.
-  constexpr int compare(size_type pos1, size_type count1,
-                        const char* absl_nonnull s, size_type count2) const {
-    return substr(pos1, count1).compare(string_view(s, count2));
-  }
-
-  // Find Utilities
-
-  // string_view::find()
-  //
-  // Finds the first occurrence of the substring `s` within the `string_view`,
-  // returning the position of the first character's match, or `npos` if no
-  // match was found.
-  size_type find(string_view s, size_type pos = 0) const noexcept;
-
-  // Overload of `string_view::find()` for finding the given character `c`
-  // within the `string_view`.
-  size_type find(char c, size_type pos = 0) const noexcept;
-
-  // Overload of `string_view::find()` for finding a substring of a different
-  // C-style string `s` within the `string_view`.
-  size_type find(const char* absl_nonnull s, size_type pos,
-                 size_type count) const {
-    return find(string_view(s, count), pos);
-  }
-
-  // Overload of `string_view::find()` for finding a different C-style string
-  // `s` within the `string_view`.
-  size_type find(const char* absl_nonnull s, size_type pos = 0) const {
-    return find(string_view(s), pos);
-  }
-
-  // string_view::rfind()
-  //
-  // Finds the last occurrence of a substring `s` within the `string_view`,
-  // returning the position of the first character's match, or `npos` if no
-  // match was found.
-  size_type rfind(string_view s, size_type pos = npos) const noexcept;
-
-  // Overload of `string_view::rfind()` for finding the last given character `c`
-  // within the `string_view`.
-  size_type rfind(char c, size_type pos = npos) const noexcept;
-
-  // Overload of `string_view::rfind()` for finding a substring of a different
-  // C-style string `s` within the `string_view`.
-  size_type rfind(const char* absl_nonnull s, size_type pos,
-                  size_type count) const {
-    return rfind(string_view(s, count), pos);
-  }
-
-  // Overload of `string_view::rfind()` for finding a different C-style string
-  // `s` within the `string_view`.
-  size_type rfind(const char* absl_nonnull s, size_type pos = npos) const {
-    return rfind(string_view(s), pos);
-  }
-
-  // string_view::find_first_of()
-  //
-  // Finds the first occurrence of any of the characters in `s` within the
-  // `string_view`, returning the start position of the match, or `npos` if no
-  // match was found.
-  size_type find_first_of(string_view s, size_type pos = 0) const noexcept;
-
-  // Overload of `string_view::find_first_of()` for finding a character `c`
-  // within the `string_view`.
-  size_type find_first_of(char c, size_type pos = 0) const noexcept {
-    return find(c, pos);
-  }
-
-  // Overload of `string_view::find_first_of()` for finding a substring of a
-  // different C-style string `s` within the `string_view`.
-  size_type find_first_of(const char* absl_nonnull s, size_type pos,
-                          size_type count) const {
-    return find_first_of(string_view(s, count), pos);
-  }
-
-  // Overload of `string_view::find_first_of()` for finding a different C-style
-  // string `s` within the `string_view`.
-  size_type find_first_of(const char* absl_nonnull s, size_type pos = 0) const {
-    return find_first_of(string_view(s), pos);
-  }
-
-  // string_view::find_last_of()
-  //
-  // Finds the last occurrence of any of the characters in `s` within the
-  // `string_view`, returning the start position of the match, or `npos` if no
-  // match was found.
-  size_type find_last_of(string_view s, size_type pos = npos) const noexcept;
-
-  // Overload of `string_view::find_last_of()` for finding a character `c`
-  // within the `string_view`.
-  size_type find_last_of(char c, size_type pos = npos) const noexcept {
-    return rfind(c, pos);
-  }
-
-  // Overload of `string_view::find_last_of()` for finding a substring of a
-  // different C-style string `s` within the `string_view`.
-  size_type find_last_of(const char* absl_nonnull s, size_type pos,
-                         size_type count) const {
-    return find_last_of(string_view(s, count), pos);
-  }
-
-  // Overload of `string_view::find_last_of()` for finding a different C-style
-  // string `s` within the `string_view`.
-  size_type find_last_of(const char* absl_nonnull s,
-                         size_type pos = npos) const {
-    return find_last_of(string_view(s), pos);
-  }
-
-  // string_view::find_first_not_of()
-  //
-  // Finds the first occurrence of any of the characters not in `s` within the
-  // `string_view`, returning the start position of the first non-match, or
-  // `npos` if no non-match was found.
-  size_type find_first_not_of(string_view s, size_type pos = 0) const noexcept;
-
-  // Overload of `string_view::find_first_not_of()` for finding a character
-  // that is not `c` within the `string_view`.
-  size_type find_first_not_of(char c, size_type pos = 0) const noexcept;
-
-  // Overload of `string_view::find_first_not_of()` for finding a substring of a
-  // different C-style string `s` within the `string_view`.
-  size_type find_first_not_of(const char* absl_nonnull s, size_type pos,
-                              size_type count) const {
-    return find_first_not_of(string_view(s, count), pos);
-  }
-
-  // Overload of `string_view::find_first_not_of()` for finding a different
-  // C-style string `s` within the `string_view`.
-  size_type find_first_not_of(const char* absl_nonnull s,
-                              size_type pos = 0) const {
-    return find_first_not_of(string_view(s), pos);
-  }
-
-  // string_view::find_last_not_of()
-  //
-  // Finds the last occurrence of any of the characters not in `s` within the
-  // `string_view`, returning the start position of the last non-match, or
-  // `npos` if no non-match was found.
-  size_type find_last_not_of(string_view s,
-                             size_type pos = npos) const noexcept;
-
-  // Overload of `string_view::find_last_not_of()` for finding a character
-  // that is not `c` within the `string_view`.
-  size_type find_last_not_of(char c, size_type pos = npos) const noexcept;
-
-  // Overload of `string_view::find_last_not_of()` for finding a substring of a
-  // different C-style string `s` within the `string_view`.
-  size_type find_last_not_of(const char* absl_nonnull s, size_type pos,
-                             size_type count) const {
-    return find_last_not_of(string_view(s, count), pos);
-  }
-
-  // Overload of `string_view::find_last_not_of()` for finding a different
-  // C-style string `s` within the `string_view`.
-  size_type find_last_not_of(const char* absl_nonnull s,
-                             size_type pos = npos) const {
-    return find_last_not_of(string_view(s), pos);
-  }
-
-#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
-  // string_view::starts_with()
-  //
-  // Returns true if the `string_view` starts with the prefix `s`.
-  //
-  // This method only exists when targeting at least C++20.
-  // If support for C++ prior to C++20 is required, use `absl::StartsWith()`
-  // from `//absl/strings/match.h` for compatibility.
-  constexpr bool starts_with(string_view s) const noexcept {
-    return s.empty() ||
-           (size() >= s.size() &&
-            ABSL_INTERNAL_STRING_VIEW_MEMCMP(data(), s.data(), s.size()) == 0);
-  }
-
-  // Overload of `string_view::starts_with()` that returns true if `c` is the
-  // first character of the `string_view`.
-  constexpr bool starts_with(char c) const noexcept {
-    return !empty() && front() == c;
-  }
-
-  // Overload of `string_view::starts_with()` that returns true if the
-  // `string_view` starts with the C-style prefix `s`.
-  constexpr bool starts_with(const char* s) const {
-    return starts_with(string_view(s));
-  }
-
-  // string_view::ends_with()
-  //
-  // Returns true if the `string_view` ends with the suffix `s`.
-  //
-  // This method only exists when targeting at least C++20.
-  // If support for C++ prior to C++20 is required, use `absl::EndsWith()`
-  // from `//absl/strings/match.h` for compatibility.
-  constexpr bool ends_with(string_view s) const noexcept {
-    return s.empty() || (size() >= s.size() && ABSL_INTERNAL_STRING_VIEW_MEMCMP(
-                                                   data() + (size() - s.size()),
-                                                   s.data(), s.size()) == 0);
-  }
-
-  // Overload of `string_view::ends_with()` that returns true if `c` is the
-  // last character of the `string_view`.
-  constexpr bool ends_with(char c) const noexcept {
-    return !empty() && back() == c;
-  }
-
-  // Overload of `string_view::ends_with()` that returns true if the
-  // `string_view` ends with the C-style suffix `s`.
-  constexpr bool ends_with(const char* s) const {
-    return ends_with(string_view(s));
-  }
-#endif  // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
-
- private:
-  // The constructor from std::string delegates to this constructor.
-  // See the comment on that constructor for the rationale.
-  struct SkipCheckLengthTag {};
-  string_view(const char* absl_nullable data, size_type len,
-              SkipCheckLengthTag) noexcept
-      : ptr_(data), length_(len) {}
-
-  static constexpr size_type kMaxSize =
-      (std::numeric_limits<difference_type>::max)();
-
-  static constexpr size_type CheckLengthInternal(size_type len) {
-    ABSL_HARDENING_ASSERT(len <= kMaxSize);
-    return len;
-  }
-
-  static constexpr size_type StrlenInternal(const char* absl_nonnull str) {
-#if defined(_MSC_VER) && !defined(__clang__)
-    // MSVC 2017+ can evaluate this at compile-time.
-    const char* begin = str;
-    while (*str != '\0') ++str;
-    return str - begin;
-#elif ABSL_HAVE_BUILTIN(__builtin_strlen) || \
-    (defined(__GNUC__) && !defined(__clang__))
-    // GCC has __builtin_strlen according to
-    // https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Other-Builtins.html, but
-    // ABSL_HAVE_BUILTIN doesn't detect that, so we use the extra checks above.
-    // __builtin_strlen is constexpr.
-    return __builtin_strlen(str);
-#else
-    return str ? strlen(str) : 0;
-#endif
-  }
-
-  static constexpr int CompareImpl(size_type length_a, size_type length_b,
-                                   int compare_result) {
-    return compare_result == 0 ? static_cast<int>(length_a > length_b) -
-                                     static_cast<int>(length_a < length_b)
-                               : (compare_result < 0 ? -1 : 1);
-  }
-
-  const char* absl_nullable ptr_;
-  size_type length_;
-};
-
-// This large function is defined inline so that in a fairly common case where
-// one of the arguments is a literal, the compiler can elide a lot of the
-// following comparisons.
-constexpr bool operator==(string_view x, string_view y) noexcept {
-  return x.size() == y.size() &&
-         (x.empty() ||
-          ABSL_INTERNAL_STRING_VIEW_MEMCMP(x.data(), y.data(), x.size()) == 0);
-}
-
-constexpr bool operator!=(string_view x, string_view y) noexcept {
-  return !(x == y);
-}
-
-constexpr bool operator<(string_view x, string_view y) noexcept {
-  return x.compare(y) < 0;
-}
-
-constexpr bool operator>(string_view x, string_view y) noexcept {
-  return y < x;
-}
-
-constexpr bool operator<=(string_view x, string_view y) noexcept {
-  return !(y < x);
-}
-
-constexpr bool operator>=(string_view x, string_view y) noexcept {
-  return !(x < y);
-}
-
-// IO Insertion Operator
-std::ostream& operator<<(std::ostream& o, string_view piece);
-
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#undef ABSL_INTERNAL_STRING_VIEW_MEMCMP
-
-#endif  // ABSL_USES_STD_STRING_VIEW
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
+using std::string_view;
 
 // ClippedSubstr()
 //
 // Like `s.substr(pos, n)`, but clips `pos` to an upper bound of `s.size()`.
 // Provided because std::string_view::substr throws if `pos > size()`
-inline string_view ClippedSubstr(string_view s, size_t pos,
-                                 size_t n = string_view::npos) {
+inline string_view ClippedSubstr(string_view s ABSL_ATTRIBUTE_LIFETIME_BOUND,
+                                 size_t pos, size_t n = string_view::npos) {
   pos = (std::min)(pos, static_cast<size_t>(s.size()));
   return s.substr(pos, n);
 }
diff --git a/absl/strings/string_view_benchmark.cc b/absl/strings/string_view_benchmark.cc
deleted file mode 100644
index 546f6ed..0000000
--- a/absl/strings/string_view_benchmark.cc
+++ /dev/null
@@ -1,380 +0,0 @@
-// Copyright 2018 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 <algorithm>
-#include <cstddef>
-#include <cstdint>
-#include <map>
-#include <random>
-#include <string>
-#include <unordered_set>
-#include <vector>
-
-#include "absl/base/attributes.h"
-#include "absl/base/internal/raw_logging.h"
-#include "absl/base/macros.h"
-#include "absl/random/random.h"
-#include "absl/strings/str_cat.h"
-#include "absl/strings/string_view.h"
-#include "benchmark/benchmark.h"
-
-namespace {
-
-void BM_StringViewFromString(benchmark::State& state) {
-  std::string s(state.range(0), 'x');
-  std::string* ps = &s;
-  struct SV {
-    SV() = default;
-    explicit SV(const std::string& s) : sv(s) {}
-    absl::string_view sv;
-  } sv;
-  SV* psv = &sv;
-  benchmark::DoNotOptimize(ps);
-  benchmark::DoNotOptimize(psv);
-  for (auto _ : state) {
-    new (psv) SV(*ps);
-    benchmark::DoNotOptimize(sv);
-  }
-}
-BENCHMARK(BM_StringViewFromString)->Arg(12)->Arg(128);
-
-// Provide a forcibly out-of-line wrapper for operator== that can be used in
-// benchmarks to measure the impact of inlining.
-ABSL_ATTRIBUTE_NOINLINE
-bool NonInlinedEq(absl::string_view a, absl::string_view b) { return a == b; }
-
-// We use functions that cannot be inlined to perform the comparison loops so
-// that inlining of the operator== can't optimize away *everything*.
-ABSL_ATTRIBUTE_NOINLINE
-void DoEqualityComparisons(benchmark::State& state, absl::string_view a,
-                           absl::string_view b) {
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(a == b);
-  }
-}
-
-void BM_EqualIdentical(benchmark::State& state) {
-  std::string x(state.range(0), 'a');
-  DoEqualityComparisons(state, x, x);
-}
-BENCHMARK(BM_EqualIdentical)->DenseRange(0, 3)->Range(4, 1 << 10);
-
-void BM_EqualSame(benchmark::State& state) {
-  std::string x(state.range(0), 'a');
-  std::string y = x;
-  DoEqualityComparisons(state, x, y);
-}
-BENCHMARK(BM_EqualSame)
-    ->DenseRange(0, 10)
-    ->Arg(20)
-    ->Arg(40)
-    ->Arg(70)
-    ->Arg(110)
-    ->Range(160, 4096);
-
-void BM_EqualDifferent(benchmark::State& state) {
-  const int len = state.range(0);
-  std::string x(len, 'a');
-  std::string y = x;
-  if (len > 0) {
-    y[len - 1] = 'b';
-  }
-  DoEqualityComparisons(state, x, y);
-}
-BENCHMARK(BM_EqualDifferent)->DenseRange(0, 3)->Range(4, 1 << 10);
-
-// This benchmark is intended to check that important simplifications can be
-// made with absl::string_view comparisons against constant strings. The idea is
-// that if constant strings cause redundant components of the comparison, the
-// compiler should detect and eliminate them. Here we use 8 different strings,
-// each with the same size. Provided our comparison makes the implementation
-// inline-able by the compiler, it should fold all of these away into a single
-// size check once per loop iteration.
-ABSL_ATTRIBUTE_NOINLINE
-void DoConstantSizeInlinedEqualityComparisons(benchmark::State& state,
-                                              absl::string_view a) {
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(a == "aaa");
-    benchmark::DoNotOptimize(a == "bbb");
-    benchmark::DoNotOptimize(a == "ccc");
-    benchmark::DoNotOptimize(a == "ddd");
-    benchmark::DoNotOptimize(a == "eee");
-    benchmark::DoNotOptimize(a == "fff");
-    benchmark::DoNotOptimize(a == "ggg");
-    benchmark::DoNotOptimize(a == "hhh");
-  }
-}
-void BM_EqualConstantSizeInlined(benchmark::State& state) {
-  std::string x(state.range(0), 'a');
-  DoConstantSizeInlinedEqualityComparisons(state, x);
-}
-// We only need to check for size of 3, and <> 3 as this benchmark only has to
-// do with size differences.
-BENCHMARK(BM_EqualConstantSizeInlined)->DenseRange(2, 4);
-
-// This benchmark exists purely to give context to the above timings: this is
-// what they would look like if the compiler is completely unable to simplify
-// between two comparisons when they are comparing against constant strings.
-ABSL_ATTRIBUTE_NOINLINE
-void DoConstantSizeNonInlinedEqualityComparisons(benchmark::State& state,
-                                                 absl::string_view a) {
-  for (auto _ : state) {
-    // Force these out-of-line to compare with the above function.
-    benchmark::DoNotOptimize(NonInlinedEq(a, "aaa"));
-    benchmark::DoNotOptimize(NonInlinedEq(a, "bbb"));
-    benchmark::DoNotOptimize(NonInlinedEq(a, "ccc"));
-    benchmark::DoNotOptimize(NonInlinedEq(a, "ddd"));
-    benchmark::DoNotOptimize(NonInlinedEq(a, "eee"));
-    benchmark::DoNotOptimize(NonInlinedEq(a, "fff"));
-    benchmark::DoNotOptimize(NonInlinedEq(a, "ggg"));
-    benchmark::DoNotOptimize(NonInlinedEq(a, "hhh"));
-  }
-}
-
-void BM_EqualConstantSizeNonInlined(benchmark::State& state) {
-  std::string x(state.range(0), 'a');
-  DoConstantSizeNonInlinedEqualityComparisons(state, x);
-}
-// We only need to check for size of 3, and <> 3 as this benchmark only has to
-// do with size differences.
-BENCHMARK(BM_EqualConstantSizeNonInlined)->DenseRange(2, 4);
-
-void BM_CompareSame(benchmark::State& state) {
-  const int len = state.range(0);
-  std::string x;
-  for (int i = 0; i < len; i++) {
-    x += 'a';
-  }
-  std::string y = x;
-  absl::string_view a = x;
-  absl::string_view b = y;
-
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(a);
-    benchmark::DoNotOptimize(b);
-    benchmark::DoNotOptimize(a.compare(b));
-  }
-}
-BENCHMARK(BM_CompareSame)->DenseRange(0, 3)->Range(4, 1 << 10);
-
-void BM_CompareFirstOneLess(benchmark::State& state) {
-  const int len = state.range(0);
-  std::string x(len, 'a');
-  std::string y = x;
-  y.back() = 'b';
-  absl::string_view a = x;
-  absl::string_view b = y;
-
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(a);
-    benchmark::DoNotOptimize(b);
-    benchmark::DoNotOptimize(a.compare(b));
-  }
-}
-BENCHMARK(BM_CompareFirstOneLess)->DenseRange(1, 3)->Range(4, 1 << 10);
-
-void BM_CompareSecondOneLess(benchmark::State& state) {
-  const int len = state.range(0);
-  std::string x(len, 'a');
-  std::string y = x;
-  x.back() = 'b';
-  absl::string_view a = x;
-  absl::string_view b = y;
-
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(a);
-    benchmark::DoNotOptimize(b);
-    benchmark::DoNotOptimize(a.compare(b));
-  }
-}
-BENCHMARK(BM_CompareSecondOneLess)->DenseRange(1, 3)->Range(4, 1 << 10);
-
-void BM_find_string_view_len_one(benchmark::State& state) {
-  std::string haystack(state.range(0), '0');
-  absl::string_view s(haystack);
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(s.find("x"));  // not present; length 1
-  }
-}
-BENCHMARK(BM_find_string_view_len_one)->Range(1, 1 << 20);
-
-void BM_find_string_view_len_two(benchmark::State& state) {
-  std::string haystack(state.range(0), '0');
-  absl::string_view s(haystack);
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(s.find("xx"));  // not present; length 2
-  }
-}
-BENCHMARK(BM_find_string_view_len_two)->Range(1, 1 << 20);
-
-void BM_find_one_char(benchmark::State& state) {
-  std::string haystack(state.range(0), '0');
-  absl::string_view s(haystack);
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(s.find('x'));  // not present
-  }
-}
-BENCHMARK(BM_find_one_char)->Range(1, 1 << 20);
-
-void BM_rfind_one_char(benchmark::State& state) {
-  std::string haystack(state.range(0), '0');
-  absl::string_view s(haystack);
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(s.rfind('x'));  // not present
-  }
-}
-BENCHMARK(BM_rfind_one_char)->Range(1, 1 << 20);
-
-void BM_worst_case_find_first_of(benchmark::State& state, int haystack_len) {
-  const int needle_len = state.range(0);
-  std::string needle;
-  for (int i = 0; i < needle_len; ++i) {
-    needle += 'a' + i;
-  }
-  std::string haystack(haystack_len, '0');  // 1000 zeros.
-
-  absl::string_view s(haystack);
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(s.find_first_of(needle));
-  }
-}
-
-void BM_find_first_of_short(benchmark::State& state) {
-  BM_worst_case_find_first_of(state, 10);
-}
-
-void BM_find_first_of_medium(benchmark::State& state) {
-  BM_worst_case_find_first_of(state, 100);
-}
-
-void BM_find_first_of_long(benchmark::State& state) {
-  BM_worst_case_find_first_of(state, 1000);
-}
-
-BENCHMARK(BM_find_first_of_short)->DenseRange(0, 4)->Arg(8)->Arg(16)->Arg(32);
-BENCHMARK(BM_find_first_of_medium)->DenseRange(0, 4)->Arg(8)->Arg(16)->Arg(32);
-BENCHMARK(BM_find_first_of_long)->DenseRange(0, 4)->Arg(8)->Arg(16)->Arg(32);
-
-struct EasyMap : public std::map<absl::string_view, uint64_t> {
-  explicit EasyMap(size_t) {}
-};
-
-// This templated benchmark helper function is intended to stress operator== or
-// operator< in a realistic test.  It surely isn't entirely realistic, but it's
-// a start.  The test creates a map of type Map, a template arg, and populates
-// it with table_size key/value pairs. Each key has WordsPerKey words.  After
-// creating the map, a number of lookups are done in random order.  Some keys
-// are used much more frequently than others in this phase of the test.
-template <typename Map, int WordsPerKey>
-void StringViewMapBenchmark(benchmark::State& state) {
-  const int table_size = state.range(0);
-  const double kFractionOfKeysThatAreHot = 0.2;
-  const int kNumLookupsOfHotKeys = 20;
-  const int kNumLookupsOfColdKeys = 1;
-  const char* words[] = {"the",   "quick",  "brown",    "fox",      "jumped",
-                         "over",  "the",    "lazy",     "dog",      "and",
-                         "found", "a",      "large",    "mushroom", "and",
-                         "a",     "couple", "crickets", "eating",   "pie"};
-  // Create some keys that consist of words in random order.
-  absl::InsecureBitGen rng;
-  std::vector<std::string> keys(table_size);
-  std::vector<int> all_indices;
-  const int kBlockSize = 1 << 12;
-  std::unordered_set<std::string> t(kBlockSize);
-  std::uniform_int_distribution<int> uniform(0, ABSL_ARRAYSIZE(words) - 1);
-  for (int i = 0; i < table_size; i++) {
-    all_indices.push_back(i);
-    do {
-      keys[i].clear();
-      for (int j = 0; j < WordsPerKey; j++) {
-        absl::StrAppend(&keys[i], j > 0 ? " " : "", words[uniform(rng)]);
-      }
-    } while (!t.insert(keys[i]).second);
-  }
-
-  // Create a list of strings to lookup: a permutation of the array of
-  // keys we just created, with repeats.  "Hot" keys get repeated more.
-  std::shuffle(all_indices.begin(), all_indices.end(), rng);
-  const int num_hot = table_size * kFractionOfKeysThatAreHot;
-  const int num_cold = table_size - num_hot;
-  std::vector<int> hot_indices(all_indices.begin(),
-                               all_indices.begin() + num_hot);
-  std::vector<int> indices;
-  for (int i = 0; i < kNumLookupsOfColdKeys; i++) {
-    indices.insert(indices.end(), all_indices.begin(), all_indices.end());
-  }
-  for (int i = 0; i < kNumLookupsOfHotKeys - kNumLookupsOfColdKeys; i++) {
-    indices.insert(indices.end(), hot_indices.begin(), hot_indices.end());
-  }
-  std::shuffle(indices.begin(), indices.end(), rng);
-  ABSL_RAW_CHECK(
-      num_cold * kNumLookupsOfColdKeys + num_hot * kNumLookupsOfHotKeys ==
-          indices.size(),
-      "");
-  // After constructing the array we probe it with absl::string_views built from
-  // test_strings.  This means operator== won't see equal pointers, so
-  // it'll have to check for equal lengths and equal characters.
-  std::vector<std::string> test_strings(indices.size());
-  for (int i = 0; i < indices.size(); i++) {
-    test_strings[i] = keys[indices[i]];
-  }
-
-  // Run the benchmark. It includes map construction but is mostly
-  // map lookups.
-  for (auto _ : state) {
-    Map h(table_size);
-    for (int i = 0; i < table_size; i++) {
-      h[keys[i]] = i * 2;
-    }
-    ABSL_RAW_CHECK(h.size() == table_size, "");
-    uint64_t sum = 0;
-    for (int i = 0; i < indices.size(); i++) {
-      sum += h[test_strings[i]];
-    }
-    benchmark::DoNotOptimize(sum);
-  }
-}
-
-void BM_StdMap_4(benchmark::State& state) {
-  StringViewMapBenchmark<EasyMap, 4>(state);
-}
-BENCHMARK(BM_StdMap_4)->Range(1 << 10, 1 << 16);
-
-void BM_StdMap_8(benchmark::State& state) {
-  StringViewMapBenchmark<EasyMap, 8>(state);
-}
-BENCHMARK(BM_StdMap_8)->Range(1 << 10, 1 << 16);
-
-void BM_CopyToStringNative(benchmark::State& state) {
-  std::string src(state.range(0), 'x');
-  absl::string_view sv(src);
-  std::string dst;
-  for (auto _ : state) {
-    dst.assign(sv.begin(), sv.end());
-  }
-}
-BENCHMARK(BM_CopyToStringNative)->Range(1 << 3, 1 << 12);
-
-void BM_AppendToStringNative(benchmark::State& state) {
-  std::string src(state.range(0), 'x');
-  absl::string_view sv(src);
-  std::string dst;
-  for (auto _ : state) {
-    dst.clear();
-    dst.insert(dst.end(), sv.begin(), sv.end());
-  }
-}
-BENCHMARK(BM_AppendToStringNative)->Range(1 << 3, 1 << 12);
-
-}  // namespace
diff --git a/absl/strings/string_view_test.cc b/absl/strings/string_view_test.cc
index 0a2a7a9..d6cec6f 100644
--- a/absl/strings/string_view_test.cc
+++ b/absl/strings/string_view_test.cc
@@ -14,8 +14,7 @@
 
 #include "absl/strings/string_view.h"
 
-#include <stdlib.h>
-
+#include <array>
 #include <cstddef>
 #include <cstdlib>
 #include <cstring>
@@ -34,704 +33,8 @@
 #include "absl/base/config.h"
 #include "absl/meta/type_traits.h"
 
-#if defined(ABSL_USES_STD_STRING_VIEW) || defined(__ANDROID__)
-// We don't control the death messaging when using std::string_view.
-// Android assert messages only go to system log, so death tests cannot inspect
-// the message for matching.
-#define ABSL_EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
-  EXPECT_DEATH_IF_SUPPORTED(statement, ".*")
-#else
-#define ABSL_EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
-  EXPECT_DEATH_IF_SUPPORTED(statement, regex)
-#endif
-
 namespace {
 
-static_assert(!absl::type_traits_internal::IsOwner<absl::string_view>::value &&
-                  absl::type_traits_internal::IsView<absl::string_view>::value,
-              "string_view is a view, not an owner");
-
-static_assert(absl::type_traits_internal::IsLifetimeBoundAssignment<
-                  absl::string_view, std::string>::value,
-              "lifetimebound assignment not detected");
-
-// A minimal allocator that uses malloc().
-template <typename T>
-struct Mallocator {
-  typedef T value_type;
-  typedef size_t size_type;
-  typedef ptrdiff_t difference_type;
-  typedef T* pointer;
-  typedef const T* const_pointer;
-  typedef T& reference;
-  typedef const T& const_reference;
-
-  size_type max_size() const {
-    return size_t(std::numeric_limits<size_type>::max()) / sizeof(value_type);
-  }
-  template <typename U>
-  struct rebind {
-    typedef Mallocator<U> other;
-  };
-  Mallocator() = default;
-  template <class U>
-  Mallocator(const Mallocator<U>&) {}  // NOLINT(runtime/explicit)
-
-  T* allocate(size_t n) { return static_cast<T*>(std::malloc(n * sizeof(T))); }
-  void deallocate(T* p, size_t) { std::free(p); }
-};
-template <typename T, typename U>
-bool operator==(const Mallocator<T>&, const Mallocator<U>&) {
-  return true;
-}
-template <typename T, typename U>
-bool operator!=(const Mallocator<T>&, const Mallocator<U>&) {
-  return false;
-}
-
-TEST(StringViewTest, Ctor) {
-  {
-    // Null.
-    absl::string_view s10;
-    EXPECT_TRUE(s10.data() == nullptr);
-    EXPECT_EQ(0u, s10.length());
-  }
-
-  {
-    // const char* without length.
-    const char* hello = "hello";
-    absl::string_view s20(hello);
-    EXPECT_TRUE(s20.data() == hello);
-    EXPECT_EQ(5u, s20.length());
-
-    // const char* with length.
-    absl::string_view s21(hello, 4);
-    EXPECT_TRUE(s21.data() == hello);
-    EXPECT_EQ(4u, s21.length());
-
-    // Not recommended, but valid C++
-    absl::string_view s22(hello, 6);
-    EXPECT_TRUE(s22.data() == hello);
-    EXPECT_EQ(6u, s22.length());
-  }
-
-  {
-    // std::string.
-    std::string hola = "hola";
-    absl::string_view s30(hola);
-    EXPECT_TRUE(s30.data() == hola.data());
-    EXPECT_EQ(4u, s30.length());
-
-    // std::string with embedded '\0'.
-    hola.push_back('\0');
-    hola.append("h2");
-    hola.push_back('\0');
-    absl::string_view s31(hola);
-    EXPECT_TRUE(s31.data() == hola.data());
-    EXPECT_EQ(8u, s31.length());
-  }
-
-  {
-    using mstring =
-        std::basic_string<char, std::char_traits<char>, Mallocator<char>>;
-    mstring str1("BUNGIE-JUMPING!");
-    const mstring str2("SLEEPING!");
-
-    absl::string_view s1(str1);
-    s1.remove_prefix(strlen("BUNGIE-JUM"));
-
-    absl::string_view s2(str2);
-    s2.remove_prefix(strlen("SLEE"));
-
-    EXPECT_EQ(s1, s2);
-    EXPECT_EQ(s1, "PING!");
-  }
-
-  // TODO(mec): absl::string_view(const absl::string_view&);
-}
-
-TEST(StringViewTest, Swap) {
-  absl::string_view a("a");
-  absl::string_view b("bbb");
-  EXPECT_TRUE(noexcept(a.swap(b)));
-  a.swap(b);
-  EXPECT_EQ(a, "bbb");
-  EXPECT_EQ(b, "a");
-  a.swap(b);
-  EXPECT_EQ(a, "a");
-  EXPECT_EQ(b, "bbb");
-}
-
-TEST(StringViewTest, STLComparator) {
-  std::string s1("foo");
-  std::string s2("bar");
-  std::string s3("baz");
-
-  absl::string_view p1(s1);
-  absl::string_view p2(s2);
-  absl::string_view p3(s3);
-
-  typedef std::map<absl::string_view, int> TestMap;
-  TestMap map;
-
-  map.insert(std::make_pair(p1, 0));
-  map.insert(std::make_pair(p2, 1));
-  map.insert(std::make_pair(p3, 2));
-  EXPECT_EQ(map.size(), 3u);
-
-  TestMap::const_iterator iter = map.begin();
-  EXPECT_EQ(iter->second, 1);
-  ++iter;
-  EXPECT_EQ(iter->second, 2);
-  ++iter;
-  EXPECT_EQ(iter->second, 0);
-  ++iter;
-  EXPECT_TRUE(iter == map.end());
-
-  TestMap::iterator new_iter = map.find("zot");
-  EXPECT_TRUE(new_iter == map.end());
-
-  new_iter = map.find("bar");
-  EXPECT_TRUE(new_iter != map.end());
-
-  map.erase(new_iter);
-  EXPECT_EQ(map.size(), 2u);
-
-  iter = map.begin();
-  EXPECT_EQ(iter->second, 2);
-  ++iter;
-  EXPECT_EQ(iter->second, 0);
-  ++iter;
-  EXPECT_TRUE(iter == map.end());
-}
-
-#define COMPARE(result, op, x, y)                                      \
-  EXPECT_EQ(result, absl::string_view((x)) op absl::string_view((y))); \
-  EXPECT_EQ(result, absl::string_view((x)).compare(absl::string_view((y))) op 0)
-
-TEST(StringViewTest, ComparisonOperators) {
-  COMPARE(true, ==, "",   "");
-  COMPARE(true, ==, "", absl::string_view());
-  COMPARE(true, ==, absl::string_view(), "");
-  COMPARE(true, ==, "a",  "a");
-  COMPARE(true, ==, "aa", "aa");
-  COMPARE(false, ==, "a",  "");
-  COMPARE(false, ==, "",   "a");
-  COMPARE(false, ==, "a",  "b");
-  COMPARE(false, ==, "a",  "aa");
-  COMPARE(false, ==, "aa", "a");
-
-  COMPARE(false, !=, "",   "");
-  COMPARE(false, !=, "a",  "a");
-  COMPARE(false, !=, "aa", "aa");
-  COMPARE(true, !=, "a",  "");
-  COMPARE(true, !=, "",   "a");
-  COMPARE(true, !=, "a",  "b");
-  COMPARE(true, !=, "a",  "aa");
-  COMPARE(true, !=, "aa", "a");
-
-  COMPARE(true, <, "a",  "b");
-  COMPARE(true, <, "a",  "aa");
-  COMPARE(true, <, "aa", "b");
-  COMPARE(true, <, "aa", "bb");
-  COMPARE(false, <, "a",  "a");
-  COMPARE(false, <, "b",  "a");
-  COMPARE(false, <, "aa", "a");
-  COMPARE(false, <, "b",  "aa");
-  COMPARE(false, <, "bb", "aa");
-
-  COMPARE(true, <=, "a",  "a");
-  COMPARE(true, <=, "a",  "b");
-  COMPARE(true, <=, "a",  "aa");
-  COMPARE(true, <=, "aa", "b");
-  COMPARE(true, <=, "aa", "bb");
-  COMPARE(false, <=, "b",  "a");
-  COMPARE(false, <=, "aa", "a");
-  COMPARE(false, <=, "b",  "aa");
-  COMPARE(false, <=, "bb", "aa");
-
-  COMPARE(false, >=, "a",  "b");
-  COMPARE(false, >=, "a",  "aa");
-  COMPARE(false, >=, "aa", "b");
-  COMPARE(false, >=, "aa", "bb");
-  COMPARE(true, >=, "a",  "a");
-  COMPARE(true, >=, "b",  "a");
-  COMPARE(true, >=, "aa", "a");
-  COMPARE(true, >=, "b",  "aa");
-  COMPARE(true, >=, "bb", "aa");
-
-  COMPARE(false, >, "a",  "a");
-  COMPARE(false, >, "a",  "b");
-  COMPARE(false, >, "a",  "aa");
-  COMPARE(false, >, "aa", "b");
-  COMPARE(false, >, "aa", "bb");
-  COMPARE(true, >, "b",  "a");
-  COMPARE(true, >, "aa", "a");
-  COMPARE(true, >, "b",  "aa");
-  COMPARE(true, >, "bb", "aa");
-}
-
-TEST(StringViewTest, ComparisonOperatorsByCharacterPosition) {
-  std::string x;
-  for (size_t i = 0; i < 256; i++) {
-    x += 'a';
-    std::string y = x;
-    COMPARE(true, ==, x, y);
-    for (size_t j = 0; j < i; j++) {
-      std::string z = x;
-      z[j] = 'b';       // Differs in position 'j'
-      COMPARE(false, ==, x, z);
-      COMPARE(true, <, x, z);
-      COMPARE(true, >, z, x);
-      if (j + 1 < i) {
-        z[j + 1] = 'A';  // Differs in position 'j+1' as well
-        COMPARE(false, ==, x, z);
-        COMPARE(true, <, x, z);
-        COMPARE(true, >, z, x);
-        z[j + 1] = 'z';  // Differs in position 'j+1' as well
-        COMPARE(false, ==, x, z);
-        COMPARE(true, <, x, z);
-        COMPARE(true, >, z, x);
-      }
-    }
-  }
-}
-#undef COMPARE
-
-// Sadly, our users often confuse std::string::npos with
-// absl::string_view::npos; So much so that we test here that they are the same.
-// They need to both be unsigned, and both be the maximum-valued integer of
-// their type.
-
-template <typename T>
-struct is_type {
-  template <typename U>
-  static bool same(U) {
-    return false;
-  }
-  static bool same(T) { return true; }
-};
-
-TEST(StringViewTest, NposMatchesStdStringView) {
-  EXPECT_EQ(absl::string_view::npos, std::string::npos);
-
-  EXPECT_TRUE(is_type<size_t>::same(absl::string_view::npos));
-  EXPECT_FALSE(is_type<size_t>::same(""));
-
-  // Make sure absl::string_view::npos continues to be a header constant.
-  char test[absl::string_view::npos & 1] = {0};
-  EXPECT_EQ(0, test[0]);
-}
-
-TEST(StringViewTest, STL1) {
-  const absl::string_view a("abcdefghijklmnopqrstuvwxyz");
-  const absl::string_view b("abc");
-  const absl::string_view c("xyz");
-  const absl::string_view d("foobar");
-  const absl::string_view e;
-  std::string temp("123");
-  temp += '\0';
-  temp += "456";
-  const absl::string_view f(temp);
-
-  EXPECT_EQ(a[6], 'g');
-  EXPECT_EQ(b[0], 'a');
-  EXPECT_EQ(c[2], 'z');
-  EXPECT_EQ(f[3], '\0');
-  EXPECT_EQ(f[5], '5');
-
-  EXPECT_EQ(*d.data(), 'f');
-  EXPECT_EQ(d.data()[5], 'r');
-  EXPECT_TRUE(e.data() == nullptr);
-
-  EXPECT_EQ(*a.begin(), 'a');
-  EXPECT_EQ(*(b.begin() + 2), 'c');
-  EXPECT_EQ(*(c.end() - 1), 'z');
-
-  EXPECT_EQ(*a.rbegin(), 'z');
-  EXPECT_EQ(*(b.rbegin() + 2), 'a');
-  EXPECT_EQ(*(c.rend() - 1), 'x');
-  EXPECT_TRUE(a.rbegin() + 26 == a.rend());
-
-  EXPECT_EQ(a.size(), 26u);
-  EXPECT_EQ(b.size(), 3u);
-  EXPECT_EQ(c.size(), 3u);
-  EXPECT_EQ(d.size(), 6u);
-  EXPECT_EQ(e.size(), 0u);
-  EXPECT_EQ(f.size(), 7u);
-
-  EXPECT_TRUE(!d.empty());
-  EXPECT_TRUE(d.begin() != d.end());
-  EXPECT_TRUE(d.begin() + 6 == d.end());
-
-  EXPECT_TRUE(e.empty());
-  EXPECT_TRUE(e.begin() == e.end());
-
-  char buf[4] = { '%', '%', '%', '%' };
-  EXPECT_EQ(a.copy(buf, 4), 4u);
-  EXPECT_EQ(buf[0], a[0]);
-  EXPECT_EQ(buf[1], a[1]);
-  EXPECT_EQ(buf[2], a[2]);
-  EXPECT_EQ(buf[3], a[3]);
-  EXPECT_EQ(a.copy(buf, 3, 7), 3u);
-  EXPECT_EQ(buf[0], a[7]);
-  EXPECT_EQ(buf[1], a[8]);
-  EXPECT_EQ(buf[2], a[9]);
-  EXPECT_EQ(buf[3], a[3]);
-  EXPECT_EQ(c.copy(buf, 99), 3u);
-  EXPECT_EQ(buf[0], c[0]);
-  EXPECT_EQ(buf[1], c[1]);
-  EXPECT_EQ(buf[2], c[2]);
-  EXPECT_EQ(buf[3], a[3]);
-#ifdef ABSL_HAVE_EXCEPTIONS
-  EXPECT_THROW(a.copy(buf, 1, 27), std::out_of_range);
-#else
-  ABSL_EXPECT_DEATH_IF_SUPPORTED(a.copy(buf, 1, 27), "absl::string_view::copy");
-#endif
-}
-
-// Separated from STL1() because some compilers produce an overly
-// large stack frame for the combined function.
-TEST(StringViewTest, STL2) {
-  const absl::string_view a("abcdefghijklmnopqrstuvwxyz");
-  const absl::string_view b("abc");
-  const absl::string_view c("xyz");
-  absl::string_view d("foobar");
-  const absl::string_view e;
-  const absl::string_view f(
-      "123"
-      "\0"
-      "456",
-      7);
-
-  d = absl::string_view();
-  EXPECT_EQ(d.size(), 0u);
-  EXPECT_TRUE(d.empty());
-  EXPECT_TRUE(d.data() == nullptr);
-  EXPECT_TRUE(d.begin() == d.end());
-
-  EXPECT_EQ(a.find(b), 0u);
-  EXPECT_EQ(a.find(b, 1), absl::string_view::npos);
-  EXPECT_EQ(a.find(c), 23u);
-  EXPECT_EQ(a.find(c, 9), 23u);
-  EXPECT_EQ(a.find(c, absl::string_view::npos), absl::string_view::npos);
-  EXPECT_EQ(b.find(c), absl::string_view::npos);
-  EXPECT_EQ(b.find(c, absl::string_view::npos), absl::string_view::npos);
-  EXPECT_EQ(a.find(d), 0u);
-  EXPECT_EQ(a.find(e), 0u);
-  EXPECT_EQ(a.find(d, 12), 12u);
-  EXPECT_EQ(a.find(e, 17), 17u);
-  absl::string_view g("xx not found bb");
-  EXPECT_EQ(a.find(g), absl::string_view::npos);
-  // empty string nonsense
-  EXPECT_EQ(d.find(b), absl::string_view::npos);
-  EXPECT_EQ(e.find(b), absl::string_view::npos);
-  EXPECT_EQ(d.find(b, 4), absl::string_view::npos);
-  EXPECT_EQ(e.find(b, 7), absl::string_view::npos);
-
-  size_t empty_search_pos = std::string().find(std::string());
-  EXPECT_EQ(d.find(d), empty_search_pos);
-  EXPECT_EQ(d.find(e), empty_search_pos);
-  EXPECT_EQ(e.find(d), empty_search_pos);
-  EXPECT_EQ(e.find(e), empty_search_pos);
-  EXPECT_EQ(d.find(d, 4), std::string().find(std::string(), 4));
-  EXPECT_EQ(d.find(e, 4), std::string().find(std::string(), 4));
-  EXPECT_EQ(e.find(d, 4), std::string().find(std::string(), 4));
-  EXPECT_EQ(e.find(e, 4), std::string().find(std::string(), 4));
-
-  EXPECT_EQ(a.find('a'), 0u);
-  EXPECT_EQ(a.find('c'), 2u);
-  EXPECT_EQ(a.find('z'), 25u);
-  EXPECT_EQ(a.find('$'), absl::string_view::npos);
-  EXPECT_EQ(a.find('\0'), absl::string_view::npos);
-  EXPECT_EQ(f.find('\0'), 3u);
-  EXPECT_EQ(f.find('3'), 2u);
-  EXPECT_EQ(f.find('5'), 5u);
-  EXPECT_EQ(g.find('o'), 4u);
-  EXPECT_EQ(g.find('o', 4), 4u);
-  EXPECT_EQ(g.find('o', 5), 8u);
-  EXPECT_EQ(a.find('b', 5), absl::string_view::npos);
-  // empty string nonsense
-  EXPECT_EQ(d.find('\0'), absl::string_view::npos);
-  EXPECT_EQ(e.find('\0'), absl::string_view::npos);
-  EXPECT_EQ(d.find('\0', 4), absl::string_view::npos);
-  EXPECT_EQ(e.find('\0', 7), absl::string_view::npos);
-  EXPECT_EQ(d.find('x'), absl::string_view::npos);
-  EXPECT_EQ(e.find('x'), absl::string_view::npos);
-  EXPECT_EQ(d.find('x', 4), absl::string_view::npos);
-  EXPECT_EQ(e.find('x', 7), absl::string_view::npos);
-
-  EXPECT_EQ(a.find(b.data(), 1, 0), 1u);
-  EXPECT_EQ(a.find(c.data(), 9, 0), 9u);
-  EXPECT_EQ(a.find(c.data(), absl::string_view::npos, 0),
-            absl::string_view::npos);
-  EXPECT_EQ(b.find(c.data(), absl::string_view::npos, 0),
-            absl::string_view::npos);
-  // empty string nonsense
-  EXPECT_EQ(d.find(b.data(), 4, 0), absl::string_view::npos);
-  EXPECT_EQ(e.find(b.data(), 7, 0), absl::string_view::npos);
-
-  EXPECT_EQ(a.find(b.data(), 1), absl::string_view::npos);
-  EXPECT_EQ(a.find(c.data(), 9), 23u);
-  EXPECT_EQ(a.find(c.data(), absl::string_view::npos), absl::string_view::npos);
-  EXPECT_EQ(b.find(c.data(), absl::string_view::npos), absl::string_view::npos);
-  // empty string nonsense
-  EXPECT_EQ(d.find(b.data(), 4), absl::string_view::npos);
-  EXPECT_EQ(e.find(b.data(), 7), absl::string_view::npos);
-
-  EXPECT_EQ(a.rfind(b), 0u);
-  EXPECT_EQ(a.rfind(b, 1), 0u);
-  EXPECT_EQ(a.rfind(c), 23u);
-  EXPECT_EQ(a.rfind(c, 22), absl::string_view::npos);
-  EXPECT_EQ(a.rfind(c, 1), absl::string_view::npos);
-  EXPECT_EQ(a.rfind(c, 0), absl::string_view::npos);
-  EXPECT_EQ(b.rfind(c), absl::string_view::npos);
-  EXPECT_EQ(b.rfind(c, 0), absl::string_view::npos);
-  EXPECT_EQ(a.rfind(d), std::string(a).rfind(std::string()));
-  EXPECT_EQ(a.rfind(e), std::string(a).rfind(std::string()));
-  EXPECT_EQ(a.rfind(d, 12), 12u);
-  EXPECT_EQ(a.rfind(e, 17), 17u);
-  EXPECT_EQ(a.rfind(g), absl::string_view::npos);
-  EXPECT_EQ(d.rfind(b), absl::string_view::npos);
-  EXPECT_EQ(e.rfind(b), absl::string_view::npos);
-  EXPECT_EQ(d.rfind(b, 4), absl::string_view::npos);
-  EXPECT_EQ(e.rfind(b, 7), absl::string_view::npos);
-  // empty string nonsense
-  EXPECT_EQ(d.rfind(d, 4), std::string().rfind(std::string()));
-  EXPECT_EQ(e.rfind(d, 7), std::string().rfind(std::string()));
-  EXPECT_EQ(d.rfind(e, 4), std::string().rfind(std::string()));
-  EXPECT_EQ(e.rfind(e, 7), std::string().rfind(std::string()));
-  EXPECT_EQ(d.rfind(d), std::string().rfind(std::string()));
-  EXPECT_EQ(e.rfind(d), std::string().rfind(std::string()));
-  EXPECT_EQ(d.rfind(e), std::string().rfind(std::string()));
-  EXPECT_EQ(e.rfind(e), std::string().rfind(std::string()));
-
-  EXPECT_EQ(g.rfind('o'), 8u);
-  EXPECT_EQ(g.rfind('q'), absl::string_view::npos);
-  EXPECT_EQ(g.rfind('o', 8), 8u);
-  EXPECT_EQ(g.rfind('o', 7), 4u);
-  EXPECT_EQ(g.rfind('o', 3), absl::string_view::npos);
-  EXPECT_EQ(f.rfind('\0'), 3u);
-  EXPECT_EQ(f.rfind('\0', 12), 3u);
-  EXPECT_EQ(f.rfind('3'), 2u);
-  EXPECT_EQ(f.rfind('5'), 5u);
-  // empty string nonsense
-  EXPECT_EQ(d.rfind('o'), absl::string_view::npos);
-  EXPECT_EQ(e.rfind('o'), absl::string_view::npos);
-  EXPECT_EQ(d.rfind('o', 4), absl::string_view::npos);
-  EXPECT_EQ(e.rfind('o', 7), absl::string_view::npos);
-
-  EXPECT_EQ(a.rfind(b.data(), 1, 0), 1u);
-  EXPECT_EQ(a.rfind(c.data(), 22, 0), 22u);
-  EXPECT_EQ(a.rfind(c.data(), 1, 0), 1u);
-  EXPECT_EQ(a.rfind(c.data(), 0, 0), 0u);
-  EXPECT_EQ(b.rfind(c.data(), 0, 0), 0u);
-  EXPECT_EQ(d.rfind(b.data(), 4, 0), 0u);
-  EXPECT_EQ(e.rfind(b.data(), 7, 0), 0u);
-}
-
-// Continued from STL2
-TEST(StringViewTest, STL2FindFirst) {
-  const absl::string_view a("abcdefghijklmnopqrstuvwxyz");
-  const absl::string_view b("abc");
-  const absl::string_view c("xyz");
-  absl::string_view d("foobar");
-  const absl::string_view e;
-  const absl::string_view f(
-      "123"
-      "\0"
-      "456",
-      7);
-  absl::string_view g("xx not found bb");
-
-  d = absl::string_view();
-  EXPECT_EQ(a.find_first_of(b), 0u);
-  EXPECT_EQ(a.find_first_of(b, 0), 0u);
-  EXPECT_EQ(a.find_first_of(b, 1), 1u);
-  EXPECT_EQ(a.find_first_of(b, 2), 2u);
-  EXPECT_EQ(a.find_first_of(b, 3), absl::string_view::npos);
-  EXPECT_EQ(a.find_first_of(c), 23u);
-  EXPECT_EQ(a.find_first_of(c, 23), 23u);
-  EXPECT_EQ(a.find_first_of(c, 24), 24u);
-  EXPECT_EQ(a.find_first_of(c, 25), 25u);
-  EXPECT_EQ(a.find_first_of(c, 26), absl::string_view::npos);
-  EXPECT_EQ(g.find_first_of(b), 13u);
-  EXPECT_EQ(g.find_first_of(c), 0u);
-  EXPECT_EQ(a.find_first_of(f), absl::string_view::npos);
-  EXPECT_EQ(f.find_first_of(a), absl::string_view::npos);
-  // empty string nonsense
-  EXPECT_EQ(a.find_first_of(d), absl::string_view::npos);
-  EXPECT_EQ(a.find_first_of(e), absl::string_view::npos);
-  EXPECT_EQ(d.find_first_of(b), absl::string_view::npos);
-  EXPECT_EQ(e.find_first_of(b), absl::string_view::npos);
-  EXPECT_EQ(d.find_first_of(d), absl::string_view::npos);
-  EXPECT_EQ(e.find_first_of(d), absl::string_view::npos);
-  EXPECT_EQ(d.find_first_of(e), absl::string_view::npos);
-  EXPECT_EQ(e.find_first_of(e), absl::string_view::npos);
-
-  EXPECT_EQ(a.find_first_not_of(b), 3u);
-  EXPECT_EQ(a.find_first_not_of(c), 0u);
-  EXPECT_EQ(b.find_first_not_of(a), absl::string_view::npos);
-  EXPECT_EQ(c.find_first_not_of(a), absl::string_view::npos);
-  EXPECT_EQ(f.find_first_not_of(a), 0u);
-  EXPECT_EQ(a.find_first_not_of(f), 0u);
-  EXPECT_EQ(a.find_first_not_of(d), 0u);
-  EXPECT_EQ(a.find_first_not_of(e), 0u);
-  // empty string nonsense
-  EXPECT_EQ(a.find_first_not_of(d), 0u);
-  EXPECT_EQ(a.find_first_not_of(e), 0u);
-  EXPECT_EQ(a.find_first_not_of(d, 1), 1u);
-  EXPECT_EQ(a.find_first_not_of(e, 1), 1u);
-  EXPECT_EQ(a.find_first_not_of(d, a.size() - 1), a.size() - 1);
-  EXPECT_EQ(a.find_first_not_of(e, a.size() - 1), a.size() - 1);
-  EXPECT_EQ(a.find_first_not_of(d, a.size()), absl::string_view::npos);
-  EXPECT_EQ(a.find_first_not_of(e, a.size()), absl::string_view::npos);
-  EXPECT_EQ(a.find_first_not_of(d, absl::string_view::npos),
-            absl::string_view::npos);
-  EXPECT_EQ(a.find_first_not_of(e, absl::string_view::npos),
-            absl::string_view::npos);
-  EXPECT_EQ(d.find_first_not_of(a), absl::string_view::npos);
-  EXPECT_EQ(e.find_first_not_of(a), absl::string_view::npos);
-  EXPECT_EQ(d.find_first_not_of(d), absl::string_view::npos);
-  EXPECT_EQ(e.find_first_not_of(d), absl::string_view::npos);
-  EXPECT_EQ(d.find_first_not_of(e), absl::string_view::npos);
-  EXPECT_EQ(e.find_first_not_of(e), absl::string_view::npos);
-
-  absl::string_view h("====");
-  EXPECT_EQ(h.find_first_not_of('='), absl::string_view::npos);
-  EXPECT_EQ(h.find_first_not_of('=', 3), absl::string_view::npos);
-  EXPECT_EQ(h.find_first_not_of('\0'), 0u);
-  EXPECT_EQ(g.find_first_not_of('x'), 2u);
-  EXPECT_EQ(f.find_first_not_of('\0'), 0u);
-  EXPECT_EQ(f.find_first_not_of('\0', 3), 4u);
-  EXPECT_EQ(f.find_first_not_of('\0', 2), 2u);
-  // empty string nonsense
-  EXPECT_EQ(d.find_first_not_of('x'), absl::string_view::npos);
-  EXPECT_EQ(e.find_first_not_of('x'), absl::string_view::npos);
-  EXPECT_EQ(d.find_first_not_of('\0'), absl::string_view::npos);
-  EXPECT_EQ(e.find_first_not_of('\0'), absl::string_view::npos);
-}
-
-// Continued from STL2
-TEST(StringViewTest, STL2FindLast) {
-  const absl::string_view a("abcdefghijklmnopqrstuvwxyz");
-  const absl::string_view b("abc");
-  const absl::string_view c("xyz");
-  absl::string_view d("foobar");
-  const absl::string_view e;
-  const absl::string_view f(
-      "123"
-      "\0"
-      "456",
-      7);
-  absl::string_view g("xx not found bb");
-  absl::string_view h("====");
-  absl::string_view i("56");
-
-  d = absl::string_view();
-  EXPECT_EQ(h.find_last_of(a), absl::string_view::npos);
-  EXPECT_EQ(g.find_last_of(a), g.size() - 1);
-  EXPECT_EQ(a.find_last_of(b), 2u);
-  EXPECT_EQ(a.find_last_of(c), a.size() - 1);
-  EXPECT_EQ(f.find_last_of(i), 6u);
-  EXPECT_EQ(a.find_last_of('a'), 0u);
-  EXPECT_EQ(a.find_last_of('b'), 1u);
-  EXPECT_EQ(a.find_last_of('z'), 25u);
-  EXPECT_EQ(a.find_last_of('a', 5), 0u);
-  EXPECT_EQ(a.find_last_of('b', 5), 1u);
-  EXPECT_EQ(a.find_last_of('b', 0), absl::string_view::npos);
-  EXPECT_EQ(a.find_last_of('z', 25), 25u);
-  EXPECT_EQ(a.find_last_of('z', 24), absl::string_view::npos);
-  EXPECT_EQ(f.find_last_of(i, 5), 5u);
-  EXPECT_EQ(f.find_last_of(i, 6), 6u);
-  EXPECT_EQ(f.find_last_of(a, 4), absl::string_view::npos);
-  // empty string nonsense
-  EXPECT_EQ(f.find_last_of(d), absl::string_view::npos);
-  EXPECT_EQ(f.find_last_of(e), absl::string_view::npos);
-  EXPECT_EQ(f.find_last_of(d, 4), absl::string_view::npos);
-  EXPECT_EQ(f.find_last_of(e, 4), absl::string_view::npos);
-  EXPECT_EQ(d.find_last_of(d), absl::string_view::npos);
-  EXPECT_EQ(d.find_last_of(e), absl::string_view::npos);
-  EXPECT_EQ(e.find_last_of(d), absl::string_view::npos);
-  EXPECT_EQ(e.find_last_of(e), absl::string_view::npos);
-  EXPECT_EQ(d.find_last_of(f), absl::string_view::npos);
-  EXPECT_EQ(e.find_last_of(f), absl::string_view::npos);
-  EXPECT_EQ(d.find_last_of(d, 4), absl::string_view::npos);
-  EXPECT_EQ(d.find_last_of(e, 4), absl::string_view::npos);
-  EXPECT_EQ(e.find_last_of(d, 4), absl::string_view::npos);
-  EXPECT_EQ(e.find_last_of(e, 4), absl::string_view::npos);
-  EXPECT_EQ(d.find_last_of(f, 4), absl::string_view::npos);
-  EXPECT_EQ(e.find_last_of(f, 4), absl::string_view::npos);
-
-  EXPECT_EQ(a.find_last_not_of(b), a.size() - 1);
-  EXPECT_EQ(a.find_last_not_of(c), 22u);
-  EXPECT_EQ(b.find_last_not_of(a), absl::string_view::npos);
-  EXPECT_EQ(b.find_last_not_of(b), absl::string_view::npos);
-  EXPECT_EQ(f.find_last_not_of(i), 4u);
-  EXPECT_EQ(a.find_last_not_of(c, 24), 22u);
-  EXPECT_EQ(a.find_last_not_of(b, 3), 3u);
-  EXPECT_EQ(a.find_last_not_of(b, 2), absl::string_view::npos);
-  // empty string nonsense
-  EXPECT_EQ(f.find_last_not_of(d), f.size() - 1);
-  EXPECT_EQ(f.find_last_not_of(e), f.size() - 1);
-  EXPECT_EQ(f.find_last_not_of(d, 4), 4u);
-  EXPECT_EQ(f.find_last_not_of(e, 4), 4u);
-  EXPECT_EQ(d.find_last_not_of(d), absl::string_view::npos);
-  EXPECT_EQ(d.find_last_not_of(e), absl::string_view::npos);
-  EXPECT_EQ(e.find_last_not_of(d), absl::string_view::npos);
-  EXPECT_EQ(e.find_last_not_of(e), absl::string_view::npos);
-  EXPECT_EQ(d.find_last_not_of(f), absl::string_view::npos);
-  EXPECT_EQ(e.find_last_not_of(f), absl::string_view::npos);
-  EXPECT_EQ(d.find_last_not_of(d, 4), absl::string_view::npos);
-  EXPECT_EQ(d.find_last_not_of(e, 4), absl::string_view::npos);
-  EXPECT_EQ(e.find_last_not_of(d, 4), absl::string_view::npos);
-  EXPECT_EQ(e.find_last_not_of(e, 4), absl::string_view::npos);
-  EXPECT_EQ(d.find_last_not_of(f, 4), absl::string_view::npos);
-  EXPECT_EQ(e.find_last_not_of(f, 4), absl::string_view::npos);
-
-  EXPECT_EQ(h.find_last_not_of('x'), h.size() - 1);
-  EXPECT_EQ(h.find_last_not_of('='), absl::string_view::npos);
-  EXPECT_EQ(b.find_last_not_of('c'), 1u);
-  EXPECT_EQ(h.find_last_not_of('x', 2), 2u);
-  EXPECT_EQ(h.find_last_not_of('=', 2), absl::string_view::npos);
-  EXPECT_EQ(b.find_last_not_of('b', 1), 0u);
-  // empty string nonsense
-  EXPECT_EQ(d.find_last_not_of('x'), absl::string_view::npos);
-  EXPECT_EQ(e.find_last_not_of('x'), absl::string_view::npos);
-  EXPECT_EQ(d.find_last_not_of('\0'), absl::string_view::npos);
-  EXPECT_EQ(e.find_last_not_of('\0'), absl::string_view::npos);
-}
-
-// Continued from STL2
-TEST(StringViewTest, STL2Substr) {
-  const absl::string_view a("abcdefghijklmnopqrstuvwxyz");
-  const absl::string_view b("abc");
-  const absl::string_view c("xyz");
-  absl::string_view d("foobar");
-  const absl::string_view e;
-
-  d = absl::string_view();
-  EXPECT_EQ(a.substr(0, 3), b);
-  EXPECT_EQ(a.substr(23), c);
-  EXPECT_EQ(a.substr(23, 3), c);
-  EXPECT_EQ(a.substr(23, 99), c);
-  EXPECT_EQ(a.substr(0), a);
-  EXPECT_EQ(a.substr(), a);
-  EXPECT_EQ(a.substr(3, 2), "de");
-  // empty string nonsense
-  EXPECT_EQ(d.substr(0, 99), e);
-  // use of npos
-  EXPECT_EQ(a.substr(0, absl::string_view::npos), a);
-  EXPECT_EQ(a.substr(23, absl::string_view::npos), c);
-  // throw exception
-#ifdef ABSL_HAVE_EXCEPTIONS
-  EXPECT_THROW((void)a.substr(99, 2), std::out_of_range);
-#else
-  ABSL_EXPECT_DEATH_IF_SUPPORTED((void)a.substr(99, 2),
-                                 "absl::string_view::substr");
-#endif
-}
-
 TEST(StringViewTest, TruncSubstr) {
   const absl::string_view hi("hi");
   EXPECT_EQ("", absl::ClippedSubstr(hi, 0, 0));
@@ -743,304 +46,6 @@
   EXPECT_EQ("", absl::ClippedSubstr(hi, 3, 2));  // truncation
 }
 
-TEST(StringViewTest, UTF8) {
-  std::string utf8 = "\u00E1";
-  std::string utf8_twice = utf8 + " " + utf8;
-  size_t utf8_len = strlen(utf8.data());
-  EXPECT_EQ(utf8_len, absl::string_view(utf8_twice).find_first_of(" "));
-  EXPECT_EQ(utf8_len, absl::string_view(utf8_twice).find_first_of(" \t"));
-}
-
-TEST(StringViewTest, FindConformance) {
-  struct {
-    std::string haystack;
-    std::string needle;
-  } specs[] = {
-    {"", ""},
-    {"", "a"},
-    {"a", ""},
-    {"a", "a"},
-    {"a", "b"},
-    {"aa", ""},
-    {"aa", "a"},
-    {"aa", "b"},
-    {"ab", "a"},
-    {"ab", "b"},
-    {"abcd", ""},
-    {"abcd", "a"},
-    {"abcd", "d"},
-    {"abcd", "ab"},
-    {"abcd", "bc"},
-    {"abcd", "cd"},
-    {"abcd", "abcd"},
-  };
-  for (const auto& s : specs) {
-    SCOPED_TRACE(s.haystack);
-    SCOPED_TRACE(s.needle);
-    std::string st = s.haystack;
-    absl::string_view sp = s.haystack;
-    for (size_t i = 0; i <= sp.size(); ++i) {
-      size_t pos = (i == sp.size()) ? absl::string_view::npos : i;
-      SCOPED_TRACE(pos);
-      EXPECT_EQ(sp.find(s.needle, pos),
-                st.find(s.needle, pos));
-      EXPECT_EQ(sp.rfind(s.needle, pos),
-                st.rfind(s.needle, pos));
-      EXPECT_EQ(sp.find_first_of(s.needle, pos),
-                st.find_first_of(s.needle, pos));
-      EXPECT_EQ(sp.find_first_not_of(s.needle, pos),
-                st.find_first_not_of(s.needle, pos));
-      EXPECT_EQ(sp.find_last_of(s.needle, pos),
-                st.find_last_of(s.needle, pos));
-      EXPECT_EQ(sp.find_last_not_of(s.needle, pos),
-                st.find_last_not_of(s.needle, pos));
-    }
-  }
-}
-
-TEST(StringViewTest, Remove) {
-  absl::string_view a("foobar");
-  std::string s1("123");
-  s1 += '\0';
-  s1 += "456";
-  absl::string_view e;
-  std::string s2;
-
-  // remove_prefix
-  absl::string_view c(a);
-  c.remove_prefix(3);
-  EXPECT_EQ(c, "bar");
-  c = a;
-  c.remove_prefix(0);
-  EXPECT_EQ(c, a);
-  c.remove_prefix(c.size());
-  EXPECT_EQ(c, e);
-
-  // remove_suffix
-  c = a;
-  c.remove_suffix(3);
-  EXPECT_EQ(c, "foo");
-  c = a;
-  c.remove_suffix(0);
-  EXPECT_EQ(c, a);
-  c.remove_suffix(c.size());
-  EXPECT_EQ(c, e);
-}
-
-TEST(StringViewTest, Set) {
-  absl::string_view a("foobar");
-  absl::string_view empty;
-  absl::string_view b;
-
-  // set
-  b = absl::string_view("foobar", 6);
-  EXPECT_EQ(b, a);
-  b = absl::string_view("foobar", 0);
-  EXPECT_EQ(b, empty);
-  b = absl::string_view("foobar", 7);
-  EXPECT_NE(b, a);
-
-  b = absl::string_view("foobar");
-  EXPECT_EQ(b, a);
-}
-
-TEST(StringViewTest, FrontBack) {
-  static const char arr[] = "abcd";
-  const absl::string_view csp(arr, 4);
-  EXPECT_EQ(&arr[0], &csp.front());
-  EXPECT_EQ(&arr[3], &csp.back());
-}
-
-TEST(StringViewTest, FrontBackSingleChar) {
-  static const char c = 'a';
-  const absl::string_view csp(&c, 1);
-  EXPECT_EQ(&c, &csp.front());
-  EXPECT_EQ(&c, &csp.back());
-}
-
-TEST(StringViewTest, FrontBackEmpty) {
-#ifndef ABSL_USES_STD_STRING_VIEW
-#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
-  // Abseil's string_view implementation has debug assertions that check that
-  // front() and back() are not called on an empty string_view.
-  absl::string_view sv;
-  ABSL_EXPECT_DEATH_IF_SUPPORTED(sv.front(), "");
-  ABSL_EXPECT_DEATH_IF_SUPPORTED(sv.back(), "");
-#endif
-#endif
-}
-
-// `std::string_view::string_view(const char*)` calls
-// `std::char_traits<char>::length(const char*)` to get the string length. In
-// libc++, it doesn't allow `nullptr` in the constexpr context, with the error
-// "read of dereferenced null pointer is not allowed in a constant expression".
-// At run time, the behavior of `std::char_traits::length()` on `nullptr` is
-// undefined by the standard and usually results in crash with libc++.
-// GCC also started rejected this in libstdc++ starting in GCC9.
-// In MSVC, creating a constexpr string_view from nullptr also triggers an
-// "unevaluable pointer value" error. This compiler implementation conforms
-// to the standard, but `absl::string_view` implements a different
-// behavior for historical reasons. We work around tests that construct
-// `string_view` from `nullptr` when using libc++.
-#if !defined(ABSL_USES_STD_STRING_VIEW) ||                    \
-    (!(defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE >= 9) && \
-     !defined(_LIBCPP_VERSION) && !defined(_MSC_VER))
-#define ABSL_HAVE_STRING_VIEW_FROM_NULLPTR 1
-#endif
-
-TEST(StringViewTest, NULLInput) {
-  absl::string_view s;
-  EXPECT_EQ(s.data(), nullptr);
-  EXPECT_EQ(s.size(), 0u);
-
-#ifdef ABSL_HAVE_STRING_VIEW_FROM_NULLPTR
-  // The `str` parameter is annotated nonnull, but we want to test the defensive
-  // null check. Use a variable instead of passing nullptr directly to avoid a
-  // `-Wnonnull` warning.
-  char* null_str = nullptr;
-  s = absl::string_view(null_str);
-  EXPECT_EQ(s.data(), nullptr);
-  EXPECT_EQ(s.size(), 0u);
-
-  // .ToString() on a absl::string_view with nullptr should produce the empty
-  // string.
-  EXPECT_EQ("", std::string(s));
-#endif  // ABSL_HAVE_STRING_VIEW_FROM_NULLPTR
-}
-
-TEST(StringViewTest, Comparisons2) {
-  // The `compare` member has 6 overloads (v: string_view, s: const char*):
-  //  (1) compare(v)
-  //  (2) compare(pos1, count1, v)
-  //  (3) compare(pos1, count1, v, pos2, count2)
-  //  (4) compare(s)
-  //  (5) compare(pos1, count1, s)
-  //  (6) compare(pos1, count1, s, count2)
-
-  absl::string_view abc("abcdefghijklmnopqrstuvwxyz");
-
-  // check comparison operations on strings longer than 4 bytes.
-  EXPECT_EQ(abc, absl::string_view("abcdefghijklmnopqrstuvwxyz"));
-  EXPECT_EQ(abc.compare(absl::string_view("abcdefghijklmnopqrstuvwxyz")), 0);
-
-  EXPECT_LT(abc, absl::string_view("abcdefghijklmnopqrstuvwxzz"));
-  EXPECT_LT(abc.compare(absl::string_view("abcdefghijklmnopqrstuvwxzz")), 0);
-
-  EXPECT_GT(abc, absl::string_view("abcdefghijklmnopqrstuvwxyy"));
-  EXPECT_GT(abc.compare(absl::string_view("abcdefghijklmnopqrstuvwxyy")), 0);
-
-  // The "substr" variants of `compare`.
-  absl::string_view digits("0123456789");
-  auto npos = absl::string_view::npos;
-
-  // Taking string_view
-  EXPECT_EQ(digits.compare(3, npos, absl::string_view("3456789")), 0);  // 2
-  EXPECT_EQ(digits.compare(3, 4, absl::string_view("3456")), 0);        // 2
-  EXPECT_EQ(digits.compare(10, 0, absl::string_view()), 0);             // 2
-  EXPECT_EQ(digits.compare(3, 4, absl::string_view("0123456789"), 3, 4),
-            0);  // 3
-  EXPECT_LT(digits.compare(3, 4, absl::string_view("0123456789"), 3, 5),
-            0);  // 3
-  EXPECT_LT(digits.compare(0, npos, absl::string_view("0123456789"), 3, 5),
-            0);  // 3
-  // Taking const char*
-  EXPECT_EQ(digits.compare(3, 4, "3456"), 0);                 // 5
-  EXPECT_EQ(digits.compare(3, npos, "3456789"), 0);           // 5
-  EXPECT_EQ(digits.compare(10, 0, ""), 0);                    // 5
-  EXPECT_EQ(digits.compare(3, 4, "0123456789", 3, 4), 0);     // 6
-  EXPECT_LT(digits.compare(3, 4, "0123456789", 3, 5), 0);     // 6
-  EXPECT_LT(digits.compare(0, npos, "0123456789", 3, 5), 0);  // 6
-}
-
-TEST(StringViewTest, At) {
-  absl::string_view abc = "abc";
-  EXPECT_EQ(abc.at(0), 'a');
-  EXPECT_EQ(abc.at(1), 'b');
-  EXPECT_EQ(abc.at(2), 'c');
-#ifdef ABSL_HAVE_EXCEPTIONS
-  EXPECT_THROW((void)abc.at(3), std::out_of_range);
-#else
-  ABSL_EXPECT_DEATH_IF_SUPPORTED((void)abc.at(3), "absl::string_view::at");
-#endif
-}
-
-#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
-TEST(StringViewTest, StartsWith) {
-  const absl::string_view a("foobar");
-  const absl::string_view b("123\0abc", 7);
-  const absl::string_view e;
-  EXPECT_TRUE(a.starts_with(a));
-  EXPECT_TRUE(a.starts_with("foo"));
-  EXPECT_TRUE(a.starts_with('f'));
-  EXPECT_TRUE(a.starts_with(e));
-  EXPECT_TRUE(b.starts_with(b));
-  EXPECT_TRUE(b.starts_with('1'));
-  EXPECT_TRUE(b.starts_with(e));
-  EXPECT_TRUE(e.starts_with(""));
-  EXPECT_FALSE(a.starts_with(b));
-  EXPECT_FALSE(b.starts_with(a));
-  EXPECT_FALSE(e.starts_with(a));
-  EXPECT_FALSE(a.starts_with('r'));
-  EXPECT_FALSE(a.starts_with('\0'));
-  EXPECT_FALSE(e.starts_with('r'));
-  EXPECT_FALSE(e.starts_with('\0'));
-
-  // Test that constexpr compiles.
-  constexpr absl::string_view kFooBar("foobar");
-  constexpr absl::string_view kFoo("foo");
-  constexpr absl::string_view kBar("bar");
-  constexpr bool k1 = kFooBar.starts_with(kFoo);
-  EXPECT_TRUE(k1);
-  constexpr bool k2 = kFooBar.starts_with(kBar);
-  EXPECT_FALSE(k2);
-  constexpr bool k3 = kFooBar.starts_with('f');
-  EXPECT_TRUE(k3);
-  constexpr bool k4 = kFooBar.starts_with("fo");
-  EXPECT_TRUE(k4);
-}
-
-TEST(StringViewTest, EndsWith) {
-  const absl::string_view a("foobar");
-  const absl::string_view b("123\0abc", 7);
-  const absl::string_view e;
-  EXPECT_TRUE(a.ends_with(a));
-  EXPECT_TRUE(a.ends_with('r'));
-  EXPECT_TRUE(a.ends_with("bar"));
-  EXPECT_TRUE(a.ends_with(e));
-  EXPECT_TRUE(b.ends_with(b));
-  EXPECT_TRUE(b.ends_with('c'));
-  EXPECT_TRUE(b.ends_with(e));
-  EXPECT_TRUE(e.ends_with(""));
-  EXPECT_FALSE(a.ends_with(b));
-  EXPECT_FALSE(b.ends_with(a));
-  EXPECT_FALSE(e.ends_with(a));
-  EXPECT_FALSE(a.ends_with('f'));
-  EXPECT_FALSE(a.ends_with('\0'));
-  EXPECT_FALSE(e.ends_with('r'));
-  EXPECT_FALSE(e.ends_with('\0'));
-
-  // Test that constexpr compiles.
-  constexpr absl::string_view kFooBar("foobar");
-  constexpr absl::string_view kFoo("foo");
-  constexpr absl::string_view kBar("bar");
-  constexpr bool k1 = kFooBar.ends_with(kFoo);
-  EXPECT_FALSE(k1);
-  constexpr bool k2 = kFooBar.ends_with(kBar);
-  EXPECT_TRUE(k2);
-  constexpr bool k3 = kFooBar.ends_with('r');
-  EXPECT_TRUE(k3);
-  constexpr bool k4 = kFooBar.ends_with("ar");
-  EXPECT_TRUE(k4);
-}
-#endif  // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
-
-struct MyCharAlloc : std::allocator<char> {};
-
-TEST(StringViewTest, ExplicitConversionOperator) {
-  absl::string_view sp = "hi";
-  EXPECT_EQ(sp, std::string(sp));
-}
-
 TEST(StringViewTest, NullSafeStringView) {
   {
     absl::string_view s = absl::NullSafeStringView(nullptr);
@@ -1078,321 +83,4 @@
   }
 }
 
-TEST(StringViewTest, ConstexprCompiles) {
-  constexpr absl::string_view sp;
-  // With `-Wnonnull` turned on, there is no way to test the defensive null
-  // check in the `string_view(const char*)` constructor in a constexpr context,
-  // as the argument needs to be constexpr. The compiler will therefore always
-  // know at compile time that the argument is nullptr and complain because the
-  // parameter is annotated nonnull. We hence turn the warning off for this
-  // test.
-#if defined(__clang__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wnonnull"
-#endif
-#ifdef ABSL_HAVE_STRING_VIEW_FROM_NULLPTR
-  constexpr absl::string_view cstr(nullptr);
-#endif
-#if defined(__clang__)
-#pragma clang diagnostic pop
-#endif
-  constexpr absl::string_view cstr_len("cstr", 4);
-
-#if defined(ABSL_USES_STD_STRING_VIEW)
-  // In libstdc++ (as of 7.2), `std::string_view::string_view(const char*)`
-  // calls `std::char_traits<char>::length(const char*)` to get the string
-  // length, but it is not marked constexpr yet. See GCC bug:
-  // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78156
-  // Also, there is a LWG issue that adds constexpr to length() which was just
-  // resolved 2017-06-02. See
-  // http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2232
-  // TODO(zhangxy): Update the condition when libstdc++ adopts the constexpr
-  // length().
-#if !defined(__GLIBCXX__)
-#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR 1
-#endif  // !__GLIBCXX__
-
-#else  // ABSL_USES_STD_STRING_VIEW
-
-// This duplicates the check for __builtin_strlen in the header.
-#if ABSL_HAVE_BUILTIN(__builtin_strlen) || \
-    (defined(__GNUC__) && !defined(__clang__))
-#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR 1
-#elif defined(__GNUC__)  // GCC or clang
-#error GCC/clang should have constexpr string_view.
-#endif
-
-// MSVC 2017+ should be able to construct a constexpr string_view from a cstr.
-#if defined(_MSC_VER)
-#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR 1
-#endif
-
-#endif  // ABSL_USES_STD_STRING_VIEW
-
-#ifdef ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR
-  constexpr absl::string_view cstr_strlen("foo");
-  EXPECT_EQ(cstr_strlen.length(), 3u);
-  constexpr absl::string_view cstr_strlen2 = "bar";
-  EXPECT_EQ(cstr_strlen2, "bar");
-
-#if ABSL_HAVE_BUILTIN(__builtin_memcmp) || \
-    (defined(__GNUC__) && !defined(__clang__))
-#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_COMPARISON 1
-#endif
-#ifdef ABSL_HAVE_CONSTEXPR_STRING_VIEW_COMPARISON
-  constexpr absl::string_view foo = "foo";
-  constexpr absl::string_view bar = "bar";
-  constexpr bool foo_eq_bar = foo == bar;
-  constexpr bool foo_ne_bar = foo != bar;
-  constexpr bool foo_lt_bar = foo < bar;
-  constexpr bool foo_le_bar = foo <= bar;
-  constexpr bool foo_gt_bar = foo > bar;
-  constexpr bool foo_ge_bar = foo >= bar;
-  constexpr int foo_compare_bar = foo.compare(bar);
-  EXPECT_FALSE(foo_eq_bar);
-  EXPECT_TRUE(foo_ne_bar);
-  EXPECT_FALSE(foo_lt_bar);
-  EXPECT_FALSE(foo_le_bar);
-  EXPECT_TRUE(foo_gt_bar);
-  EXPECT_TRUE(foo_ge_bar);
-  EXPECT_GT(foo_compare_bar, 0);
-#endif
-#endif
-
-  constexpr absl::string_view::iterator const_begin_empty = sp.begin();
-  constexpr absl::string_view::iterator const_end_empty = sp.end();
-  EXPECT_EQ(const_begin_empty, const_end_empty);
-
-#ifdef ABSL_HAVE_STRING_VIEW_FROM_NULLPTR
-  constexpr absl::string_view::iterator const_begin_nullptr = cstr.begin();
-  constexpr absl::string_view::iterator const_end_nullptr = cstr.end();
-  EXPECT_EQ(const_begin_nullptr, const_end_nullptr);
-#endif  // ABSL_HAVE_STRING_VIEW_FROM_NULLPTR
-
-  constexpr absl::string_view::iterator const_begin = cstr_len.begin();
-  constexpr absl::string_view::iterator const_end = cstr_len.end();
-  constexpr absl::string_view::size_type const_size = cstr_len.size();
-  constexpr absl::string_view::size_type const_length = cstr_len.length();
-  static_assert(const_begin + const_size == const_end,
-                "pointer arithmetic check");
-  static_assert(const_begin + const_length == const_end,
-                "pointer arithmetic check");
-#ifndef _MSC_VER
-  // MSVC has bugs doing constexpr pointer arithmetic.
-  // https://developercommunity.visualstudio.com/content/problem/482192/bad-pointer-arithmetic-in-constepxr-2019-rc1-svc1.html
-  EXPECT_EQ(const_begin + const_size, const_end);
-  EXPECT_EQ(const_begin + const_length, const_end);
-#endif
-
-  constexpr bool isempty = sp.empty();
-  EXPECT_TRUE(isempty);
-
-  constexpr const char c = cstr_len[2];
-  EXPECT_EQ(c, 't');
-
-  constexpr const char cfront = cstr_len.front();
-  constexpr const char cback = cstr_len.back();
-  EXPECT_EQ(cfront, 'c');
-  EXPECT_EQ(cback, 'r');
-
-  constexpr const char* np = sp.data();
-  constexpr const char* cstr_ptr = cstr_len.data();
-  EXPECT_EQ(np, nullptr);
-  EXPECT_NE(cstr_ptr, nullptr);
-
-  constexpr size_t sp_npos = sp.npos;
-  EXPECT_EQ(sp_npos, static_cast<size_t>(-1));
-}
-
-constexpr char ConstexprMethodsHelper() {
-#if defined(__cplusplus) && __cplusplus >= 201402L
-  absl::string_view str("123", 3);
-  str.remove_prefix(1);
-  str.remove_suffix(1);
-  absl::string_view bar;
-  str.swap(bar);
-  return bar.front();
-#else
-  return '2';
-#endif
-}
-
-TEST(StringViewTest, ConstexprMethods) {
-  // remove_prefix, remove_suffix, swap
-  static_assert(ConstexprMethodsHelper() == '2', "");
-
-  // substr
-  constexpr absl::string_view foobar("foobar", 6);
-  constexpr absl::string_view foo = foobar.substr(0, 3);
-  constexpr absl::string_view bar = foobar.substr(3);
-  EXPECT_EQ(foo, "foo");
-  EXPECT_EQ(bar, "bar");
-}
-
-TEST(StringViewTest, Noexcept) {
-  EXPECT_TRUE((std::is_nothrow_constructible<absl::string_view,
-                                             const std::string&>::value));
-  EXPECT_TRUE((std::is_nothrow_constructible<absl::string_view,
-                                             const std::string&>::value));
-  EXPECT_TRUE(std::is_nothrow_constructible<absl::string_view>::value);
-  constexpr absl::string_view sp;
-  EXPECT_TRUE(noexcept(sp.begin()));
-  EXPECT_TRUE(noexcept(sp.end()));
-  EXPECT_TRUE(noexcept(sp.cbegin()));
-  EXPECT_TRUE(noexcept(sp.cend()));
-  EXPECT_TRUE(noexcept(sp.rbegin()));
-  EXPECT_TRUE(noexcept(sp.rend()));
-  EXPECT_TRUE(noexcept(sp.crbegin()));
-  EXPECT_TRUE(noexcept(sp.crend()));
-  EXPECT_TRUE(noexcept(sp.size()));
-  EXPECT_TRUE(noexcept(sp.length()));
-  EXPECT_TRUE(noexcept(sp.empty()));
-  EXPECT_TRUE(noexcept(sp.data()));
-  EXPECT_TRUE(noexcept(sp.compare(sp)));
-  EXPECT_TRUE(noexcept(sp.find(sp)));
-  EXPECT_TRUE(noexcept(sp.find('f')));
-  EXPECT_TRUE(noexcept(sp.rfind(sp)));
-  EXPECT_TRUE(noexcept(sp.rfind('f')));
-  EXPECT_TRUE(noexcept(sp.find_first_of(sp)));
-  EXPECT_TRUE(noexcept(sp.find_first_of('f')));
-  EXPECT_TRUE(noexcept(sp.find_last_of(sp)));
-  EXPECT_TRUE(noexcept(sp.find_last_of('f')));
-  EXPECT_TRUE(noexcept(sp.find_first_not_of(sp)));
-  EXPECT_TRUE(noexcept(sp.find_first_not_of('f')));
-  EXPECT_TRUE(noexcept(sp.find_last_not_of(sp)));
-  EXPECT_TRUE(noexcept(sp.find_last_not_of('f')));
-}
-
-TEST(StringViewTest, BoundsCheck) {
-#ifndef ABSL_USES_STD_STRING_VIEW
-#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
-  // Abseil's string_view implementation has bounds-checking in debug mode.
-  absl::string_view h = "hello";
-  ABSL_EXPECT_DEATH_IF_SUPPORTED(h[5], "");
-  ABSL_EXPECT_DEATH_IF_SUPPORTED(h[static_cast<size_t>(-1)], "");
-#endif
-#endif
-}
-
-TEST(ComparisonOpsTest, StringCompareNotAmbiguous) {
-  EXPECT_EQ("hello", std::string("hello"));
-  EXPECT_LT("hello", std::string("world"));
-}
-
-TEST(ComparisonOpsTest, HeterogeneousStringViewEquals) {
-  EXPECT_EQ(absl::string_view("hello"), std::string("hello"));
-  EXPECT_EQ("hello", absl::string_view("hello"));
-}
-
-TEST(FindOneCharTest, EdgeCases) {
-  absl::string_view a("xxyyyxx");
-
-  // Set a = "xyyyx".
-  a.remove_prefix(1);
-  a.remove_suffix(1);
-
-  EXPECT_EQ(0u, a.find('x'));
-  EXPECT_EQ(0u, a.find('x', 0));
-  EXPECT_EQ(4u, a.find('x', 1));
-  EXPECT_EQ(4u, a.find('x', 4));
-  EXPECT_EQ(absl::string_view::npos, a.find('x', 5));
-
-  EXPECT_EQ(4u, a.rfind('x'));
-  EXPECT_EQ(4u, a.rfind('x', 5));
-  EXPECT_EQ(4u, a.rfind('x', 4));
-  EXPECT_EQ(0u, a.rfind('x', 3));
-  EXPECT_EQ(0u, a.rfind('x', 0));
-
-  // Set a = "yyy".
-  a.remove_prefix(1);
-  a.remove_suffix(1);
-
-  EXPECT_EQ(absl::string_view::npos, a.find('x'));
-  EXPECT_EQ(absl::string_view::npos, a.rfind('x'));
-}
-
-#ifndef ABSL_HAVE_THREAD_SANITIZER  // Allocates too much memory for tsan.
-TEST(HugeStringView, TwoPointTwoGB) {
-  if (sizeof(size_t) <= 4)
-    return;
-  // Try a huge string piece.
-  const size_t size = size_t{2200} * 1000 * 1000;
-  std::string s(size, 'a');
-  absl::string_view sp(s);
-  EXPECT_EQ(size, sp.length());
-  sp.remove_prefix(1);
-  EXPECT_EQ(size - 1, sp.length());
-  sp.remove_suffix(2);
-  EXPECT_EQ(size - 1 - 2, sp.length());
-}
-#endif  // ABSL_HAVE_THREAD_SANITIZER
-
-#if !defined(NDEBUG) && !defined(ABSL_USES_STD_STRING_VIEW)
-TEST(NonNegativeLenTest, NonNegativeLen) {
-  ABSL_EXPECT_DEATH_IF_SUPPORTED(
-      absl::string_view("xyz", static_cast<size_t>(-1)), "len <= kMaxSize");
-}
-
-TEST(LenExceedsMaxSizeTest, LenExceedsMaxSize) {
-  auto max_size = absl::string_view().max_size();
-
-  // This should construct ok (although the view itself is obviously invalid).
-  absl::string_view ok_view("", max_size);
-
-  // Adding one to the max should trigger an assertion.
-  ABSL_EXPECT_DEATH_IF_SUPPORTED(absl::string_view("", max_size + 1),
-                                 "len <= kMaxSize");
-}
-#endif  // !defined(NDEBUG) && !defined(ABSL_USES_STD_STRING_VIEW)
-
-class StringViewStreamTest : public ::testing::Test {
- public:
-  // Set negative 'width' for right justification.
-  template <typename T>
-  std::string Pad(const T& s, int width, char fill = 0) {
-    std::ostringstream oss;
-    if (fill != 0) {
-      oss << std::setfill(fill);
-    }
-    if (width < 0) {
-      width = -width;
-      oss << std::right;
-    }
-    oss << std::setw(width) << s;
-    return oss.str();
-  }
-};
-
-TEST_F(StringViewStreamTest, Padding) {
-  std::string s("hello");
-  absl::string_view sp(s);
-  for (int w = -64; w < 64; ++w) {
-    SCOPED_TRACE(w);
-    EXPECT_EQ(Pad(s, w), Pad(sp, w));
-  }
-  for (int w = -64; w < 64; ++w) {
-    SCOPED_TRACE(w);
-    EXPECT_EQ(Pad(s, w, '#'), Pad(sp, w, '#'));
-  }
-}
-
-TEST_F(StringViewStreamTest, ResetsWidth) {
-  // Width should reset after one formatted write.
-  // If we weren't resetting width after formatting the string_view,
-  // we'd have width=5 carrying over to the printing of the "]",
-  // creating "[###hi####]".
-  std::string s = "hi";
-  absl::string_view sp = s;
-  {
-    std::ostringstream oss;
-    oss << "[" << std::setfill('#') << std::setw(5) << s << "]";
-    ASSERT_EQ("[###hi]", oss.str());
-  }
-  {
-    std::ostringstream oss;
-    oss << "[" << std::setfill('#') << std::setw(5) << sp << "]";
-    EXPECT_EQ("[###hi]", oss.str());
-  }
-}
-
 }  // namespace
diff --git a/absl/strings/substitute.cc b/absl/strings/substitute.cc
index 3c2ca5d..f5d600b 100644
--- a/absl/strings/substitute.cc
+++ b/absl/strings/substitute.cc
@@ -26,7 +26,7 @@
 #include "absl/base/nullability.h"
 #include "absl/strings/ascii.h"
 #include "absl/strings/escaping.h"
-#include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/internal/append_and_overwrite.h"
 #include "absl/strings/numbers.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
@@ -85,29 +85,29 @@
   if (size == 0) return;
 
   // Build the string.
-  size_t original_size = output->size();
-  ABSL_INTERNAL_CHECK(
-      size <= std::numeric_limits<size_t>::max() - original_size,
-      "size_t overflow");
-  strings_internal::STLStringResizeUninitializedAmortized(output,
-                                                          original_size + size);
-  char* target = &(*output)[original_size];
-  for (size_t i = 0; i < format.size(); i++) {
-    if (format[i] == '$') {
-      if (absl::ascii_isdigit(static_cast<unsigned char>(format[i + 1]))) {
-        const absl::string_view src = args_array[format[i + 1] - '0'];
-        target = std::copy(src.begin(), src.end(), target);
-        ++i;  // Skip next char.
-      } else if (format[i + 1] == '$') {
-        *target++ = '$';
-        ++i;  // Skip next char.
-      }
-    } else {
-      *target++ = format[i];
-    }
-  }
-
-  assert(target == output->data() + output->size());
+  ABSL_INTERNAL_CHECK(size <= output->max_size() - output->size(),
+                      "Exceeds std::string::max_size()");
+  strings_internal::StringAppendAndOverwrite(
+      *output, size, [format, args_array](char* const buf, size_t buf_size) {
+        char* target = buf;
+        for (size_t i = 0; i < format.size(); i++) {
+          if (format[i] == '$') {
+            if (absl::ascii_isdigit(
+                    static_cast<unsigned char>(format[i + 1]))) {
+              const absl::string_view src = args_array[format[i + 1] - '0'];
+              target = std::copy(src.begin(), src.end(), target);
+              ++i;  // Skip next char.
+            } else if (format[i + 1] == '$') {
+              *target++ = '$';
+              ++i;  // Skip next char.
+            }
+          } else {
+            *target++ = format[i];
+          }
+        }
+        assert(target == buf + buf_size);
+        return buf_size;
+      });
 }
 
 Arg::Arg(const void* absl_nullable value) {
diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel
index 920928e..b3b55e7 100644
--- a/absl/synchronization/BUILD.bazel
+++ b/absl/synchronization/BUILD.bazel
@@ -14,6 +14,9 @@
 # limitations under the License.
 #
 
+load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
@@ -69,9 +72,7 @@
         "//absl/base:core_headers",
         "//absl/base:raw_logging_internal",
         "//absl/time",
-    ] + select({
-        "//conditions:default": [],
-    }),
+    ],
 )
 
 cc_test(
@@ -145,6 +146,7 @@
         "//absl/base:tracing_internal",
         "//absl/debugging:stacktrace",
         "//absl/debugging:symbolize",
+        "//absl/meta:type_traits",
         "//absl/time",
     ] + select({
         "//conditions:default": [],
@@ -360,6 +362,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     tags = [
         "no_test_wasm",
+        "noubsan",  # TODO(b/417700722):  timeouts under UBSAN.
     ],
     deps = [
         ":per_thread_sem_test_common",
diff --git a/absl/synchronization/CMakeLists.txt b/absl/synchronization/CMakeLists.txt
index 9d4844d..9c4a0b1 100644
--- a/absl/synchronization/CMakeLists.txt
+++ b/absl/synchronization/CMakeLists.txt
@@ -109,11 +109,11 @@
     absl::core_headers
     absl::dynamic_annotations
     absl::malloc_internal
+    absl::meta
     absl::nullability
     absl::raw_logging_internal
     absl::stacktrace
     absl::symbolize
-    absl::tracing_internal
     absl::time
     absl::tracing_internal
     Threads::Threads
diff --git a/absl/synchronization/barrier.cc b/absl/synchronization/barrier.cc
index 0dfd795..f5dad22 100644
--- a/absl/synchronization/barrier.cc
+++ b/absl/synchronization/barrier.cc
@@ -26,7 +26,7 @@
 }
 
 bool Barrier::Block() {
-  MutexLock l(&this->lock_);
+  MutexLock l(this->lock_);
 
   this->num_to_block_--;
   if (this->num_to_block_ < 0) {
diff --git a/absl/synchronization/barrier_test.cc b/absl/synchronization/barrier_test.cc
index bfc6cb1..2aed272 100644
--- a/absl/synchronization/barrier_test.cc
+++ b/absl/synchronization/barrier_test.cc
@@ -37,7 +37,7 @@
     }
 
     // Increment the counter.
-    absl::MutexLock lock(&mutex);
+    absl::MutexLock lock(mutex);
     ++counter;
   };
 
@@ -57,7 +57,7 @@
   // The counter should still be zero since no thread should have
   // been able to pass the barrier yet.
   {
-    absl::MutexLock lock(&mutex);
+    absl::MutexLock lock(mutex);
     EXPECT_EQ(counter, 0);
   }
 
@@ -70,6 +70,6 @@
   }
 
   // All threads should now have incremented the counter.
-  absl::MutexLock lock(&mutex);
+  absl::MutexLock lock(mutex);
   EXPECT_EQ(counter, kNumThreads);
 }
diff --git a/absl/synchronization/blocking_counter.cc b/absl/synchronization/blocking_counter.cc
index a530baf..9468469 100644
--- a/absl/synchronization/blocking_counter.cc
+++ b/absl/synchronization/blocking_counter.cc
@@ -42,7 +42,7 @@
                  "BlockingCounter::DecrementCount() called too many times");
   if (count == 0) {
     base_internal::TraceSignal(this, TraceObjectKind());
-    MutexLock l(&lock_);
+    MutexLock l(lock_);
     done_ = true;
     return true;
   }
@@ -52,7 +52,7 @@
 void BlockingCounter::Wait() {
   base_internal::TraceWait(this, TraceObjectKind());
   {
-    MutexLock l(&this->lock_);
+    MutexLock l(this->lock_);
 
     // only one thread may call Wait(). To support more than one thread,
     // implement a counter num_to_exit, like in the Barrier class.
diff --git a/absl/synchronization/internal/create_thread_identity.cc b/absl/synchronization/internal/create_thread_identity.cc
index 93cd376..0b0f920 100644
--- a/absl/synchronization/internal/create_thread_identity.cc
+++ b/absl/synchronization/internal/create_thread_identity.cc
@@ -35,7 +35,7 @@
 // ThreadIdentity storage is persistent, we maintain a free-list of previously
 // released ThreadIdentity objects.
 ABSL_CONST_INIT static base_internal::SpinLock freelist_lock(
-    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+    base_internal::SCHEDULE_KERNEL_ONLY);
 ABSL_CONST_INIT static base_internal::ThreadIdentity* thread_identity_freelist;
 
 // A per-thread destructor for reclaiming associated ThreadIdentity objects.
@@ -60,7 +60,7 @@
   //     association state in this case.
   base_internal::ClearCurrentThreadIdentity();
   {
-    base_internal::SpinLockHolder l(&freelist_lock);
+    base_internal::SpinLockHolder l(freelist_lock);
     identity->next = thread_identity_freelist;
     thread_identity_freelist = identity;
   }
@@ -108,7 +108,7 @@
 
   {
     // Re-use a previously released object if possible.
-    base_internal::SpinLockHolder l(&freelist_lock);
+    base_internal::SpinLockHolder l(freelist_lock);
     if (thread_identity_freelist) {
       identity = thread_identity_freelist;  // Take list-head.
       thread_identity_freelist = thread_identity_freelist->next;
diff --git a/absl/synchronization/internal/graphcycles.cc b/absl/synchronization/internal/graphcycles.cc
index 129067c..f58fb0a 100644
--- a/absl/synchronization/internal/graphcycles.cc
+++ b/absl/synchronization/internal/graphcycles.cc
@@ -33,15 +33,15 @@
 #include "absl/base/internal/low_level_alloc.h"
 #ifndef ABSL_LOW_LEVEL_ALLOC_MISSING
 
-#include "absl/synchronization/internal/graphcycles.h"
-
 #include <algorithm>
 #include <array>
 #include <cinttypes>
 #include <limits>
+
 #include "absl/base/internal/hide_ptr.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/internal/spinlock.h"
+#include "absl/synchronization/internal/graphcycles.h"
 
 // Do not use STL.   This module does not use standard memory allocation.
 
@@ -54,15 +54,14 @@
 // Avoid LowLevelAlloc's default arena since it calls malloc hooks in
 // which people are doing things like acquiring Mutexes.
 ABSL_CONST_INIT static absl::base_internal::SpinLock arena_mu(
-    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+    base_internal::SCHEDULE_KERNEL_ONLY);
 ABSL_CONST_INIT static base_internal::LowLevelAlloc::Arena* arena;
 
 static void InitArenaIfNecessary() {
-  arena_mu.Lock();
+  base_internal::SpinLockHolder l(arena_mu);
   if (arena == nullptr) {
     arena = base_internal::LowLevelAlloc::NewArena(0);
   }
-  arena_mu.Unlock();
 }
 
 // Number of inlined elements in Vec.  Hash table implementation
@@ -89,7 +88,7 @@
   T* end() { return ptr_ + size_; }
   const T& operator[](uint32_t i) const { return ptr_[i]; }
   T& operator[](uint32_t i) { return ptr_[i]; }
-  const T& back() const { return ptr_[size_-1]; }
+  const T& back() const { return ptr_[size_ - 1]; }
   void pop_back() { size_--; }
 
   void push_back(const T& v) {
@@ -178,7 +177,7 @@
     }
     table_[i] = v;
     // Double when 75% full.
-    if (occupied_ >= table_.size() - table_.size()/4) Grow();
+    if (occupied_ >= table_.size() - table_.size() / 4) Grow();
     return true;
   }
 
@@ -193,7 +192,7 @@
   // Example:
   //    HASH_FOR_EACH(elem, node->out) { ... }
 #define HASH_FOR_EACH(elem, eset) \
-  for (int32_t elem, _cursor = 0; (eset).Next(&_cursor, &elem); )
+  for (int32_t elem, _cursor = 0; (eset).Next(&_cursor, &elem);)
   bool Next(int32_t* cursor, int32_t* elem) {
     while (static_cast<uint32_t>(*cursor) < table_.size()) {
       int32_t v = table_[static_cast<uint32_t>(*cursor)];
@@ -209,7 +208,7 @@
  private:
   enum : int32_t { kEmpty = -1, kDel = -2 };
   Vec<int32_t> table_;
-  uint32_t occupied_;     // Count of non-empty slots (includes deleted slots)
+  uint32_t occupied_;  // Count of non-empty slots (includes deleted slots)
 
   static uint32_t Hash(int32_t a) { return static_cast<uint32_t>(a) * 41; }
 
@@ -270,25 +269,23 @@
   return g;
 }
 
-inline int32_t NodeIndex(GraphId id) {
-  return static_cast<int32_t>(id.handle);
-}
+inline int32_t NodeIndex(GraphId id) { return static_cast<int32_t>(id.handle); }
 
 inline uint32_t NodeVersion(GraphId id) {
   return static_cast<uint32_t>(id.handle >> 32);
 }
 
 struct Node {
-  int32_t rank;               // rank number assigned by Pearce-Kelly algorithm
-  uint32_t version;           // Current version number
-  int32_t next_hash;          // Next entry in hash table
-  bool visited;               // Temporary marker used by depth-first-search
-  uintptr_t masked_ptr;       // User-supplied pointer
-  NodeSet in;                 // List of immediate predecessor nodes in graph
-  NodeSet out;                // List of immediate successor nodes in graph
-  int priority;               // Priority of recorded stack trace.
-  int nstack;                 // Depth of recorded stack trace.
-  void* stack[40];            // stack[0,nstack-1] holds stack trace for node.
+  int32_t rank;          // rank number assigned by Pearce-Kelly algorithm
+  uint32_t version;      // Current version number
+  int32_t next_hash;     // Next entry in hash table
+  bool visited;          // Temporary marker used by depth-first-search
+  uintptr_t masked_ptr;  // User-supplied pointer
+  NodeSet in;            // List of immediate predecessor nodes in graph
+  NodeSet out;           // List of immediate successor nodes in graph
+  int priority;          // Priority of recorded stack trace.
+  int nstack;            // Depth of recorded stack trace.
+  void* stack[40];       // stack[0,nstack-1] holds stack trace for node.
 };
 
 // Hash table for pointer to node index lookups.
@@ -318,7 +315,7 @@
     // Advance through linked list while keeping track of the
     // predecessor slot that points to the current entry.
     auto masked = base_internal::HidePtr(ptr);
-    for (int32_t* slot = &table_[Hash(ptr)]; *slot != -1; ) {
+    for (int32_t* slot = &table_[Hash(ptr)]; *slot != -1;) {
       int32_t index = *slot;
       Node* n = (*nodes_)[static_cast<uint32_t>(index)];
       if (n->masked_ptr == masked) {
@@ -381,7 +378,9 @@
 
 GraphCycles::~GraphCycles() {
   for (auto* node : rep_->nodes_) {
-    if (node == nullptr) { continue; }
+    if (node == nullptr) {
+      continue;
+    }
     node->Node::~Node();
     base_internal::LowLevelAlloc::Free(node);
   }
@@ -474,8 +473,7 @@
 
 void* GraphCycles::Ptr(GraphId id) {
   Node* n = FindNode(rep_, id);
-  return n == nullptr ? nullptr
-                      : base_internal::UnhidePtr<void>(n->masked_ptr);
+  return n == nullptr ? nullptr : base_internal::UnhidePtr<void>(n->masked_ptr);
 }
 
 bool GraphCycles::HasNode(GraphId node) {
@@ -502,8 +500,8 @@
 static void BackwardDFS(GraphCycles::Rep* r, int32_t n, int32_t lower_bound);
 static void Reorder(GraphCycles::Rep* r);
 static void Sort(const Vec<Node*>&, Vec<int32_t>* delta);
-static void MoveToList(
-    GraphCycles::Rep* r, Vec<int32_t>* src, Vec<int32_t>* dst);
+static void MoveToList(GraphCycles::Rep* r, Vec<int32_t>* src,
+                       Vec<int32_t>* dst);
 
 bool GraphCycles::InsertEdge(GraphId idx, GraphId idy) {
   Rep* r = rep_;
@@ -605,9 +603,8 @@
 
   // Produce sorted list of all ranks that will be reassigned.
   r->merged_.resize(r->deltab_.size() + r->deltaf_.size());
-  std::merge(r->deltab_.begin(), r->deltab_.end(),
-             r->deltaf_.begin(), r->deltaf_.end(),
-             r->merged_.begin());
+  std::merge(r->deltab_.begin(), r->deltab_.end(), r->deltaf_.begin(),
+             r->deltaf_.end(), r->merged_.begin());
 
   // Assign the ranks in order to the collected list.
   for (uint32_t i = 0; i < r->list_.size(); i++) {
@@ -628,8 +625,8 @@
   std::sort(delta->begin(), delta->end(), cmp);
 }
 
-static void MoveToList(
-    GraphCycles::Rep* r, Vec<int32_t>* src, Vec<int32_t>* dst) {
+static void MoveToList(GraphCycles::Rep* r, Vec<int32_t>* src,
+                       Vec<int32_t>* dst) {
   for (auto& v : *src) {
     int32_t w = v;
     // Replace v entry with its rank
diff --git a/absl/synchronization/internal/kernel_timeout.h b/absl/synchronization/internal/kernel_timeout.h
index 06404a7..c24fa86 100644
--- a/absl/synchronization/internal/kernel_timeout.h
+++ b/absl/synchronization/internal/kernel_timeout.h
@@ -129,8 +129,8 @@
   std::chrono::nanoseconds ToChronoDuration() const;
 
   // Returns true if steady (aka monotonic) clocks are supported by the system.
-  // This method exists because go/btm requires synchronized clocks, and
-  // thus requires we use the system (aka walltime) clock.
+  // This currently returns true on all platforms, but we have encountered
+  // platforms that once lacked steady clock support.
   static constexpr bool SupportsSteadyClock() { return true; }
 
  private:
diff --git a/absl/synchronization/internal/kernel_timeout_test.cc b/absl/synchronization/internal/kernel_timeout_test.cc
index 33962f8..811246c 100644
--- a/absl/synchronization/internal/kernel_timeout_test.cc
+++ b/absl/synchronization/internal/kernel_timeout_test.cc
@@ -24,12 +24,22 @@
 #include "absl/time/time.h"
 #include "gtest/gtest.h"
 
-// Test go/btm support by randomizing the value of clock_gettime() for
-// CLOCK_MONOTONIC. This works by overriding a weak symbol in glibc.
+#if 0  // All supported platforms currently have steady clocks.
+#define ABSL_INTERNAL_KERNEL_TIMEOUT_SUPPORTS_STEADY_CLOCK 0
+#else
+#define ABSL_INTERNAL_KERNEL_TIMEOUT_SUPPORTS_STEADY_CLOCK 1
+#endif
+
+static_assert(
+    absl::synchronization_internal::KernelTimeout::SupportsSteadyClock() ==
+    static_cast<bool>(ABSL_INTERNAL_KERNEL_TIMEOUT_SUPPORTS_STEADY_CLOCK));
+
+// Randomizing the value of clock_gettime() for CLOCK_MONOTONIC.
+// This works by overriding a weak symbol in glibc.
 // We should be resistant to this randomization when !SupportsSteadyClock().
-#if defined(__GOOGLE_GRTE_VERSION__) &&      \
-    !defined(ABSL_HAVE_ADDRESS_SANITIZER) && \
-    !defined(ABSL_HAVE_MEMORY_SANITIZER) &&  \
+#if !ABSL_INTERNAL_KERNEL_TIMEOUT_SUPPORTS_STEADY_CLOCK && \
+    !defined(ABSL_HAVE_ADDRESS_SANITIZER) &&               \
+    !defined(ABSL_HAVE_MEMORY_SANITIZER) &&                \
     !defined(ABSL_HAVE_THREAD_SANITIZER)
 extern "C" int __clock_gettime(clockid_t c, struct timespec* ts);
 
diff --git a/absl/synchronization/internal/thread_pool.h b/absl/synchronization/internal/thread_pool.h
index 5eb0bb6..f87adf6 100644
--- a/absl/synchronization/internal/thread_pool.h
+++ b/absl/synchronization/internal/thread_pool.h
@@ -46,7 +46,7 @@
 
   ~ThreadPool() {
     {
-      absl::MutexLock l(&mu_);
+      absl::MutexLock l(mu_);
       for (size_t i = 0; i < threads_.size(); i++) {
         queue_.push(nullptr);  // Shutdown signal.
       }
@@ -59,7 +59,7 @@
   // Schedule a function to be run on a ThreadPool thread immediately.
   void Schedule(absl::AnyInvocable<void()> func) {
     assert(func != nullptr);
-    absl::MutexLock l(&mu_);
+    absl::MutexLock l(mu_);
     queue_.push(std::move(func));
   }
 
@@ -72,7 +72,7 @@
     while (true) {
       absl::AnyInvocable<void()> func;
       {
-        absl::MutexLock l(&mu_);
+        absl::MutexLock l(mu_);
         mu_.Await(absl::Condition(this, &ThreadPool::WorkAvailable));
         func = std::move(queue_.front());
         queue_.pop();
diff --git a/absl/synchronization/internal/waiter_test.cc b/absl/synchronization/internal/waiter_test.cc
index 6e37415..80a6985 100644
--- a/absl/synchronization/internal/waiter_test.cc
+++ b/absl/synchronization/internal/waiter_test.cc
@@ -129,7 +129,10 @@
       start + absl::Seconds(10))));
   absl::Duration waited = absl::Now() - start;
   EXPECT_GE(waited, WithTolerance(absl::Milliseconds(500)));
-  EXPECT_LT(waited, absl::Seconds(2));
+  #ifndef _MSC_VER
+    // Skip on MSVC due to flakiness.
+    EXPECT_LT(waited, absl::Seconds(2));
+  #endif
 }
 
 TYPED_TEST_P(WaiterTest, WaitDurationReached) {
@@ -139,7 +142,10 @@
       absl::synchronization_internal::KernelTimeout(absl::Milliseconds(500))));
   absl::Duration waited = absl::Now() - start;
   EXPECT_GE(waited, WithTolerance(absl::Milliseconds(500)));
-  EXPECT_LT(waited, absl::Seconds(1));
+  #ifndef _MSC_VER
+    // Skip on MSVC due to flakiness.
+    EXPECT_LT(waited, absl::Seconds(1));
+  #endif
 }
 
 TYPED_TEST_P(WaiterTest, WaitTimeReached) {
@@ -149,7 +155,10 @@
       start + absl::Milliseconds(500))));
   absl::Duration waited = absl::Now() - start;
   EXPECT_GE(waited, WithTolerance(absl::Milliseconds(500)));
-  EXPECT_LT(waited, absl::Seconds(1));
+  #ifndef _MSC_VER
+    // Skip on MSVC due to flakiness.
+    EXPECT_LT(waited, absl::Seconds(1));
+  #endif
 }
 
 REGISTER_TYPED_TEST_SUITE_P(WaiterTest,
diff --git a/absl/synchronization/lifetime_test.cc b/absl/synchronization/lifetime_test.cc
index 4c4cff6..1c11431 100644
--- a/absl/synchronization/lifetime_test.cc
+++ b/absl/synchronization/lifetime_test.cc
@@ -45,7 +45,7 @@
   CHECK(!*state) << "*state not initialized";
 
   {
-    absl::MutexLock lock(mutex);
+    absl::MutexLock lock(*mutex);
 
     notification->Notify();
     CHECK(notification->HasBeenNotified()) << "invalid Notification";
@@ -64,7 +64,7 @@
   notification->WaitForNotification();
   CHECK(notification->HasBeenNotified()) << "invalid Notification";
   {
-    absl::MutexLock lock(mutex);
+    absl::MutexLock lock(*mutex);
     *state = true;
     condvar->Signal();
   }
@@ -148,12 +148,12 @@
 // before the constructors of either grab_lock or check_still_locked are run.)
 extern absl::Mutex const_init_sanity_mutex;
 OnConstruction grab_lock([]() ABSL_NO_THREAD_SAFETY_ANALYSIS {
-  const_init_sanity_mutex.Lock();
+  const_init_sanity_mutex.lock();
 });
 ABSL_CONST_INIT absl::Mutex const_init_sanity_mutex(absl::kConstInit);
 OnConstruction check_still_locked([]() ABSL_NO_THREAD_SAFETY_ANALYSIS {
   const_init_sanity_mutex.AssertHeld();
-  const_init_sanity_mutex.Unlock();
+  const_init_sanity_mutex.unlock();
 });
 #endif  // defined(__clang__) || !(defined(_MSC_VER) && _MSC_VER > 1900)
 
diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc
index 5091b8f..9b80f1f 100644
--- a/absl/synchronization/mutex.cc
+++ b/absl/synchronization/mutex.cc
@@ -226,7 +226,7 @@
 
 // Data for doing deadlock detection.
 ABSL_CONST_INIT static absl::base_internal::SpinLock deadlock_graph_mu(
-    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+    base_internal::SCHEDULE_KERNEL_ONLY);
 
 // Graph used to detect deadlocks.
 ABSL_CONST_INIT static GraphCycles* deadlock_graph
@@ -292,7 +292,7 @@
 };
 
 ABSL_CONST_INIT static absl::base_internal::SpinLock synch_event_mu(
-    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+    base_internal::SCHEDULE_KERNEL_ONLY);
 
 // Hash table size; should be prime > 2.
 // Can't be too small, as it's used for deadlock detection information.
@@ -330,7 +330,7 @@
                                     const char* name, intptr_t bits,
                                     intptr_t lockbit) {
   uint32_t h = reinterpret_cast<uintptr_t>(addr) % kNSynchEvent;
-  synch_event_mu.Lock();
+  synch_event_mu.lock();
   // When a Mutex/CondVar is destroyed, we don't remove the associated
   // SynchEvent to keep destructors empty in release builds for performance
   // reasons. If the current call is the first to set bits (kMuEvent/kCVEvent),
@@ -392,16 +392,16 @@
   } else {
     e->refcount++;  // for return value
   }
-  synch_event_mu.Unlock();
+  synch_event_mu.unlock();
   return e;
 }
 
 // Decrement the reference count of *e, or do nothing if e==null.
 static void UnrefSynchEvent(SynchEvent* e) {
   if (e != nullptr) {
-    synch_event_mu.Lock();
+    synch_event_mu.lock();
     bool del = (--(e->refcount) == 0);
-    synch_event_mu.Unlock();
+    synch_event_mu.unlock();
     if (del) {
       base_internal::LowLevelAlloc::Free(e);
     }
@@ -414,7 +414,7 @@
 static SynchEvent* GetSynchEvent(const void* addr) {
   uint32_t h = reinterpret_cast<uintptr_t>(addr) % kNSynchEvent;
   SynchEvent* e;
-  synch_event_mu.Lock();
+  synch_event_mu.lock();
   for (e = synch_event[h];
        e != nullptr && e->masked_addr != base_internal::HidePtr(addr);
        e = e->next) {
@@ -422,7 +422,7 @@
   if (e != nullptr) {
     e->refcount++;
   }
-  synch_event_mu.Unlock();
+  synch_event_mu.unlock();
   return e;
 }
 
@@ -509,10 +509,10 @@
   const Condition* cond;   // The condition that this thread is waiting for.
                            // In Mutex, this field is set to zero if a timeout
                            // expires.
-  KernelTimeout timeout;  // timeout expiry---absolute time
-                          // In Mutex, this field is set to zero if a timeout
-                          // expires.
-  Mutex* const cvmu;      // used for transfer from cond var to mutex
+  KernelTimeout timeout;   // timeout expiry---absolute time
+                           // In Mutex, this field is set to zero if a timeout
+                           // expires.
+  Mutex* const cvmu;       // used for transfer from cond var to mutex
   PerThreadSynch* const thread;  // thread that is waiting
 
   // If not null, thread should be enqueued on the CondVar whose state
@@ -745,7 +745,8 @@
 Mutex::~Mutex() { Dtor(); }
 #endif
 
-#if !defined(NDEBUG) || defined(ABSL_HAVE_THREAD_SANITIZER)
+#if !defined(NDEBUG) || defined(ABSL_HAVE_THREAD_SANITIZER) || \
+    defined(ABSL_BUILD_DLL)
 void Mutex::Dtor() {
   if (kDebugMode) {
     this->ForgetDeadlockInfo();
@@ -1223,9 +1224,8 @@
 }
 
 static GraphId GetGraphId(Mutex* mu) ABSL_LOCKS_EXCLUDED(deadlock_graph_mu) {
-  deadlock_graph_mu.Lock();
+  base_internal::SpinLockHolder l(deadlock_graph_mu);
   GraphId id = GetGraphIdLocked(mu);
-  deadlock_graph_mu.Unlock();
   return id;
 }
 
@@ -1327,8 +1327,7 @@
   char sym[kSymLen];
   int len = 0;
   for (int i = 0; i != n; i++) {
-    if (len >= maxlen)
-      return buf;
+    if (len >= maxlen) return buf;
     size_t count = static_cast<size_t>(maxlen - len);
     if (symbolize) {
       if (!absl::Symbolize(pcs[i], sym, kSymLen)) {
@@ -1387,7 +1386,7 @@
 
   SynchLocksHeld* all_locks = Synch_GetAllLocks();
 
-  absl::base_internal::SpinLockHolder lock(&deadlock_graph_mu);
+  absl::base_internal::SpinLockHolder lock(deadlock_graph_mu);
   const GraphId mu_id = GetGraphIdLocked(mu);
 
   if (all_locks->n == 0) {
@@ -1457,7 +1456,7 @@
       }
       if (synch_deadlock_detection.load(std::memory_order_acquire) ==
           OnDeadlockCycle::kAbort) {
-        deadlock_graph_mu.Unlock();  // avoid deadlock in fatal sighandler
+        deadlock_graph_mu.unlock();  // avoid deadlock in fatal sighandler
         ABSL_RAW_LOG(FATAL, "dying due to potential deadlock");
         return mu_id;
       }
@@ -1482,11 +1481,11 @@
 void Mutex::ForgetDeadlockInfo() {
   if (kDebugMode && synch_deadlock_detection.load(std::memory_order_acquire) !=
                         OnDeadlockCycle::kIgnore) {
-    deadlock_graph_mu.Lock();
+    deadlock_graph_mu.lock();
     if (deadlock_graph != nullptr) {
       deadlock_graph->RemoveNode(this);
     }
-    deadlock_graph_mu.Unlock();
+    deadlock_graph_mu.unlock();
   }
 }
 
@@ -1528,7 +1527,7 @@
   return false;
 }
 
-void Mutex::Lock() {
+void Mutex::lock() {
   ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
   GraphId id = DebugOnlyDeadlockCheck(this);
   intptr_t v = mu_.load(std::memory_order_relaxed);
@@ -1546,7 +1545,7 @@
   ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
 }
 
-void Mutex::ReaderLock() {
+void Mutex::lock_shared() {
   ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_read_lock);
   GraphId id = DebugOnlyDeadlockCheck(this);
   intptr_t v = mu_.load(std::memory_order_relaxed);
@@ -1606,7 +1605,7 @@
   return res;
 }
 
-bool Mutex::TryLock() {
+bool Mutex::try_lock() {
   ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
   intptr_t v = mu_.load(std::memory_order_relaxed);
   // Try fast acquire.
@@ -1644,7 +1643,7 @@
   return false;
 }
 
-bool Mutex::ReaderTryLock() {
+bool Mutex::try_lock_shared() {
   ABSL_TSAN_MUTEX_PRE_LOCK(this,
                            __tsan_mutex_read_lock | __tsan_mutex_try_lock);
   intptr_t v = mu_.load(std::memory_order_relaxed);
@@ -1706,7 +1705,7 @@
   return false;
 }
 
-void Mutex::Unlock() {
+void Mutex::unlock() {
   ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0);
   DebugOnlyLockLeave(this);
   intptr_t v = mu_.load(std::memory_order_relaxed);
@@ -1776,7 +1775,7 @@
   return (v & kMuMultipleWaitersMask) == 0;
 }
 
-void Mutex::ReaderUnlock() {
+void Mutex::unlock_shared() {
   ABSL_TSAN_MUTEX_PRE_UNLOCK(this, __tsan_mutex_read_lock);
   DebugOnlyLockLeave(this);
   intptr_t v = mu_.load(std::memory_order_relaxed);
@@ -2286,7 +2285,7 @@
         // set up to walk the list
         PerThreadSynch* w_walk;   // current waiter during list walk
         PerThreadSynch* pw_walk;  // previous waiter during list walk
-        if (old_h != nullptr) {  // we've searched up to old_h before
+        if (old_h != nullptr) {   // we've searched up to old_h before
           pw_walk = old_h;
           w_walk = old_h->next;
         } else {  // no prior search, start at beginning
@@ -2762,7 +2761,7 @@
 void ReleasableMutexLock::Release() {
   ABSL_RAW_CHECK(this->mu_ != nullptr,
                  "ReleasableMutexLock::Release may only be called once");
-  this->mu_->Unlock();
+  this->mu_->unlock();
   this->mu_ = nullptr;
 }
 
diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h
index 78b1c7a..39ea0d0 100644
--- a/absl/synchronization/mutex.h
+++ b/absl/synchronization/mutex.h
@@ -61,18 +61,16 @@
 #include <atomic>
 #include <cstdint>
 #include <cstring>
-#include <iterator>
-#include <string>
 
 #include "absl/base/attributes.h"
+#include "absl/base/config.h"
 #include "absl/base/const_init.h"
-#include "absl/base/internal/identity.h"
-#include "absl/base/internal/low_level_alloc.h"
 #include "absl/base/internal/thread_identity.h"
 #include "absl/base/internal/tsan_mutex_interface.h"
+#include "absl/base/macros.h"
 #include "absl/base/nullability.h"
-#include "absl/base/port.h"
 #include "absl/base/thread_annotations.h"
+#include "absl/meta/type_traits.h"
 #include "absl/synchronization/internal/kernel_timeout.h"
 #include "absl/synchronization/internal/per_thread_sem.h"
 #include "absl/time/time.h"
@@ -92,10 +90,10 @@
 // invariants. Proper usage of mutexes prevents concurrent access by different
 // threads to the same resource.
 //
-// A `Mutex` has two basic operations: `Mutex::Lock()` and `Mutex::Unlock()`.
-// The `Lock()` operation *acquires* a `Mutex` (in a state known as an
-// *exclusive* -- or *write* -- lock), and the `Unlock()` operation *releases* a
-// Mutex. During the span of time between the Lock() and Unlock() operations,
+// A `Mutex` has two basic operations: `Mutex::lock()` and `Mutex::unlock()`.
+// The `lock()` operation *acquires* a `Mutex` (in a state known as an
+// *exclusive* -- or *write* -- lock), and the `unlock()` operation *releases* a
+// Mutex. During the span of time between the lock() and unlock() operations,
 // a mutex is said to be *held*. By design, all mutexes support exclusive/write
 // locks, as this is the most common way to use a mutex.
 //
@@ -106,23 +104,23 @@
 //
 // The `Mutex` state machine for basic lock/unlock operations is quite simple:
 //
-// |                | Lock()                 | Unlock() |
+// |                | lock()                 | unlock() |
 // |----------------+------------------------+----------|
 // | Free           | Exclusive              | invalid  |
 // | Exclusive      | blocks, then exclusive | Free     |
 //
 // The full conditions are as follows.
 //
-// * Calls to `Unlock()` require that the mutex be held, and must be made in the
-//   same thread that performed the corresponding `Lock()` operation which
+// * Calls to `unlock()` require that the mutex be held, and must be made in the
+//   same thread that performed the corresponding `lock()` operation which
 //   acquired the mutex; otherwise the call is invalid.
 //
 // * The mutex being non-reentrant (or non-recursive) means that a call to
-//   `Lock()` or `TryLock()` must not be made in a thread that already holds the
-//   mutex; such a call is invalid.
+//   `lock()` or `try_lock()` must not be made in a thread that already holds
+//   the mutex; such a call is invalid.
 //
 // * In other words, the state of being "held" has both a temporal component
-//   (from `Lock()` until `Unlock()`) as well as a thread identity component:
+//   (from `lock()` until `unlock()`) as well as a thread identity component:
 //   the mutex is held *by a particular thread*.
 //
 // An "invalid" operation has undefined behavior. The `Mutex` implementation
@@ -174,24 +172,35 @@
 
   ~Mutex();
 
-  // Mutex::Lock()
+  // Mutex::lock()
   //
   // Blocks the calling thread, if necessary, until this `Mutex` is free, and
   // then acquires it exclusively. (This lock is also known as a "write lock.")
-  void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION();
+  void lock() ABSL_EXCLUSIVE_LOCK_FUNCTION();
 
-  // Mutex::Unlock()
+  ABSL_DEPRECATE_AND_INLINE()
+  inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { lock(); }
+
+  // Mutex::unlock()
   //
   // Releases this `Mutex` and returns it from the exclusive/write state to the
   // free state. Calling thread must hold the `Mutex` exclusively.
-  void Unlock() ABSL_UNLOCK_FUNCTION();
+  void unlock() ABSL_UNLOCK_FUNCTION();
 
-  // Mutex::TryLock()
+  ABSL_DEPRECATE_AND_INLINE()
+  inline void Unlock() ABSL_UNLOCK_FUNCTION() { unlock(); }
+
+  // Mutex::try_lock()
   //
   // If the mutex can be acquired without blocking, does so exclusively and
   // returns `true`. Otherwise, returns `false`. Returns `true` with high
   // probability if the `Mutex` was free.
-  [[nodiscard]] bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true);
+  [[nodiscard]] bool try_lock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true);
+
+  ABSL_DEPRECATE_AND_INLINE()
+  [[nodiscard]] bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+    return try_lock();
+  }
 
   // Mutex::AssertHeld()
   //
@@ -211,19 +220,19 @@
   // Neither read-locks nor write-locks are reentrant/recursive to avoid
   // potential client programming errors.
   //
-  // The Mutex API provides `Writer*()` aliases for the existing `Lock()`,
-  // `Unlock()` and `TryLock()` methods for use within applications mixing
-  // reader/writer locks. Using `Reader*()` and `Writer*()` operations in this
+  // The Mutex API provides `Writer*()` aliases for the existing `lock()`,
+  // `unlock()` and `try_lock()` methods for use within applications mixing
+  // reader/writer locks. Using `*_shared()` and `Writer*()` operations in this
   // manner can make locking behavior clearer when mixing read and write modes.
   //
   // Introducing reader locks necessarily complicates the `Mutex` state
   // machine somewhat. The table below illustrates the allowed state transitions
-  // of a mutex in such cases. Note that ReaderLock() may block even if the lock
-  // is held in shared mode; this occurs when another thread is blocked on a
-  // call to WriterLock().
+  // of a mutex in such cases. Note that lock_shared() may block even if the
+  // lock is held in shared mode; this occurs when another thread is blocked on
+  // a call to lock().
   //
   // ---------------------------------------------------------------------------
-  //     Operation: WriterLock() Unlock()  ReaderLock()           ReaderUnlock()
+  //     Operation: lock()       unlock()  lock_shared() unlock_shared()
   // ---------------------------------------------------------------------------
   // State
   // ---------------------------------------------------------------------------
@@ -235,28 +244,38 @@
   //
   // In comments below, "shared" refers to a state of Shared(n) for any n > 0.
 
-  // Mutex::ReaderLock()
+  // Mutex::lock_shared()
   //
   // Blocks the calling thread, if necessary, until this `Mutex` is either free,
   // or in shared mode, and then acquires a share of it. Note that
-  // `ReaderLock()` will block if some other thread has an exclusive/writer lock
-  // on the mutex.
+  // `lock_shared()` will block if some other thread has an exclusive/writer
+  // lock on the mutex.
+  void lock_shared() ABSL_SHARED_LOCK_FUNCTION();
 
-  void ReaderLock() ABSL_SHARED_LOCK_FUNCTION();
+  ABSL_DEPRECATE_AND_INLINE()
+  void ReaderLock() ABSL_SHARED_LOCK_FUNCTION() { lock_shared(); }
 
-  // Mutex::ReaderUnlock()
+  // Mutex::unlock_shared()
   //
-  // Releases a read share of this `Mutex`. `ReaderUnlock` may return a mutex to
-  // the free state if this thread holds the last reader lock on the mutex. Note
-  // that you cannot call `ReaderUnlock()` on a mutex held in write mode.
-  void ReaderUnlock() ABSL_UNLOCK_FUNCTION();
+  // Releases a read share of this `Mutex`. `unlock_shared` may return a mutex
+  // to the free state if this thread holds the last reader lock on the mutex.
+  // Note that you cannot call `unlock_shared()` on a mutex held in write mode.
+  void unlock_shared() ABSL_UNLOCK_FUNCTION();
 
-  // Mutex::ReaderTryLock()
+  ABSL_DEPRECATE_AND_INLINE()
+  void ReaderUnlock() ABSL_UNLOCK_FUNCTION() { unlock_shared(); }
+
+  // Mutex::try_lock_shared()
   //
   // If the mutex can be acquired without blocking, acquires this mutex for
   // shared access and returns `true`. Otherwise, returns `false`. Returns
   // `true` with high probability if the `Mutex` was free or shared.
-  [[nodiscard]] bool ReaderTryLock() ABSL_SHARED_TRYLOCK_FUNCTION(true);
+  [[nodiscard]] bool try_lock_shared() ABSL_SHARED_TRYLOCK_FUNCTION(true);
+
+  ABSL_DEPRECATE_AND_INLINE()
+  [[nodiscard]] bool ReaderTryLock() ABSL_SHARED_TRYLOCK_FUNCTION(true) {
+    return try_lock_shared();
+  }
 
   // Mutex::AssertReaderHeld()
   //
@@ -278,12 +297,15 @@
   // These methods may be used (along with the complementary `Reader*()`
   // methods) to distinguish simple exclusive `Mutex` usage (`Lock()`,
   // etc.) from reader/writer lock usage.
-  void WriterLock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { this->Lock(); }
+  ABSL_DEPRECATE_AND_INLINE()
+  void WriterLock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { lock(); }
 
-  void WriterUnlock() ABSL_UNLOCK_FUNCTION() { this->Unlock(); }
+  ABSL_DEPRECATE_AND_INLINE()
+  void WriterUnlock() ABSL_UNLOCK_FUNCTION() { unlock(); }
 
+  ABSL_DEPRECATE_AND_INLINE()
   [[nodiscard]] bool WriterTryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
-    return this->TryLock();
+    return try_lock();
   }
 
   // ---------------------------------------------------------------------------
@@ -546,10 +568,10 @@
       base_internal::PerThreadSynch* absl_nonnull w);
   void Dtor();
 
-  friend class CondVar;   // for access to Trans()/Fer().
+  friend class CondVar;                // for access to Trans()/Fer().
   void Trans(MuHow absl_nonnull how);  // used for CondVar->Mutex transfer
   void Fer(base_internal::PerThreadSynch* absl_nonnull
-           w);  // used for CondVar->Mutex transfer
+               w);  // used for CondVar->Mutex transfer
 
   // Catch the error of writing Mutex when intending MutexLock.
   explicit Mutex(const volatile Mutex* absl_nullable /*ignored*/) {}
@@ -572,7 +594,7 @@
 // Class Foo {
 //  public:
 //   Foo::Bar* Baz() {
-//     MutexLock lock(&mu_);
+//     MutexLock lock(mu_);
 //     ...
 //     return bar;
 //   }
@@ -584,32 +606,46 @@
  public:
   // Constructors
 
-  // Calls `mu->Lock()` and returns when that call returns. That is, `*mu` is
-  // guaranteed to be locked when this object is constructed. Requires that
-  // `mu` be dereferenceable.
-  explicit MutexLock(Mutex* absl_nonnull mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
-      : mu_(mu) {
-    this->mu_->Lock();
-  }
-
-  // Like above, but calls `mu->LockWhen(cond)` instead. That is, in addition to
-  // the above, the condition given by `cond` is also guaranteed to hold when
-  // this object is constructed.
-  explicit MutexLock(Mutex* absl_nonnull mu, const Condition& cond)
+  // Calls `mu.lock()` and returns when that call returns. That is, `mu` is
+  // guaranteed to be locked when this object is constructed.
+  explicit MutexLock(Mutex& mu ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))
       ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
       : mu_(mu) {
-    this->mu_->LockWhen(cond);
+    this->mu_.lock();
   }
 
+  // Calls `mu->lock()` and returns when that call returns. That is, `*mu` is
+  // guaranteed to be locked when this object is constructed. Requires that
+  // `mu` be dereferenceable.
+  [[deprecated("Use the constructor that takes a reference instead")]]
+  ABSL_REFACTOR_INLINE
+  explicit MutexLock(Mutex* absl_nonnull mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : MutexLock(*mu) {}
+
+  // Like above, but calls `mu.LockWhen(cond)` instead. That is, in addition to
+  // the above, the condition given by `cond` is also guaranteed to hold when
+  // this object is constructed.
+  explicit MutexLock(Mutex& mu ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this),
+                     const Condition& cond) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    this->mu_.LockWhen(cond);
+  }
+
+  [[deprecated("Use the constructor that takes a reference instead")]]
+  ABSL_REFACTOR_INLINE
+  explicit MutexLock(Mutex* absl_nonnull mu, const Condition& cond)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : MutexLock(*mu, cond) {}
+
   MutexLock(const MutexLock&) = delete;  // NOLINT(runtime/mutex)
   MutexLock(MutexLock&&) = delete;       // NOLINT(runtime/mutex)
   MutexLock& operator=(const MutexLock&) = delete;
   MutexLock& operator=(MutexLock&&) = delete;
 
-  ~MutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->Unlock(); }
+  ~MutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_.unlock(); }
 
  private:
-  Mutex* absl_nonnull const mu_;
+  Mutex& mu_;
 };
 
 // ReaderMutexLock
@@ -618,26 +654,38 @@
 // releases a shared lock on a `Mutex` via RAII.
 class ABSL_SCOPED_LOCKABLE ReaderMutexLock {
  public:
-  explicit ReaderMutexLock(Mutex* absl_nonnull mu) ABSL_SHARED_LOCK_FUNCTION(mu)
-      : mu_(mu) {
-    mu->ReaderLock();
-  }
-
-  explicit ReaderMutexLock(Mutex* absl_nonnull mu, const Condition& cond)
+  explicit ReaderMutexLock(Mutex& mu ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))
       ABSL_SHARED_LOCK_FUNCTION(mu)
       : mu_(mu) {
-    mu->ReaderLockWhen(cond);
+    mu.lock_shared();
   }
 
+  [[deprecated("Use the constructor that takes a reference instead")]]
+  ABSL_REFACTOR_INLINE
+  explicit ReaderMutexLock(Mutex* absl_nonnull mu) ABSL_SHARED_LOCK_FUNCTION(mu)
+      : ReaderMutexLock(*mu) {}
+
+  explicit ReaderMutexLock(Mutex& mu ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this),
+                           const Condition& cond) ABSL_SHARED_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    mu.ReaderLockWhen(cond);
+  }
+
+  [[deprecated("Use the constructor that takes a reference instead")]]
+  ABSL_REFACTOR_INLINE
+  explicit ReaderMutexLock(Mutex* absl_nonnull mu, const Condition& cond)
+      ABSL_SHARED_LOCK_FUNCTION(mu)
+      : ReaderMutexLock(*mu, cond) {}
+
   ReaderMutexLock(const ReaderMutexLock&) = delete;
   ReaderMutexLock(ReaderMutexLock&&) = delete;
   ReaderMutexLock& operator=(const ReaderMutexLock&) = delete;
   ReaderMutexLock& operator=(ReaderMutexLock&&) = delete;
 
-  ~ReaderMutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->ReaderUnlock(); }
+  ~ReaderMutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_.unlock_shared(); }
 
  private:
-  Mutex* absl_nonnull const mu_;
+  Mutex& mu_;
 };
 
 // WriterMutexLock
@@ -646,27 +694,40 @@
 // releases a write (exclusive) lock on a `Mutex` via RAII.
 class ABSL_SCOPED_LOCKABLE WriterMutexLock {
  public:
-  explicit WriterMutexLock(Mutex* absl_nonnull mu)
+  explicit WriterMutexLock(Mutex& mu ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))
       ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
       : mu_(mu) {
-    mu->WriterLock();
+    mu.lock();
   }
 
-  explicit WriterMutexLock(Mutex* absl_nonnull mu, const Condition& cond)
+  [[deprecated("Use the constructor that takes a reference instead")]]
+  ABSL_REFACTOR_INLINE
+  explicit WriterMutexLock(Mutex* absl_nonnull mu)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : WriterMutexLock(*mu) {}
+
+  explicit WriterMutexLock(Mutex& mu ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this),
+                           const Condition& cond)
       ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
       : mu_(mu) {
-    mu->WriterLockWhen(cond);
+    mu.WriterLockWhen(cond);
   }
 
+  [[deprecated("Use the constructor that takes a reference instead")]]
+  ABSL_REFACTOR_INLINE
+  explicit WriterMutexLock(Mutex* absl_nonnull mu, const Condition& cond)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : WriterMutexLock(*mu, cond) {}
+
   WriterMutexLock(const WriterMutexLock&) = delete;
   WriterMutexLock(WriterMutexLock&&) = delete;
   WriterMutexLock& operator=(const WriterMutexLock&) = delete;
   WriterMutexLock& operator=(WriterMutexLock&&) = delete;
 
-  ~WriterMutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->WriterUnlock(); }
+  ~WriterMutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_.unlock(); }
 
  private:
-  Mutex* absl_nonnull const mu_;
+  Mutex& mu_;
 };
 
 // -----------------------------------------------------------------------------
@@ -713,7 +774,7 @@
 // Example using a scope guard:
 //
 //   {
-//     MutexLock lock(&mu_, count_is_zero);
+//     MutexLock lock(mu_, count_is_zero);
 //     // ...
 //   }
 //
@@ -754,27 +815,27 @@
   template <typename T, typename = void>
   Condition(
       bool (*absl_nonnull func)(T* absl_nullability_unknown),
-      typename absl::internal::type_identity<T>::type* absl_nullability_unknown
-      arg);
+      typename absl::type_identity<T>::type* absl_nullability_unknown
+          arg);
 
   // Templated version for invoking a method that returns a `bool`.
   //
   // `Condition(object, &Class::Method)` constructs a `Condition` that evaluates
   // `object->Method()`.
   //
-  // Implementation Note: `absl::internal::type_identity` is used to allow
+  // Implementation Note: `absl::type_identity` is used to allow
   // methods to come from base classes. A simpler signature like
   // `Condition(T*, bool (T::*)())` does not suffice.
   template <typename T>
   Condition(
       T* absl_nonnull object,
-      bool (absl::internal::type_identity<T>::type::* absl_nonnull method)());
+      bool (absl::type_identity<T>::type::* absl_nonnull method)());
 
   // Same as above, for const members
   template <typename T>
   Condition(
       const T* absl_nonnull object,
-      bool (absl::internal::type_identity<T>::type::* absl_nonnull method)()
+      bool (absl::type_identity<T>::type::* absl_nonnull method)()
           const);
 
   // A Condition that returns the value of `*cond`
@@ -1019,7 +1080,7 @@
       ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
       : mu_(mu) {
     if (this->mu_ != nullptr) {
-      this->mu_->Lock();
+      this->mu_->lock();
     }
   }
 
@@ -1033,7 +1094,7 @@
 
   ~MutexLockMaybe() ABSL_UNLOCK_FUNCTION() {
     if (this->mu_ != nullptr) {
-      this->mu_->Unlock();
+      this->mu_->unlock();
     }
   }
 
@@ -1051,28 +1112,41 @@
 // mutex before destruction. `Release()` may be called at most once.
 class ABSL_SCOPED_LOCKABLE ReleasableMutexLock {
  public:
-  explicit ReleasableMutexLock(Mutex* absl_nonnull mu)
-      ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
-      : mu_(mu) {
-    this->mu_->Lock();
+  explicit ReleasableMutexLock(Mutex& mu ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(
+      this)) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(&mu) {
+    this->mu_->lock();
   }
 
-  explicit ReleasableMutexLock(Mutex* absl_nonnull mu, const Condition& cond)
+  [[deprecated("Use the constructor that takes a reference instead")]]
+  ABSL_REFACTOR_INLINE
+  explicit ReleasableMutexLock(Mutex* absl_nonnull mu)
       ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
-      : mu_(mu) {
+      : ReleasableMutexLock(*mu) {}
+
+  explicit ReleasableMutexLock(
+      Mutex& mu ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this),
+      const Condition& cond) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(&mu) {
     this->mu_->LockWhen(cond);
   }
 
+  [[deprecated("Use the constructor that takes a reference instead")]]
+  ABSL_REFACTOR_INLINE
+  explicit ReleasableMutexLock(Mutex* absl_nonnull mu, const Condition& cond)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : ReleasableMutexLock(*mu, cond) {}
+
   ~ReleasableMutexLock() ABSL_UNLOCK_FUNCTION() {
     if (this->mu_ != nullptr) {
-      this->mu_->Unlock();
+      this->mu_->unlock();
     }
   }
 
   void Release() ABSL_UNLOCK_FUNCTION();
 
  private:
-  Mutex* absl_nonnull mu_;
+  Mutex* absl_nullable mu_;
   ReleasableMutexLock(const ReleasableMutexLock&) = delete;
   ReleasableMutexLock(ReleasableMutexLock&&) = delete;
   ReleasableMutexLock& operator=(const ReleasableMutexLock&) = delete;
@@ -1090,12 +1164,13 @@
 inline Mutex::~Mutex() { Dtor(); }
 #endif
 
-#if defined(NDEBUG) && !defined(ABSL_HAVE_THREAD_SANITIZER)
-// Use default (empty) destructor in release build for performance reasons.
-// We need to mark both Dtor and ~Mutex as always inline for inconsistent
-// builds that use both NDEBUG and !NDEBUG with dynamic libraries. In these
-// cases we want the empty functions to dissolve entirely rather than being
-// exported from dynamic libraries and potentially override the non-empty ones.
+#if defined(NDEBUG) && !defined(ABSL_HAVE_THREAD_SANITIZER) && \
+    !defined(ABSL_BUILD_DLL)
+// Under NDEBUG and without TSAN, Dtor is normally fully inlined for
+// performance. However, when building Abseil as a shared library
+// (ABSL_BUILD_DLL), we must provide an out-of-line definition. This ensures the
+// Mutex::Dtor symbol is exported from the DLL, maintaining ABI compatibility
+// with clients that might be built in debug mode and thus expect the symbol.
 ABSL_ATTRIBUTE_ALWAYS_INLINE
 inline void Mutex::Dtor() {}
 #endif
@@ -1134,15 +1209,15 @@
 template <typename T, typename>
 inline Condition::Condition(
     bool (*absl_nonnull func)(T* absl_nullability_unknown),
-    typename absl::internal::type_identity<T>::type* absl_nullability_unknown
-    arg)
+    typename absl::type_identity<T>::type* absl_nullability_unknown
+        arg)
     // Just delegate to the overload above.
     : Condition(func, arg) {}
 
 template <typename T>
 inline Condition::Condition(
     T* absl_nonnull object,
-    bool (absl::internal::type_identity<T>::type::* absl_nonnull method)())
+    bool (absl::type_identity<T>::type::* absl_nonnull method)())
     : eval_(&CastAndCallMethod<T, decltype(method)>), arg_(object) {
   static_assert(sizeof(&method) <= sizeof(callback_),
                 "An overlarge method pointer was passed to Condition.");
@@ -1152,7 +1227,7 @@
 template <typename T>
 inline Condition::Condition(
     const T* absl_nonnull object,
-    bool (absl::internal::type_identity<T>::type::* absl_nonnull method)()
+    bool (absl::type_identity<T>::type::* absl_nonnull method)()
         const)
     : eval_(&CastAndCallMethod<const T, decltype(method)>),
       arg_(reinterpret_cast<void*>(const_cast<T*>(object))) {
diff --git a/absl/synchronization/mutex_benchmark.cc b/absl/synchronization/mutex_benchmark.cc
index 06888df..d2c6495 100644
--- a/absl/synchronization/mutex_benchmark.cc
+++ b/absl/synchronization/mutex_benchmark.cc
@@ -30,7 +30,7 @@
 void BM_Mutex(benchmark::State& state) {
   static absl::NoDestructor<absl::Mutex> mu;
   for (auto _ : state) {
-    absl::MutexLock lock(mu.get());
+    absl::MutexLock lock(*mu.get());
   }
 }
 BENCHMARK(BM_Mutex)->UseRealTime()->Threads(1)->ThreadPerCpu();
@@ -38,7 +38,7 @@
 void BM_ReaderLock(benchmark::State& state) {
   static absl::NoDestructor<absl::Mutex> mu;
   for (auto _ : state) {
-    absl::ReaderMutexLock lock(mu.get());
+    absl::ReaderMutexLock lock(*mu.get());
   }
 }
 BENCHMARK(BM_ReaderLock)->UseRealTime()->Threads(1)->ThreadPerCpu();
@@ -46,8 +46,8 @@
 void BM_TryLock(benchmark::State& state) {
   absl::Mutex mu;
   for (auto _ : state) {
-    if (mu.TryLock()) {
-      mu.Unlock();
+    if (mu.try_lock()) {
+      mu.unlock();
     }
   }
 }
@@ -56,8 +56,8 @@
 void BM_ReaderTryLock(benchmark::State& state) {
   static absl::NoDestructor<absl::Mutex> mu;
   for (auto _ : state) {
-    if (mu->ReaderTryLock()) {
-      mu->ReaderUnlock();
+    if (mu->try_lock_shared()) {
+      mu->unlock_shared();
     }
   }
 }
@@ -72,24 +72,6 @@
   }
 }
 
-template <typename MutexType>
-class RaiiLocker {
- public:
-  explicit RaiiLocker(MutexType* mu) : mu_(mu) { mu_->Lock(); }
-  ~RaiiLocker() { mu_->Unlock(); }
- private:
-  MutexType* mu_;
-};
-
-template <>
-class RaiiLocker<std::mutex> {
- public:
-  explicit RaiiLocker(std::mutex* mu) : mu_(mu) { mu_->lock(); }
-  ~RaiiLocker() { mu_->unlock(); }
- private:
-  std::mutex* mu_;
-};
-
 // RAII object to change the Mutex priority of the running thread.
 class ScopedThreadMutexPriority {
  public:
@@ -163,7 +145,7 @@
     shared->looping_threads.fetch_add(1);
     for (int i = 0; i < kBatchSize; i++) {
       {
-        absl::MutexLock l(&shared->mu);
+        absl::MutexLock l(shared->mu);
         shared->thread_has_mutex.store(true, std::memory_order_relaxed);
         // Spin until all other threads are either out of the benchmark loop
         // or blocked on the mutex. This ensures that the mutex queue is kept
@@ -226,7 +208,7 @@
     // to keep ratio between local work and critical section approximately
     // equal regardless of number of threads.
     DelayNs(100 * state.threads(), &local);
-    RaiiLocker<MutexType> locker(&shared->mu);
+    std::scoped_lock locker(shared->mu);
     DelayNs(state.range(0), &shared->data);
   }
 }
@@ -291,7 +273,7 @@
       init->DecrementCount();
       m->LockWhen(absl::Condition(
           static_cast<bool (*)(int*)>([](int* v) { return *v == 0; }), p));
-      m->Unlock();
+      m->unlock();
     }
   };
 
@@ -317,15 +299,15 @@
   init.Wait();
 
   for (auto _ : state) {
-    mu.Lock();
-    mu.Unlock();  // Each unlock requires Condition evaluation for our waiters.
+    mu.lock();
+    mu.unlock();  // Each unlock requires Condition evaluation for our waiters.
   }
 
-  mu.Lock();
+  mu.lock();
   for (int i = 0; i < num_classes; i++) {
     equivalence_classes[i] = 0;
   }
-  mu.Unlock();
+  mu.unlock();
 }
 
 // Some configurations have higher thread limits than others.
diff --git a/absl/synchronization/mutex_test.cc b/absl/synchronization/mutex_test.cc
index a3eb3db..793acf8 100644
--- a/absl/synchronization/mutex_test.cc
+++ b/absl/synchronization/mutex_test.cc
@@ -23,7 +23,9 @@
 #include <cstdlib>
 #include <functional>
 #include <memory>
+#include <mutex>  // NOLINT(build/c++11)
 #include <random>
+#include <shared_mutex>  // NOLINT(build/c++14)
 #include <string>
 #include <thread>  // NOLINT(build/c++11)
 #include <type_traits>
@@ -106,7 +108,7 @@
 
 static void TestMu(TestContext *cxt, int c) {
   for (int i = 0; i != cxt->iterations; i++) {
-    absl::MutexLock l(&cxt->mu);
+    absl::MutexLock l(cxt->mu);
     int a = cxt->g0 + 1;
     cxt->g0 = a;
     cxt->g1--;
@@ -117,17 +119,17 @@
   for (int i = 0; i != cxt->iterations; i++) {
     do {
       std::this_thread::yield();
-    } while (!cxt->mu.TryLock());
+    } while (!cxt->mu.try_lock());
     int a = cxt->g0 + 1;
     cxt->g0 = a;
     cxt->g1--;
-    cxt->mu.Unlock();
+    cxt->mu.unlock();
   }
 }
 
 static void TestR20ms(TestContext *cxt, int c) {
   for (int i = 0; i != cxt->iterations; i++) {
-    absl::ReaderMutexLock l(&cxt->mu);
+    absl::ReaderMutexLock l(cxt->mu);
     absl::SleepFor(absl::Milliseconds(20));
     cxt->mu.AssertReaderHeld();
   }
@@ -136,7 +138,7 @@
 static void TestRW(TestContext *cxt, int c) {
   if ((c & 1) == 0) {
     for (int i = 0; i != cxt->iterations; i++) {
-      absl::WriterMutexLock l(&cxt->mu);
+      absl::WriterMutexLock l(cxt->mu);
       cxt->g0++;
       cxt->g1--;
       cxt->mu.AssertHeld();
@@ -144,7 +146,7 @@
     }
   } else {
     for (int i = 0; i != cxt->iterations; i++) {
-      absl::ReaderMutexLock l(&cxt->mu);
+      absl::ReaderMutexLock l(cxt->mu);
       CHECK_EQ(cxt->g0, -cxt->g1) << "Error in TestRW";
       cxt->mu.AssertReaderHeld();
     }
@@ -166,7 +168,7 @@
   MyContext mc;
   mc.target = c;
   mc.cxt = cxt;
-  absl::MutexLock l(&cxt->mu);
+  absl::MutexLock l(cxt->mu);
   cxt->mu.AssertHeld();
   while (cxt->g0 < cxt->iterations) {
     cxt->mu.Await(absl::Condition(&mc, &MyContext::MyTurn));
@@ -182,7 +184,7 @@
 
 static void TestSignalAll(TestContext *cxt, int c) {
   int target = c;
-  absl::MutexLock l(&cxt->mu);
+  absl::MutexLock l(cxt->mu);
   cxt->mu.AssertHeld();
   while (cxt->g0 < cxt->iterations) {
     while (cxt->g0 != target && cxt->g0 != cxt->iterations) {
@@ -200,7 +202,7 @@
 static void TestSignal(TestContext *cxt, int c) {
   CHECK_EQ(cxt->threads, 2) << "TestSignal should use 2 threads";
   int target = c;
-  absl::MutexLock l(&cxt->mu);
+  absl::MutexLock l(cxt->mu);
   cxt->mu.AssertHeld();
   while (cxt->g0 < cxt->iterations) {
     while (cxt->g0 != target && cxt->g0 != cxt->iterations) {
@@ -217,7 +219,7 @@
 
 static void TestCVTimeout(TestContext *cxt, int c) {
   int target = c;
-  absl::MutexLock l(&cxt->mu);
+  absl::MutexLock l(cxt->mu);
   cxt->mu.AssertHeld();
   while (cxt->g0 < cxt->iterations) {
     while (cxt->g0 != target && cxt->g0 != cxt->iterations) {
@@ -241,7 +243,7 @@
   absl::Condition false_cond(&kFalse);
   absl::Condition g0ge2(G0GE2, cxt);
   if (c == 0) {
-    absl::MutexLock l(&cxt->mu);
+    absl::MutexLock l(cxt->mu);
 
     absl::Time start = absl::Now();
     if (use_cv) {
@@ -309,7 +311,7 @@
     CHECK_EQ(cxt->g0, cxt->threads) << "TestTime failed";
 
   } else if (c == 1) {
-    absl::MutexLock l(&cxt->mu);
+    absl::MutexLock l(cxt->mu);
     const absl::Time start = absl::Now();
     if (use_cv) {
       cxt->cv.WaitWithTimeout(&cxt->mu, absl::Milliseconds(500));
@@ -322,7 +324,7 @@
         << "TestTime failed";
     cxt->g0++;
   } else if (c == 2) {
-    absl::MutexLock l(&cxt->mu);
+    absl::MutexLock l(cxt->mu);
     if (use_cv) {
       while (cxt->g0 < 2) {
         cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(100));
@@ -333,7 +335,7 @@
     }
     cxt->g0++;
   } else {
-    absl::MutexLock l(&cxt->mu);
+    absl::MutexLock l(cxt->mu);
     if (use_cv) {
       while (cxt->g0 < 2) {
         cxt->cv.Wait(&cxt->mu);
@@ -351,11 +353,11 @@
 
 static void EndTest(int *c0, int *c1, absl::Mutex *mu, absl::CondVar *cv,
                     const std::function<void(int)> &cb) {
-  mu->Lock();
+  mu->lock();
   int c = (*c0)++;
-  mu->Unlock();
+  mu->unlock();
   cb(c);
-  absl::MutexLock l(mu);
+  absl::MutexLock l(*mu);
   (*c1)++;
   cv->Signal();
 }
@@ -377,11 +379,11 @@
         &EndTest, &c0, &c1, &mu2, &cv2,
         std::function<void(int)>(std::bind(test, cxt, std::placeholders::_1))));
   }
-  mu2.Lock();
+  mu2.lock();
   while (c1 != threads) {
     cv2.Wait(&mu2);
   }
-  mu2.Unlock();
+  mu2.unlock();
   return cxt->g0;
 }
 
@@ -422,7 +424,7 @@
 static void WaitForA(TimeoutBugStruct *x) {
   x->mu.LockWhen(absl::Condition(&x->a));
   x->a_waiter_count--;
-  x->mu.Unlock();
+  x->mu.unlock();
 }
 
 static bool NoAWaiters(TimeoutBugStruct *x) { return x->a_waiter_count == 0; }
@@ -445,27 +447,27 @@
   // Thread A.  Sets barrier, waits for release using Mutex::Await, then
   // signals released_cv.
   pool->Schedule([&state] {
-    state.release_mu.Lock();
+    state.release_mu.lock();
 
-    state.barrier_mu.Lock();
+    state.barrier_mu.lock();
     state.barrier = true;
-    state.barrier_mu.Unlock();
+    state.barrier_mu.unlock();
 
     state.release_mu.Await(absl::Condition(&state.release));
     state.released_cv.Signal();
-    state.release_mu.Unlock();
+    state.release_mu.unlock();
   });
 
   state.barrier_mu.LockWhen(absl::Condition(&state.barrier));
-  state.barrier_mu.Unlock();
-  state.release_mu.Lock();
+  state.barrier_mu.unlock();
+  state.release_mu.lock();
   // Thread A is now blocked on release by way of Mutex::Await().
 
   // Set release.  Calling released_cv.Wait() should un-block thread A,
   // which will signal released_cv.  If not, the test will hang.
   state.release = true;
   state.released_cv.Wait(&state.release_mu);
-  state.release_mu.Unlock();
+  state.release_mu.unlock();
 }
 
 // Test that a CondVar.WaitWithTimeout(&mutex) can un-block a call to
@@ -486,20 +488,20 @@
   // Thread A.  Sets barrier, waits for release using Mutex::Await, then
   // signals released_cv.
   pool->Schedule([&state] {
-    state.release_mu.Lock();
+    state.release_mu.lock();
 
-    state.barrier_mu.Lock();
+    state.barrier_mu.lock();
     state.barrier = true;
-    state.barrier_mu.Unlock();
+    state.barrier_mu.unlock();
 
     state.release_mu.Await(absl::Condition(&state.release));
     state.released_cv.Signal();
-    state.release_mu.Unlock();
+    state.release_mu.unlock();
   });
 
   state.barrier_mu.LockWhen(absl::Condition(&state.barrier));
-  state.barrier_mu.Unlock();
-  state.release_mu.Lock();
+  state.barrier_mu.unlock();
+  state.release_mu.lock();
   // Thread A is now blocked on release by way of Mutex::Await().
 
   // Set release.  Calling released_cv.Wait() should un-block thread A,
@@ -510,7 +512,7 @@
       << "; Unrecoverable test failure: CondVar::WaitWithTimeout did not "
          "unblock the absl::Mutex::Await call in another thread.";
 
-  state.release_mu.Unlock();
+  state.release_mu.unlock();
 }
 
 // Test for regression of a bug in loop of TryRemove()
@@ -536,7 +538,7 @@
 
   x.a = true;                                    // wakeup the two waiters on A
   x.mu.Await(absl::Condition(&NoAWaiters, &x));  // wait for them to exit
-  x.mu.Unlock();
+  x.mu.unlock();
 }
 
 struct CondVarWaitDeadlock : testing::TestWithParam<int> {
@@ -556,27 +558,27 @@
 
   void Waiter1() {
     if (read_lock1) {
-      mu.ReaderLock();
+      mu.lock_shared();
       while (!cond1) {
         cv.Wait(&mu);
       }
-      mu.ReaderUnlock();
+      mu.unlock_shared();
     } else {
-      mu.Lock();
+      mu.lock();
       while (!cond1) {
         cv.Wait(&mu);
       }
-      mu.Unlock();
+      mu.unlock();
     }
   }
 
   void Waiter2() {
     if (read_lock2) {
       mu.ReaderLockWhen(absl::Condition(&cond2));
-      mu.ReaderUnlock();
+      mu.unlock_shared();
     } else {
       mu.LockWhen(absl::Condition(&cond2));
-      mu.Unlock();
+      mu.unlock();
     }
   }
 };
@@ -600,21 +602,21 @@
   absl::SleepFor(absl::Milliseconds(100));
 
   // Wake condwaiter.
-  mu.Lock();
+  mu.lock();
   cond1 = true;
   if (signal_unlocked) {
-    mu.Unlock();
+    mu.unlock();
     cv.Signal();
   } else {
     cv.Signal();
-    mu.Unlock();
+    mu.unlock();
   }
   waiter1.reset();  // "join" waiter1
 
   // Wake waiter.
-  mu.Lock();
+  mu.lock();
   cond2 = true;
-  mu.Unlock();
+  mu.unlock();
   waiter2.reset();  // "join" waiter2
 }
 
@@ -639,19 +641,19 @@
 
 // Test for regression of a bug in loop of DequeueAllWakeable()
 static void AcquireAsReader(DequeueAllWakeableBugStruct *x) {
-  x->mu.ReaderLock();
-  x->mu2.Lock();
+  x->mu.lock_shared();
+  x->mu2.lock();
   x->unfinished_count--;
   x->done1 = (x->unfinished_count == 0);
-  x->mu2.Unlock();
+  x->mu2.unlock();
   // make sure that both readers acquired mu before we release it.
   absl::SleepFor(absl::Seconds(2));
-  x->mu.ReaderUnlock();
+  x->mu.unlock_shared();
 
-  x->mu2.Lock();
+  x->mu2.lock();
   x->finished_count--;
   x->done2 = (x->finished_count == 0);
-  x->mu2.Unlock();
+  x->mu2.unlock();
 }
 
 // Test for regression of a bug in loop of DequeueAllWakeable()
@@ -663,21 +665,21 @@
   x.done1 = false;
   x.finished_count = 2;
   x.done2 = false;
-  x.mu.Lock();  // acquire mu exclusively
+  x.mu.lock();  // acquire mu exclusively
   // queue two thread that will block on reader locks on x.mu
   tp->Schedule(std::bind(&AcquireAsReader, &x));
   tp->Schedule(std::bind(&AcquireAsReader, &x));
   absl::SleepFor(absl::Seconds(1));  // give time for reader threads to block
-  x.mu.Unlock();                     // wake them up
+  x.mu.unlock();                     // wake them up
 
   // both readers should finish promptly
   EXPECT_TRUE(
       x.mu2.LockWhenWithTimeout(absl::Condition(&x.done1), absl::Seconds(10)));
-  x.mu2.Unlock();
+  x.mu2.unlock();
 
   EXPECT_TRUE(
       x.mu2.LockWhenWithTimeout(absl::Condition(&x.done2), absl::Seconds(10)));
-  x.mu2.Unlock();
+  x.mu2.unlock();
 }
 
 struct LockWhenTestStruct {
@@ -689,15 +691,15 @@
 };
 
 static bool LockWhenTestIsCond(LockWhenTestStruct *s) {
-  s->mu2.Lock();
+  s->mu2.lock();
   s->waiting = true;
-  s->mu2.Unlock();
+  s->mu2.unlock();
   return s->cond;
 }
 
 static void LockWhenTestWaitForIsCond(LockWhenTestStruct *s) {
   s->mu1.LockWhen(absl::Condition(&LockWhenTestIsCond, s));
-  s->mu1.Unlock();
+  s->mu1.unlock();
 }
 
 TEST(Mutex, LockWhen) {
@@ -705,11 +707,11 @@
 
   std::thread t(LockWhenTestWaitForIsCond, &s);
   s.mu2.LockWhen(absl::Condition(&s.waiting));
-  s.mu2.Unlock();
+  s.mu2.unlock();
 
-  s.mu1.Lock();
+  s.mu1.lock();
   s.cond = true;
-  s.mu1.Unlock();
+  s.mu1.unlock();
 
   t.join();
 }
@@ -724,20 +726,20 @@
   bool (*cond_lt_10)(int *) = [](int *p) { return *p < 10; };
 
   std::thread t1([&mu, &n, &done, cond_eq_10]() {
-    absl::ReaderMutexLock lock(&mu, absl::Condition(cond_eq_10, &n));
+    absl::ReaderMutexLock lock(mu, absl::Condition(cond_eq_10, &n));
     done = true;
   });
 
   std::thread t2[10];
   for (std::thread &t : t2) {
     t = std::thread([&mu, &n, cond_lt_10]() {
-      absl::WriterMutexLock lock(&mu, absl::Condition(cond_lt_10, &n));
+      absl::WriterMutexLock lock(mu, absl::Condition(cond_lt_10, &n));
       ++n;
     });
   }
 
   {
-    absl::MutexLock lock(&mu);
+    absl::MutexLock lock(mu);
     n = 0;
   }
 
@@ -749,7 +751,7 @@
 }
 
 // --------------------------------------------------------
-// The following test requires Mutex::ReaderLock to be a real shared
+// The following test requires Mutex::lock_shared to be a real shared
 // lock, which is not the case in all builds.
 #if !defined(ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE)
 
@@ -776,9 +778,9 @@
 // L >= mu, L < mu_waiting_on_cond
 static bool IsCond(void *v) {
   ReaderDecrementBugStruct *x = reinterpret_cast<ReaderDecrementBugStruct *>(v);
-  x->mu2.Lock();
+  x->mu2.lock();
   x->waiting_on_cond = true;
-  x->mu2.Unlock();
+  x->mu2.unlock();
   return x->cond;
 }
 
@@ -791,23 +793,23 @@
 // L={}
 static void WaitForCond(ReaderDecrementBugStruct *x) {
   absl::Mutex dummy;
-  absl::MutexLock l(&dummy);
+  absl::MutexLock l(dummy);
   x->mu.LockWhen(absl::Condition(&IsCond, x));
   x->done--;
-  x->mu.Unlock();
+  x->mu.unlock();
 }
 
 // L={}
 static void GetReadLock(ReaderDecrementBugStruct *x) {
-  x->mu.ReaderLock();
-  x->mu2.Lock();
+  x->mu.lock_shared();
+  x->mu2.lock();
   x->have_reader_lock = true;
   x->mu2.Await(absl::Condition(&x->complete));
-  x->mu2.Unlock();
-  x->mu.ReaderUnlock();
-  x->mu.Lock();
+  x->mu2.unlock();
+  x->mu.unlock_shared();
+  x->mu.lock();
   x->done--;
-  x->mu.Unlock();
+  x->mu.unlock();
 }
 
 // Test for reader counter being decremented incorrectly by waiter
@@ -823,32 +825,32 @@
   // Run WaitForCond() and wait for it to sleep
   std::thread thread1(WaitForCond, &x);
   x.mu2.LockWhen(absl::Condition(&x.waiting_on_cond));
-  x.mu2.Unlock();
+  x.mu2.unlock();
 
   // Run GetReadLock(), and wait for it to get the read lock
   std::thread thread2(GetReadLock, &x);
   x.mu2.LockWhen(absl::Condition(&x.have_reader_lock));
-  x.mu2.Unlock();
+  x.mu2.unlock();
 
   // Get the reader lock ourselves, and release it.
-  x.mu.ReaderLock();
-  x.mu.ReaderUnlock();
+  x.mu.lock_shared();
+  x.mu.unlock_shared();
 
   // The lock should be held in read mode by GetReadLock().
   // If we have the bug, the lock will be free.
   x.mu.AssertReaderHeld();
 
   // Wake up all the threads.
-  x.mu2.Lock();
+  x.mu2.lock();
   x.complete = true;
-  x.mu2.Unlock();
+  x.mu2.unlock();
 
   // TODO(delesley): turn on analysis once lock upgrading is supported.
   // (This call upgrades the lock from shared to exclusive.)
-  x.mu.Lock();
+  x.mu.lock();
   x.cond = true;
   x.mu.Await(absl::Condition(&AllDone, &x));
-  x.mu.Unlock();
+  x.mu.unlock();
 
   thread1.join();
   thread2.join();
@@ -869,9 +871,9 @@
     auto mu = absl::make_unique<absl::Mutex[]>(kNumLocks);
     for (int j = 0; j != kNumLocks; j++) {
       if ((j % 2) == 0) {
-        mu[j].WriterLock();
+        mu[j].lock();
       } else {
-        mu[j].ReaderLock();
+        mu[j].lock_shared();
       }
     }
   }
@@ -1067,15 +1069,15 @@
                                      int *running) {
   absl::InsecureBitGen gen;
   std::uniform_int_distribution<int> random_millis(0, 15);
-  mu->ReaderLock();
+  mu->lock_shared();
   while (*running == 3) {
     absl::SleepFor(absl::Milliseconds(random_millis(gen)));
     cv->WaitWithTimeout(mu, absl::Milliseconds(random_millis(gen)));
   }
-  mu->ReaderUnlock();
-  mu->Lock();
+  mu->unlock_shared();
+  mu->lock();
   (*running)--;
-  mu->Unlock();
+  mu->unlock();
 }
 
 static bool IntIsZero(int *x) { return *x == 0; }
@@ -1090,10 +1092,10 @@
   tp->Schedule(std::bind(&ReaderForReaderOnCondVar, &mu, &cv, &running));
   tp->Schedule(std::bind(&ReaderForReaderOnCondVar, &mu, &cv, &running));
   absl::SleepFor(absl::Seconds(2));
-  mu.Lock();
+  mu.lock();
   running--;
   mu.Await(absl::Condition(&IntIsZero, &running));
-  mu.Unlock();
+  mu.unlock();
 }
 
 // --------------------------------------------------------
@@ -1117,7 +1119,7 @@
     bool always_false = false;
     x->mu1.LockWhenWithTimeout(absl::Condition(&always_false),
                                absl::Milliseconds(100));
-    x->mu1.Unlock();
+    x->mu1.unlock();
   }
   CHECK_LT(x->value, 4) << "should not be invoked a fourth time";
 
@@ -1129,7 +1131,7 @@
   // wait for cond0 to become true
   x->mu0.LockWhen(absl::Condition(&ConditionWithAcquire, x));
   x->done = true;
-  x->mu0.Unlock();
+  x->mu0.unlock();
 }
 
 // Test for Condition whose function acquires other Mutexes
@@ -1145,12 +1147,12 @@
   // return false.
   absl::SleepFor(absl::Milliseconds(500));  // allow T time to hang
 
-  x.mu0.Lock();
+  x.mu0.lock();
   x.cv.WaitWithTimeout(&x.mu0, absl::Milliseconds(500));  // wake T
   // T will be woken because the Wait() will call ConditionWithAcquire()
   // for the second time, and it will return true.
 
-  x.mu0.Unlock();
+  x.mu0.unlock();
 
   // T will then acquire the lock and recheck its own condition.
   // It will find the condition true, as this is the third invocation,
@@ -1166,7 +1168,7 @@
   // is conceptually waiting both on the condition variable, and on mu2.
 
   x.mu0.LockWhen(absl::Condition(&x.done));
-  x.mu0.Unlock();
+  x.mu0.unlock();
 }
 
 TEST(Mutex, DeadlockDetector) {
@@ -1178,20 +1180,20 @@
   absl::Mutex m3;
   absl::Mutex m4;
 
-  m1.Lock();  // m1 gets ID1
-  m2.Lock();  // m2 gets ID2
-  m3.Lock();  // m3 gets ID3
-  m3.Unlock();
-  m2.Unlock();
+  m1.lock();  // m1 gets ID1
+  m2.lock();  // m2 gets ID2
+  m3.lock();  // m3 gets ID3
+  m3.unlock();
+  m2.unlock();
   // m1 still held
   m1.ForgetDeadlockInfo();  // m1 loses ID
-  m2.Lock();                // m2 gets ID2
-  m3.Lock();                // m3 gets ID3
-  m4.Lock();                // m4 gets ID4
-  m3.Unlock();
-  m2.Unlock();
-  m4.Unlock();
-  m1.Unlock();
+  m2.lock();                // m2 gets ID2
+  m3.lock();                // m3 gets ID3
+  m4.lock();                // m4 gets ID4
+  m3.unlock();
+  m2.unlock();
+  m4.unlock();
+  m1.unlock();
 }
 
 // Bazel has a test "warning" file that programs can write to if the
@@ -1246,18 +1248,18 @@
 
   absl::Mutex mu0;
   absl::Mutex mu1;
-  bool got_mu0 = mu0.TryLock();
-  mu1.Lock();  // acquire mu1 while holding mu0
+  bool got_mu0 = mu0.try_lock();
+  mu1.lock();  // acquire mu1 while holding mu0
   if (got_mu0) {
-    mu0.Unlock();
+    mu0.unlock();
   }
-  if (mu0.TryLock()) {  // try lock shouldn't cause deadlock detector to fire
-    mu0.Unlock();
+  if (mu0.try_lock()) {  // try lock shouldn't cause deadlock detector to fire
+    mu0.unlock();
   }
-  mu0.Lock();  // acquire mu0 while holding mu1; should get one deadlock
+  mu0.lock();  // acquire mu0 while holding mu1; should get one deadlock
                // report here
-  mu0.Unlock();
-  mu1.Unlock();
+  mu0.unlock();
+  mu1.unlock();
 
   absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);
 }
@@ -1272,10 +1274,10 @@
   // Check that we survive a deadlock with a lock cycle.
   std::vector<absl::Mutex> mutex(100);
   for (size_t i = 0; i != mutex.size(); i++) {
-    mutex[i].Lock();
-    mutex[(i + 1) % mutex.size()].Lock();
-    mutex[i].Unlock();
-    mutex[(i + 1) % mutex.size()].Unlock();
+    mutex[i].lock();
+    mutex[(i + 1) % mutex.size()].lock();
+    mutex[i].unlock();
+    mutex[(i + 1) % mutex.size()].unlock();
   }
 
   absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);
@@ -1295,10 +1297,10 @@
     int end = std::min(n_locks, i + 5);
     // acquire and then release locks i, i+1, ..., i+4
     for (int j = i; j < end; j++) {
-      array_of_locks[j].Lock();
+      array_of_locks[j].lock();
     }
     for (int j = i; j < end; j++) {
-      array_of_locks[j].Unlock();
+      array_of_locks[j].unlock();
     }
   }
 }
@@ -1319,11 +1321,11 @@
   absl::Mutex b, c;
 
   // Hold mutex.
-  a->Lock();
+  a->lock();
 
   // Force deadlock id assignment by acquiring another lock.
-  b.Lock();
-  b.Unlock();
+  b.lock();
+  b.unlock();
 
   // Delete the mutex. The Mutex destructor tries to remove held locks,
   // but the attempt isn't foolproof.  It can fail if:
@@ -1338,8 +1340,8 @@
   // We should end up getting assigned the same deadlock id that was
   // freed up when "a" was deleted, which will cause a spurious deadlock
   // report if the held lock entry for "a" was not invalidated.
-  c.Lock();
-  c.Unlock();
+  c.lock();
+  c.unlock();
 }
 
 // --------------------------------------------------------
@@ -1574,11 +1576,11 @@
     std::unique_ptr<absl::synchronization_internal::ThreadPool> pool =
         CreateDefaultPool();
     RunAfterDelay(params.satisfy_condition_delay, pool.get(), [&] {
-      absl::MutexLock l(&mu);
+      absl::MutexLock l(mu);
       value = true;
     });
 
-    absl::MutexLock lock(&mu);
+    absl::MutexLock lock(mu);
     absl::Time start_time = absl::Now();
     absl::Condition cond(&value);
     bool result =
@@ -1608,7 +1610,7 @@
     std::unique_ptr<absl::synchronization_internal::ThreadPool> pool =
         CreateDefaultPool();
     RunAfterDelay(params.satisfy_condition_delay, pool.get(), [&] {
-      absl::MutexLock l(&mu);
+      absl::MutexLock l(mu);
       value = true;
     });
 
@@ -1618,7 +1620,7 @@
         params.use_absolute_deadline
             ? mu.LockWhenWithDeadline(cond, start_time + params.wait_timeout)
             : mu.LockWhenWithTimeout(cond, params.wait_timeout);
-    mu.Unlock();
+    mu.unlock();
 
     if (DelayIsWithinBounds(params.expected_delay, absl::Now() - start_time)) {
       EXPECT_EQ(params.expected_result, result);
@@ -1643,7 +1645,7 @@
     std::unique_ptr<absl::synchronization_internal::ThreadPool> pool =
         CreateDefaultPool();
     RunAfterDelay(params.satisfy_condition_delay, pool.get(), [&] {
-      absl::MutexLock l(&mu);
+      absl::MutexLock l(mu);
       value = true;
     });
 
@@ -1654,7 +1656,7 @@
                                             start_time + params.wait_timeout)
             : mu.ReaderLockWhenWithTimeout(absl::Condition(&value),
                                            params.wait_timeout);
-    mu.ReaderUnlock();
+    mu.unlock_shared();
 
     if (DelayIsWithinBounds(params.expected_delay, absl::Now() - start_time)) {
       EXPECT_EQ(params.expected_result, result);
@@ -1680,12 +1682,12 @@
     std::unique_ptr<absl::synchronization_internal::ThreadPool> pool =
         CreateDefaultPool();
     RunAfterDelay(params.satisfy_condition_delay, pool.get(), [&] {
-      absl::MutexLock l(&mu);
+      absl::MutexLock l(mu);
       value = true;
       cv.Signal();
     });
 
-    absl::MutexLock lock(&mu);
+    absl::MutexLock lock(mu);
     absl::Time start_time = absl::Now();
     absl::Duration timeout = params.wait_timeout;
     absl::Time deadline = start_time + timeout;
@@ -1711,13 +1713,13 @@
   logged_mutex.EnableDebugLog("fido_mutex");
   absl::CondVar logged_cv;
   logged_cv.EnableDebugLog("rover_cv");
-  logged_mutex.Lock();
+  logged_mutex.lock();
   logged_cv.WaitWithTimeout(&logged_mutex, absl::Milliseconds(20));
-  logged_mutex.Unlock();
-  logged_mutex.ReaderLock();
-  logged_mutex.ReaderUnlock();
-  logged_mutex.Lock();
-  logged_mutex.Unlock();
+  logged_mutex.unlock();
+  logged_mutex.lock_shared();
+  logged_mutex.unlock_shared();
+  logged_mutex.lock();
+  logged_mutex.unlock();
   logged_cv.Signal();
   logged_cv.SignalAll();
 }
@@ -1735,8 +1737,8 @@
     alive[i] = true;
     mu->EnableDebugLog("Mutex");
     mu->EnableInvariantDebugging(invariant, &alive[i]);
-    mu->Lock();
-    mu->Unlock();
+    mu->lock();
+    mu->unlock();
     mu->~Mutex();
     alive[i] = false;
   }
@@ -1762,8 +1764,8 @@
         {
           absl::Mutex mu;
           mu.EnableInvariantDebugging([](void *) {}, nullptr);
-          mu.Lock();
-          mu.Unlock();
+          mu.lock();
+          mu.unlock();
         }
         {
           absl::Mutex mu;
@@ -1900,7 +1902,7 @@
 }
 
 TEST(Mutex, SignalExitedThread) {
-  // The test may expose a race when Mutex::Unlock signals a thread
+  // The test may expose a race when Mutex::unlock signals a thread
   // that has already exited.
 #if defined(__wasm__) || defined(__asmjs__)
   constexpr int kThreads = 1;  // OOMs under WASM
@@ -1913,11 +1915,11 @@
       for (int i = 0; i < kThreads; i++) {
         absl::Mutex mu;
         std::thread t([&]() {
-          mu.Lock();
-          mu.Unlock();
+          mu.lock();
+          mu.unlock();
         });
-        mu.Lock();
-        mu.Unlock();
+        mu.lock();
+        mu.unlock();
         t.join();
       }
     });
@@ -1931,7 +1933,7 @@
   std::atomic<bool> saw_wrote{false};
   auto readfunc = [&]() {
     for (size_t i = 0; i < 10; ++i) {
-      absl::ReaderMutexLock lock(&mu);
+      absl::ReaderMutexLock lock(mu);
       if (wrote) {
         saw_wrote = true;
         break;
@@ -1946,7 +1948,7 @@
   // PerThreadSynch::priority, so the writer intentionally runs on a new thread.
   std::thread t3([&]() {
     // The writer should be able squeeze between the two alternating readers.
-    absl::MutexLock lock(&mu);
+    absl::MutexLock lock(mu);
     wrote = true;
   });
   t1.join();
@@ -1978,30 +1980,30 @@
   bool morph = false;
   std::thread th([&]() {
     EXPECT_EQ(0, pthread_setschedparam(pthread_self(), SCHED_FIFO, &param));
-    mu.Lock();
+    mu.lock();
     locked = true;
     mu.Await(absl::Condition(&notified));
-    mu.Unlock();
+    mu.unlock();
     EXPECT_EQ(absl::synchronization_internal::GetOrCreateCurrentThreadIdentity()
                   ->per_thread_synch.priority,
               param.sched_priority);
-    mu.Lock();
+    mu.lock();
     mu.Await(absl::Condition(&waiting));
     morph = true;
     absl::SleepFor(absl::Seconds(1));
     cv.Signal();
-    mu.Unlock();
+    mu.unlock();
   });
-  mu.Lock();
+  mu.lock();
   mu.Await(absl::Condition(&locked));
   notified = true;
-  mu.Unlock();
-  mu.Lock();
+  mu.unlock();
+  mu.lock();
   waiting = true;
   while (!morph) {
     cv.Wait(&mu);
   }
-  mu.Unlock();
+  mu.unlock();
   th.join();
   EXPECT_NE(absl::synchronization_internal::GetOrCreateCurrentThreadIdentity()
                 ->per_thread_synch.priority,
@@ -2016,22 +2018,34 @@
   const bool kAlwaysTrue = true, kAlwaysFalse = false;
   const absl::Condition kTrueCond(&kAlwaysTrue), kFalseCond(&kAlwaysFalse);
   EXPECT_TRUE(mu.LockWhenWithTimeout(kTrueCond, absl::Milliseconds(1)));
-  mu.Unlock();
+  mu.unlock();
   EXPECT_FALSE(mu.LockWhenWithTimeout(kFalseCond, absl::Milliseconds(1)));
   EXPECT_TRUE(mu.AwaitWithTimeout(kTrueCond, absl::Milliseconds(1)));
   EXPECT_FALSE(mu.AwaitWithTimeout(kFalseCond, absl::Milliseconds(1)));
   std::thread th1([&]() {
     EXPECT_TRUE(mu.LockWhenWithTimeout(kTrueCond, absl::Milliseconds(1)));
-    mu.Unlock();
+    mu.unlock();
   });
   std::thread th2([&]() {
     EXPECT_FALSE(mu.LockWhenWithTimeout(kFalseCond, absl::Milliseconds(1)));
-    mu.Unlock();
+    mu.unlock();
   });
   absl::SleepFor(absl::Milliseconds(100));
-  mu.Unlock();
+  mu.unlock();
   th1.join();
   th2.join();
 }
 
+TEST(Mutex, ScopedLock) {
+  absl::Mutex mu;
+  {
+    std::scoped_lock l(mu);
+  }
+
+  {
+    std::shared_lock l(mu);
+    EXPECT_TRUE(l.owns_lock());
+  }
+}
+
 }  // namespace
diff --git a/absl/synchronization/notification.cc b/absl/synchronization/notification.cc
index a5853ab..a890c1b 100644
--- a/absl/synchronization/notification.cc
+++ b/absl/synchronization/notification.cc
@@ -26,7 +26,7 @@
 
 void Notification::Notify() {
   base_internal::TraceSignal(this, TraceObjectKind());
-  MutexLock l(&this->mutex_);
+  MutexLock l(this->mutex_);
 
 #ifndef NDEBUG
   if (ABSL_PREDICT_FALSE(notified_yet_.load(std::memory_order_relaxed))) {
@@ -43,7 +43,7 @@
 Notification::~Notification() {
   // Make sure that the thread running Notify() exits before the object is
   // destructed.
-  MutexLock l(&this->mutex_);
+  MutexLock l(this->mutex_);
 }
 
 void Notification::WaitForNotification() const {
@@ -51,7 +51,7 @@
   if (!HasBeenNotifiedInternal(&this->notified_yet_)) {
     this->mutex_.LockWhen(
         Condition(&HasBeenNotifiedInternal, &this->notified_yet_));
-    this->mutex_.Unlock();
+    this->mutex_.unlock();
   }
   base_internal::TraceContinue(this, TraceObjectKind());
 }
@@ -63,7 +63,7 @@
   if (!notified) {
     notified = this->mutex_.LockWhenWithTimeout(
         Condition(&HasBeenNotifiedInternal, &this->notified_yet_), timeout);
-    this->mutex_.Unlock();
+    this->mutex_.unlock();
   }
   base_internal::TraceContinue(notified ? this : nullptr, TraceObjectKind());
   return notified;
@@ -75,7 +75,7 @@
   if (!notified) {
     notified = this->mutex_.LockWhenWithDeadline(
         Condition(&HasBeenNotifiedInternal, &this->notified_yet_), deadline);
-    this->mutex_.Unlock();
+    this->mutex_.unlock();
   }
   base_internal::TraceContinue(notified ? this : nullptr, TraceObjectKind());
   return notified;
diff --git a/absl/synchronization/notification.h b/absl/synchronization/notification.h
index 1ceffdb..12df31b 100644
--- a/absl/synchronization/notification.h
+++ b/absl/synchronization/notification.h
@@ -52,7 +52,7 @@
 
 #include <atomic>
 
-#include "absl/base/attributes.h"
+#include "absl/base/config.h"
 #include "absl/base/internal/tracing.h"
 #include "absl/synchronization/mutex.h"
 #include "absl/time/time.h"
diff --git a/absl/synchronization/notification_test.cc b/absl/synchronization/notification_test.cc
index eedad17..ac5dccd 100644
--- a/absl/synchronization/notification_test.cc
+++ b/absl/synchronization/notification_test.cc
@@ -34,17 +34,17 @@
   ThreadSafeCounter() : count_(0) {}
 
   void Increment() {
-    MutexLock lock(&mutex_);
+    MutexLock lock(mutex_);
     ++count_;
   }
 
   int Get() const {
-    MutexLock lock(&mutex_);
+    MutexLock lock(mutex_);
     return count_;
   }
 
   void WaitUntilGreaterOrEqual(int n) {
-    MutexLock lock(&mutex_);
+    MutexLock lock(mutex_);
     auto cond = [this, n]() { return count_ >= n; };
     mutex_.Await(Condition(&cond));
   }
diff --git a/absl/time/BUILD.bazel b/absl/time/BUILD.bazel
index ad0313c..b68dd85 100644
--- a/absl/time/BUILD.bazel
+++ b/absl/time/BUILD.bazel
@@ -14,6 +14,9 @@
 # limitations under the License.
 #
 
+load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
@@ -118,6 +121,7 @@
         "no_test_android_arm",
         "no_test_android_arm64",
         "no_test_android_x86",
+        "no_test_ios_sim_arm64",
         "no_test_ios_x86_64",
         "no_test_lexan",
         "no_test_loonix",
diff --git a/absl/time/CMakeLists.txt b/absl/time/CMakeLists.txt
index ea91ba3..34a5ad4 100644
--- a/absl/time/CMakeLists.txt
+++ b/absl/time/CMakeLists.txt
@@ -77,6 +77,8 @@
     "internal/cctz/src/time_zone_posix.h"
     "internal/cctz/src/tzfile.h"
     "internal/cctz/src/zone_info_source.cc"
+    $<$<PLATFORM_ID:Windows>:internal/cctz/src/time_zone_name_win.cc>
+    $<$<PLATFORM_ID:Windows>:internal/cctz/src/time_zone_name_win.h>
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
diff --git a/absl/time/civil_time_benchmark.cc b/absl/time/civil_time_benchmark.cc
index 2de0233..2818a90 100644
--- a/absl/time/civil_time_benchmark.cc
+++ b/absl/time/civil_time_benchmark.cc
@@ -12,14 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "absl/time/civil_time.h"
-
 #include <cstddef>
 #include <numeric>
 #include <string>
 #include <vector>
 
 #include "absl/hash/hash.h"
+#include "absl/time/civil_time.h"
 #include "benchmark/benchmark.h"
 
 namespace {
diff --git a/absl/time/civil_time_test.cc b/absl/time/civil_time_test.cc
index 6e5c35d..a0cb29c 100644
--- a/absl/time/civil_time_test.cc
+++ b/absl/time/civil_time_test.cc
@@ -78,8 +78,7 @@
             absl::FormatCivilTime(absl::CivilMinute(2015, 1, 2)));
   EXPECT_EQ("2015-01-01T00:00",
             absl::FormatCivilTime(absl::CivilMinute(2015, 1)));
-  EXPECT_EQ("2015-01-01T00:00",
-            absl::FormatCivilTime(absl::CivilMinute(2015)));
+  EXPECT_EQ("2015-01-01T00:00", absl::FormatCivilTime(absl::CivilMinute(2015)));
 
   EXPECT_EQ("2015-01-02T03",
             absl::FormatCivilTime(absl::CivilHour(2015, 1, 2, 3, 4, 5)));
@@ -89,82 +88,63 @@
             absl::FormatCivilTime(absl::CivilHour(2015, 1, 2, 3)));
   EXPECT_EQ("2015-01-02T00",
             absl::FormatCivilTime(absl::CivilHour(2015, 1, 2)));
-  EXPECT_EQ("2015-01-01T00",
-            absl::FormatCivilTime(absl::CivilHour(2015, 1)));
-  EXPECT_EQ("2015-01-01T00",
-            absl::FormatCivilTime(absl::CivilHour(2015)));
+  EXPECT_EQ("2015-01-01T00", absl::FormatCivilTime(absl::CivilHour(2015, 1)));
+  EXPECT_EQ("2015-01-01T00", absl::FormatCivilTime(absl::CivilHour(2015)));
 
   EXPECT_EQ("2015-01-02",
             absl::FormatCivilTime(absl::CivilDay(2015, 1, 2, 3, 4, 5)));
   EXPECT_EQ("2015-01-02",
             absl::FormatCivilTime(absl::CivilDay(2015, 1, 2, 3, 4)));
-  EXPECT_EQ("2015-01-02",
-            absl::FormatCivilTime(absl::CivilDay(2015, 1, 2, 3)));
-  EXPECT_EQ("2015-01-02",
-            absl::FormatCivilTime(absl::CivilDay(2015, 1, 2)));
-  EXPECT_EQ("2015-01-01",
-            absl::FormatCivilTime(absl::CivilDay(2015, 1)));
-  EXPECT_EQ("2015-01-01",
-            absl::FormatCivilTime(absl::CivilDay(2015)));
+  EXPECT_EQ("2015-01-02", absl::FormatCivilTime(absl::CivilDay(2015, 1, 2, 3)));
+  EXPECT_EQ("2015-01-02", absl::FormatCivilTime(absl::CivilDay(2015, 1, 2)));
+  EXPECT_EQ("2015-01-01", absl::FormatCivilTime(absl::CivilDay(2015, 1)));
+  EXPECT_EQ("2015-01-01", absl::FormatCivilTime(absl::CivilDay(2015)));
 
   EXPECT_EQ("2015-01",
             absl::FormatCivilTime(absl::CivilMonth(2015, 1, 2, 3, 4, 5)));
   EXPECT_EQ("2015-01",
             absl::FormatCivilTime(absl::CivilMonth(2015, 1, 2, 3, 4)));
-  EXPECT_EQ("2015-01",
-            absl::FormatCivilTime(absl::CivilMonth(2015, 1, 2, 3)));
-  EXPECT_EQ("2015-01",
-            absl::FormatCivilTime(absl::CivilMonth(2015, 1, 2)));
-  EXPECT_EQ("2015-01",
-            absl::FormatCivilTime(absl::CivilMonth(2015, 1)));
-  EXPECT_EQ("2015-01",
-            absl::FormatCivilTime(absl::CivilMonth(2015)));
+  EXPECT_EQ("2015-01", absl::FormatCivilTime(absl::CivilMonth(2015, 1, 2, 3)));
+  EXPECT_EQ("2015-01", absl::FormatCivilTime(absl::CivilMonth(2015, 1, 2)));
+  EXPECT_EQ("2015-01", absl::FormatCivilTime(absl::CivilMonth(2015, 1)));
+  EXPECT_EQ("2015-01", absl::FormatCivilTime(absl::CivilMonth(2015)));
 
   EXPECT_EQ("2015",
             absl::FormatCivilTime(absl::CivilYear(2015, 1, 2, 3, 4, 5)));
-  EXPECT_EQ("2015",
-            absl::FormatCivilTime(absl::CivilYear(2015, 1, 2, 3, 4)));
-  EXPECT_EQ("2015",
-            absl::FormatCivilTime(absl::CivilYear(2015, 1, 2, 3)));
-  EXPECT_EQ("2015",
-            absl::FormatCivilTime(absl::CivilYear(2015, 1, 2)));
-  EXPECT_EQ("2015",
-            absl::FormatCivilTime(absl::CivilYear(2015, 1)));
-  EXPECT_EQ("2015",
-            absl::FormatCivilTime(absl::CivilYear(2015)));
+  EXPECT_EQ("2015", absl::FormatCivilTime(absl::CivilYear(2015, 1, 2, 3, 4)));
+  EXPECT_EQ("2015", absl::FormatCivilTime(absl::CivilYear(2015, 1, 2, 3)));
+  EXPECT_EQ("2015", absl::FormatCivilTime(absl::CivilYear(2015, 1, 2)));
+  EXPECT_EQ("2015", absl::FormatCivilTime(absl::CivilYear(2015, 1)));
+  EXPECT_EQ("2015", absl::FormatCivilTime(absl::CivilYear(2015)));
 }
 
 TEST(CivilTime, FieldsConstructionLimits) {
   const int kIntMax = std::numeric_limits<int>::max();
-  EXPECT_EQ("2038-01-19T03:14:07",
-            absl::FormatCivilTime(absl::CivilSecond(
-                1970, 1, 1, 0, 0, kIntMax)));
-  EXPECT_EQ("6121-02-11T05:21:07",
-            absl::FormatCivilTime(absl::CivilSecond(
-                1970, 1, 1, 0, kIntMax, kIntMax)));
+  EXPECT_EQ("2038-01-19T03:14:07", absl::FormatCivilTime(absl::CivilSecond(
+                                       1970, 1, 1, 0, 0, kIntMax)));
+  EXPECT_EQ("6121-02-11T05:21:07", absl::FormatCivilTime(absl::CivilSecond(
+                                       1970, 1, 1, 0, kIntMax, kIntMax)));
   EXPECT_EQ("251104-11-20T12:21:07",
-            absl::FormatCivilTime(absl::CivilSecond(
-                1970, 1, 1, kIntMax, kIntMax, kIntMax)));
+            absl::FormatCivilTime(
+                absl::CivilSecond(1970, 1, 1, kIntMax, kIntMax, kIntMax)));
   EXPECT_EQ("6130715-05-30T12:21:07",
-            absl::FormatCivilTime(absl::CivilSecond(
-                1970, 1, kIntMax, kIntMax, kIntMax, kIntMax)));
+            absl::FormatCivilTime(absl::CivilSecond(1970, 1, kIntMax, kIntMax,
+                                                    kIntMax, kIntMax)));
   EXPECT_EQ("185087685-11-26T12:21:07",
             absl::FormatCivilTime(absl::CivilSecond(
                 1970, kIntMax, kIntMax, kIntMax, kIntMax, kIntMax)));
 
   const int kIntMin = std::numeric_limits<int>::min();
-  EXPECT_EQ("1901-12-13T20:45:52",
-            absl::FormatCivilTime(absl::CivilSecond(
-                1970, 1, 1, 0, 0, kIntMin)));
-  EXPECT_EQ("-2182-11-20T18:37:52",
-            absl::FormatCivilTime(absl::CivilSecond(
-                1970, 1, 1, 0, kIntMin, kIntMin)));
+  EXPECT_EQ("1901-12-13T20:45:52", absl::FormatCivilTime(absl::CivilSecond(
+                                       1970, 1, 1, 0, 0, kIntMin)));
+  EXPECT_EQ("-2182-11-20T18:37:52", absl::FormatCivilTime(absl::CivilSecond(
+                                        1970, 1, 1, 0, kIntMin, kIntMin)));
   EXPECT_EQ("-247165-02-11T10:37:52",
-            absl::FormatCivilTime(absl::CivilSecond(
-                1970, 1, 1, kIntMin, kIntMin, kIntMin)));
+            absl::FormatCivilTime(
+                absl::CivilSecond(1970, 1, 1, kIntMin, kIntMin, kIntMin)));
   EXPECT_EQ("-6126776-08-01T10:37:52",
-            absl::FormatCivilTime(absl::CivilSecond(
-                1970, 1, kIntMin, kIntMin, kIntMin, kIntMin)));
+            absl::FormatCivilTime(absl::CivilSecond(1970, 1, kIntMin, kIntMin,
+                                                    kIntMin, kIntMin)));
   EXPECT_EQ("-185083747-10-31T10:37:52",
             absl::FormatCivilTime(absl::CivilSecond(
                 1970, kIntMin, kIntMin, kIntMin, kIntMin, kIntMin)));
@@ -173,14 +153,10 @@
 TEST(CivilTime, RangeLimits) {
   const absl::civil_year_t kYearMax =
       std::numeric_limits<absl::civil_year_t>::max();
-  EXPECT_EQ(absl::CivilYear(kYearMax),
-            absl::CivilYear::max());
-  EXPECT_EQ(absl::CivilMonth(kYearMax, 12),
-            absl::CivilMonth::max());
-  EXPECT_EQ(absl::CivilDay(kYearMax, 12, 31),
-            absl::CivilDay::max());
-  EXPECT_EQ(absl::CivilHour(kYearMax, 12, 31, 23),
-            absl::CivilHour::max());
+  EXPECT_EQ(absl::CivilYear(kYearMax), absl::CivilYear::max());
+  EXPECT_EQ(absl::CivilMonth(kYearMax, 12), absl::CivilMonth::max());
+  EXPECT_EQ(absl::CivilDay(kYearMax, 12, 31), absl::CivilDay::max());
+  EXPECT_EQ(absl::CivilHour(kYearMax, 12, 31, 23), absl::CivilHour::max());
   EXPECT_EQ(absl::CivilMinute(kYearMax, 12, 31, 23, 59),
             absl::CivilMinute::max());
   EXPECT_EQ(absl::CivilSecond(kYearMax, 12, 31, 23, 59, 59),
@@ -188,16 +164,11 @@
 
   const absl::civil_year_t kYearMin =
       std::numeric_limits<absl::civil_year_t>::min();
-  EXPECT_EQ(absl::CivilYear(kYearMin),
-            absl::CivilYear::min());
-  EXPECT_EQ(absl::CivilMonth(kYearMin, 1),
-            absl::CivilMonth::min());
-  EXPECT_EQ(absl::CivilDay(kYearMin, 1, 1),
-            absl::CivilDay::min());
-  EXPECT_EQ(absl::CivilHour(kYearMin, 1, 1, 0),
-            absl::CivilHour::min());
-  EXPECT_EQ(absl::CivilMinute(kYearMin, 1, 1, 0, 0),
-            absl::CivilMinute::min());
+  EXPECT_EQ(absl::CivilYear(kYearMin), absl::CivilYear::min());
+  EXPECT_EQ(absl::CivilMonth(kYearMin, 1), absl::CivilMonth::min());
+  EXPECT_EQ(absl::CivilDay(kYearMin, 1, 1), absl::CivilDay::min());
+  EXPECT_EQ(absl::CivilHour(kYearMin, 1, 1, 0), absl::CivilHour::min());
+  EXPECT_EQ(absl::CivilMinute(kYearMin, 1, 1, 0, 0), absl::CivilMinute::min());
   EXPECT_EQ(absl::CivilSecond(kYearMin, 1, 1, 0, 0, 0),
             absl::CivilSecond::min());
 }
@@ -250,8 +221,7 @@
       (std::is_convertible<absl::CivilSecond, absl::CivilMinute>::value));
   EXPECT_FALSE(
       (std::is_convertible<absl::CivilSecond, absl::CivilHour>::value));
-  EXPECT_FALSE(
-      (std::is_convertible<absl::CivilSecond, absl::CivilDay>::value));
+  EXPECT_FALSE((std::is_convertible<absl::CivilSecond, absl::CivilDay>::value));
   EXPECT_FALSE(
       (std::is_convertible<absl::CivilSecond, absl::CivilMonth>::value));
   EXPECT_FALSE(
@@ -259,27 +229,20 @@
 
   EXPECT_FALSE(
       (std::is_convertible<absl::CivilMinute, absl::CivilHour>::value));
-  EXPECT_FALSE(
-      (std::is_convertible<absl::CivilMinute, absl::CivilDay>::value));
+  EXPECT_FALSE((std::is_convertible<absl::CivilMinute, absl::CivilDay>::value));
   EXPECT_FALSE(
       (std::is_convertible<absl::CivilMinute, absl::CivilMonth>::value));
   EXPECT_FALSE(
       (std::is_convertible<absl::CivilMinute, absl::CivilYear>::value));
 
-  EXPECT_FALSE(
-      (std::is_convertible<absl::CivilHour, absl::CivilDay>::value));
-  EXPECT_FALSE(
-      (std::is_convertible<absl::CivilHour, absl::CivilMonth>::value));
-  EXPECT_FALSE(
-      (std::is_convertible<absl::CivilHour, absl::CivilYear>::value));
+  EXPECT_FALSE((std::is_convertible<absl::CivilHour, absl::CivilDay>::value));
+  EXPECT_FALSE((std::is_convertible<absl::CivilHour, absl::CivilMonth>::value));
+  EXPECT_FALSE((std::is_convertible<absl::CivilHour, absl::CivilYear>::value));
 
-  EXPECT_FALSE(
-      (std::is_convertible<absl::CivilDay, absl::CivilMonth>::value));
-  EXPECT_FALSE(
-      (std::is_convertible<absl::CivilDay, absl::CivilYear>::value));
+  EXPECT_FALSE((std::is_convertible<absl::CivilDay, absl::CivilMonth>::value));
+  EXPECT_FALSE((std::is_convertible<absl::CivilDay, absl::CivilYear>::value));
 
-  EXPECT_FALSE(
-      (std::is_convertible<absl::CivilMonth, absl::CivilYear>::value));
+  EXPECT_FALSE((std::is_convertible<absl::CivilMonth, absl::CivilYear>::value));
 }
 
 TEST(CivilTime, ExplicitCrossAlignment) {
@@ -417,8 +380,7 @@
   // Tests the relational operators of two different civil-time types.
   TEST_RELATIONAL(absl::CivilDay(2014, 1, 1),
                   absl::CivilMinute(2014, 1, 1, 1, 1));
-  TEST_RELATIONAL(absl::CivilDay(2014, 1, 1),
-                  absl::CivilMonth(2014, 2));
+  TEST_RELATIONAL(absl::CivilDay(2014, 1, 1), absl::CivilMonth(2014, 2));
 
 #undef TEST_RELATIONAL
 }
@@ -812,8 +774,7 @@
   EXPECT_EQ("-9223372036854775808-01-01T00:00", absl::FormatCivilTime(mm));
 
   absl::CivilHour hh;
-  EXPECT_TRUE(
-      absl::ParseLenientCivilTime("9223372036854775807-12-31T23", &hh));
+  EXPECT_TRUE(absl::ParseLenientCivilTime("9223372036854775807-12-31T23", &hh));
   EXPECT_EQ("9223372036854775807-12-31T23", absl::FormatCivilTime(hh));
   EXPECT_TRUE(
       absl::ParseLenientCivilTime("-9223372036854775808-01-01T00", &hh));
@@ -1181,19 +1142,13 @@
       int day;
     } leap_day;  // The date of the day after Feb 28.
   } kLeapYearTable[]{
-      {1900, 365, {3, 1}},
-      {1999, 365, {3, 1}},
+      {1900, 365, {3, 1}},  {1999, 365, {3, 1}},
       {2000, 366, {2, 29}},  // leap year
-      {2001, 365, {3, 1}},
-      {2002, 365, {3, 1}},
-      {2003, 365, {3, 1}},
-      {2004, 366, {2, 29}},  // leap year
-      {2005, 365, {3, 1}},
-      {2006, 365, {3, 1}},
-      {2007, 365, {3, 1}},
-      {2008, 366, {2, 29}},  // leap year
-      {2009, 365, {3, 1}},
-      {2100, 365, {3, 1}},
+      {2001, 365, {3, 1}},  {2002, 365, {3, 1}},
+      {2003, 365, {3, 1}},  {2004, 366, {2, 29}},  // leap year
+      {2005, 365, {3, 1}},  {2006, 365, {3, 1}},
+      {2007, 365, {3, 1}},  {2008, 366, {2, 29}},  // leap year
+      {2009, 365, {3, 1}},  {2100, 365, {3, 1}},
   };
 
   for (int i = 0; i < ABSL_ARRAYSIZE(kLeapYearTable); ++i) {
@@ -1223,7 +1178,7 @@
 
   // Bonus: Date of Thanksgiving in the United States
   // Rule: Fourth Thursday of November
-  const absl::CivilDay thanksgiving = thursday +  7 * 3;
+  const absl::CivilDay thanksgiving = thursday + 7 * 3;
   EXPECT_EQ("2014-11-27", absl::FormatCivilTime(thanksgiving));
 }
 
diff --git a/absl/time/clock.cc b/absl/time/clock.cc
index ecd539e..2a5f41b 100644
--- a/absl/time/clock.cc
+++ b/absl/time/clock.cc
@@ -125,7 +125,7 @@
 // spin-delay tuning.
 
 // Acquire seqlock (*seq) and return the value to be written to unlock.
-static inline uint64_t SeqAcquire(std::atomic<uint64_t> *seq) {
+static inline uint64_t SeqAcquire(std::atomic<uint64_t>* seq) {
   uint64_t x = seq->fetch_add(1, std::memory_order_relaxed);
 
   // We put a release fence between update to *seq and writes to shared data.
@@ -135,12 +135,12 @@
   // fetch_add would be before it, not after.
   std::atomic_thread_fence(std::memory_order_release);
 
-  return x + 2;   // original word plus 2
+  return x + 2;  // original word plus 2
 }
 
 // Release seqlock (*seq) by writing x to it---a value previously returned by
 // SeqAcquire.
-static inline void SeqRelease(std::atomic<uint64_t> *seq, uint64_t x) {
+static inline void SeqRelease(std::atomic<uint64_t>* seq, uint64_t x) {
   // The unlock store to *seq must have release ordering so that all
   // updates to shared data must finish before this store.
   seq->store(x, std::memory_order_release);  // release lock for readers
@@ -160,8 +160,8 @@
 // We require that kMinNSBetweenSamples shifted by kScale
 // have at least a bit left over for 64-bit calculations.
 static_assert(((kMinNSBetweenSamples << (kScale + 1)) >> (kScale + 1)) ==
-               kMinNSBetweenSamples,
-               "cannot represent kMaxBetweenSamplesNSScaled");
+                  kMinNSBetweenSamples,
+              "cannot represent kMaxBetweenSamplesNSScaled");
 
 // data from a sample of the kernel's time value
 struct TimeSampleAtomic {
@@ -206,8 +206,7 @@
 
   // A reader-writer lock protecting the static locations below.
   // See SeqAcquire() and SeqRelease() above.
-  absl::base_internal::SpinLock lock{absl::kConstInit,
-                                     base_internal::SCHEDULE_KERNEL_ONLY};
+  absl::base_internal::SpinLock lock{base_internal::SCHEDULE_KERNEL_ONLY};
 };
 ABSL_CONST_INIT static TimeState time_state;
 
@@ -219,7 +218,7 @@
 // assumed to be complete resyncs, which shouldn't happen.  If they do, a full
 // reinitialization of the outer algorithm should occur.)
 static int64_t GetCurrentTimeNanosFromKernel(uint64_t last_cycleclock,
-                                             uint64_t *cycleclock)
+                                             uint64_t* cycleclock)
     ABSL_EXCLUSIVE_LOCKS_REQUIRED(time_state.lock) {
   uint64_t local_approx_syscall_time_in_cycles =  // local copy
       time_state.approx_syscall_time_in_cycles.load(std::memory_order_relaxed);
@@ -275,8 +274,8 @@
 // Read the contents of *atomic into *sample.
 // Each field is read atomically, but to maintain atomicity between fields,
 // the access must be done under a lock.
-static void ReadTimeSampleAtomic(const struct TimeSampleAtomic *atomic,
-                                 struct TimeSample *sample) {
+static void ReadTimeSampleAtomic(const struct TimeSampleAtomic* atomic,
+                                 struct TimeSample* sample) {
   sample->base_ns = atomic->base_ns.load(std::memory_order_relaxed);
   sample->base_cycles = atomic->base_cycles.load(std::memory_order_relaxed);
   sample->nsscaled_per_cycle =
@@ -339,18 +338,20 @@
   // to the same shared data.
   seq_read0 = time_state.seq.load(std::memory_order_acquire);
 
-  base_ns = time_state.last_sample.base_ns.load(std::memory_order_relaxed);
+  // The algorithm does not require that the following four loads be ordered
+  // with respect to one another; it requires only that they precede the load of
+  // time_state.seq below them. Nevertheless, we mark each of them as an
+  // acquire-load, rather than using a barrier immediately before the
+  // time_state.seq load, because the former is likely faster on most CPUs of
+  // interest. Architectures that may see a regression because of this approach
+  // include PowerPC and MIPS.
+  base_ns = time_state.last_sample.base_ns.load(std::memory_order_acquire);
   base_cycles =
-      time_state.last_sample.base_cycles.load(std::memory_order_relaxed);
+      time_state.last_sample.base_cycles.load(std::memory_order_acquire);
   nsscaled_per_cycle =
-      time_state.last_sample.nsscaled_per_cycle.load(std::memory_order_relaxed);
+      time_state.last_sample.nsscaled_per_cycle.load(std::memory_order_acquire);
   min_cycles_per_sample = time_state.last_sample.min_cycles_per_sample.load(
-      std::memory_order_relaxed);
-
-  // This acquire fence pairs with the release fence in SeqAcquire.  Since it
-  // is sequenced between reads of shared data and seq_read1, the reads of
-  // shared data are effectively acquiring.
-  std::atomic_thread_fence(std::memory_order_acquire);
+      std::memory_order_acquire);
 
   // The shared-data reads are effectively acquire ordered, and the
   // shared-data writes are effectively release ordered. Therefore if our
@@ -398,7 +399,7 @@
 
 static uint64_t UpdateLastSample(
     uint64_t now_cycles, uint64_t now_ns, uint64_t delta_cycles,
-    const struct TimeSample *sample) ABSL_ATTRIBUTE_COLD;
+    const struct TimeSample* sample) ABSL_ATTRIBUTE_COLD;
 
 // The slow path of GetCurrentTimeNanos().  This is taken while gathering
 // initial samples, when enough time has elapsed since the last sample, and if
@@ -416,7 +417,7 @@
     ABSL_LOCKS_EXCLUDED(time_state.lock) {
   // Serialize access to slow-path.  Fast-path readers are not blocked yet, and
   // code below must not modify last_sample until the seqlock is acquired.
-  time_state.lock.Lock();
+  base_internal::SpinLockHolder l(time_state.lock);
 
   // Sample the kernel time base.  This is the definition of
   // "now" if we take the slow path.
@@ -439,16 +440,14 @@
   if (delta_cycles < sample.min_cycles_per_sample) {
     // Another thread updated the sample.  This path does not take the seqlock
     // so that blocked readers can make progress without blocking new readers.
-    estimated_base_ns = sample.base_ns +
-        ((delta_cycles * sample.nsscaled_per_cycle) >> kScale);
+    estimated_base_ns =
+        sample.base_ns + ((delta_cycles * sample.nsscaled_per_cycle) >> kScale);
     time_state.stats_fast_slow_paths++;
   } else {
     estimated_base_ns =
         UpdateLastSample(now_cycles, now_ns, delta_cycles, &sample);
   }
 
-  time_state.lock.Unlock();
-
   return static_cast<int64_t>(estimated_base_ns);
 }
 
@@ -457,7 +456,7 @@
 // for readers.  Returns the new estimated time.
 static uint64_t UpdateLastSample(uint64_t now_cycles, uint64_t now_ns,
                                  uint64_t delta_cycles,
-                                 const struct TimeSample *sample)
+                                 const struct TimeSample* sample)
     ABSL_EXCLUSIVE_LOCKS_REQUIRED(time_state.lock) {
   uint64_t estimated_base_ns = now_ns;
   uint64_t lock_value =
@@ -494,8 +493,8 @@
         estimated_scaled_ns = (delta_cycles >> s) * sample->nsscaled_per_cycle;
       } while (estimated_scaled_ns / sample->nsscaled_per_cycle !=
                (delta_cycles >> s));
-      estimated_base_ns = sample->base_ns +
-                          (estimated_scaled_ns >> (kScale - s));
+      estimated_base_ns =
+          sample->base_ns + (estimated_scaled_ns >> (kScale - s));
     }
 
     // Compute the assumed cycle time kMinNSBetweenSamples ns into the future
@@ -522,8 +521,8 @@
                                diff_ns - (diff_ns / 16));
     uint64_t new_nsscaled_per_cycle =
         SafeDivideAndScale(ns, assumed_next_sample_delta_cycles);
-    if (new_nsscaled_per_cycle != 0 &&
-        diff_ns < 100 * 1000 * 1000 && -diff_ns < 100 * 1000 * 1000) {
+    if (new_nsscaled_per_cycle != 0 && diff_ns < 100 * 1000 * 1000 &&
+        -diff_ns < 100 * 1000 * 1000) {
       // record the cycle time measurement
       time_state.last_sample.nsscaled_per_cycle.store(
           new_nsscaled_per_cycle, std::memory_order_relaxed);
diff --git a/absl/time/clock_test.cc b/absl/time/clock_test.cc
index bc77dbc..fb1452a 100644
--- a/absl/time/clock_test.cc
+++ b/absl/time/clock_test.cc
@@ -114,8 +114,8 @@
   EXPECT_TRUE(AssertSleepForBounded(d, early, late, timeout,
                                     AlarmPolicy::kWithoutAlarm));
 #if defined(ABSL_HAVE_ALARM)
-  EXPECT_TRUE(AssertSleepForBounded(d, early, late, timeout,
-                                    AlarmPolicy::kWithAlarm));
+  EXPECT_TRUE(
+      AssertSleepForBounded(d, early, late, timeout, AlarmPolicy::kWithAlarm));
 #endif
 }
 
diff --git a/absl/time/duration.cc b/absl/time/duration.cc
index 38c4b63..fb7c90a 100644
--- a/absl/time/duration.cc
+++ b/absl/time/duration.cc
@@ -469,7 +469,7 @@
 
 Duration& Duration::operator*=(double r) {
   if (time_internal::IsInfiniteDuration(*this) || !IsFinite(r)) {
-    const bool is_neg = std::signbit(r) != (rep_hi_.Get() < 0);
+    const bool is_neg = std::isnan(r) || std::signbit(r) != (rep_hi_.Get() < 0);
     return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
   }
   return *this = ScaleDouble<std::multiplies>(*this, r);
@@ -485,7 +485,7 @@
 
 Duration& Duration::operator/=(double r) {
   if (time_internal::IsInfiniteDuration(*this) || !IsValidDivisor(r)) {
-    const bool is_neg = std::signbit(r) != (rep_hi_.Get() < 0);
+    const bool is_neg = std::isnan(r) || std::signbit(r) != (rep_hi_.Get() < 0);
     return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
   }
   return *this = ScaleDouble<std::divides>(*this, r);
diff --git a/absl/time/duration_benchmark.cc b/absl/time/duration_benchmark.cc
index fdb26bb..e2dd4d2 100644
--- a/absl/time/duration_benchmark.cc
+++ b/absl/time/duration_benchmark.cc
@@ -359,6 +359,150 @@
 BENCHMARK(BM_Duration_ToInt64Hours);
 
 //
+// ToDoubleXYZ
+//
+void BM_Duration_ToDoubleNanoseconds(benchmark::State& state) {
+  absl::Duration d = absl::Seconds(100000);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(d);
+    double result = absl::ToDoubleNanoseconds(d);
+    benchmark::DoNotOptimize(result);
+  }
+}
+BENCHMARK(BM_Duration_ToDoubleNanoseconds);
+
+void BM_Duration_ToDoubleMicroseconds(benchmark::State& state) {
+  absl::Duration d = absl::Seconds(100000);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(d);
+    double result = absl::ToDoubleMicroseconds(d);
+    benchmark::DoNotOptimize(result);
+  }
+}
+BENCHMARK(BM_Duration_ToDoubleMicroseconds);
+
+void BM_Duration_ToDoubleMilliseconds(benchmark::State& state) {
+  absl::Duration d = absl::Seconds(100000);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(d);
+    double result = absl::ToDoubleMilliseconds(d);
+    benchmark::DoNotOptimize(result);
+  }
+}
+BENCHMARK(BM_Duration_ToDoubleMilliseconds);
+
+void BM_Duration_ToDoubleSeconds(benchmark::State& state) {
+  absl::Duration d = absl::Seconds(100000);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(d);
+    double result = absl::ToDoubleSeconds(d);
+    benchmark::DoNotOptimize(result);
+  }
+}
+BENCHMARK(BM_Duration_ToDoubleSeconds);
+
+void BM_Duration_ToDoubleMinutes(benchmark::State& state) {
+  absl::Duration d = absl::Seconds(100000);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(d);
+    double result = absl::ToDoubleMinutes(d);
+    benchmark::DoNotOptimize(result);
+  }
+}
+BENCHMARK(BM_Duration_ToDoubleMinutes);
+
+void BM_Duration_ToDoubleHours(benchmark::State& state) {
+  absl::Duration d = absl::Seconds(100000);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(d);
+    double result = absl::ToDoubleHours(d);
+    benchmark::DoNotOptimize(result);
+  }
+}
+BENCHMARK(BM_Duration_ToDoubleHours);
+
+//
+// ToDoubleXYZ Latency
+//
+void BM_Duration_ToDoubleNanoseconds_Latency(benchmark::State& state) {
+  absl::Duration d1 = absl::Seconds(100000);
+  absl::Duration d2 = absl::Seconds(100000);
+  double result = 1;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(d1);
+    benchmark::DoNotOptimize(d2);
+    benchmark::DoNotOptimize(result);
+    result = absl::ToDoubleNanoseconds(result < 0 ? d1 : d2);
+  }
+}
+BENCHMARK(BM_Duration_ToDoubleNanoseconds_Latency);
+
+void BM_Duration_ToDoubleMicroseconds_Latency(benchmark::State& state) {
+  absl::Duration d1 = absl::Seconds(100000);
+  absl::Duration d2 = absl::Seconds(100000);
+  double result = 1;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(d1);
+    benchmark::DoNotOptimize(d2);
+    benchmark::DoNotOptimize(result);
+    result = absl::ToDoubleMicroseconds(result < 0 ? d1 : d2);
+  }
+}
+BENCHMARK(BM_Duration_ToDoubleMicroseconds_Latency);
+
+void BM_Duration_ToDoubleMilliseconds_Latency(benchmark::State& state) {
+  absl::Duration d1 = absl::Seconds(100000);
+  absl::Duration d2 = absl::Seconds(100000);
+  double result = 1;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(d1);
+    benchmark::DoNotOptimize(d2);
+    benchmark::DoNotOptimize(result);
+    result = absl::ToDoubleMilliseconds(result < 0 ? d1 : d2);
+  }
+}
+BENCHMARK(BM_Duration_ToDoubleMilliseconds_Latency);
+
+void BM_Duration_ToDoubleSeconds_Latency(benchmark::State& state) {
+  absl::Duration d1 = absl::Seconds(100000);
+  absl::Duration d2 = absl::Seconds(100000);
+  double result = 1;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(d1);
+    benchmark::DoNotOptimize(d2);
+    benchmark::DoNotOptimize(result);
+    result = absl::ToDoubleSeconds(result < 0 ? d1 : d2);
+  }
+}
+BENCHMARK(BM_Duration_ToDoubleSeconds_Latency);
+
+void BM_Duration_ToDoubleMinutes_Latency(benchmark::State& state) {
+  absl::Duration d1 = absl::Seconds(100000);
+  absl::Duration d2 = absl::Seconds(100000);
+  double result = 1;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(d1);
+    benchmark::DoNotOptimize(d2);
+    benchmark::DoNotOptimize(result);
+    result = absl::ToDoubleMinutes(result < 0 ? d1 : d2);
+  }
+}
+BENCHMARK(BM_Duration_ToDoubleMinutes_Latency);
+
+void BM_Duration_ToDoubleHours_Latency(benchmark::State& state) {
+  absl::Duration d1 = absl::Seconds(100000);
+  absl::Duration d2 = absl::Seconds(100000);
+  double result = 1;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(d1);
+    benchmark::DoNotOptimize(d2);
+    benchmark::DoNotOptimize(result);
+    result = absl::ToDoubleHours(result < 0 ? d1 : d2);
+  }
+}
+BENCHMARK(BM_Duration_ToDoubleHours_Latency);
+
+//
 // To/FromTimespec
 //
 
diff --git a/absl/time/duration_test.cc b/absl/time/duration_test.cc
index 1e3fe67..dc14665 100644
--- a/absl/time/duration_test.cc
+++ b/absl/time/duration_test.cc
@@ -57,8 +57,7 @@
 // timespec ts1, ts2;
 // EXPECT_THAT(ts1, TimespecMatcher(ts2));
 MATCHER_P(TimespecMatcher, ts, "") {
-  if (ts.tv_sec == arg.tv_sec && ts.tv_nsec == arg.tv_nsec)
-    return true;
+  if (ts.tv_sec == arg.tv_sec && ts.tv_nsec == arg.tv_nsec) return true;
   *result_listener << "expected: {" << ts.tv_sec << ", " << ts.tv_nsec << "} ";
   *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_nsec << "}";
   return false;
@@ -68,8 +67,7 @@
 // timeval tv1, tv2;
 // EXPECT_THAT(tv1, TimevalMatcher(tv2));
 MATCHER_P(TimevalMatcher, tv, "") {
-  if (tv.tv_sec == arg.tv_sec && tv.tv_usec == arg.tv_usec)
-    return true;
+  if (tv.tv_sec == arg.tv_sec && tv.tv_usec == arg.tv_usec) return true;
   *result_listener << "expected: {" << tv.tv_sec << ", " << tv.tv_usec << "} ";
   *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_usec << "}";
   return false;
@@ -223,12 +221,12 @@
 
 template <int64_t N>
 void TestFromChronoBasicEquality() {
-  using std::chrono::nanoseconds;
+  using std::chrono::hours;
   using std::chrono::microseconds;
   using std::chrono::milliseconds;
-  using std::chrono::seconds;
   using std::chrono::minutes;
-  using std::chrono::hours;
+  using std::chrono::nanoseconds;
+  using std::chrono::seconds;
 
   static_assert(absl::Nanoseconds(N) == absl::FromChrono(nanoseconds(N)), "");
   static_assert(absl::Microseconds(N) == absl::FromChrono(microseconds(N)), "");
@@ -288,12 +286,12 @@
 
 template <int64_t N>
 void TestToChrono() {
-  using std::chrono::nanoseconds;
+  using std::chrono::hours;
   using std::chrono::microseconds;
   using std::chrono::milliseconds;
-  using std::chrono::seconds;
   using std::chrono::minutes;
-  using std::chrono::hours;
+  using std::chrono::nanoseconds;
+  using std::chrono::seconds;
 
   EXPECT_EQ(nanoseconds(N), absl::ToChronoNanoseconds(absl::Nanoseconds(N)));
   EXPECT_EQ(microseconds(N), absl::ToChronoMicroseconds(absl::Microseconds(N)));
@@ -320,12 +318,12 @@
 }
 
 TEST(Duration, ToChrono) {
-  using std::chrono::nanoseconds;
+  using std::chrono::hours;
   using std::chrono::microseconds;
   using std::chrono::milliseconds;
-  using std::chrono::seconds;
   using std::chrono::minutes;
-  using std::chrono::hours;
+  using std::chrono::nanoseconds;
+  using std::chrono::seconds;
 
   TestToChrono<kint64min>();
   TestToChrono<-1>();
@@ -546,18 +544,18 @@
   const absl::Duration sec_min = absl::Seconds(kint64min);
   const absl::Duration inf = absl::InfiniteDuration();
 
-#define TEST_INF_MUL_WITH_TYPE(T)                                     \
-  EXPECT_EQ(inf, inf * static_cast<T>(2));                            \
-  EXPECT_EQ(-inf, inf * static_cast<T>(-2));                          \
-  EXPECT_EQ(-inf, -inf * static_cast<T>(2));                          \
-  EXPECT_EQ(inf, -inf * static_cast<T>(-2));                          \
-  EXPECT_EQ(inf, inf * static_cast<T>(0));                            \
-  EXPECT_EQ(-inf, -inf * static_cast<T>(0));                          \
-  EXPECT_EQ(inf, sec_max * static_cast<T>(2));                        \
-  EXPECT_EQ(inf, sec_min * static_cast<T>(-2));                       \
-  EXPECT_EQ(inf, (sec_max / static_cast<T>(2)) * static_cast<T>(3));  \
-  EXPECT_EQ(-inf, sec_max * static_cast<T>(-2));                      \
-  EXPECT_EQ(-inf, sec_min * static_cast<T>(2));                       \
+#define TEST_INF_MUL_WITH_TYPE(T)                                    \
+  EXPECT_EQ(inf, inf* static_cast<T>(2));                            \
+  EXPECT_EQ(-inf, inf* static_cast<T>(-2));                          \
+  EXPECT_EQ(-inf, -inf* static_cast<T>(2));                          \
+  EXPECT_EQ(inf, -inf* static_cast<T>(-2));                          \
+  EXPECT_EQ(inf, inf* static_cast<T>(0));                            \
+  EXPECT_EQ(-inf, -inf* static_cast<T>(0));                          \
+  EXPECT_EQ(inf, sec_max* static_cast<T>(2));                        \
+  EXPECT_EQ(inf, sec_min* static_cast<T>(-2));                       \
+  EXPECT_EQ(inf, (sec_max / static_cast<T>(2)) * static_cast<T>(3)); \
+  EXPECT_EQ(-inf, sec_max* static_cast<T>(-2));                      \
+  EXPECT_EQ(-inf, sec_min* static_cast<T>(2));                       \
   EXPECT_EQ(-inf, (sec_min / static_cast<T>(2)) * static_cast<T>(3));
 
   TEST_INF_MUL_WITH_TYPE(int64_t);  // NOLINT(readability/function)
@@ -841,18 +839,18 @@
 
 TEST(Duration, NaN) {
   // Note that IEEE 754 does not define the behavior of a nan's sign when it is
-  // copied, so the code below allows for either + or - InfiniteDuration.
+  // copied. We return -InfiniteDuration in either case.
 #define TEST_NAN_HANDLING(NAME, NAN)           \
   do {                                         \
     const auto inf = absl::InfiniteDuration(); \
     auto x = NAME(NAN);                        \
-    EXPECT_TRUE(x == inf || x == -inf);        \
+    EXPECT_TRUE(x == -inf);                    \
     auto y = NAME(42);                         \
     y *= NAN;                                  \
-    EXPECT_TRUE(y == inf || y == -inf);        \
+    EXPECT_TRUE(y == -inf);                    \
     auto z = NAME(42);                         \
     z /= NAN;                                  \
-    EXPECT_TRUE(z == inf || z == -inf);        \
+    EXPECT_TRUE(z == -inf);                    \
   } while (0)
 
   const double nan = std::numeric_limits<double>::quiet_NaN();
@@ -932,9 +930,9 @@
 #ifdef ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
 
 TEST(Duration, SpaceshipOperators) {
-#define TEST_REL_OPS(UNIT)               \
+#define TEST_REL_OPS(UNIT)                                               \
   static_assert(UNIT(2) <=> UNIT(2) == std::strong_ordering::equal, ""); \
-  static_assert(UNIT(1) <=> UNIT(2) == std::strong_ordering::less, ""); \
+  static_assert(UNIT(1) <=> UNIT(2) == std::strong_ordering::less, "");  \
   static_assert(UNIT(3) <=> UNIT(2) == std::strong_ordering::greater, "");
 
   TEST_REL_OPS(absl::Nanoseconds);
@@ -1159,8 +1157,7 @@
   EXPECT_EQ(0, absl::Nanoseconds(-1) / absl::Seconds(1));  // Actual -1e-9
 
   // Tests identity a = (a/b)*b + a%b
-#define TEST_MOD_IDENTITY(a, b) \
-  EXPECT_EQ((a), ((a) / (b))*(b) + ((a)%(b)))
+#define TEST_MOD_IDENTITY(a, b) EXPECT_EQ((a), ((a) / (b)) * (b) + ((a) % (b)))
 
   TEST_MOD_IDENTITY(absl::Seconds(0), absl::Seconds(2));
   TEST_MOD_IDENTITY(absl::Seconds(1), absl::Seconds(1));
diff --git a/absl/time/internal/cctz/BUILD.bazel b/absl/time/internal/cctz/BUILD.bazel
index da30a0f..e7e2ee0 100644
--- a/absl/time/internal/cctz/BUILD.bazel
+++ b/absl/time/internal/cctz/BUILD.bazel
@@ -12,6 +12,9 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
+load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load("//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", "ABSL_DEFAULT_LINKOPTS", "ABSL_TEST_COPTS")
 
 package(features = [
@@ -56,7 +59,13 @@
         "src/time_zone_posix.h",
         "src/tzfile.h",
         "src/zone_info_source.cc",
-    ],
+    ] + select({
+        "@platforms//os:windows": [
+            "src/time_zone_name_win.cc",
+            "src/time_zone_name_win.h",
+        ],
+        "//conditions:default": [],
+    }),
     hdrs = [
         "include/cctz/time_zone.h",
         "include/cctz/zone_info_source.h",
@@ -80,9 +89,15 @@
 
 ### tests
 
-test_suite(
-    name = "all_tests",
-    visibility = ["//visibility:public"],
+cc_library(
+    name = "test_time_zone_names",
+    testonly = True,
+    srcs = ["src/test_time_zone_names.cc"],
+    hdrs = ["src/test_time_zone_names.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = ["//visibility:private"],
+    deps = ["//absl/base:config"],
 )
 
 cc_test(
@@ -137,6 +152,7 @@
     ],
     deps = [
         ":civil_time",
+        ":test_time_zone_names",
         ":time_zone",
         "//absl/base:config",
         "@googletest//:gtest",
@@ -161,6 +177,7 @@
     tags = ["benchmark"],
     deps = [
         ":civil_time",
+        ":test_time_zone_names",
         ":time_zone",
         "//absl/base:config",
         "@google_benchmark//:benchmark_main",
diff --git a/absl/time/internal/cctz/include/cctz/civil_time_detail.h b/absl/time/internal/cctz/include/cctz/civil_time_detail.h
index 2b0aed5..fe3b8bd 100644
--- a/absl/time/internal/cctz/include/cctz/civil_time_detail.h
+++ b/absl/time/internal/cctz/include/cctz/civil_time_detail.h
@@ -96,6 +96,18 @@
 CONSTEXPR_F int days_per_year(year_t y, month_t m) noexcept {
   return is_leap_year(y + (m > 2)) ? 366 : 365;
 }
+// The compiler cannot optimize away the check if we use
+// -fsanitize=array-bounds.
+// m is guaranteed to be in [1:12] in the caller, but the compiler cannot
+// optimize away the check even when this function is inlined into BreakTime.
+// To reduce the overhead, we use no_sanitize to skip the unnecessary
+// -fsanitize=array-bounds check. Remove no_sanitize once the missed
+// optimization is fixed.
+#if defined(__clang__) && defined(__has_cpp_attribute)
+#if __has_cpp_attribute(clang::no_sanitize)
+[[clang::no_sanitize("array-bounds")]]
+#endif
+#endif
 CONSTEXPR_F int days_per_month(year_t y, month_t m) noexcept {
   CONSTEXPR_D int k_days_per_month[1 + 12] = {
       -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31  // non leap year
diff --git a/absl/time/internal/cctz/src/cctz_benchmark.cc b/absl/time/internal/cctz/src/cctz_benchmark.cc
index ba7e149..ce27818 100644
--- a/absl/time/internal/cctz/src/cctz_benchmark.cc
+++ b/absl/time/internal/cctz/src/cctz_benchmark.cc
@@ -23,6 +23,7 @@
 #include "benchmark/benchmark.h"
 #include "absl/time/internal/cctz/include/cctz/civil_time.h"
 #include "absl/time/internal/cctz/include/cctz/time_zone.h"
+#include "absl/time/internal/cctz/src/test_time_zone_names.h"
 #include "absl/time/internal/cctz/src/time_zone_impl.h"
 
 namespace {
@@ -103,498 +104,10 @@
 const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z";
 const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z";
 
-// A list of known time-zone names.
-// TODO: Refactor with src/time_zone_lookup_test.cc.
-const char* const kTimeZoneNames[] = {"Africa/Abidjan",
-                                      "Africa/Accra",
-                                      "Africa/Addis_Ababa",
-                                      "Africa/Algiers",
-                                      "Africa/Asmara",
-                                      "Africa/Bamako",
-                                      "Africa/Bangui",
-                                      "Africa/Banjul",
-                                      "Africa/Bissau",
-                                      "Africa/Blantyre",
-                                      "Africa/Brazzaville",
-                                      "Africa/Bujumbura",
-                                      "Africa/Cairo",
-                                      "Africa/Casablanca",
-                                      "Africa/Ceuta",
-                                      "Africa/Conakry",
-                                      "Africa/Dakar",
-                                      "Africa/Dar_es_Salaam",
-                                      "Africa/Djibouti",
-                                      "Africa/Douala",
-                                      "Africa/El_Aaiun",
-                                      "Africa/Freetown",
-                                      "Africa/Gaborone",
-                                      "Africa/Harare",
-                                      "Africa/Johannesburg",
-                                      "Africa/Juba",
-                                      "Africa/Kampala",
-                                      "Africa/Khartoum",
-                                      "Africa/Kigali",
-                                      "Africa/Kinshasa",
-                                      "Africa/Lagos",
-                                      "Africa/Libreville",
-                                      "Africa/Lome",
-                                      "Africa/Luanda",
-                                      "Africa/Lubumbashi",
-                                      "Africa/Lusaka",
-                                      "Africa/Malabo",
-                                      "Africa/Maputo",
-                                      "Africa/Maseru",
-                                      "Africa/Mbabane",
-                                      "Africa/Mogadishu",
-                                      "Africa/Monrovia",
-                                      "Africa/Nairobi",
-                                      "Africa/Ndjamena",
-                                      "Africa/Niamey",
-                                      "Africa/Nouakchott",
-                                      "Africa/Ouagadougou",
-                                      "Africa/Porto-Novo",
-                                      "Africa/Sao_Tome",
-                                      "Africa/Timbuktu",
-                                      "Africa/Tripoli",
-                                      "Africa/Tunis",
-                                      "Africa/Windhoek",
-                                      "America/Adak",
-                                      "America/Anchorage",
-                                      "America/Anguilla",
-                                      "America/Antigua",
-                                      "America/Araguaina",
-                                      "America/Argentina/Buenos_Aires",
-                                      "America/Argentina/Catamarca",
-                                      "America/Argentina/Cordoba",
-                                      "America/Argentina/Jujuy",
-                                      "America/Argentina/La_Rioja",
-                                      "America/Argentina/Mendoza",
-                                      "America/Argentina/Rio_Gallegos",
-                                      "America/Argentina/Salta",
-                                      "America/Argentina/San_Juan",
-                                      "America/Argentina/San_Luis",
-                                      "America/Argentina/Tucuman",
-                                      "America/Argentina/Ushuaia",
-                                      "America/Aruba",
-                                      "America/Asuncion",
-                                      "America/Atikokan",
-                                      "America/Atka",
-                                      "America/Bahia",
-                                      "America/Bahia_Banderas",
-                                      "America/Barbados",
-                                      "America/Belem",
-                                      "America/Belize",
-                                      "America/Blanc-Sablon",
-                                      "America/Boa_Vista",
-                                      "America/Bogota",
-                                      "America/Boise",
-                                      "America/Cambridge_Bay",
-                                      "America/Campo_Grande",
-                                      "America/Cancun",
-                                      "America/Caracas",
-                                      "America/Cayenne",
-                                      "America/Cayman",
-                                      "America/Chicago",
-                                      "America/Chihuahua",
-                                      "America/Ciudad_Juarez",
-                                      "America/Coral_Harbour",
-                                      "America/Costa_Rica",
-                                      "America/Coyhaique",
-                                      "America/Creston",
-                                      "America/Cuiaba",
-                                      "America/Curacao",
-                                      "America/Danmarkshavn",
-                                      "America/Dawson",
-                                      "America/Dawson_Creek",
-                                      "America/Denver",
-                                      "America/Detroit",
-                                      "America/Dominica",
-                                      "America/Edmonton",
-                                      "America/Eirunepe",
-                                      "America/El_Salvador",
-                                      "America/Ensenada",
-                                      "America/Fort_Nelson",
-                                      "America/Fortaleza",
-                                      "America/Glace_Bay",
-                                      "America/Goose_Bay",
-                                      "America/Grand_Turk",
-                                      "America/Grenada",
-                                      "America/Guadeloupe",
-                                      "America/Guatemala",
-                                      "America/Guayaquil",
-                                      "America/Guyana",
-                                      "America/Halifax",
-                                      "America/Havana",
-                                      "America/Hermosillo",
-                                      "America/Indiana/Indianapolis",
-                                      "America/Indiana/Knox",
-                                      "America/Indiana/Marengo",
-                                      "America/Indiana/Petersburg",
-                                      "America/Indiana/Tell_City",
-                                      "America/Indiana/Vevay",
-                                      "America/Indiana/Vincennes",
-                                      "America/Indiana/Winamac",
-                                      "America/Inuvik",
-                                      "America/Iqaluit",
-                                      "America/Jamaica",
-                                      "America/Juneau",
-                                      "America/Kentucky/Louisville",
-                                      "America/Kentucky/Monticello",
-                                      "America/Kralendijk",
-                                      "America/La_Paz",
-                                      "America/Lima",
-                                      "America/Los_Angeles",
-                                      "America/Lower_Princes",
-                                      "America/Maceio",
-                                      "America/Managua",
-                                      "America/Manaus",
-                                      "America/Marigot",
-                                      "America/Martinique",
-                                      "America/Matamoros",
-                                      "America/Mazatlan",
-                                      "America/Menominee",
-                                      "America/Merida",
-                                      "America/Metlakatla",
-                                      "America/Mexico_City",
-                                      "America/Miquelon",
-                                      "America/Moncton",
-                                      "America/Monterrey",
-                                      "America/Montevideo",
-                                      "America/Montreal",
-                                      "America/Montserrat",
-                                      "America/Nassau",
-                                      "America/New_York",
-                                      "America/Nipigon",
-                                      "America/Nome",
-                                      "America/Noronha",
-                                      "America/North_Dakota/Beulah",
-                                      "America/North_Dakota/Center",
-                                      "America/North_Dakota/New_Salem",
-                                      "America/Nuuk",
-                                      "America/Ojinaga",
-                                      "America/Panama",
-                                      "America/Pangnirtung",
-                                      "America/Paramaribo",
-                                      "America/Phoenix",
-                                      "America/Port-au-Prince",
-                                      "America/Port_of_Spain",
-                                      "America/Porto_Acre",
-                                      "America/Porto_Velho",
-                                      "America/Puerto_Rico",
-                                      "America/Punta_Arenas",
-                                      "America/Rainy_River",
-                                      "America/Rankin_Inlet",
-                                      "America/Recife",
-                                      "America/Regina",
-                                      "America/Resolute",
-                                      "America/Rio_Branco",
-                                      "America/Santa_Isabel",
-                                      "America/Santarem",
-                                      "America/Santiago",
-                                      "America/Santo_Domingo",
-                                      "America/Sao_Paulo",
-                                      "America/Scoresbysund",
-                                      "America/Shiprock",
-                                      "America/Sitka",
-                                      "America/St_Barthelemy",
-                                      "America/St_Johns",
-                                      "America/St_Kitts",
-                                      "America/St_Lucia",
-                                      "America/St_Thomas",
-                                      "America/St_Vincent",
-                                      "America/Swift_Current",
-                                      "America/Tegucigalpa",
-                                      "America/Thule",
-                                      "America/Thunder_Bay",
-                                      "America/Tijuana",
-                                      "America/Toronto",
-                                      "America/Tortola",
-                                      "America/Vancouver",
-                                      "America/Virgin",
-                                      "America/Whitehorse",
-                                      "America/Winnipeg",
-                                      "America/Yakutat",
-                                      "America/Yellowknife",
-                                      "Antarctica/Casey",
-                                      "Antarctica/Davis",
-                                      "Antarctica/DumontDUrville",
-                                      "Antarctica/Macquarie",
-                                      "Antarctica/Mawson",
-                                      "Antarctica/McMurdo",
-                                      "Antarctica/Palmer",
-                                      "Antarctica/Rothera",
-                                      "Antarctica/Syowa",
-                                      "Antarctica/Troll",
-                                      "Antarctica/Vostok",
-                                      "Arctic/Longyearbyen",
-                                      "Asia/Aden",
-                                      "Asia/Almaty",
-                                      "Asia/Amman",
-                                      "Asia/Anadyr",
-                                      "Asia/Aqtau",
-                                      "Asia/Aqtobe",
-                                      "Asia/Ashgabat",
-                                      "Asia/Atyrau",
-                                      "Asia/Baghdad",
-                                      "Asia/Bahrain",
-                                      "Asia/Baku",
-                                      "Asia/Bangkok",
-                                      "Asia/Barnaul",
-                                      "Asia/Beirut",
-                                      "Asia/Bishkek",
-                                      "Asia/Brunei",
-                                      "Asia/Chita",
-                                      "Asia/Choibalsan",
-                                      "Asia/Chongqing",
-                                      "Asia/Colombo",
-                                      "Asia/Damascus",
-                                      "Asia/Dhaka",
-                                      "Asia/Dili",
-                                      "Asia/Dubai",
-                                      "Asia/Dushanbe",
-                                      "Asia/Famagusta",
-                                      "Asia/Gaza",
-                                      "Asia/Harbin",
-                                      "Asia/Hebron",
-                                      "Asia/Ho_Chi_Minh",
-                                      "Asia/Hong_Kong",
-                                      "Asia/Hovd",
-                                      "Asia/Irkutsk",
-                                      "Asia/Istanbul",
-                                      "Asia/Jakarta",
-                                      "Asia/Jayapura",
-                                      "Asia/Jerusalem",
-                                      "Asia/Kabul",
-                                      "Asia/Kamchatka",
-                                      "Asia/Karachi",
-                                      "Asia/Kashgar",
-                                      "Asia/Kathmandu",
-                                      "Asia/Khandyga",
-                                      "Asia/Kolkata",
-                                      "Asia/Krasnoyarsk",
-                                      "Asia/Kuala_Lumpur",
-                                      "Asia/Kuching",
-                                      "Asia/Kuwait",
-                                      "Asia/Macau",
-                                      "Asia/Magadan",
-                                      "Asia/Makassar",
-                                      "Asia/Manila",
-                                      "Asia/Muscat",
-                                      "Asia/Nicosia",
-                                      "Asia/Novokuznetsk",
-                                      "Asia/Novosibirsk",
-                                      "Asia/Omsk",
-                                      "Asia/Oral",
-                                      "Asia/Phnom_Penh",
-                                      "Asia/Pontianak",
-                                      "Asia/Pyongyang",
-                                      "Asia/Qatar",
-                                      "Asia/Qostanay",
-                                      "Asia/Qyzylorda",
-                                      "Asia/Riyadh",
-                                      "Asia/Sakhalin",
-                                      "Asia/Samarkand",
-                                      "Asia/Seoul",
-                                      "Asia/Shanghai",
-                                      "Asia/Singapore",
-                                      "Asia/Srednekolymsk",
-                                      "Asia/Taipei",
-                                      "Asia/Tashkent",
-                                      "Asia/Tbilisi",
-                                      "Asia/Tehran",
-                                      "Asia/Tel_Aviv",
-                                      "Asia/Thimphu",
-                                      "Asia/Tokyo",
-                                      "Asia/Tomsk",
-                                      "Asia/Ulaanbaatar",
-                                      "Asia/Urumqi",
-                                      "Asia/Ust-Nera",
-                                      "Asia/Vientiane",
-                                      "Asia/Vladivostok",
-                                      "Asia/Yakutsk",
-                                      "Asia/Yangon",
-                                      "Asia/Yekaterinburg",
-                                      "Asia/Yerevan",
-                                      "Atlantic/Azores",
-                                      "Atlantic/Bermuda",
-                                      "Atlantic/Canary",
-                                      "Atlantic/Cape_Verde",
-                                      "Atlantic/Faroe",
-                                      "Atlantic/Jan_Mayen",
-                                      "Atlantic/Madeira",
-                                      "Atlantic/Reykjavik",
-                                      "Atlantic/South_Georgia",
-                                      "Atlantic/St_Helena",
-                                      "Atlantic/Stanley",
-                                      "Australia/Adelaide",
-                                      "Australia/Brisbane",
-                                      "Australia/Broken_Hill",
-                                      "Australia/Canberra",
-                                      "Australia/Currie",
-                                      "Australia/Darwin",
-                                      "Australia/Eucla",
-                                      "Australia/Hobart",
-                                      "Australia/Lindeman",
-                                      "Australia/Lord_Howe",
-                                      "Australia/Melbourne",
-                                      "Australia/Perth",
-                                      "Australia/Sydney",
-                                      "Australia/Yancowinna",
-                                      "Etc/GMT",
-                                      "Etc/GMT+0",
-                                      "Etc/GMT+1",
-                                      "Etc/GMT+10",
-                                      "Etc/GMT+11",
-                                      "Etc/GMT+12",
-                                      "Etc/GMT+2",
-                                      "Etc/GMT+3",
-                                      "Etc/GMT+4",
-                                      "Etc/GMT+5",
-                                      "Etc/GMT+6",
-                                      "Etc/GMT+7",
-                                      "Etc/GMT+8",
-                                      "Etc/GMT+9",
-                                      "Etc/GMT-0",
-                                      "Etc/GMT-1",
-                                      "Etc/GMT-10",
-                                      "Etc/GMT-11",
-                                      "Etc/GMT-12",
-                                      "Etc/GMT-13",
-                                      "Etc/GMT-14",
-                                      "Etc/GMT-2",
-                                      "Etc/GMT-3",
-                                      "Etc/GMT-4",
-                                      "Etc/GMT-5",
-                                      "Etc/GMT-6",
-                                      "Etc/GMT-7",
-                                      "Etc/GMT-8",
-                                      "Etc/GMT-9",
-                                      "Etc/GMT0",
-                                      "Etc/Greenwich",
-                                      "Etc/UCT",
-                                      "Etc/UTC",
-                                      "Etc/Universal",
-                                      "Etc/Zulu",
-                                      "Europe/Amsterdam",
-                                      "Europe/Andorra",
-                                      "Europe/Astrakhan",
-                                      "Europe/Athens",
-                                      "Europe/Belfast",
-                                      "Europe/Belgrade",
-                                      "Europe/Berlin",
-                                      "Europe/Bratislava",
-                                      "Europe/Brussels",
-                                      "Europe/Bucharest",
-                                      "Europe/Budapest",
-                                      "Europe/Busingen",
-                                      "Europe/Chisinau",
-                                      "Europe/Copenhagen",
-                                      "Europe/Dublin",
-                                      "Europe/Gibraltar",
-                                      "Europe/Guernsey",
-                                      "Europe/Helsinki",
-                                      "Europe/Isle_of_Man",
-                                      "Europe/Istanbul",
-                                      "Europe/Jersey",
-                                      "Europe/Kaliningrad",
-                                      "Europe/Kirov",
-                                      "Europe/Kyiv",
-                                      "Europe/Lisbon",
-                                      "Europe/Ljubljana",
-                                      "Europe/London",
-                                      "Europe/Luxembourg",
-                                      "Europe/Madrid",
-                                      "Europe/Malta",
-                                      "Europe/Mariehamn",
-                                      "Europe/Minsk",
-                                      "Europe/Monaco",
-                                      "Europe/Moscow",
-                                      "Europe/Nicosia",
-                                      "Europe/Oslo",
-                                      "Europe/Paris",
-                                      "Europe/Podgorica",
-                                      "Europe/Prague",
-                                      "Europe/Riga",
-                                      "Europe/Rome",
-                                      "Europe/Samara",
-                                      "Europe/San_Marino",
-                                      "Europe/Sarajevo",
-                                      "Europe/Saratov",
-                                      "Europe/Simferopol",
-                                      "Europe/Skopje",
-                                      "Europe/Sofia",
-                                      "Europe/Stockholm",
-                                      "Europe/Tallinn",
-                                      "Europe/Tirane",
-                                      "Europe/Tiraspol",
-                                      "Europe/Ulyanovsk",
-                                      "Europe/Vaduz",
-                                      "Europe/Vatican",
-                                      "Europe/Vienna",
-                                      "Europe/Vilnius",
-                                      "Europe/Volgograd",
-                                      "Europe/Warsaw",
-                                      "Europe/Zagreb",
-                                      "Europe/Zurich",
-                                      "Factory",
-                                      "Indian/Antananarivo",
-                                      "Indian/Chagos",
-                                      "Indian/Christmas",
-                                      "Indian/Cocos",
-                                      "Indian/Comoro",
-                                      "Indian/Kerguelen",
-                                      "Indian/Mahe",
-                                      "Indian/Maldives",
-                                      "Indian/Mauritius",
-                                      "Indian/Mayotte",
-                                      "Indian/Reunion",
-                                      "Pacific/Apia",
-                                      "Pacific/Auckland",
-                                      "Pacific/Bougainville",
-                                      "Pacific/Chatham",
-                                      "Pacific/Chuuk",
-                                      "Pacific/Easter",
-                                      "Pacific/Efate",
-                                      "Pacific/Fakaofo",
-                                      "Pacific/Fiji",
-                                      "Pacific/Funafuti",
-                                      "Pacific/Galapagos",
-                                      "Pacific/Gambier",
-                                      "Pacific/Guadalcanal",
-                                      "Pacific/Guam",
-                                      "Pacific/Honolulu",
-                                      "Pacific/Johnston",
-                                      "Pacific/Kanton",
-                                      "Pacific/Kiritimati",
-                                      "Pacific/Kosrae",
-                                      "Pacific/Kwajalein",
-                                      "Pacific/Majuro",
-                                      "Pacific/Marquesas",
-                                      "Pacific/Midway",
-                                      "Pacific/Nauru",
-                                      "Pacific/Niue",
-                                      "Pacific/Norfolk",
-                                      "Pacific/Noumea",
-                                      "Pacific/Pago_Pago",
-                                      "Pacific/Palau",
-                                      "Pacific/Pitcairn",
-                                      "Pacific/Pohnpei",
-                                      "Pacific/Port_Moresby",
-                                      "Pacific/Rarotonga",
-                                      "Pacific/Saipan",
-                                      "Pacific/Samoa",
-                                      "Pacific/Tahiti",
-                                      "Pacific/Tarawa",
-                                      "Pacific/Tongatapu",
-                                      "Pacific/Wake",
-                                      "Pacific/Wallis",
-                                      "Pacific/Yap",
-                                      "UTC",
-                                      nullptr};
-
 std::vector<std::string> AllTimeZoneNames() {
   std::vector<std::string> names;
-  for (const char* const* namep = kTimeZoneNames; *namep != nullptr; ++namep) {
+  for (const char* const* namep = cctz::kTimeZoneNames; *namep != nullptr;
+       ++namep) {
     names.push_back(std::string("file:") + *namep);
   }
   assert(!names.empty());
@@ -889,6 +402,7 @@
     RFC3339_sec,            // 3
     "%Y-%m-%d%ET%H:%M:%S",  // 4
     "%Y-%m-%d",             // 5
+    "%F%ET%T",              // 6
 };
 const int kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
 
diff --git a/absl/time/internal/cctz/src/test_time_zone_names.cc b/absl/time/internal/cctz/src/test_time_zone_names.cc
new file mode 100644
index 0000000..ab54c9a
--- /dev/null
+++ b/absl/time/internal/cctz/src/test_time_zone_names.cc
@@ -0,0 +1,515 @@
+// Copyright 2025 Google Inc. All Rights Reserved.
+//
+// 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/time/internal/cctz/src/test_time_zone_names.h"
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+// A list of known time-zone names.
+const char* const kTimeZoneNames[] = {"Africa/Abidjan",
+                                      "Africa/Accra",
+                                      "Africa/Addis_Ababa",
+                                      "Africa/Algiers",
+                                      "Africa/Asmara",
+                                      "Africa/Bamako",
+                                      "Africa/Bangui",
+                                      "Africa/Banjul",
+                                      "Africa/Bissau",
+                                      "Africa/Blantyre",
+                                      "Africa/Brazzaville",
+                                      "Africa/Bujumbura",
+                                      "Africa/Cairo",
+                                      "Africa/Casablanca",
+                                      "Africa/Ceuta",
+                                      "Africa/Conakry",
+                                      "Africa/Dakar",
+                                      "Africa/Dar_es_Salaam",
+                                      "Africa/Djibouti",
+                                      "Africa/Douala",
+                                      "Africa/El_Aaiun",
+                                      "Africa/Freetown",
+                                      "Africa/Gaborone",
+                                      "Africa/Harare",
+                                      "Africa/Johannesburg",
+                                      "Africa/Juba",
+                                      "Africa/Kampala",
+                                      "Africa/Khartoum",
+                                      "Africa/Kigali",
+                                      "Africa/Kinshasa",
+                                      "Africa/Lagos",
+                                      "Africa/Libreville",
+                                      "Africa/Lome",
+                                      "Africa/Luanda",
+                                      "Africa/Lubumbashi",
+                                      "Africa/Lusaka",
+                                      "Africa/Malabo",
+                                      "Africa/Maputo",
+                                      "Africa/Maseru",
+                                      "Africa/Mbabane",
+                                      "Africa/Mogadishu",
+                                      "Africa/Monrovia",
+                                      "Africa/Nairobi",
+                                      "Africa/Ndjamena",
+                                      "Africa/Niamey",
+                                      "Africa/Nouakchott",
+                                      "Africa/Ouagadougou",
+                                      "Africa/Porto-Novo",
+                                      "Africa/Sao_Tome",
+                                      "Africa/Timbuktu",
+                                      "Africa/Tripoli",
+                                      "Africa/Tunis",
+                                      "Africa/Windhoek",
+                                      "America/Adak",
+                                      "America/Anchorage",
+                                      "America/Anguilla",
+                                      "America/Antigua",
+                                      "America/Araguaina",
+                                      "America/Argentina/Buenos_Aires",
+                                      "America/Argentina/Catamarca",
+                                      "America/Argentina/Cordoba",
+                                      "America/Argentina/Jujuy",
+                                      "America/Argentina/La_Rioja",
+                                      "America/Argentina/Mendoza",
+                                      "America/Argentina/Rio_Gallegos",
+                                      "America/Argentina/Salta",
+                                      "America/Argentina/San_Juan",
+                                      "America/Argentina/San_Luis",
+                                      "America/Argentina/Tucuman",
+                                      "America/Argentina/Ushuaia",
+                                      "America/Aruba",
+                                      "America/Asuncion",
+                                      "America/Atikokan",
+                                      "America/Atka",
+                                      "America/Bahia",
+                                      "America/Bahia_Banderas",
+                                      "America/Barbados",
+                                      "America/Belem",
+                                      "America/Belize",
+                                      "America/Blanc-Sablon",
+                                      "America/Boa_Vista",
+                                      "America/Bogota",
+                                      "America/Boise",
+                                      "America/Cambridge_Bay",
+                                      "America/Campo_Grande",
+                                      "America/Cancun",
+                                      "America/Caracas",
+                                      "America/Cayenne",
+                                      "America/Cayman",
+                                      "America/Chicago",
+                                      "America/Chihuahua",
+                                      "America/Ciudad_Juarez",
+                                      "America/Coral_Harbour",
+                                      "America/Costa_Rica",
+                                      "America/Coyhaique",
+                                      "America/Creston",
+                                      "America/Cuiaba",
+                                      "America/Curacao",
+                                      "America/Danmarkshavn",
+                                      "America/Dawson",
+                                      "America/Dawson_Creek",
+                                      "America/Denver",
+                                      "America/Detroit",
+                                      "America/Dominica",
+                                      "America/Edmonton",
+                                      "America/Eirunepe",
+                                      "America/El_Salvador",
+                                      "America/Ensenada",
+                                      "America/Fort_Nelson",
+                                      "America/Fortaleza",
+                                      "America/Glace_Bay",
+                                      "America/Goose_Bay",
+                                      "America/Grand_Turk",
+                                      "America/Grenada",
+                                      "America/Guadeloupe",
+                                      "America/Guatemala",
+                                      "America/Guayaquil",
+                                      "America/Guyana",
+                                      "America/Halifax",
+                                      "America/Havana",
+                                      "America/Hermosillo",
+                                      "America/Indiana/Indianapolis",
+                                      "America/Indiana/Knox",
+                                      "America/Indiana/Marengo",
+                                      "America/Indiana/Petersburg",
+                                      "America/Indiana/Tell_City",
+                                      "America/Indiana/Vevay",
+                                      "America/Indiana/Vincennes",
+                                      "America/Indiana/Winamac",
+                                      "America/Inuvik",
+                                      "America/Iqaluit",
+                                      "America/Jamaica",
+                                      "America/Juneau",
+                                      "America/Kentucky/Louisville",
+                                      "America/Kentucky/Monticello",
+                                      "America/Kralendijk",
+                                      "America/La_Paz",
+                                      "America/Lima",
+                                      "America/Los_Angeles",
+                                      "America/Lower_Princes",
+                                      "America/Maceio",
+                                      "America/Managua",
+                                      "America/Manaus",
+                                      "America/Marigot",
+                                      "America/Martinique",
+                                      "America/Matamoros",
+                                      "America/Mazatlan",
+                                      "America/Menominee",
+                                      "America/Merida",
+                                      "America/Metlakatla",
+                                      "America/Mexico_City",
+                                      "America/Miquelon",
+                                      "America/Moncton",
+                                      "America/Monterrey",
+                                      "America/Montevideo",
+                                      "America/Montreal",
+                                      "America/Montserrat",
+                                      "America/Nassau",
+                                      "America/New_York",
+                                      "America/Nipigon",
+                                      "America/Nome",
+                                      "America/Noronha",
+                                      "America/North_Dakota/Beulah",
+                                      "America/North_Dakota/Center",
+                                      "America/North_Dakota/New_Salem",
+                                      "America/Nuuk",
+                                      "America/Ojinaga",
+                                      "America/Panama",
+                                      "America/Pangnirtung",
+                                      "America/Paramaribo",
+                                      "America/Phoenix",
+                                      "America/Port-au-Prince",
+                                      "America/Port_of_Spain",
+                                      "America/Porto_Acre",
+                                      "America/Porto_Velho",
+                                      "America/Puerto_Rico",
+                                      "America/Punta_Arenas",
+                                      "America/Rainy_River",
+                                      "America/Rankin_Inlet",
+                                      "America/Recife",
+                                      "America/Regina",
+                                      "America/Resolute",
+                                      "America/Rio_Branco",
+                                      "America/Santa_Isabel",
+                                      "America/Santarem",
+                                      "America/Santiago",
+                                      "America/Santo_Domingo",
+                                      "America/Sao_Paulo",
+                                      "America/Scoresbysund",
+                                      "America/Shiprock",
+                                      "America/Sitka",
+                                      "America/St_Barthelemy",
+                                      "America/St_Johns",
+                                      "America/St_Kitts",
+                                      "America/St_Lucia",
+                                      "America/St_Thomas",
+                                      "America/St_Vincent",
+                                      "America/Swift_Current",
+                                      "America/Tegucigalpa",
+                                      "America/Thule",
+                                      "America/Thunder_Bay",
+                                      "America/Tijuana",
+                                      "America/Toronto",
+                                      "America/Tortola",
+                                      "America/Vancouver",
+                                      "America/Virgin",
+                                      "America/Whitehorse",
+                                      "America/Winnipeg",
+                                      "America/Yakutat",
+                                      "America/Yellowknife",
+                                      "Antarctica/Casey",
+                                      "Antarctica/Davis",
+                                      "Antarctica/DumontDUrville",
+                                      "Antarctica/Macquarie",
+                                      "Antarctica/Mawson",
+                                      "Antarctica/McMurdo",
+                                      "Antarctica/Palmer",
+                                      "Antarctica/Rothera",
+                                      "Antarctica/Syowa",
+                                      "Antarctica/Troll",
+                                      "Antarctica/Vostok",
+                                      "Arctic/Longyearbyen",
+                                      "Asia/Aden",
+                                      "Asia/Almaty",
+                                      "Asia/Amman",
+                                      "Asia/Anadyr",
+                                      "Asia/Aqtau",
+                                      "Asia/Aqtobe",
+                                      "Asia/Ashgabat",
+                                      "Asia/Atyrau",
+                                      "Asia/Baghdad",
+                                      "Asia/Bahrain",
+                                      "Asia/Baku",
+                                      "Asia/Bangkok",
+                                      "Asia/Barnaul",
+                                      "Asia/Beirut",
+                                      "Asia/Bishkek",
+                                      "Asia/Brunei",
+                                      "Asia/Chita",
+                                      "Asia/Choibalsan",
+                                      "Asia/Chongqing",
+                                      "Asia/Colombo",
+                                      "Asia/Damascus",
+                                      "Asia/Dhaka",
+                                      "Asia/Dili",
+                                      "Asia/Dubai",
+                                      "Asia/Dushanbe",
+                                      "Asia/Famagusta",
+                                      "Asia/Gaza",
+                                      "Asia/Harbin",
+                                      "Asia/Hebron",
+                                      "Asia/Ho_Chi_Minh",
+                                      "Asia/Hong_Kong",
+                                      "Asia/Hovd",
+                                      "Asia/Irkutsk",
+                                      "Asia/Istanbul",
+                                      "Asia/Jakarta",
+                                      "Asia/Jayapura",
+                                      "Asia/Jerusalem",
+                                      "Asia/Kabul",
+                                      "Asia/Kamchatka",
+                                      "Asia/Karachi",
+                                      "Asia/Kashgar",
+                                      "Asia/Kathmandu",
+                                      "Asia/Khandyga",
+                                      "Asia/Kolkata",
+                                      "Asia/Krasnoyarsk",
+                                      "Asia/Kuala_Lumpur",
+                                      "Asia/Kuching",
+                                      "Asia/Kuwait",
+                                      "Asia/Macau",
+                                      "Asia/Magadan",
+                                      "Asia/Makassar",
+                                      "Asia/Manila",
+                                      "Asia/Muscat",
+                                      "Asia/Nicosia",
+                                      "Asia/Novokuznetsk",
+                                      "Asia/Novosibirsk",
+                                      "Asia/Omsk",
+                                      "Asia/Oral",
+                                      "Asia/Phnom_Penh",
+                                      "Asia/Pontianak",
+                                      "Asia/Pyongyang",
+                                      "Asia/Qatar",
+                                      "Asia/Qostanay",
+                                      "Asia/Qyzylorda",
+                                      "Asia/Riyadh",
+                                      "Asia/Sakhalin",
+                                      "Asia/Samarkand",
+                                      "Asia/Seoul",
+                                      "Asia/Shanghai",
+                                      "Asia/Singapore",
+                                      "Asia/Srednekolymsk",
+                                      "Asia/Taipei",
+                                      "Asia/Tashkent",
+                                      "Asia/Tbilisi",
+                                      "Asia/Tehran",
+                                      "Asia/Tel_Aviv",
+                                      "Asia/Thimphu",
+                                      "Asia/Tokyo",
+                                      "Asia/Tomsk",
+                                      "Asia/Ulaanbaatar",
+                                      "Asia/Urumqi",
+                                      "Asia/Ust-Nera",
+                                      "Asia/Vientiane",
+                                      "Asia/Vladivostok",
+                                      "Asia/Yakutsk",
+                                      "Asia/Yangon",
+                                      "Asia/Yekaterinburg",
+                                      "Asia/Yerevan",
+                                      "Atlantic/Azores",
+                                      "Atlantic/Bermuda",
+                                      "Atlantic/Canary",
+                                      "Atlantic/Cape_Verde",
+                                      "Atlantic/Faroe",
+                                      "Atlantic/Jan_Mayen",
+                                      "Atlantic/Madeira",
+                                      "Atlantic/Reykjavik",
+                                      "Atlantic/South_Georgia",
+                                      "Atlantic/St_Helena",
+                                      "Atlantic/Stanley",
+                                      "Australia/Adelaide",
+                                      "Australia/Brisbane",
+                                      "Australia/Broken_Hill",
+                                      "Australia/Canberra",
+                                      "Australia/Currie",
+                                      "Australia/Darwin",
+                                      "Australia/Eucla",
+                                      "Australia/Hobart",
+                                      "Australia/Lindeman",
+                                      "Australia/Lord_Howe",
+                                      "Australia/Melbourne",
+                                      "Australia/Perth",
+                                      "Australia/Sydney",
+                                      "Australia/Yancowinna",
+                                      "Etc/GMT",
+                                      "Etc/GMT+0",
+                                      "Etc/GMT+1",
+                                      "Etc/GMT+10",
+                                      "Etc/GMT+11",
+                                      "Etc/GMT+12",
+                                      "Etc/GMT+2",
+                                      "Etc/GMT+3",
+                                      "Etc/GMT+4",
+                                      "Etc/GMT+5",
+                                      "Etc/GMT+6",
+                                      "Etc/GMT+7",
+                                      "Etc/GMT+8",
+                                      "Etc/GMT+9",
+                                      "Etc/GMT-0",
+                                      "Etc/GMT-1",
+                                      "Etc/GMT-10",
+                                      "Etc/GMT-11",
+                                      "Etc/GMT-12",
+                                      "Etc/GMT-13",
+                                      "Etc/GMT-14",
+                                      "Etc/GMT-2",
+                                      "Etc/GMT-3",
+                                      "Etc/GMT-4",
+                                      "Etc/GMT-5",
+                                      "Etc/GMT-6",
+                                      "Etc/GMT-7",
+                                      "Etc/GMT-8",
+                                      "Etc/GMT-9",
+                                      "Etc/GMT0",
+                                      "Etc/Greenwich",
+                                      "Etc/UCT",
+                                      "Etc/UTC",
+                                      "Etc/Universal",
+                                      "Etc/Zulu",
+                                      "Europe/Amsterdam",
+                                      "Europe/Andorra",
+                                      "Europe/Astrakhan",
+                                      "Europe/Athens",
+                                      "Europe/Belfast",
+                                      "Europe/Belgrade",
+                                      "Europe/Berlin",
+                                      "Europe/Bratislava",
+                                      "Europe/Brussels",
+                                      "Europe/Bucharest",
+                                      "Europe/Budapest",
+                                      "Europe/Busingen",
+                                      "Europe/Chisinau",
+                                      "Europe/Copenhagen",
+                                      "Europe/Dublin",
+                                      "Europe/Gibraltar",
+                                      "Europe/Guernsey",
+                                      "Europe/Helsinki",
+                                      "Europe/Isle_of_Man",
+                                      "Europe/Istanbul",
+                                      "Europe/Jersey",
+                                      "Europe/Kaliningrad",
+                                      "Europe/Kirov",
+                                      "Europe/Kyiv",
+                                      "Europe/Lisbon",
+                                      "Europe/Ljubljana",
+                                      "Europe/London",
+                                      "Europe/Luxembourg",
+                                      "Europe/Madrid",
+                                      "Europe/Malta",
+                                      "Europe/Mariehamn",
+                                      "Europe/Minsk",
+                                      "Europe/Monaco",
+                                      "Europe/Moscow",
+                                      "Europe/Nicosia",
+                                      "Europe/Oslo",
+                                      "Europe/Paris",
+                                      "Europe/Podgorica",
+                                      "Europe/Prague",
+                                      "Europe/Riga",
+                                      "Europe/Rome",
+                                      "Europe/Samara",
+                                      "Europe/San_Marino",
+                                      "Europe/Sarajevo",
+                                      "Europe/Saratov",
+                                      "Europe/Simferopol",
+                                      "Europe/Skopje",
+                                      "Europe/Sofia",
+                                      "Europe/Stockholm",
+                                      "Europe/Tallinn",
+                                      "Europe/Tirane",
+                                      "Europe/Tiraspol",
+                                      "Europe/Ulyanovsk",
+                                      "Europe/Vaduz",
+                                      "Europe/Vatican",
+                                      "Europe/Vienna",
+                                      "Europe/Vilnius",
+                                      "Europe/Volgograd",
+                                      "Europe/Warsaw",
+                                      "Europe/Zagreb",
+                                      "Europe/Zurich",
+                                      "Factory",
+                                      "Indian/Antananarivo",
+                                      "Indian/Chagos",
+                                      "Indian/Christmas",
+                                      "Indian/Cocos",
+                                      "Indian/Comoro",
+                                      "Indian/Kerguelen",
+                                      "Indian/Mahe",
+                                      "Indian/Maldives",
+                                      "Indian/Mauritius",
+                                      "Indian/Mayotte",
+                                      "Indian/Reunion",
+                                      "Pacific/Apia",
+                                      "Pacific/Auckland",
+                                      "Pacific/Bougainville",
+                                      "Pacific/Chatham",
+                                      "Pacific/Chuuk",
+                                      "Pacific/Easter",
+                                      "Pacific/Efate",
+                                      "Pacific/Fakaofo",
+                                      "Pacific/Fiji",
+                                      "Pacific/Funafuti",
+                                      "Pacific/Galapagos",
+                                      "Pacific/Gambier",
+                                      "Pacific/Guadalcanal",
+                                      "Pacific/Guam",
+                                      "Pacific/Honolulu",
+                                      "Pacific/Johnston",
+                                      "Pacific/Kanton",
+                                      "Pacific/Kiritimati",
+                                      "Pacific/Kosrae",
+                                      "Pacific/Kwajalein",
+                                      "Pacific/Majuro",
+                                      "Pacific/Marquesas",
+                                      "Pacific/Midway",
+                                      "Pacific/Nauru",
+                                      "Pacific/Niue",
+                                      "Pacific/Norfolk",
+                                      "Pacific/Noumea",
+                                      "Pacific/Pago_Pago",
+                                      "Pacific/Palau",
+                                      "Pacific/Pitcairn",
+                                      "Pacific/Pohnpei",
+                                      "Pacific/Port_Moresby",
+                                      "Pacific/Rarotonga",
+                                      "Pacific/Saipan",
+                                      "Pacific/Samoa",
+                                      "Pacific/Tahiti",
+                                      "Pacific/Tarawa",
+                                      "Pacific/Tongatapu",
+                                      "Pacific/Wake",
+                                      "Pacific/Wallis",
+                                      "Pacific/Yap",
+                                      "UTC",
+                                      nullptr};
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/time/internal/cctz/src/test_time_zone_names.h b/absl/time/internal/cctz/src/test_time_zone_names.h
new file mode 100644
index 0000000..1993994
--- /dev/null
+++ b/absl/time/internal/cctz/src/test_time_zone_names.h
@@ -0,0 +1,33 @@
+// Copyright 2025 Google Inc. All Rights Reserved.
+//
+// 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.
+
+#ifndef ABSL_TIME_INTERNAL_CCTZ_TEST_TIME_ZONE_NAMES_H_
+#define ABSL_TIME_INTERNAL_CCTZ_TEST_TIME_ZONE_NAMES_H_
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+// A list of known time-zone names.
+extern const char* const kTimeZoneNames[];
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_TEST_TIME_ZONE_NAMES_H_
diff --git a/absl/time/internal/cctz/src/time_zone_format.cc b/absl/time/internal/cctz/src/time_zone_format.cc
index 0e5f32f..5b80c80 100644
--- a/absl/time/internal/cctz/src/time_zone_format.cc
+++ b/absl/time/internal/cctz/src/time_zone_format.cc
@@ -13,12 +13,14 @@
 //   limitations under the License.
 
 #if !defined(HAS_STRPTIME)
-#if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__VXWORKS__)
+#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__VXWORKS__)
+#define HAS_STRPTIME 0
+#else
 #define HAS_STRPTIME 1  // Assume everyone else has strptime().
 #endif
 #endif
 
-#if defined(HAS_STRPTIME) && HAS_STRPTIME
+#if HAS_STRPTIME
 #if !defined(_XOPEN_SOURCE) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
 #define _XOPEN_SOURCE 500  // Exposes definitions for SUSv2 (UNIX 98).
 #endif
@@ -117,7 +119,7 @@
   tm.tm_mday = al.cs.day();
   tm.tm_mon = al.cs.month() - 1;
 
-  // Saturate tm.tm_year is cases of over/underflow.
+  // Saturate tm.tm_year in cases of over/underflow.
   if (al.cs.year() < std::numeric_limits<int>::min() + 1900) {
     tm.tm_year = std::numeric_limits<int>::min();
   } else if (al.cs.year() - 1900 > std::numeric_limits<int>::max()) {
@@ -338,7 +340,7 @@
   const std::tm tm = ToTM(al);
 
   // Scratch buffer for internal conversions.
-  char buf[3 + kDigits10_64];  // enough for longest conversion
+  char buf[6 + (kDigits10_64 + 2)];  // enough for longest conversion %F
   char* const ep = buf + sizeof(buf);
   char* bp;  // works back from ep
 
@@ -382,7 +384,7 @@
     if (cur == end || (cur - percent) % 2 == 0) continue;
 
     // Simple specifiers that we handle ourselves.
-    if (strchr("YmdeUuWwHMSzZs%", *cur)) {
+    if (strchr("YmdeFUuWwHMSTzZs%", *cur)) {
       if (cur - 1 != pending) {
         FormatTM(&result, std::string(pending, cur - 1), tm);
       }
@@ -403,6 +405,14 @@
           if (*cur == 'e' && *bp == '0') *bp = ' ';  // for Windows
           result.append(bp, static_cast<std::size_t>(ep - bp));
           break;
+        case 'F':
+          bp = Format02d(ep, al.cs.day());
+          *--bp = '-';
+          bp = Format02d(bp, al.cs.month());
+          *--bp = '-';
+          bp = Format64(bp, 0, al.cs.year());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
         case 'U':
           bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::sunday));
           result.append(bp, static_cast<std::size_t>(ep - bp));
@@ -431,6 +441,14 @@
           bp = Format02d(ep, al.cs.second());
           result.append(bp, static_cast<std::size_t>(ep - bp));
           break;
+        case 'T':
+          bp = Format02d(ep, al.cs.second());
+          *--bp = ':';
+          bp = Format02d(bp, al.cs.minute());
+          *--bp = ':';
+          bp = Format02d(bp, al.cs.hour());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
         case 'z':
           bp = FormatOffset(ep, al.offset, "");
           result.append(bp, static_cast<std::size_t>(ep - bp));
@@ -769,6 +787,20 @@
         data = ParseInt(data, 2, 1, 31, &tm.tm_mday);
         week_num = -1;
         continue;
+      case 'F':
+        data = ParseInt(data, 0, kyearmin, kyearmax, &year);
+        if (data != nullptr) {
+          saw_year = true;
+          data = (*data == '-' ? data + 1 : nullptr);
+        }
+        data = ParseInt(data, 2, 1, 12, &tm.tm_mon);
+        if (data != nullptr) {
+          tm.tm_mon -= 1;
+          data = (*data == '-' ? data + 1 : nullptr);
+        }
+        data = ParseInt(data, 2, 1, 31, &tm.tm_mday);
+        week_num = -1;
+        continue;
       case 'U':
         data = ParseInt(data, 0, 0, 53, &week_num);
         week_start = weekday::sunday;
@@ -794,13 +826,20 @@
       case 'S':
         data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
         continue;
+      case 'T':
+        data = ParseInt(data, 2, 0, 23, &tm.tm_hour);
+        twelve_hour = false;
+        data = (data != nullptr && *data == ':' ? data + 1 : nullptr);
+        data = ParseInt(data, 2, 0, 59, &tm.tm_min);
+        data = (data != nullptr && *data == ':' ? data + 1 : nullptr);
+        data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
+        continue;
       case 'I':
       case 'l':
       case 'r':  // probably uses %I
         twelve_hour = true;
         break;
       case 'R':  // uses %H
-      case 'T':  // uses %H
       case 'c':  // probably uses %H
       case 'X':  // probably uses %H
         twelve_hour = false;
diff --git a/absl/time/internal/cctz/src/time_zone_format_test.cc b/absl/time/internal/cctz/src/time_zone_format_test.cc
index 4a6c71f..a270f4d 100644
--- a/absl/time/internal/cctz/src/time_zone_format_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_format_test.cc
@@ -169,23 +169,22 @@
 
 TEST(Format, PosixConversions) {
   const time_zone tz = utc_time_zone();
-  auto tp = chrono::system_clock::from_time_t(0);
+  auto tp =
+      chrono::system_clock::from_time_t(308189482);  // 1979-10-08T00:11:22Z
 
-  TestFormatSpecifier(tp, tz, "%d", "01");
-  TestFormatSpecifier(tp, tz, "%e", " 1");  // extension but internal support
+  TestFormatSpecifier(tp, tz, "%d", "08");
+  TestFormatSpecifier(tp, tz, "%e", " 8");  // extension but internal support
   TestFormatSpecifier(tp, tz, "%H", "00");
   TestFormatSpecifier(tp, tz, "%I", "12");
-  TestFormatSpecifier(tp, tz, "%j", "001");
-  TestFormatSpecifier(tp, tz, "%m", "01");
-  TestFormatSpecifier(tp, tz, "%M", "00");
-  TestFormatSpecifier(tp, tz, "%S", "00");
-  TestFormatSpecifier(tp, tz, "%U", "00");
-#if !defined(__EMSCRIPTEN__)
-  TestFormatSpecifier(tp, tz, "%w", "4");  // 4=Thursday
-#endif
-  TestFormatSpecifier(tp, tz, "%W", "00");
-  TestFormatSpecifier(tp, tz, "%y", "70");
-  TestFormatSpecifier(tp, tz, "%Y", "1970");
+  TestFormatSpecifier(tp, tz, "%j", "281");
+  TestFormatSpecifier(tp, tz, "%m", "10");
+  TestFormatSpecifier(tp, tz, "%M", "11");
+  TestFormatSpecifier(tp, tz, "%S", "22");
+  TestFormatSpecifier(tp, tz, "%U", "40");
+  TestFormatSpecifier(tp, tz, "%w", "1");  // 1=Monday
+  TestFormatSpecifier(tp, tz, "%W", "41");
+  TestFormatSpecifier(tp, tz, "%y", "79");
+  TestFormatSpecifier(tp, tz, "%Y", "1979");
   TestFormatSpecifier(tp, tz, "%z", "+0000");
   TestFormatSpecifier(tp, tz, "%Z", "UTC");
   TestFormatSpecifier(tp, tz, "%%", "%");
@@ -193,21 +192,21 @@
 #if defined(__linux__)
   // SU/C99/TZ extensions
   TestFormatSpecifier(tp, tz, "%C", "19");
-  TestFormatSpecifier(tp, tz, "%D", "01/01/70");
-  TestFormatSpecifier(tp, tz, "%F", "1970-01-01");
-  TestFormatSpecifier(tp, tz, "%g", "70");
-  TestFormatSpecifier(tp, tz, "%G", "1970");
+  TestFormatSpecifier(tp, tz, "%D", "10/08/79");
+  TestFormatSpecifier(tp, tz, "%F", "1979-10-08");
+  TestFormatSpecifier(tp, tz, "%g", "79");
+  TestFormatSpecifier(tp, tz, "%G", "1979");
 #if defined(__GLIBC__)
   TestFormatSpecifier(tp, tz, "%k", " 0");
   TestFormatSpecifier(tp, tz, "%l", "12");
 #endif
   TestFormatSpecifier(tp, tz, "%n", "\n");
-  TestFormatSpecifier(tp, tz, "%R", "00:00");
+  TestFormatSpecifier(tp, tz, "%R", "00:11");
   TestFormatSpecifier(tp, tz, "%t", "\t");
-  TestFormatSpecifier(tp, tz, "%T", "00:00:00");
-  TestFormatSpecifier(tp, tz, "%u", "4");  // 4=Thursday
-  TestFormatSpecifier(tp, tz, "%V", "01");
-  TestFormatSpecifier(tp, tz, "%s", "0");
+  TestFormatSpecifier(tp, tz, "%T", "00:11:22");
+  TestFormatSpecifier(tp, tz, "%u", "1");  // 1=Monday
+  TestFormatSpecifier(tp, tz, "%V", "41");
+  TestFormatSpecifier(tp, tz, "%s", "308189482");
 #endif
 }
 
diff --git a/absl/time/internal/cctz/src/time_zone_lookup.cc b/absl/time/internal/cctz/src/time_zone_lookup.cc
index 90b2972..d1078de 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup.cc
@@ -32,31 +32,6 @@
 #include <zircon/types.h>
 #endif
 
-#if defined(_WIN32)
-// Include only when <icu.h> is available.
-// https://learn.microsoft.com/en-us/windows/win32/intl/international-components-for-unicode--icu-
-// https://devblogs.microsoft.com/oldnewthing/20210527-00/?p=105255
-#if defined(__has_include)
-#if __has_include(<icu.h>)
-#define USE_WIN32_LOCAL_TIME_ZONE
-#include <windows.h>
-#pragma push_macro("_WIN32_WINNT")
-#pragma push_macro("NTDDI_VERSION")
-// Minimum _WIN32_WINNT and NTDDI_VERSION to use ucal_getTimeZoneIDForWindowsID
-#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x0A00  // == _WIN32_WINNT_WIN10
-#undef NTDDI_VERSION
-#define NTDDI_VERSION 0x0A000004  // == NTDDI_WIN10_RS3
-#include <icu.h>
-#pragma pop_macro("NTDDI_VERSION")
-#pragma pop_macro("_WIN32_WINNT")
-#include <timezoneapi.h>
-
-#include <atomic>
-#endif  // __has_include(<icu.h>)
-#endif  // __has_include
-#endif  // _WIN32
-
 #include <array>
 #include <cstdint>
 #include <cstdlib>
@@ -66,87 +41,15 @@
 #include "absl/time/internal/cctz/src/time_zone_fixed.h"
 #include "absl/time/internal/cctz/src/time_zone_impl.h"
 
+#if defined(_WIN32)
+#include "absl/time/internal/cctz/src/time_zone_name_win.h"
+#endif  // _WIN32
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace time_internal {
 namespace cctz {
 
-namespace {
-#if defined(USE_WIN32_LOCAL_TIME_ZONE)
-// True if we have already failed to load the API.
-static std::atomic_bool g_ucal_getTimeZoneIDForWindowsIDUnavailable;
-static std::atomic<decltype(ucal_getTimeZoneIDForWindowsID)*>
-    g_ucal_getTimeZoneIDForWindowsIDRef;
-
-std::string win32_local_time_zone() {
-  // If we have already failed to load the API, then just give up.
-  if (g_ucal_getTimeZoneIDForWindowsIDUnavailable.load()) {
-    return "";
-  }
-
-  auto ucal_getTimeZoneIDForWindowsIDFunc =
-      g_ucal_getTimeZoneIDForWindowsIDRef.load();
-  if (ucal_getTimeZoneIDForWindowsIDFunc == nullptr) {
-    // If we have already failed to load the API, then just give up.
-    if (g_ucal_getTimeZoneIDForWindowsIDUnavailable.load()) {
-      return "";
-    }
-
-    const HMODULE icudll =
-        ::LoadLibraryExW(L"icu.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
-
-    if (icudll == nullptr) {
-      g_ucal_getTimeZoneIDForWindowsIDUnavailable.store(true);
-      return "";
-    }
-
-    ucal_getTimeZoneIDForWindowsIDFunc =
-        reinterpret_cast<decltype(ucal_getTimeZoneIDForWindowsID)*>(
-            ::GetProcAddress(icudll, "ucal_getTimeZoneIDForWindowsID"));
-
-    if (ucal_getTimeZoneIDForWindowsIDFunc == nullptr) {
-      g_ucal_getTimeZoneIDForWindowsIDUnavailable.store(true);
-      return "";
-    }
-    // store-race is not a problem here, because ::GetProcAddress() returns the
-    // same address for the same function in the same DLL.
-    g_ucal_getTimeZoneIDForWindowsIDRef.store(
-        ucal_getTimeZoneIDForWindowsIDFunc);
-
-    // We intentionally do not call ::FreeLibrary() here to avoid frequent DLL
-    // loadings and unloading. As "icu.dll" is a system library, keeping it on
-    // memory is supposed to have no major drawback.
-  }
-
-  DYNAMIC_TIME_ZONE_INFORMATION info = {};
-  if (::GetDynamicTimeZoneInformation(&info) == TIME_ZONE_ID_INVALID) {
-    return "";
-  }
-
-  std::array<UChar, 128> buffer;
-  UErrorCode status = U_ZERO_ERROR;
-  const auto num_chars_in_buffer = ucal_getTimeZoneIDForWindowsIDFunc(
-      reinterpret_cast<const UChar*>(info.TimeZoneKeyName), -1, nullptr,
-      buffer.data(), static_cast<int32_t>(buffer.size()), &status);
-  if (status != U_ZERO_ERROR || num_chars_in_buffer <= 0 ||
-      num_chars_in_buffer > static_cast<int32_t>(buffer.size())) {
-    return "";
-  }
-
-  const int num_bytes_in_utf8 = ::WideCharToMultiByte(
-      CP_UTF8, 0, reinterpret_cast<const wchar_t*>(buffer.data()),
-      static_cast<int>(num_chars_in_buffer), nullptr, 0, nullptr, nullptr);
-  std::string local_time_str;
-  local_time_str.resize(static_cast<size_t>(num_bytes_in_utf8));
-  ::WideCharToMultiByte(
-       CP_UTF8, 0, reinterpret_cast<const wchar_t*>(buffer.data()),
-       static_cast<int>(num_chars_in_buffer), &local_time_str[0],
-       num_bytes_in_utf8, nullptr, nullptr);
-  return local_time_str;
-}
-#endif  // USE_WIN32_LOCAL_TIME_ZONE
-}  // namespace
-
 std::string time_zone::name() const { return effective_impl().Name(); }
 
 time_zone::absolute_lookup time_zone::lookup(
@@ -261,8 +164,8 @@
     zone = primary_tz.c_str();
   }
 #endif
-#if defined(USE_WIN32_LOCAL_TIME_ZONE)
-  std::string win32_tz = win32_local_time_zone();
+#if defined(_WIN32)
+  std::string win32_tz = GetWindowsLocalTimeZone();
   if (!win32_tz.empty()) {
     zone = win32_tz.c_str();
   }
diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
index e1bea28..cd08a35 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -29,6 +29,7 @@
 
 #include "gtest/gtest.h"
 #include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "absl/time/internal/cctz/src/test_time_zone_names.h"
 
 namespace chrono = std::chrono;
 
@@ -39,494 +40,6 @@
 
 namespace {
 
-// A list of known time-zone names.
-const char* const kTimeZoneNames[] = {"Africa/Abidjan",
-                                      "Africa/Accra",
-                                      "Africa/Addis_Ababa",
-                                      "Africa/Algiers",
-                                      "Africa/Asmara",
-                                      "Africa/Bamako",
-                                      "Africa/Bangui",
-                                      "Africa/Banjul",
-                                      "Africa/Bissau",
-                                      "Africa/Blantyre",
-                                      "Africa/Brazzaville",
-                                      "Africa/Bujumbura",
-                                      "Africa/Cairo",
-                                      "Africa/Casablanca",
-                                      "Africa/Ceuta",
-                                      "Africa/Conakry",
-                                      "Africa/Dakar",
-                                      "Africa/Dar_es_Salaam",
-                                      "Africa/Djibouti",
-                                      "Africa/Douala",
-                                      "Africa/El_Aaiun",
-                                      "Africa/Freetown",
-                                      "Africa/Gaborone",
-                                      "Africa/Harare",
-                                      "Africa/Johannesburg",
-                                      "Africa/Juba",
-                                      "Africa/Kampala",
-                                      "Africa/Khartoum",
-                                      "Africa/Kigali",
-                                      "Africa/Kinshasa",
-                                      "Africa/Lagos",
-                                      "Africa/Libreville",
-                                      "Africa/Lome",
-                                      "Africa/Luanda",
-                                      "Africa/Lubumbashi",
-                                      "Africa/Lusaka",
-                                      "Africa/Malabo",
-                                      "Africa/Maputo",
-                                      "Africa/Maseru",
-                                      "Africa/Mbabane",
-                                      "Africa/Mogadishu",
-                                      "Africa/Monrovia",
-                                      "Africa/Nairobi",
-                                      "Africa/Ndjamena",
-                                      "Africa/Niamey",
-                                      "Africa/Nouakchott",
-                                      "Africa/Ouagadougou",
-                                      "Africa/Porto-Novo",
-                                      "Africa/Sao_Tome",
-                                      "Africa/Timbuktu",
-                                      "Africa/Tripoli",
-                                      "Africa/Tunis",
-                                      "Africa/Windhoek",
-                                      "America/Adak",
-                                      "America/Anchorage",
-                                      "America/Anguilla",
-                                      "America/Antigua",
-                                      "America/Araguaina",
-                                      "America/Argentina/Buenos_Aires",
-                                      "America/Argentina/Catamarca",
-                                      "America/Argentina/Cordoba",
-                                      "America/Argentina/Jujuy",
-                                      "America/Argentina/La_Rioja",
-                                      "America/Argentina/Mendoza",
-                                      "America/Argentina/Rio_Gallegos",
-                                      "America/Argentina/Salta",
-                                      "America/Argentina/San_Juan",
-                                      "America/Argentina/San_Luis",
-                                      "America/Argentina/Tucuman",
-                                      "America/Argentina/Ushuaia",
-                                      "America/Aruba",
-                                      "America/Asuncion",
-                                      "America/Atikokan",
-                                      "America/Atka",
-                                      "America/Bahia",
-                                      "America/Bahia_Banderas",
-                                      "America/Barbados",
-                                      "America/Belem",
-                                      "America/Belize",
-                                      "America/Blanc-Sablon",
-                                      "America/Boa_Vista",
-                                      "America/Bogota",
-                                      "America/Boise",
-                                      "America/Cambridge_Bay",
-                                      "America/Campo_Grande",
-                                      "America/Cancun",
-                                      "America/Caracas",
-                                      "America/Cayenne",
-                                      "America/Cayman",
-                                      "America/Chicago",
-                                      "America/Chihuahua",
-                                      "America/Ciudad_Juarez",
-                                      "America/Coral_Harbour",
-                                      "America/Costa_Rica",
-                                      "America/Coyhaique",
-                                      "America/Creston",
-                                      "America/Cuiaba",
-                                      "America/Curacao",
-                                      "America/Danmarkshavn",
-                                      "America/Dawson",
-                                      "America/Dawson_Creek",
-                                      "America/Denver",
-                                      "America/Detroit",
-                                      "America/Dominica",
-                                      "America/Edmonton",
-                                      "America/Eirunepe",
-                                      "America/El_Salvador",
-                                      "America/Ensenada",
-                                      "America/Fort_Nelson",
-                                      "America/Fortaleza",
-                                      "America/Glace_Bay",
-                                      "America/Goose_Bay",
-                                      "America/Grand_Turk",
-                                      "America/Grenada",
-                                      "America/Guadeloupe",
-                                      "America/Guatemala",
-                                      "America/Guayaquil",
-                                      "America/Guyana",
-                                      "America/Halifax",
-                                      "America/Havana",
-                                      "America/Hermosillo",
-                                      "America/Indiana/Indianapolis",
-                                      "America/Indiana/Knox",
-                                      "America/Indiana/Marengo",
-                                      "America/Indiana/Petersburg",
-                                      "America/Indiana/Tell_City",
-                                      "America/Indiana/Vevay",
-                                      "America/Indiana/Vincennes",
-                                      "America/Indiana/Winamac",
-                                      "America/Inuvik",
-                                      "America/Iqaluit",
-                                      "America/Jamaica",
-                                      "America/Juneau",
-                                      "America/Kentucky/Louisville",
-                                      "America/Kentucky/Monticello",
-                                      "America/Kralendijk",
-                                      "America/La_Paz",
-                                      "America/Lima",
-                                      "America/Los_Angeles",
-                                      "America/Lower_Princes",
-                                      "America/Maceio",
-                                      "America/Managua",
-                                      "America/Manaus",
-                                      "America/Marigot",
-                                      "America/Martinique",
-                                      "America/Matamoros",
-                                      "America/Mazatlan",
-                                      "America/Menominee",
-                                      "America/Merida",
-                                      "America/Metlakatla",
-                                      "America/Mexico_City",
-                                      "America/Miquelon",
-                                      "America/Moncton",
-                                      "America/Monterrey",
-                                      "America/Montevideo",
-                                      "America/Montreal",
-                                      "America/Montserrat",
-                                      "America/Nassau",
-                                      "America/New_York",
-                                      "America/Nipigon",
-                                      "America/Nome",
-                                      "America/Noronha",
-                                      "America/North_Dakota/Beulah",
-                                      "America/North_Dakota/Center",
-                                      "America/North_Dakota/New_Salem",
-                                      "America/Nuuk",
-                                      "America/Ojinaga",
-                                      "America/Panama",
-                                      "America/Pangnirtung",
-                                      "America/Paramaribo",
-                                      "America/Phoenix",
-                                      "America/Port-au-Prince",
-                                      "America/Port_of_Spain",
-                                      "America/Porto_Acre",
-                                      "America/Porto_Velho",
-                                      "America/Puerto_Rico",
-                                      "America/Punta_Arenas",
-                                      "America/Rainy_River",
-                                      "America/Rankin_Inlet",
-                                      "America/Recife",
-                                      "America/Regina",
-                                      "America/Resolute",
-                                      "America/Rio_Branco",
-                                      "America/Santa_Isabel",
-                                      "America/Santarem",
-                                      "America/Santiago",
-                                      "America/Santo_Domingo",
-                                      "America/Sao_Paulo",
-                                      "America/Scoresbysund",
-                                      "America/Shiprock",
-                                      "America/Sitka",
-                                      "America/St_Barthelemy",
-                                      "America/St_Johns",
-                                      "America/St_Kitts",
-                                      "America/St_Lucia",
-                                      "America/St_Thomas",
-                                      "America/St_Vincent",
-                                      "America/Swift_Current",
-                                      "America/Tegucigalpa",
-                                      "America/Thule",
-                                      "America/Thunder_Bay",
-                                      "America/Tijuana",
-                                      "America/Toronto",
-                                      "America/Tortola",
-                                      "America/Vancouver",
-                                      "America/Virgin",
-                                      "America/Whitehorse",
-                                      "America/Winnipeg",
-                                      "America/Yakutat",
-                                      "America/Yellowknife",
-                                      "Antarctica/Casey",
-                                      "Antarctica/Davis",
-                                      "Antarctica/DumontDUrville",
-                                      "Antarctica/Macquarie",
-                                      "Antarctica/Mawson",
-                                      "Antarctica/McMurdo",
-                                      "Antarctica/Palmer",
-                                      "Antarctica/Rothera",
-                                      "Antarctica/Syowa",
-                                      "Antarctica/Troll",
-                                      "Antarctica/Vostok",
-                                      "Arctic/Longyearbyen",
-                                      "Asia/Aden",
-                                      "Asia/Almaty",
-                                      "Asia/Amman",
-                                      "Asia/Anadyr",
-                                      "Asia/Aqtau",
-                                      "Asia/Aqtobe",
-                                      "Asia/Ashgabat",
-                                      "Asia/Atyrau",
-                                      "Asia/Baghdad",
-                                      "Asia/Bahrain",
-                                      "Asia/Baku",
-                                      "Asia/Bangkok",
-                                      "Asia/Barnaul",
-                                      "Asia/Beirut",
-                                      "Asia/Bishkek",
-                                      "Asia/Brunei",
-                                      "Asia/Chita",
-                                      "Asia/Choibalsan",
-                                      "Asia/Chongqing",
-                                      "Asia/Colombo",
-                                      "Asia/Damascus",
-                                      "Asia/Dhaka",
-                                      "Asia/Dili",
-                                      "Asia/Dubai",
-                                      "Asia/Dushanbe",
-                                      "Asia/Famagusta",
-                                      "Asia/Gaza",
-                                      "Asia/Harbin",
-                                      "Asia/Hebron",
-                                      "Asia/Ho_Chi_Minh",
-                                      "Asia/Hong_Kong",
-                                      "Asia/Hovd",
-                                      "Asia/Irkutsk",
-                                      "Asia/Istanbul",
-                                      "Asia/Jakarta",
-                                      "Asia/Jayapura",
-                                      "Asia/Jerusalem",
-                                      "Asia/Kabul",
-                                      "Asia/Kamchatka",
-                                      "Asia/Karachi",
-                                      "Asia/Kashgar",
-                                      "Asia/Kathmandu",
-                                      "Asia/Khandyga",
-                                      "Asia/Kolkata",
-                                      "Asia/Krasnoyarsk",
-                                      "Asia/Kuala_Lumpur",
-                                      "Asia/Kuching",
-                                      "Asia/Kuwait",
-                                      "Asia/Macau",
-                                      "Asia/Magadan",
-                                      "Asia/Makassar",
-                                      "Asia/Manila",
-                                      "Asia/Muscat",
-                                      "Asia/Nicosia",
-                                      "Asia/Novokuznetsk",
-                                      "Asia/Novosibirsk",
-                                      "Asia/Omsk",
-                                      "Asia/Oral",
-                                      "Asia/Phnom_Penh",
-                                      "Asia/Pontianak",
-                                      "Asia/Pyongyang",
-                                      "Asia/Qatar",
-                                      "Asia/Qostanay",
-                                      "Asia/Qyzylorda",
-                                      "Asia/Riyadh",
-                                      "Asia/Sakhalin",
-                                      "Asia/Samarkand",
-                                      "Asia/Seoul",
-                                      "Asia/Shanghai",
-                                      "Asia/Singapore",
-                                      "Asia/Srednekolymsk",
-                                      "Asia/Taipei",
-                                      "Asia/Tashkent",
-                                      "Asia/Tbilisi",
-                                      "Asia/Tehran",
-                                      "Asia/Tel_Aviv",
-                                      "Asia/Thimphu",
-                                      "Asia/Tokyo",
-                                      "Asia/Tomsk",
-                                      "Asia/Ulaanbaatar",
-                                      "Asia/Urumqi",
-                                      "Asia/Ust-Nera",
-                                      "Asia/Vientiane",
-                                      "Asia/Vladivostok",
-                                      "Asia/Yakutsk",
-                                      "Asia/Yangon",
-                                      "Asia/Yekaterinburg",
-                                      "Asia/Yerevan",
-                                      "Atlantic/Azores",
-                                      "Atlantic/Bermuda",
-                                      "Atlantic/Canary",
-                                      "Atlantic/Cape_Verde",
-                                      "Atlantic/Faroe",
-                                      "Atlantic/Jan_Mayen",
-                                      "Atlantic/Madeira",
-                                      "Atlantic/Reykjavik",
-                                      "Atlantic/South_Georgia",
-                                      "Atlantic/St_Helena",
-                                      "Atlantic/Stanley",
-                                      "Australia/Adelaide",
-                                      "Australia/Brisbane",
-                                      "Australia/Broken_Hill",
-                                      "Australia/Canberra",
-                                      "Australia/Currie",
-                                      "Australia/Darwin",
-                                      "Australia/Eucla",
-                                      "Australia/Hobart",
-                                      "Australia/Lindeman",
-                                      "Australia/Lord_Howe",
-                                      "Australia/Melbourne",
-                                      "Australia/Perth",
-                                      "Australia/Sydney",
-                                      "Australia/Yancowinna",
-                                      "Etc/GMT",
-                                      "Etc/GMT+0",
-                                      "Etc/GMT+1",
-                                      "Etc/GMT+10",
-                                      "Etc/GMT+11",
-                                      "Etc/GMT+12",
-                                      "Etc/GMT+2",
-                                      "Etc/GMT+3",
-                                      "Etc/GMT+4",
-                                      "Etc/GMT+5",
-                                      "Etc/GMT+6",
-                                      "Etc/GMT+7",
-                                      "Etc/GMT+8",
-                                      "Etc/GMT+9",
-                                      "Etc/GMT-0",
-                                      "Etc/GMT-1",
-                                      "Etc/GMT-10",
-                                      "Etc/GMT-11",
-                                      "Etc/GMT-12",
-                                      "Etc/GMT-13",
-                                      "Etc/GMT-14",
-                                      "Etc/GMT-2",
-                                      "Etc/GMT-3",
-                                      "Etc/GMT-4",
-                                      "Etc/GMT-5",
-                                      "Etc/GMT-6",
-                                      "Etc/GMT-7",
-                                      "Etc/GMT-8",
-                                      "Etc/GMT-9",
-                                      "Etc/GMT0",
-                                      "Etc/Greenwich",
-                                      "Etc/UCT",
-                                      "Etc/UTC",
-                                      "Etc/Universal",
-                                      "Etc/Zulu",
-                                      "Europe/Amsterdam",
-                                      "Europe/Andorra",
-                                      "Europe/Astrakhan",
-                                      "Europe/Athens",
-                                      "Europe/Belfast",
-                                      "Europe/Belgrade",
-                                      "Europe/Berlin",
-                                      "Europe/Bratislava",
-                                      "Europe/Brussels",
-                                      "Europe/Bucharest",
-                                      "Europe/Budapest",
-                                      "Europe/Busingen",
-                                      "Europe/Chisinau",
-                                      "Europe/Copenhagen",
-                                      "Europe/Dublin",
-                                      "Europe/Gibraltar",
-                                      "Europe/Guernsey",
-                                      "Europe/Helsinki",
-                                      "Europe/Isle_of_Man",
-                                      "Europe/Istanbul",
-                                      "Europe/Jersey",
-                                      "Europe/Kaliningrad",
-                                      "Europe/Kirov",
-                                      "Europe/Kyiv",
-                                      "Europe/Lisbon",
-                                      "Europe/Ljubljana",
-                                      "Europe/London",
-                                      "Europe/Luxembourg",
-                                      "Europe/Madrid",
-                                      "Europe/Malta",
-                                      "Europe/Mariehamn",
-                                      "Europe/Minsk",
-                                      "Europe/Monaco",
-                                      "Europe/Moscow",
-                                      "Europe/Nicosia",
-                                      "Europe/Oslo",
-                                      "Europe/Paris",
-                                      "Europe/Podgorica",
-                                      "Europe/Prague",
-                                      "Europe/Riga",
-                                      "Europe/Rome",
-                                      "Europe/Samara",
-                                      "Europe/San_Marino",
-                                      "Europe/Sarajevo",
-                                      "Europe/Saratov",
-                                      "Europe/Simferopol",
-                                      "Europe/Skopje",
-                                      "Europe/Sofia",
-                                      "Europe/Stockholm",
-                                      "Europe/Tallinn",
-                                      "Europe/Tirane",
-                                      "Europe/Tiraspol",
-                                      "Europe/Ulyanovsk",
-                                      "Europe/Vaduz",
-                                      "Europe/Vatican",
-                                      "Europe/Vienna",
-                                      "Europe/Vilnius",
-                                      "Europe/Volgograd",
-                                      "Europe/Warsaw",
-                                      "Europe/Zagreb",
-                                      "Europe/Zurich",
-                                      "Factory",
-                                      "Indian/Antananarivo",
-                                      "Indian/Chagos",
-                                      "Indian/Christmas",
-                                      "Indian/Cocos",
-                                      "Indian/Comoro",
-                                      "Indian/Kerguelen",
-                                      "Indian/Mahe",
-                                      "Indian/Maldives",
-                                      "Indian/Mauritius",
-                                      "Indian/Mayotte",
-                                      "Indian/Reunion",
-                                      "Pacific/Apia",
-                                      "Pacific/Auckland",
-                                      "Pacific/Bougainville",
-                                      "Pacific/Chatham",
-                                      "Pacific/Chuuk",
-                                      "Pacific/Easter",
-                                      "Pacific/Efate",
-                                      "Pacific/Fakaofo",
-                                      "Pacific/Fiji",
-                                      "Pacific/Funafuti",
-                                      "Pacific/Galapagos",
-                                      "Pacific/Gambier",
-                                      "Pacific/Guadalcanal",
-                                      "Pacific/Guam",
-                                      "Pacific/Honolulu",
-                                      "Pacific/Johnston",
-                                      "Pacific/Kanton",
-                                      "Pacific/Kiritimati",
-                                      "Pacific/Kosrae",
-                                      "Pacific/Kwajalein",
-                                      "Pacific/Majuro",
-                                      "Pacific/Marquesas",
-                                      "Pacific/Midway",
-                                      "Pacific/Nauru",
-                                      "Pacific/Niue",
-                                      "Pacific/Norfolk",
-                                      "Pacific/Noumea",
-                                      "Pacific/Pago_Pago",
-                                      "Pacific/Palau",
-                                      "Pacific/Pitcairn",
-                                      "Pacific/Pohnpei",
-                                      "Pacific/Port_Moresby",
-                                      "Pacific/Rarotonga",
-                                      "Pacific/Saipan",
-                                      "Pacific/Samoa",
-                                      "Pacific/Tahiti",
-                                      "Pacific/Tarawa",
-                                      "Pacific/Tongatapu",
-                                      "Pacific/Wake",
-                                      "Pacific/Wallis",
-                                      "Pacific/Yap",
-                                      "UTC",
-                                      nullptr};
-
 // Helper to return a loaded time zone by value (UTC on error).
 time_zone LoadZone(const std::string& name) {
   time_zone tz;
diff --git a/absl/time/internal/cctz/src/time_zone_name_win.cc b/absl/time/internal/cctz/src/time_zone_name_win.cc
new file mode 100644
index 0000000..db5cd28
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_name_win.cc
@@ -0,0 +1,192 @@
+// Copyright 2025 Google Inc. All Rights Reserved.
+//
+// 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.
+
+// Android local modification: ifdef out entire file to avoid complicating
+// the build system.
+#if defined(_WIN32)
+
+#include "absl/time/internal/cctz/src/time_zone_name_win.h"
+
+#include "absl/base/config.h"
+
+#if !defined(NOMINMAX)
+#define NOMINMAX
+#endif  // !defined(NOMINMAX)
+#include <windows.h>
+
+#include <algorithm>
+#include <atomic>
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+namespace {
+
+// Define UChar as wchar_t here because Win32 APIs receive UTF-16 strings as
+// wchar_t* instead of char16_t*. Using char16_t would require additional casts.
+using UChar = wchar_t;
+
+enum UErrorCode : std::int32_t {
+  U_ZERO_ERROR = 0,
+  U_BUFFER_OVERFLOW_ERROR = 15,
+};
+
+bool U_SUCCESS(UErrorCode error) { return error <= U_ZERO_ERROR; }
+
+using ucal_getTimeZoneIDForWindowsID_func = std::int32_t(__cdecl*)(
+    const UChar* winid, std::int32_t len, const char* region, UChar* id,
+    std::int32_t id_capacity, UErrorCode* status);
+
+std::atomic<bool> g_unavailable;
+std::atomic<ucal_getTimeZoneIDForWindowsID_func>
+    g_ucal_getTimeZoneIDForWindowsID;
+
+template <typename T>
+static T AsProcAddress(HMODULE module, const char* name) {
+  static_assert(
+      std::is_pointer<T>::value &&
+          std::is_function<typename std::remove_pointer<T>::type>::value,
+      "T must be a function pointer type");
+  const auto proc_address = ::GetProcAddress(module, name);
+  return reinterpret_cast<T>(reinterpret_cast<void*>(proc_address));
+}
+
+std::wstring GetSystem32Dir() {
+  std::wstring result;
+  std::uint32_t len = std::max<std::uint32_t>(
+      static_cast<std::uint32_t>(std::min<size_t>(
+          result.capacity(), std::numeric_limits<std::uint32_t>::max())),
+      1);
+  do {
+    result.resize(len);
+    len = ::GetSystemDirectoryW(&result[0], len);
+  } while (len > result.size());
+  result.resize(len);
+  return result;
+}
+
+ucal_getTimeZoneIDForWindowsID_func LoadIcuGetTimeZoneIDForWindowsID() {
+  // This function is intended to be lock free to avoid potential deadlocks
+  // with loader-lock taken inside LoadLibraryW. As LoadLibraryW and
+  // GetProcAddress are idempotent unless the DLL is unloaded, we just need to
+  // make sure global variables are read/written atomically, where
+  // memory_order_relaxed is also acceptable.
+
+  if (g_unavailable.load(std::memory_order_relaxed)) {
+    return nullptr;
+  }
+
+  {
+    const auto ucal_getTimeZoneIDForWindowsIDRef =
+        g_ucal_getTimeZoneIDForWindowsID.load(std::memory_order_relaxed);
+    if (ucal_getTimeZoneIDForWindowsIDRef != nullptr) {
+      return ucal_getTimeZoneIDForWindowsIDRef;
+    }
+  }
+
+  const std::wstring system32_dir = GetSystem32Dir();
+  if (system32_dir.empty()) {
+    g_unavailable.store(true, std::memory_order_relaxed);
+    return nullptr;
+  }
+
+  // Here LoadLibraryExW(L"icu.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32) does
+  // not work if "icu.dll" is already loaded from somewhere other than the
+  // system32 directory. Specifying the full path with LoadLibraryW is more
+  // reliable.
+  const std::wstring icu_dll_path = system32_dir + L"\\icu.dll";
+  const HMODULE icu_dll = ::LoadLibraryW(icu_dll_path.c_str());
+  if (icu_dll == nullptr) {
+    g_unavailable.store(true, std::memory_order_relaxed);
+    return nullptr;
+  }
+
+  const auto ucal_getTimeZoneIDForWindowsIDRef =
+      AsProcAddress<ucal_getTimeZoneIDForWindowsID_func>(
+          icu_dll, "ucal_getTimeZoneIDForWindowsID");
+  if (ucal_getTimeZoneIDForWindowsIDRef != nullptr) {
+    g_unavailable.store(true, std::memory_order_relaxed);
+    return nullptr;
+  }
+
+  g_ucal_getTimeZoneIDForWindowsID.store(ucal_getTimeZoneIDForWindowsIDRef,
+                                         std::memory_order_relaxed);
+
+  return ucal_getTimeZoneIDForWindowsIDRef;
+}
+
+// Convert wchar_t array (UTF-16) to UTF-8 string
+std::string Utf16ToUtf8(const wchar_t* ptr, size_t size) {
+  if (size > std::numeric_limits<int>::max()) {
+    return std::string();
+  }
+  const int chars_len = static_cast<int>(size);
+  std::string result;
+  std::size_t len = std::max<std::size_t>(
+      std::min<size_t>(result.capacity(), std::numeric_limits<int>::max()), 1);
+  do {
+    result.resize(len);
+    // TODO: Switch to std::string::data() when we require C++17 or higher.
+    len = static_cast<std::size_t>(::WideCharToMultiByte(
+        CP_UTF8, WC_ERR_INVALID_CHARS, ptr, chars_len, &result[0],
+        static_cast<int>(len), nullptr, nullptr));
+  } while (len > result.size());
+  result.resize(len);
+  return result;
+}
+
+}  // namespace
+
+std::string GetWindowsLocalTimeZone() {
+  const auto getTimeZoneIDForWindowsID = LoadIcuGetTimeZoneIDForWindowsID();
+  if (getTimeZoneIDForWindowsID == nullptr) {
+    return std::string();
+  }
+
+  DYNAMIC_TIME_ZONE_INFORMATION info = {};
+  if (::GetDynamicTimeZoneInformation(&info) == TIME_ZONE_ID_INVALID) {
+    return std::string();
+  }
+
+  std::wstring result;
+  std::size_t len = std::max<std::size_t>(
+      std::min<size_t>(result.capacity(), std::numeric_limits<int>::max()), 1);
+  for (;;) {
+    UErrorCode status = U_ZERO_ERROR;
+    result.resize(len);
+    len = static_cast<std::size_t>(
+        getTimeZoneIDForWindowsID(info.TimeZoneKeyName, -1, nullptr, &result[0],
+                                  static_cast<int>(len), &status));
+    if (U_SUCCESS(status)) {
+      return Utf16ToUtf8(result.data(), len);
+    }
+    if (status != U_BUFFER_OVERFLOW_ERROR) {
+      return std::string();
+    }
+  }
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // _WIN32
diff --git a/absl/time/internal/cctz/src/time_zone_name_win.h b/absl/time/internal/cctz/src/time_zone_name_win.h
new file mode 100644
index 0000000..f53b5a9
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_name_win.h
@@ -0,0 +1,37 @@
+// Copyright 2025 Google Inc. All Rights Reserved.
+//
+// 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.
+
+#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_NAME_WIN_H_
+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_NAME_WIN_H_
+
+#include <string>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+// Returns the local time zone ID in IANA format (e.g. "America/Los_Angeles"),
+// or the empty string on failure. Not supported on Windows 10 1809 and earlier,
+// where "icu.dll" is not available in the System32 directory.
+std::string GetWindowsLocalTimeZone();
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_NAME_WIN_H_
diff --git a/absl/time/internal/cctz/testdata/version b/absl/time/internal/cctz/testdata/version
index ef468ad..cb3be9a 100644
--- a/absl/time/internal/cctz/testdata/version
+++ b/absl/time/internal/cctz/testdata/version
@@ -1 +1 @@
-2025b
+2025c
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada b/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada
index 18d0d14..0d8c993 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel b/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel
index 18d0d14..0d8c993 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana b/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana
index 18d0d14..0d8c993 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte
index 18d0d14..0d8c993 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab b/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab
index 402c015..4ae3523 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab
+++ b/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab
@@ -3,22 +3,22 @@
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 #
-# From Paul Eggert (2023-09-06):
+# From Paul Eggert (2025-07-01):
 # This file contains a table of two-letter country codes.  Columns are
-# separated by a single tab.  Lines beginning with '#' are comments.
+# separated by a single tab.  Lines beginning with ‘#’ are comments.
 # All text uses UTF-8 encoding.  The columns of the table are as follows:
 #
 # 1.  ISO 3166-1 alpha-2 country code, current as of
-#     ISO/TC 46 N1108 (2023-04-05).  See: ISO/TC 46 Documents
+#     ISO/TC 46 N1127 (2024-02-29).  See: ISO/TC 46 Documents
 #     https://www.iso.org/committee/48750.html?view=documents
 # 2.  The usual English name for the coded region.  This sometimes
 #     departs from ISO-listed names, sometimes so that sorted subsets
-#     of names are useful (e.g., "Samoa (American)" and "Samoa
-#     (western)" rather than "American Samoa" and "Samoa"),
+#     of names are useful (e.g., “Samoa (American)” and “Samoa
+#     (western)” rather than “American Samoa” and “Samoa”),
 #     sometimes to avoid confusion among non-experts (e.g.,
-#     "Czech Republic" and "Turkey" rather than "Czechia" and "Türkiye"),
-#     and sometimes to omit needless detail or churn (e.g., "Netherlands"
-#     rather than "Netherlands (the)" or "Netherlands (Kingdom of the)").
+#     “Czech Republic” and “Turkey” rather than “Czechia” and “Türkiye”),
+#     and sometimes to omit needless detail or churn (e.g., “Netherlands”
+#     rather than “Netherlands (the)” or “Netherlands (Kingdom of the)”).
 #
 # The table is sorted by country code.
 #
@@ -71,7 +71,7 @@
 CF	Central African Rep.
 CG	Congo (Rep.)
 CH	Switzerland
-CI	Côte d'Ivoire
+CI	Côte d’Ivoire
 CK	Cook Islands
 CL	Chile
 CM	Cameroon
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab b/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
index 36535bd..cd43e3d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
+++ b/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
@@ -2,15 +2,15 @@
 #
 # This file is in the public domain.
 #
-# From Paul Eggert (2018-06-27):
+# From Paul Eggert (2025-05-15):
 # This file contains a table where each row stands for a timezone where
 # civil timestamps have agreed since 1970.  Columns are separated by
-# a single tab.  Lines beginning with '#' are comments.  All text uses
+# a single tab.  Lines beginning with ‘#’ are comments.  All text uses
 # UTF-8 encoding.  The columns of the table are as follows:
 #
 # 1.  The countries that overlap the timezone, as a comma-separated list
-#     of ISO 3166 2-character country codes.  See the file 'iso3166.tab'.
-# 2.  Latitude and longitude of the timezone's principal location
+#     of ISO 3166 2-character country codes.
+# 2.  Latitude and longitude of the timezone’s principal location
 #     in ISO 6709 sign-degrees-minutes-seconds format,
 #     either ±DDMM±DDDMM or ±DDMMSS±DDDMMSS,
 #     first latitude (+ is north), then longitude (+ is east).
@@ -197,7 +197,7 @@
 KZ	+5312+06337	Asia/Qostanay	Qostanay/Kostanay/Kustanay
 KZ	+5017+05710	Asia/Aqtobe	Aqtöbe/Aktobe
 KZ	+4431+05016	Asia/Aqtau	Mangghystaū/Mankistau
-KZ	+4707+05156	Asia/Atyrau	Atyraū/Atirau/Gur'yev
+KZ	+4707+05156	Asia/Atyrau	AtyraÅ«/Atirau/Gur’yev
 KZ	+5113+05121	Asia/Oral	West Kazakhstan
 LB	+3353+03530	Asia/Beirut
 LK	+0656+07951	Asia/Colombo
@@ -245,7 +245,7 @@
 PF	-1732-14934	Pacific/Tahiti	Society Islands
 PF	-0900-13930	Pacific/Marquesas	Marquesas Islands
 PF	-2308-13457	Pacific/Gambier	Gambier Islands
-PG,AQ,FM	-0930+14710	Pacific/Port_Moresby	Papua New Guinea (most areas), Chuuk, Yap, Dumont d'Urville
+PG,AQ,FM	-0930+14710	Pacific/Port_Moresby	Papua New Guinea (most areas), Chuuk, Yap, Dumont d’Urville
 PG	-0613+15534	Pacific/Bougainville	Bougainville
 PH	+143512+1205804	Asia/Manila
 PK	+2452+06703	Asia/Karachi
@@ -265,7 +265,7 @@
 RS,BA,HR,ME,MK,SI	+4450+02030	Europe/Belgrade
 RU	+5443+02030	Europe/Kaliningrad	MSK-01 - Kaliningrad
 RU	+554521+0373704	Europe/Moscow	MSK+00 - Moscow area
-# Mention RU and UA alphabetically.  See "territorial claims" above.
+# Mention RU and UA alphabetically.  See “territorial claims” above.
 RU,UA	+4457+03406	Europe/Simferopol	Crimea
 RU	+5836+04939	Europe/Kirov	MSK+00 - Kirov
 RU	+4844+04425	Europe/Volgograd	MSK+00 - Volgograd
@@ -353,20 +353,20 @@
 # The next section contains experimental tab-separated comments for
 # use by user agents like tzselect that identify continents and oceans.
 #
-# For example, the comment "#@AQ<tab>Antarctica/" means the country code
+# For example, the comment ‘#@AQ<tab>Antarctica/’ means the country code
 # AQ is in the continent Antarctica regardless of the Zone name,
 # so Pacific/Auckland should be listed under Antarctica as well as
-# under the Pacific because its line's country codes include AQ.
+# under the Pacific because its line’s country codes include AQ.
 #
 # If more than one country code is affected each is listed separated
-# by commas, e.g., #@IS,SH<tab>Atlantic/".  If a country code is in
+# by commas, e.g., ‘#@IS,SH<tab>Atlantic/’.  If a country code is in
 # more than one continent or ocean, each is listed separated by
-# commas, e.g., the second column of "#@CY,TR<tab>Asia/,Europe/".
+# commas, e.g., the second column of ‘#@CY,TR<tab>Asia/,Europe/’.
 #
 # These experimental comments are present only for country codes where
 # the continent or ocean is not already obvious from the Zone name.
 # For example, there is no such comment for RU since it already
-# corresponds to Zone names starting with both "Europe/" and "Asia/".
+# corresponds to Zone names starting with both ‘Europe/’ and ‘Asia/’.
 #
 #@AQ	Antarctica/
 #@IS,SH	Atlantic/
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/zonenow.tab b/absl/time/internal/cctz/testdata/zoneinfo/zonenow.tab
index 093f0a0..1d64b39 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/zonenow.tab
+++ b/absl/time/internal/cctz/testdata/zoneinfo/zonenow.tab
@@ -5,12 +5,12 @@
 # From Paul Eggert (2023-12-18):
 # This file contains a table where each row stands for a timezone
 # where civil timestamps are predicted to agree from now on.
-# This file is like zone1970.tab (see zone1970.tab's comments),
+# This file is like zone1970.tab (see zone1970.tab’s comments),
 # but with the following changes:
 #
 # 1.  Each timezone corresponds to a set of clocks that are planned
 #     to agree from now on.  This is a larger set of clocks than in
-#     zone1970.tab, where each timezone's clocks must agree from 1970 on.
+#     zone1970.tab, where each timezone’s clocks must agree from 1970 on.
 # 2.  The first column is irrelevant and ignored.
 # 3.  The table is sorted in a different way:
 #     first by standard time UTC offset;
@@ -29,19 +29,19 @@
 #XX	coordinates	TZ	comments
 #
 # -11 - SST
-XX	-1416-17042	Pacific/Pago_Pago	Midway; Samoa ("SST")
+XX	-1416-17042	Pacific/Pago_Pago	Midway; Samoa (SST)
 #
 # -11
 XX	-1901-16955	Pacific/Niue	Niue
 #
 # -10 - HST
-XX	+211825-1575130	Pacific/Honolulu	Hawaii ("HST")
+XX	+211825-1575130	Pacific/Honolulu	Hawaii (HST)
 #
 # -10
 XX	-1732-14934	Pacific/Tahiti	Tahiti; Cook Islands
 #
 # -10/-09 - HST / HDT (North America DST)
-XX	+515248-1763929	America/Adak	western Aleutians in Alaska ("HST/HDT")
+XX	+515248-1763929	America/Adak	western Aleutians in Alaska (HST/HDT)
 #
 # -09:30
 XX	-0900-13930	Pacific/Marquesas	Marquesas
@@ -50,58 +50,58 @@
 XX	-2308-13457	Pacific/Gambier	Gambier
 #
 # -09/-08 - AKST/AKDT (North America DST)
-XX	+611305-1495401	America/Anchorage	most of Alaska ("AKST/AKDT")
+XX	+611305-1495401	America/Anchorage	most of Alaska (AKST/AKDT)
 #
 # -08
 XX	-2504-13005	Pacific/Pitcairn	Pitcairn
 #
 # -08/-07 - PST/PDT (North America DST)
-XX	+340308-1181434	America/Los_Angeles	Pacific ("PST/PDT") - US & Canada; Mexico near US border
+XX	+340308-1181434	America/Los_Angeles	Pacific (PST/PDT) - US & Canada; Mexico near US border
 #
 # -07 - MST
-XX	+332654-1120424	America/Phoenix	Mountain Standard ("MST") - Arizona; western Mexico; Yukon
+XX	+332654-1120424	America/Phoenix	Mountain Standard (MST) - Arizona; western Mexico; Yukon
 #
 # -07/-06 - MST/MDT (North America DST)
-XX	+394421-1045903	America/Denver	Mountain ("MST/MDT") - US & Canada; Mexico near US border
+XX	+394421-1045903	America/Denver	Mountain (MST/MDT) - US & Canada; Mexico near US border
 #
 # -06
 XX	-0054-08936	Pacific/Galapagos	Galápagos
 #
 # -06 - CST
-XX	+1924-09909	America/Mexico_City	Central Standard ("CST") - Saskatchewan; central Mexico; Central America
+XX	+1924-09909	America/Mexico_City	Central Standard (CST) - Saskatchewan; central Mexico; Central America
 #
 # -06/-05 (Chile DST)
 XX	-2709-10926	Pacific/Easter	Easter Island
 #
 # -06/-05 - CST/CDT (North America DST)
-XX	+415100-0873900	America/Chicago	Central ("CST/CDT") - US & Canada; Mexico near US border
+XX	+415100-0873900	America/Chicago	Central (CST/CDT) - US & Canada; Mexico near US border
 #
 # -05
 XX	-1203-07703	America/Lima	eastern South America
 #
 # -05 - EST
-XX	+175805-0764736	America/Jamaica	Eastern Standard ("EST") - Caymans; Jamaica; eastern Mexico; Panama
+XX	+175805-0764736	America/Jamaica	Eastern Standard (EST) - Caymans; Jamaica; eastern Mexico; Panama
 #
 # -05/-04 - CST/CDT (Cuba DST)
 XX	+2308-08222	America/Havana	Cuba
 #
 # -05/-04 - EST/EDT (North America DST)
-XX	+404251-0740023	America/New_York	Eastern ("EST/EDT") - US & Canada
+XX	+404251-0740023	America/New_York	Eastern (EST/EDT) - US & Canada
 #
 # -04
 XX	+1030-06656	America/Caracas	western South America
 #
 # -04 - AST
-XX	+1828-06954	America/Santo_Domingo	Atlantic Standard ("AST") - eastern Caribbean
+XX	+1828-06954	America/Santo_Domingo	Atlantic Standard (AST) - eastern Caribbean
 #
 # -04/-03 (Chile DST)
 XX	-3327-07040	America/Santiago	most of Chile
 #
 # -04/-03 - AST/ADT (North America DST)
-XX	+4439-06336	America/Halifax	Atlantic ("AST/ADT") - Canada; Bermuda
+XX	+4439-06336	America/Halifax	Atlantic (AST/ADT) - Canada; Bermuda
 #
 # -03:30/-02:30 - NST/NDT (North America DST)
-XX	+4734-05243	America/St_Johns	Newfoundland ("NST/NDT")
+XX	+4734-05243	America/St_Johns	Newfoundland (NST/NDT)
 #
 # -03
 XX	-2332-04637	America/Sao_Paulo	eastern and southern South America
@@ -122,43 +122,43 @@
 XX	+3744-02540	Atlantic/Azores	Azores
 #
 # +00 - GMT
-XX	+0519-00402	Africa/Abidjan	far western Africa; Iceland ("GMT")
+XX	+0519-00402	Africa/Abidjan	far western Africa; Iceland (GMT)
 #
 # +00/+01 - GMT/BST (EU DST)
-XX	+513030-0000731	Europe/London	United Kingdom ("GMT/BST")
+XX	+513030-0000731	Europe/London	United Kingdom (GMT/BST)
 #
 # +00/+01 - WET/WEST (EU DST)
-XX	+3843-00908	Europe/Lisbon	western Europe ("WET/WEST")
+XX	+3843-00908	Europe/Lisbon	western Europe (WET/WEST)
 #
 # +00/+02 - Troll DST
 XX	-720041+0023206	Antarctica/Troll	Troll Station in Antarctica
 #
 # +01 - CET
-XX	+3647+00303	Africa/Algiers	Algeria, Tunisia ("CET")
+XX	+3647+00303	Africa/Algiers	Algeria, Tunisia (CET)
 #
 # +01 - WAT
-XX	+0627+00324	Africa/Lagos	western Africa ("WAT")
+XX	+0627+00324	Africa/Lagos	western Africa (WAT)
 #
 # +01/+00 - IST/GMT (EU DST in reverse)
-XX	+5320-00615	Europe/Dublin	Ireland ("IST/GMT")
+XX	+5320-00615	Europe/Dublin	Ireland (IST/GMT)
 #
 # +01/+00 - (Morocco DST)
 XX	+3339-00735	Africa/Casablanca	Morocco
 #
 # +01/+02 - CET/CEST (EU DST)
-XX	+4852+00220	Europe/Paris	central Europe ("CET/CEST")
+XX	+4852+00220	Europe/Paris	central Europe (CET/CEST)
 #
 # +02 - CAT
-XX	-2558+03235	Africa/Maputo	central Africa ("CAT")
+XX	-2558+03235	Africa/Maputo	central Africa (CAT)
 #
 # +02 - EET
-XX	+3254+01311	Africa/Tripoli	Libya; Kaliningrad ("EET")
+XX	+3254+01311	Africa/Tripoli	Libya; Kaliningrad (EET)
 #
 # +02 - SAST
-XX	-2615+02800	Africa/Johannesburg	southern Africa ("SAST")
+XX	-2615+02800	Africa/Johannesburg	southern Africa (SAST)
 #
 # +02/+03 - EET/EEST (EU DST)
-XX	+3758+02343	Europe/Athens	eastern Europe ("EET/EEST")
+XX	+3758+02343	Europe/Athens	eastern Europe (EET/EEST)
 #
 # +02/+03 - EET/EEST (Egypt DST)
 XX	+3003+03115	Africa/Cairo	Egypt
@@ -179,10 +179,10 @@
 XX	+4101+02858	Europe/Istanbul	Near East; Belarus
 #
 # +03 - EAT
-XX	-0117+03649	Africa/Nairobi	eastern Africa ("EAT")
+XX	-0117+03649	Africa/Nairobi	eastern Africa (EAT)
 #
 # +03 - MSK
-XX	+554521+0373704	Europe/Moscow	Moscow ("MSK")
+XX	+554521+0373704	Europe/Moscow	Moscow (MSK)
 #
 # +03:30
 XX	+3540+05126	Asia/Tehran	Iran
@@ -197,13 +197,13 @@
 XX	+4120+06918	Asia/Tashkent	Russia; Kazakhstan; Tajikistan; Turkmenistan; Uzbekistan; Maldives
 #
 # +05 - PKT
-XX	+2452+06703	Asia/Karachi	Pakistan ("PKT")
+XX	+2452+06703	Asia/Karachi	Pakistan (PKT)
 #
 # +05:30
 XX	+0656+07951	Asia/Colombo	Sri Lanka
 #
 # +05:30 - IST
-XX	+2232+08822	Asia/Kolkata	India ("IST")
+XX	+2232+08822	Asia/Kolkata	India (IST)
 #
 # +05:45
 XX	+2743+08519	Asia/Kathmandu	Nepal
@@ -218,25 +218,25 @@
 XX	+1345+10031	Asia/Bangkok	Russia; Indochina; Christmas Island
 #
 # +07 - WIB
-XX	-0610+10648	Asia/Jakarta	Indonesia ("WIB")
+XX	-0610+10648	Asia/Jakarta	Indonesia (WIB)
 #
 # +08
 XX	+0117+10351	Asia/Singapore	Russia; Brunei; Malaysia; Singapore; Concordia
 #
 # +08 - AWST
-XX	-3157+11551	Australia/Perth	Western Australia ("AWST")
+XX	-3157+11551	Australia/Perth	Western Australia (AWST)
 #
 # +08 - CST
-XX	+3114+12128	Asia/Shanghai	China ("CST")
+XX	+3114+12128	Asia/Shanghai	China (CST)
 #
 # +08 - HKT
-XX	+2217+11409	Asia/Hong_Kong	Hong Kong ("HKT")
+XX	+2217+11409	Asia/Hong_Kong	Hong Kong (HKT)
 #
 # +08 - PHT
-XX	+143512+1205804	Asia/Manila	Philippines ("PHT")
+XX	+143512+1205804	Asia/Manila	Philippines (PHT)
 #
 # +08 - WITA
-XX	-0507+11924	Asia/Makassar	Indonesia ("WITA")
+XX	-0507+11924	Asia/Makassar	Indonesia (WITA)
 #
 # +08:45
 XX	-3143+12852	Australia/Eucla	Eucla
@@ -245,31 +245,31 @@
 XX	+5203+11328	Asia/Chita	Russia; Palau; East Timor
 #
 # +09 - JST
-XX	+353916+1394441	Asia/Tokyo	Japan ("JST"); Eyre Bird Observatory
+XX	+353916+1394441	Asia/Tokyo	Japan (JST); Eyre Bird Observatory
 #
 # +09 - KST
-XX	+3733+12658	Asia/Seoul	Korea ("KST")
+XX	+3733+12658	Asia/Seoul	Korea (KST)
 #
 # +09 - WIT
-XX	-0232+14042	Asia/Jayapura	Indonesia ("WIT")
+XX	-0232+14042	Asia/Jayapura	Indonesia (WIT)
 #
 # +09:30 - ACST
-XX	-1228+13050	Australia/Darwin	Northern Territory ("ACST")
+XX	-1228+13050	Australia/Darwin	Northern Territory (ACST)
 #
 # +09:30/+10:30 - ACST/ACDT (Australia DST)
-XX	-3455+13835	Australia/Adelaide	South Australia ("ACST/ACDT")
+XX	-3455+13835	Australia/Adelaide	South Australia (ACST/ACDT)
 #
 # +10
-XX	+4310+13156	Asia/Vladivostok	Russia; Yap; Chuuk; Papua New Guinea; Dumont d'Urville
+XX	+4310+13156	Asia/Vladivostok	Russia; Yap; Chuuk; Papua New Guinea; Dumont d’Urville
 #
 # +10 - AEST
-XX	-2728+15302	Australia/Brisbane	Queensland ("AEST")
+XX	-2728+15302	Australia/Brisbane	Queensland (AEST)
 #
 # +10 - ChST
-XX	+1328+14445	Pacific/Guam	Mariana Islands ("ChST")
+XX	+1328+14445	Pacific/Guam	Mariana Islands (ChST)
 #
 # +10/+11 - AEST/AEDT (Australia DST)
-XX	-3352+15113	Australia/Sydney	southeast Australia ("AEST/AEDT")
+XX	-3352+15113	Australia/Sydney	southeast Australia (AEST/AEDT)
 #
 # +10:30/+11
 XX	-3133+15905	Australia/Lord_Howe	Lord Howe Island
@@ -284,7 +284,7 @@
 XX	+5301+15839	Asia/Kamchatka	Russia; Tuvalu; Fiji; etc.
 #
 # +12/+13 (New Zealand DST)
-XX	-3652+17446	Pacific/Auckland	New Zealand ("NZST/NZDT")
+XX	-3652+17446	Pacific/Auckland	New Zealand (NZST/NZDT)
 #
 # +12:45/+13:45 (Chatham DST)
 XX	-4357-17633	Pacific/Chatham	Chatham Islands
diff --git a/absl/time/time.cc b/absl/time/time.cc
index d983c12..faef864 100644
--- a/absl/time/time.cc
+++ b/absl/time/time.cc
@@ -249,8 +249,8 @@
 int64_t ToUnixNanos(Time t) {
   if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
       time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 33 == 0) {
-    return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) *
-            1000 * 1000 * 1000) +
+    return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) * 1000 *
+            1000 * 1000) +
            (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4);
   }
   return FloorToUnit(time_internal::ToUnixDuration(t), absl::Nanoseconds(1));
@@ -259,8 +259,8 @@
 int64_t ToUnixMicros(Time t) {
   if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
       time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 43 == 0) {
-    return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) *
-            1000 * 1000) +
+    return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) * 1000 *
+            1000) +
            (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4000);
   }
   return FloorToUnit(time_internal::ToUnixDuration(t), absl::Microseconds(1));
diff --git a/absl/time/time.h b/absl/time/time.h
index 53bca90..8e8df2e 100644
--- a/absl/time/time.h
+++ b/absl/time/time.h
@@ -589,9 +589,10 @@
     }
     return time_internal::MakePosDoubleDuration(n);
   } else {
-    if (std::isnan(n))
-      return std::signbit(n) ? -InfiniteDuration() : InfiniteDuration();
-    if (n <= (std::numeric_limits<int64_t>::min)()) return -InfiniteDuration();
+    if (std::isnan(n)) return -InfiniteDuration();
+    if (n <= static_cast<T>((std::numeric_limits<int64_t>::min)())) {
+      return -InfiniteDuration();
+    }
     return -time_internal::MakePosDoubleDuration(-n);
   }
 }
@@ -731,7 +732,6 @@
 // `absl::ParseDuration()`.
 bool AbslParseFlag(absl::string_view text, Duration* dst, std::string* error);
 
-
 // AbslUnparseFlag()
 //
 // Unparses a Duration value into a command-line string representation using
@@ -1680,14 +1680,16 @@
   return (v <= (std::numeric_limits<int64_t>::max)() / 60 &&
           v >= (std::numeric_limits<int64_t>::min)() / 60)
              ? MakeDuration(v * 60)
-             : v > 0 ? InfiniteDuration() : -InfiniteDuration();
+         : v > 0 ? InfiniteDuration()
+                 : -InfiniteDuration();
 }
 ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration FromInt64(int64_t v,
                                                            std::ratio<3600>) {
   return (v <= (std::numeric_limits<int64_t>::max)() / 3600 &&
           v >= (std::numeric_limits<int64_t>::min)() / 3600)
              ? MakeDuration(v * 3600)
-             : v > 0 ? InfiniteDuration() : -InfiniteDuration();
+         : v > 0 ? InfiniteDuration()
+                 : -InfiniteDuration();
 }
 
 // IsValidRep64<T>(0) is true if the expression `int64_t{std::declval<T>()}` is
@@ -1805,13 +1807,12 @@
                        (std::numeric_limits<int64_t>::min)()
                    ? InfiniteDuration()
                    : time_internal::MakeDuration(-time_internal::GetRepHi(d))
-             : time_internal::IsInfiniteDuration(d)
-                   ? time_internal::OppositeInfinity(d)
-                   : time_internal::MakeDuration(
-                         time_internal::NegateAndSubtractOne(
-                             time_internal::GetRepHi(d)),
-                         time_internal::kTicksPerSecond -
-                             time_internal::GetRepLo(d));
+         : time_internal::IsInfiniteDuration(d)
+             ? time_internal::OppositeInfinity(d)
+             : time_internal::MakeDuration(
+                   time_internal::NegateAndSubtractOne(
+                       time_internal::GetRepHi(d)),
+                   time_internal::kTicksPerSecond - time_internal::GetRepLo(d));
 }
 
 ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration InfiniteDuration() {
diff --git a/absl/time/time_test.cc b/absl/time/time_test.cc
index 7033326..6714a27 100644
--- a/absl/time/time_test.cc
+++ b/absl/time/time_test.cc
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 #include "absl/time/time.h"
+
 #include "absl/time/civil_time.h"
 
 #if defined(_MSC_VER)
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel
index 0668a2e..cac5e4b 100644
--- a/absl/types/BUILD.bazel
+++ b/absl/types/BUILD.bazel
@@ -13,6 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
diff --git a/absl/types/compare.h b/absl/types/compare.h
index 3cf4a91..edf1039 100644
--- a/absl/types/compare.h
+++ b/absl/types/compare.h
@@ -120,8 +120,7 @@
 // A no-op expansion that can be followed by a semicolon at class level.
 #define ABSL_COMPARE_INLINE_BASECLASS_DECL(name) static_assert(true, "")
 
-#define ABSL_COMPARE_INLINE_SUBCLASS_DECL(type, name) \
-  static const type name
+#define ABSL_COMPARE_INLINE_SUBCLASS_DECL(type, name) static const type name
 
 #define ABSL_COMPARE_INLINE_INIT(type, name, init) \
   inline constexpr type type::name(init)
@@ -190,28 +189,28 @@
   ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, unordered);
 
   // Comparisons
-  friend constexpr bool operator==(
-      partial_ordering v, compare_internal::OnlyLiteralZero) noexcept {
+  friend constexpr bool operator==(partial_ordering v,
+                                   compare_internal::OnlyLiteralZero) noexcept {
     return v.is_ordered() && v.value_ == 0;
   }
-  friend constexpr bool operator!=(
-      partial_ordering v, compare_internal::OnlyLiteralZero) noexcept {
+  friend constexpr bool operator!=(partial_ordering v,
+                                   compare_internal::OnlyLiteralZero) noexcept {
     return !v.is_ordered() || v.value_ != 0;
   }
-  friend constexpr bool operator<(
-      partial_ordering v, compare_internal::OnlyLiteralZero) noexcept {
+  friend constexpr bool operator<(partial_ordering v,
+                                  compare_internal::OnlyLiteralZero) noexcept {
     return v.is_ordered() && v.value_ < 0;
   }
-  friend constexpr bool operator<=(
-      partial_ordering v, compare_internal::OnlyLiteralZero) noexcept {
+  friend constexpr bool operator<=(partial_ordering v,
+                                   compare_internal::OnlyLiteralZero) noexcept {
     return v.is_ordered() && v.value_ <= 0;
   }
-  friend constexpr bool operator>(
-      partial_ordering v, compare_internal::OnlyLiteralZero) noexcept {
+  friend constexpr bool operator>(partial_ordering v,
+                                  compare_internal::OnlyLiteralZero) noexcept {
     return v.is_ordered() && v.value_ > 0;
   }
-  friend constexpr bool operator>=(
-      partial_ordering v, compare_internal::OnlyLiteralZero) noexcept {
+  friend constexpr bool operator>=(partial_ordering v,
+                                   compare_internal::OnlyLiteralZero) noexcept {
     return v.is_ordered() && v.value_ >= 0;
   }
   friend constexpr bool operator==(compare_internal::OnlyLiteralZero,
@@ -278,28 +277,28 @@
                                      : partial_ordering::greater);
   }
   // Comparisons
-  friend constexpr bool operator==(
-      weak_ordering v, compare_internal::OnlyLiteralZero) noexcept {
+  friend constexpr bool operator==(weak_ordering v,
+                                   compare_internal::OnlyLiteralZero) noexcept {
     return v.value_ == 0;
   }
-  friend constexpr bool operator!=(
-      weak_ordering v, compare_internal::OnlyLiteralZero) noexcept {
+  friend constexpr bool operator!=(weak_ordering v,
+                                   compare_internal::OnlyLiteralZero) noexcept {
     return v.value_ != 0;
   }
-  friend constexpr bool operator<(
-      weak_ordering v, compare_internal::OnlyLiteralZero) noexcept {
+  friend constexpr bool operator<(weak_ordering v,
+                                  compare_internal::OnlyLiteralZero) noexcept {
     return v.value_ < 0;
   }
-  friend constexpr bool operator<=(
-      weak_ordering v, compare_internal::OnlyLiteralZero) noexcept {
+  friend constexpr bool operator<=(weak_ordering v,
+                                   compare_internal::OnlyLiteralZero) noexcept {
     return v.value_ <= 0;
   }
-  friend constexpr bool operator>(
-      weak_ordering v, compare_internal::OnlyLiteralZero) noexcept {
+  friend constexpr bool operator>(weak_ordering v,
+                                  compare_internal::OnlyLiteralZero) noexcept {
     return v.value_ > 0;
   }
-  friend constexpr bool operator>=(
-      weak_ordering v, compare_internal::OnlyLiteralZero) noexcept {
+  friend constexpr bool operator>=(weak_ordering v,
+                                   compare_internal::OnlyLiteralZero) noexcept {
     return v.value_ >= 0;
   }
   friend constexpr bool operator==(compare_internal::OnlyLiteralZero,
@@ -370,28 +369,28 @@
                : (value_ < 0 ? weak_ordering::less : weak_ordering::greater);
   }
   // Comparisons
-  friend constexpr bool operator==(
-      strong_ordering v, compare_internal::OnlyLiteralZero) noexcept {
+  friend constexpr bool operator==(strong_ordering v,
+                                   compare_internal::OnlyLiteralZero) noexcept {
     return v.value_ == 0;
   }
-  friend constexpr bool operator!=(
-      strong_ordering v, compare_internal::OnlyLiteralZero) noexcept {
+  friend constexpr bool operator!=(strong_ordering v,
+                                   compare_internal::OnlyLiteralZero) noexcept {
     return v.value_ != 0;
   }
-  friend constexpr bool operator<(
-      strong_ordering v, compare_internal::OnlyLiteralZero) noexcept {
+  friend constexpr bool operator<(strong_ordering v,
+                                  compare_internal::OnlyLiteralZero) noexcept {
     return v.value_ < 0;
   }
-  friend constexpr bool operator<=(
-      strong_ordering v, compare_internal::OnlyLiteralZero) noexcept {
+  friend constexpr bool operator<=(strong_ordering v,
+                                   compare_internal::OnlyLiteralZero) noexcept {
     return v.value_ <= 0;
   }
-  friend constexpr bool operator>(
-      strong_ordering v, compare_internal::OnlyLiteralZero) noexcept {
+  friend constexpr bool operator>(strong_ordering v,
+                                  compare_internal::OnlyLiteralZero) noexcept {
     return v.value_ > 0;
   }
-  friend constexpr bool operator>=(
-      strong_ordering v, compare_internal::OnlyLiteralZero) noexcept {
+  friend constexpr bool operator>=(strong_ordering v,
+                                   compare_internal::OnlyLiteralZero) noexcept {
     return v.value_ >= 0;
   }
   friend constexpr bool operator==(compare_internal::OnlyLiteralZero,
@@ -451,14 +450,16 @@
 // SFINAE prevents implicit conversions to bool (such as from int).
 template <typename BoolT,
           absl::enable_if_t<std::is_same<bool, BoolT>::value, int> = 0>
-constexpr bool compare_result_as_less_than(const BoolT r) { return r; }
+constexpr bool compare_result_as_less_than(const BoolT r) {
+  return r;
+}
 constexpr bool compare_result_as_less_than(const absl::weak_ordering r) {
   return r < 0;
 }
 
 template <typename Compare, typename K, typename LK>
-constexpr bool do_less_than_comparison(const Compare &compare, const K &x,
-                                       const LK &y) {
+constexpr bool do_less_than_comparison(const Compare& compare, const K& x,
+                                       const LK& y) {
   return compare_result_as_less_than(compare(x, y));
 }
 
@@ -468,34 +469,34 @@
 template <typename Int,
           absl::enable_if_t<std::is_same<int, Int>::value, int> = 0>
 constexpr absl::weak_ordering compare_result_as_ordering(const Int c) {
-  return c < 0 ? absl::weak_ordering::less
-               : c == 0 ? absl::weak_ordering::equivalent
-                        : absl::weak_ordering::greater;
+  return c < 0    ? absl::weak_ordering::less
+         : c == 0 ? absl::weak_ordering::equivalent
+                  : absl::weak_ordering::greater;
 }
 constexpr absl::weak_ordering compare_result_as_ordering(
     const absl::weak_ordering c) {
   return c;
 }
 
-template <
-    typename Compare, typename K, typename LK,
-    absl::enable_if_t<!std::is_same<bool, absl::result_of_t<Compare(
-                                              const K &, const LK &)>>::value,
-                      int> = 0>
-constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare,
-                                                      const K &x, const LK &y) {
+template <typename Compare, typename K, typename LK,
+          absl::enable_if_t<
+              !std::is_same<
+                  bool, absl::result_of_t<Compare(const K&, const LK&)>>::value,
+              int> = 0>
+constexpr absl::weak_ordering do_three_way_comparison(const Compare& compare,
+                                                      const K& x, const LK& y) {
   return compare_result_as_ordering(compare(x, y));
 }
-template <
-    typename Compare, typename K, typename LK,
-    absl::enable_if_t<std::is_same<bool, absl::result_of_t<Compare(
-                                             const K &, const LK &)>>::value,
-                      int> = 0>
-constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare,
-                                                      const K &x, const LK &y) {
-  return compare(x, y) ? absl::weak_ordering::less
-                       : compare(y, x) ? absl::weak_ordering::greater
-                                       : absl::weak_ordering::equivalent;
+template <typename Compare, typename K, typename LK,
+          absl::enable_if_t<
+              std::is_same<
+                  bool, absl::result_of_t<Compare(const K&, const LK&)>>::value,
+              int> = 0>
+constexpr absl::weak_ordering do_three_way_comparison(const Compare& compare,
+                                                      const K& x, const LK& y) {
+  return compare(x, y)   ? absl::weak_ordering::less
+         : compare(y, x) ? absl::weak_ordering::greater
+                         : absl::weak_ordering::equivalent;
 }
 
 }  // namespace compare_internal
diff --git a/absl/types/compare_test.cc b/absl/types/compare_test.cc
index 455cdbb..352c9f1 100644
--- a/absl/types/compare_test.cc
+++ b/absl/types/compare_test.cc
@@ -160,9 +160,9 @@
 struct WeakOrderingLess {
   template <typename T>
   absl::weak_ordering operator()(const T& a, const T& b) const {
-    return a < b ? absl::weak_ordering::less
-                 : a == b ? absl::weak_ordering::equivalent
-                          : absl::weak_ordering::greater;
+    return a < b    ? absl::weak_ordering::less
+           : a == b ? absl::weak_ordering::equivalent
+                    : absl::weak_ordering::greater;
   }
 };
 
diff --git a/absl/types/internal/span.h b/absl/types/internal/span.h
index 1039f61..cdf3941 100644
--- a/absl/types/internal/span.h
+++ b/absl/types/internal/span.h
@@ -121,6 +121,7 @@
   using ConstData =
       decltype(span_internal::GetData(std::declval<const Container&>()));
   using MutData = decltype(span_internal::GetData(std::declval<Container&>()));
+
  public:
   static constexpr bool value = std::is_same<ConstData, MutData>::value;
 };
diff --git a/absl/types/optional.h b/absl/types/optional.h
index 65bba64..5b68a5b 100644
--- a/absl/types/optional.h
+++ b/absl/types/optional.h
@@ -31,10 +31,10 @@
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 using std::bad_optional_access;
-using std::optional;
 using std::make_optional;
-using std::nullopt_t;
 using std::nullopt;
+using std::nullopt_t;
+using std::optional;
 ABSL_NAMESPACE_END
 }  // namespace absl
 
diff --git a/absl/types/span.h b/absl/types/span.h
index 0e46ee6..03daac2 100644
--- a/absl/types/span.h
+++ b/absl/types/span.h
@@ -47,6 +47,9 @@
 //    * `absl::Span` has no static extent template parameter, nor constructors
 //      which exist only because of the static extent parameter.
 //    * `absl::Span` has an explicit mutable-reference constructor
+//    * `absl::Span::subspan(pos, len)` always truncates `len` to
+//      `size() - pos`, whereas `std::span::subspan()` only truncates when the
+//      `len` parameter is defaulted.
 //
 // For more information, see the class comments below.
 #ifndef ABSL_TYPES_SPAN_H_
@@ -96,10 +99,10 @@
 #if defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911L
 #include <ranges>  // NOLINT(build/c++20)
 template <typename T>
- // NOLINTNEXTLINE(build/c++20)
+// NOLINTNEXTLINE(build/c++20)
 inline constexpr bool std::ranges::enable_view<absl::Span<T>> = true;
 template <typename T>
- // NOLINTNEXTLINE(build/c++20)
+// NOLINTNEXTLINE(build/c++20)
 inline constexpr bool std::ranges::enable_borrowed_range<absl::Span<T>> = true;
 #endif
 
@@ -193,8 +196,9 @@
   // type C.
   template <typename C>
   using EnableIfConvertibleFrom =
-      typename std::enable_if<span_internal::HasData<T, C>::value &&
-                              span_internal::HasSize<C>::value>::type;
+      std::enable_if_t<!std::is_same_v<Span, std::remove_reference_t<C>> &&
+                       span_internal::HasData<T, C>::value &&
+                       span_internal::HasSize<C>::value>;
 
   // Used to SFINAE-enable a function when the slice elements are const.
   template <typename U>
@@ -455,6 +459,11 @@
   // will be trimmed to at most size() - `pos`. A default `len` value of `npos`
   // ensures the returned subspan continues until the end of the span.
   //
+  // Note that trimming behavior differs from `std::span::subspan()`.
+  // `std::span::subspan()` requires `len == npos || pos + len <= size()`.
+  // In other words, `std::span::subspan()` only trims `len` when its value is
+  // defaulted.
+  //
   // Examples:
   //
   //   std::vector<int> vec = {10, 11, 12, 13};
@@ -506,8 +515,7 @@
   // Support for absl::Hash.
   template <typename H>
   friend H AbslHashValue(H h, Span v) {
-    return H::combine(H::combine_contiguous(std::move(h), v.data(), v.size()),
-                      hash_internal::WeaklyMixedInteger{v.size()});
+    return H::combine_contiguous(std::move(h), v.data(), v.size());
   }
 
  private:
@@ -733,24 +741,38 @@
 //   }
 //
 template <int&... ExplicitArgumentBarrier, typename T>
-constexpr Span<T> MakeSpan(T* absl_nullable ptr, size_t size) noexcept {
+constexpr Span<T> MakeSpan(T* absl_nullable ptr ABSL_ATTRIBUTE_LIFETIME_BOUND,
+                           size_t size) noexcept {
   return Span<T>(ptr, size);
 }
 
 template <int&... ExplicitArgumentBarrier, typename T>
-Span<T> MakeSpan(T* absl_nullable begin, T* absl_nullable end) noexcept {
+Span<T> MakeSpan(T* absl_nullable begin ABSL_ATTRIBUTE_LIFETIME_BOUND,
+                 T* absl_nullable end) noexcept {
   ABSL_HARDENING_ASSERT(begin <= end);
   return Span<T>(begin, static_cast<size_t>(end - begin));
 }
 
 template <int&... ExplicitArgumentBarrier, typename C>
 constexpr auto MakeSpan(C& c) noexcept  // NOLINT(runtime/references)
-    -> decltype(absl::MakeSpan(span_internal::GetData(c), c.size())) {
+    -> std::enable_if_t<span_internal::IsView<C>::value,
+                        decltype(absl::MakeSpan(span_internal::GetData(c),
+                                                c.size()))> {
+  return MakeSpan(span_internal::GetData(c), c.size());
+}
+
+template <int&... ExplicitArgumentBarrier, typename C>
+constexpr auto MakeSpan(
+    C& c ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept  // NOLINT(runtime/references)
+    -> std::enable_if_t<!span_internal::IsView<C>::value,
+                        decltype(absl::MakeSpan(span_internal::GetData(c),
+                                                c.size()))> {
   return MakeSpan(span_internal::GetData(c), c.size());
 }
 
 template <int&... ExplicitArgumentBarrier, typename T, size_t N>
-constexpr Span<T> MakeSpan(T (&array)[N]) noexcept {
+constexpr Span<T> MakeSpan(
+    T (&array ABSL_ATTRIBUTE_LIFETIME_BOUND)[N]) noexcept {
   return Span<T>(array, N);
 }
 
@@ -779,25 +801,36 @@
 //   ProcessInts(absl::MakeConstSpan(std::vector<int>{ 0, 0, 0 }));
 //
 template <int&... ExplicitArgumentBarrier, typename T>
-constexpr Span<const T> MakeConstSpan(T* absl_nullable ptr,
-                                      size_t size) noexcept {
+constexpr Span<const T> MakeConstSpan(
+    T* absl_nullable ptr ABSL_ATTRIBUTE_LIFETIME_BOUND, size_t size) noexcept {
   return Span<const T>(ptr, size);
 }
 
 template <int&... ExplicitArgumentBarrier, typename T>
-Span<const T> MakeConstSpan(T* absl_nullable begin,
+Span<const T> MakeConstSpan(T* absl_nullable begin
+                                ABSL_ATTRIBUTE_LIFETIME_BOUND,
                             T* absl_nullable end) noexcept {
   ABSL_HARDENING_ASSERT(begin <= end);
   return Span<const T>(begin, end - begin);
 }
 
 template <int&... ExplicitArgumentBarrier, typename C>
-constexpr auto MakeConstSpan(const C& c) noexcept -> decltype(MakeSpan(c)) {
+constexpr auto MakeConstSpan(const C& c) noexcept
+    -> std::enable_if_t<span_internal::IsView<C>::value,
+                        decltype(MakeSpan(c))> {
+  return MakeSpan(c);
+}
+
+template <int&... ExplicitArgumentBarrier, typename C>
+constexpr auto MakeConstSpan(const C& c ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
+    -> std::enable_if_t<!span_internal::IsView<C>::value,
+                        decltype(MakeSpan(c))> {
   return MakeSpan(c);
 }
 
 template <int&... ExplicitArgumentBarrier, typename T, size_t N>
-constexpr Span<const T> MakeConstSpan(const T (&array)[N]) noexcept {
+constexpr Span<const T> MakeConstSpan(
+    const T (&array ABSL_ATTRIBUTE_LIFETIME_BOUND)[N]) noexcept {
   return Span<const T>(array, N);
 }
 ABSL_NAMESPACE_END
diff --git a/absl/types/span_test.cc b/absl/types/span_test.cc
index 6700b81..21b49ed 100644
--- a/absl/types/span_test.cc
+++ b/absl/types/span_test.cc
@@ -41,6 +41,20 @@
                   absl::type_traits_internal::IsView<absl::Span<int>>::value,
               "Span is a view, not an owner");
 
+using S = absl::Span<int>;
+
+static_assert(
+    std::is_trivially_destructible_v<S> && std::is_trivially_copyable_v<S> &&
+        std::is_trivially_assignable_v<S, S&> &&
+        std::is_trivially_copy_assignable_v<S> &&
+        std::is_trivially_move_assignable_v<S> &&
+        std::is_trivially_assignable_v<S, const S&&> &&
+        std::is_trivially_constructible_v<S, S&> &&
+        std::is_trivially_copy_constructible_v<S> &&
+        std::is_trivially_move_constructible_v<S> &&
+        std::is_trivially_constructible_v<S, const S&&>,
+    "Span should be trivial in everything except default-constructibility");
+
 MATCHER_P(DataIs, data,
           absl::StrCat("data() ", negation ? "isn't " : "is ",
                        testing::PrintToString(data))) {
diff --git a/absl/utility/BUILD.bazel b/absl/utility/BUILD.bazel
index 773f949..a714b02 100644
--- a/absl/utility/BUILD.bazel
+++ b/absl/utility/BUILD.bazel
@@ -14,6 +14,7 @@
 # limitations under the License.
 #
 
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
diff --git a/absl/utility/utility.h b/absl/utility/utility.h
index 4637b03..4d72c31 100644
--- a/absl/utility/utility.h
+++ b/absl/utility/utility.h
@@ -49,6 +49,19 @@
 using std::make_integer_sequence;
 using std::move;
 
+#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+// Backfill for std::nontype_t. An instance of this class can be provided as a
+// disambiguation tag to `absl::function_ref` to pass the address of a known
+// callable at compile time.
+// Requires C++20 due to `auto` template parameter.
+template <auto>
+struct nontype_t {
+  explicit nontype_t() = default;
+};
+template <auto V>
+constexpr nontype_t<V> nontype{};
+#endif
+
 ABSL_NAMESPACE_END
 }  // namespace absl
 
diff --git a/ci/absl_alternate_options.h b/ci/absl_alternate_options.h
index a563859..d5567f3 100644
--- a/ci/absl_alternate_options.h
+++ b/ci/absl_alternate_options.h
@@ -15,13 +15,11 @@
 // Alternate options.h file, used in continuous integration testing to exercise
 // option settings not used by default.
 
+// SKIP_ABSL_INLINE_NAMESPACE_CHECK
+
 #ifndef ABSL_CI_ABSL_ALTERNATE_OPTIONS_H_
 #define ABSL_CI_ABSL_ALTERNATE_OPTIONS_H_
 
-#define ABSL_OPTION_USE_STD_ANY 0
-#define ABSL_OPTION_USE_STD_OPTIONAL 0
-#define ABSL_OPTION_USE_STD_STRING_VIEW 0
-#define ABSL_OPTION_USE_STD_VARIANT 0
 #define ABSL_OPTION_USE_STD_ORDERING 0
 #define ABSL_OPTION_USE_INLINE_NAMESPACE 1
 #define ABSL_OPTION_INLINE_NAMESPACE_NAME ns
diff --git a/ci/cmake_common.sh b/ci/cmake_common.sh
index 484230c..53d3a37 100644
--- a/ci/cmake_common.sh
+++ b/ci/cmake_common.sh
@@ -16,4 +16,4 @@
 # Keep this in sync with the commit in the MODULE.bazel file.
 readonly ABSL_GOOGLETEST_VERSION="1.17.0"
 
-readonly ABSL_GOOGLETEST_DOWNLOAD_URL="https://github.com/google/googletest/releases/download/v${ABSL_GOOGLETEST_VERSION}/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz"
+ABSL_GOOGLETEST_DOWNLOAD_URL="https://github.com/google/googletest/releases/download/v${ABSL_GOOGLETEST_VERSION}/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz"
diff --git a/ci/cmake_install_test.sh b/ci/cmake_install_test.sh
index 871490f..5e3e07b 100755
--- a/ci/cmake_install_test.sh
+++ b/ci/cmake_install_test.sh
@@ -26,6 +26,12 @@
 
 source "${ABSEIL_ROOT}/ci/cmake_common.sh"
 
+# Avoid depending on GitHub by looking for a cached copy of GoogleTest.
+if [[ -r "${KOKORO_GFILE_DIR:-}/distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz" ]]; then
+  ABSL_GOOGLETEST_DOWNLOAD_URL="file:///distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz"
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
+fi
+
 source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
 readonly DOCKER_CONTAINER=${LINUX_GCC_LATEST_CONTAINER}
 
diff --git a/ci/linux_arm_clang-latest_libcxx_bazel.sh b/ci/linux_arm_clang-latest_libcxx_bazel.sh
index 631a8bd..5ad9fcc 100755
--- a/ci/linux_arm_clang-latest_libcxx_bazel.sh
+++ b/ci/linux_arm_clang-latest_libcxx_bazel.sh
@@ -88,6 +88,7 @@
             --features=external_include_paths \
             --keep_going \
             --linkopt=-stdlib=libc++ \
+            --per_file_copt=external/.*@-w \
             --show_timestamps \
             --test_env=\"GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1\" \
             --test_env=\"TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo\" \
diff --git a/ci/linux_clang-latest_libcxx_asan_bazel.sh b/ci/linux_clang-latest_libcxx_asan_bazel.sh
index cfc5510..1200ef0 100755
--- a/ci/linux_clang-latest_libcxx_asan_bazel.sh
+++ b/ci/linux_clang-latest_libcxx_asan_bazel.sh
@@ -81,6 +81,7 @@
           --action_env=\"CPLUS_INCLUDE_PATH=/opt/llvm/libcxx/include/c++/v1\" \
           --compilation_mode=\"${compilation_mode}\" \
           --copt=\"${exceptions_mode}\" \
+          --copt=\"-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG\" \
           --copt=\"-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1\" \
           --copt=\"-fsanitize=address\" \
           --copt=\"-fsanitize=${UBSAN_CHECKS}\" \
@@ -92,6 +93,7 @@
           --keep_going \
           --linkopt=\"-fsanitize=address\" \
           --linkopt=\"-fsanitize-link-c++-runtime\" \
+          --per_file_copt=external/.*@-w \
           --show_timestamps \
           --test_env=\"ASAN_SYMBOLIZER_PATH=/opt/llvm/clang/bin/llvm-symbolizer\" \
           --test_env=\"TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo\" \
diff --git a/ci/linux_clang-latest_libcxx_bazel.sh b/ci/linux_clang-latest_libcxx_bazel.sh
index 5c51d15..74af10c 100755
--- a/ci/linux_clang-latest_libcxx_bazel.sh
+++ b/ci/linux_clang-latest_libcxx_bazel.sh
@@ -89,6 +89,7 @@
             --enable_bzlmod=true \
             --features=external_include_paths \
             --keep_going \
+            --per_file_copt=external/.*@-w \
             --show_timestamps \
             --test_env=\"GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1\" \
             --test_env=\"TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo\" \
diff --git a/ci/linux_clang-latest_libcxx_tsan_bazel.sh b/ci/linux_clang-latest_libcxx_tsan_bazel.sh
index c9ea22d..8634e8d 100755
--- a/ci/linux_clang-latest_libcxx_tsan_bazel.sh
+++ b/ci/linux_clang-latest_libcxx_tsan_bazel.sh
@@ -87,6 +87,7 @@
           --features=external_include_paths \
           --keep_going \
           --linkopt=\"-fsanitize=thread\" \
+          --per_file_copt=external/.*@-w \
           --show_timestamps \
           --test_env=\"TSAN_SYMBOLIZER_PATH=/opt/llvm/clang/bin/llvm-symbolizer\" \
           --test_env=\"TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo\" \
diff --git a/ci/linux_clang-latest_libstdcxx_bazel.sh b/ci/linux_clang-latest_libstdcxx_bazel.sh
index a1620e0..3175e41 100755
--- a/ci/linux_clang-latest_libstdcxx_bazel.sh
+++ b/ci/linux_clang-latest_libstdcxx_bazel.sh
@@ -85,6 +85,7 @@
           --features=external_include_paths \
           --keep_going \
           --linkopt=\"--gcc-toolchain=/usr/local\" \
+          --per_file_copt=external/.*@-w \
           --show_timestamps \
           --test_env=\"GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1\" \
           --test_env=\"TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo\" \
diff --git a/ci/linux_docker_containers.sh b/ci/linux_docker_containers.sh
index 0f45471..cb0904c 100644
--- a/ci/linux_docker_containers.sh
+++ b/ci/linux_docker_containers.sh
@@ -16,7 +16,7 @@
 # Test scripts should source this file to get the identifiers.
 
 readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20230612"
-readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20250430"
+readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20250527"
 readonly LINUX_ARM_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_arm_hybrid-latest:20250430"
-readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20250430"
+readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20250527"
 readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20250430"
diff --git a/ci/linux_gcc-floor_libstdcxx_bazel.sh b/ci/linux_gcc-floor_libstdcxx_bazel.sh
index b683b60..0ee412d 100755
--- a/ci/linux_gcc-floor_libstdcxx_bazel.sh
+++ b/ci/linux_gcc-floor_libstdcxx_bazel.sh
@@ -81,6 +81,7 @@
           --define=\"absl=1\" \
           --features=external_include_paths \
           --keep_going \
+          --per_file_copt=external/.*@-w \
           --show_timestamps \
           --test_env=\"GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1\" \
           --test_env=\"TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo\" \
diff --git a/ci/linux_gcc-latest_libstdcxx_bazel.sh b/ci/linux_gcc-latest_libstdcxx_bazel.sh
index b092c1d..6e9b5ec 100755
--- a/ci/linux_gcc-latest_libstdcxx_bazel.sh
+++ b/ci/linux_gcc-latest_libstdcxx_bazel.sh
@@ -87,6 +87,7 @@
             --enable_bzlmod=true \
             --features=external_include_paths \
             --keep_going \
+            --per_file_copt=external/.*@-w \
             --show_timestamps \
             --test_env=\"GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1\" \
             --test_env=\"TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo\" \
diff --git a/ci/linux_gcc-latest_libstdcxx_cmake.sh b/ci/linux_gcc-latest_libstdcxx_cmake.sh
index d75209b..2f69bba 100755
--- a/ci/linux_gcc-latest_libstdcxx_cmake.sh
+++ b/ci/linux_gcc-latest_libstdcxx_cmake.sh
@@ -22,6 +22,12 @@
 
 source "${ABSEIL_ROOT}/ci/cmake_common.sh"
 
+# Avoid depending on GitHub by looking for a cached copy of GoogleTest.
+if [[ -r "${KOKORO_GFILE_DIR:-}/distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz" ]]; then
+  ABSL_GOOGLETEST_DOWNLOAD_URL="file:///distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz"
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
+fi
+
 if [[ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]]; then
   ABSL_CMAKE_CXX_STANDARDS="17 20"
 fi
diff --git a/ci/linux_gcc_alpine_cmake.sh b/ci/linux_gcc_alpine_cmake.sh
index 7cf25f7..1d64a95 100755
--- a/ci/linux_gcc_alpine_cmake.sh
+++ b/ci/linux_gcc_alpine_cmake.sh
@@ -22,6 +22,12 @@
 
 source "${ABSEIL_ROOT}/ci/cmake_common.sh"
 
+# Avoid depending on GitHub by looking for a cached copy of GoogleTest.
+if [[ -r "${KOKORO_GFILE_DIR:-}/distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz" ]]; then
+  ABSL_GOOGLETEST_DOWNLOAD_URL="file:///distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz"
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
+fi
+
 if [[ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]]; then
   ABSL_CMAKE_CXX_STANDARDS="17"
 fi
diff --git a/ci/macos_xcode_bazel.sh b/ci/macos_xcode_bazel.sh
index b05cfac..a09b405 100755
--- a/ci/macos_xcode_bazel.sh
+++ b/ci/macos_xcode_bazel.sh
@@ -19,8 +19,8 @@
 
 set -euox pipefail
 
-# Use Xcode 16.0
-sudo xcode-select -s /Applications/Xcode_16.0.app/Contents/Developer
+# Use Xcode 16.3
+sudo xcode-select -s /Applications/Xcode_16.3.app/Contents/Developer
 
 if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
@@ -37,8 +37,8 @@
 
 # Use Bazel Vendor mode to reduce reliance on external dependencies.
 if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" ]]; then
-  tar -xf "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" -C "${TMP}/"
-  BAZEL_EXTRA_ARGS="--vendor_dir=\"${TMP}/abseil-cpp_vendor\" ${BAZEL_EXTRA_ARGS:-}"
+  tar -xf "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" -C "${HOME}/"
+  BAZEL_EXTRA_ARGS="--vendor_dir=${HOME}/abseil-cpp_vendor ${BAZEL_EXTRA_ARGS:-}"
 fi
 
 # Print the compiler and Bazel versions.
@@ -54,9 +54,6 @@
   cp ${ALTERNATE_OPTIONS:-} absl/base/options.h || exit 1
 fi
 
-# Avoid using the system version of google-benchmark.
-brew uninstall google-benchmark
-
 ${BAZEL_BIN} test ... \
   --copt="-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1" \
   --copt="-Werror" \
@@ -64,6 +61,7 @@
   --enable_bzlmod=true \
   --features=external_include_paths \
   --keep_going \
+  --per_file_copt=external/.*@-w \
   --show_timestamps \
   --test_env="TZDIR=${ABSEIL_ROOT}/absl/time/internal/cctz/testdata/zoneinfo" \
   --test_output=errors \
diff --git a/ci/macos_xcode_cmake.sh b/ci/macos_xcode_cmake.sh
index 6811b87..37be939 100755
--- a/ci/macos_xcode_cmake.sh
+++ b/ci/macos_xcode_cmake.sh
@@ -16,8 +16,10 @@
 
 set -euox pipefail
 
-# Use Xcode 16.0
-sudo xcode-select -s /Applications/Xcode_16.0.app/Contents/Developer
+# Use Xcode 16.3
+sudo xcode-select -s /Applications/Xcode_16.3.app/Contents/Developer
+
+brew install cmake
 
 export CMAKE_BUILD_PARALLEL_LEVEL=$(sysctl -n hw.ncpu)
 export CTEST_PARALLEL_LEVEL=$(sysctl -n hw.ncpu)
@@ -29,6 +31,11 @@
 
 source "${ABSEIL_ROOT}/ci/cmake_common.sh"
 
+# Avoid depending on GitHub by looking for a cached copy of GoogleTest.
+if [[ -r "${KOKORO_GFILE_DIR:-}/distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz" ]]; then
+  ABSL_GOOGLETEST_DOWNLOAD_URL="${KOKORO_GFILE_DIR}/distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz"
+fi
+
 if [[ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]]; then
   ABSL_CMAKE_BUILD_TYPES="Debug"
 fi
diff --git a/ci/windows_clangcl_bazel.bat b/ci/windows_clangcl_bazel.bat
index 26fd5af..94d27aa 100755
--- a/ci/windows_clangcl_bazel.bat
+++ b/ci/windows_clangcl_bazel.bat
@@ -59,6 +59,7 @@
   --extra_execution_platforms=//:x64_windows-clang-cl ^
   --extra_toolchains=@local_config_cc//:cc-toolchain-x64_windows-clang-cl ^
   --keep_going ^
+  --per_file_copt=external/.*@/w ^
   --test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" ^
   --test_env=TZDIR="%CD%\absl\time\internal\cctz\testdata\zoneinfo" ^
   --test_output=errors ^
diff --git a/ci/windows_msvc_bazel.bat b/ci/windows_msvc_bazel.bat
index bbb57b4..6318ff1 100755
--- a/ci/windows_msvc_bazel.bat
+++ b/ci/windows_msvc_bazel.bat
@@ -50,6 +50,7 @@
   --define=absl=1 ^
   --enable_bzlmod=true ^
   --keep_going ^
+  --per_file_copt=external/.*@/w ^
   --test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" ^
   --test_env=TZDIR="%CD%\absl\time\internal\cctz\testdata\zoneinfo" ^
   --test_output=errors ^
diff --git a/ci/windows_msvc_cmake.bat b/ci/windows_msvc_cmake.bat
index 62cdb70..c0083a1 100755
--- a/ci/windows_msvc_cmake.bat
+++ b/ci/windows_msvc_cmake.bat
@@ -17,7 +17,12 @@
 :: The version of GoogleTest to be used in the CMake tests in this directory.
 :: Keep this in sync with the version in the WORKSPACE file.
 SET ABSL_GOOGLETEST_VERSION=1.17.0
-SET ABSL_GOOGLETEST_DOWNLOAD_URL=https://github.com/google/googletest/releases/download/v%ABSL_GOOGLETEST_VERSION%/googletest-%ABSL_GOOGLETEST_VERSION%.tar.gz
+
+IF EXIST %KOKORO_GFILE_DIR%\distdir\googletest-%ABSL_GOOGLETEST_VERSION%.tar.gz (
+  SET ABSL_GOOGLETEST_DOWNLOAD_URL=file://%KOKORO_GFILE_DIR%\distdir\googletest-%ABSL_GOOGLETEST_VERSION%.tar.gz
+) ELSE (
+  SET ABSL_GOOGLETEST_DOWNLOAD_URL=https://github.com/google/googletest/releases/download/v%ABSL_GOOGLETEST_VERSION%/googletest-%ABSL_GOOGLETEST_VERSION%.tar.gz
+)
 
 :: Replace '\' with '/' in Windows paths for CMake.
 :: Note that this cannot go inside the IF block above, because BAT files are weird.
diff --git a/generate_bp.py b/generate_bp.py
index 6797ba4..a34eb25 100755
--- a/generate_bp.py
+++ b/generate_bp.py
@@ -17,16 +17,19 @@
     '//absl/flags:flag',
     '//absl/flags:parse',
     '//absl/functional:bind_front',
+    '//absl/hash:hash_testing',
     '//absl/log:absl_check',
     '//absl/log:absl_log',
     '//absl/log:check',
     '//absl/log:die_if_null',
     '//absl/log:initialize',
     '//absl/log:log',
+    '//absl/log:log_streamer',
     '//absl/log:scoped_mock_log',
     '//absl/random:bit_gen_ref',
     '//absl/random:random',
     '//absl/status:statusor',
+    '//absl/status:status_matchers',
     '//absl/strings:strings',
     '//absl/synchronization:synchronization',
 ]
@@ -112,13 +115,6 @@
         vendor_available: true,
         stl: "libc++",
     }
-
-    cc_defaults {
-        name: "absl_notls_test_defaults",
-        host_supported: true,
-        stl: "libc++",
-        cflags: ["-DANDROID_DISABLE_TLS_FOR_LINKER=1"],
-    }
     '''
 
     libs_graph = {}
@@ -230,7 +226,6 @@
         if testonly:
             module_type = 'cc_test_library'
             defaults_module = 'absl_test_defaults'
-            notls_defaults_module = 'absl_notls_test_defaults'
             extra_attributes = '''
             static_libs: ["libgmock", "libgtest"],
             shared: {
@@ -276,28 +271,29 @@
         }}
         '''
 
-        # We need to generate separate versions of the library with TLS disabled
-        # for use in the dynamic linker and its dependencies, which does not
-        # support ELF TLS segments when loading itself.
-        bp_notls_deps_for_bp = ['"' + d + '_notls"' for d in bp_deps]
-        bp += f'''
-        {module_type} {{
-            name: "{bp_mod_name}_notls",
-            defaults: ["{notls_defaults_module}"],
-            {visibility_prop_notls}
-            srcs: [
-                {',\n'.join(src_files_for_bp)}
-            ],
-            {generated_hdrs_attr}
-            whole_static_libs: [
-                {',\n'.join(bp_notls_deps_for_bp)}
-            ],
-            export_static_lib_headers: [
-                {',\n'.join(bp_notls_deps_for_bp)}
-            ],
-            {extra_attributes}
-        }}
-        '''
+        if not testonly:
+            # We need to generate separate versions of the library with TLS disabled
+            # for use in the dynamic linker and its dependencies, which does not
+            # support ELF TLS segments when loading itself.
+            bp_notls_deps_for_bp = ['"' + d + '_notls"' for d in bp_deps]
+            bp += f'''
+            {module_type} {{
+                name: "{bp_mod_name}_notls",
+                defaults: ["{notls_defaults_module}"],
+                {visibility_prop_notls}
+                srcs: [
+                    {',\n'.join(src_files_for_bp)}
+                ],
+                {generated_hdrs_attr}
+                whole_static_libs: [
+                    {',\n'.join(bp_notls_deps_for_bp)}
+                ],
+                export_static_lib_headers: [
+                    {',\n'.join(bp_notls_deps_for_bp)}
+                ],
+                {extra_attributes}
+            }}
+            '''
 
         queue.extend(deps)