Merge aosp/master into stage-aosp-master

Manually, since automerger tried to break up my upgrade merge commit.

Fixes: 195029718
Change-Id: I5a1221ef54ed876b30113fdfe4262f2cd0520237
diff --git a/.github/ISSUE_TEMPLATE/00-bug_report.md b/.github/ISSUE_TEMPLATE/00-bug_report.md
new file mode 100644
index 0000000..1edf3de
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/00-bug_report.md
@@ -0,0 +1,41 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: 'bug'
+assignees: ''
+---
+
+**Describe the bug**
+
+Include a clear and concise description of what the problem is, including what
+you expected to happen, and what actually happened.
+
+**Steps to reproduce the bug**
+
+It's important that we are able to reproduce the problem that you are
+experiencing. Please provide all code and relevant steps to reproduce the
+problem, including your `BUILD`/`CMakeLists.txt` file and build commands. Links
+to a GitHub branch or [godbolt.org](https://godbolt.org/) that demonstrate the
+problem are also helpful.
+
+**What version of Abseil are you using?**
+
+**What operating system and version are you using**
+
+If you are using a Linux distribution please include the name and version of the
+distribution as well.
+
+**What compiler and version are you using?**
+
+Please include the output of `gcc -v` or `clang -v`, or the equivalent for your
+compiler.
+
+**What build system are you using?**
+
+Please include the output of `bazel --version` or `cmake --version`, or the
+equivalent for your build system.
+
+**Additional context**
+
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/90-question.md b/.github/ISSUE_TEMPLATE/90-question.md
new file mode 100644
index 0000000..84cf349
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/90-question.md
@@ -0,0 +1,7 @@
+---
+name: Question
+about: Have a question? Ask us anything! :-)
+title: ''
+labels: 'question'
+assignees: ''
+---
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..0086358
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1 @@
+blank_issues_enabled: true
diff --git a/Android.bp b/Android.bp
index 252f6ae..05de691 100644
--- a/Android.bp
+++ b/Android.bp
@@ -38,7 +38,6 @@
 cc_library_host_static {
     name: "libabsl_base",
     srcs: [
-        "absl/base/dynamic_annotations.cc",
         "absl/base/internal/cycleclock.cc",
         "absl/base/internal/exponential_biased.cc",
         "absl/base/internal/low_level_alloc.cc",
@@ -46,6 +45,7 @@
         "absl/base/internal/raw_logging.cc",
         "absl/base/internal/spinlock.cc",
         "absl/base/internal/spinlock_wait.cc",
+        "absl/base/internal/strerror.cc",
         "absl/base/internal/sysinfo.cc",
         "absl/base/internal/thread_identity.cc",
         "absl/base/internal/throw_delegate.cc",
@@ -83,17 +83,19 @@
 cc_library_host_static {
     name: "libabsl_flags",
     srcs: [
+        "absl/flags/commandlineflag.cc",
         "absl/flags/usage_config.cc",
         "absl/flags/marshalling.cc",
         "absl/flags/usage.cc",
         "absl/flags/flag.cc",
         "absl/flags/parse.cc",
+        "absl/flags/internal/commandlineflag.cc",
         "absl/flags/internal/flag.cc",
+        "absl/flags/internal/private_handle_accessor.cc",
         "absl/flags/internal/program_name.cc",
-        "absl/flags/internal/registry.cc",
         "absl/flags/internal/usage.cc",
-        "absl/flags/internal/type_erased.cc",
         "absl/flags/flag_test_defs.cc",
+        "absl/flags/reflection.cc",
     ],
 }
 
@@ -102,6 +104,7 @@
     srcs: [
         "absl/hash/internal/city.cc",
         "absl/hash/internal/hash.cc",
+        "absl/hash/internal/wyhash.cc",
     ],
 }
 
@@ -115,6 +118,7 @@
     srcs: [
         "absl/status/status.cc",
         "absl/status/status_payload_printer.cc",
+        "absl/status/statusor.cc",
     ],
 }
 
@@ -127,6 +131,8 @@
         "absl/strings/escaping.cc",
         "absl/strings/internal/charconv_bigint.cc",
         "absl/strings/internal/charconv_parse.cc",
+        "absl/strings/internal/cord_internal.cc",
+        "absl/strings/internal/cord_rep_ring.cc",
         "absl/strings/internal/escaping.cc",
         "absl/strings/internal/memutil.cc",
         "absl/strings/internal/ostringstream.cc",
diff --git a/BUILD.bazel b/BUILD.bazel
new file mode 100644
index 0000000..79fb0ec
--- /dev/null
+++ b/BUILD.bazel
@@ -0,0 +1,25 @@
+#
+# 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.
+#
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])  # Apache 2.0
+
+# Expose license for external usage through bazel.
+exports_files([
+    "AUTHORS",
+    "LICENSE",
+])
diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake
index 90c9f1f..253c73f 100644
--- a/CMake/AbseilDll.cmake
+++ b/CMake/AbseilDll.cmake
@@ -1,4 +1,5 @@
 include(CMakeParseArguments)
+include(GNUInstallDirs)
 
 set(ABSL_INTERNAL_DLL_FILES
   "algorithm/algorithm.h"
@@ -8,17 +9,17 @@
   "base/casts.h"
   "base/config.h"
   "base/const_init.h"
-  "base/dynamic_annotations.cc"
   "base/dynamic_annotations.h"
   "base/internal/atomic_hook.h"
-  "base/internal/bits.h"
   "base/internal/cycleclock.cc"
   "base/internal/cycleclock.h"
   "base/internal/direct_mmap.h"
+  "base/internal/dynamic_annotations.h"
   "base/internal/endian.h"
   "base/internal/errno_saver.h"
   "base/internal/exponential_biased.cc"
   "base/internal/exponential_biased.h"
+  "base/internal/fast_type_id.h"
   "base/internal/hide_ptr.h"
   "base/internal/identity.h"
   "base/internal/invoke.h"
@@ -35,6 +36,8 @@
   "base/internal/scheduling_mode.h"
   "base/internal/scoped_set_env.cc"
   "base/internal/scoped_set_env.h"
+  "base/internal/strerror.h"
+  "base/internal/strerror.cc"
   "base/internal/spinlock.cc"
   "base/internal/spinlock.h"
   "base/internal/spinlock_wait.cc"
@@ -58,6 +61,8 @@
   "base/policy_checks.h"
   "base/port.h"
   "base/thread_annotations.h"
+  "cleanup/cleanup.h"
+  "cleanup/internal/cleanup.h"
   "container/btree_map.h"
   "container/btree_set.h"
   "container/fixed_array.h"
@@ -119,27 +124,30 @@
   "hash/internal/hash.h"
   "hash/internal/hash.cc"
   "hash/internal/spy_hash_state.h"
+  "hash/internal/wyhash.h"
+  "hash/internal/wyhash.cc"
   "memory/memory.h"
   "meta/type_traits.h"
+  "numeric/bits.h"
   "numeric/int128.cc"
   "numeric/int128.h"
+  "numeric/internal/bits.h"
+  "numeric/internal/representation.h"
   "random/bernoulli_distribution.h"
   "random/beta_distribution.h"
   "random/bit_gen_ref.h"
   "random/discrete_distribution.cc"
   "random/discrete_distribution.h"
-  "random/distribution_format_traits.h"
   "random/distributions.h"
   "random/exponential_distribution.h"
   "random/gaussian_distribution.cc"
   "random/gaussian_distribution.h"
-  "random/internal/distributions.h"
   "random/internal/distribution_caller.h"
-  "random/internal/fast_uniform_bits.h"
   "random/internal/fastmath.h"
-  "random/internal/gaussian_distribution_gentables.cc"
+  "random/internal/fast_uniform_bits.h"
   "random/internal/generate_real.h"
   "random/internal/iostream_state_saver.h"
+  "random/internal/mock_helpers.h"
   "random/internal/nonsecure_base.h"
   "random/internal/pcg_engine.h"
   "random/internal/platform.h"
@@ -152,6 +160,7 @@
   "random/internal/randen_engine.h"
   "random/internal/randen_hwaes.cc"
   "random/internal/randen_hwaes.h"
+  "random/internal/randen_round_keys.cc"
   "random/internal/randen_slow.cc"
   "random/internal/randen_slow.h"
   "random/internal/randen_traits.h"
@@ -172,8 +181,12 @@
   "random/uniform_int_distribution.h"
   "random/uniform_real_distribution.h"
   "random/zipf_distribution.h"
+  "status/internal/status_internal.h"
+  "status/internal/statusor_internal.h"
   "status/status.h"
   "status/status.cc"
+  "status/statusor.h"
+  "status/statusor.cc"
   "status/status_payload_printer.h"
   "status/status_payload_printer.cc"
   "strings/ascii.cc"
@@ -184,12 +197,18 @@
   "strings/cord.h"
   "strings/escaping.cc"
   "strings/escaping.h"
+  "strings/internal/cord_internal.cc"
   "strings/internal/cord_internal.h"
+  "strings/internal/cord_rep_flat.h"
+  "strings/internal/cord_rep_ring.cc"
+  "strings/internal/cord_rep_ring.h"
+  "strings/internal/cord_rep_ring_reader.h"
   "strings/internal/charconv_bigint.cc"
   "strings/internal/charconv_bigint.h"
   "strings/internal/charconv_parse.cc"
   "strings/internal/charconv_parse.h"
   "strings/internal/stl_type_traits.h"
+  "strings/internal/string_constant.h"
   "strings/match.cc"
   "strings/match.h"
   "strings/numbers.cc"
@@ -244,6 +263,7 @@
   "synchronization/notification.h"
   "synchronization/internal/create_thread_identity.cc"
   "synchronization/internal/create_thread_identity.h"
+  "synchronization/internal/futex.h"
   "synchronization/internal/graphcycles.cc"
   "synchronization/internal/graphcycles.h"
   "synchronization/internal/kernel_timeout.h"
@@ -292,6 +312,8 @@
   "types/internal/conformance_aliases.h"
   "types/internal/conformance_archetype.h"
   "types/internal/conformance_profile.h"
+  "types/internal/parentheses.h"
+  "types/internal/transform_args.h"
   "types/internal/variant.h"
   "types/optional.h"
   "types/internal/optional.h"
@@ -479,7 +501,7 @@
     abseil_dll
     PUBLIC
       "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
-      $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
+      $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
   )
 
   target_compile_options(
@@ -497,8 +519,8 @@
       ${ABSL_CC_LIB_DEFINES}
   )
   install(TARGETS abseil_dll EXPORT ${PROJECT_NAME}Targets
-        RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR}
-        LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR}
-        ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR}
+        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
   )
 endfunction()
diff --git a/CMake/AbseilHelpers.cmake b/CMake/AbseilHelpers.cmake
index 86ff9eb..54fb8df 100644
--- a/CMake/AbseilHelpers.cmake
+++ b/CMake/AbseilHelpers.cmake
@@ -17,13 +17,14 @@
 include(CMakeParseArguments)
 include(AbseilConfigureCopts)
 include(AbseilDll)
-include(AbseilInstallDirs)
 
 # The IDE folder for Abseil that will be used if Abseil is included in a CMake
 # project that sets
 #    set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 # For example, Visual Studio supports folders.
-set(ABSL_IDE_FOLDER Abseil)
+if(NOT DEFINED ABSL_IDE_FOLDER)
+  set(ABSL_IDE_FOLDER Abseil)
+endif()
 
 # absl_cc_library()
 #
@@ -39,7 +40,7 @@
 # LINKOPTS: List of link options
 # PUBLIC: Add this so that this library will be exported under absl::
 # Also in IDE, target will appear in Abseil folder while non PUBLIC will be in Abseil/internal.
-# TESTONLY: When added, this target will only be built if user passes -DABSL_RUN_TESTS=ON to CMake.
+# TESTONLY: When added, this target will only be built if BUILD_TESTING=ON.
 #
 # Note:
 # By default, absl_cc_library will always create a library named absl_${NAME},
@@ -81,7 +82,7 @@
     ${ARGN}
   )
 
-  if(ABSL_CC_LIB_TESTONLY AND NOT ABSL_RUN_TESTS)
+  if(ABSL_CC_LIB_TESTONLY AND NOT BUILD_TESTING)
     return()
   endif()
 
@@ -102,7 +103,7 @@
     endif()
   endforeach()
 
-  if("${ABSL_CC_SRCS}" STREQUAL "")
+  if(ABSL_CC_SRCS STREQUAL "")
     set(ABSL_CC_LIB_IS_INTERFACE 1)
   else()
     set(ABSL_CC_LIB_IS_INTERFACE 0)
@@ -120,7 +121,11 @@
   # 4. "static"  -- This target does not depend on the DLL and should be built
   #                 statically.
   if (${ABSL_BUILD_DLL})
-    absl_internal_dll_contains(TARGET ${_NAME} OUTPUT _in_dll)
+    if(ABSL_ENABLE_INSTALL)
+      absl_internal_dll_contains(TARGET ${_NAME} OUTPUT _in_dll)
+    else()
+      absl_internal_dll_contains(TARGET ${ABSL_CC_LIB_NAME} OUTPUT _in_dll)
+    endif()
     if (${_in_dll})
       # This target should be replaced by the DLL
       set(_build_type "dll")
@@ -135,8 +140,53 @@
     set(_build_type "static")
   endif()
 
+  # Generate a pkg-config file for every library:
+  if(_build_type STREQUAL "static" OR _build_type STREQUAL "shared")
+    if(NOT ABSL_CC_LIB_TESTONLY)
+      if(absl_VERSION)
+        set(PC_VERSION "${absl_VERSION}")
+      else()
+        set(PC_VERSION "head")
+      endif()
+      foreach(dep ${ABSL_CC_LIB_DEPS})
+        if(${dep} MATCHES "^absl::(.*)")
+	  # Join deps with commas.
+          if(PC_DEPS)
+            set(PC_DEPS "${PC_DEPS},")
+          endif()
+          set(PC_DEPS "${PC_DEPS} absl_${CMAKE_MATCH_1} = ${PC_VERSION}")
+        endif()
+      endforeach()
+      foreach(cflag ${ABSL_CC_LIB_COPTS})
+        if(${cflag} MATCHES "^(-Wno|/wd)")
+          # These flags are needed to suppress warnings that might fire in our headers.
+          set(PC_CFLAGS "${PC_CFLAGS} ${cflag}")
+        elseif(${cflag} MATCHES "^(-W|/w[1234eo])")
+          # Don't impose our warnings on others.
+        else()
+          set(PC_CFLAGS "${PC_CFLAGS} ${cflag}")
+        endif()
+      endforeach()
+      FILE(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/lib/pkgconfig/absl_${_NAME}.pc" CONTENT "\
+prefix=${CMAKE_INSTALL_PREFIX}\n\
+exec_prefix=\${prefix}\n\
+libdir=\${prefix}/${CMAKE_INSTALL_LIBDIR}\n\
+includedir=\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}\n\
+\n\
+Name: absl_${_NAME}\n\
+Description: Abseil ${_NAME} library\n\
+URL: https://abseil.io/\n\
+Version: ${PC_VERSION}\n\
+Requires:${PC_DEPS}\n\
+Libs: -L\${libdir} $<JOIN:${ABSL_CC_LIB_LINKOPTS}, > $<$<NOT:$<BOOL:${ABSL_CC_LIB_IS_INTERFACE}>>:-labsl_${_NAME}>\n\
+Cflags: -I\${includedir}${PC_CFLAGS}\n")
+      INSTALL(FILES "${CMAKE_BINARY_DIR}/lib/pkgconfig/absl_${_NAME}.pc"
+              DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
+    endif()
+  endif()
+
   if(NOT ABSL_CC_LIB_IS_INTERFACE)
-    if(${_build_type} STREQUAL "dll_dep")
+    if(_build_type STREQUAL "dll_dep")
       # This target depends on the DLL. When adding dependencies to this target,
       # any depended-on-target which is contained inside the DLL is replaced
       # with a dependency on the DLL.
@@ -165,7 +215,7 @@
           "${_gtest_link_define}"
       )
 
-    elseif(${_build_type} STREQUAL "static" OR ${_build_type} STREQUAL "shared")
+    elseif(_build_type STREQUAL "static" OR _build_type STREQUAL "shared")
       add_library(${_NAME} "")
       target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS})
       target_link_libraries(${_NAME}
@@ -188,7 +238,7 @@
     target_include_directories(${_NAME}
       PUBLIC
         "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
-        $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
+        $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
     )
     target_compile_options(${_NAME}
       PRIVATE ${ABSL_CC_LIB_COPTS})
@@ -213,6 +263,7 @@
     if(ABSL_ENABLE_INSTALL)
       set_target_properties(${_NAME} PROPERTIES
         OUTPUT_NAME "absl_${_NAME}"
+        SOVERSION "2103.0.1"
       )
     endif()
   else()
@@ -221,10 +272,10 @@
     target_include_directories(${_NAME}
       INTERFACE
         "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
-        $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
+        $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
       )
 
-    if (${_build_type} STREQUAL "dll")
+    if (_build_type STREQUAL "dll")
         set(ABSL_CC_LIB_DEPS abseil_dll)
     endif()
 
@@ -241,9 +292,9 @@
   # installed abseil can't be tested.
   if(NOT ABSL_CC_LIB_TESTONLY AND ABSL_ENABLE_INSTALL)
     install(TARGETS ${_NAME} EXPORT ${PROJECT_NAME}Targets
-          RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR}
-          LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR}
-          ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR}
+          RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+          LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+          ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
     )
   endif()
 
@@ -288,7 +339,7 @@
 #     gtest_main
 # )
 function(absl_cc_test)
-  if(NOT ABSL_RUN_TESTS)
+  if(NOT BUILD_TESTING)
     return()
   endif()
 
diff --git a/CMake/AbseilInstallDirs.cmake b/CMake/AbseilInstallDirs.cmake
deleted file mode 100644
index b67272f..0000000
--- a/CMake/AbseilInstallDirs.cmake
+++ /dev/null
@@ -1,20 +0,0 @@
-include(GNUInstallDirs)
-
-# absl_VERSION is only set if we are an LTS release being installed, in which
-# case it may be into a system directory and so we need to make subdirectories
-# for each installed version of Abseil.  This mechanism is implemented in
-# Abseil's internal Copybara (https://github.com/google/copybara) workflows and
-# isn't visible in the CMake buildsystem itself.
-
-if(absl_VERSION)
-  set(ABSL_SUBDIR "${PROJECT_NAME}_${PROJECT_VERSION}")
-  set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}/${ABSL_SUBDIR}")
-  set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${ABSL_SUBDIR}")
-  set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}/{ABSL_SUBDIR}")
-  set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}/${ABSL_SUBDIR}")
-else()
-  set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}")
-  set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
-  set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}")
-  set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}")
-endif()
\ No newline at end of file
diff --git a/CMake/Googletest/CMakeLists.txt.in b/CMake/Googletest/CMakeLists.txt.in
index d60a33e..5769e3a 100644
--- a/CMake/Googletest/CMakeLists.txt.in
+++ b/CMake/Googletest/CMakeLists.txt.in
@@ -1,15 +1,14 @@
 cmake_minimum_required(VERSION 2.8.2)
 
-project(googletest-download NONE)
+project(googletest-external NONE)
 
 include(ExternalProject)
 ExternalProject_Add(googletest
-  GIT_REPOSITORY    https://github.com/google/googletest.git
-  GIT_TAG           master
-  SOURCE_DIR        "${CMAKE_BINARY_DIR}/googletest-src"
-  BINARY_DIR        "${CMAKE_BINARY_DIR}/googletest-build"
+  URL               "${absl_gtest_download_url}"  # May be empty
+  SOURCE_DIR        "${absl_gtest_src_dir}"
+  BINARY_DIR        "${absl_gtest_build_dir}"
   CONFIGURE_COMMAND ""
   BUILD_COMMAND     ""
   INSTALL_COMMAND   ""
   TEST_COMMAND      ""
-)
\ No newline at end of file
+)
diff --git a/CMake/Googletest/DownloadGTest.cmake b/CMake/Googletest/DownloadGTest.cmake
index 8a00b45..9d071c9 100644
--- a/CMake/Googletest/DownloadGTest.cmake
+++ b/CMake/Googletest/DownloadGTest.cmake
@@ -1,10 +1,11 @@
-# Downloads and unpacks googletest at configure time.  Based on the instructions
-# at https://github.com/google/googletest/tree/master/googletest#incorporating-into-an-existing-cmake-project
+# Integrates googletest at configure time.  Based on the instructions at
+# https://github.com/google/googletest/tree/master/googletest#incorporating-into-an-existing-cmake-project
 
-# Download the latest googletest from Github master
+# Set up the external googletest project, downloading the latest from Github
+# master if requested.
 configure_file(
   ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt.in
-  ${CMAKE_BINARY_DIR}/googletest-download/CMakeLists.txt
+  ${CMAKE_BINARY_DIR}/googletest-external/CMakeLists.txt
 )
 
 set(ABSL_SAVE_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
@@ -14,17 +15,17 @@
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGTEST_CREATE_SHARED_LIBRARY=1")
 endif()
 
-# Configure and build the downloaded googletest source
+# Configure and build the googletest source.
 execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
   RESULT_VARIABLE result
-  WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
+  WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-external )
 if(result)
   message(FATAL_ERROR "CMake step for googletest failed: ${result}")
 endif()
 
 execute_process(COMMAND ${CMAKE_COMMAND} --build .
   RESULT_VARIABLE result
-  WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
+  WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-external)
 if(result)
   message(FATAL_ERROR "Build step for googletest failed: ${result}")
 endif()
@@ -37,6 +38,4 @@
 
 # Add googletest directly to our build. This defines the gtest and gtest_main
 # targets.
-add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
-                 ${CMAKE_BINARY_DIR}/googletest-build
-                 EXCLUDE_FROM_ALL)
+add_subdirectory(${absl_gtest_src_dir} ${absl_gtest_build_dir} EXCLUDE_FROM_ALL)
diff --git a/CMake/README.md b/CMake/README.md
index 04d5df3..5eee817 100644
--- a/CMake/README.md
+++ b/CMake/README.md
@@ -52,7 +52,7 @@
 
 ### Running Abseil Tests with CMake
 
-Use the `-DABSL_RUN_TESTS=ON` flag to run Abseil tests.  Note that if the `-DBUILD_TESTING=OFF` flag is passed then Abseil tests will not be run.
+Use the `-DBUILD_TESTING=ON` flag to run Abseil tests.
 
 You will need to provide Abseil with a Googletest dependency.  There are two
 options for how to do this:
@@ -70,7 +70,7 @@
 cd path/to/abseil-cpp
 mkdir build
 cd build
-cmake -DABSL_USE_GOOGLETEST_HEAD=ON -DABSL_RUN_TESTS=ON ..
+cmake -DBUILD_TESTING=ON -DABSL_USE_GOOGLETEST_HEAD=ON ..
 make -j
 ctest
 ```
@@ -93,7 +93,7 @@
 absl::memory
 absl::meta
 absl::numeric
-absl::random
+absl::random_random
 absl::strings
 absl::synchronization
 absl::time
diff --git a/CMake/abslConfig.cmake.in b/CMake/abslConfig.cmake.in
index 60847fa..62d246d 100644
--- a/CMake/abslConfig.cmake.in
+++ b/CMake/abslConfig.cmake.in
@@ -1,7 +1,8 @@
 # absl CMake configuration file.
 
-include(FindThreads)
+include(CMakeFindDependencyMacro)
+find_dependency(Threads)
 
 @PACKAGE_INIT@
 
-include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
\ No newline at end of file
+include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
diff --git a/CMake/install_test_project/test.sh b/CMake/install_test_project/test.sh
index 99989b0..a3d3977 100755
--- a/CMake/install_test_project/test.sh
+++ b/CMake/install_test_project/test.sh
@@ -13,70 +13,44 @@
 # 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.
-
-# "Unit" and integration tests for Absl CMake installation
-
-# TODO(absl-team): This script isn't fully hermetic because
-# -DABSL_USE_GOOGLETEST_HEAD=ON means that this script isn't pinned to a fixed
-# version of GoogleTest. This means that an upstream change to GoogleTest could
-# break this test. Fix this by allowing this script to pin to a known-good
-# version of GoogleTest.
+#
+# Unit and integration tests for Abseil LTS CMake installation
 
 # Fail on any error. Treat unset variables an error. Print commands as executed.
 set -euox pipefail
 
-install_absl() {
-  pushd "${absl_build_dir}"
-  if [[ "${#}" -eq 1 ]]; then
-    cmake -DCMAKE_INSTALL_PREFIX="${1}" "${absl_dir}"
-  else
-    cmake "${absl_dir}"
-  fi
-  cmake --build . --target install -- -j
-  popd
-}
-
-uninstall_absl() {
-  xargs rm < "${absl_build_dir}"/install_manifest.txt
-  rm -rf "${absl_build_dir}"
-  mkdir -p "${absl_build_dir}"
-}
-
-lts_install=""
-
-while getopts ":l" lts; do
-  case "${lts}" in
-    l )
-      lts_install="true"
-      ;;
-  esac
-done
+source ci/cmake_common.sh
 
 absl_dir=/abseil-cpp
-absl_build_dir=/buildfs/absl-build
+absl_build_dir=/buildfs
 project_dir="${absl_dir}"/CMake/install_test_project
 project_build_dir=/buildfs/project-build
 
-mkdir -p "${absl_build_dir}"
+build_shared_libs="OFF"
+if [ "${LINK_TYPE:-}" = "DYNAMIC" ]; then
+  build_shared_libs="ON"
+fi
+
+# Run the LTS transformations
+./create_lts.py 99998877
+
+# Install Abseil
+pushd "${absl_build_dir}"
+cmake "${absl_dir}" \
+  -DABSL_GOOGLETEST_DOWNLOAD_URL="${ABSL_GOOGLETEST_DOWNLOAD_URL}" \
+  -DCMAKE_BUILD_TYPE=Release \
+  -DBUILD_TESTING=ON \
+  -DBUILD_SHARED_LIBS="${build_shared_libs}"
+make -j $(nproc)
+ctest -j $(nproc)
+make install
+ldconfig
+popd
+
+# Test the project against the installed Abseil
 mkdir -p "${project_build_dir}"
-
-if [[ "${lts_install}" ]]; then
-  install_dir="/usr/local"
-else
-  install_dir="${project_build_dir}"/install
-fi
-mkdir -p "${install_dir}"
-
-# Test build, install, and link against installed abseil
 pushd "${project_build_dir}"
-if [[ "${lts_install}" ]]; then
-  install_absl
-  cmake "${project_dir}"
-else
-  install_absl "${install_dir}"
-  cmake "${project_dir}" -DCMAKE_PREFIX_PATH="${install_dir}"
-fi
-
+cmake "${project_dir}"
 cmake --build . --target simple
 
 output="$(${project_build_dir}/simple "printme" 2>&1)"
@@ -88,57 +62,35 @@
 
 popd
 
-# Test that we haven't accidentally made absl::abslblah
-pushd "${install_dir}"
-
-# Starting in CMake 3.12 the default install dir is lib$bit_width
-if [[ -d lib64 ]]; then
-  libdir="lib64"
-elif [[ -d lib ]]; then
-  libdir="lib"
-else
-  echo "ls *, */*, */*/*:"
-  ls *
-  ls */*
-  ls */*/*
-  echo "unknown lib dir"
-fi
-
-if [[ "${lts_install}" ]]; then
-  # LTS versions append the date of the release to the subdir.
-  # 9999/99/99 is the dummy date used in the local_lts workflow.
-  absl_subdir="absl_99999999"
-else
-  absl_subdir="absl"
-fi
-
-if ! grep absl::strings "${libdir}/cmake/${absl_subdir}/abslTargets.cmake"; then
-  cat "${libdir}"/cmake/absl/abslTargets.cmake
+if ! grep absl::strings "/usr/local/lib/cmake/absl/abslTargets.cmake"; then
+  cat "/usr/local/lib/cmake/absl/abslTargets.cmake"
   echo "CMake targets named incorrectly"
   exit 1
 fi
 
-uninstall_absl
-popd
+pushd "${HOME}"
+cat > hello-abseil.cc << EOF
+#include <cstdlib>
 
-if [[ ! "${lts_install}" ]]; then
-  # Test that we warn if installed without a prefix or a system prefix
-  output="$(install_absl 2>&1)"
-  if [[ "${output}" != *"Please set CMAKE_INSTALL_PREFIX"* ]]; then
-    echo "Install without prefix didn't warn as expected. Output:"
-    echo "${output}"
-    exit 1
-  fi
-  uninstall_absl
+#include "absl/strings/str_format.h"
 
-  output="$(install_absl /usr 2>&1)"
-  if [[ "${output}" != *"Please set CMAKE_INSTALL_PREFIX"* ]]; then
-    echo "Install with /usr didn't warn as expected. Output:"
-    echo "${output}"
-    exit 1
-  fi
-  uninstall_absl
+int main(int argc, char **argv) {
+  absl::PrintF("Hello Abseil!\n");
+  return EXIT_SUCCESS;
+}
+EOF
+
+if [ "${LINK_TYPE:-}" != "DYNAMIC" ]; then
+  pc_args=($(pkg-config --cflags --libs --static absl_str_format))
+  g++ -static -o hello-abseil hello-abseil.cc "${pc_args[@]}"
+else
+  pc_args=($(pkg-config --cflags --libs absl_str_format))
+  g++ -o hello-abseil hello-abseil.cc "${pc_args[@]}"
 fi
+hello="$(./hello-abseil)"
+[[ "${hello}" == "Hello Abseil!" ]]
+
+popd
 
 echo "Install test complete!"
 exit 0
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 48cb6eb..3a73f70 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -22,15 +22,31 @@
 cmake_minimum_required(VERSION 3.5)
 
 # Compiler id for Apple Clang is now AppleClang.
-cmake_policy(SET CMP0025 NEW)
+if (POLICY CMP0025)
+  cmake_policy(SET CMP0025 NEW)
+endif (POLICY CMP0025)
 
 # if command can use IN_LIST
-cmake_policy(SET CMP0057 NEW)
+if (POLICY CMP0057)
+  cmake_policy(SET CMP0057 NEW)
+endif (POLICY CMP0057)
 
-# Project version variables are the empty std::string if version is unspecified
-cmake_policy(SET CMP0048 NEW)
+# Project version variables are the empty string if version is unspecified
+if (POLICY CMP0048)
+  cmake_policy(SET CMP0048 NEW)
+endif (POLICY CMP0048)
 
-project(absl CXX)
+# option() honor variables
+if (POLICY CMP0077)
+  cmake_policy(SET CMP0077 NEW)
+endif (POLICY CMP0077)
+
+# Set BUILD_TESTING to OFF by default.
+# This must come before the project() and include(CTest) lines.
+OPTION(BUILD_TESTING "Build tests" OFF)
+
+project(absl LANGUAGES CXX VERSION 20210324)
+include(CTest)
 
 # Output directory is correct by default for most build setups. However, when
 # building Abseil as a DLL, it is important to have the DLL in the same
@@ -40,10 +56,10 @@
 
 # when absl is included as subproject (i.e. using add_subdirectory(abseil-cpp))
 # in the source tree of a project that uses it, install rules are disabled.
-if(NOT "^${CMAKE_SOURCE_DIR}$" STREQUAL "^${PROJECT_SOURCE_DIR}$")
-  set(ABSL_ENABLE_INSTALL FALSE)
+if(NOT CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
+  option(ABSL_ENABLE_INSTALL "Enable install rule" OFF)
 else()
-  set(ABSL_ENABLE_INSTALL TRUE)
+  option(ABSL_ENABLE_INSTALL "Enable install rule" ON)
 endif()
 
 list(APPEND CMAKE_MODULE_PATH
@@ -51,8 +67,8 @@
   ${CMAKE_CURRENT_LIST_DIR}/absl/copts
 )
 
-include(AbseilInstallDirs)
 include(CMakePackageConfigHelpers)
+include(GNUInstallDirs)
 include(AbseilDll)
 include(AbseilHelpers)
 
@@ -81,25 +97,36 @@
 ## pthread
 find_package(Threads REQUIRED)
 
+option(ABSL_USE_EXTERNAL_GOOGLETEST
+  "If ON, Abseil will assume that the targets for GoogleTest are already provided by the including project. This makes sense when Abseil is used with add_subproject." OFF)
+
 option(ABSL_USE_GOOGLETEST_HEAD
-  "If ON, abseil will download HEAD from googletest at config time." OFF)
+  "If ON, abseil will download HEAD from GoogleTest at config time." OFF)
 
-option(ABSL_RUN_TESTS "If ON, Abseil tests will be run." OFF)
+set(ABSL_GOOGLETEST_DOWNLOAD_URL "" CACHE STRING "If set, download GoogleTest from this URL")
 
-if(${ABSL_RUN_TESTS})
-  # enable CTest.  This will set BUILD_TESTING to ON unless otherwise specified
-  # on the command line
-  include(CTest)
-  enable_testing()
-endif()
+set(ABSL_LOCAL_GOOGLETEST_DIR "/usr/src/googletest" CACHE PATH
+  "If ABSL_USE_GOOGLETEST_HEAD is OFF and ABSL_GOOGLETEST_URL is not set, specifies the directory of a local GoogleTest checkout."
+  )
 
-## check targets
 if(BUILD_TESTING)
-
-  if(${ABSL_USE_GOOGLETEST_HEAD})
-    include(CMake/Googletest/DownloadGTest.cmake)
-    set(absl_gtest_src_dir ${CMAKE_BINARY_DIR}/googletest-src)
+  ## check targets
+  if (NOT ABSL_USE_EXTERNAL_GOOGLETEST)
     set(absl_gtest_build_dir ${CMAKE_BINARY_DIR}/googletest-build)
+    if(ABSL_USE_GOOGLETEST_HEAD AND ABSL_GOOGLETEST_DOWNLOAD_URL)
+      message(FATAL_ERROR "Do not set both ABSL_USE_GOOGLETEST_HEAD and ABSL_GOOGLETEST_DOWNLOAD_URL")
+    endif()
+    if(ABSL_USE_GOOGLETEST_HEAD)
+      set(absl_gtest_download_url "https://github.com/google/googletest/archive/master.zip")
+    elseif(ABSL_GOOGLETEST_DOWNLOAD_URL)
+      set(absl_gtest_download_url ${ABSL_GOOGLETEST_DOWNLOAD_URL})
+    endif()
+    if(absl_gtest_download_url)
+      set(absl_gtest_src_dir ${CMAKE_BINARY_DIR}/googletest-src)
+    else()
+      set(absl_gtest_src_dir ${ABSL_LOCAL_GOOGLETEST_DIR})
+    endif()
+    include(CMake/Googletest/DownloadGTest.cmake)
   endif()
 
   check_target(gtest)
@@ -117,20 +144,21 @@
 add_subdirectory(absl)
 
 if(ABSL_ENABLE_INSTALL)
+  
 
   # install as a subdirectory only
   install(EXPORT ${PROJECT_NAME}Targets
     NAMESPACE absl::
-    DESTINATION "${ABSL_INSTALL_CONFIGDIR}"
+    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
   )
 
   configure_package_config_file(
     CMake/abslConfig.cmake.in
     "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
-    INSTALL_DESTINATION "${ABSL_INSTALL_CONFIGDIR}"
+    INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
   )
   install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
-    DESTINATION "${ABSL_INSTALL_CONFIGDIR}"
+    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
   )
 
   # Abseil only has a version in LTS releases.  This mechanism is accomplished
@@ -143,14 +171,16 @@
     )
 
     install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
-      DESTINATION ${ABSL_INSTALL_CONFIGDIR}
+      DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
     )
   endif()  # absl_VERSION
 
   install(DIRECTORY absl
-    DESTINATION ${ABSL_INSTALL_INCLUDEDIR}
+    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
     FILES_MATCHING
       PATTERN "*.inc"
       PATTERN "*.h"
-  )
+      PATTERN "copts" EXCLUDE
+      PATTERN "testdata" EXCLUDE
+    )
 endif()  # ABSL_ENABLE_INSTALL
diff --git a/LTS.md b/LTS.md
deleted file mode 100644
index 94363b6..0000000
--- a/LTS.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# Long Term Support (LTS) Branches
-
-This repository contains periodic snapshots of the Abseil codebase that are
-Long Term Support (LTS) branches. An LTS branch allows you to use a known
-version of Abseil without interfering with other projects which may also, in
-turn, use Abseil. (For more information about our releases, see the
-[Abseil Release Management](https://abseil.io/about/releases) guide.)
-
-## LTS Branches
-
-The following lists LTS branches and the dates on which they have been released:
-
-* [LTS Branch December 18, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_12_18/)
-* [LTS Branch June 20, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_06_20/)
-* [LTS Branch August 8, 2019](https://github.com/abseil/abseil-cpp/tree/lts_2019_08_08/)
diff --git a/METADATA b/METADATA
index 7ce40ff..23f8fb2 100644
--- a/METADATA
+++ b/METADATA
@@ -10,9 +10,9 @@
   }
   url {
     type: GIT
-    value: "https://github.googlesource.com/abseil/abseil-cpp/+/refs/heads/lts_2020_02_25"
+    value: "https://github.com/abseil/abseil-cpp"
   }
-  version: "fcb104594b0bb4b8ac306cb2f55ecdad40974683"
-  last_upgrade_date { year: 2020 month: 04 day: 27 }
+  version: "20210324.2"
+  last_upgrade_date { year: 2021 month: 07 day: 23 }
 }
 
diff --git a/README.md b/README.md
index 85de569..264c4b3 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,9 @@
 - [About Abseil](#about)
 - [Quickstart](#quickstart)
 - [Building Abseil](#build)
+- [Support](#support)
 - [Codemap](#codemap)
+- [Releases](#releases)
 - [License](#license)
 - [Links](#links)
 
@@ -42,14 +44,22 @@
 <a name="build"></a>
 ## Building Abseil
 
-[Bazel](https://bazel.build) is the official build system for Abseil,
-which is supported on most major platforms (Linux, Windows, macOS, for example)
-and compilers. See the [quickstart](https://abseil.io/docs/cpp/quickstart) for
-more information on building Abseil using the Bazel build system.
+[Bazel](https://bazel.build) and [CMake](https://cmake.org/) are the official
+build systems for Abseil.
 
-<a name="cmake"></a>
-If you require CMake support, please check the
-[CMake build instructions](CMake/README.md).
+See the [quickstart](https://abseil.io/docs/cpp/quickstart) for more information
+on building Abseil using the Bazel build system.
+
+If you require CMake support, please check the [CMake build
+instructions](CMake/README.md) and [CMake
+Quickstart](https://abseil.io/docs/cpp/quickstart-cmake).
+
+## Support
+
+Abseil is officially supported on many platforms. See the [Abseil
+platform support
+guide](https://abseil.io/docs/cpp/platforms/platforms) for details on
+supported operating systems, compilers, CPUs, etc.
 
 ## Codemap
 
@@ -62,6 +72,9 @@
 * [`algorithm`](absl/algorithm/)
   <br /> The `algorithm` library contains additions to the C++ `<algorithm>`
   library and container-based versions of such algorithms.
+* [`cleanup`](absl/cleanup/)
+  <br /> The `cleanup` library contains the control-flow-construct-like type
+  `absl::Cleanup` which is used for executing a callback on scope exit.
 * [`container`](absl/container/)
   <br /> The `container` library contains additional STL-style containers,
   including Abseil's unordered "Swiss table" containers.
@@ -79,6 +92,9 @@
   available within C++14 and C++17 versions of the C++ `<type_traits>` library.
 * [`numeric`](absl/numeric/)
   <br /> The `numeric` library contains C++11-compatible 128-bit integers.
+* [`status`](absl/status/)
+  <br /> The `status` contains abstractions for error handling, specifically
+  `absl::Status` and `absl::StatusOr<T>`.
 * [`strings`](absl/strings/)
   <br /> The `strings` library contains a variety of strings routines and
   utilities, including a C++11-compatible version of the C++17
@@ -97,6 +113,15 @@
 * [`utility`](absl/utility/)
   <br /> The `utility` library contains utility and helper code.
 
+## Releases
+
+Abseil recommends users "live-at-head" (update to the latest commit from the
+master branch as often as possible). However, we realize this philosophy doesn't
+work for every project, so we also provide [Long Term Support
+Releases](https://github.com/abseil/abseil-cpp/releases) to which we backport
+fixes for severe bugs. See our [release
+management](https://abseil.io/about/releases) document for more details.
+
 ## License
 
 The Abseil C++ library is licensed under the terms of the Apache
diff --git a/WORKSPACE b/WORKSPACE
index f2b1046..258d23b 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -19,18 +19,19 @@
 
 # GoogleTest/GoogleMock framework. Used by most unit-tests.
 http_archive(
-     name = "com_google_googletest",
-     urls = ["https://github.com/google/googletest/archive/b6cd405286ed8635ece71c72f118e659f4ade3fb.zip"],  # 2019-01-07
-     strip_prefix = "googletest-b6cd405286ed8635ece71c72f118e659f4ade3fb",
-     sha256 = "ff7a82736e158c077e76188232eac77913a15dac0b22508c390ab3f88e6d6d86",
+    name = "com_google_googletest",
+    # Keep this URL in sync with ABSL_GOOGLETEST_COMMIT in ci/cmake_common.sh.
+    urls = ["https://github.com/google/googletest/archive/8567b09290fe402cf01923e2131c5635b8ed851b.zip"],  # 2020-06-12T22:24:28Z
+    strip_prefix = "googletest-8567b09290fe402cf01923e2131c5635b8ed851b",
+    sha256 = "9a8a166eb6a56c7b3d7b19dc2c946fe4778fd6f21c7a12368ad3b836d8f1be48",
 )
 
 # Google benchmark.
 http_archive(
     name = "com_github_google_benchmark",
-    urls = ["https://github.com/google/benchmark/archive/16703ff83c1ae6d53e5155df3bb3ab0bc96083be.zip"],
-    strip_prefix = "benchmark-16703ff83c1ae6d53e5155df3bb3ab0bc96083be",
-    sha256 = "59f918c8ccd4d74b6ac43484467b500f1d64b40cc1010daa055375b322a43ba3",
+    urls = ["https://github.com/google/benchmark/archive/bf585a2789e30585b4e3ce6baf11ef2750b54677.zip"],  # 2020-11-26T11:14:03Z
+    strip_prefix = "benchmark-bf585a2789e30585b4e3ce6baf11ef2750b54677",
+    sha256 = "2a778d821997df7d8646c9c59b8edb9a573a6e04c534c01892a40aa524a7b68c",
 )
 
 # C++ rules for Bazel.
@@ -39,7 +40,6 @@
     sha256 = "9a446e9dd9c1bb180c86977a8dc1e9e659550ae732ae58bd2e8fd51e15b2c91d",
     strip_prefix = "rules_cc-262ebec3c2296296526740db4aefce68c80de7fa",
     urls = [
-        "https://mirror.bazel.build/github.com/bazelbuild/rules_cc/archive/262ebec3c2296296526740db4aefce68c80de7fa.zip",
         "https://github.com/bazelbuild/rules_cc/archive/262ebec3c2296296526740db4aefce68c80de7fa.zip",
     ],
 )
diff --git a/absl/BUILD.bazel b/absl/BUILD.bazel
index 5a03acf..c9d4a2d 100644
--- a/absl/BUILD.bazel
+++ b/absl/BUILD.bazel
@@ -12,19 +12,32 @@
 # 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.
-#
-
-load(
-    ":compiler_config_setting.bzl",
-    "create_llvm_config",
-)
 
 package(default_visibility = ["//visibility:public"])
 
-licenses(["notice"])  # Apache 2.0
+licenses(["notice"])
 
-create_llvm_config(
-    name = "llvm_compiler",
+config_setting(
+    name = "clang_compiler",
+    flag_values = {
+        "@bazel_tools//tools/cpp:compiler": "clang",
+    },
+    visibility = [":__subpackages__"],
+)
+
+config_setting(
+    name = "msvc_compiler",
+    flag_values = {
+        "@bazel_tools//tools/cpp:compiler": "msvc-cl",
+    },
+    visibility = [":__subpackages__"],
+)
+
+config_setting(
+    name = "clang-cl_compiler",
+    flag_values = {
+        "@bazel_tools//tools/cpp:compiler": "clang-cl",
+    },
     visibility = [":__subpackages__"],
 )
 
@@ -43,17 +56,17 @@
 )
 
 config_setting(
-    name = "windows",
+    name = "ppc",
     values = {
-        "cpu": "x64_windows",
+        "cpu": "ppc",
     },
     visibility = [":__subpackages__"],
 )
 
 config_setting(
-    name = "ppc",
+    name = "wasm",
     values = {
-        "cpu": "ppc",
+        "cpu": "wasm32",
     },
     visibility = [":__subpackages__"],
 )
diff --git a/absl/CMakeLists.txt b/absl/CMakeLists.txt
index fbfa782..a41e1ee 100644
--- a/absl/CMakeLists.txt
+++ b/absl/CMakeLists.txt
@@ -16,6 +16,7 @@
 
 add_subdirectory(base)
 add_subdirectory(algorithm)
+add_subdirectory(cleanup)
 add_subdirectory(container)
 add_subdirectory(debugging)
 add_subdirectory(flags)
diff --git a/absl/abseil.podspec.gen.py b/absl/abseil.podspec.gen.py
index 6aefb79..6375298 100755
--- a/absl/abseil.podspec.gen.py
+++ b/absl/abseil.podspec.gen.py
@@ -40,8 +40,8 @@
     'USE_HEADERMAP' => 'NO',
     'ALWAYS_SEARCH_USER_PATHS' => 'NO',
   }
-  s.ios.deployment_target = '7.0'
-  s.osx.deployment_target = '10.9'
+  s.ios.deployment_target = '9.0'
+  s.osx.deployment_target = '10.10'
   s.tvos.deployment_target = '9.0'
   s.watchos.deployment_target = '2.0'
 """
diff --git a/absl/algorithm/BUILD.bazel b/absl/algorithm/BUILD.bazel
index 6a96420..a3002b7 100644
--- a/absl/algorithm/BUILD.bazel
+++ b/absl/algorithm/BUILD.bazel
@@ -24,14 +24,16 @@
 
 package(default_visibility = ["//visibility:public"])
 
-licenses(["notice"])  # Apache 2.0
+licenses(["notice"])
 
 cc_library(
     name = "algorithm",
     hdrs = ["algorithm.h"],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
-    deps = ["//absl/base:config"],
+    deps = [
+        "//absl/base:config",
+    ],
 )
 
 cc_test(
diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h
index d72532d..6398438 100644
--- a/absl/algorithm/container.h
+++ b/absl/algorithm/container.h
@@ -90,10 +90,10 @@
 // lookup of std::begin and std::end, i.e.
 //   using std::begin;
 //   using std::end;
-//   std::foo(begin(c), end(c);
+//   std::foo(begin(c), end(c));
 // becomes
 //   std::foo(container_algorithm_internal::begin(c),
-//   container_algorithm_internal::end(c));
+//            container_algorithm_internal::end(c));
 // These are meant for internal use only.
 
 template <typename C>
@@ -188,7 +188,7 @@
 // c_none_of()
 //
 // Container-based version of the <algorithm> `std::none_of()` function to
-// test if no elements in a container fulfil a condition.
+// test if no elements in a container fulfill a condition.
 template <typename C, typename Pred>
 bool c_none_of(const C& c, Pred&& pred) {
   return std::none_of(container_algorithm_internal::c_begin(c),
@@ -340,24 +340,45 @@
 // c_mismatch()
 //
 // Container-based version of the <algorithm> `std::mismatch()` function to
-// return the first element where two ordered containers differ.
+// return the first element where two ordered containers differ. Applies `==` to
+// the first N elements of `c1` and `c2`, where N = min(size(c1), size(c2)).
 template <typename C1, typename C2>
 container_algorithm_internal::ContainerIterPairType<C1, C2>
 c_mismatch(C1& c1, C2& c2) {
-  return std::mismatch(container_algorithm_internal::c_begin(c1),
-                       container_algorithm_internal::c_end(c1),
-                       container_algorithm_internal::c_begin(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);
+  auto last2 = container_algorithm_internal::c_end(c2);
+
+  for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
+    // Negates equality because Cpp17EqualityComparable doesn't require clients
+    // to overload both `operator==` and `operator!=`.
+    if (!(*first1 == *first2)) {
+      break;
+    }
+  }
+
+  return std::make_pair(first1, first2);
 }
 
 // Overload of c_mismatch() for using a predicate evaluation other than `==` as
-// the function's test condition.
+// the function's test condition. Applies `pred`to the first N elements of `c1`
+// and `c2`, where N = min(size(c1), size(c2)).
 template <typename C1, typename C2, typename BinaryPredicate>
 container_algorithm_internal::ContainerIterPairType<C1, C2>
-c_mismatch(C1& c1, C2& c2, BinaryPredicate&& pred) {
-  return std::mismatch(container_algorithm_internal::c_begin(c1),
-                       container_algorithm_internal::c_end(c1),
-                       container_algorithm_internal::c_begin(c2),
-                       std::forward<BinaryPredicate>(pred));
+c_mismatch(C1& c1, C2& c2, BinaryPredicate pred) {
+  auto first1 = container_algorithm_internal::c_begin(c1);
+  auto last1 = container_algorithm_internal::c_end(c1);
+  auto first2 = container_algorithm_internal::c_begin(c2);
+  auto last2 = container_algorithm_internal::c_end(c2);
+
+  for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
+    if (!pred(*first1, *first2)) {
+      break;
+    }
+  }
+
+  return std::make_pair(first1, first2);
 }
 
 // c_equal()
@@ -539,12 +560,20 @@
 // c_swap_ranges()
 //
 // Container-based version of the <algorithm> `std::swap_ranges()` function to
-// swap a container's elements with another container's elements.
+// 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) {
-  return std::swap_ranges(container_algorithm_internal::c_begin(c1),
-                          container_algorithm_internal::c_end(c1),
-                          container_algorithm_internal::c_begin(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);
+  auto last2 = container_algorithm_internal::c_end(c2);
+
+  using std::swap;
+  for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
+    swap(*first1, *first2);
+  }
+  return first2;
 }
 
 // c_transform()
@@ -562,16 +591,23 @@
 }
 
 // Overload of c_transform() for performing a transformation using a binary
-// predicate.
+// predicate. Applies `binary_op` to the first N elements of `c1` and `c2`,
+// 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) {
-  return std::transform(container_algorithm_internal::c_begin(input1),
-                        container_algorithm_internal::c_end(input1),
-                        container_algorithm_internal::c_begin(input2), output,
-                        std::forward<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);
+  auto last2 = container_algorithm_internal::c_end(input2);
+  for (; first1 != last1 && first2 != last2;
+       ++first1, (void)++first2, ++output) {
+    *output = binary_op(*first1, *first2);
+  }
+
+  return output;
 }
 
 // c_replace()
@@ -943,9 +979,10 @@
 // c_partial_sort_copy()
 //
 // Container-based version of the <algorithm> `std::partial_sort_copy()`
-// function to sort elements within a container such that elements before
-// `middle` are sorted in ascending order, and return the result within an
-// iterator.
+// function to sort the elements in the given range `result` within the larger
+// `sequence` in ascending order (and using `result` as the output parameter).
+// 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) {
diff --git a/absl/algorithm/container_test.cc b/absl/algorithm/container_test.cc
index 0a4abe9..605afc8 100644
--- a/absl/algorithm/container_test.cc
+++ b/absl/algorithm/container_test.cc
@@ -57,9 +57,7 @@
 };
 
 struct AccumulateCalls {
-  void operator()(int value) {
-    calls.push_back(value);
-  }
+  void operator()(int value) { calls.push_back(value); }
   std::vector<int> calls;
 };
 
@@ -68,7 +66,6 @@
 bool Equals(int v1, int v2) { return v1 == v2; }
 bool IsOdd(int x) { return x % 2 != 0; }
 
-
 TEST_F(NonMutatingTest, Distance) {
   EXPECT_EQ(container_.size(), absl::c_distance(container_));
   EXPECT_EQ(sequence_.size(), absl::c_distance(sequence_));
@@ -151,13 +148,90 @@
 }
 
 TEST_F(NonMutatingTest, Mismatch) {
-  absl::c_mismatch(container_, sequence_);
-  absl::c_mismatch(sequence_, container_);
+  // Testing necessary as absl::c_mismatch executes logic.
+  {
+    auto result = absl::c_mismatch(vector_, sequence_);
+    EXPECT_EQ(result.first, vector_.end());
+    EXPECT_EQ(result.second, sequence_.end());
+  }
+  {
+    auto result = absl::c_mismatch(sequence_, vector_);
+    EXPECT_EQ(result.first, sequence_.end());
+    EXPECT_EQ(result.second, vector_.end());
+  }
+
+  sequence_.back() = 5;
+  {
+    auto result = absl::c_mismatch(vector_, sequence_);
+    EXPECT_EQ(result.first, std::prev(vector_.end()));
+    EXPECT_EQ(result.second, std::prev(sequence_.end()));
+  }
+  {
+    auto result = absl::c_mismatch(sequence_, vector_);
+    EXPECT_EQ(result.first, std::prev(sequence_.end()));
+    EXPECT_EQ(result.second, std::prev(vector_.end()));
+  }
+
+  sequence_.pop_back();
+  {
+    auto result = absl::c_mismatch(vector_, sequence_);
+    EXPECT_EQ(result.first, std::prev(vector_.end()));
+    EXPECT_EQ(result.second, sequence_.end());
+  }
+  {
+    auto result = absl::c_mismatch(sequence_, vector_);
+    EXPECT_EQ(result.first, sequence_.end());
+    EXPECT_EQ(result.second, std::prev(vector_.end()));
+  }
+  {
+    struct NoNotEquals {
+      constexpr bool operator==(NoNotEquals) const { return true; }
+      constexpr bool operator!=(NoNotEquals) const = delete;
+    };
+    std::vector<NoNotEquals> first;
+    std::list<NoNotEquals> second;
+
+    // Check this still compiles.
+    absl::c_mismatch(first, second);
+  }
 }
 
 TEST_F(NonMutatingTest, MismatchWithPredicate) {
-  absl::c_mismatch(container_, sequence_, BinPredicate);
-  absl::c_mismatch(sequence_, container_, BinPredicate);
+  // Testing necessary as absl::c_mismatch executes logic.
+  {
+    auto result = absl::c_mismatch(vector_, sequence_, BinPredicate);
+    EXPECT_EQ(result.first, vector_.begin());
+    EXPECT_EQ(result.second, sequence_.begin());
+  }
+  {
+    auto result = absl::c_mismatch(sequence_, vector_, BinPredicate);
+    EXPECT_EQ(result.first, sequence_.begin());
+    EXPECT_EQ(result.second, vector_.begin());
+  }
+
+  sequence_.front() = 0;
+  {
+    auto result = absl::c_mismatch(vector_, sequence_, BinPredicate);
+    EXPECT_EQ(result.first, vector_.begin());
+    EXPECT_EQ(result.second, sequence_.begin());
+  }
+  {
+    auto result = absl::c_mismatch(sequence_, vector_, BinPredicate);
+    EXPECT_EQ(result.first, std::next(sequence_.begin()));
+    EXPECT_EQ(result.second, std::next(vector_.begin()));
+  }
+
+  sequence_.clear();
+  {
+    auto result = absl::c_mismatch(vector_, sequence_, BinPredicate);
+    EXPECT_EQ(result.first, vector_.begin());
+    EXPECT_EQ(result.second, sequence_.end());
+  }
+  {
+    auto result = absl::c_mismatch(sequence_, vector_, BinPredicate);
+    EXPECT_EQ(result.first, sequence_.end());
+    EXPECT_EQ(result.second, vector_.begin());
+  }
 }
 
 TEST_F(NonMutatingTest, Equal) {
@@ -519,11 +593,9 @@
 TEST_F(SortingTest, NthElement) {
   std::vector<int> unsorted = {2, 4, 1, 3};
   absl::c_nth_element(unsorted, unsorted.begin() + 2);
-  EXPECT_THAT(unsorted,
-              ElementsAre(Lt(3), Lt(3), 3, Gt(3)));
+  EXPECT_THAT(unsorted, ElementsAre(Lt(3), Lt(3), 3, Gt(3)));
   absl::c_nth_element(unsorted, unsorted.begin() + 2, std::greater<int>());
-  EXPECT_THAT(unsorted,
-              ElementsAre(Gt(2), Gt(2), 2, Lt(2)));
+  EXPECT_THAT(unsorted, ElementsAre(Gt(2), Gt(2), 2, Lt(2)));
 }
 
 TEST(MutatingTest, IsPartitioned) {
@@ -676,6 +748,15 @@
   absl::c_swap_ranges(odds, evens);
   EXPECT_THAT(odds, ElementsAre(1, 3, 5));
   EXPECT_THAT(evens, ElementsAre(2, 4, 6));
+
+  odds.pop_back();
+  absl::c_swap_ranges(odds, evens);
+  EXPECT_THAT(odds, ElementsAre(2, 4));
+  EXPECT_THAT(evens, ElementsAre(1, 3, 6));
+
+  absl::c_swap_ranges(evens, odds);
+  EXPECT_THAT(odds, ElementsAre(1, 3));
+  EXPECT_THAT(evens, ElementsAre(2, 4, 6));
 }
 
 TEST_F(NonMutatingTest, Transform) {
@@ -690,6 +771,20 @@
   EXPECT_EQ(std::vector<int>({1, 5, 4}), z);
   *end = 7;
   EXPECT_EQ(std::vector<int>({1, 5, 4, 7}), z);
+
+  z.clear();
+  y.pop_back();
+  end = absl::c_transform(x, y, std::back_inserter(z), std::plus<int>());
+  EXPECT_EQ(std::vector<int>({1, 5}), z);
+  *end = 7;
+  EXPECT_EQ(std::vector<int>({1, 5, 7}), z);
+
+  z.clear();
+  std::swap(x, y);
+  end = absl::c_transform(x, y, std::back_inserter(z), std::plus<int>());
+  EXPECT_EQ(std::vector<int>({1, 5}), z);
+  *end = 7;
+  EXPECT_EQ(std::vector<int>({1, 5, 7}), z);
 }
 
 TEST(MutatingTest, Replace) {
@@ -755,10 +850,9 @@
 TEST(MutatingTest, StableSort) {
   std::vector<Element> test_vector = {{1, 1}, {2, 1}, {2, 0}, {1, 0}, {2, 2}};
   absl::c_stable_sort(test_vector);
-  EXPECT_THAT(
-      test_vector,
-      ElementsAre(IsElement(1, 1), IsElement(1, 0), IsElement(2, 1),
-                  IsElement(2, 0), IsElement(2, 2)));
+  EXPECT_THAT(test_vector,
+              ElementsAre(IsElement(1, 1), IsElement(1, 0), IsElement(2, 1),
+                          IsElement(2, 0), IsElement(2, 2)));
 }
 
 TEST(MutatingTest, StableSortWithPredicate) {
@@ -766,10 +860,9 @@
   absl::c_stable_sort(test_vector, [](const Element& e1, const Element& e2) {
     return e2 < e1;
   });
-  EXPECT_THAT(
-      test_vector,
-      ElementsAre(IsElement(2, 1), IsElement(2, 0), IsElement(2, 2),
-                  IsElement(1, 1), IsElement(1, 0)));
+  EXPECT_THAT(test_vector,
+              ElementsAre(IsElement(2, 1), IsElement(2, 0), IsElement(2, 2),
+                          IsElement(1, 1), IsElement(1, 0)));
 }
 
 TEST(MutatingTest, ReplaceCopyIf) {
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index bae7942..65ff0dd 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -24,7 +24,7 @@
 
 package(default_visibility = ["//visibility:public"])
 
-licenses(["notice"])  # Apache 2.0
+licenses(["notice"])
 
 cc_library(
     name = "atomic_hook",
@@ -115,11 +115,18 @@
 
 cc_library(
     name = "dynamic_annotations",
-    srcs = ["dynamic_annotations.cc"],
-    hdrs = ["dynamic_annotations.h"],
+    srcs = [
+        "internal/dynamic_annotations.h",
+    ],
+    hdrs = [
+        "dynamic_annotations.h",
+    ],
     copts = ABSL_DEFAULT_COPTS,
-    defines = ["__CLANG_SUPPORT_DYN_ANNOTATION__"],
     linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":config",
+        ":core_headers",
+    ],
 )
 
 cc_library(
@@ -153,7 +160,9 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = select({
-        "//absl:windows": [],
+        "//absl:msvc_compiler": [],
+        "//absl:clang-cl_compiler": [],
+        "//absl:wasm": [],
         "//conditions:default": ["-pthread"],
     }) + ABSL_DEFAULT_LINKOPTS,
     visibility = [
@@ -212,9 +221,13 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = select({
-        "//absl:windows": [
+        "//absl:msvc_compiler": [
             "-DEFAULTLIB:advapi32.lib",
         ],
+        "//absl:clang-cl_compiler": [
+            "-DEFAULTLIB:advapi32.lib",
+        ],
+        "//absl:wasm": [],
         "//conditions:default": ["-pthread"],
     }) + ABSL_DEFAULT_LINKOPTS,
     deps = [
@@ -307,6 +320,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":errno_saver",
+        ":strerror",
         "@com_google_googletest//:gtest_main",
     ],
 )
@@ -405,6 +419,7 @@
     deps = [
         ":base",
         ":base_internal",
+        ":config",
         ":core_headers",
         "//absl/synchronization",
         "@com_google_googletest//:gtest",
@@ -421,6 +436,7 @@
     deps = [
         ":base",
         ":base_internal",
+        ":config",
         ":core_headers",
         "//absl/synchronization",
         "@com_google_googletest//:gtest_main",
@@ -451,6 +467,7 @@
     testonly = 1,
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
+    tags = ["benchmark"],
     visibility = ["//visibility:private"],
     deps = [
         ":spinlock_benchmark_common",
@@ -466,6 +483,7 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        ":base",
         ":config",
         ":core_headers",
     ],
@@ -538,8 +556,13 @@
     srcs = ["internal/low_level_alloc_test.cc"],
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
-    tags = ["no_test_ios_x86_64"],
-    deps = [":malloc_internal"],
+    tags = [
+        "no_test_ios_x86_64",
+    ],
+    deps = [
+        ":malloc_internal",
+        "//absl/container:node_hash_map",
+    ],
 )
 
 cc_test(
@@ -571,31 +594,6 @@
 )
 
 cc_library(
-    name = "bits",
-    hdrs = ["internal/bits.h"],
-    linkopts = ABSL_DEFAULT_LINKOPTS,
-    visibility = [
-        "//absl:__subpackages__",
-    ],
-    deps = [
-        ":config",
-        ":core_headers",
-    ],
-)
-
-cc_test(
-    name = "bits_test",
-    size = "small",
-    srcs = ["internal/bits_test.cc"],
-    copts = ABSL_TEST_COPTS,
-    linkopts = ABSL_DEFAULT_LINKOPTS,
-    deps = [
-        ":bits",
-        "@com_google_googletest//:gtest_main",
-    ],
-)
-
-cc_library(
     name = "exponential_biased",
     srcs = ["internal/exponential_biased.cc"],
     hdrs = ["internal/exponential_biased.h"],
@@ -705,3 +703,98 @@
         "@com_google_googletest//:gtest_main",
     ],
 )
+
+cc_library(
+    name = "strerror",
+    srcs = ["internal/strerror.cc"],
+    hdrs = ["internal/strerror.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
+    deps = [
+        ":config",
+        ":core_headers",
+        ":errno_saver",
+    ],
+)
+
+cc_test(
+    name = "strerror_test",
+    size = "small",
+    srcs = ["internal/strerror_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":strerror",
+        "//absl/strings",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_binary(
+    name = "strerror_benchmark",
+    testonly = 1,
+    srcs = ["internal/strerror_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strerror",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_library(
+    name = "fast_type_id",
+    hdrs = ["internal/fast_type_id.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
+    deps = [
+        ":config",
+    ],
+)
+
+cc_test(
+    name = "fast_type_id_test",
+    size = "small",
+    srcs = ["internal/fast_type_id_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":fast_type_id",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "unique_small_name_test",
+    size = "small",
+    srcs = ["internal/unique_small_name_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    linkstatic = 1,
+    deps = [
+        ":core_headers",
+        "//absl/strings",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "optimization_test",
+    size = "small",
+    srcs = ["optimization_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":core_headers",
+        "//absl/types:optional",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index 14c52ea..981b8cc 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -105,11 +105,11 @@
   HDRS
     "dynamic_annotations.h"
   SRCS
-    "dynamic_annotations.cc"
+    "internal/dynamic_annotations.h"
   COPTS
     ${ABSL_DEFAULT_COPTS}
-  DEFINES
-    "__CLANG_SUPPORT_DYN_ANNOTATION__"
+  DEPS
+    absl::config
   PUBLIC
 )
 
@@ -191,7 +191,7 @@
     ${ABSL_DEFAULT_COPTS}
   LINKOPTS
     ${ABSL_DEFAULT_LINKOPTS}
-    $<$<BOOL:${LIBRT}>:${LIBRT}>
+    $<$<BOOL:${LIBRT}>:-lrt>
     $<$<BOOL:${MINGW}>:"advapi32">
   DEPS
     absl::atomic_hook
@@ -326,6 +326,7 @@
     ${ABSL_TEST_COPTS}
   DEPS
     absl::errno_saver
+    absl::strerror
     gmock
     gtest_main
 )
@@ -383,6 +384,7 @@
     ${ABSL_TEST_COPTS}
   DEPS
     absl::base
+    absl::config
     absl::base_internal
     absl::core_headers
     absl::synchronization
@@ -401,6 +403,7 @@
   DEPS
     absl::base
     absl::base_internal
+    absl::config
     absl::core_headers
     absl::synchronization
     gtest_main
@@ -415,6 +418,7 @@
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
+    absl::base
     absl::config
     absl::core_headers
   PUBLIC
@@ -496,6 +500,7 @@
     ${ABSL_TEST_COPTS}
   DEPS
     absl::malloc_internal
+    absl::node_hash_map
     Threads::Threads
 )
 
@@ -516,30 +521,6 @@
 
 absl_cc_library(
   NAME
-    bits
-  HDRS
-    "internal/bits.h"
-  COPTS
-    ${ABSL_DEFAULT_COPTS}
-  DEPS
-    absl::config
-    absl::core_headers
-)
-
-absl_cc_test(
-  NAME
-    bits_test
-  SRCS
-    "internal/bits_test.cc"
-  COPTS
-    ${ABSL_TEST_COPTS}
-  DEPS
-    absl::bits
-    gtest_main
-)
-
-absl_cc_library(
-  NAME
     exponential_biased
   SRCS
     "internal/exponential_biased.cc"
@@ -642,3 +623,72 @@
     gmock
     gtest_main
 )
+
+absl_cc_library(
+  NAME
+    strerror
+  SRCS
+    "internal/strerror.cc"
+  HDRS
+    "internal/strerror.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+    absl::config
+    absl::core_headers
+    absl::errno_saver
+)
+
+absl_cc_test(
+  NAME
+    strerror_test
+  SRCS
+    "internal/strerror_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::strerror
+    absl::strings
+    gmock
+    gtest_main
+)
+
+absl_cc_library(
+  NAME
+    fast_type_id
+  HDRS
+    "internal/fast_type_id.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+    absl::config
+)
+
+absl_cc_test(
+  NAME
+    fast_type_id_test
+  SRCS
+    "internal/fast_type_id_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::fast_type_id
+    gtest_main
+)
+
+absl_cc_test(
+  NAME
+    optimization_test
+  SRCS
+    "optimization_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::core_headers
+    absl::optional
+    gtest_main
+)
diff --git a/absl/base/attributes.h b/absl/base/attributes.h
index ff13862..cf2cb55 100644
--- a/absl/base/attributes.h
+++ b/absl/base/attributes.h
@@ -18,8 +18,6 @@
 // These macros are used within Abseil and allow the compiler to optimize, where
 // applicable, certain function calls.
 //
-// This file is used for both C and C++!
-//
 // Most macros here are exposing GCC or Clang features, and are stubbed out for
 // other compilers.
 //
@@ -32,34 +30,12 @@
 // of them are not supported in older version of Clang. Thus, we check
 // `__has_attribute()` first. If the check fails, we check if we are on GCC and
 // assume the attribute exists on GCC (which is verified on GCC 4.7).
-//
-// -----------------------------------------------------------------------------
-// Sanitizer Attributes
-// -----------------------------------------------------------------------------
-//
-// Sanitizer-related attributes are not "defined" in this file (and indeed
-// are not defined as such in any file). To utilize the following
-// sanitizer-related attributes within your builds, define the following macros
-// within your build using a `-D` flag, along with the given value for
-// `-fsanitize`:
-//
-//   * `ADDRESS_SANITIZER` + `-fsanitize=address` (Clang, GCC 4.8)
-//   * `MEMORY_SANITIZER` + `-fsanitize=memory` (Clang-only)
-//   * `THREAD_SANITIZER + `-fsanitize=thread` (Clang, GCC 4.8+)
-//   * `UNDEFINED_BEHAVIOR_SANITIZER` + `-fsanitize=undefined` (Clang, GCC 4.9+)
-//   * `CONTROL_FLOW_INTEGRITY` + -fsanitize=cfi (Clang-only)
-//
-// Example:
-//
-//   // Enable branches in the Abseil code that are tagged for ASan:
-//   $ bazel build --copt=-DADDRESS_SANITIZER --copt=-fsanitize=address
-//     --linkopt=-fsanitize=address *target*
-//
-// Since these macro names are only supported by GCC and Clang, we only check
-// for `__GNUC__` (GCC or Clang) and the above macros.
+
 #ifndef ABSL_BASE_ATTRIBUTES_H_
 #define ABSL_BASE_ATTRIBUTES_H_
 
+#include "absl/base/config.h"
+
 // ABSL_HAVE_ATTRIBUTE
 //
 // A function-like feature checking macro that is a wrapper around
@@ -143,7 +119,7 @@
 #if ABSL_HAVE_ATTRIBUTE(disable_tail_calls)
 #define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
 #define ABSL_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls))
-#elif defined(__GNUC__) && !defined(__clang__)
+#elif defined(__GNUC__) && !defined(__clang__) && !defined(__e2k__)
 #define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
 #define ABSL_ATTRIBUTE_NO_TAIL_CALL \
   __attribute__((optimize("no-optimize-sibling-calls")))
@@ -234,7 +210,7 @@
 // out of bounds or does other scary things with memory.
 // NOTE: GCC supports AddressSanitizer(asan) since 4.8.
 // https://gcc.gnu.org/gcc-4.8/changes.html
-#if defined(__GNUC__)
+#if ABSL_HAVE_ATTRIBUTE(no_sanitize_address)
 #define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
 #else
 #define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
@@ -242,13 +218,13 @@
 
 // ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
 //
-// Tells the  MemorySanitizer to relax the handling of a given function. All
-// "Use of uninitialized value" warnings from such functions will be suppressed,
-// and all values loaded from memory will be considered fully initialized.
-// This attribute is similar to the ADDRESS_SANITIZER attribute above, but deals
-// with initialized-ness rather than addressability issues.
+// Tells the MemorySanitizer to relax the handling of a given function. All "Use
+// of uninitialized value" warnings from such functions will be suppressed, and
+// all values loaded from memory will be considered fully initialized.  This
+// attribute is similar to the ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS attribute
+// above, but deals with initialized-ness rather than addressability issues.
 // NOTE: MemorySanitizer(msan) is supported by Clang but not GCC.
-#if defined(__clang__)
+#if ABSL_HAVE_ATTRIBUTE(no_sanitize_memory)
 #define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
 #else
 #define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
@@ -259,7 +235,7 @@
 // Tells the ThreadSanitizer to not instrument a given function.
 // NOTE: GCC supports ThreadSanitizer(tsan) since 4.8.
 // https://gcc.gnu.org/gcc-4.8/changes.html
-#if defined(__GNUC__)
+#if ABSL_HAVE_ATTRIBUTE(no_sanitize_thread)
 #define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
 #else
 #define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
@@ -271,8 +247,10 @@
 // where certain behavior (eg. division by zero) is being used intentionally.
 // NOTE: GCC supports UndefinedBehaviorSanitizer(ubsan) since 4.9.
 // https://gcc.gnu.org/gcc-4.9/changes.html
-#if defined(__GNUC__) && \
-    (defined(UNDEFINED_BEHAVIOR_SANITIZER) || defined(ADDRESS_SANITIZER))
+#if ABSL_HAVE_ATTRIBUTE(no_sanitize_undefined)
+#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
+  __attribute__((no_sanitize_undefined))
+#elif ABSL_HAVE_ATTRIBUTE(no_sanitize)
 #define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
   __attribute__((no_sanitize("undefined")))
 #else
@@ -283,7 +261,7 @@
 //
 // Tells the ControlFlowIntegrity sanitizer to not instrument a given function.
 // See https://clang.llvm.org/docs/ControlFlowIntegrity.html for details.
-#if defined(__GNUC__) && defined(CONTROL_FLOW_INTEGRITY)
+#if ABSL_HAVE_ATTRIBUTE(no_sanitize)
 #define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi")))
 #else
 #define ABSL_ATTRIBUTE_NO_SANITIZE_CFI
@@ -293,7 +271,7 @@
 //
 // Tells the SafeStack to not instrument a given function.
 // See https://clang.llvm.org/docs/SafeStack.html for details.
-#if defined(__GNUC__) && defined(SAFESTACK_SANITIZER)
+#if ABSL_HAVE_ATTRIBUTE(no_sanitize)
 #define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK \
   __attribute__((no_sanitize("safe-stack")))
 #else
@@ -507,8 +485,10 @@
 // packages/targets, as this may lead to conflicting definitions of functions at
 // link-time.
 //
+// XRay isn't currently supported on Android:
+// https://github.com/android/ndk/issues/368
 #if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_always_instrument) && \
-    !defined(ABSL_NO_XRAY_ATTRIBUTES)
+    !defined(ABSL_NO_XRAY_ATTRIBUTES) && !defined(__ANDROID__)
 #define ABSL_XRAY_ALWAYS_INSTRUMENT [[clang::xray_always_instrument]]
 #define ABSL_XRAY_NEVER_INSTRUMENT [[clang::xray_never_instrument]]
 #if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_log_args)
@@ -592,6 +572,86 @@
 #define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes)
 #endif
 
+// ABSL_FALLTHROUGH_INTENDED
+//
+// Annotates implicit fall-through between switch labels, allowing a case to
+// indicate intentional fallthrough and turn off warnings about any lack of a
+// `break` statement. The ABSL_FALLTHROUGH_INTENDED macro should be followed by
+// a semicolon and can be used in most places where `break` can, provided that
+// no statements exist between it and the next switch label.
+//
+// Example:
+//
+//  switch (x) {
+//    case 40:
+//    case 41:
+//      if (truth_is_out_there) {
+//        ++x;
+//        ABSL_FALLTHROUGH_INTENDED;  // Use instead of/along with annotations
+//                                    // in comments
+//      } else {
+//        return x;
+//      }
+//    case 42:
+//      ...
+//
+// Notes: when compiled with clang in C++11 mode, the ABSL_FALLTHROUGH_INTENDED
+// macro is expanded to the [[clang::fallthrough]] attribute, which is analysed
+// when  performing switch labels fall-through diagnostic
+// (`-Wimplicit-fallthrough`). See clang documentation on language extensions
+// for details:
+// https://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough
+//
+// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro
+// has no effect on diagnostics. In any case this macro has no effect on runtime
+// behavior and performance of code.
+
+#ifdef ABSL_FALLTHROUGH_INTENDED
+#error "ABSL_FALLTHROUGH_INTENDED should not be defined."
+#endif
+
+// TODO(zhangxy): Use c++17 standard [[fallthrough]] macro, when supported.
+#if defined(__clang__) && defined(__has_warning)
+#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
+#define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]]
+#endif
+#elif defined(__GNUC__) && __GNUC__ >= 7
+#define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
+#endif
+
+#ifndef ABSL_FALLTHROUGH_INTENDED
+#define ABSL_FALLTHROUGH_INTENDED \
+  do {                            \
+  } while (0)
+#endif
+
+// ABSL_DEPRECATED()
+//
+// Marks a deprecated class, struct, enum, function, method and variable
+// declarations. The macro argument is used as a custom diagnostic message (e.g.
+// suggestion of a better alternative).
+//
+// Examples:
+//
+//   class ABSL_DEPRECATED("Use Bar instead") Foo {...};
+//
+//   ABSL_DEPRECATED("Use Baz() instead") void Bar() {...}
+//
+//   template <typename T>
+//   ABSL_DEPRECATED("Use DoThat() instead")
+//   void DoThis();
+//
+// Every usage of a deprecated entity will trigger a warning when compiled with
+// clang's `-Wdeprecated-declarations` option. This option is turned off by
+// default, but the warnings will be reported by clang-tidy.
+#if defined(__clang__) && defined(__cplusplus) && __cplusplus >= 201103L
+#define ABSL_DEPRECATED(message) __attribute__((deprecated(message)))
+#endif
+
+#ifndef ABSL_DEPRECATED
+#define ABSL_DEPRECATED(message)
+#endif
+
 // ABSL_CONST_INIT
 //
 // A variable declaration annotated with the `ABSL_CONST_INIT` attribute will
@@ -618,4 +678,25 @@
 #define ABSL_CONST_INIT
 #endif  // ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
 
+// ABSL_ATTRIBUTE_PURE_FUNCTION
+//
+// ABSL_ATTRIBUTE_PURE_FUNCTION is used to annotate declarations of "pure"
+// functions. A function is pure if its return value is only a function of its
+// arguments. The pure attribute prohibits a function from modifying the state
+// of the program that is observable by means other than inspecting the
+// function's return value. Declaring such functions with the pure attribute
+// allows the compiler to avoid emitting some calls in repeated invocations of
+// the function with the same argument values.
+//
+// Example:
+//
+//  ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Milliseconds(Duration d);
+#if ABSL_HAVE_CPP_ATTRIBUTE(gnu::pure)
+#define ABSL_ATTRIBUTE_PURE_FUNCTION [[gnu::pure]]
+#elif ABSL_HAVE_ATTRIBUTE(pure)
+#define ABSL_ATTRIBUTE_PURE_FUNCTION __attribute__((pure))
+#else
+#define ABSL_ATTRIBUTE_PURE_FUNCTION
+#endif
+
 #endif  // ABSL_BASE_ATTRIBUTES_H_
diff --git a/absl/base/call_once.h b/absl/base/call_once.h
index bc5ec93..96109f5 100644
--- a/absl/base/call_once.h
+++ b/absl/base/call_once.h
@@ -175,17 +175,10 @@
                                        std::memory_order_relaxed) ||
       base_internal::SpinLockWait(control, ABSL_ARRAYSIZE(trans), trans,
                                   scheduling_mode) == kOnceInit) {
-    base_internal::Invoke(std::forward<Callable>(fn),
+    base_internal::invoke(std::forward<Callable>(fn),
                           std::forward<Args>(args)...);
-    // The call to SpinLockWake below is an optimization, because the waiter
-    // in SpinLockWait is waiting with a short timeout. The atomic load/store
-    // sequence is slightly faster than an atomic exchange:
-    //   old_control = control->exchange(base_internal::kOnceDone,
-    //                                   std::memory_order_release);
-    // We opt for a slightly faster case when there are no waiters, in spite
-    // of longer tail latency when there are waiters.
-    old_control = control->load(std::memory_order_relaxed);
-    control->store(base_internal::kOnceDone, std::memory_order_release);
+    old_control =
+        control->exchange(base_internal::kOnceDone, std::memory_order_release);
     if (old_control == base_internal::kOnceWaiter) {
       base_internal::SpinLockWake(control, true);
     }
diff --git a/absl/base/casts.h b/absl/base/casts.h
index 322cc1d..83c6912 100644
--- a/absl/base/casts.h
+++ b/absl/base/casts.h
@@ -159,16 +159,19 @@
   return dest;
 }
 
-// NOTE: This overload is only picked if the requirements of bit_cast are not
-// met. It is therefore UB, but is provided temporarily as previous versions of
-// this function template were unchecked. Do not use this in new code.
+// NOTE: This overload is only picked if the requirements of bit_cast are
+// not met. It is therefore UB, but is provided temporarily as previous
+// versions of this function template were unchecked. Do not use this in
+// new code.
 template <
     typename Dest, typename Source,
     typename std::enable_if<
-        !internal_casts::is_bitcastable<Dest, Source>::value, int>::type = 0>
+        !internal_casts::is_bitcastable<Dest, Source>::value,
+        int>::type = 0>
 ABSL_DEPRECATED(
-    "absl::bit_cast type requirements were violated. Update the types being "
-    "used such that they are the same size and are both TriviallyCopyable.")
+    "absl::bit_cast type requirements were violated. Update the types "
+    "being used such that they are the same size and are both "
+    "TriviallyCopyable.")
 inline Dest bit_cast(const Source& source) {
   static_assert(sizeof(Dest) == sizeof(Source),
                 "Source and destination types should have equal sizes.");
diff --git a/absl/base/config.h b/absl/base/config.h
index ee99f94..9544996 100644
--- a/absl/base/config.h
+++ b/absl/base/config.h
@@ -121,10 +121,16 @@
 #if ABSL_OPTION_USE_INLINE_NAMESPACE == 0
 #define ABSL_NAMESPACE_BEGIN
 #define ABSL_NAMESPACE_END
+#define ABSL_INTERNAL_C_SYMBOL(x) x
 #elif ABSL_OPTION_USE_INLINE_NAMESPACE == 1
 #define ABSL_NAMESPACE_BEGIN \
   inline namespace ABSL_OPTION_INLINE_NAMESPACE_NAME {
 #define ABSL_NAMESPACE_END }
+#define ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v) x##_##v
+#define ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, v) \
+  ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v)
+#define ABSL_INTERNAL_C_SYMBOL(x) \
+  ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, ABSL_OPTION_INLINE_NAMESPACE_NAME)
 #else
 #error options.h is misconfigured.
 #endif
@@ -154,6 +160,12 @@
 #define ABSL_INTERNAL_HAS_KEYWORD(x) 0
 #endif
 
+#ifdef __has_feature
+#define ABSL_HAVE_FEATURE(f) __has_feature(f)
+#else
+#define ABSL_HAVE_FEATURE(f) 0
+#endif
+
 // ABSL_HAVE_TLS is defined to 1 when __thread should be supported.
 // We assume __thread is supported on Linux when compiled with Clang or compiled
 // against libstdc++ with _GLIBCXX_HAVE_TLS defined.
@@ -210,6 +222,8 @@
 #if ABSL_INTERNAL_HAS_KEYWORD(__builtin_LINE) && \
     ABSL_INTERNAL_HAS_KEYWORD(__builtin_FILE)
 #define ABSL_HAVE_SOURCE_LOCATION_CURRENT 1
+#elif defined(__GNUC__) && __GNUC__ >= 5
+#define ABSL_HAVE_SOURCE_LOCATION_CURRENT 1
 #endif
 #endif
 
@@ -226,11 +240,9 @@
 // * Xcode 9.3 started disallowing `thread_local` for 32-bit iOS simulator
 //   targeting iOS 9.x.
 // * Xcode 10 moves the deployment target check for iOS < 9.0 to link time
-//   making __has_feature unreliable there.
+//   making ABSL_HAVE_FEATURE unreliable there.
 //
-// Otherwise, `__has_feature` is only supported by Clang so it has be inside
-// `defined(__APPLE__)` check.
-#if __has_feature(cxx_thread_local) && \
+#if ABSL_HAVE_FEATURE(cxx_thread_local) && \
     !(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
 #define ABSL_HAVE_THREAD_LOCAL 1
 #endif
@@ -262,13 +274,6 @@
 #endif
 #endif  // defined(__ANDROID__) && defined(__clang__)
 
-// Emscripten doesn't yet support `thread_local` or `__thread`.
-// https://github.com/emscripten-core/emscripten/issues/3502
-#if defined(__EMSCRIPTEN__)
-#undef ABSL_HAVE_TLS
-#undef ABSL_HAVE_THREAD_LOCAL
-#endif  // defined(__EMSCRIPTEN__)
-
 // ABSL_HAVE_INTRINSIC_INT128
 //
 // Checks whether the __int128 compiler extension for a 128-bit integral type is
@@ -319,15 +324,15 @@
 
 #if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6)
 // Clang >= 3.6
-#if __has_feature(cxx_exceptions)
+#if ABSL_HAVE_FEATURE(cxx_exceptions)
 #define ABSL_HAVE_EXCEPTIONS 1
-#endif  // __has_feature(cxx_exceptions)
+#endif  // ABSL_HAVE_FEATURE(cxx_exceptions)
 #else
 // Clang < 3.6
 // http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro
-#if defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
+#if defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions)
 #define ABSL_HAVE_EXCEPTIONS 1
-#endif  // defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
+#endif  // defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions)
 #endif  // __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6)
 
 // Handle remaining special cases and default to exceptions being supported.
@@ -367,7 +372,7 @@
 #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) ||   \
     defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \
     defined(__wasm__) || defined(__Fuchsia__) || defined(__sun) || \
-    defined(__ASYLO__)
+    defined(__ASYLO__) || defined(__myriad2__)
 #define ABSL_HAVE_MMAP 1
 #endif
 
@@ -382,6 +387,15 @@
 #define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1
 #endif
 
+// ABSL_HAVE_SCHED_GETCPU
+//
+// Checks whether sched_getcpu is available.
+#ifdef ABSL_HAVE_SCHED_GETCPU
+#error ABSL_HAVE_SCHED_GETCPU cannot be directly set
+#elif defined(__linux__)
+#define ABSL_HAVE_SCHED_GETCPU 1
+#endif
+
 // ABSL_HAVE_SCHED_YIELD
 //
 // Checks whether the platform implements sched_yield(2) as defined in
@@ -477,9 +491,9 @@
   (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
    __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \
   (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \
-   __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 120000) || \
+   __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \
   (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \
-   __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 50000))
+   __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 120000))
 #define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1
 #else
 #define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0
@@ -493,7 +507,7 @@
 #endif
 
 #ifdef __has_include
-#if __has_include(<any>) && __cplusplus >= 201703L && \
+#if __has_include(<any>) && defined(__cplusplus) && __cplusplus >= 201703L && \
     !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
 #define ABSL_HAVE_STD_ANY 1
 #endif
@@ -507,8 +521,8 @@
 #endif
 
 #ifdef __has_include
-#if __has_include(<optional>) && __cplusplus >= 201703L && \
-    !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
+#if __has_include(<optional>) && defined(__cplusplus) && \
+    __cplusplus >= 201703L && !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
 #define ABSL_HAVE_STD_OPTIONAL 1
 #endif
 #endif
@@ -521,8 +535,8 @@
 #endif
 
 #ifdef __has_include
-#if __has_include(<variant>) && __cplusplus >= 201703L && \
-    !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
+#if __has_include(<variant>) && defined(__cplusplus) && \
+    __cplusplus >= 201703L && !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
 #define ABSL_HAVE_STD_VARIANT 1
 #endif
 #endif
@@ -535,7 +549,8 @@
 #endif
 
 #ifdef __has_include
-#if __has_include(<string_view>) && __cplusplus >= 201703L
+#if __has_include(<string_view>) && defined(__cplusplus) && \
+    __cplusplus >= 201703L
 #define ABSL_HAVE_STD_STRING_VIEW 1
 #endif
 #endif
@@ -547,8 +562,9 @@
 // not correctly set by MSVC, so we use `_MSVC_LANG` to check the language
 // version.
 // TODO(zhangxy): fix tests before enabling aliasing for `std::any`.
-#if defined(_MSC_VER) && _MSC_VER >= 1910 && \
-    ((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || __cplusplus > 201402)
+#if defined(_MSC_VER) && _MSC_VER >= 1910 &&         \
+    ((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || \
+     (defined(__cplusplus) && __cplusplus > 201402))
 // #define ABSL_HAVE_STD_ANY 1
 #define ABSL_HAVE_STD_OPTIONAL 1
 #define ABSL_HAVE_STD_VARIANT 1
@@ -668,4 +684,59 @@
 #define ABSL_DLL
 #endif  // defined(_MSC_VER)
 
+// ABSL_HAVE_MEMORY_SANITIZER
+//
+// MemorySanitizer (MSan) is a detector of uninitialized reads. It consists of
+// a compiler instrumentation module and a run-time library.
+#ifdef ABSL_HAVE_MEMORY_SANITIZER
+#error "ABSL_HAVE_MEMORY_SANITIZER cannot be directly set."
+#elif defined(MEMORY_SANITIZER)
+// The MEMORY_SANITIZER macro is deprecated but we will continue to honor it
+// for now.
+#define ABSL_HAVE_MEMORY_SANITIZER 1
+#elif defined(__SANITIZE_MEMORY__)
+#define ABSL_HAVE_MEMORY_SANITIZER 1
+#elif !defined(__native_client__) && ABSL_HAVE_FEATURE(memory_sanitizer)
+#define ABSL_HAVE_MEMORY_SANITIZER 1
+#endif
+
+// ABSL_HAVE_THREAD_SANITIZER
+//
+// ThreadSanitizer (TSan) is a fast data race detector.
+#ifdef ABSL_HAVE_THREAD_SANITIZER
+#error "ABSL_HAVE_THREAD_SANITIZER cannot be directly set."
+#elif defined(THREAD_SANITIZER)
+// The THREAD_SANITIZER macro is deprecated but we will continue to honor it
+// for now.
+#define ABSL_HAVE_THREAD_SANITIZER 1
+#elif defined(__SANITIZE_THREAD__)
+#define ABSL_HAVE_THREAD_SANITIZER 1
+#elif ABSL_HAVE_FEATURE(thread_sanitizer)
+#define ABSL_HAVE_THREAD_SANITIZER 1
+#endif
+
+// ABSL_HAVE_ADDRESS_SANITIZER
+//
+// AddressSanitizer (ASan) is a fast memory error detector.
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+#error "ABSL_HAVE_ADDRESS_SANITIZER cannot be directly set."
+#elif defined(ADDRESS_SANITIZER)
+// The ADDRESS_SANITIZER macro is deprecated but we will continue to honor it
+// for now.
+#define ABSL_HAVE_ADDRESS_SANITIZER 1
+#elif defined(__SANITIZE_ADDRESS__)
+#define ABSL_HAVE_ADDRESS_SANITIZER 1
+#elif ABSL_HAVE_FEATURE(address_sanitizer)
+#define ABSL_HAVE_ADDRESS_SANITIZER 1
+#endif
+
+// ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
+//
+// Class template argument deduction is a language feature added in C++17.
+#ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
+#error "ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION cannot be directly set."
+#elif defined(__cpp_deduction_guides)
+#define ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION 1
+#endif
+
 #endif  // ABSL_BASE_CONFIG_H_
diff --git a/absl/base/dynamic_annotations.cc b/absl/base/dynamic_annotations.cc
deleted file mode 100644
index 21e822e..0000000
--- a/absl/base/dynamic_annotations.cc
+++ /dev/null
@@ -1,129 +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 <stdlib.h>
-#include <string.h>
-
-#include "absl/base/dynamic_annotations.h"
-
-#ifndef __has_feature
-#define __has_feature(x) 0
-#endif
-
-/* Compiler-based ThreadSanitizer defines
-   DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL = 1
-   and provides its own definitions of the functions. */
-
-#ifndef DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL
-# define DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL 0
-#endif
-
-/* Each function is empty and called (via a macro) only in debug mode.
-   The arguments are captured by dynamic tools at runtime. */
-
-#if DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 && !defined(__native_client__)
-
-#if __has_feature(memory_sanitizer)
-#include <sanitizer/msan_interface.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void AnnotateRWLockCreate(const char *, int,
-                          const volatile void *){}
-void AnnotateRWLockDestroy(const char *, int,
-                           const volatile void *){}
-void AnnotateRWLockAcquired(const char *, int,
-                            const volatile void *, long){}
-void AnnotateRWLockReleased(const char *, int,
-                            const volatile void *, long){}
-void AnnotateBenignRace(const char *, int,
-                        const volatile void *,
-                        const char *){}
-void AnnotateBenignRaceSized(const char *, int,
-                             const volatile void *,
-                             size_t,
-                             const char *) {}
-void AnnotateThreadName(const char *, int,
-                        const char *){}
-void AnnotateIgnoreReadsBegin(const char *, int){}
-void AnnotateIgnoreReadsEnd(const char *, int){}
-void AnnotateIgnoreWritesBegin(const char *, int){}
-void AnnotateIgnoreWritesEnd(const char *, int){}
-void AnnotateEnableRaceDetection(const char *, int, int){}
-void AnnotateMemoryIsInitialized(const char *, int,
-                                 const volatile void *mem, size_t size) {
-#if __has_feature(memory_sanitizer)
-  __msan_unpoison(mem, size);
-#else
-  (void)mem;
-  (void)size;
-#endif
-}
-
-void AnnotateMemoryIsUninitialized(const char *, int,
-                                   const volatile void *mem, size_t size) {
-#if __has_feature(memory_sanitizer)
-  __msan_allocated_memory(mem, size);
-#else
-  (void)mem;
-  (void)size;
-#endif
-}
-
-static int GetRunningOnValgrind(void) {
-#ifdef RUNNING_ON_VALGRIND
-  if (RUNNING_ON_VALGRIND) return 1;
-#endif
-  char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND");
-  if (running_on_valgrind_str) {
-    return strcmp(running_on_valgrind_str, "0") != 0;
-  }
-  return 0;
-}
-
-/* See the comments in dynamic_annotations.h */
-int RunningOnValgrind(void) {
-  static volatile int running_on_valgrind = -1;
-  int local_running_on_valgrind = running_on_valgrind;
-  /* C doesn't have thread-safe initialization of statics, and we
-     don't want to depend on pthread_once here, so hack it. */
-  ANNOTATE_BENIGN_RACE(&running_on_valgrind, "safe hack");
-  if (local_running_on_valgrind == -1)
-    running_on_valgrind = local_running_on_valgrind = GetRunningOnValgrind();
-  return local_running_on_valgrind;
-}
-
-/* See the comments in dynamic_annotations.h */
-double ValgrindSlowdown(void) {
-  /* Same initialization hack as in RunningOnValgrind(). */
-  static volatile double slowdown = 0.0;
-  double local_slowdown = slowdown;
-  ANNOTATE_BENIGN_RACE(&slowdown, "safe hack");
-  if (RunningOnValgrind() == 0) {
-    return 1.0;
-  }
-  if (local_slowdown == 0.0) {
-    char *env = getenv("VALGRIND_SLOWDOWN");
-    slowdown = local_slowdown = env ? atof(env) : 50.0;
-  }
-  return local_slowdown;
-}
-
-#ifdef __cplusplus
-}  // extern "C"
-#endif
-#endif  /* DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 */
diff --git a/absl/base/dynamic_annotations.h b/absl/base/dynamic_annotations.h
index 65a54b4..880cbf6 100644
--- a/absl/base/dynamic_annotations.h
+++ b/absl/base/dynamic_annotations.h
@@ -1,389 +1,496 @@
-/*
- *  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.
- */
-/* This file defines dynamic annotations for use with dynamic analysis
-   tool such as valgrind, PIN, etc.
+// 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.
 
-   Dynamic annotation is a source code annotation that affects
-   the generated code (that is, the annotation is not a comment).
-   Each such annotation is attached to a particular
-   instruction and/or to a particular object (address) in the program.
-
-   The annotations that should be used by users are macros in all upper-case
-   (e.g., ANNOTATE_THREAD_NAME).
-
-   Actual implementation of these macros may differ depending on the
-   dynamic analysis tool being used.
-
-   This file supports the following configurations:
-   - Dynamic Annotations enabled (with static thread-safety warnings disabled).
-     In this case, macros expand to functions implemented by Thread Sanitizer,
-     when building with TSan. When not provided an external implementation,
-     dynamic_annotations.cc provides no-op implementations.
-
-   - Static Clang thread-safety warnings enabled.
-     When building with a Clang compiler that supports thread-safety warnings,
-     a subset of annotations can be statically-checked at compile-time. We
-     expand these macros to static-inline functions that can be analyzed for
-     thread-safety, but afterwards elided when building the final binary.
-
-   - All annotations are disabled.
-     If neither Dynamic Annotations nor Clang thread-safety warnings are
-     enabled, then all annotation-macros expand to empty. */
+// This file defines dynamic annotations for use with dynamic analysis tool
+// such as valgrind, PIN, etc.
+//
+// Dynamic annotation is a source code annotation that affects the generated
+// code (that is, the annotation is not a comment). Each such annotation is
+// attached to a particular instruction and/or to a particular object (address)
+// in the program.
+//
+// The annotations that should be used by users are macros in all upper-case
+// (e.g., ABSL_ANNOTATE_THREAD_NAME).
+//
+// Actual implementation of these macros may differ depending on the dynamic
+// analysis tool being used.
+//
+// This file supports the following configurations:
+// - Dynamic Annotations enabled (with static thread-safety warnings disabled).
+//   In this case, macros expand to functions implemented by Thread Sanitizer,
+//   when building with TSan. When not provided an external implementation,
+//   dynamic_annotations.cc provides no-op implementations.
+//
+// - Static Clang thread-safety warnings enabled.
+//   When building with a Clang compiler that supports thread-safety warnings,
+//   a subset of annotations can be statically-checked at compile-time. We
+//   expand these macros to static-inline functions that can be analyzed for
+//   thread-safety, but afterwards elided when building the final binary.
+//
+// - All annotations are disabled.
+//   If neither Dynamic Annotations nor Clang thread-safety warnings are
+//   enabled, then all annotation-macros expand to empty.
 
 #ifndef ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
 #define ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
 
-#ifndef DYNAMIC_ANNOTATIONS_ENABLED
-# define DYNAMIC_ANNOTATIONS_ENABLED 0
-#endif
-
-#if DYNAMIC_ANNOTATIONS_ENABLED != 0
-
-  /* -------------------------------------------------------------
-     Annotations that suppress errors.  It is usually better to express the
-     program's synchronization using the other annotations, but these can
-     be used when all else fails. */
-
-  /* Report that we may have a benign race at "pointer", with size
-     "sizeof(*(pointer))". "pointer" must be a non-void* pointer.  Insert at the
-     point where "pointer" has been allocated, preferably close to the point
-     where the race happens.  See also ANNOTATE_BENIGN_RACE_STATIC. */
-  #define ANNOTATE_BENIGN_RACE(pointer, description) \
-    AnnotateBenignRaceSized(__FILE__, __LINE__, pointer, \
-                            sizeof(*(pointer)), description)
-
-  /* Same as ANNOTATE_BENIGN_RACE(address, description), but applies to
-     the memory range [address, address+size). */
-  #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
-    AnnotateBenignRaceSized(__FILE__, __LINE__, address, size, description)
-
-  /* Enable (enable!=0) or disable (enable==0) race detection for all threads.
-     This annotation could be useful if you want to skip expensive race analysis
-     during some period of program execution, e.g. during initialization. */
-  #define ANNOTATE_ENABLE_RACE_DETECTION(enable) \
-    AnnotateEnableRaceDetection(__FILE__, __LINE__, enable)
-
-  /* -------------------------------------------------------------
-     Annotations useful for debugging. */
-
-  /* Report the current thread name to a race detector. */
-  #define ANNOTATE_THREAD_NAME(name) \
-    AnnotateThreadName(__FILE__, __LINE__, name)
-
-  /* -------------------------------------------------------------
-     Annotations useful when implementing locks.  They are not
-     normally needed by modules that merely use locks.
-     The "lock" argument is a pointer to the lock object. */
-
-  /* Report that a lock has been created at address "lock". */
-  #define ANNOTATE_RWLOCK_CREATE(lock) \
-    AnnotateRWLockCreate(__FILE__, __LINE__, lock)
-
-  /* Report that a linker initialized lock has been created at address "lock".
-   */
-#ifdef THREAD_SANITIZER
-  #define ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
-    AnnotateRWLockCreateStatic(__FILE__, __LINE__, lock)
-#else
-  #define ANNOTATE_RWLOCK_CREATE_STATIC(lock) ANNOTATE_RWLOCK_CREATE(lock)
-#endif
-
-  /* Report that the lock at address "lock" is about to be destroyed. */
-  #define ANNOTATE_RWLOCK_DESTROY(lock) \
-    AnnotateRWLockDestroy(__FILE__, __LINE__, lock)
-
-  /* Report that the lock at address "lock" has been acquired.
-     is_w=1 for writer lock, is_w=0 for reader lock. */
-  #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
-    AnnotateRWLockAcquired(__FILE__, __LINE__, lock, is_w)
-
-  /* Report that the lock at address "lock" is about to be released. */
-  #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
-    AnnotateRWLockReleased(__FILE__, __LINE__, lock, is_w)
-
-#else  /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */
-
-  #define ANNOTATE_RWLOCK_CREATE(lock) /* empty */
-  #define ANNOTATE_RWLOCK_CREATE_STATIC(lock) /* empty */
-  #define ANNOTATE_RWLOCK_DESTROY(lock) /* empty */
-  #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */
-  #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */
-  #define ANNOTATE_BENIGN_RACE(address, description) /* empty */
-  #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */
-  #define ANNOTATE_THREAD_NAME(name) /* empty */
-  #define ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */
-
-#endif  /* DYNAMIC_ANNOTATIONS_ENABLED */
-
-/* These annotations are also made available to LLVM's Memory Sanitizer */
-#if DYNAMIC_ANNOTATIONS_ENABLED == 1 || defined(MEMORY_SANITIZER)
-  #define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
-    AnnotateMemoryIsInitialized(__FILE__, __LINE__, address, size)
-
-  #define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
-    AnnotateMemoryIsUninitialized(__FILE__, __LINE__, address, size)
-#else
-  #define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) /* empty */
-  #define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) /* empty */
-#endif  /* DYNAMIC_ANNOTATIONS_ENABLED || MEMORY_SANITIZER */
-
-/* TODO(delesley) -- Replace __CLANG_SUPPORT_DYN_ANNOTATION__ with the
-   appropriate feature ID. */
-#if defined(__clang__) && (!defined(SWIG)) \
-    && defined(__CLANG_SUPPORT_DYN_ANNOTATION__)
-
-  #if DYNAMIC_ANNOTATIONS_ENABLED == 0
-    #define ANNOTALYSIS_ENABLED
-  #endif
-
-  /* When running in opt-mode, GCC will issue a warning, if these attributes are
-     compiled. Only include them when compiling using Clang. */
-  #define ATTRIBUTE_IGNORE_READS_BEGIN \
-      __attribute((exclusive_lock_function("*")))
-  #define ATTRIBUTE_IGNORE_READS_END \
-      __attribute((unlock_function("*")))
-#else
-  #define ATTRIBUTE_IGNORE_READS_BEGIN  /* empty */
-  #define ATTRIBUTE_IGNORE_READS_END  /* empty */
-#endif  /* defined(__clang__) && ... */
-
-#if (DYNAMIC_ANNOTATIONS_ENABLED != 0) || defined(ANNOTALYSIS_ENABLED)
-  #define ANNOTATIONS_ENABLED
-#endif
-
-#if (DYNAMIC_ANNOTATIONS_ENABLED != 0)
-
-  /* Request the analysis tool to ignore all reads in the current thread
-     until ANNOTATE_IGNORE_READS_END is called.
-     Useful to ignore intentional racey reads, while still checking
-     other reads and all writes.
-     See also ANNOTATE_UNPROTECTED_READ. */
-  #define ANNOTATE_IGNORE_READS_BEGIN() \
-    AnnotateIgnoreReadsBegin(__FILE__, __LINE__)
-
-  /* Stop ignoring reads. */
-  #define ANNOTATE_IGNORE_READS_END() \
-    AnnotateIgnoreReadsEnd(__FILE__, __LINE__)
-
-  /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead. */
-  #define ANNOTATE_IGNORE_WRITES_BEGIN() \
-    AnnotateIgnoreWritesBegin(__FILE__, __LINE__)
-
-  /* Stop ignoring writes. */
-  #define ANNOTATE_IGNORE_WRITES_END() \
-    AnnotateIgnoreWritesEnd(__FILE__, __LINE__)
-
-/* Clang provides limited support for static thread-safety analysis
-   through a feature called Annotalysis. We configure macro-definitions
-   according to whether Annotalysis support is available. */
-#elif defined(ANNOTALYSIS_ENABLED)
-
-  #define ANNOTATE_IGNORE_READS_BEGIN() \
-    StaticAnnotateIgnoreReadsBegin(__FILE__, __LINE__)
-
-  #define ANNOTATE_IGNORE_READS_END() \
-    StaticAnnotateIgnoreReadsEnd(__FILE__, __LINE__)
-
-  #define ANNOTATE_IGNORE_WRITES_BEGIN() \
-    StaticAnnotateIgnoreWritesBegin(__FILE__, __LINE__)
-
-  #define ANNOTATE_IGNORE_WRITES_END() \
-    StaticAnnotateIgnoreWritesEnd(__FILE__, __LINE__)
-
-#else
-  #define ANNOTATE_IGNORE_READS_BEGIN()  /* empty */
-  #define ANNOTATE_IGNORE_READS_END()  /* empty */
-  #define ANNOTATE_IGNORE_WRITES_BEGIN()  /* empty */
-  #define ANNOTATE_IGNORE_WRITES_END()  /* empty */
-#endif
-
-/* Implement the ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
-   primitive annotations defined above. */
-#if defined(ANNOTATIONS_ENABLED)
-
-  /* Start ignoring all memory accesses (both reads and writes). */
-  #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
-    do {                                           \
-      ANNOTATE_IGNORE_READS_BEGIN();               \
-      ANNOTATE_IGNORE_WRITES_BEGIN();              \
-    }while (0)
-
-  /* Stop ignoring both reads and writes. */
-  #define ANNOTATE_IGNORE_READS_AND_WRITES_END()   \
-    do {                                           \
-      ANNOTATE_IGNORE_WRITES_END();                \
-      ANNOTATE_IGNORE_READS_END();                 \
-    }while (0)
-
-#else
-  #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN()  /* empty */
-  #define ANNOTATE_IGNORE_READS_AND_WRITES_END()  /* empty */
-#endif
-
-/* Use the macros above rather than using these functions directly. */
 #include <stddef.h>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
 #ifdef __cplusplus
-extern "C" {
-#endif
-void AnnotateRWLockCreate(const char *file, int line,
-                          const volatile void *lock);
-void AnnotateRWLockCreateStatic(const char *file, int line,
-                          const volatile void *lock);
-void AnnotateRWLockDestroy(const char *file, int line,
-                           const volatile void *lock);
-void AnnotateRWLockAcquired(const char *file, int line,
-                            const volatile void *lock, long is_w);  /* NOLINT */
-void AnnotateRWLockReleased(const char *file, int line,
-                            const volatile void *lock, long is_w);  /* NOLINT */
-void AnnotateBenignRace(const char *file, int line,
-                        const volatile void *address,
-                        const char *description);
-void AnnotateBenignRaceSized(const char *file, int line,
-                        const volatile void *address,
-                        size_t size,
-                        const char *description);
-void AnnotateThreadName(const char *file, int line,
-                        const char *name);
-void AnnotateEnableRaceDetection(const char *file, int line, int enable);
-void AnnotateMemoryIsInitialized(const char *file, int line,
-                                 const volatile void *mem, size_t size);
-void AnnotateMemoryIsUninitialized(const char *file, int line,
-                                   const volatile void *mem, size_t size);
-
-/* Annotations expand to these functions, when Dynamic Annotations are enabled.
-   These functions are either implemented as no-op calls, if no Sanitizer is
-   attached, or provided with externally-linked implementations by a library
-   like ThreadSanitizer. */
-void AnnotateIgnoreReadsBegin(const char *file, int line)
-    ATTRIBUTE_IGNORE_READS_BEGIN;
-void AnnotateIgnoreReadsEnd(const char *file, int line)
-    ATTRIBUTE_IGNORE_READS_END;
-void AnnotateIgnoreWritesBegin(const char *file, int line);
-void AnnotateIgnoreWritesEnd(const char *file, int line);
-
-#if defined(ANNOTALYSIS_ENABLED)
-/* When Annotalysis is enabled without Dynamic Annotations, the use of
-   static-inline functions allows the annotations to be read at compile-time,
-   while still letting the compiler elide the functions from the final build.
-
-   TODO(delesley) -- The exclusive lock here ignores writes as well, but
-   allows IGNORE_READS_AND_WRITES to work properly. */
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-function"
-static inline void StaticAnnotateIgnoreReadsBegin(const char *file, int line)
-    ATTRIBUTE_IGNORE_READS_BEGIN { (void)file; (void)line; }
-static inline void StaticAnnotateIgnoreReadsEnd(const char *file, int line)
-    ATTRIBUTE_IGNORE_READS_END { (void)file; (void)line; }
-static inline void StaticAnnotateIgnoreWritesBegin(
-    const char *file, int line) { (void)file; (void)line; }
-static inline void StaticAnnotateIgnoreWritesEnd(
-    const char *file, int line) { (void)file; (void)line; }
-#pragma GCC diagnostic pop
+#include "absl/base/macros.h"
 #endif
 
-/* Return non-zero value if running under valgrind.
+// TODO(rogeeff): Remove after the backward compatibility period.
+#include "absl/base/internal/dynamic_annotations.h"  // IWYU pragma: export
 
-  If "valgrind.h" is included into dynamic_annotations.cc,
-  the regular valgrind mechanism will be used.
-  See http://valgrind.org/docs/manual/manual-core-adv.html about
-  RUNNING_ON_VALGRIND and other valgrind "client requests".
-  The file "valgrind.h" may be obtained by doing
-     svn co svn://svn.valgrind.org/valgrind/trunk/include
+// -------------------------------------------------------------------------
+// Decide which features are enabled.
 
-  If for some reason you can't use "valgrind.h" or want to fake valgrind,
-  there are two ways to make this function return non-zero:
-    - Use environment variable: export RUNNING_ON_VALGRIND=1
-    - Make your tool intercept the function RunningOnValgrind() and
-      change its return value.
- */
-int RunningOnValgrind(void);
+#ifdef ABSL_HAVE_THREAD_SANITIZER
 
-/* ValgrindSlowdown returns:
-    * 1.0, if (RunningOnValgrind() == 0)
-    * 50.0, if (RunningOnValgrind() != 0 && getenv("VALGRIND_SLOWDOWN") == NULL)
-    * atof(getenv("VALGRIND_SLOWDOWN")) otherwise
-   This function can be used to scale timeout values:
-   EXAMPLE:
-   for (;;) {
-     DoExpensiveBackgroundTask();
-     SleepForSeconds(5 * ValgrindSlowdown());
-   }
- */
-double ValgrindSlowdown(void);
+#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
+#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED 1
+
+#else
+
+#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 0
+#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 0
+#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 0
+
+// Clang provides limited support for static thread-safety analysis through a
+// feature called Annotalysis. We configure macro-definitions according to
+// whether Annotalysis support is available. When running in opt-mode, GCC
+// will issue a warning, if these attributes are compiled. Only include them
+// when compiling using Clang.
+
+#if defined(__clang__)
+#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 1
+#if !defined(SWIG)
+#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1
+#endif
+#else
+#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
+#endif
+
+// Read/write annotations are enabled in Annotalysis mode; disabled otherwise.
+#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED \
+  ABSL_INTERNAL_ANNOTALYSIS_ENABLED
+
+#endif  // ABSL_HAVE_THREAD_SANITIZER
 
 #ifdef __cplusplus
-}
+#define ABSL_INTERNAL_BEGIN_EXTERN_C extern "C" {
+#define ABSL_INTERNAL_END_EXTERN_C }  // extern "C"
+#define ABSL_INTERNAL_GLOBAL_SCOPED(F) ::F
+#define ABSL_INTERNAL_STATIC_INLINE inline
+#else
+#define ABSL_INTERNAL_BEGIN_EXTERN_C  // empty
+#define ABSL_INTERNAL_END_EXTERN_C    // empty
+#define ABSL_INTERNAL_GLOBAL_SCOPED(F) F
+#define ABSL_INTERNAL_STATIC_INLINE static inline
 #endif
 
-/* ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
+// -------------------------------------------------------------------------
+// Define race annotations.
 
-     Instead of doing
-        ANNOTATE_IGNORE_READS_BEGIN();
-        ... = x;
-        ANNOTATE_IGNORE_READS_END();
-     one can use
-        ... = ANNOTATE_UNPROTECTED_READ(x); */
-#if defined(__cplusplus) && defined(ANNOTATIONS_ENABLED)
+#if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1
+// Some of the symbols used in this section (e.g. AnnotateBenignRaceSized) are
+// defined by the compiler-based santizer implementation, not by the Abseil
+// library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL.
+
+// -------------------------------------------------------------
+// Annotations that suppress errors. It is usually better to express the
+// program's synchronization using the other annotations, but these can be used
+// when all else fails.
+
+// Report that we may have a benign race at `pointer`, with size
+// "sizeof(*(pointer))". `pointer` must be a non-void* pointer. Insert at the
+// point where `pointer` has been allocated, preferably close to the point
+// where the race happens. See also ABSL_ANNOTATE_BENIGN_RACE_STATIC.
+#define ABSL_ANNOTATE_BENIGN_RACE(pointer, description) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized)  \
+  (__FILE__, __LINE__, pointer, sizeof(*(pointer)), description)
+
+// Same as ABSL_ANNOTATE_BENIGN_RACE(`address`, `description`), but applies to
+// the memory range [`address`, `address`+`size`).
+#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized)              \
+  (__FILE__, __LINE__, address, size, description)
+
+// Enable (`enable`!=0) or disable (`enable`==0) race detection for all threads.
+// This annotation could be useful if you want to skip expensive race analysis
+// during some period of program execution, e.g. during initialization.
+#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable)        \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateEnableRaceDetection) \
+  (__FILE__, __LINE__, enable)
+
+// -------------------------------------------------------------
+// Annotations useful for debugging.
+
+// Report the current thread `name` to a race detector.
+#define ABSL_ANNOTATE_THREAD_NAME(name) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateThreadName)(__FILE__, __LINE__, name)
+
+// -------------------------------------------------------------
+// Annotations useful when implementing locks. They are not normally needed by
+// modules that merely use locks. The `lock` argument is a pointer to the lock
+// object.
+
+// Report that a lock has been created at address `lock`.
+#define ABSL_ANNOTATE_RWLOCK_CREATE(lock) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreate)(__FILE__, __LINE__, lock)
+
+// Report that a linker initialized lock has been created at address `lock`.
+#ifdef ABSL_HAVE_THREAD_SANITIZER
+#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock)          \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreateStatic) \
+  (__FILE__, __LINE__, lock)
+#else
+#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
+  ABSL_ANNOTATE_RWLOCK_CREATE(lock)
+#endif
+
+// Report that the lock at address `lock` is about to be destroyed.
+#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock)
+
+// Report that the lock at address `lock` has been acquired.
+// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
+#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w)     \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockAcquired) \
+  (__FILE__, __LINE__, lock, is_w)
+
+// Report that the lock at address `lock` is about to be released.
+// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
+#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w)     \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockReleased) \
+  (__FILE__, __LINE__, lock, is_w)
+
+// Apply ABSL_ANNOTATE_BENIGN_RACE_SIZED to a static variable `static_var`.
+#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description)      \
+  namespace {                                                          \
+  class static_var##_annotator {                                       \
+   public:                                                             \
+    static_var##_annotator() {                                         \
+      ABSL_ANNOTATE_BENIGN_RACE_SIZED(&static_var, sizeof(static_var), \
+                                      #static_var ": " description);   \
+    }                                                                  \
+  };                                                                   \
+  static static_var##_annotator the##static_var##_annotator;           \
+  }  // namespace
+
+// Function prototypes of annotations provided by the compiler-based sanitizer
+// implementation.
+ABSL_INTERNAL_BEGIN_EXTERN_C
+void AnnotateRWLockCreate(const char* file, int line,
+                          const volatile void* lock);
+void AnnotateRWLockCreateStatic(const char* file, int line,
+                                const volatile void* lock);
+void AnnotateRWLockDestroy(const char* file, int line,
+                           const volatile void* lock);
+void AnnotateRWLockAcquired(const char* file, int line,
+                            const volatile void* lock, long is_w);  // NOLINT
+void AnnotateRWLockReleased(const char* file, int line,
+                            const volatile void* lock, long is_w);  // NOLINT
+void AnnotateBenignRace(const char* file, int line,
+                        const volatile void* address, const char* description);
+void AnnotateBenignRaceSized(const char* file, int line,
+                             const volatile void* address, size_t size,
+                             const char* description);
+void AnnotateThreadName(const char* file, int line, const char* name);
+void AnnotateEnableRaceDetection(const char* file, int line, int enable);
+ABSL_INTERNAL_END_EXTERN_C
+
+#else  // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 0
+
+#define ABSL_ANNOTATE_RWLOCK_CREATE(lock)                            // empty
+#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock)                     // empty
+#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock)                           // empty
+#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w)                    // empty
+#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w)                    // empty
+#define ABSL_ANNOTATE_BENIGN_RACE(address, description)              // empty
+#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description)  // empty
+#define ABSL_ANNOTATE_THREAD_NAME(name)                              // empty
+#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable)                  // empty
+#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description)    // empty
+
+#endif  // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
+
+// -------------------------------------------------------------------------
+// Define memory annotations.
+
+#ifdef ABSL_HAVE_MEMORY_SANITIZER
+
+#include <sanitizer/msan_interface.h>
+
+#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
+  __msan_unpoison(address, size)
+
+#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
+  __msan_allocated_memory(address, size)
+
+#else  // !defined(ABSL_HAVE_MEMORY_SANITIZER)
+
+// TODO(rogeeff): remove this branch
+#ifdef ABSL_HAVE_THREAD_SANITIZER
+#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
+  do {                                                     \
+    (void)(address);                                       \
+    (void)(size);                                          \
+  } while (0)
+#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
+  do {                                                       \
+    (void)(address);                                         \
+    (void)(size);                                            \
+  } while (0)
+#else
+
+#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size)    // empty
+#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size)  // empty
+
+#endif
+
+#endif  // ABSL_HAVE_MEMORY_SANITIZER
+
+// -------------------------------------------------------------------------
+// Define IGNORE_READS_BEGIN/_END attributes.
+
+#if defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+
+#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE \
+  __attribute((exclusive_lock_function("*")))
+#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE \
+  __attribute((unlock_function("*")))
+
+#else  // !defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+
+#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE  // empty
+#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE    // empty
+
+#endif  // defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+
+// -------------------------------------------------------------------------
+// Define IGNORE_READS_BEGIN/_END annotations.
+
+#if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1
+// Some of the symbols used in this section (e.g. AnnotateIgnoreReadsBegin) are
+// defined by the compiler-based implementation, not by the Abseil
+// library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL.
+
+// Request the analysis tool to ignore all reads in the current thread until
+// ABSL_ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey
+// reads, while still checking other reads and all writes.
+// See also ABSL_ANNOTATE_UNPROTECTED_READ.
+#define ABSL_ANNOTATE_IGNORE_READS_BEGIN()              \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin) \
+  (__FILE__, __LINE__)
+
+// Stop ignoring reads.
+#define ABSL_ANNOTATE_IGNORE_READS_END()              \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd) \
+  (__FILE__, __LINE__)
+
+// Function prototypes of annotations provided by the compiler-based sanitizer
+// implementation.
+ABSL_INTERNAL_BEGIN_EXTERN_C
+void AnnotateIgnoreReadsBegin(const char* file, int line)
+    ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE;
+void AnnotateIgnoreReadsEnd(const char* file,
+                            int line) ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE;
+ABSL_INTERNAL_END_EXTERN_C
+
+#elif defined(ABSL_INTERNAL_ANNOTALYSIS_ENABLED)
+
+// When Annotalysis is enabled without Dynamic Annotations, the use of
+// static-inline functions allows the annotations to be read at compile-time,
+// while still letting the compiler elide the functions from the final build.
+//
+// TODO(delesley) -- The exclusive lock here ignores writes as well, but
+// allows IGNORE_READS_AND_WRITES to work properly.
+
+#define ABSL_ANNOTATE_IGNORE_READS_BEGIN()                          \
+  ABSL_INTERNAL_GLOBAL_SCOPED(                                      \
+      ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsBegin)) \
+  ()
+
+#define ABSL_ANNOTATE_IGNORE_READS_END()                          \
+  ABSL_INTERNAL_GLOBAL_SCOPED(                                    \
+      ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsEnd)) \
+  ()
+
+ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL(
+    AbslInternalAnnotateIgnoreReadsBegin)()
+    ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE {}
+
+ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL(
+    AbslInternalAnnotateIgnoreReadsEnd)()
+    ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE {}
+
+#else
+
+#define ABSL_ANNOTATE_IGNORE_READS_BEGIN()  // empty
+#define ABSL_ANNOTATE_IGNORE_READS_END()    // empty
+
+#endif
+
+// -------------------------------------------------------------------------
+// Define IGNORE_WRITES_BEGIN/_END annotations.
+
+#if ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED == 1
+
+// Similar to ABSL_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead.
+#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__)
+
+// Stop ignoring writes.
+#define ABSL_ANNOTATE_IGNORE_WRITES_END() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__)
+
+// Function prototypes of annotations provided by the compiler-based sanitizer
+// implementation.
+ABSL_INTERNAL_BEGIN_EXTERN_C
+void AnnotateIgnoreWritesBegin(const char* file, int line);
+void AnnotateIgnoreWritesEnd(const char* file, int line);
+ABSL_INTERNAL_END_EXTERN_C
+
+#else
+
+#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN()  // empty
+#define ABSL_ANNOTATE_IGNORE_WRITES_END()    // empty
+
+#endif
+
+// -------------------------------------------------------------------------
+// Define the ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
+// primitive annotations defined above.
+//
+//     Instead of doing
+//        ABSL_ANNOTATE_IGNORE_READS_BEGIN();
+//        ... = x;
+//        ABSL_ANNOTATE_IGNORE_READS_END();
+//     one can use
+//        ... = ABSL_ANNOTATE_UNPROTECTED_READ(x);
+
+#if defined(ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED)
+
+// Start ignoring all memory accesses (both reads and writes).
+#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
+  do {                                                \
+    ABSL_ANNOTATE_IGNORE_READS_BEGIN();               \
+    ABSL_ANNOTATE_IGNORE_WRITES_BEGIN();              \
+  } while (0)
+
+// Stop ignoring both reads and writes.
+#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() \
+  do {                                              \
+    ABSL_ANNOTATE_IGNORE_WRITES_END();              \
+    ABSL_ANNOTATE_IGNORE_READS_END();               \
+  } while (0)
+
+#ifdef __cplusplus
+// ABSL_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
+#define ABSL_ANNOTATE_UNPROTECTED_READ(x) \
+  absl::base_internal::AnnotateUnprotectedRead(x)
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
 template <typename T>
-inline T ANNOTATE_UNPROTECTED_READ(const volatile T &x) { /* NOLINT */
-  ANNOTATE_IGNORE_READS_BEGIN();
+inline T AnnotateUnprotectedRead(const volatile T& x) {  // NOLINT
+  ABSL_ANNOTATE_IGNORE_READS_BEGIN();
   T res = x;
-  ANNOTATE_IGNORE_READS_END();
+  ABSL_ANNOTATE_IGNORE_READS_END();
   return res;
-  }
-#else
-  #define ANNOTATE_UNPROTECTED_READ(x) (x)
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
 #endif
 
-#if DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus)
-  /* Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable. */
-  #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description)        \
-    namespace {                                                       \
-      class static_var ## _annotator {                                \
-       public:                                                        \
-        static_var ## _annotator() {                                  \
-          ANNOTATE_BENIGN_RACE_SIZED(&static_var,                     \
-                                      sizeof(static_var),             \
-            # static_var ": " description);                           \
-        }                                                             \
-      };                                                              \
-      static static_var ## _annotator the ## static_var ## _annotator;\
-    }  // namespace
-#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */
-  #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description)  /* empty */
-#endif /* DYNAMIC_ANNOTATIONS_ENABLED */
-
-#ifdef ADDRESS_SANITIZER
-/* Describe the current state of a contiguous container such as e.g.
- * std::vector or std::string. For more details see
- * sanitizer/common_interface_defs.h, which is provided by the compiler. */
-#include <sanitizer/common_interface_defs.h>
-#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \
-  __sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
-#define ADDRESS_SANITIZER_REDZONE(name)         \
-  struct { char x[8] __attribute__ ((aligned (8))); } name
 #else
-#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid)
-#define ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "")
-#endif  // ADDRESS_SANITIZER
 
-/* Undefine the macros intended only in this file. */
-#undef ANNOTALYSIS_ENABLED
-#undef ANNOTATIONS_ENABLED
-#undef ATTRIBUTE_IGNORE_READS_BEGIN
-#undef ATTRIBUTE_IGNORE_READS_END
+#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN()  // empty
+#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END()    // empty
+#define ABSL_ANNOTATE_UNPROTECTED_READ(x) (x)
 
-#endif  /* ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ */
+#endif
+
+#ifdef __cplusplus
+#ifdef ABSL_HAVE_THREAD_SANITIZER
+ABSL_INTERNAL_BEGIN_EXTERN_C
+int RunningOnValgrind();
+double ValgrindSlowdown();
+ABSL_INTERNAL_END_EXTERN_C
+#else
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+ABSL_DEPRECATED(
+    "Don't use this interface. It is misleading and is being deleted.")
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline int RunningOnValgrind() { return 0; }
+ABSL_DEPRECATED(
+    "Don't use this interface. It is misleading and is being deleted.")
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline double ValgrindSlowdown() { return 1.0; }
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+using absl::base_internal::RunningOnValgrind;
+using absl::base_internal::ValgrindSlowdown;
+#endif
+#endif
+
+// -------------------------------------------------------------------------
+// Address sanitizer annotations
+
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+// Describe the current state of a contiguous container such as e.g.
+// std::vector or std::string. For more details see
+// sanitizer/common_interface_defs.h, which is provided by the compiler.
+#include <sanitizer/common_interface_defs.h>
+
+#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \
+  __sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
+#define ABSL_ADDRESS_SANITIZER_REDZONE(name) \
+  struct {                                   \
+    char x[8] __attribute__((aligned(8)));   \
+  } name
+
+#else
+
+#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid)  // empty
+#define ABSL_ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "")
+
+#endif  // ABSL_HAVE_ADDRESS_SANITIZER
+
+// -------------------------------------------------------------------------
+// Undefine the macros intended only for this file.
+
+#undef ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_ANNOTALYSIS_ENABLED
+#undef ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_BEGIN_EXTERN_C
+#undef ABSL_INTERNAL_END_EXTERN_C
+#undef ABSL_INTERNAL_STATIC_INLINE
+
+#endif  // ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
diff --git a/absl/base/internal/bits.h b/absl/base/internal/bits.h
deleted file mode 100644
index 8b03453..0000000
--- a/absl/base/internal/bits.h
+++ /dev/null
@@ -1,218 +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.
-
-#ifndef ABSL_BASE_INTERNAL_BITS_H_
-#define ABSL_BASE_INTERNAL_BITS_H_
-
-// This file contains bitwise ops which are implementation details of various
-// absl libraries.
-
-#include <cstdint>
-
-#include "absl/base/config.h"
-
-// Clang on Windows has __builtin_clzll; otherwise we need to use the
-// windows intrinsic functions.
-#if defined(_MSC_VER)
-#include <intrin.h>
-#if defined(_M_X64)
-#pragma intrinsic(_BitScanReverse64)
-#pragma intrinsic(_BitScanForward64)
-#endif
-#pragma intrinsic(_BitScanReverse)
-#pragma intrinsic(_BitScanForward)
-#endif
-
-#include "absl/base/attributes.h"
-
-#if defined(_MSC_VER)
-// We can achieve something similar to attribute((always_inline)) with MSVC by
-// using the __forceinline keyword, however this is not perfect. MSVC is
-// much less aggressive about inlining, and even with the __forceinline keyword.
-#define ABSL_BASE_INTERNAL_FORCEINLINE __forceinline
-#else
-// Use default attribute inline.
-#define ABSL_BASE_INTERNAL_FORCEINLINE inline ABSL_ATTRIBUTE_ALWAYS_INLINE
-#endif
-
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace base_internal {
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64Slow(uint64_t n) {
-  int zeroes = 60;
-  if (n >> 32) {
-    zeroes -= 32;
-    n >>= 32;
-  }
-  if (n >> 16) {
-    zeroes -= 16;
-    n >>= 16;
-  }
-  if (n >> 8) {
-    zeroes -= 8;
-    n >>= 8;
-  }
-  if (n >> 4) {
-    zeroes -= 4;
-    n >>= 4;
-  }
-  return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) {
-#if defined(_MSC_VER) && defined(_M_X64)
-  // MSVC does not have __buitin_clzll. Use _BitScanReverse64.
-  unsigned long result = 0;  // NOLINT(runtime/int)
-  if (_BitScanReverse64(&result, n)) {
-    return 63 - result;
-  }
-  return 64;
-#elif defined(_MSC_VER)
-  // MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse
-  unsigned long result = 0;  // NOLINT(runtime/int)
-  if ((n >> 32) && _BitScanReverse(&result, n >> 32)) {
-    return 31 - result;
-  }
-  if (_BitScanReverse(&result, n)) {
-    return 63 - result;
-  }
-  return 64;
-#elif defined(__GNUC__)
-  // Use __builtin_clzll, which uses the following instructions:
-  //  x86: bsr
-  //  ARM64: clz
-  //  PPC: cntlzd
-  static_assert(sizeof(unsigned long long) == sizeof(n),  // NOLINT(runtime/int)
-                "__builtin_clzll does not take 64-bit arg");
-
-  // Handle 0 as a special case because __builtin_clzll(0) is undefined.
-  if (n == 0) {
-    return 64;
-  }
-  return __builtin_clzll(n);
-#else
-  return CountLeadingZeros64Slow(n);
-#endif
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32Slow(uint64_t n) {
-  int zeroes = 28;
-  if (n >> 16) {
-    zeroes -= 16;
-    n >>= 16;
-  }
-  if (n >> 8) {
-    zeroes -= 8;
-    n >>= 8;
-  }
-  if (n >> 4) {
-    zeroes -= 4;
-    n >>= 4;
-  }
-  return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32(uint32_t n) {
-#if defined(_MSC_VER)
-  unsigned long result = 0;  // NOLINT(runtime/int)
-  if (_BitScanReverse(&result, n)) {
-    return 31 - result;
-  }
-  return 32;
-#elif defined(__GNUC__)
-  // Use __builtin_clz, which uses the following instructions:
-  //  x86: bsr
-  //  ARM64: clz
-  //  PPC: cntlzd
-  static_assert(sizeof(int) == sizeof(n),
-                "__builtin_clz does not take 32-bit arg");
-
-  // Handle 0 as a special case because __builtin_clz(0) is undefined.
-  if (n == 0) {
-    return 32;
-  }
-  return __builtin_clz(n);
-#else
-  return CountLeadingZeros32Slow(n);
-#endif
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64Slow(uint64_t n) {
-  int c = 63;
-  n &= ~n + 1;
-  if (n & 0x00000000FFFFFFFF) c -= 32;
-  if (n & 0x0000FFFF0000FFFF) c -= 16;
-  if (n & 0x00FF00FF00FF00FF) c -= 8;
-  if (n & 0x0F0F0F0F0F0F0F0F) c -= 4;
-  if (n & 0x3333333333333333) c -= 2;
-  if (n & 0x5555555555555555) c -= 1;
-  return c;
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64(uint64_t n) {
-#if defined(_MSC_VER) && defined(_M_X64)
-  unsigned long result = 0;  // NOLINT(runtime/int)
-  _BitScanForward64(&result, n);
-  return result;
-#elif defined(_MSC_VER)
-  unsigned long result = 0;  // NOLINT(runtime/int)
-  if (static_cast<uint32_t>(n) == 0) {
-    _BitScanForward(&result, n >> 32);
-    return result + 32;
-  }
-  _BitScanForward(&result, n);
-  return result;
-#elif defined(__GNUC__)
-  static_assert(sizeof(unsigned long long) == sizeof(n),  // NOLINT(runtime/int)
-                "__builtin_ctzll does not take 64-bit arg");
-  return __builtin_ctzll(n);
-#else
-  return CountTrailingZerosNonZero64Slow(n);
-#endif
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32Slow(uint32_t n) {
-  int c = 31;
-  n &= ~n + 1;
-  if (n & 0x0000FFFF) c -= 16;
-  if (n & 0x00FF00FF) c -= 8;
-  if (n & 0x0F0F0F0F) c -= 4;
-  if (n & 0x33333333) c -= 2;
-  if (n & 0x55555555) c -= 1;
-  return c;
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32(uint32_t n) {
-#if defined(_MSC_VER)
-  unsigned long result = 0;  // NOLINT(runtime/int)
-  _BitScanForward(&result, n);
-  return result;
-#elif defined(__GNUC__)
-  static_assert(sizeof(int) == sizeof(n),
-                "__builtin_ctz does not take 32-bit arg");
-  return __builtin_ctz(n);
-#else
-  return CountTrailingZerosNonZero32Slow(n);
-#endif
-}
-
-#undef ABSL_BASE_INTERNAL_FORCEINLINE
-
-}  // namespace base_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#endif  // ABSL_BASE_INTERNAL_BITS_H_
diff --git a/absl/base/internal/bits_test.cc b/absl/base/internal/bits_test.cc
deleted file mode 100644
index 7855fa6..0000000
--- a/absl/base/internal/bits_test.cc
+++ /dev/null
@@ -1,97 +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 "absl/base/internal/bits.h"
-
-#include "gtest/gtest.h"
-
-namespace {
-
-int CLZ64(uint64_t n) {
-  int fast = absl::base_internal::CountLeadingZeros64(n);
-  int slow = absl::base_internal::CountLeadingZeros64Slow(n);
-  EXPECT_EQ(fast, slow) << n;
-  return fast;
-}
-
-TEST(BitsTest, CountLeadingZeros64) {
-  EXPECT_EQ(64, CLZ64(uint64_t{}));
-  EXPECT_EQ(0, CLZ64(~uint64_t{}));
-
-  for (int index = 0; index < 64; index++) {
-    uint64_t x = static_cast<uint64_t>(1) << index;
-    const auto cnt = 63 - index;
-    ASSERT_EQ(cnt, CLZ64(x)) << index;
-    ASSERT_EQ(cnt, CLZ64(x + x - 1)) << index;
-  }
-}
-
-int CLZ32(uint32_t n) {
-  int fast = absl::base_internal::CountLeadingZeros32(n);
-  int slow = absl::base_internal::CountLeadingZeros32Slow(n);
-  EXPECT_EQ(fast, slow) << n;
-  return fast;
-}
-
-TEST(BitsTest, CountLeadingZeros32) {
-  EXPECT_EQ(32, CLZ32(uint32_t{}));
-  EXPECT_EQ(0, CLZ32(~uint32_t{}));
-
-  for (int index = 0; index < 32; index++) {
-    uint32_t x = static_cast<uint32_t>(1) << index;
-    const auto cnt = 31 - index;
-    ASSERT_EQ(cnt, CLZ32(x)) << index;
-    ASSERT_EQ(cnt, CLZ32(x + x - 1)) << index;
-    ASSERT_EQ(CLZ64(x), CLZ32(x) + 32);
-  }
-}
-
-int CTZ64(uint64_t n) {
-  int fast = absl::base_internal::CountTrailingZerosNonZero64(n);
-  int slow = absl::base_internal::CountTrailingZerosNonZero64Slow(n);
-  EXPECT_EQ(fast, slow) << n;
-  return fast;
-}
-
-TEST(BitsTest, CountTrailingZerosNonZero64) {
-  EXPECT_EQ(0, CTZ64(~uint64_t{}));
-
-  for (int index = 0; index < 64; index++) {
-    uint64_t x = static_cast<uint64_t>(1) << index;
-    const auto cnt = index;
-    ASSERT_EQ(cnt, CTZ64(x)) << index;
-    ASSERT_EQ(cnt, CTZ64(~(x - 1))) << index;
-  }
-}
-
-int CTZ32(uint32_t n) {
-  int fast = absl::base_internal::CountTrailingZerosNonZero32(n);
-  int slow = absl::base_internal::CountTrailingZerosNonZero32Slow(n);
-  EXPECT_EQ(fast, slow) << n;
-  return fast;
-}
-
-TEST(BitsTest, CountTrailingZerosNonZero32) {
-  EXPECT_EQ(0, CTZ32(~uint32_t{}));
-
-  for (int index = 0; index < 32; index++) {
-    uint32_t x = static_cast<uint32_t>(1) << index;
-    const auto cnt = index;
-    ASSERT_EQ(cnt, CTZ32(x)) << index;
-    ASSERT_EQ(cnt, CTZ32(~(x - 1))) << index;
-  }
-}
-
-
-}  // namespace
diff --git a/absl/base/internal/direct_mmap.h b/absl/base/internal/direct_mmap.h
index 5618867..274054c 100644
--- a/absl/base/internal/direct_mmap.h
+++ b/absl/base/internal/direct_mmap.h
@@ -61,6 +61,10 @@
 #endif
 #endif  // __BIONIC__
 
+#if defined(__NR_mmap2) && !defined(SYS_mmap2)
+#define SYS_mmap2 __NR_mmap2
+#endif
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace base_internal {
@@ -70,9 +74,13 @@
 inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
                         off64_t offset) noexcept {
 #if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \
+    defined(__m68k__) || defined(__sh__) ||                                  \
+    (defined(__hppa__) && !defined(__LP64__)) ||                             \
     (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) ||                   \
     (defined(__PPC__) && !defined(__PPC64__)) ||                             \
-    (defined(__s390__) && !defined(__s390x__))
+    (defined(__riscv) && __riscv_xlen == 32) ||                              \
+    (defined(__s390__) && !defined(__s390x__)) ||                            \
+    (defined(__sparc__) && !defined(__arch64__))
   // On these architectures, implement mmap with mmap2.
   static int pagesize = 0;
   if (pagesize == 0) {
diff --git a/absl/base/internal/dynamic_annotations.h b/absl/base/internal/dynamic_annotations.h
new file mode 100644
index 0000000..b23c5ec
--- /dev/null
+++ b/absl/base/internal/dynamic_annotations.h
@@ -0,0 +1,398 @@
+// 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.
+
+// This file defines dynamic annotations for use with dynamic analysis tool
+// such as valgrind, PIN, etc.
+//
+// Dynamic annotation is a source code annotation that affects the generated
+// code (that is, the annotation is not a comment). Each such annotation is
+// attached to a particular instruction and/or to a particular object (address)
+// in the program.
+//
+// The annotations that should be used by users are macros in all upper-case
+// (e.g., ANNOTATE_THREAD_NAME).
+//
+// Actual implementation of these macros may differ depending on the dynamic
+// analysis tool being used.
+//
+// This file supports the following configurations:
+// - Dynamic Annotations enabled (with static thread-safety warnings disabled).
+//   In this case, macros expand to functions implemented by Thread Sanitizer,
+//   when building with TSan. When not provided an external implementation,
+//   dynamic_annotations.cc provides no-op implementations.
+//
+// - Static Clang thread-safety warnings enabled.
+//   When building with a Clang compiler that supports thread-safety warnings,
+//   a subset of annotations can be statically-checked at compile-time. We
+//   expand these macros to static-inline functions that can be analyzed for
+//   thread-safety, but afterwards elided when building the final binary.
+//
+// - All annotations are disabled.
+//   If neither Dynamic Annotations nor Clang thread-safety warnings are
+//   enabled, then all annotation-macros expand to empty.
+
+#ifndef ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_
+#define ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_
+
+#include <stddef.h>
+
+#include "absl/base/config.h"
+
+// -------------------------------------------------------------------------
+// Decide which features are enabled
+
+#ifndef DYNAMIC_ANNOTATIONS_ENABLED
+#define DYNAMIC_ANNOTATIONS_ENABLED 0
+#endif
+
+#if defined(__clang__) && !defined(SWIG)
+#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1
+#endif
+
+#if DYNAMIC_ANNOTATIONS_ENABLED != 0
+
+#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
+#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED 1
+
+#else
+
+#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 0
+#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 0
+#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 0
+
+// Clang provides limited support for static thread-safety analysis through a
+// feature called Annotalysis. We configure macro-definitions according to
+// whether Annotalysis support is available. When running in opt-mode, GCC
+// will issue a warning, if these attributes are compiled. Only include them
+// when compiling using Clang.
+
+// ANNOTALYSIS_ENABLED == 1 when IGNORE_READ_ATTRIBUTE_ENABLED == 1
+#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED \
+  defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+// Read/write annotations are enabled in Annotalysis mode; disabled otherwise.
+#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED \
+  ABSL_INTERNAL_ANNOTALYSIS_ENABLED
+#endif
+
+// Memory annotations are also made available to LLVM's Memory Sanitizer
+#if defined(ABSL_HAVE_MEMORY_SANITIZER) && !defined(__native_client__)
+#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 1
+#endif
+
+#ifndef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
+#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 0
+#endif
+
+#ifdef __cplusplus
+#define ABSL_INTERNAL_BEGIN_EXTERN_C extern "C" {
+#define ABSL_INTERNAL_END_EXTERN_C }  // extern "C"
+#define ABSL_INTERNAL_GLOBAL_SCOPED(F) ::F
+#define ABSL_INTERNAL_STATIC_INLINE inline
+#else
+#define ABSL_INTERNAL_BEGIN_EXTERN_C  // empty
+#define ABSL_INTERNAL_END_EXTERN_C    // empty
+#define ABSL_INTERNAL_GLOBAL_SCOPED(F) F
+#define ABSL_INTERNAL_STATIC_INLINE static inline
+#endif
+
+// -------------------------------------------------------------------------
+// Define race annotations.
+
+#if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1
+
+// -------------------------------------------------------------
+// Annotations that suppress errors. It is usually better to express the
+// program's synchronization using the other annotations, but these can be used
+// when all else fails.
+
+// Report that we may have a benign race at `pointer`, with size
+// "sizeof(*(pointer))". `pointer` must be a non-void* pointer. Insert at the
+// point where `pointer` has been allocated, preferably close to the point
+// where the race happens. See also ANNOTATE_BENIGN_RACE_STATIC.
+#define ANNOTATE_BENIGN_RACE(pointer, description)     \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \
+  (__FILE__, __LINE__, pointer, sizeof(*(pointer)), description)
+
+// Same as ANNOTATE_BENIGN_RACE(`address`, `description`), but applies to
+// the memory range [`address`, `address`+`size`).
+#define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized)         \
+  (__FILE__, __LINE__, address, size, description)
+
+// Enable (`enable`!=0) or disable (`enable`==0) race detection for all threads.
+// This annotation could be useful if you want to skip expensive race analysis
+// during some period of program execution, e.g. during initialization.
+#define ANNOTATE_ENABLE_RACE_DETECTION(enable)             \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateEnableRaceDetection) \
+  (__FILE__, __LINE__, enable)
+
+// -------------------------------------------------------------
+// Annotations useful for debugging.
+
+// Report the current thread `name` to a race detector.
+#define ANNOTATE_THREAD_NAME(name) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateThreadName)(__FILE__, __LINE__, name)
+
+// -------------------------------------------------------------
+// Annotations useful when implementing locks. They are not normally needed by
+// modules that merely use locks. The `lock` argument is a pointer to the lock
+// object.
+
+// Report that a lock has been created at address `lock`.
+#define ANNOTATE_RWLOCK_CREATE(lock) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreate)(__FILE__, __LINE__, lock)
+
+// Report that a linker initialized lock has been created at address `lock`.
+#ifdef ABSL_HAVE_THREAD_SANITIZER
+#define ANNOTATE_RWLOCK_CREATE_STATIC(lock)               \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreateStatic) \
+  (__FILE__, __LINE__, lock)
+#else
+#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) ANNOTATE_RWLOCK_CREATE(lock)
+#endif
+
+// Report that the lock at address `lock` is about to be destroyed.
+#define ANNOTATE_RWLOCK_DESTROY(lock) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock)
+
+// Report that the lock at address `lock` has been acquired.
+// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
+#define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w)          \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockAcquired) \
+  (__FILE__, __LINE__, lock, is_w)
+
+// Report that the lock at address `lock` is about to be released.
+// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
+#define ANNOTATE_RWLOCK_RELEASED(lock, is_w)          \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockReleased) \
+  (__FILE__, __LINE__, lock, is_w)
+
+// Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable `static_var`.
+#define ANNOTATE_BENIGN_RACE_STATIC(static_var, description)      \
+  namespace {                                                     \
+  class static_var##_annotator {                                  \
+   public:                                                        \
+    static_var##_annotator() {                                    \
+      ANNOTATE_BENIGN_RACE_SIZED(&static_var, sizeof(static_var), \
+                                 #static_var ": " description);   \
+    }                                                             \
+  };                                                              \
+  static static_var##_annotator the##static_var##_annotator;      \
+  }  // namespace
+
+#else  // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 0
+
+#define ANNOTATE_RWLOCK_CREATE(lock)                            // empty
+#define ANNOTATE_RWLOCK_CREATE_STATIC(lock)                     // empty
+#define ANNOTATE_RWLOCK_DESTROY(lock)                           // empty
+#define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w)                    // empty
+#define ANNOTATE_RWLOCK_RELEASED(lock, is_w)                    // empty
+#define ANNOTATE_BENIGN_RACE(address, description)              // empty
+#define ANNOTATE_BENIGN_RACE_SIZED(address, size, description)  // empty
+#define ANNOTATE_THREAD_NAME(name)                              // empty
+#define ANNOTATE_ENABLE_RACE_DETECTION(enable)                  // empty
+#define ANNOTATE_BENIGN_RACE_STATIC(static_var, description)    // empty
+
+#endif  // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
+
+// -------------------------------------------------------------------------
+// Define memory annotations.
+
+#if ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 1
+
+#include <sanitizer/msan_interface.h>
+
+#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
+  __msan_unpoison(address, size)
+
+#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
+  __msan_allocated_memory(address, size)
+
+#else  // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 0
+
+#if DYNAMIC_ANNOTATIONS_ENABLED == 1
+#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
+  do {                                                \
+    (void)(address);                                  \
+    (void)(size);                                     \
+  } while (0)
+#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
+  do {                                                  \
+    (void)(address);                                    \
+    (void)(size);                                       \
+  } while (0)
+#else
+#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size)    // empty
+#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size)  // empty
+#endif
+
+#endif  // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
+
+// -------------------------------------------------------------------------
+// Define IGNORE_READS_BEGIN/_END attributes.
+
+#if defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+
+#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE \
+  __attribute((exclusive_lock_function("*")))
+#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE \
+  __attribute((unlock_function("*")))
+
+#else  // !defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+
+#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE  // empty
+#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE    // empty
+
+#endif  // defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+
+// -------------------------------------------------------------------------
+// Define IGNORE_READS_BEGIN/_END annotations.
+
+#if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1
+
+// Request the analysis tool to ignore all reads in the current thread until
+// ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey
+// reads, while still checking other reads and all writes.
+// See also ANNOTATE_UNPROTECTED_READ.
+#define ANNOTATE_IGNORE_READS_BEGIN() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin)(__FILE__, __LINE__)
+
+// Stop ignoring reads.
+#define ANNOTATE_IGNORE_READS_END() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd)(__FILE__, __LINE__)
+
+#elif defined(ABSL_INTERNAL_ANNOTALYSIS_ENABLED)
+
+// When Annotalysis is enabled without Dynamic Annotations, the use of
+// static-inline functions allows the annotations to be read at compile-time,
+// while still letting the compiler elide the functions from the final build.
+//
+// TODO(delesley) -- The exclusive lock here ignores writes as well, but
+// allows IGNORE_READS_AND_WRITES to work properly.
+
+#define ANNOTATE_IGNORE_READS_BEGIN() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsBegin)()
+
+#define ANNOTATE_IGNORE_READS_END() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsEnd)()
+
+#else
+
+#define ANNOTATE_IGNORE_READS_BEGIN()  // empty
+#define ANNOTATE_IGNORE_READS_END()    // empty
+
+#endif
+
+// -------------------------------------------------------------------------
+// Define IGNORE_WRITES_BEGIN/_END annotations.
+
+#if ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED == 1
+
+// Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead.
+#define ANNOTATE_IGNORE_WRITES_BEGIN() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__)
+
+// Stop ignoring writes.
+#define ANNOTATE_IGNORE_WRITES_END() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__)
+
+#else
+
+#define ANNOTATE_IGNORE_WRITES_BEGIN()  // empty
+#define ANNOTATE_IGNORE_WRITES_END()    // empty
+
+#endif
+
+// -------------------------------------------------------------------------
+// Define the ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
+// primitive annotations defined above.
+//
+//     Instead of doing
+//        ANNOTATE_IGNORE_READS_BEGIN();
+//        ... = x;
+//        ANNOTATE_IGNORE_READS_END();
+//     one can use
+//        ... = ANNOTATE_UNPROTECTED_READ(x);
+
+#if defined(ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED)
+
+// Start ignoring all memory accesses (both reads and writes).
+#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
+  do {                                           \
+    ANNOTATE_IGNORE_READS_BEGIN();               \
+    ANNOTATE_IGNORE_WRITES_BEGIN();              \
+  } while (0)
+
+// Stop ignoring both reads and writes.
+#define ANNOTATE_IGNORE_READS_AND_WRITES_END() \
+  do {                                         \
+    ANNOTATE_IGNORE_WRITES_END();              \
+    ANNOTATE_IGNORE_READS_END();               \
+  } while (0)
+
+#ifdef __cplusplus
+// ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
+#define ANNOTATE_UNPROTECTED_READ(x) \
+  absl::base_internal::AnnotateUnprotectedRead(x)
+
+#endif
+
+#else
+
+#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN()  // empty
+#define ANNOTATE_IGNORE_READS_AND_WRITES_END()    // empty
+#define ANNOTATE_UNPROTECTED_READ(x) (x)
+
+#endif
+
+// -------------------------------------------------------------------------
+// Address sanitizer annotations
+
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+// Describe the current state of a contiguous container such as e.g.
+// std::vector or std::string. For more details see
+// sanitizer/common_interface_defs.h, which is provided by the compiler.
+#include <sanitizer/common_interface_defs.h>
+
+#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \
+  __sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
+#define ADDRESS_SANITIZER_REDZONE(name)    \
+  struct {                                 \
+    char x[8] __attribute__((aligned(8))); \
+  } name
+
+#else
+
+#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid)
+#define ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "")
+
+#endif  // ABSL_HAVE_ADDRESS_SANITIZER
+
+// -------------------------------------------------------------------------
+// Undefine the macros intended only for this file.
+
+#undef ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_ANNOTALYSIS_ENABLED
+#undef ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_BEGIN_EXTERN_C
+#undef ABSL_INTERNAL_END_EXTERN_C
+#undef ABSL_INTERNAL_STATIC_INLINE
+
+#endif  // ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_
diff --git a/absl/base/internal/endian.h b/absl/base/internal/endian.h
index 9677530..dad0e9a 100644
--- a/absl/base/internal/endian.h
+++ b/absl/base/internal/endian.h
@@ -26,6 +26,7 @@
 #endif
 
 #include <cstdint>
+#include "absl/base/casts.h"
 #include "absl/base/config.h"
 #include "absl/base/internal/unaligned_access.h"
 #include "absl/base/port.h"
@@ -173,6 +174,36 @@
 
 #endif /* ENDIAN */
 
+inline uint8_t FromHost(uint8_t x) { return x; }
+inline uint16_t FromHost(uint16_t x) { return FromHost16(x); }
+inline uint32_t FromHost(uint32_t x) { return FromHost32(x); }
+inline uint64_t FromHost(uint64_t x) { return FromHost64(x); }
+inline uint8_t ToHost(uint8_t x) { return x; }
+inline uint16_t ToHost(uint16_t x) { return ToHost16(x); }
+inline uint32_t ToHost(uint32_t x) { return ToHost32(x); }
+inline uint64_t ToHost(uint64_t x) { return ToHost64(x); }
+
+inline int8_t FromHost(int8_t x) { return x; }
+inline int16_t FromHost(int16_t x) {
+  return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
+}
+inline int32_t FromHost(int32_t x) {
+  return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
+}
+inline int64_t FromHost(int64_t x) {
+  return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
+}
+inline int8_t ToHost(int8_t x) { return x; }
+inline int16_t ToHost(int16_t x) {
+  return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
+}
+inline int32_t ToHost(int32_t x) {
+  return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
+}
+inline int64_t ToHost(int64_t x) {
+  return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
+}
+
 // Functions to do unaligned loads and stores in little-endian order.
 inline uint16_t Load16(const void *p) {
   return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
@@ -233,6 +264,36 @@
 
 #endif /* ENDIAN */
 
+inline uint8_t FromHost(uint8_t x) { return x; }
+inline uint16_t FromHost(uint16_t x) { return FromHost16(x); }
+inline uint32_t FromHost(uint32_t x) { return FromHost32(x); }
+inline uint64_t FromHost(uint64_t x) { return FromHost64(x); }
+inline uint8_t ToHost(uint8_t x) { return x; }
+inline uint16_t ToHost(uint16_t x) { return ToHost16(x); }
+inline uint32_t ToHost(uint32_t x) { return ToHost32(x); }
+inline uint64_t ToHost(uint64_t x) { return ToHost64(x); }
+
+inline int8_t FromHost(int8_t x) { return x; }
+inline int16_t FromHost(int16_t x) {
+  return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
+}
+inline int32_t FromHost(int32_t x) {
+  return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
+}
+inline int64_t FromHost(int64_t x) {
+  return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
+}
+inline int8_t ToHost(int8_t x) { return x; }
+inline int16_t ToHost(int16_t x) {
+  return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
+}
+inline int32_t ToHost(int32_t x) {
+  return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
+}
+inline int64_t ToHost(int64_t x) {
+  return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
+}
+
 // Functions to do unaligned loads and stores in big-endian order.
 inline uint16_t Load16(const void *p) {
   return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
diff --git a/absl/base/internal/endian_test.cc b/absl/base/internal/endian_test.cc
index aa6b849..a1691b1 100644
--- a/absl/base/internal/endian_test.cc
+++ b/absl/base/internal/endian_test.cc
@@ -54,24 +54,22 @@
 const uint16_t k16ValueBE{0x2301};
 #endif
 
-template<typename T>
-std::vector<T> GenerateAllValuesForType() {
-  std::vector<T> result;
-  T next = std::numeric_limits<T>::min();
-  while (true) {
-    result.push_back(next);
-    if (next == std::numeric_limits<T>::max()) {
-      return result;
-    }
-    ++next;
+std::vector<uint16_t> GenerateAllUint16Values() {
+  std::vector<uint16_t> result;
+  result.reserve(size_t{1} << (sizeof(uint16_t) * 8));
+  for (uint32_t i = std::numeric_limits<uint16_t>::min();
+       i <= std::numeric_limits<uint16_t>::max(); ++i) {
+    result.push_back(static_cast<uint16_t>(i));
   }
+  return result;
 }
 
 template<typename T>
-std::vector<T> GenerateRandomIntegers(size_t numValuesToTest) {
+std::vector<T> GenerateRandomIntegers(size_t num_values_to_test) {
   std::vector<T> result;
+  result.reserve(num_values_to_test);
   std::mt19937_64 rng(kRandomSeed);
-  for (size_t i = 0; i < numValuesToTest; ++i) {
+  for (size_t i = 0; i < num_values_to_test; ++i) {
     result.push_back(rng());
   }
   return result;
@@ -148,7 +146,7 @@
 }
 
 TEST(EndianessTest, Uint16) {
-  GBSwapHelper(GenerateAllValuesForType<uint16_t>(), &Swap16);
+  GBSwapHelper(GenerateAllUint16Values(), &Swap16);
 }
 
 TEST(EndianessTest, Uint32) {
diff --git a/absl/base/internal/errno_saver_test.cc b/absl/base/internal/errno_saver_test.cc
index b845e2d..e9b742c 100644
--- a/absl/base/internal/errno_saver_test.cc
+++ b/absl/base/internal/errno_saver_test.cc
@@ -18,6 +18,7 @@
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/base/internal/strerror.h"
 
 namespace {
 using ::testing::Eq;
@@ -26,7 +27,7 @@
   int no;
 };
 std::ostream &operator<<(std::ostream &os, ErrnoPrinter ep) {
-  return os << strerror(ep.no) << " [" << ep.no << "]";
+  return os << absl::base_internal::StrError(ep.no) << " [" << ep.no << "]";
 }
 bool operator==(ErrnoPrinter one, ErrnoPrinter two) { return one.no == two.no; }
 
diff --git a/absl/base/internal/exponential_biased_test.cc b/absl/base/internal/exponential_biased_test.cc
index 90a482d..075583c 100644
--- a/absl/base/internal/exponential_biased_test.cc
+++ b/absl/base/internal/exponential_biased_test.cc
@@ -185,7 +185,7 @@
   ABSL_CONST_INIT static ExponentialBiased eb_static;
   EXPECT_THAT(eb_static.GetSkipCount(2), Ge(0));
 
-#if ABSL_HAVE_THREAD_LOCAL
+#ifdef ABSL_HAVE_THREAD_LOCAL
   thread_local ExponentialBiased eb_thread;
   EXPECT_THAT(eb_thread.GetSkipCount(2), Ge(0));
 #endif
diff --git a/absl/base/internal/fast_type_id.h b/absl/base/internal/fast_type_id.h
new file mode 100644
index 0000000..3db59e8
--- /dev/null
+++ b/absl/base/internal/fast_type_id.h
@@ -0,0 +1,48 @@
+//
+// 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.
+//
+
+#ifndef ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
+#define ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+template <typename Type>
+struct FastTypeTag {
+  constexpr static char dummy_var = 0;
+};
+
+template <typename Type>
+constexpr char FastTypeTag<Type>::dummy_var;
+
+// FastTypeId<Type>() evaluates at compile/link-time to a unique pointer for the
+// passed-in type. These are meant to be good match for keys into maps or
+// straight up comparisons.
+using FastTypeIdType = const void*;
+
+template <typename Type>
+constexpr inline FastTypeIdType FastTypeId() {
+  return &FastTypeTag<Type>::dummy_var;
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
diff --git a/absl/base/internal/fast_type_id_test.cc b/absl/base/internal/fast_type_id_test.cc
new file mode 100644
index 0000000..16f3c14
--- /dev/null
+++ b/absl/base/internal/fast_type_id_test.cc
@@ -0,0 +1,123 @@
+// 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/base/internal/fast_type_id.h"
+
+#include <cstdint>
+#include <map>
+#include <vector>
+
+#include "gtest/gtest.h"
+
+namespace {
+namespace bi = absl::base_internal;
+
+// NOLINTNEXTLINE
+#define PRIM_TYPES(A)   \
+  A(bool)               \
+  A(short)              \
+  A(unsigned short)     \
+  A(int)                \
+  A(unsigned int)       \
+  A(long)               \
+  A(unsigned long)      \
+  A(long long)          \
+  A(unsigned long long) \
+  A(float)              \
+  A(double)             \
+  A(long double)
+
+TEST(FastTypeIdTest, PrimitiveTypes) {
+  bi::FastTypeIdType type_ids[] = {
+#define A(T) bi::FastTypeId<T>(),
+    PRIM_TYPES(A)
+#undef A
+#define A(T) bi::FastTypeId<const T>(),
+    PRIM_TYPES(A)
+#undef A
+#define A(T) bi::FastTypeId<volatile T>(),
+    PRIM_TYPES(A)
+#undef A
+#define A(T) bi::FastTypeId<const volatile T>(),
+    PRIM_TYPES(A)
+#undef A
+  };
+  size_t total_type_ids = sizeof(type_ids) / sizeof(bi::FastTypeIdType);
+
+  for (int i = 0; i < total_type_ids; ++i) {
+    EXPECT_EQ(type_ids[i], type_ids[i]);
+    for (int j = 0; j < i; ++j) {
+      EXPECT_NE(type_ids[i], type_ids[j]);
+    }
+  }
+}
+
+#define FIXED_WIDTH_TYPES(A) \
+  A(int8_t)                  \
+  A(uint8_t)                 \
+  A(int16_t)                 \
+  A(uint16_t)                \
+  A(int32_t)                 \
+  A(uint32_t)                \
+  A(int64_t)                 \
+  A(uint64_t)
+
+TEST(FastTypeIdTest, FixedWidthTypes) {
+  bi::FastTypeIdType type_ids[] = {
+#define A(T) bi::FastTypeId<T>(),
+    FIXED_WIDTH_TYPES(A)
+#undef A
+#define A(T) bi::FastTypeId<const T>(),
+    FIXED_WIDTH_TYPES(A)
+#undef A
+#define A(T) bi::FastTypeId<volatile T>(),
+    FIXED_WIDTH_TYPES(A)
+#undef A
+#define A(T) bi::FastTypeId<const volatile T>(),
+    FIXED_WIDTH_TYPES(A)
+#undef A
+  };
+  size_t total_type_ids = sizeof(type_ids) / sizeof(bi::FastTypeIdType);
+
+  for (int i = 0; i < total_type_ids; ++i) {
+    EXPECT_EQ(type_ids[i], type_ids[i]);
+    for (int j = 0; j < i; ++j) {
+      EXPECT_NE(type_ids[i], type_ids[j]);
+    }
+  }
+}
+
+TEST(FastTypeIdTest, AliasTypes) {
+  using int_alias = int;
+  EXPECT_EQ(bi::FastTypeId<int_alias>(), bi::FastTypeId<int>());
+}
+
+TEST(FastTypeIdTest, TemplateSpecializations) {
+  EXPECT_NE(bi::FastTypeId<std::vector<int>>(),
+            bi::FastTypeId<std::vector<long>>());
+
+  EXPECT_NE((bi::FastTypeId<std::map<int, float>>()),
+            (bi::FastTypeId<std::map<int, double>>()));
+}
+
+struct Base {};
+struct Derived : Base {};
+struct PDerived : private Base {};
+
+TEST(FastTypeIdTest, Inheritance) {
+  EXPECT_NE(bi::FastTypeId<Base>(), bi::FastTypeId<Derived>());
+  EXPECT_NE(bi::FastTypeId<Base>(), bi::FastTypeId<PDerived>());
+}
+
+}  // namespace
diff --git a/absl/base/internal/invoke.h b/absl/base/internal/invoke.h
index c4eceeb..5c71f32 100644
--- a/absl/base/internal/invoke.h
+++ b/absl/base/internal/invoke.h
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 //
-// absl::base_internal::Invoke(f, args...) is an implementation of
+// absl::base_internal::invoke(f, args...) is an implementation of
 // INVOKE(f, args...) from section [func.require] of the C++ standard.
 //
 // [func.require]
@@ -29,7 +29,7 @@
 //    is not one of the types described in the previous item;
 // 5. f(t1, t2, ..., tN) in all other cases.
 //
-// The implementation is SFINAE-friendly: substitution failure within Invoke()
+// The implementation is SFINAE-friendly: substitution failure within invoke()
 // isn't an error.
 
 #ifndef ABSL_BASE_INTERNAL_INVOKE_H_
@@ -170,13 +170,13 @@
 
 // The result type of Invoke<F, Args...>.
 template <typename F, typename... Args>
-using InvokeT = decltype(Invoker<F, Args...>::type::Invoke(
+using invoke_result_t = decltype(Invoker<F, Args...>::type::Invoke(
     std::declval<F>(), std::declval<Args>()...));
 
 // Invoke(f, args...) is an implementation of INVOKE(f, args...) from section
 // [func.require] of the C++ standard.
 template <typename F, typename... Args>
-InvokeT<F, Args...> Invoke(F&& f, Args&&... args) {
+invoke_result_t<F, Args...> invoke(F&& f, Args&&... args) {
   return Invoker<F, Args...>::type::Invoke(std::forward<F>(f),
                                            std::forward<Args>(args)...);
 }
diff --git a/absl/base/internal/low_level_alloc.cc b/absl/base/internal/low_level_alloc.cc
index 1bf9443..229ab91 100644
--- a/absl/base/internal/low_level_alloc.cc
+++ b/absl/base/internal/low_level_alloc.cc
@@ -598,7 +598,7 @@
     section.Leave();
     result = &s->levels;
   }
-  ANNOTATE_MEMORY_IS_UNINITIALIZED(result, request);
+  ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(result, request);
   return result;
 }
 
diff --git a/absl/base/internal/low_level_alloc_test.cc b/absl/base/internal/low_level_alloc_test.cc
index 7abbbf9..31abb88 100644
--- a/absl/base/internal/low_level_alloc_test.cc
+++ b/absl/base/internal/low_level_alloc_test.cc
@@ -21,6 +21,12 @@
 #include <unordered_map>
 #include <utility>
 
+#ifdef __EMSCRIPTEN__
+#include <emscripten.h>
+#endif
+
+#include "absl/container/node_hash_map.h"
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace base_internal {
@@ -75,7 +81,7 @@
 // allocations and deallocations are reported via the MallocHook
 // interface.
 static void Test(bool use_new_arena, bool call_malloc_hook, int n) {
-  typedef std::unordered_map<int, BlockDesc> AllocMap;
+  typedef absl::node_hash_map<int, BlockDesc> AllocMap;
   AllocMap allocated;
   AllocMap::iterator it;
   BlockDesc block_desc;
@@ -156,5 +162,20 @@
 int main(int argc, char *argv[]) {
   // The actual test runs in the global constructor of `before_main`.
   printf("PASS\n");
+#ifdef __EMSCRIPTEN__
+  // clang-format off
+// This is JS here. Don't try to format it.
+    MAIN_THREAD_EM_ASM({
+      if (ENVIRONMENT_IS_WEB) {
+        if (typeof TEST_FINISH === 'function') {
+          TEST_FINISH($0);
+        } else {
+          console.error('Attempted to exit with status ' + $0);
+          console.error('But TEST_FINSIHED is not a function.');
+        }
+      }
+    }, 0);
+// clang-format on
+#endif
   return 0;
 }
diff --git a/absl/base/internal/low_level_scheduling.h b/absl/base/internal/low_level_scheduling.h
index 961cc98..9baccc0 100644
--- a/absl/base/internal/low_level_scheduling.h
+++ b/absl/base/internal/low_level_scheduling.h
@@ -18,6 +18,7 @@
 #ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
 #define ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
 
+#include "absl/base/internal/raw_logging.h"
 #include "absl/base/internal/scheduling_mode.h"
 #include "absl/base/macros.h"
 
@@ -29,6 +30,13 @@
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
+class CondVar;
+class Mutex;
+
+namespace synchronization_internal {
+int MutexDelay(int32_t c, int mode);
+}  // namespace synchronization_internal
+
 namespace base_internal {
 
 class SchedulingHelper;  // To allow use of SchedulingGuard.
@@ -53,6 +61,8 @@
  public:
   // Returns true iff the calling thread may be cooperatively rescheduled.
   static bool ReschedulingIsAllowed();
+  SchedulingGuard(const SchedulingGuard&) = delete;
+  SchedulingGuard& operator=(const SchedulingGuard&) = delete;
 
  private:
   // Disable cooperative rescheduling of the calling thread.  It may still
@@ -76,12 +86,23 @@
     bool disabled;
   };
 
-  // Access to SchedulingGuard is explicitly white-listed.
+  // A scoped helper to enable rescheduling temporarily.
+  // REQUIRES: destructor must run in same thread as constructor.
+  class ScopedEnable {
+   public:
+    ScopedEnable();
+    ~ScopedEnable();
+
+   private:
+    int scheduling_disabled_depth_;
+  };
+
+  // Access to SchedulingGuard is explicitly permitted.
+  friend class absl::CondVar;
+  friend class absl::Mutex;
   friend class SchedulingHelper;
   friend class SpinLock;
-
-  SchedulingGuard(const SchedulingGuard&) = delete;
-  SchedulingGuard& operator=(const SchedulingGuard&) = delete;
+  friend int absl::synchronization_internal::MutexDelay(int32_t c, int mode);
 };
 
 //------------------------------------------------------------------------------
@@ -100,6 +121,12 @@
   return;
 }
 
+inline SchedulingGuard::ScopedEnable::ScopedEnable()
+    : scheduling_disabled_depth_(0) {}
+inline SchedulingGuard::ScopedEnable::~ScopedEnable() {
+  ABSL_RAW_CHECK(scheduling_disabled_depth_ == 0, "disable unused warning");
+}
+
 }  // namespace base_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/base/internal/raw_logging.cc b/absl/base/internal/raw_logging.cc
index 40cea55..074e026 100644
--- a/absl/base/internal/raw_logging.cc
+++ b/absl/base/internal/raw_logging.cc
@@ -67,28 +67,32 @@
 #undef ABSL_HAVE_RAW_IO
 #endif
 
-// TODO(gfalcon): We want raw-logging to work on as many platforms as possible.
-// Explicitly #error out when not ABSL_LOW_LEVEL_WRITE_SUPPORTED, except for a
-// whitelisted set of platforms for which we expect not to be able to raw log.
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace raw_logging_internal {
+namespace {
 
-ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static absl::base_internal::AtomicHook<
-    absl::raw_logging_internal::LogPrefixHook>
-    log_prefix_hook;
-ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static absl::base_internal::AtomicHook<
-    absl::raw_logging_internal::AbortHook>
-    abort_hook;
+// TODO(gfalcon): We want raw-logging to work on as many platforms as possible.
+// Explicitly `#error` out when not `ABSL_LOW_LEVEL_WRITE_SUPPORTED`, except for
+// a selected set of platforms for which we expect not to be able to raw log.
+
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
+    absl::base_internal::AtomicHook<LogPrefixHook>
+        log_prefix_hook;
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
+    absl::base_internal::AtomicHook<AbortHook>
+        abort_hook;
 
 #ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
-static const char kTruncated[] = " ... (message truncated)\n";
+constexpr char kTruncated[] = " ... (message truncated)\n";
 
 // sprintf the format to the buffer, adjusting *buf and *size to reflect the
 // consumed bytes, and return whether the message fit without truncation.  If
 // truncation occurred, if possible leave room in the buffer for the message
 // kTruncated[].
-inline static bool VADoRawLog(char** buf, int* size, const char* format,
-                              va_list ap) ABSL_PRINTF_ATTRIBUTE(3, 0);
-inline static bool VADoRawLog(char** buf, int* size,
-                              const char* format, va_list ap) {
+bool VADoRawLog(char** buf, int* size, const char* format, va_list ap)
+    ABSL_PRINTF_ATTRIBUTE(3, 0);
+bool VADoRawLog(char** buf, int* size, const char* format, va_list ap) {
   int n = vsnprintf(*buf, *size, format, ap);
   bool result = true;
   if (n < 0 || n > *size) {
@@ -96,7 +100,7 @@
     if (static_cast<size_t>(*size) > sizeof(kTruncated)) {
       n = *size - sizeof(kTruncated);  // room for truncation message
     } else {
-      n = 0;                           // no room for truncation message
+      n = 0;  // no room for truncation message
     }
   }
   *size -= n;
@@ -105,9 +109,7 @@
 }
 #endif  // ABSL_LOW_LEVEL_WRITE_SUPPORTED
 
-static constexpr int kLogBufSize = 3000;
-
-namespace {
+constexpr int kLogBufSize = 3000;
 
 // CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
 // that invoke malloc() and getenv() that might acquire some locks.
@@ -166,7 +168,7 @@
     } else {
       DoRawLog(&buf, &size, "%s", kTruncated);
     }
-    absl::raw_logging_internal::SafeWriteToStderr(buffer, strlen(buffer));
+    SafeWriteToStderr(buffer, strlen(buffer));
   }
 #else
   static_cast<void>(format);
@@ -181,11 +183,18 @@
   }
 }
 
+// Non-formatting version of RawLog().
+//
+// TODO(gfalcon): When string_view no longer depends on base, change this
+// interface to take its message as a string_view instead.
+void DefaultInternalLog(absl::LogSeverity severity, const char* file, int line,
+                        const std::string& message) {
+  RawLog(severity, file, line, "%.*s", static_cast<int>(message.size()),
+         message.data());
+}
+
 }  // namespace
 
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace raw_logging_internal {
 void SafeWriteToStderr(const char *s, size_t len) {
 #if defined(ABSL_HAVE_SYSCALL_WRITE)
   syscall(SYS_write, STDERR_FILENO, s, len);
@@ -201,8 +210,6 @@
 }
 
 void RawLog(absl::LogSeverity severity, const char* file, int line,
-            const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5);
-void RawLog(absl::LogSeverity severity, const char* file, int line,
             const char* format, ...) {
   va_list ap;
   va_start(ap, format);
@@ -210,15 +217,6 @@
   va_end(ap);
 }
 
-// Non-formatting version of RawLog().
-//
-// TODO(gfalcon): When string_view no longer depends on base, change this
-// interface to take its message as a string_view instead.
-static void DefaultInternalLog(absl::LogSeverity severity, const char* file,
-                               int line, const std::string& message) {
-  RawLog(severity, file, line, "%s", message.c_str());
-}
-
 bool RawLoggingFullySupported() {
 #ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
   return true;
@@ -227,10 +225,14 @@
 #endif  // !ABSL_LOW_LEVEL_WRITE_SUPPORTED
 }
 
-ABSL_DLL ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL
     absl::base_internal::AtomicHook<InternalLogFunction>
         internal_log_function(DefaultInternalLog);
 
+void RegisterLogPrefixHook(LogPrefixHook func) { log_prefix_hook.Store(func); }
+
+void RegisterAbortHook(AbortHook func) { abort_hook.Store(func); }
+
 void RegisterInternalLogFunction(InternalLogFunction func) {
   internal_log_function.Store(func);
 }
diff --git a/absl/base/internal/raw_logging.h b/absl/base/internal/raw_logging.h
index 418d6c8..2bf7aab 100644
--- a/absl/base/internal/raw_logging.h
+++ b/absl/base/internal/raw_logging.h
@@ -72,10 +72,14 @@
 //
 // The API is a subset of the above: each macro only takes two arguments.  Use
 // StrCat if you need to build a richer message.
-#define ABSL_INTERNAL_LOG(severity, message)                                \
-  do {                                                                      \
-    ::absl::raw_logging_internal::internal_log_function(                    \
-        ABSL_RAW_LOGGING_INTERNAL_##severity, __FILE__, __LINE__, message); \
+#define ABSL_INTERNAL_LOG(severity, message)                                 \
+  do {                                                                       \
+    constexpr const char* absl_raw_logging_internal_filename = __FILE__;     \
+    ::absl::raw_logging_internal::internal_log_function(                     \
+        ABSL_RAW_LOGGING_INTERNAL_##severity,                                \
+        absl_raw_logging_internal_filename, __LINE__, message);              \
+    if (ABSL_RAW_LOGGING_INTERNAL_##severity == ::absl::LogSeverity::kFatal) \
+      ABSL_INTERNAL_UNREACHABLE;                                             \
   } while (0)
 
 #define ABSL_INTERNAL_CHECK(condition, message)                    \
@@ -170,10 +174,18 @@
                                      const char* file, int line,
                                      const std::string& message);
 
-ABSL_DLL ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES extern base_internal::AtomicHook<
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL extern base_internal::AtomicHook<
     InternalLogFunction>
     internal_log_function;
 
+// Registers hooks of the above types.  Only a single hook of each type may be
+// registered.  It is an error to call these functions multiple times with
+// different input arguments.
+//
+// These functions are safe to call at any point during initialization; they do
+// not block or malloc, and are async-signal safe.
+void RegisterLogPrefixHook(LogPrefixHook func);
+void RegisterAbortHook(AbortHook func);
 void RegisterInternalLogFunction(InternalLogFunction func);
 
 }  // namespace raw_logging_internal
diff --git a/absl/base/internal/spinlock.cc b/absl/base/internal/spinlock.cc
index 830d472..35c0696 100644
--- a/absl/base/internal/spinlock.cc
+++ b/absl/base/internal/spinlock.cc
@@ -66,35 +66,19 @@
   submit_profile_data.Store(fn);
 }
 
+// Static member variable definitions.
+constexpr uint32_t SpinLock::kSpinLockHeld;
+constexpr uint32_t SpinLock::kSpinLockCooperative;
+constexpr uint32_t SpinLock::kSpinLockDisabledScheduling;
+constexpr uint32_t SpinLock::kSpinLockSleeper;
+constexpr uint32_t SpinLock::kWaitTimeMask;
+
 // Uncommon constructors.
 SpinLock::SpinLock(base_internal::SchedulingMode mode)
     : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {
   ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
 }
 
-SpinLock::SpinLock(base_internal::LinkerInitialized,
-                   base_internal::SchedulingMode mode) {
-  ABSL_TSAN_MUTEX_CREATE(this, 0);
-  if (IsCooperative(mode)) {
-    InitLinkerInitializedAndCooperative();
-  }
-  // Otherwise, lockword_ is already initialized.
-}
-
-// Static (linker initialized) spinlocks always start life as functional
-// non-cooperative locks.  When their static constructor does run, it will call
-// this initializer to augment the lockword with the cooperative bit.  By
-// actually taking the lock when we do this we avoid the need for an atomic
-// operation in the regular unlock path.
-//
-// SlowLock() must be careful to re-test for this bit so that any outstanding
-// waiters may be upgraded to cooperative status.
-void SpinLock::InitLinkerInitializedAndCooperative() {
-  Lock();
-  lockword_.fetch_or(kSpinLockCooperative, std::memory_order_relaxed);
-  Unlock();
-}
-
 // 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
 // is returned from the method.
@@ -121,6 +105,14 @@
   if ((lock_value & kSpinLockHeld) == 0) {
     return;
   }
+
+  base_internal::SchedulingMode scheduling_mode;
+  if ((lock_value & kSpinLockCooperative) != 0) {
+    scheduling_mode = base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
+  } else {
+    scheduling_mode = base_internal::SCHEDULE_KERNEL_ONLY;
+  }
+
   // The lock was not obtained initially, so this thread needs to wait for
   // it.  Record the current timestamp in the local variable wait_start_time
   // so the total wait time can be stored in the lockword once this thread
@@ -133,8 +125,9 @@
     // it as having a sleeper.
     if ((lock_value & kWaitTimeMask) == 0) {
       // Here, just "mark" that the thread is going to sleep.  Don't store the
-      // lock wait time in the lock as that will cause the current lock
-      // owner to think it experienced contention.
+      // lock wait time in the lock -- the lock word stores the amount of time
+      // that the current holder waited before acquiring the lock, not the wait
+      // time of any thread currently waiting to acquire it.
       if (lockword_.compare_exchange_strong(
               lock_value, lock_value | kSpinLockSleeper,
               std::memory_order_relaxed, std::memory_order_relaxed)) {
@@ -148,15 +141,17 @@
         // this thread obtains the lock.
         lock_value = TryLockInternal(lock_value, wait_cycles);
         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
+        // example, a new lock holder may have acquired the lock with
+        // kSpinLockDisabledScheduling set, whereas the previous holder had not
+        // set that flag. In this case, attempt again to mark ourselves as a
+        // waiter.
+        continue;
       }
     }
 
-    base_internal::SchedulingMode scheduling_mode;
-    if ((lock_value & kSpinLockCooperative) != 0) {
-      scheduling_mode = base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
-    } else {
-      scheduling_mode = base_internal::SCHEDULE_KERNEL_ONLY;
-    }
     // SpinLockDelay() calls into fiber scheduler, we need to see
     // synchronization there to avoid false positives.
     ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
@@ -190,30 +185,32 @@
 // We use the upper 29 bits of the lock word to store the time spent waiting to
 // acquire this lock.  This is reported by contentionz profiling.  Since the
 // lower bits of the cycle counter wrap very quickly on high-frequency
-// processors we divide to reduce the granularity to 2^PROFILE_TIMESTAMP_SHIFT
+// processors we divide to reduce the granularity to 2^kProfileTimestampShift
 // sized units.  On a 4Ghz machine this will lose track of wait times greater
 // than (2^29/4 Ghz)*128 =~ 17.2 seconds.  Such waits should be extremely rare.
-enum { PROFILE_TIMESTAMP_SHIFT = 7 };
-enum { LOCKWORD_RESERVED_SHIFT = 3 };  // We currently reserve the lower 3 bits.
+static constexpr int kProfileTimestampShift = 7;
+
+// We currently reserve the lower 3 bits.
+static constexpr int kLockwordReservedShift = 3;
 
 uint32_t SpinLock::EncodeWaitCycles(int64_t wait_start_time,
                                     int64_t wait_end_time) {
   static const int64_t kMaxWaitTime =
-      std::numeric_limits<uint32_t>::max() >> LOCKWORD_RESERVED_SHIFT;
+      std::numeric_limits<uint32_t>::max() >> kLockwordReservedShift;
   int64_t scaled_wait_time =
-      (wait_end_time - wait_start_time) >> PROFILE_TIMESTAMP_SHIFT;
+      (wait_end_time - wait_start_time) >> kProfileTimestampShift;
 
   // Return a representation of the time spent waiting that can be stored in
   // the lock word's upper bits.
   uint32_t clamped = static_cast<uint32_t>(
-      std::min(scaled_wait_time, kMaxWaitTime) << LOCKWORD_RESERVED_SHIFT);
+      std::min(scaled_wait_time, kMaxWaitTime) << kLockwordReservedShift);
 
   if (clamped == 0) {
     return kSpinLockSleeper;  // Just wake waiters, but don't record contention.
   }
   // Bump up value if necessary to avoid returning kSpinLockSleeper.
   const uint32_t kMinWaitTime =
-      kSpinLockSleeper + (1 << LOCKWORD_RESERVED_SHIFT);
+      kSpinLockSleeper + (1 << kLockwordReservedShift);
   if (clamped == kSpinLockSleeper) {
     return kMinWaitTime;
   }
@@ -224,8 +221,7 @@
   // Cast to uint32_t first to ensure bits [63:32] are cleared.
   const uint64_t scaled_wait_time =
       static_cast<uint32_t>(lock_value & kWaitTimeMask);
-  return scaled_wait_time
-      << (PROFILE_TIMESTAMP_SHIFT - LOCKWORD_RESERVED_SHIFT);
+  return scaled_wait_time << (kProfileTimestampShift - kLockwordReservedShift);
 }
 
 }  // namespace base_internal
diff --git a/absl/base/internal/spinlock.h b/absl/base/internal/spinlock.h
index 24e2e9a..c73b5e0 100644
--- a/absl/base/internal/spinlock.h
+++ b/absl/base/internal/spinlock.h
@@ -15,11 +15,8 @@
 //
 
 //  Most users requiring mutual exclusion should use Mutex.
-//  SpinLock is provided for use in three situations:
+//  SpinLock is provided for use in two situations:
 //   - for use in code that Mutex itself depends on
-//   - to get a faster fast-path release under low contention (without an
-//     atomic read-modify-write) In return, SpinLock has worse behaviour under
-//     contention, which is why Mutex is preferred in most situations.
 //   - for async signal safety (see below)
 
 // SpinLock is async signal safe.  If a spinlock is used within a signal
@@ -36,6 +33,7 @@
 #include <atomic>
 
 #include "absl/base/attributes.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"
@@ -55,29 +53,22 @@
     ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
   }
 
-  // Special constructor for use with static SpinLock objects.  E.g.,
-  //
-  //    static SpinLock lock(base_internal::kLinkerInitialized);
-  //
-  // When initialized using this constructor, we depend on the fact
-  // that the linker has already initialized the memory appropriately. The lock
-  // is initialized in non-cooperative mode.
-  //
-  // A SpinLock constructed like this can be freely used from global
-  // initializers without worrying about the order in which global
-  // initializers run.
-  explicit SpinLock(base_internal::LinkerInitialized) {
-    // Does nothing; lockword_ is already initialized
-    ABSL_TSAN_MUTEX_CREATE(this, 0);
-  }
-
   // 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);
-  SpinLock(base_internal::LinkerInitialized,
-           base_internal::SchedulingMode mode);
 
+  // Constructor for global SpinLock instances.  See absl/base/const_init.h.
+  constexpr SpinLock(absl::ConstInitType, base_internal::SchedulingMode mode)
+      : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {}
+
+  // For global SpinLock instances prefer trivial destructor when possible.
+  // Default but non-trivial destructor in some build configurations causes an
+  // extra static initializer.
+#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
   ~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); }
+#else
+  ~SpinLock() = default;
+#endif
 
   // Acquire this SpinLock.
   inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
@@ -146,14 +137,27 @@
   //
   // bit[0] encodes whether a lock is being held.
   // bit[1] encodes whether a lock uses cooperative scheduling.
-  // bit[2] encodes whether a lock disables scheduling.
+  // bit[2] encodes whether the current lock holder disabled scheduling when
+  //        acquiring the lock. Only set when kSpinLockHeld is also set.
   // bit[3:31] encodes time a lock spent on waiting as a 29-bit unsigned int.
-  enum { kSpinLockHeld = 1 };
-  enum { kSpinLockCooperative = 2 };
-  enum { kSpinLockDisabledScheduling = 4 };
-  enum { kSpinLockSleeper = 8 };
-  enum { kWaitTimeMask =                      // Includes kSpinLockSleeper.
-    ~(kSpinLockHeld | kSpinLockCooperative | kSpinLockDisabledScheduling) };
+  //        This is set by the lock holder to indicate how long it waited on
+  //        the lock before eventually acquiring it. The number of cycles is
+  //        encoded as a 29-bit unsigned int, or in the case that the current
+  //        holder did not wait but another waiter is queued, the LSB
+  //        (kSpinLockSleeper) is set. The implementation does not explicitly
+  //        track the number of queued waiters beyond this. It must always be
+  //        assumed that waiters may exist if the current holder was required to
+  //        queue.
+  //
+  // Invariant: if the lock is not held, the value is either 0 or
+  // kSpinLockCooperative.
+  static constexpr uint32_t kSpinLockHeld = 1;
+  static constexpr uint32_t kSpinLockCooperative = 2;
+  static constexpr uint32_t kSpinLockDisabledScheduling = 4;
+  static constexpr uint32_t kSpinLockSleeper = 8;
+  // Includes kSpinLockSleeper.
+  static constexpr uint32_t kWaitTimeMask =
+      ~(kSpinLockHeld | kSpinLockCooperative | kSpinLockDisabledScheduling);
 
   // Returns true if the provided scheduling mode is cooperative.
   static constexpr bool IsCooperative(
@@ -162,7 +166,6 @@
   }
 
   uint32_t TryLockInternal(uint32_t lock_value, uint32_t wait_cycles);
-  void InitLinkerInitializedAndCooperative();
   void SlowLock() ABSL_ATTRIBUTE_COLD;
   void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD;
   uint32_t SpinLoop();
diff --git a/absl/base/internal/spinlock_akaros.inc b/absl/base/internal/spinlock_akaros.inc
index bc46894..7b0cada 100644
--- a/absl/base/internal/spinlock_akaros.inc
+++ b/absl/base/internal/spinlock_akaros.inc
@@ -20,7 +20,7 @@
 
 extern "C" {
 
-ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
     std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */,
     int /* loop */, absl::base_internal::SchedulingMode /* mode */) {
   // In Akaros, one must take care not to call anything that could cause a
@@ -29,7 +29,7 @@
   // arbitrary code.
 }
 
-ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
     std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
 
 }  // extern "C"
diff --git a/absl/base/internal/spinlock_linux.inc b/absl/base/internal/spinlock_linux.inc
index 323edd6..202f7cd 100644
--- a/absl/base/internal/spinlock_linux.inc
+++ b/absl/base/internal/spinlock_linux.inc
@@ -46,9 +46,17 @@
 #endif
 #endif
 
+#if defined(__NR_futex_time64) && !defined(SYS_futex_time64)
+#define SYS_futex_time64 __NR_futex_time64
+#endif
+
+#if defined(SYS_futex_time64) && !defined(SYS_futex)
+#define SYS_futex SYS_futex_time64
+#endif
+
 extern "C" {
 
-ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
     std::atomic<uint32_t> *w, uint32_t value, int loop,
     absl::base_internal::SchedulingMode) {
   absl::base_internal::ErrnoSaver errno_saver;
@@ -58,8 +66,8 @@
   syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, &tm);
 }
 
-ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(std::atomic<uint32_t> *w,
-                                                  bool all) {
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
+    std::atomic<uint32_t> *w, bool all) {
   syscall(SYS_futex, w, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, all ? INT_MAX : 1, 0);
 }
 
diff --git a/absl/base/internal/spinlock_posix.inc b/absl/base/internal/spinlock_posix.inc
index fcd21b1..4f6f887 100644
--- a/absl/base/internal/spinlock_posix.inc
+++ b/absl/base/internal/spinlock_posix.inc
@@ -25,7 +25,7 @@
 
 extern "C" {
 
-ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
     std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop,
     absl::base_internal::SchedulingMode /* mode */) {
   absl::base_internal::ErrnoSaver errno_saver;
@@ -40,7 +40,7 @@
   }
 }
 
-ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
     std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
 
 }  // extern "C"
diff --git a/absl/base/internal/spinlock_wait.h b/absl/base/internal/spinlock_wait.h
index 169bc74..579bd09 100644
--- a/absl/base/internal/spinlock_wait.h
+++ b/absl/base/internal/spinlock_wait.h
@@ -43,18 +43,16 @@
                       const SpinLockWaitTransition trans[],
                       SchedulingMode scheduling_mode);
 
-// If possible, wake some thread that has called SpinLockDelay(w, ...). If
-// "all" is true, wake all such threads.  This call is a hint, and on some
-// systems it may be a no-op; threads calling SpinLockDelay() will always wake
-// eventually even if SpinLockWake() is never called.
+// If possible, wake some thread that has called SpinLockDelay(w, ...). If `all`
+// is true, wake all such threads. On some systems, this may be a no-op; on
+// those systems, threads calling SpinLockDelay() will always wake eventually
+// even if SpinLockWake() is never called.
 void SpinLockWake(std::atomic<uint32_t> *w, bool all);
 
 // Wait for an appropriate spin delay on iteration "loop" of a
 // spin loop on location *w, whose previously observed value was "value".
 // SpinLockDelay() may do nothing, may yield the CPU, may sleep a clock tick,
-// or may wait for a delay that can be truncated by a call to SpinLockWake(w).
-// In all cases, it must return in bounded time even if SpinLockWake() is not
-// called.
+// or may wait for a call to SpinLockWake(w).
 void SpinLockDelay(std::atomic<uint32_t> *w, uint32_t value, int loop,
                    base_internal::SchedulingMode scheduling_mode);
 
@@ -73,21 +71,23 @@
 // By changing our extension points to be extern "C", we dodge this
 // check.
 extern "C" {
-void AbslInternalSpinLockWake(std::atomic<uint32_t> *w, bool all);
-void AbslInternalSpinLockDelay(
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(std::atomic<uint32_t> *w,
+                                                      bool all);
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
     std::atomic<uint32_t> *w, uint32_t value, int loop,
     absl::base_internal::SchedulingMode scheduling_mode);
 }
 
 inline void absl::base_internal::SpinLockWake(std::atomic<uint32_t> *w,
                                               bool all) {
-  AbslInternalSpinLockWake(w, all);
+  ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(w, all);
 }
 
 inline void absl::base_internal::SpinLockDelay(
     std::atomic<uint32_t> *w, uint32_t value, int loop,
     absl::base_internal::SchedulingMode scheduling_mode) {
-  AbslInternalSpinLockDelay(w, value, loop, scheduling_mode);
+  ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)
+  (w, value, loop, scheduling_mode);
 }
 
 #endif  // ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_
diff --git a/absl/base/internal/spinlock_win32.inc b/absl/base/internal/spinlock_win32.inc
index 78654b5..9d22481 100644
--- a/absl/base/internal/spinlock_win32.inc
+++ b/absl/base/internal/spinlock_win32.inc
@@ -20,9 +20,9 @@
 
 extern "C" {
 
-void AbslInternalSpinLockDelay(std::atomic<uint32_t>* /* lock_word */,
-                               uint32_t /* value */, int loop,
-                               absl::base_internal::SchedulingMode /* mode */) {
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
+    std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop,
+    absl::base_internal::SchedulingMode /* mode */) {
   if (loop == 0) {
   } else if (loop == 1) {
     Sleep(0);
@@ -31,7 +31,7 @@
   }
 }
 
-void AbslInternalSpinLockWake(std::atomic<uint32_t>* /* lock_word */,
-                              bool /* all */) {}
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
+    std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
 
 }  // extern "C"
diff --git a/absl/base/internal/strerror.cc b/absl/base/internal/strerror.cc
new file mode 100644
index 0000000..0d6226f
--- /dev/null
+++ b/absl/base/internal/strerror.cc
@@ -0,0 +1,88 @@
+// 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/base/internal/strerror.h"
+
+#include <array>
+#include <cerrno>
+#include <cstddef>
+#include <cstdio>
+#include <cstring>
+#include <string>
+#include <type_traits>
+
+#include "absl/base/internal/errno_saver.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+namespace {
+
+const char* StrErrorAdaptor(int errnum, char* buf, size_t buflen) {
+#if defined(_WIN32)
+  int rc = strerror_s(buf, buflen, errnum);
+  buf[buflen - 1] = '\0';  // guarantee NUL termination
+  if (rc == 0 && strncmp(buf, "Unknown error", buflen) == 0) *buf = '\0';
+  return buf;
+#else
+  // The type of `ret` is platform-specific; both of these branches must compile
+  // either way but only one will execute on any given platform:
+  auto ret = strerror_r(errnum, buf, buflen);
+  if (std::is_same<decltype(ret), int>::value) {
+    // XSI `strerror_r`; `ret` is `int`:
+    if (ret) *buf = '\0';
+    return buf;
+  } else {
+    // GNU `strerror_r`; `ret` is `char *`:
+    return reinterpret_cast<const char*>(ret);
+  }
+#endif
+}
+
+std::string StrErrorInternal(int errnum) {
+  char buf[100];
+  const char* str = StrErrorAdaptor(errnum, buf, sizeof buf);
+  if (*str == '\0') {
+    snprintf(buf, sizeof buf, "Unknown error %d", errnum);
+    str = buf;
+  }
+  return str;
+}
+
+// kSysNerr is the number of errors from a recent glibc. `StrError()` falls back
+// to `StrErrorAdaptor()` if the value is larger than this.
+constexpr int kSysNerr = 135;
+
+std::array<std::string, kSysNerr>* NewStrErrorTable() {
+  auto* table = new std::array<std::string, kSysNerr>;
+  for (int i = 0; i < static_cast<int>(table->size()); ++i) {
+    (*table)[i] = StrErrorInternal(i);
+  }
+  return table;
+}
+
+}  // namespace
+
+std::string StrError(int errnum) {
+  absl::base_internal::ErrnoSaver errno_saver;
+  static const auto* table = NewStrErrorTable();
+  if (errnum >= 0 && errnum < static_cast<int>(table->size())) {
+    return (*table)[errnum];
+  }
+  return StrErrorInternal(errnum);
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/base/internal/strerror.h b/absl/base/internal/strerror.h
new file mode 100644
index 0000000..3500973
--- /dev/null
+++ b/absl/base/internal/strerror.h
@@ -0,0 +1,39 @@
+// 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.
+
+#ifndef ABSL_BASE_INTERNAL_STRERROR_H_
+#define ABSL_BASE_INTERNAL_STRERROR_H_
+
+#include <string>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// A portable and thread-safe alternative to C89's `strerror`.
+//
+// The C89 specification of `strerror` is not suitable for use in a
+// multi-threaded application as the returned string may be changed by calls to
+// `strerror` from another thread.  The many non-stdlib alternatives differ
+// enough in their names, availability, and semantics to justify this wrapper
+// around them.  `errno` will not be modified by a call to `absl::StrError`.
+std::string StrError(int errnum);
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_STRERROR_H_
diff --git a/absl/random/mocking_bit_gen.cc b/absl/base/internal/strerror_benchmark.cc
similarity index 62%
copy from absl/random/mocking_bit_gen.cc
copy to absl/base/internal/strerror_benchmark.cc
index 6bb1e41..c9ab14a 100644
--- a/absl/random/mocking_bit_gen.cc
+++ b/absl/base/internal/strerror_benchmark.cc
@@ -1,5 +1,4 @@
-//
-// Copyright 2018 The Abseil Authors.
+// 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.
@@ -12,19 +11,19 @@
 // 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/random/mocking_bit_gen.h"
 
+#include <cerrno>
+#include <cstdio>
 #include <string>
 
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-MockingBitGen::~MockingBitGen() {
+#include "absl/base/internal/strerror.h"
+#include "benchmark/benchmark.h"
 
-  for (const auto& del : deleters_) {
-    del();
+namespace {
+void BM_AbslStrError(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(absl::base_internal::StrError(ERANGE));
   }
 }
-
-ABSL_NAMESPACE_END
-}  // namespace absl
+BENCHMARK(BM_AbslStrError);
+}  // namespace
diff --git a/absl/base/internal/strerror_test.cc b/absl/base/internal/strerror_test.cc
new file mode 100644
index 0000000..e32d5b5
--- /dev/null
+++ b/absl/base/internal/strerror_test.cc
@@ -0,0 +1,88 @@
+// 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/base/internal/strerror.h"
+
+#include <atomic>
+#include <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <string>
+#include <thread>  // NOLINT(build/c++11)
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/strings/match.h"
+
+namespace {
+using ::testing::AnyOf;
+using ::testing::Eq;
+
+TEST(StrErrorTest, ValidErrorCode) {
+  errno = ERANGE;
+  EXPECT_THAT(absl::base_internal::StrError(EDOM), Eq(strerror(EDOM)));
+  EXPECT_THAT(errno, Eq(ERANGE));
+}
+
+TEST(StrErrorTest, InvalidErrorCode) {
+  errno = ERANGE;
+  EXPECT_THAT(absl::base_internal::StrError(-1),
+              AnyOf(Eq("No error information"), Eq("Unknown error -1")));
+  EXPECT_THAT(errno, Eq(ERANGE));
+}
+
+TEST(StrErrorTest, MultipleThreads) {
+  // In this test, we will start up 2 threads and have each one call
+  // StrError 1000 times, each time with a different errnum.  We
+  // expect that StrError(errnum) will return a string equal to the
+  // one returned by strerror(errnum), if the code is known.  Since
+  // strerror is known to be thread-hostile, collect all the expected
+  // strings up front.
+  const int kNumCodes = 1000;
+  std::vector<std::string> expected_strings(kNumCodes);
+  for (int i = 0; i < kNumCodes; ++i) {
+    expected_strings[i] = strerror(i);
+  }
+
+  std::atomic_int counter(0);
+  auto thread_fun = [&]() {
+    for (int i = 0; i < kNumCodes; ++i) {
+      ++counter;
+      errno = ERANGE;
+      const std::string value = absl::base_internal::StrError(i);
+      // EXPECT_* could change errno. Stash it first.
+      int check_err = errno;
+      EXPECT_THAT(check_err, Eq(ERANGE));
+      // Only the GNU implementation is guaranteed to provide the
+      // string "Unknown error nnn". POSIX doesn't say anything.
+      if (!absl::StartsWith(value, "Unknown error ")) {
+        EXPECT_THAT(value, Eq(expected_strings[i]));
+      }
+    }
+  };
+
+  const int kNumThreads = 100;
+  std::vector<std::thread> threads;
+  for (int i = 0; i < kNumThreads; ++i) {
+    threads.push_back(std::thread(thread_fun));
+  }
+  for (auto& thread : threads) {
+    thread.join();
+  }
+
+  EXPECT_THAT(counter, Eq(kNumThreads * kNumCodes));
+}
+
+}  // namespace
diff --git a/absl/base/internal/sysinfo.cc b/absl/base/internal/sysinfo.cc
index a0930e9..4a3b205 100644
--- a/absl/base/internal/sysinfo.cc
+++ b/absl/base/internal/sysinfo.cc
@@ -39,6 +39,7 @@
 #endif
 
 #include <string.h>
+
 #include <cassert>
 #include <cstdint>
 #include <cstdio>
@@ -50,9 +51,11 @@
 #include <vector>
 
 #include "absl/base/call_once.h"
+#include "absl/base/config.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/internal/spinlock.h"
 #include "absl/base/internal/unscaledcycleclock.h"
+#include "absl/base/thread_annotations.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -72,6 +75,12 @@
 #if defined(_WIN32)
 
 static double GetNominalCPUFrequency() {
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
+    !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+  // UWP apps don't have access to the registry and currently don't provide an
+  // API informing about CPU nominal frequency.
+  return 1.0;
+#else
 #pragma comment(lib, "advapi32.lib")  // For Reg* functions.
   HKEY key;
   // Use the Reg* functions rather than the SH functions because shlwapi.dll
@@ -91,6 +100,7 @@
     }
   }
   return 1.0;
+#endif  // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP
 }
 
 #elif defined(CTL_HW) && defined(HW_CPU_FREQ)
@@ -336,15 +346,16 @@
 #else
 
 // Fallback implementation of GetTID using pthread_getspecific.
-static once_flag tid_once;
-static pthread_key_t tid_key;
-static absl::base_internal::SpinLock tid_lock(
-    absl::base_internal::kLinkerInitialized);
+ABSL_CONST_INIT static once_flag tid_once;
+ABSL_CONST_INIT static pthread_key_t tid_key;
+ABSL_CONST_INIT static absl::base_internal::SpinLock tid_lock(
+    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
 
 // We set a bit per thread in this array to indicate that an ID is in
 // use. ID 0 is unused because it is the default value returned by
 // pthread_getspecific().
-static std::vector<uint32_t>* tid_array GUARDED_BY(tid_lock) = nullptr;
+ABSL_CONST_INIT static std::vector<uint32_t> *tid_array
+    ABSL_GUARDED_BY(tid_lock) = nullptr;
 static constexpr int kBitsPerWord = 32;  // tid_array is uint32_t.
 
 // Returns the TID to tid_array.
@@ -411,6 +422,18 @@
 
 #endif
 
+// GetCachedTID() caches the thread ID in thread-local storage (which is a
+// userspace construct) to avoid unnecessary system calls. Without this caching,
+// it can take roughly 98ns, while it takes roughly 1ns with this caching.
+pid_t GetCachedTID() {
+#ifdef ABSL_HAVE_THREAD_LOCAL
+  static thread_local pid_t thread_id = GetTID();
+  return thread_id;
+#else
+  return GetTID();
+#endif  // ABSL_HAVE_THREAD_LOCAL
+}
+
 }  // namespace base_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/base/internal/sysinfo.h b/absl/base/internal/sysinfo.h
index 7246d5d..119cf1f 100644
--- a/absl/base/internal/sysinfo.h
+++ b/absl/base/internal/sysinfo.h
@@ -30,6 +30,7 @@
 
 #include <cstdint>
 
+#include "absl/base/config.h"
 #include "absl/base/port.h"
 
 namespace absl {
@@ -59,6 +60,13 @@
 #endif
 pid_t GetTID();
 
+// Like GetTID(), but caches the result in thread-local storage in order
+// to avoid unnecessary system calls. Note that there are some cases where
+// one must call through to GetTID directly, which is why this exists as a
+// separate function. For example, GetCachedTID() is not safe to call in
+// an asynchronous signal-handling context nor right after a call to fork().
+pid_t GetCachedTID();
+
 }  // namespace base_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/base/internal/sysinfo_test.cc b/absl/base/internal/sysinfo_test.cc
index fa8b88b..5f9e45f 100644
--- a/absl/base/internal/sysinfo_test.cc
+++ b/absl/base/internal/sysinfo_test.cc
@@ -37,17 +37,28 @@
       << "NumCPUs() should not have the default value of 0";
 }
 
+// Ensure that NominalCPUFrequency returns a reasonable value, or 1.00 on
+// platforms where the CPU frequency is not available through sysfs.
+//
+// POWER is particularly problematic here; some Linux kernels expose the CPU
+// frequency, while others do not. Since we can't predict a priori what a given
+// machine is going to do, just disable this test on POWER on Linux.
+#if !(defined(__linux) && (defined(__ppc64__) || defined(__PPC64__)))
 TEST(SysinfoTest, NominalCPUFrequency) {
-#if !(defined(__aarch64__) && defined(__linux__)) && !defined(__EMSCRIPTEN__)
-  EXPECT_GE(NominalCPUFrequency(), 1000.0)
-      << "NominalCPUFrequency() did not return a reasonable value";
-#else
-  // Aarch64 cannot read the CPU frequency from sysfs, so we get back 1.0.
-  // Emscripten does not have a sysfs to read from at all.
+  // Linux only exposes the CPU frequency on certain architectures, and
+  // Emscripten doesn't expose it at all.
+#if defined(__linux__) &&                                                  \
+        (defined(__aarch64__) || defined(__hppa__) || defined(__mips__) || \
+         defined(__riscv) || defined(__s390x__)) ||                        \
+    defined(__EMSCRIPTEN__)
   EXPECT_EQ(NominalCPUFrequency(), 1.0)
       << "CPU frequency detection was fixed! Please update unittest.";
+#else
+  EXPECT_GE(NominalCPUFrequency(), 1000.0)
+      << "NominalCPUFrequency() did not return a reasonable value";
 #endif
 }
+#endif
 
 TEST(SysinfoTest, GetTID) {
   EXPECT_EQ(GetTID(), GetTID());  // Basic compile and equality test.
diff --git a/absl/base/internal/thread_identity.cc b/absl/base/internal/thread_identity.cc
index d63a04a..9950e63 100644
--- a/absl/base/internal/thread_identity.cc
+++ b/absl/base/internal/thread_identity.cc
@@ -23,6 +23,7 @@
 #include <cassert>
 #include <memory>
 
+#include "absl/base/attributes.h"
 #include "absl/base/call_once.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/internal/spinlock.h"
@@ -53,9 +54,11 @@
 // exist within a process (via dlopen() or similar), references to
 // thread_identity_ptr from each instance of the code will refer to
 // *different* instances of this ptr.
-#ifdef __GNUC__
+// Apple platforms have the visibility attribute, but issue a compile warning
+// that protected visibility is unsupported.
+#if ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__)
 __attribute__((visibility("protected")))
-#endif  // __GNUC__
+#endif  // ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__)
 #if ABSL_PER_THREAD_TLS
 // Prefer __thread to thread_local as benchmarks indicate it is a bit faster.
 ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr = nullptr;
@@ -117,10 +120,10 @@
     ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
 
 // Please see the comment on `CurrentThreadIdentityIfPresent` in
-// thread_identity.h. Because DLLs cannot expose thread_local variables in
-// headers, we opt for the correct-but-slower option of placing the definition
-// of this function only in a translation unit inside DLL.
-#if defined(ABSL_BUILD_DLL) || defined(ABSL_CONSUME_DLL)
+// thread_identity.h. When we cannot expose thread_local variables in
+// headers, we opt for the correct-but-slower option of not inlining this
+// function.
+#ifndef ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT
 ThreadIdentity* CurrentThreadIdentityIfPresent() { return thread_identity_ptr; }
 #endif
 #endif
diff --git a/absl/base/internal/thread_identity.h b/absl/base/internal/thread_identity.h
index ceb109b..6e25b92 100644
--- a/absl/base/internal/thread_identity.h
+++ b/absl/base/internal/thread_identity.h
@@ -32,6 +32,7 @@
 
 #include "absl/base/config.h"
 #include "absl/base/internal/per_thread_tls.h"
+#include "absl/base/optimization.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -69,30 +70,28 @@
                          // is using this PerThreadSynch as a terminator.  Its
                          // skip field must not be filled in because the loop
                          // might then skip over the terminator.
-
-  // The wait parameters of the current wait.  waitp is null if the
-  // thread is not waiting. Transitions from null to non-null must
-  // occur before the enqueue commit point (state = kQueued in
-  // Enqueue() and CondVarEnqueue()). Transitions from non-null to
-  // null must occur after the wait is finished (state = kAvailable in
-  // Mutex::Block() and CondVar::WaitCommon()). This field may be
-  // changed only by the thread that describes this PerThreadSynch.  A
-  // special case is Fer(), which calls Enqueue() on another thread,
-  // but with an identical SynchWaitParams pointer, thus leaving the
-  // pointer unchanged.
-  SynchWaitParams *waitp;
-
-  bool suppress_fatal_errors;  // If true, try to proceed even in the face of
-                               // broken invariants.  This is used within fatal
-                               // signal handlers to improve the chances of
-                               // debug logging information being output
-                               // successfully.
-
-  intptr_t readers;     // Number of readers in mutex.
-  int priority;         // Priority of thread (updated every so often).
-
-  // When priority will next be read (cycles).
-  int64_t next_priority_read_cycles;
+  bool wake;             // This thread is to be woken from a Mutex.
+  // If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the
+  // waiter is waiting on the mutex as part of a CV Wait or Mutex Await.
+  //
+  // The value of "x->cond_waiter" is meaningless if "x" is not on a
+  // Mutex waiter list.
+  bool cond_waiter;
+  bool maybe_unlocking;  // Valid at head of Mutex waiter queue;
+                         // true if UnlockSlow could be searching
+                         // for a waiter to wake.  Used for an optimization
+                         // in Enqueue().  true is always a valid value.
+                         // Can be reset to false when the unlocker or any
+                         // writer releases the lock, or a reader fully
+                         // releases the lock.  It may not be set to false
+                         // by a reader that decrements the count to
+                         // non-zero. protected by mutex spinlock
+  bool suppress_fatal_errors;  // If true, try to proceed even in the face
+                               // of broken invariants.  This is used within
+                               // fatal signal handlers to improve the
+                               // chances of debug logging information being
+                               // output successfully.
+  int priority;                // Priority of thread (updated every so often).
 
   // State values:
   //   kAvailable: This PerThreadSynch is available.
@@ -111,30 +110,30 @@
   };
   std::atomic<State> state;
 
-  bool maybe_unlocking;  // Valid at head of Mutex waiter queue;
-                         // true if UnlockSlow could be searching
-                         // for a waiter to wake.  Used for an optimization
-                         // in Enqueue().  true is always a valid value.
-                         // Can be reset to false when the unlocker or any
-                         // writer releases the lock, or a reader fully releases
-                         // the lock.  It may not be set to false by a reader
-                         // that decrements the count to non-zero.
-                         // protected by mutex spinlock
+  // The wait parameters of the current wait.  waitp is null if the
+  // thread is not waiting. Transitions from null to non-null must
+  // occur before the enqueue commit point (state = kQueued in
+  // Enqueue() and CondVarEnqueue()). Transitions from non-null to
+  // null must occur after the wait is finished (state = kAvailable in
+  // Mutex::Block() and CondVar::WaitCommon()). This field may be
+  // changed only by the thread that describes this PerThreadSynch.  A
+  // special case is Fer(), which calls Enqueue() on another thread,
+  // but with an identical SynchWaitParams pointer, thus leaving the
+  // pointer unchanged.
+  SynchWaitParams* waitp;
 
-  bool wake;  // This thread is to be woken from a Mutex.
+  intptr_t readers;     // Number of readers in mutex.
 
-  // If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the
-  // waiter is waiting on the mutex as part of a CV Wait or Mutex Await.
-  //
-  // The value of "x->cond_waiter" is meaningless if "x" is not on a
-  // Mutex waiter list.
-  bool cond_waiter;
+  // When priority will next be read (cycles).
+  int64_t next_priority_read_cycles;
 
   // Locks held; used during deadlock detection.
   // Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity().
   SynchLocksHeld *all_locks;
 };
 
+// The instances of this class are allocated in NewThreadIdentity() with an
+// alignment of PerThreadSynch::kAlignment.
 struct ThreadIdentity {
   // Must be the first member.  The Mutex implementation requires that
   // the PerThreadSynch object associated with each thread is
@@ -144,7 +143,7 @@
 
   // Private: Reserved for absl::synchronization_internal::Waiter.
   struct WaiterState {
-    char data[128];
+    alignas(void*) char data[128];
   } waiter_state;
 
   // Used by PerThreadSem::{Get,Set}ThreadBlockedCounter().
@@ -212,7 +211,9 @@
 #define ABSL_THREAD_IDENTITY_MODE ABSL_FORCE_THREAD_IDENTITY_MODE
 #elif defined(_WIN32) && !defined(__MINGW32__)
 #define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
-#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \
+#elif defined(__APPLE__) && defined(ABSL_HAVE_THREAD_LOCAL)
+#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
+#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) &&        \
     (__GOOGLE_GRTE_VERSION__ >= 20140228L)
 // Support for async-safe TLS was specifically added in GRTEv4.  It's not
 // present in the upstream eglibc.
@@ -235,13 +236,18 @@
 #error Thread-local storage not detected on this platform
 #endif
 
-// thread_local variables cannot be in headers exposed by DLLs. However, it is
-// important for performance reasons in general that
-// `CurrentThreadIdentityIfPresent` be inlined. This is not possible across a
-// DLL boundary so, with DLLs, we opt to have the function not be inlined. Note
+// thread_local variables cannot be in headers exposed by DLLs or in certain
+// build configurations on Apple platforms. However, it is important for
+// performance reasons in general that `CurrentThreadIdentityIfPresent` be
+// inlined. In the other cases we opt to have the function not be inlined. Note
 // that `CurrentThreadIdentityIfPresent` is declared above so we can exclude
-// this entire inline definition when compiling as a DLL.
-#if !defined(ABSL_BUILD_DLL) && !defined(ABSL_CONSUME_DLL)
+// this entire inline definition.
+#if !defined(__APPLE__) && !defined(ABSL_BUILD_DLL) && \
+    !defined(ABSL_CONSUME_DLL)
+#define ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT 1
+#endif
+
+#ifdef ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT
 inline ThreadIdentity* CurrentThreadIdentityIfPresent() {
   return thread_identity_ptr;
 }
diff --git a/absl/base/internal/thread_identity_test.cc b/absl/base/internal/thread_identity_test.cc
index 3685779..46a6f74 100644
--- a/absl/base/internal/thread_identity_test.cc
+++ b/absl/base/internal/thread_identity_test.cc
@@ -21,6 +21,7 @@
 #include "absl/base/attributes.h"
 #include "absl/base/internal/spinlock.h"
 #include "absl/base/macros.h"
+#include "absl/base/thread_annotations.h"
 #include "absl/synchronization/internal/per_thread_sem.h"
 #include "absl/synchronization/mutex.h"
 
@@ -29,10 +30,9 @@
 namespace base_internal {
 namespace {
 
-// protects num_identities_reused
-static absl::base_internal::SpinLock map_lock(
-    absl::base_internal::kLinkerInitialized);
-static int num_identities_reused;
+ABSL_CONST_INIT static absl::base_internal::SpinLock map_lock(
+    absl::kConstInit, 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);
 
@@ -75,7 +75,7 @@
   // - If a thread implementation chooses to recycle threads, that
   //   correct re-initialization occurs.
   static const int kNumLoops = 3;
-  static const int kNumThreads = 400;
+  static const int kNumThreads = 32;
   for (int iter = 0; iter < kNumLoops; iter++) {
     std::vector<std::thread> threads;
     for (int i = 0; i < kNumThreads; ++i) {
@@ -90,6 +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);
   EXPECT_LT(kNumThreads, num_identities_reused);
 }
 
diff --git a/absl/base/internal/throw_delegate.cc b/absl/base/internal/throw_delegate.cc
index c055f75..c260ff1 100644
--- a/absl/base/internal/throw_delegate.cc
+++ b/absl/base/internal/throw_delegate.cc
@@ -18,6 +18,7 @@
 #include <functional>
 #include <new>
 #include <stdexcept>
+
 #include "absl/base/config.h"
 #include "absl/base/internal/raw_logging.h"
 
@@ -25,83 +26,186 @@
 ABSL_NAMESPACE_BEGIN
 namespace base_internal {
 
+// NOTE: The various STL exception throwing functions are placed within the
+// #ifdef blocks so the symbols aren't exposed on platforms that don't support
+// them, such as the Android NDK. For example, ANGLE fails to link when building
+// within AOSP without them, since the STL functions don't exist.
 namespace {
+#ifdef ABSL_HAVE_EXCEPTIONS
 template <typename T>
 [[noreturn]] void Throw(const T& error) {
-#ifdef ABSL_HAVE_EXCEPTIONS
   throw error;
-#else
-  ABSL_RAW_LOG(FATAL, "%s", error.what());
-  std::abort();
-#endif
 }
+#endif
 }  // namespace
 
 void ThrowStdLogicError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::logic_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
 }
 void ThrowStdLogicError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::logic_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
 }
 void ThrowStdInvalidArgument(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::invalid_argument(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
 }
 void ThrowStdInvalidArgument(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::invalid_argument(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
 }
 
 void ThrowStdDomainError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::domain_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
 }
 void ThrowStdDomainError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::domain_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
 }
 
 void ThrowStdLengthError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::length_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
 }
 void ThrowStdLengthError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::length_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
 }
 
 void ThrowStdOutOfRange(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::out_of_range(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
 }
 void ThrowStdOutOfRange(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::out_of_range(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
 }
 
 void ThrowStdRuntimeError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::runtime_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
 }
 void ThrowStdRuntimeError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::runtime_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
 }
 
 void ThrowStdRangeError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::range_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
 }
 void ThrowStdRangeError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::range_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
 }
 
 void ThrowStdOverflowError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::overflow_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
 }
 void ThrowStdOverflowError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::overflow_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
 }
 
 void ThrowStdUnderflowError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::underflow_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
 }
 void ThrowStdUnderflowError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::underflow_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
 }
 
-void ThrowStdBadFunctionCall() { Throw(std::bad_function_call()); }
+void ThrowStdBadFunctionCall() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::bad_function_call());
+#else
+  std::abort();
+#endif
+}
 
-void ThrowStdBadAlloc() { Throw(std::bad_alloc()); }
+void ThrowStdBadAlloc() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::bad_alloc());
+#else
+  std::abort();
+#endif
+}
 
 }  // namespace base_internal
 ABSL_NAMESPACE_END
diff --git a/absl/base/internal/tsan_mutex_interface.h b/absl/base/internal/tsan_mutex_interface.h
index 2a51060..39207d8 100644
--- a/absl/base/internal/tsan_mutex_interface.h
+++ b/absl/base/internal/tsan_mutex_interface.h
@@ -19,6 +19,8 @@
 #ifndef ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
 #define ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
 
+#include "absl/base/config.h"
+
 // ABSL_INTERNAL_HAVE_TSAN_INTERFACE
 // Macro intended only for internal use.
 //
@@ -28,7 +30,7 @@
 #error "ABSL_INTERNAL_HAVE_TSAN_INTERFACE cannot be directly set."
 #endif
 
-#if defined(THREAD_SANITIZER) && defined(__has_include)
+#if defined(ABSL_HAVE_THREAD_SANITIZER) && defined(__has_include)
 #if __has_include(<sanitizer/tsan_interface.h>)
 #define ABSL_INTERNAL_HAVE_TSAN_INTERFACE 1
 #endif
diff --git a/absl/base/internal/unaligned_access.h b/absl/base/internal/unaligned_access.h
index 6be56c8..093dd9b 100644
--- a/absl/base/internal/unaligned_access.h
+++ b/absl/base/internal/unaligned_access.h
@@ -31,80 +31,6 @@
 // The unaligned API is C++ only.  The declarations use C++ features
 // (namespaces, inline) which are absent or incompatible in C.
 #if defined(__cplusplus)
-
-#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||\
-    defined(MEMORY_SANITIZER)
-// Consider we have an unaligned load/store of 4 bytes from address 0x...05.
-// AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
-// will miss a bug if 08 is the first unaddressable byte.
-// ThreadSanitizer will also treat this as a 3-byte access to 05:07 and will
-// miss a race between this access and some other accesses to 08.
-// MemorySanitizer will correctly propagate the shadow on unaligned stores
-// and correctly report bugs on unaligned loads, but it may not properly
-// update and report the origin of the uninitialized memory.
-// For all three tools, replacing an unaligned access with a tool-specific
-// callback solves the problem.
-
-// Make sure uint16_t/uint32_t/uint64_t are defined.
-#include <stdint.h>
-
-extern "C" {
-uint16_t __sanitizer_unaligned_load16(const void *p);
-uint32_t __sanitizer_unaligned_load32(const void *p);
-uint64_t __sanitizer_unaligned_load64(const void *p);
-void __sanitizer_unaligned_store16(void *p, uint16_t v);
-void __sanitizer_unaligned_store32(void *p, uint32_t v);
-void __sanitizer_unaligned_store64(void *p, uint64_t v);
-}  // extern "C"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace base_internal {
-
-inline uint16_t UnalignedLoad16(const void *p) {
-  return __sanitizer_unaligned_load16(p);
-}
-
-inline uint32_t UnalignedLoad32(const void *p) {
-  return __sanitizer_unaligned_load32(p);
-}
-
-inline uint64_t UnalignedLoad64(const void *p) {
-  return __sanitizer_unaligned_load64(p);
-}
-
-inline void UnalignedStore16(void *p, uint16_t v) {
-  __sanitizer_unaligned_store16(p, v);
-}
-
-inline void UnalignedStore32(void *p, uint32_t v) {
-  __sanitizer_unaligned_store32(p, v);
-}
-
-inline void UnalignedStore64(void *p, uint64_t v) {
-  __sanitizer_unaligned_store64(p, v);
-}
-
-}  // namespace base_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
-  (absl::base_internal::UnalignedLoad16(_p))
-#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
-  (absl::base_internal::UnalignedLoad32(_p))
-#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \
-  (absl::base_internal::UnalignedLoad64(_p))
-
-#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
-  (absl::base_internal::UnalignedStore16(_p, _val))
-#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
-  (absl::base_internal::UnalignedStore32(_p, _val))
-#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
-  (absl::base_internal::UnalignedStore64(_p, _val))
-
-#else
-
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace base_internal {
@@ -151,8 +77,6 @@
 #define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
   (absl::base_internal::UnalignedStore64(_p, _val))
 
-#endif
-
 #endif  // defined(__cplusplus), end of unaligned API
 
 #endif  // ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
diff --git a/absl/base/internal/unique_small_name_test.cc b/absl/base/internal/unique_small_name_test.cc
new file mode 100644
index 0000000..ff8c2b3
--- /dev/null
+++ b/absl/base/internal/unique_small_name_test.cc
@@ -0,0 +1,77 @@
+// 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 "gtest/gtest.h"
+#include "absl/base/optimization.h"
+#include "absl/strings/string_view.h"
+
+// This test by itself does not do anything fancy, but it serves as binary I can
+// query in shell test.
+
+namespace {
+
+template <class T>
+void DoNotOptimize(const T& var) {
+#ifdef __GNUC__
+  asm volatile("" : "+m"(const_cast<T&>(var)));
+#else
+  std::cout << (void*)&var;
+#endif
+}
+
+int very_long_int_variable_name ABSL_INTERNAL_UNIQUE_SMALL_NAME() = 0;
+char very_long_str_variable_name[] ABSL_INTERNAL_UNIQUE_SMALL_NAME() = "abc";
+
+TEST(UniqueSmallName, NonAutomaticVar) {
+  EXPECT_EQ(very_long_int_variable_name, 0);
+  EXPECT_EQ(absl::string_view(very_long_str_variable_name), "abc");
+}
+
+int VeryLongFreeFunctionName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
+
+TEST(UniqueSmallName, FreeFunction) {
+  DoNotOptimize(&VeryLongFreeFunctionName);
+
+  EXPECT_EQ(VeryLongFreeFunctionName(), 456);
+}
+
+int VeryLongFreeFunctionName() { return 456; }
+
+struct VeryLongStructName {
+  explicit VeryLongStructName(int i);
+
+  int VeryLongMethodName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
+
+  static int VeryLongStaticMethodName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
+
+ private:
+  int fld;
+};
+
+TEST(UniqueSmallName, Struct) {
+  VeryLongStructName var(10);
+
+  DoNotOptimize(var);
+  DoNotOptimize(&VeryLongStructName::VeryLongMethodName);
+  DoNotOptimize(&VeryLongStructName::VeryLongStaticMethodName);
+
+  EXPECT_EQ(var.VeryLongMethodName(), 10);
+  EXPECT_EQ(VeryLongStructName::VeryLongStaticMethodName(), 123);
+}
+
+VeryLongStructName::VeryLongStructName(int i) : fld(i) {}
+int VeryLongStructName::VeryLongMethodName() { return fld; }
+int VeryLongStructName::VeryLongStaticMethodName() { return 123; }
+
+}  // namespace
diff --git a/absl/base/internal/unscaledcycleclock.cc b/absl/base/internal/unscaledcycleclock.cc
index f1e7bbe..1545288 100644
--- a/absl/base/internal/unscaledcycleclock.cc
+++ b/absl/base/internal/unscaledcycleclock.cc
@@ -123,9 +123,7 @@
 
 #pragma intrinsic(__rdtsc)
 
-int64_t UnscaledCycleClock::Now() {
-  return __rdtsc();
-}
+int64_t UnscaledCycleClock::Now() { return __rdtsc(); }
 
 double UnscaledCycleClock::Frequency() {
   return base_internal::NominalCPUFrequency();
diff --git a/absl/base/internal/unscaledcycleclock.h b/absl/base/internal/unscaledcycleclock.h
index cdce9bf..82f2c87 100644
--- a/absl/base/internal/unscaledcycleclock.h
+++ b/absl/base/internal/unscaledcycleclock.h
@@ -15,8 +15,8 @@
 // UnscaledCycleClock
 //    An UnscaledCycleClock yields the value and frequency of a cycle counter
 //    that increments at a rate that is approximately constant.
-//    This class is for internal / whitelisted use only, you should consider
-//    using CycleClock instead.
+//    This class is for internal use only, you should consider using CycleClock
+//    instead.
 //
 // Notes:
 // The cycle counter frequency is not necessarily the core clock frequency.
@@ -109,7 +109,7 @@
   // value.
   static double Frequency();
 
-  // Whitelisted friends.
+  // Allowed users
   friend class base_internal::CycleClock;
   friend class time_internal::UnscaledCycleClockWrapperForGetCurrentTime;
   friend class base_internal::UnscaledCycleClockWrapperForInitializeFrequency;
diff --git a/absl/base/invoke_test.cc b/absl/base/invoke_test.cc
index 6aa613c..bcdef36 100644
--- a/absl/base/invoke_test.cc
+++ b/absl/base/invoke_test.cc
@@ -86,71 +86,73 @@
   int member;
 };
 
-// CallMaybeWithArg(f) resolves either to Invoke(f) or Invoke(f, 42), depending
+// CallMaybeWithArg(f) resolves either to invoke(f) or invoke(f, 42), depending
 // on which one is valid.
 template <typename F>
-decltype(Invoke(std::declval<const F&>())) CallMaybeWithArg(const F& f) {
-  return Invoke(f);
+decltype(base_internal::invoke(std::declval<const F&>())) CallMaybeWithArg(
+    const F& f) {
+  return base_internal::invoke(f);
 }
 
 template <typename F>
-decltype(Invoke(std::declval<const F&>(), 42)) CallMaybeWithArg(const F& f) {
-  return Invoke(f, 42);
+decltype(base_internal::invoke(std::declval<const F&>(), 42)) CallMaybeWithArg(
+    const F& f) {
+  return base_internal::invoke(f, 42);
 }
 
 TEST(InvokeTest, Function) {
-  EXPECT_EQ(1, Invoke(Function, 3, 2));
-  EXPECT_EQ(1, Invoke(&Function, 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(Function, 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Function, 3, 2));
 }
 
 TEST(InvokeTest, NonCopyableArgument) {
-  EXPECT_EQ(42, Invoke(Sink, make_unique<int>(42)));
+  EXPECT_EQ(42, base_internal::invoke(Sink, make_unique<int>(42)));
 }
 
 TEST(InvokeTest, NonCopyableResult) {
-  EXPECT_THAT(Invoke(Factory, 42), ::testing::Pointee(42));
+  EXPECT_THAT(base_internal::invoke(Factory, 42), ::testing::Pointee(42));
 }
 
-TEST(InvokeTest, VoidResult) {
-  Invoke(NoOp);
-}
+TEST(InvokeTest, VoidResult) { base_internal::invoke(NoOp); }
 
 TEST(InvokeTest, ConstFunctor) {
-  EXPECT_EQ(1, Invoke(ConstFunctor(), 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(ConstFunctor(), 3, 2));
 }
 
 TEST(InvokeTest, MutableFunctor) {
   MutableFunctor f;
-  EXPECT_EQ(1, Invoke(f, 3, 2));
-  EXPECT_EQ(1, Invoke(MutableFunctor(), 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(f, 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(MutableFunctor(), 3, 2));
 }
 
 TEST(InvokeTest, EphemeralFunctor) {
   EphemeralFunctor f;
-  EXPECT_EQ(1, Invoke(std::move(f), 3, 2));
-  EXPECT_EQ(1, Invoke(EphemeralFunctor(), 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(std::move(f), 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(EphemeralFunctor(), 3, 2));
 }
 
 TEST(InvokeTest, OverloadedFunctor) {
   OverloadedFunctor f;
   const OverloadedFunctor& cf = f;
 
-  EXPECT_EQ("&", Invoke(f));
-  EXPECT_EQ("& 42", Invoke(f, " 42"));
+  EXPECT_EQ("&", base_internal::invoke(f));
+  EXPECT_EQ("& 42", base_internal::invoke(f, " 42"));
 
-  EXPECT_EQ("const&", Invoke(cf));
-  EXPECT_EQ("const& 42", Invoke(cf, " 42"));
+  EXPECT_EQ("const&", base_internal::invoke(cf));
+  EXPECT_EQ("const& 42", base_internal::invoke(cf, " 42"));
 
-  EXPECT_EQ("&&", Invoke(std::move(f)));
-  EXPECT_EQ("&& 42", Invoke(std::move(f), " 42"));
+  EXPECT_EQ("&&", base_internal::invoke(std::move(f)));
+
+  OverloadedFunctor f2;
+  EXPECT_EQ("&& 42", base_internal::invoke(std::move(f2), " 42"));
 }
 
 TEST(InvokeTest, ReferenceWrapper) {
   ConstFunctor cf;
   MutableFunctor mf;
-  EXPECT_EQ(1, Invoke(std::cref(cf), 3, 2));
-  EXPECT_EQ(1, Invoke(std::ref(cf), 3, 2));
-  EXPECT_EQ(1, Invoke(std::ref(mf), 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(std::cref(cf), 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(std::ref(cf), 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(std::ref(mf), 3, 2));
 }
 
 TEST(InvokeTest, MemberFunction) {
@@ -158,58 +160,62 @@
   std::unique_ptr<const Class> cp(new Class);
   std::unique_ptr<volatile Class> vp(new Class);
 
-  EXPECT_EQ(1, Invoke(&Class::Method, p, 3, 2));
-  EXPECT_EQ(1, Invoke(&Class::Method, p.get(), 3, 2));
-  EXPECT_EQ(1, Invoke(&Class::Method, *p, 3, 2));
-  EXPECT_EQ(1, Invoke(&Class::RefMethod, p, 3, 2));
-  EXPECT_EQ(1, Invoke(&Class::RefMethod, p.get(), 3, 2));
-  EXPECT_EQ(1, Invoke(&Class::RefMethod, *p, 3, 2));
-  EXPECT_EQ(1, Invoke(&Class::RefRefMethod, std::move(*p), 3, 2));  // NOLINT
-  EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, p, 3, 2));
-  EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, p.get(), 3, 2));
-  EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, *p, 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::Method, p, 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::Method, p.get(), 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::Method, *p, 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::RefMethod, p, 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::RefMethod, p.get(), 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::RefMethod, *p, 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::RefRefMethod, std::move(*p), 3,
+                                     2));  // NOLINT
+  EXPECT_EQ(1, base_internal::invoke(&Class::NoExceptMethod, p, 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::NoExceptMethod, p.get(), 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::NoExceptMethod, *p, 3, 2));
 
-  EXPECT_EQ(1, Invoke(&Class::ConstMethod, p, 3, 2));
-  EXPECT_EQ(1, Invoke(&Class::ConstMethod, p.get(), 3, 2));
-  EXPECT_EQ(1, Invoke(&Class::ConstMethod, *p, 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, p, 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, p.get(), 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, *p, 3, 2));
 
-  EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp, 3, 2));
-  EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp.get(), 3, 2));
-  EXPECT_EQ(1, Invoke(&Class::ConstMethod, *cp, 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, cp, 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, cp.get(), 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, *cp, 3, 2));
 
-  EXPECT_EQ(1, Invoke(&Class::VolatileMethod, p, 3, 2));
-  EXPECT_EQ(1, Invoke(&Class::VolatileMethod, p.get(), 3, 2));
-  EXPECT_EQ(1, Invoke(&Class::VolatileMethod, *p, 3, 2));
-  EXPECT_EQ(1, Invoke(&Class::VolatileMethod, vp, 3, 2));
-  EXPECT_EQ(1, Invoke(&Class::VolatileMethod, vp.get(), 3, 2));
-  EXPECT_EQ(1, Invoke(&Class::VolatileMethod, *vp, 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, p, 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, p.get(), 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, *p, 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, vp, 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, vp.get(), 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, *vp, 3, 2));
 
-  EXPECT_EQ(1, Invoke(&Class::Method, make_unique<Class>(), 3, 2));
-  EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<Class>(), 3, 2));
-  EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<const Class>(), 3, 2));
+  EXPECT_EQ(1,
+            base_internal::invoke(&Class::Method, make_unique<Class>(), 3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, make_unique<Class>(),
+                                     3, 2));
+  EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod,
+                                     make_unique<const Class>(), 3, 2));
 }
 
 TEST(InvokeTest, DataMember) {
   std::unique_ptr<Class> p(new Class{42});
   std::unique_ptr<const Class> cp(new Class{42});
-  EXPECT_EQ(42, Invoke(&Class::member, p));
-  EXPECT_EQ(42, Invoke(&Class::member, *p));
-  EXPECT_EQ(42, Invoke(&Class::member, p.get()));
+  EXPECT_EQ(42, base_internal::invoke(&Class::member, p));
+  EXPECT_EQ(42, base_internal::invoke(&Class::member, *p));
+  EXPECT_EQ(42, base_internal::invoke(&Class::member, p.get()));
 
-  Invoke(&Class::member, p) = 42;
-  Invoke(&Class::member, p.get()) = 42;
+  base_internal::invoke(&Class::member, p) = 42;
+  base_internal::invoke(&Class::member, p.get()) = 42;
 
-  EXPECT_EQ(42, Invoke(&Class::member, cp));
-  EXPECT_EQ(42, Invoke(&Class::member, *cp));
-  EXPECT_EQ(42, Invoke(&Class::member, cp.get()));
+  EXPECT_EQ(42, base_internal::invoke(&Class::member, cp));
+  EXPECT_EQ(42, base_internal::invoke(&Class::member, *cp));
+  EXPECT_EQ(42, base_internal::invoke(&Class::member, cp.get()));
 }
 
 TEST(InvokeTest, FlipFlop) {
   FlipFlop obj = {42};
   // This call could resolve to (obj.*&FlipFlop::ConstMethod)() or
   // ((*obj).*&FlipFlop::ConstMethod)(). We verify that it's the former.
-  EXPECT_EQ(42, Invoke(&FlipFlop::ConstMethod, obj));
-  EXPECT_EQ(42, Invoke(&FlipFlop::member, obj));
+  EXPECT_EQ(42, base_internal::invoke(&FlipFlop::ConstMethod, obj));
+  EXPECT_EQ(42, base_internal::invoke(&FlipFlop::member, obj));
 }
 
 TEST(InvokeTest, SfinaeFriendly) {
diff --git a/absl/base/log_severity.h b/absl/base/log_severity.h
index 65a3b16..2236422 100644
--- a/absl/base/log_severity.h
+++ b/absl/base/log_severity.h
@@ -12,8 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
-#define ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
+#ifndef ABSL_BASE_LOG_SEVERITY_H_
+#define ABSL_BASE_LOG_SEVERITY_H_
 
 #include <array>
 #include <ostream>
@@ -36,7 +36,7 @@
 // such values to a defined severity level, however in some cases values other
 // than the defined levels are useful for comparison.
 //
-// Exmaple:
+// Example:
 //
 //   // Effectively disables all logging:
 //   SetMinLogLevel(static_cast<absl::LogSeverity>(100));
@@ -118,4 +118,4 @@
 ABSL_NAMESPACE_END
 }  // namespace absl
 
-#endif  // ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
+#endif  // ABSL_BASE_LOG_SEVERITY_H_
diff --git a/absl/base/log_severity_test.cc b/absl/base/log_severity_test.cc
index 2302aa1..2c6872b 100644
--- a/absl/base/log_severity_test.cc
+++ b/absl/base/log_severity_test.cc
@@ -53,7 +53,7 @@
 }
 
 static_assert(
-    absl::flags_internal::IsAtomicFlagTypeTrait<absl::LogSeverity>::value,
+    absl::flags_internal::FlagUseOneWordStorage<absl::LogSeverity>::value,
     "Flags of type absl::LogSeverity ought to be lock-free.");
 
 using ParseFlagFromOutOfRangeIntegerTest = TestWithParam<int64_t>;
diff --git a/absl/base/macros.h b/absl/base/macros.h
index 547f93b..3e085a9 100644
--- a/absl/base/macros.h
+++ b/absl/base/macros.h
@@ -32,6 +32,7 @@
 #include <cstddef>
 
 #include "absl/base/attributes.h"
+#include "absl/base/config.h"
 #include "absl/base/optimization.h"
 #include "absl/base/port.h"
 
@@ -54,115 +55,6 @@
 ABSL_NAMESPACE_END
 }  // namespace absl
 
-// kLinkerInitialized
-//
-// An enum used only as a constructor argument to indicate that a variable has
-// static storage duration, and that the constructor should do nothing to its
-// state. Use of this macro indicates to the reader that it is legal to
-// declare a static instance of the class, provided the constructor is given
-// the absl::base_internal::kLinkerInitialized argument.
-//
-// Normally, it is unsafe to declare a static variable that has a constructor or
-// a destructor because invocation order is undefined. However, if the type can
-// be zero-initialized (which the loader does for static variables) into a valid
-// state and the type's destructor does not affect storage, then a constructor
-// for static initialization can be declared.
-//
-// Example:
-//       // Declaration
-//       explicit MyClass(absl::base_internal:LinkerInitialized x) {}
-//
-//       // Invocation
-//       static MyClass my_global(absl::base_internal::kLinkerInitialized);
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace base_internal {
-enum LinkerInitialized {
-  kLinkerInitialized = 0,
-};
-}  // namespace base_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-// ABSL_FALLTHROUGH_INTENDED
-//
-// Annotates implicit fall-through between switch labels, allowing a case to
-// indicate intentional fallthrough and turn off warnings about any lack of a
-// `break` statement. The ABSL_FALLTHROUGH_INTENDED macro should be followed by
-// a semicolon and can be used in most places where `break` can, provided that
-// no statements exist between it and the next switch label.
-//
-// Example:
-//
-//  switch (x) {
-//    case 40:
-//    case 41:
-//      if (truth_is_out_there) {
-//        ++x;
-//        ABSL_FALLTHROUGH_INTENDED;  // Use instead of/along with annotations
-//                                    // in comments
-//      } else {
-//        return x;
-//      }
-//    case 42:
-//      ...
-//
-// Notes: when compiled with clang in C++11 mode, the ABSL_FALLTHROUGH_INTENDED
-// macro is expanded to the [[clang::fallthrough]] attribute, which is analysed
-// when  performing switch labels fall-through diagnostic
-// (`-Wimplicit-fallthrough`). See clang documentation on language extensions
-// for details:
-// https://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough
-//
-// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro
-// has no effect on diagnostics. In any case this macro has no effect on runtime
-// behavior and performance of code.
-#ifdef ABSL_FALLTHROUGH_INTENDED
-#error "ABSL_FALLTHROUGH_INTENDED should not be defined."
-#endif
-
-// TODO(zhangxy): Use c++17 standard [[fallthrough]] macro, when supported.
-#if defined(__clang__) && defined(__has_warning)
-#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
-#define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]]
-#endif
-#elif defined(__GNUC__) && __GNUC__ >= 7
-#define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
-#endif
-
-#ifndef ABSL_FALLTHROUGH_INTENDED
-#define ABSL_FALLTHROUGH_INTENDED \
-  do {                            \
-  } while (0)
-#endif
-
-// ABSL_DEPRECATED()
-//
-// Marks a deprecated class, struct, enum, function, method and variable
-// declarations. The macro argument is used as a custom diagnostic message (e.g.
-// suggestion of a better alternative).
-//
-// Examples:
-//
-//   class ABSL_DEPRECATED("Use Bar instead") Foo {...};
-//
-//   ABSL_DEPRECATED("Use Baz() instead") void Bar() {...}
-//
-//   template <typename T>
-//   ABSL_DEPRECATED("Use DoThat() instead")
-//   void DoThis();
-//
-// Every usage of a deprecated entity will trigger a warning when compiled with
-// clang's `-Wdeprecated-declarations` option. This option is turned off by
-// default, but the warnings will be reported by clang-tidy.
-#if defined(__clang__) && __cplusplus >= 201103L
-#define ABSL_DEPRECATED(message) __attribute__((deprecated(message)))
-#endif
-
-#ifndef ABSL_DEPRECATED
-#define ABSL_DEPRECATED(message)
-#endif
-
 // ABSL_BAD_CALL_IF()
 //
 // Used on a function overload to trap bad calls: any call that matches the
@@ -207,6 +99,41 @@
                              : [] { assert(false && #expr); }())  // NOLINT
 #endif
 
+// `ABSL_INTERNAL_HARDENING_ABORT()` controls how `ABSL_HARDENING_ASSERT()`
+// aborts the program in release mode (when NDEBUG is defined). The
+// implementation should abort the program as quickly as possible and ideally it
+// should not be possible to ignore the abort request.
+#if (ABSL_HAVE_BUILTIN(__builtin_trap) &&         \
+     ABSL_HAVE_BUILTIN(__builtin_unreachable)) || \
+    (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_INTERNAL_HARDENING_ABORT() \
+  do {                                  \
+    __builtin_trap();                   \
+    __builtin_unreachable();            \
+  } while (false)
+#else
+#define ABSL_INTERNAL_HARDENING_ABORT() abort()
+#endif
+
+// ABSL_HARDENING_ASSERT()
+//
+// `ABSL_HARDENING_ASSERT()` is like `ABSL_ASSERT()`, but used to implement
+// runtime assertions that should be enabled in hardened builds even when
+// `NDEBUG` is defined.
+//
+// When `NDEBUG` is not defined, `ABSL_HARDENING_ASSERT()` is identical to
+// `ABSL_ASSERT()`.
+//
+// See `ABSL_OPTION_HARDENED` in `absl/base/options.h` for more information on
+// hardened mode.
+#if ABSL_OPTION_HARDENED == 1 && defined(NDEBUG)
+#define ABSL_HARDENING_ASSERT(expr)                 \
+  (ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \
+                             : [] { ABSL_INTERNAL_HARDENING_ABORT(); }())
+#else
+#define ABSL_HARDENING_ASSERT(expr) ABSL_ASSERT(expr)
+#endif
+
 #ifdef ABSL_HAVE_EXCEPTIONS
 #define ABSL_INTERNAL_TRY try
 #define ABSL_INTERNAL_CATCH_ANY catch (...)
@@ -217,4 +144,15 @@
 #define ABSL_INTERNAL_RETHROW do {} while (false)
 #endif  // ABSL_HAVE_EXCEPTIONS
 
+// `ABSL_INTERNAL_UNREACHABLE` is an unreachable statement.  A program which
+// reaches one has undefined behavior, and the compiler may optimize
+// accordingly.
+#if defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
+#define ABSL_INTERNAL_UNREACHABLE __builtin_unreachable()
+#elif defined(_MSC_VER)
+#define ABSL_INTERNAL_UNREACHABLE __assume(0)
+#else
+#define ABSL_INTERNAL_UNREACHABLE
+#endif
+
 #endif  // ABSL_BASE_MACROS_H_
diff --git a/absl/base/optimization.h b/absl/base/optimization.h
index 646523b..d090be1 100644
--- a/absl/base/optimization.h
+++ b/absl/base/optimization.h
@@ -22,13 +22,15 @@
 #ifndef ABSL_BASE_OPTIMIZATION_H_
 #define ABSL_BASE_OPTIMIZATION_H_
 
+#include <assert.h>
+
 #include "absl/base/config.h"
 
 // ABSL_BLOCK_TAIL_CALL_OPTIMIZATION
 //
-// Instructs the compiler to avoid optimizing tail-call recursion. Use of this
-// macro is useful when you wish to preserve the existing function order within
-// a stack trace for logging, debugging, or profiling purposes.
+// Instructs the compiler to avoid optimizing tail-call recursion. This macro is
+// useful when you wish to preserve the existing function order within a stack
+// trace for logging, debugging, or profiling purposes.
 //
 // Example:
 //
@@ -104,9 +106,10 @@
 // Cacheline aligning objects properly allows constructive memory sharing and
 // prevents destructive (or "false") memory sharing.
 //
-// NOTE: this macro should be replaced with usage of `alignas()` using
+// NOTE: callers should replace uses of this macro with `alignas()` using
 // `std::hardware_constructive_interference_size` and/or
-// `std::hardware_destructive_interference_size` when available within C++17.
+// `std::hardware_destructive_interference_size` when C++17 becomes available to
+// them.
 //
 // See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
 // for more information.
@@ -171,11 +174,71 @@
 // to yield performance improvements.
 #if ABSL_HAVE_BUILTIN(__builtin_expect) || \
     (defined(__GNUC__) && !defined(__clang__))
-#define ABSL_PREDICT_FALSE(x) (__builtin_expect(x, 0))
+#define ABSL_PREDICT_FALSE(x) (__builtin_expect(false || (x), false))
 #define ABSL_PREDICT_TRUE(x) (__builtin_expect(false || (x), true))
 #else
 #define ABSL_PREDICT_FALSE(x) (x)
 #define ABSL_PREDICT_TRUE(x) (x)
 #endif
 
+// ABSL_INTERNAL_ASSUME(cond)
+// Informs the compiler that a condition is always true and that it can assume
+// it to be true for optimization purposes. The call has undefined behavior if
+// the condition is false.
+// In !NDEBUG mode, the condition is checked with an assert().
+// NOTE: The expression must not have side effects, as it will only be evaluated
+// in some compilation modes and not others.
+//
+// Example:
+//
+//   int x = ...;
+//   ABSL_INTERNAL_ASSUME(x >= 0);
+//   // The compiler can optimize the division to a simple right shift using the
+//   // assumption specified above.
+//   int y = x / 16;
+//
+#if !defined(NDEBUG)
+#define ABSL_INTERNAL_ASSUME(cond) assert(cond)
+#elif ABSL_HAVE_BUILTIN(__builtin_assume)
+#define ABSL_INTERNAL_ASSUME(cond) __builtin_assume(cond)
+#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
+#define ABSL_INTERNAL_ASSUME(cond)        \
+  do {                                    \
+    if (!(cond)) __builtin_unreachable(); \
+  } while (0)
+#elif defined(_MSC_VER)
+#define ABSL_INTERNAL_ASSUME(cond) __assume(cond)
+#else
+#define ABSL_INTERNAL_ASSUME(cond)      \
+  do {                                  \
+    static_cast<void>(false && (cond)); \
+  } while (0)
+#endif
+
+// ABSL_INTERNAL_UNIQUE_SMALL_NAME(cond)
+// This macro forces small unique name on a static file level symbols like
+// static local variables or static functions. This is intended to be used in
+// macro definitions to optimize the cost of generated code. Do NOT use it on
+// symbols exported from translation unit since it may cause a link time
+// conflict.
+//
+// Example:
+//
+// #define MY_MACRO(txt)
+// namespace {
+//  char VeryVeryLongVarName[] ABSL_INTERNAL_UNIQUE_SMALL_NAME() = txt;
+//  const char* VeryVeryLongFuncName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
+//  const char* VeryVeryLongFuncName() { return txt; }
+// }
+//
+
+#if defined(__GNUC__)
+#define ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x) #x
+#define ABSL_INTERNAL_UNIQUE_SMALL_NAME1(x) ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x)
+#define ABSL_INTERNAL_UNIQUE_SMALL_NAME() \
+  asm(ABSL_INTERNAL_UNIQUE_SMALL_NAME1(.absl.__COUNTER__))
+#else
+#define ABSL_INTERNAL_UNIQUE_SMALL_NAME()
+#endif
+
 #endif  // ABSL_BASE_OPTIMIZATION_H_
diff --git a/absl/base/optimization_test.cc b/absl/base/optimization_test.cc
new file mode 100644
index 0000000..e83369f
--- /dev/null
+++ b/absl/base/optimization_test.cc
@@ -0,0 +1,129 @@
+// 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/base/optimization.h"
+
+#include "gtest/gtest.h"
+#include "absl/types/optional.h"
+
+namespace {
+
+// Tests for the ABSL_PREDICT_TRUE and ABSL_PREDICT_FALSE macros.
+// The tests only verify that the macros are functionally correct - i.e. code
+// behaves as if they weren't used. They don't try to check their impact on
+// optimization.
+
+TEST(PredictTest, PredictTrue) {
+  EXPECT_TRUE(ABSL_PREDICT_TRUE(true));
+  EXPECT_FALSE(ABSL_PREDICT_TRUE(false));
+  EXPECT_TRUE(ABSL_PREDICT_TRUE(1 == 1));
+  EXPECT_FALSE(ABSL_PREDICT_TRUE(1 == 2));
+
+  if (ABSL_PREDICT_TRUE(false)) ADD_FAILURE();
+  if (!ABSL_PREDICT_TRUE(true)) ADD_FAILURE();
+
+  EXPECT_TRUE(ABSL_PREDICT_TRUE(true) && true);
+  EXPECT_TRUE(ABSL_PREDICT_TRUE(true) || false);
+}
+
+TEST(PredictTest, PredictFalse) {
+  EXPECT_TRUE(ABSL_PREDICT_FALSE(true));
+  EXPECT_FALSE(ABSL_PREDICT_FALSE(false));
+  EXPECT_TRUE(ABSL_PREDICT_FALSE(1 == 1));
+  EXPECT_FALSE(ABSL_PREDICT_FALSE(1 == 2));
+
+  if (ABSL_PREDICT_FALSE(false)) ADD_FAILURE();
+  if (!ABSL_PREDICT_FALSE(true)) ADD_FAILURE();
+
+  EXPECT_TRUE(ABSL_PREDICT_FALSE(true) && true);
+  EXPECT_TRUE(ABSL_PREDICT_FALSE(true) || false);
+}
+
+TEST(PredictTest, OneEvaluation) {
+  // Verify that the expression is only evaluated once.
+  int x = 0;
+  if (ABSL_PREDICT_TRUE((++x) == 0)) ADD_FAILURE();
+  EXPECT_EQ(x, 1);
+  if (ABSL_PREDICT_FALSE((++x) == 0)) ADD_FAILURE();
+  EXPECT_EQ(x, 2);
+}
+
+TEST(PredictTest, OperatorOrder) {
+  // Verify that operator order inside and outside the macro behaves well.
+  // These would fail for a naive '#define ABSL_PREDICT_TRUE(x) x'
+  EXPECT_TRUE(ABSL_PREDICT_TRUE(1 && 2) == true);
+  EXPECT_TRUE(ABSL_PREDICT_FALSE(1 && 2) == true);
+  EXPECT_TRUE(!ABSL_PREDICT_TRUE(1 == 2));
+  EXPECT_TRUE(!ABSL_PREDICT_FALSE(1 == 2));
+}
+
+TEST(PredictTest, Pointer) {
+  const int x = 3;
+  const int *good_intptr = &x;
+  const int *null_intptr = nullptr;
+  EXPECT_TRUE(ABSL_PREDICT_TRUE(good_intptr));
+  EXPECT_FALSE(ABSL_PREDICT_TRUE(null_intptr));
+  EXPECT_TRUE(ABSL_PREDICT_FALSE(good_intptr));
+  EXPECT_FALSE(ABSL_PREDICT_FALSE(null_intptr));
+}
+
+TEST(PredictTest, Optional) {
+  // Note: An optional's truth value is the value's existence, not its truth.
+  absl::optional<bool> has_value(false);
+  absl::optional<bool> no_value;
+  EXPECT_TRUE(ABSL_PREDICT_TRUE(has_value));
+  EXPECT_FALSE(ABSL_PREDICT_TRUE(no_value));
+  EXPECT_TRUE(ABSL_PREDICT_FALSE(has_value));
+  EXPECT_FALSE(ABSL_PREDICT_FALSE(no_value));
+}
+
+class ImplictlyConvertibleToBool {
+ public:
+  explicit ImplictlyConvertibleToBool(bool value) : value_(value) {}
+  operator bool() const {  // NOLINT(google-explicit-constructor)
+    return value_;
+  }
+
+ private:
+  bool value_;
+};
+
+TEST(PredictTest, ImplicitBoolConversion) {
+  const ImplictlyConvertibleToBool is_true(true);
+  const ImplictlyConvertibleToBool is_false(false);
+  if (!ABSL_PREDICT_TRUE(is_true)) ADD_FAILURE();
+  if (ABSL_PREDICT_TRUE(is_false)) ADD_FAILURE();
+  if (!ABSL_PREDICT_FALSE(is_true)) ADD_FAILURE();
+  if (ABSL_PREDICT_FALSE(is_false)) ADD_FAILURE();
+}
+
+class ExplictlyConvertibleToBool {
+ public:
+  explicit ExplictlyConvertibleToBool(bool value) : value_(value) {}
+  explicit operator bool() const { return value_; }
+
+ private:
+  bool value_;
+};
+
+TEST(PredictTest, ExplicitBoolConversion) {
+  const ExplictlyConvertibleToBool is_true(true);
+  const ExplictlyConvertibleToBool is_false(false);
+  if (!ABSL_PREDICT_TRUE(is_true)) ADD_FAILURE();
+  if (ABSL_PREDICT_TRUE(is_false)) ADD_FAILURE();
+  if (!ABSL_PREDICT_FALSE(is_true)) ADD_FAILURE();
+  if (ABSL_PREDICT_FALSE(is_false)) ADD_FAILURE();
+}
+
+}  // namespace
diff --git a/absl/base/options.h b/absl/base/options.h
index 50f26e2..eca879a 100644
--- a/absl/base/options.h
+++ b/absl/base/options.h
@@ -1,6 +1,3 @@
-#ifndef ABSL_BASE_OPTIONS_H_
-#define ABSL_BASE_OPTIONS_H_
-
 // Copyright 2019 The Abseil Authors.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
@@ -67,6 +64,9 @@
 // proper Abseil implementation at compile-time, which will not be sufficient
 // to guarantee ABI stability to package managers.
 
+#ifndef ABSL_BASE_OPTIONS_H_
+#define ABSL_BASE_OPTIONS_H_
+
 // Include a standard library header to allow configuration based on the
 // standard library in use.
 #ifdef __cplusplus
@@ -206,6 +206,33 @@
 // allowed.
 
 #define ABSL_OPTION_USE_INLINE_NAMESPACE 1
-#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_2020_02_25
+#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_20210324
+
+// ABSL_OPTION_HARDENED
+//
+// This option enables a "hardened" build in release mode (in this context,
+// release mode is defined as a build where the `NDEBUG` macro is defined).
+//
+// A value of 0 means that "hardened" mode is not enabled.
+//
+// A value of 1 means that "hardened" mode is enabled.
+//
+// Hardened builds have additional security checks enabled when `NDEBUG` is
+// defined. Defining `NDEBUG` is normally used to turn `assert()` macro into a
+// no-op, as well as disabling other bespoke program consistency checks. By
+// defining ABSL_OPTION_HARDENED to 1, a select set of checks remain enabled in
+// release mode. These checks guard against programming errors that may lead to
+// security vulnerabilities. In release mode, when one of these programming
+// errors is encountered, the program will immediately abort, possibly without
+// any attempt at logging.
+//
+// The checks enabled by this option are not free; they do incur runtime cost.
+//
+// The checks enabled by this option are always active when `NDEBUG` is not
+// defined, even in the case when ABSL_OPTION_HARDENED is defined to 0. The
+// checks enabled by this option may abort the program in a different way and
+// log additional information when `NDEBUG` is not defined.
+
+#define ABSL_OPTION_HARDENED 0
 
 #endif  // ABSL_BASE_OPTIONS_H_
diff --git a/absl/base/policy_checks.h b/absl/base/policy_checks.h
index 4dfa49e..06b3243 100644
--- a/absl/base/policy_checks.h
+++ b/absl/base/policy_checks.h
@@ -41,7 +41,7 @@
 #endif
 
 // -----------------------------------------------------------------------------
-// Compiler Check
+// Toolchain Check
 // -----------------------------------------------------------------------------
 
 // We support MSVC++ 14.0 update 2 and later.
diff --git a/absl/base/port.h b/absl/base/port.h
index 6c28068..5bc4d6c 100644
--- a/absl/base/port.h
+++ b/absl/base/port.h
@@ -14,7 +14,6 @@
 //
 // This files is a forwarding header for other headers containing various
 // portability macros and functions.
-// This file is used for both C and C++!
 
 #ifndef ABSL_BASE_PORT_H_
 #define ABSL_BASE_PORT_H_
diff --git a/absl/base/spinlock_test_common.cc b/absl/base/spinlock_test_common.cc
index 08f61ba..2b572c5 100644
--- a/absl/base/spinlock_test_common.cc
+++ b/absl/base/spinlock_test_common.cc
@@ -20,10 +20,12 @@
 #include <limits>
 #include <random>
 #include <thread>  // NOLINT(build/c++11)
+#include <type_traits>
 #include <vector>
 
 #include "gtest/gtest.h"
 #include "absl/base/attributes.h"
+#include "absl/base/config.h"
 #include "absl/base/internal/low_level_scheduling.h"
 #include "absl/base/internal/scheduling_mode.h"
 #include "absl/base/internal/spinlock.h"
@@ -56,12 +58,10 @@
 static constexpr int kArrayLength = 10;
 static uint32_t values[kArrayLength];
 
-static SpinLock static_spinlock(base_internal::kLinkerInitialized);
-static SpinLock static_cooperative_spinlock(
-    base_internal::kLinkerInitialized,
-    base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL);
-static SpinLock static_noncooperative_spinlock(
-    base_internal::kLinkerInitialized, base_internal::SCHEDULE_KERNEL_ONLY);
+ABSL_CONST_INIT static SpinLock static_cooperative_spinlock(
+    absl::kConstInit, base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL);
+ABSL_CONST_INIT static SpinLock static_noncooperative_spinlock(
+    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
 
 // Simple integer hash function based on the public domain lookup2 hash.
 // http://burtleburtle.net/bob/c/lookup2.c
@@ -92,6 +92,7 @@
 
 static void ThreadedTest(SpinLock* spinlock) {
   std::vector<std::thread> threads;
+  threads.reserve(kNumThreads);
   for (int i = 0; i < kNumThreads; ++i) {
     threads.push_back(std::thread(TestFunction, i, spinlock));
   }
@@ -105,6 +106,10 @@
   }
 }
 
+#ifndef ABSL_HAVE_THREAD_SANITIZER
+static_assert(std::is_trivially_destructible<SpinLock>(), "");
+#endif
+
 TEST(SpinLock, StackNonCooperativeDisablesScheduling) {
   SpinLock spinlock(base_internal::SCHEDULE_KERNEL_ONLY);
   spinlock.Lock();
@@ -191,10 +196,6 @@
   EXPECT_GT(expected_max_value_decoded, before_max_value_decoded);
 }
 
-TEST(SpinLockWithThreads, StaticSpinLock) {
-  ThreadedTest(&static_spinlock);
-}
-
 TEST(SpinLockWithThreads, StackSpinLock) {
   SpinLock spinlock;
   ThreadedTest(&spinlock);
diff --git a/absl/base/thread_annotations.h b/absl/base/thread_annotations.h
index 5f51c0c..9695f6d 100644
--- a/absl/base/thread_annotations.h
+++ b/absl/base/thread_annotations.h
@@ -34,16 +34,11 @@
 #ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_
 #define ABSL_BASE_THREAD_ANNOTATIONS_H_
 
+#include "absl/base/attributes.h"
 #include "absl/base/config.h"
 // TODO(mbonadei): Remove after the backward compatibility period.
 #include "absl/base/internal/thread_annotations.h"  // IWYU pragma: export
 
-#if defined(__clang__)
-#define ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(x) __attribute__((x))
-#else
-#define ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(x)  // no-op
-#endif
-
 // ABSL_GUARDED_BY()
 //
 // Documents if a shared field or global variable needs to be protected by a
@@ -61,8 +56,11 @@
 //     int p1_ ABSL_GUARDED_BY(mu_);
 //     ...
 //   };
-#define ABSL_GUARDED_BY(x) \
-  ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(guarded_by(x))
+#if ABSL_HAVE_ATTRIBUTE(guarded_by)
+#define ABSL_GUARDED_BY(x) __attribute__((guarded_by(x)))
+#else
+#define ABSL_GUARDED_BY(x)
+#endif
 
 // ABSL_PT_GUARDED_BY()
 //
@@ -84,8 +82,11 @@
 //   // `q_`, guarded by `mu1_`, points to a shared memory location that is
 //   // guarded by `mu2_`:
 //   int *q_ ABSL_GUARDED_BY(mu1_) ABSL_PT_GUARDED_BY(mu2_);
-#define ABSL_PT_GUARDED_BY(x) \
-  ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(pt_guarded_by(x))
+#if ABSL_HAVE_ATTRIBUTE(pt_guarded_by)
+#define ABSL_PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x)))
+#else
+#define ABSL_PT_GUARDED_BY(x)
+#endif
 
 // ABSL_ACQUIRED_AFTER() / ABSL_ACQUIRED_BEFORE()
 //
@@ -102,11 +103,17 @@
 //
 //   Mutex m1_;
 //   Mutex m2_ ABSL_ACQUIRED_AFTER(m1_);
-#define ABSL_ACQUIRED_AFTER(...) \
-  ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(acquired_after(__VA_ARGS__))
+#if ABSL_HAVE_ATTRIBUTE(acquired_after)
+#define ABSL_ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__)))
+#else
+#define ABSL_ACQUIRED_AFTER(...)
+#endif
 
-#define ABSL_ACQUIRED_BEFORE(...) \
-  ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(acquired_before(__VA_ARGS__))
+#if ABSL_HAVE_ATTRIBUTE(acquired_before)
+#define ABSL_ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__)))
+#else
+#define ABSL_ACQUIRED_BEFORE(...)
+#endif
 
 // ABSL_EXCLUSIVE_LOCKS_REQUIRED() / ABSL_SHARED_LOCKS_REQUIRED()
 //
@@ -131,33 +138,50 @@
 //
 //   void foo() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
 //   void bar() const ABSL_SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
-#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...)   \
-  ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
-      exclusive_locks_required(__VA_ARGS__))
+#if ABSL_HAVE_ATTRIBUTE(exclusive_locks_required)
+#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \
+  __attribute__((exclusive_locks_required(__VA_ARGS__)))
+#else
+#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...)
+#endif
 
+#if ABSL_HAVE_ATTRIBUTE(shared_locks_required)
 #define ABSL_SHARED_LOCKS_REQUIRED(...) \
-  ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(shared_locks_required(__VA_ARGS__))
+  __attribute__((shared_locks_required(__VA_ARGS__)))
+#else
+#define ABSL_SHARED_LOCKS_REQUIRED(...)
+#endif
 
 // ABSL_LOCKS_EXCLUDED()
 //
 // Documents the locks acquired in the body of the function. These locks
 // cannot be held when calling this function (as Abseil's `Mutex` locks are
 // non-reentrant).
-#define ABSL_LOCKS_EXCLUDED(...) \
-  ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(locks_excluded(__VA_ARGS__))
+#if ABSL_HAVE_ATTRIBUTE(locks_excluded)
+#define ABSL_LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__)))
+#else
+#define ABSL_LOCKS_EXCLUDED(...)
+#endif
 
 // ABSL_LOCK_RETURNED()
 //
 // Documents a function that returns a mutex without acquiring it.  For example,
 // a public getter method that returns a pointer to a private mutex should
 // be annotated with ABSL_LOCK_RETURNED.
-#define ABSL_LOCK_RETURNED(x) \
-  ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(lock_returned(x))
+#if ABSL_HAVE_ATTRIBUTE(lock_returned)
+#define ABSL_LOCK_RETURNED(x) __attribute__((lock_returned(x)))
+#else
+#define ABSL_LOCK_RETURNED(x)
+#endif
 
 // ABSL_LOCKABLE
 //
 // Documents if a class/type is a lockable type (such as the `Mutex` class).
-#define ABSL_LOCKABLE ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(lockable)
+#if ABSL_HAVE_ATTRIBUTE(lockable)
+#define ABSL_LOCKABLE __attribute__((lockable))
+#else
+#define ABSL_LOCKABLE
+#endif
 
 // ABSL_SCOPED_LOCKABLE
 //
@@ -166,30 +190,43 @@
 // acquired, and the destructor should use `UNLOCK_FUNCTION()` with no
 // arguments; the analysis will assume that the destructor unlocks whatever the
 // constructor locked.
-#define ABSL_SCOPED_LOCKABLE \
-  ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(scoped_lockable)
+#if ABSL_HAVE_ATTRIBUTE(scoped_lockable)
+#define ABSL_SCOPED_LOCKABLE __attribute__((scoped_lockable))
+#else
+#define ABSL_SCOPED_LOCKABLE
+#endif
 
 // ABSL_EXCLUSIVE_LOCK_FUNCTION()
 //
 // Documents functions that acquire a lock in the body of a function, and do
 // not release it.
-#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...)    \
-  ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
-      exclusive_lock_function(__VA_ARGS__))
+#if ABSL_HAVE_ATTRIBUTE(exclusive_lock_function)
+#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \
+  __attribute__((exclusive_lock_function(__VA_ARGS__)))
+#else
+#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...)
+#endif
 
 // ABSL_SHARED_LOCK_FUNCTION()
 //
 // Documents functions that acquire a shared (reader) lock in the body of a
 // function, and do not release it.
+#if ABSL_HAVE_ATTRIBUTE(shared_lock_function)
 #define ABSL_SHARED_LOCK_FUNCTION(...) \
-  ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(shared_lock_function(__VA_ARGS__))
+  __attribute__((shared_lock_function(__VA_ARGS__)))
+#else
+#define ABSL_SHARED_LOCK_FUNCTION(...)
+#endif
 
 // ABSL_UNLOCK_FUNCTION()
 //
 // Documents functions that expect a lock to be held on entry to the function,
 // and release it in the body of the function.
-#define ABSL_UNLOCK_FUNCTION(...) \
-  ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(unlock_function(__VA_ARGS__))
+#if ABSL_HAVE_ATTRIBUTE(unlock_function)
+#define ABSL_UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__)))
+#else
+#define ABSL_UNLOCK_FUNCTION(...)
+#endif
 
 // ABSL_EXCLUSIVE_TRYLOCK_FUNCTION() / ABSL_SHARED_TRYLOCK_FUNCTION()
 //
@@ -199,31 +236,49 @@
 // success, or `false` for functions that return `false` on success. The second
 // argument specifies the mutex that is locked on success. If unspecified, this
 // mutex is assumed to be `this`.
+#if ABSL_HAVE_ATTRIBUTE(exclusive_trylock_function)
 #define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...) \
-  ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
-      exclusive_trylock_function(__VA_ARGS__))
+  __attribute__((exclusive_trylock_function(__VA_ARGS__)))
+#else
+#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...)
+#endif
 
-#define ABSL_SHARED_TRYLOCK_FUNCTION(...)    \
-  ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
-      shared_trylock_function(__VA_ARGS__))
+#if ABSL_HAVE_ATTRIBUTE(shared_trylock_function)
+#define ABSL_SHARED_TRYLOCK_FUNCTION(...) \
+  __attribute__((shared_trylock_function(__VA_ARGS__)))
+#else
+#define ABSL_SHARED_TRYLOCK_FUNCTION(...)
+#endif
 
 // ABSL_ASSERT_EXCLUSIVE_LOCK() / ABSL_ASSERT_SHARED_LOCK()
 //
 // Documents functions that dynamically check to see if a lock is held, and fail
 // if it is not held.
+#if ABSL_HAVE_ATTRIBUTE(assert_exclusive_lock)
 #define ABSL_ASSERT_EXCLUSIVE_LOCK(...) \
-  ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(assert_exclusive_lock(__VA_ARGS__))
+  __attribute__((assert_exclusive_lock(__VA_ARGS__)))
+#else
+#define ABSL_ASSERT_EXCLUSIVE_LOCK(...)
+#endif
 
+#if ABSL_HAVE_ATTRIBUTE(assert_shared_lock)
 #define ABSL_ASSERT_SHARED_LOCK(...) \
-  ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(assert_shared_lock(__VA_ARGS__))
+  __attribute__((assert_shared_lock(__VA_ARGS__)))
+#else
+#define ABSL_ASSERT_SHARED_LOCK(...)
+#endif
 
 // ABSL_NO_THREAD_SAFETY_ANALYSIS
 //
 // Turns off thread safety checking within the body of a particular function.
 // This annotation is used to mark functions that are known to be correct, but
 // the locking behavior is more complicated than the analyzer can handle.
+#if ABSL_HAVE_ATTRIBUTE(no_thread_safety_analysis)
 #define ABSL_NO_THREAD_SAFETY_ANALYSIS \
-  ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(no_thread_safety_analysis)
+  __attribute__((no_thread_safety_analysis))
+#else
+#define ABSL_NO_THREAD_SAFETY_ANALYSIS
+#endif
 
 //------------------------------------------------------------------------------
 // Tool-Supplied Annotations
@@ -262,7 +317,7 @@
 
 // Takes a reference to a guarded data member, and returns an unguarded
 // reference.
-// Do not used this function directly, use ABSL_TS_UNCHECKED_READ instead.
+// Do not use this function directly, use ABSL_TS_UNCHECKED_READ instead.
 template <typename T>
 inline const T& ts_unchecked_read(const T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
   return v;
diff --git a/absl/cleanup/BUILD.bazel b/absl/cleanup/BUILD.bazel
new file mode 100644
index 0000000..5cca898
--- /dev/null
+++ b/absl/cleanup/BUILD.bazel
@@ -0,0 +1,66 @@
+# Copyright 2021 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.
+
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load(
+    "//absl:copts/configure_copts.bzl",
+    "ABSL_DEFAULT_COPTS",
+    "ABSL_DEFAULT_LINKOPTS",
+    "ABSL_TEST_COPTS",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])
+
+cc_library(
+    name = "cleanup_internal",
+    hdrs = ["internal/cleanup.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        "//absl/base:base_internal",
+        "//absl/base:core_headers",
+        "//absl/utility",
+    ],
+)
+
+cc_library(
+    name = "cleanup",
+    hdrs = [
+        "cleanup.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":cleanup_internal",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+    ],
+)
+
+cc_test(
+    name = "cleanup_test",
+    size = "small",
+    srcs = [
+        "cleanup_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":cleanup",
+        "//absl/base:config",
+        "//absl/utility",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
diff --git a/absl/cleanup/CMakeLists.txt b/absl/cleanup/CMakeLists.txt
new file mode 100644
index 0000000..a2dd78a
--- /dev/null
+++ b/absl/cleanup/CMakeLists.txt
@@ -0,0 +1,55 @@
+# Copyright 2021 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.
+
+absl_cc_library(
+  NAME
+    cleanup_internal
+  HDRS
+    "internal/cleanup.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::base_internal
+    absl::core_headers
+    absl::utility
+  PUBLIC
+)
+
+absl_cc_library(
+  NAME
+    cleanup
+  HDRS
+    "cleanup.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::cleanup_internal
+    absl::config
+    absl::core_headers
+  PUBLIC
+)
+
+absl_cc_test(
+  NAME
+    cleanup_test
+  SRCS
+    "cleanup_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::cleanup
+    absl::config
+    absl::utility
+    gmock_main
+)
diff --git a/absl/cleanup/cleanup.h b/absl/cleanup/cleanup.h
new file mode 100644
index 0000000..61b53d5
--- /dev/null
+++ b/absl/cleanup/cleanup.h
@@ -0,0 +1,140 @@
+// Copyright 2021 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: cleanup.h
+// -----------------------------------------------------------------------------
+//
+// `absl::Cleanup` implements the scope guard idiom, invoking the contained
+// callback's `operator()() &&` on scope exit.
+//
+// Example:
+//
+// ```
+//   absl::Status CopyGoodData(const char* source_path, const char* sink_path) {
+//     FILE* source_file = fopen(source_path, "r");
+//     if (source_file == nullptr) {
+//       return absl::NotFoundError("No source file");  // No cleanups execute
+//     }
+//
+//     // C++17 style cleanup using class template argument deduction
+//     absl::Cleanup source_closer = [source_file] { fclose(source_file); };
+//
+//     FILE* sink_file = fopen(sink_path, "w");
+//     if (sink_file == nullptr) {
+//       return absl::NotFoundError("No sink file");  // First cleanup executes
+//     }
+//
+//     // C++11 style cleanup using the factory function
+//     auto sink_closer = absl::MakeCleanup([sink_file] { fclose(sink_file); });
+//
+//     Data data;
+//     while (ReadData(source_file, &data)) {
+//       if (!data.IsGood()) {
+//         absl::Status result = absl::FailedPreconditionError("Read bad data");
+//         return result;  // Both cleanups execute
+//       }
+//       SaveData(sink_file, &data);
+//     }
+//
+//     return absl::OkStatus();  // Both cleanups execute
+//   }
+// ```
+//
+// Methods:
+//
+// `std::move(cleanup).Cancel()` will prevent the callback from executing.
+//
+// `std::move(cleanup).Invoke()` will execute the callback early, before
+// destruction, and prevent the callback from executing in the destructor.
+//
+// Usage:
+//
+// `absl::Cleanup` is not an interface type. It is only intended to be used
+// within the body of a function. It is not a value type and instead models a
+// control flow construct. Check out `defer` in Golang for something similar.
+
+#ifndef ABSL_CLEANUP_CLEANUP_H_
+#define ABSL_CLEANUP_CLEANUP_H_
+
+#include <utility>
+
+#include "absl/base/config.h"
+#include "absl/base/macros.h"
+#include "absl/cleanup/internal/cleanup.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+template <typename Arg, typename Callback = void()>
+class ABSL_MUST_USE_RESULT Cleanup final {
+  static_assert(cleanup_internal::WasDeduced<Arg>(),
+                "Explicit template parameters are not supported.");
+
+  static_assert(cleanup_internal::ReturnsVoid<Callback>(),
+                "Callbacks that return values are not supported.");
+
+ public:
+  Cleanup(Callback callback)  // NOLINT
+      : storage_(std::move(callback), /* is_callback_engaged = */ true) {}
+
+  Cleanup(Cleanup&& other) = default;
+
+  void Cancel() && {
+    ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged());
+    storage_.DisengageCallback();
+  }
+
+  void Invoke() && {
+    ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged());
+    storage_.DisengageCallback();
+    storage_.InvokeCallback();
+  }
+
+  ~Cleanup() {
+    if (storage_.IsCallbackEngaged()) {
+      storage_.InvokeCallback();
+    }
+  }
+
+ private:
+  cleanup_internal::Storage<Callback> storage_;
+};
+
+// `absl::Cleanup c = /* callback */;`
+//
+// C++17 type deduction API for creating an instance of `absl::Cleanup`
+#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
+template <typename Callback>
+Cleanup(Callback callback) -> Cleanup<cleanup_internal::Tag, Callback>;
+#endif  // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
+
+// `auto c = absl::MakeCleanup(/* callback */);`
+//
+// C++11 type deduction API for creating an instance of `absl::Cleanup`
+template <typename... Args, typename Callback>
+absl::Cleanup<cleanup_internal::Tag, Callback> MakeCleanup(Callback callback) {
+  static_assert(cleanup_internal::WasDeduced<cleanup_internal::Tag, Args...>(),
+                "Explicit template parameters are not supported.");
+
+  static_assert(cleanup_internal::ReturnsVoid<Callback>(),
+                "Callbacks that return values are not supported.");
+
+  return {std::move(callback)};
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CLEANUP_CLEANUP_H_
diff --git a/absl/cleanup/cleanup_test.cc b/absl/cleanup/cleanup_test.cc
new file mode 100644
index 0000000..792595d
--- /dev/null
+++ b/absl/cleanup/cleanup_test.cc
@@ -0,0 +1,267 @@
+// Copyright 2021 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/cleanup/cleanup.h"
+
+#include <functional>
+#include <type_traits>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/utility/utility.h"
+
+namespace {
+
+using Tag = absl::cleanup_internal::Tag;
+
+template <typename Type1, typename Type2>
+constexpr bool IsSame() {
+  return (std::is_same<Type1, Type2>::value);
+}
+
+struct IdentityFactory {
+  template <typename Callback>
+  static Callback AsCallback(Callback callback) {
+    return Callback(std::move(callback));
+  }
+};
+
+// `FunctorClass` is a type used for testing `absl::Cleanup`. It is intended to
+// represent users that make their own move-only callback types outside of
+// `std::function` and lambda literals.
+class FunctorClass {
+  using Callback = std::function<void()>;
+
+ public:
+  explicit FunctorClass(Callback callback) : callback_(std::move(callback)) {}
+
+  FunctorClass(FunctorClass&& other)
+      : callback_(absl::exchange(other.callback_, Callback())) {}
+
+  FunctorClass(const FunctorClass&) = delete;
+
+  FunctorClass& operator=(const FunctorClass&) = delete;
+
+  FunctorClass& operator=(FunctorClass&&) = delete;
+
+  void operator()() const& = delete;
+
+  void operator()() && {
+    ASSERT_TRUE(callback_);
+    callback_();
+    callback_ = nullptr;
+  }
+
+ private:
+  Callback callback_;
+};
+
+struct FunctorClassFactory {
+  template <typename Callback>
+  static FunctorClass AsCallback(Callback callback) {
+    return FunctorClass(std::move(callback));
+  }
+};
+
+struct StdFunctionFactory {
+  template <typename Callback>
+  static std::function<void()> AsCallback(Callback callback) {
+    return std::function<void()>(std::move(callback));
+  }
+};
+
+using CleanupTestParams =
+    ::testing::Types<IdentityFactory, FunctorClassFactory, StdFunctionFactory>;
+template <typename>
+struct CleanupTest : public ::testing::Test {};
+TYPED_TEST_SUITE(CleanupTest, CleanupTestParams);
+
+bool fn_ptr_called = false;
+void FnPtrFunction() { fn_ptr_called = true; }
+
+TYPED_TEST(CleanupTest, FactoryProducesCorrectType) {
+  {
+    auto callback = TypeParam::AsCallback([] {});
+    auto cleanup = absl::MakeCleanup(std::move(callback));
+
+    static_assert(
+        IsSame<absl::Cleanup<Tag, decltype(callback)>, decltype(cleanup)>(),
+        "");
+  }
+
+  {
+    auto cleanup = absl::MakeCleanup(&FnPtrFunction);
+
+    static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
+                  "");
+  }
+
+  {
+    auto cleanup = absl::MakeCleanup(FnPtrFunction);
+
+    static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
+                  "");
+  }
+}
+
+#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
+TYPED_TEST(CleanupTest, CTADProducesCorrectType) {
+  {
+    auto callback = TypeParam::AsCallback([] {});
+    absl::Cleanup cleanup = std::move(callback);
+
+    static_assert(
+        IsSame<absl::Cleanup<Tag, decltype(callback)>, decltype(cleanup)>(),
+        "");
+  }
+
+  {
+    absl::Cleanup cleanup = &FnPtrFunction;
+
+    static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
+                  "");
+  }
+
+  {
+    absl::Cleanup cleanup = FnPtrFunction;
+
+    static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
+                  "");
+  }
+}
+
+TYPED_TEST(CleanupTest, FactoryAndCTADProduceSameType) {
+  {
+    auto callback = IdentityFactory::AsCallback([] {});
+    auto factory_cleanup = absl::MakeCleanup(callback);
+    absl::Cleanup deduction_cleanup = callback;
+
+    static_assert(
+        IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
+  }
+
+  {
+    auto factory_cleanup =
+        absl::MakeCleanup(FunctorClassFactory::AsCallback([] {}));
+    absl::Cleanup deduction_cleanup = FunctorClassFactory::AsCallback([] {});
+
+    static_assert(
+        IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
+  }
+
+  {
+    auto factory_cleanup =
+        absl::MakeCleanup(StdFunctionFactory::AsCallback([] {}));
+    absl::Cleanup deduction_cleanup = StdFunctionFactory::AsCallback([] {});
+
+    static_assert(
+        IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
+  }
+
+  {
+    auto factory_cleanup = absl::MakeCleanup(&FnPtrFunction);
+    absl::Cleanup deduction_cleanup = &FnPtrFunction;
+
+    static_assert(
+        IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
+  }
+
+  {
+    auto factory_cleanup = absl::MakeCleanup(FnPtrFunction);
+    absl::Cleanup deduction_cleanup = FnPtrFunction;
+
+    static_assert(
+        IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
+  }
+}
+#endif  // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
+
+TYPED_TEST(CleanupTest, BasicUsage) {
+  bool called = false;
+
+  {
+    auto cleanup =
+        absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
+    EXPECT_FALSE(called);  // Constructor shouldn't invoke the callback
+  }
+
+  EXPECT_TRUE(called);  // Destructor should invoke the callback
+}
+
+TYPED_TEST(CleanupTest, BasicUsageWithFunctionPointer) {
+  fn_ptr_called = false;
+
+  {
+    auto cleanup = absl::MakeCleanup(TypeParam::AsCallback(&FnPtrFunction));
+    EXPECT_FALSE(fn_ptr_called);  // Constructor shouldn't invoke the callback
+  }
+
+  EXPECT_TRUE(fn_ptr_called);  // Destructor should invoke the callback
+}
+
+TYPED_TEST(CleanupTest, Cancel) {
+  bool called = false;
+
+  {
+    auto cleanup =
+        absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
+    EXPECT_FALSE(called);  // Constructor shouldn't invoke the callback
+
+    std::move(cleanup).Cancel();
+    EXPECT_FALSE(called);  // Cancel shouldn't invoke the callback
+  }
+
+  EXPECT_FALSE(called);  // Destructor shouldn't invoke the callback
+}
+
+TYPED_TEST(CleanupTest, Invoke) {
+  bool called = false;
+
+  {
+    auto cleanup =
+        absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
+    EXPECT_FALSE(called);  // Constructor shouldn't invoke the callback
+
+    std::move(cleanup).Invoke();
+    EXPECT_TRUE(called);  // Invoke should invoke the callback
+
+    called = false;  // Reset tracker before destructor runs
+  }
+
+  EXPECT_FALSE(called);  // Destructor shouldn't invoke the callback
+}
+
+TYPED_TEST(CleanupTest, Move) {
+  bool called = false;
+
+  {
+    auto moved_from_cleanup =
+        absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
+    EXPECT_FALSE(called);  // Constructor shouldn't invoke the callback
+
+    {
+      auto moved_to_cleanup = std::move(moved_from_cleanup);
+      EXPECT_FALSE(called);  // Move shouldn't invoke the callback
+    }
+
+    EXPECT_TRUE(called);  // Destructor should invoke the callback
+
+    called = false;  // Reset tracker before destructor runs
+  }
+
+  EXPECT_FALSE(called);  // Destructor shouldn't invoke the callback
+}
+
+}  // namespace
diff --git a/absl/cleanup/internal/cleanup.h b/absl/cleanup/internal/cleanup.h
new file mode 100644
index 0000000..b4c4073
--- /dev/null
+++ b/absl/cleanup/internal/cleanup.h
@@ -0,0 +1,81 @@
+// Copyright 2021 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_CLEANUP_INTERNAL_CLEANUP_H_
+#define ABSL_CLEANUP_INTERNAL_CLEANUP_H_
+
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/internal/invoke.h"
+#include "absl/base/thread_annotations.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+namespace cleanup_internal {
+
+struct Tag {};
+
+template <typename Arg, typename... Args>
+constexpr bool WasDeduced() {
+  return (std::is_same<cleanup_internal::Tag, Arg>::value) &&
+         (sizeof...(Args) == 0);
+}
+
+template <typename Callback>
+constexpr bool ReturnsVoid() {
+  return (std::is_same<base_internal::invoke_result_t<Callback>, void>::value);
+}
+
+template <typename Callback>
+class Storage {
+ public:
+  Storage() = delete;
+
+  Storage(Callback callback, bool is_callback_engaged)
+      : callback_(std::move(callback)),
+        is_callback_engaged_(is_callback_engaged) {}
+
+  Storage(Storage&& other)
+      : callback_(std::move(other.callback_)),
+        is_callback_engaged_(
+            absl::exchange(other.is_callback_engaged_, false)) {}
+
+  Storage(const Storage& other) = delete;
+
+  Storage& operator=(Storage&& other) = delete;
+
+  Storage& operator=(const Storage& other) = delete;
+
+  bool IsCallbackEngaged() const { return is_callback_engaged_; }
+
+  void DisengageCallback() { is_callback_engaged_ = false; }
+
+  void InvokeCallback() ABSL_NO_THREAD_SAFETY_ANALYSIS {
+    std::move(callback_)();
+  }
+
+ private:
+  Callback callback_;
+  bool is_callback_engaged_;
+};
+
+}  // namespace cleanup_internal
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CLEANUP_INTERNAL_CLEANUP_H_
diff --git a/absl/compiler_config_setting.bzl b/absl/compiler_config_setting.bzl
deleted file mode 100644
index 6696229..0000000
--- a/absl/compiler_config_setting.bzl
+++ /dev/null
@@ -1,38 +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.
-
-"""Creates config_setting that allows selecting based on 'compiler' value."""
-
-def create_llvm_config(name, visibility):
-    # The "do_not_use_tools_cpp_compiler_present" attribute exists to
-    # distinguish between older versions of Bazel that do not support
-    # "@bazel_tools//tools/cpp:compiler" flag_value, and newer ones that do.
-    # In the future, the only way to select on the compiler will be through
-    # flag_values{"@bazel_tools//tools/cpp:compiler"} and the else branch can
-    # be removed.
-    if hasattr(cc_common, "do_not_use_tools_cpp_compiler_present"):
-        native.config_setting(
-            name = name,
-            flag_values = {
-                "@bazel_tools//tools/cpp:compiler": "llvm",
-            },
-            visibility = visibility,
-        )
-    else:
-        native.config_setting(
-            name = name,
-            values = {"compiler": "llvm"},
-            visibility = visibility,
-        )
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
index f221714..f22fdc6 100644
--- a/absl/container/BUILD.bazel
+++ b/absl/container/BUILD.bazel
@@ -14,7 +14,7 @@
 # limitations under the License.
 #
 
-load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
@@ -24,7 +24,7 @@
 
 package(default_visibility = ["//visibility:public"])
 
-licenses(["notice"])  # Apache 2.0
+licenses(["notice"])
 
 cc_library(
     name = "compressed_tuple",
@@ -60,6 +60,7 @@
     deps = [
         ":compressed_tuple",
         "//absl/algorithm",
+        "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:dynamic_annotations",
         "//absl/base:throw_delegate",
@@ -73,7 +74,9 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        ":counting_allocator",
         ":fixed_array",
+        "//absl/base:config",
         "//absl/base:exception_testing",
         "//absl/hash:hash_testing",
         "//absl/memory",
@@ -153,6 +156,7 @@
         ":counting_allocator",
         ":inlined_vector",
         ":test_instance_tracker",
+        "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:exception_testing",
         "//absl/base:raw_logging_internal",
@@ -255,6 +259,7 @@
         ":unordered_map_lookup_test",
         ":unordered_map_members_test",
         ":unordered_map_modifiers_test",
+        "//absl/base:raw_logging_internal",
         "//absl/types:any",
         "@com_google_googletest//:gtest_main",
     ],
@@ -288,6 +293,7 @@
         ":unordered_set_lookup_test",
         ":unordered_set_members_test",
         ":unordered_set_modifiers_test",
+        "//absl/base:raw_logging_internal",
         "//absl/memory",
         "//absl/strings",
         "@com_google_googletest//:gtest_main",
@@ -363,7 +369,9 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        "//absl/base:config",
         "//absl/memory",
+        "//absl/meta:type_traits",
         "//absl/utility",
     ],
 )
@@ -376,6 +384,7 @@
     tags = NOTEST_TAGS_NONMOBILE,
     deps = [
         ":container_memory",
+        ":test_instance_tracker",
         "//absl/strings",
         "@com_google_googletest//:gtest_main",
     ],
@@ -390,6 +399,7 @@
         "//absl/base:config",
         "//absl/hash",
         "//absl/strings",
+        "//absl/strings:cord",
     ],
 )
 
@@ -402,7 +412,10 @@
     deps = [
         ":hash_function_defaults",
         "//absl/hash",
+        "//absl/random",
         "//absl/strings",
+        "//absl/strings:cord",
+        "//absl/strings:cord_test_helpers",
         "@com_google_googletest//:gtest_main",
     ],
 )
@@ -586,12 +599,12 @@
         ":hashtablez_sampler",
         ":have_sse",
         ":layout",
-        "//absl/base:bits",
         "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:endian",
         "//absl/memory",
         "//absl/meta:type_traits",
+        "//absl/numeric:bits",
         "//absl/utility",
     ],
 )
@@ -609,6 +622,7 @@
         ":hashtable_debug",
         ":raw_hash_set",
         "//absl/base",
+        "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:raw_logging_internal",
         "//absl/strings",
@@ -616,6 +630,45 @@
     ],
 )
 
+cc_binary(
+    name = "raw_hash_set_benchmark",
+    testonly = 1,
+    srcs = ["internal/raw_hash_set_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":hash_function_defaults",
+        ":raw_hash_set",
+        "//absl/base:raw_logging_internal",
+        "//absl/strings:str_format",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_binary(
+    name = "raw_hash_set_probe_benchmark",
+    testonly = 1,
+    srcs = ["internal/raw_hash_set_probe_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = select({
+        "//conditions:default": [],
+    }) + ABSL_DEFAULT_LINKOPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":flat_hash_map",
+        ":hash_function_defaults",
+        ":hashtable_debug",
+        ":raw_hash_set",
+        "//absl/random",
+        "//absl/random:distributions",
+        "//absl/strings",
+        "//absl/strings:str_format",
+    ],
+)
+
 cc_test(
     name = "raw_hash_set_allocator_test",
     size = "small",
@@ -636,6 +689,7 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/meta:type_traits",
         "//absl/strings",
@@ -654,6 +708,7 @@
     visibility = ["//visibility:private"],
     deps = [
         ":layout",
+        "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:raw_logging_internal",
         "//absl/types:span",
@@ -661,6 +716,22 @@
     ],
 )
 
+cc_binary(
+    name = "layout_benchmark",
+    testonly = 1,
+    srcs = ["internal/layout_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":layout",
+        "//absl/base:core_headers",
+        "//absl/base:raw_logging_internal",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
 cc_library(
     name = "tracked",
     testonly = 1,
@@ -828,6 +899,7 @@
         "//absl/memory",
         "//absl/meta:type_traits",
         "//absl/strings",
+        "//absl/strings:cord",
         "//absl/types:compare",
         "//absl/utility",
     ],
@@ -844,6 +916,7 @@
         ":btree",
         ":flat_hash_set",
         "//absl/strings",
+        "//absl/strings:cord",
         "//absl/time",
     ],
 )
@@ -895,6 +968,7 @@
         "//absl/flags:flag",
         "//absl/hash",
         "//absl/memory",
+        "//absl/strings:cord",
         "//absl/strings:str_format",
         "//absl/time",
         "@com_github_google_benchmark//:benchmark_main",
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt
index e702ba8..2d7d0e6 100644
--- a/absl/container/CMakeLists.txt
+++ b/absl/container/CMakeLists.txt
@@ -14,15 +14,6 @@
 # limitations under the License.
 #
 
-# This is deprecated and will be removed in the future.  It also doesn't do
-# anything anyways.  Prefer to use the library associated with the API you are
-# using.
-absl_cc_library(
-  NAME
-    container
-  PUBLIC
-)
-
 absl_cc_library(
   NAME
     btree
@@ -40,6 +31,7 @@
     absl::compare
     absl::compressed_tuple
     absl::container_memory
+    absl::cord
     absl::core_headers
     absl::layout
     absl::memory
@@ -60,6 +52,7 @@
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
     absl::btree
+    absl::cord
     absl::flat_hash_set
     absl::strings
     absl::time
@@ -129,6 +122,7 @@
   DEPS
     absl::compressed_tuple
     absl::algorithm
+    absl::config
     absl::core_headers
     absl::dynamic_annotations
     absl::throw_delegate
@@ -145,6 +139,8 @@
     ${ABSL_TEST_COPTS}
   DEPS
     absl::fixed_array
+    absl::counting_allocator
+    absl::config
     absl::exception_testing
     absl::hash_testing
     absl::memory
@@ -219,6 +215,7 @@
     absl::counting_allocator
     absl::inlined_vector
     absl::test_instance_tracker
+    absl::config
     absl::core_headers
     absl::exception_testing
     absl::hash_testing
@@ -299,6 +296,7 @@
     absl::unordered_map_members_test
     absl::unordered_map_modifiers_test
     absl::any
+    absl::raw_logging_internal
     gmock_main
 )
 
@@ -335,6 +333,7 @@
     absl::unordered_set_members_test
     absl::unordered_set_modifiers_test
     absl::memory
+    absl::raw_logging_internal
     absl::strings
     gmock_main
 )
@@ -416,7 +415,9 @@
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
+    absl::config
     absl::memory
+    absl::type_traits
     absl::utility
   PUBLIC
 )
@@ -431,6 +432,7 @@
   DEPS
     absl::container_memory
     absl::strings
+    absl::test_instance_tracker
     gmock_main
 )
 
@@ -443,6 +445,7 @@
     ${ABSL_DEFAULT_COPTS}
   DEPS
     absl::config
+    absl::cord
     absl::hash
     absl::strings
   PUBLIC
@@ -456,8 +459,11 @@
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
+    absl::cord
+    absl::cord_test_helpers
     absl::hash_function_defaults
     absl::hash
+    absl::random_random
     absl::strings
     gmock_main
 )
@@ -683,6 +689,7 @@
     absl::hashtable_debug
     absl::raw_hash_set
     absl::base
+    absl::config
     absl::core_headers
     absl::raw_logging_internal
     absl::strings
@@ -711,6 +718,7 @@
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
+    absl::config
     absl::core_headers
     absl::meta
     absl::strings
@@ -728,6 +736,7 @@
     ${ABSL_TEST_COPTS}
   DEPS
     absl::layout
+    absl::config
     absl::core_headers
     absl::raw_logging_internal
     absl::span
diff --git a/absl/container/btree_benchmark.cc b/absl/container/btree_benchmark.cc
index 4af92f9..65b6790 100644
--- a/absl/container/btree_benchmark.cc
+++ b/absl/container/btree_benchmark.cc
@@ -26,6 +26,7 @@
 #include <unordered_set>
 #include <vector>
 
+#include "benchmark/benchmark.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/container/btree_map.h"
 #include "absl/container/btree_set.h"
@@ -36,9 +37,9 @@
 #include "absl/flags/flag.h"
 #include "absl/hash/hash.h"
 #include "absl/memory/memory.h"
+#include "absl/strings/cord.h"
 #include "absl/strings/str_format.h"
 #include "absl/time/time.h"
-#include "benchmark/benchmark.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -100,36 +101,24 @@
   BM_InsertImpl<T>(state, true);
 }
 
-// container::insert sometimes returns a pair<iterator, bool> and sometimes
-// returns an iterator (for multi- containers).
-template <typename Iter>
-Iter GetIterFromInsert(const std::pair<Iter, bool>& pair) {
-  return pair.first;
-}
-template <typename Iter>
-Iter GetIterFromInsert(const Iter iter) {
-  return iter;
-}
-
-// Benchmark insertion of values into a container at the end.
+// Benchmark inserting the first few elements in a container. In b-tree, this is
+// when the root node grows.
 template <typename T>
-void BM_InsertEnd(benchmark::State& state) {
+void BM_InsertSmall(benchmark::State& state) {
   using V = typename remove_pair_const<typename T::value_type>::type;
-  typename KeyOfValue<typename T::key_type, V>::type key_of_value;
 
+  const int kSize = 8;
+  std::vector<V> values = GenerateValues<V>(kSize);
   T container;
-  const int kSize = 10000;
-  for (int i = 0; i < kSize; ++i) {
-    container.insert(Generator<V>(kSize)(i));
-  }
-  V v = Generator<V>(kSize)(kSize - 1);
-  typename T::key_type k = key_of_value(v);
 
-  auto it = container.find(k);
-  while (state.KeepRunning()) {
-    // Repeatedly removing then adding v.
-    container.erase(it);
-    it = GetIterFromInsert(container.insert(v));
+  while (state.KeepRunningBatch(kSize)) {
+    for (int i = 0; i < kSize; ++i) {
+      benchmark::DoNotOptimize(container.insert(values[i]));
+    }
+    state.PauseTiming();
+    // Do not measure the time it takes to clear the container.
+    container.clear();
+    state.ResumeTiming();
   }
 }
 
@@ -438,6 +427,7 @@
 STL_ORDERED_TYPES(int32_t);
 STL_ORDERED_TYPES(int64_t);
 STL_ORDERED_TYPES(StdString);
+STL_ORDERED_TYPES(Cord);
 STL_ORDERED_TYPES(Time);
 
 #define STL_UNORDERED_TYPES(value)                                       \
@@ -458,6 +448,8 @@
   using stl_unordered_multimap_##value =                                       \
       std::unordered_multimap<value, intptr_t, hash>
 
+STL_UNORDERED_TYPES_CUSTOM_HASH(Cord, absl::Hash<absl::Cord>);
+
 STL_UNORDERED_TYPES(int32_t);
 STL_UNORDERED_TYPES(int64_t);
 STL_UNORDERED_TYPES(StdString);
@@ -478,6 +470,7 @@
 BTREE_TYPES(int32_t);
 BTREE_TYPES(int64_t);
 BTREE_TYPES(StdString);
+BTREE_TYPES(Cord);
 BTREE_TYPES(Time);
 
 #define MY_BENCHMARK4(type, func)                                              \
@@ -487,7 +480,7 @@
 #define MY_BENCHMARK3(type)               \
   MY_BENCHMARK4(type, Insert);            \
   MY_BENCHMARK4(type, InsertSorted);      \
-  MY_BENCHMARK4(type, InsertEnd);         \
+  MY_BENCHMARK4(type, InsertSmall);       \
   MY_BENCHMARK4(type, Lookup);            \
   MY_BENCHMARK4(type, FullLookup);        \
   MY_BENCHMARK4(type, Delete);            \
@@ -526,6 +519,7 @@
 MY_BENCHMARK(int32_t);
 MY_BENCHMARK(int64_t);
 MY_BENCHMARK(StdString);
+MY_BENCHMARK(Cord);
 MY_BENCHMARK(Time);
 
 // Define a type whose size and cost of moving are independently customizable.
@@ -538,19 +532,19 @@
   BigType() : BigType(0) {}
   explicit BigType(int x) { std::iota(values.begin(), values.end(), x); }
 
-  void Copy(const BigType& x) {
-    for (int i = 0; i < Size && i < Copies; ++i) values[i] = x.values[i];
+  void Copy(const BigType& other) {
+    for (int i = 0; i < Size && i < Copies; ++i) values[i] = other.values[i];
     // If Copies > Size, do extra copies.
     for (int i = Size, idx = 0; i < Copies; ++i) {
-      int64_t tmp = x.values[idx];
+      int64_t tmp = other.values[idx];
       benchmark::DoNotOptimize(tmp);
       idx = idx + 1 == Size ? 0 : idx + 1;
     }
   }
 
-  BigType(const BigType& x) { Copy(x); }
-  BigType& operator=(const BigType& x) {
-    Copy(x);
+  BigType(const BigType& other) { Copy(other); }
+  BigType& operator=(const BigType& other) {
+    Copy(other);
     return *this;
   }
 
@@ -641,14 +635,14 @@
   explicit BigTypePtr(int x) {
     ptr = absl::make_unique<BigType<Size, Size>>(x);
   }
-  BigTypePtr(const BigTypePtr& x) {
-    ptr = absl::make_unique<BigType<Size, Size>>(*x.ptr);
+  BigTypePtr(const BigTypePtr& other) {
+    ptr = absl::make_unique<BigType<Size, Size>>(*other.ptr);
   }
-  BigTypePtr(BigTypePtr&& x) noexcept = default;
-  BigTypePtr& operator=(const BigTypePtr& x) {
-    ptr = absl::make_unique<BigType<Size, Size>>(*x.ptr);
+  BigTypePtr(BigTypePtr&& other) noexcept = default;
+  BigTypePtr& operator=(const BigTypePtr& other) {
+    ptr = absl::make_unique<BigType<Size, Size>>(*other.ptr);
   }
-  BigTypePtr& operator=(BigTypePtr&& x) noexcept = default;
+  BigTypePtr& operator=(BigTypePtr&& other) noexcept = default;
 
   bool operator<(const BigTypePtr& other) const { return *ptr < *other.ptr; }
   bool operator==(const BigTypePtr& other) const { return *ptr == *other.ptr; }
diff --git a/absl/container/btree_map.h b/absl/container/btree_map.h
index d23f4ee..ea49d44 100644
--- a/absl/container/btree_map.h
+++ b/absl/container/btree_map.h
@@ -185,7 +185,7 @@
   // template <typename K> size_type erase(const K& key):
   //
   //   Erases the element with the matching key, if it exists, returning the
-  //   number of elements erased.
+  //   number of elements erased (0 or 1).
   using Base::erase;
 
   // btree_map::insert()
@@ -318,13 +318,18 @@
   //   Extracts the element at the indicated position and returns a node handle
   //   owning that extracted data.
   //
-  // template <typename K> node_type extract(const K& x):
+  // template <typename K> node_type extract(const K& k):
   //
   //   Extracts the element with the key matching the passed key value and
   //   returns a node handle owning that extracted data. If the `btree_map`
   //   does not contain an element with a matching key, this function returns an
   //   empty node handle.
   //
+  // NOTE: when compiled in an earlier version of C++ than C++17,
+  // `node_type::key()` returns a const reference to the key instead of a
+  // mutable reference. We cannot safely return a mutable reference without
+  // std::launder (which is not available before C++17).
+  //
   // NOTE: In this context, `node_type` refers to the C++17 concept of a
   // move-only type that owns and provides access to the elements in associative
   // containers (https://en.cppreference.com/w/cpp/container/node_handle).
@@ -379,9 +384,8 @@
 
   // btree_map::equal_range()
   //
-  // Returns a closed range [first, last], defined by a `std::pair` of two
-  // iterators, containing all elements with the passed key in the
-  // `btree_map`.
+  // Returns a half-open range [first, last), defined by a `std::pair` of two
+  // iterators, containing all elements with the passed key in the `btree_map`.
   using Base::equal_range;
 
   // btree_map::find()
@@ -645,13 +649,18 @@
   //   Extracts the element at the indicated position and returns a node handle
   //   owning that extracted data.
   //
-  // template <typename K> node_type extract(const K& x):
+  // template <typename K> node_type extract(const K& k):
   //
   //   Extracts the element with the key matching the passed key value and
   //   returns a node handle owning that extracted data. If the `btree_multimap`
   //   does not contain an element with a matching key, this function returns an
   //   empty node handle.
   //
+  // NOTE: when compiled in an earlier version of C++ than C++17,
+  // `node_type::key()` returns a const reference to the key instead of a
+  // mutable reference. We cannot safely return a mutable reference without
+  // std::launder (which is not available before C++17).
+  //
   // NOTE: In this context, `node_type` refers to the C++17 concept of a
   // move-only type that owns and provides access to the elements in associative
   // containers (https://en.cppreference.com/w/cpp/container/node_handle).
@@ -699,7 +708,7 @@
 
   // btree_multimap::equal_range()
   //
-  // Returns a closed range [first, last], defined by a `std::pair` of two
+  // Returns a half-open range [first, last), defined by a `std::pair` of two
   // iterators, containing all elements with the passed key in the
   // `btree_multimap`.
   using Base::equal_range;
diff --git a/absl/container/btree_set.h b/absl/container/btree_set.h
index 127fb94..21ef0a0 100644
--- a/absl/container/btree_set.h
+++ b/absl/container/btree_set.h
@@ -183,7 +183,7 @@
   // template <typename K> size_type erase(const K& key):
   //
   //   Erases the element with the matching key, if it exists, returning the
-  //   number of elements erased.
+  //   number of elements erased (0 or 1).
   using Base::erase;
 
   // btree_set::insert()
@@ -263,7 +263,7 @@
   //   Extracts the element at the indicated position and returns a node handle
   //   owning that extracted data.
   //
-  // template <typename K> node_type extract(const K& x):
+  // template <typename K> node_type extract(const K& k):
   //
   //   Extracts the element with the key matching the passed key value and
   //   returns a node handle owning that extracted data. If the `btree_set`
@@ -567,7 +567,7 @@
   //   Extracts the element at the indicated position and returns a node handle
   //   owning that extracted data.
   //
-  // template <typename K> node_type extract(const K& x):
+  // template <typename K> node_type extract(const K& k):
   //
   //   Extracts the element with the key matching the passed key value and
   //   returns a node handle owning that extracted data. If the `btree_multiset`
diff --git a/absl/container/btree_test.cc b/absl/container/btree_test.cc
index 9edf38f..74337df 100644
--- a/absl/container/btree_test.cc
+++ b/absl/container/btree_test.cc
@@ -15,6 +15,7 @@
 #include "absl/container/btree_test.h"
 
 #include <cstdint>
+#include <limits>
 #include <map>
 #include <memory>
 #include <stdexcept>
@@ -52,7 +53,9 @@
 using ::testing::ElementsAre;
 using ::testing::ElementsAreArray;
 using ::testing::IsEmpty;
+using ::testing::IsNull;
 using ::testing::Pair;
+using ::testing::SizeIs;
 
 template <typename T, typename U>
 void CheckPairEquals(const T &x, const U &y) {
@@ -89,8 +92,8 @@
 
  public:
   base_checker() : const_tree_(tree_) {}
-  base_checker(const base_checker &x)
-      : tree_(x.tree_), const_tree_(tree_), checker_(x.checker_) {}
+  base_checker(const base_checker &other)
+      : tree_(other.tree_), const_tree_(tree_), checker_(other.checker_) {}
   template <typename InputIterator>
   base_checker(InputIterator b, InputIterator e)
       : tree_(b, e), const_tree_(tree_), checker_(b, e) {}
@@ -124,11 +127,11 @@
     }
     return tree_iter;
   }
-  void value_check(const value_type &x) {
+  void value_check(const value_type &v) {
     typename KeyOfValue<typename TreeType::key_type,
                         typename TreeType::value_type>::type key_of_value;
-    const key_type &key = key_of_value(x);
-    CheckPairEquals(*find(key), x);
+    const key_type &key = key_of_value(v);
+    CheckPairEquals(*find(key), v);
     lower_bound(key);
     upper_bound(key);
     equal_range(key);
@@ -187,9 +190,9 @@
     return res;
   }
 
-  base_checker &operator=(const base_checker &x) {
-    tree_ = x.tree_;
-    checker_ = x.checker_;
+  base_checker &operator=(const base_checker &other) {
+    tree_ = other.tree_;
+    checker_ = other.checker_;
     return *this;
   }
 
@@ -250,9 +253,9 @@
     tree_.clear();
     checker_.clear();
   }
-  void swap(base_checker &x) {
-    tree_.swap(x.tree_);
-    checker_.swap(x.checker_);
+  void swap(base_checker &other) {
+    tree_.swap(other.tree_);
+    checker_.swap(other.checker_);
   }
 
   void verify() const {
@@ -323,28 +326,28 @@
 
  public:
   unique_checker() : super_type() {}
-  unique_checker(const unique_checker &x) : super_type(x) {}
+  unique_checker(const unique_checker &other) : super_type(other) {}
   template <class InputIterator>
   unique_checker(InputIterator b, InputIterator e) : super_type(b, e) {}
   unique_checker &operator=(const unique_checker &) = default;
 
   // Insertion routines.
-  std::pair<iterator, bool> insert(const value_type &x) {
+  std::pair<iterator, bool> insert(const value_type &v) {
     int size = this->tree_.size();
     std::pair<typename CheckerType::iterator, bool> checker_res =
-        this->checker_.insert(x);
-    std::pair<iterator, bool> tree_res = this->tree_.insert(x);
+        this->checker_.insert(v);
+    std::pair<iterator, bool> tree_res = this->tree_.insert(v);
     CheckPairEquals(*tree_res.first, *checker_res.first);
     EXPECT_EQ(tree_res.second, checker_res.second);
     EXPECT_EQ(this->tree_.size(), this->checker_.size());
     EXPECT_EQ(this->tree_.size(), size + tree_res.second);
     return tree_res;
   }
-  iterator insert(iterator position, const value_type &x) {
+  iterator insert(iterator position, const value_type &v) {
     int size = this->tree_.size();
     std::pair<typename CheckerType::iterator, bool> checker_res =
-        this->checker_.insert(x);
-    iterator tree_res = this->tree_.insert(position, x);
+        this->checker_.insert(v);
+    iterator tree_res = this->tree_.insert(position, v);
     CheckPairEquals(*tree_res, *checker_res.first);
     EXPECT_EQ(this->tree_.size(), this->checker_.size());
     EXPECT_EQ(this->tree_.size(), size + checker_res.second);
@@ -371,25 +374,25 @@
 
  public:
   multi_checker() : super_type() {}
-  multi_checker(const multi_checker &x) : super_type(x) {}
+  multi_checker(const multi_checker &other) : super_type(other) {}
   template <class InputIterator>
   multi_checker(InputIterator b, InputIterator e) : super_type(b, e) {}
   multi_checker &operator=(const multi_checker &) = default;
 
   // Insertion routines.
-  iterator insert(const value_type &x) {
+  iterator insert(const value_type &v) {
     int size = this->tree_.size();
-    auto checker_res = this->checker_.insert(x);
-    iterator tree_res = this->tree_.insert(x);
+    auto checker_res = this->checker_.insert(v);
+    iterator tree_res = this->tree_.insert(v);
     CheckPairEquals(*tree_res, *checker_res);
     EXPECT_EQ(this->tree_.size(), this->checker_.size());
     EXPECT_EQ(this->tree_.size(), size + 1);
     return tree_res;
   }
-  iterator insert(iterator position, const value_type &x) {
+  iterator insert(iterator position, const value_type &v) {
     int size = this->tree_.size();
-    auto checker_res = this->checker_.insert(x);
-    iterator tree_res = this->tree_.insert(position, x);
+    auto checker_res = this->checker_.insert(v);
+    iterator tree_res = this->tree_.insert(position, v);
     CheckPairEquals(*tree_res, *checker_res);
     EXPECT_EQ(this->tree_.size(), this->checker_.size());
     EXPECT_EQ(this->tree_.size(), size + 1);
@@ -812,10 +815,12 @@
 TEST(Btree, set_int32) { SetTest<int32_t>(); }
 TEST(Btree, set_int64) { SetTest<int64_t>(); }
 TEST(Btree, set_string) { SetTest<std::string>(); }
+TEST(Btree, set_cord) { SetTest<absl::Cord>(); }
 TEST(Btree, set_pair) { SetTest<std::pair<int, int>>(); }
 TEST(Btree, map_int32) { MapTest<int32_t>(); }
 TEST(Btree, map_int64) { MapTest<int64_t>(); }
 TEST(Btree, map_string) { MapTest<std::string>(); }
+TEST(Btree, map_cord) { MapTest<absl::Cord>(); }
 TEST(Btree, map_pair) { MapTest<std::pair<int, int>>(); }
 
 template <typename K, int N = 256>
@@ -847,10 +852,12 @@
 TEST(Btree, multiset_int32) { MultiSetTest<int32_t>(); }
 TEST(Btree, multiset_int64) { MultiSetTest<int64_t>(); }
 TEST(Btree, multiset_string) { MultiSetTest<std::string>(); }
+TEST(Btree, multiset_cord) { MultiSetTest<absl::Cord>(); }
 TEST(Btree, multiset_pair) { MultiSetTest<std::pair<int, int>>(); }
 TEST(Btree, multimap_int32) { MultiMapTest<int32_t>(); }
 TEST(Btree, multimap_int64) { MultiMapTest<int64_t>(); }
 TEST(Btree, multimap_string) { MultiMapTest<std::string>(); }
+TEST(Btree, multimap_cord) { MultiMapTest<absl::Cord>(); }
 TEST(Btree, multimap_pair) { MultiMapTest<std::pair<int, int>>(); }
 
 struct CompareIntToString {
@@ -1176,6 +1183,103 @@
   EXPECT_EQ(1, tmap.size());
 }
 
+}  // namespace
+
+class BtreeNodePeer {
+ public:
+  // Yields the size of a leaf node with a specific number of values.
+  template <typename ValueType>
+  constexpr static size_t GetTargetNodeSize(size_t target_values_per_node) {
+    return btree_node<
+        set_params<ValueType, std::less<ValueType>, std::allocator<ValueType>,
+                   /*TargetNodeSize=*/256,  // This parameter isn't used here.
+                   /*Multi=*/false>>::SizeWithNSlots(target_values_per_node);
+  }
+
+  // Yields the number of slots in a (non-root) leaf node for this btree.
+  template <typename Btree>
+  constexpr static size_t GetNumSlotsPerNode() {
+    return btree_node<typename Btree::params_type>::kNodeSlots;
+  }
+
+  template <typename Btree>
+  constexpr static size_t GetMaxFieldType() {
+    return std::numeric_limits<
+        typename btree_node<typename Btree::params_type>::field_type>::max();
+  }
+
+  template <typename Btree>
+  constexpr static bool UsesLinearNodeSearch() {
+    return btree_node<typename Btree::params_type>::use_linear_search::value;
+  }
+};
+
+namespace {
+
+class BtreeMapTest : public ::testing::Test {
+ public:
+  struct Key {};
+  struct Cmp {
+    template <typename T>
+    bool operator()(T, T) const {
+      return false;
+    }
+  };
+
+  struct KeyLin {
+    using absl_btree_prefer_linear_node_search = std::true_type;
+  };
+  struct CmpLin : Cmp {
+    using absl_btree_prefer_linear_node_search = std::true_type;
+  };
+
+  struct KeyBin {
+    using absl_btree_prefer_linear_node_search = std::false_type;
+  };
+  struct CmpBin : Cmp {
+    using absl_btree_prefer_linear_node_search = std::false_type;
+  };
+
+  template <typename K, typename C>
+  static bool IsLinear() {
+    return BtreeNodePeer::UsesLinearNodeSearch<absl::btree_map<K, int, C>>();
+  }
+};
+
+TEST_F(BtreeMapTest, TestLinearSearchPreferredForKeyLinearViaAlias) {
+  // Test requesting linear search by directly exporting an alias.
+  EXPECT_FALSE((IsLinear<Key, Cmp>()));
+  EXPECT_TRUE((IsLinear<KeyLin, Cmp>()));
+  EXPECT_TRUE((IsLinear<Key, CmpLin>()));
+  EXPECT_TRUE((IsLinear<KeyLin, CmpLin>()));
+}
+
+TEST_F(BtreeMapTest, LinearChoiceTree) {
+  // Cmp has precedence, and is forcing binary
+  EXPECT_FALSE((IsLinear<Key, CmpBin>()));
+  EXPECT_FALSE((IsLinear<KeyLin, CmpBin>()));
+  EXPECT_FALSE((IsLinear<KeyBin, CmpBin>()));
+  EXPECT_FALSE((IsLinear<int, CmpBin>()));
+  EXPECT_FALSE((IsLinear<std::string, CmpBin>()));
+  // Cmp has precedence, and is forcing linear
+  EXPECT_TRUE((IsLinear<Key, CmpLin>()));
+  EXPECT_TRUE((IsLinear<KeyLin, CmpLin>()));
+  EXPECT_TRUE((IsLinear<KeyBin, CmpLin>()));
+  EXPECT_TRUE((IsLinear<int, CmpLin>()));
+  EXPECT_TRUE((IsLinear<std::string, CmpLin>()));
+  // Cmp has no preference, Key determines linear vs binary.
+  EXPECT_FALSE((IsLinear<Key, Cmp>()));
+  EXPECT_TRUE((IsLinear<KeyLin, Cmp>()));
+  EXPECT_FALSE((IsLinear<KeyBin, Cmp>()));
+  // arithmetic key w/ std::less or std::greater: linear
+  EXPECT_TRUE((IsLinear<int, std::less<int>>()));
+  EXPECT_TRUE((IsLinear<double, std::greater<double>>()));
+  // arithmetic key w/ custom compare: binary
+  EXPECT_FALSE((IsLinear<int, Cmp>()));
+  // non-arithmetic key: binary
+  EXPECT_FALSE((IsLinear<std::string, std::less<std::string>>()));
+}
+
 TEST(Btree, BtreeMapCanHoldMoveOnlyTypes) {
   absl::btree_map<std::string, std::unique_ptr<std::string>> m;
 
@@ -1268,6 +1372,8 @@
   AssertKeyCompareToAdapted<std::less<absl::string_view>, absl::string_view>();
   AssertKeyCompareToAdapted<std::greater<absl::string_view>,
                             absl::string_view>();
+  AssertKeyCompareToAdapted<std::less<absl::Cord>, absl::Cord>();
+  AssertKeyCompareToAdapted<std::greater<absl::Cord>, absl::Cord>();
   AssertKeyCompareToNotAdapted<std::less<int>, int>();
   AssertKeyCompareToNotAdapted<std::greater<int>, int>();
 }
@@ -1319,28 +1425,6 @@
   EXPECT_EQ(tracker.swaps(), 0);
 }
 
-}  // namespace
-
-class BtreeNodePeer {
- public:
-  // Yields the size of a leaf node with a specific number of values.
-  template <typename ValueType>
-  constexpr static size_t GetTargetNodeSize(size_t target_values_per_node) {
-    return btree_node<
-        set_params<ValueType, std::less<ValueType>, std::allocator<ValueType>,
-                   /*TargetNodeSize=*/256,  // This parameter isn't used here.
-                   /*Multi=*/false>>::SizeWithNValues(target_values_per_node);
-  }
-
-  // Yields the number of values in a (non-root) leaf node for this set.
-  template <typename Set>
-  constexpr static size_t GetNumValuesPerNode() {
-    return btree_node<typename Set::params_type>::kNodeValues;
-  }
-};
-
-namespace {
-
 // A btree set with a specific number of values per node.
 template <typename Key, int TargetValuesPerNode, typename Cmp = std::less<Key>>
 class SizedBtreeSet
@@ -1374,7 +1458,7 @@
 TEST(Btree, MovesComparisonsCopiesSwapsTracking) {
   InstanceTracker tracker;
   // Note: this is minimum number of values per node.
-  SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/3> set3;
+  SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/4> set4;
   // Note: this is the default number of values per node for a set of int32s
   // (with 64-bit pointers).
   SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/61> set61;
@@ -1385,28 +1469,28 @@
   std::vector<int> values =
       GenerateValuesWithSeed<int>(10000, 1 << 22, /*seed=*/23);
 
-  EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set3)>(), 3);
-  EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>(), 61);
-  EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set100)>(), 100);
+  EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set4)>(), 4);
+  EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>(), 61);
+  EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set100)>(), 100);
   if (sizeof(void *) == 8) {
-    EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<absl::btree_set<int32_t>>(),
-              BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>());
+    EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<absl::btree_set<int32_t>>(),
+              BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>());
   }
 
   // Test key insertion/deletion in random order.
-  ExpectOperationCounts(45281, 132551, values, &tracker, &set3);
+  ExpectOperationCounts(56540, 134212, values, &tracker, &set4);
   ExpectOperationCounts(386718, 129807, values, &tracker, &set61);
   ExpectOperationCounts(586761, 130310, values, &tracker, &set100);
 
   // Test key insertion/deletion in sorted order.
   std::sort(values.begin(), values.end());
-  ExpectOperationCounts(26638, 92134, values, &tracker, &set3);
+  ExpectOperationCounts(24972, 85563, values, &tracker, &set4);
   ExpectOperationCounts(20208, 87757, values, &tracker, &set61);
   ExpectOperationCounts(20124, 96583, values, &tracker, &set100);
 
   // Test key insertion/deletion in reverse sorted order.
   std::reverse(values.begin(), values.end());
-  ExpectOperationCounts(49951, 119325, values, &tracker, &set3);
+  ExpectOperationCounts(54949, 127531, values, &tracker, &set4);
   ExpectOperationCounts(338813, 118266, values, &tracker, &set61);
   ExpectOperationCounts(534529, 125279, values, &tracker, &set100);
 }
@@ -1423,9 +1507,9 @@
 TEST(Btree, MovesComparisonsCopiesSwapsTrackingThreeWayCompare) {
   InstanceTracker tracker;
   // Note: this is minimum number of values per node.
-  SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/3,
+  SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/4,
                 MovableOnlyInstanceThreeWayCompare>
-      set3;
+      set4;
   // Note: this is the default number of values per node for a set of int32s
   // (with 64-bit pointers).
   SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/61,
@@ -1440,28 +1524,28 @@
   std::vector<int> values =
       GenerateValuesWithSeed<int>(10000, 1 << 22, /*seed=*/23);
 
-  EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set3)>(), 3);
-  EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>(), 61);
-  EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set100)>(), 100);
+  EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set4)>(), 4);
+  EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>(), 61);
+  EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set100)>(), 100);
   if (sizeof(void *) == 8) {
-    EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<absl::btree_set<int32_t>>(),
-              BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>());
+    EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<absl::btree_set<int32_t>>(),
+              BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>());
   }
 
   // Test key insertion/deletion in random order.
-  ExpectOperationCounts(45281, 122560, values, &tracker, &set3);
+  ExpectOperationCounts(56540, 124221, values, &tracker, &set4);
   ExpectOperationCounts(386718, 119816, values, &tracker, &set61);
   ExpectOperationCounts(586761, 120319, values, &tracker, &set100);
 
   // Test key insertion/deletion in sorted order.
   std::sort(values.begin(), values.end());
-  ExpectOperationCounts(26638, 92134, values, &tracker, &set3);
+  ExpectOperationCounts(24972, 85563, values, &tracker, &set4);
   ExpectOperationCounts(20208, 87757, values, &tracker, &set61);
   ExpectOperationCounts(20124, 96583, values, &tracker, &set100);
 
   // Test key insertion/deletion in reverse sorted order.
   std::reverse(values.begin(), values.end());
-  ExpectOperationCounts(49951, 109326, values, &tracker, &set3);
+  ExpectOperationCounts(54949, 117532, values, &tracker, &set4);
   ExpectOperationCounts(338813, 108267, values, &tracker, &set61);
   ExpectOperationCounts(534529, 115280, values, &tracker, &set100);
 }
@@ -1537,7 +1621,7 @@
 #ifdef ABSL_HAVE_EXCEPTIONS
   EXPECT_THROW(map.at(3), std::out_of_range);
 #else
-  EXPECT_DEATH(map.at(3), "absl::btree_map::at");
+  EXPECT_DEATH_IF_SUPPORTED(map.at(3), "absl::btree_map::at");
 #endif
 }
 
@@ -1954,6 +2038,30 @@
   EXPECT_EQ(res, ++other.begin());
 }
 
+TEST(Btree, ExtractMultiMapEquivalentKeys) {
+  // Note: using string keys means a three-way comparator.
+  absl::btree_multimap<std::string, int> map;
+  for (int i = 0; i < 100; ++i) {
+    for (int j = 0; j < 100; ++j) {
+      map.insert({absl::StrCat(i), j});
+    }
+  }
+
+  for (int i = 0; i < 100; ++i) {
+    const std::string key = absl::StrCat(i);
+    auto node_handle = map.extract(key);
+    EXPECT_EQ(node_handle.key(), key);
+    EXPECT_EQ(node_handle.mapped(), 0) << i;
+  }
+
+  for (int i = 0; i < 100; ++i) {
+    const std::string key = absl::StrCat(i);
+    auto node_handle = map.extract(key);
+    EXPECT_EQ(node_handle.key(), key);
+    EXPECT_EQ(node_handle.mapped(), 1) << i;
+  }
+}
+
 // For multisets, insert with hint also affects correctness because we need to
 // insert immediately before the hint if possible.
 struct InsertMultiHintData {
@@ -2095,6 +2203,31 @@
                                Pair(4, 1), Pair(4, 4), Pair(5, 5)));
 }
 
+TEST(Btree, MergeIntoSetMovableOnly) {
+  absl::btree_set<MovableOnlyInstance> src;
+  src.insert(MovableOnlyInstance(1));
+  absl::btree_multiset<MovableOnlyInstance> dst1;
+  dst1.insert(MovableOnlyInstance(2));
+  absl::btree_set<MovableOnlyInstance> dst2;
+
+  // Test merge into multiset.
+  dst1.merge(src);
+
+  EXPECT_TRUE(src.empty());
+  // ElementsAre/ElementsAreArray don't work with move-only types.
+  ASSERT_THAT(dst1, SizeIs(2));
+  EXPECT_EQ(*dst1.begin(), MovableOnlyInstance(1));
+  EXPECT_EQ(*std::next(dst1.begin()), MovableOnlyInstance(2));
+
+  // Test merge into set.
+  dst2.merge(dst1);
+
+  EXPECT_TRUE(dst1.empty());
+  ASSERT_THAT(dst2, SizeIs(2));
+  EXPECT_EQ(*dst2.begin(), MovableOnlyInstance(1));
+  EXPECT_EQ(*std::next(dst2.begin()), MovableOnlyInstance(2));
+}
+
 struct KeyCompareToWeakOrdering {
   template <typename T>
   absl::weak_ordering operator()(const T &a, const T &b) const {
@@ -2126,11 +2259,11 @@
 TEST(Btree, TryEmplaceBasicTest) {
   absl::btree_map<int, std::string> m;
 
-  // Should construct a std::string from the literal.
+  // Should construct a string from the literal.
   m.try_emplace(1, "one");
   EXPECT_EQ(1, m.size());
 
-  // Try other std::string constructors and const lvalue key.
+  // Try other string constructors and const lvalue key.
   const int key(42);
   m.try_emplace(key, 3, 'a');
   m.try_emplace(2, std::string("two"));
@@ -2398,6 +2531,368 @@
   m[n];
 }
 
+TEST(Btree, SetRangeConstructorAndInsertSupportExplicitConversionComparable) {
+  const absl::string_view names[] = {"n1", "n2"};
+
+  absl::btree_set<std::string> name_set1{std::begin(names), std::end(names)};
+  EXPECT_THAT(name_set1, ElementsAreArray(names));
+
+  absl::btree_set<std::string> name_set2;
+  name_set2.insert(std::begin(names), std::end(names));
+  EXPECT_THAT(name_set2, ElementsAreArray(names));
+}
+
+// A type that is explicitly convertible from int and counts constructor calls.
+struct ConstructorCounted {
+  explicit ConstructorCounted(int i) : i(i) { ++constructor_calls; }
+  bool operator==(int other) const { return i == other; }
+
+  int i;
+  static int constructor_calls;
+};
+int ConstructorCounted::constructor_calls = 0;
+
+struct ConstructorCountedCompare {
+  bool operator()(int a, const ConstructorCounted &b) const { return a < b.i; }
+  bool operator()(const ConstructorCounted &a, int b) const { return a.i < b; }
+  bool operator()(const ConstructorCounted &a,
+                  const ConstructorCounted &b) const {
+    return a.i < b.i;
+  }
+  using is_transparent = void;
+};
+
+TEST(Btree,
+     SetRangeConstructorAndInsertExplicitConvComparableLimitConstruction) {
+  const int i[] = {0, 1, 1};
+  ConstructorCounted::constructor_calls = 0;
+
+  absl::btree_set<ConstructorCounted, ConstructorCountedCompare> set{
+      std::begin(i), std::end(i)};
+  EXPECT_THAT(set, ElementsAre(0, 1));
+  EXPECT_EQ(ConstructorCounted::constructor_calls, 2);
+
+  set.insert(std::begin(i), std::end(i));
+  EXPECT_THAT(set, ElementsAre(0, 1));
+  EXPECT_EQ(ConstructorCounted::constructor_calls, 2);
+}
+
+TEST(Btree,
+     SetRangeConstructorAndInsertSupportExplicitConversionNonComparable) {
+  const int i[] = {0, 1};
+
+  absl::btree_set<std::vector<void *>> s1{std::begin(i), std::end(i)};
+  EXPECT_THAT(s1, ElementsAre(IsEmpty(), ElementsAre(IsNull())));
+
+  absl::btree_set<std::vector<void *>> s2;
+  s2.insert(std::begin(i), std::end(i));
+  EXPECT_THAT(s2, ElementsAre(IsEmpty(), ElementsAre(IsNull())));
+}
+
+// libstdc++ included with GCC 4.9 has a bug in the std::pair constructors that
+// prevents explicit conversions between pair types.
+// We only run this test for the libstdc++ from GCC 7 or newer because we can't
+// reliably check the libstdc++ version prior to that release.
+#if !defined(__GLIBCXX__) || \
+    (defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE >= 7)
+TEST(Btree, MapRangeConstructorAndInsertSupportExplicitConversionComparable) {
+  const std::pair<absl::string_view, int> names[] = {{"n1", 1}, {"n2", 2}};
+
+  absl::btree_map<std::string, int> name_map1{std::begin(names),
+                                              std::end(names)};
+  EXPECT_THAT(name_map1, ElementsAre(Pair("n1", 1), Pair("n2", 2)));
+
+  absl::btree_map<std::string, int> name_map2;
+  name_map2.insert(std::begin(names), std::end(names));
+  EXPECT_THAT(name_map2, ElementsAre(Pair("n1", 1), Pair("n2", 2)));
+}
+
+TEST(Btree,
+     MapRangeConstructorAndInsertExplicitConvComparableLimitConstruction) {
+  const std::pair<int, int> i[] = {{0, 1}, {1, 2}, {1, 3}};
+  ConstructorCounted::constructor_calls = 0;
+
+  absl::btree_map<ConstructorCounted, int, ConstructorCountedCompare> map{
+      std::begin(i), std::end(i)};
+  EXPECT_THAT(map, ElementsAre(Pair(0, 1), Pair(1, 2)));
+  EXPECT_EQ(ConstructorCounted::constructor_calls, 2);
+
+  map.insert(std::begin(i), std::end(i));
+  EXPECT_THAT(map, ElementsAre(Pair(0, 1), Pair(1, 2)));
+  EXPECT_EQ(ConstructorCounted::constructor_calls, 2);
+}
+
+TEST(Btree,
+     MapRangeConstructorAndInsertSupportExplicitConversionNonComparable) {
+  const std::pair<int, int> i[] = {{0, 1}, {1, 2}};
+
+  absl::btree_map<std::vector<void *>, int> m1{std::begin(i), std::end(i)};
+  EXPECT_THAT(m1,
+              ElementsAre(Pair(IsEmpty(), 1), Pair(ElementsAre(IsNull()), 2)));
+
+  absl::btree_map<std::vector<void *>, int> m2;
+  m2.insert(std::begin(i), std::end(i));
+  EXPECT_THAT(m2,
+              ElementsAre(Pair(IsEmpty(), 1), Pair(ElementsAre(IsNull()), 2)));
+}
+
+TEST(Btree, HeterogeneousTryEmplace) {
+  absl::btree_map<std::string, int> m;
+  std::string s = "key";
+  absl::string_view sv = s;
+  m.try_emplace(sv, 1);
+  EXPECT_EQ(m[s], 1);
+
+  m.try_emplace(m.end(), sv, 2);
+  EXPECT_EQ(m[s], 1);
+}
+
+TEST(Btree, HeterogeneousOperatorMapped) {
+  absl::btree_map<std::string, int> m;
+  std::string s = "key";
+  absl::string_view sv = s;
+  m[sv] = 1;
+  EXPECT_EQ(m[s], 1);
+
+  m[sv] = 2;
+  EXPECT_EQ(m[s], 2);
+}
+
+TEST(Btree, HeterogeneousInsertOrAssign) {
+  absl::btree_map<std::string, int> m;
+  std::string s = "key";
+  absl::string_view sv = s;
+  m.insert_or_assign(sv, 1);
+  EXPECT_EQ(m[s], 1);
+
+  m.insert_or_assign(m.end(), sv, 2);
+  EXPECT_EQ(m[s], 2);
+}
+#endif
+
+// This test requires std::launder for mutable key access in node handles.
+#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
+TEST(Btree, NodeHandleMutableKeyAccess) {
+  {
+    absl::btree_map<std::string, std::string> map;
+
+    map["key1"] = "mapped";
+
+    auto nh = map.extract(map.begin());
+    nh.key().resize(3);
+    map.insert(std::move(nh));
+
+    EXPECT_THAT(map, ElementsAre(Pair("key", "mapped")));
+  }
+  // Also for multimap.
+  {
+    absl::btree_multimap<std::string, std::string> map;
+
+    map.emplace("key1", "mapped");
+
+    auto nh = map.extract(map.begin());
+    nh.key().resize(3);
+    map.insert(std::move(nh));
+
+    EXPECT_THAT(map, ElementsAre(Pair("key", "mapped")));
+  }
+}
+#endif
+
+struct MultiKey {
+  int i1;
+  int i2;
+};
+
+bool operator==(const MultiKey a, const MultiKey b) {
+  return a.i1 == b.i1 && a.i2 == b.i2;
+}
+
+// A heterogeneous comparator that has different equivalence classes for
+// different lookup types.
+struct MultiKeyComp {
+  using is_transparent = void;
+  bool operator()(const MultiKey a, const MultiKey b) const {
+    if (a.i1 != b.i1) return a.i1 < b.i1;
+    return a.i2 < b.i2;
+  }
+  bool operator()(const int a, const MultiKey b) const { return a < b.i1; }
+  bool operator()(const MultiKey a, const int b) const { return a.i1 < b; }
+};
+
+// A heterogeneous, three-way comparator that has different equivalence classes
+// for different lookup types.
+struct MultiKeyThreeWayComp {
+  using is_transparent = void;
+  absl::weak_ordering operator()(const MultiKey a, const MultiKey b) const {
+    if (a.i1 < b.i1) return absl::weak_ordering::less;
+    if (a.i1 > b.i1) return absl::weak_ordering::greater;
+    if (a.i2 < b.i2) return absl::weak_ordering::less;
+    if (a.i2 > b.i2) return absl::weak_ordering::greater;
+    return absl::weak_ordering::equivalent;
+  }
+  absl::weak_ordering operator()(const int a, const MultiKey b) const {
+    if (a < b.i1) return absl::weak_ordering::less;
+    if (a > b.i1) return absl::weak_ordering::greater;
+    return absl::weak_ordering::equivalent;
+  }
+  absl::weak_ordering operator()(const MultiKey a, const int b) const {
+    if (a.i1 < b) return absl::weak_ordering::less;
+    if (a.i1 > b) return absl::weak_ordering::greater;
+    return absl::weak_ordering::equivalent;
+  }
+};
+
+template <typename Compare>
+class BtreeMultiKeyTest : public ::testing::Test {};
+using MultiKeyComps = ::testing::Types<MultiKeyComp, MultiKeyThreeWayComp>;
+TYPED_TEST_SUITE(BtreeMultiKeyTest, MultiKeyComps);
+
+TYPED_TEST(BtreeMultiKeyTest, EqualRange) {
+  absl::btree_set<MultiKey, TypeParam> set;
+  for (int i = 0; i < 100; ++i) {
+    for (int j = 0; j < 100; ++j) {
+      set.insert({i, j});
+    }
+  }
+
+  for (int i = 0; i < 100; ++i) {
+    auto equal_range = set.equal_range(i);
+    EXPECT_EQ(equal_range.first->i1, i);
+    EXPECT_EQ(equal_range.first->i2, 0) << i;
+    EXPECT_EQ(std::distance(equal_range.first, equal_range.second), 100) << i;
+  }
+}
+
+TYPED_TEST(BtreeMultiKeyTest, Extract) {
+  absl::btree_set<MultiKey, TypeParam> set;
+  for (int i = 0; i < 100; ++i) {
+    for (int j = 0; j < 100; ++j) {
+      set.insert({i, j});
+    }
+  }
+
+  for (int i = 0; i < 100; ++i) {
+    auto node_handle = set.extract(i);
+    EXPECT_EQ(node_handle.value().i1, i);
+    EXPECT_EQ(node_handle.value().i2, 0) << i;
+  }
+
+  for (int i = 0; i < 100; ++i) {
+    auto node_handle = set.extract(i);
+    EXPECT_EQ(node_handle.value().i1, i);
+    EXPECT_EQ(node_handle.value().i2, 1) << i;
+  }
+}
+
+TYPED_TEST(BtreeMultiKeyTest, Erase) {
+  absl::btree_set<MultiKey, TypeParam> set = {
+      {1, 1}, {2, 1}, {2, 2}, {3, 1}};
+  EXPECT_EQ(set.erase(2), 2);
+  EXPECT_THAT(set, ElementsAre(MultiKey{1, 1}, MultiKey{3, 1}));
+}
+
+TYPED_TEST(BtreeMultiKeyTest, Count) {
+  const absl::btree_set<MultiKey, TypeParam> set = {
+      {1, 1}, {2, 1}, {2, 2}, {3, 1}};
+  EXPECT_EQ(set.count(2), 2);
+}
+
+TEST(Btree, AllocConstructor) {
+  using Alloc = CountingAllocator<int>;
+  using Set = absl::btree_set<int, std::less<int>, Alloc>;
+  int64_t bytes_used = 0;
+  Alloc alloc(&bytes_used);
+  Set set(alloc);
+
+  set.insert({1, 2, 3});
+
+  EXPECT_THAT(set, ElementsAre(1, 2, 3));
+  EXPECT_GT(bytes_used, set.size() * sizeof(int));
+}
+
+TEST(Btree, AllocInitializerListConstructor) {
+  using Alloc = CountingAllocator<int>;
+  using Set = absl::btree_set<int, std::less<int>, Alloc>;
+  int64_t bytes_used = 0;
+  Alloc alloc(&bytes_used);
+  Set set({1, 2, 3}, alloc);
+
+  EXPECT_THAT(set, ElementsAre(1, 2, 3));
+  EXPECT_GT(bytes_used, set.size() * sizeof(int));
+}
+
+TEST(Btree, AllocRangeConstructor) {
+  using Alloc = CountingAllocator<int>;
+  using Set = absl::btree_set<int, std::less<int>, Alloc>;
+  int64_t bytes_used = 0;
+  Alloc alloc(&bytes_used);
+  std::vector<int> v = {1, 2, 3};
+  Set set(v.begin(), v.end(), alloc);
+
+  EXPECT_THAT(set, ElementsAre(1, 2, 3));
+  EXPECT_GT(bytes_used, set.size() * sizeof(int));
+}
+
+TEST(Btree, AllocCopyConstructor) {
+  using Alloc = CountingAllocator<int>;
+  using Set = absl::btree_set<int, std::less<int>, Alloc>;
+  int64_t bytes_used1 = 0;
+  Alloc alloc1(&bytes_used1);
+  Set set1(alloc1);
+
+  set1.insert({1, 2, 3});
+
+  int64_t bytes_used2 = 0;
+  Alloc alloc2(&bytes_used2);
+  Set set2(set1, alloc2);
+
+  EXPECT_THAT(set1, ElementsAre(1, 2, 3));
+  EXPECT_THAT(set2, ElementsAre(1, 2, 3));
+  EXPECT_GT(bytes_used1, set1.size() * sizeof(int));
+  EXPECT_EQ(bytes_used1, bytes_used2);
+}
+
+TEST(Btree, AllocMoveConstructor_SameAlloc) {
+  using Alloc = CountingAllocator<int>;
+  using Set = absl::btree_set<int, std::less<int>, Alloc>;
+  int64_t bytes_used = 0;
+  Alloc alloc(&bytes_used);
+  Set set1(alloc);
+
+  set1.insert({1, 2, 3});
+
+  const int64_t original_bytes_used = bytes_used;
+  EXPECT_GT(original_bytes_used, set1.size() * sizeof(int));
+
+  Set set2(std::move(set1), alloc);
+
+  EXPECT_THAT(set2, ElementsAre(1, 2, 3));
+  EXPECT_EQ(bytes_used, original_bytes_used);
+}
+
+TEST(Btree, AllocMoveConstructor_DifferentAlloc) {
+  using Alloc = CountingAllocator<int>;
+  using Set = absl::btree_set<int, std::less<int>, Alloc>;
+  int64_t bytes_used1 = 0;
+  Alloc alloc1(&bytes_used1);
+  Set set1(alloc1);
+
+  set1.insert({1, 2, 3});
+
+  const int64_t original_bytes_used = bytes_used1;
+  EXPECT_GT(original_bytes_used, set1.size() * sizeof(int));
+
+  int64_t bytes_used2 = 0;
+  Alloc alloc2(&bytes_used2);
+  Set set2(std::move(set1), alloc2);
+
+  EXPECT_THAT(set2, ElementsAre(1, 2, 3));
+  // We didn't free these bytes allocated by `set1` yet.
+  EXPECT_EQ(bytes_used1, original_bytes_used);
+  EXPECT_EQ(bytes_used2, original_bytes_used);
+}
+
 }  // namespace
 }  // namespace container_internal
 ABSL_NAMESPACE_END
diff --git a/absl/container/btree_test.h b/absl/container/btree_test.h
index 218ba41..6249080 100644
--- a/absl/container/btree_test.h
+++ b/absl/container/btree_test.h
@@ -25,6 +25,7 @@
 #include "absl/container/btree_map.h"
 #include "absl/container/btree_set.h"
 #include "absl/container/flat_hash_set.h"
+#include "absl/strings/cord.h"
 #include "absl/time/time.h"
 
 namespace absl {
@@ -100,6 +101,16 @@
   }
 };
 
+template <>
+struct Generator<Cord> {
+  int maxval;
+  explicit Generator(int m) : maxval(m) {}
+  Cord operator()(int i) const {
+    char buf[16];
+    return Cord(GenerateDigits(buf, i, maxval));
+  }
+};
+
 template <typename T, typename U>
 struct Generator<std::pair<T, U> > {
   Generator<typename remove_pair_const<T>::type> tgen;
diff --git a/absl/container/fixed_array.h b/absl/container/fixed_array.h
index a9ce99b..fcb3e54 100644
--- a/absl/container/fixed_array.h
+++ b/absl/container/fixed_array.h
@@ -41,6 +41,7 @@
 #include <type_traits>
 
 #include "absl/algorithm/algorithm.h"
+#include "absl/base/config.h"
 #include "absl/base/dynamic_annotations.h"
 #include "absl/base/internal/throw_delegate.h"
 #include "absl/base/macros.h"
@@ -106,13 +107,13 @@
 
  public:
   using allocator_type = typename AllocatorTraits::allocator_type;
-  using value_type = typename allocator_type::value_type;
-  using pointer = typename allocator_type::pointer;
-  using const_pointer = typename allocator_type::const_pointer;
-  using reference = typename allocator_type::reference;
-  using const_reference = typename allocator_type::const_reference;
-  using size_type = typename allocator_type::size_type;
-  using difference_type = typename allocator_type::difference_type;
+  using value_type = typename AllocatorTraits::value_type;
+  using pointer = typename AllocatorTraits::pointer;
+  using const_pointer = typename AllocatorTraits::const_pointer;
+  using reference = value_type&;
+  using const_reference = const value_type&;
+  using size_type = typename AllocatorTraits::size_type;
+  using difference_type = typename AllocatorTraits::difference_type;
   using iterator = pointer;
   using const_iterator = const_pointer;
   using reverse_iterator = std::reverse_iterator<iterator>;
@@ -217,7 +218,7 @@
   // Returns a reference the ith element of the fixed array.
   // REQUIRES: 0 <= i < size()
   reference operator[](size_type i) {
-    assert(i < size());
+    ABSL_HARDENING_ASSERT(i < size());
     return data()[i];
   }
 
@@ -225,14 +226,14 @@
   // ith element of the fixed array.
   // REQUIRES: 0 <= i < size()
   const_reference operator[](size_type i) const {
-    assert(i < size());
+    ABSL_HARDENING_ASSERT(i < size());
     return data()[i];
   }
 
   // FixedArray::at
   //
-  // Bounds-checked access.  Returns a reference to the ith element of the
-  // fiexed array, or throws std::out_of_range
+  // Bounds-checked access.  Returns a reference to the ith element of the fixed
+  // array, or throws std::out_of_range
   reference at(size_type i) {
     if (ABSL_PREDICT_FALSE(i >= size())) {
       base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
@@ -252,20 +253,32 @@
   // FixedArray::front()
   //
   // Returns a reference to the first element of the fixed array.
-  reference front() { return *begin(); }
+  reference front() {
+    ABSL_HARDENING_ASSERT(!empty());
+    return data()[0];
+  }
 
   // Overload of FixedArray::front() to return a reference to the first element
   // of a fixed array of const values.
-  const_reference front() const { return *begin(); }
+  const_reference front() const {
+    ABSL_HARDENING_ASSERT(!empty());
+    return data()[0];
+  }
 
   // FixedArray::back()
   //
   // Returns a reference to the last element of the fixed array.
-  reference back() { return *(end() - 1); }
+  reference back() {
+    ABSL_HARDENING_ASSERT(!empty());
+    return data()[size() - 1];
+  }
 
   // Overload of FixedArray::back() to return a reference to the last element
   // of a fixed array of const values.
-  const_reference back() const { return *(end() - 1); }
+  const_reference back() const {
+    ABSL_HARDENING_ASSERT(!empty());
+    return data()[size() - 1];
+  }
 
   // FixedArray::begin()
   //
@@ -410,15 +423,15 @@
     void AnnotateConstruct(size_type n);
     void AnnotateDestruct(size_type n);
 
-#ifdef ADDRESS_SANITIZER
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
     void* RedzoneBegin() { return &redzone_begin_; }
     void* RedzoneEnd() { return &redzone_end_ + 1; }
-#endif  // ADDRESS_SANITIZER
+#endif  // ABSL_HAVE_ADDRESS_SANITIZER
 
    private:
-    ADDRESS_SANITIZER_REDZONE(redzone_begin_);
+    ABSL_ADDRESS_SANITIZER_REDZONE(redzone_begin_);
     alignas(StorageElement) char buff_[sizeof(StorageElement[inline_elements])];
-    ADDRESS_SANITIZER_REDZONE(redzone_end_);
+    ABSL_ADDRESS_SANITIZER_REDZONE(redzone_end_);
   };
 
   class EmptyInlinedStorage {
@@ -491,22 +504,26 @@
 template <typename T, size_t N, typename A>
 void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateConstruct(
     typename FixedArray<T, N, A>::size_type n) {
-#ifdef ADDRESS_SANITIZER
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
   if (!n) return;
-  ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(), data() + n);
-  ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(), RedzoneBegin());
-#endif                   // ADDRESS_SANITIZER
+  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(),
+                                     data() + n);
+  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(),
+                                     RedzoneBegin());
+#endif  // ABSL_HAVE_ADDRESS_SANITIZER
   static_cast<void>(n);  // Mark used when not in asan mode
 }
 
 template <typename T, size_t N, typename A>
 void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateDestruct(
     typename FixedArray<T, N, A>::size_type n) {
-#ifdef ADDRESS_SANITIZER
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
   if (!n) return;
-  ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n, RedzoneEnd());
-  ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(), data());
-#endif                   // ADDRESS_SANITIZER
+  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n,
+                                     RedzoneEnd());
+  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(),
+                                     data());
+#endif  // ABSL_HAVE_ADDRESS_SANITIZER
   static_cast<void>(n);  // Mark used when not in asan mode
 }
 ABSL_NAMESPACE_END
diff --git a/absl/container/fixed_array_exception_safety_test.cc b/absl/container/fixed_array_exception_safety_test.cc
index a5bb009..e5f5929 100644
--- a/absl/container/fixed_array_exception_safety_test.cc
+++ b/absl/container/fixed_array_exception_safety_test.cc
@@ -150,8 +150,7 @@
 
 template <typename FixedArrT>
 testing::AssertionResult ReadMemory(FixedArrT* fixed_arr) {
-  // Marked volatile to prevent optimization. Used for running asan tests.
-  volatile int sum = 0;
+  int sum = 0;
   for (const auto& thrower : *fixed_arr) {
     sum += thrower.Get();
   }
diff --git a/absl/container/fixed_array_test.cc b/absl/container/fixed_array_test.cc
index c960fe5..49598e7 100644
--- a/absl/container/fixed_array_test.cc
+++ b/absl/container/fixed_array_test.cc
@@ -27,7 +27,10 @@
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/base/config.h"
 #include "absl/base/internal/exception_testing.h"
+#include "absl/base/options.h"
+#include "absl/container/internal/counting_allocator.h"
 #include "absl/hash/hash_testing.h"
 #include "absl/memory/memory.h"
 
@@ -188,6 +191,21 @@
                                  "failed bounds check");
 }
 
+TEST(FixedArrayTest, Hardened) {
+#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
+  absl::FixedArray<int> a = {1, 2, 3};
+  EXPECT_EQ(a[2], 3);
+  EXPECT_DEATH_IF_SUPPORTED(a[3], "");
+  EXPECT_DEATH_IF_SUPPORTED(a[-1], "");
+
+  absl::FixedArray<int> empty(0);
+  EXPECT_DEATH_IF_SUPPORTED(empty[0], "");
+  EXPECT_DEATH_IF_SUPPORTED(empty[-1], "");
+  EXPECT_DEATH_IF_SUPPORTED(empty.front(), "");
+  EXPECT_DEATH_IF_SUPPORTED(empty.back(), "");
+#endif
+}
+
 TEST(FixedArrayRelationalsTest, EqualArrays) {
   for (int i = 0; i < 10; ++i) {
     absl::FixedArray<int, 5> a1(i);
@@ -622,70 +640,9 @@
 }
 #endif  // __GNUC__
 
-// This is a stateful allocator, but the state lives outside of the
-// allocator (in whatever test is using the allocator). This is odd
-// but helps in tests where the allocator is propagated into nested
-// containers - that chain of allocators uses the same state and is
-// thus easier to query for aggregate allocation information.
-template <typename T>
-class CountingAllocator : public std::allocator<T> {
- public:
-  using Alloc = std::allocator<T>;
-  using pointer = typename Alloc::pointer;
-  using size_type = typename Alloc::size_type;
-
-  CountingAllocator() : bytes_used_(nullptr), instance_count_(nullptr) {}
-  explicit CountingAllocator(int64_t* b)
-      : bytes_used_(b), instance_count_(nullptr) {}
-  CountingAllocator(int64_t* b, int64_t* a)
-      : bytes_used_(b), instance_count_(a) {}
-
-  template <typename U>
-  explicit CountingAllocator(const CountingAllocator<U>& x)
-      : Alloc(x),
-        bytes_used_(x.bytes_used_),
-        instance_count_(x.instance_count_) {}
-
-  pointer allocate(size_type n, const void* const hint = nullptr) {
-    assert(bytes_used_ != nullptr);
-    *bytes_used_ += n * sizeof(T);
-    return Alloc::allocate(n, hint);
-  }
-
-  void deallocate(pointer p, size_type n) {
-    Alloc::deallocate(p, n);
-    assert(bytes_used_ != nullptr);
-    *bytes_used_ -= n * sizeof(T);
-  }
-
-  template <typename... Args>
-  void construct(pointer p, Args&&... args) {
-    Alloc::construct(p, absl::forward<Args>(args)...);
-    if (instance_count_) {
-      *instance_count_ += 1;
-    }
-  }
-
-  void destroy(pointer p) {
-    Alloc::destroy(p);
-    if (instance_count_) {
-      *instance_count_ -= 1;
-    }
-  }
-
-  template <typename U>
-  class rebind {
-   public:
-    using other = CountingAllocator<U>;
-  };
-
-  int64_t* bytes_used_;
-  int64_t* instance_count_;
-};
-
 TEST(AllocatorSupportTest, CountInlineAllocations) {
   constexpr size_t inlined_size = 4;
-  using Alloc = CountingAllocator<int>;
+  using Alloc = absl::container_internal::CountingAllocator<int>;
   using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
 
   int64_t allocated = 0;
@@ -706,7 +663,7 @@
 
 TEST(AllocatorSupportTest, CountOutoflineAllocations) {
   constexpr size_t inlined_size = 4;
-  using Alloc = CountingAllocator<int>;
+  using Alloc = absl::container_internal::CountingAllocator<int>;
   using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
 
   int64_t allocated = 0;
@@ -727,7 +684,7 @@
 
 TEST(AllocatorSupportTest, CountCopyInlineAllocations) {
   constexpr size_t inlined_size = 4;
-  using Alloc = CountingAllocator<int>;
+  using Alloc = absl::container_internal::CountingAllocator<int>;
   using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
 
   int64_t allocated1 = 0;
@@ -755,7 +712,7 @@
 
 TEST(AllocatorSupportTest, CountCopyOutoflineAllocations) {
   constexpr size_t inlined_size = 4;
-  using Alloc = CountingAllocator<int>;
+  using Alloc = absl::container_internal::CountingAllocator<int>;
   using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
 
   int64_t allocated1 = 0;
@@ -787,7 +744,7 @@
   using testing::SizeIs;
 
   constexpr size_t inlined_size = 4;
-  using Alloc = CountingAllocator<int>;
+  using Alloc = absl::container_internal::CountingAllocator<int>;
   using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
 
   {
@@ -811,16 +768,16 @@
   }
 }
 
-#ifdef ADDRESS_SANITIZER
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
 TEST(FixedArrayTest, AddressSanitizerAnnotations1) {
   absl::FixedArray<int, 32> a(10);
   int* raw = a.data();
   raw[0] = 0;
   raw[9] = 0;
-  EXPECT_DEATH(raw[-2] = 0, "container-overflow");
-  EXPECT_DEATH(raw[-1] = 0, "container-overflow");
-  EXPECT_DEATH(raw[10] = 0, "container-overflow");
-  EXPECT_DEATH(raw[31] = 0, "container-overflow");
+  EXPECT_DEATH_IF_SUPPORTED(raw[-2] = 0, "container-overflow");
+  EXPECT_DEATH_IF_SUPPORTED(raw[-1] = 0, "container-overflow");
+  EXPECT_DEATH_IF_SUPPORTED(raw[10] = 0, "container-overflow");
+  EXPECT_DEATH_IF_SUPPORTED(raw[31] = 0, "container-overflow");
 }
 
 TEST(FixedArrayTest, AddressSanitizerAnnotations2) {
@@ -828,10 +785,10 @@
   char* raw = a.data();
   raw[0] = 0;
   raw[11] = 0;
-  EXPECT_DEATH(raw[-7] = 0, "container-overflow");
-  EXPECT_DEATH(raw[-1] = 0, "container-overflow");
-  EXPECT_DEATH(raw[12] = 0, "container-overflow");
-  EXPECT_DEATH(raw[17] = 0, "container-overflow");
+  EXPECT_DEATH_IF_SUPPORTED(raw[-7] = 0, "container-overflow");
+  EXPECT_DEATH_IF_SUPPORTED(raw[-1] = 0, "container-overflow");
+  EXPECT_DEATH_IF_SUPPORTED(raw[12] = 0, "container-overflow");
+  EXPECT_DEATH_IF_SUPPORTED(raw[17] = 0, "container-overflow");
 }
 
 TEST(FixedArrayTest, AddressSanitizerAnnotations3) {
@@ -839,8 +796,8 @@
   uint64_t* raw = a.data();
   raw[0] = 0;
   raw[19] = 0;
-  EXPECT_DEATH(raw[-1] = 0, "container-overflow");
-  EXPECT_DEATH(raw[20] = 0, "container-overflow");
+  EXPECT_DEATH_IF_SUPPORTED(raw[-1] = 0, "container-overflow");
+  EXPECT_DEATH_IF_SUPPORTED(raw[20] = 0, "container-overflow");
 }
 
 TEST(FixedArrayTest, AddressSanitizerAnnotations4) {
@@ -852,13 +809,13 @@
   // there is only a 8-byte red zone before the container range, so we only
   // access the last 4 bytes of the struct to make sure it stays within the red
   // zone.
-  EXPECT_DEATH(raw[-1].z_ = 0, "container-overflow");
-  EXPECT_DEATH(raw[10] = ThreeInts(), "container-overflow");
+  EXPECT_DEATH_IF_SUPPORTED(raw[-1].z_ = 0, "container-overflow");
+  EXPECT_DEATH_IF_SUPPORTED(raw[10] = ThreeInts(), "container-overflow");
   // The actual size of storage is kDefaultBytes=256, 21*12 = 252,
   // so reading raw[21] should still trigger the correct warning.
-  EXPECT_DEATH(raw[21] = ThreeInts(), "container-overflow");
+  EXPECT_DEATH_IF_SUPPORTED(raw[21] = ThreeInts(), "container-overflow");
 }
-#endif  // ADDRESS_SANITIZER
+#endif  // ABSL_HAVE_ADDRESS_SANITIZER
 
 TEST(FixedArrayTest, AbslHashValueWorks) {
   using V = absl::FixedArray<int>;
diff --git a/absl/container/flat_hash_map.h b/absl/container/flat_hash_map.h
index fcb70d8..74def0d 100644
--- a/absl/container/flat_hash_map.h
+++ b/absl/container/flat_hash_map.h
@@ -234,7 +234,8 @@
   //
   // size_type erase(const key_type& key):
   //
-  //   Erases the element with the matching key, if it exists.
+  //   Erases the element with the matching key, if it exists, returning the
+  //   number of elements erased (0 or 1).
   using Base::erase;
 
   // flat_hash_map::insert()
@@ -383,6 +384,11 @@
   //   key value and returns a node handle owning that extracted data. If the
   //   `flat_hash_map` does not contain an element with a matching key, this
   //   function returns an empty node handle.
+  //
+  // NOTE: when compiled in an earlier version of C++ than C++17,
+  // `node_type::key()` returns a const reference to the key instead of a
+  // mutable reference. We cannot safely return a mutable reference without
+  // std::launder (which is not available before C++17).
   using Base::extract;
 
   // flat_hash_map::merge()
diff --git a/absl/container/flat_hash_map_test.cc b/absl/container/flat_hash_map_test.cc
index 728b693..89ec60c 100644
--- a/absl/container/flat_hash_map_test.cc
+++ b/absl/container/flat_hash_map_test.cc
@@ -16,6 +16,7 @@
 
 #include <memory>
 
+#include "absl/base/internal/raw_logging.h"
 #include "absl/container/internal/hash_generator_testing.h"
 #include "absl/container/internal/unordered_map_constructor_test.h"
 #include "absl/container/internal/unordered_map_lookup_test.h"
@@ -34,6 +35,19 @@
 using ::testing::Pair;
 using ::testing::UnorderedElementsAre;
 
+// Check that absl::flat_hash_map works in a global constructor.
+struct BeforeMain {
+  BeforeMain() {
+    absl::flat_hash_map<int, int> x;
+    x.insert({1, 1});
+    ABSL_RAW_CHECK(x.find(0) == x.end(), "x should not contain 0");
+    auto it = x.find(1);
+    ABSL_RAW_CHECK(it != x.end(), "x should contain 1");
+    ABSL_RAW_CHECK(it->second, "1 should map to 1");
+  }
+};
+const BeforeMain before_main;
+
 template <class K, class V>
 using Map = flat_hash_map<K, V, StatefulTestingHash, StatefulTestingEqual,
                           Alloc<std::pair<const K, V>>>;
@@ -253,6 +267,21 @@
   }
 }
 
+// This test requires std::launder for mutable key access in node handles.
+#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
+TEST(FlatHashMap, NodeHandleMutableKeyAccess) {
+  flat_hash_map<std::string, std::string> map;
+
+  map["key1"] = "mapped";
+
+  auto nh = map.extract(map.begin());
+  nh.key().resize(3);
+  map.insert(std::move(nh));
+
+  EXPECT_THAT(map, testing::ElementsAre(Pair("key", "mapped")));
+}
+#endif
+
 }  // namespace
 }  // namespace container_internal
 ABSL_NAMESPACE_END
diff --git a/absl/container/flat_hash_set.h b/absl/container/flat_hash_set.h
index 94be6e3..6b89da6 100644
--- a/absl/container/flat_hash_set.h
+++ b/absl/container/flat_hash_set.h
@@ -227,7 +227,8 @@
   //
   // size_type erase(const key_type& key):
   //
-  //   Erases the element with the matching key, if it exists.
+  //   Erases the element with the matching key, if it exists, returning the
+  //   number of elements erased (0 or 1).
   using Base::erase;
 
   // flat_hash_set::insert()
@@ -323,7 +324,7 @@
 
   // flat_hash_set::merge()
   //
-  // Extracts elements from a given `source` flat hash map into this
+  // Extracts elements from a given `source` flat hash set into this
   // `flat_hash_set`. If the destination `flat_hash_set` already contains an
   // element with an equivalent key, that element is not extracted.
   using Base::merge;
diff --git a/absl/container/flat_hash_set_test.cc b/absl/container/flat_hash_set_test.cc
index 40d7f85..8f6f994 100644
--- a/absl/container/flat_hash_set_test.cc
+++ b/absl/container/flat_hash_set_test.cc
@@ -16,6 +16,7 @@
 
 #include <vector>
 
+#include "absl/base/internal/raw_logging.h"
 #include "absl/container/internal/hash_generator_testing.h"
 #include "absl/container/internal/unordered_set_constructor_test.h"
 #include "absl/container/internal/unordered_set_lookup_test.h"
@@ -36,6 +37,17 @@
 using ::testing::UnorderedElementsAre;
 using ::testing::UnorderedElementsAreArray;
 
+// Check that absl::flat_hash_set works in a global constructor.
+struct BeforeMain {
+  BeforeMain() {
+    absl::flat_hash_set<int> x;
+    x.insert(1);
+    ABSL_RAW_CHECK(!x.contains(0), "x should not contain 0");
+    ABSL_RAW_CHECK(x.contains(1), "x should contain 1");
+  }
+};
+const BeforeMain before_main;
+
 template <class T>
 using Set =
     absl::flat_hash_set<T, StatefulTestingHash, StatefulTestingEqual, Alloc<T>>;
diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h
index 2388d47..7c18234 100644
--- a/absl/container/inlined_vector.h
+++ b/absl/container/inlined_vector.h
@@ -48,6 +48,7 @@
 
 #include "absl/algorithm/algorithm.h"
 #include "absl/base/internal/throw_delegate.h"
+#include "absl/base/macros.h"
 #include "absl/base/optimization.h"
 #include "absl/base/port.h"
 #include "absl/container/internal/inlined_vector.h"
@@ -63,7 +64,7 @@
 // `std::vector` for use cases where the vector's size is sufficiently small
 // that it can be inlined. If the inlined vector does grow beyond its estimated
 // capacity, it will trigger an initial allocation on the heap, and will behave
-// as a `std:vector`. The API of the `absl::InlinedVector` within this file is
+// as a `std::vector`. The API of the `absl::InlinedVector` within this file is
 // designed to cover the same API footprint as covered by `std::vector`.
 template <typename T, size_t N, typename A = std::allocator<T>>
 class InlinedVector {
@@ -166,11 +167,13 @@
   // Creates an inlined vector by copying the contents of `other` using `alloc`.
   InlinedVector(const InlinedVector& other, const allocator_type& alloc)
       : storage_(alloc) {
-    if (IsMemcpyOk::value && !other.storage_.GetIsAllocated()) {
+    if (other.empty()) {
+      // Empty; nothing to do.
+    } else if (IsMemcpyOk::value && !other.storage_.GetIsAllocated()) {
+      // Memcpy-able and do not need allocation.
       storage_.MemcpyFrom(other.storage_);
     } else {
-      storage_.Initialize(IteratorValueAdapter<const_pointer>(other.data()),
-                          other.size());
+      storage_.InitFrom(other.storage_);
     }
   }
 
@@ -307,16 +310,14 @@
   //
   // Returns a `reference` to the `i`th element of the inlined vector.
   reference operator[](size_type i) {
-    assert(i < size());
-
+    ABSL_HARDENING_ASSERT(i < size());
     return data()[i];
   }
 
   // Overload of `InlinedVector::operator[](...)` that returns a
   // `const_reference` to the `i`th element of the inlined vector.
   const_reference operator[](size_type i) const {
-    assert(i < size());
-
+    ABSL_HARDENING_ASSERT(i < size());
     return data()[i];
   }
 
@@ -331,7 +332,6 @@
       base_internal::ThrowStdOutOfRange(
           "`InlinedVector::at(size_type)` failed bounds check");
     }
-
     return data()[i];
   }
 
@@ -345,7 +345,6 @@
       base_internal::ThrowStdOutOfRange(
           "`InlinedVector::at(size_type) const` failed bounds check");
     }
-
     return data()[i];
   }
 
@@ -353,34 +352,30 @@
   //
   // Returns a `reference` to the first element of the inlined vector.
   reference front() {
-    assert(!empty());
-
-    return at(0);
+    ABSL_HARDENING_ASSERT(!empty());
+    return data()[0];
   }
 
   // Overload of `InlinedVector::front()` that returns a `const_reference` to
   // the first element of the inlined vector.
   const_reference front() const {
-    assert(!empty());
-
-    return at(0);
+    ABSL_HARDENING_ASSERT(!empty());
+    return data()[0];
   }
 
   // `InlinedVector::back()`
   //
   // Returns a `reference` to the last element of the inlined vector.
   reference back() {
-    assert(!empty());
-
-    return at(size() - 1);
+    ABSL_HARDENING_ASSERT(!empty());
+    return data()[size() - 1];
   }
 
   // Overload of `InlinedVector::back()` that returns a `const_reference` to the
   // last element of the inlined vector.
   const_reference back() const {
-    assert(!empty());
-
-    return at(size() - 1);
+    ABSL_HARDENING_ASSERT(!empty());
+    return data()[size() - 1];
   }
 
   // `InlinedVector::begin()`
@@ -531,7 +526,7 @@
   void assign(InputIterator first, InputIterator last) {
     size_type i = 0;
     for (; i < size() && first != last; ++i, static_cast<void>(++first)) {
-      at(i) = *first;
+      data()[i] = *first;
     }
 
     erase(data() + i, data() + size());
@@ -542,9 +537,12 @@
   //
   // Resizes the inlined vector to contain `n` elements.
   //
-  // NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n`
+  // NOTE: If `n` is smaller than `size()`, extra elements are destroyed. If `n`
   // is larger than `size()`, new elements are value-initialized.
-  void resize(size_type n) { storage_.Resize(DefaultValueAdapter(), n); }
+  void resize(size_type n) {
+    ABSL_HARDENING_ASSERT(n <= max_size());
+    storage_.Resize(DefaultValueAdapter(), n);
+  }
 
   // Overload of `InlinedVector::resize(...)` that resizes the inlined vector to
   // contain `n` elements.
@@ -552,6 +550,7 @@
   // NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n`
   // is larger than `size()`, new elements are copied-constructed from `v`.
   void resize(size_type n, const_reference v) {
+    ABSL_HARDENING_ASSERT(n <= max_size());
     storage_.Resize(CopyValueAdapter(v), n);
   }
 
@@ -573,8 +572,8 @@
   // of `v` starting at `pos`, returning an `iterator` pointing to the first of
   // the newly inserted elements.
   iterator insert(const_iterator pos, size_type n, const_reference v) {
-    assert(pos >= begin());
-    assert(pos <= end());
+    ABSL_HARDENING_ASSERT(pos >= begin());
+    ABSL_HARDENING_ASSERT(pos <= end());
 
     if (ABSL_PREDICT_TRUE(n != 0)) {
       value_type dealias = v;
@@ -600,8 +599,8 @@
             EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
   iterator insert(const_iterator pos, ForwardIterator first,
                   ForwardIterator last) {
-    assert(pos >= begin());
-    assert(pos <= end());
+    ABSL_HARDENING_ASSERT(pos >= begin());
+    ABSL_HARDENING_ASSERT(pos <= end());
 
     if (ABSL_PREDICT_TRUE(first != last)) {
       return storage_.Insert(pos, IteratorValueAdapter<ForwardIterator>(first),
@@ -619,8 +618,8 @@
   template <typename InputIterator,
             DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
   iterator insert(const_iterator pos, InputIterator first, InputIterator last) {
-    assert(pos >= begin());
-    assert(pos <= end());
+    ABSL_HARDENING_ASSERT(pos >= begin());
+    ABSL_HARDENING_ASSERT(pos <= end());
 
     size_type index = std::distance(cbegin(), pos);
     for (size_type i = index; first != last; ++i, static_cast<void>(++first)) {
@@ -636,8 +635,8 @@
   // `pos`, returning an `iterator` pointing to the newly emplaced element.
   template <typename... Args>
   iterator emplace(const_iterator pos, Args&&... args) {
-    assert(pos >= begin());
-    assert(pos <= end());
+    ABSL_HARDENING_ASSERT(pos >= begin());
+    ABSL_HARDENING_ASSERT(pos <= end());
 
     value_type dealias(std::forward<Args>(args)...);
     return storage_.Insert(pos,
@@ -670,7 +669,7 @@
   //
   // Destroys the element at `back()`, reducing the size by `1`.
   void pop_back() noexcept {
-    assert(!empty());
+    ABSL_HARDENING_ASSERT(!empty());
 
     AllocatorTraits::destroy(*storage_.GetAllocPtr(), data() + (size() - 1));
     storage_.SubtractSize(1);
@@ -683,8 +682,8 @@
   //
   // NOTE: may return `end()`, which is not dereferencable.
   iterator erase(const_iterator pos) {
-    assert(pos >= begin());
-    assert(pos < end());
+    ABSL_HARDENING_ASSERT(pos >= begin());
+    ABSL_HARDENING_ASSERT(pos < end());
 
     return storage_.Erase(pos, pos + 1);
   }
@@ -695,9 +694,9 @@
   //
   // NOTE: may return `end()`, which is not dereferencable.
   iterator erase(const_iterator from, const_iterator to) {
-    assert(from >= begin());
-    assert(from <= to);
-    assert(to <= end());
+    ABSL_HARDENING_ASSERT(from >= begin());
+    ABSL_HARDENING_ASSERT(from <= to);
+    ABSL_HARDENING_ASSERT(to <= end());
 
     if (ABSL_PREDICT_TRUE(from != to)) {
       return storage_.Erase(from, to);
diff --git a/absl/container/inlined_vector_benchmark.cc b/absl/container/inlined_vector_benchmark.cc
index 3f2b4ed..e256fad 100644
--- a/absl/container/inlined_vector_benchmark.cc
+++ b/absl/container/inlined_vector_benchmark.cc
@@ -83,7 +83,7 @@
   }
   ABSL_RAW_LOG(
       FATAL,
-      "Failed to find a std::string larger than the short std::string optimization");
+      "Failed to find a string larger than the short string optimization");
   return -1;
 }
 
@@ -534,6 +534,28 @@
 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromMove, TrivialType);
 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromMove, NontrivialType);
 
+// Measure cost of copy-constructor+destructor.
+void BM_CopyTrivial(benchmark::State& state) {
+  const int n = state.range(0);
+  InlVec<int64_t> src(n);
+  for (auto s : state) {
+    InlVec<int64_t> copy(src);
+    benchmark::DoNotOptimize(copy);
+  }
+}
+BENCHMARK(BM_CopyTrivial)->Arg(0)->Arg(1)->Arg(kLargeSize);
+
+// Measure cost of copy-constructor+destructor.
+void BM_CopyNonTrivial(benchmark::State& state) {
+  const int n = state.range(0);
+  InlVec<InlVec<int64_t>> src(n);
+  for (auto s : state) {
+    InlVec<InlVec<int64_t>> copy(src);
+    benchmark::DoNotOptimize(copy);
+  }
+}
+BENCHMARK(BM_CopyNonTrivial)->Arg(0)->Arg(1)->Arg(kLargeSize);
+
 template <typename T, size_t FromSize, size_t ToSize>
 void BM_AssignSizeRef(benchmark::State& state) {
   auto size = ToSize;
diff --git a/absl/container/inlined_vector_test.cc b/absl/container/inlined_vector_test.cc
index 2c9b0d0..98aff33 100644
--- a/absl/container/inlined_vector_test.cc
+++ b/absl/container/inlined_vector_test.cc
@@ -30,6 +30,7 @@
 #include "absl/base/internal/exception_testing.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/macros.h"
+#include "absl/base/options.h"
 #include "absl/container/internal/counting_allocator.h"
 #include "absl/container/internal/test_instance_tracker.h"
 #include "absl/hash/hash_testing.h"
@@ -247,6 +248,16 @@
   }
 }
 
+TEST(IntVec, Hardened) {
+  IntVec v;
+  Fill(&v, 10);
+  EXPECT_EQ(v[9], 9);
+#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
+  EXPECT_DEATH_IF_SUPPORTED(v[10], "");
+  EXPECT_DEATH_IF_SUPPORTED(v[-1], "");
+#endif
+}
+
 // At the end of this test loop, the elements between [erase_begin, erase_end)
 // should have reference counts == 0, and all others elements should have
 // reference counts == 1.
@@ -725,22 +736,26 @@
   // In particular, ensure that std::allocator doesn't cost anything to store.
   // The union should be absorbing some of the allocation bookkeeping overhead
   // in the larger vectors, leaving only the size_ field as overhead.
-  EXPECT_EQ(2 * sizeof(int*),
-            sizeof(absl::InlinedVector<int*, 1>) - 1 * sizeof(int*));
-  EXPECT_EQ(1 * sizeof(int*),
-            sizeof(absl::InlinedVector<int*, 2>) - 2 * sizeof(int*));
-  EXPECT_EQ(1 * sizeof(int*),
-            sizeof(absl::InlinedVector<int*, 3>) - 3 * sizeof(int*));
-  EXPECT_EQ(1 * sizeof(int*),
-            sizeof(absl::InlinedVector<int*, 4>) - 4 * sizeof(int*));
-  EXPECT_EQ(1 * sizeof(int*),
-            sizeof(absl::InlinedVector<int*, 5>) - 5 * sizeof(int*));
-  EXPECT_EQ(1 * sizeof(int*),
-            sizeof(absl::InlinedVector<int*, 6>) - 6 * sizeof(int*));
-  EXPECT_EQ(1 * sizeof(int*),
-            sizeof(absl::InlinedVector<int*, 7>) - 7 * sizeof(int*));
-  EXPECT_EQ(1 * sizeof(int*),
-            sizeof(absl::InlinedVector<int*, 8>) - 8 * sizeof(int*));
+
+  struct T { void* val; };
+  size_t expected_overhead = sizeof(T);
+
+  EXPECT_EQ((2 * expected_overhead),
+            sizeof(absl::InlinedVector<T, 1>) - sizeof(T[1]));
+  EXPECT_EQ(expected_overhead,
+            sizeof(absl::InlinedVector<T, 2>) - sizeof(T[2]));
+  EXPECT_EQ(expected_overhead,
+            sizeof(absl::InlinedVector<T, 3>) - sizeof(T[3]));
+  EXPECT_EQ(expected_overhead,
+            sizeof(absl::InlinedVector<T, 4>) - sizeof(T[4]));
+  EXPECT_EQ(expected_overhead,
+            sizeof(absl::InlinedVector<T, 5>) - sizeof(T[5]));
+  EXPECT_EQ(expected_overhead,
+            sizeof(absl::InlinedVector<T, 6>) - sizeof(T[6]));
+  EXPECT_EQ(expected_overhead,
+            sizeof(absl::InlinedVector<T, 7>) - sizeof(T[7]));
+  EXPECT_EQ(expected_overhead,
+            sizeof(absl::InlinedVector<T, 8>) - sizeof(T[8]));
 }
 
 TEST(IntVec, Clear) {
@@ -780,7 +795,7 @@
 TEST(StringVec, SelfRefPushBack) {
   std::vector<std::string> std_v;
   absl::InlinedVector<std::string, 4> v;
-  const std::string s = "A quite long std::string to ensure heap.";
+  const std::string s = "A quite long string to ensure heap.";
   std_v.push_back(s);
   v.push_back(s);
   for (int i = 0; i < 20; ++i) {
@@ -795,7 +810,7 @@
 TEST(StringVec, SelfRefPushBackWithMove) {
   std::vector<std::string> std_v;
   absl::InlinedVector<std::string, 4> v;
-  const std::string s = "A quite long std::string to ensure heap.";
+  const std::string s = "A quite long string to ensure heap.";
   std_v.push_back(s);
   v.push_back(s);
   for (int i = 0; i < 20; ++i) {
@@ -808,7 +823,7 @@
 }
 
 TEST(StringVec, SelfMove) {
-  const std::string s = "A quite long std::string to ensure heap.";
+  const std::string s = "A quite long string to ensure heap.";
   for (int len = 0; len < 20; len++) {
     SCOPED_TRACE(len);
     absl::InlinedVector<std::string, 8> v;
diff --git a/absl/container/internal/btree.h b/absl/container/internal/btree.h
index fd5c0e7..0bb3836 100644
--- a/absl/container/internal/btree.h
+++ b/absl/container/internal/btree.h
@@ -65,6 +65,7 @@
 #include "absl/container/internal/layout.h"
 #include "absl/memory/memory.h"
 #include "absl/meta/type_traits.h"
+#include "absl/strings/cord.h"
 #include "absl/strings/string_view.h"
 #include "absl/types/compare.h"
 #include "absl/utility/utility.h"
@@ -93,6 +94,19 @@
                                  absl::string_view rhs) const {
     return compare_internal::compare_result_as_ordering(lhs.compare(rhs));
   }
+  StringBtreeDefaultLess(std::less<absl::Cord>) {}  // NOLINT
+  absl::weak_ordering operator()(const absl::Cord &lhs,
+                                 const absl::Cord &rhs) const {
+    return compare_internal::compare_result_as_ordering(lhs.Compare(rhs));
+  }
+  absl::weak_ordering operator()(const absl::Cord &lhs,
+                                 absl::string_view rhs) const {
+    return compare_internal::compare_result_as_ordering(lhs.Compare(rhs));
+  }
+  absl::weak_ordering operator()(absl::string_view lhs,
+                                 const absl::Cord &rhs) const {
+    return compare_internal::compare_result_as_ordering(-rhs.Compare(lhs));
+  }
 };
 
 struct StringBtreeDefaultGreater {
@@ -107,17 +121,30 @@
                                  absl::string_view rhs) const {
     return compare_internal::compare_result_as_ordering(rhs.compare(lhs));
   }
+  StringBtreeDefaultGreater(std::greater<absl::Cord>) {}  // NOLINT
+  absl::weak_ordering operator()(const absl::Cord &lhs,
+                                 const absl::Cord &rhs) const {
+    return compare_internal::compare_result_as_ordering(rhs.Compare(lhs));
+  }
+  absl::weak_ordering operator()(const absl::Cord &lhs,
+                                 absl::string_view rhs) const {
+    return compare_internal::compare_result_as_ordering(-lhs.Compare(rhs));
+  }
+  absl::weak_ordering operator()(absl::string_view lhs,
+                                 const absl::Cord &rhs) const {
+    return compare_internal::compare_result_as_ordering(rhs.Compare(lhs));
+  }
 };
 
 // A helper class to convert a boolean comparison into a three-way "compare-to"
-// comparison that returns a negative value to indicate less-than, zero to
-// indicate equality and a positive value to indicate greater-than. This helper
+// comparison that returns an `absl::weak_ordering`. This helper
 // class is specialized for less<std::string>, greater<std::string>,
-// less<string_view>, and greater<string_view>.
+// less<string_view>, greater<string_view>, less<absl::Cord>, and
+// greater<absl::Cord>.
 //
 // key_compare_to_adapter is provided so that btree users
 // automatically get the more efficient compare-to code when using common
-// google string types with common comparison functors.
+// Abseil string types with common comparison functors.
 // These string-like specializations also turn on heterogeneous lookup by
 // default.
 template <typename Compare>
@@ -145,10 +172,52 @@
   using type = StringBtreeDefaultGreater;
 };
 
+template <>
+struct key_compare_to_adapter<std::less<absl::Cord>> {
+  using type = StringBtreeDefaultLess;
+};
+
+template <>
+struct key_compare_to_adapter<std::greater<absl::Cord>> {
+  using type = StringBtreeDefaultGreater;
+};
+
+// Detects an 'absl_btree_prefer_linear_node_search' member. This is
+// a protocol used as an opt-in or opt-out of linear search.
+//
+//  For example, this would be useful for key types that wrap an integer
+//  and define their own cheap operator<(). For example:
+//
+//   class K {
+//    public:
+//     using absl_btree_prefer_linear_node_search = std::true_type;
+//     ...
+//    private:
+//     friend bool operator<(K a, K b) { return a.k_ < b.k_; }
+//     int k_;
+//   };
+//
+//   btree_map<K, V> m;  // Uses linear search
+//
+// If T has the preference tag, then it has a preference.
+// Btree will use the tag's truth value.
+template <typename T, typename = void>
+struct has_linear_node_search_preference : std::false_type {};
+template <typename T, typename = void>
+struct prefers_linear_node_search : std::false_type {};
+template <typename T>
+struct has_linear_node_search_preference<
+    T, absl::void_t<typename T::absl_btree_prefer_linear_node_search>>
+    : std::true_type {};
+template <typename T>
+struct prefers_linear_node_search<
+    T, absl::void_t<typename T::absl_btree_prefer_linear_node_search>>
+    : T::absl_btree_prefer_linear_node_search {};
+
 template <typename Key, typename Compare, typename Alloc, int TargetNodeSize,
           bool Multi, typename SlotPolicy>
 struct common_params {
-  // If Compare is a common comparator for a std::string-like type, then we adapt it
+  // If Compare is a common comparator for a string-like type, then we adapt it
   // to use heterogeneous lookup and to be a key-compare-to comparator.
   using key_compare = typename key_compare_to_adapter<Compare>::type;
   // A type which indicates if we have a key-compare-to functor or a plain old
@@ -160,9 +229,6 @@
   using size_type = std::make_signed<size_t>::type;
   using difference_type = ptrdiff_t;
 
-  // True if this is a multiset or multimap.
-  using is_multi_container = std::integral_constant<bool, Multi>;
-
   using slot_policy = SlotPolicy;
   using slot_type = typename slot_policy::slot_type;
   using value_type = typename slot_policy::value_type;
@@ -172,6 +238,23 @@
   using reference = value_type &;
   using const_reference = const value_type &;
 
+  // For the given lookup key type, returns whether we can have multiple
+  // equivalent keys in the btree. If this is a multi-container, then we can.
+  // Otherwise, we can have multiple equivalent keys only if all of the
+  // following conditions are met:
+  // - The comparator is transparent.
+  // - The lookup key type is not the same as key_type.
+  // - The comparator is not a StringBtreeDefault{Less,Greater} comparator
+  //   that we know has the same equivalence classes for all lookup types.
+  template <typename LookupKey>
+  constexpr static bool can_have_multiple_equivalent_keys() {
+    return Multi ||
+           (IsTransparent<key_compare>::value &&
+            !std::is_same<LookupKey, Key>::value &&
+            !std::is_same<key_compare, StringBtreeDefaultLess>::value &&
+            !std::is_same<key_compare, StringBtreeDefaultGreater>::value);
+  }
+
   enum {
     kTargetNodeSize = TargetNodeSize,
 
@@ -217,10 +300,6 @@
   static void move(Alloc *alloc, slot_type *src, slot_type *dest) {
     slot_policy::move(alloc, src, dest);
   }
-  static void move(Alloc *alloc, slot_type *first, slot_type *last,
-                   slot_type *result) {
-    slot_policy::move(alloc, first, last, result);
-  }
 };
 
 // A parameters structure for holding the type parameters for a btree_map.
@@ -252,9 +331,17 @@
   };
   using is_map_container = std::true_type;
 
-  static const Key &key(const value_type &x) { return x.first; }
-  static const Key &key(const init_type &x) { return x.first; }
-  static const Key &key(const slot_type *x) { return slot_policy::key(x); }
+  template <typename V>
+  static auto key(const V &value) -> decltype(value.first) {
+    return value.first;
+  }
+  static const Key &key(const slot_type *s) { return slot_policy::key(s); }
+  static const Key &key(slot_type *s) { return slot_policy::key(s); }
+  // For use in node handle.
+  static auto mutable_key(slot_type *s)
+      -> decltype(slot_policy::mutable_key(s)) {
+    return slot_policy::mutable_key(s);
+  }
   static mapped_type &value(value_type *value) { return value->second; }
 };
 
@@ -295,13 +382,6 @@
   static void move(Alloc * /*alloc*/, slot_type *src, slot_type *dest) {
     *dest = std::move(*src);
   }
-
-  template <typename Alloc>
-  static void move(Alloc *alloc, slot_type *first, slot_type *last,
-                   slot_type *result) {
-    for (slot_type *src = first, *dest = result; src != last; ++src, ++dest)
-      move(alloc, src, dest);
-  }
 };
 
 // A parameters structure for holding the type parameters for a btree_set.
@@ -315,8 +395,10 @@
   using value_compare = typename set_params::common_params::key_compare;
   using is_map_container = std::false_type;
 
-  static const Key &key(const value_type &x) { return x; }
-  static const Key &key(const slot_type *x) { return *x; }
+  template <typename V>
+  static const V &key(const V &value) { return value; }
+  static const Key &key(const slot_type *slot) { return *slot; }
+  static const Key &key(slot_type *slot) { return *slot; }
 };
 
 // An adapter class that converts a lower-bound compare into an upper-bound
@@ -326,8 +408,8 @@
 template <typename Compare>
 struct upper_bound_adapter {
   explicit upper_bound_adapter(const Compare &c) : comp(c) {}
-  template <typename K, typename LK>
-  bool operator()(const K &a, const LK &b) const {
+  template <typename K1, typename K2>
+  bool operator()(const K1 &a, const K2 &b) const {
     // Returns true when a is not greater than b.
     return !compare_internal::compare_result_as_less_than(comp(b, a));
   }
@@ -352,6 +434,10 @@
 // useful information.
 template <typename V>
 struct SearchResult<V, false> {
+  SearchResult() {}
+  explicit SearchResult(V value) : value(value) {}
+  SearchResult(V value, MatchKind /*match*/) : value(value) {}
+
   V value;
 
   static constexpr bool HasMatch() { return false; }
@@ -364,7 +450,6 @@
 template <typename Params>
 class btree_node {
   using is_key_compare_to = typename Params::is_key_compare_to;
-  using is_multi_container = typename Params::is_multi_container;
   using field_type = typename Params::node_count_type;
   using allocator_type = typename Params::allocator_type;
   using slot_type = typename Params::slot_type;
@@ -382,15 +467,22 @@
   using difference_type = typename Params::difference_type;
 
   // Btree decides whether to use linear node search as follows:
+  //   - If the comparator expresses a preference, use that.
+  //   - If the key expresses a preference, use that.
   //   - If the key is arithmetic and the comparator is std::less or
   //     std::greater, choose linear.
   //   - Otherwise, choose binary.
   // TODO(ezb): Might make sense to add condition(s) based on node-size.
   using use_linear_search = std::integral_constant<
       bool,
-                std::is_arithmetic<key_type>::value &&
-                    (std::is_same<std::less<key_type>, key_compare>::value ||
-                     std::is_same<std::greater<key_type>, key_compare>::value)>;
+      has_linear_node_search_preference<key_compare>::value
+          ? prefers_linear_node_search<key_compare>::value
+          : has_linear_node_search_preference<key_type>::value
+                ? prefers_linear_node_search<key_type>::value
+                : std::is_arithmetic<key_type>::value &&
+                      (std::is_same<std::less<key_type>, key_compare>::value ||
+                       std::is_same<std::greater<key_type>,
+                                    key_compare>::value)>;
 
   // This class is organized by gtl::Layout as if it had the following
   // structure:
@@ -407,23 +499,23 @@
   //   // is the same as the count of values.
   //   field_type finish;
   //   // The maximum number of values the node can hold. This is an integer in
-  //   // [1, kNodeValues] for root leaf nodes, kNodeValues for non-root leaf
+  //   // [1, kNodeSlots] for root leaf nodes, kNodeSlots for non-root leaf
   //   // nodes, and kInternalNodeMaxCount (as a sentinel value) for internal
-  //   // nodes (even though there are still kNodeValues values in the node).
+  //   // nodes (even though there are still kNodeSlots values in the node).
   //   // TODO(ezb): make max_count use only 4 bits and record log2(capacity)
   //   // to free extra bits for is_root, etc.
   //   field_type max_count;
   //
   //   // The array of values. The capacity is `max_count` for leaf nodes and
-  //   // kNodeValues for internal nodes. Only the values in
+  //   // kNodeSlots for internal nodes. Only the values in
   //   // [start, finish) have been initialized and are valid.
   //   slot_type values[max_count];
   //
   //   // The array of child pointers. The keys in children[i] are all less
   //   // than key(i). The keys in children[i + 1] are all greater than key(i).
-  //   // There are 0 children for leaf nodes and kNodeValues + 1 children for
+  //   // There are 0 children for leaf nodes and kNodeSlots + 1 children for
   //   // internal nodes.
-  //   btree_node *children[kNodeValues + 1];
+  //   btree_node *children[kNodeSlots + 1];
   //
   // This class is only constructed by EmptyNodeType. Normally, pointers to the
   // layout above are allocated, cast to btree_node*, and de-allocated within
@@ -445,57 +537,62 @@
  private:
   using layout_type = absl::container_internal::Layout<btree_node *, field_type,
                                                        slot_type, btree_node *>;
-  constexpr static size_type SizeWithNValues(size_type n) {
+  constexpr static size_type SizeWithNSlots(size_type n) {
     return layout_type(/*parent*/ 1,
                        /*position, start, finish, max_count*/ 4,
-                       /*values*/ n,
+                       /*slots*/ n,
                        /*children*/ 0)
         .AllocSize();
   }
   // A lower bound for the overhead of fields other than values in a leaf node.
   constexpr static size_type MinimumOverhead() {
-    return SizeWithNValues(1) - sizeof(value_type);
+    return SizeWithNSlots(1) - sizeof(value_type);
   }
 
   // Compute how many values we can fit onto a leaf node taking into account
   // padding.
-  constexpr static size_type NodeTargetValues(const int begin, const int end) {
+  constexpr static size_type NodeTargetSlots(const int begin, const int end) {
     return begin == end ? begin
-                        : SizeWithNValues((begin + end) / 2 + 1) >
+                        : SizeWithNSlots((begin + end) / 2 + 1) >
                                   params_type::kTargetNodeSize
-                              ? NodeTargetValues(begin, (begin + end) / 2)
-                              : NodeTargetValues((begin + end) / 2 + 1, end);
+                              ? NodeTargetSlots(begin, (begin + end) / 2)
+                              : NodeTargetSlots((begin + end) / 2 + 1, end);
   }
 
   enum {
     kTargetNodeSize = params_type::kTargetNodeSize,
-    kNodeTargetValues = NodeTargetValues(0, params_type::kTargetNodeSize),
+    kNodeTargetSlots = NodeTargetSlots(0, params_type::kTargetNodeSize),
 
-    // We need a minimum of 3 values per internal node in order to perform
+    // We need a minimum of 3 slots per internal node in order to perform
     // splitting (1 value for the two nodes involved in the split and 1 value
-    // propagated to the parent as the delimiter for the split).
-    kNodeValues = kNodeTargetValues >= 3 ? kNodeTargetValues : 3,
+    // propagated to the parent as the delimiter for the split). For performance
+    // reasons, we don't allow 3 slots-per-node due to bad worst case occupancy
+    // of 1/3 (for a node, not a b-tree).
+    kMinNodeSlots = 4,
+
+    kNodeSlots =
+        kNodeTargetSlots >= kMinNodeSlots ? kNodeTargetSlots : kMinNodeSlots,
 
     // The node is internal (i.e. is not a leaf node) if and only if `max_count`
     // has this value.
     kInternalNodeMaxCount = 0,
   };
 
-  // Leaves can have less than kNodeValues values.
-  constexpr static layout_type LeafLayout(const int max_values = kNodeValues) {
+  // Leaves can have less than kNodeSlots values.
+  constexpr static layout_type LeafLayout(const int slot_count = kNodeSlots) {
     return layout_type(/*parent*/ 1,
                        /*position, start, finish, max_count*/ 4,
-                       /*values*/ max_values,
+                       /*slots*/ slot_count,
                        /*children*/ 0);
   }
   constexpr static layout_type InternalLayout() {
     return layout_type(/*parent*/ 1,
                        /*position, start, finish, max_count*/ 4,
-                       /*values*/ kNodeValues,
-                       /*children*/ kNodeValues + 1);
+                       /*slots*/ kNodeSlots,
+                       /*children*/ kNodeSlots + 1);
   }
-  constexpr static size_type LeafSize(const int max_values = kNodeValues) {
-    return LeafLayout(max_values).AllocSize();
+  constexpr static size_type LeafSize(const int slot_count = kNodeSlots) {
+    return LeafLayout(slot_count).AllocSize();
   }
   constexpr static size_type InternalSize() {
     return InternalLayout().AllocSize();
@@ -552,10 +649,10 @@
   }
   field_type max_count() const {
     // Internal nodes have max_count==kInternalNodeMaxCount.
-    // Leaf nodes have max_count in [1, kNodeValues].
+    // Leaf nodes have max_count in [1, kNodeSlots].
     const field_type max_count = GetField<1>()[3];
     return max_count == field_type{kInternalNodeMaxCount}
-               ? field_type{kNodeValues}
+               ? field_type{kNodeSlots}
                : max_count;
   }
 
@@ -633,7 +730,7 @@
       }
       ++s;
     }
-    return {s};
+    return SearchResult<int, false>{s};
   }
 
   // Returns the position of the first value whose key is not less than k using
@@ -668,7 +765,7 @@
         e = mid;
       }
     }
-    return {s};
+    return SearchResult<int, false>{s};
   }
 
   // Returns the position of the first value whose key is not less than k using
@@ -677,7 +774,7 @@
   SearchResult<int, true> binary_search_impl(
       const K &k, int s, int e, const CompareTo &comp,
       std::true_type /* IsCompareTo */) const {
-    if (is_multi_container::value) {
+    if (params_type::template can_have_multiple_equivalent_keys<K>()) {
       MatchKind exact_match = MatchKind::kNe;
       while (s != e) {
         const int mid = (s + e) >> 1;
@@ -688,14 +785,14 @@
           e = mid;
           if (c == 0) {
             // Need to return the first value whose key is not less than k,
-            // which requires continuing the binary search if this is a
-            // multi-container.
+            // which requires continuing the binary search if there could be
+            // multiple equivalent keys.
             exact_match = MatchKind::kEq;
           }
         }
       }
       return {s, exact_match};
-    } else {  // Not a multi-container.
+    } else {  // Can't have multiple equivalent keys.
       while (s != e) {
         const int mid = (s + e) >> 1;
         const absl::weak_ordering c = comp(key(mid), k);
@@ -716,14 +813,10 @@
   template <typename... Args>
   void emplace_value(size_type i, allocator_type *alloc, Args &&... args);
 
-  // Removes the value at position i, shifting all existing values and children
-  // at positions > i to the left by 1.
-  void remove_value(int i, allocator_type *alloc);
-
-  // Removes the values at positions [i, i + to_erase), shifting all values
-  // after that range to the left by to_erase. Does not change children at all.
-  void remove_values_ignore_children(int i, int to_erase,
-                                     allocator_type *alloc);
+  // Removes the values at positions [i, i + to_erase), shifting all existing
+  // values and children after that range to the left by to_erase. Clears all
+  // children between [i, i + to_erase).
+  void remove_values(field_type i, field_type to_erase, allocator_type *alloc);
 
   // Rebalances a node with its right sibling.
   void rebalance_right_to_left(int to_move, btree_node *right,
@@ -735,75 +828,87 @@
   void split(int insert_position, btree_node *dest, allocator_type *alloc);
 
   // Merges a node with its right sibling, moving all of the values and the
-  // delimiting key in the parent node onto itself.
-  void merge(btree_node *sibling, allocator_type *alloc);
-
-  // Swap the contents of "this" and "src".
-  void swap(btree_node *src, allocator_type *alloc);
+  // delimiting key in the parent node onto itself, and deleting the src node.
+  void merge(btree_node *src, allocator_type *alloc);
 
   // Node allocation/deletion routines.
-  static btree_node *init_leaf(btree_node *n, btree_node *parent,
-                               int max_count) {
-    n->set_parent(parent);
-    n->set_position(0);
-    n->set_start(0);
-    n->set_finish(0);
-    n->set_max_count(max_count);
+  void init_leaf(btree_node *parent, int max_count) {
+    set_parent(parent);
+    set_position(0);
+    set_start(0);
+    set_finish(0);
+    set_max_count(max_count);
     absl::container_internal::SanitizerPoisonMemoryRegion(
-        n->start_slot(), max_count * sizeof(slot_type));
-    return n;
+        start_slot(), max_count * sizeof(slot_type));
   }
-  static btree_node *init_internal(btree_node *n, btree_node *parent) {
-    init_leaf(n, parent, kNodeValues);
+  void init_internal(btree_node *parent) {
+    init_leaf(parent, kNodeSlots);
     // Set `max_count` to a sentinel value to indicate that this node is
     // internal.
-    n->set_max_count(kInternalNodeMaxCount);
+    set_max_count(kInternalNodeMaxCount);
     absl::container_internal::SanitizerPoisonMemoryRegion(
-        &n->mutable_child(n->start()),
-        (kNodeValues + 1) * sizeof(btree_node *));
-    return n;
-  }
-  void destroy(allocator_type *alloc) {
-    for (int i = start(); i < finish(); ++i) {
-      value_destroy(i, alloc);
-    }
+        &mutable_child(start()), (kNodeSlots + 1) * sizeof(btree_node *));
   }
 
- public:
-  // Exposed only for tests.
-  static bool testonly_uses_linear_node_search() {
-    return use_linear_search::value;
+  static void deallocate(const size_type size, btree_node *node,
+                         allocator_type *alloc) {
+    absl::container_internal::Deallocate<Alignment()>(alloc, node, size);
   }
 
+  // Deletes a node and all of its children.
+  static void clear_and_delete(btree_node *node, allocator_type *alloc);
+
  private:
   template <typename... Args>
-  void value_init(const size_type i, allocator_type *alloc, Args &&... args) {
+  void value_init(const field_type i, allocator_type *alloc, Args &&... args) {
     absl::container_internal::SanitizerUnpoisonObject(slot(i));
     params_type::construct(alloc, slot(i), std::forward<Args>(args)...);
   }
-  void value_destroy(const size_type i, allocator_type *alloc) {
+  void value_destroy(const field_type i, allocator_type *alloc) {
     params_type::destroy(alloc, slot(i));
     absl::container_internal::SanitizerPoisonObject(slot(i));
   }
-
-  // Move n values starting at value i in this node into the values starting at
-  // value j in node x.
-  void uninitialized_move_n(const size_type n, const size_type i,
-                            const size_type j, btree_node *x,
-                            allocator_type *alloc) {
-    absl::container_internal::SanitizerUnpoisonMemoryRegion(
-        x->slot(j), n * sizeof(slot_type));
-    for (slot_type *src = slot(i), *end = src + n, *dest = x->slot(j);
-         src != end; ++src, ++dest) {
-      params_type::construct(alloc, dest, src);
+  void value_destroy_n(const field_type i, const field_type n,
+                       allocator_type *alloc) {
+    for (slot_type *s = slot(i), *end = slot(i + n); s != end; ++s) {
+      params_type::destroy(alloc, s);
+      absl::container_internal::SanitizerPoisonObject(s);
     }
   }
 
-  // Destroys a range of n values, starting at index i.
-  void value_destroy_n(const size_type i, const size_type n,
-                       allocator_type *alloc) {
-    for (int j = 0; j < n; ++j) {
-      value_destroy(i + j, alloc);
+  static void transfer(slot_type *dest, slot_type *src, allocator_type *alloc) {
+    absl::container_internal::SanitizerUnpoisonObject(dest);
+    params_type::transfer(alloc, dest, src);
+    absl::container_internal::SanitizerPoisonObject(src);
+  }
+
+  // Transfers value from slot `src_i` in `src_node` to slot `dest_i` in `this`.
+  void transfer(const size_type dest_i, const size_type src_i,
+                btree_node *src_node, allocator_type *alloc) {
+    transfer(slot(dest_i), src_node->slot(src_i), alloc);
+  }
+
+  // Transfers `n` values starting at value `src_i` in `src_node` into the
+  // values starting at value `dest_i` in `this`.
+  void transfer_n(const size_type n, const size_type dest_i,
+                  const size_type src_i, btree_node *src_node,
+                  allocator_type *alloc) {
+    for (slot_type *src = src_node->slot(src_i), *end = src + n,
+                   *dest = slot(dest_i);
+         src != end; ++src, ++dest) {
+      transfer(dest, src, alloc);
+    }
+  }
+
+  // Same as above, except that we start at the end and work our way to the
+  // beginning.
+  void transfer_n_backward(const size_type n, const size_type dest_i,
+                           const size_type src_i, btree_node *src_node,
+                           allocator_type *alloc) {
+    for (slot_type *src = src_node->slot(src_i + n - 1), *end = src - n,
+                   *dest = slot(dest_i + n - 1);
+         src != end; --src, --dest) {
+      transfer(dest, src, alloc);
     }
   }
 
@@ -820,6 +925,7 @@
   using key_type = typename Node::key_type;
   using size_type = typename Node::size_type;
   using params_type = typename Node::params_type;
+  using is_map_container = typename params_type::is_map_container;
 
   using node_type = Node;
   using normal_node = typename std::remove_const<Node>::type;
@@ -831,7 +937,7 @@
   using slot_type = typename params_type::slot_type;
 
   using iterator =
-      btree_iterator<normal_node, normal_reference, normal_pointer>;
+     btree_iterator<normal_node, normal_reference, normal_pointer>;
   using const_iterator =
       btree_iterator<const_node, const_reference, const_pointer>;
 
@@ -848,20 +954,19 @@
   btree_iterator(Node *n, int p) : node(n), position(p) {}
 
   // NOTE: this SFINAE allows for implicit conversions from iterator to
-  // const_iterator, but it specifically avoids defining copy constructors so
-  // that btree_iterator can be trivially copyable. This is for performance and
-  // binary size reasons.
+  // const_iterator, but it specifically avoids hiding the copy constructor so
+  // that the trivial one will be used when possible.
   template <typename N, typename R, typename P,
             absl::enable_if_t<
                 std::is_same<btree_iterator<N, R, P>, iterator>::value &&
                     std::is_same<btree_iterator, const_iterator>::value,
                 int> = 0>
-  btree_iterator(const btree_iterator<N, R, P> &x)  // NOLINT
-      : node(x.node), position(x.position) {}
+  btree_iterator(const btree_iterator<N, R, P> other)  // NOLINT
+      : node(other.node), position(other.position) {}
 
  private:
   // This SFINAE allows explicit conversions from const_iterator to
-  // iterator, but also avoids defining a copy constructor.
+  // iterator, but also avoids hiding the copy constructor.
   // NOTE: the const_cast is safe because this constructor is only called by
   // non-const methods and the container owns the nodes.
   template <typename N, typename R, typename P,
@@ -869,8 +974,8 @@
                 std::is_same<btree_iterator<N, R, P>, const_iterator>::value &&
                     std::is_same<btree_iterator, iterator>::value,
                 int> = 0>
-  explicit btree_iterator(const btree_iterator<N, R, P> &x)
-      : node(const_cast<node_type *>(x.node)), position(x.position) {}
+  explicit btree_iterator(const btree_iterator<N, R, P> other)
+      : node(const_cast<node_type *>(other.node)), position(other.position) {}
 
   // Increment/decrement the iterator.
   void increment() {
@@ -890,16 +995,27 @@
   void decrement_slow();
 
  public:
-  bool operator==(const const_iterator &x) const {
-    return node == x.node && position == x.position;
+  bool operator==(const iterator &other) const {
+    return node == other.node && position == other.position;
   }
-  bool operator!=(const const_iterator &x) const {
-    return node != x.node || position != x.position;
+  bool operator==(const const_iterator &other) const {
+    return node == other.node && position == other.position;
+  }
+  bool operator!=(const iterator &other) const {
+    return node != other.node || position != other.position;
+  }
+  bool operator!=(const const_iterator &other) const {
+    return node != other.node || position != other.position;
   }
 
   // Accessors for the key/value the iterator is pointing at.
-  reference operator*() const { return node->value(position); }
-  pointer operator->() const { return &node->value(position); }
+  reference operator*() const {
+    ABSL_HARDENING_ASSERT(node != nullptr);
+    ABSL_HARDENING_ASSERT(node->start() <= position);
+    ABSL_HARDENING_ASSERT(node->finish() > position);
+    return node->value(position);
+  }
+  pointer operator->() const { return &operator*(); }
 
   btree_iterator &operator++() {
     increment();
@@ -921,6 +1037,8 @@
   }
 
  private:
+  friend iterator;
+  friend const_iterator;
   template <typename Params>
   friend class btree;
   template <typename Tree>
@@ -931,8 +1049,6 @@
   friend class btree_map_container;
   template <typename Tree>
   friend class btree_multiset_container;
-  template <typename N, typename R, typename P>
-  friend struct btree_iterator;
   template <typename TreeType, typename CheckerType>
   friend class base_checker;
 
@@ -942,7 +1058,8 @@
   // The node in the tree the iterator is pointing at.
   Node *node;
   // The position within the node of the tree the iterator is pointing at.
-  // TODO(ezb): make this a field_type
+  // NOTE: this is an int rather than a field_type because iterators can point
+  // to invalid positions (such as -1) in certain circumstances.
   int position;
 };
 
@@ -950,6 +1067,8 @@
 class btree {
   using node_type = btree_node<Params>;
   using is_key_compare_to = typename Params::is_key_compare_to;
+  using init_type = typename Params::init_type;
+  using field_type = typename node_type::field_type;
 
   // We use a static empty node for the root/leftmost/rightmost of empty btrees
   // in order to avoid branching in begin()/end().
@@ -984,9 +1103,9 @@
 #endif
   }
 
-  enum {
-    kNodeValues = node_type::kNodeValues,
-    kMinNodeValues = kNodeValues / 2,
+  enum : uint32_t {
+    kNodeSlots = node_type::kNodeSlots,
+    kMinNodeValues = kNodeSlots / 2,
   };
 
   struct node_stats {
@@ -994,9 +1113,9 @@
 
     node_stats(size_type l, size_type i) : leaf_nodes(l), internal_nodes(i) {}
 
-    node_stats &operator+=(const node_stats &x) {
-      leaf_nodes += x.leaf_nodes;
-      internal_nodes += x.internal_nodes;
+    node_stats &operator+=(const node_stats &other) {
+      leaf_nodes += other.leaf_nodes;
+      internal_nodes += other.internal_nodes;
       return *this;
     }
 
@@ -1016,7 +1135,8 @@
   using const_reference = typename Params::const_reference;
   using pointer = typename Params::pointer;
   using const_pointer = typename Params::const_pointer;
-  using iterator = btree_iterator<node_type, reference, pointer>;
+  using iterator =
+      typename btree_iterator<node_type, reference, pointer>::iterator;
   using const_iterator = typename iterator::const_iterator;
   using reverse_iterator = std::reverse_iterator<iterator>;
   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
@@ -1028,28 +1148,46 @@
 
  private:
   // For use in copy_or_move_values_in_order.
-  const value_type &maybe_move_from_iterator(const_iterator x) { return *x; }
-  value_type &&maybe_move_from_iterator(iterator x) { return std::move(*x); }
+  const value_type &maybe_move_from_iterator(const_iterator it) { return *it; }
+  value_type &&maybe_move_from_iterator(iterator it) {
+    // This is a destructive operation on the other container so it's safe for
+    // us to const_cast and move from the keys here even if it's a set.
+    return std::move(const_cast<value_type &>(*it));
+  }
 
   // Copies or moves (depending on the template parameter) the values in
-  // x into this btree in their order in x. This btree must be empty before this
-  // method is called. This method is used in copy construction, copy
-  // assignment, and move assignment.
+  // other into this btree in their order in other. This btree must be empty
+  // before this method is called. This method is used in copy construction,
+  // copy assignment, and move assignment.
   template <typename Btree>
-  void copy_or_move_values_in_order(Btree *x);
+  void copy_or_move_values_in_order(Btree &other);
 
   // Validates that various assumptions/requirements are true at compile time.
   constexpr static bool static_assert_validation();
 
  public:
-  btree(const key_compare &comp, const allocator_type &alloc);
+  btree(const key_compare &comp, const allocator_type &alloc)
+      : root_(comp, alloc, EmptyNode()), rightmost_(EmptyNode()), size_(0) {}
 
-  btree(const btree &x);
-  btree(btree &&x) noexcept
-      : root_(std::move(x.root_)),
-        rightmost_(absl::exchange(x.rightmost_, EmptyNode())),
-        size_(absl::exchange(x.size_, 0)) {
-    x.mutable_root() = EmptyNode();
+  btree(const btree &other) : btree(other, other.allocator()) {}
+  btree(const btree &other, const allocator_type &alloc)
+      : btree(other.key_comp(), alloc) {
+    copy_or_move_values_in_order(other);
+  }
+  btree(btree &&other) noexcept
+      : root_(std::move(other.root_)),
+        rightmost_(absl::exchange(other.rightmost_, EmptyNode())),
+        size_(absl::exchange(other.size_, 0)) {
+    other.mutable_root() = EmptyNode();
+  }
+  btree(btree &&other, const allocator_type &alloc)
+      : btree(other.key_comp(), alloc) {
+    if (alloc == other.allocator()) {
+      swap(other);
+    } else {
+      // Move values from `other` one at a time when allocators are different.
+      copy_or_move_values_in_order(other);
+    }
   }
 
   ~btree() {
@@ -1059,9 +1197,9 @@
     clear();
   }
 
-  // Assign the contents of x to *this.
-  btree &operator=(const btree &x);
-  btree &operator=(btree &&x) noexcept;
+  // Assign the contents of other to *this.
+  btree &operator=(const btree &other);
+  btree &operator=(btree &&other) noexcept;
 
   iterator begin() { return iterator(leftmost()); }
   const_iterator begin() const { return const_iterator(leftmost()); }
@@ -1078,17 +1216,22 @@
     return const_reverse_iterator(begin());
   }
 
-  // Finds the first element whose key is not less than key.
+  // Finds the first element whose key is not less than `key`.
   template <typename K>
   iterator lower_bound(const K &key) {
-    return internal_end(internal_lower_bound(key));
+    return internal_end(internal_lower_bound(key).value);
   }
   template <typename K>
   const_iterator lower_bound(const K &key) const {
-    return internal_end(internal_lower_bound(key));
+    return internal_end(internal_lower_bound(key).value);
   }
 
-  // Finds the first element whose key is greater than key.
+  // Finds the first element whose key is not less than `key` and also returns
+  // whether that element is equal to `key`.
+  template <typename K>
+  std::pair<iterator, bool> lower_bound_equal(const K &key) const;
+
+  // Finds the first element whose key is greater than `key`.
   template <typename K>
   iterator upper_bound(const K &key) {
     return internal_end(internal_upper_bound(key));
@@ -1099,23 +1242,21 @@
   }
 
   // Finds the range of values which compare equal to key. The first member of
-  // the returned pair is equal to lower_bound(key). The second member pair of
-  // the pair is equal to upper_bound(key).
+  // the returned pair is equal to lower_bound(key). The second member of the
+  // pair is equal to upper_bound(key).
   template <typename K>
-  std::pair<iterator, iterator> equal_range(const K &key) {
-    return {lower_bound(key), upper_bound(key)};
-  }
+  std::pair<iterator, iterator> equal_range(const K &key);
   template <typename K>
   std::pair<const_iterator, const_iterator> equal_range(const K &key) const {
-    return {lower_bound(key), upper_bound(key)};
+    return const_cast<btree *>(this)->equal_range(key);
   }
 
   // Inserts a value into the btree only if it does not already exist. The
   // boolean return value indicates whether insertion succeeded or failed.
   // Requirement: if `key` already exists in the btree, does not consume `args`.
   // Requirement: `key` is never referenced after consuming `args`.
-  template <typename... Args>
-  std::pair<iterator, bool> insert_unique(const key_type &key, Args &&... args);
+  template <typename K, typename... Args>
+  std::pair<iterator, bool> insert_unique(const K &key, Args &&... args);
 
   // Inserts with hint. Checks to see if the value should be placed immediately
   // before `position` in the tree. If so, then the insertion will take
@@ -1123,14 +1264,23 @@
   // logarithmic time as if a call to insert_unique() were made.
   // Requirement: if `key` already exists in the btree, does not consume `args`.
   // Requirement: `key` is never referenced after consuming `args`.
-  template <typename... Args>
+  template <typename K, typename... Args>
   std::pair<iterator, bool> insert_hint_unique(iterator position,
-                                               const key_type &key,
+                                               const K &key,
                                                Args &&... args);
 
   // Insert a range of values into the btree.
+  // Note: the first overload avoids constructing a value_type if the key
+  // already exists in the btree.
+  template <typename InputIterator,
+            typename = decltype(std::declval<const key_compare &>()(
+                params_type::key(*std::declval<InputIterator>()),
+                std::declval<const key_type &>()))>
+  void insert_iterator_unique(InputIterator b, InputIterator e, int);
+  // We need the second overload for cases in which we need to construct a
+  // value_type in order to compare it with the keys already in the btree.
   template <typename InputIterator>
-  void insert_iterator_unique(InputIterator b, InputIterator e);
+  void insert_iterator_unique(InputIterator b, InputIterator e, char);
 
   // Inserts a value into the btree.
   template <typename ValueType>
@@ -1163,18 +1313,8 @@
   // to the element after the last erased element.
   std::pair<size_type, iterator> erase_range(iterator begin, iterator end);
 
-  // Erases the specified key from the btree. Returns 1 if an element was
-  // erased and 0 otherwise.
-  template <typename K>
-  size_type erase_unique(const K &key);
-
-  // Erases all of the entries matching the specified key from the
-  // btree. Returns the number of elements erased.
-  template <typename K>
-  size_type erase_multi(const K &key);
-
-  // Finds the iterator corresponding to a key or returns end() if the key is
-  // not present.
+  // Finds an element with key equivalent to `key` or returns `end()` if `key`
+  // is not present.
   template <typename K>
   iterator find(const K &key) {
     return internal_end(internal_find(key));
@@ -1184,35 +1324,18 @@
     return internal_end(internal_find(key));
   }
 
-  // Returns a count of the number of times the key appears in the btree.
-  template <typename K>
-  size_type count_unique(const K &key) const {
-    const iterator begin = internal_find(key);
-    if (begin.node == nullptr) {
-      // The key doesn't exist in the tree.
-      return 0;
-    }
-    return 1;
-  }
-  // Returns a count of the number of times the key appears in the btree.
-  template <typename K>
-  size_type count_multi(const K &key) const {
-    const auto range = equal_range(key);
-    return std::distance(range.first, range.second);
-  }
-
   // Clear the btree, deleting all of the values it contains.
   void clear();
 
-  // Swap the contents of *this and x.
-  void swap(btree &x);
+  // Swaps the contents of `this` and `other`.
+  void swap(btree &other);
 
   const key_compare &key_comp() const noexcept {
     return root_.template get<0>();
   }
-  template <typename K, typename LK>
-  bool compare_keys(const K &x, const LK &y) const {
-    return compare_internal::compare_result_as_less_than(key_comp()(x, y));
+  template <typename K1, typename K2>
+  bool compare_keys(const K1 &a, const K2 &b) const {
+    return compare_internal::compare_result_as_less_than(key_comp()(a, b));
   }
 
   value_compare value_comp() const { return value_compare(key_comp()); }
@@ -1263,12 +1386,14 @@
     }
   }
 
-  // The average number of bytes used per value stored in the btree.
+  // The average number of bytes used per value stored in the btree assuming
+  // random insertion order.
   static double average_bytes_per_value() {
-    // Returns the number of bytes per value on a leaf node that is 75%
-    // full. Experimentally, this matches up nicely with the computed number of
-    // bytes per value in trees that had their values inserted in random order.
-    return node_type::LeafSize() / (kNodeValues * 0.75);
+    // The expected number of values per node with random insertion order is the
+    // average of the maximum and minimum numbers of values per node.
+    const double expected_values_per_node =
+        (kNodeSlots + kMinNodeValues) / 2.0;
+    return node_type::LeafSize() / expected_values_per_node;
   }
 
   // The fullness of the btree. Computed as the number of elements in the btree
@@ -1278,7 +1403,7 @@
   // Returns 0 for empty trees.
   double fullness() const {
     if (empty()) return 0.0;
-    return static_cast<double>(size()) / (nodes() * kNodeValues);
+    return static_cast<double>(size()) / (nodes() * kNodeSlots);
   }
   // The overhead of the btree structure in bytes per node. Computed as the
   // total number of bytes used by the btree minus the number of bytes used for
@@ -1322,38 +1447,24 @@
 
   // Node creation/deletion routines.
   node_type *new_internal_node(node_type *parent) {
-    node_type *p = allocate(node_type::InternalSize());
-    return node_type::init_internal(p, parent);
+    node_type *n = allocate(node_type::InternalSize());
+    n->init_internal(parent);
+    return n;
   }
   node_type *new_leaf_node(node_type *parent) {
-    node_type *p = allocate(node_type::LeafSize());
-    return node_type::init_leaf(p, parent, kNodeValues);
+    node_type *n = allocate(node_type::LeafSize());
+    n->init_leaf(parent, kNodeSlots);
+    return n;
   }
   node_type *new_leaf_root_node(const int max_count) {
-    node_type *p = allocate(node_type::LeafSize(max_count));
-    return node_type::init_leaf(p, p, max_count);
+    node_type *n = allocate(node_type::LeafSize(max_count));
+    n->init_leaf(/*parent=*/n, max_count);
+    return n;
   }
 
   // Deletion helper routines.
-  void erase_same_node(iterator begin, iterator end);
-  iterator erase_from_leaf_node(iterator begin, size_type to_erase);
   iterator rebalance_after_delete(iterator iter);
 
-  // Deallocates a node of a certain size in bytes using the allocator.
-  void deallocate(const size_type size, node_type *node) {
-    absl::container_internal::Deallocate<node_type::Alignment()>(
-        mutable_allocator(), node, size);
-  }
-
-  void delete_internal_node(node_type *node) {
-    node->destroy(mutable_allocator());
-    deallocate(node_type::InternalSize(), node);
-  }
-  void delete_leaf_node(node_type *node) {
-    node->destroy(mutable_allocator());
-    deallocate(node_type::LeafSize(node->max_count()), node);
-  }
-
   // Rebalances or splits the node iter points to.
   void rebalance_or_split(iterator *iter);
 
@@ -1391,28 +1502,19 @@
   static IterType internal_last(IterType iter);
 
   // Returns an iterator pointing to the leaf position at which key would
-  // reside in the tree. We provide 2 versions of internal_locate. The first
-  // version uses a less-than comparator and is incapable of distinguishing when
-  // there is an exact match. The second version is for the key-compare-to
-  // specialization and distinguishes exact matches. The key-compare-to
-  // specialization allows the caller to avoid a subsequent comparison to
-  // determine if an exact match was made, which is important for keys with
-  // expensive comparison, such as strings.
+  // reside in the tree, unless there is an exact match - in which case, the
+  // result may not be on a leaf. When there's a three-way comparator, we can
+  // return whether there was an exact match. This allows the caller to avoid a
+  // subsequent comparison to determine if an exact match was made, which is
+  // important for keys with expensive comparison, such as strings.
   template <typename K>
   SearchResult<iterator, is_key_compare_to::value> internal_locate(
       const K &key) const;
 
-  template <typename K>
-  SearchResult<iterator, false> internal_locate_impl(
-      const K &key, std::false_type /* IsCompareTo */) const;
-
-  template <typename K>
-  SearchResult<iterator, true> internal_locate_impl(
-      const K &key, std::true_type /* IsCompareTo */) const;
-
   // Internal routine which implements lower_bound().
   template <typename K>
-  iterator internal_lower_bound(const K &key) const;
+  SearchResult<iterator, is_key_compare_to::value> internal_lower_bound(
+      const K &key) const;
 
   // Internal routine which implements upper_bound().
   template <typename K>
@@ -1422,9 +1524,6 @@
   template <typename K>
   iterator internal_find(const K &key) const;
 
-  // Deletes a node and all of its children.
-  void internal_clear(node_type *node);
-
   // Verifies the tree structure of node.
   int internal_verify(const node_type *node, const key_type *lo,
                       const key_type *hi) const;
@@ -1444,13 +1543,6 @@
     return res;
   }
 
- public:
-  // Exposed only for tests.
-  static bool testonly_uses_linear_node_search() {
-    return node_type::testonly_uses_linear_node_search();
-  }
-
- private:
   // We use compressed tuple in order to save space because key_compare and
   // allocator_type are usually empty.
   absl::container_internal::CompressedTuple<key_compare, allocator_type,
@@ -1477,10 +1569,8 @@
   // Shift old values to create space for new value and then construct it in
   // place.
   if (i < finish()) {
-    value_init(finish(), alloc, slot(finish() - 1));
-    for (size_type j = finish() - 1; j > i; --j)
-      params_type::move(alloc, slot(j - 1), slot(j));
-    value_destroy(i, alloc);
+    transfer_n_backward(finish() - i, /*dest_i=*/i + 1, /*src_i=*/i, this,
+                        alloc);
   }
   value_init(i, alloc, std::forward<Args>(args)...);
   set_finish(finish() + 1);
@@ -1494,24 +1584,27 @@
 }
 
 template <typename P>
-inline void btree_node<P>::remove_value(const int i, allocator_type *alloc) {
-  if (!leaf() && finish() > i + 1) {
-    assert(child(i + 1)->count() == 0);
-    for (size_type j = i + 1; j < finish(); ++j) {
-      set_child(j, child(j + 1));
+inline void btree_node<P>::remove_values(const field_type i,
+                                         const field_type to_erase,
+                                         allocator_type *alloc) {
+  // Transfer values after the removed range into their new places.
+  value_destroy_n(i, to_erase, alloc);
+  const field_type orig_finish = finish();
+  const field_type src_i = i + to_erase;
+  transfer_n(orig_finish - src_i, i, src_i, this, alloc);
+
+  if (!leaf()) {
+    // Delete all children between begin and end.
+    for (int j = 0; j < to_erase; ++j) {
+      clear_and_delete(child(i + j + 1), alloc);
     }
-    clear_child(finish());
+    // Rotate children after end into new positions.
+    for (int j = i + to_erase + 1; j <= orig_finish; ++j) {
+      set_child(j - to_erase, child(j));
+      clear_child(j);
+    }
   }
-
-  remove_values_ignore_children(i, /*to_erase=*/1, alloc);
-}
-
-template <typename P>
-inline void btree_node<P>::remove_values_ignore_children(
-    const int i, const int to_erase, allocator_type *alloc) {
-  params_type::move(alloc, slot(i + to_erase), finish_slot(), slot(i));
-  value_destroy_n(finish() - to_erase, to_erase, alloc);
-  set_finish(finish() - to_erase);
+  set_finish(orig_finish - to_erase);
 }
 
 template <typename P>
@@ -1525,22 +1618,17 @@
   assert(to_move <= right->count());
 
   // 1) Move the delimiting value in the parent to the left node.
-  value_init(finish(), alloc, parent()->slot(position()));
+  transfer(finish(), position(), parent(), alloc);
 
   // 2) Move the (to_move - 1) values from the right node to the left node.
-  right->uninitialized_move_n(to_move - 1, right->start(), finish() + 1, this,
-                              alloc);
+  transfer_n(to_move - 1, finish() + 1, right->start(), right, alloc);
 
   // 3) Move the new delimiting value to the parent from the right node.
-  params_type::move(alloc, right->slot(to_move - 1),
-                    parent()->slot(position()));
+  parent()->transfer(position(), right->start() + to_move - 1, right, alloc);
 
-  // 4) Shift the values in the right node to their correct position.
-  params_type::move(alloc, right->slot(to_move), right->finish_slot(),
-                    right->start_slot());
-
-  // 5) Destroy the now-empty to_move entries in the right node.
-  right->value_destroy_n(right->finish() - to_move, to_move, alloc);
+  // 4) Shift the values in the right node to their correct positions.
+  right->transfer_n(right->count() - to_move, right->start(),
+                    right->start() + to_move, right, alloc);
 
   if (!leaf()) {
     // Move the child pointers from the right to the left node.
@@ -1575,54 +1663,19 @@
   // Lastly, a new delimiting value is moved from the left node into the
   // parent, and the remaining empty left node entries are destroyed.
 
-  if (right->count() >= to_move) {
-    // The original location of the right->count() values are sufficient to hold
-    // the new to_move entries from the parent and left node.
+  // 1) Shift existing values in the right node to their correct positions.
+  right->transfer_n_backward(right->count(), right->start() + to_move,
+                             right->start(), right, alloc);
 
-    // 1) Shift existing values in the right node to their correct positions.
-    right->uninitialized_move_n(to_move, right->finish() - to_move,
-                                right->finish(), right, alloc);
-    for (slot_type *src = right->slot(right->finish() - to_move - 1),
-                   *dest = right->slot(right->finish() - 1),
-                   *end = right->start_slot();
-         src >= end; --src, --dest) {
-      params_type::move(alloc, src, dest);
-    }
+  // 2) Move the delimiting value in the parent to the right node.
+  right->transfer(right->start() + to_move - 1, position(), parent(), alloc);
 
-    // 2) Move the delimiting value in the parent to the right node.
-    params_type::move(alloc, parent()->slot(position()),
-                      right->slot(to_move - 1));
-
-    // 3) Move the (to_move - 1) values from the left node to the right node.
-    params_type::move(alloc, slot(finish() - (to_move - 1)), finish_slot(),
-                      right->start_slot());
-  } else {
-    // The right node does not have enough initialized space to hold the new
-    // to_move entries, so part of them will move to uninitialized space.
-
-    // 1) Shift existing values in the right node to their correct positions.
-    right->uninitialized_move_n(right->count(), right->start(),
-                                right->start() + to_move, right, alloc);
-
-    // 2) Move the delimiting value in the parent to the right node.
-    right->value_init(to_move - 1, alloc, parent()->slot(position()));
-
-    // 3) Move the (to_move - 1) values from the left node to the right node.
-    const size_type uninitialized_remaining = to_move - right->count() - 1;
-    uninitialized_move_n(uninitialized_remaining,
-                         finish() - uninitialized_remaining, right->finish(),
-                         right, alloc);
-    params_type::move(alloc, slot(finish() - (to_move - 1)),
-                      slot(finish() - uninitialized_remaining),
-                      right->start_slot());
-  }
+  // 3) Move the (to_move - 1) values from the left node to the right node.
+  right->transfer_n(to_move - 1, right->start(), finish() - (to_move - 1), this,
+                    alloc);
 
   // 4) Move the new delimiting value to the parent from the left node.
-  params_type::move(alloc, slot(finish() - to_move),
-                    parent()->slot(position()));
-
-  // 5) Destroy the now-empty to_move entries in the left node.
-  value_destroy_n(finish() - to_move, to_move, alloc);
+  parent()->transfer(position(), finish() - to_move, this, alloc);
 
   if (!leaf()) {
     // Move the child pointers from the left to the right node.
@@ -1645,7 +1698,7 @@
 void btree_node<P>::split(const int insert_position, btree_node *dest,
                           allocator_type *alloc) {
   assert(dest->count() == 0);
-  assert(max_count() == kNodeValues);
+  assert(max_count() == kNodeSlots);
 
   // We bias the split based on the position being inserted. If we're
   // inserting at the beginning of the left node then bias the split to put
@@ -1653,7 +1706,7 @@
   // right node then bias the split to put more values on the left node.
   if (insert_position == start()) {
     dest->set_finish(dest->start() + finish() - 1);
-  } else if (insert_position == kNodeValues) {
+  } else if (insert_position == kNodeSlots) {
     dest->set_finish(dest->start());
   } else {
     dest->set_finish(dest->start() + count() / 2);
@@ -1662,10 +1715,7 @@
   assert(count() >= 1);
 
   // Move values from the left sibling to the right sibling.
-  uninitialized_move_n(dest->count(), finish(), dest->start(), dest, alloc);
-
-  // Destroy the now-empty entries in the left node.
-  value_destroy_n(finish(), dest->count(), alloc);
+  dest->transfer_n(dest->count(), dest->start(), finish(), this, alloc);
 
   // The split key is the largest value in the left sibling.
   --mutable_finish();
@@ -1692,11 +1742,7 @@
   value_init(finish(), alloc, parent()->slot(position()));
 
   // Move the values from the right to the left node.
-  src->uninitialized_move_n(src->count(), src->start(), finish() + 1, this,
-                            alloc);
-
-  // Destroy the now-empty entries in the right node.
-  src->value_destroy_n(src->start(), src->count(), alloc);
+  transfer_n(src->count(), finish() + 1, src->start(), src, alloc);
 
   if (!leaf()) {
     // Move the child pointers from the right to the left node.
@@ -1710,56 +1756,59 @@
   set_finish(start() + 1 + count() + src->count());
   src->set_finish(src->start());
 
-  // Remove the value on the parent node.
-  parent()->remove_value(position(), alloc);
+  // Remove the value on the parent node and delete the src node.
+  parent()->remove_values(position(), /*to_erase=*/1, alloc);
 }
 
 template <typename P>
-void btree_node<P>::swap(btree_node *x, allocator_type *alloc) {
-  using std::swap;
-  assert(leaf() == x->leaf());
-
-  // Determine which is the smaller/larger node.
-  btree_node *smaller = this, *larger = x;
-  if (smaller->count() > larger->count()) {
-    swap(smaller, larger);
+void btree_node<P>::clear_and_delete(btree_node *node, allocator_type *alloc) {
+  if (node->leaf()) {
+    node->value_destroy_n(node->start(), node->count(), alloc);
+    deallocate(LeafSize(node->max_count()), node, alloc);
+    return;
+  }
+  if (node->count() == 0) {
+    deallocate(InternalSize(), node, alloc);
+    return;
   }
 
-  // Swap the values.
-  for (slot_type *a = smaller->start_slot(), *b = larger->start_slot(),
-                 *end = smaller->finish_slot();
-       a != end; ++a, ++b) {
-    params_type::swap(alloc, a, b);
+  // The parent of the root of the subtree we are deleting.
+  btree_node *delete_root_parent = node->parent();
+
+  // Navigate to the leftmost leaf under node, and then delete upwards.
+  while (!node->leaf()) node = node->start_child();
+  // Use `int` because `pos` needs to be able to hold `kNodeSlots+1`, which
+  // isn't guaranteed to be a valid `field_type`.
+  int pos = node->position();
+  btree_node *parent = node->parent();
+  for (;;) {
+    // In each iteration of the next loop, we delete one leaf node and go right.
+    assert(pos <= parent->finish());
+    do {
+      node = parent->child(pos);
+      if (!node->leaf()) {
+        // Navigate to the leftmost leaf under node.
+        while (!node->leaf()) node = node->start_child();
+        pos = node->position();
+        parent = node->parent();
+      }
+      node->value_destroy_n(node->start(), node->count(), alloc);
+      deallocate(LeafSize(node->max_count()), node, alloc);
+      ++pos;
+    } while (pos <= parent->finish());
+
+    // Once we've deleted all children of parent, delete parent and go up/right.
+    assert(pos > parent->finish());
+    do {
+      node = parent;
+      pos = node->position();
+      parent = node->parent();
+      node->value_destroy_n(node->start(), node->count(), alloc);
+      deallocate(InternalSize(), node, alloc);
+      if (parent == delete_root_parent) return;
+      ++pos;
+    } while (pos > parent->finish());
   }
-
-  // Move values that can't be swapped.
-  const size_type to_move = larger->count() - smaller->count();
-  larger->uninitialized_move_n(to_move, smaller->finish(), smaller->finish(),
-                               smaller, alloc);
-  larger->value_destroy_n(smaller->finish(), to_move, alloc);
-
-  if (!leaf()) {
-    // Swap the child pointers.
-    std::swap_ranges(&smaller->mutable_child(smaller->start()),
-                     &smaller->mutable_child(smaller->finish() + 1),
-                     &larger->mutable_child(larger->start()));
-    // Update swapped children's parent pointers.
-    int i = smaller->start();
-    int j = larger->start();
-    for (; i <= smaller->finish(); ++i, ++j) {
-      smaller->child(i)->set_parent(smaller);
-      larger->child(j)->set_parent(larger);
-    }
-    // Move the child pointers that couldn't be swapped.
-    for (; j <= larger->finish(); ++i, ++j) {
-      smaller->init_child(i, larger->child(j));
-      larger->clear_child(j);
-    }
-  }
-
-  // Swap the `finish`s.
-  // TODO(ezb): with floating storage, will also need to swap starts.
-  swap(mutable_finish(), x->mutable_finish());
 }
 
 ////
@@ -1774,6 +1823,7 @@
       position = node->position();
       node = node->parent();
     }
+    // TODO(ezb): assert we aren't incrementing end() instead of handling.
     if (position == node->finish()) {
       *this = save;
     }
@@ -1797,6 +1847,7 @@
       position = node->position() - 1;
       node = node->parent();
     }
+    // TODO(ezb): assert we aren't decrementing begin() instead of handling.
     if (position < node->start()) {
       *this = save;
     }
@@ -1814,7 +1865,7 @@
 // btree methods
 template <typename P>
 template <typename Btree>
-void btree<P>::copy_or_move_values_in_order(Btree *x) {
+void btree<P>::copy_or_move_values_in_order(Btree &other) {
   static_assert(std::is_same<btree, Btree>::value ||
                     std::is_same<const btree, Btree>::value,
                 "Btree type must be same or const.");
@@ -1822,11 +1873,11 @@
 
   // We can avoid key comparisons because we know the order of the
   // values is the same order we'll store them in.
-  auto iter = x->begin();
-  if (iter == x->end()) return;
+  auto iter = other.begin();
+  if (iter == other.end()) return;
   insert_multi(maybe_move_from_iterator(iter));
   ++iter;
-  for (; iter != x->end(); ++iter) {
+  for (; iter != other.end(); ++iter) {
     // If the btree is not empty, we can just insert the new value at the end
     // of the tree.
     internal_emplace(end(), maybe_move_from_iterator(iter));
@@ -1845,7 +1896,7 @@
   // Note: We assert that kTargetValues, which is computed from
   // Params::kTargetNodeSize, must fit the node_type::field_type.
   static_assert(
-      kNodeValues < (1 << (8 * sizeof(typename node_type::field_type))),
+      kNodeSlots < (1 << (8 * sizeof(typename node_type::field_type))),
       "target node size too large");
 
   // Verify that key_compare returns an absl::{weak,strong}_ordering or bool.
@@ -1865,24 +1916,57 @@
 }
 
 template <typename P>
-btree<P>::btree(const key_compare &comp, const allocator_type &alloc)
-    : root_(comp, alloc, EmptyNode()), rightmost_(EmptyNode()), size_(0) {}
-
-template <typename P>
-btree<P>::btree(const btree &x) : btree(x.key_comp(), x.allocator()) {
-  copy_or_move_values_in_order(&x);
+template <typename K>
+auto btree<P>::lower_bound_equal(const K &key) const
+    -> std::pair<iterator, bool> {
+  const SearchResult<iterator, is_key_compare_to::value> res =
+      internal_lower_bound(key);
+  const iterator lower = iterator(internal_end(res.value));
+  const bool equal = res.HasMatch()
+                         ? res.IsEq()
+                         : lower != end() && !compare_keys(key, lower.key());
+  return {lower, equal};
 }
 
 template <typename P>
-template <typename... Args>
-auto btree<P>::insert_unique(const key_type &key, Args &&... args)
+template <typename K>
+auto btree<P>::equal_range(const K &key) -> std::pair<iterator, iterator> {
+  const std::pair<iterator, bool> lower_and_equal = lower_bound_equal(key);
+  const iterator lower = lower_and_equal.first;
+  if (!lower_and_equal.second) {
+    return {lower, lower};
+  }
+
+  const iterator next = std::next(lower);
+  if (!params_type::template can_have_multiple_equivalent_keys<K>()) {
+    // The next iterator after lower must point to a key greater than `key`.
+    // Note: if this assert fails, then it may indicate that the comparator does
+    // not meet the equivalence requirements for Compare
+    // (see https://en.cppreference.com/w/cpp/named_req/Compare).
+    assert(next == end() || compare_keys(key, next.key()));
+    return {lower, next};
+  }
+  // Try once more to avoid the call to upper_bound() if there's only one
+  // equivalent key. This should prevent all calls to upper_bound() in cases of
+  // unique-containers with heterogeneous comparators in which all comparison
+  // operators have the same equivalence classes.
+  if (next == end() || compare_keys(key, next.key())) return {lower, next};
+
+  // In this case, we need to call upper_bound() to avoid worst case O(N)
+  // behavior if we were to iterate over equal keys.
+  return {lower, upper_bound(key)};
+}
+
+template <typename P>
+template <typename K, typename... Args>
+auto btree<P>::insert_unique(const K &key, Args &&... args)
     -> std::pair<iterator, bool> {
   if (empty()) {
     mutable_root() = rightmost_ = new_leaf_root_node(1);
   }
 
-  auto res = internal_locate(key);
-  iterator &iter = res.value;
+  SearchResult<iterator, is_key_compare_to::value> res = internal_locate(key);
+  iterator iter = res.value;
 
   if (res.HasMatch()) {
     if (res.IsEq()) {
@@ -1900,8 +1984,8 @@
 }
 
 template <typename P>
-template <typename... Args>
-inline auto btree<P>::insert_hint_unique(iterator position, const key_type &key,
+template <typename K, typename... Args>
+inline auto btree<P>::insert_hint_unique(iterator position, const K &key,
                                          Args &&... args)
     -> std::pair<iterator, bool> {
   if (!empty()) {
@@ -1925,14 +2009,23 @@
 }
 
 template <typename P>
-template <typename InputIterator>
-void btree<P>::insert_iterator_unique(InputIterator b, InputIterator e) {
+template <typename InputIterator, typename>
+void btree<P>::insert_iterator_unique(InputIterator b, InputIterator e, int) {
   for (; b != e; ++b) {
     insert_hint_unique(end(), params_type::key(*b), *b);
   }
 }
 
 template <typename P>
+template <typename InputIterator>
+void btree<P>::insert_iterator_unique(InputIterator b, InputIterator e, char) {
+  for (; b != e; ++b) {
+    init_type value(*b);
+    insert_hint_unique(end(), params_type::key(value), std::move(value));
+  }
+}
+
+template <typename P>
 template <typename ValueType>
 auto btree<P>::insert_multi(const key_type &key, ValueType &&v) -> iterator {
   if (empty()) {
@@ -1977,46 +2070,47 @@
 }
 
 template <typename P>
-auto btree<P>::operator=(const btree &x) -> btree & {
-  if (this != &x) {
+auto btree<P>::operator=(const btree &other) -> btree & {
+  if (this != &other) {
     clear();
 
-    *mutable_key_comp() = x.key_comp();
+    *mutable_key_comp() = other.key_comp();
     if (absl::allocator_traits<
             allocator_type>::propagate_on_container_copy_assignment::value) {
-      *mutable_allocator() = x.allocator();
+      *mutable_allocator() = other.allocator();
     }
 
-    copy_or_move_values_in_order(&x);
+    copy_or_move_values_in_order(other);
   }
   return *this;
 }
 
 template <typename P>
-auto btree<P>::operator=(btree &&x) noexcept -> btree & {
-  if (this != &x) {
+auto btree<P>::operator=(btree &&other) noexcept -> btree & {
+  if (this != &other) {
     clear();
 
     using std::swap;
     if (absl::allocator_traits<
             allocator_type>::propagate_on_container_copy_assignment::value) {
       // Note: `root_` also contains the allocator and the key comparator.
-      swap(root_, x.root_);
-      swap(rightmost_, x.rightmost_);
-      swap(size_, x.size_);
+      swap(root_, other.root_);
+      swap(rightmost_, other.rightmost_);
+      swap(size_, other.size_);
     } else {
-      if (allocator() == x.allocator()) {
-        swap(mutable_root(), x.mutable_root());
-        swap(*mutable_key_comp(), *x.mutable_key_comp());
-        swap(rightmost_, x.rightmost_);
-        swap(size_, x.size_);
+      if (allocator() == other.allocator()) {
+        swap(mutable_root(), other.mutable_root());
+        swap(*mutable_key_comp(), *other.mutable_key_comp());
+        swap(rightmost_, other.rightmost_);
+        swap(size_, other.size_);
       } else {
         // We aren't allowed to propagate the allocator and the allocator is
         // different so we can't take over its memory. We must move each element
-        // individually. We need both `x` and `this` to have `x`s key comparator
-        // while moving the values so we can't swap the key comparators.
-        *mutable_key_comp() = x.key_comp();
-        copy_or_move_values_in_order(&x);
+        // individually. We need both `other` and `this` to have `other`s key
+        // comparator while moving the values so we can't swap the key
+        // comparators.
+        *mutable_key_comp() = other.key_comp();
+        copy_or_move_values_in_order(other);
       }
     }
   }
@@ -2028,7 +2122,7 @@
   bool internal_delete = false;
   if (!iter.node->leaf()) {
     // Deletion of a value on an internal node. First, move the largest value
-    // from our left child here, then delete that position (in remove_value()
+    // from our left child here, then delete that position (in remove_values()
     // below). We can get to the largest value from our left child by
     // decrementing iter.
     iterator internal_iter(iter);
@@ -2040,7 +2134,7 @@
   }
 
   // Delete the key from the leaf.
-  iter.node->remove_value(iter.position, mutable_allocator());
+  iter.node->remove_values(iter.position, /*to_erase=*/1, mutable_allocator());
   --size_;
 
   // We want to return the next value after the one we just erased. If we
@@ -2115,7 +2209,9 @@
   }
 
   if (begin.node == end.node) {
-    erase_same_node(begin, end);
+    assert(end.position > begin.position);
+    begin.node->remove_values(begin.position, end.position - begin.position,
+                              mutable_allocator());
     size_ -= count;
     return {count, rebalance_after_delete(begin)};
   }
@@ -2125,8 +2221,11 @@
     if (begin.node->leaf()) {
       const size_type remaining_to_erase = size_ - target_size;
       const size_type remaining_in_node = begin.node->finish() - begin.position;
-      begin = erase_from_leaf_node(
-          begin, (std::min)(remaining_to_erase, remaining_in_node));
+      const size_type to_erase =
+          (std::min)(remaining_to_erase, remaining_in_node);
+      begin.node->remove_values(begin.position, to_erase, mutable_allocator());
+      size_ -= to_erase;
+      begin = rebalance_after_delete(begin);
     } else {
       begin = erase(begin);
     }
@@ -2135,79 +2234,9 @@
 }
 
 template <typename P>
-void btree<P>::erase_same_node(iterator begin, iterator end) {
-  assert(begin.node == end.node);
-  assert(end.position > begin.position);
-
-  node_type *node = begin.node;
-  size_type to_erase = end.position - begin.position;
-  if (!node->leaf()) {
-    // Delete all children between begin and end.
-    for (size_type i = 0; i < to_erase; ++i) {
-      internal_clear(node->child(begin.position + i + 1));
-    }
-    // Rotate children after end into new positions.
-    for (size_type i = begin.position + to_erase + 1; i <= node->finish();
-         ++i) {
-      node->set_child(i - to_erase, node->child(i));
-      node->clear_child(i);
-    }
-  }
-  node->remove_values_ignore_children(begin.position, to_erase,
-                                      mutable_allocator());
-
-  // Do not need to update rightmost_, because
-  // * either end == this->end(), and therefore node == rightmost_, and still
-  //   exists
-  // * or end != this->end(), and therefore rightmost_ hasn't been erased, since
-  //   it wasn't covered in [begin, end)
-}
-
-template <typename P>
-auto btree<P>::erase_from_leaf_node(iterator begin, size_type to_erase)
-    -> iterator {
-  node_type *node = begin.node;
-  assert(node->leaf());
-  assert(node->finish() > begin.position);
-  assert(begin.position + to_erase <= node->finish());
-
-  node->remove_values_ignore_children(begin.position, to_erase,
-                                      mutable_allocator());
-
-  size_ -= to_erase;
-
-  return rebalance_after_delete(begin);
-}
-
-template <typename P>
-template <typename K>
-auto btree<P>::erase_unique(const K &key) -> size_type {
-  const iterator iter = internal_find(key);
-  if (iter.node == nullptr) {
-    // The key doesn't exist in the tree, return nothing done.
-    return 0;
-  }
-  erase(iter);
-  return 1;
-}
-
-template <typename P>
-template <typename K>
-auto btree<P>::erase_multi(const K &key) -> size_type {
-  const iterator begin = internal_lower_bound(key);
-  if (begin.node == nullptr) {
-    // The key doesn't exist in the tree, return nothing done.
-    return 0;
-  }
-  // Delete all of the keys between begin and upper_bound(key).
-  const iterator end = internal_end(internal_upper_bound(key));
-  return erase_range(begin, end).first;
-}
-
-template <typename P>
 void btree<P>::clear() {
   if (!empty()) {
-    internal_clear(root());
+    node_type::clear_and_delete(root(), mutable_allocator());
   }
   mutable_root() = EmptyNode();
   rightmost_ = EmptyNode();
@@ -2215,20 +2244,20 @@
 }
 
 template <typename P>
-void btree<P>::swap(btree &x) {
+void btree<P>::swap(btree &other) {
   using std::swap;
   if (absl::allocator_traits<
           allocator_type>::propagate_on_container_swap::value) {
     // Note: `root_` also contains the allocator and the key comparator.
-    swap(root_, x.root_);
+    swap(root_, other.root_);
   } else {
     // It's undefined behavior if the allocators are unequal here.
-    assert(allocator() == x.allocator());
-    swap(mutable_root(), x.mutable_root());
-    swap(*mutable_key_comp(), *x.mutable_key_comp());
+    assert(allocator() == other.allocator());
+    swap(mutable_root(), other.mutable_root());
+    swap(*mutable_key_comp(), *other.mutable_key_comp());
   }
-  swap(rightmost_, x.rightmost_);
-  swap(size_, x.size_);
+  swap(rightmost_, other.rightmost_);
+  swap(size_, other.size_);
 }
 
 template <typename P>
@@ -2248,7 +2277,7 @@
   node_type *&node = iter->node;
   int &insert_position = iter->position;
   assert(node->count() == node->max_count());
-  assert(kNodeValues == node->max_count());
+  assert(kNodeSlots == node->max_count());
 
   // First try to make room on the node by rebalancing.
   node_type *parent = node->parent();
@@ -2256,17 +2285,17 @@
     if (node->position() > parent->start()) {
       // Try rebalancing with our left sibling.
       node_type *left = parent->child(node->position() - 1);
-      assert(left->max_count() == kNodeValues);
-      if (left->count() < kNodeValues) {
+      assert(left->max_count() == kNodeSlots);
+      if (left->count() < kNodeSlots) {
         // We bias rebalancing based on the position being inserted. If we're
         // inserting at the end of the right node then we bias rebalancing to
         // fill up the left node.
-        int to_move = (kNodeValues - left->count()) /
-                      (1 + (insert_position < kNodeValues));
+        int to_move = (kNodeSlots - left->count()) /
+                      (1 + (insert_position < static_cast<int>(kNodeSlots)));
         to_move = (std::max)(1, to_move);
 
         if (insert_position - to_move >= node->start() ||
-            left->count() + to_move < kNodeValues) {
+            left->count() + to_move < static_cast<int>(kNodeSlots)) {
           left->rebalance_right_to_left(to_move, node, mutable_allocator());
 
           assert(node->max_count() - node->count() == to_move);
@@ -2285,17 +2314,17 @@
     if (node->position() < parent->finish()) {
       // Try rebalancing with our right sibling.
       node_type *right = parent->child(node->position() + 1);
-      assert(right->max_count() == kNodeValues);
-      if (right->count() < kNodeValues) {
+      assert(right->max_count() == kNodeSlots);
+      if (right->count() < kNodeSlots) {
         // We bias rebalancing based on the position being inserted. If we're
         // inserting at the beginning of the left node then we bias rebalancing
         // to fill up the right node.
-        int to_move = (kNodeValues - right->count()) /
+        int to_move = (static_cast<int>(kNodeSlots) - right->count()) /
                       (1 + (insert_position > node->start()));
         to_move = (std::max)(1, to_move);
 
         if (insert_position <= node->finish() - to_move ||
-            right->count() + to_move < kNodeValues) {
+            right->count() + to_move < static_cast<int>(kNodeSlots)) {
           node->rebalance_left_to_right(to_move, right, mutable_allocator());
 
           if (insert_position > node->finish()) {
@@ -2311,8 +2340,8 @@
 
     // Rebalancing failed, make sure there is room on the parent node for a new
     // value.
-    assert(parent->max_count() == kNodeValues);
-    if (parent->count() == kNodeValues) {
+    assert(parent->max_count() == kNodeSlots);
+    if (parent->count() == kNodeSlots) {
       iterator parent_iter(node->parent(), node->position());
       rebalance_or_split(&parent_iter);
     }
@@ -2348,12 +2377,7 @@
 template <typename P>
 void btree<P>::merge_nodes(node_type *left, node_type *right) {
   left->merge(right, mutable_allocator());
-  if (right->leaf()) {
-    if (rightmost_ == right) rightmost_ = left;
-    delete_leaf_node(right);
-  } else {
-    delete_internal_node(right);
-  }
+  if (rightmost_ == right) rightmost_ = left;
 }
 
 template <typename P>
@@ -2362,8 +2386,8 @@
   if (iter->node->position() > parent->start()) {
     // Try merging with our left sibling.
     node_type *left = parent->child(iter->node->position() - 1);
-    assert(left->max_count() == kNodeValues);
-    if (1 + left->count() + iter->node->count() <= kNodeValues) {
+    assert(left->max_count() == kNodeSlots);
+    if (1U + left->count() + iter->node->count() <= kNodeSlots) {
       iter->position += 1 + left->count();
       merge_nodes(left, iter->node);
       iter->node = left;
@@ -2373,8 +2397,8 @@
   if (iter->node->position() < parent->finish()) {
     // Try merging with our right sibling.
     node_type *right = parent->child(iter->node->position() + 1);
-    assert(right->max_count() == kNodeValues);
-    if (1 + iter->node->count() + right->count() <= kNodeValues) {
+    assert(right->max_count() == kNodeSlots);
+    if (1U + iter->node->count() + right->count() <= kNodeSlots) {
       merge_nodes(iter->node, right);
       return true;
     }
@@ -2410,21 +2434,20 @@
 
 template <typename P>
 void btree<P>::try_shrink() {
-  if (root()->count() > 0) {
+  node_type *orig_root = root();
+  if (orig_root->count() > 0) {
     return;
   }
   // Deleted the last item on the root node, shrink the height of the tree.
-  if (root()->leaf()) {
+  if (orig_root->leaf()) {
     assert(size() == 0);
-    delete_leaf_node(root());
-    mutable_root() = EmptyNode();
-    rightmost_ = EmptyNode();
+    mutable_root() = rightmost_ = EmptyNode();
   } else {
-    node_type *child = root()->start_child();
+    node_type *child = orig_root->start_child();
     child->make_root();
-    delete_internal_node(root());
     mutable_root() = child;
   }
+  node_type::clear_and_delete(orig_root, mutable_allocator());
 }
 
 template <typename P>
@@ -2452,25 +2475,30 @@
     --iter;
     ++iter.position;
   }
-  const int max_count = iter.node->max_count();
+  const field_type max_count = iter.node->max_count();
+  allocator_type *alloc = mutable_allocator();
   if (iter.node->count() == max_count) {
     // Make room in the leaf for the new item.
-    if (max_count < kNodeValues) {
+    if (max_count < kNodeSlots) {
       // Insertion into the root where the root is smaller than the full node
       // size. Simply grow the size of the root node.
       assert(iter.node == root());
       iter.node =
-          new_leaf_root_node((std::min<int>)(kNodeValues, 2 * max_count));
-      iter.node->swap(root(), mutable_allocator());
-      delete_leaf_node(root());
-      mutable_root() = iter.node;
-      rightmost_ = iter.node;
+          new_leaf_root_node((std::min<int>)(kNodeSlots, 2 * max_count));
+      // Transfer the values from the old root to the new root.
+      node_type *old_root = root();
+      node_type *new_root = iter.node;
+      new_root->transfer_n(old_root->count(), new_root->start(),
+                           old_root->start(), old_root, alloc);
+      new_root->set_finish(old_root->finish());
+      old_root->set_finish(old_root->start());
+      node_type::clear_and_delete(old_root, alloc);
+      mutable_root() = rightmost_ = new_root;
     } else {
       rebalance_or_split(&iter);
     }
   }
-  iter.node->emplace_value(iter.position, mutable_allocator(),
-                           std::forward<Args>(args)...);
+  iter.node->emplace_value(iter.position, alloc, std::forward<Args>(args)...);
   ++size_;
   return iter;
 }
@@ -2479,61 +2507,51 @@
 template <typename K>
 inline auto btree<P>::internal_locate(const K &key) const
     -> SearchResult<iterator, is_key_compare_to::value> {
-  return internal_locate_impl(key, is_key_compare_to());
-}
-
-template <typename P>
-template <typename K>
-inline auto btree<P>::internal_locate_impl(
-    const K &key, std::false_type /* IsCompareTo */) const
-    -> SearchResult<iterator, false> {
   iterator iter(const_cast<node_type *>(root()));
   for (;;) {
-    iter.position = iter.node->lower_bound(key, key_comp()).value;
-    // NOTE: we don't need to walk all the way down the tree if the keys are
-    // equal, but determining equality would require doing an extra comparison
-    // on each node on the way down, and we will need to go all the way to the
-    // leaf node in the expected case.
-    if (iter.node->leaf()) {
-      break;
-    }
-    iter.node = iter.node->child(iter.position);
-  }
-  return {iter};
-}
-
-template <typename P>
-template <typename K>
-inline auto btree<P>::internal_locate_impl(
-    const K &key, std::true_type /* IsCompareTo */) const
-    -> SearchResult<iterator, true> {
-  iterator iter(const_cast<node_type *>(root()));
-  for (;;) {
-    SearchResult<int, true> res = iter.node->lower_bound(key, key_comp());
+    SearchResult<int, is_key_compare_to::value> res =
+        iter.node->lower_bound(key, key_comp());
     iter.position = res.value;
-    if (res.match == MatchKind::kEq) {
+    if (res.IsEq()) {
       return {iter, MatchKind::kEq};
     }
+    // Note: in the non-key-compare-to case, we don't need to walk all the way
+    // down the tree if the keys are equal, but determining equality would
+    // require doing an extra comparison on each node on the way down, and we
+    // will need to go all the way to the leaf node in the expected case.
     if (iter.node->leaf()) {
       break;
     }
     iter.node = iter.node->child(iter.position);
   }
+  // Note: in the non-key-compare-to case, the key may actually be equivalent
+  // here (and the MatchKind::kNe is ignored).
   return {iter, MatchKind::kNe};
 }
 
 template <typename P>
 template <typename K>
-auto btree<P>::internal_lower_bound(const K &key) const -> iterator {
+auto btree<P>::internal_lower_bound(const K &key) const
+    -> SearchResult<iterator, is_key_compare_to::value> {
+  if (!params_type::template can_have_multiple_equivalent_keys<K>()) {
+    SearchResult<iterator, is_key_compare_to::value> ret = internal_locate(key);
+    ret.value = internal_last(ret.value);
+    return ret;
+  }
   iterator iter(const_cast<node_type *>(root()));
+  SearchResult<int, is_key_compare_to::value> res;
+  bool seen_eq = false;
   for (;;) {
-    iter.position = iter.node->lower_bound(key, key_comp()).value;
+    res = iter.node->lower_bound(key, key_comp());
+    iter.position = res.value;
     if (iter.node->leaf()) {
       break;
     }
+    seen_eq = seen_eq || res.IsEq();
     iter.node = iter.node->child(iter.position);
   }
-  return internal_last(iter);
+  if (res.IsEq()) return {iter, MatchKind::kEq};
+  return {internal_last(iter), seen_eq ? MatchKind::kEq : MatchKind::kNe};
 }
 
 template <typename P>
@@ -2553,7 +2571,7 @@
 template <typename P>
 template <typename K>
 auto btree<P>::internal_find(const K &key) const -> iterator {
-  auto res = internal_locate(key);
+  SearchResult<iterator, is_key_compare_to::value> res = internal_locate(key);
   if (res.HasMatch()) {
     if (res.IsEq()) {
       return res.value;
@@ -2568,18 +2586,6 @@
 }
 
 template <typename P>
-void btree<P>::internal_clear(node_type *node) {
-  if (!node->leaf()) {
-    for (int i = node->start(); i <= node->finish(); ++i) {
-      internal_clear(node->child(i));
-    }
-    delete_internal_node(node);
-  } else {
-    delete_leaf_node(node);
-  }
-}
-
-template <typename P>
 int btree<P>::internal_verify(const node_type *node, const key_type *lo,
                               const key_type *hi) const {
   assert(node->count() > 0);
diff --git a/absl/container/internal/btree_container.h b/absl/container/internal/btree_container.h
index f2e4c3a..03be708 100644
--- a/absl/container/internal/btree_container.h
+++ b/absl/container/internal/btree_container.h
@@ -23,6 +23,7 @@
 #include "absl/base/internal/throw_delegate.h"
 #include "absl/container/internal/btree.h"  // IWYU pragma: export
 #include "absl/container/internal/common.h"
+#include "absl/memory/memory.h"
 #include "absl/meta/type_traits.h"
 
 namespace absl {
@@ -68,10 +69,23 @@
   explicit btree_container(const key_compare &comp,
                            const allocator_type &alloc = allocator_type())
       : tree_(comp, alloc) {}
-  btree_container(const btree_container &x) = default;
-  btree_container(btree_container &&x) noexcept = default;
-  btree_container &operator=(const btree_container &x) = default;
-  btree_container &operator=(btree_container &&x) noexcept(
+  explicit btree_container(const allocator_type &alloc)
+      : tree_(key_compare(), alloc) {}
+
+  btree_container(const btree_container &other)
+      : btree_container(other, absl::allocator_traits<allocator_type>::
+                                   select_on_container_copy_construction(
+                                       other.get_allocator())) {}
+  btree_container(const btree_container &other, const allocator_type &alloc)
+      : tree_(other.tree_, alloc) {}
+
+  btree_container(btree_container &&other) noexcept(
+      std::is_nothrow_move_constructible<Tree>::value) = default;
+  btree_container(btree_container &&other, const allocator_type &alloc)
+      : tree_(std::move(other.tree_), alloc) {}
+
+  btree_container &operator=(const btree_container &other) = default;
+  btree_container &operator=(btree_container &&other) noexcept(
       std::is_nothrow_move_assignable<Tree>::value) = default;
 
   // Iterator routines.
@@ -90,6 +104,11 @@
 
   // Lookup routines.
   template <typename K = key_type>
+  size_type count(const key_arg<K> &key) const {
+    auto equal_range = this->equal_range(key);
+    return std::distance(equal_range.first, equal_range.second);
+  }
+  template <typename K = key_type>
   iterator find(const key_arg<K> &key) {
     return tree_.find(key);
   }
@@ -138,6 +157,11 @@
   iterator erase(const_iterator first, const_iterator last) {
     return tree_.erase_range(iterator(first), iterator(last)).second;
   }
+  template <typename K = key_type>
+  size_type erase(const key_arg<K> &key) {
+    auto equal_range = this->equal_range(key);
+    return tree_.erase_range(equal_range.first, equal_range.second).first;
+  }
 
   // Extract routines.
   node_type extract(iterator position) {
@@ -151,10 +175,9 @@
     return extract(iterator(position));
   }
 
- public:
   // Utility routines.
   void clear() { tree_.clear(); }
-  void swap(btree_container &x) { tree_.swap(x.tree_); }
+  void swap(btree_container &other) { tree_.swap(other.tree_); }
   void verify() const { tree_.verify(); }
 
   // Size routines.
@@ -235,7 +258,7 @@
   using super_type::super_type;
   btree_set_container() {}
 
-  // Range constructor.
+  // Range constructors.
   template <class InputIterator>
   btree_set_container(InputIterator b, InputIterator e,
                       const key_compare &comp = key_compare(),
@@ -243,56 +266,55 @@
       : super_type(comp, alloc) {
     insert(b, e);
   }
+  template <class InputIterator>
+  btree_set_container(InputIterator b, InputIterator e,
+                      const allocator_type &alloc)
+      : btree_set_container(b, e, key_compare(), alloc) {}
 
-  // Initializer list constructor.
+  // Initializer list constructors.
   btree_set_container(std::initializer_list<init_type> init,
                       const key_compare &comp = key_compare(),
                       const allocator_type &alloc = allocator_type())
       : btree_set_container(init.begin(), init.end(), comp, alloc) {}
-
-  // Lookup routines.
-  template <typename K = key_type>
-  size_type count(const key_arg<K> &key) const {
-    return this->tree_.count_unique(key);
-  }
+  btree_set_container(std::initializer_list<init_type> init,
+                      const allocator_type &alloc)
+      : btree_set_container(init.begin(), init.end(), alloc) {}
 
   // Insertion routines.
-  std::pair<iterator, bool> insert(const value_type &x) {
-    return this->tree_.insert_unique(params_type::key(x), x);
+  std::pair<iterator, bool> insert(const value_type &v) {
+    return this->tree_.insert_unique(params_type::key(v), v);
   }
-  std::pair<iterator, bool> insert(value_type &&x) {
-    return this->tree_.insert_unique(params_type::key(x), std::move(x));
+  std::pair<iterator, bool> insert(value_type &&v) {
+    return this->tree_.insert_unique(params_type::key(v), std::move(v));
   }
   template <typename... Args>
   std::pair<iterator, bool> emplace(Args &&... args) {
     init_type v(std::forward<Args>(args)...);
     return this->tree_.insert_unique(params_type::key(v), std::move(v));
   }
-  iterator insert(const_iterator position, const value_type &x) {
+  iterator insert(const_iterator hint, const value_type &v) {
     return this->tree_
-        .insert_hint_unique(iterator(position), params_type::key(x), x)
+        .insert_hint_unique(iterator(hint), params_type::key(v), v)
         .first;
   }
-  iterator insert(const_iterator position, value_type &&x) {
+  iterator insert(const_iterator hint, value_type &&v) {
     return this->tree_
-        .insert_hint_unique(iterator(position), params_type::key(x),
-                            std::move(x))
+        .insert_hint_unique(iterator(hint), params_type::key(v), std::move(v))
         .first;
   }
   template <typename... Args>
-  iterator emplace_hint(const_iterator position, Args &&... args) {
+  iterator emplace_hint(const_iterator hint, Args &&... args) {
     init_type v(std::forward<Args>(args)...);
     return this->tree_
-        .insert_hint_unique(iterator(position), params_type::key(v),
-                            std::move(v))
+        .insert_hint_unique(iterator(hint), params_type::key(v), std::move(v))
         .first;
   }
   template <typename InputIterator>
   void insert(InputIterator b, InputIterator e) {
-    this->tree_.insert_iterator_unique(b, e);
+    this->tree_.insert_iterator_unique(b, e, 0);
   }
   void insert(std::initializer_list<init_type> init) {
-    this->tree_.insert_iterator_unique(init.begin(), init.end());
+    this->tree_.insert_iterator_unique(init.begin(), init.end(), 0);
   }
   insert_return_type insert(node_type &&node) {
     if (!node) return {this->end(), false, node_type()};
@@ -315,18 +337,13 @@
     return res.first;
   }
 
-  // Deletion routines.
-  template <typename K = key_type>
-  size_type erase(const key_arg<K> &key) {
-    return this->tree_.erase_unique(key);
-  }
-  using super_type::erase;
-
   // Node extraction routines.
   template <typename K = key_type>
   node_type extract(const key_arg<K> &key) {
-    auto it = this->find(key);
-    return it == this->end() ? node_type() : extract(it);
+    const std::pair<iterator, bool> lower_and_equal =
+        this->tree_.lower_bound_equal(key);
+    return lower_and_equal.second ? extract(lower_and_equal.first)
+                                  : node_type();
   }
   using super_type::extract;
 
@@ -344,7 +361,7 @@
           int> = 0>
   void merge(btree_container<T> &src) {  // NOLINT
     for (auto src_it = src.begin(); src_it != src.end();) {
-      if (insert(std::move(*src_it)).second) {
+      if (insert(std::move(params_type::element(src_it.slot()))).second) {
         src_it = src.erase(src_it);
       } else {
         ++src_it;
@@ -371,6 +388,7 @@
 class btree_map_container : public btree_set_container<Tree> {
   using super_type = btree_set_container<Tree>;
   using params_type = typename Tree::params_type;
+  friend class BtreeNodePeer;
 
  private:
   template <class K>
@@ -392,111 +410,72 @@
   // Insertion routines.
   // Note: the nullptr template arguments and extra `const M&` overloads allow
   // for supporting bitfield arguments.
-  // Note: when we call `std::forward<M>(obj)` twice, it's safe because
-  // insert_unique/insert_hint_unique are guaranteed to not consume `obj` when
-  // `ret.second` is false.
-  template <class M>
-  std::pair<iterator, bool> insert_or_assign(const key_type &k, const M &obj) {
-    const std::pair<iterator, bool> ret = this->tree_.insert_unique(k, k, obj);
-    if (!ret.second) ret.first->second = obj;
-    return ret;
+  template <typename K = key_type, class M>
+  std::pair<iterator, bool> insert_or_assign(const key_arg<K> &k,
+                                             const M &obj) {
+    return insert_or_assign_impl(k, obj);
   }
-  template <class M, key_type * = nullptr>
-  std::pair<iterator, bool> insert_or_assign(key_type &&k, const M &obj) {
-    const std::pair<iterator, bool> ret =
-        this->tree_.insert_unique(k, std::move(k), obj);
-    if (!ret.second) ret.first->second = obj;
-    return ret;
+  template <typename K = key_type, class M, K * = nullptr>
+  std::pair<iterator, bool> insert_or_assign(key_arg<K> &&k, const M &obj) {
+    return insert_or_assign_impl(std::forward<K>(k), obj);
   }
-  template <class M, M * = nullptr>
-  std::pair<iterator, bool> insert_or_assign(const key_type &k, M &&obj) {
-    const std::pair<iterator, bool> ret =
-        this->tree_.insert_unique(k, k, std::forward<M>(obj));
-    if (!ret.second) ret.first->second = std::forward<M>(obj);
-    return ret;
+  template <typename K = key_type, class M, M * = nullptr>
+  std::pair<iterator, bool> insert_or_assign(const key_arg<K> &k, M &&obj) {
+    return insert_or_assign_impl(k, std::forward<M>(obj));
   }
-  template <class M, key_type * = nullptr, M * = nullptr>
-  std::pair<iterator, bool> insert_or_assign(key_type &&k, M &&obj) {
-    const std::pair<iterator, bool> ret =
-        this->tree_.insert_unique(k, std::move(k), std::forward<M>(obj));
-    if (!ret.second) ret.first->second = std::forward<M>(obj);
-    return ret;
+  template <typename K = key_type, class M, K * = nullptr, M * = nullptr>
+  std::pair<iterator, bool> insert_or_assign(key_arg<K> &&k, M &&obj) {
+    return insert_or_assign_impl(std::forward<K>(k), std::forward<M>(obj));
   }
-  template <class M>
-  iterator insert_or_assign(const_iterator position, const key_type &k,
+  template <typename K = key_type, class M>
+  iterator insert_or_assign(const_iterator hint, const key_arg<K> &k,
                             const M &obj) {
-    const std::pair<iterator, bool> ret =
-        this->tree_.insert_hint_unique(iterator(position), k, k, obj);
-    if (!ret.second) ret.first->second = obj;
-    return ret.first;
+    return insert_or_assign_hint_impl(hint, k, obj);
   }
-  template <class M, key_type * = nullptr>
-  iterator insert_or_assign(const_iterator position, key_type &&k,
-                            const M &obj) {
-    const std::pair<iterator, bool> ret = this->tree_.insert_hint_unique(
-        iterator(position), k, std::move(k), obj);
-    if (!ret.second) ret.first->second = obj;
-    return ret.first;
+  template <typename K = key_type, class M, K * = nullptr>
+  iterator insert_or_assign(const_iterator hint, key_arg<K> &&k, const M &obj) {
+    return insert_or_assign_hint_impl(hint, std::forward<K>(k), obj);
   }
-  template <class M, M * = nullptr>
-  iterator insert_or_assign(const_iterator position, const key_type &k,
-                            M &&obj) {
-    const std::pair<iterator, bool> ret = this->tree_.insert_hint_unique(
-        iterator(position), k, k, std::forward<M>(obj));
-    if (!ret.second) ret.first->second = std::forward<M>(obj);
-    return ret.first;
+  template <typename K = key_type, class M, M * = nullptr>
+  iterator insert_or_assign(const_iterator hint, const key_arg<K> &k, M &&obj) {
+    return insert_or_assign_hint_impl(hint, k, std::forward<M>(obj));
   }
-  template <class M, key_type * = nullptr, M * = nullptr>
-  iterator insert_or_assign(const_iterator position, key_type &&k, M &&obj) {
-    const std::pair<iterator, bool> ret = this->tree_.insert_hint_unique(
-        iterator(position), k, std::move(k), std::forward<M>(obj));
-    if (!ret.second) ret.first->second = std::forward<M>(obj);
-    return ret.first;
+  template <typename K = key_type, class M, K * = nullptr, M * = nullptr>
+  iterator insert_or_assign(const_iterator hint, key_arg<K> &&k, M &&obj) {
+    return insert_or_assign_hint_impl(hint, std::forward<K>(k),
+                                      std::forward<M>(obj));
   }
-  template <typename... Args>
-  std::pair<iterator, bool> try_emplace(const key_type &k, Args &&... args) {
-    return this->tree_.insert_unique(
-        k, std::piecewise_construct, std::forward_as_tuple(k),
-        std::forward_as_tuple(std::forward<Args>(args)...));
+
+  template <typename K = key_type, typename... Args,
+            typename absl::enable_if_t<
+                !std::is_convertible<K, const_iterator>::value, int> = 0>
+  std::pair<iterator, bool> try_emplace(const key_arg<K> &k, Args &&... args) {
+    return try_emplace_impl(k, std::forward<Args>(args)...);
   }
-  template <typename... Args>
-  std::pair<iterator, bool> try_emplace(key_type &&k, Args &&... args) {
-    // Note: `key_ref` exists to avoid a ClangTidy warning about moving from `k`
-    // and then using `k` unsequenced. This is safe because the move is into a
-    // forwarding reference and insert_unique guarantees that `key` is never
-    // referenced after consuming `args`.
-    const key_type &key_ref = k;
-    return this->tree_.insert_unique(
-        key_ref, std::piecewise_construct, std::forward_as_tuple(std::move(k)),
-        std::forward_as_tuple(std::forward<Args>(args)...));
+  template <typename K = key_type, typename... Args,
+            typename absl::enable_if_t<
+                !std::is_convertible<K, const_iterator>::value, int> = 0>
+  std::pair<iterator, bool> try_emplace(key_arg<K> &&k, Args &&... args) {
+    return try_emplace_impl(std::forward<K>(k), std::forward<Args>(args)...);
   }
-  template <typename... Args>
-  iterator try_emplace(const_iterator hint, const key_type &k,
+  template <typename K = key_type, typename... Args>
+  iterator try_emplace(const_iterator hint, const key_arg<K> &k,
                        Args &&... args) {
-    return this->tree_
-        .insert_hint_unique(iterator(hint), k, std::piecewise_construct,
-                            std::forward_as_tuple(k),
-                            std::forward_as_tuple(std::forward<Args>(args)...))
-        .first;
+    return try_emplace_hint_impl(hint, k, std::forward<Args>(args)...);
   }
-  template <typename... Args>
-  iterator try_emplace(const_iterator hint, key_type &&k, Args &&... args) {
-    // Note: `key_ref` exists to avoid a ClangTidy warning about moving from `k`
-    // and then using `k` unsequenced. This is safe because the move is into a
-    // forwarding reference and insert_hint_unique guarantees that `key` is
-    // never referenced after consuming `args`.
-    const key_type &key_ref = k;
-    return this->tree_
-        .insert_hint_unique(iterator(hint), key_ref, std::piecewise_construct,
-                            std::forward_as_tuple(std::move(k)),
-                            std::forward_as_tuple(std::forward<Args>(args)...))
-        .first;
+  template <typename K = key_type, typename... Args>
+  iterator try_emplace(const_iterator hint, key_arg<K> &&k, Args &&... args) {
+    return try_emplace_hint_impl(hint, std::forward<K>(k),
+                                 std::forward<Args>(args)...);
   }
-  mapped_type &operator[](const key_type &k) {
+
+  template <typename K = key_type>
+  mapped_type &operator[](const key_arg<K> &k) {
     return try_emplace(k).first->second;
   }
-  mapped_type &operator[](key_type &&k) {
-    return try_emplace(std::move(k)).first->second;
+  template <typename K = key_type>
+  mapped_type &operator[](key_arg<K> &&k) {
+    return try_emplace(std::forward<K>(k)).first->second;
   }
 
   template <typename K = key_type>
@@ -513,6 +492,40 @@
       base_internal::ThrowStdOutOfRange("absl::btree_map::at");
     return it->second;
   }
+
+ private:
+  // Note: when we call `std::forward<M>(obj)` twice, it's safe because
+  // insert_unique/insert_hint_unique are guaranteed to not consume `obj` when
+  // `ret.second` is false.
+  template <class K, class M>
+  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);
+    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);
+    return ret.first;
+  }
+
+  template <class K, class... Args>
+  std::pair<iterator, bool> try_emplace_impl(K &&k, Args &&... args) {
+    return this->tree_.insert_unique(
+        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,
+                            std::forward_as_tuple(std::forward<K>(k)),
+                            std::forward_as_tuple(std::forward<Args>(args)...))
+        .first;
+  }
 };
 
 // A common base class for btree_multiset and btree_multimap.
@@ -540,7 +553,7 @@
   using super_type::super_type;
   btree_multiset_container() {}
 
-  // Range constructor.
+  // Range constructors.
   template <class InputIterator>
   btree_multiset_container(InputIterator b, InputIterator e,
                            const key_compare &comp = key_compare(),
@@ -548,29 +561,30 @@
       : super_type(comp, alloc) {
     insert(b, e);
   }
+  template <class InputIterator>
+  btree_multiset_container(InputIterator b, InputIterator e,
+                           const allocator_type &alloc)
+      : btree_multiset_container(b, e, key_compare(), alloc) {}
 
-  // Initializer list constructor.
+  // Initializer list constructors.
   btree_multiset_container(std::initializer_list<init_type> init,
                            const key_compare &comp = key_compare(),
                            const allocator_type &alloc = allocator_type())
       : btree_multiset_container(init.begin(), init.end(), comp, alloc) {}
-
-  // Lookup routines.
-  template <typename K = key_type>
-  size_type count(const key_arg<K> &key) const {
-    return this->tree_.count_multi(key);
-  }
+  btree_multiset_container(std::initializer_list<init_type> init,
+                           const allocator_type &alloc)
+      : btree_multiset_container(init.begin(), init.end(), alloc) {}
 
   // Insertion routines.
-  iterator insert(const value_type &x) { return this->tree_.insert_multi(x); }
-  iterator insert(value_type &&x) {
-    return this->tree_.insert_multi(std::move(x));
+  iterator insert(const value_type &v) { return this->tree_.insert_multi(v); }
+  iterator insert(value_type &&v) {
+    return this->tree_.insert_multi(std::move(v));
   }
-  iterator insert(const_iterator position, const value_type &x) {
-    return this->tree_.insert_hint_multi(iterator(position), x);
+  iterator insert(const_iterator hint, const value_type &v) {
+    return this->tree_.insert_hint_multi(iterator(hint), v);
   }
-  iterator insert(const_iterator position, value_type &&x) {
-    return this->tree_.insert_hint_multi(iterator(position), std::move(x));
+  iterator insert(const_iterator hint, value_type &&v) {
+    return this->tree_.insert_hint_multi(iterator(hint), std::move(v));
   }
   template <typename InputIterator>
   void insert(InputIterator b, InputIterator e) {
@@ -584,9 +598,9 @@
     return this->tree_.insert_multi(init_type(std::forward<Args>(args)...));
   }
   template <typename... Args>
-  iterator emplace_hint(const_iterator position, Args &&... args) {
+  iterator emplace_hint(const_iterator hint, Args &&... args) {
     return this->tree_.insert_hint_multi(
-        iterator(position), init_type(std::forward<Args>(args)...));
+        iterator(hint), init_type(std::forward<Args>(args)...));
   }
   iterator insert(node_type &&node) {
     if (!node) return this->end();
@@ -605,18 +619,13 @@
     return res;
   }
 
-  // Deletion routines.
-  template <typename K = key_type>
-  size_type erase(const key_arg<K> &key) {
-    return this->tree_.erase_multi(key);
-  }
-  using super_type::erase;
-
   // Node extraction routines.
   template <typename K = key_type>
   node_type extract(const key_arg<K> &key) {
-    auto it = this->find(key);
-    return it == this->end() ? node_type() : extract(it);
+    const std::pair<iterator, bool> lower_and_equal =
+        this->tree_.lower_bound_equal(key);
+    return lower_and_equal.second ? extract(lower_and_equal.first)
+                                  : node_type();
   }
   using super_type::extract;
 
@@ -632,8 +641,9 @@
                            typename T::params_type::is_map_container>>::value,
           int> = 0>
   void merge(btree_container<T> &src) {  // NOLINT
-    insert(std::make_move_iterator(src.begin()),
-           std::make_move_iterator(src.end()));
+    for (auto src_it = src.begin(), end = src.end(); src_it != end; ++src_it) {
+      insert(std::move(params_type::element(src_it.slot())));
+    }
     src.clear();
   }
 
diff --git a/absl/container/internal/common.h b/absl/container/internal/common.h
index 5037d80..030e9d4 100644
--- a/absl/container/internal/common.h
+++ b/absl/container/internal/common.h
@@ -138,6 +138,7 @@
                   absl::void_t<typename Policy::mapped_type>>
     : public node_handle_base<PolicyTraits, Alloc> {
   using Base = node_handle_base<PolicyTraits, Alloc>;
+  using slot_type = typename PolicyTraits::slot_type;
 
  public:
   using key_type = typename Policy::key_type;
@@ -145,8 +146,11 @@
 
   constexpr node_handle() {}
 
-  auto key() const -> decltype(PolicyTraits::key(this->slot())) {
-    return PolicyTraits::key(this->slot());
+  // When C++17 is available, we can use std::launder to provide mutable
+  // access to the key. Otherwise, we provide const access.
+  auto key() const
+      -> decltype(PolicyTraits::mutable_key(std::declval<slot_type*>())) {
+    return PolicyTraits::mutable_key(this->slot());
   }
 
   mapped_type& mapped() const {
diff --git a/absl/container/internal/compressed_tuple.h b/absl/container/internal/compressed_tuple.h
index 4bfe92f..5ebe164 100644
--- a/absl/container/internal/compressed_tuple.h
+++ b/absl/container/internal/compressed_tuple.h
@@ -169,9 +169,33 @@
 }
 
 template <typename T, typename V>
-using TupleMoveConstructible = typename std::conditional<
-      std::is_reference<T>::value, std::is_convertible<V, T>,
-      std::is_constructible<T, V&&>>::type;
+using TupleElementMoveConstructible =
+    typename std::conditional<std::is_reference<T>::value,
+                              std::is_convertible<V, T>,
+                              std::is_constructible<T, V&&>>::type;
+
+template <bool SizeMatches, class T, class... Vs>
+struct TupleMoveConstructible : std::false_type {};
+
+template <class... Ts, class... Vs>
+struct TupleMoveConstructible<true, CompressedTuple<Ts...>, Vs...>
+    : std::integral_constant<
+          bool, absl::conjunction<
+                    TupleElementMoveConstructible<Ts, Vs&&>...>::value> {};
+
+template <typename T>
+struct compressed_tuple_size;
+
+template <typename... Es>
+struct compressed_tuple_size<CompressedTuple<Es...>>
+    : public std::integral_constant<std::size_t, sizeof...(Es)> {};
+
+template <class T, class... Vs>
+struct TupleItemsMoveConstructible
+    : std::integral_constant<
+          bool, TupleMoveConstructible<compressed_tuple_size<T>::value ==
+                                           sizeof...(Vs),
+                                       T, Vs...>::value> {};
 
 }  // namespace internal_compressed_tuple
 
@@ -217,22 +241,23 @@
   explicit constexpr CompressedTuple(const Ts&... base)
       : CompressedTuple::CompressedTupleImpl(absl::in_place, base...) {}
 
-  template <typename... Vs,
+  template <typename First, typename... Vs,
             absl::enable_if_t<
                 absl::conjunction<
                     // Ensure we are not hiding default copy/move constructors.
                     absl::negation<std::is_same<void(CompressedTuple),
-                                                void(absl::decay_t<Vs>...)>>,
-                    internal_compressed_tuple::TupleMoveConstructible<
-                        Ts, Vs&&>...>::value,
+                                                void(absl::decay_t<First>)>>,
+                    internal_compressed_tuple::TupleItemsMoveConstructible<
+                        CompressedTuple<Ts...>, First, Vs...>>::value,
                 bool> = true>
-  explicit constexpr CompressedTuple(Vs&&... base)
+  explicit constexpr CompressedTuple(First&& first, Vs&&... base)
       : CompressedTuple::CompressedTupleImpl(absl::in_place,
+                                             absl::forward<First>(first),
                                              absl::forward<Vs>(base)...) {}
 
   template <int I>
   ElemT<I>& get() & {
-    return internal_compressed_tuple::Storage<ElemT<I>, I>::get();
+    return StorageT<I>::get();
   }
 
   template <int I>
diff --git a/absl/container/internal/compressed_tuple_test.cc b/absl/container/internal/compressed_tuple_test.cc
index 1dae12d..62a7483 100644
--- a/absl/container/internal/compressed_tuple_test.cc
+++ b/absl/container/internal/compressed_tuple_test.cc
@@ -277,11 +277,11 @@
 
 TEST(CompressedTupleTest, Reference) {
   int i = 7;
-  std::string s = "Very long std::string that goes in the heap";
+  std::string s = "Very long string that goes in the heap";
   CompressedTuple<int, int&, std::string, std::string&> x(i, i, s, s);
 
   // Sanity check. We should have not moved from `s`
-  EXPECT_EQ(s, "Very long std::string that goes in the heap");
+  EXPECT_EQ(s, "Very long string that goes in the heap");
 
   EXPECT_EQ(x.get<0>(), x.get<1>());
   EXPECT_NE(&x.get<0>(), &x.get<1>());
diff --git a/absl/container/internal/container_memory.h b/absl/container/internal/container_memory.h
index d24b0f8..e67529e 100644
--- a/absl/container/internal/container_memory.h
+++ b/absl/container/internal/container_memory.h
@@ -15,28 +15,34 @@
 #ifndef ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_
 #define ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_
 
-#ifdef ADDRESS_SANITIZER
-#include <sanitizer/asan_interface.h>
-#endif
-
-#ifdef MEMORY_SANITIZER
-#include <sanitizer/msan_interface.h>
-#endif
-
 #include <cassert>
 #include <cstddef>
 #include <memory>
+#include <new>
 #include <tuple>
 #include <type_traits>
 #include <utility>
 
+#include "absl/base/config.h"
 #include "absl/memory/memory.h"
+#include "absl/meta/type_traits.h"
 #include "absl/utility/utility.h"
 
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+#include <sanitizer/asan_interface.h>
+#endif
+
+#ifdef ABSL_HAVE_MEMORY_SANITIZER
+#include <sanitizer/msan_interface.h>
+#endif
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace container_internal {
 
+template <size_t Alignment>
+struct alignas(Alignment) AlignedType {};
+
 // Allocates at least n bytes aligned to the specified alignment.
 // Alignment must be a power of 2. It must be positive.
 //
@@ -48,11 +54,14 @@
 void* Allocate(Alloc* alloc, size_t n) {
   static_assert(Alignment > 0, "");
   assert(n && "n must be positive");
-  struct alignas(Alignment) M {};
+  using M = AlignedType<Alignment>;
   using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>;
   using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>;
-  A mem_alloc(*alloc);
-  void* p = AT::allocate(mem_alloc, (n + sizeof(M) - 1) / sizeof(M));
+  // On macOS, "mem_alloc" is a #define with one argument defined in
+  // rpc/types.h, so we can't name the variable "mem_alloc" and initialize it
+  // with the "foo(bar)" syntax.
+  A my_mem_alloc(*alloc);
+  void* p = AT::allocate(my_mem_alloc, (n + sizeof(M) - 1) / sizeof(M));
   assert(reinterpret_cast<uintptr_t>(p) % Alignment == 0 &&
          "allocator does not respect alignment");
   return p;
@@ -64,11 +73,14 @@
 void Deallocate(Alloc* alloc, void* p, size_t n) {
   static_assert(Alignment > 0, "");
   assert(n && "n must be positive");
-  struct alignas(Alignment) M {};
+  using M = AlignedType<Alignment>;
   using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>;
   using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>;
-  A mem_alloc(*alloc);
-  AT::deallocate(mem_alloc, static_cast<M*>(p),
+  // On macOS, "mem_alloc" is a #define with one argument defined in
+  // rpc/types.h, so we can't name the variable "mem_alloc" and initialize it
+  // with the "foo(bar)" syntax.
+  A my_mem_alloc(*alloc);
+  AT::deallocate(my_mem_alloc, static_cast<M*>(p),
                  (n + sizeof(M) - 1) / sizeof(M));
 }
 
@@ -205,10 +217,10 @@
 
 // Helper functions for asan and msan.
 inline void SanitizerPoisonMemoryRegion(const void* m, size_t s) {
-#ifdef ADDRESS_SANITIZER
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
   ASAN_POISON_MEMORY_REGION(m, s);
 #endif
-#ifdef MEMORY_SANITIZER
+#ifdef ABSL_HAVE_MEMORY_SANITIZER
   __msan_poison(m, s);
 #endif
   (void)m;
@@ -216,10 +228,10 @@
 }
 
 inline void SanitizerUnpoisonMemoryRegion(const void* m, size_t s) {
-#ifdef ADDRESS_SANITIZER
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
   ASAN_UNPOISON_MEMORY_REGION(m, s);
 #endif
-#ifdef MEMORY_SANITIZER
+#ifdef ABSL_HAVE_MEMORY_SANITIZER
   __msan_unpoison(m, s);
 #endif
   (void)m;
@@ -246,8 +258,8 @@
 // type, which is non-portable.
 template <class Pair, class = std::true_type>
 struct OffsetOf {
-  static constexpr size_t kFirst = -1;
-  static constexpr size_t kSecond = -1;
+  static constexpr size_t kFirst = static_cast<size_t>(-1);
+  static constexpr size_t kSecond = static_cast<size_t>(-1);
 };
 
 template <class Pair>
@@ -316,11 +328,12 @@
   map_slot_type() {}
   ~map_slot_type() = delete;
   using value_type = std::pair<const K, V>;
-  using mutable_value_type = std::pair<K, V>;
+  using mutable_value_type =
+      std::pair<absl::remove_const_t<K>, absl::remove_const_t<V>>;
 
   value_type value;
   mutable_value_type mutable_value;
-  K key;
+  absl::remove_const_t<K> key;
 };
 
 template <class K, class V>
@@ -346,6 +359,20 @@
     return slot->value;
   }
 
+  // When C++17 is available, we can use std::launder to provide mutable
+  // access to the key for use in node handle.
+#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
+  static K& mutable_key(slot_type* slot) {
+    // Still check for kMutableKeys so that we can avoid calling std::launder
+    // unless necessary because it can interfere with optimizations.
+    return kMutableKeys::value ? slot->key
+                               : *std::launder(const_cast<K*>(
+                                     std::addressof(slot->value.first)));
+  }
+#else  // !(defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606)
+  static const K& mutable_key(slot_type* slot) { return key(slot); }
+#endif
+
   static const K& key(const slot_type* slot) {
     return kMutableKeys::value ? slot->key : slot->value.first;
   }
@@ -424,13 +451,6 @@
                                                    std::move(src->value));
     }
   }
-
-  template <class Allocator>
-  static void move(Allocator* alloc, slot_type* first, slot_type* last,
-                   slot_type* result) {
-    for (slot_type *src = first, *dest = result; src != last; ++src, ++dest)
-      move(alloc, src, dest);
-  }
 };
 
 }  // namespace container_internal
diff --git a/absl/container/internal/container_memory_test.cc b/absl/container/internal/container_memory_test.cc
index 7942c7b..fb9c4dd 100644
--- a/absl/container/internal/container_memory_test.cc
+++ b/absl/container/internal/container_memory_test.cc
@@ -16,10 +16,13 @@
 
 #include <cstdint>
 #include <tuple>
+#include <typeindex>
+#include <typeinfo>
 #include <utility>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/container/internal/test_instance_tracker.h"
 #include "absl/strings/string_view.h"
 
 namespace absl {
@@ -27,6 +30,11 @@
 namespace container_internal {
 namespace {
 
+using ::absl::test_internal::CopyableMovableInstance;
+using ::absl::test_internal::InstanceTracker;
+using ::testing::_;
+using ::testing::ElementsAre;
+using ::testing::Gt;
 using ::testing::Pair;
 
 TEST(Memory, AlignmentLargerThanBase) {
@@ -45,6 +53,39 @@
   Deallocate<2>(&alloc, mem, 3);
 }
 
+std::map<std::type_index, int>& AllocationMap() {
+  static auto* map = new std::map<std::type_index, int>;
+  return *map;
+}
+
+template <typename T>
+struct TypeCountingAllocator {
+  TypeCountingAllocator() = default;
+  template <typename U>
+  TypeCountingAllocator(const TypeCountingAllocator<U>&) {}  // NOLINT
+
+  using value_type = T;
+
+  T* allocate(size_t n, const void* = nullptr) {
+    AllocationMap()[typeid(T)] += n;
+    return std::allocator<T>().allocate(n);
+  }
+  void deallocate(T* p, std::size_t n) {
+    AllocationMap()[typeid(T)] -= n;
+    return std::allocator<T>().deallocate(p, n);
+  }
+};
+
+TEST(Memory, AllocateDeallocateMatchType) {
+  TypeCountingAllocator<int> alloc;
+  void* mem = Allocate<1>(&alloc, 1);
+  // Verify that it was allocated
+  EXPECT_THAT(AllocationMap(), ElementsAre(Pair(_, Gt(0))));
+  Deallocate<1>(&alloc, mem, 1);
+  // Verify that the deallocation matched.
+  EXPECT_THAT(AllocationMap(), ElementsAre(Pair(_, 0)));
+}
+
 class Fixture : public ::testing::Test {
   using Alloc = std::allocator<std::string>;
 
@@ -125,7 +166,7 @@
 }
 
 TEST(DecomposeValue, Decomposable) {
-  auto f = [](const int& x, int&& y) {
+  auto f = [](const int& x, int&& y) {  // NOLINT
     EXPECT_EQ(&x, &y);
     EXPECT_EQ(42, x);
     return 'A';
@@ -159,7 +200,8 @@
 }
 
 TEST(DecomposePair, Decomposable) {
-  auto f = [](const int& x, std::piecewise_construct_t, std::tuple<int&&> k,
+  auto f = [](const int& x,  // NOLINT
+              std::piecewise_construct_t, std::tuple<int&&> k,
               std::tuple<double>&& v) {
     EXPECT_EQ(&x, &std::get<0>(k));
     EXPECT_EQ(42, x);
@@ -184,6 +226,31 @@
                                 std::make_tuple(0.5)));
 }
 
+TEST(MapSlotPolicy, ConstKeyAndValue) {
+  using slot_policy = map_slot_policy<const CopyableMovableInstance,
+                                      const CopyableMovableInstance>;
+  using slot_type = typename slot_policy::slot_type;
+
+  union Slots {
+    Slots() {}
+    ~Slots() {}
+    slot_type slots[100];
+  } slots;
+
+  std::allocator<
+      std::pair<const CopyableMovableInstance, const CopyableMovableInstance>>
+      alloc;
+  InstanceTracker tracker;
+  slot_policy::construct(&alloc, &slots.slots[0], CopyableMovableInstance(1),
+                         CopyableMovableInstance(1));
+  for (int i = 0; i < 99; ++i) {
+    slot_policy::transfer(&alloc, &slots.slots[i + 1], &slots.slots[i]);
+  }
+  slot_policy::destroy(&alloc, &slots.slots[99]);
+
+  EXPECT_EQ(tracker.copies(), 0);
+}
+
 }  // namespace
 }  // namespace container_internal
 ABSL_NAMESPACE_END
diff --git a/absl/container/internal/counting_allocator.h b/absl/container/internal/counting_allocator.h
index 9efdc66..927cf08 100644
--- a/absl/container/internal/counting_allocator.h
+++ b/absl/container/internal/counting_allocator.h
@@ -15,7 +15,6 @@
 #ifndef ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_
 #define ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_
 
-#include <cassert>
 #include <cstdint>
 #include <memory>
 
@@ -31,33 +30,63 @@
 // containers - that chain of allocators uses the same state and is
 // thus easier to query for aggregate allocation information.
 template <typename T>
-class CountingAllocator : public std::allocator<T> {
+class CountingAllocator {
  public:
-  using Alloc = std::allocator<T>;
-  using pointer = typename Alloc::pointer;
-  using size_type = typename Alloc::size_type;
+  using Allocator = std::allocator<T>;
+  using AllocatorTraits = std::allocator_traits<Allocator>;
+  using value_type = typename AllocatorTraits::value_type;
+  using pointer = typename AllocatorTraits::pointer;
+  using const_pointer = typename AllocatorTraits::const_pointer;
+  using size_type = typename AllocatorTraits::size_type;
+  using difference_type = typename AllocatorTraits::difference_type;
 
-  CountingAllocator() : bytes_used_(nullptr) {}
-  explicit CountingAllocator(int64_t* b) : bytes_used_(b) {}
+  CountingAllocator() = default;
+  explicit CountingAllocator(int64_t* bytes_used) : bytes_used_(bytes_used) {}
+  CountingAllocator(int64_t* bytes_used, int64_t* instance_count)
+      : bytes_used_(bytes_used), instance_count_(instance_count) {}
 
   template <typename U>
   CountingAllocator(const CountingAllocator<U>& x)
-      : Alloc(x), bytes_used_(x.bytes_used_) {}
+      : bytes_used_(x.bytes_used_), instance_count_(x.instance_count_) {}
 
-  pointer allocate(size_type n,
-                   std::allocator<void>::const_pointer hint = nullptr) {
-    assert(bytes_used_ != nullptr);
-    *bytes_used_ += n * sizeof(T);
-    return Alloc::allocate(n, hint);
+  pointer allocate(
+      size_type n,
+      typename AllocatorTraits::const_void_pointer hint = nullptr) {
+    Allocator allocator;
+    pointer ptr = AllocatorTraits::allocate(allocator, n, hint);
+    if (bytes_used_ != nullptr) {
+      *bytes_used_ += n * sizeof(T);
+    }
+    return ptr;
   }
 
   void deallocate(pointer p, size_type n) {
-    Alloc::deallocate(p, n);
-    assert(bytes_used_ != nullptr);
-    *bytes_used_ -= n * sizeof(T);
+    Allocator allocator;
+    AllocatorTraits::deallocate(allocator, p, n);
+    if (bytes_used_ != nullptr) {
+      *bytes_used_ -= n * sizeof(T);
+    }
   }
 
-  template<typename U>
+  template <typename U, typename... Args>
+  void construct(U* p, Args&&... args) {
+    Allocator allocator;
+    AllocatorTraits::construct(allocator, p, std::forward<Args>(args)...);
+    if (instance_count_ != nullptr) {
+      *instance_count_ += 1;
+    }
+  }
+
+  template <typename U>
+  void destroy(U* p) {
+    Allocator allocator;
+    AllocatorTraits::destroy(allocator, p);
+    if (instance_count_ != nullptr) {
+      *instance_count_ -= 1;
+    }
+  }
+
+  template <typename U>
   class rebind {
    public:
     using other = CountingAllocator<U>;
@@ -65,7 +94,8 @@
 
   friend bool operator==(const CountingAllocator& a,
                          const CountingAllocator& b) {
-    return a.bytes_used_ == b.bytes_used_;
+    return a.bytes_used_ == b.bytes_used_ &&
+           a.instance_count_ == b.instance_count_;
   }
 
   friend bool operator!=(const CountingAllocator& a,
@@ -73,7 +103,8 @@
     return !(a == b);
   }
 
-  int64_t* bytes_used_;
+  int64_t* bytes_used_ = nullptr;
+  int64_t* instance_count_ = nullptr;
 };
 
 }  // namespace container_internal
diff --git a/absl/container/internal/hash_function_defaults.h b/absl/container/internal/hash_function_defaults.h
index 401ddf4..0683422 100644
--- a/absl/container/internal/hash_function_defaults.h
+++ b/absl/container/internal/hash_function_defaults.h
@@ -53,6 +53,7 @@
 
 #include "absl/base/config.h"
 #include "absl/hash/hash.h"
+#include "absl/strings/cord.h"
 #include "absl/strings/string_view.h"
 
 namespace absl {
@@ -72,6 +73,9 @@
   size_t operator()(absl::string_view v) const {
     return absl::Hash<absl::string_view>{}(v);
   }
+  size_t operator()(const absl::Cord& v) const {
+    return absl::Hash<absl::Cord>{}(v);
+  }
 };
 
 // Supports heterogeneous lookup for string-like elements.
@@ -82,6 +86,15 @@
     bool operator()(absl::string_view lhs, absl::string_view rhs) const {
       return lhs == rhs;
     }
+    bool operator()(const absl::Cord& lhs, const absl::Cord& rhs) const {
+      return lhs == rhs;
+    }
+    bool operator()(const absl::Cord& lhs, absl::string_view rhs) const {
+      return lhs == rhs;
+    }
+    bool operator()(absl::string_view lhs, const absl::Cord& rhs) const {
+      return lhs == rhs;
+    }
   };
 };
 
@@ -89,6 +102,8 @@
 struct HashEq<std::string> : StringHashEq {};
 template <>
 struct HashEq<absl::string_view> : StringHashEq {};
+template <>
+struct HashEq<absl::Cord> : StringHashEq {};
 
 // Supports heterogeneous lookup for pointers and smart pointers.
 template <class T>
diff --git a/absl/container/internal/hash_function_defaults_test.cc b/absl/container/internal/hash_function_defaults_test.cc
index 2eefc7e..59576b8 100644
--- a/absl/container/internal/hash_function_defaults_test.cc
+++ b/absl/container/internal/hash_function_defaults_test.cc
@@ -19,6 +19,9 @@
 #include <utility>
 
 #include "gtest/gtest.h"
+#include "absl/random/random.h"
+#include "absl/strings/cord.h"
+#include "absl/strings/cord_test_helpers.h"
 #include "absl/strings/string_view.h"
 
 namespace absl {
@@ -203,10 +206,91 @@
   EXPECT_NE(hash(&dummy), hash(cuptr));
 }
 
+TEST(EqCord, Works) {
+  hash_default_eq<absl::Cord> eq;
+  const absl::string_view a_string_view = "a";
+  const absl::Cord a_cord(a_string_view);
+  const absl::string_view b_string_view = "b";
+  const absl::Cord b_cord(b_string_view);
+
+  EXPECT_TRUE(eq(a_cord, a_cord));
+  EXPECT_TRUE(eq(a_cord, a_string_view));
+  EXPECT_TRUE(eq(a_string_view, a_cord));
+  EXPECT_FALSE(eq(a_cord, b_cord));
+  EXPECT_FALSE(eq(a_cord, b_string_view));
+  EXPECT_FALSE(eq(b_string_view, a_cord));
+}
+
+TEST(HashCord, Works) {
+  hash_default_hash<absl::Cord> hash;
+  const absl::string_view a_string_view = "a";
+  const absl::Cord a_cord(a_string_view);
+  const absl::string_view b_string_view = "b";
+  const absl::Cord b_cord(b_string_view);
+
+  EXPECT_EQ(hash(a_cord), hash(a_cord));
+  EXPECT_EQ(hash(b_cord), hash(b_cord));
+  EXPECT_EQ(hash(a_string_view), hash(a_cord));
+  EXPECT_EQ(hash(b_string_view), hash(b_cord));
+  EXPECT_EQ(hash(absl::Cord("")), hash(""));
+  EXPECT_EQ(hash(absl::Cord()), hash(absl::string_view()));
+
+  EXPECT_NE(hash(a_cord), hash(b_cord));
+  EXPECT_NE(hash(a_cord), hash(b_string_view));
+  EXPECT_NE(hash(a_string_view), hash(b_cord));
+  EXPECT_NE(hash(a_string_view), hash(b_string_view));
+}
+
+void NoOpReleaser(absl::string_view data, void* arg) {}
+
+TEST(HashCord, FragmentedCordWorks) {
+  hash_default_hash<absl::Cord> hash;
+  absl::Cord c = absl::MakeFragmentedCord({"a", "b", "c"});
+  EXPECT_FALSE(c.TryFlat().has_value());
+  EXPECT_EQ(hash(c), hash("abc"));
+}
+
+TEST(HashCord, FragmentedLongCordWorks) {
+  hash_default_hash<absl::Cord> hash;
+  // Crete some large strings which do not fit on the stack.
+  std::string a(65536, 'a');
+  std::string b(65536, 'b');
+  absl::Cord c = absl::MakeFragmentedCord({a, b});
+  EXPECT_FALSE(c.TryFlat().has_value());
+  EXPECT_EQ(hash(c), hash(a + b));
+}
+
+TEST(HashCord, RandomCord) {
+  hash_default_hash<absl::Cord> hash;
+  auto bitgen = absl::BitGen();
+  for (int i = 0; i < 1000; ++i) {
+    const int number_of_segments = absl::Uniform(bitgen, 0, 10);
+    std::vector<std::string> pieces;
+    for (size_t s = 0; s < number_of_segments; ++s) {
+      std::string str;
+      str.resize(absl::Uniform(bitgen, 0, 4096));
+      // MSVC needed the explicit return type in the lambda.
+      std::generate(str.begin(), str.end(), [&]() -> char {
+        return static_cast<char>(absl::Uniform<unsigned char>(bitgen));
+      });
+      pieces.push_back(str);
+    }
+    absl::Cord c = absl::MakeFragmentedCord(pieces);
+    EXPECT_EQ(hash(c), hash(std::string(c)));
+  }
+}
+
 // Cartesian product of (std::string, absl::string_view)
-// with (std::string, absl::string_view, const char*).
+// with (std::string, absl::string_view, const char*, absl::Cord).
 using StringTypesCartesianProduct = Types<
     // clang-format off
+    std::pair<absl::Cord, std::string>,
+    std::pair<absl::Cord, absl::string_view>,
+    std::pair<absl::Cord, absl::Cord>,
+    std::pair<absl::Cord, const char*>,
+
+    std::pair<std::string, absl::Cord>,
+    std::pair<absl::string_view, absl::Cord>,
 
     std::pair<absl::string_view, std::string>,
     std::pair<absl::string_view, absl::string_view>,
@@ -253,11 +337,11 @@
 }  // namespace absl
 
 enum Hash : size_t {
-  kStd = 0x2,       // std::hash
+  kStd = 0x1,       // std::hash
 #ifdef _MSC_VER
   kExtension = kStd,  // In MSVC, std::hash == ::hash
 #else                 // _MSC_VER
-  kExtension = 0x4,  // ::hash (GCC extension)
+  kExtension = 0x2,  // ::hash (GCC extension)
 #endif                // _MSC_VER
 };
 
diff --git a/absl/container/internal/hash_generator_testing.cc b/absl/container/internal/hash_generator_testing.cc
index 75c4db6..59cc5aa 100644
--- a/absl/container/internal/hash_generator_testing.cc
+++ b/absl/container/internal/hash_generator_testing.cc
@@ -41,8 +41,10 @@
 }  // namespace
 
 std::mt19937_64* GetSharedRng() {
-  RandomDeviceSeedSeq seed_seq;
-  static auto* rng = new std::mt19937_64(seed_seq);
+  static auto* rng = [] {
+    RandomDeviceSeedSeq seed_seq;
+    return new std::mt19937_64(seed_seq);
+  }();
   return rng;
 }
 
diff --git a/absl/container/internal/hash_policy_traits.h b/absl/container/internal/hash_policy_traits.h
index 3e1209c..46c97b1 100644
--- a/absl/container/internal/hash_policy_traits.h
+++ b/absl/container/internal/hash_policy_traits.h
@@ -17,6 +17,7 @@
 
 #include <cstddef>
 #include <memory>
+#include <new>
 #include <type_traits>
 #include <utility>
 
@@ -29,15 +30,34 @@
 // Defines how slots are initialized/destroyed/moved.
 template <class Policy, class = void>
 struct hash_policy_traits {
+  // The type of the keys stored in the hashtable.
+  using key_type = typename Policy::key_type;
+
  private:
   struct ReturnKey {
-    // We return `Key` here.
+    // When C++17 is available, we can use std::launder to provide mutable
+    // access to the key for use in node handle.
+#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
+    template <class Key,
+              absl::enable_if_t<std::is_lvalue_reference<Key>::value, int> = 0>
+    static key_type& Impl(Key&& k, int) {
+      return *std::launder(
+          const_cast<key_type*>(std::addressof(std::forward<Key>(k))));
+    }
+#endif
+
+    template <class Key>
+    static Key Impl(Key&& k, char) {
+      return std::forward<Key>(k);
+    }
+
     // When Key=T&, we forward the lvalue reference.
     // When Key=T, we return by value to avoid a dangling reference.
     // eg, for string_hash_map.
     template <class Key, class... Args>
-    Key operator()(Key&& k, const Args&...) const {
-      return std::forward<Key>(k);
+    auto operator()(Key&& k, const Args&...) const
+        -> decltype(Impl(std::forward<Key>(k), 0)) {
+      return Impl(std::forward<Key>(k), 0);
     }
   };
 
@@ -52,9 +72,6 @@
   // The actual object stored in the hash table.
   using slot_type = typename Policy::slot_type;
 
-  // The type of the keys stored in the hashtable.
-  using key_type = typename Policy::key_type;
-
   // The argument type for insertions into the hashtable. This is different
   // from value_type for increased performance. See initializer_list constructor
   // and insert() member functions for more details.
@@ -156,7 +173,7 @@
   // Returns the "key" portion of the slot.
   // Used for node handle manipulation.
   template <class P = Policy>
-  static auto key(slot_type* slot)
+  static auto mutable_key(slot_type* slot)
       -> decltype(P::apply(ReturnKey(), element(slot))) {
     return P::apply(ReturnKey(), element(slot));
   }
diff --git a/absl/container/internal/hashtablez_sampler.cc b/absl/container/internal/hashtablez_sampler.cc
index 5644725..5a29bed 100644
--- a/absl/container/internal/hashtablez_sampler.cc
+++ b/absl/container/internal/hashtablez_sampler.cc
@@ -67,10 +67,12 @@
   capacity.store(0, std::memory_order_relaxed);
   size.store(0, std::memory_order_relaxed);
   num_erases.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);
 
   create_time = absl::Now();
   // The inliner makes hardcoded skip_count difficult (especially when combined
@@ -179,7 +181,9 @@
   if (ABSL_PREDICT_TRUE(state == kDontForce)) return false;
 
   if (state == kUninitialized) {
-    state = AbslContainerInternalSampleEverything() ? kForce : kDontForce;
+    state = ABSL_INTERNAL_C_SYMBOL(AbslContainerInternalSampleEverything)()
+                ? kForce
+                : kDontForce;
     global_state.store(state, std::memory_order_relaxed);
   }
   return state == kForce;
@@ -226,7 +230,7 @@
   // 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;
-#if SWISSTABLE_HAVE_SSE2
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
   probe_length /= 16;
 #else
   probe_length /= 8;
@@ -234,6 +238,7 @@
 
   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 34d5e57..85685f7 100644
--- a/absl/container/internal/hashtablez_sampler.h
+++ b/absl/container/internal/hashtablez_sampler.h
@@ -73,10 +73,12 @@
   std::atomic<size_t> capacity;
   std::atomic<size_t> size;
   std::atomic<size_t> num_erases;
+  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;
 
   // `HashtablezSampler` maintains intrusive linked lists for all samples.  See
   // comments on `HashtablezSampler::all_` for details on these.  `init_mu`
@@ -98,13 +100,18 @@
 };
 
 inline void RecordRehashSlow(HashtablezInfo* info, size_t total_probe_length) {
-#if SWISSTABLE_HAVE_SSE2
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
   total_probe_length /= 16;
 #else
   total_probe_length /= 8;
 #endif
   info->total_probe_length.store(total_probe_length, std::memory_order_relaxed);
   info->num_erases.store(0, std::memory_order_relaxed);
+  // There is only one concurrent writer, so `load` then `store` is sufficient
+  // instead of using `fetch_add`.
+  info->num_rehashes.store(
+      1 + info->num_rehashes.load(std::memory_order_relaxed),
+      std::memory_order_relaxed);
 }
 
 inline void RecordStorageChangedSlow(HashtablezInfo* info, size_t size,
@@ -113,7 +120,8 @@
   info->capacity.store(capacity, std::memory_order_relaxed);
   if (size == 0) {
     // This is a clear, reset the total/num_erases too.
-    RecordRehashSlow(info, 0);
+    info->total_probe_length.store(0, std::memory_order_relaxed);
+    info->num_erases.store(0, std::memory_order_relaxed);
   }
 }
 
@@ -122,12 +130,21 @@
 
 inline void RecordEraseSlow(HashtablezInfo* info) {
   info->size.fetch_sub(1, std::memory_order_relaxed);
-  info->num_erases.fetch_add(1, std::memory_order_relaxed);
+  // There is only one concurrent writer, so `load` then `store` is sufficient
+  // instead of using `fetch_add`.
+  info->num_erases.store(
+      1 + info->num_erases.load(std::memory_order_relaxed),
+      std::memory_order_relaxed);
 }
 
 HashtablezInfo* SampleSlow(int64_t* next_sample);
 void UnsampleSlow(HashtablezInfo* info);
 
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+#error ABSL_INTERNAL_HASHTABLEZ_SAMPLE cannot be directly set
+#endif  // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
 class HashtablezInfoHandle {
  public:
   explicit HashtablezInfoHandle() : info_(nullptr) {}
@@ -179,19 +196,27 @@
   friend class HashtablezInfoHandlePeer;
   HashtablezInfo* info_;
 };
+#else
+// Ensure that when Hashtablez is turned off at compile time, HashtablezInfo can
+// be removed by the linker, in order to reduce the binary size.
+class HashtablezInfoHandle {
+ public:
+  explicit HashtablezInfoHandle() = default;
+  explicit HashtablezInfoHandle(std::nullptr_t) {}
 
-#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
-#error ABSL_INTERNAL_HASHTABLEZ_SAMPLE cannot be directly set
+  inline void RecordStorageChanged(size_t /*size*/, size_t /*capacity*/) {}
+  inline void RecordRehash(size_t /*total_probe_length*/) {}
+  inline void RecordInsert(size_t /*hash*/, size_t /*distance_from_desired*/) {}
+  inline void RecordErase() {}
+
+  friend inline void swap(HashtablezInfoHandle& /*lhs*/,
+                          HashtablezInfoHandle& /*rhs*/) {}
+};
 #endif  // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
 
-#if (ABSL_PER_THREAD_TLS == 1) && !defined(ABSL_BUILD_DLL) && \
-    !defined(ABSL_CONSUME_DLL)
-#define ABSL_INTERNAL_HASHTABLEZ_SAMPLE
-#endif
-
 #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
 extern ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample;
-#endif  // ABSL_PER_THREAD_TLS
+#endif  // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
 
 // Returns an RAII sampling handle that manages registration and unregistation
 // with the global sampler.
@@ -288,7 +313,7 @@
 // initialization of static storage duration objects.
 // The definition of this constant is weak, which allows us to inject a
 // different value for it at link time.
-extern "C" bool AbslContainerInternalSampleEverything();
+extern "C" bool ABSL_INTERNAL_C_SYMBOL(AbslContainerInternalSampleEverything)();
 
 }  // namespace container_internal
 ABSL_NAMESPACE_END
diff --git a/absl/container/internal/hashtablez_sampler_force_weak_definition.cc b/absl/container/internal/hashtablez_sampler_force_weak_definition.cc
index 78b9d36..ed35a7e 100644
--- a/absl/container/internal/hashtablez_sampler_force_weak_definition.cc
+++ b/absl/container/internal/hashtablez_sampler_force_weak_definition.cc
@@ -21,7 +21,8 @@
 namespace container_internal {
 
 // See hashtablez_sampler.h for details.
-extern "C" ABSL_ATTRIBUTE_WEAK bool AbslContainerInternalSampleEverything() {
+extern "C" ABSL_ATTRIBUTE_WEAK bool ABSL_INTERNAL_C_SYMBOL(
+    AbslContainerInternalSampleEverything)() {
   return false;
 }
 
diff --git a/absl/container/internal/hashtablez_sampler_test.cc b/absl/container/internal/hashtablez_sampler_test.cc
index 36f5ccd..5f4c83b 100644
--- a/absl/container/internal/hashtablez_sampler_test.cc
+++ b/absl/container/internal/hashtablez_sampler_test.cc
@@ -29,7 +29,7 @@
 #include "absl/time/clock.h"
 #include "absl/time/time.h"
 
-#if SWISSTABLE_HAVE_SSE2
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
 constexpr int kProbeLength = 16;
 #else
 constexpr int kProbeLength = 8;
@@ -38,6 +38,7 @@
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace container_internal {
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
 class HashtablezInfoHandlePeer {
  public:
   static bool IsSampled(const HashtablezInfoHandle& h) {
@@ -46,6 +47,13 @@
 
   static HashtablezInfo* GetInfo(HashtablezInfoHandle* h) { return h->info_; }
 };
+#else
+class HashtablezInfoHandlePeer {
+ public:
+  static bool IsSampled(const HashtablezInfoHandle&) { return false; }
+  static HashtablezInfo* GetInfo(HashtablezInfoHandle*) { return nullptr; }
+};
+#endif  // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
 
 namespace {
 using ::absl::synchronization_internal::ThreadPool;
@@ -76,10 +84,12 @@
   EXPECT_EQ(info.capacity.load(), 0);
   EXPECT_EQ(info.size.load(), 0);
   EXPECT_EQ(info.num_erases.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_GE(info.create_time, test_start);
 
   info.capacity.store(1, std::memory_order_relaxed);
@@ -89,16 +99,19 @@
   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.create_time = test_start - absl::Hours(20);
 
   info.PrepareForSampling();
   EXPECT_EQ(info.capacity.load(), 0);
   EXPECT_EQ(info.size.load(), 0);
   EXPECT_EQ(info.num_erases.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_GE(info.create_time, test_start);
 }
 
@@ -123,14 +136,17 @@
   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);
   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);
   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) {
@@ -167,9 +183,10 @@
   EXPECT_EQ(info.size.load(), 2);
   EXPECT_EQ(info.total_probe_length.load(), 3);
   EXPECT_EQ(info.num_erases.load(), 0);
+  EXPECT_EQ(info.num_rehashes.load(), 1);
 }
 
-#if defined(ABSL_HASHTABLEZ_SAMPLE)
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
 TEST(HashtablezSamplerTest, SmallSampleParameter) {
   SetHashtablezEnabled(true);
   SetHashtablezSampleParameter(100);
@@ -213,7 +230,6 @@
   }
   EXPECT_NEAR(sample_rate, 0.01, 0.005);
 }
-#endif
 
 TEST(HashtablezSamplerTest, Handle) {
   auto& sampler = HashtablezSampler::Global();
@@ -243,6 +259,8 @@
   });
   EXPECT_FALSE(found);
 }
+#endif
+
 
 TEST(HashtablezSamplerTest, Registration) {
   HashtablezSampler sampler;
diff --git a/absl/container/internal/have_sse.h b/absl/container/internal/have_sse.h
index 4341441..e75e1a1 100644
--- a/absl/container/internal/have_sse.h
+++ b/absl/container/internal/have_sse.h
@@ -16,33 +16,34 @@
 #ifndef ABSL_CONTAINER_INTERNAL_HAVE_SSE_H_
 #define ABSL_CONTAINER_INTERNAL_HAVE_SSE_H_
 
-#ifndef SWISSTABLE_HAVE_SSE2
+#ifndef ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
 #if defined(__SSE2__) ||  \
     (defined(_MSC_VER) && \
      (defined(_M_X64) || (defined(_M_IX86) && _M_IX86_FP >= 2)))
-#define SWISSTABLE_HAVE_SSE2 1
+#define ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2 1
 #else
-#define SWISSTABLE_HAVE_SSE2 0
+#define ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2 0
 #endif
 #endif
 
-#ifndef SWISSTABLE_HAVE_SSSE3
+#ifndef ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3
 #ifdef __SSSE3__
-#define SWISSTABLE_HAVE_SSSE3 1
+#define ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3 1
 #else
-#define SWISSTABLE_HAVE_SSSE3 0
+#define ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3 0
 #endif
 #endif
 
-#if SWISSTABLE_HAVE_SSSE3 && !SWISSTABLE_HAVE_SSE2
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3 && \
+    !ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
 #error "Bad configuration!"
 #endif
 
-#if SWISSTABLE_HAVE_SSE2
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
 #include <emmintrin.h>
 #endif
 
-#if SWISSTABLE_HAVE_SSSE3
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3
 #include <tmmintrin.h>
 #endif
 
diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h
index 4d80b72..b8aec45 100644
--- a/absl/container/internal/inlined_vector.h
+++ b/absl/container/internal/inlined_vector.h
@@ -33,6 +33,12 @@
 ABSL_NAMESPACE_BEGIN
 namespace inlined_vector_internal {
 
+// GCC does not deal very well with the below code
+#if !defined(__clang__) && defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+
 template <typename Iterator>
 using IsAtLeastForwardIterator = std::is_convertible<
     typename std::iterator_traits<Iterator>::iterator_category,
@@ -75,6 +81,23 @@
   }
 }
 
+// If kUseMemcpy is true, memcpy(dst, src, n); else do nothing.
+// Useful to avoid compiler warnings when memcpy() is used for T values
+// that are not trivially copyable in non-reachable code.
+template <bool kUseMemcpy>
+inline void MemcpyIfAllowed(void* dst, const void* src, size_t n);
+
+// memcpy when allowed.
+template <>
+inline void MemcpyIfAllowed<true>(void* dst, const void* src, size_t n) {
+  memcpy(dst, src, n);
+}
+
+// Do nothing for types that are not memcpy-able. This function is only
+// called from non-reachable branches.
+template <>
+inline void MemcpyIfAllowed<false>(void*, const void*, size_t) {}
+
 template <typename AllocatorType, typename Pointer, typename ValueAdapter,
           typename SizeType>
 void ConstructElements(AllocatorType* alloc_ptr, Pointer construct_first,
@@ -298,14 +321,20 @@
   // Storage Constructors and Destructor
   // ---------------------------------------------------------------------------
 
-  Storage() : metadata_() {}
+  Storage() : metadata_(allocator_type(), /* size and is_allocated */ 0) {}
 
-  explicit Storage(const allocator_type& alloc) : metadata_(alloc, {}) {}
+  explicit Storage(const allocator_type& alloc)
+      : metadata_(alloc, /* size and is_allocated */ 0) {}
 
   ~Storage() {
-    pointer data = GetIsAllocated() ? GetAllocatedData() : GetInlinedData();
-    inlined_vector_internal::DestroyElements(GetAllocPtr(), data, GetSize());
-    DeallocateIfAllocated();
+    if (GetSizeAndIsAllocated() == 0) {
+      // Empty and not allocated; nothing to do.
+    } else if (IsMemcpyOk::value) {
+      // No destructors need to be run; just deallocate if necessary.
+      DeallocateIfAllocated();
+    } else {
+      DestroyContents();
+    }
   }
 
   // ---------------------------------------------------------------------------
@@ -363,6 +392,8 @@
   // Storage Member Mutators
   // ---------------------------------------------------------------------------
 
+  ABSL_ATTRIBUTE_NOINLINE void InitFrom(const Storage& other);
+
   template <typename ValueAdapter>
   void Initialize(ValueAdapter values, size_type new_size);
 
@@ -445,6 +476,8 @@
   }
 
  private:
+  ABSL_ATTRIBUTE_NOINLINE void DestroyContents();
+
   using Metadata =
       container_internal::CompressedTuple<allocator_type, size_type>;
 
@@ -462,11 +495,48 @@
     Inlined inlined;
   };
 
+  template <typename... Args>
+  ABSL_ATTRIBUTE_NOINLINE reference EmplaceBackSlow(Args&&... args);
+
   Metadata metadata_;
   Data data_;
 };
 
 template <typename T, size_t N, typename A>
+void Storage<T, N, A>::DestroyContents() {
+  pointer data = GetIsAllocated() ? GetAllocatedData() : GetInlinedData();
+  inlined_vector_internal::DestroyElements(GetAllocPtr(), data, GetSize());
+  DeallocateIfAllocated();
+}
+
+template <typename T, size_t N, typename A>
+void Storage<T, N, A>::InitFrom(const Storage& other) {
+  const auto n = other.GetSize();
+  assert(n > 0);  // Empty sources handled handled in caller.
+  const_pointer src;
+  pointer dst;
+  if (!other.GetIsAllocated()) {
+    dst = GetInlinedData();
+    src = other.GetInlinedData();
+  } else {
+    // Because this is only called from the `InlinedVector` constructors, it's
+    // safe to take on the allocation with size `0`. If `ConstructElements(...)`
+    // throws, deallocation will be automatically handled by `~Storage()`.
+    size_type new_capacity = ComputeCapacity(GetInlinedCapacity(), n);
+    dst = AllocatorTraits::allocate(*GetAllocPtr(), new_capacity);
+    SetAllocatedData(dst, new_capacity);
+    src = other.GetAllocatedData();
+  }
+  if (IsMemcpyOk::value) {
+    MemcpyIfAllowed<IsMemcpyOk::value>(dst, src, sizeof(dst[0]) * n);
+  } else {
+    auto values = IteratorValueAdapter<const_pointer>(src);
+    inlined_vector_internal::ConstructElements(GetAllocPtr(), dst, &values, n);
+  }
+  GetSizeAndIsAllocated() = other.GetSizeAndIsAllocated();
+}
+
+template <typename T, size_t N, typename A>
 template <typename ValueAdapter>
 auto Storage<T, N, A>::Initialize(ValueAdapter values, size_type new_size)
     -> void {
@@ -542,48 +612,42 @@
 template <typename ValueAdapter>
 auto Storage<T, N, A>::Resize(ValueAdapter values, size_type new_size) -> void {
   StorageView storage_view = MakeStorageView();
-
-  IteratorValueAdapter<MoveIterator> move_values(
-      MoveIterator(storage_view.data));
-
-  AllocationTransaction allocation_tx(GetAllocPtr());
-  ConstructionTransaction construction_tx(GetAllocPtr());
-
-  absl::Span<value_type> construct_loop;
-  absl::Span<value_type> move_construct_loop;
-  absl::Span<value_type> destroy_loop;
-
-  if (new_size > storage_view.capacity) {
+  auto* const base = storage_view.data;
+  const size_type size = storage_view.size;
+  auto* alloc = GetAllocPtr();
+  if (new_size <= size) {
+    // Destroy extra old elements.
+    inlined_vector_internal::DestroyElements(alloc, base + new_size,
+                                             size - new_size);
+  } else if (new_size <= storage_view.capacity) {
+    // Construct new elements in place.
+    inlined_vector_internal::ConstructElements(alloc, base + size, &values,
+                                               new_size - size);
+  } else {
+    // Steps:
+    //  a. Allocate new backing store.
+    //  b. Construct new elements in new backing store.
+    //  c. Move existing elements from old backing store to now.
+    //  d. Destroy all elements in old backing store.
+    // Use transactional wrappers for the first two steps so we can roll
+    // back if necessary due to exceptions.
+    AllocationTransaction allocation_tx(alloc);
     size_type new_capacity = ComputeCapacity(storage_view.capacity, new_size);
     pointer new_data = allocation_tx.Allocate(new_capacity);
-    construct_loop = {new_data + storage_view.size,
-                      new_size - storage_view.size};
-    move_construct_loop = {new_data, storage_view.size};
-    destroy_loop = {storage_view.data, storage_view.size};
-  } else if (new_size > storage_view.size) {
-    construct_loop = {storage_view.data + storage_view.size,
-                      new_size - storage_view.size};
-  } else {
-    destroy_loop = {storage_view.data + new_size, storage_view.size - new_size};
-  }
 
-  construction_tx.Construct(construct_loop.data(), &values,
-                            construct_loop.size());
+    ConstructionTransaction construction_tx(alloc);
+    construction_tx.Construct(new_data + size, &values, new_size - size);
 
-  inlined_vector_internal::ConstructElements(
-      GetAllocPtr(), move_construct_loop.data(), &move_values,
-      move_construct_loop.size());
+    IteratorValueAdapter<MoveIterator> move_values((MoveIterator(base)));
+    inlined_vector_internal::ConstructElements(alloc, new_data, &move_values,
+                                               size);
 
-  inlined_vector_internal::DestroyElements(GetAllocPtr(), destroy_loop.data(),
-                                           destroy_loop.size());
-
-  construction_tx.Commit();
-  if (allocation_tx.DidAllocate()) {
+    inlined_vector_internal::DestroyElements(alloc, base, size);
+    construction_tx.Commit();
     DeallocateIfAllocated();
     AcquireAllocatedData(&allocation_tx);
     SetIsAllocated();
   }
-
   SetSize(new_size);
 }
 
@@ -684,44 +748,50 @@
 template <typename... Args>
 auto Storage<T, N, A>::EmplaceBack(Args&&... args) -> reference {
   StorageView storage_view = MakeStorageView();
+  const auto n = storage_view.size;
+  if (ABSL_PREDICT_TRUE(n != storage_view.capacity)) {
+    // Fast path; new element fits.
+    pointer last_ptr = storage_view.data + n;
+    AllocatorTraits::construct(*GetAllocPtr(), last_ptr,
+                               std::forward<Args>(args)...);
+    AddSize(1);
+    return *last_ptr;
+  }
+  // TODO(b/173712035): Annotate with musttail attribute to prevent regression.
+  return EmplaceBackSlow(std::forward<Args>(args)...);
+}
 
+template <typename T, size_t N, typename A>
+template <typename... Args>
+auto Storage<T, N, A>::EmplaceBackSlow(Args&&... args) -> reference {
+  StorageView storage_view = MakeStorageView();
   AllocationTransaction allocation_tx(GetAllocPtr());
-
   IteratorValueAdapter<MoveIterator> move_values(
       MoveIterator(storage_view.data));
-
-  pointer construct_data;
-  if (storage_view.size == storage_view.capacity) {
-    size_type new_capacity = NextCapacity(storage_view.capacity);
-    construct_data = allocation_tx.Allocate(new_capacity);
-  } else {
-    construct_data = storage_view.data;
-  }
-
+  size_type new_capacity = NextCapacity(storage_view.capacity);
+  pointer construct_data = allocation_tx.Allocate(new_capacity);
   pointer last_ptr = construct_data + storage_view.size;
 
+  // Construct new element.
   AllocatorTraits::construct(*GetAllocPtr(), last_ptr,
                              std::forward<Args>(args)...);
-
-  if (allocation_tx.DidAllocate()) {
-    ABSL_INTERNAL_TRY {
-      inlined_vector_internal::ConstructElements(
-          GetAllocPtr(), allocation_tx.GetData(), &move_values,
-          storage_view.size);
-    }
-    ABSL_INTERNAL_CATCH_ANY {
-      AllocatorTraits::destroy(*GetAllocPtr(), last_ptr);
-      ABSL_INTERNAL_RETHROW;
-    }
-
-    inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
-                                             storage_view.size);
-
-    DeallocateIfAllocated();
-    AcquireAllocatedData(&allocation_tx);
-    SetIsAllocated();
+  // Move elements from old backing store to new backing store.
+  ABSL_INTERNAL_TRY {
+    inlined_vector_internal::ConstructElements(
+        GetAllocPtr(), allocation_tx.GetData(), &move_values,
+        storage_view.size);
   }
+  ABSL_INTERNAL_CATCH_ANY {
+    AllocatorTraits::destroy(*GetAllocPtr(), last_ptr);
+    ABSL_INTERNAL_RETHROW;
+  }
+  // Destroy elements in old backing store.
+  inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
+                                           storage_view.size);
 
+  DeallocateIfAllocated();
+  AcquireAllocatedData(&allocation_tx);
+  SetIsAllocated();
   AddSize(1);
   return *last_ptr;
 }
@@ -885,6 +955,11 @@
   swap(*GetAllocPtr(), *other_storage_ptr->GetAllocPtr());
 }
 
+// End ignore "maybe-uninitialized"
+#if !defined(__clang__) && defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+
 }  // namespace inlined_vector_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/container/internal/layout.h b/absl/container/internal/layout.h
index 69cc85d..a59a243 100644
--- a/absl/container/internal/layout.h
+++ b/absl/container/internal/layout.h
@@ -163,6 +163,7 @@
 #include <assert.h>
 #include <stddef.h>
 #include <stdint.h>
+
 #include <ostream>
 #include <string>
 #include <tuple>
@@ -170,15 +171,16 @@
 #include <typeinfo>
 #include <utility>
 
-#ifdef ADDRESS_SANITIZER
-#include <sanitizer/asan_interface.h>
-#endif
-
+#include "absl/base/config.h"
 #include "absl/meta/type_traits.h"
 #include "absl/strings/str_cat.h"
 #include "absl/types/span.h"
 #include "absl/utility/utility.h"
 
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+#include <sanitizer/asan_interface.h>
+#endif
+
 #if defined(__GXX_RTTI)
 #define ABSL_INTERNAL_HAS_CXA_DEMANGLE
 #endif
@@ -402,7 +404,7 @@
   constexpr size_t Offset() const {
     static_assert(N < NumOffsets, "Index out of bounds");
     return adl_barrier::Align(
-        Offset<N - 1>() + SizeOf<ElementType<N - 1>>() * size_[N - 1],
+        Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1],
         ElementAlignment<N>::value);
   }
 
@@ -595,7 +597,7 @@
   constexpr size_t AllocSize() const {
     static_assert(NumTypes == NumSizes, "You must specify sizes of all fields");
     return Offset<NumTypes - 1>() +
-           SizeOf<ElementType<NumTypes - 1>>() * size_[NumTypes - 1];
+        SizeOf<ElementType<NumTypes - 1>>::value * size_[NumTypes - 1];
   }
 
   // If built with --config=asan, poisons padding bytes (if any) in the
@@ -614,12 +616,12 @@
   void PoisonPadding(const Char* p) const {
     static_assert(N < NumOffsets, "Index out of bounds");
     (void)p;
-#ifdef ADDRESS_SANITIZER
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
     PoisonPadding<Char, N - 1>(p);
     // The `if` is an optimization. It doesn't affect the observable behaviour.
     if (ElementAlignment<N - 1>::value % ElementAlignment<N>::value) {
       size_t start =
-          Offset<N - 1>() + SizeOf<ElementType<N - 1>>() * size_[N - 1];
+          Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1];
       ASAN_POISON_MEMORY_REGION(p + start, Offset<N>() - start);
     }
 #endif
@@ -643,7 +645,7 @@
   // produce "unsigned*" where another produces "unsigned int *".
   std::string DebugString() const {
     const auto offsets = Offsets();
-    const size_t sizes[] = {SizeOf<ElementType<OffsetSeq>>()...};
+    const size_t sizes[] = {SizeOf<ElementType<OffsetSeq>>::value...};
     const std::string types[] = {
         adl_barrier::TypeName<ElementType<OffsetSeq>>()...};
     std::string res = absl::StrCat("@0", types[0], "(", sizes[0], ")");
diff --git a/absl/container/internal/layout_benchmark.cc b/absl/container/internal/layout_benchmark.cc
new file mode 100644
index 0000000..d8636e8
--- /dev/null
+++ b/absl/container/internal/layout_benchmark.cc
@@ -0,0 +1,122 @@
+// 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.
+//
+// Every benchmark should have the same performance as the corresponding
+// headroom benchmark.
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/container/internal/layout.h"
+#include "benchmark/benchmark.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+namespace {
+
+using ::benchmark::DoNotOptimize;
+
+using Int128 = int64_t[2];
+
+// This benchmark provides the upper bound on performance for BM_OffsetConstant.
+template <size_t Offset, class... Ts>
+void BM_OffsetConstantHeadroom(benchmark::State& state) {
+  for (auto _ : state) {
+    DoNotOptimize(Offset);
+  }
+}
+
+template <size_t Offset, class... Ts>
+void BM_OffsetConstant(benchmark::State& state) {
+  using L = Layout<Ts...>;
+  ABSL_RAW_CHECK(L::Partial(3, 5, 7).template Offset<3>() == Offset,
+                 "Invalid offset");
+  for (auto _ : state) {
+    DoNotOptimize(L::Partial(3, 5, 7).template Offset<3>());
+  }
+}
+
+template <class... Ts>
+size_t VariableOffset(size_t n, size_t m, size_t k);
+
+template <>
+size_t VariableOffset<int8_t, int16_t, int32_t, Int128>(size_t n, size_t m,
+                                                        size_t k) {
+  auto Align = [](size_t n, size_t m) { return (n + m - 1) & ~(m - 1); };
+  return Align(Align(Align(n * 1, 2) + m * 2, 4) + k * 4, 8);
+}
+
+template <>
+size_t VariableOffset<Int128, int32_t, int16_t, int8_t>(size_t n, size_t m,
+                                                        size_t k) {
+  // No alignment is necessary.
+  return n * 16 + m * 4 + k * 2;
+}
+
+// This benchmark provides the upper bound on performance for BM_OffsetVariable.
+template <size_t Offset, class... Ts>
+void BM_OffsetVariableHeadroom(benchmark::State& state) {
+  size_t n = 3;
+  size_t m = 5;
+  size_t k = 7;
+  ABSL_RAW_CHECK(VariableOffset<Ts...>(n, m, k) == Offset, "Invalid offset");
+  for (auto _ : state) {
+    DoNotOptimize(n);
+    DoNotOptimize(m);
+    DoNotOptimize(k);
+    DoNotOptimize(VariableOffset<Ts...>(n, m, k));
+  }
+}
+
+template <size_t Offset, class... Ts>
+void BM_OffsetVariable(benchmark::State& state) {
+  using L = Layout<Ts...>;
+  size_t n = 3;
+  size_t m = 5;
+  size_t k = 7;
+  ABSL_RAW_CHECK(L::Partial(n, m, k).template Offset<3>() == Offset,
+                 "Inavlid offset");
+  for (auto _ : state) {
+    DoNotOptimize(n);
+    DoNotOptimize(m);
+    DoNotOptimize(k);
+    DoNotOptimize(L::Partial(n, m, k).template Offset<3>());
+  }
+}
+
+// Run all benchmarks in two modes:
+//
+//   Layout with padding: int8_t[3], int16_t[5], int32_t[7], Int128[?].
+//   Layout without padding: Int128[3], int32_t[5], int16_t[7], int8_t[?].
+
+#define OFFSET_BENCHMARK(NAME, OFFSET, T1, T2, T3, T4) \
+  auto& NAME##_##OFFSET##_##T1##_##T2##_##T3##_##T4 =  \
+      NAME<OFFSET, T1, T2, T3, T4>;                    \
+  BENCHMARK(NAME##_##OFFSET##_##T1##_##T2##_##T3##_##T4)
+
+OFFSET_BENCHMARK(BM_OffsetConstantHeadroom, 48, int8_t, int16_t, int32_t,
+                 Int128);
+OFFSET_BENCHMARK(BM_OffsetConstant, 48, int8_t, int16_t, int32_t, Int128);
+OFFSET_BENCHMARK(BM_OffsetConstantHeadroom, 82, Int128, int32_t, int16_t,
+                 int8_t);
+OFFSET_BENCHMARK(BM_OffsetConstant, 82, Int128, int32_t, int16_t, int8_t);
+OFFSET_BENCHMARK(BM_OffsetVariableHeadroom, 48, int8_t, int16_t, int32_t,
+                 Int128);
+OFFSET_BENCHMARK(BM_OffsetVariable, 48, int8_t, int16_t, int32_t, Int128);
+OFFSET_BENCHMARK(BM_OffsetVariableHeadroom, 82, Int128, int32_t, int16_t,
+                 int8_t);
+OFFSET_BENCHMARK(BM_OffsetVariable, 82, Int128, int32_t, int16_t, int8_t);
+}  // namespace
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/container/internal/layout_test.cc b/absl/container/internal/layout_test.cc
index 8f3628a..1d7158f 100644
--- a/absl/container/internal/layout_test.cc
+++ b/absl/container/internal/layout_test.cc
@@ -17,6 +17,7 @@
 // We need ::max_align_t because some libstdc++ versions don't provide
 // std::max_align_t
 #include <stddef.h>
+
 #include <cstdint>
 #include <memory>
 #include <sstream>
@@ -24,6 +25,7 @@
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/base/config.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/types/span.h"
 
@@ -126,8 +128,10 @@
   {
     using L = Layout<int32_t, int32_t>;
     SameType<std::tuple<int32_t, int32_t>, L::ElementTypes>();
-    SameType<std::tuple<int32_t, int32_t>, decltype(L::Partial())::ElementTypes>();
-    SameType<std::tuple<int32_t, int32_t>, decltype(L::Partial(0))::ElementTypes>();
+    SameType<std::tuple<int32_t, int32_t>,
+             decltype(L::Partial())::ElementTypes>();
+    SameType<std::tuple<int32_t, int32_t>,
+             decltype(L::Partial(0))::ElementTypes>();
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
@@ -366,18 +370,21 @@
   {
     using L = Layout<int32_t>;
     EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<0>(p))));
-    EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3).Pointer<0>(p))));
   }
   {
     using L = Layout<int32_t, int32_t>;
     EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<0>(p))));
-    EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
-    EXPECT_EQ(12, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<1>(p))));
     EXPECT_EQ(0,
-              Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<0>(p))));
+              Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
     EXPECT_EQ(12,
-              Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<1>(p))));
+              Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<1>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<0>(p))));
+    EXPECT_EQ(
+        12, Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<1>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3, 5).Pointer<0>(p))));
     EXPECT_EQ(12, Distance(p, Type<const int32_t*>(L(3, 5).Pointer<1>(p))));
   }
@@ -385,39 +392,44 @@
     using L = Layout<int8_t, int32_t, Int128>;
     EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<0>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<0>(p))));
-    EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<1>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<1>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<0>(p))));
-    EXPECT_EQ(4, Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<1>(p))));
+    EXPECT_EQ(4,
+              Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<1>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<0>(p))));
-    EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<1>(p))));
+    EXPECT_EQ(8,
+              Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<1>(p))));
     EXPECT_EQ(0,
               Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<0>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<1>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<1>(p))));
     EXPECT_EQ(0,
               Distance(p, Type<const Int128*>(L::Partial(0, 0).Pointer<2>(p))));
     EXPECT_EQ(0,
               Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<0>(p))));
-    EXPECT_EQ(4,
-              Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<1>(p))));
+    EXPECT_EQ(
+        4, Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<1>(p))));
     EXPECT_EQ(8,
               Distance(p, Type<const Int128*>(L::Partial(1, 0).Pointer<2>(p))));
     EXPECT_EQ(0,
               Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<0>(p))));
-    EXPECT_EQ(8,
-              Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<1>(p))));
+    EXPECT_EQ(
+        8, Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<1>(p))));
     EXPECT_EQ(24,
               Distance(p, Type<const Int128*>(L::Partial(5, 3).Pointer<2>(p))));
     EXPECT_EQ(
         0, Distance(p, Type<const int8_t*>(L::Partial(0, 0, 0).Pointer<0>(p))));
     EXPECT_EQ(
-        0, Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
+        0,
+        Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
     EXPECT_EQ(
         0, Distance(p, Type<const Int128*>(L::Partial(0, 0, 0).Pointer<2>(p))));
     EXPECT_EQ(
         0, Distance(p, Type<const int8_t*>(L::Partial(1, 0, 0).Pointer<0>(p))));
     EXPECT_EQ(
-        4, Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
+        4,
+        Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
     EXPECT_EQ(
         8, Distance(p, Type<const Int128*>(L::Partial(1, 0, 0).Pointer<2>(p))));
     EXPECT_EQ(
@@ -426,7 +438,8 @@
         24,
         Distance(p, Type<const Int128*>(L::Partial(5, 3, 1).Pointer<2>(p))));
     EXPECT_EQ(
-        8, Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
+        8,
+        Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L(5, 3, 1).Pointer<0>(p))));
     EXPECT_EQ(24, Distance(p, Type<const Int128*>(L(5, 3, 1).Pointer<2>(p))));
     EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<1>(p))));
@@ -437,75 +450,78 @@
   alignas(max_align_t) const unsigned char p[100] = {};
   {
     using L = Layout<int32_t>;
-    EXPECT_EQ(0,
-              Distance(p, Type<const int32_t*>(L::Partial().Pointer<int32_t>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3).Pointer<int32_t>(p))));
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
-    EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<int8_t>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<int8_t>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<int8_t>(p))));
-    EXPECT_EQ(4,
-              Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<int8_t>(p))));
-    EXPECT_EQ(8,
-              Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
     EXPECT_EQ(
-        0, Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
+        0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<int8_t>(p))));
     EXPECT_EQ(
-        0, Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p))));
+        0, Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        4,
+        Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        8,
+        Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(0, Distance(p, Type<const int32_t*>(
+                                 L::Partial(0, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(
         0,
         Distance(p, Type<const Int128*>(L::Partial(0, 0).Pointer<Int128>(p))));
     EXPECT_EQ(
-        0, Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(
-        4, Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p))));
+        0,
+        Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(4, Distance(p, Type<const int32_t*>(
+                                 L::Partial(1, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(
         8,
         Distance(p, Type<const Int128*>(L::Partial(1, 0).Pointer<Int128>(p))));
     EXPECT_EQ(
-        0, Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
-    EXPECT_EQ(
-        8, Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p))));
+        0,
+        Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
+    EXPECT_EQ(8, Distance(p, Type<const int32_t*>(
+                                 L::Partial(5, 3).Pointer<int32_t>(p))));
     EXPECT_EQ(
         24,
         Distance(p, Type<const Int128*>(L::Partial(5, 3).Pointer<Int128>(p))));
-    EXPECT_EQ(
-        0,
-        Distance(p, Type<const int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(
-        0,
-        Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p))));
+    EXPECT_EQ(0, Distance(p, Type<const int8_t*>(
+                                 L::Partial(0, 0, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(0, Distance(p, Type<const int32_t*>(
+                                 L::Partial(0, 0, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<const Int128*>(
                                  L::Partial(0, 0, 0).Pointer<Int128>(p))));
-    EXPECT_EQ(
-        0,
-        Distance(p, Type<const int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(
-        4,
-        Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p))));
+    EXPECT_EQ(0, Distance(p, Type<const int8_t*>(
+                                 L::Partial(1, 0, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(4, Distance(p, Type<const int32_t*>(
+                                 L::Partial(1, 0, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(8, Distance(p, Type<const Int128*>(
                                  L::Partial(1, 0, 0).Pointer<Int128>(p))));
-    EXPECT_EQ(
-        0,
-        Distance(p, Type<const int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p))));
+    EXPECT_EQ(0, Distance(p, Type<const int8_t*>(
+                                 L::Partial(5, 3, 1).Pointer<int8_t>(p))));
     EXPECT_EQ(24, Distance(p, Type<const Int128*>(
                                   L::Partial(5, 3, 1).Pointer<Int128>(p))));
-    EXPECT_EQ(
-        8,
-        Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p))));
+    EXPECT_EQ(8, Distance(p, Type<const int32_t*>(
+                                 L::Partial(5, 3, 1).Pointer<int32_t>(p))));
     EXPECT_EQ(24,
               Distance(p, Type<const Int128*>(L(5, 3, 1).Pointer<Int128>(p))));
-    EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<int32_t>(p))));
   }
 }
 
@@ -546,15 +562,18 @@
     EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<1>(p))));
     EXPECT_EQ(24, Distance(p, Type<Int128*>(L::Partial(5, 3).Pointer<2>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<0>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
     EXPECT_EQ(0, Distance(p, Type<Int128*>(L::Partial(0, 0, 0).Pointer<2>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<0>(p))));
-    EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
+    EXPECT_EQ(4,
+              Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
     EXPECT_EQ(8, Distance(p, Type<Int128*>(L::Partial(1, 0, 0).Pointer<2>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<0>(p))));
     EXPECT_EQ(24,
               Distance(p, Type<Int128*>(L::Partial(5, 3, 1).Pointer<2>(p))));
-    EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
+    EXPECT_EQ(8,
+              Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L(5, 3, 1).Pointer<0>(p))));
     EXPECT_EQ(24, Distance(p, Type<Int128*>(L(5, 3, 1).Pointer<2>(p))));
     EXPECT_EQ(8, Distance(p, Type<int32_t*>(L(5, 3, 1).Pointer<1>(p))));
@@ -566,48 +585,61 @@
   {
     using L = Layout<int32_t>;
     EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial().Pointer<int32_t>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<int32_t*>(L(3).Pointer<int32_t>(p))));
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial().Pointer<int8_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0).Pointer<int8_t>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1).Pointer<int8_t>(p))));
-    EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
+    EXPECT_EQ(4,
+              Distance(p, Type<int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5).Pointer<int8_t>(p))));
-    EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p))));
+    EXPECT_EQ(8,
+              Distance(p, Type<int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(0,
               Distance(p, Type<Int128*>(L::Partial(0, 0).Pointer<Int128>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        4, Distance(p, Type<int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(8,
               Distance(p, Type<Int128*>(L::Partial(1, 0).Pointer<Int128>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
-    EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p))));
     EXPECT_EQ(24,
               Distance(p, Type<Int128*>(L::Partial(5, 3).Pointer<Int128>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(
         0, Distance(p, Type<Int128*>(L::Partial(0, 0, 0).Pointer<Int128>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(4,
-              Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        4,
+        Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(
         8, Distance(p, Type<Int128*>(L::Partial(1, 0, 0).Pointer<Int128>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p))));
     EXPECT_EQ(
         24, Distance(p, Type<Int128*>(L::Partial(5, 3, 1).Pointer<Int128>(p))));
-    EXPECT_EQ(8,
-              Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        8,
+        Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L(5, 3, 1).Pointer<int8_t>(p))));
     EXPECT_EQ(24, Distance(p, Type<Int128*>(L(5, 3, 1).Pointer<Int128>(p))));
     EXPECT_EQ(8, Distance(p, Type<int32_t*>(L(5, 3, 1).Pointer<int32_t>(p))));
@@ -788,67 +820,72 @@
   {
     using L = Layout<int32_t>;
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<const int32_t>>(L::Partial(0).Slice<0>(p)).data()));
+        0, Distance(
+               p, Type<Span<const int32_t>>(L::Partial(0).Slice<0>(p)).data()));
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
-    EXPECT_EQ(0, Distance(p, Type<Span<const int32_t>>(L(3).Slice<0>(p)).data()));
+        0, Distance(
+               p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
+    EXPECT_EQ(0,
+              Distance(p, Type<Span<const int32_t>>(L(3).Slice<0>(p)).data()));
   }
   {
     using L = Layout<int32_t, int32_t>;
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
+        0, Distance(
+               p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p,
-                 Type<Span<const int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
+        Distance(
+            p, Type<Span<const int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
     EXPECT_EQ(
         12,
-        Distance(p,
-                 Type<Span<const int32_t>>(L::Partial(3, 5).Slice<1>(p)).data()));
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<0>(p)).data()));
-    EXPECT_EQ(12,
-              Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<1>(p)).data()));
+        Distance(
+            p, Type<Span<const int32_t>>(L::Partial(3, 5).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0, Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        12, Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<1>(p)).data()));
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<const int8_t>>(L::Partial(0).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<const int8_t>>(L::Partial(1).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<const int8_t>>(L::Partial(5).Slice<0>(p)).data()));
+        0, Distance(
+               p, Type<Span<const int8_t>>(L::Partial(0).Slice<0>(p)).data()));
     EXPECT_EQ(
         0, Distance(
-               p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        0,
-        Distance(p,
-                 Type<Span<const int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
+               p, Type<Span<const int8_t>>(L::Partial(1).Slice<0>(p)).data()));
     EXPECT_EQ(
         0, Distance(
-               p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        4,
-        Distance(p,
-                 Type<Span<const int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        8,
-        Distance(p,
-                 Type<Span<const int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
+               p, Type<Span<const int8_t>>(L::Partial(5).Slice<0>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
+            p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(
+            p, Type<Span<const int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(
+            p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        4,
+        Distance(
+            p, Type<Span<const int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(
+            p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        8,
+        Distance(
+            p, Type<Span<const int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(
+            p,
+            Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
@@ -862,7 +899,8 @@
     EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
+            p,
+            Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
     EXPECT_EQ(
         4,
         Distance(
@@ -876,7 +914,8 @@
     EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
+            p,
+            Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
     EXPECT_EQ(
         24,
         Distance(
@@ -888,12 +927,14 @@
             p,
             Type<Span<const int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data()));
     EXPECT_EQ(
-        0, Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
+        0,
+        Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
     EXPECT_EQ(
         24,
         Distance(p, Type<Span<const Int128>>(L(5, 3, 1).Slice<2>(p)).data()));
     EXPECT_EQ(
-        8, Distance(p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
+        8,
+        Distance(p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
   }
 }
 
@@ -904,98 +945,94 @@
     EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<const int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
+            p,
+            Type<Span<const int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<const int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
+            p,
+            Type<Span<const int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
     EXPECT_EQ(
-        0, Distance(p, Type<Span<const int32_t>>(L(3).Slice<int32_t>(p)).data()));
+        0,
+        Distance(p, Type<Span<const int32_t>>(L(3).Slice<int32_t>(p)).data()));
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
     EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<const int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<const int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<const int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data()));
+            p,
+            Type<Span<const int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
             p,
-            Type<Span<const int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data()));
-    EXPECT_EQ(
-        0,
-        Distance(
-            p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        4,
-        Distance(
-            p,
-            Type<Span<const int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data()));
-    EXPECT_EQ(
-        0,
-        Distance(
-            p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        8,
-        Distance(
-            p,
-            Type<Span<const int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data()));
+            Type<Span<const int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
             p,
-            Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data()));
+            Type<Span<const int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<const int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p))
+        Distance(p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<int8_t>(p))
                         .data()));
+    EXPECT_EQ(0, Distance(p, Type<Span<const int32_t>>(
+                                 L::Partial(0, 0).Slice<int32_t>(p))
+                                 .data()));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<int8_t>(p))
+                        .data()));
+    EXPECT_EQ(4, Distance(p, Type<Span<const int32_t>>(
+                                 L::Partial(1, 0).Slice<int32_t>(p))
+                                 .data()));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<int8_t>(p))
+                        .data()));
+    EXPECT_EQ(8, Distance(p, Type<Span<const int32_t>>(
+                                 L::Partial(5, 3).Slice<int32_t>(p))
+                                 .data()));
+    EXPECT_EQ(0, Distance(p, Type<Span<const int8_t>>(
+                                 L::Partial(0, 0, 0).Slice<int8_t>(p))
+                                 .data()));
+    EXPECT_EQ(0, Distance(p, Type<Span<const int32_t>>(
+                                 L::Partial(0, 0, 0).Slice<int32_t>(p))
+                                 .data()));
     EXPECT_EQ(0, Distance(p, Type<Span<const Int128>>(
                                  L::Partial(0, 0, 0).Slice<Int128>(p))
                                  .data()));
-    EXPECT_EQ(
-        0,
-        Distance(
-            p,
-            Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        4,
-        Distance(p, Type<Span<const int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p))
-                        .data()));
+    EXPECT_EQ(0, Distance(p, Type<Span<const int8_t>>(
+                                 L::Partial(1, 0, 0).Slice<int8_t>(p))
+                                 .data()));
+    EXPECT_EQ(4, Distance(p, Type<Span<const int32_t>>(
+                                 L::Partial(1, 0, 0).Slice<int32_t>(p))
+                                 .data()));
     EXPECT_EQ(8, Distance(p, Type<Span<const Int128>>(
                                  L::Partial(1, 0, 0).Slice<Int128>(p))
                                  .data()));
-    EXPECT_EQ(
-        0,
-        Distance(
-            p,
-            Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data()));
+    EXPECT_EQ(0, Distance(p, Type<Span<const int8_t>>(
+                                 L::Partial(5, 3, 1).Slice<int8_t>(p))
+                                 .data()));
     EXPECT_EQ(24, Distance(p, Type<Span<const Int128>>(
                                   L::Partial(5, 3, 1).Slice<Int128>(p))
                                   .data()));
-    EXPECT_EQ(
-        8,
-        Distance(p, Type<Span<const int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p))
-                        .data()));
+    EXPECT_EQ(8, Distance(p, Type<Span<const int32_t>>(
+                                 L::Partial(5, 3, 1).Slice<int32_t>(p))
+                                 .data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
+        Distance(p,
+                 Type<Span<const int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         24,
         Distance(p,
                  Type<Span<const Int128>>(L(5, 3, 1).Slice<Int128>(p)).data()));
     EXPECT_EQ(
-        8, Distance(
-               p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
+        8,
+        Distance(
+            p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
   }
 }
 
@@ -1003,18 +1040,19 @@
   alignas(max_align_t) unsigned char p[100];
   {
     using L = Layout<int32_t>;
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<0>(p)).data()));
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        0, Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        0, Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
     EXPECT_EQ(0, Distance(p, Type<Span<int32_t>>(L(3).Slice<0>(p)).data()));
   }
   {
     using L = Layout<int32_t, int32_t>;
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
     EXPECT_EQ(
-        0, Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
+        0, Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
     EXPECT_EQ(
         12,
         Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<1>(p)).data()));
@@ -1023,55 +1061,63 @@
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<0>(p)).data()));
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<0>(p)).data()));
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<0>(p)).data()));
     EXPECT_EQ(
-        0, Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
+        0, Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<0>(p)).data()));
     EXPECT_EQ(
-        0, Distance(p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
+        0, Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<0>(p)).data()));
     EXPECT_EQ(
-        0, Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        4, Distance(p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        8, Distance(p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
+        0, Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<0>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
+        Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<1>(p)).data()));
+        Distance(p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        4,
+        Distance(p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        8,
+        Distance(p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0, Distance(
+               p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        0, Distance(
+               p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<1>(p)).data()));
     EXPECT_EQ(
         0, Distance(
                p, Type<Span<Int128>>(L::Partial(0, 0, 0).Slice<2>(p)).data()));
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
+        0, Distance(
+               p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
     EXPECT_EQ(
-        4,
-        Distance(p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<1>(p)).data()));
+        4, Distance(
+               p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<1>(p)).data()));
     EXPECT_EQ(
         8, Distance(
                p, Type<Span<Int128>>(L::Partial(1, 0, 0).Slice<2>(p)).data()));
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
+        0, Distance(
+               p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
     EXPECT_EQ(
         24, Distance(
                 p, Type<Span<Int128>>(L::Partial(5, 3, 1).Slice<2>(p)).data()));
     EXPECT_EQ(
-        8,
-        Distance(p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data()));
-    EXPECT_EQ(0, Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
+        8, Distance(
+               p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data()));
+    EXPECT_EQ(0,
+              Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
     EXPECT_EQ(24,
               Distance(p, Type<Span<Int128>>(L(5, 3, 1).Slice<2>(p)).data()));
-    EXPECT_EQ(8, Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
+    EXPECT_EQ(8,
+              Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
   }
 }
 
@@ -1080,66 +1126,84 @@
   {
     using L = Layout<int32_t>;
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
+        0, Distance(
+               p, Type<Span<int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
-    EXPECT_EQ(0, Distance(p, Type<Span<int32_t>>(L(3).Slice<int32_t>(p)).data()));
+        0, Distance(
+               p, Type<Span<int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
+    EXPECT_EQ(0,
+              Distance(p, Type<Span<int32_t>>(L(3).Slice<int32_t>(p)).data()));
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
     EXPECT_EQ(
-        0, Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
+        0,
+        Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data()));
+        Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        4, Distance(
-               p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data()));
+        Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        8, Distance(
-               p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data()));
+        Distance(p,
+                 Type<Span<int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p)).data()));
+            p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(p,
+                 Type<Span<int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data()));
+    EXPECT_EQ(
+        4,
+        Distance(
+            p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(p,
+                 Type<Span<int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data()));
+    EXPECT_EQ(
+        8,
+        Distance(
+            p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(
+            p,
+            Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(
+            p,
+            Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
             p,
             Type<Span<Int128>>(L::Partial(0, 0, 0).Slice<Int128>(p)).data()));
     EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data()));
+        0,
+        Distance(
+            p,
+            Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         4,
         Distance(
-            p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p)).data()));
+            p,
+            Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p)).data()));
     EXPECT_EQ(
         8,
         Distance(
             p,
             Type<Span<Int128>>(L::Partial(1, 0, 0).Slice<Int128>(p)).data()));
     EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data()));
+        0,
+        Distance(
+            p,
+            Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         24,
         Distance(
@@ -1148,14 +1212,16 @@
     EXPECT_EQ(
         8,
         Distance(
-            p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p)).data()));
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
+            p,
+            Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p)).data()));
+    EXPECT_EQ(
+        0, Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         24,
         Distance(p, Type<Span<Int128>>(L(5, 3, 1).Slice<Int128>(p)).data()));
     EXPECT_EQ(
-        8, Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
+        8,
+        Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
   }
 }
 
@@ -1254,17 +1320,17 @@
   }
   {
     const auto x = L::Partial(1, 2, 3);
-    EXPECT_THAT(
-        (Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(x.Slices(p))),
-        Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
-              IsSameSlice(x.Slice<2>(p))));
+    EXPECT_THAT((Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(
+                    x.Slices(p))),
+                Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
+                      IsSameSlice(x.Slice<2>(p))));
   }
   {
     const L x(1, 2, 3);
-    EXPECT_THAT(
-        (Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(x.Slices(p))),
-        Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
-              IsSameSlice(x.Slice<2>(p))));
+    EXPECT_THAT((Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(
+                    x.Slices(p))),
+                Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
+                      IsSameSlice(x.Slice<2>(p))));
   }
 }
 
@@ -1314,7 +1380,7 @@
 };
 
 void ExpectRegionPoisoned(const unsigned char* p, size_t n, bool poisoned) {
-#ifdef ADDRESS_SANITIZER
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
   for (size_t i = 0; i != n; ++i) {
     EXPECT_EQ(poisoned, __asan_address_is_poisoned(p + i));
   }
@@ -1396,7 +1462,8 @@
               x.DebugString());
   }
   {
-    constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3);
+    constexpr auto x =
+        Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3);
     EXPECT_EQ(
         "@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; "
         "@16" +
@@ -1404,7 +1471,8 @@
         x.DebugString());
   }
   {
-    constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3, 4);
+    constexpr auto x =
+        Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3, 4);
     EXPECT_EQ(
         "@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; "
         "@16" +
diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc
index 919ac07..bfef071 100644
--- a/absl/container/internal/raw_hash_set.cc
+++ b/absl/container/internal/raw_hash_set.cc
@@ -27,7 +27,7 @@
 
 // Returns "random" seed.
 inline size_t RandomSeed() {
-#if ABSL_HAVE_THREAD_LOCAL
+#ifdef ABSL_HAVE_THREAD_LOCAL
   static thread_local size_t counter = 0;
   size_t value = ++counter;
 #else   // ABSL_HAVE_THREAD_LOCAL
@@ -43,6 +43,19 @@
   return (H1(hash, ctrl) ^ RandomSeed()) % 13 > 6;
 }
 
+void ConvertDeletedToEmptyAndFullToDeleted(
+    ctrl_t* ctrl, size_t capacity) {
+  assert(ctrl[capacity] == kSentinel);
+  assert(IsValidCapacity(capacity));
+  for (ctrl_t* pos = ctrl; pos != ctrl + capacity + 1; pos += Group::kWidth) {
+    Group{pos}.ConvertSpecialToEmptyAndFullToDeleted(pos);
+  }
+  // Copy the cloned ctrl bytes.
+  std::memcpy(ctrl + capacity + 1, ctrl, Group::kWidth);
+  ctrl[capacity] = kSentinel;
+}
+
+
 }  // 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 ca7be8d..8615de8 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -102,8 +102,8 @@
 #include <type_traits>
 #include <utility>
 
-#include "absl/base/internal/bits.h"
 #include "absl/base/internal/endian.h"
+#include "absl/base/optimization.h"
 #include "absl/base/port.h"
 #include "absl/container/internal/common.h"
 #include "absl/container/internal/compressed_tuple.h"
@@ -115,12 +115,23 @@
 #include "absl/container/internal/layout.h"
 #include "absl/memory/memory.h"
 #include "absl/meta/type_traits.h"
+#include "absl/numeric/bits.h"
 #include "absl/utility/utility.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace container_internal {
 
+template <typename AllocType>
+void SwapAlloc(AllocType& lhs, AllocType& rhs,
+               std::true_type /* propagate_on_container_swap */) {
+  using std::swap;
+  swap(lhs, rhs);
+}
+template <typename AllocType>
+void SwapAlloc(AllocType& /*lhs*/, AllocType& /*rhs*/,
+               std::false_type /* propagate_on_container_swap */) {}
+
 template <size_t Width>
 class probe_seq {
  public:
@@ -168,24 +179,19 @@
 
 // TODO(alkis): Switch to std::is_nothrow_swappable when gcc/clang supports it.
 template <class T>
-constexpr bool IsNoThrowSwappable() {
+constexpr bool IsNoThrowSwappable(std::true_type = {} /* is_swappable */) {
   using std::swap;
   return noexcept(swap(std::declval<T&>(), std::declval<T&>()));
 }
-
-template <typename T>
-int TrailingZeros(T x) {
-  return sizeof(T) == 8 ? base_internal::CountTrailingZerosNonZero64(
-                              static_cast<uint64_t>(x))
-                        : base_internal::CountTrailingZerosNonZero32(
-                              static_cast<uint32_t>(x));
+template <class T>
+constexpr bool IsNoThrowSwappable(std::false_type /* is_swappable */) {
+  return false;
 }
 
 template <typename T>
-int LeadingZeros(T x) {
-  return sizeof(T) == 8
-             ? base_internal::CountLeadingZeros64(static_cast<uint64_t>(x))
-             : base_internal::CountLeadingZeros32(static_cast<uint32_t>(x));
+uint32_t TrailingZeros(T x) {
+  ABSL_INTERNAL_ASSUME(x != 0);
+  return countr_zero(x);
 }
 
 // An abstraction over a bitmask. It provides an easy way to iterate through the
@@ -215,26 +221,24 @@
   }
   explicit operator bool() const { return mask_ != 0; }
   int operator*() const { return LowestBitSet(); }
-  int LowestBitSet() const {
+  uint32_t LowestBitSet() const {
     return container_internal::TrailingZeros(mask_) >> Shift;
   }
-  int HighestBitSet() const {
-    return (sizeof(T) * CHAR_BIT - container_internal::LeadingZeros(mask_) -
-            1) >>
-           Shift;
+  uint32_t HighestBitSet() const {
+    return static_cast<uint32_t>((bit_width(mask_) - 1) >> Shift);
   }
 
   BitMask begin() const { return *this; }
   BitMask end() const { return BitMask(0); }
 
-  int TrailingZeros() const {
+  uint32_t TrailingZeros() const {
     return container_internal::TrailingZeros(mask_) >> Shift;
   }
 
-  int LeadingZeros() const {
+  uint32_t LeadingZeros() const {
     constexpr int total_significant_bits = SignificantBits << Shift;
     constexpr int extra_bits = sizeof(T) * 8 - total_significant_bits;
-    return container_internal::LeadingZeros(mask_ << extra_bits) >> Shift;
+    return countl_zero(mask_ << extra_bits) >> Shift;
   }
 
  private:
@@ -312,7 +316,7 @@
 inline bool IsDeleted(ctrl_t c) { return c == kDeleted; }
 inline bool IsEmptyOrDeleted(ctrl_t c) { return c < kSentinel; }
 
-#if SWISSTABLE_HAVE_SSE2
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
 
 // https://github.com/abseil/abseil-cpp/issues/209
 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87853
@@ -346,7 +350,7 @@
 
   // Returns a bitmask representing the positions of empty slots.
   BitMask<uint32_t, kWidth> MatchEmpty() const {
-#if SWISSTABLE_HAVE_SSSE3
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3
     // This only works because kEmpty is -128.
     return BitMask<uint32_t, kWidth>(
         _mm_movemask_epi8(_mm_sign_epi8(ctrl, ctrl)));
@@ -365,14 +369,14 @@
   // Returns the number of trailing empty or deleted elements in the group.
   uint32_t CountLeadingEmptyOrDeleted() const {
     auto special = _mm_set1_epi8(kSentinel);
-    return TrailingZeros(
-        _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)) + 1);
+    return TrailingZeros(static_cast<uint32_t>(
+        _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)) + 1));
   }
 
   void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const {
     auto msbs = _mm_set1_epi8(static_cast<char>(-128));
     auto x126 = _mm_set1_epi8(126);
-#if SWISSTABLE_HAVE_SSSE3
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3
     auto res = _mm_or_si128(_mm_shuffle_epi8(x126, ctrl), msbs);
 #else
     auto zero = _mm_setzero_si128();
@@ -384,7 +388,7 @@
 
   __m128i ctrl;
 };
-#endif  // SWISSTABLE_HAVE_SSE2
+#endif  // ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
 
 struct GroupPortableImpl {
   static constexpr size_t kWidth = 8;
@@ -438,7 +442,7 @@
   uint64_t ctrl;
 };
 
-#if SWISSTABLE_HAVE_SSE2
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
 using Group = GroupSse2Impl;
 #else
 using Group = GroupPortableImpl;
@@ -457,25 +461,23 @@
 //   DELETED -> EMPTY
 //   EMPTY -> EMPTY
 //   FULL -> DELETED
-inline void ConvertDeletedToEmptyAndFullToDeleted(
-    ctrl_t* ctrl, size_t capacity) {
-  assert(ctrl[capacity] == kSentinel);
-  assert(IsValidCapacity(capacity));
-  for (ctrl_t* pos = ctrl; pos != ctrl + capacity + 1; pos += Group::kWidth) {
-    Group{pos}.ConvertSpecialToEmptyAndFullToDeleted(pos);
-  }
-  // Copy the cloned ctrl bytes.
-  std::memcpy(ctrl + capacity + 1, ctrl, Group::kWidth);
-  ctrl[capacity] = kSentinel;
-}
+void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t* ctrl, size_t capacity);
 
 // Rounds up the capacity to the next power of 2 minus 1, with a minimum of 1.
 inline size_t NormalizeCapacity(size_t n) {
-  return n ? ~size_t{} >> LeadingZeros(n) : 1;
+  return n ? ~size_t{} >> countl_zero(n) : 1;
 }
 
-// We use 7/8th as maximum load factor.
-// For 16-wide groups, that gives an average of two empty slots per group.
+// General notes on capacity/growth methods below:
+// - We use 7/8th as maximum load factor. For 16-wide groups, that gives an
+//   average of two empty slots per group.
+// - For (capacity+1) >= Group::kWidth, growth is 7/8*capacity.
+// - For (capacity+1) < Group::kWidth, growth == capacity. In this case, we
+//   never need to probe (the whole table fits in one group) so we don't need a
+//   load factor less than 1.
+
+// Given `capacity` of the table, returns the size (i.e. number of full slots)
+// at which we should grow the capacity.
 inline size_t CapacityToGrowth(size_t capacity) {
   assert(IsValidCapacity(capacity));
   // `capacity*7/8`
@@ -486,7 +488,7 @@
   return capacity - capacity / 8;
 }
 // From desired "growth" to a lowerbound of the necessary capacity.
-// Might not be a valid one and required NormalizeCapacity().
+// Might not be a valid one and requires NormalizeCapacity().
 inline size_t GrowthToLowerboundCapacity(size_t growth) {
   // `growth*8/7`
   if (Group::kWidth == 8 && growth == 7) {
@@ -496,6 +498,76 @@
   return growth + static_cast<size_t>((static_cast<int64_t>(growth) - 1) / 7);
 }
 
+inline void AssertIsFull(ctrl_t* ctrl) {
+  ABSL_HARDENING_ASSERT((ctrl != nullptr && IsFull(*ctrl)) &&
+                        "Invalid operation on iterator. The element might have "
+                        "been erased, or the table might have rehashed.");
+}
+
+inline void AssertIsValid(ctrl_t* ctrl) {
+  ABSL_HARDENING_ASSERT((ctrl == nullptr || IsFull(*ctrl)) &&
+                        "Invalid operation on iterator. The element might have "
+                        "been erased, or the table might have rehashed.");
+}
+
+struct FindInfo {
+  size_t offset;
+  size_t probe_length;
+};
+
+// The representation of the object has two modes:
+//  - small: For capacities < kWidth-1
+//  - large: For the rest.
+//
+// Differences:
+//  - In small 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 are valid. The rest contain dummy kEmpty values that do not
+//  represent a real slot. This is important to take into account on
+//  find_first_non_full(), where we never try ShouldInsertBackwards() for
+//  small tables.
+inline bool is_small(size_t capacity) { return capacity < Group::kWidth - 1; }
+
+inline probe_seq<Group::kWidth> probe(ctrl_t* ctrl, size_t hash,
+                                      size_t capacity) {
+  return probe_seq<Group::kWidth>(H1(hash, ctrl), capacity);
+}
+
+// Probes the raw_hash_set with the probe sequence for hash and returns the
+// pointer to the first empty or deleted slot.
+// NOTE: this function must work with tables having both kEmpty and kDelete
+// in one group. Such tables appears during drop_deletes_without_resize.
+//
+// This function is very useful when insertions happen and:
+// - the input is already a set
+// - there are enough slots
+// - the element with the hash is not in the table
+inline FindInfo find_first_non_full(ctrl_t* ctrl, size_t hash,
+                                    size_t capacity) {
+  auto seq = probe(ctrl, hash, capacity);
+  while (true) {
+    Group g{ctrl + seq.offset()};
+    auto mask = g.MatchEmptyOrDeleted();
+    if (mask) {
+#if !defined(NDEBUG)
+      // We want to add entropy even when ASLR is not enabled.
+      // In debug build we will randomly insert in either the front or back of
+      // the group.
+      // TODO(kfm,sbenza): revisit after we do unconditional mixing
+      if (!is_small(capacity) && ShouldInsertBackwards(hash, ctrl)) {
+        return {seq.offset(mask.HighestBitSet()), seq.index()};
+      }
+#endif
+      return {seq.offset(mask.LowestBitSet()), seq.index()};
+    }
+    seq.next();
+    assert(seq.index() < capacity && "full table!");
+  }
+}
+
 // Policy: a policy defines how to perform different operations on
 // the slots of the hashtable (see hash_policy_traits.h for the full interface
 // of policy).
@@ -510,7 +582,8 @@
 // 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.
 //
-// Allocator: an Allocator [https://devdocs.io/cpp/concept/allocator] with which
+// 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>
@@ -616,7 +689,7 @@
 
     // PRECONDITION: not an end() iterator.
     reference operator*() const {
-      assert_is_full();
+      AssertIsFull(ctrl_);
       return PolicyTraits::element(slot_);
     }
 
@@ -625,7 +698,7 @@
 
     // PRECONDITION: not an end() iterator.
     iterator& operator++() {
-      assert_is_full();
+      AssertIsFull(ctrl_);
       ++ctrl_;
       ++slot_;
       skip_empty_or_deleted();
@@ -639,8 +712,8 @@
     }
 
     friend bool operator==(const iterator& a, const iterator& b) {
-      a.assert_is_valid();
-      b.assert_is_valid();
+      AssertIsValid(a.ctrl_);
+      AssertIsValid(b.ctrl_);
       return a.ctrl_ == b.ctrl_;
     }
     friend bool operator!=(const iterator& a, const iterator& b) {
@@ -648,24 +721,19 @@
     }
 
    private:
-    iterator(ctrl_t* ctrl) : ctrl_(ctrl) {}  // for end()
-    iterator(ctrl_t* ctrl, slot_type* slot) : ctrl_(ctrl), slot_(slot) {}
-
-    void assert_is_full() const { assert(IsFull(*ctrl_)); }
-    void assert_is_valid() const {
-      assert(!ctrl_ || IsFull(*ctrl_) || *ctrl_ == kSentinel);
+    iterator(ctrl_t* ctrl, slot_type* slot) : ctrl_(ctrl), slot_(slot) {
+      // This assumption helps the compiler know that any non-end iterator is
+      // not equal to any end iterator.
+      ABSL_INTERNAL_ASSUME(ctrl != nullptr);
     }
 
     void skip_empty_or_deleted() {
       while (IsEmptyOrDeleted(*ctrl_)) {
-        // ctrl is not necessarily aligned to Group::kWidth. It is also likely
-        // to read past the space for ctrl bytes and into slots. This is ok
-        // because ctrl has sizeof() == 1 and slot has sizeof() >= 1 so there
-        // is no way to read outside the combined slot array.
         uint32_t shift = Group{ctrl_}.CountLeadingEmptyOrDeleted();
         ctrl_ += shift;
         slot_ += shift;
       }
+      if (ABSL_PREDICT_FALSE(*ctrl_ == kSentinel)) ctrl_ = nullptr;
     }
 
     ctrl_t* ctrl_ = nullptr;
@@ -724,10 +792,10 @@
   explicit raw_hash_set(size_t bucket_count, const hasher& hash = hasher(),
                         const key_equal& eq = key_equal(),
                         const allocator_type& alloc = allocator_type())
-      : ctrl_(EmptyGroup()), settings_(0, hash, eq, alloc) {
+      : ctrl_(EmptyGroup()),
+        settings_(0, HashtablezInfoHandle(), hash, eq, alloc) {
     if (bucket_count) {
       capacity_ = NormalizeCapacity(bucket_count);
-      reset_growth_left();
       initialize_slots();
     }
   }
@@ -833,10 +901,10 @@
     // than a full `insert`.
     for (const auto& v : that) {
       const size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, v);
-      auto target = find_first_non_full(hash);
+      auto target = find_first_non_full(ctrl_, hash, capacity_);
       set_ctrl(target.offset, H2(hash));
       emplace_at(target.offset, v);
-      infoz_.RecordInsert(hash, target.probe_length);
+      infoz().RecordInsert(hash, target.probe_length);
     }
     size_ = that.size();
     growth_left() -= that.size();
@@ -850,28 +918,27 @@
         slots_(absl::exchange(that.slots_, nullptr)),
         size_(absl::exchange(that.size_, 0)),
         capacity_(absl::exchange(that.capacity_, 0)),
-        infoz_(absl::exchange(that.infoz_, HashtablezInfoHandle())),
         // Hash, equality and allocator are copied instead of moved because
         // `that` must be left valid. If Hash is std::function<Key>, moving it
         // would create a nullptr functor that cannot be called.
-        settings_(that.settings_) {
-    // growth_left was copied above, reset the one from `that`.
-    that.growth_left() = 0;
-  }
+        settings_(absl::exchange(that.growth_left(), 0),
+                  absl::exchange(that.infoz(), HashtablezInfoHandle()),
+                  that.hash_ref(), that.eq_ref(), that.alloc_ref()) {}
 
   raw_hash_set(raw_hash_set&& that, const allocator_type& a)
       : ctrl_(EmptyGroup()),
         slots_(nullptr),
         size_(0),
         capacity_(0),
-        settings_(0, that.hash_ref(), that.eq_ref(), a) {
+        settings_(0, HashtablezInfoHandle(), that.hash_ref(), that.eq_ref(),
+                  a) {
     if (a == that.alloc_ref()) {
       std::swap(ctrl_, that.ctrl_);
       std::swap(slots_, that.slots_);
       std::swap(size_, that.size_);
       std::swap(capacity_, that.capacity_);
       std::swap(growth_left(), that.growth_left());
-      std::swap(infoz_, that.infoz_);
+      std::swap(infoz(), that.infoz());
     } else {
       reserve(that.size());
       // Note: this will copy elements of dense_set and unordered_set instead of
@@ -907,12 +974,12 @@
     it.skip_empty_or_deleted();
     return it;
   }
-  iterator end() { return {ctrl_ + capacity_}; }
+  iterator end() { return {}; }
 
   const_iterator begin() const {
     return const_cast<raw_hash_set*>(this)->begin();
   }
-  const_iterator end() const { return const_cast<raw_hash_set*>(this)->end(); }
+  const_iterator end() const { return {}; }
   const_iterator cbegin() const { return begin(); }
   const_iterator cend() const { return end(); }
 
@@ -942,7 +1009,7 @@
       reset_growth_left();
     }
     assert(empty());
-    infoz_.RecordStorageChanged(0, capacity_);
+    infoz().RecordStorageChanged(0, capacity_);
   }
 
   // This overload kicks in when the argument is an rvalue of insertable and
@@ -1015,7 +1082,7 @@
 
   template <class InputIt>
   void insert(InputIt first, InputIt last) {
-    for (; first != last; ++first) insert(*first);
+    for (; first != last; ++first) emplace(*first);
   }
 
   template <class T, RequiresNotInit<T> = 0, RequiresInsertable<const T&> = 0>
@@ -1042,7 +1109,9 @@
   }
 
   iterator insert(const_iterator, node_type&& node) {
-    return insert(std::move(node)).first;
+    auto res = insert(std::move(node));
+    node = std::move(res.node);
+    return res.position;
   }
 
   // This overload kicks in if we can deduce the key from args. This enables us
@@ -1171,7 +1240,7 @@
   // 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) {
-    it.assert_is_full();
+    AssertIsFull(it.ctrl_);
     PolicyTraits::destroy(&alloc_ref(), it.slot_);
     erase_meta_only(it);
   }
@@ -1205,7 +1274,7 @@
   }
 
   node_type extract(const_iterator position) {
-    position.inner_.assert_is_full();
+    AssertIsFull(position.inner_.ctrl_);
     auto node =
         CommonAccess::Transfer<node_type>(alloc_ref(), position.inner_.slot_);
     erase_meta_only(position);
@@ -1222,8 +1291,8 @@
 
   void swap(raw_hash_set& that) noexcept(
       IsNoThrowSwappable<hasher>() && IsNoThrowSwappable<key_equal>() &&
-      (!AllocTraits::propagate_on_container_swap::value ||
-       IsNoThrowSwappable<allocator_type>())) {
+      IsNoThrowSwappable<allocator_type>(
+          typename AllocTraits::propagate_on_container_swap{})) {
     using std::swap;
     swap(ctrl_, that.ctrl_);
     swap(slots_, that.slots_);
@@ -1232,20 +1301,16 @@
     swap(growth_left(), that.growth_left());
     swap(hash_ref(), that.hash_ref());
     swap(eq_ref(), that.eq_ref());
-    swap(infoz_, that.infoz_);
-    if (AllocTraits::propagate_on_container_swap::value) {
-      swap(alloc_ref(), that.alloc_ref());
-    } else {
-      // If the allocators do not compare equal it is officially undefined
-      // behavior. We choose to do nothing.
-    }
+    swap(infoz(), that.infoz());
+    SwapAlloc(alloc_ref(), that.alloc_ref(),
+              typename AllocTraits::propagate_on_container_swap{});
   }
 
   void rehash(size_t n) {
     if (n == 0 && capacity_ == 0) return;
     if (n == 0 && size_ == 0) {
       destroy_slots();
-      infoz_.RecordStorageChanged(0, 0);
+      infoz().RecordStorageChanged(0, 0);
       return;
     }
     // bitor is a faster way of doing `max` here. We will round up to the next
@@ -1257,7 +1322,12 @@
     }
   }
 
-  void reserve(size_t n) { rehash(GrowthToLowerboundCapacity(n)); }
+  void reserve(size_t n) {
+    size_t m = GrowthToLowerboundCapacity(n);
+    if (m > capacity_) {
+      resize(NormalizeCapacity(m));
+    }
+  }
 
   // Extension API: support for heterogeneous keys.
   //
@@ -1282,7 +1352,7 @@
   void prefetch(const key_arg<K>& key) const {
     (void)key;
 #if defined(__GNUC__)
-    auto seq = probe(hash_ref()(key));
+    auto seq = probe(ctrl_, hash_ref()(key), capacity_);
     __builtin_prefetch(static_cast<const void*>(ctrl_ + seq.offset()));
     __builtin_prefetch(static_cast<const void*>(slots_ + seq.offset()));
 #endif  // __GNUC__
@@ -1297,7 +1367,7 @@
   // called heterogeneous key support.
   template <class K = key_type>
   iterator find(const key_arg<K>& key, size_t hash) {
-    auto seq = probe(hash);
+    auto seq = probe(ctrl_, hash, capacity_);
     while (true) {
       Group g{ctrl_ + seq.offset()};
       for (int i : g.Match(H2(hash))) {
@@ -1308,6 +1378,7 @@
       }
       if (ABSL_PREDICT_TRUE(g.MatchEmpty())) return end();
       seq.next();
+      assert(seq.index() < capacity_ && "full table!");
     }
   }
   template <class K = key_type>
@@ -1457,7 +1528,7 @@
 
     set_ctrl(index, was_never_full ? kEmpty : kDeleted);
     growth_left() += was_never_full;
-    infoz_.RecordErase();
+    infoz().RecordErase();
   }
 
   void initialize_slots() {
@@ -1474,7 +1545,7 @@
     // bound more carefully.
     if (std::is_same<SlotAlloc, std::allocator<slot_type>>::value &&
         slots_ == nullptr) {
-      infoz_ = Sample();
+      infoz() = Sample();
     }
 
     auto layout = MakeLayout(capacity_);
@@ -1484,7 +1555,7 @@
     slots_ = layout.template Pointer<1>(mem);
     reset_ctrl();
     reset_growth_left();
-    infoz_.RecordStorageChanged(size_, capacity_);
+    infoz().RecordStorageChanged(size_, capacity_);
   }
 
   void destroy_slots() {
@@ -1518,7 +1589,7 @@
       if (IsFull(old_ctrl[i])) {
         size_t hash = PolicyTraits::apply(HashElement{hash_ref()},
                                           PolicyTraits::element(old_slots + i));
-        auto target = find_first_non_full(hash);
+        auto target = find_first_non_full(ctrl_, hash, capacity_);
         size_t new_i = target.offset;
         total_probe_length += target.probe_length;
         set_ctrl(new_i, H2(hash));
@@ -1532,12 +1603,12 @@
       Deallocate<Layout::Alignment()>(&alloc_ref(), old_ctrl,
                                       layout.AllocSize());
     }
-    infoz_.RecordRehash(total_probe_length);
+    infoz().RecordRehash(total_probe_length);
   }
 
   void drop_deletes_without_resize() ABSL_ATTRIBUTE_NOINLINE {
     assert(IsValidCapacity(capacity_));
-    assert(!is_small());
+    assert(!is_small(capacity_));
     // Algorithm:
     // - mark all DELETED slots as EMPTY
     // - mark all FULL slots as DELETED
@@ -1562,7 +1633,7 @@
       if (!IsDeleted(ctrl_[i])) continue;
       size_t hash = PolicyTraits::apply(HashElement{hash_ref()},
                                         PolicyTraits::element(slots_ + i));
-      auto target = find_first_non_full(hash);
+      auto target = find_first_non_full(ctrl_, hash, capacity_);
       size_t new_i = target.offset;
       total_probe_length += target.probe_length;
 
@@ -1570,7 +1641,8 @@
       // If they do, we don't need to move the object as it falls already in the
       // best probe we can.
       const auto probe_index = [&](size_t pos) {
-        return ((pos - probe(hash).offset()) & capacity_) / Group::kWidth;
+        return ((pos - probe(ctrl_, hash, capacity_).offset()) & capacity_) /
+               Group::kWidth;
       };
 
       // Element doesn't move.
@@ -1597,7 +1669,7 @@
       }
     }
     reset_growth_left();
-    infoz_.RecordRehash(total_probe_length);
+    infoz().RecordRehash(total_probe_length);
   }
 
   void rehash_and_grow_if_necessary() {
@@ -1614,7 +1686,7 @@
 
   bool has_element(const value_type& elem) const {
     size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, elem);
-    auto seq = probe(hash);
+    auto seq = probe(ctrl_, hash, capacity_);
     while (true) {
       Group g{ctrl_ + seq.offset()};
       for (int i : g.Match(H2(hash))) {
@@ -1629,41 +1701,6 @@
     return false;
   }
 
-  // Probes the raw_hash_set with the probe sequence for hash and returns the
-  // pointer to the first empty or deleted slot.
-  // NOTE: this function must work with tables having both kEmpty and kDelete
-  // in one group. Such tables appears during drop_deletes_without_resize.
-  //
-  // This function is very useful when insertions happen and:
-  // - the input is already a set
-  // - there are enough slots
-  // - the element with the hash is not in the table
-  struct FindInfo {
-    size_t offset;
-    size_t probe_length;
-  };
-  FindInfo find_first_non_full(size_t hash) {
-    auto seq = probe(hash);
-    while (true) {
-      Group g{ctrl_ + seq.offset()};
-      auto mask = g.MatchEmptyOrDeleted();
-      if (mask) {
-#if !defined(NDEBUG)
-        // We want to add entropy even when ASLR is not enabled.
-        // In debug build we will randomly insert in either the front or back of
-        // the group.
-        // TODO(kfm,sbenza): revisit after we do unconditional mixing
-        if (!is_small() && ShouldInsertBackwards(hash, ctrl_)) {
-          return {seq.offset(mask.HighestBitSet()), seq.index()};
-        }
-#endif
-        return {seq.offset(mask.LowestBitSet()), seq.index()};
-      }
-      assert(seq.index() < capacity_ && "full table!");
-      seq.next();
-    }
-  }
-
   // TODO(alkis): Optimize this assuming *this and that don't overlap.
   raw_hash_set& move_assign(raw_hash_set&& that, std::true_type) {
     raw_hash_set tmp(std::move(that));
@@ -1680,7 +1717,7 @@
   template <class K>
   std::pair<size_t, bool> find_or_prepare_insert(const K& key) {
     auto hash = hash_ref()(key);
-    auto seq = probe(hash);
+    auto seq = probe(ctrl_, hash, capacity_);
     while (true) {
       Group g{ctrl_ + seq.offset()};
       for (int i : g.Match(H2(hash))) {
@@ -1691,21 +1728,22 @@
       }
       if (ABSL_PREDICT_TRUE(g.MatchEmpty())) break;
       seq.next();
+      assert(seq.index() < capacity_ && "full table!");
     }
     return {prepare_insert(hash), true};
   }
 
   size_t prepare_insert(size_t hash) ABSL_ATTRIBUTE_NOINLINE {
-    auto target = find_first_non_full(hash);
+    auto target = find_first_non_full(ctrl_, hash, capacity_);
     if (ABSL_PREDICT_FALSE(growth_left() == 0 &&
                            !IsDeleted(ctrl_[target.offset]))) {
       rehash_and_grow_if_necessary();
-      target = find_first_non_full(hash);
+      target = find_first_non_full(ctrl_, hash, capacity_);
     }
     ++size_;
     growth_left() -= IsEmpty(ctrl_[target.offset]);
     set_ctrl(target.offset, H2(hash));
-    infoz_.RecordInsert(hash, target.probe_length);
+    infoz().RecordInsert(hash, target.probe_length);
     return target.offset;
   }
 
@@ -1733,10 +1771,6 @@
  private:
   friend struct RawHashSetTestOnlyAccess;
 
-  probe_seq<Group::kWidth> probe(size_t hash) const {
-    return probe_seq<Group::kWidth>(H1(hash, ctrl_), capacity_);
-  }
-
   // Reset all ctrl bytes back to kEmpty, except the sentinel.
   void reset_ctrl() {
     std::memset(ctrl_, kEmpty, capacity_ + Group::kWidth);
@@ -1766,29 +1800,15 @@
 
   size_t& growth_left() { return settings_.template get<0>(); }
 
-  // The representation of the object has two modes:
-  //  - small: For capacities < kWidth-1
-  //  - large: For the rest.
-  //
-  // Differences:
-  //  - In small 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 are valid. The rest contain dummy kEmpty values that do not
-  //  represent a real slot. This is important to take into account on
-  //  find_first_non_full(), where we never try ShouldInsertBackwards() for
-  //  small tables.
-  bool is_small() const { return capacity_ < Group::kWidth - 1; }
+  HashtablezInfoHandle& infoz() { return settings_.template get<1>(); }
 
-  hasher& hash_ref() { return settings_.template get<1>(); }
-  const hasher& hash_ref() const { return settings_.template get<1>(); }
-  key_equal& eq_ref() { return settings_.template get<2>(); }
-  const key_equal& eq_ref() const { return settings_.template get<2>(); }
-  allocator_type& alloc_ref() { return settings_.template get<3>(); }
+  hasher& hash_ref() { return settings_.template get<2>(); }
+  const hasher& hash_ref() const { return settings_.template get<2>(); }
+  key_equal& eq_ref() { return settings_.template get<3>(); }
+  const key_equal& eq_ref() const { return settings_.template get<3>(); }
+  allocator_type& alloc_ref() { return settings_.template get<4>(); }
   const allocator_type& alloc_ref() const {
-    return settings_.template get<3>();
+    return settings_.template get<4>();
   }
 
   // TODO(alkis): Investigate removing some of these fields:
@@ -1798,10 +1818,11 @@
   slot_type* slots_ = nullptr;     // [capacity * slot_type]
   size_t size_ = 0;                // number of full slots
   size_t capacity_ = 0;            // total number of slots
-  HashtablezInfoHandle infoz_;
-  absl::container_internal::CompressedTuple<size_t /* growth_left */, hasher,
+  absl::container_internal::CompressedTuple<size_t /* growth_left */,
+                                            HashtablezInfoHandle, hasher,
                                             key_equal, allocator_type>
-      settings_{0, hasher{}, key_equal{}, allocator_type{}};
+      settings_{0, HashtablezInfoHandle{}, hasher{}, key_equal{},
+                allocator_type{}};
 };
 
 // Erases all elements that satisfy the predicate `pred` from the container `c`.
@@ -1825,7 +1846,7 @@
                              const typename Set::key_type& key) {
     size_t num_probes = 0;
     size_t hash = set.hash_ref()(key);
-    auto seq = set.probe(hash);
+    auto seq = probe(set.ctrl_, hash, set.capacity_);
     while (true) {
       container_internal::Group g{set.ctrl_ + seq.offset()};
       for (int i : g.Match(container_internal::H2(hash))) {
diff --git a/absl/container/internal/raw_hash_set_allocator_test.cc b/absl/container/internal/raw_hash_set_allocator_test.cc
index 7ac4b9f..e73f53f 100644
--- a/absl/container/internal/raw_hash_set_allocator_test.cc
+++ b/absl/container/internal/raw_hash_set_allocator_test.cc
@@ -424,6 +424,81 @@
   EXPECT_EQ(0, it->num_copies());
 }
 
+// This allocator is similar to std::pmr::polymorphic_allocator.
+// Note the disabled assignment.
+template <class T>
+class PAlloc {
+  template <class>
+  friend class PAlloc;
+
+ public:
+  // types
+  using value_type = T;
+
+  // traits
+  using propagate_on_container_swap = std::false_type;
+
+  PAlloc() noexcept = default;
+  explicit PAlloc(size_t id) noexcept : id_(id) {}
+  PAlloc(const PAlloc&) noexcept = default;
+  PAlloc& operator=(const PAlloc&) noexcept = delete;
+
+  template <class U>
+  PAlloc(const PAlloc<U>& that) noexcept : id_(that.id_) {}  // NOLINT
+
+  template <class U>
+  struct rebind {
+    using other = PAlloc<U>;
+  };
+
+  constexpr PAlloc select_on_container_copy_construction() const { return {}; }
+
+  // public member functions
+  T* allocate(size_t) { return new T; }
+  void deallocate(T* p, size_t) { delete p; }
+
+  friend bool operator==(const PAlloc& a, const PAlloc& b) {
+    return a.id_ == b.id_;
+  }
+  friend bool operator!=(const PAlloc& a, const PAlloc& b) { return !(a == b); }
+
+ private:
+  size_t id_ = std::numeric_limits<size_t>::max();
+};
+
+// This doesn't compile with GCC 5.4 and 5.5 due to a bug in noexcept handing.
+#if !defined(__GNUC__) || __GNUC__ != 5 || (__GNUC_MINOR__ != 4 && \
+    __GNUC_MINOR__ != 5)
+TEST(NoPropagateOn, Swap) {
+  using PA = PAlloc<char>;
+  using Table = raw_hash_set<Policy, Identity, std::equal_to<int32_t>, PA>;
+
+  Table t1(PA{1}), t2(PA{2});
+  swap(t1, t2);
+  EXPECT_EQ(t1.get_allocator(), PA(1));
+  EXPECT_EQ(t2.get_allocator(), PA(2));
+}
+#endif
+
+TEST(NoPropagateOn, CopyConstruct) {
+  using PA = PAlloc<char>;
+  using Table = raw_hash_set<Policy, Identity, std::equal_to<int32_t>, PA>;
+
+  Table t1(PA{1}), t2(t1);
+  EXPECT_EQ(t1.get_allocator(), PA(1));
+  EXPECT_EQ(t2.get_allocator(), PA());
+}
+
+TEST(NoPropagateOn, Assignment) {
+  using PA = PAlloc<char>;
+  using Table = raw_hash_set<Policy, Identity, std::equal_to<int32_t>, PA>;
+
+  Table t1(PA{1}), t2(PA{2});
+  t1 = t2;
+  EXPECT_EQ(t1.get_allocator(), PA(1));
+  EXPECT_EQ(t2.get_allocator(), PA(2));
+}
+
 }  // namespace
 }  // namespace container_internal
 ABSL_NAMESPACE_END
diff --git a/absl/container/internal/raw_hash_set_benchmark.cc b/absl/container/internal/raw_hash_set_benchmark.cc
new file mode 100644
index 0000000..f9be2c5
--- /dev/null
+++ b/absl/container/internal/raw_hash_set_benchmark.cc
@@ -0,0 +1,396 @@
+// 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 "absl/container/internal/raw_hash_set.h"
+
+#include <numeric>
+#include <random>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/container/internal/hash_function_defaults.h"
+#include "absl/strings/str_format.h"
+#include "benchmark/benchmark.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+struct RawHashSetTestOnlyAccess {
+  template <typename C>
+  static auto GetSlots(const C& c) -> decltype(c.slots_) {
+    return c.slots_;
+  }
+};
+
+namespace {
+
+struct IntPolicy {
+  using slot_type = int64_t;
+  using key_type = int64_t;
+  using init_type = int64_t;
+
+  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) {
+    *new_slot = *old_slot;
+  }
+
+  static int64_t& element(slot_type* slot) { return *slot; }
+
+  template <class F>
+  static auto apply(F&& f, int64_t x) -> decltype(std::forward<F>(f)(x, x)) {
+    return std::forward<F>(f)(x, x);
+  }
+};
+
+class StringPolicy {
+  template <class F, class K, class V,
+            class = typename std::enable_if<
+                std::is_convertible<const K&, absl::string_view>::value>::type>
+  decltype(std::declval<F>()(
+      std::declval<const absl::string_view&>(), std::piecewise_construct,
+      std::declval<std::tuple<K>>(),
+      std::declval<V>())) static apply_impl(F&& f,
+                                            std::pair<std::tuple<K>, V> p) {
+    const absl::string_view& key = std::get<0>(p.first);
+    return std::forward<F>(f)(key, std::piecewise_construct, std::move(p.first),
+                              std::move(p.second));
+  }
+
+ public:
+  struct slot_type {
+    struct ctor {};
+
+    template <class... Ts>
+    slot_type(ctor, Ts&&... ts) : pair(std::forward<Ts>(ts)...) {}
+
+    std::pair<std::string, std::string> pair;
+  };
+
+  using key_type = std::string;
+  using init_type = std::pair<std::string, std::string>;
+
+  template <class allocator_type, class... Args>
+  static void construct(allocator_type* alloc, slot_type* slot, Args... args) {
+    std::allocator_traits<allocator_type>::construct(
+        *alloc, slot, typename slot_type::ctor(), std::forward<Args>(args)...);
+  }
+
+  template <class allocator_type>
+  static void destroy(allocator_type* alloc, slot_type* slot) {
+    std::allocator_traits<allocator_type>::destroy(*alloc, slot);
+  }
+
+  template <class allocator_type>
+  static void transfer(allocator_type* alloc, slot_type* new_slot,
+                       slot_type* old_slot) {
+    construct(alloc, new_slot, std::move(old_slot->pair));
+    destroy(alloc, old_slot);
+  }
+
+  static std::pair<std::string, std::string>& element(slot_type* slot) {
+    return slot->pair;
+  }
+
+  template <class F, class... Args>
+  static auto apply(F&& f, Args&&... args)
+      -> decltype(apply_impl(std::forward<F>(f),
+                             PairArgs(std::forward<Args>(args)...))) {
+    return apply_impl(std::forward<F>(f),
+                      PairArgs(std::forward<Args>(args)...));
+  }
+};
+
+struct StringHash : container_internal::hash_default_hash<absl::string_view> {
+  using is_transparent = void;
+};
+struct StringEq : std::equal_to<absl::string_view> {
+  using is_transparent = void;
+};
+
+struct StringTable
+    : raw_hash_set<StringPolicy, StringHash, StringEq, std::allocator<int>> {
+  using Base = typename StringTable::raw_hash_set;
+  StringTable() {}
+  using Base::Base;
+};
+
+struct IntTable
+    : raw_hash_set<IntPolicy, container_internal::hash_default_hash<int64_t>,
+                   std::equal_to<int64_t>, std::allocator<int64_t>> {
+  using Base = typename IntTable::raw_hash_set;
+  IntTable() {}
+  using Base::Base;
+};
+
+struct string_generator {
+  template <class RNG>
+  std::string operator()(RNG& rng) const {
+    std::string res;
+    res.resize(12);
+    std::uniform_int_distribution<uint32_t> printable_ascii(0x20, 0x7E);
+    std::generate(res.begin(), res.end(), [&] { return printable_ascii(rng); });
+    return res;
+  }
+
+  size_t size;
+};
+
+// Model a cache in steady state.
+//
+// On a table of size N, keep deleting the LRU entry and add a random one.
+void BM_CacheInSteadyState(benchmark::State& state) {
+  std::random_device rd;
+  std::mt19937 rng(rd());
+  string_generator gen{12};
+  StringTable t;
+  std::deque<std::string> keys;
+  while (t.size() < state.range(0)) {
+    auto x = t.emplace(gen(rng), gen(rng));
+    if (x.second) keys.push_back(x.first->first);
+  }
+  ABSL_RAW_CHECK(state.range(0) >= 10, "");
+  while (state.KeepRunning()) {
+    // Some cache hits.
+    std::deque<std::string>::const_iterator it;
+    for (int i = 0; i != 90; ++i) {
+      if (i % 10 == 0) it = keys.end();
+      ::benchmark::DoNotOptimize(t.find(*--it));
+    }
+    // Some cache misses.
+    for (int i = 0; i != 10; ++i) ::benchmark::DoNotOptimize(t.find(gen(rng)));
+    ABSL_RAW_CHECK(t.erase(keys.front()), keys.front().c_str());
+    keys.pop_front();
+    while (true) {
+      auto x = t.emplace(gen(rng), gen(rng));
+      if (x.second) {
+        keys.push_back(x.first->first);
+        break;
+      }
+    }
+  }
+  state.SetItemsProcessed(state.iterations());
+  state.SetLabel(absl::StrFormat("load_factor=%.2f", t.load_factor()));
+}
+
+template <typename Benchmark>
+void CacheInSteadyStateArgs(Benchmark* bm) {
+  // The default.
+  const float max_load_factor = 0.875;
+  // When the cache is at the steady state, the probe sequence will equal
+  // capacity if there is no reclamation of deleted slots. Pick a number large
+  // enough to make the benchmark slow for that case.
+  const size_t capacity = 1 << 10;
+
+  // Check N data points to cover load factors in [0.4, 0.8).
+  const size_t kNumPoints = 10;
+  for (size_t i = 0; i != kNumPoints; ++i)
+    bm->Arg(std::ceil(
+        capacity * (max_load_factor + i * max_load_factor / kNumPoints) / 2));
+}
+BENCHMARK(BM_CacheInSteadyState)->Apply(CacheInSteadyStateArgs);
+
+void BM_EndComparison(benchmark::State& state) {
+  std::random_device rd;
+  std::mt19937 rng(rd());
+  string_generator gen{12};
+  StringTable t;
+  while (t.size() < state.range(0)) {
+    t.emplace(gen(rng), gen(rng));
+  }
+
+  for (auto _ : state) {
+    for (auto it = t.begin(); it != t.end(); ++it) {
+      benchmark::DoNotOptimize(it);
+      benchmark::DoNotOptimize(t);
+      benchmark::DoNotOptimize(it != t.end());
+    }
+  }
+}
+BENCHMARK(BM_EndComparison)->Arg(400);
+
+void BM_CopyCtor(benchmark::State& state) {
+  std::random_device rd;
+  std::mt19937 rng(rd());
+  IntTable t;
+  std::uniform_int_distribution<uint64_t> dist(0, ~uint64_t{});
+
+  while (t.size() < state.range(0)) {
+    t.emplace(dist(rng));
+  }
+
+  for (auto _ : state) {
+    IntTable t2 = t;
+    benchmark::DoNotOptimize(t2);
+  }
+}
+BENCHMARK(BM_CopyCtor)->Range(128, 4096);
+
+void BM_CopyAssign(benchmark::State& state) {
+  std::random_device rd;
+  std::mt19937 rng(rd());
+  IntTable t;
+  std::uniform_int_distribution<uint64_t> dist(0, ~uint64_t{});
+  while (t.size() < state.range(0)) {
+    t.emplace(dist(rng));
+  }
+
+  IntTable t2;
+  for (auto _ : state) {
+    t2 = t;
+    benchmark::DoNotOptimize(t2);
+  }
+}
+BENCHMARK(BM_CopyAssign)->Range(128, 4096);
+
+void BM_NoOpReserveIntTable(benchmark::State& state) {
+  IntTable t;
+  t.reserve(100000);
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(t);
+    t.reserve(100000);
+  }
+}
+BENCHMARK(BM_NoOpReserveIntTable);
+
+void BM_NoOpReserveStringTable(benchmark::State& state) {
+  StringTable t;
+  t.reserve(100000);
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(t);
+    t.reserve(100000);
+  }
+}
+BENCHMARK(BM_NoOpReserveStringTable);
+
+void BM_ReserveIntTable(benchmark::State& state) {
+  int reserve_size = state.range(0);
+  for (auto _ : state) {
+    state.PauseTiming();
+    IntTable t;
+    state.ResumeTiming();
+    benchmark::DoNotOptimize(t);
+    t.reserve(reserve_size);
+  }
+}
+BENCHMARK(BM_ReserveIntTable)->Range(128, 4096);
+
+void BM_ReserveStringTable(benchmark::State& state) {
+  int reserve_size = state.range(0);
+  for (auto _ : state) {
+    state.PauseTiming();
+    StringTable t;
+    state.ResumeTiming();
+    benchmark::DoNotOptimize(t);
+    t.reserve(reserve_size);
+  }
+}
+BENCHMARK(BM_ReserveStringTable)->Range(128, 4096);
+
+void BM_Group_Match(benchmark::State& state) {
+  std::array<ctrl_t, Group::kWidth> group;
+  std::iota(group.begin(), group.end(), -4);
+  Group g{group.data()};
+  h2_t h = 1;
+  for (auto _ : state) {
+    ::benchmark::DoNotOptimize(h);
+    ::benchmark::DoNotOptimize(g.Match(h));
+  }
+}
+BENCHMARK(BM_Group_Match);
+
+void BM_Group_MatchEmpty(benchmark::State& state) {
+  std::array<ctrl_t, Group::kWidth> group;
+  std::iota(group.begin(), group.end(), -4);
+  Group g{group.data()};
+  for (auto _ : state) ::benchmark::DoNotOptimize(g.MatchEmpty());
+}
+BENCHMARK(BM_Group_MatchEmpty);
+
+void BM_Group_MatchEmptyOrDeleted(benchmark::State& state) {
+  std::array<ctrl_t, Group::kWidth> group;
+  std::iota(group.begin(), group.end(), -4);
+  Group g{group.data()};
+  for (auto _ : state) ::benchmark::DoNotOptimize(g.MatchEmptyOrDeleted());
+}
+BENCHMARK(BM_Group_MatchEmptyOrDeleted);
+
+void BM_Group_CountLeadingEmptyOrDeleted(benchmark::State& state) {
+  std::array<ctrl_t, Group::kWidth> group;
+  std::iota(group.begin(), group.end(), -2);
+  Group g{group.data()};
+  for (auto _ : state)
+    ::benchmark::DoNotOptimize(g.CountLeadingEmptyOrDeleted());
+}
+BENCHMARK(BM_Group_CountLeadingEmptyOrDeleted);
+
+void BM_Group_MatchFirstEmptyOrDeleted(benchmark::State& state) {
+  std::array<ctrl_t, Group::kWidth> group;
+  std::iota(group.begin(), group.end(), -2);
+  Group g{group.data()};
+  for (auto _ : state) ::benchmark::DoNotOptimize(*g.MatchEmptyOrDeleted());
+}
+BENCHMARK(BM_Group_MatchFirstEmptyOrDeleted);
+
+void BM_DropDeletes(benchmark::State& state) {
+  constexpr size_t capacity = (1 << 20) - 1;
+  std::vector<ctrl_t> ctrl(capacity + 1 + Group::kWidth);
+  ctrl[capacity] = kSentinel;
+  std::vector<ctrl_t> pattern = {kEmpty, 2, kDeleted, 2, kEmpty, 1, kDeleted};
+  for (size_t i = 0; i != capacity; ++i) {
+    ctrl[i] = pattern[i % pattern.size()];
+  }
+  while (state.KeepRunning()) {
+    state.PauseTiming();
+    std::vector<ctrl_t> ctrl_copy = ctrl;
+    state.ResumeTiming();
+    ConvertDeletedToEmptyAndFullToDeleted(ctrl_copy.data(), capacity);
+    ::benchmark::DoNotOptimize(ctrl_copy[capacity]);
+  }
+}
+BENCHMARK(BM_DropDeletes);
+
+}  // namespace
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+// These methods are here to make it easy to examine the assembly for targeted
+// parts of the API.
+auto CodegenAbslRawHashSetInt64Find(absl::container_internal::IntTable* table,
+                                    int64_t key) -> decltype(table->find(key)) {
+  return table->find(key);
+}
+
+bool CodegenAbslRawHashSetInt64FindNeEnd(
+    absl::container_internal::IntTable* table, int64_t key) {
+  return table->find(key) != table->end();
+}
+
+bool CodegenAbslRawHashSetInt64Contains(
+    absl::container_internal::IntTable* table, int64_t key) {
+  return table->contains(key);
+}
+
+void CodegenAbslRawHashSetInt64Iterate(
+    absl::container_internal::IntTable* table) {
+  for (auto x : *table) benchmark::DoNotOptimize(x);
+}
+
+int odr =
+    (::benchmark::DoNotOptimize(std::make_tuple(
+         &CodegenAbslRawHashSetInt64Find, &CodegenAbslRawHashSetInt64FindNeEnd,
+         &CodegenAbslRawHashSetInt64Contains,
+         &CodegenAbslRawHashSetInt64Iterate)),
+     1);
diff --git a/absl/container/internal/raw_hash_set_probe_benchmark.cc b/absl/container/internal/raw_hash_set_probe_benchmark.cc
new file mode 100644
index 0000000..7169a2e
--- /dev/null
+++ b/absl/container/internal/raw_hash_set_probe_benchmark.cc
@@ -0,0 +1,590 @@
+// 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.
+//
+// Generates probe length statistics for many combinations of key types and key
+// distributions, all using the default hash function for swisstable.
+
+#include <memory>
+#include <regex>  // NOLINT
+#include <vector>
+
+#include "absl/container/flat_hash_map.h"
+#include "absl/container/internal/hash_function_defaults.h"
+#include "absl/container/internal/hashtable_debug.h"
+#include "absl/container/internal/raw_hash_set.h"
+#include "absl/random/distributions.h"
+#include "absl/random/random.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/string_view.h"
+#include "absl/strings/strip.h"
+
+namespace {
+
+enum class OutputStyle { kRegular, kBenchmark };
+
+// The --benchmark command line flag.
+// This is populated from main().
+// When run in "benchmark" mode, we have different output. This allows
+// A/B comparisons with tools like `benchy`.
+absl::string_view benchmarks;
+
+OutputStyle output() {
+  return !benchmarks.empty() ? OutputStyle::kBenchmark : OutputStyle::kRegular;
+}
+
+template <class T>
+struct Policy {
+  using slot_type = T;
+  using key_type = T;
+  using init_type = T;
+
+  template <class allocator_type, class Arg>
+  static void construct(allocator_type* alloc, slot_type* slot,
+                        const Arg& arg) {
+    std::allocator_traits<allocator_type>::construct(*alloc, slot, arg);
+  }
+
+  template <class allocator_type>
+  static void destroy(allocator_type* alloc, slot_type* slot) {
+    std::allocator_traits<allocator_type>::destroy(*alloc, slot);
+  }
+
+  static slot_type& element(slot_type* slot) { return *slot; }
+
+  template <class F, class... Args>
+  static auto apply(F&& f, const slot_type& arg)
+      -> decltype(std::forward<F>(f)(arg, arg)) {
+    return std::forward<F>(f)(arg, arg);
+  }
+};
+
+absl::BitGen& GlobalBitGen() {
+  static auto* value = new absl::BitGen;
+  return *value;
+}
+
+// Keeps a pool of allocations and randomly gives one out.
+// This introduces more randomization to the addresses given to swisstable and
+// should help smooth out this factor from probe length calculation.
+template <class T>
+class RandomizedAllocator {
+ public:
+  using value_type = T;
+
+  RandomizedAllocator() = default;
+  template <typename U>
+  RandomizedAllocator(RandomizedAllocator<U>) {}  // NOLINT
+
+  static T* allocate(size_t n) {
+    auto& pointers = GetPointers(n);
+    // Fill the pool
+    while (pointers.size() < kRandomPool) {
+      pointers.push_back(std::allocator<T>{}.allocate(n));
+    }
+
+    // Choose a random one.
+    size_t i = absl::Uniform<size_t>(GlobalBitGen(), 0, pointers.size());
+    T* result = pointers[i];
+    pointers[i] = pointers.back();
+    pointers.pop_back();
+    return result;
+  }
+
+  static void deallocate(T* p, size_t n) {
+    // Just put it back on the pool. No need to release the memory.
+    GetPointers(n).push_back(p);
+  }
+
+ private:
+  // We keep at least kRandomPool allocations for each size.
+  static constexpr size_t kRandomPool = 20;
+
+  static std::vector<T*>& GetPointers(size_t n) {
+    static auto* m = new absl::flat_hash_map<size_t, std::vector<T*>>();
+    return (*m)[n];
+  }
+};
+
+template <class T>
+struct DefaultHash {
+  using type = absl::container_internal::hash_default_hash<T>;
+};
+
+template <class T>
+using DefaultHashT = typename DefaultHash<T>::type;
+
+template <class T>
+struct Table : absl::container_internal::raw_hash_set<
+                   Policy<T>, DefaultHashT<T>,
+                   absl::container_internal::hash_default_eq<T>,
+                   RandomizedAllocator<T>> {};
+
+struct LoadSizes {
+  size_t min_load;
+  size_t max_load;
+};
+
+LoadSizes GetMinMaxLoadSizes() {
+  static const auto sizes = [] {
+    Table<int> t;
+
+    // First, fill enough to have a good distribution.
+    constexpr size_t kMinSize = 10000;
+    while (t.size() < kMinSize) t.insert(t.size());
+
+    const auto reach_min_load_factor = [&] {
+      const double lf = t.load_factor();
+      while (lf <= t.load_factor()) t.insert(t.size());
+    };
+
+    // Then, insert until we reach min load factor.
+    reach_min_load_factor();
+    const size_t min_load_size = t.size();
+
+    // Keep going until we hit min load factor again, then go back one.
+    t.insert(t.size());
+    reach_min_load_factor();
+
+    return LoadSizes{min_load_size, t.size() - 1};
+  }();
+  return sizes;
+}
+
+struct Ratios {
+  double min_load;
+  double avg_load;
+  double max_load;
+};
+
+// See absl/container/internal/hashtable_debug.h for details on
+// probe length calculation.
+template <class ElemFn>
+Ratios CollectMeanProbeLengths() {
+  const auto min_max_sizes = GetMinMaxLoadSizes();
+
+  ElemFn elem;
+  using Key = decltype(elem());
+  Table<Key> t;
+
+  Ratios result;
+  while (t.size() < min_max_sizes.min_load) t.insert(elem());
+  result.min_load =
+      absl::container_internal::GetHashtableDebugProbeSummary(t).mean;
+
+  while (t.size() < (min_max_sizes.min_load + min_max_sizes.max_load) / 2)
+    t.insert(elem());
+  result.avg_load =
+      absl::container_internal::GetHashtableDebugProbeSummary(t).mean;
+
+  while (t.size() < min_max_sizes.max_load) t.insert(elem());
+  result.max_load =
+      absl::container_internal::GetHashtableDebugProbeSummary(t).mean;
+
+  return result;
+}
+
+template <int Align>
+uintptr_t PointerForAlignment() {
+  alignas(Align) static constexpr uintptr_t kInitPointer = 0;
+  return reinterpret_cast<uintptr_t>(&kInitPointer);
+}
+
+// This incomplete type is used for testing hash of pointers of different
+// alignments.
+// NOTE: We are generating invalid pointer values on the fly with
+// reinterpret_cast. There are not "safely derived" pointers so using them is
+// technically UB. It is unlikely to be a problem, though.
+template <int Align>
+struct Ptr;
+
+template <int Align>
+Ptr<Align>* MakePtr(uintptr_t v) {
+  if (sizeof(v) == 8) {
+    constexpr int kCopyBits = 16;
+    // Ensure high bits are all the same.
+    v = static_cast<uintptr_t>(static_cast<intptr_t>(v << kCopyBits) >>
+                               kCopyBits);
+  }
+  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;
+  }
+};
+
+constexpr char kStringFormat[] = "/path/to/file/name-%07d-of-9999999.txt";
+
+template <bool small>
+struct String {
+  std::string value;
+  static std::string Make(uint32_t v) {
+    return {small ? absl::StrCat(v) : absl::StrFormat(kStringFormat, v)};
+  }
+};
+
+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++; }
+  mutable T current{};
+};
+
+template <int Align>
+struct Sequential<Ptr<Align>*> {
+  Ptr<Align>* operator()() const {
+    auto* result = MakePtr<Align>(current);
+    current += Align;
+    return result;
+  }
+  mutable uintptr_t current = PointerForAlignment<Align>();
+};
+
+
+template <bool small>
+struct Sequential<String<small>> {
+  std::string operator()() const { return String<small>::Make(current++); }
+  mutable uint32_t current = 0;
+};
+
+template <class T, class U>
+struct Sequential<std::pair<T, U>> {
+  mutable Sequential<T> tseq;
+  mutable Sequential<U> useq;
+
+  using RealT = decltype(tseq());
+  using RealU = decltype(useq());
+
+  mutable std::vector<RealT> ts;
+  mutable std::vector<RealU> us;
+  mutable size_t ti = 0, ui = 0;
+
+  std::pair<RealT, RealU> operator()() const {
+    std::pair<RealT, RealU> value{get_t(), get_u()};
+    if (ti == 0) {
+      ti = ui + 1;
+      ui = 0;
+    } else {
+      --ti;
+      ++ui;
+    }
+    return value;
+  }
+
+  RealT get_t() const {
+    while (ti >= ts.size()) ts.push_back(tseq());
+    return ts[ti];
+  }
+
+  RealU get_u() const {
+    while (ui >= us.size()) us.push_back(useq());
+    return us[ui];
+  }
+};
+
+template <class T, int percent_skip>
+struct AlmostSequential {
+  mutable Sequential<T> current;
+
+  auto operator()() const -> decltype(current()) {
+    while (absl::Uniform(GlobalBitGen(), 0.0, 1.0) <= percent_skip / 100.)
+      current();
+    return current();
+  }
+};
+
+struct Uniform {
+  template <typename T>
+  T operator()(T) const {
+    return absl::Uniform<T>(absl::IntervalClosed, GlobalBitGen(), T{0}, ~T{0});
+  }
+};
+
+struct Gaussian {
+  template <typename T>
+  T operator()(T) const {
+    double d;
+    do {
+      d = absl::Gaussian<double>(GlobalBitGen(), 1e6, 1e4);
+    } while (d <= 0 || d > std::numeric_limits<T>::max() / 2);
+    return static_cast<T>(d);
+  }
+};
+
+struct Zipf {
+  template <typename T>
+  T operator()(T) const {
+    return absl::Zipf<T>(GlobalBitGen(), std::numeric_limits<T>::max(), 1.6);
+  }
+};
+
+template <class T, class Dist>
+struct Random {
+  T operator()() const { return Dist{}(T{}); }
+};
+
+template <class Dist, int Align>
+struct Random<Ptr<Align>*, Dist> {
+  Ptr<Align>* operator()() const {
+    return MakePtr<Align>(Random<uintptr_t, Dist>{}() * Align);
+  }
+};
+
+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, bool small>
+struct Random<String<small>, Dist> {
+  std::string operator()() const {
+    return String<small>::Make(Random<uint32_t, Dist>{}());
+  }
+};
+
+template <class T, class U, class Dist>
+struct Random<std::pair<T, U>, Dist> {
+  auto operator()() const
+      -> decltype(std::make_pair(Random<T, Dist>{}(), Random<U, Dist>{}())) {
+    return std::make_pair(Random<T, Dist>{}(), Random<U, Dist>{}());
+  }
+};
+
+template <typename>
+std::string Name();
+
+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 <bool small>
+std::string Name(String<small>*) {
+  return small ? "StrS" : "StrL";
+}
+
+template <class T, class U>
+std::string Name(std::pair<T, U>*) {
+  if (output() == OutputStyle::kBenchmark)
+    return absl::StrCat("P_", Name<T>(), "_", Name<U>());
+  return absl::StrCat("P<", Name<T>(), ",", Name<U>(), ">");
+}
+
+template <class T>
+std::string Name(Sequential<T>*) {
+  return "Sequential";
+}
+
+template <class T, int P>
+std::string Name(AlmostSequential<T, P>*) {
+  return absl::StrCat("AlmostSeq_", P);
+}
+
+template <class T>
+std::string Name(Random<T, Uniform>*) {
+  return "UnifRand";
+}
+
+template <class T>
+std::string Name(Random<T, Gaussian>*) {
+  return "GausRand";
+}
+
+template <class T>
+std::string Name(Random<T, Zipf>*) {
+  return "ZipfRand";
+}
+
+template <typename T>
+std::string Name() {
+  return Name(static_cast<T*>(nullptr));
+}
+
+constexpr int kNameWidth = 15;
+constexpr int kDistWidth = 16;
+
+bool CanRunBenchmark(absl::string_view name) {
+  static std::regex* const filter = []() -> std::regex* {
+    return benchmarks.empty() || benchmarks == "all"
+               ? nullptr
+               : new std::regex(std::string(benchmarks));
+  }();
+  return filter == nullptr || std::regex_search(std::string(name), *filter);
+}
+
+struct Result {
+  std::string name;
+  std::string dist_name;
+  Ratios ratios;
+};
+
+template <typename T, typename Dist>
+void RunForTypeAndDistribution(std::vector<Result>& results) {
+  std::string name = absl::StrCat(Name<T>(), "/", Name<Dist>());
+  // We have to check against all three names (min/avg/max) before we run it.
+  // If any of them is enabled, we run it.
+  if (!CanRunBenchmark(absl::StrCat(name, "/min")) &&
+      !CanRunBenchmark(absl::StrCat(name, "/avg")) &&
+      !CanRunBenchmark(absl::StrCat(name, "/max"))) {
+    return;
+  }
+  results.push_back({Name<T>(), Name<Dist>(), CollectMeanProbeLengths<Dist>()});
+}
+
+template <class T>
+void RunForType(std::vector<Result>& results) {
+  RunForTypeAndDistribution<T, Sequential<T>>(results);
+  RunForTypeAndDistribution<T, AlmostSequential<T, 20>>(results);
+  RunForTypeAndDistribution<T, AlmostSequential<T, 50>>(results);
+  RunForTypeAndDistribution<T, Random<T, Uniform>>(results);
+#ifdef NDEBUG
+  // Disable these in non-opt mode because they take too long.
+  RunForTypeAndDistribution<T, Random<T, Gaussian>>(results);
+  RunForTypeAndDistribution<T, Random<T, Zipf>>(results);
+#endif  // NDEBUG
+}
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  // Parse the benchmark flags. Ignore all of them except the regex pattern.
+  for (int i = 1; i < argc; ++i) {
+    absl::string_view arg = argv[i];
+    const auto next = [&] { return argv[std::min(i + 1, argc - 1)]; };
+
+    if (absl::ConsumePrefix(&arg, "--benchmark_filter")) {
+      if (arg == "") {
+        // --benchmark_filter X
+        benchmarks = next();
+      } else if (absl::ConsumePrefix(&arg, "=")) {
+        // --benchmark_filter=X
+        benchmarks = arg;
+      }
+    }
+
+    // Any --benchmark flag turns on the mode.
+    if (absl::ConsumePrefix(&arg, "--benchmark")) {
+      if (benchmarks.empty()) benchmarks="all";
+    }
+  }
+
+  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<true>>(results);
+  RunForType<String<false>>(results);
+  RunForType<std::pair<uint64_t, String<true>>>(results);
+  RunForType<std::pair<String<true>, uint64_t>>(results);
+  RunForType<std::pair<uint64_t, String<false>>>(results);
+  RunForType<std::pair<String<false>, uint64_t>>(results);
+
+  switch (output()) {
+    case OutputStyle::kRegular:
+      absl::PrintF("%-*s%-*s       Min       Avg       Max\n%s\n", kNameWidth,
+                   "Type", kDistWidth, "Distribution",
+                   std::string(kNameWidth + kDistWidth + 10 * 3, '-'));
+      for (const auto& result : results) {
+        absl::PrintF("%-*s%-*s  %8.4f  %8.4f  %8.4f\n", kNameWidth, result.name,
+                     kDistWidth, result.dist_name, result.ratios.min_load,
+                     result.ratios.avg_load, result.ratios.max_load);
+      }
+      break;
+    case OutputStyle::kBenchmark: {
+      absl::PrintF("{\n");
+      absl::PrintF("  \"benchmarks\": [\n");
+      absl::string_view comma;
+      for (const auto& result : results) {
+        auto print = [&](absl::string_view stat, double Ratios::*val) {
+          std::string name =
+              absl::StrCat(result.name, "/", result.dist_name, "/", stat);
+          // Check the regex again. We might had have enabled only one of the
+          // stats for the benchmark.
+          if (!CanRunBenchmark(name)) return;
+          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("      \"iterations\": 1,\n");
+          absl::PrintF("      \"name\": \"%s\",\n", name);
+          absl::PrintF("      \"time_unit\": \"ns\"\n");
+          absl::PrintF("    }\n");
+          comma = ",";
+        };
+        print("min", &Ratios::min_load);
+        print("avg", &Ratios::avg_load);
+        print("max", &Ratios::max_load);
+      }
+      absl::PrintF("  ],\n");
+      absl::PrintF("  \"context\": {\n");
+      absl::PrintF("  }\n");
+      absl::PrintF("}\n");
+      break;
+    }
+  }
+
+  return 0;
+}
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc
index a96ae68..7dac65a 100644
--- a/absl/container/internal/raw_hash_set_test.cc
+++ b/absl/container/internal/raw_hash_set_test.cc
@@ -14,6 +14,7 @@
 
 #include "absl/container/internal/raw_hash_set.h"
 
+#include <atomic>
 #include <cmath>
 #include <cstdint>
 #include <deque>
@@ -22,10 +23,13 @@
 #include <numeric>
 #include <random>
 #include <string>
+#include <unordered_map>
+#include <unordered_set>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "absl/base/attributes.h"
+#include "absl/base/config.h"
 #include "absl/base/internal/cycleclock.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/container/internal/container_memory.h"
@@ -47,11 +51,10 @@
 
 namespace {
 
-using ::testing::DoubleNear;
 using ::testing::ElementsAre;
+using ::testing::Eq;
 using ::testing::Ge;
 using ::testing::Lt;
-using ::testing::Optional;
 using ::testing::Pair;
 using ::testing::UnorderedElementsAre;
 
@@ -74,8 +77,14 @@
   for (size_t growth = 0; growth < 10000; ++growth) {
     SCOPED_TRACE(growth);
     size_t capacity = NormalizeCapacity(GrowthToLowerboundCapacity(growth));
-    // The capacity is large enough for `growth`
+    // The capacity is large enough for `growth`.
     EXPECT_THAT(CapacityToGrowth(capacity), Ge(growth));
+    // For (capacity+1) < kWidth, growth should equal capacity.
+    if (capacity + 1 < Group::kWidth) {
+      EXPECT_THAT(CapacityToGrowth(capacity), Eq(capacity));
+    } else {
+      EXPECT_THAT(CapacityToGrowth(capacity), Lt(capacity));
+    }
     if (growth != 0 && capacity > 1) {
       // There is no smaller capacity that works.
       EXPECT_THAT(CapacityToGrowth(capacity / 2), Lt(growth));
@@ -249,25 +258,43 @@
   }
 }
 
-struct IntPolicy {
-  using slot_type = int64_t;
-  using key_type = int64_t;
-  using init_type = int64_t;
+template <class T>
+struct ValuePolicy {
+  using slot_type = T;
+  using key_type = T;
+  using init_type = T;
 
-  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) {
-    *new_slot = *old_slot;
+  template <class Allocator, class... Args>
+  static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
+    absl::allocator_traits<Allocator>::construct(*alloc, slot,
+                                                 std::forward<Args>(args)...);
   }
 
-  static int64_t& element(slot_type* slot) { return *slot; }
+  template <class Allocator>
+  static void destroy(Allocator* alloc, slot_type* slot) {
+    absl::allocator_traits<Allocator>::destroy(*alloc, slot);
+  }
 
-  template <class F>
-  static auto apply(F&& f, int64_t x) -> decltype(std::forward<F>(f)(x, x)) {
-    return std::forward<F>(f)(x, x);
+  template <class Allocator>
+  static void transfer(Allocator* alloc, slot_type* new_slot,
+                       slot_type* old_slot) {
+    construct(alloc, new_slot, std::move(*old_slot));
+    destroy(alloc, old_slot);
+  }
+
+  static T& element(slot_type* slot) { return *slot; }
+
+  template <class F, class... Args>
+  static decltype(absl::container_internal::DecomposeValue(
+      std::declval<F>(), std::declval<Args>()...))
+  apply(F&& f, Args&&... args) {
+    return absl::container_internal::DecomposeValue(
+        std::forward<F>(f), std::forward<Args>(args)...);
   }
 };
 
+using IntPolicy = ValuePolicy<int64_t>;
+
 class StringPolicy {
   template <class F, class K, class V,
             class = typename std::enable_if<
@@ -392,6 +419,13 @@
     size_t growth_left;
     void* infoz;
   };
+  struct MockTableInfozDisabled {
+    void* ctrl;
+    void* slots;
+    size_t size;
+    size_t capacity;
+    size_t growth_left;
+  };
   struct StatelessHash {
     size_t operator()(absl::string_view) const { return 0; }
   };
@@ -399,17 +433,27 @@
     size_t dummy;
   };
 
-  EXPECT_EQ(
-      sizeof(MockTable),
-      sizeof(
-          raw_hash_set<StringPolicy, StatelessHash,
-                       std::equal_to<absl::string_view>, std::allocator<int>>));
+  if (std::is_empty<HashtablezInfoHandle>::value) {
+    EXPECT_EQ(sizeof(MockTableInfozDisabled),
+              sizeof(raw_hash_set<StringPolicy, StatelessHash,
+                                  std::equal_to<absl::string_view>,
+                                  std::allocator<int>>));
 
-  EXPECT_EQ(
-      sizeof(MockTable) + sizeof(StatefulHash),
-      sizeof(
-          raw_hash_set<StringPolicy, StatefulHash,
-                       std::equal_to<absl::string_view>, std::allocator<int>>));
+    EXPECT_EQ(sizeof(MockTableInfozDisabled) + sizeof(StatefulHash),
+              sizeof(raw_hash_set<StringPolicy, StatefulHash,
+                                  std::equal_to<absl::string_view>,
+                                  std::allocator<int>>));
+  } else {
+    EXPECT_EQ(sizeof(MockTable),
+              sizeof(raw_hash_set<StringPolicy, StatelessHash,
+                                  std::equal_to<absl::string_view>,
+                                  std::allocator<int>>));
+
+    EXPECT_EQ(sizeof(MockTable) + sizeof(StatefulHash),
+              sizeof(raw_hash_set<StringPolicy, StatefulHash,
+                                  std::equal_to<absl::string_view>,
+                                  std::allocator<int>>));
+  }
 }
 
 TEST(Table, Empty) {
@@ -846,7 +890,8 @@
 std::vector<int64_t> CollectBadMergeKeys(size_t N) {
   static constexpr int kGroupSize = Group::kWidth - 1;
 
-  auto topk_range = [](size_t b, size_t e, IntTable* t) -> std::vector<int64_t> {
+  auto topk_range = [](size_t b, size_t e,
+                       IntTable* t) -> std::vector<int64_t> {
     for (size_t i = b; i != e; ++i) {
       t->emplace(i);
     }
@@ -1000,8 +1045,8 @@
 // 1. Create new table and reserve it to keys.size() * 2
 // 2. Insert all keys xored with seed
 // 3. Collect ProbeStats from final table.
-ProbeStats CollectProbeStatsOnKeysXoredWithSeed(const std::vector<int64_t>& keys,
-                                                size_t num_iters) {
+ProbeStats CollectProbeStatsOnKeysXoredWithSeed(
+    const std::vector<int64_t>& keys, size_t num_iters) {
   const size_t reserve_size = keys.size() * 2;
 
   ProbeStats stats;
@@ -1655,6 +1700,38 @@
   EXPECT_THAT(t2, UnorderedElementsAre(Pair("0", "~0")));
 }
 
+TEST(Table, IteratorEmplaceConstructibleRequirement) {
+  struct Value {
+    explicit Value(absl::string_view view) : value(view) {}
+    std::string value;
+
+    bool operator==(const Value& other) const { return value == other.value; }
+  };
+  struct H {
+    size_t operator()(const Value& v) const {
+      return absl::Hash<std::string>{}(v.value);
+    }
+  };
+
+  struct Table : raw_hash_set<ValuePolicy<Value>, H, std::equal_to<Value>,
+                              std::allocator<Value>> {
+    using Base = typename Table::raw_hash_set;
+    using Base::Base;
+  };
+
+  std::string input[3]{"A", "B", "C"};
+
+  Table t(std::begin(input), std::end(input));
+  EXPECT_THAT(t, UnorderedElementsAre(Value{"A"}, Value{"B"}, Value{"C"}));
+
+  input[0] = "D";
+  input[1] = "E";
+  input[2] = "F";
+  t.insert(std::begin(input), std::end(input));
+  EXPECT_THAT(t, UnorderedElementsAre(Value{"A"}, Value{"B"}, Value{"C"},
+                                      Value{"D"}, Value{"E"}, Value{"F"}));
+}
+
 TEST(Nodes, EmptyNodeType) {
   using node_type = StringTable::node_type;
   node_type n;
@@ -1666,9 +1743,9 @@
 }
 
 TEST(Nodes, ExtractInsert) {
-  constexpr char k0[] = "Very long std::string zero.";
-  constexpr char k1[] = "Very long std::string one.";
-  constexpr char k2[] = "Very long std::string two.";
+  constexpr char k0[] = "Very long string zero.";
+  constexpr char k1[] = "Very long string one.";
+  constexpr char k2[] = "Very long string two.";
   StringTable t = {{k0, ""}, {k1, ""}, {k2, ""}};
   EXPECT_THAT(t,
               UnorderedElementsAre(Pair(k0, ""), Pair(k1, ""), Pair(k2, "")));
@@ -1709,6 +1786,26 @@
   EXPECT_FALSE(node);
 }
 
+TEST(Nodes, HintInsert) {
+  IntTable t = {1, 2, 3};
+  auto node = t.extract(1);
+  EXPECT_THAT(t, UnorderedElementsAre(2, 3));
+  auto it = t.insert(t.begin(), std::move(node));
+  EXPECT_THAT(t, UnorderedElementsAre(1, 2, 3));
+  EXPECT_EQ(*it, 1);
+  EXPECT_FALSE(node);
+
+  node = t.extract(2);
+  EXPECT_THAT(t, UnorderedElementsAre(1, 3));
+  // reinsert 2 to make the next insert fail.
+  t.insert(2);
+  EXPECT_THAT(t, UnorderedElementsAre(1, 2, 3));
+  it = t.insert(t.begin(), std::move(node));
+  EXPECT_EQ(*it, 2);
+  // The node was not emptied by the insert call.
+  EXPECT_TRUE(node);
+}
+
 IntTable MakeSimpleTable(size_t size) {
   IntTable t;
   while (t.size() < size) t.insert(t.size());
@@ -1791,11 +1888,11 @@
 
   IntTable t;
   // Extra simple "regexp" as regexp support is highly varied across platforms.
-  constexpr char kDeathMsg[] = "IsFull";
+  constexpr char kDeathMsg[] = "Invalid operation on iterator";
   EXPECT_DEATH_IF_SUPPORTED(t.erase(t.end()), kDeathMsg);
 }
 
-#if defined(ABSL_HASHTABLEZ_SAMPLE)
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
 TEST(RawHashSamplerTest, Sample) {
   // Enable the feature even if the prod default is off.
   SetHashtablezEnabled(true);
@@ -1803,20 +1900,36 @@
 
   auto& sampler = HashtablezSampler::Global();
   size_t start_size = 0;
-  start_size += sampler.Iterate([&](const HashtablezInfo&) { ++start_size; });
+  std::unordered_set<const HashtablezInfo*> preexisting_info;
+  start_size += sampler.Iterate([&](const HashtablezInfo& info) {
+    preexisting_info.insert(&info);
+    ++start_size;
+  });
 
   std::vector<IntTable> tables;
   for (int i = 0; i < 1000000; ++i) {
     tables.emplace_back();
     tables.back().insert(1);
+    tables.back().insert(i % 5);
   }
   size_t end_size = 0;
-  end_size += sampler.Iterate([&](const HashtablezInfo&) { ++end_size; });
+  std::unordered_map<size_t, int> observed_checksums;
+  end_size += sampler.Iterate([&](const HashtablezInfo& info) {
+    if (preexisting_info.count(&info) == 0) {
+      observed_checksums[info.hashes_bitwise_xor.load(
+          std::memory_order_relaxed)]++;
+    }
+    ++end_size;
+  });
 
   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);
+  }
 }
-#endif  // ABSL_HASHTABLEZ_SAMPLER
+#endif  // ABSL_INTERNAL_HASHTABLEZ_SAMPLE
 
 TEST(RawHashSamplerTest, DoNotSampleCustomAllocators) {
   // Enable the feature even if the prod default is off.
@@ -1839,7 +1952,7 @@
               0.00, 0.001);
 }
 
-#ifdef ADDRESS_SANITIZER
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
 TEST(Sanitizer, PoisoningUnused) {
   IntTable t;
   t.reserve(5);
@@ -1863,7 +1976,7 @@
   t.erase(0);
   EXPECT_TRUE(__asan_address_is_poisoned(&v));
 }
-#endif  // ADDRESS_SANITIZER
+#endif  // ABSL_HAVE_ADDRESS_SANITIZER
 
 }  // namespace
 }  // namespace container_internal
diff --git a/absl/container/internal/unordered_map_constructor_test.h b/absl/container/internal/unordered_map_constructor_test.h
index 76ee95e..3f90ad7 100644
--- a/absl/container/internal/unordered_map_constructor_test.h
+++ b/absl/container/internal/unordered_map_constructor_test.h
@@ -16,6 +16,7 @@
 #define ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_CONSTRUCTOR_TEST_H_
 
 #include <algorithm>
+#include <unordered_map>
 #include <vector>
 
 #include "gmock/gmock.h"
diff --git a/absl/container/internal/unordered_map_modifiers_test.h b/absl/container/internal/unordered_map_modifiers_test.h
index b8c513f..8c9ca77 100644
--- a/absl/container/internal/unordered_map_modifiers_test.h
+++ b/absl/container/internal/unordered_map_modifiers_test.h
@@ -286,6 +286,8 @@
   }
 };
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UniquePtrModifiersTest);
+
 TYPED_TEST_SUITE_P(UniquePtrModifiersTest);
 
 // Test that we do not move from rvalue arguments if an insertion does not
diff --git a/absl/container/node_hash_map.h b/absl/container/node_hash_map.h
index fccea18..7a39f62 100644
--- a/absl/container/node_hash_map.h
+++ b/absl/container/node_hash_map.h
@@ -225,7 +225,8 @@
   //
   // size_type erase(const key_type& key):
   //
-  //   Erases the element with the matching key, if it exists.
+  //   Erases the element with the matching key, if it exists, returning the
+  //   number of elements erased (0 or 1).
   using Base::erase;
 
   // node_hash_map::insert()
@@ -374,6 +375,11 @@
   //   key value and returns a node handle owning that extracted data. If the
   //   `node_hash_map` does not contain an element with a matching key, this
   //   function returns an empty node handle.
+  //
+  // NOTE: when compiled in an earlier version of C++ than C++17,
+  // `node_type::key()` returns a const reference to the key instead of a
+  // mutable reference. We cannot safely return a mutable reference without
+  // std::launder (which is not available before C++17).
   using Base::extract;
 
   // node_hash_map::merge()
@@ -514,12 +520,6 @@
   //
   // Returns the function used for comparing keys equality.
   using Base::key_eq;
-
-  ABSL_DEPRECATED("Call `hash_function()` instead.")
-  typename Base::hasher hash_funct() { return this->hash_function(); }
-
-  ABSL_DEPRECATED("Call `rehash()` instead.")
-  void resize(typename Base::size_type hint) { this->rehash(hint); }
 };
 
 // erase_if(node_hash_map<>, Pred)
diff --git a/absl/container/node_hash_map_test.cc b/absl/container/node_hash_map_test.cc
index 5d74b81..8f59a1e 100644
--- a/absl/container/node_hash_map_test.cc
+++ b/absl/container/node_hash_map_test.cc
@@ -254,6 +254,21 @@
   }
 }
 
+// This test requires std::launder for mutable key access in node handles.
+#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
+TEST(NodeHashMap, NodeHandleMutableKeyAccess) {
+  node_hash_map<std::string, std::string> map;
+
+  map["key1"] = "mapped";
+
+  auto nh = map.extract(map.begin());
+  nh.key().resize(3);
+  map.insert(std::move(nh));
+
+  EXPECT_THAT(map, testing::ElementsAre(Pair("key", "mapped")));
+}
+#endif
+
 }  // namespace
 }  // namespace container_internal
 ABSL_NAMESPACE_END
diff --git a/absl/container/node_hash_set.h b/absl/container/node_hash_set.h
index ad54b6d..93b15f4 100644
--- a/absl/container/node_hash_set.h
+++ b/absl/container/node_hash_set.h
@@ -18,7 +18,7 @@
 //
 // An `absl::node_hash_set<T>` is an unordered associative container designed to
 // be a more efficient replacement for `std::unordered_set`. Like
-// `unordered_set`, search, insertion, and deletion of map elements can be done
+// `unordered_set`, search, insertion, and deletion of set elements can be done
 // as an `O(1)` operation. However, `node_hash_set` (and other unordered
 // associative containers known as the collection of Abseil "Swiss tables")
 // contain other optimizations that result in both memory and computation
@@ -60,7 +60,7 @@
 // following notable differences:
 //
 // * Supports heterogeneous lookup, through `find()`, `operator[]()` and
-//   `insert()`, provided that the map is provided a compatible heterogeneous
+//   `insert()`, provided that the set is provided a compatible heterogeneous
 //   hashing function and equality operator.
 // * Contains a `capacity()` member function indicating the number of element
 //   slots (open, deleted, and empty) within the hash set.
@@ -76,13 +76,13 @@
 // Example:
 //
 //   // Create a node hash set of three strings
-//   absl::node_hash_map<std::string, std::string> ducks =
+//   absl::node_hash_set<std::string> ducks =
 //     {"huey", "dewey", "louie"};
 //
-//  // Insert a new element into the node hash map
-//  ducks.insert("donald"};
+//  // Insert a new element into the node hash set
+//  ducks.insert("donald");
 //
-//  // Force a rehash of the node hash map
+//  // Force a rehash of the node hash set
 //  ducks.rehash(0);
 //
 //  // See if "dewey" is present
@@ -100,7 +100,7 @@
  public:
   // Constructors and Assignment Operators
   //
-  // A node_hash_set supports the same overload set as `std::unordered_map`
+  // A node_hash_set supports the same overload set as `std::unordered_set`
   // for construction and assignment:
   //
   // *  Default constructor
@@ -167,7 +167,7 @@
   // available within the `node_hash_set`.
   //
   // NOTE: this member function is particular to `absl::node_hash_set` and is
-  // not provided in the `std::unordered_map` API.
+  // not provided in the `std::unordered_set` API.
   using Base::capacity;
 
   // node_hash_set::empty()
@@ -208,7 +208,7 @@
   //   `void`.
   //
   //   NOTE: this return behavior is different than that of STL containers in
-  //   general and `std::unordered_map` in particular.
+  //   general and `std::unordered_set` in particular.
   //
   // iterator erase(const_iterator first, const_iterator last):
   //
@@ -217,7 +217,8 @@
   //
   // size_type erase(const key_type& key):
   //
-  //   Erases the element with the matching key, if it exists.
+  //   Erases the element with the matching key, if it exists, returning the
+  //   number of elements erased (0 or 1).
   using Base::erase;
 
   // node_hash_set::insert()
@@ -313,7 +314,7 @@
 
   // node_hash_set::merge()
   //
-  // Extracts elements from a given `source` flat hash map into this
+  // Extracts elements from a given `source` node hash set into this
   // `node_hash_set`. If the destination `node_hash_set` already contains an
   // element with an equivalent key, that element is not extracted.
   using Base::merge;
@@ -321,15 +322,15 @@
   // node_hash_set::swap(node_hash_set& other)
   //
   // Exchanges the contents of this `node_hash_set` with those of the `other`
-  // flat hash map, avoiding invocation of any move, copy, or swap operations on
+  // node hash set, avoiding invocation of any move, copy, or swap operations on
   // individual elements.
   //
   // All iterators and references on the `node_hash_set` remain valid, excepting
   // for the past-the-end iterator, which is invalidated.
   //
-  // `swap()` requires that the flat hash set's hashing and key equivalence
+  // `swap()` requires that the node hash set's hashing and key equivalence
   // functions be Swappable, and are exchaged using unqualified calls to
-  // non-member `swap()`. If the map's allocator has
+  // non-member `swap()`. If the set's allocator has
   // `std::allocator_traits<allocator_type>::propagate_on_container_swap::value`
   // set to `true`, the allocators are also exchanged using an unqualified call
   // to non-member `swap()`; otherwise, the allocators are not swapped.
@@ -384,14 +385,14 @@
   // node_hash_set::bucket_count()
   //
   // Returns the number of "buckets" within the `node_hash_set`. Note that
-  // because a flat hash map contains all elements within its internal storage,
+  // because a node hash set contains all elements within its internal storage,
   // this value simply equals the current capacity of the `node_hash_set`.
   using Base::bucket_count;
 
   // node_hash_set::load_factor()
   //
   // Returns the current load factor of the `node_hash_set` (the average number
-  // of slots occupied with a value within the hash map).
+  // of slots occupied with a value within the hash set).
   using Base::load_factor;
 
   // node_hash_set::max_load_factor()
@@ -427,12 +428,6 @@
   //
   // Returns the function used for comparing keys equality.
   using Base::key_eq;
-
-  ABSL_DEPRECATED("Call `hash_function()` instead.")
-  typename Base::hasher hash_funct() { return this->hash_function(); }
-
-  ABSL_DEPRECATED("Call `rehash()` instead.")
-  void resize(typename Base::size_type hint) { this->rehash(hint); }
 };
 
 // erase_if(node_hash_set<>, Pred)
diff --git a/absl/copts/AbseilConfigureCopts.cmake b/absl/copts/AbseilConfigureCopts.cmake
index 77d4ace..942ce90 100644
--- a/absl/copts/AbseilConfigureCopts.cmake
+++ b/absl/copts/AbseilConfigureCopts.cmake
@@ -12,16 +12,16 @@
   set(ABSL_BUILD_DLL FALSE)
 endif()
 
-if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "AMD64")
+if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64")
   if (MSVC)
     set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_MSVC_X64_FLAGS}")
   else()
     set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_X64_FLAGS}")
   endif()
-elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm.*|aarch64")
-  if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
+elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm.*|aarch64")
+  if (CMAKE_SIZEOF_VOID_P STREQUAL "8")
     set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_ARM64_FLAGS}")
-  elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4")
+  elseif(CMAKE_SIZEOF_VOID_P STREQUAL "4")
     set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_ARM32_FLAGS}")
   else()
     message(WARNING "Value of CMAKE_SIZEOF_VOID_P (${CMAKE_SIZEOF_VOID_P}) is not supported.")
@@ -32,20 +32,18 @@
 endif()
 
 
-if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
   set(ABSL_DEFAULT_COPTS "${ABSL_GCC_FLAGS}")
   set(ABSL_TEST_COPTS "${ABSL_GCC_FLAGS};${ABSL_GCC_TEST_FLAGS}")
-elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
-  # MATCHES so we get both Clang and AppleClang
+elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")  # MATCHES so we get both Clang and AppleClang
   if(MSVC)
     # clang-cl is half MSVC, half LLVM
     set(ABSL_DEFAULT_COPTS "${ABSL_CLANG_CL_FLAGS}")
     set(ABSL_TEST_COPTS "${ABSL_CLANG_CL_FLAGS};${ABSL_CLANG_CL_TEST_FLAGS}")
-    set(ABSL_DEFAULT_LINKOPTS "${ABSL_MSVC_LINKOPTS}")
   else()
     set(ABSL_DEFAULT_COPTS "${ABSL_LLVM_FLAGS}")
     set(ABSL_TEST_COPTS "${ABSL_LLVM_FLAGS};${ABSL_LLVM_TEST_FLAGS}")
-    if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+    if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
       # AppleClang doesn't have lsan
       # https://developer.apple.com/documentation/code_diagnostics
       if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5)
@@ -54,7 +52,7 @@
       endif()
     endif()
   endif()
-elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
   set(ABSL_DEFAULT_COPTS "${ABSL_MSVC_FLAGS}")
   set(ABSL_TEST_COPTS "${ABSL_MSVC_FLAGS};${ABSL_MSVC_TEST_FLAGS}")
   set(ABSL_DEFAULT_LINKOPTS "${ABSL_MSVC_LINKOPTS}")
@@ -64,11 +62,4 @@
   set(ABSL_TEST_COPTS "")
 endif()
 
-if("${CMAKE_CXX_STANDARD}" EQUAL 98)
-  message(FATAL_ERROR "Abseil requires at least C++11")
-elseif(NOT "${CMAKE_CXX_STANDARD}")
-  message(STATUS "No CMAKE_CXX_STANDARD set, assuming 11")
-  set(ABSL_CXX_STANDARD 11)
-else()
-  set(ABSL_CXX_STANDARD "${CMAKE_CXX_STANDARD}")
-endif()
+set(ABSL_CXX_STANDARD "${CMAKE_CXX_STANDARD}")
diff --git a/absl/copts/GENERATED_AbseilCopts.cmake b/absl/copts/GENERATED_AbseilCopts.cmake
index 7ef6339..51742c9 100644
--- a/absl/copts/GENERATED_AbseilCopts.cmake
+++ b/absl/copts/GENERATED_AbseilCopts.cmake
@@ -5,47 +5,6 @@
 
 list(APPEND ABSL_CLANG_CL_FLAGS
     "/W3"
-    "-Wno-c++98-compat-pedantic"
-    "-Wno-conversion"
-    "-Wno-covered-switch-default"
-    "-Wno-deprecated"
-    "-Wno-disabled-macro-expansion"
-    "-Wno-double-promotion"
-    "-Wno-comma"
-    "-Wno-extra-semi"
-    "-Wno-extra-semi-stmt"
-    "-Wno-packed"
-    "-Wno-padded"
-    "-Wno-sign-compare"
-    "-Wno-float-conversion"
-    "-Wno-float-equal"
-    "-Wno-format-nonliteral"
-    "-Wno-gcc-compat"
-    "-Wno-global-constructors"
-    "-Wno-exit-time-destructors"
-    "-Wno-non-modular-include-in-module"
-    "-Wno-old-style-cast"
-    "-Wno-range-loop-analysis"
-    "-Wno-reserved-id-macro"
-    "-Wno-shorten-64-to-32"
-    "-Wno-switch-enum"
-    "-Wno-thread-safety-negative"
-    "-Wno-unknown-warning-option"
-    "-Wno-unreachable-code"
-    "-Wno-unused-macros"
-    "-Wno-weak-vtables"
-    "-Wno-zero-as-null-pointer-constant"
-    "-Wbitfield-enum-conversion"
-    "-Wbool-conversion"
-    "-Wconstant-conversion"
-    "-Wenum-conversion"
-    "-Wint-conversion"
-    "-Wliteral-conversion"
-    "-Wnon-literal-null-conversion"
-    "-Wnull-conversion"
-    "-Wobjc-literal-conversion"
-    "-Wno-sign-conversion"
-    "-Wstring-conversion"
     "/DNOMINMAX"
     "/DWIN32_LEAN_AND_MEAN"
     "/D_CRT_SECURE_NO_WARNINGS"
@@ -78,16 +37,17 @@
     "-Wextra"
     "-Wcast-qual"
     "-Wconversion-null"
+    "-Wformat-security"
     "-Wmissing-declarations"
     "-Woverlength-strings"
     "-Wpointer-arith"
+    "-Wundef"
     "-Wunused-local-typedefs"
     "-Wunused-result"
     "-Wvarargs"
     "-Wvla"
     "-Wwrite-strings"
-    "-Wno-missing-field-initializers"
-    "-Wno-sign-compare"
+    "-DNOMINMAX"
 )
 
 list(APPEND ABSL_GCC_TEST_FLAGS
@@ -103,48 +63,37 @@
 list(APPEND ABSL_LLVM_FLAGS
     "-Wall"
     "-Wextra"
-    "-Weverything"
-    "-Wno-c++98-compat-pedantic"
-    "-Wno-conversion"
-    "-Wno-covered-switch-default"
-    "-Wno-deprecated"
-    "-Wno-disabled-macro-expansion"
-    "-Wno-double-promotion"
-    "-Wno-comma"
-    "-Wno-extra-semi"
-    "-Wno-extra-semi-stmt"
-    "-Wno-packed"
-    "-Wno-padded"
-    "-Wno-sign-compare"
-    "-Wno-float-conversion"
-    "-Wno-float-equal"
-    "-Wno-format-nonliteral"
-    "-Wno-gcc-compat"
-    "-Wno-global-constructors"
-    "-Wno-exit-time-destructors"
-    "-Wno-non-modular-include-in-module"
-    "-Wno-old-style-cast"
-    "-Wno-range-loop-analysis"
-    "-Wno-reserved-id-macro"
-    "-Wno-shorten-64-to-32"
-    "-Wno-switch-enum"
-    "-Wno-thread-safety-negative"
-    "-Wno-unknown-warning-option"
-    "-Wno-unreachable-code"
-    "-Wno-unused-macros"
-    "-Wno-weak-vtables"
-    "-Wno-zero-as-null-pointer-constant"
-    "-Wbitfield-enum-conversion"
-    "-Wbool-conversion"
-    "-Wconstant-conversion"
-    "-Wenum-conversion"
-    "-Wint-conversion"
+    "-Wcast-qual"
+    "-Wconversion"
+    "-Wfloat-overflow-conversion"
+    "-Wfloat-zero-conversion"
+    "-Wfor-loop-analysis"
+    "-Wformat-security"
+    "-Wgnu-redeclared-enum"
+    "-Winfinite-recursion"
     "-Wliteral-conversion"
-    "-Wnon-literal-null-conversion"
-    "-Wnull-conversion"
-    "-Wobjc-literal-conversion"
-    "-Wno-sign-conversion"
+    "-Wmissing-declarations"
+    "-Woverlength-strings"
+    "-Wpointer-arith"
+    "-Wself-assign"
+    "-Wshadow"
     "-Wstring-conversion"
+    "-Wtautological-overlap-compare"
+    "-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-implicit-int-conversion"
+    "-Wno-shorten-64-to-32"
+    "-Wno-sign-conversion"
+    "-DNOMINMAX"
 )
 
 list(APPEND ABSL_LLVM_TEST_FLAGS
diff --git a/absl/copts/GENERATED_copts.bzl b/absl/copts/GENERATED_copts.bzl
index 3cc4878..6707488 100644
--- a/absl/copts/GENERATED_copts.bzl
+++ b/absl/copts/GENERATED_copts.bzl
@@ -6,47 +6,6 @@
 
 ABSL_CLANG_CL_FLAGS = [
     "/W3",
-    "-Wno-c++98-compat-pedantic",
-    "-Wno-conversion",
-    "-Wno-covered-switch-default",
-    "-Wno-deprecated",
-    "-Wno-disabled-macro-expansion",
-    "-Wno-double-promotion",
-    "-Wno-comma",
-    "-Wno-extra-semi",
-    "-Wno-extra-semi-stmt",
-    "-Wno-packed",
-    "-Wno-padded",
-    "-Wno-sign-compare",
-    "-Wno-float-conversion",
-    "-Wno-float-equal",
-    "-Wno-format-nonliteral",
-    "-Wno-gcc-compat",
-    "-Wno-global-constructors",
-    "-Wno-exit-time-destructors",
-    "-Wno-non-modular-include-in-module",
-    "-Wno-old-style-cast",
-    "-Wno-range-loop-analysis",
-    "-Wno-reserved-id-macro",
-    "-Wno-shorten-64-to-32",
-    "-Wno-switch-enum",
-    "-Wno-thread-safety-negative",
-    "-Wno-unknown-warning-option",
-    "-Wno-unreachable-code",
-    "-Wno-unused-macros",
-    "-Wno-weak-vtables",
-    "-Wno-zero-as-null-pointer-constant",
-    "-Wbitfield-enum-conversion",
-    "-Wbool-conversion",
-    "-Wconstant-conversion",
-    "-Wenum-conversion",
-    "-Wint-conversion",
-    "-Wliteral-conversion",
-    "-Wnon-literal-null-conversion",
-    "-Wnull-conversion",
-    "-Wobjc-literal-conversion",
-    "-Wno-sign-conversion",
-    "-Wstring-conversion",
     "/DNOMINMAX",
     "/DWIN32_LEAN_AND_MEAN",
     "/D_CRT_SECURE_NO_WARNINGS",
@@ -79,16 +38,17 @@
     "-Wextra",
     "-Wcast-qual",
     "-Wconversion-null",
+    "-Wformat-security",
     "-Wmissing-declarations",
     "-Woverlength-strings",
     "-Wpointer-arith",
+    "-Wundef",
     "-Wunused-local-typedefs",
     "-Wunused-result",
     "-Wvarargs",
     "-Wvla",
     "-Wwrite-strings",
-    "-Wno-missing-field-initializers",
-    "-Wno-sign-compare",
+    "-DNOMINMAX",
 ]
 
 ABSL_GCC_TEST_FLAGS = [
@@ -104,48 +64,37 @@
 ABSL_LLVM_FLAGS = [
     "-Wall",
     "-Wextra",
-    "-Weverything",
-    "-Wno-c++98-compat-pedantic",
-    "-Wno-conversion",
-    "-Wno-covered-switch-default",
-    "-Wno-deprecated",
-    "-Wno-disabled-macro-expansion",
-    "-Wno-double-promotion",
-    "-Wno-comma",
-    "-Wno-extra-semi",
-    "-Wno-extra-semi-stmt",
-    "-Wno-packed",
-    "-Wno-padded",
-    "-Wno-sign-compare",
-    "-Wno-float-conversion",
-    "-Wno-float-equal",
-    "-Wno-format-nonliteral",
-    "-Wno-gcc-compat",
-    "-Wno-global-constructors",
-    "-Wno-exit-time-destructors",
-    "-Wno-non-modular-include-in-module",
-    "-Wno-old-style-cast",
-    "-Wno-range-loop-analysis",
-    "-Wno-reserved-id-macro",
-    "-Wno-shorten-64-to-32",
-    "-Wno-switch-enum",
-    "-Wno-thread-safety-negative",
-    "-Wno-unknown-warning-option",
-    "-Wno-unreachable-code",
-    "-Wno-unused-macros",
-    "-Wno-weak-vtables",
-    "-Wno-zero-as-null-pointer-constant",
-    "-Wbitfield-enum-conversion",
-    "-Wbool-conversion",
-    "-Wconstant-conversion",
-    "-Wenum-conversion",
-    "-Wint-conversion",
+    "-Wcast-qual",
+    "-Wconversion",
+    "-Wfloat-overflow-conversion",
+    "-Wfloat-zero-conversion",
+    "-Wfor-loop-analysis",
+    "-Wformat-security",
+    "-Wgnu-redeclared-enum",
+    "-Winfinite-recursion",
     "-Wliteral-conversion",
-    "-Wnon-literal-null-conversion",
-    "-Wnull-conversion",
-    "-Wobjc-literal-conversion",
-    "-Wno-sign-conversion",
+    "-Wmissing-declarations",
+    "-Woverlength-strings",
+    "-Wpointer-arith",
+    "-Wself-assign",
+    "-Wshadow",
     "-Wstring-conversion",
+    "-Wtautological-overlap-compare",
+    "-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-implicit-int-conversion",
+    "-Wno-shorten-64-to-32",
+    "-Wno-sign-conversion",
+    "-DNOMINMAX",
 ]
 
 ABSL_LLVM_TEST_FLAGS = [
diff --git a/absl/copts/configure_copts.bzl b/absl/copts/configure_copts.bzl
index 9dd6bd0..669a906 100644
--- a/absl/copts/configure_copts.bzl
+++ b/absl/copts/configure_copts.bzl
@@ -22,21 +22,21 @@
 )
 
 ABSL_DEFAULT_COPTS = select({
-    "//absl:windows": ABSL_MSVC_FLAGS,
-    "//absl:llvm_compiler": ABSL_LLVM_FLAGS,
+    "//absl:msvc_compiler": ABSL_MSVC_FLAGS,
+    "//absl:clang-cl_compiler": ABSL_CLANG_CL_FLAGS,
+    "//absl:clang_compiler": ABSL_LLVM_FLAGS,
     "//conditions:default": ABSL_GCC_FLAGS,
 })
 
-# in absence of modules (--compiler=gcc or -c opt), cc_tests leak their copts
-# to their (included header) dependencies and fail to build outside absl
 ABSL_TEST_COPTS = ABSL_DEFAULT_COPTS + select({
-    "//absl:windows": ABSL_MSVC_TEST_FLAGS,
-    "//absl:llvm_compiler": ABSL_LLVM_TEST_FLAGS,
+    "//absl:msvc_compiler": ABSL_MSVC_TEST_FLAGS,
+    "//absl:clang-cl_compiler": ABSL_CLANG_CL_TEST_FLAGS,
+    "//absl:clang_compiler": ABSL_LLVM_TEST_FLAGS,
     "//conditions:default": ABSL_GCC_TEST_FLAGS,
 })
 
 ABSL_DEFAULT_LINKOPTS = select({
-    "//absl:windows": ABSL_MSVC_LINKOPTS,
+    "//absl:msvc_compiler": ABSL_MSVC_LINKOPTS,
     "//conditions:default": [],
 })
 
@@ -48,7 +48,7 @@
     ":cpu_darwin": ABSL_RANDOM_HWAES_X64_FLAGS,
     ":cpu_x64_windows_msvc": ABSL_RANDOM_HWAES_MSVC_X64_FLAGS,
     ":cpu_x64_windows": ABSL_RANDOM_HWAES_MSVC_X64_FLAGS,
-    ":cpu_haswell": ABSL_RANDOM_HWAES_X64_FLAGS,
+    ":cpu_k8": ABSL_RANDOM_HWAES_X64_FLAGS,
     ":cpu_ppc": ["-mcrypto"],
 
     # Supported by default or unsupported.
@@ -65,7 +65,7 @@
     # These configs have consistent flags to enable HWAES intsructions.
     cpu_configs = [
         "ppc",
-        "haswell",
+        "k8",
         "darwin_x86_64",
         "darwin",
         "x64_windows_msvc",
diff --git a/absl/copts/copts.py b/absl/copts/copts.py
index 704ef23..cf52981 100644
--- a/absl/copts/copts.py
+++ b/absl/copts/copts.py
@@ -16,77 +16,6 @@
     "/W3",
 ]
 
-LLVM_BIG_WARNING_FLAGS = [
-    "-Wall",
-    "-Wextra",
-    "-Weverything",
-]
-
-# Docs on single flags is preceded by a comment.
-# Docs on groups of flags is preceded by ###.
-LLVM_DISABLE_WARNINGS_FLAGS = [
-    # Abseil does not support C++98
-    "-Wno-c++98-compat-pedantic",
-    # Turns off all implicit conversion warnings. Most are re-enabled below.
-    "-Wno-conversion",
-    "-Wno-covered-switch-default",
-    "-Wno-deprecated",
-    "-Wno-disabled-macro-expansion",
-    "-Wno-double-promotion",
-    ###
-    # Turned off as they include valid C++ code.
-    "-Wno-comma",
-    "-Wno-extra-semi",
-    "-Wno-extra-semi-stmt",
-    "-Wno-packed",
-    "-Wno-padded",
-    ###
-    # Google style does not use unsigned integers, though STL containers
-    # have unsigned types.
-    "-Wno-sign-compare",
-    ###
-    "-Wno-float-conversion",
-    "-Wno-float-equal",
-    "-Wno-format-nonliteral",
-    # Too aggressive: warns on Clang extensions enclosed in Clang-only
-    # compilation paths.
-    "-Wno-gcc-compat",
-    ###
-    # Some internal globals are necessary. Don't do this at home.
-    "-Wno-global-constructors",
-    "-Wno-exit-time-destructors",
-    ###
-    "-Wno-non-modular-include-in-module",
-    "-Wno-old-style-cast",
-    # Warns on preferred usage of non-POD types such as string_view
-    "-Wno-range-loop-analysis",
-    "-Wno-reserved-id-macro",
-    "-Wno-shorten-64-to-32",
-    "-Wno-switch-enum",
-    "-Wno-thread-safety-negative",
-    "-Wno-unknown-warning-option",
-    "-Wno-unreachable-code",
-    # Causes warnings on include guards
-    "-Wno-unused-macros",
-    "-Wno-weak-vtables",
-    # Causes warnings on usage of types/compare.h comparison operators.
-    "-Wno-zero-as-null-pointer-constant",
-    ###
-    # Implicit conversion warnings turned off by -Wno-conversion
-    # which are re-enabled below.
-    "-Wbitfield-enum-conversion",
-    "-Wbool-conversion",
-    "-Wconstant-conversion",
-    "-Wenum-conversion",
-    "-Wint-conversion",
-    "-Wliteral-conversion",
-    "-Wnon-literal-null-conversion",
-    "-Wnull-conversion",
-    "-Wobjc-literal-conversion",
-    "-Wno-sign-conversion",
-    "-Wstring-conversion",
-]
-
 LLVM_TEST_DISABLE_WARNINGS_FLAGS = [
     "-Wno-c99-extensions",
     "-Wno-deprecated-declarations",
@@ -125,21 +54,18 @@
         "-Wextra",
         "-Wcast-qual",
         "-Wconversion-null",
+        "-Wformat-security",
         "-Wmissing-declarations",
         "-Woverlength-strings",
         "-Wpointer-arith",
+        "-Wundef",
         "-Wunused-local-typedefs",
         "-Wunused-result",
         "-Wvarargs",
         "-Wvla",  # variable-length array
         "-Wwrite-strings",
-        # gcc-4.x has spurious missing field initializer warnings.
-        # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36750
-        # Remove when gcc-4.x is no longer supported.
-        "-Wno-missing-field-initializers",
-        # Google style does not use unsigned integers, though STL containers
-        # have unsigned types.
-        "-Wno-sign-compare",
+        # Don't define min and max macros (Build on Windows using gcc)
+        "-DNOMINMAX",
     ],
     "ABSL_GCC_TEST_FLAGS": [
         "-Wno-conversion-null",
@@ -150,12 +76,48 @@
         "-Wno-unused-parameter",
         "-Wno-unused-private-field",
     ],
-    "ABSL_LLVM_FLAGS":
-        LLVM_BIG_WARNING_FLAGS + LLVM_DISABLE_WARNINGS_FLAGS,
+    "ABSL_LLVM_FLAGS": [
+        "-Wall",
+        "-Wextra",
+        "-Wcast-qual",
+        "-Wconversion",
+        "-Wfloat-overflow-conversion",
+        "-Wfloat-zero-conversion",
+        "-Wfor-loop-analysis",
+        "-Wformat-security",
+        "-Wgnu-redeclared-enum",
+        "-Winfinite-recursion",
+        "-Wliteral-conversion",
+        "-Wmissing-declarations",
+        "-Woverlength-strings",
+        "-Wpointer-arith",
+        "-Wself-assign",
+        "-Wshadow",
+        "-Wstring-conversion",
+        "-Wtautological-overlap-compare",
+        "-Wundef",
+        "-Wuninitialized",
+        "-Wunreachable-code",
+        "-Wunused-comparison",
+        "-Wunused-local-typedefs",
+        "-Wunused-result",
+        "-Wvla",
+        "-Wwrite-strings",
+        # Warnings that are enabled by group warning flags like -Wall that we
+        # explicitly disable.
+        "-Wno-float-conversion",
+        "-Wno-implicit-float-conversion",
+        "-Wno-implicit-int-float-conversion",
+        "-Wno-implicit-int-conversion",
+        "-Wno-shorten-64-to-32",
+        "-Wno-sign-conversion",
+        # Don't define min and max macros (Build on Windows using clang)
+        "-DNOMINMAX",
+    ],
     "ABSL_LLVM_TEST_FLAGS":
         LLVM_TEST_DISABLE_WARNINGS_FLAGS,
     "ABSL_CLANG_CL_FLAGS":
-        (MSVC_BIG_WARNING_FLAGS + LLVM_DISABLE_WARNINGS_FLAGS + MSVC_DEFINES),
+        (MSVC_BIG_WARNING_FLAGS + MSVC_DEFINES),
     "ABSL_CLANG_CL_TEST_FLAGS":
         LLVM_TEST_DISABLE_WARNINGS_FLAGS,
     "ABSL_MSVC_FLAGS":
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel
index 8f521be..5385bcb 100644
--- a/absl/debugging/BUILD.bazel
+++ b/absl/debugging/BUILD.bazel
@@ -26,7 +26,7 @@
     default_visibility = ["//visibility:public"],
 )
 
-licenses(["notice"])  # Apache 2.0
+licenses(["notice"])
 
 cc_library(
     name = "stacktrace",
@@ -55,6 +55,7 @@
     name = "symbolize",
     srcs = [
         "symbolize.cc",
+        "symbolize_darwin.inc",
         "symbolize_elf.inc",
         "symbolize_unimplemented.inc",
         "symbolize_win32.inc",
@@ -65,7 +66,8 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS + select({
-        "//absl:windows": ["-DEFAULTLIB:dbghelp.lib"],
+        "//absl:msvc_compiler": ["-DEFAULTLIB:dbghelp.lib"],
+        "//absl:clang-cl_compiler": ["-DEFAULTLIB:dbghelp.lib"],
         "//conditions:default": [],
     }),
     deps = [
@@ -77,6 +79,7 @@
         "//absl/base:dynamic_annotations",
         "//absl/base:malloc_internal",
         "//absl/base:raw_logging_internal",
+        "//absl/strings",
     ],
 )
 
@@ -84,20 +87,24 @@
     name = "symbolize_test",
     srcs = ["symbolize_test.cc"],
     copts = ABSL_TEST_COPTS + select({
-        "//absl:windows": ["/Z7"],
+        "//absl:msvc_compiler": ["/Z7"],
+        "//absl:clang-cl_compiler": ["/Z7"],
         "//conditions:default": [],
     }),
     linkopts = ABSL_DEFAULT_LINKOPTS + select({
-        "//absl:windows": ["/DEBUG"],
+        "//absl:msvc_compiler": ["/DEBUG"],
+        "//absl:clang-cl_compiler": ["/DEBUG"],
         "//conditions:default": [],
     }),
     deps = [
         ":stack_consumption",
         ":symbolize",
         "//absl/base",
+        "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:raw_logging_internal",
         "//absl/memory",
+        "//absl/strings",
         "@com_google_googletest//:gtest",
     ],
 )
@@ -144,7 +151,9 @@
     srcs = ["failure_signal_handler_test.cc"],
     copts = ABSL_TEST_COPTS,
     linkopts = select({
-        "//absl:windows": [],
+        "//absl:msvc_compiler": [],
+        "//absl:clang-cl_compiler": [],
+        "//absl:wasm": [],
         "//conditions:default": ["-pthread"],
     }) + ABSL_DEFAULT_LINKOPTS,
     deps = [
@@ -200,6 +209,7 @@
     deps = [
         ":demangle_internal",
         ":stack_consumption",
+        "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:raw_logging_internal",
         "//absl/memory",
@@ -233,7 +243,7 @@
 # These targets exists for use in tests only, explicitly configuring the
 # LEAK_SANITIZER macro. It must be linked with -fsanitize=leak for lsan.
 ABSL_LSAN_LINKOPTS = select({
-    "//absl:llvm_compiler": ["-fsanitize=leak"],
+    "//absl:clang_compiler": ["-fsanitize=leak"],
     "//conditions:default": [],
 })
 
@@ -243,13 +253,14 @@
     srcs = ["leak_check.cc"],
     hdrs = ["leak_check.h"],
     copts = select({
-        "//absl:llvm_compiler": ["-DLEAK_SANITIZER"],
+        "//absl:clang_compiler": ["-DLEAK_SANITIZER"],
         "//conditions:default": [],
     }),
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = ["//visibility:private"],
     deps = [
         "//absl/base:config",
+        "//absl/base:core_headers",
     ],
 )
 
@@ -263,6 +274,7 @@
     visibility = ["//visibility:private"],
     deps = [
         "//absl/base:config",
+        "//absl/base:core_headers",
     ],
 )
 
@@ -270,7 +282,7 @@
     name = "leak_check_test",
     srcs = ["leak_check_test.cc"],
     copts = select({
-        "//absl:llvm_compiler": ["-DABSL_EXPECT_LEAK_SANITIZER"],
+        "//absl:clang_compiler": ["-DABSL_EXPECT_LEAK_SANITIZER"],
         "//conditions:default": [],
     }),
     linkopts = ABSL_LSAN_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt
index 7733615..074b44c 100644
--- a/absl/debugging/CMakeLists.txt
+++ b/absl/debugging/CMakeLists.txt
@@ -46,6 +46,7 @@
     "internal/symbolize.h"
   SRCS
     "symbolize.cc"
+    "symbolize_darwin.inc"
     "symbolize_elf.inc"
     "symbolize_unimplemented.inc"
     "symbolize_win32.inc"
@@ -63,6 +64,7 @@
     absl::dynamic_annotations
     absl::malloc_internal
     absl::raw_logging_internal
+    absl::strings
   PUBLIC
 )
 
@@ -80,9 +82,11 @@
     absl::stack_consumption
     absl::symbolize
     absl::base
+    absl::config
     absl::core_headers
     absl::memory
     absl::raw_logging_internal
+    absl::strings
     gmock
 )
 
@@ -186,6 +190,7 @@
   DEPS
     absl::demangle_internal
     absl::stack_consumption
+    absl::config
     absl::core_headers
     absl::memory
     absl::raw_logging_internal
diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc
index 1f69bfa..3ddebd7 100644
--- a/absl/debugging/failure_signal_handler.cc
+++ b/absl/debugging/failure_signal_handler.cc
@@ -21,6 +21,7 @@
 #ifdef _WIN32
 #include <windows.h>
 #else
+#include <sched.h>
 #include <unistd.h>
 #endif
 
@@ -135,9 +136,10 @@
 #else
   const size_t page_mask = sysconf(_SC_PAGESIZE) - 1;
 #endif
-  size_t stack_size = (std::max(SIGSTKSZ, 65536) + page_mask) & ~page_mask;
-#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
-    defined(THREAD_SANITIZER)
+  size_t stack_size =
+      (std::max<size_t>(SIGSTKSZ, 65536) + page_mask) & ~page_mask;
+#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
+    defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER)
   // Account for sanitizer instrumentation requiring additional stack space.
   stack_size *= 5;
 #endif
@@ -219,17 +221,24 @@
   absl::raw_logging_internal::SafeWriteToStderr(data, strlen(data));
 }
 
-static void WriteSignalMessage(int signo, void (*writerfn)(const char*)) {
-  char buf[64];
+static void WriteSignalMessage(int signo, int cpu,
+                               void (*writerfn)(const char*)) {
+  char buf[96];
+  char on_cpu[32] = {0};
+  if (cpu != -1) {
+    snprintf(on_cpu, sizeof(on_cpu), " on cpu %d", cpu);
+  }
   const char* const signal_string =
       debugging_internal::FailureSignalToString(signo);
   if (signal_string != nullptr && signal_string[0] != '\0') {
-    snprintf(buf, sizeof(buf), "*** %s received at time=%ld ***\n",
+    snprintf(buf, sizeof(buf), "*** %s received at time=%ld%s ***\n",
              signal_string,
-             static_cast<long>(time(nullptr)));  // NOLINT(runtime/int)
+             static_cast<long>(time(nullptr)),   // NOLINT(runtime/int)
+             on_cpu);
   } else {
-    snprintf(buf, sizeof(buf), "*** Signal %d received at time=%ld ***\n",
-             signo, static_cast<long>(time(nullptr)));  // NOLINT(runtime/int)
+    snprintf(buf, sizeof(buf), "*** Signal %d received at time=%ld%s ***\n",
+             signo, static_cast<long>(time(nullptr)),  // NOLINT(runtime/int)
+             on_cpu);
   }
   writerfn(buf);
 }
@@ -269,10 +278,10 @@
 // Called by AbslFailureSignalHandler() to write the failure info. It is
 // called once with writerfn set to WriteToStderr() and then possibly
 // with writerfn set to the user provided function.
-static void WriteFailureInfo(int signo, void* ucontext,
+static void WriteFailureInfo(int signo, void* ucontext, int cpu,
                              void (*writerfn)(const char*)) {
   WriterFnStruct writerfn_struct{writerfn};
-  WriteSignalMessage(signo, writerfn);
+  WriteSignalMessage(signo, cpu, writerfn);
   WriteStackTrace(ucontext, fsh_options.symbolize_stacktrace, WriterFnWrapper,
                   &writerfn_struct);
 }
@@ -334,6 +343,14 @@
     }
   }
 
+  // Increase the chance that the CPU we report was the same CPU on which the
+  // signal was received by doing this as early as possible, i.e. after
+  // verifying that this is not a recursive signal handler invocation.
+  int my_cpu = -1;
+#ifdef ABSL_HAVE_SCHED_GETCPU
+  my_cpu = sched_getcpu();
+#endif
+
 #ifdef ABSL_HAVE_ALARM
   // Set an alarm to abort the program in case this code hangs or deadlocks.
   if (fsh_options.alarm_on_failure_secs > 0) {
@@ -344,12 +361,12 @@
 #endif
 
   // First write to stderr.
-  WriteFailureInfo(signo, ucontext, WriteToStderr);
+  WriteFailureInfo(signo, ucontext, my_cpu, WriteToStderr);
 
   // Riskier code (because it is less likely to be async-signal-safe)
   // goes after this point.
   if (fsh_options.writerfn != nullptr) {
-    WriteFailureInfo(signo, ucontext, fsh_options.writerfn);
+    WriteFailureInfo(signo, ucontext, my_cpu, fsh_options.writerfn);
   }
 
   if (fsh_options.call_previous_handler) {
diff --git a/absl/debugging/failure_signal_handler.h b/absl/debugging/failure_signal_handler.h
index f5a8396..0c0f585 100644
--- a/absl/debugging/failure_signal_handler.h
+++ b/absl/debugging/failure_signal_handler.h
@@ -88,7 +88,7 @@
   bool call_previous_handler = false;
 
   // If non-null, indicates a pointer to a callback function that will be called
-  // upon failure, with a std::string argument containing failure data. This function
+  // upon failure, with a string argument containing failure data. This function
   // may be used as a hook to write failure data to a secondary location, such
   // as a log file. This function may also be called with null data, as a hint
   // to flush any buffered data before the program may be terminated. Consider
diff --git a/absl/debugging/failure_signal_handler_test.cc b/absl/debugging/failure_signal_handler_test.cc
index 863fb51..6a62428 100644
--- a/absl/debugging/failure_signal_handler_test.cc
+++ b/absl/debugging/failure_signal_handler_test.cc
@@ -55,7 +55,7 @@
               exit_regex);
 #else
   // Windows doesn't have testing::KilledBySignal().
-  EXPECT_DEATH(InstallHandlerAndRaise(signo), exit_regex);
+  EXPECT_DEATH_IF_SUPPORTED(InstallHandlerAndRaise(signo), exit_regex);
 #endif
 }
 
@@ -107,8 +107,8 @@
               testing::KilledBySignal(signo), exit_regex);
 #else
   // Windows doesn't have testing::KilledBySignal().
-  EXPECT_DEATH(InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo),
-               exit_regex);
+  EXPECT_DEATH_IF_SUPPORTED(
+      InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo), exit_regex);
 #endif
 
   // Open the file in this process and check its contents.
@@ -122,6 +122,12 @@
           "*** ", absl::debugging_internal::FailureSignalToString(signo),
           " received at ")));
 
+  // On platforms where it is possible to get the current CPU, the
+  // CPU number is also logged. Check that it is present in output.
+#if defined(__linux__)
+  EXPECT_THAT(error_line, testing::HasSubstr(" on cpu "));
+#endif
+
   if (absl::debugging_internal::StackTraceWorksForTest()) {
     std::getline(error_output, error_line);
     EXPECT_THAT(error_line, StartsWith("PC: "));
diff --git a/absl/debugging/internal/address_is_readable.cc b/absl/debugging/internal/address_is_readable.cc
index 6537606..329c285 100644
--- a/absl/debugging/internal/address_is_readable.cc
+++ b/absl/debugging/internal/address_is_readable.cc
@@ -68,6 +68,7 @@
 // unimplemented.
 // This is a namespace-scoped variable for correct zero-initialization.
 static std::atomic<uint64_t> pid_and_fds;  // initially 0, an invalid pid.
+
 bool AddressIsReadable(const void *addr) {
   absl::base_internal::ErrnoSaver errno_saver;
   // We test whether a byte is readable by using write().  Normally, this would
@@ -86,7 +87,7 @@
     int pid;
     int read_fd;
     int write_fd;
-    uint64_t local_pid_and_fds = pid_and_fds.load(std::memory_order_relaxed);
+    uint64_t local_pid_and_fds = pid_and_fds.load(std::memory_order_acquire);
     Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd);
     while (current_pid != pid) {
       int p[2];
@@ -98,13 +99,13 @@
       fcntl(p[1], F_SETFD, FD_CLOEXEC);
       uint64_t new_pid_and_fds = Pack(current_pid, p[0], p[1]);
       if (pid_and_fds.compare_exchange_strong(
-              local_pid_and_fds, new_pid_and_fds, std::memory_order_relaxed,
+              local_pid_and_fds, new_pid_and_fds, std::memory_order_release,
               std::memory_order_relaxed)) {
         local_pid_and_fds = new_pid_and_fds;  // fds exposed to other threads
       } else {  // fds not exposed to other threads; we can close them.
         close(p[0]);
         close(p[1]);
-        local_pid_and_fds = pid_and_fds.load(std::memory_order_relaxed);
+        local_pid_and_fds = pid_and_fds.load(std::memory_order_acquire);
       }
       Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd);
     }
@@ -124,7 +125,7 @@
       // If pid_and_fds contains the problematic file descriptors we just used,
       // this call will forget them, and the loop will try again.
       pid_and_fds.compare_exchange_strong(local_pid_and_fds, 0,
-                                          std::memory_order_relaxed,
+                                          std::memory_order_release,
                                           std::memory_order_relaxed);
     }
   } while (errno == EBADF);
diff --git a/absl/debugging/internal/demangle.cc b/absl/debugging/internal/demangle.cc
index fc615c3..5cd5632 100644
--- a/absl/debugging/internal/demangle.cc
+++ b/absl/debugging/internal/demangle.cc
@@ -126,6 +126,7 @@
     {"Dn", "std::nullptr_t", 0},  // i.e., decltype(nullptr)
     {"Df", "decimal32", 0},       // IEEE 754r decimal floating point (32 bits)
     {"Di", "char32_t", 0},
+    {"Du", "char8_t", 0},
     {"Ds", "char16_t", 0},
     {"Dh", "float16", 0},         // IEEE 754r half-precision float (16 bits)
     {nullptr, nullptr, 0},
@@ -151,7 +152,7 @@
 // frame, so every byte counts.
 typedef struct {
   int mangled_idx;                   // Cursor of mangled name.
-  int out_cur_idx;                   // Cursor of output std::string.
+  int out_cur_idx;                   // Cursor of output string.
   int prev_name_idx;                 // For constructors/destructors.
   signed int prev_name_length : 16;  // For constructors/destructors.
   signed int nest_level : 15;        // For nested names.
@@ -172,8 +173,8 @@
 // Only one copy of this exists for each call to Demangle, so the size of this
 // struct is nearly inconsequential.
 typedef struct {
-  const char *mangled_begin;  // Beginning of input std::string.
-  char *out;                  // Beginning of output std::string.
+  const char *mangled_begin;  // Beginning of input string.
+  char *out;                  // Beginning of output string.
   int out_end_idx;            // One past last allowed output character.
   int recursion_depth;        // For stack exhaustion prevention.
   int steps;               // Cap how much work we'll do, regardless of depth.
@@ -385,30 +386,35 @@
 // by GCC 4.5.x and later versions (and our locally-modified version of GCC
 // 4.4.x) to indicate functions which have been cloned during optimization.
 // We treat any sequence (.<alpha>+.<digit>+)+ as a function clone suffix.
+// Additionally, '_' is allowed along with the alphanumeric sequence.
 static bool IsFunctionCloneSuffix(const char *str) {
   size_t i = 0;
   while (str[i] != '\0') {
-    // Consume a single .<alpha>+.<digit>+ sequence.
-    if (str[i] != '.' || !IsAlpha(str[i + 1])) {
+    bool parsed = false;
+    // Consume a single [.<alpha> | _]*[.<digit>]* sequence.
+    if (str[i] == '.' && (IsAlpha(str[i + 1]) || str[i + 1] == '_')) {
+      parsed = true;
+      i += 2;
+      while (IsAlpha(str[i]) || str[i] == '_') {
+        ++i;
+      }
+    }
+    if (str[i] == '.' && IsDigit(str[i + 1])) {
+      parsed = true;
+      i += 2;
+      while (IsDigit(str[i])) {
+        ++i;
+      }
+    }
+    if (!parsed)
       return false;
-    }
-    i += 2;
-    while (IsAlpha(str[i])) {
-      ++i;
-    }
-    if (str[i] != '.' || !IsDigit(str[i + 1])) {
-      return false;
-    }
-    i += 2;
-    while (IsDigit(str[i])) {
-      ++i;
-    }
   }
   return true;  // Consumed everything in "str".
 }
 
 static bool EndsWith(State *state, const char chr) {
   return state->parse_state.out_cur_idx > 0 &&
+         state->parse_state.out_cur_idx < state->out_end_idx &&
          chr == state->out[state->parse_state.out_cur_idx - 1];
 }
 
@@ -421,8 +427,10 @@
     if (str[0] == '<' && EndsWith(state, '<')) {
       Append(state, " ", 1);
     }
-    // Remember the last identifier name for ctors/dtors.
-    if (IsAlpha(str[0]) || str[0] == '_') {
+    // Remember the last identifier name for ctors/dtors,
+    // but only if we haven't yet overflown the buffer.
+    if (state->parse_state.out_cur_idx < state->out_end_idx &&
+        (IsAlpha(str[0]) || str[0] == '_')) {
       state->parse_state.prev_name_idx = state->parse_state.out_cur_idx;
       state->parse_state.prev_name_length = length;
     }
@@ -962,6 +970,7 @@
 //                ::= TT <type>
 //                ::= TI <type>
 //                ::= TS <type>
+//                ::= TH <type>  # thread-local
 //                ::= Tc <call-offset> <call-offset> <(base) encoding>
 //                ::= GV <(object) name>
 //                ::= T <call-offset> <(base) encoding>
@@ -980,7 +989,7 @@
   ComplexityGuard guard(state);
   if (guard.IsTooComplex()) return false;
   ParseState copy = state->parse_state;
-  if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTIS") &&
+  if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTISH") &&
       ParseType(state)) {
     return true;
   }
@@ -1077,20 +1086,28 @@
   return false;
 }
 
-// <ctor-dtor-name> ::= C1 | C2 | C3
+// <ctor-dtor-name> ::= C1 | C2 | C3 | CI1 <base-class-type> | CI2
+// <base-class-type>
 //                  ::= D0 | D1 | D2
 // # GCC extensions: "unified" constructor/destructor.  See
-// # https://github.com/gcc-mirror/gcc/blob/7ad17b583c3643bd4557f29b8391ca7ef08391f5/gcc/cp/mangle.c#L1847
+// #
+// https://github.com/gcc-mirror/gcc/blob/7ad17b583c3643bd4557f29b8391ca7ef08391f5/gcc/cp/mangle.c#L1847
 //                  ::= C4 | D4
 static bool ParseCtorDtorName(State *state) {
   ComplexityGuard guard(state);
   if (guard.IsTooComplex()) return false;
   ParseState copy = state->parse_state;
-  if (ParseOneCharToken(state, 'C') && ParseCharClass(state, "1234")) {
-    const char *const prev_name = state->out + state->parse_state.prev_name_idx;
-    MaybeAppendWithLength(state, prev_name,
-                          state->parse_state.prev_name_length);
-    return true;
+  if (ParseOneCharToken(state, 'C')) {
+    if (ParseCharClass(state, "1234")) {
+      const char *const prev_name =
+          state->out + state->parse_state.prev_name_idx;
+      MaybeAppendWithLength(state, prev_name,
+                            state->parse_state.prev_name_length);
+      return true;
+    } else if (ParseOneCharToken(state, 'I') && ParseCharClass(state, "12") &&
+               ParseClassEnumType(state)) {
+      return true;
+    }
   }
   state->parse_state = copy;
 
@@ -1139,6 +1156,7 @@
 //        ::= <decltype>
 //        ::= <substitution>
 //        ::= Dp <type>          # pack expansion of (C++0x)
+//        ::= Dv <num-elems> _   # GNU vector extension
 //
 static bool ParseType(State *state) {
   ComplexityGuard guard(state);
@@ -1205,6 +1223,12 @@
     return true;
   }
 
+  if (ParseTwoCharToken(state, "Dv") && ParseNumber(state, nullptr) &&
+      ParseOneCharToken(state, '_')) {
+    return true;
+  }
+  state->parse_state = copy;
+
   return false;
 }
 
@@ -1253,13 +1277,42 @@
   return false;
 }
 
-// <function-type> ::= F [Y] <bare-function-type> E
+//  <exception-spec> ::= Do                # non-throwing
+//                                           exception-specification (e.g.,
+//                                           noexcept, throw())
+//                   ::= DO <expression> E # computed (instantiation-dependent)
+//                                           noexcept
+//                   ::= Dw <type>+ E      # dynamic exception specification
+//                                           with instantiation-dependent types
+static bool ParseExceptionSpec(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+
+  if (ParseTwoCharToken(state, "Do")) return true;
+
+  ParseState copy = state->parse_state;
+  if (ParseTwoCharToken(state, "DO") && ParseExpression(state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+  if (ParseTwoCharToken(state, "Dw") && OneOrMore(ParseType, state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  return false;
+}
+
+// <function-type> ::= [exception-spec] F [Y] <bare-function-type> [O] E
 static bool ParseFunctionType(State *state) {
   ComplexityGuard guard(state);
   if (guard.IsTooComplex()) return false;
   ParseState copy = state->parse_state;
-  if (ParseOneCharToken(state, 'F') &&
+  if (Optional(ParseExceptionSpec(state)) && ParseOneCharToken(state, 'F') &&
       Optional(ParseOneCharToken(state, 'Y')) && ParseBareFunctionType(state) &&
+      Optional(ParseOneCharToken(state, 'O')) &&
       ParseOneCharToken(state, 'E')) {
     return true;
   }
@@ -1887,7 +1940,8 @@
 bool Demangle(const char *mangled, char *out, int out_size) {
   State state;
   InitState(&state, mangled, out, out_size);
-  return ParseTopLevelMangledName(&state) && !Overflowed(&state);
+  return ParseTopLevelMangledName(&state) && !Overflowed(&state) &&
+         state.parse_state.out_cur_idx > 0;
 }
 
 }  // namespace debugging_internal
diff --git a/absl/debugging/internal/demangle_test.cc b/absl/debugging/internal/demangle_test.cc
index c6f1ce1..6b14290 100644
--- a/absl/debugging/internal/demangle_test.cc
+++ b/absl/debugging/internal/demangle_test.cc
@@ -18,6 +18,7 @@
 #include <string>
 
 #include "gtest/gtest.h"
+#include "absl/base/config.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/debugging/internal/stack_consumption.h"
 #include "absl/memory/memory.h"
@@ -69,12 +70,34 @@
   EXPECT_STREQ("Foo()", tmp);
   EXPECT_TRUE(Demangle("_ZL3Foov.isra.2.constprop.18", tmp, sizeof(tmp)));
   EXPECT_STREQ("Foo()", tmp);
-  // Invalid (truncated), should not demangle.
-  EXPECT_FALSE(Demangle("_ZL3Foov.clo", tmp, sizeof(tmp)));
+  // Demangle suffixes produced by -funique-internal-linkage-names.
+  EXPECT_TRUE(Demangle("_ZL3Foov.__uniq.12345", tmp, sizeof(tmp)));
+  EXPECT_STREQ("Foo()", tmp);
+  EXPECT_TRUE(Demangle("_ZL3Foov.__uniq.12345.isra.2.constprop.18", tmp,
+                       sizeof(tmp)));
+  EXPECT_STREQ("Foo()", tmp);
+  // Suffixes without the number should also demangle.
+  EXPECT_TRUE(Demangle("_ZL3Foov.clo", tmp, sizeof(tmp)));
+  EXPECT_STREQ("Foo()", tmp);
+  // Suffixes with just the number should also demangle.
+  EXPECT_TRUE(Demangle("_ZL3Foov.123", tmp, sizeof(tmp)));
+  EXPECT_STREQ("Foo()", tmp);
+  // (.clone. followed by non-number), should also demangle.
+  EXPECT_TRUE(Demangle("_ZL3Foov.clone.foo", tmp, sizeof(tmp)));
+  EXPECT_STREQ("Foo()", tmp);
+  // (.clone. followed by multiple numbers), should also demangle.
+  EXPECT_TRUE(Demangle("_ZL3Foov.clone.123.456", tmp, sizeof(tmp)));
+  EXPECT_STREQ("Foo()", tmp);
+  // (a long valid suffix), should demangle.
+  EXPECT_TRUE(Demangle("_ZL3Foov.part.9.165493.constprop.775.31805", tmp,
+                       sizeof(tmp)));
+  EXPECT_STREQ("Foo()", tmp);
+  // Invalid (. without anything else), should not demangle.
+  EXPECT_FALSE(Demangle("_ZL3Foov.", tmp, sizeof(tmp)));
+  // Invalid (. with mix of alpha and digits), should not demangle.
+  EXPECT_FALSE(Demangle("_ZL3Foov.abc123", tmp, sizeof(tmp)));
   // Invalid (.clone. not followed by number), should not demangle.
   EXPECT_FALSE(Demangle("_ZL3Foov.clone.", tmp, sizeof(tmp)));
-  // Invalid (.clone. followed by non-number), should not demangle.
-  EXPECT_FALSE(Demangle("_ZL3Foov.clone.foo", tmp, sizeof(tmp)));
   // Invalid (.constprop. not followed by number), should not demangle.
   EXPECT_FALSE(Demangle("_ZL3Foov.isra.2.constprop.", tmp, sizeof(tmp)));
 }
@@ -82,9 +105,10 @@
 // Tests that verify that Demangle footprint is within some limit.
 // They are not to be run under sanitizers as the sanitizers increase
 // stack consumption by about 4x.
-#if defined(ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION) &&   \
-    !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \
-    !defined(THREAD_SANITIZER)
+#if defined(ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION) && \
+    !defined(ABSL_HAVE_ADDRESS_SANITIZER) &&                   \
+    !defined(ABSL_HAVE_MEMORY_SANITIZER) &&                    \
+    !defined(ABSL_HAVE_THREAD_SANITIZER)
 
 static const char *g_mangled;
 static char g_demangle_buffer[4096];
diff --git a/absl/debugging/internal/examine_stack.cc b/absl/debugging/internal/examine_stack.cc
index a3dd893..589a3ef 100644
--- a/absl/debugging/internal/examine_stack.cc
+++ b/absl/debugging/internal/examine_stack.cc
@@ -20,6 +20,10 @@
 #include <unistd.h>
 #endif
 
+#ifdef __APPLE__
+#include <sys/ucontext.h>
+#endif
+
 #include <csignal>
 #include <cstdio>
 
@@ -42,30 +46,72 @@
     ucontext_t* context = reinterpret_cast<ucontext_t*>(vuc);
 #if defined(__aarch64__)
     return reinterpret_cast<void*>(context->uc_mcontext.pc);
+#elif defined(__alpha__)
+    return reinterpret_cast<void*>(context->uc_mcontext.sc_pc);
 #elif defined(__arm__)
     return reinterpret_cast<void*>(context->uc_mcontext.arm_pc);
+#elif defined(__hppa__)
+    return reinterpret_cast<void*>(context->uc_mcontext.sc_iaoq[0]);
 #elif defined(__i386__)
     if (14 < ABSL_ARRAYSIZE(context->uc_mcontext.gregs))
       return reinterpret_cast<void*>(context->uc_mcontext.gregs[14]);
+#elif defined(__ia64__)
+    return reinterpret_cast<void*>(context->uc_mcontext.sc_ip);
+#elif defined(__m68k__)
+    return reinterpret_cast<void*>(context->uc_mcontext.gregs[16]);
 #elif defined(__mips__)
     return reinterpret_cast<void*>(context->uc_mcontext.pc);
 #elif defined(__powerpc64__)
     return reinterpret_cast<void*>(context->uc_mcontext.gp_regs[32]);
 #elif defined(__powerpc__)
-    return reinterpret_cast<void*>(context->uc_mcontext.regs->nip);
+    return reinterpret_cast<void*>(context->uc_mcontext.uc_regs->gregs[32]);
 #elif defined(__riscv)
     return reinterpret_cast<void*>(context->uc_mcontext.__gregs[REG_PC]);
 #elif defined(__s390__) && !defined(__s390x__)
     return reinterpret_cast<void*>(context->uc_mcontext.psw.addr & 0x7fffffff);
 #elif defined(__s390__) && defined(__s390x__)
     return reinterpret_cast<void*>(context->uc_mcontext.psw.addr);
+#elif defined(__sh__)
+    return reinterpret_cast<void*>(context->uc_mcontext.pc);
+#elif defined(__sparc__) && !defined(__arch64__)
+    return reinterpret_cast<void*>(context->uc_mcontext.gregs[19]);
+#elif defined(__sparc__) && defined(__arch64__)
+    return reinterpret_cast<void*>(context->uc_mcontext.mc_gregs[19]);
 #elif defined(__x86_64__)
     if (16 < ABSL_ARRAYSIZE(context->uc_mcontext.gregs))
       return reinterpret_cast<void*>(context->uc_mcontext.gregs[16]);
+#elif defined(__e2k__)
+    return reinterpret_cast<void*>(context->uc_mcontext.cr0_hi);
 #else
 #error "Undefined Architecture."
 #endif
   }
+#elif defined(__APPLE__)
+  if (vuc != nullptr) {
+    ucontext_t* signal_ucontext = reinterpret_cast<ucontext_t*>(vuc);
+#if defined(__aarch64__)
+    return reinterpret_cast<void*>(
+        __darwin_arm_thread_state64_get_pc(signal_ucontext->uc_mcontext->__ss));
+#elif defined(__arm__)
+#if __DARWIN_UNIX03
+    return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__pc);
+#else
+    return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.pc);
+#endif
+#elif defined(__i386__)
+#if __DARWIN_UNIX03
+    return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__eip);
+#else
+    return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.eip);
+#endif
+#elif defined(__x86_64__)
+#if __DARWIN_UNIX03
+    return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__rip);
+#else
+    return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.rip);
+#endif
+#endif
+  }
 #elif defined(__akaros__)
   auto* ctx = reinterpret_cast<struct user_context*>(vuc);
   return reinterpret_cast<void*>(get_user_ctx_pc(ctx));
diff --git a/absl/debugging/internal/stack_consumption.cc b/absl/debugging/internal/stack_consumption.cc
index 875ca6d..e3dd51c 100644
--- a/absl/debugging/internal/stack_consumption.cc
+++ b/absl/debugging/internal/stack_consumption.cc
@@ -42,7 +42,8 @@
 // one of them is null, the results of p<q, p>q, p<=q, and p>=q are
 // unspecified. Therefore, instead we hardcode the direction of the
 // stack on platforms we know about.
-#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || \
+    defined(__aarch64__)
 constexpr bool kStackGrowsDown = true;
 #else
 #error Need to define kStackGrowsDown
diff --git a/absl/debugging/internal/stack_consumption.h b/absl/debugging/internal/stack_consumption.h
index 5e60ec4..2b5e715 100644
--- a/absl/debugging/internal/stack_consumption.h
+++ b/absl/debugging/internal/stack_consumption.h
@@ -24,8 +24,9 @@
 // Use this feature test macro to detect its availability.
 #ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
 #error ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION cannot be set directly
-#elif !defined(__APPLE__) && !defined(_WIN32) && \
-    (defined(__i386__) || defined(__x86_64__) || defined(__ppc__))
+#elif !defined(__APPLE__) && !defined(_WIN32) &&                     \
+    (defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || \
+     defined(__aarch64__))
 #define ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION 1
 
 namespace absl {
diff --git a/absl/debugging/internal/stacktrace_aarch64-inl.inc b/absl/debugging/internal/stacktrace_aarch64-inl.inc
index 411ea30..f4859d7 100644
--- a/absl/debugging/internal/stacktrace_aarch64-inl.inc
+++ b/absl/debugging/internal/stacktrace_aarch64-inl.inc
@@ -37,8 +37,11 @@
   absl::debugging_internal::VDSOSupport vdso;
   if (vdso.IsPresent()) {
     absl::debugging_internal::VDSOSupport::SymbolInfo symbol_info;
-    if (!vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.6.39", STT_FUNC,
-                           &symbol_info) ||
+    auto lookup = [&](int type) {
+      return vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.6.39", type,
+                               &symbol_info);
+    };
+    if ((!lookup(STT_FUNC) && !lookup(STT_NOTYPE)) ||
         symbol_info.address == nullptr) {
       // Unexpected: VDSO is present, yet the expected symbol is missing
       // or null.
@@ -74,6 +77,8 @@
 // checks (the strictness of which is controlled by the boolean parameter
 // "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
 template<bool STRICT_UNWINDING, bool WITH_CONTEXT>
+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS  // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY   // May read random elements from stack.
 static void **NextStackFrame(void **old_frame_pointer, const void *uc) {
   void **new_frame_pointer = reinterpret_cast<void**>(*old_frame_pointer);
   bool check_frame_size = true;
@@ -123,6 +128,8 @@
 }
 
 template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS  // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY   // May read random elements from stack.
 static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
                       const void *ucp, int *min_dropped_frames) {
 #ifdef __GNUC__
diff --git a/absl/debugging/internal/stacktrace_arm-inl.inc b/absl/debugging/internal/stacktrace_arm-inl.inc
index fffda96..2a1bf2e 100644
--- a/absl/debugging/internal/stacktrace_arm-inl.inc
+++ b/absl/debugging/internal/stacktrace_arm-inl.inc
@@ -1,9 +1,18 @@
-// Copyright 2011 and onwards Google Inc.
-// All rights reserved.
+// Copyright 2017 The Abseil Authors.
 //
-// Author: Doug Kwan
+// 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 is inspired by Craig Silverstein's PowerPC stacktrace code.
-//
 
 #ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_
 #define ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_
diff --git a/absl/debugging/internal/stacktrace_config.h b/absl/debugging/internal/stacktrace_config.h
index d4e8480..cca410d 100644
--- a/absl/debugging/internal/stacktrace_config.h
+++ b/absl/debugging/internal/stacktrace_config.h
@@ -21,6 +21,8 @@
 #ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
 #define ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
 
+#include "absl/base/config.h"
+
 #if defined(ABSL_STACKTRACE_INL_HEADER)
 #error ABSL_STACKTRACE_INL_HEADER cannot be directly set
 
@@ -28,43 +30,51 @@
 #define ABSL_STACKTRACE_INL_HEADER \
     "absl/debugging/internal/stacktrace_win32-inl.inc"
 
+#elif defined(__APPLE__)
+#ifdef ABSL_HAVE_THREAD_LOCAL
+// Thread local support required for UnwindImpl.
+#define ABSL_STACKTRACE_INL_HEADER \
+  "absl/debugging/internal/stacktrace_generic-inl.inc"
+#endif
+
 #elif defined(__linux__) && !defined(__ANDROID__)
 
-#if !defined(NO_FRAME_POINTER)
-# if defined(__i386__) || defined(__x86_64__)
+#if defined(NO_FRAME_POINTER) && \
+    (defined(__i386__) || defined(__x86_64__) || defined(__aarch64__))
+// Note: The libunwind-based implementation is not available to open-source
+// users.
 #define ABSL_STACKTRACE_INL_HEADER \
-    "absl/debugging/internal/stacktrace_x86-inl.inc"
-# elif defined(__ppc__) || defined(__PPC__)
-#define ABSL_STACKTRACE_INL_HEADER \
-    "absl/debugging/internal/stacktrace_powerpc-inl.inc"
-# elif defined(__aarch64__)
-#define ABSL_STACKTRACE_INL_HEADER \
-    "absl/debugging/internal/stacktrace_aarch64-inl.inc"
-# elif defined(__arm__)
+  "absl/debugging/internal/stacktrace_libunwind-inl.inc"
+#define STACKTRACE_USES_LIBUNWIND 1
+#elif defined(NO_FRAME_POINTER) && defined(__has_include)
+#if __has_include(<execinfo.h>)
 // Note: When using glibc this may require -funwind-tables to function properly.
 #define ABSL_STACKTRACE_INL_HEADER \
   "absl/debugging/internal/stacktrace_generic-inl.inc"
-# else
+#endif
+#elif defined(__i386__) || defined(__x86_64__)
 #define ABSL_STACKTRACE_INL_HEADER \
-   "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
-# endif
-#else  // defined(NO_FRAME_POINTER)
-# if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
+  "absl/debugging/internal/stacktrace_x86-inl.inc"
+#elif defined(__ppc__) || defined(__PPC__)
 #define ABSL_STACKTRACE_INL_HEADER \
-    "absl/debugging/internal/stacktrace_generic-inl.inc"
-# elif defined(__ppc__) || defined(__PPC__)
+  "absl/debugging/internal/stacktrace_powerpc-inl.inc"
+#elif defined(__aarch64__)
 #define ABSL_STACKTRACE_INL_HEADER \
-    "absl/debugging/internal/stacktrace_generic-inl.inc"
-# else
+  "absl/debugging/internal/stacktrace_aarch64-inl.inc"
+#elif defined(__has_include)
+#if __has_include(<execinfo.h>)
+// Note: When using glibc this may require -funwind-tables to function properly.
 #define ABSL_STACKTRACE_INL_HEADER \
-   "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
-# endif
-#endif  // NO_FRAME_POINTER
+  "absl/debugging/internal/stacktrace_generic-inl.inc"
+#endif
+#endif
 
-#else
+#endif
+
+// Fallback to the empty implementation.
+#if !defined(ABSL_STACKTRACE_INL_HEADER)
 #define ABSL_STACKTRACE_INL_HEADER \
   "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
-
 #endif
 
 #endif  // ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
diff --git a/absl/debugging/internal/stacktrace_generic-inl.inc b/absl/debugging/internal/stacktrace_generic-inl.inc
index ac034c9..b2792a1 100644
--- a/absl/debugging/internal/stacktrace_generic-inl.inc
+++ b/absl/debugging/internal/stacktrace_generic-inl.inc
@@ -1,7 +1,16 @@
-// Copyright 2000 - 2007 Google Inc.
-// All rights reserved.
+// Copyright 2017 The Abseil Authors.
 //
-// Author: Sanjay Ghemawat
+// 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.
 //
 // Portable implementation - just use glibc
 //
diff --git a/absl/debugging/internal/stacktrace_powerpc-inl.inc b/absl/debugging/internal/stacktrace_powerpc-inl.inc
index 2e7c2f4..cf8c051 100644
--- a/absl/debugging/internal/stacktrace_powerpc-inl.inc
+++ b/absl/debugging/internal/stacktrace_powerpc-inl.inc
@@ -131,7 +131,12 @@
       const ucontext_t* signal_context =
           reinterpret_cast<const ucontext_t*>(uc);
       void **const sp_before_signal =
-          reinterpret_cast<void**>(signal_context->uc_mcontext.gp_regs[PT_R1]);
+#if defined(__PPC64__)
+          reinterpret_cast<void **>(signal_context->uc_mcontext.gp_regs[PT_R1]);
+#else
+          reinterpret_cast<void **>(
+              signal_context->uc_mcontext.uc_regs->gregs[PT_R1]);
+#endif
       // Check that alleged sp before signal is nonnull and is reasonably
       // aligned.
       if (sp_before_signal != nullptr &&
diff --git a/absl/debugging/internal/stacktrace_win32-inl.inc b/absl/debugging/internal/stacktrace_win32-inl.inc
index 9c2c558..1c666c8 100644
--- a/absl/debugging/internal/stacktrace_win32-inl.inc
+++ b/absl/debugging/internal/stacktrace_win32-inl.inc
@@ -46,11 +46,19 @@
     OUT PVOID *backtrace,
     OUT PULONG backtrace_hash);
 
+// It is not possible to load RtlCaptureStackBackTrace at static init time in
+// UWP. CaptureStackBackTrace is the public version of RtlCaptureStackBackTrace
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
+    !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
+    &::CaptureStackBackTrace;
+#else
 // Load the function we need at static init time, where we don't have
 // to worry about someone else holding the loader's lock.
 static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
-   (RtlCaptureStackBackTrace_Function*)
-   GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace");
+    (RtlCaptureStackBackTrace_Function*)GetProcAddress(
+        GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace");
+#endif  // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP
 
 template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
 static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
diff --git a/absl/debugging/internal/symbolize.h b/absl/debugging/internal/symbolize.h
index 5d0858b..4f26130 100644
--- a/absl/debugging/internal/symbolize.h
+++ b/absl/debugging/internal/symbolize.h
@@ -18,10 +18,13 @@
 #ifndef ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_
 #define ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_
 
+#ifdef __cplusplus
+
 #include <cstddef>
 #include <cstdint>
 
 #include "absl/base/config.h"
+#include "absl/strings/string_view.h"
 
 #ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
 #error ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE cannot be directly set
@@ -45,7 +48,7 @@
 //
 // This is not async-signal-safe.
 bool ForEachSection(int fd,
-                    const std::function<bool(const std::string& name,
+                    const std::function<bool(absl::string_view name,
                                              const ElfW(Shdr) &)>& callback);
 
 // Gets the section header for the given name, if it exists. Returns true on
@@ -59,6 +62,12 @@
 
 #endif  // ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
 
+#ifdef ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE
+#error ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE cannot be directly set
+#elif defined(__APPLE__)
+#define ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE 1
+#endif
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace debugging_internal {
@@ -109,20 +118,30 @@
 //   filename != nullptr
 //
 // Returns true if the file was successfully registered.
-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);
 
 // Looks up the file mapping registered by RegisterFileMappingHint for an
 // address range. If there is one, the file name is stored in *filename and
 // *start and *end are modified to reflect the registered mapping. Returns
 // whether any hint was found.
-bool GetFileMappingHint(const void** start,
-                        const void** end,
-                        uint64_t    *  offset,
+bool GetFileMappingHint(const void** start, const void** end, uint64_t* offset,
                         const char** filename);
 
 }  // namespace debugging_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
 
+#endif  // __cplusplus
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C"
+#endif  // __cplusplus
+
+    bool
+    AbslInternalGetFileMappingHint(const void** start, const void** end,
+                                   uint64_t* offset, const char** filename);
+
 #endif  // ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_
diff --git a/absl/debugging/internal/vdso_support.cc b/absl/debugging/internal/vdso_support.cc
index 1e8a78a..6be16d9 100644
--- a/absl/debugging/internal/vdso_support.cc
+++ b/absl/debugging/internal/vdso_support.cc
@@ -76,15 +76,6 @@
   }
 #endif  // __GLIBC_PREREQ(2, 16)
   if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) {
-    // Valgrind zaps AT_SYSINFO_EHDR and friends from the auxv[]
-    // on stack, and so glibc works as if VDSO was not present.
-    // But going directly to kernel via /proc/self/auxv below bypasses
-    // Valgrind zapping. So we check for Valgrind separately.
-    if (RunningOnValgrind()) {
-      vdso_base_.store(nullptr, std::memory_order_relaxed);
-      getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed);
-      return nullptr;
-    }
     int fd = open("/proc/self/auxv", O_RDONLY);
     if (fd == -1) {
       // Kernel too old to have a VDSO.
@@ -175,18 +166,6 @@
   return ret_code == 0 ? cpu : ret_code;
 }
 
-// We need to make sure VDSOSupport::Init() is called before
-// InitGoogle() does any setuid or chroot calls.  If VDSOSupport
-// is used in any global constructor, this will happen, since
-// VDSOSupport's constructor calls Init.  But if not, we need to
-// ensure it here, with a global constructor of our own.  This
-// is an allowed exception to the normal rule against non-trivial
-// global constructors.
-static class VDSOInitHelper {
- public:
-  VDSOInitHelper() { VDSOSupport::Init(); }
-} vdso_init_helper;
-
 }  // namespace debugging_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/debugging/leak_check.cc b/absl/debugging/leak_check.cc
index ff90495..764ca0a 100644
--- a/absl/debugging/leak_check.cc
+++ b/absl/debugging/leak_check.cc
@@ -16,6 +16,7 @@
 // When lsan is not linked in, these functions are not available,
 // therefore Abseil code which depends on these functions is conditioned on the
 // definition of LEAK_SANITIZER.
+#include "absl/base/attributes.h"
 #include "absl/debugging/leak_check.h"
 
 #ifndef LEAK_SANITIZER
@@ -23,6 +24,7 @@
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 bool HaveLeakSanitizer() { return false; }
+bool LeakCheckerIsActive() { return false; }
 void DoIgnoreLeak(const void*) { }
 void RegisterLivePointers(const void*, size_t) { }
 void UnRegisterLivePointers(const void*, size_t) { }
@@ -35,9 +37,23 @@
 
 #include <sanitizer/lsan_interface.h>
 
+#if ABSL_HAVE_ATTRIBUTE_WEAK
+extern "C" ABSL_ATTRIBUTE_WEAK int __lsan_is_turned_off();
+#endif
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 bool HaveLeakSanitizer() { return true; }
+
+#if ABSL_HAVE_ATTRIBUTE_WEAK
+bool LeakCheckerIsActive() {
+  return !(&__lsan_is_turned_off && __lsan_is_turned_off());
+}
+#else
+bool LeakCheckerIsActive() { return true; }
+#endif
+
+bool FindAndReportLeaks() { return __lsan_do_recoverable_leak_check(); }
 void DoIgnoreLeak(const void* ptr) { __lsan_ignore_object(ptr); }
 void RegisterLivePointers(const void* ptr, size_t size) {
   __lsan_register_root_region(ptr, size);
diff --git a/absl/debugging/leak_check.h b/absl/debugging/leak_check.h
index 7a5a22d..5fc2b05 100644
--- a/absl/debugging/leak_check.h
+++ b/absl/debugging/leak_check.h
@@ -43,6 +43,12 @@
 // currently built into this target.
 bool HaveLeakSanitizer();
 
+// LeakCheckerIsActive()
+//
+// Returns true if a leak-checking sanitizer (either ASan or standalone LSan) is
+// currently built into this target and is turned on.
+bool LeakCheckerIsActive();
+
 // DoIgnoreLeak()
 //
 // Implements `IgnoreLeak()` below. This function should usually
@@ -62,7 +68,8 @@
 //
 // If the passed `ptr` does not point to an actively allocated object at the
 // time `IgnoreLeak()` is called, the call is a no-op; if it is actively
-// allocated, the object must not get deallocated later.
+// allocated, leak sanitizer will assume this object is referenced even if
+// there is no actual reference in user memory.
 //
 template <typename T>
 T* IgnoreLeak(T* ptr) {
@@ -70,6 +77,19 @@
   return ptr;
 }
 
+// FindAndReportLeaks()
+//
+// If any leaks are detected, prints a leak report and returns true.  This
+// function may be called repeatedly, and does not affect end-of-process leak
+// checking.
+//
+// Example:
+// if (FindAndReportLeaks()) {
+//   ... diagnostic already printed. Exit with failure code.
+//   exit(1)
+// }
+bool FindAndReportLeaks();
+
 // LeakCheckDisabler
 //
 // This helper class indicates that any heap allocations done in the code block
diff --git a/absl/debugging/leak_check_fail_test.cc b/absl/debugging/leak_check_fail_test.cc
index 2887cea..c49b81a 100644
--- a/absl/debugging/leak_check_fail_test.cc
+++ b/absl/debugging/leak_check_fail_test.cc
@@ -25,7 +25,7 @@
   // failed exit code.
 
   char* foo = strdup("lsan should complain about this leaked string");
-  ABSL_RAW_LOG(INFO, "Should detect leaked std::string %s", foo);
+  ABSL_RAW_LOG(INFO, "Should detect leaked string %s", foo);
 }
 
 TEST(LeakCheckTest, LeakMemoryAfterDisablerScope) {
@@ -34,7 +34,7 @@
   // failed exit code.
   { absl::LeakCheckDisabler disabler; }
   char* foo = strdup("lsan should also complain about this leaked string");
-  ABSL_RAW_LOG(INFO, "Re-enabled leak detection.Should detect leaked std::string %s",
+  ABSL_RAW_LOG(INFO, "Re-enabled leak detection.Should detect leaked string %s",
                foo);
 }
 
diff --git a/absl/debugging/leak_check_test.cc b/absl/debugging/leak_check_test.cc
index 93a7edd..9fcfc8e 100644
--- a/absl/debugging/leak_check_test.cc
+++ b/absl/debugging/leak_check_test.cc
@@ -23,20 +23,22 @@
 TEST(LeakCheckTest, DetectLeakSanitizer) {
 #ifdef ABSL_EXPECT_LEAK_SANITIZER
   EXPECT_TRUE(absl::HaveLeakSanitizer());
+  EXPECT_TRUE(absl::LeakCheckerIsActive());
 #else
   EXPECT_FALSE(absl::HaveLeakSanitizer());
+  EXPECT_FALSE(absl::LeakCheckerIsActive());
 #endif
 }
 
 TEST(LeakCheckTest, IgnoreLeakSuppressesLeakedMemoryErrors) {
   auto foo = absl::IgnoreLeak(new std::string("some ignored leaked string"));
-  ABSL_RAW_LOG(INFO, "Ignoring leaked std::string %s", foo->c_str());
+  ABSL_RAW_LOG(INFO, "Ignoring leaked string %s", foo->c_str());
 }
 
 TEST(LeakCheckTest, LeakCheckDisablerIgnoresLeak) {
   absl::LeakCheckDisabler disabler;
-  auto foo = new std::string("some std::string leaked while checks are disabled");
-  ABSL_RAW_LOG(INFO, "Ignoring leaked std::string %s", foo->c_str());
+  auto foo = new std::string("some string leaked while checks are disabled");
+  ABSL_RAW_LOG(INFO, "Ignoring leaked string %s", foo->c_str());
 }
 
 }  // namespace
diff --git a/absl/debugging/symbolize.cc b/absl/debugging/symbolize.cc
index 54ed970..5e4a25d 100644
--- a/absl/debugging/symbolize.cc
+++ b/absl/debugging/symbolize.cc
@@ -14,12 +14,23 @@
 
 #include "absl/debugging/symbolize.h"
 
+#ifdef _WIN32
+#include <winapifamily.h>
+#if !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)) || \
+    WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+// UWP doesn't have access to win32 APIs.
+#define ABSL_INTERNAL_HAVE_SYMBOLIZE_WIN32
+#endif
+#endif
+
 #if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE)
 #include "absl/debugging/symbolize_elf.inc"
-#elif defined(_WIN32)
+#elif defined(ABSL_INTERNAL_HAVE_SYMBOLIZE_WIN32)
 // The Windows Symbolizer only works if PDB files containing the debug info
 // are available to the program at runtime.
 #include "absl/debugging/symbolize_win32.inc"
+#elif defined(__APPLE__)
+#include "absl/debugging/symbolize_darwin.inc"
 #else
 #include "absl/debugging/symbolize_unimplemented.inc"
 #endif
diff --git a/absl/debugging/symbolize_darwin.inc b/absl/debugging/symbolize_darwin.inc
new file mode 100644
index 0000000..443ce9e
--- /dev/null
+++ b/absl/debugging/symbolize_darwin.inc
@@ -0,0 +1,101 @@
+// 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 <cxxabi.h>
+#include <execinfo.h>
+
+#include <algorithm>
+#include <cstring>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/debugging/internal/demangle.h"
+#include "absl/strings/numbers.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+void InitializeSymbolizer(const char*) {}
+
+namespace debugging_internal {
+namespace {
+
+static std::string GetSymbolString(absl::string_view backtrace_line) {
+  // Example Backtrace lines:
+  // 0   libimaging_shared.dylib             0x018c152a
+  // _ZNSt11_Deque_baseIN3nik7mediadb4PageESaIS2_EE17_M_initialize_mapEm + 3478
+  //
+  // or
+  // 0   libimaging_shared.dylib             0x0000000001895c39
+  // _ZN3nik4util19register_shared_ptrINS_3gpu7TextureEEEvPKvS5_ + 39
+  //
+  // or
+  // 0   mysterious_app                      0x0124000120120009 main + 17
+  auto address_pos = backtrace_line.find(" 0x");
+  if (address_pos == absl::string_view::npos) return std::string();
+  absl::string_view symbol_view = backtrace_line.substr(address_pos + 1);
+
+  auto space_pos = symbol_view.find(" ");
+  if (space_pos == absl::string_view::npos) return std::string();
+  symbol_view = symbol_view.substr(space_pos + 1);  // to mangled symbol
+
+  auto plus_pos = symbol_view.find(" + ");
+  if (plus_pos == absl::string_view::npos) return std::string();
+  symbol_view = symbol_view.substr(0, plus_pos);  // strip remainng
+
+  return std::string(symbol_view);
+}
+
+}  // namespace
+}  // namespace debugging_internal
+
+bool Symbolize(const void* pc, char* out, int out_size) {
+  if (out_size <= 0 || pc == nullptr) {
+    out = nullptr;
+    return false;
+  }
+
+  // This allocates a char* array.
+  char** frame_strings = backtrace_symbols(const_cast<void**>(&pc), 1);
+
+  if (frame_strings == nullptr) return false;
+
+  std::string symbol = debugging_internal::GetSymbolString(frame_strings[0]);
+  free(frame_strings);
+
+  char tmp_buf[1024];
+  if (debugging_internal::Demangle(symbol.c_str(), tmp_buf, sizeof(tmp_buf))) {
+    size_t len = strlen(tmp_buf);
+    if (len + 1 <= static_cast<size_t>(out_size)) {  // +1 for '\0'
+      assert(len < sizeof(tmp_buf));
+      memmove(out, tmp_buf, len + 1);
+    }
+  } else {
+    strncpy(out, symbol.c_str(), out_size);
+  }
+
+  if (out[out_size - 1] != '\0') {
+    // strncpy() does not '\0' terminate when it truncates.
+    static constexpr char kEllipsis[] = "...";
+    int ellipsis_size = std::min<int>(sizeof(kEllipsis) - 1, out_size - 1);
+    memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size);
+    out[out_size - 1] = '\0';
+  }
+
+  return true;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/debugging/symbolize_elf.inc b/absl/debugging/symbolize_elf.inc
index c371635..f4d5727 100644
--- a/absl/debugging/symbolize_elf.inc
+++ b/absl/debugging/symbolize_elf.inc
@@ -57,6 +57,7 @@
 #include <unistd.h>
 
 #include <algorithm>
+#include <array>
 #include <atomic>
 #include <cerrno>
 #include <cinttypes>
@@ -74,6 +75,7 @@
 #include "absl/base/port.h"
 #include "absl/debugging/internal/demangle.h"
 #include "absl/debugging/internal/vdso_support.h"
+#include "absl/strings/string_view.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -82,6 +84,12 @@
 static char *argv0_value = nullptr;
 
 void InitializeSymbolizer(const char *argv0) {
+#ifdef ABSL_HAVE_VDSO_SUPPORT
+  // We need to make sure VDSOSupport::Init() is called before any setuid or
+  // chroot calls, so InitializeSymbolizer() should be called very early in the
+  // life of a program.
+  absl::debugging_internal::VDSOSupport::Init();
+#endif
   if (argv0_value != nullptr) {
     free(argv0_value);
     argv0_value = nullptr;
@@ -149,13 +157,15 @@
 // Moreover, we are using only TryLock(), 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.
-base_internal::SpinLock g_decorators_mu(base_internal::kLinkerInitialized);
+ABSL_CONST_INIT absl::base_internal::SpinLock g_decorators_mu(
+    absl::kConstInit, 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.
-base_internal::SpinLock g_file_mapping_mu(base_internal::kLinkerInitialized);
+ABSL_CONST_INIT absl::base_internal::SpinLock g_file_mapping_mu(
+    absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY);
 
 // Async-signal-safe function to zero a buffer.
 // memset() is not guaranteed to be async-signal-safe.
@@ -175,6 +185,7 @@
         fd(-1),
         elf_type(-1) {
     SafeMemZero(&elf_header, sizeof(elf_header));
+    SafeMemZero(&phdr[0], sizeof(phdr));
   }
 
   char *filename;
@@ -187,6 +198,10 @@
   int fd;
   int elf_type;
   ElfW(Ehdr) elf_header;
+
+  // PT_LOAD program header describing executable code.
+  // Normally we expect just one, but SWIFT binaries have two.
+  std::array<ElfW(Phdr), 2> phdr;
 };
 
 // Build 4-way associative cache for symbols. Within each cache line, symbols
@@ -496,7 +511,7 @@
 const int kMaxSectionNameLen = 64;
 
 bool ForEachSection(int fd,
-                    const std::function<bool(const std::string &name,
+                    const std::function<bool(absl::string_view name,
                                              const ElfW(Shdr) &)> &callback) {
   ElfW(Ehdr) elf_header;
   if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
@@ -518,7 +533,7 @@
       return false;
     }
     off_t name_offset = shstrtab.sh_offset + out.sh_name;
-    char header_name[kMaxSectionNameLen + 1];
+    char header_name[kMaxSectionNameLen];
     ssize_t n_read =
         ReadFromOffset(fd, &header_name, kMaxSectionNameLen, name_offset);
     if (n_read == -1) {
@@ -527,9 +542,8 @@
       // Long read?
       return false;
     }
-    header_name[n_read] = '\0';
 
-    std::string name(header_name);
+    absl::string_view name(header_name, strnlen(header_name, n_read));
     if (!callback(name, out)) {
       break;
     }
@@ -1264,6 +1278,36 @@
       ABSL_RAW_LOG(WARNING, "%s: failed to read elf header", obj->filename);
       return false;
     }
+    const int phnum = obj->elf_header.e_phnum;
+    const int phentsize = obj->elf_header.e_phentsize;
+    size_t phoff = obj->elf_header.e_phoff;
+    size_t num_executable_load_segments = 0;
+    for (int j = 0; j < phnum; j++) {
+      ElfW(Phdr) phdr;
+      if (!ReadFromOffsetExact(obj->fd, &phdr, sizeof(phdr), phoff)) {
+        ABSL_RAW_LOG(WARNING, "%s: failed to read program header %d",
+                     obj->filename, j);
+        return false;
+      }
+      phoff += phentsize;
+      constexpr int rx = PF_X | PF_R;
+      if (phdr.p_type != PT_LOAD || (phdr.p_flags & rx) != rx) {
+        // Not a LOAD segment, or not executable code.
+        continue;
+      }
+      if (num_executable_load_segments < obj->phdr.size()) {
+        memcpy(&obj->phdr[num_executable_load_segments++], &phdr, sizeof(phdr));
+      } else {
+        ABSL_RAW_LOG(WARNING, "%s: too many executable LOAD segments",
+                     obj->filename);
+        break;
+      }
+    }
+    if (num_executable_load_segments == 0) {
+      // This object has no "r-x" LOAD segments. That's unexpected.
+      ABSL_RAW_LOG(WARNING, "%s: no executable LOAD segments", obj->filename);
+      return false;
+    }
   }
   return true;
 }
@@ -1287,23 +1331,52 @@
   int fd = -1;
   if (obj != nullptr) {
     if (MaybeInitializeObjFile(obj)) {
-      if (obj->elf_type == ET_DYN &&
-          reinterpret_cast<uint64_t>(obj->start_addr) >= obj->offset) {
+      const size_t start_addr = reinterpret_cast<size_t>(obj->start_addr);
+      if (obj->elf_type == ET_DYN && start_addr >= obj->offset) {
         // This object was relocated.
         //
         // For obj->offset > 0, adjust the relocation since a mapping at offset
         // X in the file will have a start address of [true relocation]+X.
-        relocation = reinterpret_cast<ptrdiff_t>(obj->start_addr) - obj->offset;
+        relocation = start_addr - obj->offset;
+
+        // Note: some binaries have multiple "rx" LOAD segments. We must
+        // find the right one.
+        ElfW(Phdr) *phdr = nullptr;
+        for (size_t j = 0; j < obj->phdr.size(); j++) {
+          ElfW(Phdr) &p = obj->phdr[j];
+          if (p.p_type != PT_LOAD) {
+            // We only expect PT_LOADs. This must be PT_NULL that we didn't
+            // write over (i.e. we exhausted all interesting PT_LOADs).
+            ABSL_RAW_CHECK(p.p_type == PT_NULL, "unexpected p_type");
+            break;
+          }
+          if (pc < reinterpret_cast<void *>(start_addr + p.p_memsz)) {
+            phdr = &p;
+            break;
+          }
+        }
+        if (phdr == nullptr) {
+          // That's unexpected. Hope for the best.
+          ABSL_RAW_LOG(
+              WARNING,
+              "%s: unable to find LOAD segment for pc: %p, start_addr: %zx",
+              obj->filename, pc, start_addr);
+        } else {
+          // Adjust relocation in case phdr.p_vaddr != 0.
+          // This happens for binaries linked with `lld --rosegment`, and for
+          // binaries linked with BFD `ld -z separate-code`.
+          relocation -= phdr->p_vaddr - phdr->p_offset;
+        }
       }
 
       fd = obj->fd;
-    }
-    if (GetSymbolFromObjectFile(*obj, pc, relocation, symbol_buf_,
-                                sizeof(symbol_buf_), tmp_buf_,
-                                sizeof(tmp_buf_)) == SYMBOL_FOUND) {
-      // Only try to demangle the symbol name if it fit into symbol_buf_.
-      DemangleInplace(symbol_buf_, sizeof(symbol_buf_), tmp_buf_,
-                      sizeof(tmp_buf_));
+      if (GetSymbolFromObjectFile(*obj, pc, relocation, symbol_buf_,
+                                  sizeof(symbol_buf_), tmp_buf_,
+                                  sizeof(tmp_buf_)) == SYMBOL_FOUND) {
+        // Only try to demangle the symbol name if it fit into symbol_buf_.
+        DemangleInplace(symbol_buf_, sizeof(symbol_buf_), tmp_buf_,
+                        sizeof(tmp_buf_));
+      }
     }
   } else {
 #if ABSL_HAVE_VDSO_SUPPORT
@@ -1374,7 +1447,7 @@
 
   if (!g_decorators_mu.TryLock()) {
     // Someone else is using decorators. Get out.
-    return false;
+    return -2;
   }
   int ret = ticket;
   if (g_num_decorators >= kMaxDecorators) {
@@ -1402,7 +1475,7 @@
   if (g_num_file_mapping_hints >= kMaxFileMappingHints) {
     ret = false;
   } else {
-    // TODO(ckennelly): Move this into a std::string copy routine.
+    // TODO(ckennelly): Move this into a string copy routine.
     int len = strlen(filename);
     char *dst = static_cast<char *>(
         base_internal::LowLevelAlloc::AllocWithArena(len + 1, SigSafeArena()));
@@ -1453,7 +1526,7 @@
 
 bool Symbolize(const void *pc, char *out, int out_size) {
   // Symbolization is very slow under tsan.
-  ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
+  ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
   SAFE_ASSERT(out_size >= 0);
   debugging_internal::Symbolizer *s = debugging_internal::AllocateSymbolizer();
   const char *name = s->GetSymbol(pc);
@@ -1472,9 +1545,16 @@
     }
   }
   debugging_internal::FreeSymbolizer(s);
-  ANNOTATE_IGNORE_READS_AND_WRITES_END();
+  ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END();
   return ok;
 }
 
 ABSL_NAMESPACE_END
 }  // namespace absl
+
+extern "C" bool AbslInternalGetFileMappingHint(const void **start,
+                                               const void **end, uint64_t *offset,
+                                               const char **filename) {
+  return absl::debugging_internal::GetFileMappingHint(start, end, offset,
+                                                      filename);
+}
diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc
index a1d03aa..a2dd495 100644
--- a/absl/debugging/symbolize_test.cc
+++ b/absl/debugging/symbolize_test.cc
@@ -27,11 +27,13 @@
 #include "gtest/gtest.h"
 #include "absl/base/attributes.h"
 #include "absl/base/casts.h"
+#include "absl/base/config.h"
 #include "absl/base/internal/per_thread_tls.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/optimization.h"
 #include "absl/debugging/internal/stack_consumption.h"
 #include "absl/memory/memory.h"
+#include "absl/strings/string_view.h"
 
 using testing::Contains;
 
@@ -144,7 +146,8 @@
   return TrySymbolizeWithLimit(pc, sizeof(try_symbolize_buffer));
 }
 
-#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) || \
+    defined(ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE)
 
 TEST(Symbolize, Cached) {
   // Compilers should give us pointers to them.
@@ -218,8 +221,8 @@
 static int GetStackConsumptionUpperLimit() {
   // Symbolize stack consumption should be within 2kB.
   int stack_consumption_upper_limit = 2048;
-#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
-    defined(THREAD_SANITIZER)
+#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
+    defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER)
   // Account for sanitizer instrumentation requiring additional stack space.
   stack_consumption_upper_limit *= 5;
 #endif
@@ -258,6 +261,7 @@
 
 #endif  // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
 
+#ifndef ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE
 // Use a 64K page size for PPC.
 const size_t kPageSize = 64 << 10;
 // We place a read-only symbols into the .text section and verify that we can
@@ -399,8 +403,8 @@
 
   std::vector<std::string> sections;
   ASSERT_TRUE(absl::debugging_internal::ForEachSection(
-      fd, [&sections](const std::string &name, const ElfW(Shdr) &) {
-        sections.push_back(name);
+      fd, [&sections](const absl::string_view name, const ElfW(Shdr) &) {
+        sections.emplace_back(name);
         return true;
       }));
 
@@ -413,6 +417,7 @@
 
   close(fd);
 }
+#endif  // !ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE
 
 // x86 specific tests.  Uses some inline assembler.
 extern "C" {
@@ -541,7 +546,8 @@
   absl::InitializeSymbolizer(argv[0]);
   testing::InitGoogleTest(&argc, argv);
 
-#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) || \
+    defined(ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE)
   TestWithPCInsideInlineFunction();
   TestWithPCInsideNonInlineFunction();
   TestWithReturnAddress();
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel
index cdb4e7e..147249e 100644
--- a/absl/flags/BUILD.bazel
+++ b/absl/flags/BUILD.bazel
@@ -14,7 +14,7 @@
 # limitations under the License.
 #
 
-load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
 load(
     "//absl:copts/configure_copts.bzl",
     "ABSL_DEFAULT_COPTS",
@@ -24,29 +24,21 @@
 
 package(default_visibility = ["//visibility:public"])
 
-licenses(["notice"])  # Apache 2.0
+licenses(["notice"])
 
 cc_library(
-    name = "flag_internal",
-    srcs = [
-        "internal/flag.cc",
-    ],
+    name = "path_util",
     hdrs = [
-        "internal/flag.h",
+        "internal/path_util.h",
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
-    visibility = ["//absl/base:__subpackages__"],
+    visibility = [
+        "//absl/flags:__pkg__",
+    ],
     deps = [
-        ":config",
-        ":handle",
-        ":registry",
-        "//absl/base",
         "//absl/base:config",
-        "//absl/base:core_headers",
-        "//absl/memory",
         "//absl/strings",
-        "//absl/synchronization",
     ],
 )
 
@@ -73,22 +65,6 @@
 )
 
 cc_library(
-    name = "path_util",
-    hdrs = [
-        "internal/path_util.h",
-    ],
-    copts = ABSL_DEFAULT_COPTS,
-    linkopts = ABSL_DEFAULT_LINKOPTS,
-    visibility = [
-        "//absl/flags:__pkg__",
-    ],
-    deps = [
-        "//absl/base:config",
-        "//absl/strings",
-    ],
-)
-
-cc_library(
     name = "config",
     srcs = [
         "usage_config.cc",
@@ -129,34 +105,47 @@
 )
 
 cc_library(
-    name = "handle",
+    name = "commandlineflag_internal",
+    srcs = [
+        "internal/commandlineflag.cc",
+    ],
     hdrs = [
         "internal/commandlineflag.h",
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
-    visibility = [
-        "//absl/flags:__pkg__",
-    ],
     deps = [
-        ":config",
-        ":marshalling",
         "//absl/base:config",
-        "//absl/base:core_headers",
+        "//absl/base:fast_type_id",
+    ],
+)
+
+cc_library(
+    name = "commandlineflag",
+    srcs = [
+        "commandlineflag.cc",
+    ],
+    hdrs = [
+        "commandlineflag.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":commandlineflag_internal",
+        "//absl/base:config",
+        "//absl/base:fast_type_id",
         "//absl/strings",
         "//absl/types:optional",
     ],
 )
 
 cc_library(
-    name = "registry",
+    name = "private_handle_accessor",
     srcs = [
-        "internal/registry.cc",
-        "internal/type_erased.cc",
+        "internal/private_handle_accessor.cc",
     ],
     hdrs = [
-        "internal/registry.h",
-        "internal/type_erased.h",
+        "internal/private_handle_accessor.h",
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
@@ -164,17 +153,67 @@
         "//absl/flags:__pkg__",
     ],
     deps = [
+        ":commandlineflag",
+        ":commandlineflag_internal",
+        "//absl/base:config",
+        "//absl/strings",
+    ],
+)
+
+cc_library(
+    name = "reflection",
+    srcs = [
+        "reflection.cc",
+    ],
+    hdrs = [
+        "internal/registry.h",
+        "reflection.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":commandlineflag",
+        ":commandlineflag_internal",
         ":config",
-        ":handle",
+        ":private_handle_accessor",
         "//absl/base:config",
         "//absl/base:core_headers",
-        "//absl/base:raw_logging_internal",
+        "//absl/container:flat_hash_map",
         "//absl/strings",
         "//absl/synchronization",
     ],
 )
 
 cc_library(
+    name = "flag_internal",
+    srcs = [
+        "internal/flag.cc",
+    ],
+    hdrs = [
+        "internal/flag.h",
+        "internal/sequence_lock.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = ["//absl/base:__subpackages__"],
+    deps = [
+        ":commandlineflag",
+        ":commandlineflag_internal",
+        ":config",
+        ":marshalling",
+        ":reflection",
+        "//absl/base",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/memory",
+        "//absl/meta:type_traits",
+        "//absl/strings",
+        "//absl/synchronization",
+        "//absl/utility",
+    ],
+)
+
+cc_library(
     name = "flag",
     srcs = [
         "flag.cc",
@@ -188,9 +227,7 @@
     deps = [
         ":config",
         ":flag_internal",
-        ":handle",
-        ":marshalling",
-        ":registry",
+        ":reflection",
         "//absl/base",
         "//absl/base:config",
         "//absl/base:core_headers",
@@ -212,13 +249,14 @@
         "//absl/flags:__pkg__",
     ],
     deps = [
+        ":commandlineflag",
         ":config",
         ":flag",
         ":flag_internal",
-        ":handle",
         ":path_util",
+        ":private_handle_accessor",
         ":program_name",
-        ":registry",
+        ":reflection",
         "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/strings",
@@ -254,12 +292,14 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        ":commandlineflag",
+        ":commandlineflag_internal",
         ":config",
         ":flag",
         ":flag_internal",
-        ":handle",
+        ":private_handle_accessor",
         ":program_name",
-        ":registry",
+        ":reflection",
         ":usage",
         ":usage_internal",
         "//absl/base:config",
@@ -276,15 +316,17 @@
     name = "commandlineflag_test",
     size = "small",
     srcs = [
-        "internal/commandlineflag_test.cc",
+        "commandlineflag_test.cc",
     ],
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        ":commandlineflag",
+        ":commandlineflag_internal",
         ":config",
         ":flag",
-        ":handle",
-        ":registry",
+        ":private_handle_accessor",
+        ":reflection",
         "//absl/memory",
         "//absl/strings",
         "@com_google_googletest//:gtest_main",
@@ -318,10 +360,12 @@
         ":config",
         ":flag",
         ":flag_internal",
-        ":handle",
-        ":registry",
+        ":marshalling",
+        ":reflection",
         "//absl/base:core_headers",
+        "//absl/base:malloc_internal",
         "//absl/strings",
+        "//absl/time",
         "@com_google_googletest//:gtest_main",
     ],
 )
@@ -333,10 +377,18 @@
         "flag_benchmark.cc",
     ],
     copts = ABSL_TEST_COPTS,
+    linkopts = select({
+        "//conditions:default": [],
+    }) + ABSL_DEFAULT_LINKOPTS,
     tags = ["benchmark"],
     visibility = ["//visibility:private"],
     deps = [
+        "flag_benchmark.lds",
         ":flag",
+        ":marshalling",
+        ":parse",
+        ":reflection",
+        "//absl/strings",
         "//absl/time",
         "//absl/types:optional",
         "@com_github_google_benchmark//:benchmark_main",
@@ -358,20 +410,6 @@
 )
 
 cc_test(
-    name = "path_util_test",
-    size = "small",
-    srcs = [
-        "internal/path_util_test.cc",
-    ],
-    copts = ABSL_TEST_COPTS,
-    linkopts = ABSL_DEFAULT_LINKOPTS,
-    deps = [
-        ":path_util",
-        "@com_google_googletest//:gtest_main",
-    ],
-)
-
-cc_test(
     name = "parse_test",
     size = "small",
     srcs = [
@@ -382,7 +420,8 @@
     deps = [
         ":flag",
         ":parse",
-        ":registry",
+        ":reflection",
+        ":usage_internal",
         "//absl/base:raw_logging_internal",
         "//absl/base:scoped_set_env",
         "//absl/strings",
@@ -392,6 +431,20 @@
 )
 
 cc_test(
+    name = "path_util_test",
+    size = "small",
+    srcs = [
+        "internal/path_util_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":path_util",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
     name = "program_name_test",
     size = "small",
     srcs = [
@@ -407,19 +460,40 @@
 )
 
 cc_test(
-    name = "type_erased_test",
+    name = "reflection_test",
     size = "small",
     srcs = [
-        "internal/type_erased_test.cc",
+        "reflection_test.cc",
     ],
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        ":commandlineflag_internal",
         ":flag",
-        ":handle",
         ":marshalling",
-        ":registry",
+        ":reflection",
+        ":usage_internal",
         "//absl/memory",
+        "//absl/strings",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "sequence_lock_test",
+    size = "small",
+    timeout = "moderate",
+    srcs = [
+        "internal/sequence_lock_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    shard_count = 31,
+    deps = [
+        ":flag_internal",
+        "//absl/base",
+        "//absl/container:fixed_array",
+        "//absl/time",
         "@com_google_googletest//:gtest_main",
     ],
 )
@@ -455,10 +529,9 @@
         ":parse",
         ":path_util",
         ":program_name",
-        ":registry",
+        ":reflection",
         ":usage",
         ":usage_internal",
-        "//absl/memory",
         "//absl/strings",
         "@com_google_googletest//:gtest",
     ],
diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt
index 1d25f0d..caac69c 100644
--- a/absl/flags/CMakeLists.txt
+++ b/absl/flags/CMakeLists.txt
@@ -17,22 +17,16 @@
 # Internal-only target, do not depend on directly.
 absl_cc_library(
   NAME
-    flags_internal
-  SRCS
-    "internal/flag.cc"
+    flags_path_util
   HDRS
-    "internal/flag.h"
+    "internal/path_util.h"
   COPTS
     ${ABSL_DEFAULT_COPTS}
   LINKOPTS
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
-    absl::base
     absl::config
-    absl::flags_config
-    absl::flags_handle
-    absl::flags_registry
-    absl::synchronization
+    absl::strings
   PUBLIC
 )
 
@@ -57,22 +51,6 @@
   PUBLIC
 )
 
-# Internal-only target, do not depend on directly.
-absl_cc_library(
-  NAME
-    flags_path_util
-  HDRS
-    "internal/path_util.h"
-  COPTS
-    ${ABSL_DEFAULT_COPTS}
-  LINKOPTS
-    ${ABSL_DEFAULT_LINKOPTS}
-  DEPS
-    absl::config
-    absl::strings
-  PUBLIC
-)
-
 absl_cc_library(
   NAME
     flags_config
@@ -116,7 +94,9 @@
 # Internal-only target, do not depend on directly.
 absl_cc_library(
   NAME
-    flags_handle
+    flags_commandlineflag_internal
+  SRCS
+    "internal/commandlineflag.cc"
   HDRS
     "internal/commandlineflag.h"
   COPTS
@@ -125,37 +105,93 @@
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
     absl::config
-    absl::flags_config
-    absl::flags_marshalling
-    absl::core_headers
-    absl::optional
-    absl::raw_logging_internal
-    absl::strings
-    absl::synchronization
+    absl::fast_type_id
 )
 
-# Internal-only target, do not depend on directly.
 absl_cc_library(
   NAME
-    flags_registry
+    flags_commandlineflag
   SRCS
-    "internal/registry.cc"
-    "internal/type_erased.cc"
+    "commandlineflag.cc"
   HDRS
-    "internal/registry.h"
-    "internal/type_erased.h"
+    "commandlineflag.h"
   COPTS
     ${ABSL_DEFAULT_COPTS}
   LINKOPTS
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
     absl::config
+    absl::fast_type_id
+    absl::flags_commandlineflag_internal
+    absl::optional
+    absl::strings
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+  NAME
+    flags_private_handle_accessor
+  SRCS
+    "internal/private_handle_accessor.cc"
+  HDRS
+    "internal/private_handle_accessor.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+    absl::config
+    absl::flags_commandlineflag
+    absl::flags_commandlineflag_internal
+    absl::strings
+)
+
+absl_cc_library(
+  NAME
+    flags_reflection
+  SRCS
+    "reflection.cc"
+  HDRS
+    "reflection.h"
+    "internal/registry.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+    absl::config
+    absl::flags_commandlineflag
+    absl::flags_private_handle_accessor
     absl::flags_config
-    absl::flags_handle
-    absl::core_headers
-    absl::raw_logging_internal
     absl::strings
     absl::synchronization
+    absl::flat_hash_map
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+  NAME
+    flags_internal
+  SRCS
+    "internal/flag.cc"
+  HDRS
+    "internal/flag.h"
+    "internal/sequence_lock.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+    absl::base
+    absl::config
+    absl::flags_commandlineflag
+    absl::flags_commandlineflag_internal
+    absl::flags_config
+    absl::flags_marshalling
+    absl::synchronization
+    absl::meta
+    absl::utility
+  PUBLIC
 )
 
 absl_cc_library(
@@ -172,11 +208,10 @@
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
     absl::config
+    absl::flags_commandlineflag
     absl::flags_config
-    absl::flags_handle
     absl::flags_internal
-    absl::flags_marshalling
-    absl::flags_registry
+    absl::flags_reflection
     absl::base
     absl::core_headers
     absl::strings
@@ -198,11 +233,12 @@
     absl::config
     absl::flags_config
     absl::flags
-    absl::flags_handle
+    absl::flags_commandlineflag
     absl::flags_internal
     absl::flags_path_util
+    absl::flags_private_handle_accessor
     absl::flags_program_name
-    absl::flags_registry
+    absl::flags_reflection
     absl::strings
     absl::synchronization
 )
@@ -243,10 +279,12 @@
     absl::core_headers
     absl::flags_config
     absl::flags
-    absl::flags_handle
+    absl::flags_commandlineflag
+    absl::flags_commandlineflag_internal
     absl::flags_internal
+    absl::flags_private_handle_accessor
     absl::flags_program_name
-    absl::flags_registry
+    absl::flags_reflection
     absl::flags_usage
     absl::strings
     absl::synchronization
@@ -259,14 +297,16 @@
   NAME
     flags_commandlineflag_test
   SRCS
-    "internal/commandlineflag_test.cc"
+    "commandlineflag_test.cc"
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
     absl::flags
+    absl::flags_commandlineflag
+    absl::flags_commandlineflag_internal
     absl::flags_config
-    absl::flags_handle
-    absl::flags_registry
+    absl::flags_private_handle_accessor
+    absl::flags_reflection
     absl::memory
     absl::strings
     gtest_main
@@ -296,10 +336,11 @@
     absl::core_headers
     absl::flags
     absl::flags_config
-    absl::flags_handle
     absl::flags_internal
-    absl::flags_registry
+    absl::flags_marshalling
+    absl::flags_reflection
     absl::strings
+    absl::time
     gtest_main
 )
 
@@ -325,7 +366,8 @@
   DEPS
     absl::flags
     absl::flags_parse
-    absl::flags_registry
+    absl::flags_reflection
+    absl::flags_usage_internal
     absl::raw_logging_internal
     absl::scoped_set_env
     absl::span
@@ -360,19 +402,33 @@
 
 absl_cc_test(
   NAME
-    flags_type_erased_test
+    flags_reflection_test
   SRCS
-    "internal/type_erased_test.cc"
+    "reflection_test.cc"
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
+    absl::flags_commandlineflag_internal
     absl::flags
-    absl::flags_handle
-    absl::flags_marshalling
-    absl::flags_registry
+    absl::flags_reflection
+    absl::flags_usage
     absl::memory
     absl::strings
-    gtest_main
+    gmock_main
+)
+
+absl_cc_test(
+  NAME
+    flags_sequence_lock_test
+  SRCS
+    "internal/sequence_lock_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::base
+    absl::flags_internal
+    absl::time
+    gmock_main
 )
 
 absl_cc_test(
@@ -403,9 +459,8 @@
     absl::flags_path_util
     absl::flags_program_name
     absl::flags_parse
-    absl::flags_registry
+    absl::flags_reflection
     absl::flags_usage
-    absl::memory
     absl::strings
     gtest
 )
diff --git a/absl/flags/commandlineflag.cc b/absl/flags/commandlineflag.cc
new file mode 100644
index 0000000..9f3b4a5
--- /dev/null
+++ b/absl/flags/commandlineflag.cc
@@ -0,0 +1,34 @@
+//
+// 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/flags/commandlineflag.h"
+
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+bool CommandLineFlag::IsRetired() const { return false; }
+bool CommandLineFlag::ParseFrom(absl::string_view value, std::string* error) {
+  return ParseFrom(value, flags_internal::SET_FLAGS_VALUE,
+                   flags_internal::kProgrammaticChange, *error);
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/flags/commandlineflag.h b/absl/flags/commandlineflag.h
new file mode 100644
index 0000000..f2fa089
--- /dev/null
+++ b/absl/flags/commandlineflag.h
@@ -0,0 +1,200 @@
+//
+// 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.
+//
+// -----------------------------------------------------------------------------
+// File: commandlineflag.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the `CommandLineFlag`, which acts as a type-erased
+// handle for accessing metadata about the Abseil Flag in question.
+//
+// Because an actual Abseil flag is of an unspecified type, you should not
+// manipulate or interact directly with objects of that type. Instead, use the
+// CommandLineFlag type as an intermediary.
+#ifndef ABSL_FLAGS_COMMANDLINEFLAG_H_
+#define ABSL_FLAGS_COMMANDLINEFLAG_H_
+
+#include <memory>
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/fast_type_id.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace flags_internal {
+class PrivateHandleAccessor;
+}  // namespace flags_internal
+
+// CommandLineFlag
+//
+// This type acts as a type-erased handle for an instance of an Abseil Flag and
+// holds reflection information pertaining to that flag. Use CommandLineFlag to
+// access a flag's name, location, help string etc.
+//
+// To obtain an absl::CommandLineFlag, invoke `absl::FindCommandLineFlag()`
+// passing it the flag name string.
+//
+// Example:
+//
+//   // Obtain reflection handle for a flag named "flagname".
+//   const absl::CommandLineFlag* my_flag_data =
+//        absl::FindCommandLineFlag("flagname");
+//
+//   // Now you can get flag info from that reflection handle.
+//   std::string flag_location = my_flag_data->Filename();
+//   ...
+class CommandLineFlag {
+ public:
+  constexpr CommandLineFlag() = default;
+
+  // Not copyable/assignable.
+  CommandLineFlag(const CommandLineFlag&) = delete;
+  CommandLineFlag& operator=(const CommandLineFlag&) = delete;
+
+  // absl::CommandLineFlag::IsOfType()
+  //
+  // Return true iff flag has type T.
+  template <typename T>
+  inline bool IsOfType() const {
+    return TypeId() == base_internal::FastTypeId<T>();
+  }
+
+  // absl::CommandLineFlag::TryGet()
+  //
+  // Attempts to retrieve the flag value. Returns value on success,
+  // absl::nullopt otherwise.
+  template <typename T>
+  absl::optional<T> TryGet() const {
+    if (IsRetired() || !IsOfType<T>()) {
+      return absl::nullopt;
+    }
+
+    // Implementation notes:
+    //
+    // We are wrapping a union around the value of `T` to serve three purposes:
+    //
+    //  1. `U.value` has correct size and alignment for a value of type `T`
+    //  2. The `U.value` constructor is not invoked since U's constructor does
+    //     not do it explicitly.
+    //  3. The `U.value` destructor is invoked since U's destructor does it
+    //     explicitly. This makes `U` a kind of RAII wrapper around non default
+    //     constructible value of T, which is destructed when we leave the
+    //     scope. We do need to destroy U.value, which is constructed by
+    //     CommandLineFlag::Read even though we left it in a moved-from state
+    //     after std::move.
+    //
+    // All of this serves to avoid requiring `T` being default constructible.
+    union U {
+      T value;
+      U() {}
+      ~U() { value.~T(); }
+    };
+    U u;
+
+    Read(&u.value);
+    // allow retired flags to be "read", so we can report invalid access.
+    if (IsRetired()) {
+      return absl::nullopt;
+    }
+    return std::move(u.value);
+  }
+
+  // absl::CommandLineFlag::Name()
+  //
+  // Returns name of this flag.
+  virtual absl::string_view Name() const = 0;
+
+  // absl::CommandLineFlag::Filename()
+  //
+  // Returns name of the file where this flag is defined.
+  virtual std::string Filename() const = 0;
+
+  // absl::CommandLineFlag::Help()
+  //
+  // Returns help message associated with this flag.
+  virtual std::string Help() const = 0;
+
+  // absl::CommandLineFlag::IsRetired()
+  //
+  // Returns true iff this object corresponds to retired flag.
+  virtual bool IsRetired() const;
+
+  // absl::CommandLineFlag::DefaultValue()
+  //
+  // Returns the default value for this flag.
+  virtual std::string DefaultValue() const = 0;
+
+  // absl::CommandLineFlag::CurrentValue()
+  //
+  // Returns the current value for this flag.
+  virtual std::string CurrentValue() const = 0;
+
+  // absl::CommandLineFlag::ParseFrom()
+  //
+  // Sets the value of the flag based on specified string `value`. If the flag
+  // was successfully set to new value, it returns true. Otherwise, sets `error`
+  // to indicate the error, leaves the flag unchanged, and returns false.
+  bool ParseFrom(absl::string_view value, std::string* error);
+
+ protected:
+  ~CommandLineFlag() = default;
+
+ private:
+  friend class flags_internal::PrivateHandleAccessor;
+
+  // Sets the value of the flag based on specified string `value`. If the flag
+  // was successfully set to new value, it returns true. Otherwise, sets `error`
+  // to indicate the error, leaves the flag unchanged, and returns false. There
+  // are three ways to set the flag's value:
+  //  * Update the current flag value
+  //  * Update the flag's default value
+  //  * Update the current flag value if it was never set before
+  // The mode is selected based on `set_mode` parameter.
+  virtual bool ParseFrom(absl::string_view value,
+                         flags_internal::FlagSettingMode set_mode,
+                         flags_internal::ValueSource source,
+                         std::string& error) = 0;
+
+  // Returns id of the flag's value type.
+  virtual flags_internal::FlagFastTypeId TypeId() const = 0;
+
+  // Interface to save flag to some persistent state. Returns current flag state
+  // or nullptr if flag does not support saving and restoring a state.
+  virtual std::unique_ptr<flags_internal::FlagStateInterface> SaveState() = 0;
+
+  // Copy-construct a new value of the flag's type in a memory referenced by
+  // the dst based on the current flag's value.
+  virtual void Read(void* dst) const = 0;
+
+  // To be deleted. Used to return true if flag's current value originated from
+  // command line.
+  virtual bool IsSpecifiedOnCommandLine() const = 0;
+
+  // Validates supplied value usign validator or parseflag routine
+  virtual bool ValidateInputValue(absl::string_view value) const = 0;
+
+  // Checks that flags default value can be converted to string and back to the
+  // flag's value type.
+  virtual void CheckDefaultValueParsingRoundtrip() const = 0;
+};
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_FLAGS_COMMANDLINEFLAG_H_
diff --git a/absl/flags/commandlineflag_test.cc b/absl/flags/commandlineflag_test.cc
new file mode 100644
index 0000000..585db4b
--- /dev/null
+++ b/absl/flags/commandlineflag_test.cc
@@ -0,0 +1,231 @@
+//
+//  Copyright 2019 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/flags/commandlineflag.h"
+
+#include <memory>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "absl/flags/flag.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/flags/internal/private_handle_accessor.h"
+#include "absl/flags/reflection.h"
+#include "absl/flags/usage_config.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/match.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+
+ABSL_FLAG(int, int_flag, 201, "int_flag help");
+ABSL_FLAG(std::string, string_flag, "dflt",
+          absl::StrCat("string_flag", " help"));
+ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
+
+// These are only used to test default values.
+ABSL_FLAG(int, int_flag2, 201, "");
+ABSL_FLAG(std::string, string_flag2, "dflt", "");
+
+namespace {
+
+namespace flags = absl::flags_internal;
+
+class CommandLineFlagTest : public testing::Test {
+ protected:
+  static void SetUpTestSuite() {
+    // Install a function to normalize filenames before this test is run.
+    absl::FlagsUsageConfig default_config;
+    default_config.normalize_filename = &CommandLineFlagTest::NormalizeFileName;
+    absl::SetFlagsUsageConfig(default_config);
+  }
+
+  void SetUp() override { flag_saver_ = absl::make_unique<absl::FlagSaver>(); }
+  void TearDown() override { flag_saver_.reset(); }
+
+ private:
+  static std::string NormalizeFileName(absl::string_view fname) {
+#ifdef _WIN32
+    std::string normalized(fname);
+    std::replace(normalized.begin(), normalized.end(), '\\', '/');
+    fname = normalized;
+#endif
+    return std::string(fname);
+  }
+
+  std::unique_ptr<absl::FlagSaver> flag_saver_;
+};
+
+TEST_F(CommandLineFlagTest, TestAttributesAccessMethods) {
+  auto* flag_01 = absl::FindCommandLineFlag("int_flag");
+
+  ASSERT_TRUE(flag_01);
+  EXPECT_EQ(flag_01->Name(), "int_flag");
+  EXPECT_EQ(flag_01->Help(), "int_flag help");
+  EXPECT_TRUE(!flag_01->IsRetired());
+  EXPECT_TRUE(flag_01->IsOfType<int>());
+  EXPECT_TRUE(!flag_01->IsOfType<bool>());
+  EXPECT_TRUE(!flag_01->IsOfType<std::string>());
+  EXPECT_TRUE(absl::EndsWith(flag_01->Filename(),
+                             "absl/flags/commandlineflag_test.cc"))
+      << flag_01->Filename();
+
+  auto* flag_02 = absl::FindCommandLineFlag("string_flag");
+
+  ASSERT_TRUE(flag_02);
+  EXPECT_EQ(flag_02->Name(), "string_flag");
+  EXPECT_EQ(flag_02->Help(), "string_flag help");
+  EXPECT_TRUE(!flag_02->IsRetired());
+  EXPECT_TRUE(flag_02->IsOfType<std::string>());
+  EXPECT_TRUE(!flag_02->IsOfType<bool>());
+  EXPECT_TRUE(!flag_02->IsOfType<int>());
+  EXPECT_TRUE(absl::EndsWith(flag_02->Filename(),
+                             "absl/flags/commandlineflag_test.cc"))
+      << flag_02->Filename();
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(CommandLineFlagTest, TestValueAccessMethods) {
+  absl::SetFlag(&FLAGS_int_flag2, 301);
+  auto* flag_01 = absl::FindCommandLineFlag("int_flag2");
+
+  ASSERT_TRUE(flag_01);
+  EXPECT_EQ(flag_01->CurrentValue(), "301");
+  EXPECT_EQ(flag_01->DefaultValue(), "201");
+
+  absl::SetFlag(&FLAGS_string_flag2, "new_str_value");
+  auto* flag_02 = absl::FindCommandLineFlag("string_flag2");
+
+  ASSERT_TRUE(flag_02);
+  EXPECT_EQ(flag_02->CurrentValue(), "new_str_value");
+  EXPECT_EQ(flag_02->DefaultValue(), "dflt");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(CommandLineFlagTest, TestParseFromCurrentValue) {
+  std::string err;
+
+  auto* flag_01 = absl::FindCommandLineFlag("int_flag");
+  EXPECT_FALSE(
+      flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
+
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      *flag_01, "11", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err));
+  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11);
+  EXPECT_FALSE(
+      flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
+
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      *flag_01, "-123", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
+      err));
+  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
+  EXPECT_FALSE(
+      flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
+
+  EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom(
+      *flag_01, "xyz", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
+      err));
+  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
+  EXPECT_EQ(err, "Illegal value 'xyz' specified for flag 'int_flag'");
+  EXPECT_FALSE(
+      flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
+
+  EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom(
+      *flag_01, "A1", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err));
+  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
+  EXPECT_EQ(err, "Illegal value 'A1' specified for flag 'int_flag'");
+  EXPECT_FALSE(
+      flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
+
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      *flag_01, "0x10", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
+      err));
+  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 16);
+  EXPECT_FALSE(
+      flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
+
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      *flag_01, "011", flags::SET_FLAGS_VALUE, flags::kCommandLine, err));
+  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11);
+  EXPECT_TRUE(flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
+
+  EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom(
+      *flag_01, "", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err));
+  EXPECT_EQ(err, "Illegal value '' specified for flag 'int_flag'");
+
+  auto* flag_02 = absl::FindCommandLineFlag("string_flag");
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      *flag_02, "xyz", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
+      err));
+  EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "xyz");
+
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      *flag_02, "", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err));
+  EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(CommandLineFlagTest, TestParseFromDefaultValue) {
+  std::string err;
+
+  auto* flag_01 = absl::FindCommandLineFlag("int_flag");
+
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      *flag_01, "111", flags::SET_FLAGS_DEFAULT, flags::kProgrammaticChange,
+      err));
+  EXPECT_EQ(flag_01->DefaultValue(), "111");
+
+  auto* flag_02 = absl::FindCommandLineFlag("string_flag");
+
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      *flag_02, "abc", flags::SET_FLAGS_DEFAULT, flags::kProgrammaticChange,
+      err));
+  EXPECT_EQ(flag_02->DefaultValue(), "abc");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(CommandLineFlagTest, TestParseFromIfDefault) {
+  std::string err;
+
+  auto* flag_01 = absl::FindCommandLineFlag("int_flag");
+
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      *flag_01, "22", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange,
+      err))
+      << err;
+  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22);
+
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      *flag_01, "33", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange,
+      err));
+  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22);
+  // EXPECT_EQ(err, "ERROR: int_flag is already set to 22");
+
+  // Reset back to default value
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      *flag_01, "201", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
+      err));
+
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      *flag_01, "33", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange,
+      err));
+  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 201);
+  // EXPECT_EQ(err, "ERROR: int_flag is already set to 201");
+}
+
+}  // namespace
diff --git a/absl/flags/config.h b/absl/flags/config.h
index 001f8fe..5ab1f31 100644
--- a/absl/flags/config.h
+++ b/absl/flags/config.h
@@ -45,17 +45,6 @@
 #define ABSL_FLAGS_STRIP_HELP ABSL_FLAGS_STRIP_NAMES
 #endif
 
-// ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD macro is used for using atomics with
-// double words, e.g. absl::Duration.
-// For reasons in bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80878, modern
-// versions of GCC do not support cmpxchg16b instruction in standard atomics.
-#ifdef ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD
-#error "ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD should not be defined."
-#elif defined(__clang__) && defined(__x86_64__) && \
-    defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16)
-#define ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD 1
-#endif
-
 // ABSL_FLAGS_INTERNAL_HAS_RTTI macro is used for selecting if we can use RTTI
 // for flag type identification.
 #ifdef ABSL_FLAGS_INTERNAL_HAS_RTTI
@@ -64,4 +53,24 @@
 #define ABSL_FLAGS_INTERNAL_HAS_RTTI 1
 #endif  // !defined(__GNUC__) || defined(__GXX_RTTI)
 
+// These macros represent the "source of truth" for the list of supported
+// built-in types.
+#define ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(A) \
+  A(bool, bool)                              \
+  A(short, short)                            \
+  A(unsigned short, unsigned_short)          \
+  A(int, int)                                \
+  A(unsigned int, unsigned_int)              \
+  A(long, long)                              \
+  A(unsigned long, unsigned_long)            \
+  A(long long, long_long)                    \
+  A(unsigned long long, unsigned_long_long)  \
+  A(double, double)                          \
+  A(float, float)
+
+#define ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(A) \
+  ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(A)         \
+  A(std::string, std_string)                   \
+  A(std::vector<std::string>, std_vector_of_string)
+
 #endif  // ABSL_FLAGS_CONFIG_H_
diff --git a/absl/flags/declare.h b/absl/flags/declare.h
index 0f8cc6a..b9794d8 100644
--- a/absl/flags/declare.h
+++ b/absl/flags/declare.h
@@ -26,7 +26,6 @@
 #define ABSL_FLAGS_DECLARE_H_
 
 #include "absl/base/config.h"
-#include "absl/strings/string_view.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
diff --git a/absl/flags/flag.cc b/absl/flags/flag.cc
index f7a457b..531df12 100644
--- a/absl/flags/flag.cc
+++ b/absl/flags/flag.cc
@@ -16,8 +16,6 @@
 #include "absl/flags/flag.h"
 
 #include "absl/base/config.h"
-#include "absl/flags/internal/commandlineflag.h"
-#include "absl/flags/internal/flag.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
diff --git a/absl/flags/flag.h b/absl/flags/flag.h
index cff02c1..f09580b 100644
--- a/absl/flags/flag.h
+++ b/absl/flags/flag.h
@@ -33,14 +33,12 @@
 #include <type_traits>
 
 #include "absl/base/attributes.h"
-#include "absl/base/casts.h"
 #include "absl/base/config.h"
+#include "absl/base/optimization.h"
 #include "absl/flags/config.h"
-#include "absl/flags/declare.h"
-#include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/flag.h"
 #include "absl/flags/internal/registry.h"
-#include "absl/flags/marshalling.h"
+#include "absl/strings/string_view.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -110,50 +108,53 @@
         impl_(nullptr) {}
 #endif
 
-  flags_internal::Flag<T>* GetImpl() const {
+  flags_internal::Flag<T>& GetImpl() const {
     if (!inited_.load(std::memory_order_acquire)) {
       absl::MutexLock l(flags_internal::GetGlobalConstructionGuard());
 
       if (inited_.load(std::memory_order_acquire)) {
-        return impl_;
+        return *impl_;
       }
 
-      impl_ =
-          new flags_internal::Flag<T>(name_, filename_,
-                                      {flags_internal::FlagHelpMsg(help_gen_),
-                                       flags_internal::FlagHelpKind::kGenFunc},
-                                      default_value_gen_);
+      impl_ = new flags_internal::Flag<T>(
+          name_, filename_,
+          {flags_internal::FlagHelpMsg(help_gen_),
+           flags_internal::FlagHelpKind::kGenFunc},
+          {flags_internal::FlagDefaultSrc(default_value_gen_),
+           flags_internal::FlagDefaultKind::kGenFunc});
       inited_.store(true, std::memory_order_release);
     }
 
-    return impl_;
+    return *impl_;
   }
 
   // Public methods of `absl::Flag<T>` are NOT part of the Abseil Flags API.
   // See https://abseil.io/docs/cpp/guides/flags
-  bool IsRetired() const { return GetImpl()->IsRetired(); }
-  bool IsAbseilFlag() const { return GetImpl()->IsAbseilFlag(); }
-  absl::string_view Name() const { return GetImpl()->Name(); }
-  std::string Help() const { return GetImpl()->Help(); }
-  bool IsModified() const { return GetImpl()->IsModified(); }
+  bool IsRetired() const { return GetImpl().IsRetired(); }
+  absl::string_view Name() const { return GetImpl().Name(); }
+  std::string Help() const { return GetImpl().Help(); }
+  bool IsModified() const { return GetImpl().IsModified(); }
   bool IsSpecifiedOnCommandLine() const {
-    return GetImpl()->IsSpecifiedOnCommandLine();
+    return GetImpl().IsSpecifiedOnCommandLine();
   }
-  absl::string_view Typename() const { return GetImpl()->Typename(); }
-  std::string Filename() const { return GetImpl()->Filename(); }
-  std::string DefaultValue() const { return GetImpl()->DefaultValue(); }
-  std::string CurrentValue() const { return GetImpl()->CurrentValue(); }
+  std::string Filename() const { return GetImpl().Filename(); }
+  std::string DefaultValue() const { return GetImpl().DefaultValue(); }
+  std::string CurrentValue() const { return GetImpl().CurrentValue(); }
   template <typename U>
   inline bool IsOfType() const {
-    return GetImpl()->template IsOfType<U>();
+    return GetImpl().template IsOfType<U>();
   }
-  T Get() const { return GetImpl()->Get(); }
-  bool AtomicGet(T* v) const { return GetImpl()->AtomicGet(v); }
-  void Set(const T& v) { GetImpl()->Set(v); }
-  void SetCallback(const flags_internal::FlagCallbackFunc mutation_callback) {
-    GetImpl()->SetCallback(mutation_callback);
+  T Get() const {
+    return flags_internal::FlagImplPeer::InvokeGet<T>(GetImpl());
   }
-  void InvokeCallback() { GetImpl()->InvokeCallback(); }
+  void Set(const T& v) {
+    flags_internal::FlagImplPeer::InvokeSet(GetImpl(), v);
+  }
+  void InvokeCallback() { GetImpl().InvokeCallback(); }
+
+  const CommandLineFlag& Reflect() const {
+    return flags_internal::FlagImplPeer::InvokeReflect(GetImpl());
+  }
 
   // The data members are logically private, but they need to be public for
   // this to be an aggregate type.
@@ -185,7 +186,7 @@
 //   std::string first_name = absl::GetFlag(FLAGS_firstname);
 template <typename T>
 ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag) {
-  return flag.Get();
+  return flags_internal::FlagImplPeer::InvokeGet<T>(flag);
 }
 
 // SetFlag()
@@ -197,7 +198,7 @@
 // but especially within performance-critical code.
 template <typename T>
 void SetFlag(absl::Flag<T>* flag, const T& v) {
-  flag->Set(v);
+  flags_internal::FlagImplPeer::InvokeSet(*flag, v);
 }
 
 // Overload of `SetFlag()` to allow callers to pass in a value that is
@@ -206,7 +207,22 @@
 template <typename T, typename V>
 void SetFlag(absl::Flag<T>* flag, const V& v) {
   T value(v);
-  flag->Set(value);
+  flags_internal::FlagImplPeer::InvokeSet(*flag, value);
+}
+
+// GetFlagReflectionHandle()
+//
+// Returns the reflection handle corresponding to specified Abseil Flag
+// instance. Use this handle to access flag's reflection information, like name,
+// location, default value etc.
+//
+// Example:
+//
+//   std::string = absl::GetFlagReflectionHandle(FLAGS_count).DefaultValue();
+
+template <typename T>
+const CommandLineFlag& GetFlagReflectionHandle(const absl::Flag<T>& f) {
+  return flags_internal::FlagImplPeer::InvokeReflect(f);
 }
 
 ABSL_NAMESPACE_END
@@ -269,27 +285,31 @@
 // -----------------------------------------------------------------------------
 
 // ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_NAMES
+#if !defined(_MSC_VER) || defined(__clang__)
+#define ABSL_FLAG_IMPL_FLAG_PTR(flag) flag
+#define ABSL_FLAG_IMPL_HELP_ARG(name)                      \
+  absl::flags_internal::HelpArg<AbslFlagHelpGenFor##name>( \
+      FLAGS_help_storage_##name)
+#define ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name) \
+  absl::flags_internal::DefaultArg<Type, AbslFlagDefaultGenFor##name>(0)
+#else
+#define ABSL_FLAG_IMPL_FLAG_PTR(flag) flag.GetImpl()
+#define ABSL_FLAG_IMPL_HELP_ARG(name) &AbslFlagHelpGenFor##name::NonConst
+#define ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name) &AbslFlagDefaultGenFor##name::Gen
+#endif
 
 #if ABSL_FLAGS_STRIP_NAMES
 #define ABSL_FLAG_IMPL_FLAGNAME(txt) ""
 #define ABSL_FLAG_IMPL_FILENAME() ""
-#if !defined(_MSC_VER) || defined(__clang__)
-#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
-  absl::flags_internal::FlagRegistrar<T, false>(&flag)
-#else
-#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
-  absl::flags_internal::FlagRegistrar<T, false>(flag.GetImpl())
-#endif
+#define ABSL_FLAG_IMPL_REGISTRAR(T, flag)                                      \
+  absl::flags_internal::FlagRegistrar<T, false>(ABSL_FLAG_IMPL_FLAG_PTR(flag), \
+                                                nullptr)
 #else
 #define ABSL_FLAG_IMPL_FLAGNAME(txt) txt
 #define ABSL_FLAG_IMPL_FILENAME() __FILE__
-#if !defined(_MSC_VER) || defined(__clang__)
-#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
-  absl::flags_internal::FlagRegistrar<T, true>(&flag)
-#else
-#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
-  absl::flags_internal::FlagRegistrar<T, true>(flag.GetImpl())
-#endif
+#define ABSL_FLAG_IMPL_REGISTRAR(T, flag)                                     \
+  absl::flags_internal::FlagRegistrar<T, true>(ABSL_FLAG_IMPL_FLAG_PTR(flag), \
+                                               __FILE__)
 #endif
 
 // ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_HELP
@@ -305,50 +325,48 @@
 // between the two via the call to HelpArg in absl::Flag instantiation below.
 // If help message expression is constexpr evaluable compiler will optimize
 // away this whole struct.
-#define ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, txt)                     \
-  struct AbslFlagHelpGenFor##name {                                        \
-    template <typename T = void>                                           \
-    static constexpr const char* Const() {                                 \
-      return absl::flags_internal::HelpConstexprWrap(                      \
-          ABSL_FLAG_IMPL_FLAGHELP(txt));                                   \
-    }                                                                      \
-    static std::string NonConst() { return ABSL_FLAG_IMPL_FLAGHELP(txt); } \
-  }
+// TODO(rogeeff): place these generated structs into local namespace and apply
+// ABSL_INTERNAL_UNIQUE_SHORT_NAME.
+// TODO(rogeeff): Apply __attribute__((nodebug)) to FLAGS_help_storage_##name
+#define ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, txt)                       \
+  struct AbslFlagHelpGenFor##name {                                          \
+    /* The expression is run in the caller as part of the   */               \
+    /* default value argument. That keeps temporaries alive */               \
+    /* long enough for NonConst to work correctly.          */               \
+    static constexpr absl::string_view Value(                                \
+        absl::string_view v = ABSL_FLAG_IMPL_FLAGHELP(txt)) {                \
+      return v;                                                              \
+    }                                                                        \
+    static std::string NonConst() { return std::string(Value()); }           \
+  };                                                                         \
+  constexpr auto FLAGS_help_storage_##name ABSL_INTERNAL_UNIQUE_SMALL_NAME() \
+      ABSL_ATTRIBUTE_SECTION_VARIABLE(flags_help_cold) =                     \
+          absl::flags_internal::HelpStringAsArray<AbslFlagHelpGenFor##name>( \
+              0);
 
-#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value)   \
-  static void* AbslFlagsInitFlag##name() {                                  \
-    return absl::flags_internal::MakeFromDefaultValue<Type>(default_value); \
-  }
+#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value)     \
+  struct AbslFlagDefaultGenFor##name {                                        \
+    Type value = absl::flags_internal::InitDefaultValue<Type>(default_value); \
+    static void Gen(void* p) {                                                \
+      new (p) Type(AbslFlagDefaultGenFor##name{}.value);                      \
+    }                                                                         \
+  };
 
 // ABSL_FLAG_IMPL
 //
 // Note: Name of registrar object is not arbitrary. It is used to "grab"
 // global name for FLAGS_no<flag_name> symbol, thus preventing the possibility
 // of defining two flags with names foo and nofoo.
-#if !defined(_MSC_VER) || defined(__clang__)
-#define ABSL_FLAG_IMPL(Type, name, default_value, help)             \
-  namespace absl /* block flags in namespaces */ {}                 \
-  ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \
-  ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help);                  \
-  ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{                    \
-      ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(),    \
-      absl::flags_internal::HelpArg<AbslFlagHelpGenFor##name>(0),   \
-      &AbslFlagsInitFlag##name};                                    \
-  extern bool FLAGS_no##name;                                       \
-  bool FLAGS_no##name = ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)
-#else
-// MSVC version uses aggregate initialization. We also do not try to
-// optimize away help wrapper.
-#define ABSL_FLAG_IMPL(Type, name, default_value, help)               \
-  namespace absl /* block flags in namespaces */ {}                   \
-  ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value)   \
-  ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help);                    \
-  ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{                      \
-      ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(),      \
-      &AbslFlagHelpGenFor##name::NonConst, &AbslFlagsInitFlag##name}; \
-  extern bool FLAGS_no##name;                                         \
-  bool FLAGS_no##name = ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)
-#endif
+#define ABSL_FLAG_IMPL(Type, name, default_value, help)                       \
+  namespace absl /* block flags in namespaces */ {}                           \
+  ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value)           \
+  ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help)                             \
+  ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{                              \
+      ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(),              \
+      ABSL_FLAG_IMPL_HELP_ARG(name), ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name)}; \
+  extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name;             \
+  absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name =                   \
+      ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)
 
 // ABSL_RETIRED_FLAG
 //
@@ -369,11 +387,12 @@
 //
 // `default_value` is only used as a double check on the type. `explanation` is
 // unused.
-// TODO(rogeeff): Return an anonymous struct instead of bool, and place it into
-// the unnamed namespace.
-#define ABSL_RETIRED_FLAG(type, flagname, default_value, explanation) \
-  ABSL_ATTRIBUTE_UNUSED static const bool ignored_##flagname =        \
-      ([] { return type(default_value); },                            \
-       absl::flags_internal::RetiredFlag<type>(#flagname))
+// TODO(rogeeff): replace RETIRED_FLAGS with FLAGS once forward declarations of
+// retired flags are cleaned up.
+#define ABSL_RETIRED_FLAG(type, name, default_value, explanation)      \
+  static absl::flags_internal::RetiredFlag<type> RETIRED_FLAGS_##name; \
+  ABSL_ATTRIBUTE_UNUSED static const auto RETIRED_FLAGS_REG_##name =   \
+      (RETIRED_FLAGS_##name.Retire(#name),                             \
+       ::absl::flags_internal::FlagRegistrarEmpty{})
 
 #endif  // ABSL_FLAGS_FLAG_H_
diff --git a/absl/flags/flag_benchmark.cc b/absl/flags/flag_benchmark.cc
index 87f7317..57584f8 100644
--- a/absl/flags/flag_benchmark.cc
+++ b/absl/flags/flag_benchmark.cc
@@ -13,7 +13,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
 #include "absl/flags/flag.h"
+#include "absl/flags/marshalling.h"
+#include "absl/flags/parse.h"
+#include "absl/flags/reflection.h"
+#include "absl/strings/string_view.h"
 #include "absl/time/time.h"
 #include "absl/types/optional.h"
 #include "benchmark/benchmark.h"
@@ -94,7 +103,33 @@
 
 #define FLAG_DEF(T) ABSL_FLAG(T, T##_flag, {}, "");
 
+#if defined(__clang__) && defined(__linux__)
+// Force the flags used for benchmarks into a separate ELF section.
+// This ensures that, even when other parts of the code might change size,
+// the layout of the flags across cachelines is kept constant. This makes
+// benchmark results more reproducible across unrelated code changes.
+#pragma clang section data = ".benchmark_flags"
+#endif
 BENCHMARKED_TYPES(FLAG_DEF)
+#if defined(__clang__) && defined(__linux__)
+#pragma clang section data = ""
+#endif
+// Register thousands of flags to bloat up the size of the registry.
+// This mimics real life production binaries.
+#define DEFINE_FLAG_0(name) ABSL_FLAG(int, name, 0, "");
+#define DEFINE_FLAG_1(name) DEFINE_FLAG_0(name##0) DEFINE_FLAG_0(name##1)
+#define DEFINE_FLAG_2(name) DEFINE_FLAG_1(name##0) DEFINE_FLAG_1(name##1)
+#define DEFINE_FLAG_3(name) DEFINE_FLAG_2(name##0) DEFINE_FLAG_2(name##1)
+#define DEFINE_FLAG_4(name) DEFINE_FLAG_3(name##0) DEFINE_FLAG_3(name##1)
+#define DEFINE_FLAG_5(name) DEFINE_FLAG_4(name##0) DEFINE_FLAG_4(name##1)
+#define DEFINE_FLAG_6(name) DEFINE_FLAG_5(name##0) DEFINE_FLAG_5(name##1)
+#define DEFINE_FLAG_7(name) DEFINE_FLAG_6(name##0) DEFINE_FLAG_6(name##1)
+#define DEFINE_FLAG_8(name) DEFINE_FLAG_7(name##0) DEFINE_FLAG_7(name##1)
+#define DEFINE_FLAG_9(name) DEFINE_FLAG_8(name##0) DEFINE_FLAG_8(name##1)
+#define DEFINE_FLAG_10(name) DEFINE_FLAG_9(name##0) DEFINE_FLAG_9(name##1)
+#define DEFINE_FLAG_11(name) DEFINE_FLAG_10(name##0) DEFINE_FLAG_10(name##1)
+#define DEFINE_FLAG_12(name) DEFINE_FLAG_11(name##0) DEFINE_FLAG_11(name##1)
+DEFINE_FLAG_12(bloat_flag_);
 
 namespace {
 
@@ -104,8 +139,30 @@
       benchmark::DoNotOptimize(absl::GetFlag(FLAGS_##T##_flag)); \
     }                                                            \
   }                                                              \
-  BENCHMARK(BM_GetFlag_##T);
+  BENCHMARK(BM_GetFlag_##T)->ThreadRange(1, 16);
 
 BENCHMARKED_TYPES(BM_GetFlag)
 
+void BM_ThreadedFindCommandLineFlag(benchmark::State& state) {
+  char dummy[] = "dummy";
+  char* argv[] = {dummy};
+  // We need to ensure that flags have been parsed. That is where the registry
+  // is finalized.
+  absl::ParseCommandLine(1, argv);
+
+  for (auto s : state) {
+    benchmark::DoNotOptimize(
+        absl::FindCommandLineFlag("bloat_flag_010101010101"));
+  }
+}
+BENCHMARK(BM_ThreadedFindCommandLineFlag)->ThreadRange(1, 16);
+
 }  // namespace
+
+#define InvokeGetFlag(T)                                               \
+  T AbslInvokeGetFlag##T() { return absl::GetFlag(FLAGS_##T##_flag); } \
+  int odr##T = (benchmark::DoNotOptimize(AbslInvokeGetFlag##T), 1);
+
+BENCHMARKED_TYPES(InvokeGetFlag)
+
+// To veiw disassembly use: gdb ${BINARY}  -batch -ex "disassemble /s $FUNC"
diff --git a/absl/flags/flag_benchmark.lds b/absl/flags/flag_benchmark.lds
new file mode 100644
index 0000000..af115df
--- /dev/null
+++ b/absl/flags/flag_benchmark.lds
@@ -0,0 +1,13 @@
+/* This linker script forces the flags used by flags_benchmark
+ * into a separate page-aligned section. This isn't necessary for
+ * correctness but ensures that the benchmark results are more
+ * reproducible across unrelated code changes.
+ */
+SECTIONS {
+  .benchmark_flags : {
+    . = ALIGN(0x1000);
+    * (.benchmark_flags);
+  }
+}
+
+INSERT AFTER .data
diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc
index 4984d28..6912b54 100644
--- a/absl/flags/flag_test.cc
+++ b/absl/flags/flag_test.cc
@@ -15,25 +15,31 @@
 
 #include "absl/flags/flag.h"
 
+#include <stddef.h>
 #include <stdint.h>
 
+#include <atomic>
 #include <cmath>
+#include <new>
 #include <string>
+#include <thread>  // NOLINT
 #include <vector>
 
 #include "gtest/gtest.h"
 #include "absl/base/attributes.h"
+#include "absl/base/macros.h"
 #include "absl/flags/config.h"
 #include "absl/flags/declare.h"
-#include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/flag.h"
-#include "absl/flags/internal/registry.h"
+#include "absl/flags/marshalling.h"
+#include "absl/flags/reflection.h"
 #include "absl/flags/usage_config.h"
 #include "absl/strings/match.h"
 #include "absl/strings/numbers.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/str_split.h"
 #include "absl/strings/string_view.h"
+#include "absl/time/time.h"
 
 ABSL_DECLARE_FLAG(int64_t, mistyped_int_flag);
 ABSL_DECLARE_FLAG(std::vector<std::string>, mistyped_string_flag);
@@ -43,34 +49,15 @@
 namespace flags = absl::flags_internal;
 
 std::string TestHelpMsg() { return "dynamic help"; }
+#if defined(_MSC_VER) && !defined(__clang__)
+std::string TestLiteralHelpMsg() { return "literal help"; }
+#endif
 template <typename T>
-void* TestMakeDflt() {
-  return new T{};
+void TestMakeDflt(void* dst) {
+  new (dst) T{};
 }
 void TestCallback() {}
 
-template <typename T>
-bool TestConstructionFor() {
-  constexpr flags::FlagHelpArg help_arg{flags::FlagHelpMsg("literal help"),
-                                        flags::FlagHelpKind::kLiteral};
-  constexpr flags::Flag<T> f1("f1", "file", help_arg, &TestMakeDflt<T>);
-  EXPECT_EQ(f1.Name(), "f1");
-  EXPECT_EQ(f1.Help(), "literal help");
-  EXPECT_EQ(f1.Filename(), "file");
-
-  ABSL_CONST_INIT static flags::Flag<T> f2(
-      "f2", "file",
-      {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc},
-      &TestMakeDflt<T>);
-  flags::FlagRegistrar<T, false>(&f2).OnUpdate(TestCallback);
-
-  EXPECT_EQ(f2.Name(), "f2");
-  EXPECT_EQ(f2.Help(), "dynamic help");
-  EXPECT_EQ(f2.Filename(), "file");
-
-  return true;
-}
-
 struct UDT {
   UDT() = default;
   UDT(const UDT&) = default;
@@ -96,21 +83,124 @@
 #endif
     return std::string(fname);
   }
+  absl::FlagSaver flag_saver_;
 };
 
-TEST_F(FlagTest, TestConstruction) {
-  TestConstructionFor<bool>();
-  TestConstructionFor<int16_t>();
-  TestConstructionFor<uint16_t>();
-  TestConstructionFor<int32_t>();
-  TestConstructionFor<uint32_t>();
-  TestConstructionFor<int64_t>();
-  TestConstructionFor<uint64_t>();
-  TestConstructionFor<double>();
-  TestConstructionFor<float>();
-  TestConstructionFor<std::string>();
+struct S1 {
+  S1() = default;
+  S1(const S1&) = default;
+  int32_t f1;
+  int64_t f2;
+};
 
-  TestConstructionFor<UDT>();
+struct S2 {
+  S2() = default;
+  S2(const S2&) = default;
+  int64_t f1;
+  double f2;
+};
+
+TEST_F(FlagTest, Traits) {
+  EXPECT_EQ(flags::StorageKind<int>(),
+            flags::FlagValueStorageKind::kOneWordAtomic);
+  EXPECT_EQ(flags::StorageKind<bool>(),
+            flags::FlagValueStorageKind::kOneWordAtomic);
+  EXPECT_EQ(flags::StorageKind<double>(),
+            flags::FlagValueStorageKind::kOneWordAtomic);
+  EXPECT_EQ(flags::StorageKind<int64_t>(),
+            flags::FlagValueStorageKind::kOneWordAtomic);
+
+  EXPECT_EQ(flags::StorageKind<S1>(),
+            flags::FlagValueStorageKind::kSequenceLocked);
+  EXPECT_EQ(flags::StorageKind<S2>(),
+            flags::FlagValueStorageKind::kSequenceLocked);
+// Make sure absl::Duration uses the sequence-locked code path. MSVC 2015
+// doesn't consider absl::Duration to be trivially-copyable so we just
+// restrict this to clang as it seems to be a well-behaved compiler.
+#ifdef __clang__
+  EXPECT_EQ(flags::StorageKind<absl::Duration>(),
+            flags::FlagValueStorageKind::kSequenceLocked);
+#endif
+
+  EXPECT_EQ(flags::StorageKind<std::string>(),
+            flags::FlagValueStorageKind::kAlignedBuffer);
+  EXPECT_EQ(flags::StorageKind<std::vector<std::string>>(),
+            flags::FlagValueStorageKind::kAlignedBuffer);
+}
+
+// --------------------------------------------------------------------
+
+constexpr flags::FlagHelpArg help_arg{flags::FlagHelpMsg("literal help"),
+                                      flags::FlagHelpKind::kLiteral};
+
+using String = std::string;
+
+#if !defined(_MSC_VER) || defined(__clang__)
+#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind)                        \
+  constexpr flags::FlagDefaultArg f1default##T{                            \
+      flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind};     \
+  constexpr absl::Flag<T> f1##T{"f1", "file", help_arg, f1default##T};     \
+  ABSL_CONST_INIT absl::Flag<T> f2##T {                                    \
+    "f2", "file",                                                          \
+        {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc}, \
+        flags::FlagDefaultArg {                                            \
+      flags::FlagDefaultSrc(&TestMakeDflt<T>),                             \
+          flags::FlagDefaultKind::kGenFunc                                 \
+    }                                                                      \
+  }
+#else
+#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind)                    \
+  constexpr flags::FlagDefaultArg f1default##T{                        \
+      flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind}; \
+  constexpr absl::Flag<T> f1##T{"f1", "file", &TestLiteralHelpMsg,     \
+                                &TestMakeDflt<T>};                     \
+  ABSL_CONST_INIT absl::Flag<T> f2##T {                                \
+    "f2", "file", &TestHelpMsg, &TestMakeDflt<T>                       \
+  }
+#endif
+
+DEFINE_CONSTRUCTED_FLAG(bool, true, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(int16_t, 1, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(uint16_t, 2, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(int32_t, 3, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(uint32_t, 4, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(int64_t, 5, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(uint64_t, 6, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(float, 7.8, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(double, 9.10, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(String, &TestMakeDflt<String>, kGenFunc);
+DEFINE_CONSTRUCTED_FLAG(UDT, &TestMakeDflt<UDT>, kGenFunc);
+
+template <typename T>
+bool TestConstructionFor(const absl::Flag<T>& f1, absl::Flag<T>& f2) {
+  EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Name(), "f1");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Help(), "literal help");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Filename(), "file");
+
+  flags::FlagRegistrar<T, false>(ABSL_FLAG_IMPL_FLAG_PTR(f2), nullptr)
+      .OnUpdate(TestCallback);
+
+  EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Name(), "f2");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Help(), "dynamic help");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Filename(), "file");
+
+  return true;
+}
+
+#define TEST_CONSTRUCTED_FLAG(T) TestConstructionFor(f1##T, f2##T);
+
+TEST_F(FlagTest, TestConstruction) {
+  TEST_CONSTRUCTED_FLAG(bool);
+  TEST_CONSTRUCTED_FLAG(int16_t);
+  TEST_CONSTRUCTED_FLAG(uint16_t);
+  TEST_CONSTRUCTED_FLAG(int32_t);
+  TEST_CONSTRUCTED_FLAG(uint32_t);
+  TEST_CONSTRUCTED_FLAG(int64_t);
+  TEST_CONSTRUCTED_FLAG(uint64_t);
+  TEST_CONSTRUCTED_FLAG(float);
+  TEST_CONSTRUCTED_FLAG(double);
+  TEST_CONSTRUCTED_FLAG(String);
+  TEST_CONSTRUCTED_FLAG(UDT);
 }
 
 // --------------------------------------------------------------------
@@ -128,6 +218,7 @@
 ABSL_DECLARE_FLAG(double, test_flag_09);
 ABSL_DECLARE_FLAG(float, test_flag_10);
 ABSL_DECLARE_FLAG(std::string, test_flag_11);
+ABSL_DECLARE_FLAG(absl::Duration, test_flag_12);
 
 namespace {
 
@@ -135,17 +226,30 @@
 
 TEST_F(FlagTest, TestFlagDeclaration) {
   // test that we can access flag objects.
-  EXPECT_EQ(FLAGS_test_flag_01.Name(), "test_flag_01");
-  EXPECT_EQ(FLAGS_test_flag_02.Name(), "test_flag_02");
-  EXPECT_EQ(FLAGS_test_flag_03.Name(), "test_flag_03");
-  EXPECT_EQ(FLAGS_test_flag_04.Name(), "test_flag_04");
-  EXPECT_EQ(FLAGS_test_flag_05.Name(), "test_flag_05");
-  EXPECT_EQ(FLAGS_test_flag_06.Name(), "test_flag_06");
-  EXPECT_EQ(FLAGS_test_flag_07.Name(), "test_flag_07");
-  EXPECT_EQ(FLAGS_test_flag_08.Name(), "test_flag_08");
-  EXPECT_EQ(FLAGS_test_flag_09.Name(), "test_flag_09");
-  EXPECT_EQ(FLAGS_test_flag_10.Name(), "test_flag_10");
-  EXPECT_EQ(FLAGS_test_flag_11.Name(), "test_flag_11");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Name(),
+            "test_flag_01");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Name(),
+            "test_flag_02");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Name(),
+            "test_flag_03");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Name(),
+            "test_flag_04");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Name(),
+            "test_flag_05");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Name(),
+            "test_flag_06");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Name(),
+            "test_flag_07");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Name(),
+            "test_flag_08");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Name(),
+            "test_flag_09");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Name(),
+            "test_flag_10");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Name(),
+            "test_flag_11");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Name(),
+            "test_flag_12");
 }
 #endif  // !ABSL_FLAGS_STRIP_NAMES
 
@@ -164,6 +268,7 @@
 ABSL_FLAG(double, test_flag_09, -9.876e-50, "test flag 09");
 ABSL_FLAG(float, test_flag_10, 1.234e12f, "test flag 10");
 ABSL_FLAG(std::string, test_flag_11, "", "test flag 11");
+ABSL_FLAG(absl::Duration, test_flag_12, absl::Minutes(10), "test flag 12");
 
 namespace {
 
@@ -171,66 +276,169 @@
 TEST_F(FlagTest, TestFlagDefinition) {
   absl::string_view expected_file_name = "absl/flags/flag_test.cc";
 
-  EXPECT_EQ(FLAGS_test_flag_01.Name(), "test_flag_01");
-  EXPECT_EQ(FLAGS_test_flag_01.Help(), "test flag 01");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_01.Filename(), expected_file_name))
-      << FLAGS_test_flag_01.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Name(),
+            "test_flag_01");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Help(),
+            "test flag 01");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_02.Name(), "test_flag_02");
-  EXPECT_EQ(FLAGS_test_flag_02.Help(), "test flag 02");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_02.Filename(), expected_file_name))
-      << FLAGS_test_flag_02.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Name(),
+            "test_flag_02");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Help(),
+            "test flag 02");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_03.Name(), "test_flag_03");
-  EXPECT_EQ(FLAGS_test_flag_03.Help(), "test flag 03");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_03.Filename(), expected_file_name))
-      << FLAGS_test_flag_03.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Name(),
+            "test_flag_03");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Help(),
+            "test flag 03");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_04.Name(), "test_flag_04");
-  EXPECT_EQ(FLAGS_test_flag_04.Help(), "test flag 04");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_04.Filename(), expected_file_name))
-      << FLAGS_test_flag_04.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Name(),
+            "test_flag_04");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Help(),
+            "test flag 04");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_05.Name(), "test_flag_05");
-  EXPECT_EQ(FLAGS_test_flag_05.Help(), "test flag 05");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_05.Filename(), expected_file_name))
-      << FLAGS_test_flag_05.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Name(),
+            "test_flag_05");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Help(),
+            "test flag 05");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_06.Name(), "test_flag_06");
-  EXPECT_EQ(FLAGS_test_flag_06.Help(), "test flag 06");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_06.Filename(), expected_file_name))
-      << FLAGS_test_flag_06.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Name(),
+            "test_flag_06");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Help(),
+            "test flag 06");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_07.Name(), "test_flag_07");
-  EXPECT_EQ(FLAGS_test_flag_07.Help(), "test flag 07");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_07.Filename(), expected_file_name))
-      << FLAGS_test_flag_07.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Name(),
+            "test_flag_07");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Help(),
+            "test flag 07");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_08.Name(), "test_flag_08");
-  EXPECT_EQ(FLAGS_test_flag_08.Help(), "test flag 08");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_08.Filename(), expected_file_name))
-      << FLAGS_test_flag_08.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Name(),
+            "test_flag_08");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Help(),
+            "test flag 08");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_09.Name(), "test_flag_09");
-  EXPECT_EQ(FLAGS_test_flag_09.Help(), "test flag 09");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_09.Filename(), expected_file_name))
-      << FLAGS_test_flag_09.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Name(),
+            "test_flag_09");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Help(),
+            "test flag 09");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_10.Name(), "test_flag_10");
-  EXPECT_EQ(FLAGS_test_flag_10.Help(), "test flag 10");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_10.Filename(), expected_file_name))
-      << FLAGS_test_flag_10.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Name(),
+            "test_flag_10");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Help(),
+            "test flag 10");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_11.Name(), "test_flag_11");
-  EXPECT_EQ(FLAGS_test_flag_11.Help(), "test flag 11");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_11.Filename(), expected_file_name))
-      << FLAGS_test_flag_11.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Name(),
+            "test_flag_11");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Help(),
+            "test flag 11");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Filename();
+
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Name(),
+            "test_flag_12");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Help(),
+            "test flag 12");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename();
 }
 #endif  // !ABSL_FLAGS_STRIP_NAMES
 
 // --------------------------------------------------------------------
 
 TEST_F(FlagTest, TestDefault) {
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).DefaultValue(),
+            "true");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).DefaultValue(),
+            "1234");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).DefaultValue(),
+            "-34");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).DefaultValue(),
+            "189");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).DefaultValue(),
+            "10765");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).DefaultValue(),
+            "40000");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).DefaultValue(),
+            "-1234567");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).DefaultValue(),
+            "9876543");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).DefaultValue(),
+            "-9.876e-50");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).DefaultValue(),
+            "1.234e+12");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).DefaultValue(),
+            "");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).DefaultValue(),
+            "10m");
+
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).CurrentValue(),
+            "true");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).CurrentValue(),
+            "1234");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).CurrentValue(),
+            "-34");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).CurrentValue(),
+            "189");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).CurrentValue(),
+            "10765");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).CurrentValue(),
+            "40000");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).CurrentValue(),
+            "-1234567");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).CurrentValue(),
+            "9876543");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).CurrentValue(),
+            "-9.876e-50");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).CurrentValue(),
+            "1.234e+12");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).CurrentValue(),
+            "");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).CurrentValue(),
+            "10m");
+
   EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true);
   EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234);
   EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_03), -34);
@@ -242,6 +450,68 @@
   EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), -9.876e-50, 1e-55);
   EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f);
   EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "");
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Minutes(10));
+}
+
+// --------------------------------------------------------------------
+
+struct NonTriviallyCopyableAggregate {
+  NonTriviallyCopyableAggregate() = default;
+  NonTriviallyCopyableAggregate(const NonTriviallyCopyableAggregate& rhs)
+      : value(rhs.value) {}
+  NonTriviallyCopyableAggregate& operator=(
+      const NonTriviallyCopyableAggregate& rhs) {
+    value = rhs.value;
+    return *this;
+  }
+
+  int value;
+};
+bool AbslParseFlag(absl::string_view src, NonTriviallyCopyableAggregate* f,
+                   std::string* e) {
+  return absl::ParseFlag(src, &f->value, e);
+}
+std::string AbslUnparseFlag(const NonTriviallyCopyableAggregate& ntc) {
+  return absl::StrCat(ntc.value);
+}
+
+bool operator==(const NonTriviallyCopyableAggregate& ntc1,
+                const NonTriviallyCopyableAggregate& ntc2) {
+  return ntc1.value == ntc2.value;
+}
+
+}  // namespace
+
+ABSL_FLAG(bool, test_flag_eb_01, {}, "");
+ABSL_FLAG(int32_t, test_flag_eb_02, {}, "");
+ABSL_FLAG(int64_t, test_flag_eb_03, {}, "");
+ABSL_FLAG(double, test_flag_eb_04, {}, "");
+ABSL_FLAG(std::string, test_flag_eb_05, {}, "");
+ABSL_FLAG(NonTriviallyCopyableAggregate, test_flag_eb_06, {}, "");
+
+namespace {
+
+TEST_F(FlagTest, TestEmptyBracesDefault) {
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_01).DefaultValue(),
+            "false");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_02).DefaultValue(),
+            "0");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_03).DefaultValue(),
+            "0");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_04).DefaultValue(),
+            "0");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_05).DefaultValue(),
+            "");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_06).DefaultValue(),
+            "0");
+
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_01), false);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_02), 0);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_03), 0);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_04), 0.0);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_05), "");
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_06),
+            NonTriviallyCopyableAggregate{});
 }
 
 // --------------------------------------------------------------------
@@ -279,6 +549,75 @@
 
   absl::SetFlag(&FLAGS_test_flag_11, "asdf");
   EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "asdf");
+
+  absl::SetFlag(&FLAGS_test_flag_12, absl::Seconds(110));
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Seconds(110));
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(FlagTest, TestGetViaReflection) {
+  auto* handle = absl::FindCommandLineFlag("test_flag_01");
+  EXPECT_EQ(*handle->TryGet<bool>(), true);
+  handle = absl::FindCommandLineFlag("test_flag_02");
+  EXPECT_EQ(*handle->TryGet<int>(), 1234);
+  handle = absl::FindCommandLineFlag("test_flag_03");
+  EXPECT_EQ(*handle->TryGet<int16_t>(), -34);
+  handle = absl::FindCommandLineFlag("test_flag_04");
+  EXPECT_EQ(*handle->TryGet<uint16_t>(), 189);
+  handle = absl::FindCommandLineFlag("test_flag_05");
+  EXPECT_EQ(*handle->TryGet<int32_t>(), 10765);
+  handle = absl::FindCommandLineFlag("test_flag_06");
+  EXPECT_EQ(*handle->TryGet<uint32_t>(), 40000);
+  handle = absl::FindCommandLineFlag("test_flag_07");
+  EXPECT_EQ(*handle->TryGet<int64_t>(), -1234567);
+  handle = absl::FindCommandLineFlag("test_flag_08");
+  EXPECT_EQ(*handle->TryGet<uint64_t>(), 9876543);
+  handle = absl::FindCommandLineFlag("test_flag_09");
+  EXPECT_NEAR(*handle->TryGet<double>(), -9.876e-50, 1e-55);
+  handle = absl::FindCommandLineFlag("test_flag_10");
+  EXPECT_NEAR(*handle->TryGet<float>(), 1.234e12f, 1e5f);
+  handle = absl::FindCommandLineFlag("test_flag_11");
+  EXPECT_EQ(*handle->TryGet<std::string>(), "");
+  handle = absl::FindCommandLineFlag("test_flag_12");
+  EXPECT_EQ(*handle->TryGet<absl::Duration>(), absl::Minutes(10));
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(FlagTest, ConcurrentSetAndGet) {
+  static constexpr int kNumThreads = 8;
+  // Two arbitrary durations. One thread will concurrently flip the flag
+  // between these two values, while the other threads read it and verify
+  // that no other value is seen.
+  static const absl::Duration kValidDurations[] = {
+      absl::Seconds(int64_t{0x6cebf47a9b68c802}) + absl::Nanoseconds(229702057),
+      absl::Seconds(int64_t{0x23fec0307e4e9d3}) + absl::Nanoseconds(44555374)};
+  absl::SetFlag(&FLAGS_test_flag_12, kValidDurations[0]);
+
+  std::atomic<bool> stop{false};
+  std::vector<std::thread> threads;
+  auto* handle = absl::FindCommandLineFlag("test_flag_12");
+  for (int i = 0; i < kNumThreads; i++) {
+    threads.emplace_back([&]() {
+      while (!stop.load(std::memory_order_relaxed)) {
+        // Try loading the flag both directly and via a reflection
+        // handle.
+        absl::Duration v = absl::GetFlag(FLAGS_test_flag_12);
+        EXPECT_TRUE(v == kValidDurations[0] || v == kValidDurations[1]);
+        v = *handle->TryGet<absl::Duration>();
+        EXPECT_TRUE(v == kValidDurations[0] || v == kValidDurations[1]);
+      }
+    });
+  }
+  absl::Time end_time = absl::Now() + absl::Seconds(1);
+  int i = 0;
+  while (absl::Now() < end_time) {
+    absl::SetFlag(&FLAGS_test_flag_12,
+                  kValidDurations[i++ % ABSL_ARRAYSIZE(kValidDurations)]);
+  }
+  stop.store(true, std::memory_order_relaxed);
+  for (auto& t : threads) t.join();
 }
 
 // --------------------------------------------------------------------
@@ -287,28 +626,33 @@
 
 }  // namespace
 
-ABSL_FLAG(int, test_flag_12, GetDflt1(), "test flag 12");
-ABSL_FLAG(std::string, test_flag_13, absl::StrCat("AAA", "BBB"),
-          "test flag 13");
+ABSL_FLAG(int, test_int_flag_with_non_const_default, GetDflt1(),
+          "test int flag non const default");
+ABSL_FLAG(std::string, test_string_flag_with_non_const_default,
+          absl::StrCat("AAA", "BBB"), "test string flag non const default");
 
 namespace {
 
 TEST_F(FlagTest, TestNonConstexprDefault) {
-  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), 1);
-  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), "AAABBB");
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_int_flag_with_non_const_default), 1);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_string_flag_with_non_const_default),
+            "AAABBB");
 }
 
 // --------------------------------------------------------------------
 
 }  // namespace
 
-ABSL_FLAG(bool, test_flag_14, true, absl::StrCat("test ", "flag ", "14"));
+ABSL_FLAG(bool, test_flag_with_non_const_help, true,
+          absl::StrCat("test ", "flag ", "non const help"));
 
 namespace {
 
 #if !ABSL_FLAGS_STRIP_HELP
 TEST_F(FlagTest, TestNonConstexprHelp) {
-  EXPECT_EQ(FLAGS_test_flag_14.Help(), "test flag 14");
+  EXPECT_EQ(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_with_non_const_help).Help(),
+      "test flag non const help");
 }
 #endif  //! ABSL_FLAGS_STRIP_HELP
 
@@ -374,14 +718,14 @@
 
 }  // namespace
 
-ABSL_FLAG(CustomUDT, test_flag_15, CustomUDT(), "test flag 15");
+ABSL_FLAG(CustomUDT, test_flag_custom_udt, CustomUDT(), "test flag custom UDT");
 
 namespace {
 
 TEST_F(FlagTest, TestCustomUDT) {
-  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_15), CustomUDT(1, 1));
-  absl::SetFlag(&FLAGS_test_flag_15, CustomUDT(2, 3));
-  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_15), CustomUDT(2, 3));
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_custom_udt), CustomUDT(1, 1));
+  absl::SetFlag(&FLAGS_test_flag_custom_udt, CustomUDT(2, 3));
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_custom_udt), CustomUDT(2, 3));
 }
 
 // MSVC produces link error on the type mismatch.
@@ -391,18 +735,22 @@
 using FlagDeathTest = FlagTest;
 
 TEST_F(FlagDeathTest, TestTypeMismatchValidations) {
-  EXPECT_DEBUG_DEATH(
+#if !defined(NDEBUG)
+  EXPECT_DEATH_IF_SUPPORTED(
       static_cast<void>(absl::GetFlag(FLAGS_mistyped_int_flag)),
       "Flag 'mistyped_int_flag' is defined as one type and declared "
       "as another");
-  EXPECT_DEATH(absl::SetFlag(&FLAGS_mistyped_int_flag, 1),
-               "Flag 'mistyped_int_flag' is defined as one type and declared "
-               "as another");
+  EXPECT_DEATH_IF_SUPPORTED(
+      static_cast<void>(absl::GetFlag(FLAGS_mistyped_string_flag)),
+      "Flag 'mistyped_string_flag' is defined as one type and "
+      "declared as another");
+#endif
 
-  EXPECT_DEATH(static_cast<void>(absl::GetFlag(FLAGS_mistyped_string_flag)),
-               "Flag 'mistyped_string_flag' is defined as one type and "
-               "declared as another");
-  EXPECT_DEATH(
+  EXPECT_DEATH_IF_SUPPORTED(
+      absl::SetFlag(&FLAGS_mistyped_int_flag, 1),
+      "Flag 'mistyped_int_flag' is defined as one type and declared "
+      "as another");
+  EXPECT_DEATH_IF_SUPPORTED(
       absl::SetFlag(&FLAGS_mistyped_string_flag, std::vector<std::string>{}),
       "Flag 'mistyped_string_flag' is defined as one type and declared as "
       "another");
@@ -440,16 +788,17 @@
 
 // Flag default values can be specified with a value that converts to the flag
 // value type implicitly.
-ABSL_FLAG(ConversionTestVal, test_flag_16,
-          ConversionTestVal::ViaImplicitConv::kTen, "test flag 16");
+ABSL_FLAG(ConversionTestVal, test_flag_implicit_conv,
+          ConversionTestVal::ViaImplicitConv::kTen,
+          "test flag init via implicit conversion");
 
 namespace {
 
 TEST_F(FlagTest, CanSetViaImplicitConversion) {
-  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_16).a, 10);
-  absl::SetFlag(&FLAGS_test_flag_16,
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_implicit_conv).a, 10);
+  absl::SetFlag(&FLAGS_test_flag_implicit_conv,
                 ConversionTestVal::ViaImplicitConv::kEleven);
-  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_16).a, 11);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_implicit_conv).a, 11);
 }
 
 // --------------------------------------------------------------------
@@ -494,25 +843,103 @@
   EXPECT_EQ(absl::GetFlag(FLAGS_ndc_flag2).value, 25);
 }
 
-// --------------------------------------------------------------------
-
 }  // namespace
 
+// --------------------------------------------------------------------
+
 ABSL_RETIRED_FLAG(bool, old_bool_flag, true, "old descr");
 ABSL_RETIRED_FLAG(int, old_int_flag, (int)std::sqrt(10), "old descr");
 ABSL_RETIRED_FLAG(std::string, old_str_flag, "", absl::StrCat("old ", "descr"));
 
+bool initializaion_order_fiasco_test = [] {
+  // Iterate over all the flags during static initialization.
+  // This should not trigger ASan's initialization-order-fiasco.
+  auto* handle1 = absl::FindCommandLineFlag("flag_on_separate_file");
+  auto* handle2 = absl::FindCommandLineFlag("retired_flag_on_separate_file");
+  if (handle1 != nullptr && handle2 != nullptr) {
+    return handle1->Name() == handle2->Name();
+  }
+  return true;
+}();
+
 namespace {
 
 TEST_F(FlagTest, TestRetiredFlagRegistration) {
-  bool is_bool = false;
-  EXPECT_TRUE(flags::IsRetiredFlag("old_bool_flag", &is_bool));
-  EXPECT_TRUE(is_bool);
-  EXPECT_TRUE(flags::IsRetiredFlag("old_int_flag", &is_bool));
-  EXPECT_FALSE(is_bool);
-  EXPECT_TRUE(flags::IsRetiredFlag("old_str_flag", &is_bool));
-  EXPECT_FALSE(is_bool);
-  EXPECT_FALSE(flags::IsRetiredFlag("some_other_flag", &is_bool));
+  auto* handle = absl::FindCommandLineFlag("old_bool_flag");
+  EXPECT_TRUE(handle->IsOfType<bool>());
+  EXPECT_TRUE(handle->IsRetired());
+  handle = absl::FindCommandLineFlag("old_int_flag");
+  EXPECT_TRUE(handle->IsOfType<int>());
+  EXPECT_TRUE(handle->IsRetired());
+  handle = absl::FindCommandLineFlag("old_str_flag");
+  EXPECT_TRUE(handle->IsOfType<std::string>());
+  EXPECT_TRUE(handle->IsRetired());
+}
+
+}  // namespace
+
+// --------------------------------------------------------------------
+
+namespace {
+
+// User-defined type with small alignment, but size exceeding 16.
+struct SmallAlignUDT {
+  SmallAlignUDT() : c('A'), s(12) {}
+  char c;
+  int16_t s;
+  char bytes[14];
+};
+
+bool AbslParseFlag(absl::string_view, SmallAlignUDT*, std::string*) {
+  return true;
+}
+std::string AbslUnparseFlag(const SmallAlignUDT&) { return ""; }
+
+// User-defined type with small size, but not trivially copyable.
+struct NonTriviallyCopyableUDT {
+  NonTriviallyCopyableUDT() : c('A') {}
+  NonTriviallyCopyableUDT(const NonTriviallyCopyableUDT& rhs) : c(rhs.c) {}
+  NonTriviallyCopyableUDT& operator=(const NonTriviallyCopyableUDT& rhs) {
+    c = rhs.c;
+    return *this;
+  }
+
+  char c;
+};
+
+bool AbslParseFlag(absl::string_view, NonTriviallyCopyableUDT*, std::string*) {
+  return true;
+}
+std::string AbslUnparseFlag(const NonTriviallyCopyableUDT&) { return ""; }
+
+}  // namespace
+
+ABSL_FLAG(SmallAlignUDT, test_flag_sa_udt, {}, "help");
+ABSL_FLAG(NonTriviallyCopyableUDT, test_flag_ntc_udt, {}, "help");
+
+namespace {
+
+TEST_F(FlagTest, TestSmallAlignUDT) {
+  SmallAlignUDT value = absl::GetFlag(FLAGS_test_flag_sa_udt);
+  EXPECT_EQ(value.c, 'A');
+  EXPECT_EQ(value.s, 12);
+
+  value.c = 'B';
+  value.s = 45;
+  absl::SetFlag(&FLAGS_test_flag_sa_udt, value);
+  value = absl::GetFlag(FLAGS_test_flag_sa_udt);
+  EXPECT_EQ(value.c, 'B');
+  EXPECT_EQ(value.s, 45);
+}
+
+TEST_F(FlagTest, TestNonTriviallyCopyableUDT) {
+  NonTriviallyCopyableUDT value = absl::GetFlag(FLAGS_test_flag_ntc_udt);
+  EXPECT_EQ(value.c, 'A');
+
+  value.c = 'B';
+  absl::SetFlag(&FLAGS_test_flag_ntc_udt, value);
+  value = absl::GetFlag(FLAGS_test_flag_ntc_udt);
+  EXPECT_EQ(value.c, 'B');
 }
 
 }  // namespace
diff --git a/absl/flags/flag_test_defs.cc b/absl/flags/flag_test_defs.cc
index 49f91de..4e1693c 100644
--- a/absl/flags/flag_test_defs.cc
+++ b/absl/flags/flag_test_defs.cc
@@ -20,5 +20,5 @@
 
 ABSL_FLAG(int, mistyped_int_flag, 0, "");
 ABSL_FLAG(std::string, mistyped_string_flag, "", "");
-ABSL_RETIRED_FLAG(bool, old_bool_flag, true,
-                  "repetition of retired flag definition");
+ABSL_FLAG(bool, flag_on_separate_file, false, "");
+ABSL_RETIRED_FLAG(bool, retired_flag_on_separate_file, false, "");
diff --git a/absl/random/mocking_bit_gen.cc b/absl/flags/internal/commandlineflag.cc
similarity index 76%
rename from absl/random/mocking_bit_gen.cc
rename to absl/flags/internal/commandlineflag.cc
index 6bb1e41..4482955 100644
--- a/absl/random/mocking_bit_gen.cc
+++ b/absl/flags/internal/commandlineflag.cc
@@ -1,5 +1,5 @@
 //
-// Copyright 2018 The Abseil Authors.
+// 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.
@@ -12,19 +12,15 @@
 // 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/random/mocking_bit_gen.h"
 
-#include <string>
+#include "absl/flags/internal/commandlineflag.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
-MockingBitGen::~MockingBitGen() {
+namespace flags_internal {
 
-  for (const auto& del : deleters_) {
-    del();
-  }
-}
+FlagStateInterface::~FlagStateInterface() {}
 
+}  // namespace flags_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/flags/internal/commandlineflag.h b/absl/flags/internal/commandlineflag.h
index 6363c66..ebfe81b 100644
--- a/absl/flags/internal/commandlineflag.h
+++ b/absl/flags/internal/commandlineflag.h
@@ -16,41 +16,19 @@
 #ifndef ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
 #define ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
 
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <typeinfo>
-
 #include "absl/base/config.h"
-#include "absl/base/macros.h"
-#include "absl/flags/config.h"
-#include "absl/flags/marshalling.h"
-#include "absl/strings/string_view.h"
-#include "absl/types/optional.h"
+#include "absl/base/internal/fast_type_id.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace flags_internal {
 
-// An alias for flag static type id. Values of type identify the flag value type
-// simialarly to typeid(T), but without relying on RTTI being available. In most
+// An alias for flag fast type id. This value identifies the flag value type
+// similarly to typeid(T), without relying on RTTI being available. In most
 // cases this id is enough to uniquely identify the flag's value type. In a few
 // cases we'll have to resort to using actual RTTI implementation if it is
 // available.
-using FlagStaticTypeId = void* (*)();
-
-// Address of this function template is used in current implementation as a flag
-// static type id.
-template <typename T>
-void* FlagStaticTypeIdGen() {
-#if defined(ABSL_FLAGS_INTERNAL_HAS_RTTI)
-  return const_cast<std::type_info*>(&typeid(T));
-#else
-  return nullptr;
-#endif
-}
+using FlagFastTypeId = absl::base_internal::FastTypeIdType;
 
 // Options that control SetCommandLineOptionWithMode.
 enum FlagSettingMode {
@@ -65,7 +43,7 @@
   SET_FLAGS_DEFAULT
 };
 
-// Options that control SetFromString: Source of a value.
+// Options that control ParseFrom: Source of a value.
 enum ValueSource {
   // Flag is being set by value specified on a command line.
   kCommandLine,
@@ -77,135 +55,12 @@
 // of a flag produced this flag state from method CommandLineFlag::SaveState().
 class FlagStateInterface {
  public:
-  virtual ~FlagStateInterface() {}
+  virtual ~FlagStateInterface();
 
   // Restores the flag originated this object to the saved state.
   virtual void Restore() const = 0;
 };
 
-// Holds all information for a flag.
-class CommandLineFlag {
- public:
-  constexpr CommandLineFlag() = default;
-
-  // Not copyable/assignable.
-  CommandLineFlag(const CommandLineFlag&) = delete;
-  CommandLineFlag& operator=(const CommandLineFlag&) = delete;
-
-  // Non-polymorphic access methods.
-
-  // Return true iff flag has type T.
-  template <typename T>
-  inline bool IsOfType() const {
-    return TypeId() == &flags_internal::FlagStaticTypeIdGen<T>;
-  }
-
-  // Attempts to retrieve the flag value. Returns value on success,
-  // absl::nullopt otherwise.
-  template <typename T>
-  absl::optional<T> Get() const {
-    if (IsRetired() || !IsOfType<T>()) {
-      return absl::nullopt;
-    }
-
-    // Implementation notes:
-    //
-    // We are wrapping a union around the value of `T` to serve three purposes:
-    //
-    //  1. `U.value` has correct size and alignment for a value of type `T`
-    //  2. The `U.value` constructor is not invoked since U's constructor does
-    //     not do it explicitly.
-    //  3. The `U.value` destructor is invoked since U's destructor does it
-    //     explicitly. This makes `U` a kind of RAII wrapper around non default
-    //     constructible value of T, which is destructed when we leave the
-    //     scope. We do need to destroy U.value, which is constructed by
-    //     CommandLineFlag::Read even though we left it in a moved-from state
-    //     after std::move.
-    //
-    // All of this serves to avoid requiring `T` being default constructible.
-    union U {
-      T value;
-      U() {}
-      ~U() { value.~T(); }
-    };
-    U u;
-
-    Read(&u.value);
-    return std::move(u.value);
-  }
-
-  // Polymorphic access methods
-
-  // Returns name of this flag.
-  virtual absl::string_view Name() const = 0;
-  // Returns name of the file where this flag is defined.
-  virtual std::string Filename() const = 0;
-  // Returns name of the flag's value type for some built-in types or empty
-  // std::string.
-  virtual absl::string_view Typename() const = 0;
-  // Returns help message associated with this flag.
-  virtual std::string Help() const = 0;
-  // Returns true iff this object corresponds to retired flag.
-  virtual bool IsRetired() const { return false; }
-  // Returns true iff this is a handle to an Abseil Flag.
-  virtual bool IsAbseilFlag() const { return true; }
-  // Returns id of the flag's value type.
-  virtual FlagStaticTypeId TypeId() const = 0;
-  virtual bool IsModified() const = 0;
-  virtual bool IsSpecifiedOnCommandLine() const = 0;
-  virtual std::string DefaultValue() const = 0;
-  virtual std::string CurrentValue() const = 0;
-
-  // Interfaces to operate on validators.
-  virtual bool ValidateInputValue(absl::string_view value) const = 0;
-
-  // Interface to save flag to some persistent state. Returns current flag state
-  // or nullptr if flag does not support saving and restoring a state.
-  virtual std::unique_ptr<FlagStateInterface> SaveState() = 0;
-
-  // Sets the value of the flag based on specified std::string `value`. If the flag
-  // was successfully set to new value, it returns true. Otherwise, sets `error`
-  // to indicate the error, leaves the flag unchanged, and returns false. There
-  // are three ways to set the flag's value:
-  //  * Update the current flag value
-  //  * Update the flag's default value
-  //  * Update the current flag value if it was never set before
-  // The mode is selected based on `set_mode` parameter.
-  virtual bool SetFromString(absl::string_view value,
-                             flags_internal::FlagSettingMode set_mode,
-                             flags_internal::ValueSource source,
-                             std::string* error) = 0;
-
-  // Checks that flags default value can be converted to std::string and back to the
-  // flag's value type.
-  virtual void CheckDefaultValueParsingRoundtrip() const = 0;
-
- protected:
-  ~CommandLineFlag() = default;
-
- private:
-  // Copy-construct a new value of the flag's type in a memory referenced by
-  // the dst based on the current flag's value.
-  virtual void Read(void* dst) const = 0;
-};
-
-// This macro is the "source of truth" for the list of supported flag built-in
-// types.
-#define ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(A) \
-  A(bool)                                    \
-  A(short)                                   \
-  A(unsigned short)                          \
-  A(int)                                     \
-  A(unsigned int)                            \
-  A(long)                                    \
-  A(unsigned long)                           \
-  A(long long)                               \
-  A(unsigned long long)                      \
-  A(double)                                  \
-  A(float)                                   \
-  A(std::string)                             \
-  A(std::vector<std::string>)
-
 }  // namespace flags_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/flags/internal/commandlineflag_test.cc b/absl/flags/internal/commandlineflag_test.cc
deleted file mode 100644
index 0e8bc31..0000000
--- a/absl/flags/internal/commandlineflag_test.cc
+++ /dev/null
@@ -1,219 +0,0 @@
-//
-//  Copyright 2019 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/flags/internal/commandlineflag.h"
-
-#include <memory>
-#include <string>
-
-#include "gtest/gtest.h"
-#include "absl/flags/flag.h"
-#include "absl/flags/internal/registry.h"
-#include "absl/flags/usage_config.h"
-#include "absl/memory/memory.h"
-#include "absl/strings/match.h"
-#include "absl/strings/str_cat.h"
-#include "absl/strings/string_view.h"
-
-ABSL_FLAG(int, int_flag, 201, "int_flag help");
-ABSL_FLAG(std::string, string_flag, "dflt",
-          absl::StrCat("string_flag", " help"));
-ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
-
-namespace {
-
-namespace flags = absl::flags_internal;
-
-class CommandLineFlagTest : public testing::Test {
- protected:
-  static void SetUpTestSuite() {
-    // Install a function to normalize filenames before this test is run.
-    absl::FlagsUsageConfig default_config;
-    default_config.normalize_filename = &CommandLineFlagTest::NormalizeFileName;
-    absl::SetFlagsUsageConfig(default_config);
-  }
-
-  void SetUp() override { flag_saver_ = absl::make_unique<flags::FlagSaver>(); }
-  void TearDown() override { flag_saver_.reset(); }
-
- private:
-  static std::string NormalizeFileName(absl::string_view fname) {
-#ifdef _WIN32
-    std::string normalized(fname);
-    std::replace(normalized.begin(), normalized.end(), '\\', '/');
-    fname = normalized;
-#endif
-    return std::string(fname);
-  }
-
-  std::unique_ptr<flags::FlagSaver> flag_saver_;
-};
-
-TEST_F(CommandLineFlagTest, TestAttributesAccessMethods) {
-  auto* flag_01 = flags::FindCommandLineFlag("int_flag");
-
-  ASSERT_TRUE(flag_01);
-  EXPECT_EQ(flag_01->Name(), "int_flag");
-  EXPECT_EQ(flag_01->Help(), "int_flag help");
-  EXPECT_EQ(flag_01->Typename(), "");
-  EXPECT_TRUE(!flag_01->IsRetired());
-  EXPECT_TRUE(flag_01->IsOfType<int>());
-  EXPECT_TRUE(
-      absl::EndsWith(flag_01->Filename(),
-                     "absl/flags/internal/commandlineflag_test.cc"))
-      << flag_01->Filename();
-
-  auto* flag_02 = flags::FindCommandLineFlag("string_flag");
-
-  ASSERT_TRUE(flag_02);
-  EXPECT_EQ(flag_02->Name(), "string_flag");
-  EXPECT_EQ(flag_02->Help(), "string_flag help");
-  EXPECT_EQ(flag_02->Typename(), "");
-  EXPECT_TRUE(!flag_02->IsRetired());
-  EXPECT_TRUE(flag_02->IsOfType<std::string>());
-  EXPECT_TRUE(
-      absl::EndsWith(flag_02->Filename(),
-                     "absl/flags/internal/commandlineflag_test.cc"))
-      << flag_02->Filename();
-
-  auto* flag_03 = flags::FindRetiredFlag("bool_retired_flag");
-
-  ASSERT_TRUE(flag_03);
-  EXPECT_EQ(flag_03->Name(), "bool_retired_flag");
-  EXPECT_EQ(flag_03->Help(), "");
-  EXPECT_EQ(flag_03->Typename(), "");
-  EXPECT_TRUE(flag_03->IsRetired());
-  EXPECT_TRUE(flag_03->IsOfType<bool>());
-  EXPECT_EQ(flag_03->Filename(), "RETIRED");
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(CommandLineFlagTest, TestValueAccessMethods) {
-  absl::SetFlag(&FLAGS_int_flag, 301);
-  auto* flag_01 = flags::FindCommandLineFlag("int_flag");
-
-  ASSERT_TRUE(flag_01);
-  EXPECT_EQ(flag_01->CurrentValue(), "301");
-  EXPECT_EQ(flag_01->DefaultValue(), "201");
-
-  absl::SetFlag(&FLAGS_string_flag, "new_str_value");
-  auto* flag_02 = flags::FindCommandLineFlag("string_flag");
-
-  ASSERT_TRUE(flag_02);
-  EXPECT_EQ(flag_02->CurrentValue(), "new_str_value");
-  EXPECT_EQ(flag_02->DefaultValue(), "dflt");
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(CommandLineFlagTest, TestSetFromStringCurrentValue) {
-  std::string err;
-
-  auto* flag_01 = flags::FindCommandLineFlag("int_flag");
-  EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
-
-  EXPECT_TRUE(flag_01->SetFromString("11", flags::SET_FLAGS_VALUE,
-                                     flags::kProgrammaticChange, &err));
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11);
-  EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
-
-  EXPECT_TRUE(flag_01->SetFromString("-123", flags::SET_FLAGS_VALUE,
-                                     flags::kProgrammaticChange, &err));
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
-  EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
-
-  EXPECT_TRUE(!flag_01->SetFromString("xyz", flags::SET_FLAGS_VALUE,
-                                      flags::kProgrammaticChange, &err));
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
-  EXPECT_EQ(err, "Illegal value 'xyz' specified for flag 'int_flag'");
-  EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
-
-  EXPECT_TRUE(!flag_01->SetFromString("A1", flags::SET_FLAGS_VALUE,
-                                      flags::kProgrammaticChange, &err));
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
-  EXPECT_EQ(err, "Illegal value 'A1' specified for flag 'int_flag'");
-  EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
-
-  EXPECT_TRUE(flag_01->SetFromString("0x10", flags::SET_FLAGS_VALUE,
-                                     flags::kProgrammaticChange, &err));
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 16);
-  EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
-
-  EXPECT_TRUE(flag_01->SetFromString("011", flags::SET_FLAGS_VALUE,
-                                     flags::kCommandLine, &err));
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11);
-  EXPECT_TRUE(flag_01->IsSpecifiedOnCommandLine());
-
-  EXPECT_TRUE(!flag_01->SetFromString("", flags::SET_FLAGS_VALUE,
-                                      flags::kProgrammaticChange, &err));
-  EXPECT_EQ(err, "Illegal value '' specified for flag 'int_flag'");
-
-  auto* flag_02 = flags::FindCommandLineFlag("string_flag");
-  EXPECT_TRUE(flag_02->SetFromString("xyz", flags::SET_FLAGS_VALUE,
-                                     flags::kProgrammaticChange, &err));
-  EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "xyz");
-
-  EXPECT_TRUE(flag_02->SetFromString("", flags::SET_FLAGS_VALUE,
-                                     flags::kProgrammaticChange, &err));
-  EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "");
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(CommandLineFlagTest, TestSetFromStringDefaultValue) {
-  std::string err;
-
-  auto* flag_01 = flags::FindCommandLineFlag("int_flag");
-
-  EXPECT_TRUE(flag_01->SetFromString("111", flags::SET_FLAGS_DEFAULT,
-                                     flags::kProgrammaticChange, &err));
-  EXPECT_EQ(flag_01->DefaultValue(), "111");
-
-  auto* flag_02 = flags::FindCommandLineFlag("string_flag");
-
-  EXPECT_TRUE(flag_02->SetFromString("abc", flags::SET_FLAGS_DEFAULT,
-                                     flags::kProgrammaticChange, &err));
-  EXPECT_EQ(flag_02->DefaultValue(), "abc");
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(CommandLineFlagTest, TestSetFromStringIfDefault) {
-  std::string err;
-
-  auto* flag_01 = flags::FindCommandLineFlag("int_flag");
-
-  EXPECT_TRUE(flag_01->SetFromString("22", flags::SET_FLAG_IF_DEFAULT,
-                                     flags::kProgrammaticChange, &err))
-      << err;
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22);
-
-  EXPECT_TRUE(flag_01->SetFromString("33", flags::SET_FLAG_IF_DEFAULT,
-                                     flags::kProgrammaticChange, &err));
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22);
-  // EXPECT_EQ(err, "ERROR: int_flag is already set to 22");
-
-  // Reset back to default value
-  EXPECT_TRUE(flag_01->SetFromString("201", flags::SET_FLAGS_VALUE,
-                                     flags::kProgrammaticChange, &err));
-
-  EXPECT_TRUE(flag_01->SetFromString("33", flags::SET_FLAG_IF_DEFAULT,
-                                     flags::kProgrammaticChange, &err));
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 201);
-  // EXPECT_EQ(err, "ERROR: int_flag is already set to 201");
-}
-
-}  // namespace
diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc
index 5a921e2..f83c1fe 100644
--- a/absl/flags/internal/flag.cc
+++ b/absl/flags/internal/flag.cc
@@ -15,21 +15,26 @@
 
 #include "absl/flags/internal/flag.h"
 
+#include <assert.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <string.h>
 
+#include <array>
 #include <atomic>
 #include <memory>
+#include <new>
 #include <string>
-#include <vector>
+#include <typeinfo>
 
-#include "absl/base/attributes.h"
+#include "absl/base/call_once.h"
+#include "absl/base/casts.h"
 #include "absl/base/config.h"
-#include "absl/base/const_init.h"
 #include "absl/base/optimization.h"
+#include "absl/flags/config.h"
 #include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/usage_config.h"
+#include "absl/memory/memory.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
 #include "absl/synchronization/mutex.h"
@@ -47,10 +52,10 @@
 namespace {
 
 // Currently we only validate flag values for user-defined flag types.
-bool ShouldValidateFlagValue(FlagStaticTypeId flag_type_id) {
-#define DONT_VALIDATE(T) \
-  if (flag_type_id == &FlagStaticTypeIdGen<T>) return false;
-  ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(DONT_VALIDATE)
+bool ShouldValidateFlagValue(FlagFastTypeId flag_type_id) {
+#define DONT_VALIDATE(T, _) \
+  if (flag_type_id == base_internal::FastTypeId<T>()) return false;
+  ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(DONT_VALIDATE)
 #undef DONT_VALIDATE
 
   return true;
@@ -62,55 +67,139 @@
 // 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;
 
  private:
-  absl::Mutex* mu_;
+  absl::Mutex& mu_;
 };
 
 }  // namespace
 
+///////////////////////////////////////////////////////////////////////////////
+// Persistent state of the flag data.
+
+class FlagImpl;
+
+class FlagState : public flags_internal::FlagStateInterface {
+ public:
+  template <typename V>
+  FlagState(FlagImpl& flag_impl, const V& v, bool modified,
+            bool on_command_line, int64_t counter)
+      : flag_impl_(flag_impl),
+        value_(v),
+        modified_(modified),
+        on_command_line_(on_command_line),
+        counter_(counter) {}
+
+  ~FlagState() override {
+    if (flag_impl_.ValueStorageKind() != FlagValueStorageKind::kAlignedBuffer &&
+        flag_impl_.ValueStorageKind() != FlagValueStorageKind::kSequenceLocked)
+      return;
+    flags_internal::Delete(flag_impl_.op_, value_.heap_allocated);
+  }
+
+ private:
+  friend class FlagImpl;
+
+  // Restores the flag to the saved state.
+  void Restore() const override {
+    if (!flag_impl_.RestoreState(*this)) return;
+
+    ABSL_INTERNAL_LOG(INFO,
+                      absl::StrCat("Restore saved value of ", flag_impl_.Name(),
+                                   " to: ", flag_impl_.CurrentValue()));
+  }
+
+  // Flag and saved flag data.
+  FlagImpl& flag_impl_;
+  union SavedValue {
+    explicit SavedValue(void* v) : heap_allocated(v) {}
+    explicit SavedValue(int64_t v) : one_word(v) {}
+
+    void* heap_allocated;
+    int64_t one_word;
+  } value_;
+  bool modified_;
+  bool on_command_line_;
+  int64_t counter_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Flag implementation, which does not depend on flag value type.
+
+DynValueDeleter::DynValueDeleter(FlagOpFn op_arg) : op(op_arg) {}
+
+void DynValueDeleter::operator()(void* ptr) const {
+  if (op == nullptr) return;
+
+  Delete(op, ptr);
+}
+
 void FlagImpl::Init() {
   new (&data_guard_) absl::Mutex;
 
-  absl::MutexLock lock(reinterpret_cast<absl::Mutex*>(&data_guard_));
+  auto def_kind = static_cast<FlagDefaultKind>(def_kind_);
 
-  value_.dynamic = MakeInitValue().release();
-  StoreAtomic();
+  switch (ValueStorageKind()) {
+    case FlagValueStorageKind::kAlignedBuffer:
+      // For this storage kind the default_value_ always points to gen_func
+      // during initialization.
+      assert(def_kind == FlagDefaultKind::kGenFunc);
+      (*default_value_.gen_func)(AlignedBufferValue());
+      break;
+    case FlagValueStorageKind::kOneWordAtomic: {
+      alignas(int64_t) std::array<char, sizeof(int64_t)> buf{};
+      if (def_kind == FlagDefaultKind::kGenFunc) {
+        (*default_value_.gen_func)(buf.data());
+      } else {
+        assert(def_kind != FlagDefaultKind::kDynamicValue);
+        std::memcpy(buf.data(), &default_value_, Sizeof(op_));
+      }
+      OneWordValue().store(absl::bit_cast<int64_t>(buf),
+                           std::memory_order_release);
+      break;
+    }
+    case FlagValueStorageKind::kSequenceLocked: {
+      // For this storage kind the default_value_ always points to gen_func
+      // during initialization.
+      assert(def_kind == FlagDefaultKind::kGenFunc);
+      (*default_value_.gen_func)(AtomicBufferValue());
+      break;
+    }
+  }
+  seq_lock_.MarkInitialized();
 }
 
-// Ensures that the lazily initialized data is initialized,
-// and returns pointer to the mutex guarding flags data.
 absl::Mutex* FlagImpl::DataGuard() const {
   absl::call_once(const_cast<FlagImpl*>(this)->init_control_, &FlagImpl::Init,
                   const_cast<FlagImpl*>(this));
 
-  // data_guard_ is initialized.
+  // data_guard_ is initialized inside Init.
   return reinterpret_cast<absl::Mutex*>(&data_guard_);
 }
 
-void FlagImpl::AssertValidType(FlagStaticTypeId type_id) const {
-  FlagStaticTypeId this_type_id = flags_internal::StaticTypeId(op_);
+void FlagImpl::AssertValidType(FlagFastTypeId rhs_type_id,
+                               const std::type_info* (*gen_rtti)()) const {
+  FlagFastTypeId lhs_type_id = flags_internal::FastTypeId(op_);
 
-  // `type_id` is the type id corresponding to the declaration visibile at the
-  // call site. `this_type_id` is the type id corresponding to the type stored
-  // during flag definition. They must match for this operation to be
-  // well-defined.
-  if (ABSL_PREDICT_TRUE(type_id == this_type_id)) return;
+  // `rhs_type_id` is the fast type id corresponding to the declaration
+  // visibile at the call site. `lhs_type_id` is the fast type id
+  // corresponding to the type specified in flag definition. They must match
+  //  for this operation to be well-defined.
+  if (ABSL_PREDICT_TRUE(lhs_type_id == rhs_type_id)) return;
 
-  void* lhs_runtime_type_id = type_id();
-  void* rhs_runtime_type_id = this_type_id();
+  const std::type_info* lhs_runtime_type_id =
+      flags_internal::RuntimeTypeId(op_);
+  const std::type_info* rhs_runtime_type_id = (*gen_rtti)();
 
   if (lhs_runtime_type_id == rhs_runtime_type_id) return;
 
 #if defined(ABSL_FLAGS_INTERNAL_HAS_RTTI)
-  if (*reinterpret_cast<std::type_info*>(lhs_runtime_type_id) ==
-      *reinterpret_cast<std::type_info*>(rhs_runtime_type_id))
-    return;
+  if (*lhs_runtime_type_id == *rhs_runtime_type_id) return;
 #endif
 
   ABSL_INTERNAL_LOG(
@@ -120,19 +209,40 @@
 
 std::unique_ptr<void, DynValueDeleter> FlagImpl::MakeInitValue() const {
   void* res = nullptr;
-  if (DefaultKind() == FlagDefaultKind::kDynamicValue) {
-    res = flags_internal::Clone(op_, default_value_.dynamic_value);
-  } else {
-    res = (*default_value_.gen_func)();
+  switch (DefaultKind()) {
+    case FlagDefaultKind::kDynamicValue:
+      res = flags_internal::Clone(op_, default_value_.dynamic_value);
+      break;
+    case FlagDefaultKind::kGenFunc:
+      res = flags_internal::Alloc(op_);
+      (*default_value_.gen_func)(res);
+      break;
+    default:
+      res = flags_internal::Clone(op_, &default_value_);
+      break;
   }
   return {res, DynValueDeleter{op_}};
 }
 
 void FlagImpl::StoreValue(const void* src) {
-  flags_internal::Copy(op_, src, value_.dynamic);
-  StoreAtomic();
+  switch (ValueStorageKind()) {
+    case FlagValueStorageKind::kAlignedBuffer:
+      Copy(op_, src, AlignedBufferValue());
+      seq_lock_.IncrementModificationCount();
+      break;
+    case FlagValueStorageKind::kOneWordAtomic: {
+      int64_t one_word_val = 0;
+      std::memcpy(&one_word_val, src, Sizeof(op_));
+      OneWordValue().store(one_word_val, std::memory_order_release);
+      seq_lock_.IncrementModificationCount();
+      break;
+    }
+    case FlagValueStorageKind::kSequenceLocked: {
+      seq_lock_.Write(AtomicBufferValue(), src, Sizeof(op_));
+      break;
+    }
+  }
   modified_ = true;
-  ++counter_;
   InvokeCallback();
 }
 
@@ -147,9 +257,12 @@
                                                     : help_.gen_func();
 }
 
-bool FlagImpl::IsModified() const {
-  absl::MutexLock l(DataGuard());
-  return modified_;
+FlagFastTypeId FlagImpl::TypeId() const {
+  return flags_internal::FastTypeId(op_);
+}
+
+int64_t FlagImpl::ModificationCount() const {
+  return seq_lock_.ModificationCount();
 }
 
 bool FlagImpl::IsSpecifiedOnCommandLine() const {
@@ -165,9 +278,27 @@
 }
 
 std::string FlagImpl::CurrentValue() const {
-  absl::MutexLock l(DataGuard());
+  auto* guard = DataGuard();  // Make sure flag initialized
+  switch (ValueStorageKind()) {
+    case FlagValueStorageKind::kAlignedBuffer: {
+      absl::MutexLock l(guard);
+      return flags_internal::Unparse(op_, AlignedBufferValue());
+    }
+    case FlagValueStorageKind::kOneWordAtomic: {
+      const auto one_word_val =
+          absl::bit_cast<std::array<char, sizeof(int64_t)>>(
+              OneWordValue().load(std::memory_order_acquire));
+      return flags_internal::Unparse(op_, one_word_val.data());
+    }
+    case FlagValueStorageKind::kSequenceLocked: {
+      std::unique_ptr<void, DynValueDeleter> cloned(flags_internal::Alloc(op_),
+                                                    DynValueDeleter{op_});
+      ReadSequenceLockedData(cloned.get());
+      return flags_internal::Unparse(op_, cloned.get());
+    }
+  }
 
-  return flags_internal::Unparse(op_, value_.dynamic);
+  return "";
 }
 
 void FlagImpl::SetCallback(const FlagCallbackFunc mutation_callback) {
@@ -199,44 +330,100 @@
   // 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());
+  MutexRelock relock(*DataGuard());
   absl::MutexLock lock(&callback_->guard);
   cb();
 }
 
-bool FlagImpl::RestoreState(const void* value, bool modified,
-                            bool on_command_line, int64_t counter) {
-  {
-    absl::MutexLock l(DataGuard());
+std::unique_ptr<FlagStateInterface> FlagImpl::SaveState() {
+  absl::MutexLock l(DataGuard());
 
-    if (counter_ == counter) return false;
+  bool modified = modified_;
+  bool on_command_line = on_command_line_;
+  switch (ValueStorageKind()) {
+    case FlagValueStorageKind::kAlignedBuffer: {
+      return absl::make_unique<FlagState>(
+          *this, flags_internal::Clone(op_, AlignedBufferValue()), modified,
+          on_command_line, ModificationCount());
+    }
+    case FlagValueStorageKind::kOneWordAtomic: {
+      return absl::make_unique<FlagState>(
+          *this, OneWordValue().load(std::memory_order_acquire), modified,
+          on_command_line, ModificationCount());
+    }
+    case FlagValueStorageKind::kSequenceLocked: {
+      void* cloned = flags_internal::Alloc(op_);
+      // Read is guaranteed to be successful because we hold the lock.
+      bool success =
+          seq_lock_.TryRead(cloned, AtomicBufferValue(), Sizeof(op_));
+      assert(success);
+      static_cast<void>(success);
+      return absl::make_unique<FlagState>(*this, cloned, modified,
+                                          on_command_line, ModificationCount());
+    }
+  }
+  return nullptr;
+}
+
+bool FlagImpl::RestoreState(const FlagState& flag_state) {
+  absl::MutexLock l(DataGuard());
+  if (flag_state.counter_ == ModificationCount()) {
+    return false;
   }
 
-  Write(value);
-
-  {
-    absl::MutexLock l(DataGuard());
-
-    modified_ = modified;
-    on_command_line_ = on_command_line;
+  switch (ValueStorageKind()) {
+    case FlagValueStorageKind::kAlignedBuffer:
+    case FlagValueStorageKind::kSequenceLocked:
+      StoreValue(flag_state.value_.heap_allocated);
+      break;
+    case FlagValueStorageKind::kOneWordAtomic:
+      StoreValue(&flag_state.value_.one_word);
+      break;
   }
 
+  modified_ = flag_state.modified_;
+  on_command_line_ = flag_state.on_command_line_;
+
   return true;
 }
 
+template <typename StorageT>
+StorageT* FlagImpl::OffsetValue() const {
+  char* p = reinterpret_cast<char*>(const_cast<FlagImpl*>(this));
+  // The offset is deduced via Flag value type specific op_.
+  size_t offset = flags_internal::ValueOffset(op_);
+
+  return reinterpret_cast<StorageT*>(p + offset);
+}
+
+void* FlagImpl::AlignedBufferValue() const {
+  assert(ValueStorageKind() == FlagValueStorageKind::kAlignedBuffer);
+  return OffsetValue<void>();
+}
+
+std::atomic<uint64_t>* FlagImpl::AtomicBufferValue() const {
+  assert(ValueStorageKind() == FlagValueStorageKind::kSequenceLocked);
+  return OffsetValue<std::atomic<uint64_t>>();
+}
+
+std::atomic<int64_t>& FlagImpl::OneWordValue() const {
+  assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic);
+  return OffsetValue<FlagOneWordValue>()->value;
+}
+
 // Attempts to parse supplied `value` string using parsing routine in the `flag`
 // argument. If parsing successful, this function replaces the dst with newly
 // parsed value. In case if any error is encountered in either step, the error
 // message is stored in 'err'
 std::unique_ptr<void, DynValueDeleter> FlagImpl::TryParse(
-    absl::string_view value, std::string* err) const {
+    absl::string_view value, std::string& err) const {
   std::unique_ptr<void, DynValueDeleter> tentative_value = MakeInitValue();
 
   std::string parse_err;
   if (!flags_internal::Parse(op_, value, tentative_value.get(), &parse_err)) {
     absl::string_view err_sep = parse_err.empty() ? "" : "; ";
-    *err = absl::StrCat("Illegal value '", value, "' specified for flag '",
-                        Name(), "'", err_sep, parse_err);
+    err = absl::StrCat("Illegal value '", value, "' specified for flag '",
+                       Name(), "'", err_sep, parse_err);
     return nullptr;
   }
 
@@ -244,32 +431,44 @@
 }
 
 void FlagImpl::Read(void* dst) const {
-  absl::ReaderMutexLock l(DataGuard());
-
-  flags_internal::CopyConstruct(op_, value_.dynamic, dst);
+  auto* guard = DataGuard();  // Make sure flag initialized
+  switch (ValueStorageKind()) {
+    case FlagValueStorageKind::kAlignedBuffer: {
+      absl::MutexLock l(guard);
+      flags_internal::CopyConstruct(op_, AlignedBufferValue(), dst);
+      break;
+    }
+    case FlagValueStorageKind::kOneWordAtomic: {
+      const int64_t one_word_val =
+          OneWordValue().load(std::memory_order_acquire);
+      std::memcpy(dst, &one_word_val, Sizeof(op_));
+      break;
+    }
+    case FlagValueStorageKind::kSequenceLocked: {
+      ReadSequenceLockedData(dst);
+      break;
+    }
+  }
 }
 
-void FlagImpl::StoreAtomic() {
-  size_t data_size = flags_internal::Sizeof(op_);
-
-  if (data_size <= sizeof(int64_t)) {
-    int64_t t = 0;
-    std::memcpy(&t, value_.dynamic, data_size);
-    value_.atomics.small_atomic.store(t, std::memory_order_release);
+void FlagImpl::ReadSequenceLockedData(void* dst) const {
+  int size = Sizeof(op_);
+  // Attempt to read using the sequence lock.
+  if (ABSL_PREDICT_TRUE(seq_lock_.TryRead(dst, AtomicBufferValue(), size))) {
+    return;
   }
-#if defined(ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD)
-  else if (data_size <= sizeof(FlagsInternalTwoWordsType)) {
-    FlagsInternalTwoWordsType t{0, 0};
-    std::memcpy(&t, value_.dynamic, data_size);
-    value_.atomics.big_atomic.store(t, std::memory_order_release);
-  }
-#endif
+  // We failed due to contention. Acquire the lock to prevent contention
+  // and try again.
+  absl::ReaderMutexLock l(DataGuard());
+  bool success = seq_lock_.TryRead(dst, AtomicBufferValue(), size);
+  assert(success);
+  static_cast<void>(success);
 }
 
 void FlagImpl::Write(const void* src) {
   absl::MutexLock l(DataGuard());
 
-  if (ShouldValidateFlagValue(flags_internal::StaticTypeId(op_))) {
+  if (ShouldValidateFlagValue(flags_internal::FastTypeId(op_))) {
     std::unique_ptr<void, DynValueDeleter> obj{flags_internal::Clone(op_, src),
                                                DynValueDeleter{op_}};
     std::string ignored_error;
@@ -291,8 +490,8 @@
 //  * Update the flag's default value
 //  * Update the current flag value if it was never set before
 // The mode is selected based on 'set_mode' parameter.
-bool FlagImpl::SetFromString(absl::string_view value, FlagSettingMode set_mode,
-                             ValueSource source, std::string* err) {
+bool FlagImpl::ParseFrom(absl::string_view value, FlagSettingMode set_mode,
+                         ValueSource source, std::string& err) {
   absl::MutexLock l(DataGuard());
 
   switch (set_mode) {
@@ -339,7 +538,7 @@
       }
 
       if (!modified_) {
-        // Need to set both default value *and* current, in this case
+        // Need to set both default value *and* current, in this case.
         StoreValue(default_value_.dynamic_value);
         modified_ = false;
       }
@@ -361,7 +560,7 @@
     ABSL_INTERNAL_LOG(
         FATAL,
         absl::StrCat("Flag ", Name(), " (from ", Filename(),
-                     "): std::string form of default value '", v,
+                     "): string form of default value '", v,
                      "' could not be parsed; error=", error));
   }
 
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index 35a148c..e6bade0 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -16,94 +16,94 @@
 #ifndef ABSL_FLAGS_INTERNAL_FLAG_H_
 #define ABSL_FLAGS_INTERNAL_FLAG_H_
 
+#include <stddef.h>
 #include <stdint.h>
 
 #include <atomic>
 #include <cstring>
 #include <memory>
+#include <new>
 #include <string>
 #include <type_traits>
+#include <typeinfo>
 
+#include "absl/base/attributes.h"
 #include "absl/base/call_once.h"
 #include "absl/base/config.h"
+#include "absl/base/optimization.h"
 #include "absl/base/thread_annotations.h"
+#include "absl/flags/commandlineflag.h"
 #include "absl/flags/config.h"
 #include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/registry.h"
-#include "absl/memory/memory.h"
-#include "absl/strings/str_cat.h"
+#include "absl/flags/internal/sequence_lock.h"
+#include "absl/flags/marshalling.h"
+#include "absl/meta/type_traits.h"
 #include "absl/strings/string_view.h"
 #include "absl/synchronization/mutex.h"
+#include "absl/utility/utility.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
-namespace flags_internal {
 
+///////////////////////////////////////////////////////////////////////////////
+// Forward declaration of absl::Flag<T> public API.
+namespace flags_internal {
 template <typename T>
 class Flag;
+}  // namespace flags_internal
+
+#if defined(_MSC_VER) && !defined(__clang__)
+template <typename T>
+class Flag;
+#else
+template <typename T>
+using Flag = flags_internal::Flag<T>;
+#endif
+
+template <typename T>
+ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag);
+
+template <typename T>
+void SetFlag(absl::Flag<T>* flag, const T& v);
+
+template <typename T, typename V>
+void SetFlag(absl::Flag<T>* flag, const V& v);
+
+template <typename U>
+const CommandLineFlag& GetFlagReflectionHandle(const absl::Flag<U>& f);
 
 ///////////////////////////////////////////////////////////////////////////////
 // Flag value type operations, eg., parsing, copying, etc. are provided
 // by function specific to that type with a signature matching FlagOpFn.
 
+namespace flags_internal {
+
 enum class FlagOp {
+  kAlloc,
   kDelete,
-  kClone,
   kCopy,
   kCopyConstruct,
   kSizeof,
-  kStaticTypeId,
+  kFastTypeId,
+  kRuntimeTypeId,
   kParse,
   kUnparse,
+  kValueOffset,
 };
 using FlagOpFn = void* (*)(FlagOp, const void*, void*, void*);
 
-// Flag value specific operations routine.
+// Forward declaration for Flag value specific operations.
 template <typename T>
-void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3) {
-  switch (op) {
-    case FlagOp::kDelete:
-      delete static_cast<const T*>(v1);
-      return nullptr;
-    case FlagOp::kClone:
-      return new T(*static_cast<const T*>(v1));
-    case FlagOp::kCopy:
-      *static_cast<T*>(v2) = *static_cast<const T*>(v1);
-      return nullptr;
-    case FlagOp::kCopyConstruct:
-      new (v2) T(*static_cast<const T*>(v1));
-      return nullptr;
-    case FlagOp::kSizeof:
-      return reinterpret_cast<void*>(sizeof(T));
-    case FlagOp::kStaticTypeId:
-      return reinterpret_cast<void*>(&FlagStaticTypeIdGen<T>);
-    case FlagOp::kParse: {
-      // Initialize the temporary instance of type T based on current value in
-      // destination (which is going to be flag's default value).
-      T temp(*static_cast<T*>(v2));
-      if (!absl::ParseFlag<T>(*static_cast<const absl::string_view*>(v1), &temp,
-                              static_cast<std::string*>(v3))) {
-        return nullptr;
-      }
-      *static_cast<T*>(v2) = std::move(temp);
-      return v2;
-    }
-    case FlagOp::kUnparse:
-      *static_cast<std::string*>(v2) =
-          absl::UnparseFlag<T>(*static_cast<const T*>(v1));
-      return nullptr;
-    default:
-      return nullptr;
-  }
-}
+void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3);
 
-// Deletes memory interpreting obj as flag value type pointer.
-inline void Delete(FlagOpFn op, const void* obj) {
-  op(FlagOp::kDelete, obj, nullptr, nullptr);
+// Allocate aligned memory for a flag value.
+inline void* Alloc(FlagOpFn op) {
+  return op(FlagOp::kAlloc, nullptr, nullptr, nullptr);
 }
-// Makes a copy of flag value pointed by obj.
-inline void* Clone(FlagOpFn op, const void* obj) {
-  return op(FlagOp::kClone, obj, nullptr, nullptr);
+// Deletes memory interpreting obj as flag value type pointer.
+inline void Delete(FlagOpFn op, void* obj) {
+  op(FlagOp::kDelete, nullptr, obj, nullptr);
 }
 // Copies src to dst interpreting as flag value type pointers.
 inline void Copy(FlagOpFn op, const void* src, void* dst) {
@@ -114,6 +114,12 @@
 inline void CopyConstruct(FlagOpFn op, const void* src, void* dst) {
   op(FlagOp::kCopyConstruct, src, dst, nullptr);
 }
+// Makes a copy of flag value pointed by obj.
+inline void* Clone(FlagOpFn op, const void* obj) {
+  void* res = flags_internal::Alloc(op);
+  flags_internal::CopyConstruct(op, obj, res);
+  return res;
+}
 // Returns true if parsing of input text is successfull.
 inline bool Parse(FlagOpFn op, absl::string_view text, void* dst,
                   std::string* error) {
@@ -132,41 +138,36 @@
   return static_cast<size_t>(reinterpret_cast<intptr_t>(
       op(FlagOp::kSizeof, nullptr, nullptr, nullptr)));
 }
-// Returns static type id coresponding to the value type.
-inline FlagStaticTypeId StaticTypeId(FlagOpFn op) {
-  return reinterpret_cast<FlagStaticTypeId>(
-      op(FlagOp::kStaticTypeId, nullptr, nullptr, nullptr));
+// Returns fast type id coresponding to the value type.
+inline FlagFastTypeId FastTypeId(FlagOpFn op) {
+  return reinterpret_cast<FlagFastTypeId>(
+      op(FlagOp::kFastTypeId, nullptr, nullptr, nullptr));
+}
+// Returns fast type id coresponding to the value type.
+inline const std::type_info* RuntimeTypeId(FlagOpFn op) {
+  return reinterpret_cast<const std::type_info*>(
+      op(FlagOp::kRuntimeTypeId, nullptr, nullptr, nullptr));
+}
+// Returns offset of the field value_ from the field impl_ inside of
+// absl::Flag<T> data. Given FlagImpl pointer p you can get the
+// location of the corresponding value as:
+//      reinterpret_cast<char*>(p) + ValueOffset().
+inline ptrdiff_t ValueOffset(FlagOpFn op) {
+  // This sequence of casts reverses the sequence from
+  // `flags_internal::FlagOps()`
+  return static_cast<ptrdiff_t>(reinterpret_cast<intptr_t>(
+      op(FlagOp::kValueOffset, nullptr, nullptr, nullptr)));
 }
 
-///////////////////////////////////////////////////////////////////////////////
-// Persistent state of the flag data.
-
+// Returns an address of RTTI's typeid(T).
 template <typename T>
-class FlagState : public flags_internal::FlagStateInterface {
- public:
-  FlagState(Flag<T>* flag, T&& cur, bool modified, bool on_command_line,
-            int64_t counter)
-      : flag_(flag),
-        cur_value_(std::move(cur)),
-        modified_(modified),
-        on_command_line_(on_command_line),
-        counter_(counter) {}
-
-  ~FlagState() override = default;
-
- private:
-  friend class Flag<T>;
-
-  // Restores the flag to the saved state.
-  void Restore() const override;
-
-  // Flag and saved flag data.
-  Flag<T>* flag_;
-  T cur_value_;
-  bool modified_;
-  bool on_command_line_;
-  int64_t counter_;
-};
+inline const std::type_info* GenRuntimeTypeId() {
+#if defined(ABSL_FLAGS_INTERNAL_HAS_RTTI)
+  return &typeid(T);
+#else
+  return nullptr;
+#endif
+}
 
 ///////////////////////////////////////////////////////////////////////////////
 // Flag help auxiliary structs.
@@ -176,6 +177,28 @@
 // cases.
 using HelpGenFunc = std::string (*)();
 
+template <size_t N>
+struct FixedCharArray {
+  char value[N];
+
+  template <size_t... I>
+  static constexpr FixedCharArray<N> FromLiteralString(
+      absl::string_view str, absl::index_sequence<I...>) {
+    return (void)str, FixedCharArray<N>({{str[I]..., '\0'}});
+  }
+};
+
+template <typename Gen, size_t N = Gen::Value().size()>
+constexpr FixedCharArray<N + 1> HelpStringAsArray(int) {
+  return FixedCharArray<N + 1>::FromLiteralString(
+      Gen::Value(), absl::make_index_sequence<N>{});
+}
+
+template <typename Gen>
+constexpr std::false_type HelpStringAsArray(char) {
+  return std::false_type{};
+}
+
 union FlagHelpMsg {
   constexpr explicit FlagHelpMsg(const char* help_msg) : literal(help_msg) {}
   constexpr explicit FlagHelpMsg(HelpGenFunc help_gen) : gen_func(help_gen) {}
@@ -193,40 +216,28 @@
 
 extern const char kStrippedFlagHelp[];
 
-// HelpConstexprWrap is used by struct AbslFlagHelpGenFor##name generated by
-// ABSL_FLAG macro. It is only used to silence the compiler in the case where
-// help message expression is not constexpr and does not have type const char*.
-// If help message expression is indeed constexpr const char* HelpConstexprWrap
-// is just a trivial identity function.
-template <typename T>
-const char* HelpConstexprWrap(const T&) {
-  return nullptr;
-}
-constexpr const char* HelpConstexprWrap(const char* p) { return p; }
-constexpr const char* HelpConstexprWrap(char* p) { return p; }
-
 // These two HelpArg overloads allows us to select at compile time one of two
 // way to pass Help argument to absl::Flag. We'll be passing
-// AbslFlagHelpGenFor##name as T and integer 0 as a single argument to prefer
-// first overload if possible. If T::Const is evaluatable on constexpr
-// context (see non template int parameter below) we'll choose first overload.
-// In this case the help message expression is immediately evaluated and is used
-// to construct the absl::Flag. No additionl code is generated by ABSL_FLAG.
-// Otherwise SFINAE kicks in and first overload is dropped from the
+// AbslFlagHelpGenFor##name as Gen and integer 0 as a single argument to prefer
+// first overload if possible. If help message is evaluatable on constexpr
+// context We'll be able to make FixedCharArray out of it and we'll choose first
+// overload. In this case the help message expression is immediately evaluated
+// and is used to construct the absl::Flag. No additionl code is generated by
+// ABSL_FLAG Otherwise SFINAE kicks in and first overload is dropped from the
 // consideration, in which case the second overload will be used. The second
 // overload does not attempt to evaluate the help message expression
 // immediately and instead delays the evaluation by returing the function
 // pointer (&T::NonConst) genering the help message when necessary. This is
 // evaluatable in constexpr context, but the cost is an extra function being
 // generated in the ABSL_FLAG code.
-template <typename T, int = (T::Const(), 1)>
-constexpr FlagHelpArg HelpArg(int) {
-  return {FlagHelpMsg(T::Const()), FlagHelpKind::kLiteral};
+template <typename Gen, size_t N>
+constexpr FlagHelpArg HelpArg(const FixedCharArray<N>& value) {
+  return {FlagHelpMsg(value.value), FlagHelpKind::kLiteral};
 }
 
-template <typename T>
-constexpr FlagHelpArg HelpArg(char) {
-  return {FlagHelpMsg(&T::NonConst), FlagHelpKind::kGenFunc};
+template <typename Gen>
+constexpr FlagHelpArg HelpArg(std::false_type) {
+  return {FlagHelpMsg(&Gen::NonConst), FlagHelpKind::kGenFunc};
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -234,110 +245,129 @@
 
 // Signature for the function generating the initial flag value (usually
 // based on default value supplied in flag's definition)
-using FlagDfltGenFunc = void* (*)();
+using FlagDfltGenFunc = void (*)(void*);
 
 union FlagDefaultSrc {
   constexpr explicit FlagDefaultSrc(FlagDfltGenFunc gen_func_arg)
       : gen_func(gen_func_arg) {}
 
+#define ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE(T, name) \
+  T name##_value;                                  \
+  constexpr explicit FlagDefaultSrc(T value) : name##_value(value) {}  // NOLINT
+  ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE)
+#undef ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE
+
   void* dynamic_value;
   FlagDfltGenFunc gen_func;
 };
 
-enum class FlagDefaultKind : uint8_t { kDynamicValue = 0, kGenFunc = 1 };
+enum class FlagDefaultKind : uint8_t {
+  kDynamicValue = 0,
+  kGenFunc = 1,
+  kOneWord = 2  // for default values UP to one word in size
+};
+
+struct FlagDefaultArg {
+  FlagDefaultSrc source;
+  FlagDefaultKind kind;
+};
+
+// This struct and corresponding overload to InitDefaultValue are used to
+// facilitate usage of {} as default value in ABSL_FLAG macro.
+// TODO(rogeeff): Fix handling types with explicit constructors.
+struct EmptyBraces {};
+
+template <typename T>
+constexpr T InitDefaultValue(T t) {
+  return t;
+}
+
+template <typename T>
+constexpr T InitDefaultValue(EmptyBraces) {
+  return T{};
+}
+
+template <typename ValueT, typename GenT,
+          typename std::enable_if<std::is_integral<ValueT>::value, int>::type =
+              (GenT{}, 0)>
+constexpr FlagDefaultArg DefaultArg(int) {
+  return {FlagDefaultSrc(GenT{}.value), FlagDefaultKind::kOneWord};
+}
+
+template <typename ValueT, typename GenT>
+constexpr FlagDefaultArg DefaultArg(char) {
+  return {FlagDefaultSrc(&GenT::Gen), FlagDefaultKind::kGenFunc};
+}
 
 ///////////////////////////////////////////////////////////////////////////////
 // Flag current value auxiliary structs.
 
-// The minimum atomic size we believe to generate lock free code, i.e. all
-// trivially copyable types not bigger this size generate lock free code.
-static constexpr int kMinLockFreeAtomicSize = 8;
+constexpr int64_t UninitializedFlagValue() { return 0xababababababababll; }
 
-// The same as kMinLockFreeAtomicSize but maximum atomic size. As double words
-// might use two registers, we want to dispatch the logic for them.
-#if defined(ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD)
-static constexpr int kMaxLockFreeAtomicSize = 16;
-#else
-static constexpr int kMaxLockFreeAtomicSize = 8;
-#endif
-
-// We can use atomic in cases when it fits in the register, trivially copyable
-// in order to make memcpy operations.
 template <typename T>
-struct IsAtomicFlagTypeTrait {
-  static constexpr bool value =
-      (sizeof(T) <= kMaxLockFreeAtomicSize &&
-       type_traits_internal::is_trivially_copyable<T>::value);
-};
+using FlagUseOneWordStorage = std::integral_constant<
+    bool, absl::type_traits_internal::is_trivially_copyable<T>::value &&
+              (sizeof(T) <= 8)>;
 
-// Clang does not always produce cmpxchg16b instruction when alignment of a 16
-// bytes type is not 16.
-struct alignas(16) FlagsInternalTwoWordsType {
-  int64_t first;
-  int64_t second;
-};
+template <class T>
+using FlagShouldUseSequenceLock = std::integral_constant<
+    bool, absl::type_traits_internal::is_trivially_copyable<T>::value &&
+              (sizeof(T) > 8)>;
 
-constexpr bool operator==(const FlagsInternalTwoWordsType& that,
-                          const FlagsInternalTwoWordsType& other) {
-  return that.first == other.first && that.second == other.second;
-}
-constexpr bool operator!=(const FlagsInternalTwoWordsType& that,
-                          const FlagsInternalTwoWordsType& other) {
-  return !(that == other);
-}
-
-constexpr int64_t SmallAtomicInit() { return 0xababababababababll; }
-
-template <typename T, typename S = void>
-struct BestAtomicType {
-  using type = int64_t;
-  static constexpr int64_t AtomicInit() { return SmallAtomicInit(); }
+enum class FlagValueStorageKind : uint8_t {
+  kAlignedBuffer = 0,
+  kOneWordAtomic = 1,
+  kSequenceLocked = 2,
 };
 
 template <typename T>
-struct BestAtomicType<
-    T, typename std::enable_if<(kMinLockFreeAtomicSize < sizeof(T) &&
-                                sizeof(T) <= kMaxLockFreeAtomicSize),
-                               void>::type> {
-  using type = FlagsInternalTwoWordsType;
-  static constexpr FlagsInternalTwoWordsType AtomicInit() {
-    return {SmallAtomicInit(), SmallAtomicInit()};
+static constexpr FlagValueStorageKind StorageKind() {
+  return FlagUseOneWordStorage<T>::value ? FlagValueStorageKind::kOneWordAtomic
+         : FlagShouldUseSequenceLock<T>::value
+             ? FlagValueStorageKind::kSequenceLocked
+             : FlagValueStorageKind::kAlignedBuffer;
+}
+
+struct FlagOneWordValue {
+  constexpr FlagOneWordValue() : value(UninitializedFlagValue()) {}
+
+  std::atomic<int64_t> value;
+};
+
+template <typename T,
+          FlagValueStorageKind Kind = flags_internal::StorageKind<T>()>
+struct FlagValue;
+
+template <typename T>
+struct FlagValue<T, FlagValueStorageKind::kAlignedBuffer> {
+  bool Get(const SequenceLock&, T&) const { return false; }
+
+  alignas(T) char value[sizeof(T)];
+};
+
+template <typename T>
+struct FlagValue<T, FlagValueStorageKind::kOneWordAtomic> : FlagOneWordValue {
+  bool Get(const SequenceLock&, T& dst) const {
+    int64_t one_word_val = value.load(std::memory_order_acquire);
+    if (ABSL_PREDICT_FALSE(one_word_val == UninitializedFlagValue())) {
+      return false;
+    }
+    std::memcpy(&dst, static_cast<const void*>(&one_word_val), sizeof(T));
+    return true;
   }
 };
 
-struct FlagValue {
-  // Heap allocated value.
-  void* dynamic = nullptr;
-  // For some types, a copy of the current value is kept in an atomically
-  // accessible field.
-  union Atomics {
-    // Using small atomic for small types.
-    std::atomic<int64_t> small_atomic;
-    template <typename T,
-              typename K = typename std::enable_if<
-                  (sizeof(T) <= kMinLockFreeAtomicSize), void>::type>
-    int64_t load() const {
-      return small_atomic.load(std::memory_order_acquire);
-    }
+template <typename T>
+struct FlagValue<T, FlagValueStorageKind::kSequenceLocked> {
+  bool Get(const SequenceLock& lock, T& dst) const {
+    return lock.TryRead(&dst, value_words, sizeof(T));
+  }
 
-#if defined(ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD)
-    // Using big atomics for big types.
-    std::atomic<FlagsInternalTwoWordsType> big_atomic;
-    template <typename T, typename K = typename std::enable_if<
-                              (kMinLockFreeAtomicSize < sizeof(T) &&
-                               sizeof(T) <= kMaxLockFreeAtomicSize),
-                              void>::type>
-    FlagsInternalTwoWordsType load() const {
-      return big_atomic.load(std::memory_order_acquire);
-    }
-    constexpr Atomics()
-        : big_atomic{FlagsInternalTwoWordsType{SmallAtomicInit(),
-                                               SmallAtomicInit()}} {}
-#else
-    constexpr Atomics() : small_atomic{SmallAtomicInit()} {}
-#endif
-  };
-  Atomics atomics{};
+  static constexpr int kNumWords =
+      flags_internal::AlignUp(sizeof(T), sizeof(uint64_t)) / sizeof(uint64_t);
+
+  alignas(T) alignas(
+      std::atomic<uint64_t>) std::atomic<uint64_t> value_words[kNumWords];
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -358,134 +388,141 @@
 // The class encapsulates the Flag's data and access to it.
 
 struct DynValueDeleter {
-  explicit DynValueDeleter(FlagOpFn op_arg = nullptr) : op(op_arg) {}
-  void operator()(void* ptr) const {
-    if (op != nullptr) Delete(op, ptr);
-  }
+  explicit DynValueDeleter(FlagOpFn op_arg = nullptr);
+  void operator()(void* ptr) const;
 
   FlagOpFn op;
 };
 
-class FlagImpl {
+class FlagState;
+
+class FlagImpl final : public CommandLineFlag {
  public:
   constexpr FlagImpl(const char* name, const char* filename, FlagOpFn op,
-                     FlagHelpArg help, FlagDfltGenFunc default_value_gen)
+                     FlagHelpArg help, FlagValueStorageKind value_kind,
+                     FlagDefaultArg default_arg)
       : name_(name),
         filename_(filename),
         op_(op),
         help_(help.source),
         help_source_kind_(static_cast<uint8_t>(help.kind)),
-        def_kind_(static_cast<uint8_t>(FlagDefaultKind::kGenFunc)),
+        value_storage_kind_(static_cast<uint8_t>(value_kind)),
+        def_kind_(static_cast<uint8_t>(default_arg.kind)),
         modified_(false),
         on_command_line_(false),
-        counter_(0),
         callback_(nullptr),
-        default_value_(default_value_gen),
+        default_value_(default_arg.source),
         data_guard_{} {}
 
   // Constant access methods
-  absl::string_view Name() const;
-  std::string Filename() const;
-  std::string Help() const;
-  bool IsModified() const ABSL_LOCKS_EXCLUDED(*DataGuard());
-  bool IsSpecifiedOnCommandLine() const ABSL_LOCKS_EXCLUDED(*DataGuard());
-  std::string DefaultValue() const ABSL_LOCKS_EXCLUDED(*DataGuard());
-  std::string CurrentValue() const ABSL_LOCKS_EXCLUDED(*DataGuard());
-  void Read(void* dst) const ABSL_LOCKS_EXCLUDED(*DataGuard());
-
-  template <typename T, typename std::enable_if<
-                            !IsAtomicFlagTypeTrait<T>::value, int>::type = 0>
-  void Get(T* dst) const {
-    AssertValidType(&flags_internal::FlagStaticTypeIdGen<T>);
-    Read(dst);
-  }
-  // Overload for `GetFlag()` for types that support lock-free reads.
-  template <typename T, typename std::enable_if<IsAtomicFlagTypeTrait<T>::value,
-                                                int>::type = 0>
-  void Get(T* dst) const {
-    // For flags of types which can be accessed "atomically" we want to avoid
-    // slowing down flag value access due to type validation. That's why
-    // this validation is hidden behind !NDEBUG
-#ifndef NDEBUG
-    AssertValidType(&flags_internal::FlagStaticTypeIdGen<T>);
-#endif
-    using U = flags_internal::BestAtomicType<T>;
-    typename U::type r = value_.atomics.template load<T>();
-    if (r != U::AtomicInit()) {
-      std::memcpy(static_cast<void*>(dst), &r, sizeof(T));
-    } else {
-      Read(dst);
-    }
-  }
-  template <typename T>
-  void Set(const T& src) {
-    AssertValidType(&flags_internal::FlagStaticTypeIdGen<T>);
-    Write(&src);
-  }
+  void Read(void* dst) const override ABSL_LOCKS_EXCLUDED(*DataGuard());
 
   // Mutating access methods
   void Write(const void* src) ABSL_LOCKS_EXCLUDED(*DataGuard());
-  bool SetFromString(absl::string_view value, FlagSettingMode set_mode,
-                     ValueSource source, std::string* err)
-      ABSL_LOCKS_EXCLUDED(*DataGuard());
-  // If possible, updates copy of the Flag's value that is stored in an
-  // atomic word.
-  void StoreAtomic() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
 
   // Interfaces to operate on callbacks.
   void SetCallback(const FlagCallbackFunc mutation_callback)
       ABSL_LOCKS_EXCLUDED(*DataGuard());
   void InvokeCallback() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
 
-  // Interfaces to save/restore mutable flag data
-  template <typename T>
-  std::unique_ptr<FlagStateInterface> SaveState(Flag<T>* flag) const
-      ABSL_LOCKS_EXCLUDED(*DataGuard()) {
-    T&& cur_value = flag->Get();
-    absl::MutexLock l(DataGuard());
-
-    return absl::make_unique<FlagState<T>>(
-        flag, std::move(cur_value), modified_, on_command_line_, counter_);
-  }
-  bool RestoreState(const void* value, bool modified, bool on_command_line,
-                    int64_t counter) ABSL_LOCKS_EXCLUDED(*DataGuard());
-
-  // Value validation interfaces.
-  void CheckDefaultValueParsingRoundtrip() const
-      ABSL_LOCKS_EXCLUDED(*DataGuard());
-  bool ValidateInputValue(absl::string_view value) const
-      ABSL_LOCKS_EXCLUDED(*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
+  // absl::GetFlag(FLAGS_foo) validates that the type of FLAGS_foo is indeed
+  // int. To do that we pass the "assumed" type id (which is deduced from type
+  // int) as an argument `type_id`, which is in turn is validated against the
+  // type id stored in flag object by flag definition statement.
+  void AssertValidType(FlagFastTypeId type_id,
+                       const std::type_info* (*gen_rtti)()) const;
 
  private:
+  template <typename T>
+  friend class Flag;
+  friend class FlagState;
+
   // Ensures that `data_guard_` is initialized and returns it.
-  absl::Mutex* DataGuard() const ABSL_LOCK_RETURNED((absl::Mutex*)&data_guard_);
+  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());
   // Flag initialization called via absl::call_once.
   void Init();
-  // Attempts to parse supplied `value` std::string. If parsing is successful,
+
+  // Offset value access methods. One per storage kind. These methods to not
+  // respect const correctness, so be very carefull using them.
+
+  // This is a shared helper routine which encapsulates most of the magic. Since
+  // it is only used inside the three routines below, which are defined in
+  // flag.cc, we can define it in that file as well.
+  template <typename StorageT>
+  StorageT* OffsetValue() const;
+  // This is an accessor for a value stored in an aligned buffer storage
+  // used for non-trivially-copyable data types.
+  // Returns a mutable pointer to the start of a buffer.
+  void* AlignedBufferValue() const;
+
+  // The same as above, but used for sequencelock-protected storage.
+  std::atomic<uint64_t>* AtomicBufferValue() const;
+
+  // This is an accessor for a value stored as one word atomic. Returns a
+  // mutable reference to an atomic value.
+  std::atomic<int64_t>& OneWordValue() const;
+
+  // Attempts to parse supplied `value` string. If parsing is successful,
   // returns new value. Otherwise returns nullptr.
   std::unique_ptr<void, DynValueDeleter> TryParse(absl::string_view value,
-                                                  std::string* err) const
+                                                  std::string& err) const
       ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
   // Stores the flag value based on the pointer to the source.
   void StoreValue(const void* src) 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());
+
   FlagHelpKind HelpSourceKind() const {
     return static_cast<FlagHelpKind>(help_source_kind_);
   }
+  FlagValueStorageKind ValueStorageKind() const {
+    return static_cast<FlagValueStorageKind>(value_storage_kind_);
+  }
   FlagDefaultKind DefaultKind() const
       ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()) {
     return static_cast<FlagDefaultKind>(def_kind_);
   }
-  // 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
-  // absl::GetFlag(FLAGS_foo) validates that the type of FLAGS_foo is indeed
-  // int. To do that we pass the "assumed" type id (which is deduced from type
-  // int) as an argument `op`, which is in turn is validated against the type id
-  // stored in flag object by flag definition statement.
-  void AssertValidType(FlagStaticTypeId type_id) const;
+
+  // CommandLineFlag interface implementation
+  absl::string_view Name() const override;
+  std::string Filename() const override;
+  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());
+  bool ValidateInputValue(absl::string_view value) const override
+      ABSL_LOCKS_EXCLUDED(*DataGuard());
+  void CheckDefaultValueParsingRoundtrip() const override
+      ABSL_LOCKS_EXCLUDED(*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());
+
+  // 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());
+
+  bool ParseFrom(absl::string_view value, FlagSettingMode set_mode,
+                 ValueSource source, std::string& error) override
+      ABSL_LOCKS_EXCLUDED(*DataGuard());
 
   // Immutable flag's state.
 
@@ -499,40 +536,35 @@
   const FlagHelpMsg help_;
   // Indicates if help message was supplied as literal or generator func.
   const uint8_t help_source_kind_ : 1;
+  // Kind of storage this flag is using for the flag's value.
+  const uint8_t value_storage_kind_ : 2;
 
-  // ------------------------------------------------------------------------
-  // The bytes containing the const bitfields must not be shared with bytes
-  // containing the mutable bitfields.
-  // ------------------------------------------------------------------------
-
-  // Unique tag for absl::call_once call to initialize this flag.
-  //
-  // The placement of this variable between the immutable and mutable bitfields
-  // is important as prevents them from occupying the same byte. If you remove
-  // this variable, make sure to maintain this property.
-  absl::once_flag init_control_;
+  uint8_t : 0;  // The bytes containing the const bitfields must not be
+                // shared with bytes containing the mutable bitfields.
 
   // Mutable flag's state (guarded by `data_guard_`).
 
-  // If def_kind_ == kDynamicValue, default_value_ holds a dynamically allocated
-  // value.
-  uint8_t def_kind_ : 1 ABSL_GUARDED_BY(*DataGuard());
+  // def_kind_ is not guard by DataGuard() since it is accessed in Init without
+  // locks.
+  uint8_t def_kind_ : 2;
   // Has this flag's value been modified?
   bool modified_ : 1 ABSL_GUARDED_BY(*DataGuard());
   // Has this flag been specified on command line.
   bool on_command_line_ : 1 ABSL_GUARDED_BY(*DataGuard());
 
-  // Mutation counter
-  int64_t counter_ ABSL_GUARDED_BY(*DataGuard());
+  // Unique tag for absl::call_once call to initialize this flag.
+  absl::once_flag init_control_;
+
+  // Sequence lock / mutation counter.
+  flags_internal::SequenceLock seq_lock_;
+
   // Optional flag's callback and absl::Mutex to guard the invocations.
   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
   // these two cases.
-  FlagDefaultSrc default_value_ ABSL_GUARDED_BY(*DataGuard());
-  // Current Flag Value
-  FlagValue value_;
+  FlagDefaultSrc default_value_;
 
   // This is reserved space for an absl::Mutex to guard flag data. It will be
   // initialized in FlagImpl::Init via placement new.
@@ -549,11 +581,29 @@
 // flag reflection handle interface.
 
 template <typename T>
-class Flag final : public flags_internal::CommandLineFlag {
+class Flag {
  public:
-  constexpr Flag(const char* name, const char* filename, const FlagHelpArg help,
-                 const FlagDfltGenFunc default_value_gen)
-      : impl_(name, filename, &FlagOps<T>, help, default_value_gen) {}
+  constexpr Flag(const char* name, const char* filename, FlagHelpArg help,
+                 const FlagDefaultArg default_arg)
+      : impl_(name, filename, &FlagOps<T>, help,
+              flags_internal::StorageKind<T>(), default_arg),
+        value_() {}
+
+  // CommandLineFlag interface
+  absl::string_view Name() const { return impl_.Name(); }
+  std::string Filename() const { return impl_.Filename(); }
+  std::string Help() const { return impl_.Help(); }
+  // Do not use. To be removed.
+  bool IsSpecifiedOnCommandLine() const {
+    return impl_.IsSpecifiedOnCommandLine();
+  }
+  std::string DefaultValue() const { return impl_.DefaultValue(); }
+  std::string CurrentValue() const { return impl_.CurrentValue(); }
+
+ private:
+  template <typename, bool>
+  friend class FlagRegistrar;
+  friend class FlagImplPeer;
 
   T Get() const {
     // See implementation notes in CommandLineFlag::Get().
@@ -564,106 +614,132 @@
     };
     U u;
 
-    impl_.Get(&u.value);
+#if !defined(NDEBUG)
+    impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>);
+#endif
+
+    if (ABSL_PREDICT_FALSE(!value_.Get(impl_.seq_lock_, u.value))) {
+      impl_.Read(&u.value);
+    }
     return std::move(u.value);
   }
-  void Set(const T& v) { impl_.Set(v); }
-  void SetCallback(const FlagCallbackFunc mutation_callback) {
-    impl_.SetCallback(mutation_callback);
+  void Set(const T& v) {
+    impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>);
+    impl_.Write(&v);
   }
 
-  // CommandLineFlag interface
-  absl::string_view Name() const override { return impl_.Name(); }
-  std::string Filename() const override { return impl_.Filename(); }
-  absl::string_view Typename() const override { return ""; }
-  std::string Help() const override { return impl_.Help(); }
-  bool IsModified() const override { return impl_.IsModified(); }
-  bool IsSpecifiedOnCommandLine() const override {
-    return impl_.IsSpecifiedOnCommandLine();
-  }
-  std::string DefaultValue() const override { return impl_.DefaultValue(); }
-  std::string CurrentValue() const override { return impl_.CurrentValue(); }
-  bool ValidateInputValue(absl::string_view value) const override {
-    return impl_.ValidateInputValue(value);
-  }
-
-  // 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 {
-    return impl_.SaveState(this);
-  }
-
-  // Restores the flag state to the supplied state object. If there is
-  // nothing to restore returns false. Otherwise returns true.
-  bool RestoreState(const FlagState<T>& flag_state) {
-    return impl_.RestoreState(&flag_state.cur_value_, flag_state.modified_,
-                              flag_state.on_command_line_, flag_state.counter_);
-  }
-  bool SetFromString(absl::string_view value, FlagSettingMode set_mode,
-                     ValueSource source, std::string* error) override {
-    return impl_.SetFromString(value, set_mode, source, error);
-  }
-  void CheckDefaultValueParsingRoundtrip() const override {
-    impl_.CheckDefaultValueParsingRoundtrip();
-  }
-
- private:
-  friend class FlagState<T>;
-
-  void Read(void* dst) const override { impl_.Read(dst); }
-  FlagStaticTypeId TypeId() const override { return &FlagStaticTypeIdGen<T>; }
+  // Access to the reflection.
+  const CommandLineFlag& Reflect() const { return impl_; }
 
   // Flag's data
+  // The implementation depends on value_ field to be placed exactly after the
+  // impl_ field, so that impl_ can figure out the offset to the value and
+  // access it.
   FlagImpl impl_;
+  FlagValue<T> value_;
 };
 
-template <typename T>
-inline void FlagState<T>::Restore() const {
-  if (flag_->RestoreState(*this)) {
-    ABSL_INTERNAL_LOG(INFO,
-                      absl::StrCat("Restore saved value of ", flag_->Name(),
-                                   " to: ", flag_->CurrentValue()));
+///////////////////////////////////////////////////////////////////////////////
+// Trampoline for friend access
+
+class FlagImplPeer {
+ public:
+  template <typename T, typename FlagType>
+  static T InvokeGet(const FlagType& flag) {
+    return flag.Get();
   }
+  template <typename FlagType, typename T>
+  static void InvokeSet(FlagType& flag, const T& v) {
+    flag.Set(v);
+  }
+  template <typename FlagType>
+  static const CommandLineFlag& InvokeReflect(const FlagType& f) {
+    return f.Reflect();
+  }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Implementation of Flag value specific operations routine.
+template <typename T>
+void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3) {
+  switch (op) {
+    case FlagOp::kAlloc: {
+      std::allocator<T> alloc;
+      return std::allocator_traits<std::allocator<T>>::allocate(alloc, 1);
+    }
+    case FlagOp::kDelete: {
+      T* p = static_cast<T*>(v2);
+      p->~T();
+      std::allocator<T> alloc;
+      std::allocator_traits<std::allocator<T>>::deallocate(alloc, p, 1);
+      return nullptr;
+    }
+    case FlagOp::kCopy:
+      *static_cast<T*>(v2) = *static_cast<const T*>(v1);
+      return nullptr;
+    case FlagOp::kCopyConstruct:
+      new (v2) T(*static_cast<const T*>(v1));
+      return nullptr;
+    case FlagOp::kSizeof:
+      return reinterpret_cast<void*>(static_cast<uintptr_t>(sizeof(T)));
+    case FlagOp::kFastTypeId:
+      return const_cast<void*>(base_internal::FastTypeId<T>());
+    case FlagOp::kRuntimeTypeId:
+      return const_cast<std::type_info*>(GenRuntimeTypeId<T>());
+    case FlagOp::kParse: {
+      // Initialize the temporary instance of type T based on current value in
+      // destination (which is going to be flag's default value).
+      T temp(*static_cast<T*>(v2));
+      if (!absl::ParseFlag<T>(*static_cast<const absl::string_view*>(v1), &temp,
+                              static_cast<std::string*>(v3))) {
+        return nullptr;
+      }
+      *static_cast<T*>(v2) = std::move(temp);
+      return v2;
+    }
+    case FlagOp::kUnparse:
+      *static_cast<std::string*>(v2) =
+          absl::UnparseFlag<T>(*static_cast<const T*>(v1));
+      return nullptr;
+    case FlagOp::kValueOffset: {
+      // Round sizeof(FlagImp) to a multiple of alignof(FlagValue<T>) to get the
+      // offset of the data.
+      ptrdiff_t round_to = alignof(FlagValue<T>);
+      ptrdiff_t offset =
+          (sizeof(FlagImpl) + round_to - 1) / round_to * round_to;
+      return reinterpret_cast<void*>(offset);
+    }
+  }
+  return nullptr;
 }
 
+///////////////////////////////////////////////////////////////////////////////
 // This class facilitates Flag object registration and tail expression-based
 // flag definition, for example:
 // ABSL_FLAG(int, foo, 42, "Foo help").OnUpdate(NotifyFooWatcher);
+struct FlagRegistrarEmpty {};
 template <typename T, bool do_register>
 class FlagRegistrar {
  public:
-  explicit FlagRegistrar(Flag<T>* flag) : flag_(flag) {
-    if (do_register) flags_internal::RegisterCommandLineFlag(flag_);
+  explicit FlagRegistrar(Flag<T>& flag, const char* filename) : flag_(flag) {
+    if (do_register)
+      flags_internal::RegisterCommandLineFlag(flag_.impl_, filename);
   }
 
-  FlagRegistrar& OnUpdate(FlagCallbackFunc cb) && {
-    flag_->SetCallback(cb);
+  FlagRegistrar OnUpdate(FlagCallbackFunc cb) && {
+    flag_.impl_.SetCallback(cb);
     return *this;
   }
 
-  // Make the registrar "die" gracefully as a bool on a line where registration
-  // happens. Registrar objects are intended to live only as temporary.
-  operator bool() const { return true; }  // NOLINT
+  // Make the registrar "die" gracefully as an empty struct on a line where
+  // registration happens. Registrar objects are intended to live only as
+  // temporary.
+  operator FlagRegistrarEmpty() const { return {}; }  // NOLINT
 
  private:
-  Flag<T>* flag_;  // Flag being registered (not owned).
+  Flag<T>& flag_;  // Flag being registered (not owned).
 };
 
-// This struct and corresponding overload to MakeDefaultValue are used to
-// facilitate usage of {} as default value in ABSL_FLAG macro.
-struct EmptyBraces {};
-
-template <typename T>
-T* MakeFromDefaultValue(T t) {
-  return new T(std::move(t));
-}
-
-template <typename T>
-T* MakeFromDefaultValue(EmptyBraces) {
-  return new T;
-}
-
 }  // namespace flags_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/flags/internal/parse.h b/absl/flags/internal/parse.h
index 03e8a07..de706c8 100644
--- a/absl/flags/internal/parse.h
+++ b/absl/flags/internal/parse.h
@@ -21,6 +21,7 @@
 
 #include "absl/base/config.h"
 #include "absl/flags/declare.h"
+#include "absl/strings/string_view.h"
 
 ABSL_DECLARE_FLAG(std::vector<std::string>, flagfile);
 ABSL_DECLARE_FLAG(std::vector<std::string>, fromenv);
@@ -44,6 +45,13 @@
                                         UsageFlagsAction usage_flag_act,
                                         OnUndefinedFlag on_undef_flag);
 
+// --------------------------------------------------------------------
+// Inspect original command line
+
+// Returns true if flag with specified name was either present on the original
+// command line or specified in flag file present on the original command line.
+bool WasPresentOnCommandLine(absl::string_view flag_name);
+
 }  // namespace flags_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/flags/internal/path_util.h b/absl/flags/internal/path_util.h
index 365c830..a6594d3 100644
--- a/absl/flags/internal/path_util.h
+++ b/absl/flags/internal/path_util.h
@@ -17,7 +17,6 @@
 #define ABSL_FLAGS_INTERNAL_PATH_UTIL_H_
 
 #include "absl/base/config.h"
-#include "absl/strings/match.h"
 #include "absl/strings/string_view.h"
 
 namespace absl {
diff --git a/absl/flags/internal/private_handle_accessor.cc b/absl/flags/internal/private_handle_accessor.cc
new file mode 100644
index 0000000..a7eb58b
--- /dev/null
+++ b/absl/flags/internal/private_handle_accessor.cc
@@ -0,0 +1,65 @@
+//
+// 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/flags/internal/private_handle_accessor.h"
+
+#include <memory>
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/flags/commandlineflag.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace flags_internal {
+
+FlagFastTypeId PrivateHandleAccessor::TypeId(const CommandLineFlag& flag) {
+  return flag.TypeId();
+}
+
+std::unique_ptr<FlagStateInterface> PrivateHandleAccessor::SaveState(
+    CommandLineFlag& flag) {
+  return flag.SaveState();
+}
+
+bool PrivateHandleAccessor::IsSpecifiedOnCommandLine(
+    const CommandLineFlag& flag) {
+  return flag.IsSpecifiedOnCommandLine();
+}
+
+bool PrivateHandleAccessor::ValidateInputValue(const CommandLineFlag& flag,
+                                               absl::string_view value) {
+  return flag.ValidateInputValue(value);
+}
+
+void PrivateHandleAccessor::CheckDefaultValueParsingRoundtrip(
+    const CommandLineFlag& flag) {
+  flag.CheckDefaultValueParsingRoundtrip();
+}
+
+bool PrivateHandleAccessor::ParseFrom(CommandLineFlag& flag,
+                                      absl::string_view value,
+                                      flags_internal::FlagSettingMode set_mode,
+                                      flags_internal::ValueSource source,
+                                      std::string& error) {
+  return flag.ParseFrom(value, set_mode, source, error);
+}
+
+}  // namespace flags_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
diff --git a/absl/flags/internal/private_handle_accessor.h b/absl/flags/internal/private_handle_accessor.h
new file mode 100644
index 0000000..c64435c
--- /dev/null
+++ b/absl/flags/internal/private_handle_accessor.h
@@ -0,0 +1,61 @@
+//
+// 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.
+
+#ifndef ABSL_FLAGS_INTERNAL_PRIVATE_HANDLE_ACCESSOR_H_
+#define ABSL_FLAGS_INTERNAL_PRIVATE_HANDLE_ACCESSOR_H_
+
+#include <memory>
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/flags/commandlineflag.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace flags_internal {
+
+// This class serves as a trampoline to access private methods of
+// CommandLineFlag. This class is intended for use exclusively internally inside
+// of the Abseil Flags implementation.
+class PrivateHandleAccessor {
+ public:
+  // Access to CommandLineFlag::TypeId.
+  static FlagFastTypeId TypeId(const CommandLineFlag& flag);
+
+  // Access to CommandLineFlag::SaveState.
+  static std::unique_ptr<FlagStateInterface> SaveState(CommandLineFlag& flag);
+
+  // Access to CommandLineFlag::IsSpecifiedOnCommandLine.
+  static bool IsSpecifiedOnCommandLine(const CommandLineFlag& flag);
+
+  // Access to CommandLineFlag::ValidateInputValue.
+  static bool ValidateInputValue(const CommandLineFlag& flag,
+                                 absl::string_view value);
+
+  // Access to CommandLineFlag::CheckDefaultValueParsingRoundtrip.
+  static void CheckDefaultValueParsingRoundtrip(const CommandLineFlag& flag);
+
+  static bool ParseFrom(CommandLineFlag& flag, absl::string_view value,
+                        flags_internal::FlagSettingMode set_mode,
+                        flags_internal::ValueSource source, std::string& error);
+};
+
+}  // namespace flags_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_FLAGS_INTERNAL_PRIVATE_HANDLE_ACCESSOR_H_
diff --git a/absl/flags/internal/program_name_test.cc b/absl/flags/internal/program_name_test.cc
index 269142f..aff9f63 100644
--- a/absl/flags/internal/program_name_test.cc
+++ b/absl/flags/internal/program_name_test.cc
@@ -25,7 +25,7 @@
 
 namespace flags = absl::flags_internal;
 
-TEST(FlagsPathUtilTest, TestInitialProgamName) {
+TEST(FlagsPathUtilTest, TestProgamNameInterfaces) {
   flags::SetProgramInvocationName("absl/flags/program_name_test");
   std::string program_name = flags::ProgramInvocationName();
   for (char& c : program_name)
@@ -43,9 +43,7 @@
 
   EXPECT_TRUE(absl::EndsWith(program_name, expect_name)) << program_name;
   EXPECT_EQ(flags::ShortProgramInvocationName(), expect_basename);
-}
 
-TEST(FlagsPathUtilTest, TestProgamNameInterfaces) {
   flags::SetProgramInvocationName("a/my_test");
 
   EXPECT_EQ(flags::ProgramInvocationName(), "a/my_test");
diff --git a/absl/flags/internal/registry.cc b/absl/flags/internal/registry.cc
deleted file mode 100644
index e434a85..0000000
--- a/absl/flags/internal/registry.cc
+++ /dev/null
@@ -1,351 +0,0 @@
-//
-// Copyright 2019 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/flags/internal/registry.h"
-
-#include <assert.h>
-#include <stdlib.h>
-
-#include <functional>
-#include <map>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "absl/base/config.h"
-#include "absl/base/internal/raw_logging.h"
-#include "absl/base/thread_annotations.h"
-#include "absl/flags/internal/commandlineflag.h"
-#include "absl/flags/usage_config.h"
-#include "absl/strings/str_cat.h"
-#include "absl/strings/string_view.h"
-#include "absl/synchronization/mutex.h"
-
-// --------------------------------------------------------------------
-// FlagRegistry implementation
-//    A FlagRegistry holds all flag objects indexed
-//    by their names so that if you know a flag's name you can access or
-//    set it.
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace flags_internal {
-
-// --------------------------------------------------------------------
-// FlagRegistry
-//    A FlagRegistry singleton object holds all flag objects indexed
-//    by their names so that if you know a flag's name (as a C
-//    string), you can access or set it.  If the function is named
-//    FooLocked(), you must own the registry lock before calling
-//    the function; otherwise, you should *not* hold the lock, and
-//    the function will acquire it itself if needed.
-// --------------------------------------------------------------------
-
-class FlagRegistry {
- public:
-  FlagRegistry() = default;
-  ~FlagRegistry() = default;
-
-  // Store a flag in this registry.  Takes ownership of *flag.
-  void RegisterFlag(CommandLineFlag* flag);
-
-  void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION(lock_) { lock_.Lock(); }
-  void Unlock() ABSL_UNLOCK_FUNCTION(lock_) { 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.
-  CommandLineFlag* FindFlagLocked(absl::string_view name);
-
-  // Returns the retired flag object for the specified name, or nullptr if not
-  // found or not retired.  Does not emit a warning.
-  CommandLineFlag* FindRetiredFlagLocked(absl::string_view name);
-
-  static FlagRegistry* GlobalRegistry();  // returns a singleton registry
-
- private:
-  friend class FlagSaverImpl;  // reads all the flags in order to copy them
-  friend void ForEachFlagUnlocked(
-      std::function<void(CommandLineFlag*)> visitor);
-
-  // The map from name to flag, for FindFlagLocked().
-  using FlagMap = std::map<absl::string_view, CommandLineFlag*>;
-  using FlagIterator = FlagMap::iterator;
-  using FlagConstIterator = FlagMap::const_iterator;
-  FlagMap flags_;
-
-  absl::Mutex lock_;
-
-  // Disallow
-  FlagRegistry(const FlagRegistry&);
-  FlagRegistry& operator=(const FlagRegistry&);
-};
-
-FlagRegistry* FlagRegistry::GlobalRegistry() {
-  static FlagRegistry* global_registry = new FlagRegistry;
-  return global_registry;
-}
-
-namespace {
-
-class FlagRegistryLock {
- public:
-  explicit FlagRegistryLock(FlagRegistry* fr) : fr_(fr) { fr_->Lock(); }
-  ~FlagRegistryLock() { fr_->Unlock(); }
-
- private:
-  FlagRegistry* const fr_;
-};
-
-void DestroyRetiredFlag(CommandLineFlag* flag);
-}  // namespace
-
-void FlagRegistry::RegisterFlag(CommandLineFlag* flag) {
-  FlagRegistryLock registry_lock(this);
-  std::pair<FlagIterator, bool> ins =
-      flags_.insert(FlagMap::value_type(flag->Name(), flag));
-  if (ins.second == false) {  // means the name was already in the map
-    CommandLineFlag* old_flag = ins.first->second;
-    if (flag->IsRetired() != old_flag->IsRetired()) {
-      // All registrations must agree on the 'retired' flag.
-      flags_internal::ReportUsageError(
-          absl::StrCat(
-              "Retired flag '", flag->Name(),
-              "' was defined normally in file '",
-              (flag->IsRetired() ? old_flag->Filename() : flag->Filename()),
-              "'."),
-          true);
-    } else if (flag->TypeId() != old_flag->TypeId()) {
-      flags_internal::ReportUsageError(
-          absl::StrCat("Flag '", flag->Name(),
-                       "' was defined more than once but with "
-                       "differing types. Defined in files '",
-                       old_flag->Filename(), "' and '", flag->Filename(),
-                       "' with types '", old_flag->Typename(), "' and '",
-                       flag->Typename(), "', respectively."),
-          true);
-    } else if (old_flag->IsRetired()) {
-      // Retired flag can just be deleted.
-      DestroyRetiredFlag(flag);
-      return;
-    } else if (old_flag->Filename() != flag->Filename()) {
-      flags_internal::ReportUsageError(
-          absl::StrCat("Flag '", flag->Name(),
-                       "' was defined more than once (in files '",
-                       old_flag->Filename(), "' and '", flag->Filename(),
-                       "')."),
-          true);
-    } else {
-      flags_internal::ReportUsageError(
-          absl::StrCat(
-              "Something wrong with flag '", flag->Name(), "' in file '",
-              flag->Filename(), "'. One possibility: file '", flag->Filename(),
-              "' is being linked both statically and dynamically into this "
-              "executable. e.g. some files listed as srcs to a test and also "
-              "listed as srcs of some shared lib deps of the same test."),
-          true);
-    }
-    // All cases above are fatal, except for the retired flags.
-    std::exit(1);
-  }
-}
-
-CommandLineFlag* FlagRegistry::FindFlagLocked(absl::string_view name) {
-  FlagConstIterator i = flags_.find(name);
-  if (i == flags_.end()) {
-    return nullptr;
-  }
-
-  if (i->second->IsRetired()) {
-    flags_internal::ReportUsageError(
-        absl::StrCat("Accessing retired flag '", name, "'"), false);
-  }
-
-  return i->second;
-}
-
-CommandLineFlag* FlagRegistry::FindRetiredFlagLocked(absl::string_view name) {
-  FlagConstIterator i = flags_.find(name);
-  if (i == flags_.end() || !i->second->IsRetired()) {
-    return nullptr;
-  }
-
-  return i->second;
-}
-
-// --------------------------------------------------------------------
-// FlagSaver
-// FlagSaverImpl
-//    This class stores the states of all flags at construct time,
-//    and restores all flags to that state at destruct time.
-//    Its major implementation challenge is that it never modifies
-//    pointers in the 'main' registry, so global FLAG_* vars always
-//    point to the right place.
-// --------------------------------------------------------------------
-
-class FlagSaverImpl {
- public:
-  FlagSaverImpl() = default;
-  FlagSaverImpl(const FlagSaverImpl&) = delete;
-  void operator=(const FlagSaverImpl&) = delete;
-
-  // Saves the flag states from the flag registry into this object.
-  // It's an error to call this more than once.
-  void SaveFromRegistry() {
-    assert(backup_registry_.empty());  // call only once!
-    flags_internal::ForEachFlag([&](flags_internal::CommandLineFlag* flag) {
-      if (auto flag_state = flag->SaveState()) {
-        backup_registry_.emplace_back(std::move(flag_state));
-      }
-    });
-  }
-
-  // Restores the saved flag states into the flag registry.
-  void RestoreToRegistry() {
-    for (const auto& flag_state : backup_registry_) {
-      flag_state->Restore();
-    }
-  }
-
- private:
-  std::vector<std::unique_ptr<flags_internal::FlagStateInterface>>
-      backup_registry_;
-};
-
-FlagSaver::FlagSaver() : impl_(new FlagSaverImpl) { impl_->SaveFromRegistry(); }
-
-void FlagSaver::Ignore() {
-  delete impl_;
-  impl_ = nullptr;
-}
-
-FlagSaver::~FlagSaver() {
-  if (!impl_) return;
-
-  impl_->RestoreToRegistry();
-  delete impl_;
-}
-
-// --------------------------------------------------------------------
-
-CommandLineFlag* FindCommandLineFlag(absl::string_view name) {
-  if (name.empty()) return nullptr;
-  FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
-  FlagRegistryLock frl(registry);
-
-  return registry->FindFlagLocked(name);
-}
-
-CommandLineFlag* FindRetiredFlag(absl::string_view name) {
-  FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
-  FlagRegistryLock frl(registry);
-
-  return registry->FindRetiredFlagLocked(name);
-}
-
-// --------------------------------------------------------------------
-
-void ForEachFlagUnlocked(std::function<void(CommandLineFlag*)> visitor) {
-  FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
-  for (FlagRegistry::FlagConstIterator i = registry->flags_.begin();
-       i != registry->flags_.end(); ++i) {
-    visitor(i->second);
-  }
-}
-
-void ForEachFlag(std::function<void(CommandLineFlag*)> visitor) {
-  FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
-  FlagRegistryLock frl(registry);
-  ForEachFlagUnlocked(visitor);
-}
-
-// --------------------------------------------------------------------
-
-bool RegisterCommandLineFlag(CommandLineFlag* flag) {
-  FlagRegistry::GlobalRegistry()->RegisterFlag(flag);
-  return true;
-}
-
-// --------------------------------------------------------------------
-
-namespace {
-
-class RetiredFlagObj final : public flags_internal::CommandLineFlag {
- public:
-  constexpr RetiredFlagObj(const char* name, FlagStaticTypeId type_id)
-      : name_(name), type_id_(type_id) {}
-
- private:
-  absl::string_view Name() const override { return name_; }
-  std::string Filename() const override { return "RETIRED"; }
-  absl::string_view Typename() const override { return ""; }
-  FlagStaticTypeId TypeId() const override { return type_id_; }
-  std::string Help() const override { return ""; }
-  bool IsRetired() const override { return true; }
-  bool IsModified() const override { return false; }
-  bool IsSpecifiedOnCommandLine() const override { return false; }
-  std::string DefaultValue() const override { return ""; }
-  std::string CurrentValue() const override { return ""; }
-
-  // Any input is valid
-  bool ValidateInputValue(absl::string_view) const override { return true; }
-
-  std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override {
-    return nullptr;
-  }
-
-  bool SetFromString(absl::string_view, flags_internal::FlagSettingMode,
-                     flags_internal::ValueSource, std::string*) override {
-    return false;
-  }
-
-  void CheckDefaultValueParsingRoundtrip() const override {}
-
-  void Read(void*) const override {}
-
-  // Data members
-  const char* const name_;
-  const FlagStaticTypeId type_id_;
-};
-
-void DestroyRetiredFlag(flags_internal::CommandLineFlag* flag) {
-  assert(flag->IsRetired());
-  delete static_cast<RetiredFlagObj*>(flag);
-}
-
-}  // namespace
-
-bool Retire(const char* name, FlagStaticTypeId type_id) {
-  auto* flag = new flags_internal::RetiredFlagObj(name, type_id);
-  FlagRegistry::GlobalRegistry()->RegisterFlag(flag);
-  return true;
-}
-
-// --------------------------------------------------------------------
-
-bool IsRetiredFlag(absl::string_view name, bool* type_is_bool) {
-  assert(!name.empty());
-  CommandLineFlag* flag = flags_internal::FindRetiredFlag(name);
-  if (flag == nullptr) {
-    return false;
-  }
-  assert(type_is_bool);
-  *type_is_bool = flag->IsOfType<bool>();
-  return true;
-}
-
-}  // namespace flags_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
diff --git a/absl/flags/internal/registry.h b/absl/flags/internal/registry.h
index 69ff889..4b68c85 100644
--- a/absl/flags/internal/registry.h
+++ b/absl/flags/internal/registry.h
@@ -17,11 +17,9 @@
 #define ABSL_FLAGS_INTERNAL_REGISTRY_H_
 
 #include <functional>
-#include <map>
-#include <string>
 
 #include "absl/base/config.h"
-#include "absl/base/macros.h"
+#include "absl/flags/commandlineflag.h"
 #include "absl/flags/internal/commandlineflag.h"
 #include "absl/strings/string_view.h"
 
@@ -32,19 +30,15 @@
 ABSL_NAMESPACE_BEGIN
 namespace flags_internal {
 
-CommandLineFlag* FindCommandLineFlag(absl::string_view name);
-CommandLineFlag* FindRetiredFlag(absl::string_view name);
-
-// Executes specified visitor for each non-retired flag in the registry.
-// Requires the caller hold the registry lock.
-void ForEachFlagUnlocked(std::function<void(CommandLineFlag*)> visitor);
 // Executes specified visitor for each non-retired flag in the registry. While
 // callback are executed, the registry is locked and can't be changed.
-void ForEachFlag(std::function<void(CommandLineFlag*)> visitor);
+void ForEachFlag(std::function<void(CommandLineFlag&)> visitor);
 
 //-----------------------------------------------------------------------------
 
-bool RegisterCommandLineFlag(CommandLineFlag*);
+bool RegisterCommandLineFlag(CommandLineFlag&, const char* filename);
+
+void FinalizeRegistry();
 
 //-----------------------------------------------------------------------------
 // Retired registrations:
@@ -79,42 +73,21 @@
 //
 
 // Retire flag with name "name" and type indicated by ops.
-bool Retire(const char* name, FlagStaticTypeId type_id);
+void Retire(const char* name, FlagFastTypeId type_id, char* buf);
+
+constexpr size_t kRetiredFlagObjSize = 3 * sizeof(void*);
+constexpr size_t kRetiredFlagObjAlignment = alignof(void*);
 
 // Registered a retired flag with name 'flag_name' and type 'T'.
 template <typename T>
-inline bool RetiredFlag(const char* flag_name) {
-  return flags_internal::Retire(flag_name, &FlagStaticTypeIdGen<T>);
-}
-
-// If the flag is retired, returns true and indicates in |*type_is_bool|
-// whether the type of the retired flag is a bool.
-// Only to be called by code that needs to explicitly ignore retired flags.
-bool IsRetiredFlag(absl::string_view name, bool* type_is_bool);
-
-//-----------------------------------------------------------------------------
-// Saves the states (value, default value, whether the user has set
-// the flag, registered validators, etc) of all flags, and restores
-// them when the FlagSaver is destroyed.
-//
-// This class is thread-safe.  However, its destructor writes to
-// exactly the set of flags that have changed value during its
-// lifetime, so concurrent _direct_ access to those flags
-// (i.e. FLAGS_foo instead of {Get,Set}CommandLineOption()) is unsafe.
-
-class FlagSaver {
+class RetiredFlag {
  public:
-  FlagSaver();
-  ~FlagSaver();
-
-  FlagSaver(const FlagSaver&) = delete;
-  void operator=(const FlagSaver&) = delete;
-
-  // Prevents saver from restoring the saved state of flags.
-  void Ignore();
+  void Retire(const char* flag_name) {
+    flags_internal::Retire(flag_name, base_internal::FastTypeId<T>(), buf_);
+  }
 
  private:
-  class FlagSaverImpl* impl_;  // we use pimpl here to keep API steady
+  alignas(kRetiredFlagObjAlignment) char buf_[kRetiredFlagObjSize];
 };
 
 }  // namespace flags_internal
diff --git a/absl/flags/internal/sequence_lock.h b/absl/flags/internal/sequence_lock.h
new file mode 100644
index 0000000..807b2a7
--- /dev/null
+++ b/absl/flags/internal/sequence_lock.h
@@ -0,0 +1,187 @@
+//
+// 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.
+
+#ifndef ABSL_FLAGS_INTERNAL_SEQUENCE_LOCK_H_
+#define ABSL_FLAGS_INTERNAL_SEQUENCE_LOCK_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <atomic>
+#include <cassert>
+#include <cstring>
+
+#include "absl/base/optimization.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace flags_internal {
+
+// Align 'x' up to the nearest 'align' bytes.
+inline constexpr size_t AlignUp(size_t x, size_t align) {
+  return align * ((x + align - 1) / align);
+}
+
+// A SequenceLock implements lock-free reads. A sequence counter is incremented
+// before and after each write, and readers access the counter before and after
+// accessing the protected data. If the counter is verified to not change during
+// the access, and the sequence counter value was even, then the reader knows
+// that the read was race-free and valid. Otherwise, the reader must fall back
+// to a Mutex-based code path.
+//
+// This particular SequenceLock starts in an "uninitialized" state in which
+// TryRead() returns false. It must be enabled by calling MarkInitialized().
+// This serves as a marker that the associated flag value has not yet been
+// initialized and a slow path needs to be taken.
+//
+// The memory reads and writes protected by this lock must use the provided
+// `TryRead()` and `Write()` functions. These functions behave similarly to
+// `memcpy()`, with one oddity: the protected data must be an array of
+// `std::atomic<int64>`. This is to comply with the C++ standard, which
+// considers data races on non-atomic objects to be undefined behavior. See "Can
+// Seqlocks Get Along With Programming Language Memory Models?"[1] by Hans J.
+// Boehm for more details.
+//
+// [1] https://www.hpl.hp.com/techreports/2012/HPL-2012-68.pdf
+class SequenceLock {
+ public:
+  constexpr SequenceLock() : lock_(kUninitialized) {}
+
+  // Mark that this lock is ready for use.
+  void MarkInitialized() {
+    assert(lock_.load(std::memory_order_relaxed) == kUninitialized);
+    lock_.store(0, std::memory_order_release);
+  }
+
+  // Copy "size" bytes of data from "src" to "dst", protected as a read-side
+  // critical section of the sequence lock.
+  //
+  // Unlike traditional sequence lock implementations which loop until getting a
+  // clean read, this implementation returns false in the case of concurrent
+  // calls to `Write`. In such a case, the caller should fall back to a
+  // locking-based slow path.
+  //
+  // Returns false if the sequence lock was not yet marked as initialized.
+  //
+  // NOTE: If this returns false, "dst" may be overwritten with undefined
+  // (potentially uninitialized) data.
+  bool TryRead(void* dst, const std::atomic<uint64_t>* src, size_t size) const {
+    // Acquire barrier ensures that no loads done by f() are reordered
+    // above the first load of the sequence counter.
+    int64_t seq_before = lock_.load(std::memory_order_acquire);
+    if (ABSL_PREDICT_FALSE(seq_before & 1) == 1) return false;
+    RelaxedCopyFromAtomic(dst, src, size);
+    // Another acquire fence ensures that the load of 'lock_' below is
+    // strictly ordered after the RelaxedCopyToAtomic call above.
+    std::atomic_thread_fence(std::memory_order_acquire);
+    int64_t seq_after = lock_.load(std::memory_order_relaxed);
+    return ABSL_PREDICT_TRUE(seq_before == seq_after);
+  }
+
+  // Copy "size" bytes from "src" to "dst" as a write-side critical section
+  // of the sequence lock. Any concurrent readers will be forced to retry
+  // until they get a read that does not conflict with this write.
+  //
+  // This call must be externally synchronized against other calls to Write,
+  // but may proceed concurrently with reads.
+  void Write(std::atomic<uint64_t>* dst, const void* src, size_t size) {
+    // We can use relaxed instructions to increment the counter since we
+    // are extenally synchronized. The std::atomic_thread_fence below
+    // ensures that the counter updates don't get interleaved with the
+    // copy to the data.
+    int64_t orig_seq = lock_.load(std::memory_order_relaxed);
+    assert((orig_seq & 1) == 0);  // Must be initially unlocked.
+    lock_.store(orig_seq + 1, std::memory_order_relaxed);
+
+    // We put a release fence between update to lock_ and writes to shared data.
+    // Thus all stores to shared data are effectively release operations and
+    // update to lock_ above cannot be re-ordered past any of them. Note that
+    // this barrier is not for the fetch_add above.  A release barrier for the
+    // fetch_add would be before it, not after.
+    std::atomic_thread_fence(std::memory_order_release);
+    RelaxedCopyToAtomic(dst, src, size);
+    // "Release" semantics ensure that none of the writes done by
+    // RelaxedCopyToAtomic() can be reordered after the following modification.
+    lock_.store(orig_seq + 2, std::memory_order_release);
+  }
+
+  // Return the number of times that Write() has been called.
+  //
+  // REQUIRES: This must be externally synchronized against concurrent calls to
+  // `Write()` or `IncrementModificationCount()`.
+  // REQUIRES: `MarkInitialized()` must have been previously called.
+  int64_t ModificationCount() const {
+    int64_t val = lock_.load(std::memory_order_relaxed);
+    assert(val != kUninitialized && (val & 1) == 0);
+    return val / 2;
+  }
+
+  // REQUIRES: This must be externally synchronized against concurrent calls to
+  // `Write()` or `ModificationCount()`.
+  // REQUIRES: `MarkInitialized()` must have been previously called.
+  void IncrementModificationCount() {
+    int64_t val = lock_.load(std::memory_order_relaxed);
+    assert(val != kUninitialized);
+    lock_.store(val + 2, std::memory_order_relaxed);
+  }
+
+ private:
+  // Perform the equivalent of "memcpy(dst, src, size)", but using relaxed
+  // atomics.
+  static void RelaxedCopyFromAtomic(void* dst, const std::atomic<uint64_t>* src,
+                                    size_t size) {
+    char* dst_byte = static_cast<char*>(dst);
+    while (size >= sizeof(uint64_t)) {
+      uint64_t word = src->load(std::memory_order_relaxed);
+      std::memcpy(dst_byte, &word, sizeof(word));
+      dst_byte += sizeof(word);
+      src++;
+      size -= sizeof(word);
+    }
+    if (size > 0) {
+      uint64_t word = src->load(std::memory_order_relaxed);
+      std::memcpy(dst_byte, &word, size);
+    }
+  }
+
+  // Perform the equivalent of "memcpy(dst, src, size)", but using relaxed
+  // atomics.
+  static void RelaxedCopyToAtomic(std::atomic<uint64_t>* dst, const void* src,
+                                  size_t size) {
+    const char* src_byte = static_cast<const char*>(src);
+    while (size >= sizeof(uint64_t)) {
+      uint64_t word;
+      std::memcpy(&word, src_byte, sizeof(word));
+      dst->store(word, std::memory_order_relaxed);
+      src_byte += sizeof(word);
+      dst++;
+      size -= sizeof(word);
+    }
+    if (size > 0) {
+      uint64_t word = 0;
+      std::memcpy(&word, src_byte, size);
+      dst->store(word, std::memory_order_relaxed);
+    }
+  }
+
+  static constexpr int64_t kUninitialized = -1;
+  std::atomic<int64_t> lock_;
+};
+
+}  // namespace flags_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_FLAGS_INTERNAL_SEQUENCE_LOCK_H_
diff --git a/absl/flags/internal/sequence_lock_test.cc b/absl/flags/internal/sequence_lock_test.cc
new file mode 100644
index 0000000..c3ec372
--- /dev/null
+++ b/absl/flags/internal/sequence_lock_test.cc
@@ -0,0 +1,169 @@
+// 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/flags/internal/sequence_lock.h"
+
+#include <algorithm>
+#include <atomic>
+#include <thread>  // NOLINT(build/c++11)
+#include <tuple>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/sysinfo.h"
+#include "absl/container/fixed_array.h"
+#include "absl/time/clock.h"
+
+namespace {
+
+namespace flags = absl::flags_internal;
+
+class ConcurrentSequenceLockTest
+    : public testing::TestWithParam<std::tuple<int, int>> {
+ public:
+  ConcurrentSequenceLockTest()
+      : buf_bytes_(std::get<0>(GetParam())),
+        num_threads_(std::get<1>(GetParam())) {}
+
+ protected:
+  const int buf_bytes_;
+  const int num_threads_;
+};
+
+TEST_P(ConcurrentSequenceLockTest, ReadAndWrite) {
+  const int buf_words =
+      flags::AlignUp(buf_bytes_, sizeof(uint64_t)) / sizeof(uint64_t);
+
+  // The buffer that will be protected by the SequenceLock.
+  absl::FixedArray<std::atomic<uint64_t>> protected_buf(buf_words);
+  for (auto& v : protected_buf) v = -1;
+
+  flags::SequenceLock seq_lock;
+  std::atomic<bool> stop{false};
+  std::atomic<int64_t> bad_reads{0};
+  std::atomic<int64_t> good_reads{0};
+  std::atomic<int64_t> unsuccessful_reads{0};
+
+  // Start a bunch of threads which read 'protected_buf' under the sequence
+  // lock. The main thread will concurrently update 'protected_buf'. The updates
+  // always consist of an array of identical integers. The reader ensures that
+  // any data it reads matches that pattern (i.e. the reads are not "torn").
+  std::vector<std::thread> threads;
+  for (int i = 0; i < num_threads_; i++) {
+    threads.emplace_back([&]() {
+      absl::FixedArray<char> local_buf(buf_bytes_);
+      while (!stop.load(std::memory_order_relaxed)) {
+        if (seq_lock.TryRead(local_buf.data(), protected_buf.data(),
+                             buf_bytes_)) {
+          bool good = true;
+          for (const auto& v : local_buf) {
+            if (v != local_buf[0]) good = false;
+          }
+          if (good) {
+            good_reads.fetch_add(1, std::memory_order_relaxed);
+          } else {
+            bad_reads.fetch_add(1, std::memory_order_relaxed);
+          }
+        } else {
+          unsuccessful_reads.fetch_add(1, std::memory_order_relaxed);
+        }
+      }
+    });
+  }
+  while (unsuccessful_reads.load(std::memory_order_relaxed) < num_threads_) {
+    absl::SleepFor(absl::Milliseconds(1));
+  }
+  seq_lock.MarkInitialized();
+
+  // Run a maximum of 5 seconds. On Windows, the scheduler behavior seems
+  // somewhat unfair and without an explicit timeout for this loop, the tests
+  // can run a long time.
+  absl::Time deadline = absl::Now() + absl::Seconds(5);
+  for (int i = 0; i < 100 && absl::Now() < deadline; i++) {
+    absl::FixedArray<char> writer_buf(buf_bytes_);
+    for (auto& v : writer_buf) v = i;
+    seq_lock.Write(protected_buf.data(), writer_buf.data(), buf_bytes_);
+    absl::SleepFor(absl::Microseconds(10));
+  }
+  stop.store(true, std::memory_order_relaxed);
+  for (auto& t : threads) t.join();
+  ASSERT_GE(good_reads, 0);
+  ASSERT_EQ(bad_reads, 0);
+}
+
+// Simple helper for generating a range of thread counts.
+// Generates [low, low*scale, low*scale^2, ...high)
+// (even if high is between low*scale^k and low*scale^(k+1)).
+std::vector<int> MultiplicativeRange(int low, int high, int scale) {
+  std::vector<int> result;
+  for (int current = low; current < high; current *= scale) {
+    result.push_back(current);
+  }
+  result.push_back(high);
+  return result;
+}
+
+#ifndef ABSL_HAVE_THREAD_SANITIZER
+const int kMaxThreads = absl::base_internal::NumCPUs();
+#else
+// With TSAN, a lot of threads contending for atomic access on the sequence
+// lock make this test run too slowly.
+const int kMaxThreads = std::min(absl::base_internal::NumCPUs(), 4);
+#endif
+
+// Return all of the interesting buffer sizes worth testing:
+// powers of two and adjacent values.
+std::vector<int> InterestingBufferSizes() {
+  std::vector<int> ret;
+  for (int v : MultiplicativeRange(1, 128, 2)) {
+    ret.push_back(v);
+    if (v > 1) {
+      ret.push_back(v - 1);
+    }
+    ret.push_back(v + 1);
+  }
+  return ret;
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    TestManyByteSizes, ConcurrentSequenceLockTest,
+    testing::Combine(
+        // Buffer size (bytes).
+        testing::ValuesIn(InterestingBufferSizes()),
+        // Number of reader threads.
+        testing::ValuesIn(MultiplicativeRange(1, kMaxThreads, 2))));
+
+// Simple single-threaded test, parameterized by the size of the buffer to be
+// protected.
+class SequenceLockTest : public testing::TestWithParam<int> {};
+
+TEST_P(SequenceLockTest, SingleThreaded) {
+  const int size = GetParam();
+  absl::FixedArray<std::atomic<uint64_t>> protected_buf(
+      flags::AlignUp(size, sizeof(uint64_t)) / sizeof(uint64_t));
+
+  flags::SequenceLock seq_lock;
+  seq_lock.MarkInitialized();
+
+  std::vector<char> src_buf(size, 'x');
+  seq_lock.Write(protected_buf.data(), src_buf.data(), size);
+
+  std::vector<char> dst_buf(size, '0');
+  ASSERT_TRUE(seq_lock.TryRead(dst_buf.data(), protected_buf.data(), size));
+  ASSERT_EQ(src_buf, dst_buf);
+}
+INSTANTIATE_TEST_SUITE_P(TestManyByteSizes, SequenceLockTest,
+                         // Buffer size (bytes).
+                         testing::Range(1, 128));
+
+}  // namespace
diff --git a/absl/flags/internal/type_erased.cc b/absl/flags/internal/type_erased.cc
deleted file mode 100644
index 490bc4e..0000000
--- a/absl/flags/internal/type_erased.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-//
-// Copyright 2019 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/flags/internal/type_erased.h"
-
-#include <assert.h>
-
-#include <string>
-
-#include "absl/base/config.h"
-#include "absl/base/internal/raw_logging.h"
-#include "absl/flags/internal/commandlineflag.h"
-#include "absl/flags/internal/registry.h"
-#include "absl/flags/usage_config.h"
-#include "absl/strings/string_view.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace flags_internal {
-
-bool GetCommandLineOption(absl::string_view name, std::string* value) {
-  if (name.empty()) return false;
-  assert(value);
-
-  CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
-  if (flag == nullptr || flag->IsRetired()) {
-    return false;
-  }
-
-  *value = flag->CurrentValue();
-  return true;
-}
-
-bool SetCommandLineOption(absl::string_view name, absl::string_view value) {
-  return SetCommandLineOptionWithMode(name, value,
-                                      flags_internal::SET_FLAGS_VALUE);
-}
-
-bool SetCommandLineOptionWithMode(absl::string_view name,
-                                  absl::string_view value,
-                                  FlagSettingMode set_mode) {
-  CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
-
-  if (!flag || flag->IsRetired()) return false;
-
-  std::string error;
-  if (!flag->SetFromString(value, set_mode, kProgrammaticChange, &error)) {
-    // Errors here are all of the form: the provided name was a recognized
-    // flag, but the value was invalid (bad type, or validation failed).
-    flags_internal::ReportUsageError(error, false);
-    return false;
-  }
-
-  return true;
-}
-
-// --------------------------------------------------------------------
-
-bool IsValidFlagValue(absl::string_view name, absl::string_view value) {
-  CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
-
-  return flag != nullptr &&
-         (flag->IsRetired() || flag->ValidateInputValue(value));
-}
-
-// --------------------------------------------------------------------
-
-bool SpecifiedOnCommandLine(absl::string_view name) {
-  CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
-  if (flag != nullptr && !flag->IsRetired()) {
-    return flag->IsSpecifiedOnCommandLine();
-  }
-  return false;
-}
-
-}  // namespace flags_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
diff --git a/absl/flags/internal/type_erased.h b/absl/flags/internal/type_erased.h
deleted file mode 100644
index 188429c..0000000
--- a/absl/flags/internal/type_erased.h
+++ /dev/null
@@ -1,90 +0,0 @@
-//
-// Copyright 2019 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_FLAGS_INTERNAL_TYPE_ERASED_H_
-#define ABSL_FLAGS_INTERNAL_TYPE_ERASED_H_
-
-#include <string>
-
-#include "absl/base/config.h"
-#include "absl/flags/internal/commandlineflag.h"
-#include "absl/flags/internal/registry.h"
-#include "absl/strings/string_view.h"
-
-// --------------------------------------------------------------------
-// Registry interfaces operating on type erased handles.
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace flags_internal {
-
-// If a flag named "name" exists, store its current value in *OUTPUT
-// and return true.  Else return false without changing *OUTPUT.
-// Thread-safe.
-bool GetCommandLineOption(absl::string_view name, std::string* value);
-
-// Set the value of the flag named "name" to value.  If successful,
-// returns true.  If not successful (e.g., the flag was not found or
-// the value is not a valid value), returns false.
-// Thread-safe.
-bool SetCommandLineOption(absl::string_view name, absl::string_view value);
-
-bool SetCommandLineOptionWithMode(absl::string_view name,
-                                  absl::string_view value,
-                                  FlagSettingMode set_mode);
-
-//-----------------------------------------------------------------------------
-
-// Returns true iff all of the following conditions are true:
-// (a) "name" names a registered flag
-// (b) "value" can be parsed succesfully according to the type of the flag
-// (c) parsed value passes any validator associated with the flag
-bool IsValidFlagValue(absl::string_view name, absl::string_view value);
-
-//-----------------------------------------------------------------------------
-
-// Returns true iff a flag named "name" was specified on the command line
-// (either directly, or via one of --flagfile or --fromenv or --tryfromenv).
-//
-// Any non-command-line modification of the flag does not affect the
-// result of this function.  So for example, if a flag was passed on
-// the command line but then reset via SET_FLAGS_DEFAULT, this
-// function will still return true.
-bool SpecifiedOnCommandLine(absl::string_view name);
-
-//-----------------------------------------------------------------------------
-
-// If a flag with specified "name" exists and has type T, store
-// its current value in *dst and return true.  Else return false
-// without touching *dst.  T must obey all of the requirements for
-// types passed to DEFINE_FLAG.
-template <typename T>
-inline bool GetByName(absl::string_view name, T* dst) {
-  CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
-  if (!flag) return false;
-
-  if (auto val = flag->Get<T>()) {
-    *dst = *val;
-    return true;
-  }
-
-  return false;
-}
-
-}  // namespace flags_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#endif  // ABSL_FLAGS_INTERNAL_TYPE_ERASED_H_
diff --git a/absl/flags/internal/type_erased_test.cc b/absl/flags/internal/type_erased_test.cc
deleted file mode 100644
index 4ce5981..0000000
--- a/absl/flags/internal/type_erased_test.cc
+++ /dev/null
@@ -1,157 +0,0 @@
-//
-//  Copyright 2019 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/flags/internal/type_erased.h"
-
-#include <memory>
-#include <string>
-
-#include "gtest/gtest.h"
-#include "absl/flags/flag.h"
-#include "absl/flags/internal/commandlineflag.h"
-#include "absl/flags/internal/registry.h"
-#include "absl/flags/marshalling.h"
-#include "absl/memory/memory.h"
-
-ABSL_FLAG(int, int_flag, 1, "int_flag help");
-ABSL_FLAG(std::string, string_flag, "dflt", "string_flag help");
-ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
-
-namespace {
-
-namespace flags = absl::flags_internal;
-
-class TypeErasedTest : public testing::Test {
- protected:
-  void SetUp() override { flag_saver_ = absl::make_unique<flags::FlagSaver>(); }
-  void TearDown() override { flag_saver_.reset(); }
-
- private:
-  std::unique_ptr<flags::FlagSaver> flag_saver_;
-};
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestGetCommandLineOption) {
-  std::string value;
-  EXPECT_TRUE(flags::GetCommandLineOption("int_flag", &value));
-  EXPECT_EQ(value, "1");
-
-  EXPECT_TRUE(flags::GetCommandLineOption("string_flag", &value));
-  EXPECT_EQ(value, "dflt");
-
-  EXPECT_FALSE(flags::GetCommandLineOption("bool_retired_flag", &value));
-
-  EXPECT_FALSE(flags::GetCommandLineOption("unknown_flag", &value));
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestSetCommandLineOption) {
-  EXPECT_TRUE(flags::SetCommandLineOption("int_flag", "101"));
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
-
-  EXPECT_TRUE(flags::SetCommandLineOption("string_flag", "asdfgh"));
-  EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
-
-  EXPECT_FALSE(flags::SetCommandLineOption("bool_retired_flag", "true"));
-
-  EXPECT_FALSE(flags::SetCommandLineOption("unknown_flag", "true"));
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestSetCommandLineOptionWithMode_SET_FLAGS_VALUE) {
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "101",
-                                                  flags::SET_FLAGS_VALUE));
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
-
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("string_flag", "asdfgh",
-                                                  flags::SET_FLAGS_VALUE));
-  EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
-
-  EXPECT_FALSE(flags::SetCommandLineOptionWithMode("bool_retired_flag", "true",
-                                                   flags::SET_FLAGS_VALUE));
-
-  EXPECT_FALSE(flags::SetCommandLineOptionWithMode("unknown_flag", "true",
-                                                   flags::SET_FLAGS_VALUE));
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestSetCommandLineOptionWithMode_SET_FLAG_IF_DEFAULT) {
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "101",
-                                                  flags::SET_FLAG_IF_DEFAULT));
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
-
-  // This semantic is broken. We return true instead of false. Value is not
-  // updated.
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "202",
-                                                  flags::SET_FLAG_IF_DEFAULT));
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
-
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("string_flag", "asdfgh",
-                                                  flags::SET_FLAG_IF_DEFAULT));
-  EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
-
-  EXPECT_FALSE(flags::SetCommandLineOptionWithMode("bool_retired_flag", "true",
-                                                   flags::SET_FLAG_IF_DEFAULT));
-
-  EXPECT_FALSE(flags::SetCommandLineOptionWithMode("unknown_flag", "true",
-                                                   flags::SET_FLAG_IF_DEFAULT));
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestSetCommandLineOptionWithMode_SET_FLAGS_DEFAULT) {
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "101",
-                                                  flags::SET_FLAGS_DEFAULT));
-
-  // Set it again to ensure that resetting logic is covered.
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "102",
-                                                  flags::SET_FLAGS_DEFAULT));
-
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "103",
-                                                  flags::SET_FLAGS_DEFAULT));
-
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("string_flag", "asdfgh",
-                                                  flags::SET_FLAGS_DEFAULT));
-  EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
-
-  EXPECT_FALSE(flags::SetCommandLineOptionWithMode("bool_retired_flag", "true",
-                                                   flags::SET_FLAGS_DEFAULT));
-
-  EXPECT_FALSE(flags::SetCommandLineOptionWithMode("unknown_flag", "true",
-                                                   flags::SET_FLAGS_DEFAULT));
-
-  // This should be successfull, since flag is still is not set
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "202",
-                                                  flags::SET_FLAG_IF_DEFAULT));
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 202);
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestIsValidFlagValue) {
-  EXPECT_TRUE(flags::IsValidFlagValue("int_flag", "57"));
-  EXPECT_TRUE(flags::IsValidFlagValue("int_flag", "-101"));
-  EXPECT_FALSE(flags::IsValidFlagValue("int_flag", "1.1"));
-
-  EXPECT_TRUE(flags::IsValidFlagValue("string_flag", "#%^#%^$%DGHDG$W%adsf"));
-
-  EXPECT_TRUE(flags::IsValidFlagValue("bool_retired_flag", "true"));
-}
-
-}  // namespace
diff --git a/absl/flags/internal/usage.cc b/absl/flags/internal/usage.cc
index ff90716..a588c7f 100644
--- a/absl/flags/internal/usage.cc
+++ b/absl/flags/internal/usage.cc
@@ -15,6 +15,8 @@
 
 #include "absl/flags/internal/usage.h"
 
+#include <stdint.h>
+
 #include <functional>
 #include <map>
 #include <ostream>
@@ -23,10 +25,11 @@
 #include <vector>
 
 #include "absl/base/config.h"
+#include "absl/flags/commandlineflag.h"
 #include "absl/flags/flag.h"
-#include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/flag.h"
 #include "absl/flags/internal/path_util.h"
+#include "absl/flags/internal/private_handle_accessor.h"
 #include "absl/flags/internal/program_name.h"
 #include "absl/flags/internal/registry.h"
 #include "absl/flags/usage_config.h"
@@ -34,46 +37,25 @@
 #include "absl/strings/str_split.h"
 #include "absl/strings/string_view.h"
 
-ABSL_FLAG(bool, help, false,
-          "show help on important flags for this binary [tip: all flags can "
-          "have two dashes]");
-ABSL_FLAG(bool, helpfull, false, "show help on all flags");
-ABSL_FLAG(bool, helpshort, false,
-          "show help on only the main module for this program");
-ABSL_FLAG(bool, helppackage, false,
-          "show help on all modules in the main package");
-ABSL_FLAG(bool, version, false, "show version and build info and exit");
-ABSL_FLAG(bool, only_check_args, false, "exit after checking all flags");
-ABSL_FLAG(std::string, helpon, "",
-          "show help on the modules named by this flag value");
-ABSL_FLAG(std::string, helpmatch, "",
-          "show help on modules whose name contains the specified substr");
+// Dummy global variables to prevent anyone else defining these.
+bool FLAGS_help = false;
+bool FLAGS_helpfull = false;
+bool FLAGS_helpshort = false;
+bool FLAGS_helppackage = false;
+bool FLAGS_version = false;
+bool FLAGS_only_check_args = false;
+bool FLAGS_helpon = false;
+bool FLAGS_helpmatch = false;
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace flags_internal {
 namespace {
 
-absl::string_view TypenameForHelp(const flags_internal::CommandLineFlag& flag) {
-  // Only report names of v1 built-in types
-#define HANDLE_V1_BUILTIN_TYPE(t) \
-  if (flag.IsOfType<t>()) {       \
-    return #t;                    \
-  }
+using PerFlagFilter = std::function<bool(const absl::CommandLineFlag&)>;
 
-  HANDLE_V1_BUILTIN_TYPE(bool);
-  HANDLE_V1_BUILTIN_TYPE(int32_t);
-  HANDLE_V1_BUILTIN_TYPE(int64_t);
-  HANDLE_V1_BUILTIN_TYPE(uint64_t);
-  HANDLE_V1_BUILTIN_TYPE(double);
-#undef HANDLE_V1_BUILTIN_TYPE
-
-  if (flag.IsOfType<std::string>()) {
-    return "string";
-  }
-
-  return "";
-}
+// Maximum length size in a human readable format.
+constexpr size_t kHrfMaxLineLength = 80;
 
 // This class is used to emit an XML element with `tag` and `text`.
 // It adds opening and closing tags and escapes special characters in the text.
@@ -127,21 +109,24 @@
  public:
   // Pretty printer holds on to the std::ostream& reference to direct an output
   // to that stream.
-  FlagHelpPrettyPrinter(int max_line_len, std::ostream* out)
-      : out_(*out),
+  FlagHelpPrettyPrinter(size_t max_line_len, size_t min_line_len,
+                        size_t wrapped_line_indent, std::ostream& out)
+      : out_(out),
         max_line_len_(max_line_len),
+        min_line_len_(min_line_len),
+        wrapped_line_indent_(wrapped_line_indent),
         line_len_(0),
         first_line_(true) {}
 
   void Write(absl::string_view str, bool wrap_line = false) {
-    // Empty std::string - do nothing.
+    // Empty string - do nothing.
     if (str.empty()) return;
 
     std::vector<absl::string_view> tokens;
     if (wrap_line) {
       for (auto line : absl::StrSplit(str, absl::ByAnyChar("\n\r"))) {
         if (!tokens.empty()) {
-          // Keep line separators in the input std::string.
+          // Keep line separators in the input string.
           tokens.push_back("\n");
         }
         for (auto token :
@@ -156,14 +141,15 @@
     for (auto token : tokens) {
       bool new_line = (line_len_ == 0);
 
-      // Respect line separators in the input std::string.
+      // Respect line separators in the input string.
       if (token == "\n") {
         EndLine();
         continue;
       }
 
-      // Write the token, ending the std::string first if necessary/possible.
-      if (!new_line && (line_len_ + token.size() >= max_line_len_)) {
+      // Write the token, ending the string first if necessary/possible.
+      if (!new_line &&
+          (line_len_ + static_cast<int>(token.size()) >= max_line_len_)) {
         EndLine();
         new_line = true;
       }
@@ -182,13 +168,12 @@
 
   void StartLine() {
     if (first_line_) {
-      out_ << "    ";
-      line_len_ = 4;
+      line_len_ = min_line_len_;
       first_line_ = false;
     } else {
-      out_ << "      ";
-      line_len_ = 6;
+      line_len_ = min_line_len_ + wrapped_line_indent_;
     }
+    out_ << std::string(line_len_, ' ');
   }
   void EndLine() {
     out_ << '\n';
@@ -197,14 +182,15 @@
 
  private:
   std::ostream& out_;
-  const int max_line_len_;
-  int line_len_;
+  const size_t max_line_len_;
+  const size_t min_line_len_;
+  const size_t wrapped_line_indent_;
+  size_t line_len_;
   bool first_line_;
 };
 
-void FlagHelpHumanReadable(const flags_internal::CommandLineFlag& flag,
-                           std::ostream* out) {
-  FlagHelpPrettyPrinter printer(80, out);  // Max line length is 80.
+void FlagHelpHumanReadable(const CommandLineFlag& flag, std::ostream& out) {
+  FlagHelpPrettyPrinter printer(kHrfMaxLineLength, 4, 2, out);
 
   // Flag name.
   printer.Write(absl::StrCat("--", flag.Name()));
@@ -212,23 +198,20 @@
   // Flag help.
   printer.Write(absl::StrCat("(", flag.Help(), ");"), /*wrap_line=*/true);
 
-  // Flag data type (for V1 flags only).
-  if (!flag.IsAbseilFlag() && !flag.IsRetired()) {
-    printer.Write(absl::StrCat("type: ", TypenameForHelp(flag), ";"));
-  }
-
   // The listed default value will be the actual default from the flag
   // definition in the originating source file, unless the value has
   // subsequently been modified using SetCommandLineOption() with mode
   // SET_FLAGS_DEFAULT.
   std::string dflt_val = flag.DefaultValue();
+  std::string curr_val = flag.CurrentValue();
+  bool is_modified = curr_val != dflt_val;
+
   if (flag.IsOfType<std::string>()) {
     dflt_val = absl::StrCat("\"", dflt_val, "\"");
   }
   printer.Write(absl::StrCat("default: ", dflt_val, ";"));
 
-  if (flag.IsModified()) {
-    std::string curr_val = flag.CurrentValue();
+  if (is_modified) {
     if (flag.IsOfType<std::string>()) {
       curr_val = absl::StrCat("\"", curr_val, "\"");
     }
@@ -243,7 +226,7 @@
 // If a flag's help message has been stripped (e.g. by adding '#define
 // STRIP_FLAG_HELP 1' then this flag will not be displayed by '--help'
 // and its variants.
-void FlagsHelpImpl(std::ostream& out, flags_internal::FlagKindFilter filter_cb,
+void FlagsHelpImpl(std::ostream& out, PerFlagFilter filter_cb,
                    HelpFormat format, absl::string_view program_usage_message) {
   if (format == HelpFormat::kHumanReadable) {
     out << flags_internal::ShortProgramInvocationName() << ": "
@@ -268,30 +251,28 @@
   // This map is used to output matching flags grouped by package and file
   // name.
   std::map<std::string,
-           std::map<std::string,
-                    std::vector<const flags_internal::CommandLineFlag*>>>
+           std::map<std::string, std::vector<const absl::CommandLineFlag*>>>
       matching_flags;
 
-  flags_internal::ForEachFlag([&](flags_internal::CommandLineFlag* flag) {
-    std::string flag_filename = flag->Filename();
-
+  flags_internal::ForEachFlag([&](absl::CommandLineFlag& flag) {
     // Ignore retired flags.
-    if (flag->IsRetired()) return;
+    if (flag.IsRetired()) return;
 
     // If the flag has been stripped, pretend that it doesn't exist.
-    if (flag->Help() == flags_internal::kStrippedFlagHelp) return;
+    if (flag.Help() == flags_internal::kStrippedFlagHelp) return;
 
     // Make sure flag satisfies the filter
-    if (!filter_cb || !filter_cb(flag_filename)) return;
+    if (!filter_cb(flag)) return;
+
+    std::string flag_filename = flag.Filename();
 
     matching_flags[std::string(flags_internal::Package(flag_filename))]
                   [flag_filename]
-                      .push_back(flag);
+                      .push_back(&flag);
   });
 
-  absl::string_view
-      package_separator;             // controls blank lines between packages.
-  absl::string_view file_separator;  // controls blank lines between files.
+  absl::string_view package_separator;  // controls blank lines between packages
+  absl::string_view file_separator;     // controls blank lines between files
   for (const auto& package : matching_flags) {
     if (format == HelpFormat::kHumanReadable) {
       out << package_separator;
@@ -313,27 +294,46 @@
   }
 
   if (format == HelpFormat::kHumanReadable) {
+    FlagHelpPrettyPrinter printer(kHrfMaxLineLength, 0, 0, out);
+
     if (filter_cb && matching_flags.empty()) {
-      out << "  No modules matched: use -helpfull\n";
+      printer.Write("No flags matched.\n", true);
     }
+    printer.EndLine();
+    printer.Write(
+        "Try --helpfull to get a list of all flags or --help=substring "
+        "shows help for flags which include specified substring in either "
+        "in the name, or description or path.\n",
+        true);
   } else {
     // The end of the document.
     out << "</AllFlags>\n";
   }
 }
 
+void FlagsHelpImpl(std::ostream& out,
+                   flags_internal::FlagKindFilter filename_filter_cb,
+                   HelpFormat format, absl::string_view program_usage_message) {
+  FlagsHelpImpl(
+      out,
+      [&](const absl::CommandLineFlag& flag) {
+        return filename_filter_cb && filename_filter_cb(flag.Filename());
+      },
+      format, program_usage_message);
+}
+
 }  // namespace
 
 // --------------------------------------------------------------------
 // Produces the help message describing specific flag.
-void FlagHelp(std::ostream& out, const flags_internal::CommandLineFlag& flag,
+void FlagHelp(std::ostream& out, const CommandLineFlag& flag,
               HelpFormat format) {
   if (format == HelpFormat::kHumanReadable)
-    flags_internal::FlagHelpHumanReadable(flag, &out);
+    flags_internal::FlagHelpHumanReadable(flag, out);
 }
 
 // --------------------------------------------------------------------
-// Produces the help messages for all flags matching the filter.
+// Produces the help messages for all flags matching the filename filter.
 // If filter is empty produces help messages for all flags.
 void FlagsHelp(std::ostream& out, absl::string_view filter, HelpFormat format,
                absl::string_view program_usage_message) {
@@ -348,68 +348,171 @@
 // If so, handles them appropriately.
 int HandleUsageFlags(std::ostream& out,
                      absl::string_view program_usage_message) {
-  if (absl::GetFlag(FLAGS_helpshort)) {
-    flags_internal::FlagsHelpImpl(
-        out, flags_internal::GetUsageConfig().contains_helpshort_flags,
-        HelpFormat::kHumanReadable, program_usage_message);
-    return 1;
-  }
+  switch (GetFlagsHelpMode()) {
+    case HelpMode::kNone:
+      break;
+    case HelpMode::kImportant:
+      flags_internal::FlagsHelpImpl(
+          out, flags_internal::GetUsageConfig().contains_help_flags,
+          GetFlagsHelpFormat(), program_usage_message);
+      return 1;
 
-  if (absl::GetFlag(FLAGS_helpfull)) {
-    // show all options
-    flags_internal::FlagsHelp(out, "", HelpFormat::kHumanReadable,
-                              program_usage_message);
-    return 1;
-  }
+    case HelpMode::kShort:
+      flags_internal::FlagsHelpImpl(
+          out, flags_internal::GetUsageConfig().contains_helpshort_flags,
+          GetFlagsHelpFormat(), program_usage_message);
+      return 1;
 
-  if (!absl::GetFlag(FLAGS_helpon).empty()) {
-    flags_internal::FlagsHelp(
-        out, absl::StrCat("/", absl::GetFlag(FLAGS_helpon), "."),
-        HelpFormat::kHumanReadable, program_usage_message);
-    return 1;
-  }
+    case HelpMode::kFull:
+      flags_internal::FlagsHelp(out, "", GetFlagsHelpFormat(),
+                                program_usage_message);
+      return 1;
 
-  if (!absl::GetFlag(FLAGS_helpmatch).empty()) {
-    flags_internal::FlagsHelp(out, absl::GetFlag(FLAGS_helpmatch),
-                              HelpFormat::kHumanReadable,
-                              program_usage_message);
-    return 1;
-  }
+    case HelpMode::kPackage:
+      flags_internal::FlagsHelpImpl(
+          out, flags_internal::GetUsageConfig().contains_helppackage_flags,
+          GetFlagsHelpFormat(), program_usage_message);
 
-  if (absl::GetFlag(FLAGS_help)) {
-    flags_internal::FlagsHelpImpl(
-        out, flags_internal::GetUsageConfig().contains_help_flags,
-        HelpFormat::kHumanReadable, program_usage_message);
+      return 1;
 
-    out << "\nTry --helpfull to get a list of all flags.\n";
+    case HelpMode::kMatch: {
+      std::string substr = GetFlagsHelpMatchSubstr();
+      if (substr.empty()) {
+        // show all options
+        flags_internal::FlagsHelp(out, substr, GetFlagsHelpFormat(),
+                                  program_usage_message);
+      } else {
+        auto filter_cb = [&substr](const absl::CommandLineFlag& flag) {
+          if (absl::StrContains(flag.Name(), substr)) return true;
+          if (absl::StrContains(flag.Filename(), substr)) return true;
+          if (absl::StrContains(flag.Help(), substr)) return true;
 
-    return 1;
-  }
+          return false;
+        };
+        flags_internal::FlagsHelpImpl(
+            out, filter_cb, HelpFormat::kHumanReadable, program_usage_message);
+      }
 
-  if (absl::GetFlag(FLAGS_helppackage)) {
-    flags_internal::FlagsHelpImpl(
-        out, flags_internal::GetUsageConfig().contains_helppackage_flags,
-        HelpFormat::kHumanReadable, program_usage_message);
+      return 1;
+    }
+    case HelpMode::kVersion:
+      if (flags_internal::GetUsageConfig().version_string)
+        out << flags_internal::GetUsageConfig().version_string();
+      // Unlike help, we may be asking for version in a script, so return 0
+      return 0;
 
-    out << "\nTry --helpfull to get a list of all flags.\n";
-
-    return 1;
-  }
-
-  if (absl::GetFlag(FLAGS_version)) {
-    if (flags_internal::GetUsageConfig().version_string)
-      out << flags_internal::GetUsageConfig().version_string();
-    // Unlike help, we may be asking for version in a script, so return 0
-    return 0;
-  }
-
-  if (absl::GetFlag(FLAGS_only_check_args)) {
-    return 0;
+    case HelpMode::kOnlyCheckArgs:
+      return 0;
   }
 
   return -1;
 }
 
+// --------------------------------------------------------------------
+// Globals representing usage reporting flags
+
+namespace {
+
+ABSL_CONST_INIT absl::Mutex help_attributes_guard(absl::kConstInit);
+ABSL_CONST_INIT std::string* match_substr
+    ABSL_GUARDED_BY(help_attributes_guard) = nullptr;
+ABSL_CONST_INIT HelpMode help_mode ABSL_GUARDED_BY(help_attributes_guard) =
+    HelpMode::kNone;
+ABSL_CONST_INIT HelpFormat help_format ABSL_GUARDED_BY(help_attributes_guard) =
+    HelpFormat::kHumanReadable;
+
+}  // namespace
+
+std::string GetFlagsHelpMatchSubstr() {
+  absl::MutexLock l(&help_attributes_guard);
+  if (match_substr == nullptr) return "";
+  return *match_substr;
+}
+
+void SetFlagsHelpMatchSubstr(absl::string_view substr) {
+  absl::MutexLock l(&help_attributes_guard);
+  if (match_substr == nullptr) match_substr = new std::string;
+  match_substr->assign(substr.data(), substr.size());
+}
+
+HelpMode GetFlagsHelpMode() {
+  absl::MutexLock l(&help_attributes_guard);
+  return help_mode;
+}
+
+void SetFlagsHelpMode(HelpMode mode) {
+  absl::MutexLock l(&help_attributes_guard);
+  help_mode = mode;
+}
+
+HelpFormat GetFlagsHelpFormat() {
+  absl::MutexLock l(&help_attributes_guard);
+  return help_format;
+}
+
+void SetFlagsHelpFormat(HelpFormat format) {
+  absl::MutexLock l(&help_attributes_guard);
+  help_format = format;
+}
+
+// Deduces usage flags from the input argument in a form --name=value or
+// --name. argument is already split into name and value before we call this
+// function.
+bool DeduceUsageFlags(absl::string_view name, absl::string_view value) {
+  if (absl::ConsumePrefix(&name, "help")) {
+    if (name == "") {
+      if (value.empty()) {
+        SetFlagsHelpMode(HelpMode::kImportant);
+      } else {
+        SetFlagsHelpMode(HelpMode::kMatch);
+        SetFlagsHelpMatchSubstr(value);
+      }
+      return true;
+    }
+
+    if (name == "match") {
+      SetFlagsHelpMode(HelpMode::kMatch);
+      SetFlagsHelpMatchSubstr(value);
+      return true;
+    }
+
+    if (name == "on") {
+      SetFlagsHelpMode(HelpMode::kMatch);
+      SetFlagsHelpMatchSubstr(absl::StrCat("/", value, "."));
+      return true;
+    }
+
+    if (name == "full") {
+      SetFlagsHelpMode(HelpMode::kFull);
+      return true;
+    }
+
+    if (name == "short") {
+      SetFlagsHelpMode(HelpMode::kShort);
+      return true;
+    }
+
+    if (name == "package") {
+      SetFlagsHelpMode(HelpMode::kPackage);
+      return true;
+    }
+
+    return false;
+  }
+
+  if (name == "version") {
+    SetFlagsHelpMode(HelpMode::kVersion);
+    return true;
+  }
+
+  if (name == "only_check_args") {
+    SetFlagsHelpMode(HelpMode::kOnlyCheckArgs);
+    return true;
+  }
+
+  return false;
+}
+
 }  // namespace flags_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/flags/internal/usage.h b/absl/flags/internal/usage.h
index 6b080fd..c0bcac5 100644
--- a/absl/flags/internal/usage.h
+++ b/absl/flags/internal/usage.h
@@ -20,8 +20,8 @@
 #include <string>
 
 #include "absl/base/config.h"
+#include "absl/flags/commandlineflag.h"
 #include "absl/flags/declare.h"
-#include "absl/flags/internal/commandlineflag.h"
 #include "absl/strings/string_view.h"
 
 // --------------------------------------------------------------------
@@ -36,8 +36,9 @@
   kHumanReadable,
 };
 
-// Outputs the help message describing specific flag.
-void FlagHelp(std::ostream& out, const flags_internal::CommandLineFlag& flag,
+// Streams the help message describing `flag` to `out`.
+// The default value for `flag` is included in the output.
+void FlagHelp(std::ostream& out, const CommandLineFlag& flag,
               HelpFormat format = HelpFormat::kHumanReadable);
 
 // Produces the help messages for all flags matching the filter. A flag matches
@@ -65,17 +66,39 @@
 int HandleUsageFlags(std::ostream& out,
                      absl::string_view program_usage_message);
 
+// --------------------------------------------------------------------
+// Globals representing usage reporting flags
+
+enum class HelpMode {
+  kNone,
+  kImportant,
+  kShort,
+  kFull,
+  kPackage,
+  kMatch,
+  kVersion,
+  kOnlyCheckArgs
+};
+
+// Returns substring to filter help output (--help=substr argument)
+std::string GetFlagsHelpMatchSubstr();
+// Returns the requested help mode.
+HelpMode GetFlagsHelpMode();
+// Returns the requested help format.
+HelpFormat GetFlagsHelpFormat();
+
+// These are corresponding setters to the attributes above.
+void SetFlagsHelpMatchSubstr(absl::string_view);
+void SetFlagsHelpMode(HelpMode);
+void SetFlagsHelpFormat(HelpFormat);
+
+// Deduces usage flags from the input argument in a form --name=value or
+// --name. argument is already split into name and value before we call this
+// function.
+bool DeduceUsageFlags(absl::string_view name, absl::string_view value);
+
 }  // namespace flags_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
 
-ABSL_DECLARE_FLAG(bool, help);
-ABSL_DECLARE_FLAG(bool, helpfull);
-ABSL_DECLARE_FLAG(bool, helpshort);
-ABSL_DECLARE_FLAG(bool, helppackage);
-ABSL_DECLARE_FLAG(bool, version);
-ABSL_DECLARE_FLAG(bool, only_check_args);
-ABSL_DECLARE_FLAG(std::string, helpon);
-ABSL_DECLARE_FLAG(std::string, helpmatch);
-
 #endif  // ABSL_FLAGS_INTERNAL_USAGE_H_
diff --git a/absl/flags/internal/usage_test.cc b/absl/flags/internal/usage_test.cc
index e1e57e5..b5c2487 100644
--- a/absl/flags/internal/usage_test.cc
+++ b/absl/flags/internal/usage_test.cc
@@ -21,15 +21,13 @@
 #include <string>
 
 #include "gtest/gtest.h"
-#include "absl/flags/declare.h"
 #include "absl/flags/flag.h"
 #include "absl/flags/internal/parse.h"
 #include "absl/flags/internal/path_util.h"
 #include "absl/flags/internal/program_name.h"
-#include "absl/flags/internal/registry.h"
+#include "absl/flags/reflection.h"
 #include "absl/flags/usage.h"
 #include "absl/flags/usage_config.h"
-#include "absl/memory/memory.h"
 #include "absl/strings/match.h"
 #include "absl/strings/string_view.h"
 
@@ -89,9 +87,14 @@
     default_config.normalize_filename = &NormalizeFileName;
     absl::SetFlagsUsageConfig(default_config);
   }
+  ~UsageReportingTest() override {
+    flags::SetFlagsHelpMode(flags::HelpMode::kNone);
+    flags::SetFlagsHelpMatchSubstr("");
+    flags::SetFlagsHelpFormat(flags::HelpFormat::kHumanReadable);
+  }
 
  private:
-  flags::FlagSaver flag_saver_;
+  absl::FlagSaver flag_saver_;
 };
 
 // --------------------------------------------------------------------
@@ -103,15 +106,16 @@
 
 #ifndef _WIN32
   // TODO(rogeeff): figure out why this does not work on Windows.
-  EXPECT_DEATH(absl::SetProgramUsageMessage("custom usage message"),
-               ".*SetProgramUsageMessage\\(\\) called twice.*");
+  EXPECT_DEATH_IF_SUPPORTED(
+      absl::SetProgramUsageMessage("custom usage message"),
+      ".*SetProgramUsageMessage\\(\\) called twice.*");
 #endif
 }
 
 // --------------------------------------------------------------------
 
 TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_01) {
-  const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_01");
+  const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_01");
   std::stringstream test_buf;
 
   flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
@@ -123,7 +127,7 @@
 }
 
 TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_02) {
-  const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_02");
+  const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_02");
   std::stringstream test_buf;
 
   flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
@@ -135,7 +139,7 @@
 }
 
 TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_03) {
-  const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_03");
+  const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_03");
   std::stringstream test_buf;
 
   flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
@@ -147,7 +151,7 @@
 }
 
 TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_04) {
-  const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_04");
+  const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_04");
   std::stringstream test_buf;
 
   flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
@@ -159,7 +163,7 @@
 }
 
 TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_05) {
-  const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_05");
+  const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_05");
   std::stringstream test_buf;
 
   flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
@@ -192,6 +196,10 @@
       Some more help.
       Even more long long long long long long long long long long long long help
       message.); default: "";
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
 )";
 
   std::stringstream test_buf_01;
@@ -215,7 +223,11 @@
   EXPECT_EQ(test_buf_04.str(),
             R"(usage_test: Custom usage message
 
-  No modules matched: use -helpfull
+No flags matched.
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
 )");
 
   std::stringstream test_buf_05;
@@ -227,12 +239,8 @@
       absl::StartsWith(test_out_str, "usage_test: Custom usage message"));
   EXPECT_TRUE(absl::StrContains(
       test_out_str, "Flags from absl/flags/internal/usage_test.cc:"));
-  EXPECT_TRUE(absl::StrContains(test_out_str,
-                                "Flags from absl/flags/internal/usage.cc:"));
   EXPECT_TRUE(
       absl::StrContains(test_out_str, "-usage_reporting_test_flag_01 "));
-  EXPECT_TRUE(absl::StrContains(test_out_str, "-help (show help"))
-      << test_out_str;
 }
 
 // --------------------------------------------------------------------
@@ -245,7 +253,7 @@
 // --------------------------------------------------------------------
 
 TEST_F(UsageReportingTest, TestUsageFlag_helpshort) {
-  absl::SetFlag(&FLAGS_helpshort, true);
+  flags::SetFlagsHelpMode(flags::HelpMode::kShort);
 
   std::stringstream test_buf;
   EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
@@ -268,13 +276,17 @@
       Some more help.
       Even more long long long long long long long long long long long long help
       message.); default: "";
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
 )");
 }
 
 // --------------------------------------------------------------------
 
-TEST_F(UsageReportingTest, TestUsageFlag_help) {
-  absl::SetFlag(&FLAGS_help, true);
+TEST_F(UsageReportingTest, TestUsageFlag_help_simple) {
+  flags::SetFlagsHelpMode(flags::HelpMode::kImportant);
 
   std::stringstream test_buf;
   EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
@@ -298,14 +310,74 @@
       Even more long long long long long long long long long long long long help
       message.); default: "";
 
-Try --helpfull to get a list of all flags.
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
+)");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(UsageReportingTest, TestUsageFlag_help_one_flag) {
+  flags::SetFlagsHelpMode(flags::HelpMode::kMatch);
+  flags::SetFlagsHelpMatchSubstr("usage_reporting_test_flag_06");
+
+  std::stringstream test_buf;
+  EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
+  EXPECT_EQ(test_buf.str(),
+            R"(usage_test: Custom usage message
+
+  Flags from absl/flags/internal/usage_test.cc:
+    --usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
+
+      Some more help.
+      Even more long long long long long long long long long long long long help
+      message.); default: "";
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
+)");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(UsageReportingTest, TestUsageFlag_help_multiple_flag) {
+  flags::SetFlagsHelpMode(flags::HelpMode::kMatch);
+  flags::SetFlagsHelpMatchSubstr("test_flag");
+
+  std::stringstream test_buf;
+  EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
+  EXPECT_EQ(test_buf.str(),
+            R"(usage_test: Custom usage message
+
+  Flags from absl/flags/internal/usage_test.cc:
+    --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
+      default: 101;
+    --usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
+      default: false;
+    --usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
+      default: 1.03;
+    --usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
+      default: 1000000000000004;
+    --usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
+      default: UDT{};
+    --usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
+
+      Some more help.
+      Even more long long long long long long long long long long long long help
+      message.); default: "";
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
 )");
 }
 
 // --------------------------------------------------------------------
 
 TEST_F(UsageReportingTest, TestUsageFlag_helppackage) {
-  absl::SetFlag(&FLAGS_helppackage, true);
+  flags::SetFlagsHelpMode(flags::HelpMode::kPackage);
 
   std::stringstream test_buf;
   EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
@@ -329,14 +401,16 @@
       Even more long long long long long long long long long long long long help
       message.); default: "";
 
-Try --helpfull to get a list of all flags.
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
 )");
 }
 
 // --------------------------------------------------------------------
 
 TEST_F(UsageReportingTest, TestUsageFlag_version) {
-  absl::SetFlag(&FLAGS_version, true);
+  flags::SetFlagsHelpMode(flags::HelpMode::kVersion);
 
   std::stringstream test_buf;
   EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 0);
@@ -350,7 +424,7 @@
 // --------------------------------------------------------------------
 
 TEST_F(UsageReportingTest, TestUsageFlag_only_check_args) {
-  absl::SetFlag(&FLAGS_only_check_args, true);
+  flags::SetFlagsHelpMode(flags::HelpMode::kOnlyCheckArgs);
 
   std::stringstream test_buf;
   EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 0);
@@ -360,17 +434,22 @@
 // --------------------------------------------------------------------
 
 TEST_F(UsageReportingTest, TestUsageFlag_helpon) {
-  absl::SetFlag(&FLAGS_helpon, "bla-bla");
+  flags::SetFlagsHelpMode(flags::HelpMode::kMatch);
+  flags::SetFlagsHelpMatchSubstr("/bla-bla.");
 
   std::stringstream test_buf_01;
   EXPECT_EQ(flags::HandleUsageFlags(test_buf_01, kTestUsageMessage), 1);
   EXPECT_EQ(test_buf_01.str(),
             R"(usage_test: Custom usage message
 
-  No modules matched: use -helpfull
+No flags matched.
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
 )");
 
-  absl::SetFlag(&FLAGS_helpon, "usage_test");
+  flags::SetFlagsHelpMatchSubstr("/usage_test.");
 
   std::stringstream test_buf_02;
   EXPECT_EQ(flags::HandleUsageFlags(test_buf_02, kTestUsageMessage), 1);
@@ -393,6 +472,10 @@
       Some more help.
       Even more long long long long long long long long long long long long help
       message.); default: "";
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
 )");
 }
 
diff --git a/absl/flags/marshalling.cc b/absl/flags/marshalling.cc
index 6f2ddda..81f9ceb 100644
--- a/absl/flags/marshalling.cc
+++ b/absl/flags/marshalling.cc
@@ -74,15 +74,16 @@
 }
 
 template <typename IntType>
-inline bool ParseFlagImpl(absl::string_view text, IntType* dst) {
+inline bool ParseFlagImpl(absl::string_view text, IntType& dst) {
   text = absl::StripAsciiWhitespace(text);
 
-  return absl::numbers_internal::safe_strtoi_base(text, dst, NumericBase(text));
+  return absl::numbers_internal::safe_strtoi_base(text, &dst,
+                                                  NumericBase(text));
 }
 
 bool AbslParseFlag(absl::string_view text, short* dst, std::string*) {
   int val;
-  if (!ParseFlagImpl(text, &val)) return false;
+  if (!ParseFlagImpl(text, val)) return false;
   if (static_cast<short>(val) != val)  // worked, but number out of range
     return false;
   *dst = static_cast<short>(val);
@@ -91,7 +92,7 @@
 
 bool AbslParseFlag(absl::string_view text, unsigned short* dst, std::string*) {
   unsigned int val;
-  if (!ParseFlagImpl(text, &val)) return false;
+  if (!ParseFlagImpl(text, val)) return false;
   if (static_cast<unsigned short>(val) !=
       val)  // worked, but number out of range
     return false;
@@ -100,28 +101,28 @@
 }
 
 bool AbslParseFlag(absl::string_view text, int* dst, std::string*) {
-  return ParseFlagImpl(text, dst);
+  return ParseFlagImpl(text, *dst);
 }
 
 bool AbslParseFlag(absl::string_view text, unsigned int* dst, std::string*) {
-  return ParseFlagImpl(text, dst);
+  return ParseFlagImpl(text, *dst);
 }
 
 bool AbslParseFlag(absl::string_view text, long* dst, std::string*) {
-  return ParseFlagImpl(text, dst);
+  return ParseFlagImpl(text, *dst);
 }
 
 bool AbslParseFlag(absl::string_view text, unsigned long* dst, std::string*) {
-  return ParseFlagImpl(text, dst);
+  return ParseFlagImpl(text, *dst);
 }
 
 bool AbslParseFlag(absl::string_view text, long long* dst, std::string*) {
-  return ParseFlagImpl(text, dst);
+  return ParseFlagImpl(text, *dst);
 }
 
 bool AbslParseFlag(absl::string_view text, unsigned long long* dst,
                    std::string*) {
-  return ParseFlagImpl(text, dst);
+  return ParseFlagImpl(text, *dst);
 }
 
 // --------------------------------------------------------------------
@@ -172,7 +173,7 @@
 std::string Unparse(unsigned long long v) { return absl::StrCat(v); }
 template <typename T>
 std::string UnparseFloatingPointVal(T v) {
-  // digits10 is guaranteed to roundtrip correctly in std::string -> value -> std::string
+  // digits10 is guaranteed to roundtrip correctly in string -> value -> string
   // conversions, but may not be enough to represent all the values correctly.
   std::string digit10_str =
       absl::StrFormat("%.*g", std::numeric_limits<T>::digits10, v);
diff --git a/absl/flags/marshalling.h b/absl/flags/marshalling.h
index 0b50335..7cbc136 100644
--- a/absl/flags/marshalling.h
+++ b/absl/flags/marshalling.h
@@ -83,7 +83,7 @@
 //   // AbslParseFlag converts from a string to OutputMode.
 //   // Must be in same namespace as OutputMode.
 //
-//   // Parses an OutputMode from the command line flag value `text. Returns
+//   // Parses an OutputMode from the command line flag value `text`. Returns
 //   // `true` and sets `*mode` on success; returns `false` and sets `*error`
 //   // on failure.
 //   bool AbslParseFlag(absl::string_view text,
@@ -139,7 +139,7 @@
 //
 //   // Within the implementation, `AbslParseFlag()` will, in turn invoke
 //   // `absl::ParseFlag()` on its constituent `int` and `std::string` types
-//   // (which have built-in Abseil flag support.
+//   // (which have built-in Abseil flag support).
 //
 //   bool AbslParseFlag(absl::string_view text, MyFlagType* flag,
 //                      std::string* err) {
diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc
index 812e498..dd1a679 100644
--- a/absl/flags/parse.cc
+++ b/absl/flags/parse.cc
@@ -34,14 +34,16 @@
 #include "absl/base/config.h"
 #include "absl/base/const_init.h"
 #include "absl/base/thread_annotations.h"
+#include "absl/flags/commandlineflag.h"
 #include "absl/flags/config.h"
 #include "absl/flags/flag.h"
 #include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/flag.h"
 #include "absl/flags/internal/parse.h"
+#include "absl/flags/internal/private_handle_accessor.h"
 #include "absl/flags/internal/program_name.h"
-#include "absl/flags/internal/registry.h"
 #include "absl/flags/internal/usage.h"
+#include "absl/flags/reflection.h"
 #include "absl/flags/usage.h"
 #include "absl/flags/usage_config.h"
 #include "absl/strings/ascii.h"
@@ -66,6 +68,22 @@
 ABSL_CONST_INIT bool tryfromenv_needs_processing
     ABSL_GUARDED_BY(processing_checks_guard) = false;
 
+ABSL_CONST_INIT absl::Mutex specified_flags_guard(absl::kConstInit);
+ABSL_CONST_INIT std::vector<const CommandLineFlag*>* specified_flags
+    ABSL_GUARDED_BY(specified_flags_guard) = nullptr;
+
+struct SpecifiedFlagsCompare {
+  bool operator()(const CommandLineFlag* a, const CommandLineFlag* b) const {
+    return a->Name() < b->Name();
+  }
+  bool operator()(const CommandLineFlag* a, absl::string_view b) const {
+    return a->Name() < b;
+  }
+  bool operator()(absl::string_view a, const CommandLineFlag* b) const {
+    return a < b->Name();
+  }
+};
+
 }  // namespace
 }  // namespace flags_internal
 ABSL_NAMESPACE_END
@@ -205,7 +223,7 @@
 // Reads the environment variable with name `name` and stores results in
 // `value`. If variable is not present in environment returns false, otherwise
 // returns true.
-bool GetEnvVar(const char* var_name, std::string* var_value) {
+bool GetEnvVar(const char* var_name, std::string& var_value) {
 #ifdef _WIN32
   char buf[1024];
   auto get_res = GetEnvironmentVariableA(var_name, buf, sizeof(buf));
@@ -217,14 +235,14 @@
     return false;
   }
 
-  *var_value = std::string(buf, get_res);
+  var_value = std::string(buf, get_res);
 #else
   const char* val = ::getenv(var_name);
   if (val == nullptr) {
     return false;
   }
 
-  *var_value = val;
+  var_value = val;
 #endif
 
   return true;
@@ -272,11 +290,11 @@
 //  found flag or nullptr
 //  is negative in case of --nofoo
 std::tuple<CommandLineFlag*, bool> LocateFlag(absl::string_view flag_name) {
-  CommandLineFlag* flag = flags_internal::FindCommandLineFlag(flag_name);
+  CommandLineFlag* flag = absl::FindCommandLineFlag(flag_name);
   bool is_negative = false;
 
   if (!flag && absl::ConsumePrefix(&flag_name, "no")) {
-    flag = flags_internal::FindCommandLineFlag(flag_name);
+    flag = absl::FindCommandLineFlag(flag_name);
     is_negative = true;
   }
 
@@ -289,16 +307,17 @@
 // back.
 void CheckDefaultValuesParsingRoundtrip() {
 #ifndef NDEBUG
-  flags_internal::ForEachFlag([&](CommandLineFlag* flag) {
-    if (flag->IsRetired()) return;
+  flags_internal::ForEachFlag([&](CommandLineFlag& flag) {
+    if (flag.IsRetired()) return;
 
-#define IGNORE_TYPE(T) \
-  if (flag->IsOfType<T>()) return;
+#define ABSL_FLAGS_INTERNAL_IGNORE_TYPE(T, _) \
+  if (flag.IsOfType<T>()) return;
 
-    ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(IGNORE_TYPE)
-#undef IGNORE_TYPE
+    ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(ABSL_FLAGS_INTERNAL_IGNORE_TYPE)
+#undef ABSL_FLAGS_INTERNAL_IGNORE_TYPE
 
-    flag->CheckDefaultValueParsingRoundtrip();
+    flags_internal::PrivateHandleAccessor::CheckDefaultValueParsingRoundtrip(
+        flag);
   });
 #endif
 }
@@ -311,13 +330,13 @@
 // the first flagfile in the input list are processed before the second flagfile
 // etc.
 bool ReadFlagfiles(const std::vector<std::string>& flagfiles,
-                   std::vector<ArgsList>* input_args) {
+                   std::vector<ArgsList>& input_args) {
   bool success = true;
   for (auto it = flagfiles.rbegin(); it != flagfiles.rend(); ++it) {
     ArgsList al;
 
     if (al.ReadFromFlagfile(*it)) {
-      input_args->push_back(al);
+      input_args.push_back(al);
     } else {
       success = false;
     }
@@ -332,7 +351,7 @@
 // `flag_name` is a string from the input flag_names list. If successful we
 // append a single ArgList at the end of the input_args.
 bool ReadFlagsFromEnv(const std::vector<std::string>& flag_names,
-                      std::vector<ArgsList>* input_args,
+                      std::vector<ArgsList>& input_args,
                       bool fail_on_absent_in_env) {
   bool success = true;
   std::vector<std::string> args;
@@ -353,7 +372,7 @@
 
     const std::string envname = absl::StrCat("FLAGS_", flag_name);
     std::string envval;
-    if (!GetEnvVar(envname.c_str(), &envval)) {
+    if (!GetEnvVar(envname.c_str(), envval)) {
       if (fail_on_absent_in_env) {
         flags_internal::ReportUsageError(
             absl::StrCat(envname, " not found in environment"), true);
@@ -368,7 +387,7 @@
   }
 
   if (success) {
-    input_args->emplace_back(args);
+    input_args.emplace_back(args);
   }
 
   return success;
@@ -378,8 +397,8 @@
 
 // Returns success status, which is true if were able to handle all generator
 // flags (flagfile, fromenv, tryfromemv) successfully.
-bool HandleGeneratorFlags(std::vector<ArgsList>* input_args,
-                          std::vector<std::string>* flagfile_value) {
+bool HandleGeneratorFlags(std::vector<ArgsList>& input_args,
+                          std::vector<std::string>& flagfile_value) {
   bool success = true;
 
   absl::MutexLock l(&flags_internal::processing_checks_guard);
@@ -404,9 +423,9 @@
   if (flags_internal::flagfile_needs_processing) {
     auto flagfiles = absl::GetFlag(FLAGS_flagfile);
 
-    if (input_args->size() == 1) {
-      flagfile_value->insert(flagfile_value->end(), flagfiles.begin(),
-                             flagfiles.end());
+    if (input_args.size() == 1) {
+      flagfile_value.insert(flagfile_value.end(), flagfiles.begin(),
+                            flagfiles.end());
     }
 
     success &= ReadFlagfiles(flagfiles, input_args);
@@ -533,10 +552,10 @@
     curr_list->PopFront();
     value = curr_list->Front();
 
-    // Heuristic to detect the case where someone treats a std::string arg
+    // Heuristic to detect the case where someone treats a string arg
     // like a bool or just forgets to pass a value:
     // --my_string_var --foo=bar
-    // We look for a flag of std::string type, whose value begins with a
+    // We look for a flag of string type, whose value begins with a
     // dash and corresponds to known flag or standalone --.
     if (!value.empty() && value[0] == '-' && flag.IsOfType<std::string>()) {
       auto maybe_flag_name = std::get<0>(SplitNameAndValue(value.substr(1)));
@@ -575,12 +594,28 @@
 
 // --------------------------------------------------------------------
 
+bool WasPresentOnCommandLine(absl::string_view flag_name) {
+  absl::MutexLock l(&specified_flags_guard);
+  ABSL_INTERNAL_CHECK(specified_flags != nullptr,
+                      "ParseCommandLine is not invoked yet");
+
+  return std::binary_search(specified_flags->begin(), specified_flags->end(),
+                            flag_name, SpecifiedFlagsCompare{});
+}
+
+// --------------------------------------------------------------------
+
 std::vector<char*> ParseCommandLineImpl(int argc, char* argv[],
                                         ArgvListAction arg_list_act,
                                         UsageFlagsAction usage_flag_act,
                                         OnUndefinedFlag on_undef_flag) {
   ABSL_INTERNAL_CHECK(argc > 0, "Missing argv[0]");
 
+  // Once parsing has started we will not have more flag registrations.
+  // If we did, they would be missing during parsing, which is a problem on
+  // itself.
+  flags_internal::FinalizeRegistry();
+
   // This routine does not return anything since we abort on failure.
   CheckDefaultValuesParsingRoundtrip();
 
@@ -605,13 +640,20 @@
   }
   output_args.push_back(argv[0]);
 
+  absl::MutexLock l(&specified_flags_guard);
+  if (specified_flags == nullptr) {
+    specified_flags = new std::vector<const CommandLineFlag*>;
+  } else {
+    specified_flags->clear();
+  }
+
   // Iterate through the list of the input arguments. First level are arguments
   // originated from argc/argv. Following levels are arguments originated from
   // recursive parsing of flagfile(s).
   bool success = true;
   while (!input_args.empty()) {
     // 10. First we process the built-in generator flags.
-    success &= HandleGeneratorFlags(&input_args, &flagfile_value);
+    success &= HandleGeneratorFlags(input_args, flagfile_value);
 
     // 30. Select top-most (most recent) arguments list. If it is empty drop it
     // and re-try.
@@ -646,7 +688,7 @@
 
     // 60. Split the current argument on '=' to figure out the argument
     // name and value. If flag name is empty it means we've got "--". value
-    // can be empty either if there were no '=' in argument std::string at all or
+    // can be empty either if there were no '=' in argument string at all or
     // an argument looked like "--foo=". In a latter case is_empty_value is
     // true.
     absl::string_view flag_name;
@@ -671,6 +713,11 @@
     std::tie(flag, is_negative) = LocateFlag(flag_name);
 
     if (flag == nullptr) {
+      // Usage flags are not modeled as Abseil flags. Locate them separately.
+      if (flags_internal::DeduceUsageFlags(flag_name, value)) {
+        continue;
+      }
+
       if (on_undef_flag != OnUndefinedFlag::kIgnoreUndefined) {
         undefined_flag_names.emplace_back(arg_from_argv,
                                           std::string(flag_name));
@@ -692,13 +739,17 @@
     }
 
     // 100. Set the located flag to a new new value, unless it is retired.
-    // Setting retired flag fails, but we ignoring it here.
-    if (flag->IsRetired()) continue;
-
+    // Setting retired flag fails, but we ignoring it here while also reporting
+    // access to retired flag.
     std::string error;
-    if (!flag->SetFromString(value, SET_FLAGS_VALUE, kCommandLine, &error)) {
+    if (!flags_internal::PrivateHandleAccessor::ParseFrom(
+            *flag, value, SET_FLAGS_VALUE, kCommandLine, error)) {
+      if (flag->IsRetired()) continue;
+
       flags_internal::ReportUsageError(error, true);
       success = false;
+    } else {
+      specified_flags->push_back(flag);
     }
   }
 
@@ -750,6 +801,10 @@
     }
   }
 
+  // Trim and sort the vector.
+  specified_flags->shrink_to_fit();
+  std::sort(specified_flags->begin(), specified_flags->end(),
+            SpecifiedFlagsCompare{});
   return output_args;
 }
 
diff --git a/absl/flags/parse.h b/absl/flags/parse.h
index f37b060..929de2c 100644
--- a/absl/flags/parse.h
+++ b/absl/flags/parse.h
@@ -23,7 +23,6 @@
 #ifndef ABSL_FLAGS_PARSE_H_
 #define ABSL_FLAGS_PARSE_H_
 
-#include <string>
 #include <vector>
 
 #include "absl/base/config.h"
diff --git a/absl/flags/parse_test.cc b/absl/flags/parse_test.cc
index 6f49377..41bc0bc 100644
--- a/absl/flags/parse_test.cc
+++ b/absl/flags/parse_test.cc
@@ -28,7 +28,8 @@
 #include "absl/flags/declare.h"
 #include "absl/flags/flag.h"
 #include "absl/flags/internal/parse.h"
-#include "absl/flags/internal/registry.h"
+#include "absl/flags/internal/usage.h"
+#include "absl/flags/reflection.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
 #include "absl/strings/substitute.h"
@@ -171,8 +172,8 @@
 // temporary directory location. This way we can test inclusion of one flagfile
 // from another flagfile.
 const char* GetFlagfileFlag(const std::vector<FlagfileData>& ffd,
-                            std::string* flagfile_flag) {
-  *flagfile_flag = "--flagfile=";
+                            std::string& flagfile_flag) {
+  flagfile_flag = "--flagfile=";
   absl::string_view separator;
   for (const auto& flagfile_data : ffd) {
     std::string flagfile_name =
@@ -183,11 +184,11 @@
       flagfile_out << absl::Substitute(line, GetTestTempDir()) << "\n";
     }
 
-    absl::StrAppend(flagfile_flag, separator, flagfile_name);
+    absl::StrAppend(&flagfile_flag, separator, flagfile_name);
     separator = ",";
   }
 
-  return flagfile_flag->c_str();
+  return flagfile_flag.c_str();
 }
 
 }  // namespace
@@ -207,8 +208,11 @@
 using testing::ElementsAreArray;
 
 class ParseTest : public testing::Test {
+ public:
+  ~ParseTest() override { flags::SetFlagsHelpMode(flags::HelpMode::kNone); }
+
  private:
-  flags::FlagSaver flag_saver_;
+  absl::FlagSaver flag_saver_;
 };
 
 // --------------------------------------------------------------------
@@ -481,21 +485,22 @@
       "testbin",
       "--undefined_flag",
   };
-  EXPECT_DEATH(InvokeParse(in_args1),
-               "Unknown command line flag 'undefined_flag'");
+  EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1),
+                            "Unknown command line flag 'undefined_flag'");
 
   const char* in_args2[] = {
       "testbin",
       "--noprefixed_flag",
   };
-  EXPECT_DEATH(InvokeParse(in_args2),
-               "Unknown command line flag 'noprefixed_flag'");
+  EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2),
+                            "Unknown command line flag 'noprefixed_flag'");
 
   const char* in_args3[] = {
       "testbin",
       "--Int_flag=1",
   };
-  EXPECT_DEATH(InvokeParse(in_args3), "Unknown command line flag 'Int_flag'");
+  EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args3),
+                            "Unknown command line flag 'Int_flag'");
 }
 
 // --------------------------------------------------------------------
@@ -505,7 +510,7 @@
       "testbin",
       "--bool_flag=",
   };
-  EXPECT_DEATH(
+  EXPECT_DEATH_IF_SUPPORTED(
       InvokeParse(in_args1),
       "Missing the value after assignment for the boolean flag 'bool_flag'");
 
@@ -513,7 +518,7 @@
       "testbin",
       "--nobool_flag=true",
   };
-  EXPECT_DEATH(InvokeParse(in_args2),
+  EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2),
                "Negative form with assignment is not valid for the boolean "
                "flag 'bool_flag'");
 }
@@ -525,14 +530,14 @@
       "testbin",
       "--nostring_flag",
   };
-  EXPECT_DEATH(InvokeParse(in_args1),
+  EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1),
                "Negative form is not valid for the flag 'string_flag'");
 
   const char* in_args2[] = {
       "testbin",
       "--int_flag",
   };
-  EXPECT_DEATH(InvokeParse(in_args2),
+  EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2),
                "Missing the value for the flag 'int_flag'");
 }
 
@@ -543,7 +548,7 @@
       "testbin",
       "--udt_flag=1",
   };
-  EXPECT_DEATH(InvokeParse(in_args1),
+  EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1),
                "Illegal value '1' specified for flag 'udt_flag'; Use values A, "
                "AAA instead");
 
@@ -552,7 +557,7 @@
       "--udt_flag",
       "AA",
   };
-  EXPECT_DEATH(InvokeParse(in_args2),
+  EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2),
                "Illegal value 'AA' specified for flag 'udt_flag'; Use values "
                "A, AAA instead");
 }
@@ -587,14 +592,14 @@
   const char* in_args1[] = {
       "testbin",
       GetFlagfileFlag({{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
-                      &flagfile_flag),
+                      flagfile_flag),
   };
   TestParse(in_args1, -1, 0.1, "q2w2  ", true);
 
   const char* in_args2[] = {
       "testbin",
       GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)}},
-                      &flagfile_flag),
+                      flagfile_flag),
   };
   TestParse(in_args2, 100, 0.1, "q2w2  ", false);
 }
@@ -608,7 +613,7 @@
       "testbin",
       GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)},
                        {"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
-                      &flagfile_flag),
+                      flagfile_flag),
   };
   TestParse(in_args1, -1, 0.1, "q2w2  ", true);
 }
@@ -621,7 +626,7 @@
   const char* in_args1[] = {
       "testbin", "--int_flag=3",
       GetFlagfileFlag({{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
-                      &flagfile_flag),
+                      flagfile_flag),
       "-double_flag=0.2"};
   TestParse(in_args1, -1, 0.2, "q2w2  ", true);
 }
@@ -636,10 +641,14 @@
       "--flagfile=$0/parse_test.ff2",
   };
 
+  GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)},
+                   {"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
+                      flagfile_flag);
+
   const char* in_args1[] = {
       "testbin",
       GetFlagfileFlag({{"parse_test.ff3", absl::MakeConstSpan(ff3_data)}},
-                      &flagfile_flag),
+                      flagfile_flag),
   };
   TestParse(in_args1, 100, 0.1, "q2w2  ", false);
 }
@@ -656,9 +665,9 @@
   const char* in_args1[] = {
       "testbin",
       GetFlagfileFlag({{"parse_test.ff4",
-                        absl::MakeConstSpan(ff4_data)}}, &flagfile_flag),
+                        absl::MakeConstSpan(ff4_data)}}, flagfile_flag),
   };
-  EXPECT_DEATH(InvokeParse(in_args1),
+  EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1),
                "Unknown command line flag 'unknown_flag'");
 
   constexpr const char* const ff5_data[] = {
@@ -668,9 +677,9 @@
   const char* in_args2[] = {
       "testbin",
       GetFlagfileFlag({{"parse_test.ff5",
-                        absl::MakeConstSpan(ff5_data)}}, &flagfile_flag),
+                        absl::MakeConstSpan(ff5_data)}}, flagfile_flag),
   };
-  EXPECT_DEATH(InvokeParse(in_args2),
+  EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2),
                "Unknown command line flag 'int_flag 10'");
 
   constexpr const char* const ff6_data[] = {
@@ -680,16 +689,17 @@
   const char* in_args3[] = {
       "testbin",
       GetFlagfileFlag({{"parse_test.ff6", absl::MakeConstSpan(ff6_data)}},
-                      &flagfile_flag),
+                      flagfile_flag),
   };
-  EXPECT_DEATH(InvokeParse(in_args3),
+  EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args3),
                "Flagfile can't contain position arguments or --");
 
   const char* in_args4[] = {
       "testbin",
       "--flagfile=invalid_flag_file",
   };
-  EXPECT_DEATH(InvokeParse(in_args4), "Can't open flagfile invalid_flag_file");
+  EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args4),
+                            "Can't open flagfile invalid_flag_file");
 
   constexpr const char* const ff7_data[] = {
       "--int_flag=10",
@@ -700,9 +710,9 @@
   const char* in_args5[] = {
       "testbin",
       GetFlagfileFlag({{"parse_test.ff7", absl::MakeConstSpan(ff7_data)}},
-                      &flagfile_flag),
+                      flagfile_flag),
   };
-  EXPECT_DEATH(InvokeParse(in_args5),
+  EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args5),
                "Unexpected line in the flagfile .*: \\*bin\\*");
 }
 
@@ -724,7 +734,7 @@
 TEST_F(ParseDeathTest, TestReadingUnsetRequiredFlagsFromEnv) {
   const char* in_args1[] = {"testbin", "--fromenv=int_flag"};
 
-  EXPECT_DEATH(InvokeParse(in_args1),
+  EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1),
                "FLAGS_int_flag not found in environment");
 }
 
@@ -735,7 +745,8 @@
 
   ScopedSetEnv set_tryfromenv("FLAGS_tryfromenv", "int_flag");
 
-  EXPECT_DEATH(InvokeParse(in_args1), "Infinite recursion on flag tryfromenv");
+  EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1),
+                            "Infinite recursion on flag tryfromenv");
 }
 
 // --------------------------------------------------------------------
@@ -844,7 +855,7 @@
 
 // --------------------------------------------------------------------
 
-TEST_F(ParseDeathTest, TestHelpFlagHandling) {
+TEST_F(ParseDeathTest, TestSimpleHelpFlagHandling) {
   const char* in_args1[] = {
       "testbin",
       "--help",
@@ -863,7 +874,56 @@
       flags::UsageFlagsAction::kIgnoreUsage,
       flags::OnUndefinedFlag::kAbortIfUndefined);
 
+  EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kImportant);
   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 3);
 }
 
+// --------------------------------------------------------------------
+
+TEST_F(ParseDeathTest, TestSubstringHelpFlagHandling) {
+  const char* in_args1[] = {
+      "testbin",
+      "--help=abcd",
+  };
+
+  auto out_args1 = flags::ParseCommandLineImpl(
+      2, const_cast<char**>(in_args1), flags::ArgvListAction::kRemoveParsedArgs,
+      flags::UsageFlagsAction::kIgnoreUsage,
+      flags::OnUndefinedFlag::kAbortIfUndefined);
+
+  EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kMatch);
+  EXPECT_EQ(flags::GetFlagsHelpMatchSubstr(), "abcd");
+
+  const char* in_args2[] = {"testbin", "--help", "some_positional_arg"};
+
+  auto out_args2 = flags::ParseCommandLineImpl(
+      3, const_cast<char**>(in_args2), flags::ArgvListAction::kRemoveParsedArgs,
+      flags::UsageFlagsAction::kIgnoreUsage,
+      flags::OnUndefinedFlag::kAbortIfUndefined);
+
+  EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kImportant);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, WasPresentOnCommandLine) {
+  const char* in_args1[] = {
+      "testbin",        "arg1", "--bool_flag",
+      "--int_flag=211", "arg2", "--double_flag=1.1",
+      "--string_flag",  "asd",  "--",
+      "--some_flag",    "arg4",
+  };
+
+  InvokeParse(in_args1);
+
+  EXPECT_TRUE(flags::WasPresentOnCommandLine("bool_flag"));
+  EXPECT_TRUE(flags::WasPresentOnCommandLine("int_flag"));
+  EXPECT_TRUE(flags::WasPresentOnCommandLine("double_flag"));
+  EXPECT_TRUE(flags::WasPresentOnCommandLine("string_flag"));
+  EXPECT_FALSE(flags::WasPresentOnCommandLine("some_flag"));
+  EXPECT_FALSE(flags::WasPresentOnCommandLine("another_flag"));
+}
+
+// --------------------------------------------------------------------
+
 }  // namespace
diff --git a/absl/flags/reflection.cc b/absl/flags/reflection.cc
new file mode 100644
index 0000000..0c76110
--- /dev/null
+++ b/absl/flags/reflection.cc
@@ -0,0 +1,350 @@
+//
+//  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/flags/reflection.h"
+
+#include <assert.h>
+
+#include <atomic>
+#include <map>
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/base/thread_annotations.h"
+#include "absl/flags/commandlineflag.h"
+#include "absl/flags/internal/private_handle_accessor.h"
+#include "absl/flags/internal/registry.h"
+#include "absl/flags/usage_config.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace flags_internal {
+
+// --------------------------------------------------------------------
+// FlagRegistry
+//    A FlagRegistry singleton object holds all flag objects indexed by their
+//    names so that if you know a flag's name, you can access or set it. If the
+//    function is named FooLocked(), you must own the registry lock before
+//    calling the function; otherwise, you should *not* hold the lock, and the
+//    function will acquire it itself if needed.
+// --------------------------------------------------------------------
+
+class FlagRegistry {
+ public:
+  FlagRegistry() = default;
+  ~FlagRegistry() = default;
+
+  // 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(); }
+
+  // Returns the flag object for the specified name, or nullptr if not found.
+  // Will emit a warning if a 'retired' flag is specified.
+  CommandLineFlag* FindFlag(absl::string_view name);
+
+  static FlagRegistry& GlobalRegistry();  // returns a singleton registry
+
+ private:
+  friend class flags_internal::FlagSaverImpl;  // reads all the flags in order
+                                               // to copy them
+  friend void ForEachFlag(std::function<void(CommandLineFlag&)> visitor);
+  friend void FinalizeRegistry();
+
+  // The map from name to flag, for FindFlag().
+  using FlagMap = std::map<absl::string_view, CommandLineFlag*>;
+  using FlagIterator = FlagMap::iterator;
+  using FlagConstIterator = FlagMap::const_iterator;
+  FlagMap flags_;
+  std::vector<CommandLineFlag*> flat_flags_;
+  std::atomic<bool> finalized_flags_{false};
+
+  absl::Mutex lock_;
+
+  // Disallow
+  FlagRegistry(const FlagRegistry&);
+  FlagRegistry& operator=(const FlagRegistry&);
+};
+
+namespace {
+
+class FlagRegistryLock {
+ public:
+  explicit FlagRegistryLock(FlagRegistry& fr) : fr_(fr) { fr_.Lock(); }
+  ~FlagRegistryLock() { fr_.Unlock(); }
+
+ private:
+  FlagRegistry& fr_;
+};
+
+}  // namespace
+
+CommandLineFlag* FlagRegistry::FindFlag(absl::string_view name) {
+  if (finalized_flags_.load(std::memory_order_acquire)) {
+    // We could save some gcus here if we make `Name()` be non-virtual.
+    // We could move the `const char*` name to the base class.
+    auto it = std::partition_point(
+        flat_flags_.begin(), flat_flags_.end(),
+        [=](CommandLineFlag* f) { return f->Name() < name; });
+    if (it != flat_flags_.end() && (*it)->Name() == name) return *it;
+  }
+
+  FlagRegistryLock frl(*this);
+  auto it = flags_.find(name);
+  return it != flags_.end() ? it->second : nullptr;
+}
+
+void FlagRegistry::RegisterFlag(CommandLineFlag& flag, const char* filename) {
+  if (filename != nullptr &&
+      flag.Filename() != GetUsageConfig().normalize_filename(filename)) {
+    flags_internal::ReportUsageError(
+        absl::StrCat(
+            "Inconsistency between flag object and registration for flag '",
+            flag.Name(),
+            "', likely due to duplicate flags or an ODR violation. Relevant "
+            "files: ",
+            flag.Filename(), " and ", filename),
+        true);
+    std::exit(1);
+  }
+
+  FlagRegistryLock registry_lock(*this);
+
+  std::pair<FlagIterator, bool> ins =
+      flags_.insert(FlagMap::value_type(flag.Name(), &flag));
+  if (ins.second == false) {  // means the name was already in the map
+    CommandLineFlag& old_flag = *ins.first->second;
+    if (flag.IsRetired() != old_flag.IsRetired()) {
+      // All registrations must agree on the 'retired' flag.
+      flags_internal::ReportUsageError(
+          absl::StrCat(
+              "Retired flag '", flag.Name(), "' was defined normally in file '",
+              (flag.IsRetired() ? old_flag.Filename() : flag.Filename()), "'."),
+          true);
+    } else if (flags_internal::PrivateHandleAccessor::TypeId(flag) !=
+               flags_internal::PrivateHandleAccessor::TypeId(old_flag)) {
+      flags_internal::ReportUsageError(
+          absl::StrCat("Flag '", flag.Name(),
+                       "' was defined more than once but with "
+                       "differing types. Defined in files '",
+                       old_flag.Filename(), "' and '", flag.Filename(), "'."),
+          true);
+    } else if (old_flag.IsRetired()) {
+      return;
+    } else if (old_flag.Filename() != flag.Filename()) {
+      flags_internal::ReportUsageError(
+          absl::StrCat("Flag '", flag.Name(),
+                       "' was defined more than once (in files '",
+                       old_flag.Filename(), "' and '", flag.Filename(), "')."),
+          true);
+    } else {
+      flags_internal::ReportUsageError(
+          absl::StrCat(
+              "Something is wrong with flag '", flag.Name(), "' in file '",
+              flag.Filename(), "'. One possibility: file '", flag.Filename(),
+              "' is being linked both statically and dynamically into this "
+              "executable. e.g. some files listed as srcs to a test and also "
+              "listed as srcs of some shared lib deps of the same test."),
+          true);
+    }
+    // All cases above are fatal, except for the retired flags.
+    std::exit(1);
+  }
+}
+
+FlagRegistry& FlagRegistry::GlobalRegistry() {
+  static FlagRegistry* global_registry = new FlagRegistry;
+  return *global_registry;
+}
+
+// --------------------------------------------------------------------
+
+void ForEachFlag(std::function<void(CommandLineFlag&)> visitor) {
+  FlagRegistry& registry = FlagRegistry::GlobalRegistry();
+
+  if (registry.finalized_flags_.load(std::memory_order_acquire)) {
+    for (const auto& i : registry.flat_flags_) visitor(*i);
+  }
+
+  FlagRegistryLock frl(registry);
+  for (const auto& i : registry.flags_) visitor(*i.second);
+}
+
+// --------------------------------------------------------------------
+
+bool RegisterCommandLineFlag(CommandLineFlag& flag, const char* filename) {
+  FlagRegistry::GlobalRegistry().RegisterFlag(flag, filename);
+  return true;
+}
+
+void FinalizeRegistry() {
+  auto& registry = FlagRegistry::GlobalRegistry();
+  FlagRegistryLock frl(registry);
+  if (registry.finalized_flags_.load(std::memory_order_relaxed)) {
+    // Was already finalized. Ignore the second time.
+    return;
+  }
+  registry.flat_flags_.reserve(registry.flags_.size());
+  for (const auto& f : registry.flags_) {
+    registry.flat_flags_.push_back(f.second);
+  }
+  registry.flags_.clear();
+  registry.finalized_flags_.store(true, std::memory_order_release);
+}
+
+// --------------------------------------------------------------------
+
+namespace {
+
+class RetiredFlagObj final : public CommandLineFlag {
+ public:
+  constexpr RetiredFlagObj(const char* name, FlagFastTypeId type_id)
+      : name_(name), type_id_(type_id) {}
+
+ private:
+  absl::string_view Name() const override { return name_; }
+  std::string Filename() const override {
+    OnAccess();
+    return "RETIRED";
+  }
+  FlagFastTypeId TypeId() const override { return type_id_; }
+  std::string Help() const override {
+    OnAccess();
+    return "";
+  }
+  bool IsRetired() const override { return true; }
+  bool IsSpecifiedOnCommandLine() const override {
+    OnAccess();
+    return false;
+  }
+  std::string DefaultValue() const override {
+    OnAccess();
+    return "";
+  }
+  std::string CurrentValue() const override {
+    OnAccess();
+    return "";
+  }
+
+  // Any input is valid
+  bool ValidateInputValue(absl::string_view) const override {
+    OnAccess();
+    return true;
+  }
+
+  std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override {
+    return nullptr;
+  }
+
+  bool ParseFrom(absl::string_view, flags_internal::FlagSettingMode,
+                 flags_internal::ValueSource, std::string&) override {
+    OnAccess();
+    return false;
+  }
+
+  void CheckDefaultValueParsingRoundtrip() const override { OnAccess(); }
+
+  void Read(void*) const override { OnAccess(); }
+
+  void OnAccess() const {
+    flags_internal::ReportUsageError(
+        absl::StrCat("Accessing retired flag '", name_, "'"), false);
+  }
+
+  // Data members
+  const char* const name_;
+  const FlagFastTypeId type_id_;
+};
+
+}  // namespace
+
+void Retire(const char* name, FlagFastTypeId type_id, char* buf) {
+  static_assert(sizeof(RetiredFlagObj) == kRetiredFlagObjSize, "");
+  static_assert(alignof(RetiredFlagObj) == kRetiredFlagObjAlignment, "");
+  auto* flag = ::new (static_cast<void*>(buf))
+      flags_internal::RetiredFlagObj(name, type_id);
+  FlagRegistry::GlobalRegistry().RegisterFlag(*flag, nullptr);
+}
+
+// --------------------------------------------------------------------
+
+class FlagSaverImpl {
+ public:
+  FlagSaverImpl() = default;
+  FlagSaverImpl(const FlagSaverImpl&) = delete;
+  void operator=(const FlagSaverImpl&) = delete;
+
+  // Saves the flag states from the flag registry into this object.
+  // It's an error to call this more than once.
+  void SaveFromRegistry() {
+    assert(backup_registry_.empty());  // call only once!
+    flags_internal::ForEachFlag([&](CommandLineFlag& flag) {
+      if (auto flag_state =
+              flags_internal::PrivateHandleAccessor::SaveState(flag)) {
+        backup_registry_.emplace_back(std::move(flag_state));
+      }
+    });
+  }
+
+  // Restores the saved flag states into the flag registry.
+  void RestoreToRegistry() {
+    for (const auto& flag_state : backup_registry_) {
+      flag_state->Restore();
+    }
+  }
+
+ private:
+  std::vector<std::unique_ptr<flags_internal::FlagStateInterface>>
+      backup_registry_;
+};
+
+}  // namespace flags_internal
+
+FlagSaver::FlagSaver() : impl_(new flags_internal::FlagSaverImpl) {
+  impl_->SaveFromRegistry();
+}
+
+FlagSaver::~FlagSaver() {
+  if (!impl_) return;
+
+  impl_->RestoreToRegistry();
+  delete impl_;
+}
+
+// --------------------------------------------------------------------
+
+CommandLineFlag* FindCommandLineFlag(absl::string_view name) {
+  if (name.empty()) return nullptr;
+  flags_internal::FlagRegistry& registry =
+      flags_internal::FlagRegistry::GlobalRegistry();
+  return registry.FindFlag(name);
+}
+
+// --------------------------------------------------------------------
+
+absl::flat_hash_map<absl::string_view, absl::CommandLineFlag*> GetAllFlags() {
+  absl::flat_hash_map<absl::string_view, absl::CommandLineFlag*> res;
+  flags_internal::ForEachFlag([&](CommandLineFlag& flag) {
+    if (!flag.IsRetired()) res.insert({flag.Name(), &flag});
+  });
+  return res;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/flags/reflection.h b/absl/flags/reflection.h
new file mode 100644
index 0000000..e6baf5d
--- /dev/null
+++ b/absl/flags/reflection.h
@@ -0,0 +1,90 @@
+//
+// 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.
+//
+// -----------------------------------------------------------------------------
+// File: reflection.h
+// -----------------------------------------------------------------------------
+//
+// This file defines the routines to access and operate on an Abseil Flag's
+// reflection handle.
+
+#ifndef ABSL_FLAGS_REFLECTION_H_
+#define ABSL_FLAGS_REFLECTION_H_
+
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/container/flat_hash_map.h"
+#include "absl/flags/commandlineflag.h"
+#include "absl/flags/internal/commandlineflag.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace flags_internal {
+class FlagSaverImpl;
+}  // namespace flags_internal
+
+// FindCommandLineFlag()
+//
+// Returns the reflection handle of an Abseil flag of the specified name, or
+// `nullptr` if not found. This function will emit a warning if the name of a
+// 'retired' flag is specified.
+absl::CommandLineFlag* FindCommandLineFlag(absl::string_view name);
+
+// Returns current state of the Flags registry in a form of mapping from flag
+// name to a flag reflection handle.
+absl::flat_hash_map<absl::string_view, absl::CommandLineFlag*> GetAllFlags();
+
+//------------------------------------------------------------------------------
+// FlagSaver
+//------------------------------------------------------------------------------
+//
+// A FlagSaver object stores the state of flags in the scope where the FlagSaver
+// is defined, allowing modification of those flags within that scope and
+// automatic restoration of the flags to their previous state upon leaving the
+// scope.
+//
+// A FlagSaver can be used within tests to temporarily change the test
+// environment and restore the test case to its previous state.
+//
+// Example:
+//
+//   void MyFunc() {
+//    absl::FlagSaver fs;
+//    ...
+//    absl::SetFlag(&FLAGS_myFlag, otherValue);
+//    ...
+//  } // scope of FlagSaver left, flags return to previous state
+//
+// This class is thread-safe.
+
+class FlagSaver {
+ public:
+  FlagSaver();
+  ~FlagSaver();
+
+  FlagSaver(const FlagSaver&) = delete;
+  void operator=(const FlagSaver&) = delete;
+
+ private:
+  flags_internal::FlagSaverImpl* impl_;
+};
+
+//-----------------------------------------------------------------------------
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_FLAGS_REFLECTION_H_
diff --git a/absl/flags/reflection_test.cc b/absl/flags/reflection_test.cc
new file mode 100644
index 0000000..79cfa90
--- /dev/null
+++ b/absl/flags/reflection_test.cc
@@ -0,0 +1,265 @@
+//
+//  Copyright 2019 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/flags/reflection.h"
+
+#include <memory>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/flags/declare.h"
+#include "absl/flags/flag.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/flags/marshalling.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_split.h"
+
+ABSL_FLAG(int, int_flag, 1, "int_flag help");
+ABSL_FLAG(std::string, string_flag, "dflt", "string_flag help");
+ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
+
+namespace {
+
+class ReflectionTest : public testing::Test {
+ protected:
+  void SetUp() override { flag_saver_ = absl::make_unique<absl::FlagSaver>(); }
+  void TearDown() override { flag_saver_.reset(); }
+
+ private:
+  std::unique_ptr<absl::FlagSaver> flag_saver_;
+};
+
+// --------------------------------------------------------------------
+
+TEST_F(ReflectionTest, TestFindCommandLineFlag) {
+  auto* handle = absl::FindCommandLineFlag("some_flag");
+  EXPECT_EQ(handle, nullptr);
+
+  handle = absl::FindCommandLineFlag("int_flag");
+  EXPECT_NE(handle, nullptr);
+
+  handle = absl::FindCommandLineFlag("string_flag");
+  EXPECT_NE(handle, nullptr);
+
+  handle = absl::FindCommandLineFlag("bool_retired_flag");
+  EXPECT_NE(handle, nullptr);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ReflectionTest, TestGetAllFlags) {
+  auto all_flags = absl::GetAllFlags();
+  EXPECT_NE(all_flags.find("int_flag"), all_flags.end());
+  EXPECT_EQ(all_flags.find("bool_retired_flag"), all_flags.end());
+  EXPECT_EQ(all_flags.find("some_undefined_flag"), all_flags.end());
+
+  std::vector<absl::string_view> flag_names_first_attempt;
+  auto all_flags_1 = absl::GetAllFlags();
+  for (auto f : all_flags_1) {
+    flag_names_first_attempt.push_back(f.first);
+  }
+
+  std::vector<absl::string_view> flag_names_second_attempt;
+  auto all_flags_2 = absl::GetAllFlags();
+  for (auto f : all_flags_2) {
+    flag_names_second_attempt.push_back(f.first);
+  }
+
+  EXPECT_THAT(flag_names_first_attempt,
+              ::testing::UnorderedElementsAreArray(flag_names_second_attempt));
+}
+
+// --------------------------------------------------------------------
+
+struct CustomUDT {
+  CustomUDT() : a(1), b(1) {}
+  CustomUDT(int a_, int b_) : a(a_), b(b_) {}
+
+  friend bool operator==(const CustomUDT& f1, const CustomUDT& f2) {
+    return f1.a == f2.a && f1.b == f2.b;
+  }
+
+  int a;
+  int b;
+};
+bool AbslParseFlag(absl::string_view in, CustomUDT* f, std::string*) {
+  std::vector<absl::string_view> parts =
+      absl::StrSplit(in, ':', absl::SkipWhitespace());
+
+  if (parts.size() != 2) return false;
+
+  if (!absl::SimpleAtoi(parts[0], &f->a)) return false;
+
+  if (!absl::SimpleAtoi(parts[1], &f->b)) return false;
+
+  return true;
+}
+std::string AbslUnparseFlag(const CustomUDT& f) {
+  return absl::StrCat(f.a, ":", f.b);
+}
+
+}  // namespace
+
+// --------------------------------------------------------------------
+
+ABSL_FLAG(bool, test_flag_01, true, "");
+ABSL_FLAG(int, test_flag_02, 1234, "");
+ABSL_FLAG(int16_t, test_flag_03, -34, "");
+ABSL_FLAG(uint16_t, test_flag_04, 189, "");
+ABSL_FLAG(int32_t, test_flag_05, 10765, "");
+ABSL_FLAG(uint32_t, test_flag_06, 40000, "");
+ABSL_FLAG(int64_t, test_flag_07, -1234567, "");
+ABSL_FLAG(uint64_t, test_flag_08, 9876543, "");
+ABSL_FLAG(double, test_flag_09, -9.876e-50, "");
+ABSL_FLAG(float, test_flag_10, 1.234e12f, "");
+ABSL_FLAG(std::string, test_flag_11, "", "");
+ABSL_FLAG(absl::Duration, test_flag_12, absl::Minutes(10), "");
+static int counter = 0;
+ABSL_FLAG(int, test_flag_13, 200, "").OnUpdate([]() { counter++; });
+ABSL_FLAG(CustomUDT, test_flag_14, {}, "");
+
+namespace {
+
+TEST_F(ReflectionTest, TestFlagSaverInScope) {
+  {
+    absl::FlagSaver s;
+    counter = 0;
+    absl::SetFlag(&FLAGS_test_flag_01, false);
+    absl::SetFlag(&FLAGS_test_flag_02, -1021);
+    absl::SetFlag(&FLAGS_test_flag_03, 6009);
+    absl::SetFlag(&FLAGS_test_flag_04, 44);
+    absl::SetFlag(&FLAGS_test_flag_05, +800);
+    absl::SetFlag(&FLAGS_test_flag_06, -40978756);
+    absl::SetFlag(&FLAGS_test_flag_07, 23405);
+    absl::SetFlag(&FLAGS_test_flag_08, 975310);
+    absl::SetFlag(&FLAGS_test_flag_09, 1.00001);
+    absl::SetFlag(&FLAGS_test_flag_10, -3.54f);
+    absl::SetFlag(&FLAGS_test_flag_11, "asdf");
+    absl::SetFlag(&FLAGS_test_flag_12, absl::Hours(20));
+    absl::SetFlag(&FLAGS_test_flag_13, 4);
+    absl::SetFlag(&FLAGS_test_flag_14, CustomUDT{-1, -2});
+  }
+
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_03), -34);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_04), 189);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_05), 10765);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_06), 40000);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_07), -1234567);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 9876543);
+  EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), -9.876e-50, 1e-55);
+  EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "");
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Minutes(10));
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), 200);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_14), CustomUDT{});
+  EXPECT_EQ(counter, 2);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ReflectionTest, TestFlagSaverVsUpdateViaReflection) {
+  {
+    absl::FlagSaver s;
+    counter = 0;
+    std::string error;
+    EXPECT_TRUE(
+        absl::FindCommandLineFlag("test_flag_01")->ParseFrom("false", &error))
+        << error;
+    EXPECT_TRUE(
+        absl::FindCommandLineFlag("test_flag_02")->ParseFrom("-4536", &error))
+        << error;
+    EXPECT_TRUE(
+        absl::FindCommandLineFlag("test_flag_03")->ParseFrom("111", &error))
+        << error;
+    EXPECT_TRUE(
+        absl::FindCommandLineFlag("test_flag_04")->ParseFrom("909", &error))
+        << error;
+    EXPECT_TRUE(
+        absl::FindCommandLineFlag("test_flag_05")->ParseFrom("-2004", &error))
+        << error;
+    EXPECT_TRUE(
+        absl::FindCommandLineFlag("test_flag_06")->ParseFrom("1000023", &error))
+        << error;
+    EXPECT_TRUE(
+        absl::FindCommandLineFlag("test_flag_07")->ParseFrom("69305", &error))
+        << error;
+    EXPECT_TRUE(absl::FindCommandLineFlag("test_flag_08")
+                    ->ParseFrom("1000000001", &error))
+        << error;
+    EXPECT_TRUE(
+        absl::FindCommandLineFlag("test_flag_09")->ParseFrom("2.09021", &error))
+        << error;
+    EXPECT_TRUE(
+        absl::FindCommandLineFlag("test_flag_10")->ParseFrom("-33.1", &error))
+        << error;
+    EXPECT_TRUE(
+        absl::FindCommandLineFlag("test_flag_11")->ParseFrom("ADD_FOO", &error))
+        << error;
+    EXPECT_TRUE(absl::FindCommandLineFlag("test_flag_12")
+                    ->ParseFrom("3h11m16s", &error))
+        << error;
+    EXPECT_TRUE(
+        absl::FindCommandLineFlag("test_flag_13")->ParseFrom("0", &error))
+        << error;
+    EXPECT_TRUE(
+        absl::FindCommandLineFlag("test_flag_14")->ParseFrom("10:1", &error))
+        << error;
+  }
+
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_03), -34);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_04), 189);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_05), 10765);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_06), 40000);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_07), -1234567);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 9876543);
+  EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), -9.876e-50, 1e-55);
+  EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "");
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Minutes(10));
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), 200);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_14), CustomUDT{});
+  EXPECT_EQ(counter, 2);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ReflectionTest, TestMultipleFlagSaversInEnclosedScopes) {
+  {
+    absl::FlagSaver s;
+    absl::SetFlag(&FLAGS_test_flag_08, 10);
+    EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 10);
+    {
+      absl::FlagSaver s;
+      absl::SetFlag(&FLAGS_test_flag_08, 20);
+      EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 20);
+      {
+        absl::FlagSaver s;
+        absl::SetFlag(&FLAGS_test_flag_08, -200);
+        EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), -200);
+      }
+      EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 20);
+    }
+    EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 10);
+  }
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 9876543);
+}
+
+}  // namespace
diff --git a/absl/flags/usage_config.cc b/absl/flags/usage_config.cc
index 2d837ec..5d7426d 100644
--- a/absl/flags/usage_config.cc
+++ b/absl/flags/usage_config.cc
@@ -15,6 +15,7 @@
 
 #include "absl/flags/usage_config.h"
 
+#include <functional>
 #include <iostream>
 #include <string>
 
@@ -33,7 +34,8 @@
 
 // Additional report of fatal usage error message before we std::exit. Error is
 // fatal if is_fatal argument to ReportUsageError is true.
-ABSL_ATTRIBUTE_WEAK void AbslInternalReportFatalUsageError(absl::string_view) {}
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(
+    AbslInternalReportFatalUsageError)(absl::string_view) {}
 
 }  // extern "C"
 
@@ -50,10 +52,15 @@
 bool ContainsHelpshortFlags(absl::string_view filename) {
   // By default we only want flags in binary's main. We expect the main
   // routine to reside in <program>.cc or <program>-main.cc or
-  // <program>_main.cc, where the <program> is the name of the binary.
+  // <program>_main.cc, where the <program> is the name of the binary
+  // (without .exe on Windows).
   auto suffix = flags_internal::Basename(filename);
-  if (!absl::ConsumePrefix(&suffix,
-                           flags_internal::ShortProgramInvocationName()))
+  auto program_name = flags_internal::ShortProgramInvocationName();
+  absl::string_view program_name_ref = program_name;
+#if defined(_WIN32)
+  absl::ConsumeSuffix(&program_name_ref, ".exe");
+#endif
+  if (!absl::ConsumePrefix(&suffix, program_name_ref))
     return false;
   return absl::StartsWith(suffix, ".") || absl::StartsWith(suffix, "-main.") ||
          absl::StartsWith(suffix, "_main.");
@@ -122,7 +129,7 @@
   std::cerr << "ERROR: " << msg << std::endl;
 
   if (is_fatal) {
-    AbslInternalReportFatalUsageError(msg);
+    ABSL_INTERNAL_C_SYMBOL(AbslInternalReportFatalUsageError)(msg);
   }
 }
 
diff --git a/absl/flags/usage_config.h b/absl/flags/usage_config.h
index 0ed7e1b..ded7030 100644
--- a/absl/flags/usage_config.h
+++ b/absl/flags/usage_config.h
@@ -90,7 +90,7 @@
   // program output.
   flags_internal::FlagKindFilter contains_helppackage_flags;
 
-  // Generates std::string containing program version. This is the std::string reported
+  // Generates string containing program version. This is the string reported
   // when user specifies --version in a command line.
   std::function<std::string()> version_string;
 
@@ -127,7 +127,8 @@
 
 // Additional report of fatal usage error message before we std::exit. Error is
 // fatal if is_fatal argument to ReportUsageError is true.
-void AbslInternalReportFatalUsageError(absl::string_view);
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalReportFatalUsageError)(
+    absl::string_view);
 
 }  // extern "C"
 
diff --git a/absl/flags/usage_config_test.cc b/absl/flags/usage_config_test.cc
index 70eca30..e57a883 100644
--- a/absl/flags/usage_config_test.cc
+++ b/absl/flags/usage_config_test.cc
@@ -84,7 +84,11 @@
 // --------------------------------------------------------------------
 
 TEST_F(FlagsUsageConfigTest, TestContainsHelpshortFlags) {
+#if defined(_WIN32)
+  flags::SetProgramInvocationName("usage_config_test.exe");
+#else
   flags::SetProgramInvocationName("usage_config_test");
+#endif
 
   auto config = flags::GetUsageConfig();
   EXPECT_TRUE(config.contains_helpshort_flags("adir/cd/usage_config_test.cc"));
diff --git a/absl/functional/BUILD.bazel b/absl/functional/BUILD.bazel
index 432546c..ebd9b99 100644
--- a/absl/functional/BUILD.bazel
+++ b/absl/functional/BUILD.bazel
@@ -24,7 +24,7 @@
 
 package(default_visibility = ["//visibility:public"])
 
-licenses(["notice"])  # Apache 2.0
+licenses(["notice"])
 
 cc_library(
     name = "bind_front",
diff --git a/absl/functional/function_ref.h b/absl/functional/function_ref.h
index 370acc5..6e03ac2 100644
--- a/absl/functional/function_ref.h
+++ b/absl/functional/function_ref.h
@@ -90,7 +90,7 @@
   // Used to disable constructors for objects that are not compatible with the
   // signature of this FunctionRef.
   template <typename F,
-            typename FR = absl::base_internal::InvokeT<F, Args&&...>>
+            typename FR = absl::base_internal::invoke_result_t<F, Args&&...>>
   using EnableIfCompatible =
       typename std::enable_if<std::is_void<R>::value ||
                               std::is_convertible<FR, R>::value>::type;
diff --git a/absl/functional/internal/front_binder.h b/absl/functional/internal/front_binder.h
index a4d95da..45f52de 100644
--- a/absl/functional/internal/front_binder.h
+++ b/absl/functional/internal/front_binder.h
@@ -33,7 +33,7 @@
 // Invoke the method, expanding the tuple of bound arguments.
 template <class R, class Tuple, size_t... Idx, class... Args>
 R Apply(Tuple&& bound, absl::index_sequence<Idx...>, Args&&... free) {
-  return base_internal::Invoke(
+  return base_internal::invoke(
       absl::forward<Tuple>(bound).template get<Idx>()...,
       absl::forward<Args>(free)...);
 }
@@ -50,22 +50,22 @@
   constexpr explicit FrontBinder(absl::in_place_t, Ts&&... ts)
       : bound_args_(absl::forward<Ts>(ts)...) {}
 
-  template <class... FreeArgs,
-            class R = base_internal::InvokeT<F&, BoundArgs&..., FreeArgs&&...>>
+  template <class... FreeArgs, class R = base_internal::invoke_result_t<
+                                   F&, BoundArgs&..., FreeArgs&&...>>
   R operator()(FreeArgs&&... free_args) & {
     return functional_internal::Apply<R>(bound_args_, Idx(),
                                          absl::forward<FreeArgs>(free_args)...);
   }
 
   template <class... FreeArgs,
-            class R = base_internal::InvokeT<const F&, const BoundArgs&...,
-                                             FreeArgs&&...>>
+            class R = base_internal::invoke_result_t<
+                const F&, const BoundArgs&..., FreeArgs&&...>>
   R operator()(FreeArgs&&... free_args) const& {
     return functional_internal::Apply<R>(bound_args_, Idx(),
                                          absl::forward<FreeArgs>(free_args)...);
   }
 
-  template <class... FreeArgs, class R = base_internal::InvokeT<
+  template <class... FreeArgs, class R = base_internal::invoke_result_t<
                                    F&&, BoundArgs&&..., FreeArgs&&...>>
   R operator()(FreeArgs&&... free_args) && {
     // This overload is called when *this is an rvalue. If some of the bound
@@ -75,8 +75,8 @@
   }
 
   template <class... FreeArgs,
-            class R = base_internal::InvokeT<const F&&, const BoundArgs&&...,
-                                             FreeArgs&&...>>
+            class R = base_internal::invoke_result_t<
+                const F&&, const BoundArgs&&..., FreeArgs&&...>>
   R operator()(FreeArgs&&... free_args) const&& {
     // This overload is called when *this is an rvalue. If some of the bound
     // arguments are stored by value or rvalue reference, we move them.
diff --git a/absl/functional/internal/function_ref.h b/absl/functional/internal/function_ref.h
index d157505..b5bb8b4 100644
--- a/absl/functional/internal/function_ref.h
+++ b/absl/functional/internal/function_ref.h
@@ -71,14 +71,14 @@
 R InvokeObject(VoidPtr ptr, typename ForwardT<Args>::type... args) {
   auto o = static_cast<const Obj*>(ptr.obj);
   return static_cast<R>(
-      absl::base_internal::Invoke(*o, std::forward<Args>(args)...));
+      absl::base_internal::invoke(*o, std::forward<Args>(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>(
-      absl::base_internal::Invoke(f, std::forward<Args>(args)...));
+      absl::base_internal::invoke(f, std::forward<Args>(args)...));
 }
 
 template <typename Sig>
diff --git a/absl/hash/BUILD.bazel b/absl/hash/BUILD.bazel
index ffe8c29..4b2c220 100644
--- a/absl/hash/BUILD.bazel
+++ b/absl/hash/BUILD.bazel
@@ -24,7 +24,7 @@
 
 package(default_visibility = ["//visibility:public"])
 
-licenses(["notice"])  # Apache 2.0
+licenses(["notice"])
 
 cc_library(
     name = "hash",
@@ -37,6 +37,8 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":city",
+        ":wyhash",
+        "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:endian",
         "//absl/container:fixed_array",
@@ -76,10 +78,30 @@
         "//absl/container:flat_hash_set",
         "//absl/meta:type_traits",
         "//absl/numeric:int128",
+        "//absl/strings:cord_test_helpers",
         "@com_google_googletest//:gtest_main",
     ],
 )
 
+cc_binary(
+    name = "hash_benchmark",
+    testonly = 1,
+    srcs = ["hash_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":hash",
+        "//absl/base:core_headers",
+        "//absl/random",
+        "//absl/strings",
+        "//absl/strings:cord",
+        "//absl/strings:cord_test_helpers",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
 cc_library(
     name = "spy_hash_state",
     testonly = 1,
@@ -119,3 +141,30 @@
         "@com_google_googletest//:gtest_main",
     ],
 )
+
+cc_library(
+    name = "wyhash",
+    srcs = ["internal/wyhash.cc"],
+    hdrs = ["internal/wyhash.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        "//absl/base:config",
+        "//absl/base:endian",
+        "//absl/numeric:int128",
+    ],
+)
+
+cc_test(
+    name = "wyhash_test",
+    srcs = ["internal/wyhash_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":wyhash",
+        "//absl/strings",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt
index febc551..b43bfa5 100644
--- a/absl/hash/CMakeLists.txt
+++ b/absl/hash/CMakeLists.txt
@@ -24,7 +24,9 @@
     "internal/hash.h"
   COPTS
     ${ABSL_DEFAULT_COPTS}
-  DEPS
+    DEPS
+    absl::city
+    absl::config
     absl::core_headers
     absl::endian
     absl::fixed_array
@@ -34,7 +36,7 @@
     absl::optional
     absl::variant
     absl::utility
-    absl::city
+    absl::wyhash
   PUBLIC
 )
 
@@ -62,6 +64,7 @@
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
+    absl::cord_test_helpers
     absl::hash
     absl::hash_testing
     absl::core_headers
@@ -113,3 +116,30 @@
     gmock_main
 )
 
+absl_cc_library(
+  NAME
+    wyhash
+  HDRS
+    "internal/wyhash.h"
+  SRCS
+    "internal/wyhash.cc"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::config
+    absl::endian
+    absl::int128
+)
+
+absl_cc_test(
+  NAME
+    wyhash_test
+  SRCS
+    "internal/wyhash_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::wyhash
+    absl::strings
+    gmock_main
+)
diff --git a/absl/hash/hash.h b/absl/hash/hash.h
index 23a65ea..5de132c 100644
--- a/absl/hash/hash.h
+++ b/absl/hash/hash.h
@@ -37,8 +37,11 @@
 // types. Hashing of that combined state is separately done by `absl::Hash`.
 //
 // One should assume that a hash algorithm is chosen randomly at the start of
-// each process.  E.g., absl::Hash<int>()(9) in one process and
-// absl::Hash<int>()(9) in another process are likely to differ.
+// each process.  E.g., `absl::Hash<int>{}(9)` in one process and
+// `absl::Hash<int>{}(9)` in another process are likely to differ.
+//
+// `absl::Hash` is intended to strongly mix input bits with a target of passing
+// an [Avalanche Test](https://en.wikipedia.org/wiki/Avalanche_effect).
 //
 // Example:
 //
@@ -85,7 +88,6 @@
 //  * T is an arithmetic or pointer type
 //  * T defines an overload for `AbslHashValue(H, const T&)` for an arbitrary
 //    hash state `H`.
-//  - T defines a specialization of `HASH_NAMESPACE::hash<T>`
 //  - T defines a specialization of `std::hash<T>`
 //
 // `absl::Hash` intrinsically supports the following types:
@@ -98,6 +100,7 @@
 //   * std::tuple<Ts...>, if all the Ts... are hashable
 //   * std::unique_ptr and std::shared_ptr
 //   * All string-like types including:
+//     * absl::Cord
 //     * std::string
 //     * std::string_view (as well as any instance of std::basic_string that
 //       uses char and std::char_traits)
@@ -124,8 +127,6 @@
 //   * Natively supported types out of the box (see above)
 //   * Types for which an `AbslHashValue()` overload is provided (such as
 //     user-defined types). See "Adding Type Support to `absl::Hash`" below.
-//   * Types which define a `HASH_NAMESPACE::hash<T>` specialization (aka
-//     `__gnu_cxx::hash<T>` for gcc/Clang or `stdext::hash<T>` for MSVC)
 //   * Types which define a `std::hash<T>` specialization
 //
 // The fallback to legacy hash functions exists mainly for backwards
diff --git a/absl/hash/hash_benchmark.cc b/absl/hash/hash_benchmark.cc
new file mode 100644
index 0000000..d498ac2
--- /dev/null
+++ b/absl/hash/hash_benchmark.cc
@@ -0,0 +1,254 @@
+// 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 <string>
+#include <type_traits>
+#include <typeindex>
+#include <utility>
+#include <vector>
+
+#include "absl/base/attributes.h"
+#include "absl/hash/hash.h"
+#include "absl/random/random.h"
+#include "absl/strings/cord.h"
+#include "absl/strings/cord_test_helpers.h"
+#include "absl/strings/string_view.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+using absl::Hash;
+
+template <template <typename> class H, typename T>
+void RunBenchmark(benchmark::State& state, T value) {
+  H<T> h;
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(value);
+    benchmark::DoNotOptimize(h(value));
+  }
+}
+
+}  // namespace
+
+template <typename T>
+using AbslHash = absl::Hash<T>;
+
+class TypeErasedInterface {
+ public:
+  virtual ~TypeErasedInterface() = default;
+
+  template <typename H>
+  friend H AbslHashValue(H state, const TypeErasedInterface& wrapper) {
+    state = H::combine(std::move(state), std::type_index(typeid(wrapper)));
+    wrapper.HashValue(absl::HashState::Create(&state));
+    return state;
+  }
+
+ private:
+  virtual void HashValue(absl::HashState state) const = 0;
+};
+
+template <typename T>
+struct TypeErasedAbslHash {
+  class Wrapper : public TypeErasedInterface {
+   public:
+    explicit Wrapper(const T& value) : value_(value) {}
+
+   private:
+    void HashValue(absl::HashState state) const override {
+      absl::HashState::combine(std::move(state), value_);
+    }
+
+    const T& value_;
+  };
+
+  size_t operator()(const T& value) {
+    return absl::Hash<Wrapper>{}(Wrapper(value));
+  }
+};
+
+template <typename FuncType>
+inline FuncType* ODRUseFunction(FuncType* ptr) {
+  volatile FuncType* dummy = ptr;
+  return dummy;
+}
+
+absl::Cord FlatCord(size_t size) {
+  absl::Cord result(std::string(size, 'a'));
+  result.Flatten();
+  return result;
+}
+
+absl::Cord FragmentedCord(size_t size) {
+  const size_t orig_size = size;
+  std::vector<std::string> chunks;
+  size_t chunk_size = std::max<size_t>(1, size / 10);
+  while (size > chunk_size) {
+    chunks.push_back(std::string(chunk_size, 'a'));
+    size -= chunk_size;
+  }
+  if (size > 0) {
+    chunks.push_back(std::string(size, 'a'));
+  }
+  absl::Cord result = absl::MakeFragmentedCord(chunks);
+  (void) orig_size;
+  assert(result.size() == orig_size);
+  return result;
+}
+
+// Generates a benchmark and a codegen method for the provided types.  The
+// codegen method provides a well known entrypoint for dumping assembly.
+#define MAKE_BENCHMARK(hash, name, ...)                          \
+  namespace {                                                    \
+  void BM_##hash##_##name(benchmark::State& state) {             \
+    RunBenchmark<hash>(state, __VA_ARGS__);                      \
+  }                                                              \
+  BENCHMARK(BM_##hash##_##name);                                 \
+  }                                                              \
+  size_t Codegen##hash##name(const decltype(__VA_ARGS__)& arg);  \
+  size_t Codegen##hash##name(const decltype(__VA_ARGS__)& arg) { \
+    return hash<decltype(__VA_ARGS__)>{}(arg);                   \
+  }                                                              \
+  bool absl_hash_test_odr_use##hash##name =                      \
+      ODRUseFunction(&Codegen##hash##name);
+
+MAKE_BENCHMARK(AbslHash, Int32, int32_t{});
+MAKE_BENCHMARK(AbslHash, Int64, int64_t{});
+MAKE_BENCHMARK(AbslHash, Double, 1.2);
+MAKE_BENCHMARK(AbslHash, DoubleZero, 0.0);
+MAKE_BENCHMARK(AbslHash, PairInt32Int32, std::pair<int32_t, int32_t>{});
+MAKE_BENCHMARK(AbslHash, PairInt64Int64, std::pair<int64_t, int64_t>{});
+MAKE_BENCHMARK(AbslHash, TupleInt32BoolInt64,
+               std::tuple<int32_t, bool, int64_t>{});
+MAKE_BENCHMARK(AbslHash, String_0, std::string());
+MAKE_BENCHMARK(AbslHash, String_10, std::string(10, 'a'));
+MAKE_BENCHMARK(AbslHash, String_30, std::string(30, 'a'));
+MAKE_BENCHMARK(AbslHash, String_90, std::string(90, 'a'));
+MAKE_BENCHMARK(AbslHash, String_200, std::string(200, 'a'));
+MAKE_BENCHMARK(AbslHash, String_5000, std::string(5000, 'a'));
+MAKE_BENCHMARK(AbslHash, Cord_Flat_0, absl::Cord());
+MAKE_BENCHMARK(AbslHash, Cord_Flat_10, FlatCord(10));
+MAKE_BENCHMARK(AbslHash, Cord_Flat_30, FlatCord(30));
+MAKE_BENCHMARK(AbslHash, Cord_Flat_90, FlatCord(90));
+MAKE_BENCHMARK(AbslHash, Cord_Flat_200, FlatCord(200));
+MAKE_BENCHMARK(AbslHash, Cord_Flat_5000, FlatCord(5000));
+MAKE_BENCHMARK(AbslHash, Cord_Fragmented_200, FragmentedCord(200));
+MAKE_BENCHMARK(AbslHash, Cord_Fragmented_5000, FragmentedCord(5000));
+MAKE_BENCHMARK(AbslHash, VectorInt64_10, std::vector<int64_t>(10));
+MAKE_BENCHMARK(AbslHash, VectorInt64_100, std::vector<int64_t>(100));
+MAKE_BENCHMARK(AbslHash, VectorDouble_10, std::vector<double>(10, 1.1));
+MAKE_BENCHMARK(AbslHash, VectorDouble_100, std::vector<double>(100, 1.1));
+MAKE_BENCHMARK(AbslHash, PairStringString_0,
+               std::make_pair(std::string(), std::string()));
+MAKE_BENCHMARK(AbslHash, PairStringString_10,
+               std::make_pair(std::string(10, 'a'), std::string(10, 'b')));
+MAKE_BENCHMARK(AbslHash, PairStringString_30,
+               std::make_pair(std::string(30, 'a'), std::string(30, 'b')));
+MAKE_BENCHMARK(AbslHash, PairStringString_90,
+               std::make_pair(std::string(90, 'a'), std::string(90, 'b')));
+MAKE_BENCHMARK(AbslHash, PairStringString_200,
+               std::make_pair(std::string(200, 'a'), std::string(200, 'b')));
+MAKE_BENCHMARK(AbslHash, PairStringString_5000,
+               std::make_pair(std::string(5000, 'a'), std::string(5000, 'b')));
+
+MAKE_BENCHMARK(TypeErasedAbslHash, Int32, int32_t{});
+MAKE_BENCHMARK(TypeErasedAbslHash, Int64, int64_t{});
+MAKE_BENCHMARK(TypeErasedAbslHash, PairInt32Int32,
+               std::pair<int32_t, int32_t>{});
+MAKE_BENCHMARK(TypeErasedAbslHash, PairInt64Int64,
+               std::pair<int64_t, int64_t>{});
+MAKE_BENCHMARK(TypeErasedAbslHash, TupleInt32BoolInt64,
+               std::tuple<int32_t, bool, int64_t>{});
+MAKE_BENCHMARK(TypeErasedAbslHash, String_0, std::string());
+MAKE_BENCHMARK(TypeErasedAbslHash, String_10, std::string(10, 'a'));
+MAKE_BENCHMARK(TypeErasedAbslHash, String_30, std::string(30, 'a'));
+MAKE_BENCHMARK(TypeErasedAbslHash, String_90, std::string(90, 'a'));
+MAKE_BENCHMARK(TypeErasedAbslHash, String_200, std::string(200, 'a'));
+MAKE_BENCHMARK(TypeErasedAbslHash, String_5000, std::string(5000, 'a'));
+MAKE_BENCHMARK(TypeErasedAbslHash, VectorDouble_10,
+               std::vector<double>(10, 1.1));
+MAKE_BENCHMARK(TypeErasedAbslHash, VectorDouble_100,
+               std::vector<double>(100, 1.1));
+
+// The latency benchmark attempts to model the speed of the hash function in
+// production. When a hash function is used for hashtable lookups it is rarely
+// used to hash N items in a tight loop nor on constant sized strings. Instead,
+// after hashing there is a potential equality test plus a (usually) large
+// amount of user code. To simulate this effectively we introduce a data
+// dependency between elements we hash by using the hash of the Nth element as
+// the selector of the N+1th element to hash. This isolates the hash function
+// code much like in production. As a bonus we use the hash to generate strings
+// of size [1,N] (instead of fixed N) to disable perfect branch predictions in
+// hash function implementations.
+namespace {
+// 16kb fits in L1 cache of most CPUs we care about. Keeping memory latency low
+// will allow us to attribute most time to CPU which means more accurate
+// measurements.
+static constexpr size_t kEntropySize = 16 << 10;
+static char entropy[kEntropySize + 1024];
+ABSL_ATTRIBUTE_UNUSED static const bool kInitialized = [] {
+  absl::BitGen gen;
+  static_assert(sizeof(entropy) % sizeof(uint64_t) == 0, "");
+  for (int i = 0; i != sizeof(entropy); i += sizeof(uint64_t)) {
+    auto rand = absl::Uniform<uint64_t>(gen);
+    memcpy(&entropy[i], &rand, sizeof(uint64_t));
+  }
+  return true;
+}();
+}  // namespace
+
+template <class T>
+struct PodRand {
+  static_assert(std::is_pod<T>::value, "");
+  static_assert(kEntropySize + sizeof(T) < sizeof(entropy), "");
+
+  T Get(size_t i) const {
+    T v;
+    memcpy(&v, &entropy[i % kEntropySize], sizeof(T));
+    return v;
+  }
+};
+
+template <size_t N>
+struct StringRand {
+  static_assert(kEntropySize + N < sizeof(entropy), "");
+
+  absl::string_view Get(size_t i) const {
+    // This has a small bias towards small numbers. Because max N is ~200 this
+    // is very small and prefer to be very fast instead of absolutely accurate.
+    // Also we pass N = 2^K+1 so that mod reduces to a bitand.
+    size_t s = (i % (N - 1)) + 1;
+    return {&entropy[i % kEntropySize], s};
+  }
+};
+
+#define MAKE_LATENCY_BENCHMARK(hash, name, ...)              \
+  namespace {                                                \
+  void BM_latency_##hash##_##name(benchmark::State& state) { \
+    __VA_ARGS__ r;                                           \
+    hash<decltype(r.Get(0))> h;                              \
+    size_t i = 871401241;                                    \
+    for (auto _ : state) {                                   \
+      benchmark::DoNotOptimize(i = h(r.Get(i)));             \
+    }                                                        \
+  }                                                          \
+  BENCHMARK(BM_latency_##hash##_##name);                     \
+  }  // namespace
+
+MAKE_LATENCY_BENCHMARK(AbslHash, Int32, PodRand<int32_t>);
+MAKE_LATENCY_BENCHMARK(AbslHash, Int64, PodRand<int64_t>);
+MAKE_LATENCY_BENCHMARK(AbslHash, String9, StringRand<9>);
+MAKE_LATENCY_BENCHMARK(AbslHash, String33, StringRand<33>);
+MAKE_LATENCY_BENCHMARK(AbslHash, String65, StringRand<65>);
+MAKE_LATENCY_BENCHMARK(AbslHash, String257, StringRand<257>);
diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc
index f02a537..1d2e6cf 100644
--- a/absl/hash/hash_test.cc
+++ b/absl/hash/hash_test.cc
@@ -42,6 +42,7 @@
 #include "absl/hash/internal/spy_hash_state.h"
 #include "absl/meta/type_traits.h"
 #include "absl/numeric/int128.h"
+#include "absl/strings/cord_test_helpers.h"
 
 namespace {
 
@@ -81,8 +82,8 @@
 }
 
 REGISTER_TYPED_TEST_CASE_P(HashValueIntTest, BasicUsage, FastPath);
-using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t, uint32_t,
-                                uint64_t, size_t>;
+using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t,
+                                uint32_t, uint64_t, size_t>;
 INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueIntTest, IntTypes);
 
 enum LegacyEnum { kValue1, kValue2, kValue3 };
@@ -269,6 +270,22 @@
   }
 };
 
+absl::Cord FlatCord(absl::string_view sv) {
+  absl::Cord c(sv);
+  c.Flatten();
+  return c;
+}
+
+absl::Cord FragmentedCord(absl::string_view sv) {
+  if (sv.size() < 2) {
+    return absl::Cord(sv);
+  }
+  size_t halfway = sv.size() / 2;
+  std::vector<absl::string_view> parts = {sv.substr(0, halfway),
+                                          sv.substr(halfway)};
+  return absl::MakeFragmentedCord(parts);
+}
+
 TEST(HashValueTest, Strings) {
   EXPECT_TRUE((is_hashable<std::string>::value));
 
@@ -277,25 +294,29 @@
   const std::string large = std::string(2048, 'x');  // multiple of chunk size
   const std::string huge = std::string(5000, 'a');   // not a multiple
 
-  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
-      std::string(), absl::string_view(),
-      std::string(""), absl::string_view(""),
-      std::string(small), absl::string_view(small),
-      std::string(dup), absl::string_view(dup),
-      std::string(large), absl::string_view(large),
-      std::string(huge), absl::string_view(huge))));
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(  //
+      std::string(), absl::string_view(), absl::Cord(),                     //
+      std::string(""), absl::string_view(""), absl::Cord(""),               //
+      std::string(small), absl::string_view(small), absl::Cord(small),      //
+      std::string(dup), absl::string_view(dup), absl::Cord(dup),            //
+      std::string(large), absl::string_view(large), absl::Cord(large),      //
+      std::string(huge), absl::string_view(huge), FlatCord(huge),           //
+      FragmentedCord(huge))));
 
   // Also check that nested types maintain the same hash.
   const WrapInTuple t{};
-  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
-      t(std::string()), t(absl::string_view()),
-      t(std::string("")), t(absl::string_view("")),
-      t(std::string(small)), t(absl::string_view(small)),
-      t(std::string(dup)), t(absl::string_view(dup)),
-      t(std::string(large)), t(absl::string_view(large)),
-      t(std::string(huge)), t(absl::string_view(huge)))));
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(  //
+      t(std::string()), t(absl::string_view()), t(absl::Cord()),            //
+      t(std::string("")), t(absl::string_view("")), t(absl::Cord("")),      //
+      t(std::string(small)), t(absl::string_view(small)),                   //
+          t(absl::Cord(small)),                                             //
+      t(std::string(dup)), t(absl::string_view(dup)), t(absl::Cord(dup)),   //
+      t(std::string(large)), t(absl::string_view(large)),                   //
+          t(absl::Cord(large)),                                             //
+      t(std::string(huge)), t(absl::string_view(huge)),                     //
+          t(FlatCord(huge)), t(FragmentedCord(huge)))));
 
-  // Make sure that hashing a `const char*` does not use its std::string-value.
+  // Make sure that hashing a `const char*` does not use its string-value.
   EXPECT_NE(SpyHash(static_cast<const char*>("ABC")),
             SpyHash(absl::string_view("ABC")));
 }
@@ -386,7 +407,7 @@
 INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueSequenceTest, IntSequenceTypes);
 
 // Private type that only supports AbslHashValue to make sure our chosen hash
-// implentation is recursive within absl::Hash.
+// implementation is recursive within absl::Hash.
 // It uses std::abs() on the value to provide different bitwise representations
 // of the same logical value.
 struct Private {
@@ -491,7 +512,7 @@
     SCOPED_TRACE(big_buffer_size);
     std::string big_buffer;
     for (int i = 0; i < big_buffer_size; ++i) {
-      // Arbitrary std::string
+      // Arbitrary string
       big_buffer.push_back(32 + (i * (i / 3)) % 64);
     }
     auto big_buffer_hash = hash(PiecewiseHashTester(big_buffer));
@@ -560,6 +581,24 @@
       MM{{1, "foo"}, {1, "foo"}, {43, "bar"}}, MM{{1, "foo"}, {43, "baz"}})));
 }
 
+TEST(HashValueTest, ReferenceWrapper) {
+  EXPECT_TRUE(is_hashable<std::reference_wrapper<Private>>::value);
+
+  Private p1{1}, p10{10};
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+      p1, p10, std::ref(p1), std::ref(p10), std::cref(p1), std::cref(p10))));
+
+  EXPECT_TRUE(is_hashable<std::reference_wrapper<int>>::value);
+  int one = 1, ten = 10;
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+      one, ten, std::ref(one), std::ref(ten), std::cref(one), std::cref(ten))));
+
+  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+      std::make_tuple(std::tuple<std::reference_wrapper<int>>(std::ref(one)),
+                      std::tuple<std::reference_wrapper<int>>(std::ref(ten)),
+                      std::tuple<int>(one), std::tuple<int>(ten))));
+}
+
 template <typename T, typename = void>
 struct IsHashCallable : std::false_type {};
 
@@ -780,8 +819,8 @@
 }
 
 REGISTER_TYPED_TEST_CASE_P(HashIntTest, BasicUsage);
-using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t, uint32_t,
-                                uint64_t, size_t>;
+using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t,
+                                uint32_t, uint64_t, size_t>;
 INSTANTIATE_TYPED_TEST_CASE_P(My, HashIntTest, IntTypes);
 
 struct StructWithPadding {
diff --git a/absl/hash/internal/city.cc b/absl/hash/internal/city.cc
index e122c18..5460134 100644
--- a/absl/hash/internal/city.cc
+++ b/absl/hash/internal/city.cc
@@ -200,10 +200,6 @@
 
 static uint64_t ShiftMix(uint64_t val) { return val ^ (val >> 47); }
 
-static uint64_t HashLen16(uint64_t u, uint64_t v) {
-  return Hash128to64(uint128(u, v));
-}
-
 static uint64_t HashLen16(uint64_t u, uint64_t v, uint64_t mul) {
   // Murmur-inspired hashing.
   uint64_t a = (u ^ v) * mul;
@@ -214,6 +210,11 @@
   return b;
 }
 
+static uint64_t HashLen16(uint64_t u, uint64_t v) {
+  const uint64_t kMul = 0x9ddfea08eb382d69ULL;
+  return HashLen16(u, v, kMul);
+}
+
 static uint64_t HashLen0to16(const char *s, size_t len) {
   if (len >= 8) {
     uint64_t mul = k2 + len * 2;
@@ -253,9 +254,8 @@
 
 // Return a 16-byte hash for 48 bytes.  Quick and dirty.
 // Callers do best to use "random-looking" values for a and b.
-static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(uint64_t w, uint64_t x,
-                                                        uint64_t y, uint64_t z,
-                                                        uint64_t a, uint64_t b) {
+static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(
+    uint64_t w, uint64_t x, uint64_t y, uint64_t z, uint64_t a, uint64_t b) {
   a += w;
   b = Rotate(b + a + z, 21);
   uint64_t c = a;
@@ -266,8 +266,9 @@
 }
 
 // Return a 16-byte hash for s[0] ... s[31], a, and b.  Quick and dirty.
-static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(const char *s, uint64_t a,
-                                                        uint64_t b) {
+static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(const char *s,
+                                                            uint64_t a,
+                                                            uint64_t b) {
   return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16),
                                 Fetch64(s + 24), a, b);
 }
@@ -310,8 +311,10 @@
   uint64_t x = Fetch64(s + len - 40);
   uint64_t y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
   uint64_t z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
-  std::pair<uint64_t, uint64_t> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
-  std::pair<uint64_t, uint64_t> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
+  std::pair<uint64_t, uint64_t> v =
+      WeakHashLen32WithSeeds(s + len - 64, len, z);
+  std::pair<uint64_t, uint64_t> w =
+      WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
   x = x * k1 + Fetch64(s);
 
   // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
@@ -337,7 +340,7 @@
 }
 
 uint64_t CityHash64WithSeeds(const char *s, size_t len, uint64_t seed0,
-                           uint64_t seed1) {
+                             uint64_t seed1) {
   return HashLen16(CityHash64(s, len) - seed0, seed1);
 }
 
diff --git a/absl/hash/internal/city.h b/absl/hash/internal/city.h
index 161c774..393da0b 100644
--- a/absl/hash/internal/city.h
+++ b/absl/hash/internal/city.h
@@ -56,11 +56,6 @@
 ABSL_NAMESPACE_BEGIN
 namespace hash_internal {
 
-typedef std::pair<uint64_t, uint64_t> uint128;
-
-inline uint64_t Uint128Low64(const uint128 &x) { return x.first; }
-inline uint64_t Uint128High64(const uint128 &x) { return x.second; }
-
 // Hash function for a byte array.
 uint64_t CityHash64(const char *s, size_t len);
 
@@ -71,24 +66,11 @@
 // Hash function for a byte array.  For convenience, two seeds are also
 // hashed into the result.
 uint64_t CityHash64WithSeeds(const char *s, size_t len, uint64_t seed0,
-                           uint64_t seed1);
+                             uint64_t seed1);
 
 // Hash function for a byte array.  Most useful in 32-bit binaries.
 uint32_t CityHash32(const char *s, size_t len);
 
-// Hash 128 input bits down to 64 bits of output.
-// This is intended to be a reasonably good hash function.
-inline uint64_t Hash128to64(const uint128 &x) {
-  // Murmur-inspired hashing.
-  const uint64_t kMul = 0x9ddfea08eb382d69ULL;
-  uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul;
-  a ^= (a >> 47);
-  uint64_t b = (Uint128High64(x) ^ a) * kMul;
-  b ^= (b >> 47);
-  b *= kMul;
-  return b;
-}
-
 }  // namespace hash_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/hash/internal/hash.cc b/absl/hash/internal/hash.cc
index b44ecb3..1433eb9 100644
--- a/absl/hash/internal/hash.cc
+++ b/absl/hash/internal/hash.cc
@@ -18,9 +18,9 @@
 ABSL_NAMESPACE_BEGIN
 namespace hash_internal {
 
-uint64_t CityHashState::CombineLargeContiguousImpl32(uint64_t state,
-                                                     const unsigned char* first,
-                                                     size_t len) {
+uint64_t HashState::CombineLargeContiguousImpl32(uint64_t state,
+                                                 const unsigned char* first,
+                                                 size_t len) {
   while (len >= PiecewiseChunkSize()) {
     state =
         Mix(state, absl::hash_internal::CityHash32(reinterpret_cast<const char*>(first),
@@ -33,13 +33,11 @@
                                std::integral_constant<int, 4>{});
 }
 
-uint64_t CityHashState::CombineLargeContiguousImpl64(uint64_t state,
-                                                     const unsigned char* first,
-                                                     size_t len) {
+uint64_t HashState::CombineLargeContiguousImpl64(uint64_t state,
+                                                 const unsigned char* first,
+                                                 size_t len) {
   while (len >= PiecewiseChunkSize()) {
-    state =
-        Mix(state, absl::hash_internal::CityHash64(reinterpret_cast<const char*>(first),
-                                         PiecewiseChunkSize()));
+    state = Mix(state, Hash64(first, PiecewiseChunkSize()));
     len -= PiecewiseChunkSize();
     first += PiecewiseChunkSize();
   }
@@ -48,7 +46,24 @@
                                std::integral_constant<int, 8>{});
 }
 
-ABSL_CONST_INIT const void* const CityHashState::kSeed = &kSeed;
+ABSL_CONST_INIT const void* const HashState::kSeed = &kSeed;
+
+// The salt array used by Wyhash. This array is NOT the mechanism used to make
+// absl::Hash non-deterministic between program invocations.  See `Seed()` for
+// that mechanism.
+//
+// Any random values are fine. These values are just digits from the decimal
+// part of pi.
+// https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number
+constexpr uint64_t kWyhashSalt[5] = {
+    uint64_t{0x243F6A8885A308D3}, uint64_t{0x13198A2E03707344},
+    uint64_t{0xA4093822299F31D0}, uint64_t{0x082EFA98EC4E6C89},
+    uint64_t{0x452821E638D01377},
+};
+
+uint64_t HashState::WyhashImpl(const unsigned char* data, size_t len) {
+  return Wyhash(data, len, Seed(), kWyhashSalt);
+}
 
 }  // namespace hash_internal
 ABSL_NAMESPACE_END
diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h
index ae7a60c..7fb0af0 100644
--- a/absl/hash/internal/hash.h
+++ b/absl/hash/internal/hash.h
@@ -38,9 +38,11 @@
 #include <utility>
 #include <vector>
 
-#include "absl/base/internal/endian.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/unaligned_access.h"
 #include "absl/base/port.h"
 #include "absl/container/fixed_array.h"
+#include "absl/hash/internal/wyhash.h"
 #include "absl/meta/type_traits.h"
 #include "absl/numeric/int128.h"
 #include "absl/strings/string_view.h"
@@ -53,12 +55,65 @@
 ABSL_NAMESPACE_BEGIN
 namespace hash_internal {
 
-class PiecewiseCombiner;
-
 // Internal detail: Large buffers are hashed in smaller chunks.  This function
 // 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:
+//
+//   H add_buffer(state, data, size)
+//   H finalize(state)
+//
+// `add_buffer` can be called zero or more times, followed by a single call to
+// `finalize`.  This will produce the same hash expansion as concatenating each
+// buffer piece into a single contiguous buffer, and passing this to
+// `H::combine_contiguous`.
+//
+//  Example usage:
+//    PiecewiseCombiner combiner;
+//    for (const auto& piece : pieces) {
+//      state = combiner.add_buffer(std::move(state), piece.data, piece.size);
+//    }
+//    return combiner.finalize(std::move(state));
+class PiecewiseCombiner {
+ public:
+  PiecewiseCombiner() : position_(0) {}
+  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>
+  H add_buffer(H state, const unsigned char* data, size_t size);
+  template <typename H>
+  H add_buffer(H state, const char* data, size_t size) {
+    return add_buffer(std::move(state),
+                      reinterpret_cast<const unsigned char*>(data), size);
+  }
+
+  // PiecewiseCombiner::finalize()
+  //
+  // Finishes combining the hash sequence, which may may modify the provided
+  // hash state.
+  //
+  // Once finalize() is called, add_buffer() may no longer be called. The
+  // resulting hash state will be the same as if the pieces passed to
+  // add_buffer() were concatenated into a single flat buffer, and then provided
+  // to H::combine_contiguous().
+  template <typename H>
+  H finalize(H state);
+
+ private:
+  unsigned char buf_[PiecewiseChunkSize()];
+  size_t position_;
+};
+
 // HashStateBase
 //
 // A hash state object represents an intermediate state in the computation
@@ -125,8 +180,7 @@
   template <typename T>
   static H combine_contiguous(H state, const T* data, size_t size);
 
- private:
-  friend class PiecewiseCombiner;
+  using AbslInternalPiecewiseCombiner = PiecewiseCombiner;
 };
 
 // is_uniquely_represented
@@ -197,61 +251,6 @@
   return H::combine_contiguous(std::move(hash_state), start, sizeof(value));
 }
 
-// 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:
-//
-//   H add_buffer(state, data, size)
-//   H finalize(state)
-//
-// `add_buffer` can be called zero or more times, followed by a single call to
-// `finalize`.  This will produce the same hash expansion as concatenating each
-// buffer piece into a single contiguous buffer, and passing this to
-// `H::combine_contiguous`.
-//
-//  Example usage:
-//    PiecewiseCombiner combiner;
-//    for (const auto& piece : pieces) {
-//      state = combiner.add_buffer(std::move(state), piece.data, piece.size);
-//    }
-//    return combiner.finalize(std::move(state));
-class PiecewiseCombiner {
- public:
-  PiecewiseCombiner() : position_(0) {}
-  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>
-  H add_buffer(H state, const unsigned char* data, size_t size);
-  template <typename H>
-  H add_buffer(H state, const char* data, size_t size) {
-    return add_buffer(std::move(state),
-                      reinterpret_cast<const unsigned char*>(data), size);
-  }
-
-  // PiecewiseCombiner::finalize()
-  //
-  // Finishes combining the hash sequence, which may may modify the provided
-  // hash state.
-  //
-  // Once finalize() is called, add_buffer() may no longer be called. The
-  // resulting hash state will be the same as if the pieces passed to
-  // add_buffer() were concatenated into a single flat buffer, and then provided
-  // to H::combine_contiguous().
-  template <typename H>
-  H finalize(H state);
-
- private:
-  unsigned char buf_[PiecewiseChunkSize()];
-  size_t position_;
-};
-
 // -----------------------------------------------------------------------------
 // AbslHashValue for Basic Types
 // -----------------------------------------------------------------------------
@@ -413,6 +412,7 @@
 // All the string-like types supported here provide the same hash expansion for
 // the same character sequence. These types are:
 //
+//  - `absl::Cord`
 //  - `std::string` (and std::basic_string<char, std::char_traits<char>, A> for
 //      any allocator A)
 //  - `absl::string_view` and `std::string_view`
@@ -553,6 +553,13 @@
 // AbslHashValue for Wrapper Types
 // -----------------------------------------------------------------------------
 
+// AbslHashValue for hashing std::reference_wrapper
+template <typename H, typename T>
+typename std::enable_if<is_hashable<T>::value, H>::type AbslHashValue(
+    H hash_state, std::reference_wrapper<T> opt) {
+  return H::combine(std::move(hash_state), opt.get());
+}
+
 // AbslHashValue for hashing absl::optional
 template <typename H, typename T>
 typename std::enable_if<is_hashable<T>::value, H>::type AbslHashValue(
@@ -707,9 +714,8 @@
 struct is_hashable
     : std::integral_constant<bool, HashSelect::template Apply<T>::value> {};
 
-// CityHashState
-class ABSL_DLL CityHashState
-    : public HashStateBase<CityHashState> {
+// HashState
+class ABSL_DLL HashState : public HashStateBase<HashState> {
   // 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
@@ -728,23 +734,22 @@
 
  public:
   // Move only
-  CityHashState(CityHashState&&) = default;
-  CityHashState& operator=(CityHashState&&) = default;
+  HashState(HashState&&) = default;
+  HashState& operator=(HashState&&) = default;
 
-  // CityHashState::combine_contiguous()
+  // HashState::combine_contiguous()
   //
   // Fundamental base case for hash recursion: mixes the given range of bytes
   // into the hash state.
-  static CityHashState combine_contiguous(CityHashState hash_state,
-                                          const unsigned char* first,
-                                          size_t size) {
-    return CityHashState(
+  static HashState combine_contiguous(HashState hash_state,
+                                      const unsigned char* first, size_t size) {
+    return HashState(
         CombineContiguousImpl(hash_state.state_, first, size,
                               std::integral_constant<int, sizeof(size_t)>{}));
   }
-  using CityHashState::HashStateBase::combine_contiguous;
+  using HashState::HashStateBase::combine_contiguous;
 
-  // CityHashState::hash()
+  // HashState::hash()
   //
   // For performance reasons in non-opt mode, we specialize this for
   // integral types.
@@ -756,24 +761,24 @@
     return static_cast<size_t>(Mix(Seed(), static_cast<uint64_t>(value)));
   }
 
-  // Overload of CityHashState::hash()
+  // Overload of HashState::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(CityHashState{}, value).state_);
+    return static_cast<size_t>(combine(HashState{}, 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.
-  CityHashState() : state_(Seed()) {}
+  HashState() : 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.
-  CityHashState(const CityHashState&) = default;
+  HashState(const HashState&) = default;
 
-  explicit CityHashState(uint64_t state) : state_(state) {}
+  explicit HashState(uint64_t state) : state_(state) {}
 
   // Implementation of the base case for combine_contiguous where we actually
   // mix the bytes into the state.
@@ -786,7 +791,8 @@
   static uint64_t CombineContiguousImpl(uint64_t state,
                                         const unsigned char* first, size_t len,
                                         std::integral_constant<int, 8>
-                                        /* sizeof_size_t*/);
+                                        /* sizeof_size_t */);
+
 
   // Slow dispatch path for calls to CombineContiguousImpl with a size argument
   // larger than PiecewiseChunkSize().  Has the same effect as calling
@@ -799,26 +805,54 @@
                                                size_t len);
 
   // Reads 9 to 16 bytes from p.
-  // The first 8 bytes are in .first, the rest (zero padded) bytes are in
-  // .second.
+  // The least significant 8 bytes are in .first, the rest (zero padded) bytes
+  // are in .second.
   static std::pair<uint64_t, uint64_t> Read9To16(const unsigned char* p,
                                                  size_t len) {
-    uint64_t high = little_endian::Load64(p + len - 8);
-    return {little_endian::Load64(p), high >> (128 - len * 8)};
+    uint64_t low_mem = absl::base_internal::UnalignedLoad64(p);
+    uint64_t high_mem = absl::base_internal::UnalignedLoad64(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 >> (128 - len * 8)};
   }
 
   // Reads 4 to 8 bytes from p. Zero pads to fill uint64_t.
   static uint64_t Read4To8(const unsigned char* p, size_t len) {
-    return (static_cast<uint64_t>(little_endian::Load32(p + len - 4))
-            << (len - 4) * 8) |
-           little_endian::Load32(p);
+    uint32_t low_mem = absl::base_internal::UnalignedLoad32(p);
+    uint32_t high_mem = absl::base_internal::UnalignedLoad32(p + len - 4);
+#ifdef ABSL_IS_LITTLE_ENDIAN
+    uint32_t most_significant = high_mem;
+    uint32_t least_significant = low_mem;
+#else
+    uint32_t most_significant = low_mem;
+    uint32_t least_significant = high_mem;
+#endif
+    return (static_cast<uint64_t>(most_significant) << (len - 4) * 8) |
+           least_significant;
   }
 
   // Reads 1 to 3 bytes from p. Zero pads to fill uint32_t.
   static uint32_t Read1To3(const unsigned char* p, size_t len) {
-    return static_cast<uint32_t>((p[0]) |                         //
-                                 (p[len / 2] << (len / 2 * 8)) |  //
-                                 (p[len - 1] << ((len - 1) * 8)));
+    unsigned char mem0 = p[0];
+    unsigned char mem1 = p[len / 2];
+    unsigned char mem2 = p[len - 1];
+#ifdef ABSL_IS_LITTLE_ENDIAN
+    unsigned char significant2 = mem2;
+    unsigned char significant1 = mem1;
+    unsigned char significant0 = mem0;
+#else
+    unsigned char significant2 = mem0;
+    unsigned char significant1 = mem1;
+    unsigned char significant0 = mem2;
+#endif
+    return static_cast<uint32_t>(significant0 |                     //
+                                 (significant1 << (len / 2 * 8)) |  //
+                                 (significant2 << ((len - 1) * 8)));
   }
 
   ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t Mix(uint64_t state, uint64_t v) {
@@ -833,6 +867,19 @@
     return static_cast<uint64_t>(m ^ (m >> (sizeof(m) * 8 / 2)));
   }
 
+  // An extern to avoid bloat on a direct call to Wyhash() with fixed values for
+  // both the seed and salt parameters.
+  static uint64_t WyhashImpl(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 WyhashImpl(data, len);
+#else
+    return absl::hash_internal::CityHash64(reinterpret_cast<const char*>(data), len);
+#endif
+  }
+
   // Seed()
   //
   // A non-deterministic seed.
@@ -850,15 +897,22 @@
   // 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__)
+    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
   }
   static const void* const kSeed;
 
   uint64_t state_;
 };
 
-// CityHashState::CombineContiguousImpl()
-inline uint64_t CityHashState::CombineContiguousImpl(
+// HashState::CombineContiguousImpl()
+inline uint64_t HashState::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
@@ -880,18 +934,18 @@
   return Mix(state, v);
 }
 
-// Overload of CityHashState::CombineContiguousImpl()
-inline uint64_t CityHashState::CombineContiguousImpl(
+// Overload of HashState::CombineContiguousImpl()
+inline uint64_t HashState::CombineContiguousImpl(
     uint64_t state, const unsigned char* first, size_t len,
     std::integral_constant<int, 8> /* sizeof_size_t */) {
-  // For large values we use CityHash, for small ones we just use a
-  // multiplicative hash.
+  // For large values we use Wyhash or CityHash depending on the platform, for
+  // small ones we just use a multiplicative hash.
   uint64_t v;
   if (len > 16) {
     if (ABSL_PREDICT_FALSE(len > PiecewiseChunkSize())) {
       return CombineLargeContiguousImpl64(state, first, len);
     }
-    v = absl::hash_internal::CityHash64(reinterpret_cast<const char*>(first), len);
+    v = Hash64(first, len);
   } else if (len > 8) {
     auto p = Read9To16(first, len);
     state = Mix(state, p.first);
@@ -922,7 +976,7 @@
 
 template <typename T>
 struct HashImpl {
-  size_t operator()(const T& value) const { return CityHashState::hash(value); }
+  size_t operator()(const T& value) const { return HashState::hash(value); }
 };
 
 template <typename T>
@@ -955,12 +1009,15 @@
     return state;
   }
 
-  // Complete the buffer and hash it
-  const size_t bytes_needed = PiecewiseChunkSize() - position_;
-  memcpy(buf_ + position_, data, bytes_needed);
-  state = H::combine_contiguous(std::move(state), buf_, PiecewiseChunkSize());
-  data += bytes_needed;
-  size -= bytes_needed;
+  // If the buffer is partially filled we need to complete the buffer
+  // and hash it.
+  if (position_ != 0) {
+    const size_t bytes_needed = PiecewiseChunkSize() - position_;
+    memcpy(buf_ + position_, data, bytes_needed);
+    state = H::combine_contiguous(std::move(state), buf_, PiecewiseChunkSize());
+    data += bytes_needed;
+    size -= bytes_needed;
+  }
 
   // Hash whatever chunks we can without copying
   while (size >= PiecewiseChunkSize()) {
diff --git a/absl/hash/internal/wyhash.cc b/absl/hash/internal/wyhash.cc
new file mode 100644
index 0000000..642bde4
--- /dev/null
+++ b/absl/hash/internal/wyhash.cc
@@ -0,0 +1,111 @@
+// 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/wyhash.h"
+
+#include "absl/base/internal/unaligned_access.h"
+#include "absl/numeric/int128.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace hash_internal {
+
+static uint64_t WyhashMix(uint64_t v0, uint64_t v1) {
+  absl::uint128 p = v0;
+  p *= v1;
+  return absl::Uint128Low64(p) ^ absl::Uint128High64(p);
+}
+
+uint64_t Wyhash(const void* data, size_t len, uint64_t seed,
+                const uint64_t salt[]) {
+  const uint8_t* ptr = static_cast<const uint8_t*>(data);
+  uint64_t starting_length = static_cast<uint64_t>(len);
+  uint64_t current_state = seed ^ salt[0];
+
+  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 two separate hash states
+    // which we will then hash together.
+    uint64_t duplicated_state = current_state;
+
+    do {
+      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);
+
+      uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state);
+      uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state);
+      current_state = (cs0 ^ cs1);
+
+      uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state);
+      uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state);
+      duplicated_state = (ds0 ^ ds1);
+
+      ptr += 64;
+      len -= 64;
+    } while (len > 64);
+
+    current_state = current_state ^ duplicated_state;
+  }
+
+  // We now have a data `ptr` with at most 64 bytes and the current state
+  // of the hashing state machine stored in current_state.
+  while (len > 16) {
+    uint64_t a = absl::base_internal::UnalignedLoad64(ptr);
+    uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8);
+
+    current_state = WyhashMix(a ^ salt[1], b ^ current_state);
+
+    ptr += 16;
+    len -= 16;
+  }
+
+  // We now have a data `ptr` with at most 16 bytes.
+  uint64_t a = 0;
+  uint64_t b = 0;
+  if (len > 8) {
+    // When we have at least 9 and at most 16 bytes, set A to the first 64
+    // bits of the input and B to the last 64 bits of the input. Yes, they will
+    // overlap in the middle if we are working with less than the full 16
+    // bytes.
+    a = absl::base_internal::UnalignedLoad64(ptr);
+    b = absl::base_internal::UnalignedLoad64(ptr + len - 8);
+  } else if (len > 3) {
+    // If we have at least 4 and at most 8 bytes, set A to the first 32
+    // bits and B to the last 32 bits.
+    a = absl::base_internal::UnalignedLoad32(ptr);
+    b = absl::base_internal::UnalignedLoad32(ptr + len - 4);
+  } else if (len > 0) {
+    // If we have at least 1 and at most 3 bytes, read all of the provided
+    // bits into A, with some adjustments.
+    a = ((ptr[0] << 16) | (ptr[len >> 1] << 8) | ptr[len - 1]);
+    b = 0;
+  } else {
+    a = 0;
+    b = 0;
+  }
+
+  uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state);
+  uint64_t z = salt[1] ^ starting_length;
+  return WyhashMix(w, z);
+}
+
+}  // namespace hash_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/hash/internal/wyhash.h b/absl/hash/internal/wyhash.h
new file mode 100644
index 0000000..4aff4e9
--- /dev/null
+++ b/absl/hash/internal/wyhash.h
@@ -0,0 +1,48 @@
+// 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 the Wyhash
+// algorithm.
+//
+// Wyhash 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.
+
+#ifndef ABSL_HASH_INTERNAL_WYHASH_H_
+#define ABSL_HASH_INTERNAL_WYHASH_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.
+//
+// To allow all hashable types (including string_view and Span) to depend on
+// this algoritm, we keep the API low-level, with as few dependencies as
+// possible.
+uint64_t Wyhash(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_WYHASH_H_
diff --git a/absl/hash/internal/wyhash_test.cc b/absl/hash/internal/wyhash_test.cc
new file mode 100644
index 0000000..9fb06d2
--- /dev/null
+++ b/absl/hash/internal/wyhash_test.cc
@@ -0,0 +1,486 @@
+// 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/wyhash.h"
+
+#include "absl/strings/escaping.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+static const uint64_t kCurrentSeed = 0;
+static const uint64_t kSalt[5] = {0xa0761d6478bd642f, 0xe7037ed1a0b428dbl,
+                                  0x8ebc6af09c88c6e3, 0x589965cc75374cc3l,
+                                  0x1d8e4e27c47d124f};
+
+// Note: We don't account for endianness, so the values here are only correct if
+// you're also running on a little endian platform.
+
+TEST(WyhashTest, EmptyString) {
+  const std::string s = "";
+  EXPECT_EQ(
+      absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt),
+      4808886099364463827);
+}
+
+TEST(WyhashTest, Spaces) {
+  const std::string s = "   ";
+  EXPECT_EQ(
+      absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt),
+      1686201463024549249);
+}
+
+TEST(WyhashTest, RepeatingString) {
+  const std::string s = "aaaa";
+  EXPECT_EQ(
+      absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt),
+      6646112255271966632);
+}
+
+TEST(WyhashTest, HexString) {
+  const std::string small = "\x01\x02\x03";
+  const std::string med = "\x01\x02\x03\x04";
+
+  EXPECT_EQ(absl::hash_internal::Wyhash(small.c_str(), small.length(),
+                                        kCurrentSeed, kSalt),
+            11989428023081740911ULL);
+  EXPECT_EQ(absl::hash_internal::Wyhash(med.c_str(), med.length(), kCurrentSeed,
+                                        kSalt),
+            9765997711188871556ULL);
+}
+
+TEST(WyhashTest, Words) {
+  const std::string s = "third_party|wyhash|64";
+  EXPECT_EQ(
+      absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt),
+      3702018632387611330);
+}
+
+TEST(WyhashTest, LongString) {
+  const std::string s =
+      "AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvWxYz"
+      "0123456789AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOp"
+      "QrStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEf"
+      "GhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvWxYz012345"
+      "6789AbCdEfGhIjKlMnOpQrStUvWxYz0123456789";
+
+  EXPECT_EQ(
+      absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt),
+      9245411362605796064ULL);
+}
+
+TEST(WyhashTest, BigReference) {
+  struct ExpectedResult {
+    absl::string_view base64_data;
+    uint64_t seed;
+    uint64_t hash;
+  } expected_results[] = {
+      {"", uint64_t{0xec42b7ab404b8acb}, uint64_t{0xe5a40d39ab796423}},
+      {"Zw==", uint64_t{0xeeee074043a3ee0f}, uint64_t{0xa6564b468248c683}},
+      {"xmk=", uint64_t{0x857902089c393de}, uint64_t{0xef192f401b116e1c}},
+      {"c1H/", uint64_t{0x993df040024ca3af}, uint64_t{0xbe8dc0c54617639d}},
+      {"SuwpzQ==", uint64_t{0xc4e4c2acea740e96}, uint64_t{0x93d7f665b5521c8e}},
+      {"uqvy++M=", uint64_t{0x6a214b3db872d0cf}, uint64_t{0x646d70bb42445f28}},
+      {"RnzCVPgb", uint64_t{0x44343db6a89dba4d}, uint64_t{0x96a7b1e3cc9bd426}},
+      {"6OeNdlouYw==", uint64_t{0x77b5d6d1ae1dd483},
+       uint64_t{0x76020289ab0790c4}},
+      {"M5/JmmYyDbc=", uint64_t{0x89ab8ecb44d221f1},
+       uint64_t{0x39f842e4133b9b44}},
+      {"MVijWiVdBRdY", uint64_t{0x60244b17577ca81b},
+       uint64_t{0x2b8d7047be4bcaab}},
+      {"6V7Uq7LNxpu0VA==", uint64_t{0x59a08dcee0717067},
+       uint64_t{0x99628abef6716a97}},
+      {"EQ6CdEEhPdyHcOk=", uint64_t{0xf5f20db3ade57396},
+       uint64_t{0x4432e02ba42b2740}},
+      {"PqFB4fxnPgF+l+rc", uint64_t{0xbf8dee0751ad3efb},
+       uint64_t{0x74d810efcad7918a}},
+      {"a5aPOFwq7LA7+zKvPA==", uint64_t{0x6b7a06b268d63e30},
+       uint64_t{0x88c84e986002507f}},
+      {"VOwY21wCGv5D+/qqOvs=", uint64_t{0xb8c37f0ae0f54c82},
+       uint64_t{0x4f99acf193cf39b9}},
+      {"KdHmBTx8lHXYvmGJ+Vy7", uint64_t{0x9fcbed0c38e50eef},
+       uint64_t{0xd90e7a3655891e37}},
+      {"qJkPlbHr8bMF7/cA6aE65Q==", uint64_t{0x2af4bade1d8e3a1d},
+       uint64_t{0x3bb378b1d4df8fcf}},
+      {"ygvL0EhHZL0fIx6oHHtkxRQ=", uint64_t{0x714e3aa912da2f2c},
+       uint64_t{0xf78e94045c052d47}},
+      {"c1rFXkt5YztwZCQRngncqtSs", uint64_t{0xf5ee75e3cbb82c1c},
+       uint64_t{0x26da0b2130da6b40}},
+      {"8hsQrzszzeNQSEcVXLtvIhm6mw==", uint64_t{0x620e7007321b93b9},
+       uint64_t{0x30b4d426af8c6986}},
+      {"ffUL4RocfyP4KfikGxO1yk7omDI=", uint64_t{0xc08528cac2e551fc},
+       uint64_t{0x5413b4aaf3baaeae}},
+      {"OOB5TT00vF9Od/rLbAWshiErqhpV", uint64_t{0x6a1debf9cc3ad39},
+       uint64_t{0x756ab265370a1597}},
+      {"or5wtXM7BFzTNpSzr+Lw5J5PMhVJ/Q==", uint64_t{0x7e0a3c88111fc226},
+       uint64_t{0xdaf5f4b7d09814fb}},
+      {"gk6pCHDUsoopVEiaCrzVDhioRKxb844=", uint64_t{0x1301fef15df39edb},
+       uint64_t{0x8f874ae37742b75e}},
+      {"TNctmwlC5QbEM6/No4R/La3UdkfeMhzs", uint64_t{0x64e181f3d5817ab},
+       uint64_t{0x8fecd03956121ce8}},
+      {"SsQw9iAjhWz7sgcE9OwLuSC6hsM+BfHs2Q==", uint64_t{0xafafc44961078ecb},
+       uint64_t{0x229c292ea7a08285}},
+      {"ZzO3mVCj4xTT2TT3XqDyEKj2BZQBvrS8RHg=", uint64_t{0x4f7bb45549250094},
+       uint64_t{0xbb4bf0692d14bae}},
+      {"+klp5iPQGtppan5MflEls0iEUzqU+zGZkDJX", uint64_t{0xa30061abaa2818c},
+       uint64_t{0x207b24ca3bdac1db}},
+      {"RO6bvOnlJc8I9eniXlNgqtKy0IX6VNg16NRmgg==", uint64_t{0xd902ee3e44a5705f},
+       uint64_t{0x64f6cd6745d3825b}},
+      {"ZJjZqId1ZXBaij9igClE3nyliU5XWdNRrayGlYA=", uint64_t{0x316d36da516f583},
+       uint64_t{0xa2b2e1656b58df1e}},
+      {"7BfkhfGMDGbxfMB8uyL85GbaYQtjr2K8g7RpLzr/", uint64_t{0x402d83f9f834f616},
+       uint64_t{0xd01d30d9ee7a148}},
+      {"rycWk6wHH7htETQtje9PidS2YzXBx+Qkg2fY7ZYS7A==",
+       uint64_t{0x9c604164c016b72c}, uint64_t{0x1cb4cd00ab804e3b}},
+      {"RTkC2OUK+J13CdGllsH0H5WqgspsSa6QzRZouqx6pvI=",
+       uint64_t{0x3f4507e01f9e73ba}, uint64_t{0x4697f2637fd90999}},
+      {"tKjKmbLCNyrLCM9hycOAXm4DKNpM12oZ7dLTmUx5iwAi",
+       uint64_t{0xc3fe0d5be8d2c7c7}, uint64_t{0x8383a756b5688c07}},
+      {"VprUGNH+5NnNRaORxgH/ySrZFQFDL+4VAodhfBNinmn8cg==",
+       uint64_t{0x531858a40bfa7ea1}, uint64_t{0x695c29cb3696a975}},
+      {"gc1xZaY+q0nPcUvOOnWnT3bqfmT/geth/f7Dm2e/DemMfk4=",
+       uint64_t{0x86689478a7a7e8fa}, uint64_t{0xda2e5a5a5e971521}},
+      {"Mr35fIxqx1ukPAL0su1yFuzzAU3wABCLZ8+ZUFsXn47UmAph",
+       uint64_t{0x4ec948b8e7f27288}, uint64_t{0x7935d4befa056b2b}},
+      {"A9G8pw2+m7+rDtWYAdbl8tb2fT7FFo4hLi2vAsa5Y8mKH3CX3g==",
+       uint64_t{0xce46c7213c10032}, uint64_t{0x38dd541ca95420fe}},
+      {"DFaJGishGwEHDdj9ixbCoaTjz9KS0phLNWHVVdFsM93CvPft3hM=",
+       uint64_t{0xf63e96ee6f32a8b6}, uint64_t{0xcc06c7a4963f967f}},
+      {"7+Ugx+Kr3aRNgYgcUxru62YkTDt5Hqis+2po81hGBkcrJg4N0uuy",
+       uint64_t{0x1cfe85e65fc5225}, uint64_t{0xbf0f6f66e232fb20}},
+      {"H2w6O8BUKqu6Tvj2xxaecxEI2wRgIgqnTTG1WwOgDSINR13Nm4d4Vg==",
+       uint64_t{0x45c474f1cee1d2e8}, uint64_t{0xf7efb32d373fe71a}},
+      {"1XBMnIbqD5jy65xTDaf6WtiwtdtQwv1dCVoqpeKj+7cTR1SaMWMyI04=",
+       uint64_t{0x6e024e14015f329c}, uint64_t{0xe2e64634b1c12660}},
+      {"znZbdXG2TSFrKHEuJc83gPncYpzXGbAebUpP0XxzH0rpe8BaMQ17nDbt",
+       uint64_t{0x760c40502103ae1c}, uint64_t{0x285b8fd1638e306d}},
+      {"ylu8Atu13j1StlcC1MRMJJXIl7USgDDS22HgVv0WQ8hx/8pNtaiKB17hCQ==",
+       uint64_t{0x17fd05c3c560c320}, uint64_t{0x658e8a4e3b714d6c}},
+      {"M6ZVVzsd7vAvbiACSYHioH/440dp4xG2mLlBnxgiqEvI/aIEGpD0Sf4VS0g=",
+       uint64_t{0x8b34200a6f8e90d9}, uint64_t{0xf391fb968e0eb398}},
+      {"li3oFSXLXI+ubUVGJ4blP6mNinGKLHWkvGruun85AhVn6iuMtocbZPVhqxzn",
+       uint64_t{0x6be89e50818bdf69}, uint64_t{0x744a9ea0cc144bf2}},
+      {"kFuQHuUCqBF3Tc3hO4dgdIp223ShaCoog48d5Do5zMqUXOh5XpGK1t5XtxnfGA==",
+       uint64_t{0xfb389773315b47d8}, uint64_t{0x12636f2be11012f1}},
+      {"jWmOad0v0QhXVJd1OdGuBZtDYYS8wBVHlvOeTQx9ZZnm8wLEItPMeihj72E0nWY=",
+       uint64_t{0x4f2512a23f61efee}, uint64_t{0x29c57de825948f80}},
+      {"z+DHU52HaOQdW4JrZwDQAebEA6rm13Zg/9lPYA3txt3NjTBqFZlOMvTRnVzRbl23",
+       uint64_t{0x59ccd92fc16c6fda}, uint64_t{0x58c6f99ab0d1c021}},
+      {"MmBiGDfYeTayyJa/tVycg+rN7f9mPDFaDc+23j0TlW9094er0ADigsl4QX7V3gG/qw==",
+       uint64_t{0x25c5a7f5bd330919}, uint64_t{0x13e7b5a7b82fe3bb}},
+      {"774RK+9rOL4iFvs1q2qpo/JVc/I39buvNjqEFDtDvyoB0FXxPI2vXqOrk08VPfIHkmU=",
+       uint64_t{0x51df4174d34c97d7}, uint64_t{0x10fbc87901e02b63}},
+      {"+slatXiQ7/2lK0BkVUI1qzNxOOLP3I1iK6OfHaoxgqT63FpzbElwEXSwdsryq3UlHK0I",
+       uint64_t{0x80ce6d76f89cb57}, uint64_t{0xa24c9184901b748b}},
+      {"64mVTbQ47dHjHlOHGS/hjJwr/"
+       "K2frCNpn87exOqMzNUVYiPKmhCbfS7vBUce5tO6Ec9osQ==",
+       uint64_t{0x20961c911965f684}, uint64_t{0xcac4fd4c5080e581}},
+      {"fIsaG1r530SFrBqaDj1kqE0AJnvvK8MNEZbII2Yw1OK77v0V59xabIh0B5axaz/"
+       "+a2V5WpA=",
+       uint64_t{0x4e5b926ec83868e7}, uint64_t{0xc38bdb7483ba68e1}},
+      {"PGih0zDEOWCYGxuHGDFu9Ivbff/"
+       "iE7BNUq65tycTR2R76TerrXALRosnzaNYO5fjFhTi+CiS",
+       uint64_t{0x3927b30b922eecef}, uint64_t{0xdb2a8069b2ceaffa}},
+      {"RnpA/"
+       "zJnEnnLjmICORByRVb9bCOgxF44p3VMiW10G7PvW7IhwsWajlP9kIwNA9FjAD2GoQHk2Q="
+       "=",
+       uint64_t{0xbd0291284a49b61c}, uint64_t{0xdf9fe91d0d1c7887}},
+      {"qFklMceaTHqJpy2qavJE+EVBiNFOi6OxjOA3LeIcBop1K7w8xQi3TrDk+"
+       "BrWPRIbfprszSaPfrI=",
+       uint64_t{0x73a77c575bcc956}, uint64_t{0xe83f49e96e2e6a08}},
+      {"cLbfUtLl3EcQmITWoTskUR8da/VafRDYF/ylPYwk7/"
+       "zazk6ssyrzxMN3mmSyvrXR2yDGNZ3WDrTT",
+       uint64_t{0x766a0e2ade6d09a6}, uint64_t{0xc69e61b62ca2b62}},
+      {"s/"
+       "Jf1+"
+       "FbsbCpXWPTUSeWyMH6e4CvTFvPE5Fs6Z8hvFITGyr0dtukHzkI84oviVLxhM1xMxrMAy1db"
+       "w==",
+       uint64_t{0x2599f4f905115869}, uint64_t{0xb4a4f3f85f8298fe}},
+      {"FvyQ00+j7nmYZVQ8hI1Edxd0AWplhTfWuFGiu34AK5X8u2hLX1bE97sZM0CmeLe+"
+       "7LgoUT1fJ/axybE=",
+       uint64_t{0xd8256e5444d21e53}, uint64_t{0x167a1b39e1e95f41}},
+      {"L8ncxMaYLBH3g9buPu8hfpWZNlOF7nvWLNv9IozH07uQsIBWSKxoPy8+"
+       "LW4tTuzC6CIWbRGRRD1sQV/4",
+       uint64_t{0xf664a91333fb8dfd}, uint64_t{0xf8a2a5649855ee41}},
+      {"CDK0meI07yrgV2kQlZZ+"
+       "wuVqhc2NmzqeLH7bmcA6kchsRWFPeVF5Wqjjaj556ABeUoUr3yBmfU3kWOakkg==",
+       uint64_t{0x9625b859be372cd1}, uint64_t{0x27992565b595c498}},
+      {"d23/vc5ONh/"
+       "HkMiq+gYk4gaCNYyuFKwUkvn46t+dfVcKfBTYykr4kdvAPNXGYLjM4u1YkAEFpJP+"
+       "nX7eOvs=",
+       uint64_t{0x7b99940782e29898}, uint64_t{0x3e08cca5b71f9346}},
+      {"NUR3SRxBkxTSbtQORJpu/GdR6b/h6sSGfsMj/KFd99ahbh+9r7LSgSGmkGVB/"
+       "mGoT0pnMTQst7Lv2q6QN6Vm",
+       uint64_t{0x4fe12fa5383b51a8}, uint64_t{0xad406b10c770a6d2}},
+      {"2BOFlcI3Z0RYDtS9T9Ie9yJoXlOdigpPeeT+CRujb/"
+       "O39Ih5LPC9hP6RQk1kYESGyaLZZi3jtabHs7DiVx/VDg==",
+       uint64_t{0xe2ccb09ac0f5b4b6}, uint64_t{0xd1713ce6e552bcf2}},
+      {"FF2HQE1FxEvWBpg6Z9zAMH+Zlqx8S1JD/"
+       "wIlViL6ZDZY63alMDrxB0GJQahmAtjlm26RGLnjW7jmgQ4Ie3I+014=",
+       uint64_t{0x7d0a37adbd7b753b}, uint64_t{0x753b287194c73ad3}},
+      {"tHmO7mqVL/PX11nZrz50Hc+M17Poj5lpnqHkEN+4bpMx/"
+       "YGbkrGOaYjoQjgmt1X2QyypK7xClFrjeWrCMdlVYtbW",
+       uint64_t{0xd3ae96ef9f7185f2}, uint64_t{0x5ae41a95f600af1c}},
+      {"/WiHi9IQcxRImsudkA/KOTqGe8/"
+       "gXkhKIHkjddv5S9hi02M049dIK3EUyAEjkjpdGLUs+BN0QzPtZqjIYPOgwsYE9g==",
+       uint64_t{0x4fb88ea63f79a0d8}, uint64_t{0x4a61163b86a8bb4c}},
+      {"qds+1ExSnU11L4fTSDz/QE90g4Jh6ioqSh3KDOTOAo2pQGL1k/"
+       "9CCC7J23YF27dUTzrWsCQA2m4epXoCc3yPHb3xElA=",
+       uint64_t{0xed564e259bb5ebe9}, uint64_t{0x42eeaa79e760c7e4}},
+      {"8FVYHx40lSQPTHheh08Oq0/"
+       "pGm2OlG8BEf8ezvAxHuGGdgCkqpXIueJBF2mQJhTfDy5NncO8ntS7vaKs7sCNdDaNGOEi",
+       uint64_t{0x3e3256b60c428000}, uint64_t{0x698df622ef465b0a}},
+      {"4ZoEIrJtstiCkeew3oRzmyJHVt/pAs2pj0HgHFrBPztbQ10NsQ/"
+       "lM6DM439QVxpznnBSiHMgMQJhER+70l72LqFTO1JiIQ==",
+       uint64_t{0xfb05bad59ec8705}, uint64_t{0x157583111e1a6026}},
+      {"hQPtaYI+wJyxXgwD5n8jGIKFKaFA/"
+       "P83KqCKZfPthnjwdOFysqEOYwAaZuaaiv4cDyi9TyS8hk5cEbNP/jrI7q6pYGBLbsM=",
+       uint64_t{0xafdc251dbf97b5f8}, uint64_t{0xaa1388f078e793e0}},
+      {"S4gpMSKzMD7CWPsSfLeYyhSpfWOntyuVZdX1xSBjiGvsspwOZcxNKCRIOqAA0moUfOh3I5+"
+       "juQV4rsqYElMD/gWfDGpsWZKQ",
+       uint64_t{0x10ec9c92ddb5dcbc}, uint64_t{0xf10d68d0f3309360}},
+      {"oswxop+"
+       "bthuDLT4j0PcoSKby4LhF47ZKg8K17xxHf74UsGCzTBbOz0MM8hQEGlyqDT1iUiAYnaPaUp"
+       "L2mRK0rcIUYA4qLt5uOw==",
+       uint64_t{0x9a767d5822c7dac4}, uint64_t{0x2af056184457a3de}},
+      {"0II/"
+       "697p+"
+       "BtLSjxj5989OXI004TogEb94VUnDzOVSgMXie72cuYRvTFNIBgtXlKfkiUjeqVpd4a+"
+       "n5bxNOD1TGrjQtzKU5r7obo=",
+       uint64_t{0xee46254080d6e2db}, uint64_t{0x6d0058e1590b2489}},
+      {"E84YZW2qipAlMPmctrg7TKlwLZ68l4L+c0xRDUfyyFrA4MAti0q9sHq3TDFviH0Y+"
+       "Kq3tEE5srWFA8LM9oomtmvm5PYxoaarWPLc",
+       uint64_t{0xbbb669588d8bf398}, uint64_t{0x638f287f68817f12}},
+      {"x3pa4HIElyZG0Nj7Vdy9IdJIR4izLmypXw5PCmZB5y68QQ4uRaVVi3UthsoJROvbjDJkP2D"
+       "Q6L/eN8pFeLFzNPKBYzcmuMOb5Ull7w==",
+       uint64_t{0xdc2afaa529beef44}, uint64_t{0xc46b71fecefd5467}},
+      {"jVDKGYIuWOP/"
+       "QKLdd2wi8B2VJA8Wh0c8PwrXJVM8FOGM3voPDVPyDJOU6QsBDPseoR8uuKd19OZ/"
+       "zAvSCB+zlf6upAsBlheUKgCfKww=",
+       uint64_t{0xf1f67391d45013a8}, uint64_t{0x2c8e94679d964e0a}},
+      {"mkquunhmYe1aR2wmUz4vcvLEcKBoe6H+kjUok9VUn2+eTSkWs4oDDtJvNCWtY5efJwg/"
+       "j4PgjRYWtqnrCkhaqJaEvkkOwVfgMIwF3e+d",
+       uint64_t{0x16fce2b8c65a3429}, uint64_t{0x8612b797ce22503a}},
+      {"fRelvKYonTQ+s+rnnvQw+JzGfFoPixtna0vzcSjiDqX5s2Kg2//"
+       "UGrK+AVCyMUhO98WoB1DDbrsOYSw2QzrcPe0+3ck9sePvb+Q/IRaHbw==",
+       uint64_t{0xf4b096699f49fe67}, uint64_t{0x59f929babfba7170}},
+      {"DUwXFJzagljo44QeJ7/"
+       "6ZKw4QXV18lhkYT2jglMr8WB3CHUU4vdsytvw6AKv42ZcG6fRkZkq9fpnmXy6xG0aO3WPT1"
+       "eHuyFirAlkW+zKtwg=",
+       uint64_t{0xca584c4bc8198682}, uint64_t{0x9527556923fb49a0}},
+      {"cYmZCrOOBBongNTr7e4nYn52uQUy2mfe48s50JXx2AZ6cRAt/"
+       "xRHJ5QbEoEJOeOHsJyM4nbzwFm++SlT6gFZZHJpkXJ92JkR86uS/eV1hJUR",
+       uint64_t{0xed269fc3818b6aad}, uint64_t{0x1039ab644f5e150b}},
+      {"EXeHBDfhwzAKFhsMcH9+2RHwV+mJaN01+9oacF6vgm8mCXRd6jeN9U2oAb0of5c5cO4i+"
+       "Vb/LlHZSMI490SnHU0bejhSCC2gsC5d2K30ER3iNA==",
+       uint64_t{0x33f253cbb8fe66a8}, uint64_t{0x7816c83f3aa05e6d}},
+      {"FzkzRYoNjkxFhZDso94IHRZaJUP61nFYrh5MwDwv9FNoJ5jyNCY/"
+       "eazPZk+tbmzDyJIGw2h3GxaWZ9bSlsol/vK98SbkMKCQ/wbfrXRLcDzdd/8=",
+       uint64_t{0xd0b76b2c1523d99c}, uint64_t{0xf51d2f564518c619}},
+      {"Re4aXISCMlYY/XsX7zkIFR04ta03u4zkL9dVbLXMa/q6hlY/CImVIIYRN3VKP4pnd0AUr/"
+       "ugkyt36JcstAInb4h9rpAGQ7GMVOgBniiMBZ/MGU7H",
+       uint64_t{0xfd28f0811a2a237f}, uint64_t{0x67d494cff03ac004}},
+      {"ueLyMcqJXX+MhO4UApylCN9WlTQ+"
+       "ltJmItgG7vFUtqs2qNwBMjmAvr5u0sAKd8jpzV0dDPTwchbIeAW5zbtkA2NABJV6hFM48ib"
+       "4/J3A5mseA3cS8w==",
+       uint64_t{0x6261fb136482e84}, uint64_t{0x2802d636ced1cfbb}},
+      {"6Si7Yi11L+jZMkwaN+GUuzXMrlvEqviEkGOilNq0h8TdQyYKuFXzkYc/"
+       "q74gP3pVCyiwz9KpVGMM9vfnq36riMHRknkmhQutxLZs5fbmOgEO69HglCU=",
+       uint64_t{0x458efc750bca7c3a}, uint64_t{0xf64e20bad771cb12}},
+      {"Q6AbOofGuTJOegPh9Clm/"
+       "9crtUMQqylKrTc1fhfJo1tqvpXxhU4k08kntL1RG7woRnFrVh2UoMrL1kjin+s9CanT+"
+       "y4hHwLqRranl9FjvxfVKm3yvg68",
+       uint64_t{0xa7e69ff84e5e7c27}, uint64_t{0xb9a6cf84a83e15e}},
+      {"ieQEbIPvqY2YfIjHnqfJiO1/MIVRk0RoaG/WWi3kFrfIGiNLCczYoklgaecHMm/"
+       "1sZ96AjO+a5stQfZbJQwS7Sc1ODABEdJKcTsxeW2hbh9A6CFzpowP1A==",
+       uint64_t{0x3c59bfd0c29efe9e}, uint64_t{0x8da6630319609301}},
+      {"zQUv8hFB3zh2GGl3KTvCmnfzE+"
+       "SUgQPVaSVIELFX5H9cE3FuVFGmymkPQZJLAyzC90Cmi8GqYCvPqTuAAB//"
+       "XTJxy4bCcVArgZG9zJXpjowpNBfr3ngWrSE=",
+       uint64_t{0x10befacc6afd298d}, uint64_t{0x40946a86e2a996f3}},
+      {"US4hcC1+op5JKGC7eIs8CUgInjKWKlvKQkapulxW262E/"
+       "B2ye79QxOexf188u2mFwwe3WTISJHRZzS61IwljqAWAWoBAqkUnW8SHmIDwHUP31J0p5sGd"
+       "P47L",
+       uint64_t{0x41d5320b0a38efa7}, uint64_t{0xcab7f5997953fa76}},
+      {"9bHUWFna2LNaGF6fQLlkx1Hkt24nrkLE2CmFdWgTQV3FFbUe747SSqYw6ebpTa07MWSpWRP"
+       "sHesVo2B9tqHbe7eQmqYebPDFnNqrhSdZwFm9arLQVs+7a3Ic6A==",
+       uint64_t{0x58db1c7450fe17f3}, uint64_t{0x39129ca0e04fc465}},
+      {"Kb3DpHRUPhtyqgs3RuXjzA08jGb59hjKTOeFt1qhoINfYyfTt2buKhD6YVffRCPsgK9SeqZ"
+       "qRPJSyaqsa0ovyq1WnWW8jI/NhvAkZTVHUrX2pC+cD3OPYT05Dag=",
+       uint64_t{0x6098c055a335b7a6}, uint64_t{0x5238221fd685e1b8}},
+      {"gzxyMJIPlU+bJBwhFUCHSofZ/"
+       "319LxqMoqnt3+L6h2U2+ZXJCSsYpE80xmR0Ta77Jq54o92SMH87HV8dGOaCTuAYF+"
+       "lDL42SY1P316Cl0sZTS2ow3ZqwGbcPNs/1",
+       uint64_t{0x1bbacec67845a801}, uint64_t{0x175130c407dbcaab}},
+      {"uR7V0TW+FGVMpsifnaBAQ3IGlr1wx5sKd7TChuqRe6OvUXTlD4hKWy8S+"
+       "8yyOw8lQabism19vOQxfmocEOW/"
+       "vzY0pEa87qHrAZy4s9fH2Bltu8vaOIe+agYohhYORQ==",
+       uint64_t{0xc419cfc7442190}, uint64_t{0x2f20e7536c0b0df}},
+      {"1UR5eoo2aCwhacjZHaCh9bkOsITp6QunUxHQ2SfeHv0imHetzt/"
+       "Z70mhyWZBalv6eAx+YfWKCUib2SHDtz/"
+       "A2dc3hqUWX5VfAV7FQsghPUAtu6IiRatq4YSLpDvKZBQ=",
+       uint64_t{0xc95e510d94ba270c}, uint64_t{0x2742cb488a04ad56}},
+      {"opubR7H63BH7OtY+Avd7QyQ25UZ8kLBdFDsBTwZlY6gA/"
+       "u+x+"
+       "czC9AaZMgmQrUy15DH7YMGsvdXnviTtI4eVI4aF1H9Rl3NXMKZgwFOsdTfdcZeeHVRzBBKX"
+       "8jUfh1il",
+       uint64_t{0xff1ae05c98089c3f}, uint64_t{0xd6afb593879ff93b}},
+      {"DC0kXcSXtfQ9FbSRwirIn5tgPri0sbzHSa78aDZVDUKCMaBGyFU6BmrulywYX8yzvwprdLs"
+       "oOwTWN2wMjHlPDqrvVHNEjnmufRDblW+nSS+xtKNs3N5xsxXdv6JXDrAB/Q==",
+       uint64_t{0x90c02b8dceced493}, uint64_t{0xf50ad64caac0ca7f}},
+      {"BXRBk+3wEP3Lpm1y75wjoz+PgB0AMzLe8tQ1AYU2/"
+       "oqrQB2YMC6W+9QDbcOfkGbeH+b7IBkt/"
+       "gwCMw2HaQsRFEsurXtcQ3YwRuPz5XNaw5NAvrNa67Fm7eRzdE1+hWLKtA8=",
+       uint64_t{0x9f8a76697ab1aa36}, uint64_t{0x2ade95c4261364ae}},
+      {"RRBSvEGYnzR9E45Aps/+WSnpCo/X7gJLO4DRnUqFrJCV/kzWlusLE/"
+       "6ZU6RoUf2ROwcgEvUiXTGjLs7ts3t9SXnJHxC1KiOzxHdYLMhVvgNd3hVSAXODpKFSkVXND"
+       "55G2L1W",
+       uint64_t{0x6ba1bf3d811a531d}, uint64_t{0x5c4f3299faacd07a}},
+      {"jeh6Qazxmdi57pa9S3XSnnZFIRrnc6s8QLrah5OX3SB/V2ErSPoEAumavzQPkdKF1/"
+       "SfvmdL+qgF1C+Yawy562QaFqwVGq7+tW0yxP8FStb56ZRgNI4IOmI30s1Ei7iops9Uuw==",
+       uint64_t{0x6a418974109c67b4}, uint64_t{0xfffe3bff0ae5e9bc}},
+      {"6QO5nnDrY2/"
+       "wrUXpltlKy2dSBcmK15fOY092CR7KxAjNfaY+"
+       "aAmtWbbzQk3MjBg03x39afSUN1fkrWACdyQKRaGxgwq6MGNxI6W+8DLWJBHzIXrntrE/"
+       "ml6fnNXEpxplWJ1vEs4=",
+       uint64_t{0x8472f1c2b3d230a3}, uint64_t{0x1db785c0005166e4}},
+      {"0oPxeEHhqhcFuwonNfLd5jF3RNATGZS6NPoS0WklnzyokbTqcl4BeBkMn07+fDQv83j/"
+       "BpGUwcWO05f3+DYzocfnizpFjLJemFGsls3gxcBYxcbqWYev51tG3lN9EvRE+X9+Pwww",
+       uint64_t{0x5e06068f884e73a7}, uint64_t{0xea000d962ad18418}},
+      {"naSBSjtOKgAOg8XVbR5cHAW3Y+QL4Pb/JO9/"
+       "oy6L08wvVRZqo0BrssMwhzBP401Um7A4ppAupbQeJFdMrysY34AuSSNvtNUy5VxjNECwiNt"
+       "gwYHw7yakDUv8WvonctmnoSPKENegQg==",
+       uint64_t{0x55290b1a8f170f59}, uint64_t{0xe42aef38359362d9}},
+      {"vPyl8DxVeRe1OpilKb9KNwpGkQRtA94UpAHetNh+"
+       "95V7nIW38v7PpzhnTWIml5kw3So1Si0TXtIUPIbsu32BNhoH7QwFvLM+"
+       "JACgSpc5e3RjsL6Qwxxi11npwxRmRUqATDeMUfRAjxg=",
+       uint64_t{0x5501cfd83dfe706a}, uint64_t{0xc8e95657348a3891}},
+      {"QC9i2GjdTMuNC1xQJ74ngKfrlA4w3o58FhvNCltdIpuMhHP1YsDA78scQPLbZ3OCUgeQguY"
+       "f/vw6zAaVKSgwtaykqg5ka/4vhz4hYqWU5ficdXqClHl+zkWEY26slCNYOM5nnDlly8Cj",
+       uint64_t{0xe43ed13d13a66990}, uint64_t{0xc162eca864f238c6}},
+      {"7CNIgQhAHX27nxI0HeB5oUTnTdgKpRDYDKwRcXfSFGP1XeT9nQF6WKCMjL1tBV6x7KuJ91G"
+       "Zz11F4c+8s+MfqEAEpd4FHzamrMNjGcjCyrVtU6y+7HscMVzr7Q/"
+       "ODLcPEFztFnwjvCjmHw==",
+       uint64_t{0xdf43bc375cf5283f}, uint64_t{0xbe1fb373e20579ad}},
+      {"Qa/hC2RPXhANSospe+gUaPfjdK/yhQvfm4cCV6/pdvCYWPv8p1kMtKOX3h5/"
+       "8oZ31fsmx4Axphu5qXJokuhZKkBUJueuMpxRyXpwSWz2wELx5glxF7CM0Fn+"
+       "OevnkhUn5jsPlG2r5jYlVn8=",
+       uint64_t{0x8112b806d288d7b5}, uint64_t{0x628a1d4f40aa6ffd}},
+      {"kUw/0z4l3a89jTwN5jpG0SHY5km/"
+       "IVhTjgM5xCiPRLncg40aqWrJ5vcF891AOq5hEpSq0bUCJUMFXgct7kvnys905HjerV7Vs1G"
+       "y84tgVJ70/2+pAZTsB/PzNOE/G6sOj4+GbTzkQu819OLB",
+       uint64_t{0xd52a18abb001cb46}, uint64_t{0xa87bdb7456340f90}},
+      {"VDdfSDbO8Tdj3T5W0XM3EI7iHh5xpIutiM6dvcJ/fhe23V/srFEkDy5iZf/"
+       "VnA9kfi2C79ENnFnbOReeuZW1b3MUXB9lgC6U4pOTuC+"
+       "jHK3Qnpyiqzj7h3ISJSuo2pob7vY6VHZo6Fn7exEqHg==",
+       uint64_t{0xe12b76a2433a1236}, uint64_t{0x5960ef3ba982c801}},
+      {"Ldfvy3ORdquM/R2fIkhH/ONi69mcP1AEJ6n/"
+       "oropwecAsLJzQSgezSY8bEiEs0VnFTBBsW+RtZY6tDj03fnb3amNUOq1b7jbqyQkL9hpl+"
+       "2Z2J8IaVSeownWl+bQcsR5/xRktIMckC5AtF4YHfU=",
+       uint64_t{0x175bf7319cf1fa00}, uint64_t{0x5026586df9a431ec}},
+      {"BrbNpb42+"
+       "VzZAjJw6QLirXzhweCVRfwlczzZ0VX2xluskwBqyfnGovz5EuX79JJ31VNXa5hTkAyQat3l"
+       "YKRADTdAdwE5PqM1N7YaMqqsqoAAAeuYVXuk5eWCykYmClNdSspegwgCuT+403JigBzi",
+       uint64_t{0xd63d57b3f67525ae}, uint64_t{0xfe4b8a20fdf0840b}},
+      {"gB3NGHJJvVcuPyF0ZSvHwnWSIfmaI7La24VMPQVoIIWF7Z74NltPZZpx2f+cocESM+"
+       "ILzQW9p+BC8x5IWz7N4Str2WLGKMdgmaBfNkEhSHQDU0IJEOnpUt0HmjhFaBlx0/"
+       "LTmhua+rQ6Wup8ezLwfg==",
+       uint64_t{0x933faea858832b73}, uint64_t{0xdcb761867da7072f}},
+      {"hTKHlRxx6Pl4gjG+6ksvvj0CWFicUg3WrPdSJypDpq91LUWRni2KF6+"
+       "81ZoHBFhEBrCdogKqeK+hy9bLDnx7g6rAFUjtn1+cWzQ2YjiOpz4+"
+       "ROBB7lnwjyTGWzJD1rXtlso1g2qVH8XJVigC5M9AIxM=",
+       uint64_t{0x53d061e5f8e7c04f}, uint64_t{0xc10d4653667275b7}},
+      {"IWQBelSQnhrr0F3BhUpXUIDauhX6f95Qp+A0diFXiUK7irwPG1oqBiqHyK/SH/"
+       "9S+"
+       "rln9DlFROAmeFdH0OCJi2tFm4afxYzJTFR4HnR4cG4x12JqHaZLQx6iiu6CE3rtWBVz99oA"
+       "wCZUOEXIsLU24o2Y",
+       uint64_t{0xdb4124556dd515e0}, uint64_t{0x727720deec13110b}},
+      {"TKo+l+"
+       "1dOXdLvIrFqeLaHdm0HZnbcdEgOoLVcGRiCbAMR0j5pIFw8D36tefckAS1RCFOH5IgP8yiF"
+       "T0Gd0a2hI3+"
+       "fTKA7iK96NekxWeoeqzJyctc6QsoiyBlkZerRxs5RplrxoeNg29kKDTM0K94mnhD9g==",
+       uint64_t{0x4fb31a0dd681ee71}, uint64_t{0x710b009662858dc9}},
+      {"YU4e7G6EfQYvxCFoCrrT0EFgVLHFfOWRTJQJ5gxM3G2b+"
+       "1kJf9YPrpsxF6Xr6nYtS8reEEbDoZJYqnlk9lXSkVArm88Cqn6d25VCx3+"
+       "49MqC0trIlXtb7SXUUhwpJK16T0hJUfPH7s5cMZXc6YmmbFuBNPE=",
+       uint64_t{0x27cc72eefa138e4c}, uint64_t{0xfbf8f7a3ecac1eb7}},
+      {"/I/"
+       "eImMwPo1U6wekNFD1Jxjk9XQVi1D+"
+       "FPdqcHifYXQuP5aScNQfxMAmaPR2XhuOQhADV5tTVbBKwCDCX4E3jcDNHzCiPvViZF1W27t"
+       "xaf2BbFQdwKrNCmrtzcluBFYu0XZfc7RU1RmxK/RtnF1qHsq/O4pp",
+       uint64_t{0x44bc2dfba4bd3ced}, uint64_t{0xb6fc4fcd0722e3df}},
+      {"CJTT9WGcY2XykTdo8KodRIA29qsqY0iHzWZRjKHb9alwyJ7RZAE3V5Juv4MY3MeYEr1EPCC"
+       "MxO7yFXqT8XA8YTjaMp3bafRt17Pw8JC4iKJ1zN+WWKOESrj+"
+       "3aluGQqn8z1EzqY4PH7rLG575PYeWsP98BugdA==",
+       uint64_t{0x242da1e3a439bed8}, uint64_t{0x7cb86dcc55104aac}},
+      {"ZlhyQwLhXQyIUEnMH/"
+       "AEW27vh9xrbNKJxpWGtrEmKhd+nFqAfbeNBQjW0SfG1YI0xQkQMHXjuTt4P/"
+       "EpZRtA47ibZDVS8TtaxwyBjuIDwqcN09eCtpC+Ls+"
+       "vWDTLmBeDM3u4hmzz4DQAYsLiZYSJcldg9Q3wszw=",
+       uint64_t{0xdc559c746e35c139}, uint64_t{0x19e71e9b45c3a51e}},
+      {"v2KU8y0sCrBghmnm8lzGJlwo6D6ObccAxCf10heoDtYLosk4ztTpLlpSFEyu23MLA1tJkcg"
+       "Rko04h19QMG0mOw/"
+       "wc93EXAweriBqXfvdaP85sZABwiKO+6rtS9pacRVpYYhHJeVTQ5NzrvBvi1huxAr+"
+       "xswhVMfL",
+       uint64_t{0xd0b0350275b9989}, uint64_t{0x51de38573c2bea48}},
+      {"QhKlnIS6BuVCTQsnoE67E/"
+       "yrgogE8EwO7xLaEGei26m0gEU4OksefJgppDh3X0x0Cs78Dr9IHK5b977CmZlrTRmwhlP8p"
+       "M+UzXPNRNIZuN3ntOum/QhUWP8SGpirheXENWsXMQ/"
+       "nxtxakyEtrNkKk471Oov9juP8oQ==",
+       uint64_t{0xb04489e41d17730c}, uint64_t{0xa73ab6996d6df158}},
+      {"/ZRMgnoRt+Uo6fUPr9FqQvKX7syhgVqWu+"
+       "WUSsiQ68UlN0efSP6Eced5gJZL6tg9gcYJIkhjuQNITU0Q3TjVAnAcobgbJikCn6qZ6pRxK"
+       "BY4MTiAlfGD3T7R7hwJwx554MAy++Zb/YUFlnCaCJiwQMnowF7aQzwYFCo=",
+       uint64_t{0x2217285eb4572156}, uint64_t{0x55ef2b8c930817b2}},
+      {"NB7tU5fNE8nI+SXGfipc7sRkhnSkUF1krjeo6k+8FITaAtdyz+"
+       "o7mONgXmGLulBPH9bEwyYhKNVY0L+njNQrZ9YC2aXsFD3PdZsxAFaBT3VXEzh+"
+       "NGBTjDASNL3mXyS8Yv1iThGfHoY7T4aR0NYGJ+k+pR6f+KrPC96M",
+       uint64_t{0x12c2e8e68aede73b}, uint64_t{0xb2850bf5fae87157}},
+      {"8T6wrqCtEO6/rwxF6lvMeyuigVOLwPipX/FULvwyu+1wa5sQGav/"
+       "2FsLHUVn6cGSi0LlFwLewGHPFJDLR0u4t7ZUyM//"
+       "x6da0sWgOa5hzDqjsVGmjxEHXiaXKW3i4iSZNuxoNbMQkIbVML+"
+       "DkYu9ND0O2swg4itGeVSzXA==",
+       uint64_t{0x4d612125bdc4fd00}, uint64_t{0xecf3de1acd04651f}},
+      {"Ntf1bMRdondtMv1CYr3G80iDJ4WSAlKy5H34XdGruQiCrnRGDBa+"
+       "eUi7vKp4gp3BBcVGl8eYSasVQQjn7MLvb3BjtXx6c/"
+       "bCL7JtpzQKaDnPr9GWRxpBXVxKREgMM7d8lm35EODv0w+"
+       "hQLfVSh8OGs7fsBb68nNWPLeeSOo=",
+       uint64_t{0x81826b553954464e}, uint64_t{0xcc0a40552559ff32}},
+      {"VsSAw72Ro6xks02kaiLuiTEIWBC5bgqr4WDnmP8vglXzAhixk7td926rm9jNimL+"
+       "kroPSygZ9gl63aF5DCPOACXmsbmhDrAQuUzoh9ZKhWgElLQsrqo1KIjWoZT5b5QfVUXY9lS"
+       "IBg3U75SqORoTPq7HalxxoIT5diWOcJQi",
+       uint64_t{0xc2e5d345dc0ddd2d}, uint64_t{0xc385c374f20315b1}},
+      {"j+loZ+C87+"
+       "bJxNVebg94gU0mSLeDulcHs84tQT7BZM2rzDSLiCNxUedHr1ZWJ9ejTiBa0dqy2I2ABc++"
+       "xzOLcv+//YfibtjKtYggC6/3rv0XCc7xu6d/"
+       "O6xO+XOBhOWAQ+IHJVHf7wZnDxIXB8AUHsnjEISKj7823biqXjyP3g==",
+       uint64_t{0x3da6830a9e32631e}, uint64_t{0xb90208a4c7234183}},
+      {"f3LlpcPElMkspNtDq5xXyWU62erEaKn7RWKlo540gR6mZsNpK1czV/"
+       "sOmqaq8XAQLEn68LKj6/"
+       "cFkJukxRzCa4OF1a7cCAXYFp9+wZDu0bw4y63qbpjhdCl8GO6Z2lkcXy7KOzbPE01ukg7+"
+       "gN+7uKpoohgAhIwpAKQXmX5xtd0=",
+       uint64_t{0xc9ae5c8759b4877a}, uint64_t{0x58aa1ca7a4c075d9}},
+  };
+
+  for (const auto& expected_result : expected_results) {
+    std::string str;
+    ASSERT_TRUE(absl::Base64Unescape(expected_result.base64_data, &str));
+    EXPECT_EQ(absl::hash_internal::Wyhash(str.data(), str.size(),
+                                          expected_result.seed, kSalt),
+              expected_result.hash);
+  }
+}
+
+}  // namespace
diff --git a/absl/memory/BUILD.bazel b/absl/memory/BUILD.bazel
index 2ba9d7c..d2824a0 100644
--- a/absl/memory/BUILD.bazel
+++ b/absl/memory/BUILD.bazel
@@ -24,7 +24,7 @@
 
 package(default_visibility = ["//visibility:public"])
 
-licenses(["notice"])  # Apache 2.0
+licenses(["notice"])
 
 cc_library(
     name = "memory",
diff --git a/absl/memory/memory.h b/absl/memory/memory.h
index 513f710..2b5ff62 100644
--- a/absl/memory/memory.h
+++ b/absl/memory/memory.h
@@ -420,6 +420,9 @@
 //
 // A C++11 compatible implementation of C++17's std::allocator_traits.
 //
+#if __cplusplus >= 201703L
+using std::allocator_traits;
+#else  // __cplusplus >= 201703L
 template <typename Alloc>
 struct allocator_traits {
   using allocator_type = Alloc;
@@ -609,6 +612,7 @@
     return a;
   }
 };
+#endif  // __cplusplus >= 201703L
 
 namespace memory_internal {
 
diff --git a/absl/memory/memory_test.cc b/absl/memory/memory_test.cc
index c47820e..1990c7b 100644
--- a/absl/memory/memory_test.cc
+++ b/absl/memory/memory_test.cc
@@ -17,6 +17,7 @@
 #include "absl/memory/memory.h"
 
 #include <sys/types.h>
+
 #include <cstddef>
 #include <memory>
 #include <string>
@@ -36,10 +37,10 @@
 // been called, via the instance_count variable.
 class DestructorVerifier {
  public:
-  DestructorVerifier() { ++instance_count_;  }
+  DestructorVerifier() { ++instance_count_; }
   DestructorVerifier(const DestructorVerifier&) = delete;
   DestructorVerifier& operator=(const DestructorVerifier&) = delete;
-  ~DestructorVerifier() {  --instance_count_; }
+  ~DestructorVerifier() { --instance_count_; }
 
   // The number of instances of this class currently active.
   static int instance_count() { return instance_count_; }
@@ -156,9 +157,7 @@
     allocs().push_back(n);
     return ::operator new[](n);
   }
-  void operator delete[](void* p) {
-    return ::operator delete[](p);
-  }
+  void operator delete[](void* p) { return ::operator delete[](p); }
   static std::vector<size_t>& allocs() {
     static auto& v = *new std::vector<size_t>;
     return v;
@@ -171,8 +170,7 @@
   ArrayWatch::allocs().clear();
 
   auto p = absl::make_unique<ArrayWatch[]>(5);
-  static_assert(std::is_same<decltype(p),
-                             std::unique_ptr<ArrayWatch[]>>::value,
+  static_assert(std::is_same<decltype(p), std::unique_ptr<ArrayWatch[]>>::value,
                 "unexpected return type");
   EXPECT_THAT(ArrayWatch::allocs(), ElementsAre(5 * sizeof(ArrayWatch)));
 }
@@ -181,7 +179,7 @@
   // Ensure that absl::make_unique is not ambiguous with std::make_unique.
   // In C++14 mode, the below call to make_unique has both types as candidates.
   struct TakesStdType {
-    explicit TakesStdType(const std::vector<int> &vec) {}
+    explicit TakesStdType(const std::vector<int>& vec) {}
   };
   using absl::make_unique;
   (void)make_unique<TakesStdType>(std::vector<int>());
@@ -541,8 +539,8 @@
   MinimalMockAllocator(const MinimalMockAllocator& other)
       : value(other.value) {}
   using value_type = TestValue;
-  MOCK_METHOD1(allocate, value_type*(size_t));
-  MOCK_METHOD2(deallocate, void(value_type*, size_t));
+  MOCK_METHOD(value_type*, allocate, (size_t));
+  MOCK_METHOD(void, deallocate, (value_type*, size_t));
 
   int value;
 };
@@ -557,7 +555,7 @@
   EXPECT_CALL(mock, deallocate(&x, 7));
 
   EXPECT_EQ(&x, Traits::allocate(mock, 7));
-  Traits::allocate(mock, 7, static_cast<const void*>(&hint));
+  static_cast<void>(Traits::allocate(mock, 7, static_cast<const void*>(&hint)));
   EXPECT_EQ(&x, Traits::allocate(mock, 7, static_cast<const void*>(&hint)));
   Traits::deallocate(mock, &x, 7);
 
@@ -579,13 +577,14 @@
   explicit FullMockAllocator(int value) : value(value) {}
   FullMockAllocator(const FullMockAllocator& other) : value(other.value) {}
   using value_type = TestValue;
-  MOCK_METHOD1(allocate, value_type*(size_t));
-  MOCK_METHOD2(allocate, value_type*(size_t, const void*));
-  MOCK_METHOD2(construct, void(value_type*, int*));
-  MOCK_METHOD1(destroy, void(value_type*));
-  MOCK_CONST_METHOD0(max_size, size_t());
-  MOCK_CONST_METHOD0(select_on_container_copy_construction,
-                     FullMockAllocator());
+  MOCK_METHOD(value_type*, allocate, (size_t));
+  MOCK_METHOD(value_type*, allocate, (size_t, const void*));
+  MOCK_METHOD(void, construct, (value_type*, int*));
+  MOCK_METHOD(void, destroy, (value_type*));
+  MOCK_METHOD(size_t, max_size, (),
+              (const));
+  MOCK_METHOD(FullMockAllocator, select_on_container_copy_construction, (),
+              (const));
 
   int value;
 };
@@ -642,8 +641,7 @@
   struct CanThrowAllocator {
     using is_nothrow = std::false_type;
   };
-  struct UnspecifiedAllocator {
-  };
+  struct UnspecifiedAllocator {};
   EXPECT_TRUE(absl::allocator_is_nothrow<NoThrowAllocator>::value);
   EXPECT_FALSE(absl::allocator_is_nothrow<CanThrowAllocator>::value);
   EXPECT_FALSE(absl::allocator_is_nothrow<UnspecifiedAllocator>::value);
diff --git a/absl/meta/BUILD.bazel b/absl/meta/BUILD.bazel
index c06d2d9..5585fcc 100644
--- a/absl/meta/BUILD.bazel
+++ b/absl/meta/BUILD.bazel
@@ -24,7 +24,7 @@
 
 package(default_visibility = ["//visibility:public"])
 
-licenses(["notice"])  # Apache 2.0
+licenses(["notice"])
 
 cc_library(
     name = "type_traits",
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h
index ba87d2f..d5cb5f3 100644
--- a/absl/meta/type_traits.h
+++ b/absl/meta/type_traits.h
@@ -219,7 +219,7 @@
 // This metafunction is designed to be a drop-in replacement for the C++17
 // `std::conjunction` metafunction.
 template <typename... Ts>
-struct conjunction;
+struct conjunction : std::true_type {};
 
 template <typename T, typename... Ts>
 struct conjunction<T, Ts...>
@@ -228,9 +228,6 @@
 template <typename T>
 struct conjunction<T> : T {};
 
-template <>
-struct conjunction<> : std::true_type {};
-
 // disjunction
 //
 // Performs a compile-time logical OR operation on the passed types (which
@@ -241,7 +238,7 @@
 // This metafunction is designed to be a drop-in replacement for the C++17
 // `std::disjunction` metafunction.
 template <typename... Ts>
-struct disjunction;
+struct disjunction : std::false_type {};
 
 template <typename T, typename... Ts>
 struct disjunction<T, Ts...> :
@@ -250,9 +247,6 @@
 template <typename T>
 struct disjunction<T> : T {};
 
-template <>
-struct disjunction<> : std::false_type {};
-
 // negation
 //
 // Performs a compile-time logical NOT operation on the passed type (which
@@ -616,8 +610,22 @@
 template <typename T>
 using underlying_type_t = typename std::underlying_type<T>::type;
 
-template <typename T>
-using result_of_t = typename std::result_of<T>::type;
+
+namespace type_traits_internal {
+
+#if __cplusplus >= 201703L
+// std::result_of is deprecated (C++17) or removed (C++20)
+template<typename> struct result_of;
+template<typename F, typename... Args>
+struct result_of<F(Args...)> : std::invoke_result<F, Args...> {};
+#else
+template<typename F> using result_of = std::result_of<F>;
+#endif
+
+}  // namespace type_traits_internal
+
+template<typename F>
+using result_of_t = typename type_traits_internal::result_of<F>::type;
 
 namespace type_traits_internal {
 // In MSVC we can't probe std::hash or stdext::hash because it triggers a
diff --git a/absl/numeric/BUILD.bazel b/absl/numeric/BUILD.bazel
index e09e52d..ea587bf 100644
--- a/absl/numeric/BUILD.bazel
+++ b/absl/numeric/BUILD.bazel
@@ -22,7 +22,36 @@
 
 package(default_visibility = ["//visibility:public"])
 
-licenses(["notice"])  # Apache 2.0
+licenses(["notice"])
+
+cc_library(
+    name = "bits",
+    hdrs = [
+        "bits.h",
+        "internal/bits.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        "//absl/base:config",
+        "//absl/base:core_headers",
+    ],
+)
+
+cc_test(
+    name = "bits_test",
+    size = "small",
+    srcs = [
+        "bits_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":bits",
+        "//absl/random",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
 
 cc_library(
     name = "int128",
@@ -35,6 +64,7 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        ":bits",
         "//absl/base:config",
         "//absl/base:core_headers",
     ],
@@ -71,3 +101,15 @@
         "@com_github_google_benchmark//:benchmark_main",
     ],
 )
+
+cc_library(
+    name = "representation",
+    hdrs = [
+        "internal/representation.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        "//absl/base:config",
+    ],
+)
diff --git a/absl/numeric/CMakeLists.txt b/absl/numeric/CMakeLists.txt
index 242889f..781987d 100644
--- a/absl/numeric/CMakeLists.txt
+++ b/absl/numeric/CMakeLists.txt
@@ -16,6 +16,33 @@
 
 absl_cc_library(
   NAME
+    bits
+  HDRS
+    "bits.h"
+    "internal/bits.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::core_headers
+  PUBLIC
+)
+
+absl_cc_test(
+  NAME
+    bits_test
+  SRCS
+    "bits_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::bits
+    absl::core_headers
+    absl::random_random
+    gmock_main
+)
+
+absl_cc_library(
+  NAME
     int128
   HDRS
     "int128.h"
@@ -28,6 +55,7 @@
   DEPS
     absl::config
     absl::core_headers
+    absl::bits
   PUBLIC
 )
 
@@ -58,3 +86,15 @@
     absl::int128
   PUBLIC
 )
+
+absl_cc_library(
+  NAME
+    numeric_representation
+  HDRS
+    "internal/representation.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::config
+  PUBLIC
+)
diff --git a/absl/numeric/bits.h b/absl/numeric/bits.h
new file mode 100644
index 0000000..52013ad
--- /dev/null
+++ b/absl/numeric/bits.h
@@ -0,0 +1,177 @@
+// 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.
+//
+// -----------------------------------------------------------------------------
+// File: bits.h
+// -----------------------------------------------------------------------------
+//
+// This file contains implementations of C++20's bitwise math functions, as
+// defined by:
+//
+// P0553R4:
+//  http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0553r4.html
+// P0556R3:
+//  http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0556r3.html
+// P1355R2:
+//  http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1355r2.html
+// P1956R1:
+//  http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1956r1.pdf
+//
+// When using a standard library that implements these functions, we use the
+// standard library's implementation.
+
+#ifndef ABSL_NUMERIC_BITS_H_
+#define ABSL_NUMERIC_BITS_H_
+
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+
+#if (defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L) || \
+    (defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L)
+#include <bit>
+#endif
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/numeric/internal/bits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+#if !(defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L)
+// rotating
+template <class T>
+ABSL_MUST_USE_RESULT constexpr
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    rotl(T x, int s) noexcept {
+  return numeric_internal::RotateLeft(x, s);
+}
+
+template <class T>
+ABSL_MUST_USE_RESULT constexpr
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    rotr(T x, int s) noexcept {
+  return numeric_internal::RotateRight(x, s);
+}
+
+// Counting functions
+//
+// While these functions are typically constexpr, on some platforms, they may
+// not be marked as constexpr due to constraints of the compiler/available
+// intrinsics.
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, int>::type
+    countl_zero(T x) noexcept {
+  return numeric_internal::CountLeadingZeroes(x);
+}
+
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, int>::type
+    countl_one(T x) noexcept {
+  // Avoid integer promotion to a wider type
+  return countl_zero(static_cast<T>(~x));
+}
+
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CTZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, int>::type
+    countr_zero(T x) noexcept {
+  return numeric_internal::CountTrailingZeroes(x);
+}
+
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CTZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, int>::type
+    countr_one(T x) noexcept {
+  // Avoid integer promotion to a wider type
+  return countr_zero(static_cast<T>(~x));
+}
+
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline
+    typename std::enable_if<std::is_unsigned<T>::value, int>::type
+    popcount(T x) noexcept {
+  return numeric_internal::Popcount(x);
+}
+#else  // defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L
+
+using std::countl_one;
+using std::countl_zero;
+using std::countr_one;
+using std::countr_zero;
+using std::popcount;
+using std::rotl;
+using std::rotr;
+
+#endif
+
+#if !(defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L)
+// Returns: true if x is an integral power of two; false otherwise.
+template <class T>
+constexpr inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type
+has_single_bit(T x) noexcept {
+  return x != 0 && (x & (x - 1)) == 0;
+}
+
+// Returns: If x == 0, 0; otherwise one plus the base-2 logarithm of x, with any
+// fractional part discarded.
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    bit_width(T x) noexcept {
+  return std::numeric_limits<T>::digits - countl_zero(x);
+}
+
+// Returns: If x == 0, 0; otherwise the maximal value y such that
+// has_single_bit(y) is true and y <= x.
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    bit_floor(T x) noexcept {
+  return x == 0 ? 0 : T{1} << (bit_width(x) - 1);
+}
+
+// Returns: N, where N is the smallest power of 2 greater than or equal to x.
+//
+// Preconditions: N is representable as a value of type T.
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    bit_ceil(T x) {
+  // If T is narrower than unsigned, T{1} << bit_width will be promoted.  We
+  // want to force it to wraparound so that bit_ceil of an invalid value are not
+  // core constant expressions.
+  //
+  // BitCeilNonPowerOf2 triggers an overflow in constexpr contexts if we would
+  // undergo promotion to unsigned but not fit the result into T without
+  // truncation.
+  return has_single_bit(x) ? T{1} << (bit_width(x) - 1)
+                           : numeric_internal::BitCeilNonPowerOf2(x);
+}
+#else  // defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L
+
+using std::bit_ceil;
+using std::bit_floor;
+using std::bit_width;
+using std::has_single_bit;
+
+#endif
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_NUMERIC_BITS_H_
diff --git a/absl/numeric/bits_test.cc b/absl/numeric/bits_test.cc
new file mode 100644
index 0000000..7c942aa
--- /dev/null
+++ b/absl/numeric/bits_test.cc
@@ -0,0 +1,573 @@
+// 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/numeric/bits.h"
+
+#include <limits>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/random/random.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace {
+
+TEST(Rotate, Left) {
+  static_assert(rotl(uint8_t{0x12}, 0) == uint8_t{0x12}, "");
+  static_assert(rotl(uint16_t{0x1234}, 0) == uint16_t{0x1234}, "");
+  static_assert(rotl(uint32_t{0x12345678UL}, 0) == uint32_t{0x12345678UL}, "");
+  static_assert(rotl(uint64_t{0x12345678ABCDEF01ULL}, 0) ==
+                    uint64_t{0x12345678ABCDEF01ULL},
+                "");
+
+  EXPECT_EQ(rotl(uint8_t{0x12}, 0), uint8_t{0x12});
+  EXPECT_EQ(rotl(uint16_t{0x1234}, 0), uint16_t{0x1234});
+  EXPECT_EQ(rotl(uint32_t{0x12345678UL}, 0), uint32_t{0x12345678UL});
+  EXPECT_EQ(rotl(uint64_t{0x12345678ABCDEF01ULL}, 0),
+            uint64_t{0x12345678ABCDEF01ULL});
+
+  EXPECT_EQ(rotl(uint8_t{0x12}, 8), uint8_t{0x12});
+  EXPECT_EQ(rotl(uint16_t{0x1234}, 16), uint16_t{0x1234});
+  EXPECT_EQ(rotl(uint32_t{0x12345678UL}, 32), uint32_t{0x12345678UL});
+  EXPECT_EQ(rotl(uint64_t{0x12345678ABCDEF01ULL}, 64),
+            uint64_t{0x12345678ABCDEF01ULL});
+
+  EXPECT_EQ(rotl(uint8_t{0x12}, -8), uint8_t{0x12});
+  EXPECT_EQ(rotl(uint16_t{0x1234}, -16), uint16_t{0x1234});
+  EXPECT_EQ(rotl(uint32_t{0x12345678UL}, -32), uint32_t{0x12345678UL});
+  EXPECT_EQ(rotl(uint64_t{0x12345678ABCDEF01ULL}, -64),
+            uint64_t{0x12345678ABCDEF01ULL});
+
+  EXPECT_EQ(rotl(uint8_t{0x12}, 4), uint8_t{0x21});
+  EXPECT_EQ(rotl(uint16_t{0x1234}, 4), uint16_t{0x2341});
+  EXPECT_EQ(rotl(uint32_t{0x12345678UL}, 4), uint32_t{0x23456781UL});
+  EXPECT_EQ(rotl(uint64_t{0x12345678ABCDEF01ULL}, 4),
+            uint64_t{0x2345678ABCDEF011ULL});
+
+  EXPECT_EQ(rotl(uint8_t{0x12}, -4), uint8_t{0x21});
+  EXPECT_EQ(rotl(uint16_t{0x1234}, -4), uint16_t{0x4123});
+  EXPECT_EQ(rotl(uint32_t{0x12345678UL}, -4), uint32_t{0x81234567UL});
+  EXPECT_EQ(rotl(uint64_t{0x12345678ABCDEF01ULL}, -4),
+            uint64_t{0x112345678ABCDEF0ULL});
+}
+
+TEST(Rotate, Right) {
+  static_assert(rotr(uint8_t{0x12}, 0) == uint8_t{0x12}, "");
+  static_assert(rotr(uint16_t{0x1234}, 0) == uint16_t{0x1234}, "");
+  static_assert(rotr(uint32_t{0x12345678UL}, 0) == uint32_t{0x12345678UL}, "");
+  static_assert(rotr(uint64_t{0x12345678ABCDEF01ULL}, 0) ==
+                    uint64_t{0x12345678ABCDEF01ULL},
+                "");
+
+  EXPECT_EQ(rotr(uint8_t{0x12}, 0), uint8_t{0x12});
+  EXPECT_EQ(rotr(uint16_t{0x1234}, 0), uint16_t{0x1234});
+  EXPECT_EQ(rotr(uint32_t{0x12345678UL}, 0), uint32_t{0x12345678UL});
+  EXPECT_EQ(rotr(uint64_t{0x12345678ABCDEF01ULL}, 0),
+            uint64_t{0x12345678ABCDEF01ULL});
+
+  EXPECT_EQ(rotr(uint8_t{0x12}, 8), uint8_t{0x12});
+  EXPECT_EQ(rotr(uint16_t{0x1234}, 16), uint16_t{0x1234});
+  EXPECT_EQ(rotr(uint32_t{0x12345678UL}, 32), uint32_t{0x12345678UL});
+  EXPECT_EQ(rotr(uint64_t{0x12345678ABCDEF01ULL}, 64),
+            uint64_t{0x12345678ABCDEF01ULL});
+
+  EXPECT_EQ(rotr(uint8_t{0x12}, -8), uint8_t{0x12});
+  EXPECT_EQ(rotr(uint16_t{0x1234}, -16), uint16_t{0x1234});
+  EXPECT_EQ(rotr(uint32_t{0x12345678UL}, -32), uint32_t{0x12345678UL});
+  EXPECT_EQ(rotr(uint64_t{0x12345678ABCDEF01ULL}, -64),
+            uint64_t{0x12345678ABCDEF01ULL});
+
+  EXPECT_EQ(rotr(uint8_t{0x12}, 4), uint8_t{0x21});
+  EXPECT_EQ(rotr(uint16_t{0x1234}, 4), uint16_t{0x4123});
+  EXPECT_EQ(rotr(uint32_t{0x12345678UL}, 4), uint32_t{0x81234567UL});
+  EXPECT_EQ(rotr(uint64_t{0x12345678ABCDEF01ULL}, 4),
+            uint64_t{0x112345678ABCDEF0ULL});
+
+  EXPECT_EQ(rotr(uint8_t{0x12}, -4), uint8_t{0x21});
+  EXPECT_EQ(rotr(uint16_t{0x1234}, -4), uint16_t{0x2341});
+  EXPECT_EQ(rotr(uint32_t{0x12345678UL}, -4), uint32_t{0x23456781UL});
+  EXPECT_EQ(rotr(uint64_t{0x12345678ABCDEF01ULL}, -4),
+            uint64_t{0x2345678ABCDEF011ULL});
+}
+
+TEST(Rotate, Symmetry) {
+  // rotr(x, s) is equivalent to rotl(x, -s)
+  absl::BitGen rng;
+  constexpr int kTrials = 100;
+
+  for (int i = 0; i < kTrials; ++i) {
+    uint8_t value = absl::Uniform(rng, std::numeric_limits<uint8_t>::min(),
+                                  std::numeric_limits<uint8_t>::max());
+    int shift = absl::Uniform(rng, -2 * std::numeric_limits<uint8_t>::digits,
+                              2 * std::numeric_limits<uint8_t>::digits);
+
+    EXPECT_EQ(rotl(value, shift), rotr(value, -shift));
+  }
+
+  for (int i = 0; i < kTrials; ++i) {
+    uint16_t value = absl::Uniform(rng, std::numeric_limits<uint16_t>::min(),
+                                   std::numeric_limits<uint16_t>::max());
+    int shift = absl::Uniform(rng, -2 * std::numeric_limits<uint16_t>::digits,
+                              2 * std::numeric_limits<uint16_t>::digits);
+
+    EXPECT_EQ(rotl(value, shift), rotr(value, -shift));
+  }
+
+  for (int i = 0; i < kTrials; ++i) {
+    uint32_t value = absl::Uniform(rng, std::numeric_limits<uint32_t>::min(),
+                                   std::numeric_limits<uint32_t>::max());
+    int shift = absl::Uniform(rng, -2 * std::numeric_limits<uint32_t>::digits,
+                              2 * std::numeric_limits<uint32_t>::digits);
+
+    EXPECT_EQ(rotl(value, shift), rotr(value, -shift));
+  }
+
+  for (int i = 0; i < kTrials; ++i) {
+    uint64_t value = absl::Uniform(rng, std::numeric_limits<uint64_t>::min(),
+                                   std::numeric_limits<uint64_t>::max());
+    int shift = absl::Uniform(rng, -2 * std::numeric_limits<uint64_t>::digits,
+                              2 * std::numeric_limits<uint64_t>::digits);
+
+    EXPECT_EQ(rotl(value, shift), rotr(value, -shift));
+  }
+}
+
+TEST(Counting, LeadingZeroes) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CLZ
+  static_assert(countl_zero(uint8_t{}) == 8, "");
+  static_assert(countl_zero(static_cast<uint8_t>(-1)) == 0, "");
+  static_assert(countl_zero(uint16_t{}) == 16, "");
+  static_assert(countl_zero(static_cast<uint16_t>(-1)) == 0, "");
+  static_assert(countl_zero(uint32_t{}) == 32, "");
+  static_assert(countl_zero(~uint32_t{}) == 0, "");
+  static_assert(countl_zero(uint64_t{}) == 64, "");
+  static_assert(countl_zero(~uint64_t{}) == 0, "");
+#endif
+
+  EXPECT_EQ(countl_zero(uint8_t{}), 8);
+  EXPECT_EQ(countl_zero(static_cast<uint8_t>(-1)), 0);
+  EXPECT_EQ(countl_zero(uint16_t{}), 16);
+  EXPECT_EQ(countl_zero(static_cast<uint16_t>(-1)), 0);
+  EXPECT_EQ(countl_zero(uint32_t{}), 32);
+  EXPECT_EQ(countl_zero(~uint32_t{}), 0);
+  EXPECT_EQ(countl_zero(uint64_t{}), 64);
+  EXPECT_EQ(countl_zero(~uint64_t{}), 0);
+
+  for (int i = 0; i < 8; i++) {
+    EXPECT_EQ(countl_zero(static_cast<uint8_t>(1u << i)), 7 - i);
+  }
+
+  for (int i = 0; i < 16; i++) {
+    EXPECT_EQ(countl_zero(static_cast<uint16_t>(1u << i)), 15 - i);
+  }
+
+  for (int i = 0; i < 32; i++) {
+    EXPECT_EQ(countl_zero(uint32_t{1} << i), 31 - i);
+  }
+
+  for (int i = 0; i < 64; i++) {
+    EXPECT_EQ(countl_zero(uint64_t{1} << i), 63 - i);
+  }
+}
+
+TEST(Counting, LeadingOnes) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CLZ
+  static_assert(countl_one(uint8_t{}) == 0, "");
+  static_assert(countl_one(static_cast<uint8_t>(-1)) == 8, "");
+  static_assert(countl_one(uint16_t{}) == 0, "");
+  static_assert(countl_one(static_cast<uint16_t>(-1)) == 16, "");
+  static_assert(countl_one(uint32_t{}) == 0, "");
+  static_assert(countl_one(~uint32_t{}) == 32, "");
+  static_assert(countl_one(uint64_t{}) == 0, "");
+  static_assert(countl_one(~uint64_t{}) == 64, "");
+#endif
+
+  EXPECT_EQ(countl_one(uint8_t{}), 0);
+  EXPECT_EQ(countl_one(static_cast<uint8_t>(-1)), 8);
+  EXPECT_EQ(countl_one(uint16_t{}), 0);
+  EXPECT_EQ(countl_one(static_cast<uint16_t>(-1)), 16);
+  EXPECT_EQ(countl_one(uint32_t{}), 0);
+  EXPECT_EQ(countl_one(~uint32_t{}), 32);
+  EXPECT_EQ(countl_one(uint64_t{}), 0);
+  EXPECT_EQ(countl_one(~uint64_t{}), 64);
+}
+
+TEST(Counting, TrailingZeroes) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CTZ
+  static_assert(countr_zero(uint8_t{}) == 8, "");
+  static_assert(countr_zero(static_cast<uint8_t>(-1)) == 0, "");
+  static_assert(countr_zero(uint16_t{}) == 16, "");
+  static_assert(countr_zero(static_cast<uint16_t>(-1)) == 0, "");
+  static_assert(countr_zero(uint32_t{}) == 32, "");
+  static_assert(countr_zero(~uint32_t{}) == 0, "");
+  static_assert(countr_zero(uint64_t{}) == 64, "");
+  static_assert(countr_zero(~uint64_t{}) == 0, "");
+#endif
+
+  EXPECT_EQ(countr_zero(uint8_t{}), 8);
+  EXPECT_EQ(countr_zero(static_cast<uint8_t>(-1)), 0);
+  EXPECT_EQ(countr_zero(uint16_t{}), 16);
+  EXPECT_EQ(countr_zero(static_cast<uint16_t>(-1)), 0);
+  EXPECT_EQ(countr_zero(uint32_t{}), 32);
+  EXPECT_EQ(countr_zero(~uint32_t{}), 0);
+  EXPECT_EQ(countr_zero(uint64_t{}), 64);
+  EXPECT_EQ(countr_zero(~uint64_t{}), 0);
+}
+
+TEST(Counting, TrailingOnes) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CTZ
+  static_assert(countr_one(uint8_t{}) == 0, "");
+  static_assert(countr_one(static_cast<uint8_t>(-1)) == 8, "");
+  static_assert(countr_one(uint16_t{}) == 0, "");
+  static_assert(countr_one(static_cast<uint16_t>(-1)) == 16, "");
+  static_assert(countr_one(uint32_t{}) == 0, "");
+  static_assert(countr_one(~uint32_t{}) == 32, "");
+  static_assert(countr_one(uint64_t{}) == 0, "");
+  static_assert(countr_one(~uint64_t{}) == 64, "");
+#endif
+
+  EXPECT_EQ(countr_one(uint8_t{}), 0);
+  EXPECT_EQ(countr_one(static_cast<uint8_t>(-1)), 8);
+  EXPECT_EQ(countr_one(uint16_t{}), 0);
+  EXPECT_EQ(countr_one(static_cast<uint16_t>(-1)), 16);
+  EXPECT_EQ(countr_one(uint32_t{}), 0);
+  EXPECT_EQ(countr_one(~uint32_t{}), 32);
+  EXPECT_EQ(countr_one(uint64_t{}), 0);
+  EXPECT_EQ(countr_one(~uint64_t{}), 64);
+}
+
+TEST(Counting, Popcount) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT
+  static_assert(popcount(uint8_t{}) == 0, "");
+  static_assert(popcount(uint8_t{1}) == 1, "");
+  static_assert(popcount(static_cast<uint8_t>(-1)) == 8, "");
+  static_assert(popcount(uint16_t{}) == 0, "");
+  static_assert(popcount(uint16_t{1}) == 1, "");
+  static_assert(popcount(static_cast<uint16_t>(-1)) == 16, "");
+  static_assert(popcount(uint32_t{}) == 0, "");
+  static_assert(popcount(uint32_t{1}) == 1, "");
+  static_assert(popcount(~uint32_t{}) == 32, "");
+  static_assert(popcount(uint64_t{}) == 0, "");
+  static_assert(popcount(uint64_t{1}) == 1, "");
+  static_assert(popcount(~uint64_t{}) == 64, "");
+#endif  // ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT
+
+  EXPECT_EQ(popcount(uint8_t{}), 0);
+  EXPECT_EQ(popcount(uint8_t{1}), 1);
+  EXPECT_EQ(popcount(static_cast<uint8_t>(-1)), 8);
+  EXPECT_EQ(popcount(uint16_t{}), 0);
+  EXPECT_EQ(popcount(uint16_t{1}), 1);
+  EXPECT_EQ(popcount(static_cast<uint16_t>(-1)), 16);
+  EXPECT_EQ(popcount(uint32_t{}), 0);
+  EXPECT_EQ(popcount(uint32_t{1}), 1);
+  EXPECT_EQ(popcount(~uint32_t{}), 32);
+  EXPECT_EQ(popcount(uint64_t{}), 0);
+  EXPECT_EQ(popcount(uint64_t{1}), 1);
+  EXPECT_EQ(popcount(~uint64_t{}), 64);
+
+  for (int i = 0; i < 8; i++) {
+    EXPECT_EQ(popcount(static_cast<uint8_t>(uint8_t{1} << i)), 1);
+    EXPECT_EQ(popcount(static_cast<uint8_t>(static_cast<uint8_t>(-1) ^
+                                            (uint8_t{1} << i))),
+              7);
+  }
+
+  for (int i = 0; i < 16; i++) {
+    EXPECT_EQ(popcount(static_cast<uint16_t>(uint16_t{1} << i)), 1);
+    EXPECT_EQ(popcount(static_cast<uint16_t>(static_cast<uint16_t>(-1) ^
+                                             (uint16_t{1} << i))),
+              15);
+  }
+
+  for (int i = 0; i < 32; i++) {
+    EXPECT_EQ(popcount(uint32_t{1} << i), 1);
+    EXPECT_EQ(popcount(static_cast<uint32_t>(-1) ^ (uint32_t{1} << i)), 31);
+  }
+
+  for (int i = 0; i < 64; i++) {
+    EXPECT_EQ(popcount(uint64_t{1} << i), 1);
+    EXPECT_EQ(popcount(static_cast<uint64_t>(-1) ^ (uint64_t{1} << i)), 63);
+  }
+}
+
+template <typename T>
+struct PopcountInput {
+  T value = 0;
+  int expected = 0;
+};
+
+template <typename T>
+PopcountInput<T> GeneratePopcountInput(absl::BitGen& gen) {
+  PopcountInput<T> ret;
+  for (int i = 0; i < std::numeric_limits<T>::digits; i++) {
+    bool coin = absl::Bernoulli(gen, 0.2);
+    if (coin) {
+      ret.value |= T{1} << i;
+      ret.expected++;
+    }
+  }
+  return ret;
+}
+
+TEST(Counting, PopcountFuzz) {
+  absl::BitGen rng;
+  constexpr int kTrials = 100;
+
+  for (int i = 0; i < kTrials; ++i) {
+    auto input = GeneratePopcountInput<uint8_t>(rng);
+    EXPECT_EQ(popcount(input.value), input.expected);
+  }
+
+  for (int i = 0; i < kTrials; ++i) {
+    auto input = GeneratePopcountInput<uint16_t>(rng);
+    EXPECT_EQ(popcount(input.value), input.expected);
+  }
+
+  for (int i = 0; i < kTrials; ++i) {
+    auto input = GeneratePopcountInput<uint32_t>(rng);
+    EXPECT_EQ(popcount(input.value), input.expected);
+  }
+
+  for (int i = 0; i < kTrials; ++i) {
+    auto input = GeneratePopcountInput<uint64_t>(rng);
+    EXPECT_EQ(popcount(input.value), input.expected);
+  }
+}
+
+TEST(IntegralPowersOfTwo, SingleBit) {
+  EXPECT_FALSE(has_single_bit(uint8_t{}));
+  EXPECT_FALSE(has_single_bit(static_cast<uint8_t>(-1)));
+  EXPECT_FALSE(has_single_bit(uint16_t{}));
+  EXPECT_FALSE(has_single_bit(static_cast<uint16_t>(-1)));
+  EXPECT_FALSE(has_single_bit(uint32_t{}));
+  EXPECT_FALSE(has_single_bit(~uint32_t{}));
+  EXPECT_FALSE(has_single_bit(uint64_t{}));
+  EXPECT_FALSE(has_single_bit(~uint64_t{}));
+
+  static_assert(!has_single_bit(0u), "");
+  static_assert(has_single_bit(1u), "");
+  static_assert(has_single_bit(2u), "");
+  static_assert(!has_single_bit(3u), "");
+  static_assert(has_single_bit(4u), "");
+  static_assert(!has_single_bit(1337u), "");
+  static_assert(has_single_bit(65536u), "");
+  static_assert(has_single_bit(uint32_t{1} << 30), "");
+  static_assert(has_single_bit(uint64_t{1} << 42), "");
+
+  EXPECT_FALSE(has_single_bit(0u));
+  EXPECT_TRUE(has_single_bit(1u));
+  EXPECT_TRUE(has_single_bit(2u));
+  EXPECT_FALSE(has_single_bit(3u));
+  EXPECT_TRUE(has_single_bit(4u));
+  EXPECT_FALSE(has_single_bit(1337u));
+  EXPECT_TRUE(has_single_bit(65536u));
+  EXPECT_TRUE(has_single_bit(uint32_t{1} << 30));
+  EXPECT_TRUE(has_single_bit(uint64_t{1} << 42));
+
+  EXPECT_TRUE(has_single_bit(
+      static_cast<uint8_t>(std::numeric_limits<uint8_t>::max() / 2 + 1)));
+  EXPECT_TRUE(has_single_bit(
+      static_cast<uint16_t>(std::numeric_limits<uint16_t>::max() / 2 + 1)));
+  EXPECT_TRUE(has_single_bit(
+      static_cast<uint32_t>(std::numeric_limits<uint32_t>::max() / 2 + 1)));
+  EXPECT_TRUE(has_single_bit(
+      static_cast<uint64_t>(std::numeric_limits<uint64_t>::max() / 2 + 1)));
+}
+
+template <typename T, T arg, T = bit_ceil(arg)>
+bool IsBitCeilConstantExpression(int) {
+  return true;
+}
+template <typename T, T arg>
+bool IsBitCeilConstantExpression(char) {
+  return false;
+}
+
+TEST(IntegralPowersOfTwo, Ceiling) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CLZ
+  static_assert(bit_ceil(0u) == 1, "");
+  static_assert(bit_ceil(1u) == 1, "");
+  static_assert(bit_ceil(2u) == 2, "");
+  static_assert(bit_ceil(3u) == 4, "");
+  static_assert(bit_ceil(4u) == 4, "");
+  static_assert(bit_ceil(1337u) == 2048, "");
+  static_assert(bit_ceil(65536u) == 65536, "");
+  static_assert(bit_ceil(65536u - 1337u) == 65536, "");
+  static_assert(bit_ceil(uint32_t{0x80000000}) == uint32_t{0x80000000}, "");
+  static_assert(bit_ceil(uint64_t{0x40000000000}) == uint64_t{0x40000000000},
+                "");
+  static_assert(
+      bit_ceil(uint64_t{0x8000000000000000}) == uint64_t{0x8000000000000000},
+      "");
+
+  EXPECT_TRUE((IsBitCeilConstantExpression<uint8_t, uint8_t{0x0}>(0)));
+  EXPECT_TRUE((IsBitCeilConstantExpression<uint8_t, uint8_t{0x80}>(0)));
+  EXPECT_FALSE((IsBitCeilConstantExpression<uint8_t, uint8_t{0x81}>(0)));
+  EXPECT_FALSE((IsBitCeilConstantExpression<uint8_t, uint8_t{0xff}>(0)));
+
+  EXPECT_TRUE((IsBitCeilConstantExpression<uint16_t, uint16_t{0x0}>(0)));
+  EXPECT_TRUE((IsBitCeilConstantExpression<uint16_t, uint16_t{0x8000}>(0)));
+  EXPECT_FALSE((IsBitCeilConstantExpression<uint16_t, uint16_t{0x8001}>(0)));
+  EXPECT_FALSE((IsBitCeilConstantExpression<uint16_t, uint16_t{0xffff}>(0)));
+
+  EXPECT_TRUE((IsBitCeilConstantExpression<uint32_t, uint32_t{0x0}>(0)));
+  EXPECT_TRUE((IsBitCeilConstantExpression<uint32_t, uint32_t{0x80000000}>(0)));
+  EXPECT_FALSE(
+      (IsBitCeilConstantExpression<uint32_t, uint32_t{0x80000001}>(0)));
+  EXPECT_FALSE(
+      (IsBitCeilConstantExpression<uint32_t, uint32_t{0xffffffff}>(0)));
+
+  EXPECT_TRUE((IsBitCeilConstantExpression<uint64_t, uint64_t{0x0}>(0)));
+  EXPECT_TRUE(
+      (IsBitCeilConstantExpression<uint64_t, uint64_t{0x8000000000000000}>(0)));
+  EXPECT_FALSE(
+      (IsBitCeilConstantExpression<uint64_t, uint64_t{0x8000000000000001}>(0)));
+  EXPECT_FALSE(
+      (IsBitCeilConstantExpression<uint64_t, uint64_t{0xffffffffffffffff}>(0)));
+#endif
+
+  EXPECT_EQ(bit_ceil(0u), 1);
+  EXPECT_EQ(bit_ceil(1u), 1);
+  EXPECT_EQ(bit_ceil(2u), 2);
+  EXPECT_EQ(bit_ceil(3u), 4);
+  EXPECT_EQ(bit_ceil(4u), 4);
+  EXPECT_EQ(bit_ceil(1337u), 2048);
+  EXPECT_EQ(bit_ceil(65536u), 65536);
+  EXPECT_EQ(bit_ceil(65536u - 1337u), 65536);
+  EXPECT_EQ(bit_ceil(uint64_t{0x40000000000}), uint64_t{0x40000000000});
+}
+
+TEST(IntegralPowersOfTwo, Floor) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CLZ
+  static_assert(bit_floor(0u) == 0, "");
+  static_assert(bit_floor(1u) == 1, "");
+  static_assert(bit_floor(2u) == 2, "");
+  static_assert(bit_floor(3u) == 2, "");
+  static_assert(bit_floor(4u) == 4, "");
+  static_assert(bit_floor(1337u) == 1024, "");
+  static_assert(bit_floor(65536u) == 65536, "");
+  static_assert(bit_floor(65536u - 1337u) == 32768, "");
+  static_assert(bit_floor(uint64_t{0x40000000000}) == uint64_t{0x40000000000},
+                "");
+#endif
+
+  EXPECT_EQ(bit_floor(0u), 0);
+  EXPECT_EQ(bit_floor(1u), 1);
+  EXPECT_EQ(bit_floor(2u), 2);
+  EXPECT_EQ(bit_floor(3u), 2);
+  EXPECT_EQ(bit_floor(4u), 4);
+  EXPECT_EQ(bit_floor(1337u), 1024);
+  EXPECT_EQ(bit_floor(65536u), 65536);
+  EXPECT_EQ(bit_floor(65536u - 1337u), 32768);
+  EXPECT_EQ(bit_floor(uint64_t{0x40000000000}), uint64_t{0x40000000000});
+
+  for (int i = 0; i < 8; i++) {
+    uint8_t input = uint8_t{1} << i;
+    EXPECT_EQ(bit_floor(input), input);
+    if (i > 0) {
+      EXPECT_EQ(bit_floor(static_cast<uint8_t>(input + 1)), input);
+    }
+  }
+
+  for (int i = 0; i < 16; i++) {
+    uint16_t input = uint16_t{1} << i;
+    EXPECT_EQ(bit_floor(input), input);
+    if (i > 0) {
+      EXPECT_EQ(bit_floor(static_cast<uint16_t>(input + 1)), input);
+    }
+  }
+
+  for (int i = 0; i < 32; i++) {
+    uint32_t input = uint32_t{1} << i;
+    EXPECT_EQ(bit_floor(input), input);
+    if (i > 0) {
+      EXPECT_EQ(bit_floor(input + 1), input);
+    }
+  }
+
+  for (int i = 0; i < 64; i++) {
+    uint64_t input = uint64_t{1} << i;
+    EXPECT_EQ(bit_floor(input), input);
+    if (i > 0) {
+      EXPECT_EQ(bit_floor(input + 1), input);
+    }
+  }
+}
+
+TEST(IntegralPowersOfTwo, Width) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CLZ
+  static_assert(bit_width(uint8_t{}) == 0, "");
+  static_assert(bit_width(uint8_t{1}) == 1, "");
+  static_assert(bit_width(uint8_t{3}) == 2, "");
+  static_assert(bit_width(static_cast<uint8_t>(-1)) == 8, "");
+  static_assert(bit_width(uint16_t{}) == 0, "");
+  static_assert(bit_width(uint16_t{1}) == 1, "");
+  static_assert(bit_width(uint16_t{3}) == 2, "");
+  static_assert(bit_width(static_cast<uint16_t>(-1)) == 16, "");
+  static_assert(bit_width(uint32_t{}) == 0, "");
+  static_assert(bit_width(uint32_t{1}) == 1, "");
+  static_assert(bit_width(uint32_t{3}) == 2, "");
+  static_assert(bit_width(~uint32_t{}) == 32, "");
+  static_assert(bit_width(uint64_t{}) == 0, "");
+  static_assert(bit_width(uint64_t{1}) == 1, "");
+  static_assert(bit_width(uint64_t{3}) == 2, "");
+  static_assert(bit_width(~uint64_t{}) == 64, "");
+#endif
+
+  EXPECT_EQ(bit_width(uint8_t{}), 0);
+  EXPECT_EQ(bit_width(uint8_t{1}), 1);
+  EXPECT_EQ(bit_width(uint8_t{3}), 2);
+  EXPECT_EQ(bit_width(static_cast<uint8_t>(-1)), 8);
+  EXPECT_EQ(bit_width(uint16_t{}), 0);
+  EXPECT_EQ(bit_width(uint16_t{1}), 1);
+  EXPECT_EQ(bit_width(uint16_t{3}), 2);
+  EXPECT_EQ(bit_width(static_cast<uint16_t>(-1)), 16);
+  EXPECT_EQ(bit_width(uint32_t{}), 0);
+  EXPECT_EQ(bit_width(uint32_t{1}), 1);
+  EXPECT_EQ(bit_width(uint32_t{3}), 2);
+  EXPECT_EQ(bit_width(~uint32_t{}), 32);
+  EXPECT_EQ(bit_width(uint64_t{}), 0);
+  EXPECT_EQ(bit_width(uint64_t{1}), 1);
+  EXPECT_EQ(bit_width(uint64_t{3}), 2);
+  EXPECT_EQ(bit_width(~uint64_t{}), 64);
+
+  for (int i = 0; i < 8; i++) {
+    EXPECT_EQ(bit_width(static_cast<uint8_t>(uint8_t{1} << i)), i + 1);
+  }
+
+  for (int i = 0; i < 16; i++) {
+    EXPECT_EQ(bit_width(static_cast<uint16_t>(uint16_t{1} << i)), i + 1);
+  }
+
+  for (int i = 0; i < 32; i++) {
+    EXPECT_EQ(bit_width(uint32_t{1} << i), i + 1);
+  }
+
+  for (int i = 0; i < 64; i++) {
+    EXPECT_EQ(bit_width(uint64_t{1} << i), i + 1);
+  }
+}
+
+// On GCC and Clang, anticiapte that implementations will be constexpr
+#if defined(__GNUC__)
+static_assert(ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT,
+              "popcount should be constexpr");
+static_assert(ABSL_INTERNAL_HAS_CONSTEXPR_CLZ, "clz should be constexpr");
+static_assert(ABSL_INTERNAL_HAS_CONSTEXPR_CTZ, "ctz should be constexpr");
+#endif
+
+}  // namespace
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/numeric/int128.cc b/absl/numeric/int128.cc
index b605a87..5160df7 100644
--- a/absl/numeric/int128.cc
+++ b/absl/numeric/int128.cc
@@ -15,6 +15,7 @@
 #include "absl/numeric/int128.h"
 
 #include <stddef.h>
+
 #include <cassert>
 #include <iomanip>
 #include <ostream>  // NOLINT(readability/streams)
@@ -22,6 +23,9 @@
 #include <string>
 #include <type_traits>
 
+#include "absl/base/optimization.h"
+#include "absl/numeric/bits.h"
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
@@ -31,44 +35,26 @@
 namespace {
 
 // Returns the 0-based position of the last set bit (i.e., most significant bit)
-// in the given uint64_t. The argument may not be 0.
+// in the given uint128. The argument is not 0.
 //
 // For example:
 //   Given: 5 (decimal) == 101 (binary)
 //   Returns: 2
-#define STEP(T, n, pos, sh)                   \
-  do {                                        \
-    if ((n) >= (static_cast<T>(1) << (sh))) { \
-      (n) = (n) >> (sh);                      \
-      (pos) |= (sh);                          \
-    }                                         \
-  } while (0)
-static inline int Fls64(uint64_t n) {
-  assert(n != 0);
-  int pos = 0;
-  STEP(uint64_t, n, pos, 0x20);
-  uint32_t n32 = static_cast<uint32_t>(n);
-  STEP(uint32_t, n32, pos, 0x10);
-  STEP(uint32_t, n32, pos, 0x08);
-  STEP(uint32_t, n32, pos, 0x04);
-  return pos + ((uint64_t{0x3333333322221100} >> (n32 << 2)) & 0x3);
-}
-#undef STEP
-
-// Like Fls64() above, but returns the 0-based position of the last set bit
-// (i.e., most significant bit) in the given uint128. The argument may not be 0.
-static inline int Fls128(uint128 n) {
+inline ABSL_ATTRIBUTE_ALWAYS_INLINE int Fls128(uint128 n) {
   if (uint64_t hi = Uint128High64(n)) {
-    return Fls64(hi) + 64;
+    ABSL_INTERNAL_ASSUME(hi != 0);
+    return 127 - countl_zero(hi);
   }
-  return Fls64(Uint128Low64(n));
+  const uint64_t low = Uint128Low64(n);
+  ABSL_INTERNAL_ASSUME(low != 0);
+  return 63 - countl_zero(low);
 }
 
 // Long division/modulo for uint128 implemented using the shift-subtract
 // division algorithm adapted from:
 // https://stackoverflow.com/questions/5386377/division-without-using
-void DivModImpl(uint128 dividend, uint128 divisor, uint128* quotient_ret,
-                uint128* remainder_ret) {
+inline void DivModImpl(uint128 dividend, uint128 divisor, uint128* quotient_ret,
+                       uint128* remainder_ret) {
   assert(divisor != 0);
 
   if (divisor > dividend) {
diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h
index 636e3a5..0dd814a 100644
--- a/absl/numeric/int128.h
+++ b/absl/numeric/int128.h
@@ -792,28 +792,21 @@
 }
 
 inline bool operator<(uint128 lhs, uint128 rhs) {
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  return static_cast<unsigned __int128>(lhs) <
+         static_cast<unsigned __int128>(rhs);
+#else
   return (Uint128High64(lhs) == Uint128High64(rhs))
              ? (Uint128Low64(lhs) < Uint128Low64(rhs))
              : (Uint128High64(lhs) < Uint128High64(rhs));
+#endif
 }
 
-inline bool operator>(uint128 lhs, uint128 rhs) {
-  return (Uint128High64(lhs) == Uint128High64(rhs))
-             ? (Uint128Low64(lhs) > Uint128Low64(rhs))
-             : (Uint128High64(lhs) > Uint128High64(rhs));
-}
+inline bool operator>(uint128 lhs, uint128 rhs) { return rhs < lhs; }
 
-inline bool operator<=(uint128 lhs, uint128 rhs) {
-  return (Uint128High64(lhs) == Uint128High64(rhs))
-             ? (Uint128Low64(lhs) <= Uint128Low64(rhs))
-             : (Uint128High64(lhs) <= Uint128High64(rhs));
-}
+inline bool operator<=(uint128 lhs, uint128 rhs) { return !(rhs < lhs); }
 
-inline bool operator>=(uint128 lhs, uint128 rhs) {
-  return (Uint128High64(lhs) == Uint128High64(rhs))
-             ? (Uint128Low64(lhs) >= Uint128Low64(rhs))
-             : (Uint128High64(lhs) >= Uint128High64(rhs));
-}
+inline bool operator>=(uint128 lhs, uint128 rhs) { return !(lhs < rhs); }
 
 // Unary operators.
 
@@ -870,6 +863,9 @@
 // Arithmetic operators.
 
 inline uint128 operator<<(uint128 lhs, int amount) {
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  return static_cast<unsigned __int128>(lhs) << amount;
+#else
   // uint64_t shifts of >= 64 are undefined, so we will need some
   // special-casing.
   if (amount < 64) {
@@ -881,9 +877,13 @@
     return lhs;
   }
   return MakeUint128(Uint128Low64(lhs) << (amount - 64), 0);
+#endif
 }
 
 inline uint128 operator>>(uint128 lhs, int amount) {
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  return static_cast<unsigned __int128>(lhs) >> amount;
+#else
   // uint64_t shifts of >= 64 are undefined, so we will need some
   // special-casing.
   if (amount < 64) {
@@ -895,6 +895,7 @@
     return lhs;
   }
   return MakeUint128(0, Uint128High64(lhs) >> (amount - 64));
+#endif
 }
 
 inline uint128 operator+(uint128 lhs, uint128 rhs) {
diff --git a/absl/numeric/int128_benchmark.cc b/absl/numeric/int128_benchmark.cc
index a5502d9..eab1515 100644
--- a/absl/numeric/int128_benchmark.cc
+++ b/absl/numeric/int128_benchmark.cc
@@ -12,15 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "absl/numeric/int128.h"
-
 #include <algorithm>
 #include <cstdint>
+#include <limits>
 #include <random>
 #include <vector>
 
 #include "benchmark/benchmark.h"
 #include "absl/base/config.h"
+#include "absl/numeric/int128.h"
 
 namespace {
 
@@ -32,57 +32,85 @@
   return std::mt19937(seed);
 }
 
-std::vector<std::pair<absl::uint128, absl::uint128>>
-GetRandomClass128SampleUniformDivisor() {
-  std::vector<std::pair<absl::uint128, absl::uint128>> values;
+template <typename T,
+          typename H = typename std::conditional<
+              std::numeric_limits<T>::is_signed, int64_t, uint64_t>::type>
+std::vector<std::pair<T, T>> GetRandomClass128SampleUniformDivisor() {
+  std::vector<std::pair<T, T>> values;
   std::mt19937 random = MakeRandomEngine();
-  std::uniform_int_distribution<uint64_t> uniform_uint64;
+  std::uniform_int_distribution<H> uniform_h;
   values.reserve(kSampleSize);
   for (size_t i = 0; i < kSampleSize; ++i) {
-    absl::uint128 a =
-        absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
-    absl::uint128 b =
-        absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
-    values.emplace_back(std::max(a, b),
-                        std::max(absl::uint128(2), std::min(a, b)));
+    T a{absl::MakeUint128(uniform_h(random), uniform_h(random))};
+    T b{absl::MakeUint128(uniform_h(random), uniform_h(random))};
+    values.emplace_back(std::max(a, b), std::max(T(2), std::min(a, b)));
   }
   return values;
 }
 
+template <typename T>
 void BM_DivideClass128UniformDivisor(benchmark::State& state) {
-  auto values = GetRandomClass128SampleUniformDivisor();
+  auto values = GetRandomClass128SampleUniformDivisor<T>();
   while (state.KeepRunningBatch(values.size())) {
     for (const auto& pair : values) {
       benchmark::DoNotOptimize(pair.first / pair.second);
     }
   }
 }
-BENCHMARK(BM_DivideClass128UniformDivisor);
+BENCHMARK_TEMPLATE(BM_DivideClass128UniformDivisor, absl::uint128);
+BENCHMARK_TEMPLATE(BM_DivideClass128UniformDivisor, absl::int128);
 
-std::vector<std::pair<absl::uint128, uint64_t>>
-GetRandomClass128SampleSmallDivisor() {
-  std::vector<std::pair<absl::uint128, uint64_t>> values;
+template <typename T>
+void BM_RemainderClass128UniformDivisor(benchmark::State& state) {
+  auto values = GetRandomClass128SampleUniformDivisor<T>();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first % pair.second);
+    }
+  }
+}
+BENCHMARK_TEMPLATE(BM_RemainderClass128UniformDivisor, absl::uint128);
+BENCHMARK_TEMPLATE(BM_RemainderClass128UniformDivisor, absl::int128);
+
+template <typename T,
+          typename H = typename std::conditional<
+              std::numeric_limits<T>::is_signed, int64_t, uint64_t>::type>
+std::vector<std::pair<T, H>> GetRandomClass128SampleSmallDivisor() {
+  std::vector<std::pair<T, H>> values;
   std::mt19937 random = MakeRandomEngine();
-  std::uniform_int_distribution<uint64_t> uniform_uint64;
+  std::uniform_int_distribution<H> uniform_h;
   values.reserve(kSampleSize);
   for (size_t i = 0; i < kSampleSize; ++i) {
-    absl::uint128 a =
-        absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
-    uint64_t b = std::max(uint64_t{2}, uniform_uint64(random));
-    values.emplace_back(std::max(a, absl::uint128(b)), b);
+    T a{absl::MakeUint128(uniform_h(random), uniform_h(random))};
+    H b{std::max(H{2}, uniform_h(random))};
+    values.emplace_back(std::max(a, T(b)), b);
   }
   return values;
 }
 
+template <typename T>
 void BM_DivideClass128SmallDivisor(benchmark::State& state) {
-  auto values = GetRandomClass128SampleSmallDivisor();
+  auto values = GetRandomClass128SampleSmallDivisor<T>();
   while (state.KeepRunningBatch(values.size())) {
     for (const auto& pair : values) {
       benchmark::DoNotOptimize(pair.first / pair.second);
     }
   }
 }
-BENCHMARK(BM_DivideClass128SmallDivisor);
+BENCHMARK_TEMPLATE(BM_DivideClass128SmallDivisor, absl::uint128);
+BENCHMARK_TEMPLATE(BM_DivideClass128SmallDivisor, absl::int128);
+
+template <typename T>
+void BM_RemainderClass128SmallDivisor(benchmark::State& state) {
+  auto values = GetRandomClass128SampleSmallDivisor<T>();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first % pair.second);
+    }
+  }
+}
+BENCHMARK_TEMPLATE(BM_RemainderClass128SmallDivisor, absl::uint128);
+BENCHMARK_TEMPLATE(BM_RemainderClass128SmallDivisor, absl::int128);
 
 std::vector<std::pair<absl::uint128, absl::uint128>> GetRandomClass128Sample() {
   std::vector<std::pair<absl::uint128, absl::uint128>> values;
@@ -121,74 +149,107 @@
 
 // Some implementations of <random> do not support __int128 when it is
 // available, so we make our own uniform_int_distribution-like type.
+template <typename T,
+          typename H = typename std::conditional<
+              std::is_same<T, __int128>::value, int64_t, uint64_t>::type>
 class UniformIntDistribution128 {
  public:
   // NOLINTNEXTLINE: mimicking std::uniform_int_distribution API
-  unsigned __int128 operator()(std::mt19937& generator) {
-    return (static_cast<unsigned __int128>(dist64_(generator)) << 64) |
-           dist64_(generator);
+  T operator()(std::mt19937& generator) {
+    return (static_cast<T>(dist64_(generator)) << 64) | dist64_(generator);
   }
 
  private:
-  std::uniform_int_distribution<uint64_t> dist64_;
+  std::uniform_int_distribution<H> dist64_;
 };
 
-std::vector<std::pair<unsigned __int128, unsigned __int128>>
-GetRandomIntrinsic128SampleUniformDivisor() {
-  std::vector<std::pair<unsigned __int128, unsigned __int128>> values;
+template <typename T,
+          typename H = typename std::conditional<
+              std::is_same<T, __int128>::value, int64_t, uint64_t>::type>
+std::vector<std::pair<T, T>> GetRandomIntrinsic128SampleUniformDivisor() {
+  std::vector<std::pair<T, T>> values;
   std::mt19937 random = MakeRandomEngine();
-  UniformIntDistribution128 uniform_uint128;
+  UniformIntDistribution128<T> uniform_128;
   values.reserve(kSampleSize);
   for (size_t i = 0; i < kSampleSize; ++i) {
-    unsigned __int128 a = uniform_uint128(random);
-    unsigned __int128 b = uniform_uint128(random);
-    values.emplace_back(
-        std::max(a, b),
-        std::max(static_cast<unsigned __int128>(2), std::min(a, b)));
+    T a = uniform_128(random);
+    T b = uniform_128(random);
+    values.emplace_back(std::max(a, b),
+                        std::max(static_cast<T>(2), std::min(a, b)));
   }
   return values;
 }
 
+template <typename T>
 void BM_DivideIntrinsic128UniformDivisor(benchmark::State& state) {
-  auto values = GetRandomIntrinsic128SampleUniformDivisor();
+  auto values = GetRandomIntrinsic128SampleUniformDivisor<T>();
   while (state.KeepRunningBatch(values.size())) {
     for (const auto& pair : values) {
       benchmark::DoNotOptimize(pair.first / pair.second);
     }
   }
 }
-BENCHMARK(BM_DivideIntrinsic128UniformDivisor);
+BENCHMARK_TEMPLATE(BM_DivideIntrinsic128UniformDivisor, unsigned __int128);
+BENCHMARK_TEMPLATE(BM_DivideIntrinsic128UniformDivisor, __int128);
 
-std::vector<std::pair<unsigned __int128, uint64_t>>
-GetRandomIntrinsic128SampleSmallDivisor() {
-  std::vector<std::pair<unsigned __int128, uint64_t>> values;
+template <typename T>
+void BM_RemainderIntrinsic128UniformDivisor(benchmark::State& state) {
+  auto values = GetRandomIntrinsic128SampleUniformDivisor<T>();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first % pair.second);
+    }
+  }
+}
+BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128UniformDivisor, unsigned __int128);
+BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128UniformDivisor, __int128);
+
+template <typename T,
+          typename H = typename std::conditional<
+              std::is_same<T, __int128>::value, int64_t, uint64_t>::type>
+std::vector<std::pair<T, H>> GetRandomIntrinsic128SampleSmallDivisor() {
+  std::vector<std::pair<T, H>> values;
   std::mt19937 random = MakeRandomEngine();
-  UniformIntDistribution128 uniform_uint128;
-  std::uniform_int_distribution<uint64_t> uniform_uint64;
+  UniformIntDistribution128<T> uniform_int128;
+  std::uniform_int_distribution<H> uniform_int64;
   values.reserve(kSampleSize);
   for (size_t i = 0; i < kSampleSize; ++i) {
-    unsigned __int128 a = uniform_uint128(random);
-    uint64_t b = std::max(uint64_t{2}, uniform_uint64(random));
-    values.emplace_back(std::max(a, static_cast<unsigned __int128>(b)), b);
+    T a = uniform_int128(random);
+    H b = std::max(H{2}, uniform_int64(random));
+    values.emplace_back(std::max(a, static_cast<T>(b)), b);
   }
   return values;
 }
 
+template <typename T>
 void BM_DivideIntrinsic128SmallDivisor(benchmark::State& state) {
-  auto values = GetRandomIntrinsic128SampleSmallDivisor();
+  auto values = GetRandomIntrinsic128SampleSmallDivisor<T>();
   while (state.KeepRunningBatch(values.size())) {
     for (const auto& pair : values) {
       benchmark::DoNotOptimize(pair.first / pair.second);
     }
   }
 }
-BENCHMARK(BM_DivideIntrinsic128SmallDivisor);
+BENCHMARK_TEMPLATE(BM_DivideIntrinsic128SmallDivisor, unsigned __int128);
+BENCHMARK_TEMPLATE(BM_DivideIntrinsic128SmallDivisor, __int128);
+
+template <typename T>
+void BM_RemainderIntrinsic128SmallDivisor(benchmark::State& state) {
+  auto values = GetRandomIntrinsic128SampleSmallDivisor<T>();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first % pair.second);
+    }
+  }
+}
+BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128SmallDivisor, unsigned __int128);
+BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128SmallDivisor, __int128);
 
 std::vector<std::pair<unsigned __int128, unsigned __int128>>
       GetRandomIntrinsic128Sample() {
   std::vector<std::pair<unsigned __int128, unsigned __int128>> values;
   std::mt19937 random = MakeRandomEngine();
-  UniformIntDistribution128 uniform_uint128;
+  UniformIntDistribution128<unsigned __int128> uniform_uint128;
   values.reserve(kSampleSize);
   for (size_t i = 0; i < kSampleSize; ++i) {
     values.emplace_back(uniform_uint128(random), uniform_uint128(random));
diff --git a/absl/numeric/internal/bits.h b/absl/numeric/internal/bits.h
new file mode 100644
index 0000000..bfef06b
--- /dev/null
+++ b/absl/numeric/internal/bits.h
@@ -0,0 +1,358 @@
+// 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.
+
+#ifndef ABSL_NUMERIC_INTERNAL_BITS_H_
+#define ABSL_NUMERIC_INTERNAL_BITS_H_
+
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+
+// Clang on Windows has __builtin_clzll; otherwise we need to use the
+// windows intrinsic functions.
+#if defined(_MSC_VER) && !defined(__clang__)
+#include <intrin.h>
+#endif
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+
+#if defined(__GNUC__) && !defined(__clang__)
+// GCC
+#define ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(x) 1
+#else
+#define ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(x) ABSL_HAVE_BUILTIN(x)
+#endif
+
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcountl) && \
+    ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcountll)
+#define ABSL_INTERNAL_CONSTEXPR_POPCOUNT constexpr
+#define ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT 1
+#else
+#define ABSL_INTERNAL_CONSTEXPR_POPCOUNT
+#define ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT 0
+#endif
+
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clz) && \
+    ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clzll)
+#define ABSL_INTERNAL_CONSTEXPR_CLZ constexpr
+#define ABSL_INTERNAL_HAS_CONSTEXPR_CLZ 1
+#else
+#define ABSL_INTERNAL_CONSTEXPR_CLZ
+#define ABSL_INTERNAL_HAS_CONSTEXPR_CLZ 0
+#endif
+
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctz) && \
+    ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctzll)
+#define ABSL_INTERNAL_CONSTEXPR_CTZ constexpr
+#define ABSL_INTERNAL_HAS_CONSTEXPR_CTZ 1
+#else
+#define ABSL_INTERNAL_CONSTEXPR_CTZ
+#define ABSL_INTERNAL_HAS_CONSTEXPR_CTZ 0
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace numeric_internal {
+
+constexpr bool IsPowerOf2(unsigned int x) noexcept {
+  return x != 0 && (x & (x - 1)) == 0;
+}
+
+template <class T>
+ABSL_MUST_USE_RESULT ABSL_ATTRIBUTE_ALWAYS_INLINE constexpr T RotateRight(
+    T x, int s) noexcept {
+  static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+  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)));
+}
+
+template <class T>
+ABSL_MUST_USE_RESULT ABSL_ATTRIBUTE_ALWAYS_INLINE constexpr T RotateLeft(
+    T x, int s) noexcept {
+  static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+  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)));
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int
+Popcount32(uint32_t x) noexcept {
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcount)
+  static_assert(sizeof(unsigned int) == sizeof(x),
+                "__builtin_popcount does not take 32-bit arg");
+  return __builtin_popcount(x);
+#else
+  x -= ((x >> 1) & 0x55555555);
+  x = ((x >> 2) & 0x33333333) + (x & 0x33333333);
+  return static_cast<int>((((x + (x >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24);
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int
+Popcount64(uint64_t x) noexcept {
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcountll)
+  static_assert(sizeof(unsigned long long) == sizeof(x),  // NOLINT(runtime/int)
+                "__builtin_popcount does not take 64-bit arg");
+  return __builtin_popcountll(x);
+#else
+  x -= (x >> 1) & 0x5555555555555555ULL;
+  x = ((x >> 2) & 0x3333333333333333ULL) + (x & 0x3333333333333333ULL);
+  return static_cast<int>(
+      (((x + (x >> 4)) & 0xF0F0F0F0F0F0F0FULL) * 0x101010101010101ULL) >> 56);
+#endif
+}
+
+template <class T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int
+Popcount(T x) noexcept {
+  static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+  static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
+                "T must have a power-of-2 size");
+  static_assert(sizeof(x) <= sizeof(uint64_t), "T is too large");
+  return sizeof(x) <= sizeof(uint32_t) ? Popcount32(x) : Popcount64(x);
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int
+CountLeadingZeroes32(uint32_t x) {
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clz)
+  // Use __builtin_clz, which uses the following instructions:
+  //  x86: bsr, lzcnt
+  //  ARM64: clz
+  //  PPC: cntlzd
+
+  static_assert(sizeof(unsigned int) == sizeof(x),
+                "__builtin_clz does not take 32-bit arg");
+  // Handle 0 as a special case because __builtin_clz(0) is undefined.
+  return x == 0 ? 32 : __builtin_clz(x);
+#elif defined(_MSC_VER) && !defined(__clang__)
+  unsigned long result = 0;  // NOLINT(runtime/int)
+  if (_BitScanReverse(&result, x)) {
+    return 31 - result;
+  }
+  return 32;
+#else
+  int zeroes = 28;
+  if (x >> 16) {
+    zeroes -= 16;
+    x >>= 16;
+  }
+  if (x >> 8) {
+    zeroes -= 8;
+    x >>= 8;
+  }
+  if (x >> 4) {
+    zeroes -= 4;
+    x >>= 4;
+  }
+  return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[x] + zeroes;
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int
+CountLeadingZeroes16(uint16_t x) {
+#if ABSL_HAVE_BUILTIN(__builtin_clzs)
+  static_assert(sizeof(unsigned short) == sizeof(x),  // NOLINT(runtime/int)
+                "__builtin_clzs does not take 16-bit arg");
+  return x == 0 ? 16 : __builtin_clzs(x);
+#else
+  return CountLeadingZeroes32(x) - 16;
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int
+CountLeadingZeroes64(uint64_t x) {
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clzll)
+  // Use __builtin_clzll, which uses the following instructions:
+  //  x86: bsr, lzcnt
+  //  ARM64: clz
+  //  PPC: cntlzd
+  static_assert(sizeof(unsigned long long) == sizeof(x),  // NOLINT(runtime/int)
+                "__builtin_clzll does not take 64-bit arg");
+
+  // Handle 0 as a special case because __builtin_clzll(0) is undefined.
+  return x == 0 ? 64 : __builtin_clzll(x);
+#elif defined(_MSC_VER) && !defined(__clang__) && \
+    (defined(_M_X64) || defined(_M_ARM64))
+  // MSVC does not have __buitin_clzll. Use _BitScanReverse64.
+  unsigned long result = 0;  // NOLINT(runtime/int)
+  if (_BitScanReverse64(&result, x)) {
+    return 63 - result;
+  }
+  return 64;
+#elif defined(_MSC_VER) && !defined(__clang__)
+  // MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse
+  unsigned long result = 0;  // NOLINT(runtime/int)
+  if ((x >> 32) &&
+      _BitScanReverse(&result, static_cast<unsigned long>(x >> 32))) {
+    return 31 - result;
+  }
+  if (_BitScanReverse(&result, static_cast<unsigned long>(x))) {
+    return 63 - result;
+  }
+  return 64;
+#else
+  int zeroes = 60;
+  if (x >> 32) {
+    zeroes -= 32;
+    x >>= 32;
+  }
+  if (x >> 16) {
+    zeroes -= 16;
+    x >>= 16;
+  }
+  if (x >> 8) {
+    zeroes -= 8;
+    x >>= 8;
+  }
+  if (x >> 4) {
+    zeroes -= 4;
+    x >>= 4;
+  }
+  return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[x] + zeroes;
+#endif
+}
+
+template <typename T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int
+CountLeadingZeroes(T x) {
+  static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+  static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
+                "T must have a power-of-2 size");
+  static_assert(sizeof(T) <= sizeof(uint64_t), "T too large");
+  return sizeof(T) <= sizeof(uint16_t)
+             ? CountLeadingZeroes16(static_cast<uint16_t>(x)) -
+                   (std::numeric_limits<uint16_t>::digits -
+                    std::numeric_limits<T>::digits)
+             : (sizeof(T) <= sizeof(uint32_t)
+                    ? CountLeadingZeroes32(static_cast<uint32_t>(x)) -
+                          (std::numeric_limits<uint32_t>::digits -
+                           std::numeric_limits<T>::digits)
+                    : CountLeadingZeroes64(x));
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int
+CountTrailingZeroesNonzero32(uint32_t x) {
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctz)
+  static_assert(sizeof(unsigned int) == sizeof(x),
+                "__builtin_ctz does not take 32-bit arg");
+  return __builtin_ctz(x);
+#elif defined(_MSC_VER) && !defined(__clang__)
+  unsigned long result = 0;  // NOLINT(runtime/int)
+  _BitScanForward(&result, x);
+  return result;
+#else
+  int c = 31;
+  x &= ~x + 1;
+  if (x & 0x0000FFFF) c -= 16;
+  if (x & 0x00FF00FF) c -= 8;
+  if (x & 0x0F0F0F0F) c -= 4;
+  if (x & 0x33333333) c -= 2;
+  if (x & 0x55555555) c -= 1;
+  return c;
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int
+CountTrailingZeroesNonzero64(uint64_t x) {
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctzll)
+  static_assert(sizeof(unsigned long long) == sizeof(x),  // NOLINT(runtime/int)
+                "__builtin_ctzll does not take 64-bit arg");
+  return __builtin_ctzll(x);
+#elif defined(_MSC_VER) && !defined(__clang__) && \
+    (defined(_M_X64) || defined(_M_ARM64))
+  unsigned long result = 0;  // NOLINT(runtime/int)
+  _BitScanForward64(&result, x);
+  return result;
+#elif defined(_MSC_VER) && !defined(__clang__)
+  unsigned long result = 0;  // NOLINT(runtime/int)
+  if (static_cast<uint32_t>(x) == 0) {
+    _BitScanForward(&result, static_cast<unsigned long>(x >> 32));
+    return result + 32;
+  }
+  _BitScanForward(&result, static_cast<unsigned long>(x));
+  return result;
+#else
+  int c = 63;
+  x &= ~x + 1;
+  if (x & 0x00000000FFFFFFFF) c -= 32;
+  if (x & 0x0000FFFF0000FFFF) c -= 16;
+  if (x & 0x00FF00FF00FF00FF) c -= 8;
+  if (x & 0x0F0F0F0F0F0F0F0F) c -= 4;
+  if (x & 0x3333333333333333) c -= 2;
+  if (x & 0x5555555555555555) c -= 1;
+  return c;
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int
+CountTrailingZeroesNonzero16(uint16_t x) {
+#if ABSL_HAVE_BUILTIN(__builtin_ctzs)
+  static_assert(sizeof(unsigned short) == sizeof(x),  // NOLINT(runtime/int)
+                "__builtin_ctzs does not take 16-bit arg");
+  return __builtin_ctzs(x);
+#else
+  return CountTrailingZeroesNonzero32(x);
+#endif
+}
+
+template <class T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int
+CountTrailingZeroes(T x) noexcept {
+  static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+  static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
+                "T must have a power-of-2 size");
+  static_assert(sizeof(T) <= sizeof(uint64_t), "T too large");
+  return x == 0 ? std::numeric_limits<T>::digits
+                : (sizeof(T) <= sizeof(uint16_t)
+                       ? CountTrailingZeroesNonzero16(static_cast<uint16_t>(x))
+                       : (sizeof(T) <= sizeof(uint32_t)
+                              ? CountTrailingZeroesNonzero32(
+                                    static_cast<uint32_t>(x))
+                              : CountTrailingZeroesNonzero64(x)));
+}
+
+// If T is narrower than unsigned, T{1} << bit_width will be promoted.  We
+// want to force it to wraparound so that bit_ceil of an invalid value are not
+// core constant expressions.
+template <class T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    BitCeilPromotionHelper(T x, T promotion) {
+  return (T{1} << (x + promotion)) >> promotion;
+}
+
+template <class T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    BitCeilNonPowerOf2(T x) {
+  // If T is narrower than unsigned, it undergoes promotion to unsigned when we
+  // shift.  We calculate the number of bits added by the wider type.
+  return BitCeilPromotionHelper(
+      static_cast<T>(std::numeric_limits<T>::digits - CountLeadingZeroes(x)),
+      T{sizeof(T) >= sizeof(unsigned) ? 0
+                                      : std::numeric_limits<unsigned>::digits -
+                                            std::numeric_limits<T>::digits});
+}
+
+}  // namespace numeric_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_NUMERIC_INTERNAL_BITS_H_
diff --git a/absl/numeric/internal/representation.h b/absl/numeric/internal/representation.h
new file mode 100644
index 0000000..82d332f
--- /dev/null
+++ b/absl/numeric/internal/representation.h
@@ -0,0 +1,55 @@
+// Copyright 2021 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_NUMERIC_INTERNAL_REPRESENTATION_H_
+#define ABSL_NUMERIC_INTERNAL_REPRESENTATION_H_
+
+#include <limits>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace numeric_internal {
+
+// Returns true iff long double is represented as a pair of doubles added
+// together.
+inline constexpr bool IsDoubleDouble() {
+  // A double-double value always has exactly twice the precision of a double
+  // value--one double carries the high digits and one double carries the low
+  // digits. This property is not shared with any other common floating-point
+  // representation, so this test won't trigger false positives. For reference,
+  // this table gives the number of bits of precision of each common
+  // floating-point representation:
+  //
+  //                type     precision
+  //         IEEE single          24 b
+  //         IEEE double          53
+  //     x86 long double          64
+  //       double-double         106
+  //      IEEE quadruple         113
+  //
+  // Note in particular that a quadruple-precision float has greater precision
+  // than a double-double float despite taking up the same amount of memory; the
+  // quad has more of its bits allocated to the mantissa than the double-double
+  // has.
+  return std::numeric_limits<long double>::digits ==
+         2 * std::numeric_limits<double>::digits;
+}
+
+}  // namespace numeric_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_NUMERIC_INTERNAL_REPRESENTATION_H_
diff --git a/absl/random/BUILD.bazel b/absl/random/BUILD.bazel
index f78fbc7..66ffcbc 100644
--- a/absl/random/BUILD.bazel
+++ b/absl/random/BUILD.bazel
@@ -53,7 +53,6 @@
         "bernoulli_distribution.h",
         "beta_distribution.h",
         "discrete_distribution.h",
-        "distribution_format_traits.h",
         "distributions.h",
         "exponential_distribution.h",
         "gaussian_distribution.h",
@@ -70,7 +69,8 @@
         "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/meta:type_traits",
-        "//absl/random/internal:distributions",
+        "//absl/numeric:bits",
+        "//absl/random/internal:distribution_caller",
         "//absl/random/internal:fast_uniform_bits",
         "//absl/random/internal:fastmath",
         "//absl/random/internal:generate_real",
@@ -79,7 +79,6 @@
         "//absl/random/internal:uniform_helper",
         "//absl/random/internal:wide_multiply",
         "//absl/strings",
-        "//absl/types:span",
     ],
 )
 
@@ -117,11 +116,12 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        ":random",
         "//absl/base:core_headers",
+        "//absl/base:fast_type_id",
         "//absl/meta:type_traits",
         "//absl/random/internal:distribution_caller",
         "//absl/random/internal:fast_uniform_bits",
-        "//absl/random/internal:mocking_bit_gen_base",
     ],
 )
 
@@ -141,20 +141,17 @@
 cc_library(
     name = "mocking_bit_gen",
     testonly = 1,
-    srcs = [
-        "mocking_bit_gen.cc",
-    ],
     hdrs = [
         "mocking_bit_gen.h",
     ],
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":distributions",
-        "//absl/base:raw_logging_internal",
+        ":random",
+        "//absl/base:fast_type_id",
         "//absl/container:flat_hash_map",
         "//absl/meta:type_traits",
         "//absl/random/internal:distribution_caller",
-        "//absl/random/internal:mocking_bit_gen_base",
         "//absl/strings",
         "//absl/types:span",
         "//absl/types:variant",
@@ -173,6 +170,7 @@
     deps = [
         ":distributions",
         ":random",
+        "//absl/random/internal:pcg_engine",
         "//absl/random/internal:sequence_urbg",
         "@com_google_googletest//:gtest_main",
     ],
@@ -190,7 +188,9 @@
         ":distributions",
         ":random",
         "//absl/base:raw_logging_internal",
+        "//absl/numeric:representation",
         "//absl/random/internal:distribution_test_util",
+        "//absl/random/internal:pcg_engine",
         "//absl/random/internal:sequence_urbg",
         "//absl/strings",
         "//absl/strings:str_format",
@@ -201,6 +201,7 @@
 cc_test(
     name = "distributions_test",
     size = "small",
+    timeout = "moderate",
     srcs = [
         "distributions_test.cc",
     ],
@@ -238,9 +239,9 @@
     deps = [
         ":distributions",
         ":random",
-        "//absl/base:core_headers",
         "//absl/base:raw_logging_internal",
         "//absl/random/internal:distribution_test_util",
+        "//absl/random/internal:pcg_engine",
         "//absl/random/internal:sequence_urbg",
         "//absl/strings",
         "//absl/strings:str_format",
@@ -261,6 +262,7 @@
         ":random",
         "//absl/base:raw_logging_internal",
         "//absl/random/internal:distribution_test_util",
+        "//absl/random/internal:pcg_engine",
         "//absl/random/internal:sequence_urbg",
         "//absl/strings",
         "@com_google_googletest//:gtest_main",
@@ -288,6 +290,7 @@
         "//absl/base:raw_logging_internal",
         "//absl/container:flat_hash_map",
         "//absl/random/internal:distribution_test_util",
+        "//absl/random/internal:pcg_engine",
         "//absl/random/internal:sequence_urbg",
         "//absl/strings",
         "//absl/strings:str_format",
@@ -306,7 +309,9 @@
         ":random",
         "//absl/base:core_headers",
         "//absl/base:raw_logging_internal",
+        "//absl/numeric:representation",
         "//absl/random/internal:distribution_test_util",
+        "//absl/random/internal:pcg_engine",
         "//absl/random/internal:sequence_urbg",
         "//absl/strings",
         "//absl/strings:str_format",
@@ -328,6 +333,7 @@
         ":random",
         "//absl/base:core_headers",
         "//absl/base:raw_logging_internal",
+        "//absl/numeric:representation",
         "//absl/random/internal:distribution_test_util",
         "//absl/random/internal:sequence_urbg",
         "//absl/strings",
@@ -350,6 +356,7 @@
         ":random",
         "//absl/base:raw_logging_internal",
         "//absl/random/internal:distribution_test_util",
+        "//absl/random/internal:pcg_engine",
         "//absl/random/internal:sequence_urbg",
         "//absl/strings",
         "@com_google_googletest//:gtest_main",
@@ -373,7 +380,9 @@
         ":distributions",
         ":random",
         "//absl/base:raw_logging_internal",
+        "//absl/numeric:representation",
         "//absl/random/internal:distribution_test_util",
+        "//absl/random/internal:pcg_engine",
         "//absl/random/internal:sequence_urbg",
         "//absl/strings",
         "@com_google_googletest//:gtest_main",
@@ -393,6 +402,7 @@
         ":random",
         "//absl/base:raw_logging_internal",
         "//absl/random/internal:distribution_test_util",
+        "//absl/random/internal:pcg_engine",
         "//absl/random/internal:sequence_urbg",
         "//absl/strings",
         "@com_google_googletest//:gtest_main",
@@ -408,6 +418,7 @@
     deps = [
         ":bit_gen_ref",
         ":random",
+        "//absl/base:fast_type_id",
         "//absl/random/internal:sequence_urbg",
         "@com_google_googletest//:gtest_main",
     ],
@@ -417,6 +428,7 @@
     name = "mocking_bit_gen_test",
     size = "small",
     srcs = ["mocking_bit_gen_test.cc"],
+    copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":bit_gen_ref",
@@ -431,6 +443,8 @@
     name = "mock_distributions_test",
     size = "small",
     srcs = ["mock_distributions_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":mock_distributions",
         ":mocking_bit_gen",
diff --git a/absl/random/CMakeLists.txt b/absl/random/CMakeLists.txt
index efa55d8..3009a03 100644
--- a/absl/random/CMakeLists.txt
+++ b/absl/random/CMakeLists.txt
@@ -45,7 +45,6 @@
     absl::core_headers
     absl::random_internal_distribution_caller
     absl::random_internal_fast_uniform_bits
-    absl::random_internal_mocking_bit_gen_base
     absl::type_traits
 )
 
@@ -62,6 +61,7 @@
     absl::random_bit_gen_ref
     absl::random_random
     absl::random_internal_sequence_urbg
+    absl::fast_type_id
     gmock
     gtest_main
 )
@@ -69,16 +69,16 @@
 # Internal-only target, do not depend on directly.
 absl_cc_library(
   NAME
-    random_internal_mocking_bit_gen_base
+    random_internal_mock_helpers
   HDRS
-    "internal/mocking_bit_gen_base.h"
+    "internal/mock_helpers.h"
   COPTS
     ${ABSL_DEFAULT_COPTS}
   LINKOPTS
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
-    absl::random_random
-    absl::strings
+    absl::fast_type_id
+    absl::optional
 )
 
 # Internal-only target, do not depend on directly.
@@ -93,6 +93,7 @@
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
     absl::random_mocking_bit_gen
+    absl::random_internal_mock_helpers
   TESTONLY
 )
 
@@ -102,8 +103,6 @@
   HDRS
     "mock_distributions.h"
     "mocking_bit_gen.h"
-  SRCS
-    "mocking_bit_gen.cc"
   COPTS
     ${ABSL_DEFAULT_COPTS}
   LINKOPTS
@@ -113,8 +112,8 @@
     absl::raw_logging_internal
     absl::random_distributions
     absl::random_internal_distribution_caller
-    absl::random_internal_mocking_bit_gen_base
     absl::random_internal_mock_overload_set
+    absl::random_random
     absl::strings
     absl::span
     absl::type_traits
@@ -168,7 +167,6 @@
     "bernoulli_distribution.h"
     "beta_distribution.h"
     "discrete_distribution.h"
-    "distribution_format_traits.h"
     "distributions.h"
     "exponential_distribution.h"
     "gaussian_distribution.h"
@@ -186,7 +184,7 @@
     absl::config
     absl::core_headers
     absl::random_internal_generate_real
-    absl::random_internal_distributions
+    absl::random_internal_distribution_caller
     absl::random_internal_fast_uniform_bits
     absl::random_internal_fastmath
     absl::random_internal_iostream_state_saver
@@ -194,7 +192,6 @@
     absl::random_internal_uniform_helper
     absl::random_internal_wide_multiply
     absl::strings
-    absl::span
     absl::type_traits
 )
 
@@ -247,6 +244,7 @@
     absl::random_distributions
     absl::random_random
     absl::random_internal_sequence_urbg
+    absl::random_internal_pcg_engine
     gmock
     gtest_main
 )
@@ -261,10 +259,12 @@
   LINKOPTS
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
+    absl::numeric_representation
     absl::random_distributions
     absl::random_random
     absl::random_internal_distribution_test_util
     absl::random_internal_sequence_urbg
+    absl::random_internal_pcg_engine
     absl::raw_logging_internal
     absl::strings
     absl::str_format
@@ -314,9 +314,9 @@
     ${ABSL_TEST_COPTS}
   LINKOPTS
     ${ABSL_DEFAULT_LINKOPTS}
-    absl::core_headers
     absl::random_distributions
     absl::random_internal_distribution_test_util
+    absl::random_internal_pcg_engine
     absl::random_internal_sequence_urbg
     absl::random_random
     absl::raw_logging_internal
@@ -338,6 +338,7 @@
   DEPS
     absl::random_distributions
     absl::random_internal_distribution_test_util
+    absl::random_internal_pcg_engine
     absl::random_internal_sequence_urbg
     absl::random_random
     absl::raw_logging_internal
@@ -361,6 +362,7 @@
     absl::core_headers
     absl::flat_hash_map
     absl::random_internal_distribution_test_util
+    absl::random_internal_pcg_engine
     absl::random_internal_sequence_urbg
     absl::raw_logging_internal
     absl::strings
@@ -380,8 +382,10 @@
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
     absl::core_headers
+    absl::numeric_representation
     absl::random_distributions
     absl::random_internal_distribution_test_util
+    absl::random_internal_pcg_engine
     absl::random_internal_sequence_urbg
     absl::random_random
     absl::raw_logging_internal
@@ -402,6 +406,7 @@
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
     absl::core_headers
+    absl::numeric_representation
     absl::random_distributions
     absl::random_internal_distribution_test_util
     absl::random_internal_sequence_urbg
@@ -425,6 +430,7 @@
   DEPS
     absl::random_distributions
     absl::random_internal_distribution_test_util
+    absl::random_internal_pcg_engine
     absl::random_internal_sequence_urbg
     absl::random_random
     absl::raw_logging_internal
@@ -443,8 +449,10 @@
   LINKOPTS
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
+    absl::numeric_representation
     absl::random_distributions
     absl::random_internal_distribution_test_util
+    absl::random_internal_pcg_engine
     absl::random_internal_sequence_urbg
     absl::random_random
     absl::strings
@@ -464,6 +472,7 @@
   DEPS
     absl::random_distributions
     absl::random_internal_distribution_test_util
+    absl::random_internal_pcg_engine
     absl::random_internal_sequence_urbg
     absl::random_random
     absl::raw_logging_internal
@@ -529,27 +538,8 @@
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
     absl::config
-)
-
-# Internal-only target, do not depend on directly.
-absl_cc_library(
-  NAME
-    random_internal_distributions
-  HDRS
-    "internal/distributions.h"
-  COPTS
-    ${ABSL_DEFAULT_COPTS}
-  LINKOPTS
-    ${ABSL_DEFAULT_LINKOPTS}
-  DEPS
-    absl::random_internal_distribution_caller
-    absl::random_internal_fast_uniform_bits
-    absl::random_internal_fastmath
-    absl::random_internal_traits
-    absl::random_internal_uniform_helper
-    absl::span
-    absl::strings
-    absl::type_traits
+    absl::utility
+    absl::fast_type_id
 )
 
 # Internal-only target, do not depend on directly.
@@ -625,6 +615,7 @@
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
     absl::config
+    absl::endian
   TESTONLY
 )
 
@@ -740,7 +731,6 @@
     absl::random_internal_salted_seed_seq
     absl::random_internal_seed_material
     absl::span
-    absl::strings
     absl::type_traits
 )
 
@@ -773,6 +763,7 @@
   LINKOPTS
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
+    absl::endian
     absl::random_internal_iostream_state_saver
     absl::random_internal_randen
     absl::raw_logging_internal
@@ -785,8 +776,9 @@
     random_internal_platform
   HDRS
     "internal/randen_traits.h"
-    "internal/randen-keys.inc"
     "internal/platform.h"
+  SRCS
+    "internal/randen_round_keys.cc"
   COPTS
     ${ABSL_DEFAULT_COPTS}
   LINKOPTS
@@ -1133,6 +1125,7 @@
   LINKOPTS
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
+    absl::endian
     absl::random_internal_randen_slow
     gtest_main
 )
@@ -1168,9 +1161,7 @@
   LINKOPTS
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
-    absl::core_headers
-    absl::random_internal_fast_uniform_bits
-    absl::random_internal_iostream_state_saver
+    absl::config
     absl::random_internal_traits
     absl::type_traits
 )
@@ -1178,6 +1169,21 @@
 # Internal-only target, do not depend on directly.
 absl_cc_test(
   NAME
+    random_internal_uniform_helper_test
+  SRCS
+    "internal/uniform_helper_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+    absl::random_internal_uniform_helper
+    gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+  NAME
     random_internal_iostream_state_saver_test
   SRCS
     "internal/iostream_state_saver_test.cc"
diff --git a/absl/random/bernoulli_distribution_test.cc b/absl/random/bernoulli_distribution_test.cc
index f2c3b99..b250f87 100644
--- a/absl/random/bernoulli_distribution_test.cc
+++ b/absl/random/bernoulli_distribution_test.cc
@@ -21,6 +21,7 @@
 #include <utility>
 
 #include "gtest/gtest.h"
+#include "absl/random/internal/pcg_engine.h"
 #include "absl/random/internal/sequence_urbg.h"
 #include "absl/random/random.h"
 
@@ -63,7 +64,10 @@
   size_t trials = para.second;
   double p = para.first;
 
-  absl::InsecureBitGen rng;
+  // We use a fixed bit generator for distribution accuracy tests.  This allows
+  // these tests to be deterministic, while still testing the qualify of the
+  // implementation.
+  absl::random_internal::pcg64_2018_engine rng(0x2B7E151628AED2A6);
 
   size_t yes = 0;
   absl::bernoulli_distribution dist(p);
@@ -131,7 +135,7 @@
       0x275b0dc7e0a18acfull, 0x36cebe0d2653682eull, 0x0361e9b23861596bull,
   });
 
-  // Generate a std::string of '0' and '1' for the distribution output.
+  // Generate a string of '0' and '1' for the distribution output.
   auto generate = [&urbg](absl::bernoulli_distribution& dist) {
     std::string output;
     output.reserve(36);
@@ -176,7 +180,7 @@
        0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
        0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull});
 
-  // Generate a std::string of '0' and '1' for the distribution output.
+  // Generate a string of '0' and '1' for the distribution output.
   auto generate = [&urbg](absl::bernoulli_distribution& dist) {
     std::string output;
     output.reserve(13);
diff --git a/absl/random/beta_distribution_test.cc b/absl/random/beta_distribution_test.cc
index d0111b3..44cdfdd 100644
--- a/absl/random/beta_distribution_test.cc
+++ b/absl/random/beta_distribution_test.cc
@@ -21,14 +21,17 @@
 #include <random>
 #include <sstream>
 #include <string>
+#include <type_traits>
 #include <unordered_map>
 #include <vector>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "absl/base/internal/raw_logging.h"
+#include "absl/numeric/internal/representation.h"
 #include "absl/random/internal/chi_square.h"
 #include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/pcg_engine.h"
 #include "absl/random/internal/sequence_urbg.h"
 #include "absl/random/random.h"
 #include "absl/strings/str_cat.h"
@@ -41,7 +44,15 @@
 template <typename IntType>
 class BetaDistributionInterfaceTest : public ::testing::Test {};
 
-using RealTypes = ::testing::Types<float, double, long double>;
+// double-double arithmetic is not supported well by either GCC or Clang; see
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99048,
+// https://bugs.llvm.org/show_bug.cgi?id=49131, and
+// https://bugs.llvm.org/show_bug.cgi?id=49132. Don't bother running these tests
+// with double doubles until compiler support is better.
+using RealTypes =
+    std::conditional<absl::numeric_internal::IsDoubleDouble(),
+                     ::testing::Types<float, double>,
+                     ::testing::Types<float, double, long double>>::type;
 TYPED_TEST_CASE(BetaDistributionInterfaceTest, RealTypes);
 
 TYPED_TEST(BetaDistributionInterfaceTest, SerializeTest) {
@@ -52,9 +63,6 @@
   const TypeParam kLargeA =
       std::exp(std::log((std::numeric_limits<TypeParam>::max)()) -
                std::log(std::log((std::numeric_limits<TypeParam>::max)())));
-  const TypeParam kLargeAPPC = std::exp(
-      std::log((std::numeric_limits<TypeParam>::max)()) -
-      std::log(std::log((std::numeric_limits<TypeParam>::max)())) - 10.0f);
   using param_type = typename absl::beta_distribution<TypeParam>::param_type;
 
   constexpr int kCount = 1000;
@@ -75,9 +83,6 @@
       kLargeA,                                //
       std::nextafter(kLargeA, TypeParam(0)),  //
       std::nextafter(kLargeA, std::numeric_limits<TypeParam>::max()),
-      kLargeAPPC,  //
-      std::nextafter(kLargeAPPC, TypeParam(0)),
-      std::nextafter(kLargeAPPC, std::numeric_limits<TypeParam>::max()),
       // Boundary cases.
       std::numeric_limits<TypeParam>::max(),
       std::numeric_limits<TypeParam>::epsilon(),
@@ -124,28 +129,6 @@
 
       ss >> after;
 
-#if defined(__powerpc64__) || defined(__PPC64__) || defined(__powerpc__) || \
-    defined(__ppc__) || defined(__PPC__)
-      if (std::is_same<TypeParam, long double>::value) {
-        // Roundtripping floating point values requires sufficient precision
-        // to reconstruct the exact value. It turns out that long double
-        // has some errors doing this on ppc.
-        if (alpha <= std::numeric_limits<double>::max() &&
-            alpha >= std::numeric_limits<double>::lowest()) {
-          EXPECT_EQ(static_cast<double>(before.alpha()),
-                    static_cast<double>(after.alpha()))
-              << ss.str();
-        }
-        if (beta <= std::numeric_limits<double>::max() &&
-            beta >= std::numeric_limits<double>::lowest()) {
-          EXPECT_EQ(static_cast<double>(before.beta()),
-                    static_cast<double>(after.beta()))
-              << ss.str();
-        }
-        continue;
-      }
-#endif
-
       EXPECT_EQ(before.alpha(), after.alpha());
       EXPECT_EQ(before.beta(), after.beta());
       EXPECT_EQ(before, after)           //
@@ -159,8 +142,12 @@
 }
 
 TYPED_TEST(BetaDistributionInterfaceTest, DegenerateCases) {
+  // We use a fixed bit generator for distribution accuracy tests.  This allows
+  // these tests to be deterministic, while still testing the qualify of the
+  // implementation.
+  absl::random_internal::pcg64_2018_engine rng(0x2B7E151628AED2A6);
+
   // Extreme cases when the params are abnormal.
-  absl::InsecureBitGen gen;
   constexpr int kCount = 1000;
   const TypeParam kSmallValues[] = {
       std::numeric_limits<TypeParam>::min(),
@@ -186,7 +173,7 @@
         int ones = 0;
         absl::beta_distribution<TypeParam> d(alpha, beta);
         for (int i = 0; i < kCount; ++i) {
-          TypeParam x = d(gen);
+          TypeParam x = d(rng);
           if (x == 0.0) {
             zeros++;
           } else if (x == 1.0) {
@@ -212,7 +199,7 @@
       for (TypeParam beta : kLargeValues) {
         absl::beta_distribution<TypeParam> d(alpha, beta);
         for (int i = 0; i < kCount; ++i) {
-          EXPECT_EQ(d(gen), 0.0);
+          EXPECT_EQ(d(rng), 0.0);
         }
       }
     }
@@ -227,7 +214,7 @@
       for (TypeParam beta : kSmallValues) {
         absl::beta_distribution<TypeParam> d(alpha, beta);
         for (int i = 0; i < kCount; ++i) {
-          EXPECT_EQ(d(gen), 1.0);
+          EXPECT_EQ(d(rng), 1.0);
         }
       }
     }
@@ -237,7 +224,7 @@
     absl::beta_distribution<TypeParam> d(std::numeric_limits<TypeParam>::max(),
                                          std::numeric_limits<TypeParam>::max());
     for (int i = 0; i < kCount; ++i) {
-      EXPECT_EQ(d(gen), 0.5);
+      EXPECT_EQ(d(rng), 0.5);
     }
   }
   {
@@ -246,7 +233,7 @@
         std::numeric_limits<TypeParam>::max(),
         std::numeric_limits<TypeParam>::max() * 0.9999);
     for (int i = 0; i < kCount; ++i) {
-      TypeParam x = d(gen);
+      TypeParam x = d(rng);
       EXPECT_NE(x, 0.5f);
       EXPECT_FLOAT_EQ(x, 0.500025f);
     }
diff --git a/absl/random/bit_gen_ref.h b/absl/random/bit_gen_ref.h
index e877116..9555460 100644
--- a/absl/random/bit_gen_ref.h
+++ b/absl/random/bit_gen_ref.h
@@ -24,11 +24,11 @@
 #ifndef ABSL_RANDOM_BIT_GEN_REF_H_
 #define ABSL_RANDOM_BIT_GEN_REF_H_
 
+#include "absl/base/internal/fast_type_id.h"
 #include "absl/base/macros.h"
 #include "absl/meta/type_traits.h"
 #include "absl/random/internal/distribution_caller.h"
 #include "absl/random/internal/fast_uniform_bits.h"
-#include "absl/random/internal/mocking_bit_gen_base.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -51,6 +51,10 @@
         typename std::decay<decltype(std::declval<URBG>()())>::type>::value>>
     : std::true_type {};
 
+template <typename>
+struct DistributionCaller;
+class MockHelpers;
+
 }  // namespace random_internal
 
 // -----------------------------------------------------------------------------
@@ -77,23 +81,50 @@
 //    }
 //
 class BitGenRef {
- public:
-  using result_type = uint64_t;
+  // SFINAE to detect whether the URBG type includes a member matching
+  // bool InvokeMock(base_internal::FastTypeIdType, void*, void*).
+  //
+  // These live inside BitGenRef so that they have friend access
+  // to MockingBitGen. (see similar methods in DistributionCaller).
+  template <template <class...> class Trait, class AlwaysVoid, class... Args>
+  struct detector : std::false_type {};
+  template <template <class...> class Trait, class... Args>
+  struct detector<Trait, absl::void_t<Trait<Args...>>, Args...>
+      : std::true_type {};
 
-  BitGenRef(const absl::BitGenRef&) = default;
-  BitGenRef(absl::BitGenRef&&) = default;
-  BitGenRef& operator=(const absl::BitGenRef&) = default;
-  BitGenRef& operator=(absl::BitGenRef&&) = default;
+  template <class T>
+  using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock(
+      std::declval<base_internal::FastTypeIdType>(), std::declval<void*>(),
+      std::declval<void*>()));
+
+  template <typename T>
+  using HasInvokeMock = typename detector<invoke_mock_t, void, T>::type;
+
+ public:
+  BitGenRef(const BitGenRef&) = default;
+  BitGenRef(BitGenRef&&) = default;
+  BitGenRef& operator=(const BitGenRef&) = default;
+  BitGenRef& operator=(BitGenRef&&) = default;
+
+  template <typename URBG, typename absl::enable_if_t<
+                               (!std::is_same<URBG, BitGenRef>::value &&
+                                random_internal::is_urbg<URBG>::value &&
+                                !HasInvokeMock<URBG>::value)>* = nullptr>
+  BitGenRef(URBG& gen)  // NOLINT
+      : t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
+        mock_call_(NotAMock),
+        generate_impl_fn_(ImplFn<URBG>) {}
 
   template <typename URBG,
-            typename absl::enable_if_t<
-                (!std::is_same<URBG, BitGenRef>::value &&
-                 random_internal::is_urbg<URBG>::value)>* = nullptr>
+            typename absl::enable_if_t<(!std::is_same<URBG, BitGenRef>::value &&
+                                        random_internal::is_urbg<URBG>::value &&
+                                        HasInvokeMock<URBG>::value)>* = nullptr>
   BitGenRef(URBG& gen)  // NOLINT
-      : mocked_gen_ptr_(MakeMockPointer(&gen)),
-        t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
-        generate_impl_fn_(ImplFn<URBG>) {
-  }
+      : t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
+        mock_call_(&MockCall<URBG>),
+        generate_impl_fn_(ImplFn<URBG>) {}
+
+  using result_type = uint64_t;
 
   static constexpr result_type(min)() {
     return (std::numeric_limits<result_type>::min)();
@@ -106,14 +137,9 @@
   result_type operator()() { return generate_impl_fn_(t_erased_gen_ptr_); }
 
  private:
-  friend struct absl::random_internal::DistributionCaller<absl::BitGenRef>;
   using impl_fn = result_type (*)(uintptr_t);
-  using mocker_base_t = absl::random_internal::MockingBitGenBase;
-
-  // Convert an arbitrary URBG pointer into either a valid mocker_base_t
-  // pointer or a nullptr.
-  static inline mocker_base_t* MakeMockPointer(mocker_base_t* t) { return t; }
-  static inline mocker_base_t* MakeMockPointer(void*) { return nullptr; }
+  using mock_call_fn = bool (*)(uintptr_t, base_internal::FastTypeIdType, void*,
+                                void*);
 
   template <typename URBG>
   static result_type ImplFn(uintptr_t ptr) {
@@ -123,30 +149,32 @@
     return fast_uniform_bits(*reinterpret_cast<URBG*>(ptr));
   }
 
-  mocker_base_t* mocked_gen_ptr_;
-  uintptr_t t_erased_gen_ptr_;
-  impl_fn generate_impl_fn_;
-};
-
-namespace random_internal {
-
-template <>
-struct DistributionCaller<absl::BitGenRef> {
-  template <typename DistrT, typename FormatT, typename... Args>
-  static typename DistrT::result_type Call(absl::BitGenRef* gen_ref,
-                                           Args&&... args) {
-    auto* mock_ptr = gen_ref->mocked_gen_ptr_;
-    if (mock_ptr == nullptr) {
-      DistrT dist(std::forward<Args>(args)...);
-      return dist(*gen_ref);
-    } else {
-      return mock_ptr->template Call<DistrT, FormatT>(
-          std::forward<Args>(args)...);
-    }
+  // Get a type-erased InvokeMock pointer.
+  template <typename URBG>
+  static bool MockCall(uintptr_t gen_ptr, base_internal::FastTypeIdType type,
+                       void* result, void* arg_tuple) {
+    return reinterpret_cast<URBG*>(gen_ptr)->InvokeMock(type, result,
+                                                        arg_tuple);
   }
+  static bool NotAMock(uintptr_t, base_internal::FastTypeIdType, void*, void*) {
+    return false;
+  }
+
+  inline bool InvokeMock(base_internal::FastTypeIdType type, void* args_tuple,
+                         void* result) {
+    if (mock_call_ == NotAMock) return false;  // avoids an indirect call.
+    return mock_call_(t_erased_gen_ptr_, type, args_tuple, result);
+  }
+
+  uintptr_t t_erased_gen_ptr_;
+  mock_call_fn mock_call_;
+  impl_fn generate_impl_fn_;
+
+  template <typename>
+  friend struct ::absl::random_internal::DistributionCaller;  // for InvokeMock
+  friend class ::absl::random_internal::MockHelpers;          // for InvokeMock
 };
 
-}  // namespace random_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
 
diff --git a/absl/random/bit_gen_ref_test.cc b/absl/random/bit_gen_ref_test.cc
index ca0e4d7..1135cf2 100644
--- a/absl/random/bit_gen_ref_test.cc
+++ b/absl/random/bit_gen_ref_test.cc
@@ -17,30 +17,31 @@
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/base/internal/fast_type_id.h"
 #include "absl/random/internal/sequence_urbg.h"
 #include "absl/random/random.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
-class ConstBitGen : public absl::random_internal::MockingBitGenBase {
-  bool CallImpl(const std::type_info&, void*, void* result) override {
+class ConstBitGen {
+ public:
+  // URBG interface
+  using result_type = absl::BitGen::result_type;
+
+  static constexpr result_type(min)() { return (absl::BitGen::min)(); }
+  static constexpr result_type(max)() { return (absl::BitGen::max)(); }
+  result_type operator()() { return 1; }
+
+  // InvokeMock method
+  bool InvokeMock(base_internal::FastTypeIdType index, void*, void* result) {
     *static_cast<int*>(result) = 42;
     return true;
   }
 };
 
-namespace random_internal {
-template <>
-struct DistributionCaller<ConstBitGen> {
-  template <typename DistrT, typename FormatT, typename... Args>
-  static typename DistrT::result_type Call(ConstBitGen* gen, Args&&... args) {
-    return gen->template Call<DistrT, FormatT>(std::forward<Args>(args)...);
-  }
-};
-}  // namespace random_internal
-
 namespace {
+
 int FnTest(absl::BitGenRef gen_ref) { return absl::Uniform(gen_ref, 1, 7); }
 
 template <typename T>
diff --git a/absl/random/discrete_distribution_test.cc b/absl/random/discrete_distribution_test.cc
index 7296f0a..6d00700 100644
--- a/absl/random/discrete_distribution_test.cc
+++ b/absl/random/discrete_distribution_test.cc
@@ -29,6 +29,7 @@
 #include "absl/base/internal/raw_logging.h"
 #include "absl/random/internal/chi_square.h"
 #include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/pcg_engine.h"
 #include "absl/random/internal/sequence_urbg.h"
 #include "absl/random/random.h"
 #include "absl/strings/str_cat.h"
@@ -156,7 +157,10 @@
   std::iota(std::begin(weights), std::end(weights), 1);
   absl::discrete_distribution<int> dist(std::begin(weights), std::end(weights));
 
-  absl::InsecureBitGen rng;
+  // We use a fixed bit generator for distribution accuracy tests.  This allows
+  // these tests to be deterministic, while still testing the qualify of the
+  // implementation.
+  absl::random_internal::pcg64_2018_engine rng(0x2B7E151628AED2A6);
 
   std::vector<int32_t> counts(kBuckets, 0);
   for (size_t i = 0; i < kTrials; i++) {
diff --git a/absl/random/distribution_format_traits.h b/absl/random/distribution_format_traits.h
deleted file mode 100644
index 22b358c..0000000
--- a/absl/random/distribution_format_traits.h
+++ /dev/null
@@ -1,278 +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.
-//
-#ifndef ABSL_RANDOM_DISTRIBUTION_FORMAT_TRAITS_H_
-#define ABSL_RANDOM_DISTRIBUTION_FORMAT_TRAITS_H_
-
-#include <string>
-#include <tuple>
-#include <typeinfo>
-
-#include "absl/meta/type_traits.h"
-#include "absl/random/bernoulli_distribution.h"
-#include "absl/random/beta_distribution.h"
-#include "absl/random/exponential_distribution.h"
-#include "absl/random/gaussian_distribution.h"
-#include "absl/random/log_uniform_int_distribution.h"
-#include "absl/random/poisson_distribution.h"
-#include "absl/random/uniform_int_distribution.h"
-#include "absl/random/uniform_real_distribution.h"
-#include "absl/random/zipf_distribution.h"
-#include "absl/strings/str_cat.h"
-#include "absl/strings/str_join.h"
-#include "absl/strings/string_view.h"
-#include "absl/types/span.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-
-struct IntervalClosedClosedTag;
-struct IntervalClosedOpenTag;
-struct IntervalOpenClosedTag;
-struct IntervalOpenOpenTag;
-
-namespace random_internal {
-
-// ScalarTypeName defines a preferred hierarchy of preferred type names for
-// scalars, and is evaluated at compile time for the specific type
-// specialization.
-template <typename T>
-constexpr const char* ScalarTypeName() {
-  static_assert(std::is_integral<T>() || std::is_floating_point<T>(), "");
-  // clang-format off
-    return
-        std::is_same<T, float>::value ? "float" :
-        std::is_same<T, double>::value ? "double" :
-        std::is_same<T, long double>::value ? "long double" :
-        std::is_same<T, bool>::value ? "bool" :
-        std::is_signed<T>::value && sizeof(T) == 1 ? "int8_t" :
-        std::is_signed<T>::value && sizeof(T) == 2 ? "int16_t" :
-        std::is_signed<T>::value && sizeof(T) == 4 ? "int32_t" :
-        std::is_signed<T>::value && sizeof(T) == 8 ? "int64_t" :
-        std::is_unsigned<T>::value && sizeof(T) == 1 ? "uint8_t" :
-        std::is_unsigned<T>::value && sizeof(T) == 2 ? "uint16_t" :
-        std::is_unsigned<T>::value && sizeof(T) == 4 ? "uint32_t" :
-        std::is_unsigned<T>::value && sizeof(T) == 8 ? "uint64_t" :
-            "undefined";
-  // clang-format on
-
-  // NOTE: It would be nice to use typeid(T).name(), but that's an
-  // implementation-defined attribute which does not necessarily
-  // correspond to a name. We could potentially demangle it
-  // using, e.g. abi::__cxa_demangle.
-}
-
-// Distribution traits used by DistributionCaller and internal implementation
-// details of the mocking framework.
-/*
-struct DistributionFormatTraits {
-   // Returns the parameterized name of the distribution function.
-   static constexpr const char* FunctionName()
-   // Format DistrT parameters.
-   static std::string FormatArgs(DistrT& dist);
-   // Format DistrT::result_type results.
-   static std::string FormatResults(DistrT& dist);
-};
-*/
-template <typename DistrT>
-struct DistributionFormatTraits;
-
-template <typename R>
-struct DistributionFormatTraits<absl::uniform_int_distribution<R>> {
-  using distribution_t = absl::uniform_int_distribution<R>;
-  using result_t = typename distribution_t::result_type;
-
-  static constexpr const char* Name() { return "Uniform"; }
-
-  static std::string FunctionName() {
-    return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
-  }
-  static std::string FormatArgs(const distribution_t& d) {
-    return absl::StrCat("absl::IntervalClosedClosed, ", (d.min)(), ", ",
-                        (d.max)());
-  }
-  static std::string FormatResults(absl::Span<const result_t> results) {
-    return absl::StrJoin(results, ", ");
-  }
-};
-
-template <typename R>
-struct DistributionFormatTraits<absl::uniform_real_distribution<R>> {
-  using distribution_t = absl::uniform_real_distribution<R>;
-  using result_t = typename distribution_t::result_type;
-
-  static constexpr const char* Name() { return "Uniform"; }
-
-  static std::string FunctionName() {
-    return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
-  }
-  static std::string FormatArgs(const distribution_t& d) {
-    return absl::StrCat((d.min)(), ", ", (d.max)());
-  }
-  static std::string FormatResults(absl::Span<const result_t> results) {
-    return absl::StrJoin(results, ", ");
-  }
-};
-
-template <typename R>
-struct DistributionFormatTraits<absl::exponential_distribution<R>> {
-  using distribution_t = absl::exponential_distribution<R>;
-  using result_t = typename distribution_t::result_type;
-
-  static constexpr const char* Name() { return "Exponential"; }
-
-  static std::string FunctionName() {
-    return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
-  }
-  static std::string FormatArgs(const distribution_t& d) {
-    return absl::StrCat(d.lambda());
-  }
-  static std::string FormatResults(absl::Span<const result_t> results) {
-    return absl::StrJoin(results, ", ");
-  }
-};
-
-template <typename R>
-struct DistributionFormatTraits<absl::poisson_distribution<R>> {
-  using distribution_t = absl::poisson_distribution<R>;
-  using result_t = typename distribution_t::result_type;
-
-  static constexpr const char* Name() { return "Poisson"; }
-
-  static std::string FunctionName() {
-    return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
-  }
-  static std::string FormatArgs(const distribution_t& d) {
-    return absl::StrCat(d.mean());
-  }
-  static std::string FormatResults(absl::Span<const result_t> results) {
-    return absl::StrJoin(results, ", ");
-  }
-};
-
-template <>
-struct DistributionFormatTraits<absl::bernoulli_distribution> {
-  using distribution_t = absl::bernoulli_distribution;
-  using result_t = typename distribution_t::result_type;
-
-  static constexpr const char* Name() { return "Bernoulli"; }
-
-  static constexpr const char* FunctionName() { return Name(); }
-  static std::string FormatArgs(const distribution_t& d) {
-    return absl::StrCat(d.p());
-  }
-  static std::string FormatResults(absl::Span<const result_t> results) {
-    return absl::StrJoin(results, ", ");
-  }
-};
-
-template <typename R>
-struct DistributionFormatTraits<absl::beta_distribution<R>> {
-  using distribution_t = absl::beta_distribution<R>;
-  using result_t = typename distribution_t::result_type;
-
-  static constexpr const char* Name() { return "Beta"; }
-
-  static std::string FunctionName() {
-    return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
-  }
-  static std::string FormatArgs(const distribution_t& d) {
-    return absl::StrCat(d.alpha(), ", ", d.beta());
-  }
-  static std::string FormatResults(absl::Span<const result_t> results) {
-    return absl::StrJoin(results, ", ");
-  }
-};
-
-template <typename R>
-struct DistributionFormatTraits<absl::zipf_distribution<R>> {
-  using distribution_t = absl::zipf_distribution<R>;
-  using result_t = typename distribution_t::result_type;
-
-  static constexpr const char* Name() { return "Zipf"; }
-
-  static std::string FunctionName() {
-    return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
-  }
-  static std::string FormatArgs(const distribution_t& d) {
-    return absl::StrCat(d.k(), ", ", d.v(), ", ", d.q());
-  }
-  static std::string FormatResults(absl::Span<const result_t> results) {
-    return absl::StrJoin(results, ", ");
-  }
-};
-
-template <typename R>
-struct DistributionFormatTraits<absl::gaussian_distribution<R>> {
-  using distribution_t = absl::gaussian_distribution<R>;
-  using result_t = typename distribution_t::result_type;
-
-  static constexpr const char* Name() { return "Gaussian"; }
-
-  static std::string FunctionName() {
-    return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
-  }
-  static std::string FormatArgs(const distribution_t& d) {
-    return absl::StrJoin(std::make_tuple(d.mean(), d.stddev()), ", ");
-  }
-  static std::string FormatResults(absl::Span<const result_t> results) {
-    return absl::StrJoin(results, ", ");
-  }
-};
-
-template <typename R>
-struct DistributionFormatTraits<absl::log_uniform_int_distribution<R>> {
-  using distribution_t = absl::log_uniform_int_distribution<R>;
-  using result_t = typename distribution_t::result_type;
-
-  static constexpr const char* Name() { return "LogUniform"; }
-
-  static std::string FunctionName() {
-    return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
-  }
-  static std::string FormatArgs(const distribution_t& d) {
-    return absl::StrJoin(std::make_tuple((d.min)(), (d.max)(), d.base()), ", ");
-  }
-  static std::string FormatResults(absl::Span<const result_t> results) {
-    return absl::StrJoin(results, ", ");
-  }
-};
-
-template <typename NumType>
-struct UniformDistributionWrapper;
-
-template <typename NumType>
-struct DistributionFormatTraits<UniformDistributionWrapper<NumType>> {
-  using distribution_t = UniformDistributionWrapper<NumType>;
-  using result_t = NumType;
-
-  static constexpr const char* Name() { return "Uniform"; }
-
-  static std::string FunctionName() {
-    return absl::StrCat(Name(), "<", ScalarTypeName<NumType>(), ">");
-  }
-  static std::string FormatArgs(const distribution_t& d) {
-    return absl::StrCat((d.min)(), ", ", (d.max)());
-  }
-  static std::string FormatResults(absl::Span<const result_t> results) {
-    return absl::StrJoin(results, ", ");
-  }
-};
-
-}  // namespace random_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#endif  // ABSL_RANDOM_DISTRIBUTION_FORMAT_TRAITS_H_
diff --git a/absl/random/distributions.h b/absl/random/distributions.h
index d026d92..31c7969 100644
--- a/absl/random/distributions.h
+++ b/absl/random/distributions.h
@@ -55,10 +55,9 @@
 #include "absl/base/internal/inline_variable.h"
 #include "absl/random/bernoulli_distribution.h"
 #include "absl/random/beta_distribution.h"
-#include "absl/random/distribution_format_traits.h"
 #include "absl/random/exponential_distribution.h"
 #include "absl/random/gaussian_distribution.h"
-#include "absl/random/internal/distributions.h"  // IWYU pragma: export
+#include "absl/random/internal/distribution_caller.h"  // IWYU pragma: export
 #include "absl/random/internal/uniform_helper.h"  // IWYU pragma: export
 #include "absl/random/log_uniform_int_distribution.h"
 #include "absl/random/poisson_distribution.h"
@@ -126,14 +125,13 @@
         R lo, R hi) {
   using gen_t = absl::decay_t<URBG>;
   using distribution_t = random_internal::UniformDistributionWrapper<R>;
-  using format_t = random_internal::DistributionFormatTraits<distribution_t>;
 
   auto a = random_internal::uniform_lower_bound(tag, lo, hi);
   auto b = random_internal::uniform_upper_bound(tag, lo, hi);
-  if (a > b) return a;
+  if (!random_internal::is_uniform_range_valid(a, b)) return lo;
 
   return random_internal::DistributionCaller<gen_t>::template Call<
-      distribution_t, format_t>(&urbg, tag, lo, hi);
+      distribution_t>(&urbg, tag, lo, hi);
 }
 
 // absl::Uniform<T>(bitgen, lo, hi)
@@ -146,15 +144,14 @@
         R lo, R hi) {
   using gen_t = absl::decay_t<URBG>;
   using distribution_t = random_internal::UniformDistributionWrapper<R>;
-  using format_t = random_internal::DistributionFormatTraits<distribution_t>;
-
   constexpr auto tag = absl::IntervalClosedOpen;
+
   auto a = random_internal::uniform_lower_bound(tag, lo, hi);
   auto b = random_internal::uniform_upper_bound(tag, lo, hi);
-  if (a > b) return a;
+  if (!random_internal::is_uniform_range_valid(a, b)) return lo;
 
   return random_internal::DistributionCaller<gen_t>::template Call<
-      distribution_t, format_t>(&urbg, lo, hi);
+      distribution_t>(&urbg, lo, hi);
 }
 
 // absl::Uniform(tag, bitgen, lo, hi)
@@ -172,14 +169,13 @@
   using gen_t = absl::decay_t<URBG>;
   using return_t = typename random_internal::uniform_inferred_return_t<A, B>;
   using distribution_t = random_internal::UniformDistributionWrapper<return_t>;
-  using format_t = random_internal::DistributionFormatTraits<distribution_t>;
 
   auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi);
   auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi);
-  if (a > b) return a;
+  if (!random_internal::is_uniform_range_valid(a, b)) return lo;
 
   return random_internal::DistributionCaller<gen_t>::template Call<
-      distribution_t, format_t>(&urbg, tag, static_cast<return_t>(lo),
+      distribution_t>(&urbg, tag, static_cast<return_t>(lo),
                                 static_cast<return_t>(hi));
 }
 
@@ -196,15 +192,14 @@
   using gen_t = absl::decay_t<URBG>;
   using return_t = typename random_internal::uniform_inferred_return_t<A, B>;
   using distribution_t = random_internal::UniformDistributionWrapper<return_t>;
-  using format_t = random_internal::DistributionFormatTraits<distribution_t>;
 
   constexpr auto tag = absl::IntervalClosedOpen;
   auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi);
   auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi);
-  if (a > b) return a;
+  if (!random_internal::is_uniform_range_valid(a, b)) return lo;
 
   return random_internal::DistributionCaller<gen_t>::template Call<
-      distribution_t, format_t>(&urbg, static_cast<return_t>(lo),
+      distribution_t>(&urbg, static_cast<return_t>(lo),
                                 static_cast<return_t>(hi));
 }
 
@@ -217,10 +212,9 @@
 Uniform(URBG&& urbg) {  // NOLINT(runtime/references)
   using gen_t = absl::decay_t<URBG>;
   using distribution_t = random_internal::UniformDistributionWrapper<R>;
-  using format_t = random_internal::DistributionFormatTraits<distribution_t>;
 
   return random_internal::DistributionCaller<gen_t>::template Call<
-      distribution_t, format_t>(&urbg);
+      distribution_t>(&urbg);
 }
 
 // -----------------------------------------------------------------------------
@@ -248,10 +242,9 @@
                double p) {
   using gen_t = absl::decay_t<URBG>;
   using distribution_t = absl::bernoulli_distribution;
-  using format_t = random_internal::DistributionFormatTraits<distribution_t>;
 
   return random_internal::DistributionCaller<gen_t>::template Call<
-      distribution_t, format_t>(&urbg, p);
+      distribution_t>(&urbg, p);
 }
 
 // -----------------------------------------------------------------------------
@@ -281,10 +274,9 @@
 
   using gen_t = absl::decay_t<URBG>;
   using distribution_t = typename absl::beta_distribution<RealType>;
-  using format_t = random_internal::DistributionFormatTraits<distribution_t>;
 
   return random_internal::DistributionCaller<gen_t>::template Call<
-      distribution_t, format_t>(&urbg, alpha, beta);
+      distribution_t>(&urbg, alpha, beta);
 }
 
 // -----------------------------------------------------------------------------
@@ -314,10 +306,9 @@
 
   using gen_t = absl::decay_t<URBG>;
   using distribution_t = typename absl::exponential_distribution<RealType>;
-  using format_t = random_internal::DistributionFormatTraits<distribution_t>;
 
   return random_internal::DistributionCaller<gen_t>::template Call<
-      distribution_t, format_t>(&urbg, lambda);
+      distribution_t>(&urbg, lambda);
 }
 
 // -----------------------------------------------------------------------------
@@ -346,10 +337,9 @@
 
   using gen_t = absl::decay_t<URBG>;
   using distribution_t = typename absl::gaussian_distribution<RealType>;
-  using format_t = random_internal::DistributionFormatTraits<distribution_t>;
 
   return random_internal::DistributionCaller<gen_t>::template Call<
-      distribution_t, format_t>(&urbg, mean, stddev);
+      distribution_t>(&urbg, mean, stddev);
 }
 
 // -----------------------------------------------------------------------------
@@ -389,10 +379,9 @@
 
   using gen_t = absl::decay_t<URBG>;
   using distribution_t = typename absl::log_uniform_int_distribution<IntType>;
-  using format_t = random_internal::DistributionFormatTraits<distribution_t>;
 
   return random_internal::DistributionCaller<gen_t>::template Call<
-      distribution_t, format_t>(&urbg, lo, hi, base);
+      distribution_t>(&urbg, lo, hi, base);
 }
 
 // -----------------------------------------------------------------------------
@@ -420,10 +409,9 @@
 
   using gen_t = absl::decay_t<URBG>;
   using distribution_t = typename absl::poisson_distribution<IntType>;
-  using format_t = random_internal::DistributionFormatTraits<distribution_t>;
 
   return random_internal::DistributionCaller<gen_t>::template Call<
-      distribution_t, format_t>(&urbg, mean);
+      distribution_t>(&urbg, mean);
 }
 
 // -----------------------------------------------------------------------------
@@ -453,10 +441,9 @@
 
   using gen_t = absl::decay_t<URBG>;
   using distribution_t = typename absl::zipf_distribution<IntType>;
-  using format_t = random_internal::DistributionFormatTraits<distribution_t>;
 
   return random_internal::DistributionCaller<gen_t>::template Call<
-      distribution_t, format_t>(&urbg, hi, q, v);
+      distribution_t>(&urbg, hi, q, v);
 }
 
 ABSL_NAMESPACE_END
diff --git a/absl/random/distributions_test.cc b/absl/random/distributions_test.cc
index 2d92723..5866a07 100644
--- a/absl/random/distributions_test.cc
+++ b/absl/random/distributions_test.cc
@@ -29,94 +29,6 @@
 
 class RandomDistributionsTest : public testing::Test {};
 
-TEST_F(RandomDistributionsTest, UniformBoundFunctions) {
-  using absl::IntervalClosedClosed;
-  using absl::IntervalClosedOpen;
-  using absl::IntervalOpenClosed;
-  using absl::IntervalOpenOpen;
-  using absl::random_internal::uniform_lower_bound;
-  using absl::random_internal::uniform_upper_bound;
-
-  // absl::uniform_int_distribution natively assumes IntervalClosedClosed
-  // absl::uniform_real_distribution natively assumes IntervalClosedOpen
-
-  EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, 0, 100), 1);
-  EXPECT_EQ(uniform_lower_bound(IntervalOpenOpen, 0, 100), 1);
-  EXPECT_GT(uniform_lower_bound<float>(IntervalOpenClosed, 0, 1.0), 0);
-  EXPECT_GT(uniform_lower_bound<float>(IntervalOpenOpen, 0, 1.0), 0);
-  EXPECT_GT(uniform_lower_bound<double>(IntervalOpenClosed, 0, 1.0), 0);
-  EXPECT_GT(uniform_lower_bound<double>(IntervalOpenOpen, 0, 1.0), 0);
-
-  EXPECT_EQ(uniform_lower_bound(IntervalClosedClosed, 0, 100), 0);
-  EXPECT_EQ(uniform_lower_bound(IntervalClosedOpen, 0, 100), 0);
-  EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedClosed, 0, 1.0), 0);
-  EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedOpen, 0, 1.0), 0);
-  EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedClosed, 0, 1.0), 0);
-  EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedOpen, 0, 1.0), 0);
-
-  EXPECT_EQ(uniform_upper_bound(IntervalOpenOpen, 0, 100), 99);
-  EXPECT_EQ(uniform_upper_bound(IntervalClosedOpen, 0, 100), 99);
-  EXPECT_EQ(uniform_upper_bound<float>(IntervalOpenOpen, 0, 1.0), 1.0);
-  EXPECT_EQ(uniform_upper_bound<float>(IntervalClosedOpen, 0, 1.0), 1.0);
-  EXPECT_EQ(uniform_upper_bound<double>(IntervalOpenOpen, 0, 1.0), 1.0);
-  EXPECT_EQ(uniform_upper_bound<double>(IntervalClosedOpen, 0, 1.0), 1.0);
-
-  EXPECT_EQ(uniform_upper_bound(IntervalOpenClosed, 0, 100), 100);
-  EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, 0, 100), 100);
-  EXPECT_GT(uniform_upper_bound<float>(IntervalOpenClosed, 0, 1.0), 1.0);
-  EXPECT_GT(uniform_upper_bound<float>(IntervalClosedClosed, 0, 1.0), 1.0);
-  EXPECT_GT(uniform_upper_bound<double>(IntervalOpenClosed, 0, 1.0), 1.0);
-  EXPECT_GT(uniform_upper_bound<double>(IntervalClosedClosed, 0, 1.0), 1.0);
-
-  // Negative value tests
-  EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, -100, -1), -99);
-  EXPECT_EQ(uniform_lower_bound(IntervalOpenOpen, -100, -1), -99);
-  EXPECT_GT(uniform_lower_bound<float>(IntervalOpenClosed, -2.0, -1.0), -2.0);
-  EXPECT_GT(uniform_lower_bound<float>(IntervalOpenOpen, -2.0, -1.0), -2.0);
-  EXPECT_GT(uniform_lower_bound<double>(IntervalOpenClosed, -2.0, -1.0), -2.0);
-  EXPECT_GT(uniform_lower_bound<double>(IntervalOpenOpen, -2.0, -1.0), -2.0);
-
-  EXPECT_EQ(uniform_lower_bound(IntervalClosedClosed, -100, -1), -100);
-  EXPECT_EQ(uniform_lower_bound(IntervalClosedOpen, -100, -1), -100);
-  EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedClosed, -2.0, -1.0), -2.0);
-  EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedOpen, -2.0, -1.0), -2.0);
-  EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedClosed, -2.0, -1.0),
-            -2.0);
-  EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedOpen, -2.0, -1.0), -2.0);
-
-  EXPECT_EQ(uniform_upper_bound(IntervalOpenOpen, -100, -1), -2);
-  EXPECT_EQ(uniform_upper_bound(IntervalClosedOpen, -100, -1), -2);
-  EXPECT_EQ(uniform_upper_bound<float>(IntervalOpenOpen, -2.0, -1.0), -1.0);
-  EXPECT_EQ(uniform_upper_bound<float>(IntervalClosedOpen, -2.0, -1.0), -1.0);
-  EXPECT_EQ(uniform_upper_bound<double>(IntervalOpenOpen, -2.0, -1.0), -1.0);
-  EXPECT_EQ(uniform_upper_bound<double>(IntervalClosedOpen, -2.0, -1.0), -1.0);
-
-  EXPECT_EQ(uniform_upper_bound(IntervalOpenClosed, -100, -1), -1);
-  EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, -100, -1), -1);
-  EXPECT_GT(uniform_upper_bound<float>(IntervalOpenClosed, -2.0, -1.0), -1.0);
-  EXPECT_GT(uniform_upper_bound<float>(IntervalClosedClosed, -2.0, -1.0), -1.0);
-  EXPECT_GT(uniform_upper_bound<double>(IntervalOpenClosed, -2.0, -1.0), -1.0);
-  EXPECT_GT(uniform_upper_bound<double>(IntervalClosedClosed, -2.0, -1.0),
-            -1.0);
-
-  // Edge cases: the next value toward itself is itself.
-  const double d = 1.0;
-  const float f = 1.0;
-  EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, d, d), d);
-  EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, f, f), f);
-
-  EXPECT_GT(uniform_lower_bound(IntervalOpenClosed, 1.0, 2.0), 1.0);
-  EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, +0.0), 1.0);
-  EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, -0.0), 1.0);
-  EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, -1.0), 1.0);
-
-  EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, 0.0f,
-                                std::numeric_limits<float>::max()),
-            std::numeric_limits<float>::max());
-  EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, 0.0,
-                                std::numeric_limits<double>::max()),
-            std::numeric_limits<double>::max());
-}
 
 struct Invalid {};
 
@@ -284,7 +196,9 @@
 
   // Properly promotes float.
   CheckArgsInferType<float, double, double>();
+}
 
+TEST_F(RandomDistributionsTest, UniformExamples) {
   // Examples.
   absl::InsecureBitGen gen;
   EXPECT_NE(1, absl::Uniform(gen, static_cast<uint16_t>(0), 1.0f));
@@ -307,6 +221,58 @@
   absl::Uniform<uint64_t>(gen);
 }
 
+TEST_F(RandomDistributionsTest, UniformNonsenseRanges) {
+  // The ranges used in this test are undefined behavior.
+  // The results are arbitrary and subject to future changes.
+  absl::InsecureBitGen gen;
+
+  // <uint>
+  EXPECT_EQ(0, absl::Uniform<uint64_t>(gen, 0, 0));
+  EXPECT_EQ(1, absl::Uniform<uint64_t>(gen, 1, 0));
+  EXPECT_EQ(0, absl::Uniform<uint64_t>(absl::IntervalOpenOpen, gen, 0, 0));
+  EXPECT_EQ(1, absl::Uniform<uint64_t>(absl::IntervalOpenOpen, gen, 1, 0));
+
+  constexpr auto m = (std::numeric_limits<uint64_t>::max)();
+
+  EXPECT_EQ(m, absl::Uniform(gen, m, m));
+  EXPECT_EQ(m, absl::Uniform(gen, m, m - 1));
+  EXPECT_EQ(m - 1, absl::Uniform(gen, m - 1, m));
+  EXPECT_EQ(m, absl::Uniform(absl::IntervalOpenOpen, gen, m, m));
+  EXPECT_EQ(m, absl::Uniform(absl::IntervalOpenOpen, gen, m, m - 1));
+  EXPECT_EQ(m - 1, absl::Uniform(absl::IntervalOpenOpen, gen, m - 1, m));
+
+  // <int>
+  EXPECT_EQ(0, absl::Uniform<int64_t>(gen, 0, 0));
+  EXPECT_EQ(1, absl::Uniform<int64_t>(gen, 1, 0));
+  EXPECT_EQ(0, absl::Uniform<int64_t>(absl::IntervalOpenOpen, gen, 0, 0));
+  EXPECT_EQ(1, absl::Uniform<int64_t>(absl::IntervalOpenOpen, gen, 1, 0));
+
+  constexpr auto l = (std::numeric_limits<int64_t>::min)();
+  constexpr auto r = (std::numeric_limits<int64_t>::max)();
+
+  EXPECT_EQ(l, absl::Uniform(gen, l, l));
+  EXPECT_EQ(r, absl::Uniform(gen, r, r));
+  EXPECT_EQ(r, absl::Uniform(gen, r, r - 1));
+  EXPECT_EQ(r - 1, absl::Uniform(gen, r - 1, r));
+  EXPECT_EQ(l, absl::Uniform(absl::IntervalOpenOpen, gen, l, l));
+  EXPECT_EQ(r, absl::Uniform(absl::IntervalOpenOpen, gen, r, r));
+  EXPECT_EQ(r, absl::Uniform(absl::IntervalOpenOpen, gen, r, r - 1));
+  EXPECT_EQ(r - 1, absl::Uniform(absl::IntervalOpenOpen, gen, r - 1, r));
+
+  // <double>
+  const double e = std::nextafter(1.0, 2.0);  // 1 + epsilon
+  const double f = std::nextafter(1.0, 0.0);  // 1 - epsilon
+  const double g = std::numeric_limits<double>::denorm_min();
+
+  EXPECT_EQ(1.0, absl::Uniform(gen, 1.0, e));
+  EXPECT_EQ(1.0, absl::Uniform(gen, 1.0, f));
+  EXPECT_EQ(0.0, absl::Uniform(gen, 0.0, g));
+
+  EXPECT_EQ(e, absl::Uniform(absl::IntervalOpenOpen, gen, 1.0, e));
+  EXPECT_EQ(f, absl::Uniform(absl::IntervalOpenOpen, gen, 1.0, f));
+  EXPECT_EQ(g, absl::Uniform(absl::IntervalOpenOpen, gen, 0.0, g));
+}
+
 // TODO(lar): Validate properties of non-default interval-semantics.
 TEST_F(RandomDistributionsTest, UniformReal) {
   std::vector<double> values(kSize);
diff --git a/absl/random/exponential_distribution_test.cc b/absl/random/exponential_distribution_test.cc
index f3cfd76..af11d61 100644
--- a/absl/random/exponential_distribution_test.cc
+++ b/absl/random/exponential_distribution_test.cc
@@ -30,8 +30,10 @@
 #include "gtest/gtest.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/macros.h"
+#include "absl/numeric/internal/representation.h"
 #include "absl/random/internal/chi_square.h"
 #include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/pcg_engine.h"
 #include "absl/random/internal/sequence_urbg.h"
 #include "absl/random/random.h"
 #include "absl/strings/str_cat.h"
@@ -46,11 +48,15 @@
 template <typename RealType>
 class ExponentialDistributionTypedTest : public ::testing::Test {};
 
-#if defined(__EMSCRIPTEN__)
-using RealTypes = ::testing::Types<float, double>;
-#else
-using RealTypes = ::testing::Types<float, double, long double>;
-#endif  // defined(__EMSCRIPTEN__)
+// double-double arithmetic is not supported well by either GCC or Clang; see
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99048,
+// https://bugs.llvm.org/show_bug.cgi?id=49131, and
+// https://bugs.llvm.org/show_bug.cgi?id=49132. Don't bother running these tests
+// with double doubles until compiler support is better.
+using RealTypes =
+    std::conditional<absl::numeric_internal::IsDoubleDouble(),
+                     ::testing::Types<float, double>,
+                     ::testing::Types<float, double, long double>>::type;
 TYPED_TEST_CASE(ExponentialDistributionTypedTest, RealTypes);
 
 TYPED_TEST(ExponentialDistributionTypedTest, SerializeTest) {
@@ -129,23 +135,6 @@
 
     ss >> after;
 
-#if defined(__powerpc64__) || defined(__PPC64__) || defined(__powerpc__) || \
-    defined(__ppc__) || defined(__PPC__)
-    if (std::is_same<TypeParam, long double>::value) {
-      // Roundtripping floating point values requires sufficient precision to
-      // reconstruct the exact value. It turns out that long double has some
-      // errors doing this on ppc, particularly for values
-      // near {1.0 +/- epsilon}.
-      if (lambda <= std::numeric_limits<double>::max() &&
-          lambda >= std::numeric_limits<double>::lowest()) {
-        EXPECT_EQ(static_cast<double>(before.lambda()),
-                  static_cast<double>(after.lambda()))
-            << ss.str();
-      }
-      continue;
-    }
-#endif
-
     EXPECT_EQ(before.lambda(), after.lambda())  //
         << ss.str() << " "                      //
         << (ss.good() ? "good " : "")           //
@@ -205,7 +194,10 @@
   template <typename D>
   double SingleChiSquaredTest();
 
-  absl::InsecureBitGen rng_;
+  // We use a fixed bit generator for distribution accuracy tests.  This allows
+  // these tests to be deterministic, while still testing the qualify of the
+  // implementation.
+  absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
 };
 
 template <typename D>
diff --git a/absl/random/gaussian_distribution_test.cc b/absl/random/gaussian_distribution_test.cc
index 49c0751..c0bac2b 100644
--- a/absl/random/gaussian_distribution_test.cc
+++ b/absl/random/gaussian_distribution_test.cc
@@ -21,12 +21,14 @@
 #include <iterator>
 #include <random>
 #include <string>
+#include <type_traits>
 #include <vector>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/macros.h"
+#include "absl/numeric/internal/representation.h"
 #include "absl/random/internal/chi_square.h"
 #include "absl/random/internal/distribution_test_util.h"
 #include "absl/random/internal/sequence_urbg.h"
@@ -43,7 +45,15 @@
 template <typename RealType>
 class GaussianDistributionInterfaceTest : public ::testing::Test {};
 
-using RealTypes = ::testing::Types<float, double, long double>;
+// double-double arithmetic is not supported well by either GCC or Clang; see
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99048,
+// https://bugs.llvm.org/show_bug.cgi?id=49131, and
+// https://bugs.llvm.org/show_bug.cgi?id=49132. Don't bother running these tests
+// with double doubles until compiler support is better.
+using RealTypes =
+    std::conditional<absl::numeric_internal::IsDoubleDouble(),
+                     ::testing::Types<float, double>,
+                     ::testing::Types<float, double, long double>>::type;
 TYPED_TEST_CASE(GaussianDistributionInterfaceTest, RealTypes);
 
 TYPED_TEST(GaussianDistributionInterfaceTest, SerializeTest) {
@@ -129,29 +139,6 @@
 
         ss >> after;
 
-#if defined(__powerpc64__) || defined(__PPC64__) || defined(__powerpc__) || \
-    defined(__ppc__) || defined(__PPC__)
-        if (std::is_same<TypeParam, long double>::value) {
-          // Roundtripping floating point values requires sufficient precision
-          // to reconstruct the exact value.  It turns out that long double
-          // has some errors doing this on ppc, particularly for values
-          // near {1.0 +/- epsilon}.
-          if (mean <= std::numeric_limits<double>::max() &&
-              mean >= std::numeric_limits<double>::lowest()) {
-            EXPECT_EQ(static_cast<double>(before.mean()),
-                      static_cast<double>(after.mean()))
-                << ss.str();
-          }
-          if (stddev <= std::numeric_limits<double>::max() &&
-              stddev >= std::numeric_limits<double>::lowest()) {
-            EXPECT_EQ(static_cast<double>(before.stddev()),
-                      static_cast<double>(after.stddev()))
-                << ss.str();
-          }
-          continue;
-        }
-#endif
-
         EXPECT_EQ(before.mean(), after.mean());
         EXPECT_EQ(before.stddev(), after.stddev())  //
             << ss.str() << " "                      //
@@ -213,7 +200,10 @@
   template <typename D>
   double SingleChiSquaredTest();
 
-  absl::InsecureBitGen rng_;
+  // We use a fixed bit generator for distribution accuracy tests.  This allows
+  // these tests to be deterministic, while still testing the qualify of the
+  // implementation.
+  absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
 };
 
 template <typename D>
diff --git a/absl/random/internal/BUILD.bazel b/absl/random/internal/BUILD.bazel
index d7ad4ef..612b150 100644
--- a/absl/random/internal/BUILD.bazel
+++ b/absl/random/internal/BUILD.bazel
@@ -30,16 +30,13 @@
     "//absl/random:__pkg__",
 ])
 
-licenses(["notice"])  # Apache 2.0
+licenses(["notice"])
 
 cc_library(
     name = "traits",
     hdrs = ["traits.h"],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
-    visibility = [
-        "//absl/random:__pkg__",
-    ],
     deps = ["//absl/base:config"],
 )
 
@@ -48,24 +45,10 @@
     hdrs = ["distribution_caller.h"],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
-    visibility = [
-        "//absl/random:__pkg__",
-    ],
-    deps = ["//absl/base:config"],
-)
-
-cc_library(
-    name = "distributions",
-    hdrs = ["distributions.h"],
-    copts = ABSL_DEFAULT_COPTS,
-    linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
-        ":distribution_caller",
-        ":traits",
-        ":uniform_helper",
-        "//absl/base",
-        "//absl/meta:type_traits",
-        "//absl/strings",
+        "//absl/base:config",
+        "//absl/base:fast_type_id",
+        "//absl/utility",
     ],
 )
 
@@ -76,10 +59,10 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
-    visibility = [
-        "//absl/random:__pkg__",
+    deps = [
+        "//absl/base:config",
+        "//absl/meta:type_traits",
     ],
-    deps = ["//absl/base:config"],
 )
 
 cc_library(
@@ -92,7 +75,8 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS + select({
-        "//absl:windows": ["-DEFAULTLIB:bcrypt.lib"],
+        "//absl:msvc_compiler": ["-DEFAULTLIB:bcrypt.lib"],
+        "//absl:clang-cl_compiler": ["-DEFAULTLIB:bcrypt.lib"],
         "//conditions:default": [],
     }),
     deps = [
@@ -115,7 +99,9 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = select({
-        "//absl:windows": [],
+        "//absl:msvc_compiler": [],
+        "//absl:clang-cl_compiler": [],
+        "//absl:wasm": [],
         "//conditions:default": ["-pthread"],
     }) + ABSL_DEFAULT_LINKOPTS,
     deps = [
@@ -140,7 +126,10 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
-    deps = ["//absl/base:config"],
+    deps = [
+        "//absl/base:config",
+        "//absl/base:endian",
+    ],
 )
 
 cc_library(
@@ -191,8 +180,8 @@
     deps = [
         ":fastmath",
         ":traits",
-        "//absl/base:bits",
         "//absl/meta:type_traits",
+        "//absl/numeric:bits",
     ],
 )
 
@@ -203,7 +192,7 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
-    deps = ["//absl/base:bits"],
+    deps = ["//absl/numeric:bits"],
 )
 
 cc_library(
@@ -213,8 +202,8 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":traits",
-        "//absl/base:bits",
         "//absl/base:config",
+        "//absl/numeric:bits",
         "//absl/numeric:int128",
     ],
 )
@@ -230,7 +219,6 @@
         ":seed_material",
         "//absl/base:core_headers",
         "//absl/meta:type_traits",
-        "//absl/strings",
         "//absl/types:optional",
         "//absl/types:span",
     ],
@@ -246,6 +234,7 @@
         ":iostream_state_saver",
         "//absl/base:config",
         "//absl/meta:type_traits",
+        "//absl/numeric:bits",
         "//absl/numeric:int128",
     ],
 )
@@ -258,19 +247,22 @@
     deps = [
         ":iostream_state_saver",
         ":randen",
+        "//absl/base:endian",
         "//absl/meta:type_traits",
     ],
 )
 
 cc_library(
     name = "platform",
+    srcs = [
+        "randen_round_keys.cc",
+    ],
     hdrs = [
         "randen_traits.h",
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     textual_hdrs = [
-        "randen-keys.inc",
         "platform.h",
     ],
     deps = ["//absl/base:config"],
@@ -335,13 +327,10 @@
         "randen_hwaes.h",
     ],
     copts = ABSL_DEFAULT_COPTS + ABSL_RANDOM_RANDEN_COPTS + select({
-        "//absl:windows": [],
+        "//absl:msvc_compiler": [],
+        "//absl:clang-cl_compiler": [],
         "//conditions:default": ["-Wno-pass-failed"],
     }),
-    # copts in RANDEN_HWAES_COPTS can make this target unusable as a module
-    # leading to a Clang diagnostic. Furthermore, it only has a private header
-    # anyway and thus there wouldn't be any gain from using it as a module.
-    features = ["-header_modules"],
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":platform",
@@ -419,8 +408,8 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":generate_real",
-        "//absl/base:bits",
         "//absl/flags:flag",
+        "//absl/numeric:bits",
         "@com_google_googletest//:gtest_main",
     ],
 )
@@ -504,12 +493,11 @@
 )
 
 cc_library(
-    name = "mocking_bit_gen_base",
-    hdrs = ["mocking_bit_gen_base.h"],
-    linkopts = ABSL_DEFAULT_LINKOPTS,
+    name = "mock_helpers",
+    hdrs = ["mock_helpers.h"],
     deps = [
-        "//absl/random",
-        "//absl/strings",
+        "//absl/base:fast_type_id",
+        "//absl/types:optional",
     ],
 )
 
@@ -517,10 +505,8 @@
     name = "mock_overload_set",
     testonly = 1,
     hdrs = ["mock_overload_set.h"],
-    visibility = [
-        "//absl/random:__pkg__",
-    ],
     deps = [
+        ":mock_helpers",
         "//absl/random:mocking_bit_gen",
         "@com_google_googletest//:gtest",
     ],
@@ -625,7 +611,9 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        ":platform",
         ":randen_slow",
+        "//absl/base:endian",
         "@com_google_googletest//:gtest_main",
     ],
 )
@@ -655,7 +643,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":wide_multiply",
-        "//absl/base:bits",
+        "//absl/numeric:bits",
         "//absl/numeric:int128",
         "@com_google_googletest//:gtest_main",
     ],
@@ -669,6 +657,7 @@
     deps = [
         ":platform",
         ":randen_engine",
+        "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:raw_logging_internal",
     ],
@@ -680,6 +669,8 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        ":traits",
+        "//absl/base:config",
         "//absl/meta:type_traits",
     ],
 )
@@ -705,6 +696,7 @@
 cc_test(
     name = "randen_benchmarks",
     size = "medium",
+    timeout = "long",
     srcs = ["randen_benchmarks.cc"],
     copts = ABSL_TEST_COPTS + ABSL_RANDOM_RANDEN_COPTS,
     flaky = 1,
@@ -733,3 +725,15 @@
         "@com_google_googletest//:gtest_main",
     ],
 )
+
+cc_test(
+    name = "uniform_helper_test",
+    size = "small",
+    srcs = ["uniform_helper_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":uniform_helper",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
diff --git a/absl/random/internal/distribution_caller.h b/absl/random/internal/distribution_caller.h
index 02603cf..fc81b78 100644
--- a/absl/random/internal/distribution_caller.h
+++ b/absl/random/internal/distribution_caller.h
@@ -20,6 +20,8 @@
 #include <utility>
 
 #include "absl/base/config.h"
+#include "absl/base/internal/fast_type_id.h"
+#include "absl/utility/utility.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -30,27 +32,57 @@
 // to intercept such calls.
 template <typename URBG>
 struct DistributionCaller {
-  // Call the provided distribution type. The parameters are expected
-  // to be explicitly specified.
-  // DistrT is the distribution type.
-  // FormatT is the formatter type:
+  // SFINAE to detect whether the URBG type includes a member matching
+  // bool InvokeMock(base_internal::FastTypeIdType, void*, void*).
   //
-  // struct FormatT {
-  //   using result_type = distribution_t::result_type;
-  //   static std::string FormatCall(
-  //       const distribution_t& distr,
-  //       absl::Span<const result_type>);
-  //
-  //   static std::string FormatExpectation(
-  //       absl::string_view match_args,
-  //       absl::Span<const result_t> results);
-  // }
-  //
-  template <typename DistrT, typename FormatT, typename... Args>
-  static typename DistrT::result_type Call(URBG* urbg, Args&&... args) {
+  // These live inside BitGenRef so that they have friend access
+  // to MockingBitGen. (see similar methods in DistributionCaller).
+  template <template <class...> class Trait, class AlwaysVoid, class... Args>
+  struct detector : std::false_type {};
+  template <template <class...> class Trait, class... Args>
+  struct detector<Trait, absl::void_t<Trait<Args...>>, Args...>
+      : std::true_type {};
+
+  template <class T>
+  using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock(
+      std::declval<::absl::base_internal::FastTypeIdType>(),
+      std::declval<void*>(), std::declval<void*>()));
+
+  using HasInvokeMock = typename detector<invoke_mock_t, void, URBG>::type;
+
+  // Default implementation of distribution caller.
+  template <typename DistrT, typename... Args>
+  static typename DistrT::result_type Impl(std::false_type, URBG* urbg,
+                                           Args&&... args) {
     DistrT dist(std::forward<Args>(args)...);
     return dist(*urbg);
   }
+
+  // Mock implementation of distribution caller.
+  // The underlying KeyT must match the KeyT constructed by MockOverloadSet.
+  template <typename DistrT, typename... Args>
+  static typename DistrT::result_type Impl(std::true_type, URBG* urbg,
+                                           Args&&... args) {
+    using ResultT = typename DistrT::result_type;
+    using ArgTupleT = std::tuple<absl::decay_t<Args>...>;
+    using KeyT = ResultT(DistrT, ArgTupleT);
+
+    ArgTupleT arg_tuple(std::forward<Args>(args)...);
+    ResultT result;
+    if (!urbg->InvokeMock(::absl::base_internal::FastTypeId<KeyT>(), &arg_tuple,
+                          &result)) {
+      auto dist = absl::make_from_tuple<DistrT>(arg_tuple);
+      result = dist(*urbg);
+    }
+    return result;
+  }
+
+  // Default implementation of distribution caller.
+  template <typename DistrT, typename... Args>
+  static typename DistrT::result_type Call(URBG* urbg, Args&&... args) {
+    return Impl<DistrT, Args...>(HasInvokeMock{}, urbg,
+                                 std::forward<Args>(args)...);
+  }
 };
 
 }  // namespace random_internal
diff --git a/absl/random/internal/distributions.h b/absl/random/internal/distributions.h
deleted file mode 100644
index d7e3c01..0000000
--- a/absl/random/internal/distributions.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2019 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_RANDOM_INTERNAL_DISTRIBUTIONS_H_
-#define ABSL_RANDOM_INTERNAL_DISTRIBUTIONS_H_
-
-#include <type_traits>
-
-#include "absl/meta/type_traits.h"
-#include "absl/random/internal/distribution_caller.h"
-#include "absl/random/internal/traits.h"
-#include "absl/random/internal/uniform_helper.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace random_internal {
-
-// In the absence of an explicitly provided return-type, the template
-// "uniform_inferred_return_t<A, B>" is used to derive a suitable type, based on
-// the data-types of the endpoint-arguments {A lo, B hi}.
-//
-// Given endpoints {A lo, B hi}, one of {A, B} will be chosen as the
-// return-type, if one type can be implicitly converted into the other, in a
-// lossless way. The template "is_widening_convertible" implements the
-// compile-time logic for deciding if such a conversion is possible.
-//
-// If no such conversion between {A, B} exists, then the overload for
-// absl::Uniform() will be discarded, and the call will be ill-formed.
-// Return-type for absl::Uniform() when the return-type is inferred.
-template <typename A, typename B>
-using uniform_inferred_return_t =
-    absl::enable_if_t<absl::disjunction<is_widening_convertible<A, B>,
-                                        is_widening_convertible<B, A>>::value,
-                      typename std::conditional<
-                          is_widening_convertible<A, B>::value, B, A>::type>;
-
-}  // namespace random_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#endif  // ABSL_RANDOM_INTERNAL_DISTRIBUTIONS_H_
diff --git a/absl/random/internal/explicit_seed_seq.h b/absl/random/internal/explicit_seed_seq.h
index 6a743ea..e3aa31a 100644
--- a/absl/random/internal/explicit_seed_seq.h
+++ b/absl/random/internal/explicit_seed_seq.h
@@ -23,6 +23,7 @@
 #include <vector>
 
 #include "absl/base/config.h"
+#include "absl/base/internal/endian.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -73,7 +74,7 @@
   template <typename OutIterator>
   void generate(OutIterator begin, OutIterator end) {
     for (size_t index = 0; begin != end; begin++) {
-      *begin = state_.empty() ? 0 : state_[index++];
+      *begin = state_.empty() ? 0 : little_endian::FromHost32(state_[index++]);
       if (index >= state_.size()) {
         index = 0;
       }
diff --git a/absl/random/internal/fast_uniform_bits.h b/absl/random/internal/fast_uniform_bits.h
index f13c872..425aaf7 100644
--- a/absl/random/internal/fast_uniform_bits.h
+++ b/absl/random/internal/fast_uniform_bits.h
@@ -21,6 +21,7 @@
 #include <type_traits>
 
 #include "absl/base/config.h"
+#include "absl/meta/type_traits.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -38,28 +39,17 @@
 template <typename URBG>
 constexpr typename URBG::result_type RangeSize() {
   using result_type = typename URBG::result_type;
+  static_assert((URBG::max)() != (URBG::min)(), "URBG range cannot be 0.");
   return ((URBG::max)() == (std::numeric_limits<result_type>::max)() &&
           (URBG::min)() == std::numeric_limits<result_type>::lowest())
              ? result_type{0}
-             : (URBG::max)() - (URBG::min)() + result_type{1};
-}
-
-template <typename UIntType>
-constexpr UIntType LargestPowerOfTwoLessThanOrEqualTo(UIntType n) {
-  return n < 2 ? n : 2 * LargestPowerOfTwoLessThanOrEqualTo(n / 2);
-}
-
-// Given a URBG generating values in the closed interval [Lo, Hi], returns the
-// largest power of two less than or equal to `Hi - Lo + 1`.
-template <typename URBG>
-constexpr typename URBG::result_type PowerOfTwoSubRangeSize() {
-  return LargestPowerOfTwoLessThanOrEqualTo(RangeSize<URBG>());
+             : ((URBG::max)() - (URBG::min)() + result_type{1});
 }
 
 // Computes the floor of the log. (i.e., std::floor(std::log2(N));
 template <typename UIntType>
 constexpr UIntType IntegerLog2(UIntType n) {
-  return (n <= 1) ? 0 : 1 + IntegerLog2(n / 2);
+  return (n <= 1) ? 0 : 1 + IntegerLog2(n >> 1);
 }
 
 // Returns the number of bits of randomness returned through
@@ -68,18 +58,23 @@
 constexpr size_t NumBits() {
   return RangeSize<URBG>() == 0
              ? std::numeric_limits<typename URBG::result_type>::digits
-             : IntegerLog2(PowerOfTwoSubRangeSize<URBG>());
+             : IntegerLog2(RangeSize<URBG>());
 }
 
 // Given a shift value `n`, constructs a mask with exactly the low `n` bits set.
 // If `n == 0`, all bits are set.
 template <typename UIntType>
-constexpr UIntType MaskFromShift(UIntType n) {
+constexpr UIntType MaskFromShift(size_t n) {
   return ((n % std::numeric_limits<UIntType>::digits) == 0)
              ? ~UIntType{0}
              : (UIntType{1} << n) - UIntType{1};
 }
 
+// Tags used to dispatch FastUniformBits::generate to the simple or more complex
+// entropy extraction algorithm.
+struct SimplifiedLoopTag {};
+struct RejectionLoopTag {};
+
 // FastUniformBits implements a fast path to acquire uniform independent bits
 // from a type which conforms to the [rand.req.urbg] concept.
 // Parameterized by:
@@ -107,50 +102,16 @@
                 "Class-template FastUniformBits<> must be parameterized using "
                 "an unsigned type.");
 
-  // PowerOfTwoVariate() generates a single random variate, always returning a
-  // value in the half-open interval `[0, PowerOfTwoSubRangeSize<URBG>())`. If
-  // the URBG already generates values in a power-of-two range, the generator
-  // itself is used. Otherwise, we use rejection sampling on the largest
-  // possible power-of-two-sized subrange.
-  struct PowerOfTwoTag {};
-  struct RejectionSamplingTag {};
-  template <typename URBG>
-  static typename URBG::result_type PowerOfTwoVariate(
-      URBG& g) {  // NOLINT(runtime/references)
-    using tag =
-        typename std::conditional<IsPowerOfTwoOrZero(RangeSize<URBG>()),
-                                  PowerOfTwoTag, RejectionSamplingTag>::type;
-    return PowerOfTwoVariate(g, tag{});
-  }
-
-  template <typename URBG>
-  static typename URBG::result_type PowerOfTwoVariate(
-      URBG& g,  // NOLINT(runtime/references)
-      PowerOfTwoTag) {
-    return g() - (URBG::min)();
-  }
-
-  template <typename URBG>
-  static typename URBG::result_type PowerOfTwoVariate(
-      URBG& g,  // NOLINT(runtime/references)
-      RejectionSamplingTag) {
-    // Use rejection sampling to ensure uniformity across the range.
-    typename URBG::result_type u;
-    do {
-      u = g() - (URBG::min)();
-    } while (u >= PowerOfTwoSubRangeSize<URBG>());
-    return u;
-  }
-
   // Generate() generates a random value, dispatched on whether
-  // the underlying URBG must loop over multiple calls or not.
+  // the underlying URBG must use rejection sampling to generate a value,
+  // or whether a simplified loop will suffice.
   template <typename URBG>
   result_type Generate(URBG& g,  // NOLINT(runtime/references)
-                       std::true_type /* avoid_looping */);
+                       SimplifiedLoopTag);
 
   template <typename URBG>
   result_type Generate(URBG& g,  // NOLINT(runtime/references)
-                       std::false_type /* avoid_looping */);
+                       RejectionLoopTag);
 };
 
 template <typename UIntType>
@@ -162,31 +123,47 @@
   // Y = (2 ^ kRange) - 1
   static_assert((URBG::max)() > (URBG::min)(),
                 "URBG::max and URBG::min may not be equal.");
+
+  using tag = absl::conditional_t<IsPowerOfTwoOrZero(RangeSize<URBG>()),
+                                  SimplifiedLoopTag, RejectionLoopTag>;
+  return Generate(g, tag{});
+}
+
+template <typename UIntType>
+template <typename URBG>
+typename FastUniformBits<UIntType>::result_type
+FastUniformBits<UIntType>::Generate(URBG& g,  // NOLINT(runtime/references)
+                                    SimplifiedLoopTag) {
+  // The simplified version of FastUniformBits works only on URBGs that have
+  // a range that is a power of 2. In this case we simply loop and shift without
+  // attempting to balance the bits across calls.
+  static_assert(IsPowerOfTwoOrZero(RangeSize<URBG>()),
+                "incorrect Generate tag for URBG instance");
+
+  static constexpr size_t kResultBits =
+      std::numeric_limits<result_type>::digits;
+  static constexpr size_t kUrbgBits = NumBits<URBG>();
+  static constexpr size_t kIters =
+      (kResultBits / kUrbgBits) + (kResultBits % kUrbgBits != 0);
+  static constexpr size_t kShift = (kIters == 1) ? 0 : kUrbgBits;
+  static constexpr auto kMin = (URBG::min)();
+
+  result_type r = static_cast<result_type>(g() - kMin);
+  for (size_t n = 1; n < kIters; ++n) {
+    r = (r << kShift) + static_cast<result_type>(g() - kMin);
+  }
+  return r;
+}
+
+template <typename UIntType>
+template <typename URBG>
+typename FastUniformBits<UIntType>::result_type
+FastUniformBits<UIntType>::Generate(URBG& g,  // NOLINT(runtime/references)
+                                    RejectionLoopTag) {
+  static_assert(!IsPowerOfTwoOrZero(RangeSize<URBG>()),
+                "incorrect Generate tag for URBG instance");
   using urbg_result_type = typename URBG::result_type;
-  constexpr urbg_result_type kRangeMask =
-      RangeSize<URBG>() == 0
-          ? (std::numeric_limits<urbg_result_type>::max)()
-          : static_cast<urbg_result_type>(PowerOfTwoSubRangeSize<URBG>() - 1);
-  return Generate(g, std::integral_constant<bool, (kRangeMask >= (max)())>{});
-}
 
-template <typename UIntType>
-template <typename URBG>
-typename FastUniformBits<UIntType>::result_type
-FastUniformBits<UIntType>::Generate(URBG& g,  // NOLINT(runtime/references)
-                                    std::true_type /* avoid_looping */) {
-  // The width of the result_type is less than than the width of the random bits
-  // provided by URBG.  Thus, generate a single value and then simply mask off
-  // the required bits.
-
-  return PowerOfTwoVariate(g) & (max)();
-}
-
-template <typename UIntType>
-template <typename URBG>
-typename FastUniformBits<UIntType>::result_type
-FastUniformBits<UIntType>::Generate(URBG& g,  // NOLINT(runtime/references)
-                                    std::false_type /* avoid_looping */) {
   // See [rand.adapt.ibits] for more details on the constants calculated below.
   //
   // It is preferable to use roughly the same number of bits from each generator
@@ -199,21 +176,44 @@
   // `kSmallIters` and `kLargeIters` times respectively such
   // that
   //
-  //    `kTotalWidth == kSmallIters * kSmallWidth
-  //                    + kLargeIters * kLargeWidth`
+  //    `kResultBits == kSmallIters * kSmallBits
+  //                    + kLargeIters * kLargeBits`
   //
-  // where `kTotalWidth` is the total number of bits in `result_type`.
+  // where `kResultBits` is the total number of bits in `result_type`.
   //
-  constexpr size_t kTotalWidth = std::numeric_limits<result_type>::digits;
-  constexpr size_t kUrbgWidth = NumBits<URBG>();
-  constexpr size_t kTotalIters =
-      kTotalWidth / kUrbgWidth + (kTotalWidth % kUrbgWidth != 0);
-  constexpr size_t kSmallWidth = kTotalWidth / kTotalIters;
-  constexpr size_t kLargeWidth = kSmallWidth + 1;
+  static constexpr size_t kResultBits =
+      std::numeric_limits<result_type>::digits;                      // w
+  static constexpr urbg_result_type kUrbgRange = RangeSize<URBG>();  // R
+  static constexpr size_t kUrbgBits = NumBits<URBG>();               // m
+
+  // compute the initial estimate of the bits used.
+  // [rand.adapt.ibits] 2 (c)
+  static constexpr size_t kA =  // ceil(w/m)
+      (kResultBits / kUrbgBits) + ((kResultBits % kUrbgBits) != 0);  // n'
+
+  static constexpr size_t kABits = kResultBits / kA;  // w0'
+  static constexpr urbg_result_type kARejection =
+      ((kUrbgRange >> kABits) << kABits);  // y0'
+
+  // refine the selection to reduce the rejection frequency.
+  static constexpr size_t kTotalIters =
+      ((kUrbgRange - kARejection) <= (kARejection / kA)) ? kA : (kA + 1);  // n
+
+  // [rand.adapt.ibits] 2 (b)
+  static constexpr size_t kSmallIters =
+      kTotalIters - (kResultBits % kTotalIters);                   // n0
+  static constexpr size_t kSmallBits = kResultBits / kTotalIters;  // w0
+  static constexpr urbg_result_type kSmallRejection =
+      ((kUrbgRange >> kSmallBits) << kSmallBits);  // y0
+
+  static constexpr size_t kLargeBits = kSmallBits + 1;  // w0+1
+  static constexpr urbg_result_type kLargeRejection =
+      ((kUrbgRange >> kLargeBits) << kLargeBits);  // y1
+
   //
-  // Because `kLargeWidth == kSmallWidth + 1`, it follows that
+  // Because `kLargeBits == kSmallBits + 1`, it follows that
   //
-  //     `kTotalWidth == kTotalIters * kSmallWidth + kLargeIters`
+  //     `kResultBits == kSmallIters * kSmallBits + kLargeIters`
   //
   // and therefore
   //
@@ -224,36 +224,40 @@
   // mentioned above, if the URBG width is a divisor of `kTotalWidth`, then
   // there would be no need for any large iterations (i.e., one loop would
   // suffice), and indeed, in this case, `kLargeIters` would be zero.
-  constexpr size_t kLargeIters = kTotalWidth % kSmallWidth;
-  constexpr size_t kSmallIters =
-      (kTotalWidth - (kLargeWidth * kLargeIters)) / kSmallWidth;
+  static_assert(kResultBits == kSmallIters * kSmallBits +
+                                   (kTotalIters - kSmallIters) * kLargeBits,
+                "Error in looping constant calculations.");
 
-  static_assert(
-      kTotalWidth == kSmallIters * kSmallWidth + kLargeIters * kLargeWidth,
-      "Error in looping constant calculations.");
+  // The small shift is essentially small bits, but due to the potential
+  // of generating a smaller result_type from a larger urbg type, the actual
+  // shift might be 0.
+  static constexpr size_t kSmallShift = kSmallBits % kResultBits;
+  static constexpr auto kSmallMask =
+      MaskFromShift<urbg_result_type>(kSmallShift);
+  static constexpr size_t kLargeShift = kLargeBits % kResultBits;
+  static constexpr auto kLargeMask =
+      MaskFromShift<urbg_result_type>(kLargeShift);
+
+  static constexpr auto kMin = (URBG::min)();
 
   result_type s = 0;
-
-  constexpr size_t kSmallShift = kSmallWidth % kTotalWidth;
-  constexpr result_type kSmallMask = MaskFromShift(result_type{kSmallShift});
   for (size_t n = 0; n < kSmallIters; ++n) {
-    s = (s << kSmallShift) +
-        (static_cast<result_type>(PowerOfTwoVariate(g)) & kSmallMask);
+    urbg_result_type v;
+    do {
+      v = g() - kMin;
+    } while (v >= kSmallRejection);
+
+    s = (s << kSmallShift) + static_cast<result_type>(v & kSmallMask);
   }
 
-  constexpr size_t kLargeShift = kLargeWidth % kTotalWidth;
-  constexpr result_type kLargeMask = MaskFromShift(result_type{kLargeShift});
-  for (size_t n = 0; n < kLargeIters; ++n) {
-    s = (s << kLargeShift) +
-        (static_cast<result_type>(PowerOfTwoVariate(g)) & kLargeMask);
+  for (size_t n = kSmallIters; n < kTotalIters; ++n) {
+    urbg_result_type v;
+    do {
+      v = g() - kMin;
+    } while (v >= kLargeRejection);
+
+    s = (s << kLargeShift) + static_cast<result_type>(v & kLargeMask);
   }
-
-  static_assert(
-      kLargeShift == kSmallShift + 1 ||
-          (kLargeShift == 0 &&
-           kSmallShift == std::numeric_limits<result_type>::digits - 1),
-      "Error in looping constant calculations");
-
   return s;
 }
 
diff --git a/absl/random/internal/fast_uniform_bits_test.cc b/absl/random/internal/fast_uniform_bits_test.cc
index f5b837e..cee702d 100644
--- a/absl/random/internal/fast_uniform_bits_test.cc
+++ b/absl/random/internal/fast_uniform_bits_test.cc
@@ -34,8 +34,8 @@
   using Limits = std::numeric_limits<TypeParam>;
   using FastBits = FastUniformBits<TypeParam>;
 
-  EXPECT_EQ(0, FastBits::min());
-  EXPECT_EQ(Limits::max(), FastBits::max());
+  EXPECT_EQ(0, (FastBits::min)());
+  EXPECT_EQ((Limits::max)(), (FastBits::max)());
 
   constexpr int kIters = 10000;
   std::random_device rd;
@@ -43,8 +43,8 @@
   FastBits fast;
   for (int i = 0; i < kIters; i++) {
     const auto v = fast(gen);
-    EXPECT_LE(v, FastBits::max());
-    EXPECT_GE(v, FastBits::min());
+    EXPECT_LE(v, (FastBits::max)());
+    EXPECT_GE(v, (FastBits::min)());
   }
 }
 
@@ -52,21 +52,26 @@
 struct FakeUrbg {
   using result_type = UIntType;
 
+  FakeUrbg() = default;
+  explicit FakeUrbg(bool r) : reject(r) {}
+
   static constexpr result_type(max)() { return Hi; }
   static constexpr result_type(min)() { return Lo; }
-  result_type operator()() { return Val; }
-};
+  result_type operator()() {
+    // when reject is set, return Hi half the time.
+    return ((++calls % 2) == 1 && reject) ? Hi : Val;
+  }
 
-using UrngOddbits = FakeUrbg<uint8_t, 1, 0xfe, 0x73>;
-using Urng4bits = FakeUrbg<uint8_t, 1, 0x10, 2>;
-using Urng31bits = FakeUrbg<uint32_t, 1, 0xfffffffe, 0x60070f03>;
-using Urng32bits = FakeUrbg<uint32_t, 0, 0xffffffff, 0x74010f01>;
+  bool reject = false;
+  size_t calls = 0;
+};
 
 TEST(FastUniformBitsTest, IsPowerOfTwoOrZero) {
   EXPECT_TRUE(IsPowerOfTwoOrZero(uint8_t{0}));
   EXPECT_TRUE(IsPowerOfTwoOrZero(uint8_t{1}));
   EXPECT_TRUE(IsPowerOfTwoOrZero(uint8_t{2}));
   EXPECT_FALSE(IsPowerOfTwoOrZero(uint8_t{3}));
+  EXPECT_TRUE(IsPowerOfTwoOrZero(uint8_t{4}));
   EXPECT_TRUE(IsPowerOfTwoOrZero(uint8_t{16}));
   EXPECT_FALSE(IsPowerOfTwoOrZero(uint8_t{17}));
   EXPECT_FALSE(IsPowerOfTwoOrZero((std::numeric_limits<uint8_t>::max)()));
@@ -75,6 +80,7 @@
   EXPECT_TRUE(IsPowerOfTwoOrZero(uint16_t{1}));
   EXPECT_TRUE(IsPowerOfTwoOrZero(uint16_t{2}));
   EXPECT_FALSE(IsPowerOfTwoOrZero(uint16_t{3}));
+  EXPECT_TRUE(IsPowerOfTwoOrZero(uint16_t{4}));
   EXPECT_TRUE(IsPowerOfTwoOrZero(uint16_t{16}));
   EXPECT_FALSE(IsPowerOfTwoOrZero(uint16_t{17}));
   EXPECT_FALSE(IsPowerOfTwoOrZero((std::numeric_limits<uint16_t>::max)()));
@@ -91,181 +97,237 @@
   EXPECT_TRUE(IsPowerOfTwoOrZero(uint64_t{1}));
   EXPECT_TRUE(IsPowerOfTwoOrZero(uint64_t{2}));
   EXPECT_FALSE(IsPowerOfTwoOrZero(uint64_t{3}));
+  EXPECT_TRUE(IsPowerOfTwoOrZero(uint64_t{4}));
   EXPECT_TRUE(IsPowerOfTwoOrZero(uint64_t{64}));
   EXPECT_FALSE(IsPowerOfTwoOrZero(uint64_t{17}));
   EXPECT_FALSE(IsPowerOfTwoOrZero((std::numeric_limits<uint64_t>::max)()));
 }
 
 TEST(FastUniformBitsTest, IntegerLog2) {
-  EXPECT_EQ(IntegerLog2(uint16_t{0}), 0);
-  EXPECT_EQ(IntegerLog2(uint16_t{1}), 0);
-  EXPECT_EQ(IntegerLog2(uint16_t{2}), 1);
-  EXPECT_EQ(IntegerLog2(uint16_t{3}), 1);
-  EXPECT_EQ(IntegerLog2(uint16_t{4}), 2);
-  EXPECT_EQ(IntegerLog2(uint16_t{5}), 2);
-  EXPECT_EQ(IntegerLog2(std::numeric_limits<uint64_t>::max()), 63);
+  EXPECT_EQ(0, IntegerLog2(uint16_t{0}));
+  EXPECT_EQ(0, IntegerLog2(uint16_t{1}));
+  EXPECT_EQ(1, IntegerLog2(uint16_t{2}));
+  EXPECT_EQ(1, IntegerLog2(uint16_t{3}));
+  EXPECT_EQ(2, IntegerLog2(uint16_t{4}));
+  EXPECT_EQ(2, IntegerLog2(uint16_t{5}));
+  EXPECT_EQ(2, IntegerLog2(uint16_t{7}));
+  EXPECT_EQ(3, IntegerLog2(uint16_t{8}));
+  EXPECT_EQ(63, IntegerLog2((std::numeric_limits<uint64_t>::max)()));
 }
 
 TEST(FastUniformBitsTest, RangeSize) {
-  EXPECT_EQ((RangeSize<FakeUrbg<uint8_t, 0, 3>>()), 4);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint8_t, 2, 2>>()), 1);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint8_t, 2, 5>>()), 4);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint8_t, 2, 6>>()), 5);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint8_t, 2, 10>>()), 9);
+  EXPECT_EQ(2, (RangeSize<FakeUrbg<uint8_t, 0, 1>>()));
+  EXPECT_EQ(3, (RangeSize<FakeUrbg<uint8_t, 0, 2>>()));
+  EXPECT_EQ(4, (RangeSize<FakeUrbg<uint8_t, 0, 3>>()));
+  //  EXPECT_EQ(0, (RangeSize<FakeUrbg<uint8_t, 2, 2>>()));
+  EXPECT_EQ(4, (RangeSize<FakeUrbg<uint8_t, 2, 5>>()));
+  EXPECT_EQ(5, (RangeSize<FakeUrbg<uint8_t, 2, 6>>()));
+  EXPECT_EQ(9, (RangeSize<FakeUrbg<uint8_t, 2, 10>>()));
   EXPECT_EQ(
-      (RangeSize<FakeUrbg<uint8_t, 0, std::numeric_limits<uint8_t>::max()>>()),
-      0);
+      0, (RangeSize<
+             FakeUrbg<uint8_t, 0, (std::numeric_limits<uint8_t>::max)()>>()));
 
-  EXPECT_EQ((RangeSize<FakeUrbg<uint16_t, 0, 3>>()), 4);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint16_t, 2, 2>>()), 1);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint16_t, 2, 5>>()), 4);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint16_t, 2, 6>>()), 5);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint16_t, 1000, 1017>>()), 18);
-  EXPECT_EQ((RangeSize<
-                FakeUrbg<uint16_t, 0, std::numeric_limits<uint16_t>::max()>>()),
-            0);
+  EXPECT_EQ(4, (RangeSize<FakeUrbg<uint16_t, 0, 3>>()));
+  EXPECT_EQ(4, (RangeSize<FakeUrbg<uint16_t, 2, 5>>()));
+  EXPECT_EQ(5, (RangeSize<FakeUrbg<uint16_t, 2, 6>>()));
+  EXPECT_EQ(18, (RangeSize<FakeUrbg<uint16_t, 1000, 1017>>()));
+  EXPECT_EQ(
+      0, (RangeSize<
+             FakeUrbg<uint16_t, 0, (std::numeric_limits<uint16_t>::max)()>>()));
 
-  EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 0, 3>>()), 4);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 2, 2>>()), 1);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 2, 5>>()), 4);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 2, 6>>()), 5);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 1000, 1017>>()), 18);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 0, 0xffffffff>>()), 0);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 1, 0xffffffff>>()), 0xffffffff);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 1, 0xfffffffe>>()), 0xfffffffe);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 2, 0xfffffffe>>()), 0xfffffffd);
-  EXPECT_EQ((RangeSize<
-                FakeUrbg<uint32_t, 0, std::numeric_limits<uint32_t>::max()>>()),
-            0);
+  EXPECT_EQ(4, (RangeSize<FakeUrbg<uint32_t, 0, 3>>()));
+  EXPECT_EQ(4, (RangeSize<FakeUrbg<uint32_t, 2, 5>>()));
+  EXPECT_EQ(5, (RangeSize<FakeUrbg<uint32_t, 2, 6>>()));
+  EXPECT_EQ(18, (RangeSize<FakeUrbg<uint32_t, 1000, 1017>>()));
+  EXPECT_EQ(0, (RangeSize<FakeUrbg<uint32_t, 0, 0xffffffff>>()));
+  EXPECT_EQ(0xffffffff, (RangeSize<FakeUrbg<uint32_t, 1, 0xffffffff>>()));
+  EXPECT_EQ(0xfffffffe, (RangeSize<FakeUrbg<uint32_t, 1, 0xfffffffe>>()));
+  EXPECT_EQ(0xfffffffd, (RangeSize<FakeUrbg<uint32_t, 2, 0xfffffffe>>()));
+  EXPECT_EQ(
+      0, (RangeSize<
+             FakeUrbg<uint32_t, 0, (std::numeric_limits<uint32_t>::max)()>>()));
 
-  EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 0, 3>>()), 4);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 2, 2>>()), 1);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 2, 5>>()), 4);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 2, 6>>()), 5);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 1000, 1017>>()), 18);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 0, 0xffffffff>>()), 0x100000000ull);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 1, 0xffffffff>>()), 0xffffffffull);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 1, 0xfffffffe>>()), 0xfffffffeull);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 2, 0xfffffffe>>()), 0xfffffffdull);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 0, 0xffffffffffffffffull>>()), 0ull);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 1, 0xffffffffffffffffull>>()),
-            0xffffffffffffffffull);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 1, 0xfffffffffffffffeull>>()),
-            0xfffffffffffffffeull);
-  EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 2, 0xfffffffffffffffeull>>()),
-            0xfffffffffffffffdull);
-  EXPECT_EQ((RangeSize<
-                FakeUrbg<uint64_t, 0, std::numeric_limits<uint64_t>::max()>>()),
-            0);
+  EXPECT_EQ(4, (RangeSize<FakeUrbg<uint64_t, 0, 3>>()));
+  EXPECT_EQ(4, (RangeSize<FakeUrbg<uint64_t, 2, 5>>()));
+  EXPECT_EQ(5, (RangeSize<FakeUrbg<uint64_t, 2, 6>>()));
+  EXPECT_EQ(18, (RangeSize<FakeUrbg<uint64_t, 1000, 1017>>()));
+  EXPECT_EQ(0x100000000, (RangeSize<FakeUrbg<uint64_t, 0, 0xffffffff>>()));
+  EXPECT_EQ(0xffffffff, (RangeSize<FakeUrbg<uint64_t, 1, 0xffffffff>>()));
+  EXPECT_EQ(0xfffffffe, (RangeSize<FakeUrbg<uint64_t, 1, 0xfffffffe>>()));
+  EXPECT_EQ(0xfffffffd, (RangeSize<FakeUrbg<uint64_t, 2, 0xfffffffe>>()));
+  EXPECT_EQ(0, (RangeSize<FakeUrbg<uint64_t, 0, 0xffffffffffffffff>>()));
+  EXPECT_EQ(0xffffffffffffffff,
+            (RangeSize<FakeUrbg<uint64_t, 1, 0xffffffffffffffff>>()));
+  EXPECT_EQ(0xfffffffffffffffe,
+            (RangeSize<FakeUrbg<uint64_t, 1, 0xfffffffffffffffe>>()));
+  EXPECT_EQ(0xfffffffffffffffd,
+            (RangeSize<FakeUrbg<uint64_t, 2, 0xfffffffffffffffe>>()));
+  EXPECT_EQ(
+      0, (RangeSize<
+             FakeUrbg<uint64_t, 0, (std::numeric_limits<uint64_t>::max)()>>()));
 }
 
-TEST(FastUniformBitsTest, PowerOfTwoSubRangeSize) {
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint8_t, 0, 3>>()), 4);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint8_t, 2, 2>>()), 1);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint8_t, 2, 5>>()), 4);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint8_t, 2, 6>>()), 4);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint8_t, 2, 10>>()), 8);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<
-                FakeUrbg<uint8_t, 0, std::numeric_limits<uint8_t>::max()>>()),
-            0);
+// The constants need to be choosen so that an infinite rejection loop doesn't
+// happen...
+using Urng1_5bit = FakeUrbg<uint8_t, 0, 2, 0>;  // ~1.5 bits (range 3)
+using Urng4bits = FakeUrbg<uint8_t, 1, 0x10, 2>;
+using Urng22bits = FakeUrbg<uint32_t, 0, 0x3fffff, 0x301020>;
+using Urng31bits = FakeUrbg<uint32_t, 1, 0xfffffffe, 0x60070f03>;  // ~31.9 bits
+using Urng32bits = FakeUrbg<uint32_t, 0, 0xffffffff, 0x74010f01>;
+using Urng33bits =
+    FakeUrbg<uint64_t, 1, 0x1ffffffff, 0x013301033>;  // ~32.9 bits
+using Urng63bits = FakeUrbg<uint64_t, 1, 0xfffffffffffffffe,
+                            0xfedcba9012345678>;  // ~63.9 bits
+using Urng64bits =
+    FakeUrbg<uint64_t, 0, 0xffffffffffffffff, 0x123456780fedcba9>;
 
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint16_t, 0, 3>>()), 4);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint16_t, 2, 2>>()), 1);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint16_t, 2, 5>>()), 4);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint16_t, 2, 6>>()), 4);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint16_t, 1000, 1017>>()), 16);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<
-                FakeUrbg<uint16_t, 0, std::numeric_limits<uint16_t>::max()>>()),
-            0);
-
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 0, 3>>()), 4);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 2, 2>>()), 1);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 2, 5>>()), 4);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 2, 6>>()), 4);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 1000, 1017>>()), 16);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 0, 0xffffffff>>()), 0);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 1, 0xffffffff>>()),
-            0x80000000);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 1, 0xfffffffe>>()),
-            0x80000000);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<
-                FakeUrbg<uint32_t, 0, std::numeric_limits<uint32_t>::max()>>()),
-            0);
-
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 0, 3>>()), 4);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 2, 2>>()), 1);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 2, 5>>()), 4);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 2, 6>>()), 4);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 1000, 1017>>()), 16);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 0, 0xffffffff>>()),
-            0x100000000ull);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 1, 0xffffffff>>()),
-            0x80000000ull);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 1, 0xfffffffe>>()),
-            0x80000000ull);
-  EXPECT_EQ(
-      (PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 0, 0xffffffffffffffffull>>()),
-      0);
-  EXPECT_EQ(
-      (PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 1, 0xffffffffffffffffull>>()),
-      0x8000000000000000ull);
-  EXPECT_EQ(
-      (PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 1, 0xfffffffffffffffeull>>()),
-      0x8000000000000000ull);
-  EXPECT_EQ((PowerOfTwoSubRangeSize<
-                FakeUrbg<uint64_t, 0, std::numeric_limits<uint64_t>::max()>>()),
-            0);
-}
-
-TEST(FastUniformBitsTest, Urng4_VariousOutputs) {
+TEST(FastUniformBitsTest, OutputsUpTo32Bits) {
   // Tests that how values are composed; the single-bit deltas should be spread
   // across each invocation.
+  Urng1_5bit urng1_5;
   Urng4bits urng4;
+  Urng22bits urng22;
   Urng31bits urng31;
   Urng32bits urng32;
+  Urng33bits urng33;
+  Urng63bits urng63;
+  Urng64bits urng64;
 
   // 8-bit types
   {
     FastUniformBits<uint8_t> fast8;
+    EXPECT_EQ(0x0, fast8(urng1_5));
     EXPECT_EQ(0x11, fast8(urng4));
+    EXPECT_EQ(0x20, fast8(urng22));
     EXPECT_EQ(0x2, fast8(urng31));
     EXPECT_EQ(0x1, fast8(urng32));
+    EXPECT_EQ(0x32, fast8(urng33));
+    EXPECT_EQ(0x77, fast8(urng63));
+    EXPECT_EQ(0xa9, fast8(urng64));
   }
 
   // 16-bit types
   {
     FastUniformBits<uint16_t> fast16;
+    EXPECT_EQ(0x0, fast16(urng1_5));
     EXPECT_EQ(0x1111, fast16(urng4));
-    EXPECT_EQ(0xf02, fast16(urng31));
-    EXPECT_EQ(0xf01, fast16(urng32));
+    EXPECT_EQ(0x1020, fast16(urng22));
+    EXPECT_EQ(0x0f02, fast16(urng31));
+    EXPECT_EQ(0x0f01, fast16(urng32));
+    EXPECT_EQ(0x1032, fast16(urng33));
+    EXPECT_EQ(0x5677, fast16(urng63));
+    EXPECT_EQ(0xcba9, fast16(urng64));
   }
 
   // 32-bit types
   {
     FastUniformBits<uint32_t> fast32;
+    EXPECT_EQ(0x0, fast32(urng1_5));
     EXPECT_EQ(0x11111111, fast32(urng4));
+    EXPECT_EQ(0x08301020, fast32(urng22));
     EXPECT_EQ(0x0f020f02, fast32(urng31));
     EXPECT_EQ(0x74010f01, fast32(urng32));
+    EXPECT_EQ(0x13301032, fast32(urng33));
+    EXPECT_EQ(0x12345677, fast32(urng63));
+    EXPECT_EQ(0x0fedcba9, fast32(urng64));
+  }
+}
+
+TEST(FastUniformBitsTest, Outputs64Bits) {
+  // Tests that how values are composed; the single-bit deltas should be spread
+  // across each invocation.
+  FastUniformBits<uint64_t> fast64;
+
+  {
+    FakeUrbg<uint8_t, 0, 1, 0> urng0;
+    FakeUrbg<uint8_t, 0, 1, 1> urng1;
+    Urng4bits urng4;
+    Urng22bits urng22;
+    Urng31bits urng31;
+    Urng32bits urng32;
+    Urng33bits urng33;
+    Urng63bits urng63;
+    Urng64bits urng64;
+
+    // somewhat degenerate cases only create a single bit.
+    EXPECT_EQ(0x0, fast64(urng0));
+    EXPECT_EQ(64, urng0.calls);
+    EXPECT_EQ(0xffffffffffffffff, fast64(urng1));
+    EXPECT_EQ(64, urng1.calls);
+
+    // less degenerate cases.
+    EXPECT_EQ(0x1111111111111111, fast64(urng4));
+    EXPECT_EQ(16, urng4.calls);
+    EXPECT_EQ(0x01020c0408301020, fast64(urng22));
+    EXPECT_EQ(3, urng22.calls);
+    EXPECT_EQ(0x387811c3c0870f02, fast64(urng31));
+    EXPECT_EQ(3, urng31.calls);
+    EXPECT_EQ(0x74010f0174010f01, fast64(urng32));
+    EXPECT_EQ(2, urng32.calls);
+    EXPECT_EQ(0x808194040cb01032, fast64(urng33));
+    EXPECT_EQ(3, urng33.calls);
+    EXPECT_EQ(0x1234567712345677, fast64(urng63));
+    EXPECT_EQ(2, urng63.calls);
+    EXPECT_EQ(0x123456780fedcba9, fast64(urng64));
+    EXPECT_EQ(1, urng64.calls);
   }
 
-  // 64-bit types
+  // The 1.5 bit case is somewhat interesting in that the algorithm refinement
+  // causes one extra small sample. Comments here reference the names used in
+  // [rand.adapt.ibits] that correspond to this case.
   {
-    FastUniformBits<uint64_t> fast64;
-    EXPECT_EQ(0x1111111111111111, fast64(urng4));
+    Urng1_5bit urng1_5;
+
+    // w = 64
+    // R = 3
+    // m = 1
+    // n' = 64
+    // w0' = 1
+    // y0' = 2
+    // n = (1 <= 0) > 64 : 65 = 65
+    // n0 = 65 - (64%65) = 1
+    // n1 = 64
+    // w0 = 0
+    // y0 = 3
+    // w1 = 1
+    // y1 = 2
+    EXPECT_EQ(0x0, fast64(urng1_5));
+    EXPECT_EQ(65, urng1_5.calls);
+  }
+
+  // Validate rejections for non-power-of-2 cases.
+  {
+    Urng1_5bit urng1_5(true);
+    Urng31bits urng31(true);
+    Urng33bits urng33(true);
+    Urng63bits urng63(true);
+
+    // For 1.5 bits, there would be 1+2*64, except the first
+    // value was accepted and shifted off the end.
+    EXPECT_EQ(0, fast64(urng1_5));
+    EXPECT_EQ(128, urng1_5.calls);
     EXPECT_EQ(0x387811c3c0870f02, fast64(urng31));
-    EXPECT_EQ(0x74010f0174010f01, fast64(urng32));
+    EXPECT_EQ(6, urng31.calls);
+    EXPECT_EQ(0x808194040cb01032, fast64(urng33));
+    EXPECT_EQ(6, urng33.calls);
+    EXPECT_EQ(0x1234567712345677, fast64(urng63));
+    EXPECT_EQ(4, urng63.calls);
   }
 }
 
 TEST(FastUniformBitsTest, URBG32bitRegression) {
   // Validate with deterministic 32-bit std::minstd_rand
   // to ensure that operator() performs as expected.
+
+  EXPECT_EQ(2147483646, RangeSize<std::minstd_rand>());
+  EXPECT_EQ(30, IntegerLog2(RangeSize<std::minstd_rand>()));
+
   std::minstd_rand gen(1);
   FastUniformBits<uint64_t> fast64;
 
-  EXPECT_EQ(0x05e47095f847c122ull, fast64(gen));
-  EXPECT_EQ(0x8f82c1ba30b64d22ull, fast64(gen));
-  EXPECT_EQ(0x3b971a3558155039ull, fast64(gen));
+  EXPECT_EQ(0x05e47095f8791f45, fast64(gen));
+  EXPECT_EQ(0x028be17e3c07c122, fast64(gen));
+  EXPECT_EQ(0x55d2847c1626e8c2, fast64(gen));
 }
 
 }  // namespace
diff --git a/absl/random/internal/fastmath.h b/absl/random/internal/fastmath.h
index 6baeb5a..963b769 100644
--- a/absl/random/internal/fastmath.h
+++ b/absl/random/internal/fastmath.h
@@ -22,27 +22,22 @@
 #include <cmath>
 #include <cstdint>
 
-#include "absl/base/internal/bits.h"
+#include "absl/numeric/bits.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace random_internal {
 
-// Returns the position of the first bit set.
-inline int LeadingSetBit(uint64_t n) {
-  return 64 - base_internal::CountLeadingZeros64(n);
-}
-
 // Compute log2(n) using integer operations.
 // While std::log2 is more accurate than std::log(n) / std::log(2), for
 // very large numbers--those close to std::numeric_limits<uint64_t>::max() - 2,
 // for instance--std::log2 rounds up rather than down, which introduces
 // definite skew in the results.
 inline int IntLog2Floor(uint64_t n) {
-  return (n <= 1) ? 0 : (63 - base_internal::CountLeadingZeros64(n));
+  return (n <= 1) ? 0 : (63 - countl_zero(n));
 }
 inline int IntLog2Ceil(uint64_t n) {
-  return (n <= 1) ? 0 : (64 - base_internal::CountLeadingZeros64(n - 1));
+  return (n <= 1) ? 0 : (64 - countl_zero(n - 1));
 }
 
 inline double StirlingLogFactorial(double n) {
@@ -55,18 +50,6 @@
          (1.0 / 360.0) * ninv * ninv * ninv;
 }
 
-// Rotate value right.
-//
-// We only implement the uint32_t / uint64_t versions because
-// 1) those are the only ones we use, and
-// 2) those are the only ones where clang detects the rotate idiom correctly.
-inline constexpr uint32_t rotr(uint32_t value, uint8_t bits) {
-  return (value >> (bits & 31)) | (value << ((-bits) & 31));
-}
-inline constexpr uint64_t rotr(uint64_t value, uint8_t bits) {
-  return (value >> (bits & 63)) | (value << ((-bits) & 63));
-}
-
 }  // namespace random_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/random/internal/fastmath_test.cc b/absl/random/internal/fastmath_test.cc
index 65859c2..0d6f9dc 100644
--- a/absl/random/internal/fastmath_test.cc
+++ b/absl/random/internal/fastmath_test.cc
@@ -27,19 +27,6 @@
 
 namespace {
 
-TEST(DistributionImplTest, LeadingSetBit) {
-  using absl::random_internal::LeadingSetBit;
-  constexpr uint64_t kZero = 0;
-  EXPECT_EQ(0, LeadingSetBit(kZero));
-  EXPECT_EQ(64, LeadingSetBit(~kZero));
-
-  for (int index = 0; index < 64; index++) {
-    uint64_t x = static_cast<uint64_t>(1) << index;
-    EXPECT_EQ(index + 1, LeadingSetBit(x)) << index;
-    EXPECT_EQ(index + 1, LeadingSetBit(x + x - 1)) << index;
-  }
-}
-
 TEST(FastMathTest, IntLog2FloorTest) {
   using absl::random_internal::IntLog2Floor;
   constexpr uint64_t kZero = 0;
diff --git a/absl/random/internal/gaussian_distribution_gentables.cc b/absl/random/internal/gaussian_distribution_gentables.cc
index a2bf039..a95333d 100644
--- a/absl/random/internal/gaussian_distribution_gentables.cc
+++ b/absl/random/internal/gaussian_distribution_gentables.cc
@@ -111,12 +111,9 @@
          "\n"
          "#include \"absl/random/gaussian_distribution.h\"\n"
          "\n"
-         // "namespace " and "absl" are broken apart so as not to conflict with
-         // script that adds the LTS inline namespace.
-         "namespace "
-         "absl {\n"
-         "namespace "
-         "random_internal {\n"
+         "namespace absl {\n"
+         "ABSL_NAMESPACE_BEGIN\n"
+         "namespace random_internal {\n"
          "\n"
          "const gaussian_distribution_base::Tables\n"
          "    gaussian_distribution_base::zg_ = {\n";
@@ -125,10 +122,9 @@
   FormatArrayContents(os, tables_.f);
   *os << "};\n"
          "\n"
-         "}  // namespace "
-         "random_internal\n"
-         "}  // namespace "
-         "absl\n"
+         "}  // namespace random_internal\n"
+         "ABSL_NAMESPACE_END\n"
+         "}  // namespace absl\n"
          "\n"
          "// clang-format on\n"
          "// END GENERATED CODE";
diff --git a/absl/random/internal/generate_real.h b/absl/random/internal/generate_real.h
index 20f6d20..4f62873 100644
--- a/absl/random/internal/generate_real.h
+++ b/absl/random/internal/generate_real.h
@@ -23,8 +23,8 @@
 #include <limits>
 #include <type_traits>
 
-#include "absl/base/internal/bits.h"
 #include "absl/meta/type_traits.h"
+#include "absl/numeric/bits.h"
 #include "absl/random/internal/fastmath.h"
 #include "absl/random/internal/traits.h"
 
@@ -120,7 +120,7 @@
 
   // Number of leading zeros is mapped to the exponent: 2^-clz
   // bits is 0..01xxxxxx. After shifting, we're left with 1xxx...0..0
-  int clz = base_internal::CountLeadingZeros64(bits);
+  int clz = countl_zero(bits);
   bits <<= (IncludeZero ? clz : (clz & 63));  // remove 0-bits.
   exp -= clz;                                 // set the exponent.
   bits >>= (63 - kExp);
diff --git a/absl/random/internal/generate_real_test.cc b/absl/random/internal/generate_real_test.cc
index aa02f0c..b099dbf 100644
--- a/absl/random/internal/generate_real_test.cc
+++ b/absl/random/internal/generate_real_test.cc
@@ -20,8 +20,8 @@
 #include <string>
 
 #include "gtest/gtest.h"
-#include "absl/base/internal/bits.h"
 #include "absl/flags/flag.h"
+#include "absl/numeric/bits.h"
 
 ABSL_FLAG(int64_t, absl_random_test_trials, 50000,
           "Number of trials for the probability tests.");
@@ -413,14 +413,13 @@
 }
 
 TEST(GenerateRealTest, ExhaustiveFloat) {
-  using absl::base_internal::CountLeadingZeros64;
   auto ToFloat = [](uint64_t a) {
     return GenerateRealFromBits<float, GeneratePositiveTag, true>(a);
   };
 
   // Rely on RandU64ToFloat generating values from greatest to least when
-  // supplied with uint64_t values from greatest (0xfff...) to least (0x0).  Thus,
-  // this algorithm stores the previous value, and if the new value is at
+  // supplied with uint64_t values from greatest (0xfff...) to least (0x0).
+  // Thus, this algorithm stores the previous value, and if the new value is at
   // greater than or equal to the previous value, then there is a collision in
   // the generation algorithm.
   //
@@ -464,7 +463,7 @@
 
     // Adjust decrement and check value based on how many leading 0
     // bits are set in the current value.
-    const int clz = CountLeadingZeros64(x);
+    const int clz = absl::countl_zero(x);
     if (clz < kDig) {
       dec <<= (kDig - clz);
       chk = (~uint64_t(0)) >> (clz + 1);
diff --git a/absl/random/internal/iostream_state_saver.h b/absl/random/internal/iostream_state_saver.h
index 7378829..e6e242e 100644
--- a/absl/random/internal/iostream_state_saver.h
+++ b/absl/random/internal/iostream_state_saver.h
@@ -192,8 +192,8 @@
 
   template <typename OStream>
   inline void write(absl::uint128 val, OStream& out) {
-    uint64_t h = Uint128High64(val);
-    uint64_t l = Uint128Low64(val);
+    uint64_t h = absl::Uint128High64(val);
+    uint64_t l = absl::Uint128Low64(val);
     out << h << out.fill() << l;
   }
 };
diff --git a/absl/random/internal/iostream_state_saver_test.cc b/absl/random/internal/iostream_state_saver_test.cc
index 7bb8ad9..6e66266 100644
--- a/absl/random/internal/iostream_state_saver_test.cc
+++ b/absl/random/internal/iostream_state_saver_test.cc
@@ -14,6 +14,9 @@
 
 #include "absl/random/internal/iostream_state_saver.h"
 
+#include <errno.h>
+#include <stdio.h>
+
 #include <sstream>
 #include <string>
 
@@ -272,7 +275,6 @@
   }
 }
 
-#if !defined(__EMSCRIPTEN__)
 TEST(IOStreamStateSaver, RoundTripLongDoubles) {
   // Technically, C++ only guarantees that long double is at least as large as a
   // double.  Practically it varies from 64-bits to 128-bits.
@@ -350,7 +352,6 @@
     }
   }
 }
-#endif  // !defined(__EMSCRIPTEN__)
 
 TEST(StrToDTest, DoubleMin) {
   const char kV[] = "2.22507385850720138e-308";
diff --git a/absl/random/internal/mock_helpers.h b/absl/random/internal/mock_helpers.h
new file mode 100644
index 0000000..9d6ab21
--- /dev/null
+++ b/absl/random/internal/mock_helpers.h
@@ -0,0 +1,134 @@
+//
+// Copyright 2019 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_RANDOM_INTERNAL_MOCK_HELPERS_H_
+#define ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_
+
+#include <tuple>
+#include <type_traits>
+
+#include "absl/base/internal/fast_type_id.h"
+#include "absl/types/optional.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace random_internal {
+
+// MockHelpers works in conjunction with MockOverloadSet, MockingBitGen, and
+// BitGenRef to enable the mocking capability for absl distribution functions.
+//
+// MockingBitGen registers mocks based on the typeid of a mock signature, KeyT,
+// which is used to generate a unique id.
+//
+// KeyT is a signature of the form:
+//   result_type(discriminator_type, std::tuple<args...>)
+// The mocked function signature will be composed from KeyT as:
+//   result_type(args...)
+//
+class MockHelpers {
+  using IdType = ::absl::base_internal::FastTypeIdType;
+
+  // Given a key signature type used to index the mock, extract the components.
+  // KeyT is expected to have the form:
+  //   result_type(discriminator_type, arg_tuple_type)
+  template <typename KeyT>
+  struct KeySignature;
+
+  template <typename ResultT, typename DiscriminatorT, typename ArgTupleT>
+  struct KeySignature<ResultT(DiscriminatorT, ArgTupleT)> {
+    using result_type = ResultT;
+    using discriminator_type = DiscriminatorT;
+    using arg_tuple_type = ArgTupleT;
+  };
+
+  // Detector for InvokeMock.
+  template <class T>
+  using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock(
+      std::declval<IdType>(), std::declval<void*>(), std::declval<void*>()));
+
+  // Empty implementation of InvokeMock.
+  template <typename KeyT, typename ReturnT, typename ArgTupleT, typename URBG,
+            typename... Args>
+  static absl::optional<ReturnT> InvokeMockImpl(char, URBG*, Args&&...) {
+    return absl::nullopt;
+  }
+
+  // Non-empty implementation of InvokeMock.
+  template <typename KeyT, typename ReturnT, typename ArgTupleT, typename URBG,
+            typename = invoke_mock_t<URBG>, typename... Args>
+  static absl::optional<ReturnT> InvokeMockImpl(int, URBG* urbg,
+                                                Args&&... args) {
+    ArgTupleT arg_tuple(std::forward<Args>(args)...);
+    ReturnT result;
+    if (urbg->InvokeMock(::absl::base_internal::FastTypeId<KeyT>(), &arg_tuple,
+                         &result)) {
+      return result;
+    }
+    return absl::nullopt;
+  }
+
+ public:
+  // InvokeMock is private; this provides access for some specialized use cases.
+  template <typename URBG>
+  static inline bool PrivateInvokeMock(URBG* urbg, IdType type,
+                                       void* args_tuple, void* result) {
+    return urbg->InvokeMock(type, args_tuple, result);
+  }
+
+  // Invoke a mock for the KeyT (may or may not be a signature).
+  //
+  // KeyT is used to generate a typeid-based lookup key for the mock.
+  // KeyT is a signature of the form:
+  //   result_type(discriminator_type, std::tuple<args...>)
+  // The mocked function signature will be composed from KeyT as:
+  //   result_type(args...)
+  //
+  // An instance of arg_tuple_type must be constructable from Args..., since
+  // the underlying mechanism requires a pointer to an argument tuple.
+  template <typename KeyT, typename URBG, typename... Args>
+  static auto MaybeInvokeMock(URBG* urbg, Args&&... args)
+      -> absl::optional<typename KeySignature<KeyT>::result_type> {
+    // Use function overloading to dispatch to the implemenation since
+    // more modern patterns (e.g. require + constexpr) are not supported in all
+    // compiler configurations.
+    return InvokeMockImpl<KeyT, typename KeySignature<KeyT>::result_type,
+                          typename KeySignature<KeyT>::arg_tuple_type, URBG>(
+        0, urbg, std::forward<Args>(args)...);
+  }
+
+  // Acquire a mock for the KeyT (may or may not be a signature).
+  //
+  // KeyT is used to generate a typeid-based lookup for the mock.
+  // KeyT is a signature of the form:
+  //   result_type(discriminator_type, std::tuple<args...>)
+  // The mocked function signature will be composed from KeyT as:
+  //   result_type(args...)
+  template <typename KeyT, typename MockURBG>
+  static auto MockFor(MockURBG& m)
+      -> decltype(m.template RegisterMock<
+                  typename KeySignature<KeyT>::result_type,
+                  typename KeySignature<KeyT>::arg_tuple_type>(
+          m, std::declval<IdType>())) {
+    return m.template RegisterMock<typename KeySignature<KeyT>::result_type,
+                                   typename KeySignature<KeyT>::arg_tuple_type>(
+        m, ::absl::base_internal::FastTypeId<KeyT>());
+  }
+};
+
+}  // namespace random_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_
diff --git a/absl/random/internal/mock_overload_set.h b/absl/random/internal/mock_overload_set.h
index c2a30d8..0d9c6c1 100644
--- a/absl/random/internal/mock_overload_set.h
+++ b/absl/random/internal/mock_overload_set.h
@@ -19,7 +19,7 @@
 #include <type_traits>
 
 #include "gmock/gmock.h"
-#include "gtest/gtest.h"
+#include "absl/random/internal/mock_helpers.h"
 #include "absl/random/mocking_bit_gen.h"
 
 namespace absl {
@@ -35,17 +35,22 @@
 // EXPECT_CALL(mock_single_overload, Call(...))` will expand to a call to
 // `mock_single_overload.gmock_Call(...)`. Because expectations are stored on
 // the MockingBitGen (an argument passed inside `Call(...)`), this forwards to
-// arguments to Mocking::Register.
+// arguments to MockingBitGen::Register.
+//
+// The underlying KeyT must match the KeyT constructed by DistributionCaller.
 template <typename DistrT, typename Ret, typename... Args>
 struct MockSingleOverload<DistrT, Ret(MockingBitGen&, Args...)> {
   static_assert(std::is_same<typename DistrT::result_type, Ret>::value,
                 "Overload signature must have return type matching the "
-                "distributions result type.");
-  auto gmock_Call(
-      absl::MockingBitGen& gen,  // NOLINT(google-runtime-references)
-      const ::testing::Matcher<Args>&... args)
-      -> decltype(gen.Register<DistrT, Args...>(args...)) {
-    return gen.Register<DistrT, Args...>(args...);
+                "distribution result_type.");
+  using KeyT = Ret(DistrT, std::tuple<Args...>);
+
+  template <typename MockURBG>
+  auto gmock_Call(MockURBG& gen, const ::testing::Matcher<Args>&... matchers)
+      -> decltype(MockHelpers::MockFor<KeyT>(gen).gmock_Call(matchers...)) {
+    static_assert(std::is_base_of<MockingBitGen, MockURBG>::value,
+                  "Mocking requires an absl::MockingBitGen");
+    return MockHelpers::MockFor<KeyT>(gen).gmock_Call(matchers...);
   }
 };
 
@@ -53,13 +58,17 @@
 struct MockSingleOverload<DistrT, Ret(Arg, MockingBitGen&, Args...)> {
   static_assert(std::is_same<typename DistrT::result_type, Ret>::value,
                 "Overload signature must have return type matching the "
-                "distributions result type.");
-  auto gmock_Call(
-      const ::testing::Matcher<Arg>& arg,
-      absl::MockingBitGen& gen,  // NOLINT(google-runtime-references)
-      const ::testing::Matcher<Args>&... args)
-      -> decltype(gen.Register<DistrT, Arg, Args...>(arg, args...)) {
-    return gen.Register<DistrT, Arg, Args...>(arg, args...);
+                "distribution result_type.");
+  using KeyT = Ret(DistrT, std::tuple<Arg, Args...>);
+
+  template <typename MockURBG>
+  auto gmock_Call(const ::testing::Matcher<Arg>& matcher, MockURBG& gen,
+                  const ::testing::Matcher<Args>&... matchers)
+      -> decltype(MockHelpers::MockFor<KeyT>(gen).gmock_Call(matcher,
+                                                             matchers...)) {
+    static_assert(std::is_base_of<MockingBitGen, MockURBG>::value,
+                  "Mocking requires an absl::MockingBitGen");
+    return MockHelpers::MockFor<KeyT>(gen).gmock_Call(matcher, matchers...);
   }
 };
 
diff --git a/absl/random/internal/mocking_bit_gen_base.h b/absl/random/internal/mocking_bit_gen_base.h
deleted file mode 100644
index eeeae9d..0000000
--- a/absl/random/internal/mocking_bit_gen_base.h
+++ /dev/null
@@ -1,120 +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.
-//
-#ifndef ABSL_RANDOM_INTERNAL_MOCKING_BIT_GEN_BASE_H_
-#define ABSL_RANDOM_INTERNAL_MOCKING_BIT_GEN_BASE_H_
-
-#include <atomic>
-#include <deque>
-#include <string>
-#include <typeinfo>
-
-#include "absl/random/random.h"
-#include "absl/strings/str_cat.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace random_internal {
-
-// MockingBitGenExpectationFormatter is invoked to format unsatisfied mocks
-// and remaining results into a description string.
-template <typename DistrT, typename FormatT>
-struct MockingBitGenExpectationFormatter {
-  std::string operator()(absl::string_view args) {
-    return absl::StrCat(FormatT::FunctionName(), "(", args, ")");
-  }
-};
-
-// MockingBitGenCallFormatter is invoked to format each distribution call
-// into a description string for the mock log.
-template <typename DistrT, typename FormatT>
-struct MockingBitGenCallFormatter {
-  std::string operator()(const DistrT& dist,
-                         const typename DistrT::result_type& result) {
-    return absl::StrCat(
-        FormatT::FunctionName(), "(", FormatT::FormatArgs(dist), ") => {",
-        FormatT::FormatResults(absl::MakeSpan(&result, 1)), "}");
-  }
-};
-
-class MockingBitGenBase {
-  template <typename>
-  friend struct DistributionCaller;
-  using generator_type = absl::BitGen;
-
- public:
-  // URBG interface
-  using result_type = generator_type::result_type;
-  static constexpr result_type(min)() { return (generator_type::min)(); }
-  static constexpr result_type(max)() { return (generator_type::max)(); }
-  result_type operator()() { return gen_(); }
-
-  MockingBitGenBase() : gen_(), observed_call_log_() {}
-  virtual ~MockingBitGenBase() = default;
-
- protected:
-  const std::deque<std::string>& observed_call_log() {
-    return observed_call_log_;
-  }
-
-  // CallImpl is the type-erased virtual dispatch.
-  // The type of dist is always distribution<T>,
-  // The type of result is always distribution<T>::result_type.
-  virtual bool CallImpl(const std::type_info& distr_type, void* dist_args,
-                        void* result) = 0;
-
-  template <typename DistrT, typename ArgTupleT>
-  static const std::type_info& GetTypeId() {
-    return typeid(std::pair<absl::decay_t<DistrT>, absl::decay_t<ArgTupleT>>);
-  }
-
-  // Call the generating distribution function.
-  // Invoked by DistributionCaller<>::Call<DistT, FormatT>.
-  // DistT is the distribution type.
-  // FormatT is the distribution formatter traits type.
-  template <typename DistrT, typename FormatT, typename... Args>
-  typename DistrT::result_type Call(Args&&... args) {
-    using distr_result_type = typename DistrT::result_type;
-    using ArgTupleT = std::tuple<absl::decay_t<Args>...>;
-
-    ArgTupleT arg_tuple(std::forward<Args>(args)...);
-    auto dist = absl::make_from_tuple<DistrT>(arg_tuple);
-
-    distr_result_type result{};
-    bool found_match =
-        CallImpl(GetTypeId<DistrT, ArgTupleT>(), &arg_tuple, &result);
-
-    if (!found_match) {
-      result = dist(gen_);
-    }
-
-    // TODO(asoffer): Forwarding the args through means we no longer need to
-    // extract them from the from the distribution in formatter traits. We can
-    // just StrJoin them.
-    observed_call_log_.push_back(
-        MockingBitGenCallFormatter<DistrT, FormatT>{}(dist, result));
-    return result;
-  }
-
- private:
-  generator_type gen_;
-  std::deque<std::string> observed_call_log_;
-};  // namespace random_internal
-
-}  // namespace random_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#endif  // ABSL_RANDOM_INTERNAL_MOCKING_BIT_GEN_BASE_H_
diff --git a/absl/random/internal/nanobenchmark.cc b/absl/random/internal/nanobenchmark.cc
index 8fee77f..c918181 100644
--- a/absl/random/internal/nanobenchmark.cc
+++ b/absl/random/internal/nanobenchmark.cc
@@ -101,7 +101,7 @@
   char brand_string[49];
   uint32_t abcd[4];
 
-  // Check if brand std::string is supported (it is on all reasonable Intel/AMD)
+  // Check if brand string is supported (it is on all reasonable Intel/AMD)
   Cpuid(0x80000000U, 0, abcd);
   if (abcd[0] < 0x80000004U) {
     return std::string();
diff --git a/absl/random/internal/nanobenchmark_test.cc b/absl/random/internal/nanobenchmark_test.cc
index ab824ef..f1571e2 100644
--- a/absl/random/internal/nanobenchmark_test.cc
+++ b/absl/random/internal/nanobenchmark_test.cc
@@ -53,7 +53,7 @@
   // Avoid migrating between cores - important on multi-socket systems.
   int cpu = -1;
   if (argc == 2) {
-    if (!SimpleAtoi(argv[1], &cpu)) {
+    if (!absl::SimpleAtoi(argv[1], &cpu)) {
       ABSL_RAW_LOG(FATAL, "The optional argument must be a CPU number >= 0.\n");
     }
   }
diff --git a/absl/random/internal/pcg_engine.h b/absl/random/internal/pcg_engine.h
index 53c23fe..8efaf2e 100644
--- a/absl/random/internal/pcg_engine.h
+++ b/absl/random/internal/pcg_engine.h
@@ -19,6 +19,7 @@
 
 #include "absl/base/config.h"
 #include "absl/meta/type_traits.h"
+#include "absl/numeric/bits.h"
 #include "absl/numeric/int128.h"
 #include "absl/random/internal/fastmath.h"
 #include "absl/random/internal/iostream_state_saver.h"
@@ -261,7 +262,7 @@
     uint64_t rotate = h >> 58u;
     uint64_t s = Uint128Low64(state) ^ h;
 #endif
-    return random_internal::rotr(s, rotate);
+    return rotr(s, rotate);
   }
 };
 
@@ -281,8 +282,8 @@
   using state_type = uint64_t;
   using result_type = uint32_t;
   inline uint32_t operator()(uint64_t state) {
-    return random_internal::rotr(
-        static_cast<uint32_t>(((state >> 18) ^ state) >> 27), state >> 59);
+    return rotr(static_cast<uint32_t>(((state >> 18) ^ state) >> 27),
+                state >> 59);
   }
 };
 
diff --git a/absl/random/internal/randen-keys.inc b/absl/random/internal/randen-keys.inc
deleted file mode 100644
index fa4b166..0000000
--- a/absl/random/internal/randen-keys.inc
+++ /dev/null
@@ -1,207 +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_RANDOM_INTERNAL_RANDEN_KEYS_INC_
-#define ABSL_RANDOM_INTERNAL_RANDEN_KEYS_INC_
-
-// Textual header to include the randen_keys where necessary.
-// REQUIRES: struct u64x2{}
-//
-// PROVIDES: kKeys
-// PROVIDES: round_keys[]
-
-// "Nothing up my sleeve" numbers from the first hex digits of Pi, obtained
-// from http://hexpi.sourceforge.net/. The array was generated by following
-// Python script:
-/*
-python << EOF
-"""Generates Randen round keys array from pi-hex.62500.txt file."""
-import binascii
-
-KEYS = 136
-
-def chunks(l, n):
-    """Yield successive n-sized chunks from l."""
-    for i in range(0, len(l), n):
-        yield l[i:i + n]
-
-def pairwise(t):
-    """Transforms sequence into sequence of pairs."""
-    it = iter(t)
-    return zip(it,it)
-
-def digits_from_pi():
-  """Reads digits from hexpi.sourceforge.net file."""
-  with open("pi-hex.62500.txt") as file:
-    return file.read()
-
-def digits_from_urandom():
-  """Reads digits from /dev/urandom."""
-  with open("/dev/urandom") as file:
-    return binascii.hexlify(file.read(KEYS * 16))
-
-digits = digits_from_pi()
-print("static constexpr const size_t kRoundKeys = {0};\n".format(KEYS))
-print("alignas(16) constexpr const u64x2 round_keys[kRoundKeys] = {")
-
-for i, (hi, lo) in zip(range(KEYS), pairwise(chunks(digits, 16))):
-  hi = "0x{0}ull".format(hi)
-  lo = "0x{0}ull".format(lo)
-  print("  u64x2({0}, {1}){2}".format(hi, lo, ',' if i+1 < KEYS else ''))
-
-print("};")
-EOF
-*/
-
-static constexpr const size_t kRoundKeys = 136;
-
-alignas(16) constexpr u64x2 round_keys[kRoundKeys] = {
-    u64x2(0x243F6A8885A308D3ull, 0x13198A2E03707344ull),
-    u64x2(0xA4093822299F31D0ull, 0x082EFA98EC4E6C89ull),
-    u64x2(0x452821E638D01377ull, 0xBE5466CF34E90C6Cull),
-    u64x2(0xC0AC29B7C97C50DDull, 0x3F84D5B5B5470917ull),
-    u64x2(0x9216D5D98979FB1Bull, 0xD1310BA698DFB5ACull),
-    u64x2(0x2FFD72DBD01ADFB7ull, 0xB8E1AFED6A267E96ull),
-    u64x2(0xBA7C9045F12C7F99ull, 0x24A19947B3916CF7ull),
-    u64x2(0x0801F2E2858EFC16ull, 0x636920D871574E69ull),
-    u64x2(0xA458FEA3F4933D7Eull, 0x0D95748F728EB658ull),
-    u64x2(0x718BCD5882154AEEull, 0x7B54A41DC25A59B5ull),
-    u64x2(0x9C30D5392AF26013ull, 0xC5D1B023286085F0ull),
-    u64x2(0xCA417918B8DB38EFull, 0x8E79DCB0603A180Eull),
-    u64x2(0x6C9E0E8BB01E8A3Eull, 0xD71577C1BD314B27ull),
-    u64x2(0x78AF2FDA55605C60ull, 0xE65525F3AA55AB94ull),
-    u64x2(0x5748986263E81440ull, 0x55CA396A2AAB10B6ull),
-    u64x2(0xB4CC5C341141E8CEull, 0xA15486AF7C72E993ull),
-    u64x2(0xB3EE1411636FBC2Aull, 0x2BA9C55D741831F6ull),
-    u64x2(0xCE5C3E169B87931Eull, 0xAFD6BA336C24CF5Cull),
-    u64x2(0x7A32538128958677ull, 0x3B8F48986B4BB9AFull),
-    u64x2(0xC4BFE81B66282193ull, 0x61D809CCFB21A991ull),
-    u64x2(0x487CAC605DEC8032ull, 0xEF845D5DE98575B1ull),
-    u64x2(0xDC262302EB651B88ull, 0x23893E81D396ACC5ull),
-    u64x2(0x0F6D6FF383F44239ull, 0x2E0B4482A4842004ull),
-    u64x2(0x69C8F04A9E1F9B5Eull, 0x21C66842F6E96C9Aull),
-    u64x2(0x670C9C61ABD388F0ull, 0x6A51A0D2D8542F68ull),
-    u64x2(0x960FA728AB5133A3ull, 0x6EEF0B6C137A3BE4ull),
-    u64x2(0xBA3BF0507EFB2A98ull, 0xA1F1651D39AF0176ull),
-    u64x2(0x66CA593E82430E88ull, 0x8CEE8619456F9FB4ull),
-    u64x2(0x7D84A5C33B8B5EBEull, 0xE06F75D885C12073ull),
-    u64x2(0x401A449F56C16AA6ull, 0x4ED3AA62363F7706ull),
-    u64x2(0x1BFEDF72429B023Dull, 0x37D0D724D00A1248ull),
-    u64x2(0xDB0FEAD349F1C09Bull, 0x075372C980991B7Bull),
-    u64x2(0x25D479D8F6E8DEF7ull, 0xE3FE501AB6794C3Bull),
-    u64x2(0x976CE0BD04C006BAull, 0xC1A94FB6409F60C4ull),
-    u64x2(0x5E5C9EC2196A2463ull, 0x68FB6FAF3E6C53B5ull),
-    u64x2(0x1339B2EB3B52EC6Full, 0x6DFC511F9B30952Cull),
-    u64x2(0xCC814544AF5EBD09ull, 0xBEE3D004DE334AFDull),
-    u64x2(0x660F2807192E4BB3ull, 0xC0CBA85745C8740Full),
-    u64x2(0xD20B5F39B9D3FBDBull, 0x5579C0BD1A60320Aull),
-    u64x2(0xD6A100C6402C7279ull, 0x679F25FEFB1FA3CCull),
-    u64x2(0x8EA5E9F8DB3222F8ull, 0x3C7516DFFD616B15ull),
-    u64x2(0x2F501EC8AD0552ABull, 0x323DB5FAFD238760ull),
-    u64x2(0x53317B483E00DF82ull, 0x9E5C57BBCA6F8CA0ull),
-    u64x2(0x1A87562EDF1769DBull, 0xD542A8F6287EFFC3ull),
-    u64x2(0xAC6732C68C4F5573ull, 0x695B27B0BBCA58C8ull),
-    u64x2(0xE1FFA35DB8F011A0ull, 0x10FA3D98FD2183B8ull),
-    u64x2(0x4AFCB56C2DD1D35Bull, 0x9A53E479B6F84565ull),
-    u64x2(0xD28E49BC4BFB9790ull, 0xE1DDF2DAA4CB7E33ull),
-    u64x2(0x62FB1341CEE4C6E8ull, 0xEF20CADA36774C01ull),
-    u64x2(0xD07E9EFE2BF11FB4ull, 0x95DBDA4DAE909198ull),
-    u64x2(0xEAAD8E716B93D5A0ull, 0xD08ED1D0AFC725E0ull),
-    u64x2(0x8E3C5B2F8E7594B7ull, 0x8FF6E2FBF2122B64ull),
-    u64x2(0x8888B812900DF01Cull, 0x4FAD5EA0688FC31Cull),
-    u64x2(0xD1CFF191B3A8C1ADull, 0x2F2F2218BE0E1777ull),
-    u64x2(0xEA752DFE8B021FA1ull, 0xE5A0CC0FB56F74E8ull),
-    u64x2(0x18ACF3D6CE89E299ull, 0xB4A84FE0FD13E0B7ull),
-    u64x2(0x7CC43B81D2ADA8D9ull, 0x165FA26680957705ull),
-    u64x2(0x93CC7314211A1477ull, 0xE6AD206577B5FA86ull),
-    u64x2(0xC75442F5FB9D35CFull, 0xEBCDAF0C7B3E89A0ull),
-    u64x2(0xD6411BD3AE1E7E49ull, 0x00250E2D2071B35Eull),
-    u64x2(0x226800BB57B8E0AFull, 0x2464369BF009B91Eull),
-    u64x2(0x5563911D59DFA6AAull, 0x78C14389D95A537Full),
-    u64x2(0x207D5BA202E5B9C5ull, 0x832603766295CFA9ull),
-    u64x2(0x11C819684E734A41ull, 0xB3472DCA7B14A94Aull),
-    u64x2(0x1B5100529A532915ull, 0xD60F573FBC9BC6E4ull),
-    u64x2(0x2B60A47681E67400ull, 0x08BA6FB5571BE91Full),
-    u64x2(0xF296EC6B2A0DD915ull, 0xB6636521E7B9F9B6ull),
-    u64x2(0xFF34052EC5855664ull, 0x53B02D5DA99F8FA1ull),
-    u64x2(0x08BA47996E85076Aull, 0x4B7A70E9B5B32944ull),
-    u64x2(0xDB75092EC4192623ull, 0xAD6EA6B049A7DF7Dull),
-    u64x2(0x9CEE60B88FEDB266ull, 0xECAA8C71699A18FFull),
-    u64x2(0x5664526CC2B19EE1ull, 0x193602A575094C29ull),
-    u64x2(0xA0591340E4183A3Eull, 0x3F54989A5B429D65ull),
-    u64x2(0x6B8FE4D699F73FD6ull, 0xA1D29C07EFE830F5ull),
-    u64x2(0x4D2D38E6F0255DC1ull, 0x4CDD20868470EB26ull),
-    u64x2(0x6382E9C6021ECC5Eull, 0x09686B3F3EBAEFC9ull),
-    u64x2(0x3C9718146B6A70A1ull, 0x687F358452A0E286ull),
-    u64x2(0xB79C5305AA500737ull, 0x3E07841C7FDEAE5Cull),
-    u64x2(0x8E7D44EC5716F2B8ull, 0xB03ADA37F0500C0Dull),
-    u64x2(0xF01C1F040200B3FFull, 0xAE0CF51A3CB574B2ull),
-    u64x2(0x25837A58DC0921BDull, 0xD19113F97CA92FF6ull),
-    u64x2(0x9432477322F54701ull, 0x3AE5E58137C2DADCull),
-    u64x2(0xC8B576349AF3DDA7ull, 0xA94461460FD0030Eull),
-    u64x2(0xECC8C73EA4751E41ull, 0xE238CD993BEA0E2Full),
-    u64x2(0x3280BBA1183EB331ull, 0x4E548B384F6DB908ull),
-    u64x2(0x6F420D03F60A04BFull, 0x2CB8129024977C79ull),
-    u64x2(0x5679B072BCAF89AFull, 0xDE9A771FD9930810ull),
-    u64x2(0xB38BAE12DCCF3F2Eull, 0x5512721F2E6B7124ull),
-    u64x2(0x501ADDE69F84CD87ull, 0x7A5847187408DA17ull),
-    u64x2(0xBC9F9ABCE94B7D8Cull, 0xEC7AEC3ADB851DFAull),
-    u64x2(0x63094366C464C3D2ull, 0xEF1C18473215D808ull),
-    u64x2(0xDD433B3724C2BA16ull, 0x12A14D432A65C451ull),
-    u64x2(0x50940002133AE4DDull, 0x71DFF89E10314E55ull),
-    u64x2(0x81AC77D65F11199Bull, 0x043556F1D7A3C76Bull),
-    u64x2(0x3C11183B5924A509ull, 0xF28FE6ED97F1FBFAull),
-    u64x2(0x9EBABF2C1E153C6Eull, 0x86E34570EAE96FB1ull),
-    u64x2(0x860E5E0A5A3E2AB3ull, 0x771FE71C4E3D06FAull),
-    u64x2(0x2965DCB999E71D0Full, 0x803E89D65266C825ull),
-    u64x2(0x2E4CC9789C10B36Aull, 0xC6150EBA94E2EA78ull),
-    u64x2(0xA6FC3C531E0A2DF4ull, 0xF2F74EA7361D2B3Dull),
-    u64x2(0x1939260F19C27960ull, 0x5223A708F71312B6ull),
-    u64x2(0xEBADFE6EEAC31F66ull, 0xE3BC4595A67BC883ull),
-    u64x2(0xB17F37D1018CFF28ull, 0xC332DDEFBE6C5AA5ull),
-    u64x2(0x6558218568AB9702ull, 0xEECEA50FDB2F953Bull),
-    u64x2(0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull),
-    u64x2(0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull),
-    u64x2(0x0334FE1EAA0363CFull, 0xB5735C904C70A239ull),
-    u64x2(0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull),
-    u64x2(0x9CAB5CABB2F3846Eull, 0x648B1EAF19BDF0CAull),
-    u64x2(0xA02369B9655ABB50ull, 0x40685A323C2AB4B3ull),
-    u64x2(0x319EE9D5C021B8F7ull, 0x9B540B19875FA099ull),
-    u64x2(0x95F7997E623D7DA8ull, 0xF837889A97E32D77ull),
-    u64x2(0x11ED935F16681281ull, 0x0E358829C7E61FD6ull),
-    u64x2(0x96DEDFA17858BA99ull, 0x57F584A51B227263ull),
-    u64x2(0x9B83C3FF1AC24696ull, 0xCDB30AEB532E3054ull),
-    u64x2(0x8FD948E46DBC3128ull, 0x58EBF2EF34C6FFEAull),
-    u64x2(0xFE28ED61EE7C3C73ull, 0x5D4A14D9E864B7E3ull),
-    u64x2(0x42105D14203E13E0ull, 0x45EEE2B6A3AAABEAull),
-    u64x2(0xDB6C4F15FACB4FD0ull, 0xC742F442EF6ABBB5ull),
-    u64x2(0x654F3B1D41CD2105ull, 0xD81E799E86854DC7ull),
-    u64x2(0xE44B476A3D816250ull, 0xCF62A1F25B8D2646ull),
-    u64x2(0xFC8883A0C1C7B6A3ull, 0x7F1524C369CB7492ull),
-    u64x2(0x47848A0B5692B285ull, 0x095BBF00AD19489Dull),
-    u64x2(0x1462B17423820D00ull, 0x58428D2A0C55F5EAull),
-    u64x2(0x1DADF43E233F7061ull, 0x3372F0928D937E41ull),
-    u64x2(0xD65FECF16C223BDBull, 0x7CDE3759CBEE7460ull),
-    u64x2(0x4085F2A7CE77326Eull, 0xA607808419F8509Eull),
-    u64x2(0xE8EFD85561D99735ull, 0xA969A7AAC50C06C2ull),
-    u64x2(0x5A04ABFC800BCADCull, 0x9E447A2EC3453484ull),
-    u64x2(0xFDD567050E1E9EC9ull, 0xDB73DBD3105588CDull),
-    u64x2(0x675FDA79E3674340ull, 0xC5C43465713E38D8ull),
-    u64x2(0x3D28F89EF16DFF20ull, 0x153E21E78FB03D4Aull),
-    u64x2(0xE6E39F2BDB83ADF7ull, 0xE93D5A68948140F7ull),
-    u64x2(0xF64C261C94692934ull, 0x411520F77602D4F7ull),
-    u64x2(0xBCF46B2ED4A10068ull, 0xD40824713320F46Aull),
-    u64x2(0x43B7D4B7500061AFull, 0x1E39F62E97244546ull)};
-
-#endif  // ABSL_RANDOM_INTERNAL_RANDEN_KEYS_INC_
diff --git a/absl/random/internal/randen.cc b/absl/random/internal/randen.cc
index 78a1e00..c1bc044 100644
--- a/absl/random/internal/randen.cc
+++ b/absl/random/internal/randen.cc
@@ -17,7 +17,7 @@
 #include "absl/base/internal/raw_logging.h"
 #include "absl/random/internal/randen_detect.h"
 
-// RANDen = RANDom generator or beetroots in Swiss German.
+// RANDen = RANDom generator or beetroots in Swiss High German.
 // 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
 // generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
 //
diff --git a/absl/random/internal/randen.h b/absl/random/internal/randen.h
index c2834aa..9a3840b 100644
--- a/absl/random/internal/randen.h
+++ b/absl/random/internal/randen.h
@@ -26,7 +26,7 @@
 ABSL_NAMESPACE_BEGIN
 namespace random_internal {
 
-// RANDen = RANDom generator or beetroots in Swiss German.
+// RANDen = RANDom generator or beetroots in Swiss High German.
 // 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
 // generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
 //
diff --git a/absl/random/internal/randen_detect.cc b/absl/random/internal/randen_detect.cc
index d63230c..bbe7b96 100644
--- a/absl/random/internal/randen_detect.cc
+++ b/absl/random/internal/randen_detect.cc
@@ -1,13 +1,13 @@
 // Copyright 2017 The Abseil Authors.
 //
-// Licensed under the Apache License, Version 2.0 (the"License");
+// 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,
+// 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.
diff --git a/absl/random/internal/randen_engine.h b/absl/random/internal/randen_engine.h
index 6b33731..92bb890 100644
--- a/absl/random/internal/randen_engine.h
+++ b/absl/random/internal/randen_engine.h
@@ -23,6 +23,7 @@
 #include <limits>
 #include <type_traits>
 
+#include "absl/base/internal/endian.h"
 #include "absl/meta/type_traits.h"
 #include "absl/random/internal/iostream_state_saver.h"
 #include "absl/random/internal/randen.h"
@@ -76,7 +77,7 @@
       impl_.Generate(state_);
     }
 
-    return state_[next_++];
+    return little_endian::ToHost(state_[next_++]);
   }
 
   template <class SeedSequence>
@@ -181,7 +182,8 @@
       // In the case that `elem` is `uint8_t`, it must be cast to something
       // larger so that it prints as an integer rather than a character. For
       // simplicity, apply the cast all circumstances.
-      os << static_cast<numeric_type>(elem) << os.fill();
+      os << static_cast<numeric_type>(little_endian::FromHost(elem))
+         << os.fill();
     }
     os << engine.next_;
     return os;
@@ -200,7 +202,7 @@
       // necessary to read a wider type and then cast it to uint8_t.
       numeric_type value;
       is >> value;
-      elem = static_cast<result_type>(value);
+      elem = little_endian::ToHost(static_cast<result_type>(value));
     }
     is >> next;
     if (is.fail()) {
diff --git a/absl/random/internal/randen_hwaes.cc b/absl/random/internal/randen_hwaes.cc
index e23844f..b5a3f90 100644
--- a/absl/random/internal/randen_hwaes.cc
+++ b/absl/random/internal/randen_hwaes.cc
@@ -24,6 +24,7 @@
 
 #include "absl/base/attributes.h"
 #include "absl/random/internal/platform.h"
+#include "absl/random/internal/randen_traits.h"
 
 // ABSL_RANDEN_HWAES_IMPL indicates whether this file will contain
 // a hardware accelerated implementation of randen, or whether it
@@ -115,8 +116,16 @@
 // Accelerated implementations are supported.
 // We need the per-architecture includes and defines.
 //
+namespace {
 
-#include "absl/random/internal/randen_traits.h"
+using absl::random_internal::RandenTraits;
+
+// Randen operates on 128-bit vectors.
+struct alignas(16) u64x2 {
+  uint64_t data[2];
+};
+
+}  // namespace
 
 // TARGET_CRYPTO defines a crypto attribute for each architecture.
 //
@@ -141,6 +150,7 @@
 #include <altivec.h>
 // <altivec.h> #defines vector __vector; in C++, this is bad form.
 #undef vector
+#undef bool
 
 // Rely on the PowerPC AltiVec vector operations for accelerated AES
 // instructions. GCC support of the PPC vector types is described in:
@@ -150,7 +160,6 @@
 using Vector128 = __vector unsigned long long;  // NOLINT(runtime/int)
 
 namespace {
-
 inline ABSL_TARGET_CRYPTO Vector128 ReverseBytes(const Vector128& v) {
   // Reverses the bytes of the vector.
   const __vector unsigned char perm = {15, 14, 13, 12, 11, 10, 9, 8,
@@ -177,14 +186,9 @@
 }
 
 // Enables native loads in the round loop by pre-swapping.
-inline ABSL_TARGET_CRYPTO void SwapEndian(uint64_t* state) {
-  using absl::random_internal::RandenTraits;
-  constexpr size_t kLanes = 2;
-  constexpr size_t kFeistelBlocks = RandenTraits::kFeistelBlocks;
-
-  for (uint32_t branch = 0; branch < kFeistelBlocks; ++branch) {
-    const Vector128 v = ReverseBytes(Vector128Load(state + kLanes * branch));
-    Vector128Store(v, state + kLanes * branch);
+inline ABSL_TARGET_CRYPTO void SwapEndian(u64x2* state) {
+  for (uint32_t block = 0; block < RandenTraits::kFeistelBlocks; ++block) {
+    Vector128Store(ReverseBytes(Vector128Load(state + block)), state + block);
   }
 }
 
@@ -251,7 +255,7 @@
   return vaesmcq_u8(vaeseq_u8(state, uint8x16_t{})) ^ round_key;
 }
 
-inline ABSL_TARGET_CRYPTO void SwapEndian(uint64_t*) {}
+inline ABSL_TARGET_CRYPTO void SwapEndian(void*) {}
 
 }  // namespace
 
@@ -297,39 +301,12 @@
   return Vector128(_mm_aesenc_si128(state.data(), round_key.data()));
 }
 
-inline ABSL_TARGET_CRYPTO void SwapEndian(uint64_t*) {}
+inline ABSL_TARGET_CRYPTO void SwapEndian(void*) {}
 
 }  // namespace
 
 #endif
 
-namespace {
-
-// u64x2 is a 128-bit, (2 x uint64_t lanes) struct used to store
-// the randen_keys.
-struct alignas(16) u64x2 {
-  constexpr u64x2(uint64_t hi, uint64_t lo)
-#if defined(ABSL_ARCH_PPC)
-      // This has been tested with PPC running in little-endian mode;
-      // We byte-swap the u64x2 structure from little-endian to big-endian
-      // because altivec always runs in big-endian mode.
-      : v{__builtin_bswap64(hi), __builtin_bswap64(lo)} {
-#else
-      : v{lo, hi} {
-#endif
-  }
-
-  constexpr bool operator==(const u64x2& other) const {
-    return v[0] == other.v[0] && v[1] == other.v[1];
-  }
-
-  constexpr bool operator!=(const u64x2& other) const {
-    return !(*this == other);
-  }
-
-  uint64_t v[2];
-};  // namespace
-
 #ifdef __clang__
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wunknown-pragmas"
@@ -338,7 +315,6 @@
 // At this point, all of the platform-specific features have been defined /
 // implemented.
 //
-// REQUIRES: using u64x2 = ...
 // REQUIRES: using Vector128 = ...
 // REQUIRES: Vector128 Vector128Load(void*) {...}
 // REQUIRES: void Vector128Store(Vector128, void*) {...}
@@ -347,94 +323,50 @@
 //
 // PROVIDES: absl::random_internal::RandenHwAes::Absorb
 // PROVIDES: absl::random_internal::RandenHwAes::Generate
-
-// RANDen = RANDom generator or beetroots in Swiss German.
-// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
-// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
-//
-// High-level summary:
-// 1) Reverie (see "A Robust and Sponge-Like PRNG with Improved Efficiency") is
-//    a sponge-like random generator that requires a cryptographic permutation.
-//    It improves upon "Provably Robust Sponge-Based PRNGs and KDFs" by
-//    achieving backtracking resistance with only one Permute() per buffer.
-//
-// 2) "Simpira v2: A Family of Efficient Permutations Using the AES Round
-//    Function" constructs up to 1024-bit permutations using an improved
-//    Generalized Feistel network with 2-round AES-128 functions. This Feistel
-//    block shuffle achieves diffusion faster and is less vulnerable to
-//    sliced-biclique attacks than the Type-2 cyclic shuffle.
-//
-// 3) "Improving the Generalized Feistel" and "New criterion for diffusion
-//    property" extends the same kind of improved Feistel block shuffle to 16
-//    branches, which enables a 2048-bit permutation.
-//
-// We combine these three ideas and also change Simpira's subround keys from
-// structured/low-entropy counters to digits of Pi.
-
-// Randen constants.
-using absl::random_internal::RandenTraits;
-constexpr size_t kStateBytes = RandenTraits::kStateBytes;
-constexpr size_t kCapacityBytes = RandenTraits::kCapacityBytes;
-constexpr size_t kFeistelBlocks = RandenTraits::kFeistelBlocks;
-constexpr size_t kFeistelRounds = RandenTraits::kFeistelRounds;
-constexpr size_t kFeistelFunctions = RandenTraits::kFeistelFunctions;
-
-// Independent keys (272 = 2.1 KiB) for the first AES subround of each function.
-constexpr size_t kKeys = kFeistelRounds * kFeistelFunctions;
-
-// INCLUDE keys.
-#include "absl/random/internal/randen-keys.inc"
-
-static_assert(kKeys == kRoundKeys, "kKeys and kRoundKeys must be equal");
-static_assert(round_keys[kKeys - 1] != u64x2(0, 0),
-              "Too few round_keys initializers");
-
-// Number of uint64_t lanes per 128-bit vector;
-constexpr size_t kLanes = 2;
+namespace {
 
 // Block shuffles applies a shuffle to the entire state between AES rounds.
 // Improved odd-even shuffle from "New criterion for diffusion property".
-inline ABSL_TARGET_CRYPTO void BlockShuffle(uint64_t* state) {
-  static_assert(kFeistelBlocks == 16, "Expecting 16 FeistelBlocks.");
+inline ABSL_TARGET_CRYPTO void BlockShuffle(u64x2* state) {
+  static_assert(RandenTraits::kFeistelBlocks == 16,
+                "Expecting 16 FeistelBlocks.");
 
-  constexpr size_t shuffle[kFeistelBlocks] = {7,  2, 13, 4,  11, 8,  3, 6,
-                                              15, 0, 9,  10, 1,  14, 5, 12};
+  constexpr size_t shuffle[RandenTraits::kFeistelBlocks] = {
+      7, 2, 13, 4, 11, 8, 3, 6, 15, 0, 9, 10, 1, 14, 5, 12};
 
-  // The fully unrolled loop without the memcpy improves the speed by about
-  // 30% over the equivalent loop.
-  const Vector128 v0 = Vector128Load(state + kLanes * shuffle[0]);
-  const Vector128 v1 = Vector128Load(state + kLanes * shuffle[1]);
-  const Vector128 v2 = Vector128Load(state + kLanes * shuffle[2]);
-  const Vector128 v3 = Vector128Load(state + kLanes * shuffle[3]);
-  const Vector128 v4 = Vector128Load(state + kLanes * shuffle[4]);
-  const Vector128 v5 = Vector128Load(state + kLanes * shuffle[5]);
-  const Vector128 v6 = Vector128Load(state + kLanes * shuffle[6]);
-  const Vector128 v7 = Vector128Load(state + kLanes * shuffle[7]);
-  const Vector128 w0 = Vector128Load(state + kLanes * shuffle[8]);
-  const Vector128 w1 = Vector128Load(state + kLanes * shuffle[9]);
-  const Vector128 w2 = Vector128Load(state + kLanes * shuffle[10]);
-  const Vector128 w3 = Vector128Load(state + kLanes * shuffle[11]);
-  const Vector128 w4 = Vector128Load(state + kLanes * shuffle[12]);
-  const Vector128 w5 = Vector128Load(state + kLanes * shuffle[13]);
-  const Vector128 w6 = Vector128Load(state + kLanes * shuffle[14]);
-  const Vector128 w7 = Vector128Load(state + kLanes * shuffle[15]);
+  const Vector128 v0 = Vector128Load(state + shuffle[0]);
+  const Vector128 v1 = Vector128Load(state + shuffle[1]);
+  const Vector128 v2 = Vector128Load(state + shuffle[2]);
+  const Vector128 v3 = Vector128Load(state + shuffle[3]);
+  const Vector128 v4 = Vector128Load(state + shuffle[4]);
+  const Vector128 v5 = Vector128Load(state + shuffle[5]);
+  const Vector128 v6 = Vector128Load(state + shuffle[6]);
+  const Vector128 v7 = Vector128Load(state + shuffle[7]);
+  const Vector128 w0 = Vector128Load(state + shuffle[8]);
+  const Vector128 w1 = Vector128Load(state + shuffle[9]);
+  const Vector128 w2 = Vector128Load(state + shuffle[10]);
+  const Vector128 w3 = Vector128Load(state + shuffle[11]);
+  const Vector128 w4 = Vector128Load(state + shuffle[12]);
+  const Vector128 w5 = Vector128Load(state + shuffle[13]);
+  const Vector128 w6 = Vector128Load(state + shuffle[14]);
+  const Vector128 w7 = Vector128Load(state + shuffle[15]);
 
-  Vector128Store(v0, state + kLanes * 0);
-  Vector128Store(v1, state + kLanes * 1);
-  Vector128Store(v2, state + kLanes * 2);
-  Vector128Store(v3, state + kLanes * 3);
-  Vector128Store(v4, state + kLanes * 4);
-  Vector128Store(v5, state + kLanes * 5);
-  Vector128Store(v6, state + kLanes * 6);
-  Vector128Store(v7, state + kLanes * 7);
-  Vector128Store(w0, state + kLanes * 8);
-  Vector128Store(w1, state + kLanes * 9);
-  Vector128Store(w2, state + kLanes * 10);
-  Vector128Store(w3, state + kLanes * 11);
-  Vector128Store(w4, state + kLanes * 12);
-  Vector128Store(w5, state + kLanes * 13);
-  Vector128Store(w6, state + kLanes * 14);
-  Vector128Store(w7, state + kLanes * 15);
+  Vector128Store(v0, state + 0);
+  Vector128Store(v1, state + 1);
+  Vector128Store(v2, state + 2);
+  Vector128Store(v3, state + 3);
+  Vector128Store(v4, state + 4);
+  Vector128Store(v5, state + 5);
+  Vector128Store(v6, state + 6);
+  Vector128Store(v7, state + 7);
+  Vector128Store(w0, state + 8);
+  Vector128Store(w1, state + 9);
+  Vector128Store(w2, state + 10);
+  Vector128Store(w3, state + 11);
+  Vector128Store(w4, state + 12);
+  Vector128Store(w5, state + 13);
+  Vector128Store(w6, state + 14);
+  Vector128Store(w7, state + 15);
 }
 
 // Feistel round function using two AES subrounds. Very similar to F()
@@ -443,27 +375,28 @@
 // parallel hides the 7-cycle AESNI latency on HSW. Note that the Feistel
 // XORs are 'free' (included in the second AES instruction).
 inline ABSL_TARGET_CRYPTO const u64x2* FeistelRound(
-    uint64_t* state, const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys) {
-  static_assert(kFeistelBlocks == 16, "Expecting 16 FeistelBlocks.");
+    u64x2* state, const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys) {
+  static_assert(RandenTraits::kFeistelBlocks == 16,
+                "Expecting 16 FeistelBlocks.");
 
   // MSVC does a horrible job at unrolling loops.
   // So we unroll the loop by hand to improve the performance.
-  const Vector128 s0 = Vector128Load(state + kLanes * 0);
-  const Vector128 s1 = Vector128Load(state + kLanes * 1);
-  const Vector128 s2 = Vector128Load(state + kLanes * 2);
-  const Vector128 s3 = Vector128Load(state + kLanes * 3);
-  const Vector128 s4 = Vector128Load(state + kLanes * 4);
-  const Vector128 s5 = Vector128Load(state + kLanes * 5);
-  const Vector128 s6 = Vector128Load(state + kLanes * 6);
-  const Vector128 s7 = Vector128Load(state + kLanes * 7);
-  const Vector128 s8 = Vector128Load(state + kLanes * 8);
-  const Vector128 s9 = Vector128Load(state + kLanes * 9);
-  const Vector128 s10 = Vector128Load(state + kLanes * 10);
-  const Vector128 s11 = Vector128Load(state + kLanes * 11);
-  const Vector128 s12 = Vector128Load(state + kLanes * 12);
-  const Vector128 s13 = Vector128Load(state + kLanes * 13);
-  const Vector128 s14 = Vector128Load(state + kLanes * 14);
-  const Vector128 s15 = Vector128Load(state + kLanes * 15);
+  const Vector128 s0 = Vector128Load(state + 0);
+  const Vector128 s1 = Vector128Load(state + 1);
+  const Vector128 s2 = Vector128Load(state + 2);
+  const Vector128 s3 = Vector128Load(state + 3);
+  const Vector128 s4 = Vector128Load(state + 4);
+  const Vector128 s5 = Vector128Load(state + 5);
+  const Vector128 s6 = Vector128Load(state + 6);
+  const Vector128 s7 = Vector128Load(state + 7);
+  const Vector128 s8 = Vector128Load(state + 8);
+  const Vector128 s9 = Vector128Load(state + 9);
+  const Vector128 s10 = Vector128Load(state + 10);
+  const Vector128 s11 = Vector128Load(state + 11);
+  const Vector128 s12 = Vector128Load(state + 12);
+  const Vector128 s13 = Vector128Load(state + 13);
+  const Vector128 s14 = Vector128Load(state + 14);
+  const Vector128 s15 = Vector128Load(state + 15);
 
   // Encode even blocks with keys.
   const Vector128 e0 = AesRound(s0, Vector128Load(keys + 0));
@@ -486,14 +419,14 @@
   const Vector128 o15 = AesRound(e14, s15);
 
   // Store odd blocks. (These will be shuffled later).
-  Vector128Store(o1, state + kLanes * 1);
-  Vector128Store(o3, state + kLanes * 3);
-  Vector128Store(o5, state + kLanes * 5);
-  Vector128Store(o7, state + kLanes * 7);
-  Vector128Store(o9, state + kLanes * 9);
-  Vector128Store(o11, state + kLanes * 11);
-  Vector128Store(o13, state + kLanes * 13);
-  Vector128Store(o15, state + kLanes * 15);
+  Vector128Store(o1, state + 1);
+  Vector128Store(o3, state + 3);
+  Vector128Store(o5, state + 5);
+  Vector128Store(o7, state + 7);
+  Vector128Store(o9, state + 9);
+  Vector128Store(o11, state + 11);
+  Vector128Store(o13, state + 13);
+  Vector128Store(o15, state + 15);
 
   return keys + 8;
 }
@@ -503,16 +436,13 @@
 // 2^64 queries if the round function is a PRF. This is similar to the b=8 case
 // of Simpira v2, but more efficient than its generic construction for b=16.
 inline ABSL_TARGET_CRYPTO void Permute(
-    const void* ABSL_RANDOM_INTERNAL_RESTRICT keys, uint64_t* state) {
-  const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys128 =
-      static_cast<const u64x2*>(keys);
-
+    u64x2* state, const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys) {
   // (Successfully unrolled; the first iteration jumps into the second half)
 #ifdef __clang__
 #pragma clang loop unroll_count(2)
 #endif
-  for (size_t round = 0; round < kFeistelRounds; ++round) {
-    keys128 = FeistelRound(state, keys128);
+  for (size_t round = 0; round < RandenTraits::kFeistelRounds; ++round) {
+    keys = FeistelRound(state, keys);
     BlockShuffle(state);
   }
 }
@@ -528,96 +458,101 @@
 const void* ABSL_TARGET_CRYPTO RandenHwAes::GetKeys() {
   // Round keys for one AES per Feistel round and branch.
   // The canonical implementation uses first digits of Pi.
-  return round_keys;
+#if defined(ABSL_ARCH_PPC)
+  return kRandenRoundKeysBE;
+#else
+  return kRandenRoundKeys;
+#endif
 }
 
 // NOLINTNEXTLINE
 void ABSL_TARGET_CRYPTO RandenHwAes::Absorb(const void* seed_void,
                                             void* state_void) {
-  auto* state = static_cast<uint64_t*>(state_void);
-  const auto* seed = static_cast<const uint64_t*>(seed_void);
+  static_assert(RandenTraits::kCapacityBytes / sizeof(Vector128) == 1,
+                "Unexpected Randen kCapacityBlocks");
+  static_assert(RandenTraits::kStateBytes / sizeof(Vector128) == 16,
+                "Unexpected Randen kStateBlocks");
 
-  constexpr size_t kCapacityBlocks = kCapacityBytes / sizeof(Vector128);
-  constexpr size_t kStateBlocks = kStateBytes / sizeof(Vector128);
+  auto* state =
+      reinterpret_cast<u64x2 * ABSL_RANDOM_INTERNAL_RESTRICT>(state_void);
+  const auto* seed =
+      reinterpret_cast<const u64x2 * ABSL_RANDOM_INTERNAL_RESTRICT>(seed_void);
 
-  static_assert(kCapacityBlocks * sizeof(Vector128) == kCapacityBytes,
-                "Not i*V");
-  static_assert(kCapacityBlocks == 1, "Unexpected Randen kCapacityBlocks");
-  static_assert(kStateBlocks == 16, "Unexpected Randen kStateBlocks");
+  Vector128 b1 = Vector128Load(state + 1);
+  b1 ^= Vector128Load(seed + 0);
+  Vector128Store(b1, state + 1);
 
-  Vector128 b1 = Vector128Load(state + kLanes * 1);
-  b1 ^= Vector128Load(seed + kLanes * 0);
-  Vector128Store(b1, state + kLanes * 1);
+  Vector128 b2 = Vector128Load(state + 2);
+  b2 ^= Vector128Load(seed + 1);
+  Vector128Store(b2, state + 2);
 
-  Vector128 b2 = Vector128Load(state + kLanes * 2);
-  b2 ^= Vector128Load(seed + kLanes * 1);
-  Vector128Store(b2, state + kLanes * 2);
+  Vector128 b3 = Vector128Load(state + 3);
+  b3 ^= Vector128Load(seed + 2);
+  Vector128Store(b3, state + 3);
 
-  Vector128 b3 = Vector128Load(state + kLanes * 3);
-  b3 ^= Vector128Load(seed + kLanes * 2);
-  Vector128Store(b3, state + kLanes * 3);
+  Vector128 b4 = Vector128Load(state + 4);
+  b4 ^= Vector128Load(seed + 3);
+  Vector128Store(b4, state + 4);
 
-  Vector128 b4 = Vector128Load(state + kLanes * 4);
-  b4 ^= Vector128Load(seed + kLanes * 3);
-  Vector128Store(b4, state + kLanes * 4);
+  Vector128 b5 = Vector128Load(state + 5);
+  b5 ^= Vector128Load(seed + 4);
+  Vector128Store(b5, state + 5);
 
-  Vector128 b5 = Vector128Load(state + kLanes * 5);
-  b5 ^= Vector128Load(seed + kLanes * 4);
-  Vector128Store(b5, state + kLanes * 5);
+  Vector128 b6 = Vector128Load(state + 6);
+  b6 ^= Vector128Load(seed + 5);
+  Vector128Store(b6, state + 6);
 
-  Vector128 b6 = Vector128Load(state + kLanes * 6);
-  b6 ^= Vector128Load(seed + kLanes * 5);
-  Vector128Store(b6, state + kLanes * 6);
+  Vector128 b7 = Vector128Load(state + 7);
+  b7 ^= Vector128Load(seed + 6);
+  Vector128Store(b7, state + 7);
 
-  Vector128 b7 = Vector128Load(state + kLanes * 7);
-  b7 ^= Vector128Load(seed + kLanes * 6);
-  Vector128Store(b7, state + kLanes * 7);
+  Vector128 b8 = Vector128Load(state + 8);
+  b8 ^= Vector128Load(seed + 7);
+  Vector128Store(b8, state + 8);
 
-  Vector128 b8 = Vector128Load(state + kLanes * 8);
-  b8 ^= Vector128Load(seed + kLanes * 7);
-  Vector128Store(b8, state + kLanes * 8);
+  Vector128 b9 = Vector128Load(state + 9);
+  b9 ^= Vector128Load(seed + 8);
+  Vector128Store(b9, state + 9);
 
-  Vector128 b9 = Vector128Load(state + kLanes * 9);
-  b9 ^= Vector128Load(seed + kLanes * 8);
-  Vector128Store(b9, state + kLanes * 9);
+  Vector128 b10 = Vector128Load(state + 10);
+  b10 ^= Vector128Load(seed + 9);
+  Vector128Store(b10, state + 10);
 
-  Vector128 b10 = Vector128Load(state + kLanes * 10);
-  b10 ^= Vector128Load(seed + kLanes * 9);
-  Vector128Store(b10, state + kLanes * 10);
+  Vector128 b11 = Vector128Load(state + 11);
+  b11 ^= Vector128Load(seed + 10);
+  Vector128Store(b11, state + 11);
 
-  Vector128 b11 = Vector128Load(state + kLanes * 11);
-  b11 ^= Vector128Load(seed + kLanes * 10);
-  Vector128Store(b11, state + kLanes * 11);
+  Vector128 b12 = Vector128Load(state + 12);
+  b12 ^= Vector128Load(seed + 11);
+  Vector128Store(b12, state + 12);
 
-  Vector128 b12 = Vector128Load(state + kLanes * 12);
-  b12 ^= Vector128Load(seed + kLanes * 11);
-  Vector128Store(b12, state + kLanes * 12);
+  Vector128 b13 = Vector128Load(state + 13);
+  b13 ^= Vector128Load(seed + 12);
+  Vector128Store(b13, state + 13);
 
-  Vector128 b13 = Vector128Load(state + kLanes * 13);
-  b13 ^= Vector128Load(seed + kLanes * 12);
-  Vector128Store(b13, state + kLanes * 13);
+  Vector128 b14 = Vector128Load(state + 14);
+  b14 ^= Vector128Load(seed + 13);
+  Vector128Store(b14, state + 14);
 
-  Vector128 b14 = Vector128Load(state + kLanes * 14);
-  b14 ^= Vector128Load(seed + kLanes * 13);
-  Vector128Store(b14, state + kLanes * 14);
-
-  Vector128 b15 = Vector128Load(state + kLanes * 15);
-  b15 ^= Vector128Load(seed + kLanes * 14);
-  Vector128Store(b15, state + kLanes * 15);
+  Vector128 b15 = Vector128Load(state + 15);
+  b15 ^= Vector128Load(seed + 14);
+  Vector128Store(b15, state + 15);
 }
 
 // NOLINTNEXTLINE
-void ABSL_TARGET_CRYPTO RandenHwAes::Generate(const void* keys,
+void ABSL_TARGET_CRYPTO RandenHwAes::Generate(const void* keys_void,
                                               void* state_void) {
-  static_assert(kCapacityBytes == sizeof(Vector128), "Capacity mismatch");
+  static_assert(RandenTraits::kCapacityBytes == sizeof(Vector128),
+                "Capacity mismatch");
 
-  auto* state = static_cast<uint64_t*>(state_void);
+  auto* state = reinterpret_cast<u64x2*>(state_void);
+  const auto* keys = reinterpret_cast<const u64x2*>(keys_void);
 
   const Vector128 prev_inner = Vector128Load(state);
 
   SwapEndian(state);
 
-  Permute(keys, state);
+  Permute(state, keys);
 
   SwapEndian(state);
 
diff --git a/absl/random/internal/randen_hwaes.h b/absl/random/internal/randen_hwaes.h
index bce36b5..71a7f69 100644
--- a/absl/random/internal/randen_hwaes.h
+++ b/absl/random/internal/randen_hwaes.h
@@ -26,7 +26,7 @@
 ABSL_NAMESPACE_BEGIN
 namespace random_internal {
 
-// RANDen = RANDom generator or beetroots in Swiss German.
+// RANDen = RANDom generator or beetroots in Swiss High German.
 // 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
 // generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
 //
diff --git a/absl/random/internal/randen_hwaes_test.cc b/absl/random/internal/randen_hwaes_test.cc
index a7cbd46..66ddb43 100644
--- a/absl/random/internal/randen_hwaes_test.cc
+++ b/absl/random/internal/randen_hwaes_test.cc
@@ -27,12 +27,14 @@
 using absl::random_internal::RandenHwAes;
 using absl::random_internal::RandenTraits;
 
-struct randen {
-  static constexpr size_t kStateSizeT =
-      RandenTraits::kStateBytes / sizeof(uint64_t);
+// Local state parameters.
+constexpr size_t kSeedBytes =
+    RandenTraits::kStateBytes - RandenTraits::kCapacityBytes;
+constexpr size_t kStateSizeT = RandenTraits::kStateBytes / sizeof(uint64_t);
+constexpr size_t kSeedSizeT = kSeedBytes / sizeof(uint32_t);
+
+struct alignas(16) randen {
   uint64_t state[kStateSizeT];
-  static constexpr size_t kSeedSizeT =
-      RandenTraits::kSeedBytes / sizeof(uint32_t);
   uint32_t seed[kSeedSizeT];
 };
 
diff --git a/absl/random/internal/randen_round_keys.cc b/absl/random/internal/randen_round_keys.cc
new file mode 100644
index 0000000..5fb3ca5
--- /dev/null
+++ b/absl/random/internal/randen_round_keys.cc
@@ -0,0 +1,462 @@
+// 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/random/internal/randen_traits.h"
+
+// This file contains only the round keys for randen.
+//
+// "Nothing up my sleeve" numbers from the first hex digits of Pi, obtained
+// from http://hexpi.sourceforge.net/. The array was generated by following
+// Python script:
+
+/*
+python >tmp.cc << EOF
+"""Generates Randen round keys array from pi-hex.62500.txt file."""
+import binascii
+
+KEYS = 17 * 8
+
+def chunks(l, n):
+    """Yield successive n-sized chunks from l."""
+    for i in range(0, len(l), n):
+        yield l[i:i + n]
+
+def pairwise(t):
+    """Transforms sequence into sequence of pairs."""
+    it = iter(t)
+    return zip(it,it)
+
+def digits_from_pi():
+  """Reads digits from hexpi.sourceforge.net file."""
+  with open("pi-hex.62500.txt") as file:
+    return file.read()
+
+def digits_from_urandom():
+  """Reads digits from /dev/urandom."""
+  with open("/dev/urandom") as file:
+    return binascii.hexlify(file.read(KEYS * 16))
+
+def print_row(b)
+  print("  0x{0}, 0x{1}, 0x{2}, 0x{3}, 0x{4}, 0x{5}, 0x{6}, 0x{7}, 0x{8}, 0x{9},
+0x{10}, 0x{11}, 0x{12}, 0x{13}, 0x{14}, 0x{15},".format(*b))
+
+
+digits = digits_from_pi()
+#digits = digits_from_urandom()
+
+print("namespace {")
+print("static constexpr size_t kKeyBytes = {0};\n".format(KEYS * 16))
+print("}")
+
+print("alignas(16) const unsigned char kRandenRoundKeysBE[kKeyBytes] = {")
+
+for i, u16 in zip(range(KEYS), chunks(digits, 32)):
+  b = list(chunks(u16, 2))
+  print_row(b)
+
+print("};")
+
+print("alignas(16) const unsigned char kRandenRoundKeys[kKeyBytes] = {")
+
+for i, u16 in zip(range(KEYS), chunks(digits, 32)):
+  b = list(chunks(u16, 2))
+  b.reverse()
+  print_row(b)
+
+print("};")
+
+EOF
+
+*/
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace random_internal {
+namespace {
+static constexpr size_t kKeyBytes = 2176;
+}
+
+alignas(16) const unsigned char kRandenRoundKeysBE[kKeyBytes] = {
+    0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, 0x13, 0x19, 0x8A, 0x2E,
+    0x03, 0x70, 0x73, 0x44, 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
+    0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89, 0x45, 0x28, 0x21, 0xE6,
+    0x38, 0xD0, 0x13, 0x77, 0xBE, 0x54, 0x66, 0xCF, 0x34, 0xE9, 0x0C, 0x6C,
+    0xC0, 0xAC, 0x29, 0xB7, 0xC9, 0x7C, 0x50, 0xDD, 0x3F, 0x84, 0xD5, 0xB5,
+    0xB5, 0x47, 0x09, 0x17, 0x92, 0x16, 0xD5, 0xD9, 0x89, 0x79, 0xFB, 0x1B,
+    0xD1, 0x31, 0x0B, 0xA6, 0x98, 0xDF, 0xB5, 0xAC, 0x2F, 0xFD, 0x72, 0xDB,
+    0xD0, 0x1A, 0xDF, 0xB7, 0xB8, 0xE1, 0xAF, 0xED, 0x6A, 0x26, 0x7E, 0x96,
+    0xBA, 0x7C, 0x90, 0x45, 0xF1, 0x2C, 0x7F, 0x99, 0x24, 0xA1, 0x99, 0x47,
+    0xB3, 0x91, 0x6C, 0xF7, 0x08, 0x01, 0xF2, 0xE2, 0x85, 0x8E, 0xFC, 0x16,
+    0x63, 0x69, 0x20, 0xD8, 0x71, 0x57, 0x4E, 0x69, 0xA4, 0x58, 0xFE, 0xA3,
+    0xF4, 0x93, 0x3D, 0x7E, 0x0D, 0x95, 0x74, 0x8F, 0x72, 0x8E, 0xB6, 0x58,
+    0x71, 0x8B, 0xCD, 0x58, 0x82, 0x15, 0x4A, 0xEE, 0x7B, 0x54, 0xA4, 0x1D,
+    0xC2, 0x5A, 0x59, 0xB5, 0x9C, 0x30, 0xD5, 0x39, 0x2A, 0xF2, 0x60, 0x13,
+    0xC5, 0xD1, 0xB0, 0x23, 0x28, 0x60, 0x85, 0xF0, 0xCA, 0x41, 0x79, 0x18,
+    0xB8, 0xDB, 0x38, 0xEF, 0x8E, 0x79, 0xDC, 0xB0, 0x60, 0x3A, 0x18, 0x0E,
+    0x6C, 0x9E, 0x0E, 0x8B, 0xB0, 0x1E, 0x8A, 0x3E, 0xD7, 0x15, 0x77, 0xC1,
+    0xBD, 0x31, 0x4B, 0x27, 0x78, 0xAF, 0x2F, 0xDA, 0x55, 0x60, 0x5C, 0x60,
+    0xE6, 0x55, 0x25, 0xF3, 0xAA, 0x55, 0xAB, 0x94, 0x57, 0x48, 0x98, 0x62,
+    0x63, 0xE8, 0x14, 0x40, 0x55, 0xCA, 0x39, 0x6A, 0x2A, 0xAB, 0x10, 0xB6,
+    0xB4, 0xCC, 0x5C, 0x34, 0x11, 0x41, 0xE8, 0xCE, 0xA1, 0x54, 0x86, 0xAF,
+    0x7C, 0x72, 0xE9, 0x93, 0xB3, 0xEE, 0x14, 0x11, 0x63, 0x6F, 0xBC, 0x2A,
+    0x2B, 0xA9, 0xC5, 0x5D, 0x74, 0x18, 0x31, 0xF6, 0xCE, 0x5C, 0x3E, 0x16,
+    0x9B, 0x87, 0x93, 0x1E, 0xAF, 0xD6, 0xBA, 0x33, 0x6C, 0x24, 0xCF, 0x5C,
+    0x7A, 0x32, 0x53, 0x81, 0x28, 0x95, 0x86, 0x77, 0x3B, 0x8F, 0x48, 0x98,
+    0x6B, 0x4B, 0xB9, 0xAF, 0xC4, 0xBF, 0xE8, 0x1B, 0x66, 0x28, 0x21, 0x93,
+    0x61, 0xD8, 0x09, 0xCC, 0xFB, 0x21, 0xA9, 0x91, 0x48, 0x7C, 0xAC, 0x60,
+    0x5D, 0xEC, 0x80, 0x32, 0xEF, 0x84, 0x5D, 0x5D, 0xE9, 0x85, 0x75, 0xB1,
+    0xDC, 0x26, 0x23, 0x02, 0xEB, 0x65, 0x1B, 0x88, 0x23, 0x89, 0x3E, 0x81,
+    0xD3, 0x96, 0xAC, 0xC5, 0x0F, 0x6D, 0x6F, 0xF3, 0x83, 0xF4, 0x42, 0x39,
+    0x2E, 0x0B, 0x44, 0x82, 0xA4, 0x84, 0x20, 0x04, 0x69, 0xC8, 0xF0, 0x4A,
+    0x9E, 0x1F, 0x9B, 0x5E, 0x21, 0xC6, 0x68, 0x42, 0xF6, 0xE9, 0x6C, 0x9A,
+    0x67, 0x0C, 0x9C, 0x61, 0xAB, 0xD3, 0x88, 0xF0, 0x6A, 0x51, 0xA0, 0xD2,
+    0xD8, 0x54, 0x2F, 0x68, 0x96, 0x0F, 0xA7, 0x28, 0xAB, 0x51, 0x33, 0xA3,
+    0x6E, 0xEF, 0x0B, 0x6C, 0x13, 0x7A, 0x3B, 0xE4, 0xBA, 0x3B, 0xF0, 0x50,
+    0x7E, 0xFB, 0x2A, 0x98, 0xA1, 0xF1, 0x65, 0x1D, 0x39, 0xAF, 0x01, 0x76,
+    0x66, 0xCA, 0x59, 0x3E, 0x82, 0x43, 0x0E, 0x88, 0x8C, 0xEE, 0x86, 0x19,
+    0x45, 0x6F, 0x9F, 0xB4, 0x7D, 0x84, 0xA5, 0xC3, 0x3B, 0x8B, 0x5E, 0xBE,
+    0xE0, 0x6F, 0x75, 0xD8, 0x85, 0xC1, 0x20, 0x73, 0x40, 0x1A, 0x44, 0x9F,
+    0x56, 0xC1, 0x6A, 0xA6, 0x4E, 0xD3, 0xAA, 0x62, 0x36, 0x3F, 0x77, 0x06,
+    0x1B, 0xFE, 0xDF, 0x72, 0x42, 0x9B, 0x02, 0x3D, 0x37, 0xD0, 0xD7, 0x24,
+    0xD0, 0x0A, 0x12, 0x48, 0xDB, 0x0F, 0xEA, 0xD3, 0x49, 0xF1, 0xC0, 0x9B,
+    0x07, 0x53, 0x72, 0xC9, 0x80, 0x99, 0x1B, 0x7B, 0x25, 0xD4, 0x79, 0xD8,
+    0xF6, 0xE8, 0xDE, 0xF7, 0xE3, 0xFE, 0x50, 0x1A, 0xB6, 0x79, 0x4C, 0x3B,
+    0x97, 0x6C, 0xE0, 0xBD, 0x04, 0xC0, 0x06, 0xBA, 0xC1, 0xA9, 0x4F, 0xB6,
+    0x40, 0x9F, 0x60, 0xC4, 0x5E, 0x5C, 0x9E, 0xC2, 0x19, 0x6A, 0x24, 0x63,
+    0x68, 0xFB, 0x6F, 0xAF, 0x3E, 0x6C, 0x53, 0xB5, 0x13, 0x39, 0xB2, 0xEB,
+    0x3B, 0x52, 0xEC, 0x6F, 0x6D, 0xFC, 0x51, 0x1F, 0x9B, 0x30, 0x95, 0x2C,
+    0xCC, 0x81, 0x45, 0x44, 0xAF, 0x5E, 0xBD, 0x09, 0xBE, 0xE3, 0xD0, 0x04,
+    0xDE, 0x33, 0x4A, 0xFD, 0x66, 0x0F, 0x28, 0x07, 0x19, 0x2E, 0x4B, 0xB3,
+    0xC0, 0xCB, 0xA8, 0x57, 0x45, 0xC8, 0x74, 0x0F, 0xD2, 0x0B, 0x5F, 0x39,
+    0xB9, 0xD3, 0xFB, 0xDB, 0x55, 0x79, 0xC0, 0xBD, 0x1A, 0x60, 0x32, 0x0A,
+    0xD6, 0xA1, 0x00, 0xC6, 0x40, 0x2C, 0x72, 0x79, 0x67, 0x9F, 0x25, 0xFE,
+    0xFB, 0x1F, 0xA3, 0xCC, 0x8E, 0xA5, 0xE9, 0xF8, 0xDB, 0x32, 0x22, 0xF8,
+    0x3C, 0x75, 0x16, 0xDF, 0xFD, 0x61, 0x6B, 0x15, 0x2F, 0x50, 0x1E, 0xC8,
+    0xAD, 0x05, 0x52, 0xAB, 0x32, 0x3D, 0xB5, 0xFA, 0xFD, 0x23, 0x87, 0x60,
+    0x53, 0x31, 0x7B, 0x48, 0x3E, 0x00, 0xDF, 0x82, 0x9E, 0x5C, 0x57, 0xBB,
+    0xCA, 0x6F, 0x8C, 0xA0, 0x1A, 0x87, 0x56, 0x2E, 0xDF, 0x17, 0x69, 0xDB,
+    0xD5, 0x42, 0xA8, 0xF6, 0x28, 0x7E, 0xFF, 0xC3, 0xAC, 0x67, 0x32, 0xC6,
+    0x8C, 0x4F, 0x55, 0x73, 0x69, 0x5B, 0x27, 0xB0, 0xBB, 0xCA, 0x58, 0xC8,
+    0xE1, 0xFF, 0xA3, 0x5D, 0xB8, 0xF0, 0x11, 0xA0, 0x10, 0xFA, 0x3D, 0x98,
+    0xFD, 0x21, 0x83, 0xB8, 0x4A, 0xFC, 0xB5, 0x6C, 0x2D, 0xD1, 0xD3, 0x5B,
+    0x9A, 0x53, 0xE4, 0x79, 0xB6, 0xF8, 0x45, 0x65, 0xD2, 0x8E, 0x49, 0xBC,
+    0x4B, 0xFB, 0x97, 0x90, 0xE1, 0xDD, 0xF2, 0xDA, 0xA4, 0xCB, 0x7E, 0x33,
+    0x62, 0xFB, 0x13, 0x41, 0xCE, 0xE4, 0xC6, 0xE8, 0xEF, 0x20, 0xCA, 0xDA,
+    0x36, 0x77, 0x4C, 0x01, 0xD0, 0x7E, 0x9E, 0xFE, 0x2B, 0xF1, 0x1F, 0xB4,
+    0x95, 0xDB, 0xDA, 0x4D, 0xAE, 0x90, 0x91, 0x98, 0xEA, 0xAD, 0x8E, 0x71,
+    0x6B, 0x93, 0xD5, 0xA0, 0xD0, 0x8E, 0xD1, 0xD0, 0xAF, 0xC7, 0x25, 0xE0,
+    0x8E, 0x3C, 0x5B, 0x2F, 0x8E, 0x75, 0x94, 0xB7, 0x8F, 0xF6, 0xE2, 0xFB,
+    0xF2, 0x12, 0x2B, 0x64, 0x88, 0x88, 0xB8, 0x12, 0x90, 0x0D, 0xF0, 0x1C,
+    0x4F, 0xAD, 0x5E, 0xA0, 0x68, 0x8F, 0xC3, 0x1C, 0xD1, 0xCF, 0xF1, 0x91,
+    0xB3, 0xA8, 0xC1, 0xAD, 0x2F, 0x2F, 0x22, 0x18, 0xBE, 0x0E, 0x17, 0x77,
+    0xEA, 0x75, 0x2D, 0xFE, 0x8B, 0x02, 0x1F, 0xA1, 0xE5, 0xA0, 0xCC, 0x0F,
+    0xB5, 0x6F, 0x74, 0xE8, 0x18, 0xAC, 0xF3, 0xD6, 0xCE, 0x89, 0xE2, 0x99,
+    0xB4, 0xA8, 0x4F, 0xE0, 0xFD, 0x13, 0xE0, 0xB7, 0x7C, 0xC4, 0x3B, 0x81,
+    0xD2, 0xAD, 0xA8, 0xD9, 0x16, 0x5F, 0xA2, 0x66, 0x80, 0x95, 0x77, 0x05,
+    0x93, 0xCC, 0x73, 0x14, 0x21, 0x1A, 0x14, 0x77, 0xE6, 0xAD, 0x20, 0x65,
+    0x77, 0xB5, 0xFA, 0x86, 0xC7, 0x54, 0x42, 0xF5, 0xFB, 0x9D, 0x35, 0xCF,
+    0xEB, 0xCD, 0xAF, 0x0C, 0x7B, 0x3E, 0x89, 0xA0, 0xD6, 0x41, 0x1B, 0xD3,
+    0xAE, 0x1E, 0x7E, 0x49, 0x00, 0x25, 0x0E, 0x2D, 0x20, 0x71, 0xB3, 0x5E,
+    0x22, 0x68, 0x00, 0xBB, 0x57, 0xB8, 0xE0, 0xAF, 0x24, 0x64, 0x36, 0x9B,
+    0xF0, 0x09, 0xB9, 0x1E, 0x55, 0x63, 0x91, 0x1D, 0x59, 0xDF, 0xA6, 0xAA,
+    0x78, 0xC1, 0x43, 0x89, 0xD9, 0x5A, 0x53, 0x7F, 0x20, 0x7D, 0x5B, 0xA2,
+    0x02, 0xE5, 0xB9, 0xC5, 0x83, 0x26, 0x03, 0x76, 0x62, 0x95, 0xCF, 0xA9,
+    0x11, 0xC8, 0x19, 0x68, 0x4E, 0x73, 0x4A, 0x41, 0xB3, 0x47, 0x2D, 0xCA,
+    0x7B, 0x14, 0xA9, 0x4A, 0x1B, 0x51, 0x00, 0x52, 0x9A, 0x53, 0x29, 0x15,
+    0xD6, 0x0F, 0x57, 0x3F, 0xBC, 0x9B, 0xC6, 0xE4, 0x2B, 0x60, 0xA4, 0x76,
+    0x81, 0xE6, 0x74, 0x00, 0x08, 0xBA, 0x6F, 0xB5, 0x57, 0x1B, 0xE9, 0x1F,
+    0xF2, 0x96, 0xEC, 0x6B, 0x2A, 0x0D, 0xD9, 0x15, 0xB6, 0x63, 0x65, 0x21,
+    0xE7, 0xB9, 0xF9, 0xB6, 0xFF, 0x34, 0x05, 0x2E, 0xC5, 0x85, 0x56, 0x64,
+    0x53, 0xB0, 0x2D, 0x5D, 0xA9, 0x9F, 0x8F, 0xA1, 0x08, 0xBA, 0x47, 0x99,
+    0x6E, 0x85, 0x07, 0x6A, 0x4B, 0x7A, 0x70, 0xE9, 0xB5, 0xB3, 0x29, 0x44,
+    0xDB, 0x75, 0x09, 0x2E, 0xC4, 0x19, 0x26, 0x23, 0xAD, 0x6E, 0xA6, 0xB0,
+    0x49, 0xA7, 0xDF, 0x7D, 0x9C, 0xEE, 0x60, 0xB8, 0x8F, 0xED, 0xB2, 0x66,
+    0xEC, 0xAA, 0x8C, 0x71, 0x69, 0x9A, 0x18, 0xFF, 0x56, 0x64, 0x52, 0x6C,
+    0xC2, 0xB1, 0x9E, 0xE1, 0x19, 0x36, 0x02, 0xA5, 0x75, 0x09, 0x4C, 0x29,
+    0xA0, 0x59, 0x13, 0x40, 0xE4, 0x18, 0x3A, 0x3E, 0x3F, 0x54, 0x98, 0x9A,
+    0x5B, 0x42, 0x9D, 0x65, 0x6B, 0x8F, 0xE4, 0xD6, 0x99, 0xF7, 0x3F, 0xD6,
+    0xA1, 0xD2, 0x9C, 0x07, 0xEF, 0xE8, 0x30, 0xF5, 0x4D, 0x2D, 0x38, 0xE6,
+    0xF0, 0x25, 0x5D, 0xC1, 0x4C, 0xDD, 0x20, 0x86, 0x84, 0x70, 0xEB, 0x26,
+    0x63, 0x82, 0xE9, 0xC6, 0x02, 0x1E, 0xCC, 0x5E, 0x09, 0x68, 0x6B, 0x3F,
+    0x3E, 0xBA, 0xEF, 0xC9, 0x3C, 0x97, 0x18, 0x14, 0x6B, 0x6A, 0x70, 0xA1,
+    0x68, 0x7F, 0x35, 0x84, 0x52, 0xA0, 0xE2, 0x86, 0xB7, 0x9C, 0x53, 0x05,
+    0xAA, 0x50, 0x07, 0x37, 0x3E, 0x07, 0x84, 0x1C, 0x7F, 0xDE, 0xAE, 0x5C,
+    0x8E, 0x7D, 0x44, 0xEC, 0x57, 0x16, 0xF2, 0xB8, 0xB0, 0x3A, 0xDA, 0x37,
+    0xF0, 0x50, 0x0C, 0x0D, 0xF0, 0x1C, 0x1F, 0x04, 0x02, 0x00, 0xB3, 0xFF,
+    0xAE, 0x0C, 0xF5, 0x1A, 0x3C, 0xB5, 0x74, 0xB2, 0x25, 0x83, 0x7A, 0x58,
+    0xDC, 0x09, 0x21, 0xBD, 0xD1, 0x91, 0x13, 0xF9, 0x7C, 0xA9, 0x2F, 0xF6,
+    0x94, 0x32, 0x47, 0x73, 0x22, 0xF5, 0x47, 0x01, 0x3A, 0xE5, 0xE5, 0x81,
+    0x37, 0xC2, 0xDA, 0xDC, 0xC8, 0xB5, 0x76, 0x34, 0x9A, 0xF3, 0xDD, 0xA7,
+    0xA9, 0x44, 0x61, 0x46, 0x0F, 0xD0, 0x03, 0x0E, 0xEC, 0xC8, 0xC7, 0x3E,
+    0xA4, 0x75, 0x1E, 0x41, 0xE2, 0x38, 0xCD, 0x99, 0x3B, 0xEA, 0x0E, 0x2F,
+    0x32, 0x80, 0xBB, 0xA1, 0x18, 0x3E, 0xB3, 0x31, 0x4E, 0x54, 0x8B, 0x38,
+    0x4F, 0x6D, 0xB9, 0x08, 0x6F, 0x42, 0x0D, 0x03, 0xF6, 0x0A, 0x04, 0xBF,
+    0x2C, 0xB8, 0x12, 0x90, 0x24, 0x97, 0x7C, 0x79, 0x56, 0x79, 0xB0, 0x72,
+    0xBC, 0xAF, 0x89, 0xAF, 0xDE, 0x9A, 0x77, 0x1F, 0xD9, 0x93, 0x08, 0x10,
+    0xB3, 0x8B, 0xAE, 0x12, 0xDC, 0xCF, 0x3F, 0x2E, 0x55, 0x12, 0x72, 0x1F,
+    0x2E, 0x6B, 0x71, 0x24, 0x50, 0x1A, 0xDD, 0xE6, 0x9F, 0x84, 0xCD, 0x87,
+    0x7A, 0x58, 0x47, 0x18, 0x74, 0x08, 0xDA, 0x17, 0xBC, 0x9F, 0x9A, 0xBC,
+    0xE9, 0x4B, 0x7D, 0x8C, 0xEC, 0x7A, 0xEC, 0x3A, 0xDB, 0x85, 0x1D, 0xFA,
+    0x63, 0x09, 0x43, 0x66, 0xC4, 0x64, 0xC3, 0xD2, 0xEF, 0x1C, 0x18, 0x47,
+    0x32, 0x15, 0xD8, 0x08, 0xDD, 0x43, 0x3B, 0x37, 0x24, 0xC2, 0xBA, 0x16,
+    0x12, 0xA1, 0x4D, 0x43, 0x2A, 0x65, 0xC4, 0x51, 0x50, 0x94, 0x00, 0x02,
+    0x13, 0x3A, 0xE4, 0xDD, 0x71, 0xDF, 0xF8, 0x9E, 0x10, 0x31, 0x4E, 0x55,
+    0x81, 0xAC, 0x77, 0xD6, 0x5F, 0x11, 0x19, 0x9B, 0x04, 0x35, 0x56, 0xF1,
+    0xD7, 0xA3, 0xC7, 0x6B, 0x3C, 0x11, 0x18, 0x3B, 0x59, 0x24, 0xA5, 0x09,
+    0xF2, 0x8F, 0xE6, 0xED, 0x97, 0xF1, 0xFB, 0xFA, 0x9E, 0xBA, 0xBF, 0x2C,
+    0x1E, 0x15, 0x3C, 0x6E, 0x86, 0xE3, 0x45, 0x70, 0xEA, 0xE9, 0x6F, 0xB1,
+    0x86, 0x0E, 0x5E, 0x0A, 0x5A, 0x3E, 0x2A, 0xB3, 0x77, 0x1F, 0xE7, 0x1C,
+    0x4E, 0x3D, 0x06, 0xFA, 0x29, 0x65, 0xDC, 0xB9, 0x99, 0xE7, 0x1D, 0x0F,
+    0x80, 0x3E, 0x89, 0xD6, 0x52, 0x66, 0xC8, 0x25, 0x2E, 0x4C, 0xC9, 0x78,
+    0x9C, 0x10, 0xB3, 0x6A, 0xC6, 0x15, 0x0E, 0xBA, 0x94, 0xE2, 0xEA, 0x78,
+    0xA6, 0xFC, 0x3C, 0x53, 0x1E, 0x0A, 0x2D, 0xF4, 0xF2, 0xF7, 0x4E, 0xA7,
+    0x36, 0x1D, 0x2B, 0x3D, 0x19, 0x39, 0x26, 0x0F, 0x19, 0xC2, 0x79, 0x60,
+    0x52, 0x23, 0xA7, 0x08, 0xF7, 0x13, 0x12, 0xB6, 0xEB, 0xAD, 0xFE, 0x6E,
+    0xEA, 0xC3, 0x1F, 0x66, 0xE3, 0xBC, 0x45, 0x95, 0xA6, 0x7B, 0xC8, 0x83,
+    0xB1, 0x7F, 0x37, 0xD1, 0x01, 0x8C, 0xFF, 0x28, 0xC3, 0x32, 0xDD, 0xEF,
+    0xBE, 0x6C, 0x5A, 0xA5, 0x65, 0x58, 0x21, 0x85, 0x68, 0xAB, 0x97, 0x02,
+    0xEE, 0xCE, 0xA5, 0x0F, 0xDB, 0x2F, 0x95, 0x3B, 0x2A, 0xEF, 0x7D, 0xAD,
+    0x5B, 0x6E, 0x2F, 0x84, 0x15, 0x21, 0xB6, 0x28, 0x29, 0x07, 0x61, 0x70,
+    0xEC, 0xDD, 0x47, 0x75, 0x61, 0x9F, 0x15, 0x10, 0x13, 0xCC, 0xA8, 0x30,
+    0xEB, 0x61, 0xBD, 0x96, 0x03, 0x34, 0xFE, 0x1E, 0xAA, 0x03, 0x63, 0xCF,
+    0xB5, 0x73, 0x5C, 0x90, 0x4C, 0x70, 0xA2, 0x39, 0xD5, 0x9E, 0x9E, 0x0B,
+    0xCB, 0xAA, 0xDE, 0x14, 0xEE, 0xCC, 0x86, 0xBC, 0x60, 0x62, 0x2C, 0xA7,
+    0x9C, 0xAB, 0x5C, 0xAB, 0xB2, 0xF3, 0x84, 0x6E, 0x64, 0x8B, 0x1E, 0xAF,
+    0x19, 0xBD, 0xF0, 0xCA, 0xA0, 0x23, 0x69, 0xB9, 0x65, 0x5A, 0xBB, 0x50,
+    0x40, 0x68, 0x5A, 0x32, 0x3C, 0x2A, 0xB4, 0xB3, 0x31, 0x9E, 0xE9, 0xD5,
+    0xC0, 0x21, 0xB8, 0xF7, 0x9B, 0x54, 0x0B, 0x19, 0x87, 0x5F, 0xA0, 0x99,
+    0x95, 0xF7, 0x99, 0x7E, 0x62, 0x3D, 0x7D, 0xA8, 0xF8, 0x37, 0x88, 0x9A,
+    0x97, 0xE3, 0x2D, 0x77, 0x11, 0xED, 0x93, 0x5F, 0x16, 0x68, 0x12, 0x81,
+    0x0E, 0x35, 0x88, 0x29, 0xC7, 0xE6, 0x1F, 0xD6, 0x96, 0xDE, 0xDF, 0xA1,
+    0x78, 0x58, 0xBA, 0x99, 0x57, 0xF5, 0x84, 0xA5, 0x1B, 0x22, 0x72, 0x63,
+    0x9B, 0x83, 0xC3, 0xFF, 0x1A, 0xC2, 0x46, 0x96, 0xCD, 0xB3, 0x0A, 0xEB,
+    0x53, 0x2E, 0x30, 0x54, 0x8F, 0xD9, 0x48, 0xE4, 0x6D, 0xBC, 0x31, 0x28,
+    0x58, 0xEB, 0xF2, 0xEF, 0x34, 0xC6, 0xFF, 0xEA, 0xFE, 0x28, 0xED, 0x61,
+    0xEE, 0x7C, 0x3C, 0x73, 0x5D, 0x4A, 0x14, 0xD9, 0xE8, 0x64, 0xB7, 0xE3,
+    0x42, 0x10, 0x5D, 0x14, 0x20, 0x3E, 0x13, 0xE0, 0x45, 0xEE, 0xE2, 0xB6,
+    0xA3, 0xAA, 0xAB, 0xEA, 0xDB, 0x6C, 0x4F, 0x15, 0xFA, 0xCB, 0x4F, 0xD0,
+    0xC7, 0x42, 0xF4, 0x42, 0xEF, 0x6A, 0xBB, 0xB5, 0x65, 0x4F, 0x3B, 0x1D,
+    0x41, 0xCD, 0x21, 0x05, 0xD8, 0x1E, 0x79, 0x9E, 0x86, 0x85, 0x4D, 0xC7,
+    0xE4, 0x4B, 0x47, 0x6A, 0x3D, 0x81, 0x62, 0x50, 0xCF, 0x62, 0xA1, 0xF2,
+    0x5B, 0x8D, 0x26, 0x46, 0xFC, 0x88, 0x83, 0xA0, 0xC1, 0xC7, 0xB6, 0xA3,
+    0x7F, 0x15, 0x24, 0xC3, 0x69, 0xCB, 0x74, 0x92, 0x47, 0x84, 0x8A, 0x0B,
+    0x56, 0x92, 0xB2, 0x85, 0x09, 0x5B, 0xBF, 0x00, 0xAD, 0x19, 0x48, 0x9D,
+    0x14, 0x62, 0xB1, 0x74, 0x23, 0x82, 0x0D, 0x00, 0x58, 0x42, 0x8D, 0x2A,
+    0x0C, 0x55, 0xF5, 0xEA, 0x1D, 0xAD, 0xF4, 0x3E, 0x23, 0x3F, 0x70, 0x61,
+    0x33, 0x72, 0xF0, 0x92, 0x8D, 0x93, 0x7E, 0x41, 0xD6, 0x5F, 0xEC, 0xF1,
+    0x6C, 0x22, 0x3B, 0xDB, 0x7C, 0xDE, 0x37, 0x59, 0xCB, 0xEE, 0x74, 0x60,
+    0x40, 0x85, 0xF2, 0xA7, 0xCE, 0x77, 0x32, 0x6E, 0xA6, 0x07, 0x80, 0x84,
+    0x19, 0xF8, 0x50, 0x9E, 0xE8, 0xEF, 0xD8, 0x55, 0x61, 0xD9, 0x97, 0x35,
+    0xA9, 0x69, 0xA7, 0xAA, 0xC5, 0x0C, 0x06, 0xC2, 0x5A, 0x04, 0xAB, 0xFC,
+    0x80, 0x0B, 0xCA, 0xDC, 0x9E, 0x44, 0x7A, 0x2E, 0xC3, 0x45, 0x34, 0x84,
+    0xFD, 0xD5, 0x67, 0x05, 0x0E, 0x1E, 0x9E, 0xC9, 0xDB, 0x73, 0xDB, 0xD3,
+    0x10, 0x55, 0x88, 0xCD, 0x67, 0x5F, 0xDA, 0x79, 0xE3, 0x67, 0x43, 0x40,
+    0xC5, 0xC4, 0x34, 0x65, 0x71, 0x3E, 0x38, 0xD8, 0x3D, 0x28, 0xF8, 0x9E,
+    0xF1, 0x6D, 0xFF, 0x20, 0x15, 0x3E, 0x21, 0xE7, 0x8F, 0xB0, 0x3D, 0x4A,
+    0xE6, 0xE3, 0x9F, 0x2B, 0xDB, 0x83, 0xAD, 0xF7, 0xE9, 0x3D, 0x5A, 0x68,
+    0x94, 0x81, 0x40, 0xF7, 0xF6, 0x4C, 0x26, 0x1C, 0x94, 0x69, 0x29, 0x34,
+    0x41, 0x15, 0x20, 0xF7, 0x76, 0x02, 0xD4, 0xF7, 0xBC, 0xF4, 0x6B, 0x2E,
+    0xD4, 0xA1, 0x00, 0x68, 0xD4, 0x08, 0x24, 0x71, 0x33, 0x20, 0xF4, 0x6A,
+    0x43, 0xB7, 0xD4, 0xB7, 0x50, 0x00, 0x61, 0xAF, 0x1E, 0x39, 0xF6, 0x2E,
+    0x97, 0x24, 0x45, 0x46,
+};
+
+alignas(16) const unsigned char kRandenRoundKeys[kKeyBytes] = {
+    0x44, 0x73, 0x70, 0x03, 0x2E, 0x8A, 0x19, 0x13, 0xD3, 0x08, 0xA3, 0x85,
+    0x88, 0x6A, 0x3F, 0x24, 0x89, 0x6C, 0x4E, 0xEC, 0x98, 0xFA, 0x2E, 0x08,
+    0xD0, 0x31, 0x9F, 0x29, 0x22, 0x38, 0x09, 0xA4, 0x6C, 0x0C, 0xE9, 0x34,
+    0xCF, 0x66, 0x54, 0xBE, 0x77, 0x13, 0xD0, 0x38, 0xE6, 0x21, 0x28, 0x45,
+    0x17, 0x09, 0x47, 0xB5, 0xB5, 0xD5, 0x84, 0x3F, 0xDD, 0x50, 0x7C, 0xC9,
+    0xB7, 0x29, 0xAC, 0xC0, 0xAC, 0xB5, 0xDF, 0x98, 0xA6, 0x0B, 0x31, 0xD1,
+    0x1B, 0xFB, 0x79, 0x89, 0xD9, 0xD5, 0x16, 0x92, 0x96, 0x7E, 0x26, 0x6A,
+    0xED, 0xAF, 0xE1, 0xB8, 0xB7, 0xDF, 0x1A, 0xD0, 0xDB, 0x72, 0xFD, 0x2F,
+    0xF7, 0x6C, 0x91, 0xB3, 0x47, 0x99, 0xA1, 0x24, 0x99, 0x7F, 0x2C, 0xF1,
+    0x45, 0x90, 0x7C, 0xBA, 0x69, 0x4E, 0x57, 0x71, 0xD8, 0x20, 0x69, 0x63,
+    0x16, 0xFC, 0x8E, 0x85, 0xE2, 0xF2, 0x01, 0x08, 0x58, 0xB6, 0x8E, 0x72,
+    0x8F, 0x74, 0x95, 0x0D, 0x7E, 0x3D, 0x93, 0xF4, 0xA3, 0xFE, 0x58, 0xA4,
+    0xB5, 0x59, 0x5A, 0xC2, 0x1D, 0xA4, 0x54, 0x7B, 0xEE, 0x4A, 0x15, 0x82,
+    0x58, 0xCD, 0x8B, 0x71, 0xF0, 0x85, 0x60, 0x28, 0x23, 0xB0, 0xD1, 0xC5,
+    0x13, 0x60, 0xF2, 0x2A, 0x39, 0xD5, 0x30, 0x9C, 0x0E, 0x18, 0x3A, 0x60,
+    0xB0, 0xDC, 0x79, 0x8E, 0xEF, 0x38, 0xDB, 0xB8, 0x18, 0x79, 0x41, 0xCA,
+    0x27, 0x4B, 0x31, 0xBD, 0xC1, 0x77, 0x15, 0xD7, 0x3E, 0x8A, 0x1E, 0xB0,
+    0x8B, 0x0E, 0x9E, 0x6C, 0x94, 0xAB, 0x55, 0xAA, 0xF3, 0x25, 0x55, 0xE6,
+    0x60, 0x5C, 0x60, 0x55, 0xDA, 0x2F, 0xAF, 0x78, 0xB6, 0x10, 0xAB, 0x2A,
+    0x6A, 0x39, 0xCA, 0x55, 0x40, 0x14, 0xE8, 0x63, 0x62, 0x98, 0x48, 0x57,
+    0x93, 0xE9, 0x72, 0x7C, 0xAF, 0x86, 0x54, 0xA1, 0xCE, 0xE8, 0x41, 0x11,
+    0x34, 0x5C, 0xCC, 0xB4, 0xF6, 0x31, 0x18, 0x74, 0x5D, 0xC5, 0xA9, 0x2B,
+    0x2A, 0xBC, 0x6F, 0x63, 0x11, 0x14, 0xEE, 0xB3, 0x5C, 0xCF, 0x24, 0x6C,
+    0x33, 0xBA, 0xD6, 0xAF, 0x1E, 0x93, 0x87, 0x9B, 0x16, 0x3E, 0x5C, 0xCE,
+    0xAF, 0xB9, 0x4B, 0x6B, 0x98, 0x48, 0x8F, 0x3B, 0x77, 0x86, 0x95, 0x28,
+    0x81, 0x53, 0x32, 0x7A, 0x91, 0xA9, 0x21, 0xFB, 0xCC, 0x09, 0xD8, 0x61,
+    0x93, 0x21, 0x28, 0x66, 0x1B, 0xE8, 0xBF, 0xC4, 0xB1, 0x75, 0x85, 0xE9,
+    0x5D, 0x5D, 0x84, 0xEF, 0x32, 0x80, 0xEC, 0x5D, 0x60, 0xAC, 0x7C, 0x48,
+    0xC5, 0xAC, 0x96, 0xD3, 0x81, 0x3E, 0x89, 0x23, 0x88, 0x1B, 0x65, 0xEB,
+    0x02, 0x23, 0x26, 0xDC, 0x04, 0x20, 0x84, 0xA4, 0x82, 0x44, 0x0B, 0x2E,
+    0x39, 0x42, 0xF4, 0x83, 0xF3, 0x6F, 0x6D, 0x0F, 0x9A, 0x6C, 0xE9, 0xF6,
+    0x42, 0x68, 0xC6, 0x21, 0x5E, 0x9B, 0x1F, 0x9E, 0x4A, 0xF0, 0xC8, 0x69,
+    0x68, 0x2F, 0x54, 0xD8, 0xD2, 0xA0, 0x51, 0x6A, 0xF0, 0x88, 0xD3, 0xAB,
+    0x61, 0x9C, 0x0C, 0x67, 0xE4, 0x3B, 0x7A, 0x13, 0x6C, 0x0B, 0xEF, 0x6E,
+    0xA3, 0x33, 0x51, 0xAB, 0x28, 0xA7, 0x0F, 0x96, 0x76, 0x01, 0xAF, 0x39,
+    0x1D, 0x65, 0xF1, 0xA1, 0x98, 0x2A, 0xFB, 0x7E, 0x50, 0xF0, 0x3B, 0xBA,
+    0xB4, 0x9F, 0x6F, 0x45, 0x19, 0x86, 0xEE, 0x8C, 0x88, 0x0E, 0x43, 0x82,
+    0x3E, 0x59, 0xCA, 0x66, 0x73, 0x20, 0xC1, 0x85, 0xD8, 0x75, 0x6F, 0xE0,
+    0xBE, 0x5E, 0x8B, 0x3B, 0xC3, 0xA5, 0x84, 0x7D, 0x06, 0x77, 0x3F, 0x36,
+    0x62, 0xAA, 0xD3, 0x4E, 0xA6, 0x6A, 0xC1, 0x56, 0x9F, 0x44, 0x1A, 0x40,
+    0x48, 0x12, 0x0A, 0xD0, 0x24, 0xD7, 0xD0, 0x37, 0x3D, 0x02, 0x9B, 0x42,
+    0x72, 0xDF, 0xFE, 0x1B, 0x7B, 0x1B, 0x99, 0x80, 0xC9, 0x72, 0x53, 0x07,
+    0x9B, 0xC0, 0xF1, 0x49, 0xD3, 0xEA, 0x0F, 0xDB, 0x3B, 0x4C, 0x79, 0xB6,
+    0x1A, 0x50, 0xFE, 0xE3, 0xF7, 0xDE, 0xE8, 0xF6, 0xD8, 0x79, 0xD4, 0x25,
+    0xC4, 0x60, 0x9F, 0x40, 0xB6, 0x4F, 0xA9, 0xC1, 0xBA, 0x06, 0xC0, 0x04,
+    0xBD, 0xE0, 0x6C, 0x97, 0xB5, 0x53, 0x6C, 0x3E, 0xAF, 0x6F, 0xFB, 0x68,
+    0x63, 0x24, 0x6A, 0x19, 0xC2, 0x9E, 0x5C, 0x5E, 0x2C, 0x95, 0x30, 0x9B,
+    0x1F, 0x51, 0xFC, 0x6D, 0x6F, 0xEC, 0x52, 0x3B, 0xEB, 0xB2, 0x39, 0x13,
+    0xFD, 0x4A, 0x33, 0xDE, 0x04, 0xD0, 0xE3, 0xBE, 0x09, 0xBD, 0x5E, 0xAF,
+    0x44, 0x45, 0x81, 0xCC, 0x0F, 0x74, 0xC8, 0x45, 0x57, 0xA8, 0xCB, 0xC0,
+    0xB3, 0x4B, 0x2E, 0x19, 0x07, 0x28, 0x0F, 0x66, 0x0A, 0x32, 0x60, 0x1A,
+    0xBD, 0xC0, 0x79, 0x55, 0xDB, 0xFB, 0xD3, 0xB9, 0x39, 0x5F, 0x0B, 0xD2,
+    0xCC, 0xA3, 0x1F, 0xFB, 0xFE, 0x25, 0x9F, 0x67, 0x79, 0x72, 0x2C, 0x40,
+    0xC6, 0x00, 0xA1, 0xD6, 0x15, 0x6B, 0x61, 0xFD, 0xDF, 0x16, 0x75, 0x3C,
+    0xF8, 0x22, 0x32, 0xDB, 0xF8, 0xE9, 0xA5, 0x8E, 0x60, 0x87, 0x23, 0xFD,
+    0xFA, 0xB5, 0x3D, 0x32, 0xAB, 0x52, 0x05, 0xAD, 0xC8, 0x1E, 0x50, 0x2F,
+    0xA0, 0x8C, 0x6F, 0xCA, 0xBB, 0x57, 0x5C, 0x9E, 0x82, 0xDF, 0x00, 0x3E,
+    0x48, 0x7B, 0x31, 0x53, 0xC3, 0xFF, 0x7E, 0x28, 0xF6, 0xA8, 0x42, 0xD5,
+    0xDB, 0x69, 0x17, 0xDF, 0x2E, 0x56, 0x87, 0x1A, 0xC8, 0x58, 0xCA, 0xBB,
+    0xB0, 0x27, 0x5B, 0x69, 0x73, 0x55, 0x4F, 0x8C, 0xC6, 0x32, 0x67, 0xAC,
+    0xB8, 0x83, 0x21, 0xFD, 0x98, 0x3D, 0xFA, 0x10, 0xA0, 0x11, 0xF0, 0xB8,
+    0x5D, 0xA3, 0xFF, 0xE1, 0x65, 0x45, 0xF8, 0xB6, 0x79, 0xE4, 0x53, 0x9A,
+    0x5B, 0xD3, 0xD1, 0x2D, 0x6C, 0xB5, 0xFC, 0x4A, 0x33, 0x7E, 0xCB, 0xA4,
+    0xDA, 0xF2, 0xDD, 0xE1, 0x90, 0x97, 0xFB, 0x4B, 0xBC, 0x49, 0x8E, 0xD2,
+    0x01, 0x4C, 0x77, 0x36, 0xDA, 0xCA, 0x20, 0xEF, 0xE8, 0xC6, 0xE4, 0xCE,
+    0x41, 0x13, 0xFB, 0x62, 0x98, 0x91, 0x90, 0xAE, 0x4D, 0xDA, 0xDB, 0x95,
+    0xB4, 0x1F, 0xF1, 0x2B, 0xFE, 0x9E, 0x7E, 0xD0, 0xE0, 0x25, 0xC7, 0xAF,
+    0xD0, 0xD1, 0x8E, 0xD0, 0xA0, 0xD5, 0x93, 0x6B, 0x71, 0x8E, 0xAD, 0xEA,
+    0x64, 0x2B, 0x12, 0xF2, 0xFB, 0xE2, 0xF6, 0x8F, 0xB7, 0x94, 0x75, 0x8E,
+    0x2F, 0x5B, 0x3C, 0x8E, 0x1C, 0xC3, 0x8F, 0x68, 0xA0, 0x5E, 0xAD, 0x4F,
+    0x1C, 0xF0, 0x0D, 0x90, 0x12, 0xB8, 0x88, 0x88, 0x77, 0x17, 0x0E, 0xBE,
+    0x18, 0x22, 0x2F, 0x2F, 0xAD, 0xC1, 0xA8, 0xB3, 0x91, 0xF1, 0xCF, 0xD1,
+    0xE8, 0x74, 0x6F, 0xB5, 0x0F, 0xCC, 0xA0, 0xE5, 0xA1, 0x1F, 0x02, 0x8B,
+    0xFE, 0x2D, 0x75, 0xEA, 0xB7, 0xE0, 0x13, 0xFD, 0xE0, 0x4F, 0xA8, 0xB4,
+    0x99, 0xE2, 0x89, 0xCE, 0xD6, 0xF3, 0xAC, 0x18, 0x05, 0x77, 0x95, 0x80,
+    0x66, 0xA2, 0x5F, 0x16, 0xD9, 0xA8, 0xAD, 0xD2, 0x81, 0x3B, 0xC4, 0x7C,
+    0x86, 0xFA, 0xB5, 0x77, 0x65, 0x20, 0xAD, 0xE6, 0x77, 0x14, 0x1A, 0x21,
+    0x14, 0x73, 0xCC, 0x93, 0xA0, 0x89, 0x3E, 0x7B, 0x0C, 0xAF, 0xCD, 0xEB,
+    0xCF, 0x35, 0x9D, 0xFB, 0xF5, 0x42, 0x54, 0xC7, 0x5E, 0xB3, 0x71, 0x20,
+    0x2D, 0x0E, 0x25, 0x00, 0x49, 0x7E, 0x1E, 0xAE, 0xD3, 0x1B, 0x41, 0xD6,
+    0x1E, 0xB9, 0x09, 0xF0, 0x9B, 0x36, 0x64, 0x24, 0xAF, 0xE0, 0xB8, 0x57,
+    0xBB, 0x00, 0x68, 0x22, 0x7F, 0x53, 0x5A, 0xD9, 0x89, 0x43, 0xC1, 0x78,
+    0xAA, 0xA6, 0xDF, 0x59, 0x1D, 0x91, 0x63, 0x55, 0xA9, 0xCF, 0x95, 0x62,
+    0x76, 0x03, 0x26, 0x83, 0xC5, 0xB9, 0xE5, 0x02, 0xA2, 0x5B, 0x7D, 0x20,
+    0x4A, 0xA9, 0x14, 0x7B, 0xCA, 0x2D, 0x47, 0xB3, 0x41, 0x4A, 0x73, 0x4E,
+    0x68, 0x19, 0xC8, 0x11, 0xE4, 0xC6, 0x9B, 0xBC, 0x3F, 0x57, 0x0F, 0xD6,
+    0x15, 0x29, 0x53, 0x9A, 0x52, 0x00, 0x51, 0x1B, 0x1F, 0xE9, 0x1B, 0x57,
+    0xB5, 0x6F, 0xBA, 0x08, 0x00, 0x74, 0xE6, 0x81, 0x76, 0xA4, 0x60, 0x2B,
+    0xB6, 0xF9, 0xB9, 0xE7, 0x21, 0x65, 0x63, 0xB6, 0x15, 0xD9, 0x0D, 0x2A,
+    0x6B, 0xEC, 0x96, 0xF2, 0xA1, 0x8F, 0x9F, 0xA9, 0x5D, 0x2D, 0xB0, 0x53,
+    0x64, 0x56, 0x85, 0xC5, 0x2E, 0x05, 0x34, 0xFF, 0x44, 0x29, 0xB3, 0xB5,
+    0xE9, 0x70, 0x7A, 0x4B, 0x6A, 0x07, 0x85, 0x6E, 0x99, 0x47, 0xBA, 0x08,
+    0x7D, 0xDF, 0xA7, 0x49, 0xB0, 0xA6, 0x6E, 0xAD, 0x23, 0x26, 0x19, 0xC4,
+    0x2E, 0x09, 0x75, 0xDB, 0xFF, 0x18, 0x9A, 0x69, 0x71, 0x8C, 0xAA, 0xEC,
+    0x66, 0xB2, 0xED, 0x8F, 0xB8, 0x60, 0xEE, 0x9C, 0x29, 0x4C, 0x09, 0x75,
+    0xA5, 0x02, 0x36, 0x19, 0xE1, 0x9E, 0xB1, 0xC2, 0x6C, 0x52, 0x64, 0x56,
+    0x65, 0x9D, 0x42, 0x5B, 0x9A, 0x98, 0x54, 0x3F, 0x3E, 0x3A, 0x18, 0xE4,
+    0x40, 0x13, 0x59, 0xA0, 0xF5, 0x30, 0xE8, 0xEF, 0x07, 0x9C, 0xD2, 0xA1,
+    0xD6, 0x3F, 0xF7, 0x99, 0xD6, 0xE4, 0x8F, 0x6B, 0x26, 0xEB, 0x70, 0x84,
+    0x86, 0x20, 0xDD, 0x4C, 0xC1, 0x5D, 0x25, 0xF0, 0xE6, 0x38, 0x2D, 0x4D,
+    0xC9, 0xEF, 0xBA, 0x3E, 0x3F, 0x6B, 0x68, 0x09, 0x5E, 0xCC, 0x1E, 0x02,
+    0xC6, 0xE9, 0x82, 0x63, 0x86, 0xE2, 0xA0, 0x52, 0x84, 0x35, 0x7F, 0x68,
+    0xA1, 0x70, 0x6A, 0x6B, 0x14, 0x18, 0x97, 0x3C, 0x5C, 0xAE, 0xDE, 0x7F,
+    0x1C, 0x84, 0x07, 0x3E, 0x37, 0x07, 0x50, 0xAA, 0x05, 0x53, 0x9C, 0xB7,
+    0x0D, 0x0C, 0x50, 0xF0, 0x37, 0xDA, 0x3A, 0xB0, 0xB8, 0xF2, 0x16, 0x57,
+    0xEC, 0x44, 0x7D, 0x8E, 0xB2, 0x74, 0xB5, 0x3C, 0x1A, 0xF5, 0x0C, 0xAE,
+    0xFF, 0xB3, 0x00, 0x02, 0x04, 0x1F, 0x1C, 0xF0, 0xF6, 0x2F, 0xA9, 0x7C,
+    0xF9, 0x13, 0x91, 0xD1, 0xBD, 0x21, 0x09, 0xDC, 0x58, 0x7A, 0x83, 0x25,
+    0xDC, 0xDA, 0xC2, 0x37, 0x81, 0xE5, 0xE5, 0x3A, 0x01, 0x47, 0xF5, 0x22,
+    0x73, 0x47, 0x32, 0x94, 0x0E, 0x03, 0xD0, 0x0F, 0x46, 0x61, 0x44, 0xA9,
+    0xA7, 0xDD, 0xF3, 0x9A, 0x34, 0x76, 0xB5, 0xC8, 0x2F, 0x0E, 0xEA, 0x3B,
+    0x99, 0xCD, 0x38, 0xE2, 0x41, 0x1E, 0x75, 0xA4, 0x3E, 0xC7, 0xC8, 0xEC,
+    0x08, 0xB9, 0x6D, 0x4F, 0x38, 0x8B, 0x54, 0x4E, 0x31, 0xB3, 0x3E, 0x18,
+    0xA1, 0xBB, 0x80, 0x32, 0x79, 0x7C, 0x97, 0x24, 0x90, 0x12, 0xB8, 0x2C,
+    0xBF, 0x04, 0x0A, 0xF6, 0x03, 0x0D, 0x42, 0x6F, 0x10, 0x08, 0x93, 0xD9,
+    0x1F, 0x77, 0x9A, 0xDE, 0xAF, 0x89, 0xAF, 0xBC, 0x72, 0xB0, 0x79, 0x56,
+    0x24, 0x71, 0x6B, 0x2E, 0x1F, 0x72, 0x12, 0x55, 0x2E, 0x3F, 0xCF, 0xDC,
+    0x12, 0xAE, 0x8B, 0xB3, 0x17, 0xDA, 0x08, 0x74, 0x18, 0x47, 0x58, 0x7A,
+    0x87, 0xCD, 0x84, 0x9F, 0xE6, 0xDD, 0x1A, 0x50, 0xFA, 0x1D, 0x85, 0xDB,
+    0x3A, 0xEC, 0x7A, 0xEC, 0x8C, 0x7D, 0x4B, 0xE9, 0xBC, 0x9A, 0x9F, 0xBC,
+    0x08, 0xD8, 0x15, 0x32, 0x47, 0x18, 0x1C, 0xEF, 0xD2, 0xC3, 0x64, 0xC4,
+    0x66, 0x43, 0x09, 0x63, 0x51, 0xC4, 0x65, 0x2A, 0x43, 0x4D, 0xA1, 0x12,
+    0x16, 0xBA, 0xC2, 0x24, 0x37, 0x3B, 0x43, 0xDD, 0x55, 0x4E, 0x31, 0x10,
+    0x9E, 0xF8, 0xDF, 0x71, 0xDD, 0xE4, 0x3A, 0x13, 0x02, 0x00, 0x94, 0x50,
+    0x6B, 0xC7, 0xA3, 0xD7, 0xF1, 0x56, 0x35, 0x04, 0x9B, 0x19, 0x11, 0x5F,
+    0xD6, 0x77, 0xAC, 0x81, 0xFA, 0xFB, 0xF1, 0x97, 0xED, 0xE6, 0x8F, 0xF2,
+    0x09, 0xA5, 0x24, 0x59, 0x3B, 0x18, 0x11, 0x3C, 0xB1, 0x6F, 0xE9, 0xEA,
+    0x70, 0x45, 0xE3, 0x86, 0x6E, 0x3C, 0x15, 0x1E, 0x2C, 0xBF, 0xBA, 0x9E,
+    0xFA, 0x06, 0x3D, 0x4E, 0x1C, 0xE7, 0x1F, 0x77, 0xB3, 0x2A, 0x3E, 0x5A,
+    0x0A, 0x5E, 0x0E, 0x86, 0x25, 0xC8, 0x66, 0x52, 0xD6, 0x89, 0x3E, 0x80,
+    0x0F, 0x1D, 0xE7, 0x99, 0xB9, 0xDC, 0x65, 0x29, 0x78, 0xEA, 0xE2, 0x94,
+    0xBA, 0x0E, 0x15, 0xC6, 0x6A, 0xB3, 0x10, 0x9C, 0x78, 0xC9, 0x4C, 0x2E,
+    0x3D, 0x2B, 0x1D, 0x36, 0xA7, 0x4E, 0xF7, 0xF2, 0xF4, 0x2D, 0x0A, 0x1E,
+    0x53, 0x3C, 0xFC, 0xA6, 0xB6, 0x12, 0x13, 0xF7, 0x08, 0xA7, 0x23, 0x52,
+    0x60, 0x79, 0xC2, 0x19, 0x0F, 0x26, 0x39, 0x19, 0x83, 0xC8, 0x7B, 0xA6,
+    0x95, 0x45, 0xBC, 0xE3, 0x66, 0x1F, 0xC3, 0xEA, 0x6E, 0xFE, 0xAD, 0xEB,
+    0xA5, 0x5A, 0x6C, 0xBE, 0xEF, 0xDD, 0x32, 0xC3, 0x28, 0xFF, 0x8C, 0x01,
+    0xD1, 0x37, 0x7F, 0xB1, 0x3B, 0x95, 0x2F, 0xDB, 0x0F, 0xA5, 0xCE, 0xEE,
+    0x02, 0x97, 0xAB, 0x68, 0x85, 0x21, 0x58, 0x65, 0x70, 0x61, 0x07, 0x29,
+    0x28, 0xB6, 0x21, 0x15, 0x84, 0x2F, 0x6E, 0x5B, 0xAD, 0x7D, 0xEF, 0x2A,
+    0x96, 0xBD, 0x61, 0xEB, 0x30, 0xA8, 0xCC, 0x13, 0x10, 0x15, 0x9F, 0x61,
+    0x75, 0x47, 0xDD, 0xEC, 0x39, 0xA2, 0x70, 0x4C, 0x90, 0x5C, 0x73, 0xB5,
+    0xCF, 0x63, 0x03, 0xAA, 0x1E, 0xFE, 0x34, 0x03, 0xA7, 0x2C, 0x62, 0x60,
+    0xBC, 0x86, 0xCC, 0xEE, 0x14, 0xDE, 0xAA, 0xCB, 0x0B, 0x9E, 0x9E, 0xD5,
+    0xCA, 0xF0, 0xBD, 0x19, 0xAF, 0x1E, 0x8B, 0x64, 0x6E, 0x84, 0xF3, 0xB2,
+    0xAB, 0x5C, 0xAB, 0x9C, 0xB3, 0xB4, 0x2A, 0x3C, 0x32, 0x5A, 0x68, 0x40,
+    0x50, 0xBB, 0x5A, 0x65, 0xB9, 0x69, 0x23, 0xA0, 0x99, 0xA0, 0x5F, 0x87,
+    0x19, 0x0B, 0x54, 0x9B, 0xF7, 0xB8, 0x21, 0xC0, 0xD5, 0xE9, 0x9E, 0x31,
+    0x77, 0x2D, 0xE3, 0x97, 0x9A, 0x88, 0x37, 0xF8, 0xA8, 0x7D, 0x3D, 0x62,
+    0x7E, 0x99, 0xF7, 0x95, 0xD6, 0x1F, 0xE6, 0xC7, 0x29, 0x88, 0x35, 0x0E,
+    0x81, 0x12, 0x68, 0x16, 0x5F, 0x93, 0xED, 0x11, 0x63, 0x72, 0x22, 0x1B,
+    0xA5, 0x84, 0xF5, 0x57, 0x99, 0xBA, 0x58, 0x78, 0xA1, 0xDF, 0xDE, 0x96,
+    0x54, 0x30, 0x2E, 0x53, 0xEB, 0x0A, 0xB3, 0xCD, 0x96, 0x46, 0xC2, 0x1A,
+    0xFF, 0xC3, 0x83, 0x9B, 0xEA, 0xFF, 0xC6, 0x34, 0xEF, 0xF2, 0xEB, 0x58,
+    0x28, 0x31, 0xBC, 0x6D, 0xE4, 0x48, 0xD9, 0x8F, 0xE3, 0xB7, 0x64, 0xE8,
+    0xD9, 0x14, 0x4A, 0x5D, 0x73, 0x3C, 0x7C, 0xEE, 0x61, 0xED, 0x28, 0xFE,
+    0xEA, 0xAB, 0xAA, 0xA3, 0xB6, 0xE2, 0xEE, 0x45, 0xE0, 0x13, 0x3E, 0x20,
+    0x14, 0x5D, 0x10, 0x42, 0xB5, 0xBB, 0x6A, 0xEF, 0x42, 0xF4, 0x42, 0xC7,
+    0xD0, 0x4F, 0xCB, 0xFA, 0x15, 0x4F, 0x6C, 0xDB, 0xC7, 0x4D, 0x85, 0x86,
+    0x9E, 0x79, 0x1E, 0xD8, 0x05, 0x21, 0xCD, 0x41, 0x1D, 0x3B, 0x4F, 0x65,
+    0x46, 0x26, 0x8D, 0x5B, 0xF2, 0xA1, 0x62, 0xCF, 0x50, 0x62, 0x81, 0x3D,
+    0x6A, 0x47, 0x4B, 0xE4, 0x92, 0x74, 0xCB, 0x69, 0xC3, 0x24, 0x15, 0x7F,
+    0xA3, 0xB6, 0xC7, 0xC1, 0xA0, 0x83, 0x88, 0xFC, 0x9D, 0x48, 0x19, 0xAD,
+    0x00, 0xBF, 0x5B, 0x09, 0x85, 0xB2, 0x92, 0x56, 0x0B, 0x8A, 0x84, 0x47,
+    0xEA, 0xF5, 0x55, 0x0C, 0x2A, 0x8D, 0x42, 0x58, 0x00, 0x0D, 0x82, 0x23,
+    0x74, 0xB1, 0x62, 0x14, 0x41, 0x7E, 0x93, 0x8D, 0x92, 0xF0, 0x72, 0x33,
+    0x61, 0x70, 0x3F, 0x23, 0x3E, 0xF4, 0xAD, 0x1D, 0x60, 0x74, 0xEE, 0xCB,
+    0x59, 0x37, 0xDE, 0x7C, 0xDB, 0x3B, 0x22, 0x6C, 0xF1, 0xEC, 0x5F, 0xD6,
+    0x9E, 0x50, 0xF8, 0x19, 0x84, 0x80, 0x07, 0xA6, 0x6E, 0x32, 0x77, 0xCE,
+    0xA7, 0xF2, 0x85, 0x40, 0xC2, 0x06, 0x0C, 0xC5, 0xAA, 0xA7, 0x69, 0xA9,
+    0x35, 0x97, 0xD9, 0x61, 0x55, 0xD8, 0xEF, 0xE8, 0x84, 0x34, 0x45, 0xC3,
+    0x2E, 0x7A, 0x44, 0x9E, 0xDC, 0xCA, 0x0B, 0x80, 0xFC, 0xAB, 0x04, 0x5A,
+    0xCD, 0x88, 0x55, 0x10, 0xD3, 0xDB, 0x73, 0xDB, 0xC9, 0x9E, 0x1E, 0x0E,
+    0x05, 0x67, 0xD5, 0xFD, 0xD8, 0x38, 0x3E, 0x71, 0x65, 0x34, 0xC4, 0xC5,
+    0x40, 0x43, 0x67, 0xE3, 0x79, 0xDA, 0x5F, 0x67, 0x4A, 0x3D, 0xB0, 0x8F,
+    0xE7, 0x21, 0x3E, 0x15, 0x20, 0xFF, 0x6D, 0xF1, 0x9E, 0xF8, 0x28, 0x3D,
+    0xF7, 0x40, 0x81, 0x94, 0x68, 0x5A, 0x3D, 0xE9, 0xF7, 0xAD, 0x83, 0xDB,
+    0x2B, 0x9F, 0xE3, 0xE6, 0xF7, 0xD4, 0x02, 0x76, 0xF7, 0x20, 0x15, 0x41,
+    0x34, 0x29, 0x69, 0x94, 0x1C, 0x26, 0x4C, 0xF6, 0x6A, 0xF4, 0x20, 0x33,
+    0x71, 0x24, 0x08, 0xD4, 0x68, 0x00, 0xA1, 0xD4, 0x2E, 0x6B, 0xF4, 0xBC,
+    0x46, 0x45, 0x24, 0x97, 0x2E, 0xF6, 0x39, 0x1E, 0xAF, 0x61, 0x00, 0x50,
+    0xB7, 0xD4, 0xB7, 0x43,
+};
+
+}  // namespace random_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/random/internal/randen_slow.cc b/absl/random/internal/randen_slow.cc
index 8d07458..4e5f3dc 100644
--- a/absl/random/internal/randen_slow.cc
+++ b/absl/random/internal/randen_slow.cc
@@ -20,6 +20,7 @@
 
 #include "absl/base/attributes.h"
 #include "absl/random/internal/platform.h"
+#include "absl/random/internal/randen_traits.h"
 
 #if ABSL_HAVE_ATTRIBUTE(always_inline) || \
     (defined(__GNUC__) && !defined(__clang__))
@@ -225,35 +226,16 @@
     0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c,
 };
 
-struct alignas(16) u64x2 {
-  constexpr u64x2() : v{0, 0} {};
-  constexpr u64x2(uint64_t hi, uint64_t lo) : v{lo, hi} {}
-
-  uint64_t v[2];
-};
-
 // Software implementation of the Vector128 class, using uint32_t
 // as an underlying vector register.
-//
-struct Vector128 {
-  inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128& operator^=(
-      const Vector128& other) {
-    s[0] ^= other.s[0];
-    s[1] ^= other.s[1];
-    s[2] ^= other.s[2];
-    s[3] ^= other.s[3];
-    return *this;
-  }
-
+struct alignas(16) Vector128 {
   uint32_t s[4];
 };
 
 inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128
-Vector128Load(const void* ABSL_RANDOM_INTERNAL_RESTRICT from) {
+Vector128Load(const void* from) {
   Vector128 result;
-  const uint8_t* ABSL_RANDOM_INTERNAL_RESTRICT src =
-      reinterpret_cast<const uint8_t*>(from);
-
+  const uint8_t* src = reinterpret_cast<const uint8_t*>(from);
   result.s[0] = static_cast<uint32_t>(src[0]) << 24 |
                 static_cast<uint32_t>(src[1]) << 16 |
                 static_cast<uint32_t>(src[2]) << 8 |
@@ -274,7 +256,7 @@
 }
 
 inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void Vector128Store(
-    const Vector128& v, void* ABSL_RANDOM_INTERNAL_RESTRICT to) {
+    const Vector128& v, void* to) {
   uint8_t* dst = reinterpret_cast<uint8_t*>(to);
   dst[0] = static_cast<uint8_t>(v.s[0] >> 24);
   dst[1] = static_cast<uint8_t>(v.s[0] >> 16);
@@ -298,91 +280,57 @@
 // symmetry of AES (ensures previously equal columns differ afterwards).
 inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128
 AesRound(const Vector128& state, const Vector128& round_key) {
-  // clang-format off
   Vector128 result;
-  result.s[0] = round_key.s[0] ^
-                te0[uint8_t(state.s[0] >> 24)] ^
-                te1[uint8_t(state.s[1] >> 16)] ^
-                te2[uint8_t(state.s[2] >> 8)] ^
+  result.s[0] = round_key.s[0] ^                  //
+                te0[uint8_t(state.s[0] >> 24)] ^  //
+                te1[uint8_t(state.s[1] >> 16)] ^  //
+                te2[uint8_t(state.s[2] >> 8)] ^   //
                 te3[uint8_t(state.s[3])];
-  result.s[1] = round_key.s[1] ^
-                te0[uint8_t(state.s[1] >> 24)] ^
-                te1[uint8_t(state.s[2] >> 16)] ^
-                te2[uint8_t(state.s[3] >> 8)] ^
+  result.s[1] = round_key.s[1] ^                  //
+                te0[uint8_t(state.s[1] >> 24)] ^  //
+                te1[uint8_t(state.s[2] >> 16)] ^  //
+                te2[uint8_t(state.s[3] >> 8)] ^   //
                 te3[uint8_t(state.s[0])];
-  result.s[2] = round_key.s[2] ^
-                te0[uint8_t(state.s[2] >> 24)] ^
-                te1[uint8_t(state.s[3] >> 16)] ^
-                te2[uint8_t(state.s[0] >> 8)] ^
+  result.s[2] = round_key.s[2] ^                  //
+                te0[uint8_t(state.s[2] >> 24)] ^  //
+                te1[uint8_t(state.s[3] >> 16)] ^  //
+                te2[uint8_t(state.s[0] >> 8)] ^   //
                 te3[uint8_t(state.s[1])];
-  result.s[3] = round_key.s[3] ^
-                te0[uint8_t(state.s[3] >> 24)] ^
-                te1[uint8_t(state.s[0] >> 16)] ^
-                te2[uint8_t(state.s[1] >> 8)] ^
+  result.s[3] = round_key.s[3] ^                  //
+                te0[uint8_t(state.s[3] >> 24)] ^  //
+                te1[uint8_t(state.s[0] >> 16)] ^  //
+                te2[uint8_t(state.s[1] >> 8)] ^   //
                 te3[uint8_t(state.s[2])];
   return result;
-  // clang-format on
 }
 
-// RANDen = RANDom generator or beetroots in Swiss German.
-// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
-// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
-//
-// High-level summary:
-// 1) Reverie (see "A Robust and Sponge-Like PRNG with Improved Efficiency") is
-//    a sponge-like random generator that requires a cryptographic permutation.
-//    It improves upon "Provably Robust Sponge-Based PRNGs and KDFs" by
-//    achieving backtracking resistance with only one Permute() per buffer.
-//
-// 2) "Simpira v2: A Family of Efficient Permutations Using the AES Round
-//    Function" constructs up to 1024-bit permutations using an improved
-//    Generalized Feistel network with 2-round AES-128 functions. This Feistel
-//    block shuffle achieves diffusion faster and is less vulnerable to
-//    sliced-biclique attacks than the Type-2 cyclic shuffle.
-//
-// 3) "Improving the Generalized Feistel" and "New criterion for diffusion
-//    property" extends the same kind of improved Feistel block shuffle to 16
-//    branches, which enables a 2048-bit permutation.
-//
-// Combine these three ideas and also change Simpira's subround keys from
-// structured/low-entropy counters to digits of Pi.
+using ::absl::random_internal::RandenTraits;
 
-// Randen constants.
-constexpr size_t kFeistelBlocks = 16;
-constexpr size_t kFeistelFunctions = kFeistelBlocks / 2;  // = 8
-constexpr size_t kFeistelRounds = 16 + 1;  // > 4 * log2(kFeistelBlocks)
-constexpr size_t kKeys = kFeistelRounds * kFeistelFunctions;
-
-// INCLUDE keys.
-#include "absl/random/internal/randen-keys.inc"
-
-static_assert(kKeys == kRoundKeys, "kKeys and kRoundKeys must be equal");
-
-// 2 uint64_t lanes per Vector128
-static constexpr size_t kLanes = 2;
+// Randen operates on 128-bit vectors.
+struct alignas(16) u64x2 {
+  uint64_t data[2];
+};
 
 // The improved Feistel block shuffle function for 16 blocks.
 inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void BlockShuffle(
-    uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state_u64) {
-  static_assert(kFeistelBlocks == 16,
+    u64x2* state) {
+  static_assert(RandenTraits::kFeistelBlocks == 16,
                 "Feistel block shuffle only works for 16 blocks.");
 
-  constexpr size_t shuffle[kFeistelBlocks] = {7,  2, 13, 4,  11, 8,  3, 6,
-                                              15, 0, 9,  10, 1,  14, 5, 12};
-
-  u64x2* ABSL_RANDOM_INTERNAL_RESTRICT state =
-      reinterpret_cast<u64x2*>(state_u64);
+  constexpr size_t shuffle[RandenTraits::kFeistelBlocks] = {
+      7, 2, 13, 4, 11, 8, 3, 6, 15, 0, 9, 10, 1, 14, 5, 12};
 
   // The fully unrolled loop without the memcpy improves the speed by about
-  // 30% over the equivalent (leaving code here as a comment):
-  if (false) {
-    u64x2 source[kFeistelBlocks];
-    std::memcpy(source, state, sizeof(source));
-    for (size_t i = 0; i < kFeistelBlocks; i++) {
-      const u64x2 v0 = source[shuffle[i]];
-      state[i] = v0;
-    }
+  // 30% over the equivalent:
+#if 0
+  u64x2 source[RandenTraits::kFeistelBlocks];
+  std::memcpy(source, state, sizeof(source));
+  for (size_t i = 0; i < RandenTraits::kFeistelBlocks; i++) {
+    const u64x2 v0 = source[shuffle[i]];
+    state[i] = v0;
   }
+  return;
+#endif
 
   const u64x2 v0 = state[shuffle[0]];
   const u64x2 v1 = state[shuffle[1]];
@@ -424,23 +372,23 @@
 // parallel hides the 7-cycle AESNI latency on HSW. Note that the Feistel
 // XORs are 'free' (included in the second AES instruction).
 inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE const u64x2* FeistelRound(
-    uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state,
+    u64x2* ABSL_RANDOM_INTERNAL_RESTRICT state,
     const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys) {
-  for (size_t branch = 0; branch < kFeistelBlocks; branch += 4) {
-    const Vector128 s0 = Vector128Load(state + kLanes * branch);
-    const Vector128 s1 = Vector128Load(state + kLanes * (branch + 1));
+  for (size_t branch = 0; branch < RandenTraits::kFeistelBlocks; branch += 4) {
+    const Vector128 s0 = Vector128Load(state + branch);
+    const Vector128 s1 = Vector128Load(state + branch + 1);
     const Vector128 f0 = AesRound(s0, Vector128Load(keys));
     keys++;
     const Vector128 o1 = AesRound(f0, s1);
-    Vector128Store(o1, state + kLanes * (branch + 1));
+    Vector128Store(o1, state + branch + 1);
 
     // Manually unroll this loop once. about 10% better than not unrolled.
-    const Vector128 s2 = Vector128Load(state + kLanes * (branch + 2));
-    const Vector128 s3 = Vector128Load(state + kLanes * (branch + 3));
+    const Vector128 s2 = Vector128Load(state + branch + 2);
+    const Vector128 s3 = Vector128Load(state + branch + 3);
     const Vector128 f2 = AesRound(s2, Vector128Load(keys));
     keys++;
     const Vector128 o3 = AesRound(f2, s3);
-    Vector128Store(o3, state + kLanes * (branch + 3));
+    Vector128Store(o3, state + branch + 3);
   }
   return keys;
 }
@@ -450,11 +398,9 @@
 // 2^64 queries if the round function is a PRF. This is similar to the b=8 case
 // of Simpira v2, but more efficient than its generic construction for b=16.
 inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void Permute(
-    const void* keys, uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state) {
-  const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys128 =
-      static_cast<const u64x2*>(keys);
-  for (size_t round = 0; round < kFeistelRounds; ++round) {
-    keys128 = FeistelRound(state, keys128);
+    u64x2* state, const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys) {
+  for (size_t round = 0; round < RandenTraits::kFeistelRounds; ++round) {
+    keys = FeistelRound(state, keys);
     BlockShuffle(state);
   }
 }
@@ -468,37 +414,42 @@
 const void* RandenSlow::GetKeys() {
   // Round keys for one AES per Feistel round and branch.
   // The canonical implementation uses first digits of Pi.
-  return round_keys;
+  return kRandenRoundKeys;
 }
 
 void RandenSlow::Absorb(const void* seed_void, void* state_void) {
-  uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state =
-      reinterpret_cast<uint64_t*>(state_void);
-  const uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT seed =
-      reinterpret_cast<const uint64_t*>(seed_void);
+  auto* state =
+      reinterpret_cast<uint64_t * ABSL_RANDOM_INTERNAL_RESTRICT>(state_void);
+  const auto* seed =
+      reinterpret_cast<const uint64_t * ABSL_RANDOM_INTERNAL_RESTRICT>(
+          seed_void);
 
-  constexpr size_t kCapacityBlocks = kCapacityBytes / sizeof(uint64_t);
-  static_assert(kCapacityBlocks * sizeof(uint64_t) == kCapacityBytes,
-                "Not i*V");
-  for (size_t i = kCapacityBlocks; i < kStateBytes / sizeof(uint64_t); ++i) {
+  constexpr size_t kCapacityBlocks =
+      RandenTraits::kCapacityBytes / sizeof(uint64_t);
+  static_assert(
+      kCapacityBlocks * sizeof(uint64_t) == RandenTraits::kCapacityBytes,
+      "Not i*V");
+
+  for (size_t i = kCapacityBlocks;
+       i < RandenTraits::kStateBytes / sizeof(uint64_t); ++i) {
     state[i] ^= seed[i - kCapacityBlocks];
   }
 }
 
-void RandenSlow::Generate(const void* keys, void* state_void) {
-  static_assert(kCapacityBytes == sizeof(Vector128), "Capacity mismatch");
+void RandenSlow::Generate(const void* keys_void, void* state_void) {
+  static_assert(RandenTraits::kCapacityBytes == sizeof(u64x2),
+                "Capacity mismatch");
 
-  uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state =
-      reinterpret_cast<uint64_t*>(state_void);
+  auto* state = reinterpret_cast<u64x2*>(state_void);
+  const auto* keys = reinterpret_cast<const u64x2*>(keys_void);
 
-  const Vector128 prev_inner = Vector128Load(state);
+  const u64x2 prev_inner = state[0];
 
-  Permute(keys, state);
+  Permute(state, keys);
 
   // Ensure backtracking resistance.
-  Vector128 inner = Vector128Load(state);
-  inner ^= prev_inner;
-  Vector128Store(inner, state);
+  state[0].data[0] ^= prev_inner.data[0];
+  state[0].data[1] ^= prev_inner.data[1];
 }
 
 }  // namespace random_internal
diff --git a/absl/random/internal/randen_slow.h b/absl/random/internal/randen_slow.h
index 72f92b5..532c3a8 100644
--- a/absl/random/internal/randen_slow.h
+++ b/absl/random/internal/randen_slow.h
@@ -23,18 +23,11 @@
 ABSL_NAMESPACE_BEGIN
 namespace random_internal {
 
-// RANDen = RANDom generator or beetroots in Swiss German.
+// RANDen = RANDom generator or beetroots in Swiss High German.
 // RandenSlow implements the basic state manipulation methods for
 // architectures lacking AES hardware acceleration intrinsics.
 class RandenSlow {
  public:
-  // Size of the entire sponge / state for the randen PRNG.
-  static constexpr size_t kStateBytes = 256;  // 2048-bit
-
-  // Size of the 'inner' (inaccessible) part of the sponge. Larger values would
-  // require more frequent calls to RandenGenerate.
-  static constexpr size_t kCapacityBytes = 16;  // 128-bit
-
   static void Generate(const void* keys, void* state_void);
   static void Absorb(const void* seed_void, void* state_void);
   static const void* GetKeys();
diff --git a/absl/random/internal/randen_slow_test.cc b/absl/random/internal/randen_slow_test.cc
index c07155d..4861ffa 100644
--- a/absl/random/internal/randen_slow_test.cc
+++ b/absl/random/internal/randen_slow_test.cc
@@ -17,18 +17,21 @@
 #include <cstring>
 
 #include "gtest/gtest.h"
+#include "absl/base/internal/endian.h"
+#include "absl/random/internal/randen_traits.h"
 
 namespace {
 
 using absl::random_internal::RandenSlow;
+using absl::random_internal::RandenTraits;
 
 // Local state parameters.
 constexpr size_t kSeedBytes =
-    RandenSlow::kStateBytes - RandenSlow::kCapacityBytes;
-constexpr size_t kStateSizeT = RandenSlow::kStateBytes / sizeof(uint64_t);
+    RandenTraits::kStateBytes - RandenTraits::kCapacityBytes;
+constexpr size_t kStateSizeT = RandenTraits::kStateBytes / sizeof(uint64_t);
 constexpr size_t kSeedSizeT = kSeedBytes / sizeof(uint32_t);
 
-struct randen {
+struct alignas(16) randen {
   uint64_t state[kStateSizeT];
   uint32_t seed[kSeedSizeT];
 };
@@ -54,7 +57,7 @@
 
   uint64_t* id = d.state;
   for (const auto& elem : kGolden) {
-    EXPECT_EQ(elem, *id++);
+    EXPECT_EQ(absl::little_endian::FromHost64(elem), *id++);
   }
 }
 
diff --git a/absl/random/internal/randen_traits.h b/absl/random/internal/randen_traits.h
index 2b8bbe7..120022c 100644
--- a/absl/random/internal/randen_traits.h
+++ b/absl/random/internal/randen_traits.h
@@ -28,10 +28,29 @@
 ABSL_NAMESPACE_BEGIN
 namespace random_internal {
 
-// RANDen = RANDom generator or beetroots in Swiss German.
+// RANDen = RANDom generator or beetroots in Swiss High German.
 // 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
 // generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
 //
+// High-level summary:
+// 1) Reverie (see "A Robust and Sponge-Like PRNG with Improved Efficiency") is
+//    a sponge-like random generator that requires a cryptographic permutation.
+//    It improves upon "Provably Robust Sponge-Based PRNGs and KDFs" by
+//    achieving backtracking resistance with only one Permute() per buffer.
+//
+// 2) "Simpira v2: A Family of Efficient Permutations Using the AES Round
+//    Function" constructs up to 1024-bit permutations using an improved
+//    Generalized Feistel network with 2-round AES-128 functions. This Feistel
+//    block shuffle achieves diffusion faster and is less vulnerable to
+//    sliced-biclique attacks than the Type-2 cyclic shuffle.
+//
+// 3) "Improving the Generalized Feistel" and "New criterion for diffusion
+//    property" extends the same kind of improved Feistel block shuffle to 16
+//    branches, which enables a 2048-bit permutation.
+//
+// Combine these three ideas and also change Simpira's subround keys from
+// structured/low-entropy counters to digits of Pi (or other random source).
+
 // RandenTraits contains the basic algorithm traits, such as the size of the
 // state, seed, sponge, etc.
 struct RandenTraits {
@@ -45,17 +64,23 @@
   // Size of the default seed consumed by the sponge.
   static constexpr size_t kSeedBytes = kStateBytes - kCapacityBytes;
 
+  // Assuming 128-bit blocks, the number of blocks in the state.
   // Largest size for which security proofs are known.
   static constexpr size_t kFeistelBlocks = 16;
 
-  // Type-2 generalized Feistel => one round function for every two blocks.
-  static constexpr size_t kFeistelFunctions = kFeistelBlocks / 2;  // = 8
-
   // Ensures SPRP security and two full subblock diffusions.
   // Must be > 4 * log2(kFeistelBlocks).
   static constexpr size_t kFeistelRounds = 16 + 1;
+
+  // Size of the key. A 128-bit key block is used for every-other
+  // feistel block (Type-2 generalized Feistel network) in each round.
+  static constexpr size_t kKeyBytes = 16 * kFeistelRounds * kFeistelBlocks / 2;
 };
 
+// Randen key arrays. In randen_round_keys.cc
+extern const unsigned char kRandenRoundKeys[RandenTraits::kKeyBytes];
+extern const unsigned char kRandenRoundKeysBE[RandenTraits::kKeyBytes];
+
 }  // namespace random_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/random/internal/uniform_helper.h b/absl/random/internal/uniform_helper.h
index 663107c..1243bc1 100644
--- a/absl/random/internal/uniform_helper.h
+++ b/absl/random/internal/uniform_helper.h
@@ -19,10 +19,13 @@
 #include <limits>
 #include <type_traits>
 
+#include "absl/base/config.h"
 #include "absl/meta/type_traits.h"
+#include "absl/random/internal/traits.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
+
 template <typename IntType>
 class uniform_int_distribution;
 
@@ -58,6 +61,26 @@
     : public random_internal::TagTypeCompare<IntervalOpenOpenTag> {};
 
 namespace random_internal {
+
+// In the absence of an explicitly provided return-type, the template
+// "uniform_inferred_return_t<A, B>" is used to derive a suitable type, based on
+// the data-types of the endpoint-arguments {A lo, B hi}.
+//
+// Given endpoints {A lo, B hi}, one of {A, B} will be chosen as the
+// return-type, if one type can be implicitly converted into the other, in a
+// lossless way. The template "is_widening_convertible" implements the
+// compile-time logic for deciding if such a conversion is possible.
+//
+// If no such conversion between {A, B} exists, then the overload for
+// absl::Uniform() will be discarded, and the call will be ill-formed.
+// Return-type for absl::Uniform() when the return-type is inferred.
+template <typename A, typename B>
+using uniform_inferred_return_t =
+    absl::enable_if_t<absl::disjunction<is_widening_convertible<A, B>,
+                                        is_widening_convertible<B, A>>::value,
+                      typename std::conditional<
+                          is_widening_convertible<A, B>::value, B, A>::type>;
+
 // The functions
 //    uniform_lower_bound(tag, a, b)
 // and
@@ -82,7 +105,7 @@
                           std::is_same<Tag, IntervalOpenOpenTag>>>::value,
     IntType>
 uniform_lower_bound(Tag, IntType a, IntType) {
-  return a + 1;
+  return a < (std::numeric_limits<IntType>::max)() ? (a + 1) : a;
 }
 
 template <typename FloatType, typename Tag>
@@ -113,7 +136,7 @@
                           std::is_same<Tag, IntervalOpenOpenTag>>>::value,
     IntType>
 uniform_upper_bound(Tag, IntType, IntType b) {
-  return b - 1;
+  return b > (std::numeric_limits<IntType>::min)() ? (b - 1) : b;
 }
 
 template <typename FloatType, typename Tag>
@@ -149,12 +172,53 @@
   return std::nextafter(b, (std::numeric_limits<FloatType>::max)());
 }
 
+// Returns whether the bounds are valid for the underlying distribution.
+// Inputs must have already been resolved via uniform_*_bound calls.
+//
+// The c++ standard constraints in [rand.dist.uni.int] are listed as:
+//    requires: lo <= hi.
+//
+// In the uniform_int_distrubtion, {lo, hi} are closed, closed. Thus:
+// [0, 0] is legal.
+// [0, 0) is not legal, but [0, 1) is, which translates to [0, 0].
+// (0, 1) is not legal, but (0, 2) is, which translates to [1, 1].
+// (0, 0] is not legal, but (0, 1] is, which translates to [1, 1].
+//
+// The c++ standard constraints in [rand.dist.uni.real] are listed as:
+//    requires: lo <= hi.
+//    requires: (hi - lo) <= numeric_limits<T>::max()
+//
+// In the uniform_real_distribution, {lo, hi} are closed, open, Thus:
+// [0, 0] is legal, which is [0, 0+epsilon).
+// [0, 0) is legal.
+// (0, 0) is not legal, but (0-epsilon, 0+epsilon) is.
+// (0, 0] is not legal, but (0, 0+epsilon] is.
+//
+template <typename FloatType>
+absl::enable_if_t<std::is_floating_point<FloatType>::value, bool>
+is_uniform_range_valid(FloatType a, FloatType b) {
+  return a <= b && std::isfinite(b - a);
+}
+
+template <typename IntType>
+absl::enable_if_t<std::is_integral<IntType>::value, bool>
+is_uniform_range_valid(IntType a, IntType b) {
+  return a <= b;
+}
+
+// UniformDistribution selects either absl::uniform_int_distribution
+// or absl::uniform_real_distribution depending on the NumType parameter.
 template <typename NumType>
 using UniformDistribution =
     typename std::conditional<std::is_integral<NumType>::value,
                               absl::uniform_int_distribution<NumType>,
                               absl::uniform_real_distribution<NumType>>::type;
 
+// UniformDistributionWrapper is used as the underlying distribution type
+// by the absl::Uniform template function. It selects the proper Abseil
+// uniform distribution and provides constructor overloads that match the
+// expected parameter order as well as adjusting distribtuion bounds based
+// on the tag.
 template <typename NumType>
 struct UniformDistributionWrapper : public UniformDistribution<NumType> {
   template <typename TagType>
diff --git a/absl/random/internal/uniform_helper_test.cc b/absl/random/internal/uniform_helper_test.cc
new file mode 100644
index 0000000..173c49b
--- /dev/null
+++ b/absl/random/internal/uniform_helper_test.cc
@@ -0,0 +1,279 @@
+// 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/random/internal/uniform_helper.h"
+
+#include <cmath>
+#include <cstdint>
+#include <random>
+
+#include "gtest/gtest.h"
+
+namespace {
+
+using absl::IntervalClosedClosedTag;
+using absl::IntervalClosedOpenTag;
+using absl::IntervalOpenClosedTag;
+using absl::IntervalOpenOpenTag;
+using absl::random_internal::uniform_inferred_return_t;
+using absl::random_internal::uniform_lower_bound;
+using absl::random_internal::uniform_upper_bound;
+
+class UniformHelperTest : public testing::Test {};
+
+TEST_F(UniformHelperTest, UniformBoundFunctionsGeneral) {
+  constexpr IntervalClosedClosedTag IntervalClosedClosed;
+  constexpr IntervalClosedOpenTag IntervalClosedOpen;
+  constexpr IntervalOpenClosedTag IntervalOpenClosed;
+  constexpr IntervalOpenOpenTag IntervalOpenOpen;
+
+  // absl::uniform_int_distribution natively assumes IntervalClosedClosed
+  // absl::uniform_real_distribution natively assumes IntervalClosedOpen
+
+  EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, 0, 100), 1);
+  EXPECT_EQ(uniform_lower_bound(IntervalOpenOpen, 0, 100), 1);
+  EXPECT_GT(uniform_lower_bound<float>(IntervalOpenClosed, 0, 1.0), 0);
+  EXPECT_GT(uniform_lower_bound<float>(IntervalOpenOpen, 0, 1.0), 0);
+  EXPECT_GT(uniform_lower_bound<double>(IntervalOpenClosed, 0, 1.0), 0);
+  EXPECT_GT(uniform_lower_bound<double>(IntervalOpenOpen, 0, 1.0), 0);
+
+  EXPECT_EQ(uniform_lower_bound(IntervalClosedClosed, 0, 100), 0);
+  EXPECT_EQ(uniform_lower_bound(IntervalClosedOpen, 0, 100), 0);
+  EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedClosed, 0, 1.0), 0);
+  EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedOpen, 0, 1.0), 0);
+  EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedClosed, 0, 1.0), 0);
+  EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedOpen, 0, 1.0), 0);
+
+  EXPECT_EQ(uniform_upper_bound(IntervalOpenOpen, 0, 100), 99);
+  EXPECT_EQ(uniform_upper_bound(IntervalClosedOpen, 0, 100), 99);
+  EXPECT_EQ(uniform_upper_bound<float>(IntervalOpenOpen, 0, 1.0), 1.0);
+  EXPECT_EQ(uniform_upper_bound<float>(IntervalClosedOpen, 0, 1.0), 1.0);
+  EXPECT_EQ(uniform_upper_bound<double>(IntervalOpenOpen, 0, 1.0), 1.0);
+  EXPECT_EQ(uniform_upper_bound<double>(IntervalClosedOpen, 0, 1.0), 1.0);
+
+  EXPECT_EQ(uniform_upper_bound(IntervalOpenClosed, 0, 100), 100);
+  EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, 0, 100), 100);
+  EXPECT_GT(uniform_upper_bound<float>(IntervalOpenClosed, 0, 1.0), 1.0);
+  EXPECT_GT(uniform_upper_bound<float>(IntervalClosedClosed, 0, 1.0), 1.0);
+  EXPECT_GT(uniform_upper_bound<double>(IntervalOpenClosed, 0, 1.0), 1.0);
+  EXPECT_GT(uniform_upper_bound<double>(IntervalClosedClosed, 0, 1.0), 1.0);
+
+  // Negative value tests
+  EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, -100, -1), -99);
+  EXPECT_EQ(uniform_lower_bound(IntervalOpenOpen, -100, -1), -99);
+  EXPECT_GT(uniform_lower_bound<float>(IntervalOpenClosed, -2.0, -1.0), -2.0);
+  EXPECT_GT(uniform_lower_bound<float>(IntervalOpenOpen, -2.0, -1.0), -2.0);
+  EXPECT_GT(uniform_lower_bound<double>(IntervalOpenClosed, -2.0, -1.0), -2.0);
+  EXPECT_GT(uniform_lower_bound<double>(IntervalOpenOpen, -2.0, -1.0), -2.0);
+
+  EXPECT_EQ(uniform_lower_bound(IntervalClosedClosed, -100, -1), -100);
+  EXPECT_EQ(uniform_lower_bound(IntervalClosedOpen, -100, -1), -100);
+  EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedClosed, -2.0, -1.0), -2.0);
+  EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedOpen, -2.0, -1.0), -2.0);
+  EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedClosed, -2.0, -1.0),
+            -2.0);
+  EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedOpen, -2.0, -1.0), -2.0);
+
+  EXPECT_EQ(uniform_upper_bound(IntervalOpenOpen, -100, -1), -2);
+  EXPECT_EQ(uniform_upper_bound(IntervalClosedOpen, -100, -1), -2);
+  EXPECT_EQ(uniform_upper_bound<float>(IntervalOpenOpen, -2.0, -1.0), -1.0);
+  EXPECT_EQ(uniform_upper_bound<float>(IntervalClosedOpen, -2.0, -1.0), -1.0);
+  EXPECT_EQ(uniform_upper_bound<double>(IntervalOpenOpen, -2.0, -1.0), -1.0);
+  EXPECT_EQ(uniform_upper_bound<double>(IntervalClosedOpen, -2.0, -1.0), -1.0);
+
+  EXPECT_EQ(uniform_upper_bound(IntervalOpenClosed, -100, -1), -1);
+  EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, -100, -1), -1);
+  EXPECT_GT(uniform_upper_bound<float>(IntervalOpenClosed, -2.0, -1.0), -1.0);
+  EXPECT_GT(uniform_upper_bound<float>(IntervalClosedClosed, -2.0, -1.0), -1.0);
+  EXPECT_GT(uniform_upper_bound<double>(IntervalOpenClosed, -2.0, -1.0), -1.0);
+  EXPECT_GT(uniform_upper_bound<double>(IntervalClosedClosed, -2.0, -1.0),
+            -1.0);
+
+  EXPECT_GT(uniform_lower_bound(IntervalOpenClosed, 1.0, 2.0), 1.0);
+  EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, +0.0), 1.0);
+  EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, -0.0), 1.0);
+  EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, -1.0), 1.0);
+}
+
+TEST_F(UniformHelperTest, UniformBoundFunctionsIntBounds) {
+  // Verifies the saturating nature of uniform_lower_bound and
+  // uniform_upper_bound
+  constexpr IntervalOpenOpenTag IntervalOpenOpen;
+
+  // uint max.
+  constexpr auto m = (std::numeric_limits<uint64_t>::max)();
+
+  EXPECT_EQ(1, uniform_lower_bound(IntervalOpenOpen, 0u, 0u));
+  EXPECT_EQ(m, uniform_lower_bound(IntervalOpenOpen, m, m));
+  EXPECT_EQ(m, uniform_lower_bound(IntervalOpenOpen, m - 1, m - 1));
+  EXPECT_EQ(0, uniform_upper_bound(IntervalOpenOpen, 0u, 0u));
+  EXPECT_EQ(m - 1, uniform_upper_bound(IntervalOpenOpen, m, m));
+
+  // int min/max
+  constexpr auto l = (std::numeric_limits<int64_t>::min)();
+  constexpr auto r = (std::numeric_limits<int64_t>::max)();
+  EXPECT_EQ(1, uniform_lower_bound(IntervalOpenOpen, 0, 0));
+  EXPECT_EQ(l + 1, uniform_lower_bound(IntervalOpenOpen, l, l));
+  EXPECT_EQ(r, uniform_lower_bound(IntervalOpenOpen, r - 1, r - 1));
+  EXPECT_EQ(r, uniform_lower_bound(IntervalOpenOpen, r, r));
+  EXPECT_EQ(-1, uniform_upper_bound(IntervalOpenOpen, 0, 0));
+  EXPECT_EQ(l, uniform_upper_bound(IntervalOpenOpen, l, l));
+  EXPECT_EQ(r - 1, uniform_upper_bound(IntervalOpenOpen, r, r));
+}
+
+TEST_F(UniformHelperTest, UniformBoundFunctionsRealBounds) {
+  // absl::uniform_real_distribution natively assumes IntervalClosedOpen;
+  // use the inverse here so each bound has to change.
+  constexpr IntervalOpenClosedTag IntervalOpenClosed;
+
+  // Edge cases: the next value toward itself is itself.
+  EXPECT_EQ(1.0, uniform_lower_bound(IntervalOpenClosed, 1.0, 1.0));
+  EXPECT_EQ(1.0f, uniform_lower_bound(IntervalOpenClosed, 1.0f, 1.0f));
+
+  // rightmost and leftmost finite values.
+  constexpr auto r = (std::numeric_limits<double>::max)();
+  const auto re = std::nexttoward(r, 0.0);
+  constexpr auto l = -r;
+  const auto le = std::nexttoward(l, 0.0);
+
+  EXPECT_EQ(l, uniform_lower_bound(IntervalOpenClosed, l, l));     // (l,l)
+  EXPECT_EQ(r, uniform_lower_bound(IntervalOpenClosed, r, r));     // (r,r)
+  EXPECT_EQ(le, uniform_lower_bound(IntervalOpenClosed, l, r));    // (l,r)
+  EXPECT_EQ(le, uniform_lower_bound(IntervalOpenClosed, l, 0.0));  // (l, 0)
+  EXPECT_EQ(le, uniform_lower_bound(IntervalOpenClosed, l, le));   // (l, le)
+  EXPECT_EQ(r, uniform_lower_bound(IntervalOpenClosed, re, r));    // (re, r)
+
+  EXPECT_EQ(le, uniform_upper_bound(IntervalOpenClosed, l, l));   // (l,l)
+  EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, r, r));    // (r,r)
+  EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, l, r));    // (l,r)
+  EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, l, re));   // (l,re)
+  EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, 0.0, r));  // (0, r)
+  EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, re, r));   // (re, r)
+  EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, le, re));  // (le, re)
+
+  const double e = std::nextafter(1.0, 2.0);  // 1 + epsilon
+  const double f = std::nextafter(1.0, 0.0);  // 1 - epsilon
+
+  // (1.0, 1.0 + epsilon)
+  EXPECT_EQ(e, uniform_lower_bound(IntervalOpenClosed, 1.0, e));
+  EXPECT_EQ(std::nextafter(e, 2.0),
+            uniform_upper_bound(IntervalOpenClosed, 1.0, e));
+
+  // (1.0-epsilon, 1.0)
+  EXPECT_EQ(1.0, uniform_lower_bound(IntervalOpenClosed, f, 1.0));
+  EXPECT_EQ(e, uniform_upper_bound(IntervalOpenClosed, f, 1.0));
+
+  // denorm cases.
+  const double g = std::numeric_limits<double>::denorm_min();
+  const double h = std::nextafter(g, 1.0);
+
+  // (0, denorm_min)
+  EXPECT_EQ(g, uniform_lower_bound(IntervalOpenClosed, 0.0, g));
+  EXPECT_EQ(h, uniform_upper_bound(IntervalOpenClosed, 0.0, g));
+
+  // (denorm_min, 1.0)
+  EXPECT_EQ(h, uniform_lower_bound(IntervalOpenClosed, g, 1.0));
+  EXPECT_EQ(e, uniform_upper_bound(IntervalOpenClosed, g, 1.0));
+
+  // Edge cases: invalid bounds.
+  EXPECT_EQ(f, uniform_lower_bound(IntervalOpenClosed, 1.0, -1.0));
+}
+
+struct Invalid {};
+
+template <typename A, typename B>
+auto InferredUniformReturnT(int) -> uniform_inferred_return_t<A, B>;
+
+template <typename, typename>
+Invalid InferredUniformReturnT(...);
+
+// Given types <A, B, Expect>, CheckArgsInferType() verifies that
+//
+//   uniform_inferred_return_t<A, B> and
+//   uniform_inferred_return_t<B, A>
+//
+// returns the type "Expect".
+//
+// This interface can also be used to assert that a given inferred return types
+// are invalid. Writing:
+//
+//   CheckArgsInferType<float, int, Invalid>()
+//
+// will assert that this overload does not exist.
+template <typename A, typename B, typename Expect>
+void CheckArgsInferType() {
+  static_assert(
+      absl::conjunction<
+          std::is_same<Expect, decltype(InferredUniformReturnT<A, B>(0))>,
+          std::is_same<Expect,
+                       decltype(InferredUniformReturnT<B, A>(0))>>::value,
+      "");
+}
+
+TEST_F(UniformHelperTest, UniformTypeInference) {
+  // Infers common types.
+  CheckArgsInferType<uint16_t, uint16_t, uint16_t>();
+  CheckArgsInferType<uint32_t, uint32_t, uint32_t>();
+  CheckArgsInferType<uint64_t, uint64_t, uint64_t>();
+  CheckArgsInferType<int16_t, int16_t, int16_t>();
+  CheckArgsInferType<int32_t, int32_t, int32_t>();
+  CheckArgsInferType<int64_t, int64_t, int64_t>();
+  CheckArgsInferType<float, float, float>();
+  CheckArgsInferType<double, double, double>();
+
+  // Properly promotes uint16_t.
+  CheckArgsInferType<uint16_t, uint32_t, uint32_t>();
+  CheckArgsInferType<uint16_t, uint64_t, uint64_t>();
+  CheckArgsInferType<uint16_t, int32_t, int32_t>();
+  CheckArgsInferType<uint16_t, int64_t, int64_t>();
+  CheckArgsInferType<uint16_t, float, float>();
+  CheckArgsInferType<uint16_t, double, double>();
+
+  // Properly promotes int16_t.
+  CheckArgsInferType<int16_t, int32_t, int32_t>();
+  CheckArgsInferType<int16_t, int64_t, int64_t>();
+  CheckArgsInferType<int16_t, float, float>();
+  CheckArgsInferType<int16_t, double, double>();
+
+  // Invalid (u)int16_t-pairings do not compile.
+  // See "CheckArgsInferType" comments above, for how this is achieved.
+  CheckArgsInferType<uint16_t, int16_t, Invalid>();
+  CheckArgsInferType<int16_t, uint32_t, Invalid>();
+  CheckArgsInferType<int16_t, uint64_t, Invalid>();
+
+  // Properly promotes uint32_t.
+  CheckArgsInferType<uint32_t, uint64_t, uint64_t>();
+  CheckArgsInferType<uint32_t, int64_t, int64_t>();
+  CheckArgsInferType<uint32_t, double, double>();
+
+  // Properly promotes int32_t.
+  CheckArgsInferType<int32_t, int64_t, int64_t>();
+  CheckArgsInferType<int32_t, double, double>();
+
+  // Invalid (u)int32_t-pairings do not compile.
+  CheckArgsInferType<uint32_t, int32_t, Invalid>();
+  CheckArgsInferType<int32_t, uint64_t, Invalid>();
+  CheckArgsInferType<int32_t, float, Invalid>();
+  CheckArgsInferType<uint32_t, float, Invalid>();
+
+  // Invalid (u)int64_t-pairings do not compile.
+  CheckArgsInferType<uint64_t, int64_t, Invalid>();
+  CheckArgsInferType<int64_t, float, Invalid>();
+  CheckArgsInferType<int64_t, double, Invalid>();
+
+  // Properly promotes float.
+  CheckArgsInferType<float, double, double>();
+}
+
+}  // namespace
diff --git a/absl/random/internal/wide_multiply.h b/absl/random/internal/wide_multiply.h
index 6e4cf1b..b6e6c4b 100644
--- a/absl/random/internal/wide_multiply.h
+++ b/absl/random/internal/wide_multiply.h
@@ -26,7 +26,7 @@
 #endif
 
 #include "absl/base/config.h"
-#include "absl/base/internal/bits.h"
+#include "absl/numeric/bits.h"
 #include "absl/numeric/int128.h"
 #include "absl/random/internal/traits.h"
 
@@ -38,9 +38,9 @@
 // MultiplyU64ToU128 multiplies two 64-bit values to a 128-bit value.
 // If an intrinsic is available, it is used, otherwise use native 32-bit
 // multiplies to construct the result.
-inline uint128 MultiplyU64ToU128(uint64_t a, uint64_t b) {
+inline absl::uint128 MultiplyU64ToU128(uint64_t a, uint64_t b) {
 #if defined(ABSL_HAVE_INTRINSIC_INT128)
-  return uint128(static_cast<__uint128_t>(a) * b);
+  return absl::uint128(static_cast<__uint128_t>(a) * b);
 #elif defined(ABSL_INTERNAL_USE_UMUL128)
   // uint64_t * uint64_t => uint128 multiply using imul intrinsic on MSVC.
   uint64_t high = 0;
@@ -93,14 +93,14 @@
 template <>
 struct wide_multiply<uint64_t> {
   using input_type = uint64_t;
-  using result_type = uint128;
+  using result_type = absl::uint128;
 
   static result_type multiply(uint64_t a, uint64_t b) {
     return MultiplyU64ToU128(a, b);
   }
 
-  static uint64_t hi(result_type r) { return Uint128High64(r); }
-  static uint64_t lo(result_type r) { return Uint128Low64(r); }
+  static uint64_t hi(result_type r) { return absl::Uint128High64(r); }
+  static uint64_t lo(result_type r) { return absl::Uint128Low64(r); }
 };
 #endif
 
diff --git a/absl/random/internal/wide_multiply_test.cc b/absl/random/internal/wide_multiply_test.cc
index 922603f..e276cb5 100644
--- a/absl/random/internal/wide_multiply_test.cc
+++ b/absl/random/internal/wide_multiply_test.cc
@@ -15,7 +15,6 @@
 #include "absl/random/internal/wide_multiply.h"
 
 #include "gtest/gtest.h"
-#include "absl/base/internal/bits.h"
 #include "absl/numeric/int128.h"
 
 using absl::random_internal::MultiplyU64ToU128;
@@ -28,7 +27,7 @@
 
   EXPECT_EQ(absl::uint128(0), MultiplyU64ToU128(0, 0));
 
-  // Max uint64
+  // Max uint64_t
   EXPECT_EQ(MultiplyU64ToU128(kMax, kMax),
             absl::MakeUint128(0xfffffffffffffffe, 0x0000000000000001));
   EXPECT_EQ(absl::MakeUint128(0, kMax), MultiplyU64ToU128(kMax, 1));
diff --git a/absl/random/log_uniform_int_distribution.h b/absl/random/log_uniform_int_distribution.h
index 960816e..43e1011 100644
--- a/absl/random/log_uniform_int_distribution.h
+++ b/absl/random/log_uniform_int_distribution.h
@@ -23,6 +23,7 @@
 #include <ostream>
 #include <type_traits>
 
+#include "absl/numeric/bits.h"
 #include "absl/random/internal/fastmath.h"
 #include "absl/random/internal/generate_real.h"
 #include "absl/random/internal/iostream_state_saver.h"
@@ -68,8 +69,10 @@
       if (base_ == 2) {
         // Determine where the first set bit is on range(), giving a log2(range)
         // value which can be used to construct bounds.
-        log_range_ = (std::min)(random_internal::LeadingSetBit(range()),
-                                std::numeric_limits<unsigned_type>::digits);
+        log_range_ =
+            (std::min)(bit_width(range()),
+                       static_cast<unsigned_type>(
+                           std::numeric_limits<unsigned_type>::digits));
       } else {
         // NOTE: Computing the logN(x) introduces error from 2 sources:
         // 1. Conversion of int to double loses precision for values >=
diff --git a/absl/random/log_uniform_int_distribution_test.cc b/absl/random/log_uniform_int_distribution_test.cc
index 5270531..5e780d9 100644
--- a/absl/random/log_uniform_int_distribution_test.cc
+++ b/absl/random/log_uniform_int_distribution_test.cc
@@ -27,6 +27,7 @@
 #include "absl/base/internal/raw_logging.h"
 #include "absl/random/internal/chi_square.h"
 #include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/pcg_engine.h"
 #include "absl/random/internal/sequence_urbg.h"
 #include "absl/random/random.h"
 #include "absl/strings/str_cat.h"
@@ -121,7 +122,10 @@
   // data generated by the log-uniform-int distribution.
   double ChiSquaredTestImpl();
 
-  absl::InsecureBitGen rng_;
+  // We use a fixed bit generator for distribution accuracy tests.  This allows
+  // these tests to be deterministic, while still testing the qualify of the
+  // implementation.
+  absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
 };
 
 double LogUniformIntChiSquaredTest::ChiSquaredTestImpl() {
@@ -194,7 +198,6 @@
 
 TEST_P(LogUniformIntChiSquaredTest, MultiTest) {
   const int kTrials = 5;
-
   int failures = 0;
   for (int i = 0; i < kTrials; i++) {
     double p_value = ChiSquaredTestImpl();
diff --git a/absl/random/mock_distributions.h b/absl/random/mock_distributions.h
index d36d5ba..764ab37 100644
--- a/absl/random/mock_distributions.h
+++ b/absl/random/mock_distributions.h
@@ -27,6 +27,11 @@
 // More information about the Googletest testing framework is available at
 // https://github.com/google/googletest
 //
+// EXPECT_CALL and ON_CALL need to be made within the same DLL component as
+// the call to absl::Uniform and related methods, otherwise mocking will fail
+// since the  underlying implementation creates a type-specific pointer which
+// will be distinct across different DLL boundaries.
+//
 // Example:
 //
 //   absl::MockingBitGen mock;
diff --git a/absl/random/mocking_bit_gen.h b/absl/random/mocking_bit_gen.h
index 36cef91..7b2b80e 100644
--- a/absl/random/mocking_bit_gen.h
+++ b/absl/random/mocking_bit_gen.h
@@ -33,17 +33,16 @@
 #include <memory>
 #include <tuple>
 #include <type_traits>
-#include <typeindex>
-#include <typeinfo>
 #include <utility>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/base/internal/fast_type_id.h"
 #include "absl/container/flat_hash_map.h"
 #include "absl/meta/type_traits.h"
 #include "absl/random/distributions.h"
 #include "absl/random/internal/distribution_caller.h"
-#include "absl/random/internal/mocking_bit_gen_base.h"
+#include "absl/random/random.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/str_join.h"
 #include "absl/types/span.h"
@@ -54,11 +53,12 @@
 ABSL_NAMESPACE_BEGIN
 
 namespace random_internal {
-
-template <typename, typename>
-struct MockSingleOverload;
+template <typename>
+struct DistributionCaller;
+class MockHelpers;
 
 }  // namespace random_internal
+class BitGenRef;
 
 // MockingBitGen
 //
@@ -96,100 +96,144 @@
 // At this time, only mock distributions supplied within the Abseil random
 // library are officially supported.
 //
-class MockingBitGen : public absl::random_internal::MockingBitGenBase {
+// EXPECT_CALL and ON_CALL need to be made within the same DLL component as
+// the call to absl::Uniform and related methods, otherwise mocking will fail
+// since the  underlying implementation creates a type-specific pointer which
+// will be distinct across different DLL boundaries.
+//
+class MockingBitGen {
  public:
-  MockingBitGen() {}
+  MockingBitGen() = default;
+  ~MockingBitGen() = default;
 
-  ~MockingBitGen() override;
+  // URBG interface
+  using result_type = absl::BitGen::result_type;
+
+  static constexpr result_type(min)() { return (absl::BitGen::min)(); }
+  static constexpr result_type(max)() { return (absl::BitGen::max)(); }
+  result_type operator()() { return gen_(); }
 
  private:
-  template <typename DistrT, typename... Args>
-  using MockFnType =
-      ::testing::MockFunction<typename DistrT::result_type(Args...)>;
+  // GetMockFnType returns the testing::MockFunction for a result and tuple.
+  // This method only exists for type deduction and is otherwise unimplemented.
+  template <typename ResultT, typename... Args>
+  static auto GetMockFnType(ResultT, std::tuple<Args...>)
+      -> ::testing::MockFunction<ResultT(Args...)>;
 
-  // MockingBitGen::Register
+  // MockFnCaller is a helper method for use with absl::apply to
+  // apply an ArgTupleT to a compatible MockFunction.
+  // NOTE: MockFnCaller is essentially equivalent to the lambda:
+  // [fn](auto... args) { return fn->Call(std::move(args)...)}
+  // however that fails to build on some supported platforms.
+  template <typename MockFnType, typename ResultT, typename Tuple>
+  struct MockFnCaller;
+
+  // specialization for std::tuple.
+  template <typename MockFnType, typename ResultT, typename... Args>
+  struct MockFnCaller<MockFnType, ResultT, std::tuple<Args...>> {
+    MockFnType* fn;
+    inline ResultT operator()(Args... args) {
+      return fn->Call(std::move(args)...);
+    }
+  };
+
+  // FunctionHolder owns a particular ::testing::MockFunction associated with
+  // a mocked type signature, and implement the type-erased Apply call, which
+  // applies type-erased arguments to the mock.
+  class FunctionHolder {
+   public:
+    virtual ~FunctionHolder() = default;
+
+    // Call is a dispatch function which converts the
+    // generic type-erased parameters into a specific mock invocation call.
+    virtual void Apply(/*ArgTupleT*/ void* args_tuple,
+                       /*ResultT*/ void* result) = 0;
+  };
+
+  template <typename MockFnType, typename ResultT, typename ArgTupleT>
+  class FunctionHolderImpl final : public FunctionHolder {
+   public:
+    void Apply(void* args_tuple, void* result) override {
+      // Requires tuple_args to point to a ArgTupleT, which is a
+      // std::tuple<Args...> used to invoke the mock function. Requires result
+      // to point to a ResultT, which is the result of the call.
+      *static_cast<ResultT*>(result) =
+          absl::apply(MockFnCaller<MockFnType, ResultT, ArgTupleT>{&mock_fn_},
+                      *static_cast<ArgTupleT*>(args_tuple));
+    }
+
+    MockFnType mock_fn_;
+  };
+
+  // MockingBitGen::RegisterMock
   //
-  // Register<DistrT, FormatT, ArgTupleT> is the main extension point for
-  // extending the MockingBitGen framework. It provides a mechanism to install a
-  // mock expectation for the distribution `distr_t` onto the MockingBitGen
-  // context.
+  // RegisterMock<ResultT, ArgTupleT>(FastTypeIdType) is the main extension
+  // point for extending the MockingBitGen framework. It provides a mechanism to
+  // install a mock expectation for a function like ResultT(Args...) keyed by
+  // type_idex onto the MockingBitGen context. The key is that the type_index
+  // used to register must match the type index used to call the mock.
   //
   // The returned MockFunction<...> type can be used to setup additional
   // distribution parameters of the expectation.
-  template <typename DistrT, typename... Args, typename... Ms>
-  decltype(std::declval<MockFnType<DistrT, Args...>>().gmock_Call(
-      std::declval<Ms>()...))
-  Register(Ms&&... matchers) {
-    auto& mock =
-        mocks_[std::type_index(GetTypeId<DistrT, std::tuple<Args...>>())];
+  template <typename ResultT, typename ArgTupleT, typename SelfT>
+  auto RegisterMock(SelfT&, base_internal::FastTypeIdType type)
+      -> decltype(GetMockFnType(std::declval<ResultT>(),
+                                std::declval<ArgTupleT>()))& {
+    using MockFnType = decltype(GetMockFnType(std::declval<ResultT>(),
+                                              std::declval<ArgTupleT>()));
 
-    if (!mock.mock_fn) {
-      auto* mock_fn = new MockFnType<DistrT, Args...>;
-      mock.mock_fn = mock_fn;
-      mock.match_impl = &MatchImpl<DistrT, Args...>;
-      deleters_.emplace_back([mock_fn] { delete mock_fn; });
+    using WrappedFnType = absl::conditional_t<
+        std::is_same<SelfT, ::testing::NiceMock<absl::MockingBitGen>>::value,
+        ::testing::NiceMock<MockFnType>,
+        absl::conditional_t<
+            std::is_same<SelfT,
+                         ::testing::NaggyMock<absl::MockingBitGen>>::value,
+            ::testing::NaggyMock<MockFnType>,
+            absl::conditional_t<
+                std::is_same<SelfT,
+                             ::testing::StrictMock<absl::MockingBitGen>>::value,
+                ::testing::StrictMock<MockFnType>, MockFnType>>>;
+
+    using ImplT = FunctionHolderImpl<WrappedFnType, ResultT, ArgTupleT>;
+    auto& mock = mocks_[type];
+    if (!mock) {
+      mock = absl::make_unique<ImplT>();
     }
-
-    return static_cast<MockFnType<DistrT, Args...>*>(mock.mock_fn)
-        ->gmock_Call(std::forward<Ms>(matchers)...);
+    return static_cast<ImplT*>(mock.get())->mock_fn_;
   }
 
-  mutable std::vector<std::function<void()>> deleters_;
-
-  using match_impl_fn = void (*)(void* mock_fn, void* t_erased_dist_args,
-                                 void* t_erased_result);
-  struct MockData {
-    void* mock_fn = nullptr;
-    match_impl_fn match_impl = nullptr;
-  };
-
-  mutable absl::flat_hash_map<std::type_index, MockData> mocks_;
-
-  template <typename DistrT, typename... Args>
-  static void MatchImpl(void* mock_fn, void* dist_args, void* result) {
-    using result_type = typename DistrT::result_type;
-    *static_cast<result_type*>(result) = absl::apply(
-        [mock_fn](Args... args) -> result_type {
-          return (*static_cast<MockFnType<DistrT, Args...>*>(mock_fn))
-              .Call(std::move(args)...);
-        },
-        *static_cast<std::tuple<Args...>*>(dist_args));
-  }
-
-  // Looks for an appropriate mock - Returns the mocked result if one is found.
-  // Otherwise, returns a random value generated by the underlying URBG.
-  bool CallImpl(const std::type_info& key_type, void* dist_args,
-                void* result) override {
+  // MockingBitGen::InvokeMock
+  //
+  // InvokeMock(FastTypeIdType, args, result) is the entrypoint for invoking
+  // mocks registered on MockingBitGen.
+  //
+  // When no mocks are registered on the provided FastTypeIdType, returns false.
+  // Otherwise attempts to invoke the mock function ResultT(Args...) that
+  // was previously registered via the type_index.
+  // Requires tuple_args to point to a ArgTupleT, which is a std::tuple<Args...>
+  // used to invoke the mock function.
+  // Requires result to point to a ResultT, which is the result of the call.
+  inline bool InvokeMock(base_internal::FastTypeIdType type, void* args_tuple,
+                         void* result) {
     // Trigger a mock, if there exists one that matches `param`.
-    auto it = mocks_.find(std::type_index(key_type));
+    auto it = mocks_.find(type);
     if (it == mocks_.end()) return false;
-    auto* mock_data = static_cast<MockData*>(&it->second);
-    mock_data->match_impl(mock_data->mock_fn, dist_args, result);
+    it->second->Apply(args_tuple, result);
     return true;
   }
 
-  template <typename, typename>
-  friend struct ::absl::random_internal::MockSingleOverload;
-  friend struct ::absl::random_internal::DistributionCaller<
-      absl::MockingBitGen>;
+  absl::flat_hash_map<base_internal::FastTypeIdType,
+                      std::unique_ptr<FunctionHolder>>
+      mocks_;
+  absl::BitGen gen_;
+
+  template <typename>
+  friend struct ::absl::random_internal::DistributionCaller;  // for InvokeMock
+  friend class ::absl::BitGenRef;                             // for InvokeMock
+  friend class ::absl::random_internal::MockHelpers;  // for RegisterMock,
+                                                      // InvokeMock
 };
 
-// -----------------------------------------------------------------------------
-// Implementation Details Only Below
-// -----------------------------------------------------------------------------
-
-namespace random_internal {
-
-template <>
-struct DistributionCaller<absl::MockingBitGen> {
-  template <typename DistrT, typename FormatT, typename... Args>
-  static typename DistrT::result_type Call(absl::MockingBitGen* gen,
-                                           Args&&... args) {
-    return gen->template Call<DistrT, FormatT>(std::forward<Args>(args)...);
-  }
-};
-
-}  // namespace random_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
 
diff --git a/absl/random/mocking_bit_gen_test.cc b/absl/random/mocking_bit_gen_test.cc
index f0ffc9a..f63b6e4 100644
--- a/absl/random/mocking_bit_gen_test.cc
+++ b/absl/random/mocking_bit_gen_test.cc
@@ -26,6 +26,8 @@
 #include "absl/random/random.h"
 
 namespace {
+
+using ::testing::_;
 using ::testing::Ne;
 using ::testing::Return;
 
@@ -344,4 +346,47 @@
   EXPECT_EQ(absl::Poisson<int>(gen, 2.0), 4);
 }
 
+TEST(MockingBitGen, NiceMock) {
+  ::testing::NiceMock<absl::MockingBitGen> gen;
+  ON_CALL(absl::MockUniform<int>(), Call(gen, _, _)).WillByDefault(Return(145));
+
+  ON_CALL(absl::MockPoisson<int>(), Call(gen, _)).WillByDefault(Return(3));
+
+  EXPECT_EQ(absl::Uniform(gen, 1, 1000), 145);
+  EXPECT_EQ(absl::Uniform(gen, 10, 1000), 145);
+  EXPECT_EQ(absl::Uniform(gen, 100, 1000), 145);
+}
+
+TEST(MockingBitGen, NaggyMock) {
+  // This is difficult to test, as only the output matters, so just verify
+  // that ON_CALL can be installed. Anything else requires log inspection.
+  ::testing::NaggyMock<absl::MockingBitGen> gen;
+
+  ON_CALL(absl::MockUniform<int>(), Call(gen, _, _)).WillByDefault(Return(145));
+  ON_CALL(absl::MockPoisson<int>(), Call(gen, _)).WillByDefault(Return(3));
+
+  EXPECT_EQ(absl::Uniform(gen, 1, 1000), 145);
+}
+
+TEST(MockingBitGen, StrictMock_NotEnough) {
+  EXPECT_NONFATAL_FAILURE(
+      []() {
+        ::testing::StrictMock<absl::MockingBitGen> gen;
+        EXPECT_CALL(absl::MockUniform<int>(), Call(gen, _, _))
+            .WillOnce(Return(145));
+      }(),
+      "unsatisfied and active");
+}
+
+TEST(MockingBitGen, StrictMock_TooMany) {
+  ::testing::StrictMock<absl::MockingBitGen> gen;
+
+  EXPECT_CALL(absl::MockUniform<int>(), Call(gen, _, _)).WillOnce(Return(145));
+  EXPECT_EQ(absl::Uniform(gen, 1, 1000), 145);
+
+  EXPECT_NONFATAL_FAILURE(
+      [&]() { EXPECT_EQ(absl::Uniform(gen, 10, 1000), 0); }(),
+      "over-saturated and active");
+}
+
 }  // namespace
diff --git a/absl/random/poisson_distribution_test.cc b/absl/random/poisson_distribution_test.cc
index 9d215fb..8baabd1 100644
--- a/absl/random/poisson_distribution_test.cc
+++ b/absl/random/poisson_distribution_test.cc
@@ -30,6 +30,7 @@
 #include "absl/container/flat_hash_map.h"
 #include "absl/random/internal/chi_square.h"
 #include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/pcg_engine.h"
 #include "absl/random/internal/sequence_urbg.h"
 #include "absl/random/random.h"
 #include "absl/strings/str_cat.h"
@@ -257,7 +258,10 @@
   template <typename D>
   bool SingleZTest(const double p, const size_t samples);
 
-  absl::InsecureBitGen rng_;
+  // We use a fixed bit generator for distribution accuracy tests.  This allows
+  // these tests to be deterministic, while still testing the qualify of the
+  // implementation.
+  absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
 };
 
 template <typename D>
@@ -357,9 +361,13 @@
  private:
   void InitChiSquaredTest(const double buckets);
 
-  absl::InsecureBitGen rng_;
   std::vector<size_t> cutoffs_;
   std::vector<double> expected_;
+
+  // We use a fixed bit generator for distribution accuracy tests.  This allows
+  // these tests to be deterministic, while still testing the qualify of the
+  // implementation.
+  absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
 };
 
 void PoissonDistributionChiSquaredTest::InitChiSquaredTest(
diff --git a/absl/random/random.h b/absl/random/random.h
index c8f326e..71b6309 100644
--- a/absl/random/random.h
+++ b/absl/random/random.h
@@ -109,7 +109,7 @@
 
 // absl::BitGen::max()
 //
-// Returns the largest possible value from this bit generator., and
+// Returns the largest possible value from this bit generator.
 
 // absl::BitGen::discard(num)
 //
diff --git a/absl/random/seed_sequences_test.cc b/absl/random/seed_sequences_test.cc
index 2cc8b0e..fe1100b 100644
--- a/absl/random/seed_sequences_test.cc
+++ b/absl/random/seed_sequences_test.cc
@@ -96,7 +96,6 @@
 void TestReproducibleVariateSequencesForNonsecureURBG() {
   const size_t kNumVariates = 1000;
 
-  // Master RNG instance.
   URBG rng;
   // Reused for both RNG instances.
   auto reusable_seed = absl::CreateSeedSeqFrom(&rng);
diff --git a/absl/random/uniform_int_distribution.h b/absl/random/uniform_int_distribution.h
index da66564..c1f54cc 100644
--- a/absl/random/uniform_int_distribution.h
+++ b/absl/random/uniform_int_distribution.h
@@ -196,7 +196,7 @@
 uniform_int_distribution<IntType>::Generate(
     URBG& g,  // NOLINT(runtime/references)
     typename random_internal::make_unsigned_bits<IntType>::type R) {
-    random_internal::FastUniformBits<unsigned_type> fast_bits;
+  random_internal::FastUniformBits<unsigned_type> fast_bits;
   unsigned_type bits = fast_bits(g);
   const unsigned_type Lim = R + 1;
   if ((R & Lim) == 0) {
diff --git a/absl/random/uniform_int_distribution_test.cc b/absl/random/uniform_int_distribution_test.cc
index aacff88..276d72a 100644
--- a/absl/random/uniform_int_distribution_test.cc
+++ b/absl/random/uniform_int_distribution_test.cc
@@ -26,6 +26,7 @@
 #include "absl/base/internal/raw_logging.h"
 #include "absl/random/internal/chi_square.h"
 #include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/pcg_engine.h"
 #include "absl/random/internal/sequence_urbg.h"
 #include "absl/random/random.h"
 #include "absl/strings/str_cat.h"
@@ -123,7 +124,7 @@
   absl::uniform_int_distribution<TypeParam> dist(10, 1);
   auto x = dist(gen);
 
-  // Any value will generate a non-empty std::string.
+  // Any value will generate a non-empty string.
   EXPECT_FALSE(absl::StrCat(+x).empty()) << x;
 #endif  // NDEBUG
 }
@@ -134,7 +135,11 @@
   using param_type =
       typename absl::uniform_int_distribution<TypeParam>::param_type;
 
-  absl::InsecureBitGen rng;
+  // We use a fixed bit generator for distribution accuracy tests.  This allows
+  // these tests to be deterministic, while still testing the qualify of the
+  // implementation.
+  absl::random_internal::pcg64_2018_engine rng{0x2B7E151628AED2A6};
+
   std::vector<double> values(kSize);
   for (const auto& param :
        {param_type(0, Limits::max()), param_type(13, 127)}) {
@@ -178,7 +183,11 @@
   const TypeParam min = std::is_unsigned<TypeParam>::value ? 37 : -37;
   const TypeParam max = min + kBuckets;
 
-  absl::InsecureBitGen rng;
+  // We use a fixed bit generator for distribution accuracy tests.  This allows
+  // these tests to be deterministic, while still testing the qualify of the
+  // implementation.
+  absl::random_internal::pcg64_2018_engine rng{0x2B7E151628AED2A6};
+
   absl::uniform_int_distribution<TypeParam> dist(min, max);
 
   std::vector<int32_t> counts(kBuckets + 1, 0);
diff --git a/absl/random/uniform_real_distribution_test.cc b/absl/random/uniform_real_distribution_test.cc
index a56374a..18bcd3b 100644
--- a/absl/random/uniform_real_distribution_test.cc
+++ b/absl/random/uniform_real_distribution_test.cc
@@ -20,13 +20,16 @@
 #include <random>
 #include <sstream>
 #include <string>
+#include <type_traits>
 #include <vector>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "absl/base/internal/raw_logging.h"
+#include "absl/numeric/internal/representation.h"
 #include "absl/random/internal/chi_square.h"
 #include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/pcg_engine.h"
 #include "absl/random/internal/sequence_urbg.h"
 #include "absl/random/random.h"
 #include "absl/strings/str_cat.h"
@@ -54,11 +57,15 @@
 template <typename RealType>
 class UniformRealDistributionTest : public ::testing::Test {};
 
-#if defined(__EMSCRIPTEN__)
-using RealTypes = ::testing::Types<float, double>;
-#else
-using RealTypes = ::testing::Types<float, double, long double>;
-#endif  // defined(__EMSCRIPTEN__)
+// double-double arithmetic is not supported well by either GCC or Clang; see
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99048,
+// https://bugs.llvm.org/show_bug.cgi?id=49131, and
+// https://bugs.llvm.org/show_bug.cgi?id=49132. Don't bother running these tests
+// with double doubles until compiler support is better.
+using RealTypes =
+    std::conditional<absl::numeric_internal::IsDoubleDouble(),
+                     ::testing::Types<float, double>,
+                     ::testing::Types<float, double, long double>>::type;
 
 TYPED_TEST_SUITE(UniformRealDistributionTest, RealTypes);
 
@@ -207,7 +214,11 @@
   constexpr int kSize = 1000000;
   std::vector<double> values(kSize);
 
-  absl::InsecureBitGen rng;
+  // We use a fixed bit generator for distribution accuracy tests.  This allows
+  // these tests to be deterministic, while still testing the qualify of the
+  // implementation.
+  absl::random_internal::pcg64_2018_engine rng{0x2B7E151628AED2A6};
+
   absl::uniform_real_distribution<TypeParam> dist;
   for (int i = 0; i < kSize; i++) {
     values[i] = dist(rng);
@@ -237,7 +248,11 @@
   const int kThreshold =
       absl::random_internal::ChiSquareValue(kBuckets - 1, 0.999999);
 
-  absl::InsecureBitGen rng;
+  // We use a fixed bit generator for distribution accuracy tests.  This allows
+  // these tests to be deterministic, while still testing the qualify of the
+  // implementation.
+  absl::random_internal::pcg64_2018_engine rng{0x2B7E151628AED2A6};
+
   for (const auto& param : {param_type(0, 1), param_type(5, 12),
                             param_type(-5, 13), param_type(-5, -2)}) {
     const double min_val = param.a();
diff --git a/absl/random/zipf_distribution_test.cc b/absl/random/zipf_distribution_test.cc
index 4d4a0fc..f8cf70e 100644
--- a/absl/random/zipf_distribution_test.cc
+++ b/absl/random/zipf_distribution_test.cc
@@ -27,6 +27,7 @@
 #include "gtest/gtest.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/random/internal/chi_square.h"
+#include "absl/random/internal/pcg_engine.h"
 #include "absl/random/internal/sequence_urbg.h"
 #include "absl/random/random.h"
 #include "absl/strings/str_cat.h"
@@ -213,7 +214,10 @@
  public:
   ZipfTest() : ZipfModel(GetParam().k(), GetParam().q(), GetParam().v()) {}
 
-  absl::InsecureBitGen rng_;
+  // We use a fixed bit generator for distribution accuracy tests.  This allows
+  // these tests to be deterministic, while still testing the qualify of the
+  // implementation.
+  absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
 };
 
 TEST_P(ZipfTest, ChiSquaredTest) {
diff --git a/absl/status/BUILD.bazel b/absl/status/BUILD.bazel
index 2b83077..189bd73 100644
--- a/absl/status/BUILD.bazel
+++ b/absl/status/BUILD.bazel
@@ -26,11 +26,12 @@
 
 package(default_visibility = ["//visibility:public"])
 
-licenses(["notice"])  # Apache 2.0
+licenses(["notice"])
 
 cc_library(
     name = "status",
     srcs = [
+        "internal/status_internal.h",
         "status.cc",
         "status_payload_printer.cc",
     ],
@@ -40,6 +41,7 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     deps = [
+        "//absl/base:atomic_hook",
         "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:raw_logging_internal",
@@ -63,3 +65,39 @@
         "@com_google_googletest//:gtest_main",
     ],
 )
+
+cc_library(
+    name = "statusor",
+    srcs = [
+        "internal/statusor_internal.h",
+        "statusor.cc",
+    ],
+    hdrs = [
+        "statusor.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        ":status",
+        "//absl/base:core_headers",
+        "//absl/base:raw_logging_internal",
+        "//absl/meta:type_traits",
+        "//absl/strings",
+        "//absl/types:variant",
+        "//absl/utility",
+    ],
+)
+
+cc_test(
+    name = "statusor_test",
+    size = "small",
+    srcs = ["statusor_test.cc"],
+    deps = [
+        ":status",
+        ":statusor",
+        "//absl/base",
+        "//absl/memory",
+        "//absl/types:any",
+        "//absl/utility",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
diff --git a/absl/status/CMakeLists.txt b/absl/status/CMakeLists.txt
index f05cee5..f0d798a 100644
--- a/absl/status/CMakeLists.txt
+++ b/absl/status/CMakeLists.txt
@@ -19,12 +19,14 @@
   HDRS
     "status.h"
   SRCS
+    "internal/status_internal.h"
     "status.cc"
     "status_payload_printer.h"
     "status_payload_printer.cc"
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
+    absl::atomic_hook
     absl::config
     absl::core_headers
     absl::raw_logging_internal
@@ -50,3 +52,37 @@
     absl::strings
     gmock_main
 )
+
+absl_cc_library(
+  NAME
+    statusor
+  HDRS
+    "statusor.h"
+  SRCS
+    "statusor.cc"
+    "internal/statusor_internal.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::status
+    absl::core_headers
+    absl::raw_logging_internal
+    absl::type_traits
+    absl::strings
+    absl::utility
+    absl::variant
+  PUBLIC
+)
+
+absl_cc_test(
+  NAME
+    statusor_test
+  SRCS
+   "statusor_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::status
+    absl::statusor
+    gmock_main
+)
diff --git a/absl/status/internal/status_internal.h b/absl/status/internal/status_internal.h
new file mode 100644
index 0000000..99a2d96
--- /dev/null
+++ b/absl/status/internal/status_internal.h
@@ -0,0 +1,69 @@
+// Copyright 2019 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_STATUS_INTERNAL_STATUS_INTERNAL_H_
+#define ABSL_STATUS_INTERNAL_STATUS_INTERNAL_H_
+
+#include <string>
+
+#include "absl/container/inlined_vector.h"
+#include "absl/strings/cord.h"
+
+#ifndef SWIG
+// Disabled for SWIG as it doesn't parse attributes correctly.
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+// Returned Status objects may not be ignored. Codesearch doesn't handle ifdefs
+// as part of a class definitions (b/6995610), so we use a forward declaration.
+class ABSL_MUST_USE_RESULT Status;
+ABSL_NAMESPACE_END
+}  // namespace absl
+#endif  // !SWIG
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+enum class StatusCode : int;
+
+namespace status_internal {
+
+// Container for status payloads.
+struct Payload {
+  std::string type_url;
+  absl::Cord payload;
+};
+
+using Payloads = absl::InlinedVector<Payload, 1>;
+
+// Reference-counted representation of Status data.
+struct StatusRep {
+  StatusRep(absl::StatusCode code, std::string message,
+            std::unique_ptr<status_internal::Payloads> payloads)
+      : ref(int32_t{1}),
+        code(code),
+        message(std::move(message)),
+        payloads(std::move(payloads)) {}
+
+  std::atomic<int32_t> ref;
+  absl::StatusCode code;
+  std::string message;
+  std::unique_ptr<status_internal::Payloads> payloads;
+};
+
+absl::StatusCode MapToLocalCode(int value);
+}  // namespace status_internal
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STATUS_INTERNAL_STATUS_INTERNAL_H_
diff --git a/absl/status/internal/statusor_internal.h b/absl/status/internal/statusor_internal.h
new file mode 100644
index 0000000..eaac2c0
--- /dev/null
+++ b/absl/status/internal/statusor_internal.h
@@ -0,0 +1,396 @@
+// 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.
+#ifndef ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_
+#define ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_
+
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/attributes.h"
+#include "absl/meta/type_traits.h"
+#include "absl/status/status.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+template <typename T>
+class ABSL_MUST_USE_RESULT StatusOr;
+
+namespace internal_statusor {
+
+// Detects whether `U` has conversion operator to `StatusOr<T>`, i.e. `operator
+// StatusOr<T>()`.
+template <typename T, typename U, typename = void>
+struct HasConversionOperatorToStatusOr : std::false_type {};
+
+template <typename T, typename U>
+void test(char (*)[sizeof(std::declval<U>().operator absl::StatusOr<T>())]);
+
+template <typename T, typename U>
+struct HasConversionOperatorToStatusOr<T, U, decltype(test<T, U>(0))>
+    : std::true_type {};
+
+// Detects whether `T` is constructible or convertible from `StatusOr<U>`.
+template <typename T, typename U>
+using IsConstructibleOrConvertibleFromStatusOr =
+    absl::disjunction<std::is_constructible<T, StatusOr<U>&>,
+                      std::is_constructible<T, const StatusOr<U>&>,
+                      std::is_constructible<T, StatusOr<U>&&>,
+                      std::is_constructible<T, const StatusOr<U>&&>,
+                      std::is_convertible<StatusOr<U>&, T>,
+                      std::is_convertible<const StatusOr<U>&, T>,
+                      std::is_convertible<StatusOr<U>&&, T>,
+                      std::is_convertible<const StatusOr<U>&&, T>>;
+
+// Detects whether `T` is constructible or convertible or assignable from
+// `StatusOr<U>`.
+template <typename T, typename U>
+using IsConstructibleOrConvertibleOrAssignableFromStatusOr =
+    absl::disjunction<IsConstructibleOrConvertibleFromStatusOr<T, U>,
+                      std::is_assignable<T&, StatusOr<U>&>,
+                      std::is_assignable<T&, const StatusOr<U>&>,
+                      std::is_assignable<T&, StatusOr<U>&&>,
+                      std::is_assignable<T&, const StatusOr<U>&&>>;
+
+// Detects whether direct initializing `StatusOr<T>` from `U` is ambiguous, i.e.
+// when `U` is `StatusOr<V>` and `T` is constructible or convertible from `V`.
+template <typename T, typename U>
+struct IsDirectInitializationAmbiguous
+    : public absl::conditional_t<
+          std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>,
+                       U>::value,
+          std::false_type,
+          IsDirectInitializationAmbiguous<
+              T, absl::remove_cv_t<absl::remove_reference_t<U>>>> {};
+
+template <typename T, typename V>
+struct IsDirectInitializationAmbiguous<T, absl::StatusOr<V>>
+    : public IsConstructibleOrConvertibleFromStatusOr<T, V> {};
+
+// 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_cv_t<absl::remove_reference_t<U>>>,
+    absl::negation<absl::disjunction<
+        std::is_same<absl::StatusOr<T>,
+                     absl::remove_cv_t<absl::remove_reference_t<U>>>,
+        std::is_same<absl::Status,
+                     absl::remove_cv_t<absl::remove_reference_t<U>>>,
+        std::is_same<absl::in_place_t,
+                     absl::remove_cv_t<absl::remove_reference_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:
+// 1. `U` is `StatusOr<V>`.
+// 2. `T` is constructible and assignable from `V`.
+// 3. `T` is constructible and assignable from `U` (i.e. `StatusOr<V>`).
+// For example, the following code is considered ambiguous:
+// (`T` is `bool`, `U` is `StatusOr<bool>`, `V` is `bool`)
+//   StatusOr<bool> s1 = true;  // s1.ok() && s1.ValueOrDie() == true
+//   StatusOr<bool> s2 = false;  // s2.ok() && s2.ValueOrDie() == false
+//   s1 = s2;  // ambiguous, `s1 = s2.ValueOrDie()` or `s1 = bool(s2)`?
+template <typename T, typename U>
+struct IsForwardingAssignmentAmbiguous
+    : public absl::conditional_t<
+          std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>,
+                       U>::value,
+          std::false_type,
+          IsForwardingAssignmentAmbiguous<
+              T, absl::remove_cv_t<absl::remove_reference_t<U>>>> {};
+
+template <typename T, typename U>
+struct IsForwardingAssignmentAmbiguous<T, absl::StatusOr<U>>
+    : public IsConstructibleOrConvertibleOrAssignableFromStatusOr<T, U> {};
+
+// Checks against the constraints of the forwarding assignment, i.e. whether
+// `StatusOr<T>::operator(U&&)` should participate in overload resolution.
+template <typename T, typename U>
+using IsForwardingAssignmentValid = absl::disjunction<
+    // Short circuits if T is basically U.
+    std::is_same<T, absl::remove_cv_t<absl::remove_reference_t<U>>>,
+    absl::negation<absl::disjunction<
+        std::is_same<absl::StatusOr<T>,
+                     absl::remove_cv_t<absl::remove_reference_t<U>>>,
+        std::is_same<absl::Status,
+                     absl::remove_cv_t<absl::remove_reference_t<U>>>,
+        std::is_same<absl::in_place_t,
+                     absl::remove_cv_t<absl::remove_reference_t<U>>>,
+        IsForwardingAssignmentAmbiguous<T, U>>>>;
+
+class Helper {
+ public:
+  // Move type-agnostic error handling to the .cc.
+  static void HandleInvalidStatusCtorArg(Status*);
+  ABSL_ATTRIBUTE_NORETURN static void Crash(const absl::Status& status);
+};
+
+// Construct an instance of T in `p` through placement new, passing Args... to
+// the constructor.
+// This abstraction is here mostly for the gcc performance fix.
+template <typename T, typename... Args>
+ABSL_ATTRIBUTE_NONNULL(1) void PlacementNew(void* p, Args&&... args) {
+  new (p) T(std::forward<Args>(args)...);
+}
+
+// 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.
+template <typename T>
+class StatusOrData {
+  template <typename U>
+  friend class StatusOrData;
+
+ public:
+  StatusOrData() = delete;
+
+  StatusOrData(const StatusOrData& other) {
+    if (other.ok()) {
+      MakeValue(other.data_);
+      MakeStatus();
+    } else {
+      MakeStatus(other.status_);
+    }
+  }
+
+  StatusOrData(StatusOrData&& other) noexcept {
+    if (other.ok()) {
+      MakeValue(std::move(other.data_));
+      MakeStatus();
+    } else {
+      MakeStatus(std::move(other.status_));
+    }
+  }
+
+  template <typename U>
+  explicit StatusOrData(const StatusOrData<U>& other) {
+    if (other.ok()) {
+      MakeValue(other.data_);
+      MakeStatus();
+    } else {
+      MakeStatus(other.status_);
+    }
+  }
+
+  template <typename U>
+  explicit StatusOrData(StatusOrData<U>&& other) {
+    if (other.ok()) {
+      MakeValue(std::move(other.data_));
+      MakeStatus();
+    } else {
+      MakeStatus(std::move(other.status_));
+    }
+  }
+
+  template <typename... Args>
+  explicit StatusOrData(absl::in_place_t, Args&&... args)
+      : data_(std::forward<Args>(args)...) {
+    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>
+  explicit StatusOrData(U&& v) : status_(std::forward<U>(v)) {
+    EnsureNotOk();
+  }
+
+  StatusOrData& operator=(const StatusOrData& other) {
+    if (this == &other) return *this;
+    if (other.ok())
+      Assign(other.data_);
+    else
+      AssignStatus(other.status_);
+    return *this;
+  }
+
+  StatusOrData& operator=(StatusOrData&& other) {
+    if (this == &other) return *this;
+    if (other.ok())
+      Assign(std::move(other.data_));
+    else
+      AssignStatus(std::move(other.status_));
+    return *this;
+  }
+
+  ~StatusOrData() {
+    if (ok()) {
+      status_.~Status();
+      data_.~T();
+    } else {
+      status_.~Status();
+    }
+  }
+
+  template <typename U>
+  void Assign(U&& value) {
+    if (ok()) {
+      data_ = std::forward<U>(value);
+    } else {
+      MakeValue(std::forward<U>(value));
+      status_ = OkStatus();
+    }
+  }
+
+  template <typename U>
+  void AssignStatus(U&& v) {
+    Clear();
+    status_ = static_cast<absl::Status>(std::forward<U>(v));
+    EnsureNotOk();
+  }
+
+  bool ok() const { return status_.ok(); }
+
+ protected:
+  // status_ will always be active after the constructor.
+  // We make it a union to be able to initialize exactly how we need without
+  // waste.
+  // Eg. in the copy constructor we use the default constructor of Status in
+  // the ok() path to avoid an extra Ref call.
+  union {
+    Status status_;
+  };
+
+  // data_ is active iff status_.ok()==true
+  struct Dummy {};
+  union {
+    // 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_;
+  };
+
+  void Clear() {
+    if (ok()) data_.~T();
+  }
+
+  void EnsureOk() const {
+    if (ABSL_PREDICT_FALSE(!ok())) Helper::Crash(status_);
+  }
+
+  void EnsureNotOk() {
+    if (ABSL_PREDICT_FALSE(ok())) Helper::HandleInvalidStatusCtorArg(&status_);
+  }
+
+  // Construct the value (ie. data_) through placement new with the passed
+  // argument.
+  template <typename... Arg>
+  void MakeValue(Arg&&... arg) {
+    internal_statusor::PlacementNew<T>(&dummy_, std::forward<Arg>(arg)...);
+  }
+
+  // Construct the status (ie. status_) through placement new with the passed
+  // argument.
+  template <typename... Args>
+  void MakeStatus(Args&&... args) {
+    internal_statusor::PlacementNew<Status>(&status_,
+                                            std::forward<Args>(args)...);
+  }
+};
+
+// Helper base classes to allow implicitly deleted constructors and assignment
+// operators in `StatusOr`. For example, `CopyCtorBase` will explicitly delete
+// the copy constructor when T is not copy constructible and `StatusOr` will
+// inherit that behavior implicitly.
+template <typename T, bool = std::is_copy_constructible<T>::value>
+struct CopyCtorBase {
+  CopyCtorBase() = default;
+  CopyCtorBase(const CopyCtorBase&) = default;
+  CopyCtorBase(CopyCtorBase&&) = default;
+  CopyCtorBase& operator=(const CopyCtorBase&) = default;
+  CopyCtorBase& operator=(CopyCtorBase&&) = default;
+};
+
+template <typename T>
+struct CopyCtorBase<T, false> {
+  CopyCtorBase() = default;
+  CopyCtorBase(const CopyCtorBase&) = delete;
+  CopyCtorBase(CopyCtorBase&&) = default;
+  CopyCtorBase& operator=(const CopyCtorBase&) = default;
+  CopyCtorBase& operator=(CopyCtorBase&&) = default;
+};
+
+template <typename T, bool = std::is_move_constructible<T>::value>
+struct MoveCtorBase {
+  MoveCtorBase() = default;
+  MoveCtorBase(const MoveCtorBase&) = default;
+  MoveCtorBase(MoveCtorBase&&) = default;
+  MoveCtorBase& operator=(const MoveCtorBase&) = default;
+  MoveCtorBase& operator=(MoveCtorBase&&) = default;
+};
+
+template <typename T>
+struct MoveCtorBase<T, false> {
+  MoveCtorBase() = default;
+  MoveCtorBase(const MoveCtorBase&) = default;
+  MoveCtorBase(MoveCtorBase&&) = delete;
+  MoveCtorBase& operator=(const MoveCtorBase&) = default;
+  MoveCtorBase& operator=(MoveCtorBase&&) = default;
+};
+
+template <typename T, bool = std::is_copy_constructible<T>::value&&
+                          std::is_copy_assignable<T>::value>
+struct CopyAssignBase {
+  CopyAssignBase() = default;
+  CopyAssignBase(const CopyAssignBase&) = default;
+  CopyAssignBase(CopyAssignBase&&) = default;
+  CopyAssignBase& operator=(const CopyAssignBase&) = default;
+  CopyAssignBase& operator=(CopyAssignBase&&) = default;
+};
+
+template <typename T>
+struct CopyAssignBase<T, false> {
+  CopyAssignBase() = default;
+  CopyAssignBase(const CopyAssignBase&) = default;
+  CopyAssignBase(CopyAssignBase&&) = default;
+  CopyAssignBase& operator=(const CopyAssignBase&) = delete;
+  CopyAssignBase& operator=(CopyAssignBase&&) = default;
+};
+
+template <typename T, bool = std::is_move_constructible<T>::value&&
+                          std::is_move_assignable<T>::value>
+struct MoveAssignBase {
+  MoveAssignBase() = default;
+  MoveAssignBase(const MoveAssignBase&) = default;
+  MoveAssignBase(MoveAssignBase&&) = default;
+  MoveAssignBase& operator=(const MoveAssignBase&) = default;
+  MoveAssignBase& operator=(MoveAssignBase&&) = default;
+};
+
+template <typename T>
+struct MoveAssignBase<T, false> {
+  MoveAssignBase() = default;
+  MoveAssignBase(const MoveAssignBase&) = default;
+  MoveAssignBase(MoveAssignBase&&) = default;
+  MoveAssignBase& operator=(const MoveAssignBase&) = default;
+  MoveAssignBase& operator=(MoveAssignBase&&) = delete;
+};
+
+ABSL_ATTRIBUTE_NORETURN void ThrowBadStatusOrAccess(absl::Status status);
+
+}  // namespace internal_statusor
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_
diff --git a/absl/status/status.cc b/absl/status/status.cc
index df3b740..51a0d26 100644
--- a/absl/status/status.cc
+++ b/absl/status/status.cc
@@ -27,8 +27,6 @@
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
-// The implementation was intentionally kept same as util::error::Code_Name()
-// to ease the migration.
 std::string StatusCodeToString(StatusCode code) {
   switch (code) {
     case StatusCode::kOk:
@@ -80,7 +78,7 @@
                                  absl::string_view type_url) {
   if (payloads == nullptr) return -1;
 
-  for (int i = 0; i < payloads->size(); ++i) {
+  for (size_t i = 0; i < payloads->size(); ++i) {
     if ((*payloads)[i].type_url == type_url) return i;
   }
 
@@ -169,15 +167,15 @@
     bool in_reverse =
         payloads->size() > 1 && reinterpret_cast<uintptr_t>(payloads) % 13 > 6;
 
-    for (int index = 0; index < payloads->size(); ++index) {
+    for (size_t index = 0; index < payloads->size(); ++index) {
       const auto& elem =
           (*payloads)[in_reverse ? payloads->size() - 1 - index : index];
 
 #ifdef NDEBUG
       visitor(elem.type_url, elem.payload);
 #else
-      // In debug mode invaldiate the type url to prevent users from relying on
-      // this std::string lifetime.
+      // In debug mode invalidate the type url to prevent users from relying on
+      // this string lifetime.
 
       // NOLINTNEXTLINE intentional extra conversion to force temporary.
       visitor(std::string(elem.type_url), elem.payload);
@@ -209,13 +207,12 @@
   }
 }
 
-uintptr_t Status::NewRep(absl::StatusCode code, absl::string_view msg,
-                         std::unique_ptr<status_internal::Payloads> payloads) {
-  status_internal::StatusRep* rep = new status_internal::StatusRep;
-  rep->ref.store(1, std::memory_order_relaxed);
-  rep->code = code;
-  rep->message.assign(msg.data(), msg.size());
-  rep->payloads = std::move(payloads);
+uintptr_t Status::NewRep(
+    absl::StatusCode code, absl::string_view msg,
+    std::unique_ptr<status_internal::Payloads> payloads) {
+  status_internal::StatusRep* rep = new status_internal::StatusRep(
+      code, std::string(msg.data(), msg.size()),
+      std::move(payloads));
   return PointerToRep(rep);
 }
 
@@ -241,8 +238,9 @@
 void Status::PrepareToModify() {
   ABSL_RAW_CHECK(!ok(), "PrepareToModify shouldn't be called on OK status.");
   if (IsInlined(rep_)) {
-    rep_ = NewRep(static_cast<absl::StatusCode>(raw_code()),
-                  absl::string_view(), nullptr);
+    rep_ =
+        NewRep(static_cast<absl::StatusCode>(raw_code()), absl::string_view(),
+               nullptr);
     return;
   }
 
@@ -253,7 +251,8 @@
     if (rep->payloads) {
       payloads = absl::make_unique<status_internal::Payloads>(*rep->payloads);
     }
-    rep_ = NewRep(rep->code, message(), std::move(payloads));
+    rep_ = NewRep(rep->code, message(),
+                  std::move(payloads));
     UnrefNonInlined(rep_i);
   }
 }
@@ -292,20 +291,26 @@
   return true;
 }
 
-std::string Status::ToStringSlow() const {
+std::string Status::ToStringSlow(StatusToStringMode mode) const {
   std::string text;
   absl::StrAppend(&text, absl::StatusCodeToString(code()), ": ", message());
-  status_internal::StatusPayloadPrinter printer =
-      status_internal::GetStatusPayloadPrinter();
-  this->ForEachPayload([&](absl::string_view type_url,
-                           const absl::Cord& payload) {
-    absl::optional<std::string> result;
-    if (printer) result = printer(type_url, payload);
-    absl::StrAppend(
-        &text, " [", type_url, "='",
-        result.has_value() ? *result : absl::CHexEscape(std::string(payload)),
-        "']");
-  });
+
+  const bool with_payload = (mode & StatusToStringMode::kWithPayload) ==
+                      StatusToStringMode::kWithPayload;
+
+  if (with_payload) {
+    status_internal::StatusPayloadPrinter printer =
+        status_internal::GetStatusPayloadPrinter();
+    this->ForEachPayload([&](absl::string_view type_url,
+                             const absl::Cord& payload) {
+      absl::optional<std::string> result;
+      if (printer) result = printer(type_url, payload);
+      absl::StrAppend(
+          &text, " [", type_url, "='",
+          result.has_value() ? *result : absl::CHexEscape(std::string(payload)),
+          "']");
+    });
+  }
 
   return text;
 }
diff --git a/absl/status/status.h b/absl/status/status.h
index 9706d4b..61486fe 100644
--- a/absl/status/status.h
+++ b/absl/status/status.h
@@ -11,6 +11,43 @@
 // 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: status.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the Abseil `status` library, consisting of:
+//
+//   * An `absl::Status` class for holding error handling information
+//   * A set of canonical `absl::StatusCode` error codes, and associated
+//     utilities for generating and propagating status codes.
+//   * A set of helper functions for creating status codes and checking their
+//     values
+//
+// Within Google, `absl::Status` is the primary mechanism for gracefully
+// handling errors across API boundaries (and in particular across RPC
+// boundaries). Some of these errors may be recoverable, but others may not.
+// Most functions that can produce a recoverable error should be designed to
+// return an `absl::Status` (or `absl::StatusOr`).
+//
+// Example:
+//
+// absl::Status myFunction(absl::string_view fname, ...) {
+//   ...
+//   // encounter error
+//   if (error condition) {
+//     return absl::InvalidArgumentError("bad mode");
+//   }
+//   // else, return OK
+//   return absl::OkStatus();
+// }
+//
+// An `absl::Status` is designed to either return "OK" or one of a number of
+// different error codes, corresponding to typical error conditions.
+// In almost all cases, when using `absl::Status` you should use the canonical
+// error codes (of type `absl::StatusCode`) enumerated in this header file.
+// These canonical codes are understood across the codebase and will be
+// accepted across all API and RPC boundaries.
 #ifndef ABSL_STATUS_STATUS_H_
 #define ABSL_STATUS_STATUS_H_
 
@@ -18,165 +55,536 @@
 #include <string>
 
 #include "absl/container/inlined_vector.h"
+#include "absl/status/internal/status_internal.h"
 #include "absl/strings/cord.h"
+#include "absl/strings/string_view.h"
 #include "absl/types/optional.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
+// absl::StatusCode
+//
+// An `absl::StatusCode` is an enumerated type indicating either no error ("OK")
+// or an error condition. In most cases, an `absl::Status` indicates a
+// recoverable error, and the purpose of signalling an error is to indicate what
+// action to take in response to that error. These error codes map to the proto
+// RPC error codes indicated in https://cloud.google.com/apis/design/errors.
+//
+// The errors listed below are the canonical errors associated with
+// `absl::Status` and are used throughout the codebase. As a result, these
+// error codes are somewhat generic.
+//
+// In general, try to return the most specific error that applies if more than
+// one error may pertain. For example, prefer `kOutOfRange` over
+// `kFailedPrecondition` if both codes apply. Similarly prefer `kNotFound` or
+// `kAlreadyExists` over `kFailedPrecondition`.
+//
+// Because these errors may travel RPC boundaries, these codes are tied to the
+// `google.rpc.Code` definitions within
+// https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto
+// The string value of these RPC codes is denoted within each enum below.
+//
+// If your error handling code requires more context, you can attach payloads
+// to your status. See `absl::Status::SetPayload()` and
+// `absl::Status::GetPayload()` below.
 enum class StatusCode : int {
+  // StatusCode::kOk
+  //
+  // kOK (gRPC code "OK") does not indicate an error; this value is returned on
+  // success. It is typical to check for this value before proceeding on any
+  // given call across an API or RPC boundary. To check this value, use the
+  // `absl::Status::ok()` member function rather than inspecting the raw code.
   kOk = 0,
+
+  // StatusCode::kCancelled
+  //
+  // kCancelled (gRPC code "CANCELLED") indicates the operation was cancelled,
+  // typically by the caller.
   kCancelled = 1,
+
+  // StatusCode::kUnknown
+  //
+  // kUnknown (gRPC code "UNKNOWN") indicates an unknown error occurred. In
+  // general, more specific errors should be raised, if possible. Errors raised
+  // by APIs that do not return enough error information may be converted to
+  // this error.
   kUnknown = 2,
+
+  // StatusCode::kInvalidArgument
+  //
+  // kInvalidArgument (gRPC code "INVALID_ARGUMENT") indicates the caller
+  // specified an invalid argument, such a malformed filename. Note that such
+  // errors should be narrowly limited to indicate to the invalid nature of the
+  // arguments themselves. Errors with validly formed arguments that may cause
+  // errors with the state of the receiving system should be denoted with
+  // `kFailedPrecondition` instead.
   kInvalidArgument = 3,
+
+  // StatusCode::kDeadlineExceeded
+  //
+  // kDeadlineExceeded (gRPC code "DEADLINE_EXCEEDED") indicates a deadline
+  // expired before the operation could complete. For operations that may change
+  // state within a system, this error may be returned even if the operation has
+  // completed successfully. For example, a successful response from a server
+  // could have been delayed long enough for the deadline to expire.
   kDeadlineExceeded = 4,
+
+  // StatusCode::kNotFound
+  //
+  // kNotFound (gRPC code "NOT_FOUND") indicates some requested entity (such as
+  // a file or directory) was not found.
+  //
+  // `kNotFound` is useful if a request should be denied for an entire class of
+  // users, such as during a gradual feature rollout or undocumented allow list.
+  // If, instead, a request should be denied for specific sets of users, such as
+  // through user-based access control, use `kPermissionDenied` instead.
   kNotFound = 5,
+
+  // StatusCode::kAlreadyExists
+  //
+  // kAlreadyExists (gRPC code "ALREADY_EXISTS") indicates the entity that a
+  // caller attempted to create (such as file or directory) is already present.
   kAlreadyExists = 6,
+
+  // StatusCode::kPermissionDenied
+  //
+  // kPermissionDenied (gRPC code "PERMISSION_DENIED") indicates that the caller
+  // does not have permission to execute the specified operation. Note that this
+  // error is different than an error due to an *un*authenticated user. This
+  // error code does not imply the request is valid or the requested entity
+  // exists or satisfies any other pre-conditions.
+  //
+  // `kPermissionDenied` must not be used for rejections caused by exhausting
+  // some resource. Instead, use `kResourceExhausted` for those errors.
+  // `kPermissionDenied` must not be used if the caller cannot be identified.
+  // Instead, use `kUnauthenticated` for those errors.
   kPermissionDenied = 7,
+
+  // StatusCode::kResourceExhausted
+  //
+  // kResourceExhausted (gRPC code "RESOURCE_EXHAUSTED") indicates some resource
+  // has been exhausted, perhaps a per-user quota, or perhaps the entire file
+  // system is out of space.
   kResourceExhausted = 8,
+
+  // StatusCode::kFailedPrecondition
+  //
+  // kFailedPrecondition (gRPC code "FAILED_PRECONDITION") indicates that the
+  // operation was rejected because the system is not in a state required for
+  // the operation's execution. For example, a directory to be deleted may be
+  // non-empty, an "rmdir" operation is applied to a non-directory, etc.
+  //
+  // Some guidelines that may help a service implementer in deciding between
+  // `kFailedPrecondition`, `kAborted`, and `kUnavailable`:
+  //
+  //  (a) Use `kUnavailable` if the client can retry just the failing call.
+  //  (b) Use `kAborted` if the client should retry at a higher transaction
+  //      level (such as when a client-specified test-and-set fails, indicating
+  //      the client should restart a read-modify-write sequence).
+  //  (c) Use `kFailedPrecondition` if the client should not retry until
+  //      the system state has been explicitly fixed. For example, if an "rmdir"
+  //      fails because the directory is non-empty, `kFailedPrecondition`
+  //      should be returned since the client should not retry unless
+  //      the files are deleted from the directory.
   kFailedPrecondition = 9,
+
+  // StatusCode::kAborted
+  //
+  // kAborted (gRPC code "ABORTED") indicates the operation was aborted,
+  // typically due to a concurrency issue such as a sequencer check failure or a
+  // failed transaction.
+  //
+  // See the guidelines above for deciding between `kFailedPrecondition`,
+  // `kAborted`, and `kUnavailable`.
   kAborted = 10,
+
+  // StatusCode::kOutOfRange
+  //
+  // kOutOfRange (gRPC code "OUT_OF_RANGE") indicates the operation was
+  // attempted past the valid range, such as seeking or reading past an
+  // end-of-file.
+  //
+  // Unlike `kInvalidArgument`, this error indicates a problem that may
+  // be fixed if the system state changes. For example, a 32-bit file
+  // system will generate `kInvalidArgument` if asked to read at an
+  // offset that is not in the range [0,2^32-1], but it will generate
+  // `kOutOfRange` if asked to read from an offset past the current
+  // file size.
+  //
+  // There is a fair bit of overlap between `kFailedPrecondition` and
+  // `kOutOfRange`.  We recommend using `kOutOfRange` (the more specific
+  // error) when it applies so that callers who are iterating through
+  // a space can easily look for an `kOutOfRange` error to detect when
+  // they are done.
   kOutOfRange = 11,
+
+  // StatusCode::kUnimplemented
+  //
+  // kUnimplemented (gRPC code "UNIMPLEMENTED") indicates the operation is not
+  // implemented or supported in this service. In this case, the operation
+  // should not be re-attempted.
   kUnimplemented = 12,
+
+  // StatusCode::kInternal
+  //
+  // kInternal (gRPC code "INTERNAL") indicates an internal error has occurred
+  // and some invariants expected by the underlying system have not been
+  // satisfied. This error code is reserved for serious errors.
   kInternal = 13,
+
+  // StatusCode::kUnavailable
+  //
+  // kUnavailable (gRPC code "UNAVAILABLE") indicates the service is currently
+  // unavailable and that this is most likely a transient condition. An error
+  // such as this can be corrected by retrying with a backoff scheme. Note that
+  // it is not always safe to retry non-idempotent operations.
+  //
+  // See the guidelines above for deciding between `kFailedPrecondition`,
+  // `kAborted`, and `kUnavailable`.
   kUnavailable = 14,
+
+  // StatusCode::kDataLoss
+  //
+  // kDataLoss (gRPC code "DATA_LOSS") indicates that unrecoverable data loss or
+  // corruption has occurred. As this error is serious, proper alerting should
+  // be attached to errors such as this.
   kDataLoss = 15,
+
+  // StatusCode::kUnauthenticated
+  //
+  // kUnauthenticated (gRPC code "UNAUTHENTICATED") indicates that the request
+  // does not have valid authentication credentials for the operation. Correct
+  // the authentication and try again.
   kUnauthenticated = 16,
+
+  // StatusCode::DoNotUseReservedForFutureExpansionUseDefaultInSwitchInstead_
+  //
+  // NOTE: this error code entry should not be used and you should not rely on
+  // its value, which may change.
+  //
+  // The purpose of this enumerated value is to force people who handle status
+  // codes with `switch()` statements to *not* simply enumerate all possible
+  // values, but instead provide a "default:" case. Providing such a default
+  // case ensures that code will compile when new codes are added.
   kDoNotUseReservedForFutureExpansionUseDefaultInSwitchInstead_ = 20
 };
 
+// StatusCodeToString()
+//
 // Returns the name for the status code, or "" if it is an unknown value.
 std::string StatusCodeToString(StatusCode code);
 
+// operator<<
+//
 // Streams StatusCodeToString(code) to `os`.
 std::ostream& operator<<(std::ostream& os, StatusCode code);
 
-namespace status_internal {
-
-// Container for status payloads.
-struct Payload {
-  std::string type_url;
-  absl::Cord payload;
+// absl::StatusToStringMode
+//
+// An `absl::StatusToStringMode` is an enumerated type indicating how
+// `absl::Status::ToString()` should construct the output string for an non-ok
+// status.
+enum class StatusToStringMode : int {
+  // ToString will not contain any extra data (such as payloads). It will only
+  // contain the error code and message, if any.
+  kWithNoExtraData = 0,
+  // ToString will contain the payloads.
+  kWithPayload = 1 << 0,
+  // ToString will include all the extra data this Status has.
+  kWithEverything = ~kWithNoExtraData,
 };
 
-using Payloads = absl::InlinedVector<Payload, 1>;
+// absl::StatusToStringMode is specified as a bitmask type, which means the
+// following operations must be provided:
+inline constexpr StatusToStringMode operator&(StatusToStringMode lhs,
+                                              StatusToStringMode rhs) {
+  return static_cast<StatusToStringMode>(static_cast<int>(lhs) &
+                                         static_cast<int>(rhs));
+}
+inline constexpr StatusToStringMode operator|(StatusToStringMode lhs,
+                                              StatusToStringMode rhs) {
+  return static_cast<StatusToStringMode>(static_cast<int>(lhs) |
+                                         static_cast<int>(rhs));
+}
+inline constexpr StatusToStringMode operator^(StatusToStringMode lhs,
+                                              StatusToStringMode rhs) {
+  return static_cast<StatusToStringMode>(static_cast<int>(lhs) ^
+                                         static_cast<int>(rhs));
+}
+inline constexpr StatusToStringMode operator~(StatusToStringMode arg) {
+  return static_cast<StatusToStringMode>(~static_cast<int>(arg));
+}
+inline StatusToStringMode& operator&=(StatusToStringMode& lhs,
+                                      StatusToStringMode rhs) {
+  lhs = lhs & rhs;
+  return lhs;
+}
+inline StatusToStringMode& operator|=(StatusToStringMode& lhs,
+                                      StatusToStringMode rhs) {
+  lhs = lhs | rhs;
+  return lhs;
+}
+inline StatusToStringMode& operator^=(StatusToStringMode& lhs,
+                                      StatusToStringMode rhs) {
+  lhs = lhs ^ rhs;
+  return lhs;
+}
 
-// Reference-counted representation of Status data.
-struct StatusRep {
-  std::atomic<int32_t> ref;
-  absl::StatusCode code;
-  std::string message;
-  std::unique_ptr<status_internal::Payloads> payloads;
-};
-
-absl::StatusCode MapToLocalCode(int value);
-}  // namespace status_internal
-
-class ABSL_MUST_USE_RESULT Status final {
+// absl::Status
+//
+// The `absl::Status` class is generally used to gracefully handle errors
+// across API boundaries (and in particular across RPC boundaries). Some of
+// these errors may be recoverable, but others may not. Most
+// functions which can produce a recoverable error should be designed to return
+// either an `absl::Status` (or the similar `absl::StatusOr<T>`, which holds
+// either an object of type `T` or an error).
+//
+// API developers should construct their functions to return `absl::OkStatus()`
+// upon success, or an `absl::StatusCode` upon another type of error (e.g
+// an `absl::StatusCode::kInvalidArgument` error). The API provides convenience
+// functions to constuct each status code.
+//
+// Example:
+//
+// absl::Status myFunction(absl::string_view fname, ...) {
+//   ...
+//   // encounter error
+//   if (error condition) {
+//     // Construct an absl::StatusCode::kInvalidArgument error
+//     return absl::InvalidArgumentError("bad mode");
+//   }
+//   // else, return OK
+//   return absl::OkStatus();
+// }
+//
+// Users handling status error codes should prefer checking for an OK status
+// using the `ok()` member function. Handling multiple error codes may justify
+// use of switch statement, but only check for error codes you know how to
+// handle; do not try to exhaustively match against all canonical error codes.
+// Errors that cannot be handled should be logged and/or propagated for higher
+// levels to deal with. If you do use a switch statement, make sure that you
+// also provide a `default:` switch case, so that code does not break as other
+// canonical codes are added to the API.
+//
+// Example:
+//
+//   absl::Status result = DoSomething();
+//   if (!result.ok()) {
+//     LOG(ERROR) << result;
+//   }
+//
+//   // Provide a default if switching on multiple error codes
+//   switch (result.code()) {
+//     // The user hasn't authenticated. Ask them to reauth
+//     case absl::StatusCode::kUnauthenticated:
+//       DoReAuth();
+//       break;
+//     // The user does not have permission. Log an error.
+//     case absl::StatusCode::kPermissionDenied:
+//       LOG(ERROR) << result;
+//       break;
+//     // Propagate the error otherwise.
+//     default:
+//       return true;
+//   }
+//
+// An `absl::Status` can optionally include a payload with more information
+// about the error. Typically, this payload serves one of several purposes:
+//
+//   * It may provide more fine-grained semantic information about the error to
+//     facilitate actionable remedies.
+//   * It may provide human-readable contexual information that is more
+//     appropriate to display to an end user.
+//
+// Example:
+//
+//   absl::Status result = DoSomething();
+//   // Inform user to retry after 30 seconds
+//   // See more error details in googleapis/google/rpc/error_details.proto
+//   if (absl::IsResourceExhausted(result)) {
+//     google::rpc::RetryInfo info;
+//     info.retry_delay().seconds() = 30;
+//     // Payloads require a unique key (a URL to ensure no collisions with
+//     // other payloads), and an `absl::Cord` to hold the encoded data.
+//     absl::string_view url = "type.googleapis.com/google.rpc.RetryInfo";
+//     result.SetPayload(url, info.SerializeAsCord());
+//     return result;
+//   }
+//
+// For documentation see https://abseil.io/docs/cpp/guides/status.
+//
+// Returned Status objects may not be ignored. status_internal.h has a forward
+// declaration of the form
+// class ABSL_MUST_USE_RESULT Status;
+class Status final {
  public:
-  // Creates an OK status with no message or payload.
+  // Constructors
+
+  // This default constructor creates an OK status with no message or payload.
+  // Avoid this constructor and prefer explicit construction of an OK status
+  // with `absl::OkStatus()`.
   Status();
 
-  // Create a status in the canonical error space with the specified code and
-  // error message.  If `code == util::error::OK`, `msg` is ignored and an
-  // object identical to an OK status is constructed.
+  // Creates a status in the canonical error space with the specified
+  // `absl::StatusCode` and error message.  If `code == absl::StatusCode::kOk`,  // NOLINT
+  // `msg` is ignored and an object identical to an OK status is constructed.
   //
-  // `msg` must be in UTF-8. The implementation may complain (e.g.,
+  // The `msg` string must be in UTF-8. The implementation may complain (e.g.,  // NOLINT
   // by printing a warning) if it is not.
   Status(absl::StatusCode code, absl::string_view msg);
 
   Status(const Status&);
   Status& operator=(const Status& x);
 
-  // Move operations.
+  // Move operators
+
   // The moved-from state is valid but unspecified.
   Status(Status&&) noexcept;
   Status& operator=(Status&&);
 
   ~Status();
 
-  // If `this->ok()`, stores `new_status` into *this. If `!this->ok()`,
-  // preserves the current data. May, in the future, augment the current status
-  // with additional information about `new_status`.
+  // Status::Update()
   //
-  // Convenient way of keeping track of the first error encountered.
-  // Instead of:
-  //   if (overall_status.ok()) overall_status = new_status
-  // Use:
+  // Updates the existing status with `new_status` provided that `this->ok()`.
+  // If the existing status already contains a non-OK error, this update has no
+  // effect and preserves the current data. Note that this behavior may change
+  // in the future to augment a current non-ok status with additional
+  // information about `new_status`.
+  //
+  // `Update()` provides a convenient way of keeping track of the first error
+  // encountered.
+  //
+  // Example:
+  //   // Instead of "if (overall_status.ok()) overall_status = new_status"
   //   overall_status.Update(new_status);
   //
-  // Style guide exception for rvalue reference granted in CL 153567220.
   void Update(const Status& new_status);
   void Update(Status&& new_status);
 
-  // Returns true if the Status is OK.
+  // Status::ok()
+  //
+  // Returns `true` if `this->ok()`. Prefer checking for an OK status using this
+  // member function.
   ABSL_MUST_USE_RESULT bool ok() const;
 
-  // Returns the (canonical) error code.
+  // Status::code()
+  //
+  // Returns the canonical error code of type `absl::StatusCode` of this status.
   absl::StatusCode code() const;
 
-  // Returns the raw (canonical) error code which could be out of the range of
-  // the local `absl::StatusCode` enum. NOTE: This should only be called when
-  // converting to wire format. Use `code` for error handling.
+  // Status::raw_code()
+  //
+  // Returns a raw (canonical) error code corresponding to the enum value of
+  // `google.rpc.Code` definitions within
+  // https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto.
+  // These values could be out of the range of canonical `absl::StatusCode`
+  // enum values.
+  //
+  // NOTE: This function should only be called when converting to an associated
+  // wire format. Use `Status::code()` for error handling.
   int raw_code() const;
 
-  // Returns the error message.  Note: prefer ToString() for debug logging.
-  // This message rarely describes the error code.  It is not unusual for the
-  // error message to be the empty std::string.
+  // Status::message()
+  //
+  // Returns the error message associated with this error code, if available.
+  // Note that this message rarely describes the error code.  It is not unusual
+  // for the error message to be the empty string. As a result, prefer
+  // `Status::ToString()` for debug logging.
   absl::string_view message() const;
 
   friend bool operator==(const Status&, const Status&);
   friend bool operator!=(const Status&, const Status&);
 
-  // Returns a combination of the error code name, the message and the payloads.
-  // You can expect the code name and the message to be substrings of the
-  // result, and the payloads to be printed by the registered printer extensions
-  // if they are recognized.
-  // WARNING: Do not depend on the exact format of the result of `ToString()`
-  // which is subject to change.
-  std::string ToString() const;
+  // Status::ToString()
+  //
+  // Returns a string based on the `mode`. By default, it returns combination of
+  // the error code name, the message and any associated payload messages. This
+  // string is designed simply to be human readable and its exact format should
+  // not be load bearing. Do not depend on the exact format of the result of
+  // `ToString()` which is subject to change.
+  //
+  // The printed code name and the message are generally substrings of the
+  // result, and the payloads to be printed use the status payload printer
+  // mechanism (which is internal).
+  std::string ToString(
+      StatusToStringMode mode = StatusToStringMode::kWithPayload) const;
 
+  // Status::IgnoreError()
+  //
   // Ignores any errors. This method does nothing except potentially suppress
   // complaints from any tools that are checking that errors are not dropped on
   // the floor.
   void IgnoreError() const;
 
-  // Swap the contents of `a` with `b`
+  // swap()
+  //
+  // Swap the contents of one status with another.
   friend void swap(Status& a, Status& b);
 
-  // Payload management APIs
+  //----------------------------------------------------------------------------
+  // Payload Management APIs
+  //----------------------------------------------------------------------------
 
-  // Type URL should be unique and follow the naming convention below:
-  // The idea of type URL comes from `google.protobuf.Any`
-  // (https://developers.google.com/protocol-buffers/docs/proto3#any). The
-  // type URL should be globally unique and follow the format of URL
-  // (https://en.wikipedia.org/wiki/URL). The default type URL for a given
-  // protobuf message type is "type.googleapis.com/packagename.messagename". For
-  // other custom wire formats, users should define the format of type URL in a
-  // similar practice so as to minimize the chance of conflict between type
-  // URLs. Users should make sure that the type URL can be mapped to a concrete
+  // A payload may be attached to a status to provide additional context to an
+  // error that may not be satisifed by an existing `absl::StatusCode`.
+  // Typically, this payload serves one of several purposes:
+  //
+  //   * It may provide more fine-grained semantic information about the error
+  //     to facilitate actionable remedies.
+  //   * It may provide human-readable contexual information that is more
+  //     appropriate to display to an end user.
+  //
+  // A payload consists of a [key,value] pair, where the key is a string
+  // referring to a unique "type URL" and the value is an object of type
+  // `absl::Cord` to hold the contextual data.
+  //
+  // The "type URL" should be unique and follow the format of a URL
+  // (https://en.wikipedia.org/wiki/URL) and, ideally, provide some
+  // documentation or schema on how to interpret its associated data. For
+  // example, the default type URL for a protobuf message type is
+  // "type.googleapis.com/packagename.messagename". Other custom wire formats
+  // should define the format of type URL in a similar practice so as to
+  // minimize the chance of conflict between type URLs.
+  // Users should ensure that the type URL can be mapped to a concrete
   // C++ type if they want to deserialize the payload and read it effectively.
+  //
+  // To attach a payload to a status object, call `Status::SetPayload()`,
+  // passing it the type URL and an `absl::Cord` of associated data. Similarly,
+  // to extract the payload from a status, call `Status::GetPayload()`. You
+  // may attach multiple payloads (with differing type URLs) to any given
+  // status object, provided that the status is currently exhibiting an error
+  // code (i.e. is not OK).
 
-  // Gets the payload based for `type_url` key, if it is present.
+  // Status::GetPayload()
+  //
+  // Gets the payload of a status given its unique `type_url` key, if present.
   absl::optional<absl::Cord> GetPayload(absl::string_view type_url) const;
 
-  // Sets the payload for `type_url` key for a non-ok status, overwriting any
-  // existing payload for `type_url`.
+  // Status::SetPayload()
   //
-  // NOTE: Does nothing if the Status is ok.
+  // Sets the payload for a non-ok status using a `type_url` key, overwriting
+  // any existing payload for that `type_url`.
+  //
+  // NOTE: This function does nothing if the Status is ok.
   void SetPayload(absl::string_view type_url, absl::Cord payload);
 
-  // Erases the payload corresponding to the `type_url` key.  Returns true if
+  // Status::ErasePayload()
+  //
+  // Erases the payload corresponding to the `type_url` key.  Returns `true` if
   // the payload was present.
   bool ErasePayload(absl::string_view type_url);
 
-  // Iterates over the stored payloads and calls `visitor(type_key, payload)`
-  // for each one.
+  // Status::ForEachPayload()
   //
-  // NOTE: The order of calls to `visitor` is not specified and may change at
+  // Iterates over the stored payloads and calls the
+  // `visitor(type_key, payload)` callable for each one.
+  //
+  // NOTE: The order of calls to `visitor()` is not specified and may change at
   // any time.
   //
-  // NOTE: Any mutation on the same 'Status' object during visitation is
+  // NOTE: Any mutation on the same 'absl::Status' object during visitation is
   // forbidden and could result in undefined behavior.
   void ForEachPayload(
       const std::function<void(absl::string_view, const absl::Cord&)>& visitor)
@@ -201,8 +609,9 @@
   status_internal::Payloads* GetPayloads();
 
   // Takes ownership of payload.
-  static uintptr_t NewRep(absl::StatusCode code, absl::string_view msg,
-                          std::unique_ptr<status_internal::Payloads> payload);
+  static uintptr_t NewRep(
+      absl::StatusCode code, absl::string_view msg,
+      std::unique_ptr<status_internal::Payloads> payload);
   static bool EqualsSlow(const absl::Status& a, const absl::Status& b);
 
   // MSVC 14.0 limitation requires the const.
@@ -231,8 +640,7 @@
   static uintptr_t PointerToRep(status_internal::StatusRep* r);
   static status_internal::StatusRep* RepToPointer(uintptr_t r);
 
-  // Returns std::string for non-ok Status.
-  std::string ToStringSlow() const;
+  std::string ToStringSlow(StatusToStringMode mode) const;
 
   // Status supports two different representations.
   //  - When the low bit is off it is an inlined representation.
@@ -245,14 +653,93 @@
   uintptr_t rep_;
 };
 
-// Returns an OK status, equivalent to a default constructed instance.
+// OkStatus()
+//
+// Returns an OK status, equivalent to a default constructed instance. Prefer
+// usage of `absl::OkStatus()` when constructing such an OK status.
 Status OkStatus();
 
+// operator<<()
+//
 // Prints a human-readable representation of `x` to `os`.
 std::ostream& operator<<(std::ostream& os, const Status& x);
 
-// -----------------------------------------------------------------
+// IsAborted()
+// IsAlreadyExists()
+// IsCancelled()
+// IsDataLoss()
+// IsDeadlineExceeded()
+// IsFailedPrecondition()
+// IsInternal()
+// IsInvalidArgument()
+// IsNotFound()
+// IsOutOfRange()
+// IsPermissionDenied()
+// IsResourceExhausted()
+// IsUnauthenticated()
+// IsUnavailable()
+// IsUnimplemented()
+// IsUnknown()
+//
+// These convenience functions return `true` if a given status matches the
+// `absl::StatusCode` error code of its associated function.
+ABSL_MUST_USE_RESULT bool IsAborted(const Status& status);
+ABSL_MUST_USE_RESULT bool IsAlreadyExists(const Status& status);
+ABSL_MUST_USE_RESULT bool IsCancelled(const Status& status);
+ABSL_MUST_USE_RESULT bool IsDataLoss(const Status& status);
+ABSL_MUST_USE_RESULT bool IsDeadlineExceeded(const Status& status);
+ABSL_MUST_USE_RESULT bool IsFailedPrecondition(const Status& status);
+ABSL_MUST_USE_RESULT bool IsInternal(const Status& status);
+ABSL_MUST_USE_RESULT bool IsInvalidArgument(const Status& status);
+ABSL_MUST_USE_RESULT bool IsNotFound(const Status& status);
+ABSL_MUST_USE_RESULT bool IsOutOfRange(const Status& status);
+ABSL_MUST_USE_RESULT bool IsPermissionDenied(const Status& status);
+ABSL_MUST_USE_RESULT bool IsResourceExhausted(const Status& status);
+ABSL_MUST_USE_RESULT bool IsUnauthenticated(const Status& status);
+ABSL_MUST_USE_RESULT bool IsUnavailable(const Status& status);
+ABSL_MUST_USE_RESULT bool IsUnimplemented(const Status& status);
+ABSL_MUST_USE_RESULT bool IsUnknown(const Status& status);
+
+// AbortedError()
+// AlreadyExistsError()
+// CancelledError()
+// DataLossError()
+// DeadlineExceededError()
+// FailedPreconditionError()
+// InternalError()
+// InvalidArgumentError()
+// NotFoundError()
+// OutOfRangeError()
+// PermissionDeniedError()
+// ResourceExhaustedError()
+// UnauthenticatedError()
+// UnavailableError()
+// UnimplementedError()
+// UnknownError()
+//
+// These convenience functions create an `absl::Status` object with an error
+// code as indicated by the associated function name, using the error message
+// passed in `message`.
+Status AbortedError(absl::string_view message);
+Status AlreadyExistsError(absl::string_view message);
+Status CancelledError(absl::string_view message);
+Status DataLossError(absl::string_view message);
+Status DeadlineExceededError(absl::string_view message);
+Status FailedPreconditionError(absl::string_view message);
+Status InternalError(absl::string_view message);
+Status InvalidArgumentError(absl::string_view message);
+Status NotFoundError(absl::string_view message);
+Status OutOfRangeError(absl::string_view message);
+Status PermissionDeniedError(absl::string_view message);
+Status ResourceExhaustedError(absl::string_view message);
+Status UnauthenticatedError(absl::string_view message);
+Status UnavailableError(absl::string_view message);
+Status UnimplementedError(absl::string_view message);
+Status UnknownError(absl::string_view message);
+
+//------------------------------------------------------------------------------
 // Implementation details follow
+//------------------------------------------------------------------------------
 
 inline Status::Status() : rep_(CodeToInlinedRep(absl::StatusCode::kOk)) {}
 
@@ -276,9 +763,11 @@
 
 inline Status& Status::operator=(Status&& x) {
   uintptr_t old_rep = rep_;
-  rep_ = x.rep_;
-  x.rep_ = MovedFromRep();
-  Unref(old_rep);
+  if (x.rep_ != old_rep) {
+    rep_ = x.rep_;
+    x.rep_ = MovedFromRep();
+    Unref(old_rep);
+  }
   return *this;
 }
 
@@ -315,8 +804,8 @@
   return !(lhs == rhs);
 }
 
-inline std::string Status::ToString() const {
-  return ok() ? "OK" : ToStringSlow();
+inline std::string Status::ToString(StatusToStringMode mode) const {
+  return ok() ? "OK" : ToStringSlow(mode);
 }
 
 inline void Status::IgnoreError() const {
@@ -378,50 +867,11 @@
 
 inline Status OkStatus() { return Status(); }
 
-// Each of the functions below creates a Status object with a particular error
-// code and the given message. The error code of the returned status object
-// matches the name of the function.
-Status AbortedError(absl::string_view message);
-Status AlreadyExistsError(absl::string_view message);
-Status CancelledError(absl::string_view message);
-Status DataLossError(absl::string_view message);
-Status DeadlineExceededError(absl::string_view message);
-Status FailedPreconditionError(absl::string_view message);
-Status InternalError(absl::string_view message);
-Status InvalidArgumentError(absl::string_view message);
-Status NotFoundError(absl::string_view message);
-Status OutOfRangeError(absl::string_view message);
-Status PermissionDeniedError(absl::string_view message);
-Status ResourceExhaustedError(absl::string_view message);
-Status UnauthenticatedError(absl::string_view message);
-Status UnavailableError(absl::string_view message);
-Status UnimplementedError(absl::string_view message);
-Status UnknownError(absl::string_view message);
-
 // Creates a `Status` object with the `absl::StatusCode::kCancelled` error code
 // and an empty message. It is provided only for efficiency, given that
 // message-less kCancelled errors are common in the infrastructure.
 inline Status CancelledError() { return Status(absl::StatusCode::kCancelled); }
 
-// Each of the functions below returns true if the given status matches the
-// error code implied by the function's name.
-ABSL_MUST_USE_RESULT bool IsAborted(const Status& status);
-ABSL_MUST_USE_RESULT bool IsAlreadyExists(const Status& status);
-ABSL_MUST_USE_RESULT bool IsCancelled(const Status& status);
-ABSL_MUST_USE_RESULT bool IsDataLoss(const Status& status);
-ABSL_MUST_USE_RESULT bool IsDeadlineExceeded(const Status& status);
-ABSL_MUST_USE_RESULT bool IsFailedPrecondition(const Status& status);
-ABSL_MUST_USE_RESULT bool IsInternal(const Status& status);
-ABSL_MUST_USE_RESULT bool IsInvalidArgument(const Status& status);
-ABSL_MUST_USE_RESULT bool IsNotFound(const Status& status);
-ABSL_MUST_USE_RESULT bool IsOutOfRange(const Status& status);
-ABSL_MUST_USE_RESULT bool IsPermissionDenied(const Status& status);
-ABSL_MUST_USE_RESULT bool IsResourceExhausted(const Status& status);
-ABSL_MUST_USE_RESULT bool IsUnauthenticated(const Status& status);
-ABSL_MUST_USE_RESULT bool IsUnavailable(const Status& status);
-ABSL_MUST_USE_RESULT bool IsUnimplemented(const Status& status);
-ABSL_MUST_USE_RESULT bool IsUnknown(const Status& status);
-
 ABSL_NAMESPACE_END
 }  // namespace absl
 
diff --git a/absl/status/status_payload_printer.cc b/absl/status/status_payload_printer.cc
index ad96d76..a47aea1 100644
--- a/absl/status/status_payload_printer.cc
+++ b/absl/status/status_payload_printer.cc
@@ -16,26 +16,21 @@
 #include <atomic>
 
 #include "absl/base/attributes.h"
+#include "absl/base/internal/atomic_hook.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace status_internal {
 
-namespace {
-// Tried constant initialized global variable but it doesn't work with Lexan
-// (MSVC's `std::atomic` has trouble constant initializing).
-std::atomic<StatusPayloadPrinter>& GetStatusPayloadPrinterStorage() {
-  ABSL_CONST_INIT static std::atomic<StatusPayloadPrinter> instance{nullptr};
-  return instance;
-}
-}  // namespace
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
+static absl::base_internal::AtomicHook<StatusPayloadPrinter> storage;
 
 void SetStatusPayloadPrinter(StatusPayloadPrinter printer) {
-  GetStatusPayloadPrinterStorage().store(printer, std::memory_order_relaxed);
+  storage.Store(printer);
 }
 
 StatusPayloadPrinter GetStatusPayloadPrinter() {
-  return GetStatusPayloadPrinterStorage().load(std::memory_order_relaxed);
+  return storage.Load();
 }
 
 }  // namespace status_internal
diff --git a/absl/status/status_test.cc b/absl/status/status_test.cc
index ca9488a..0e1a43c 100644
--- a/absl/status/status_test.cc
+++ b/absl/status/status_test.cc
@@ -280,6 +280,27 @@
                     HasSubstr("[bar='\\xff']")));
 }
 
+TEST(Status, ToStringMode) {
+  absl::Status s(absl::StatusCode::kInternal, "fail");
+  s.SetPayload("foo", absl::Cord("bar"));
+  s.SetPayload("bar", absl::Cord("\377"));
+
+  EXPECT_EQ("INTERNAL: fail",
+            s.ToString(absl::StatusToStringMode::kWithNoExtraData));
+
+  EXPECT_THAT(s.ToString(absl::StatusToStringMode::kWithPayload),
+              AllOf(HasSubstr("INTERNAL: fail"), HasSubstr("[foo='bar']"),
+                    HasSubstr("[bar='\\xff']")));
+
+  EXPECT_THAT(s.ToString(absl::StatusToStringMode::kWithEverything),
+              AllOf(HasSubstr("INTERNAL: fail"), HasSubstr("[foo='bar']"),
+                    HasSubstr("[bar='\\xff']")));
+
+  EXPECT_THAT(s.ToString(~absl::StatusToStringMode::kWithPayload),
+              AllOf(HasSubstr("INTERNAL: fail"), Not(HasSubstr("[foo='bar']")),
+                    Not(HasSubstr("[bar='\\xff']"))));
+}
+
 absl::Status EraseAndReturn(const absl::Status& base) {
   absl::Status copy = base;
   EXPECT_TRUE(copy.ErasePayload(kUrl1));
@@ -397,6 +418,12 @@
     assignee = std::move(status);
     EXPECT_EQ(assignee, copy);
   }
+  {
+    absl::Status status(absl::StatusCode::kInvalidArgument, "message");
+    absl::Status copy(status);
+    status = static_cast<absl::Status&&>(status);
+    EXPECT_EQ(status, copy);
+  }
 }
 
 TEST(Status, Update) {
@@ -454,5 +481,4 @@
   test_swap(no_payload, with_payload);
   test_swap(with_payload, no_payload);
 }
-
 }  // namespace
diff --git a/absl/status/statusor.cc b/absl/status/statusor.cc
new file mode 100644
index 0000000..b954b45
--- /dev/null
+++ b/absl/status/statusor.cc
@@ -0,0 +1,71 @@
+// 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/status/statusor.h"
+
+#include <cstdlib>
+#include <utility>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/status/status.h"
+#include "absl/strings/str_cat.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+BadStatusOrAccess::BadStatusOrAccess(absl::Status status)
+    : status_(std::move(status)) {}
+
+BadStatusOrAccess::~BadStatusOrAccess() = default;
+const char* BadStatusOrAccess::what() const noexcept {
+  return "Bad StatusOr access";
+}
+
+const absl::Status& BadStatusOrAccess::status() const { return status_; }
+
+namespace internal_statusor {
+
+void Helper::HandleInvalidStatusCtorArg(absl::Status* status) {
+  const char* kMessage =
+      "An OK status is not a valid constructor argument to StatusOr<T>";
+#ifdef NDEBUG
+  ABSL_INTERNAL_LOG(ERROR, kMessage);
+#else
+  ABSL_INTERNAL_LOG(FATAL, kMessage);
+#endif
+  // In optimized builds, we will fall back to InternalError.
+  *status = absl::InternalError(kMessage);
+}
+
+void Helper::Crash(const absl::Status& status) {
+  ABSL_INTERNAL_LOG(
+      FATAL,
+      absl::StrCat("Attempting to fetch value instead of handling error ",
+                   status.ToString()));
+}
+
+void ThrowBadStatusOrAccess(absl::Status status) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  throw absl::BadStatusOrAccess(std::move(status));
+#else
+  ABSL_INTERNAL_LOG(
+      FATAL,
+      absl::StrCat("Attempting to fetch value instead of handling error ",
+                   status.ToString()));
+  std::abort();
+#endif
+}
+
+}  // namespace internal_statusor
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/status/statusor.h b/absl/status/statusor.h
new file mode 100644
index 0000000..b7c55cc
--- /dev/null
+++ b/absl/status/statusor.h
@@ -0,0 +1,760 @@
+// 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.
+//
+// -----------------------------------------------------------------------------
+// File: statusor.h
+// -----------------------------------------------------------------------------
+//
+// An `absl::StatusOr<T>` represents a union of an `absl::Status` object
+// and an object of type `T`. The `absl::StatusOr<T>` will either contain an
+// object of type `T` (indicating a successful operation), or an error (of type
+// `absl::Status`) explaining why such a value is not present.
+//
+// In general, check the success of an operation returning an
+// `absl::StatusOr<T>` like you would an `absl::Status` by using the `ok()`
+// member function.
+//
+// Example:
+//
+//   StatusOr<Foo> result = Calculation();
+//   if (result.ok()) {
+//     result->DoSomethingCool();
+//   } else {
+//     LOG(ERROR) << result.status();
+//   }
+#ifndef ABSL_STATUS_STATUSOR_H_
+#define ABSL_STATUS_STATUSOR_H_
+
+#include <exception>
+#include <initializer_list>
+#include <new>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/attributes.h"
+#include "absl/meta/type_traits.h"
+#include "absl/status/internal/statusor_internal.h"
+#include "absl/status/status.h"
+#include "absl/types/variant.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// BadStatusOrAccess
+//
+// This class defines the type of object to throw (if exceptions are enabled),
+// when accessing the value of an `absl::StatusOr<T>` object that does not
+// contain a value. This behavior is analogous to that of
+// `std::bad_optional_access` in the case of accessing an invalid
+// `std::optional` value.
+//
+// Example:
+//
+// try {
+//   absl::StatusOr<int> v = FetchInt();
+//   DoWork(v.value());  // Accessing value() when not "OK" may throw
+// } catch (absl::BadStatusOrAccess& ex) {
+//   LOG(ERROR) << ex.status();
+// }
+class BadStatusOrAccess : public std::exception {
+ public:
+  explicit BadStatusOrAccess(absl::Status status);
+  ~BadStatusOrAccess() override;
+
+  // BadStatusOrAccess::what()
+  //
+  // Returns the associated explanatory string of the `absl::StatusOr<T>`
+  // object's error code. This function only returns the string literal "Bad
+  // StatusOr Access" for cases when evaluating general exceptions.
+  //
+  // The pointer of this string is guaranteed to be valid until any non-const
+  // function is invoked on the exception object.
+  const char* what() const noexcept override;
+
+  // BadStatusOrAccess::status()
+  //
+  // Returns the associated `absl::Status` of the `absl::StatusOr<T>` object's
+  // error.
+  const absl::Status& status() const;
+
+ private:
+  absl::Status status_;
+};
+
+// Returned StatusOr objects may not be ignored.
+template <typename T>
+class ABSL_MUST_USE_RESULT StatusOr;
+
+// absl::StatusOr<T>
+//
+// The `absl::StatusOr<T>` class template is a union of an `absl::Status` object
+// and an object of type `T`. The `absl::StatusOr<T>` models an object that is
+// either a usable object, or an error (of type `absl::Status`) explaining why
+// such an object is not present. An `absl::StatusOr<T>` is typically the return
+// value of a function which may fail.
+//
+// An `absl::StatusOr<T>` can never hold an "OK" status (an
+// `absl::StatusCode::kOk` value); instead, the presence of an object of type
+// `T` indicates success. Instead of checking for a `kOk` value, use the
+// `absl::StatusOr<T>::ok()` member function. (It is for this reason, and code
+// readability, that using the `ok()` function is preferred for `absl::Status`
+// as well.)
+//
+// Example:
+//
+//   StatusOr<Foo> result = DoBigCalculationThatCouldFail();
+//   if (result.ok()) {
+//     result->DoSomethingCool();
+//   } else {
+//     LOG(ERROR) << result.status();
+//   }
+//
+// Accessing the object held by an `absl::StatusOr<T>` should be performed via
+// `operator*` or `operator->`, after a call to `ok()` confirms that the
+// `absl::StatusOr<T>` holds an object of type `T`:
+//
+// Example:
+//
+//   absl::StatusOr<int> i = GetCount();
+//   if (i.ok()) {
+//     updated_total += *i
+//   }
+//
+// NOTE: using `absl::StatusOr<T>::value()` when no valid value is present will
+// throw an exception if exceptions are enabled or terminate the process when
+// exceptions are not enabled.
+//
+// Example:
+//
+//   StatusOr<Foo> result = DoBigCalculationThatCouldFail();
+//   const Foo& foo = result.value();    // Crash/exception if no value present
+//   foo.DoSomethingCool();
+//
+// A `absl::StatusOr<T*>` can be constructed from a null pointer like any other
+// pointer value, and the result will be that `ok()` returns `true` and
+// `value()` returns `nullptr`. Checking the value of pointer in an
+// `absl::StatusOr<T>` generally requires a bit more care, to ensure both that a
+// value is present and that value is not null:
+//
+//  StatusOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg);
+//  if (!result.ok()) {
+//    LOG(ERROR) << result.status();
+//  } else if (*result == nullptr) {
+//    LOG(ERROR) << "Unexpected null pointer";
+//  } else {
+//    (*result)->DoSomethingCool();
+//  }
+//
+// Example factory implementation returning StatusOr<T>:
+//
+//  StatusOr<Foo> FooFactory::MakeFoo(int arg) {
+//    if (arg <= 0) {
+//      return absl::Status(absl::StatusCode::kInvalidArgument,
+//                          "Arg must be positive");
+//    }
+//    return Foo(arg);
+//  }
+template <typename T>
+class StatusOr : 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> {
+  template <typename U>
+  friend class StatusOr;
+
+  typedef internal_statusor::StatusOrData<T> Base;
+
+ public:
+  // StatusOr<T>::value_type
+  //
+  // This instance data provides a generic `value_type` member for use within
+  // generic programming. This usage is analogous to that of
+  // `optional::value_type` in the case of `std::optional`.
+  typedef T value_type;
+
+  // Constructors
+
+  // Constructs a new `absl::StatusOr` with an `absl::StatusCode::kUnknown`
+  // status. This constructor is marked 'explicit' to prevent usages in return
+  // values such as 'return {};', under the misconception that
+  // `absl::StatusOr<std::vector<int>>` will be initialized with an empty
+  // vector, instead of an `absl::StatusCode::kUnknown` error code.
+  explicit StatusOr();
+
+  // `StatusOr<T>` is copy constructible if `T` is copy constructible.
+  StatusOr(const StatusOr&) = default;
+  // `StatusOr<T>` is copy assignable if `T` is copy constructible and copy
+  // assignable.
+  StatusOr& operator=(const StatusOr&) = default;
+
+  // `StatusOr<T>` is move constructible if `T` is move constructible.
+  StatusOr(StatusOr&&) = default;
+  // `StatusOr<T>` is moveAssignable if `T` is move constructible and move
+  // assignable.
+  StatusOr& operator=(StatusOr&&) = default;
+
+  // Converting Constructors
+
+  // Constructs a new `absl::StatusOr<T>` from an `absl::StatusOr<U>`, when `T`
+  // is constructible from `U`. To avoid ambiguity, these constructors are
+  // disabled if `T` is also constructible from `StatusOr<U>.`. This constructor
+  // is explicit if and only if the corresponding construction of `T` from `U`
+  // is explicit. (This constructor inherits its explicitness from the
+  // underlying constructor.)
+  template <
+      typename U,
+      absl::enable_if_t<
+          absl::conjunction<
+              absl::negation<std::is_same<T, U>>,
+              std::is_constructible<T, const U&>,
+              std::is_convertible<const U&, T>,
+              absl::negation<
+                  internal_statusor::IsConstructibleOrConvertibleFromStatusOr<
+                      T, U>>>::value,
+          int> = 0>
+  StatusOr(const StatusOr<U>& other)  // NOLINT
+      : Base(static_cast<const typename StatusOr<U>::Base&>(other)) {}
+  template <
+      typename U,
+      absl::enable_if_t<
+          absl::conjunction<
+              absl::negation<std::is_same<T, U>>,
+              std::is_constructible<T, const U&>,
+              absl::negation<std::is_convertible<const U&, T>>,
+              absl::negation<
+                  internal_statusor::IsConstructibleOrConvertibleFromStatusOr<
+                      T, U>>>::value,
+          int> = 0>
+  explicit StatusOr(const StatusOr<U>& other)
+      : Base(static_cast<const typename StatusOr<U>::Base&>(other)) {}
+
+  template <
+      typename U,
+      absl::enable_if_t<
+          absl::conjunction<
+              absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
+              std::is_convertible<U&&, T>,
+              absl::negation<
+                  internal_statusor::IsConstructibleOrConvertibleFromStatusOr<
+                      T, U>>>::value,
+          int> = 0>
+  StatusOr(StatusOr<U>&& other)  // NOLINT
+      : Base(static_cast<typename StatusOr<U>::Base&&>(other)) {}
+  template <
+      typename U,
+      absl::enable_if_t<
+          absl::conjunction<
+              absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
+              absl::negation<std::is_convertible<U&&, T>>,
+              absl::negation<
+                  internal_statusor::IsConstructibleOrConvertibleFromStatusOr<
+                      T, U>>>::value,
+          int> = 0>
+  explicit StatusOr(StatusOr<U>&& other)
+      : Base(static_cast<typename StatusOr<U>::Base&&>(other)) {}
+
+  // Converting Assignment Operators
+
+  // Creates an `absl::StatusOr<T>` through assignment from an
+  // `absl::StatusOr<U>` when:
+  //
+  //   * Both `absl::StatusOr<T>` and `absl::StatusOr<U>` are OK by assigning
+  //     `U` to `T` directly.
+  //   * `absl::StatusOr<T>` is OK and `absl::StatusOr<U>` contains an error
+  //      code by destroying `absl::StatusOr<T>`'s value and assigning from
+  //      `absl::StatusOr<U>'
+  //   * `absl::StatusOr<T>` contains an error code and `absl::StatusOr<U>` is
+  //      OK by directly initializing `T` from `U`.
+  //   * Both `absl::StatusOr<T>` and `absl::StatusOr<U>` contain an error
+  //     code by assigning the `Status` in `absl::StatusOr<U>` to
+  //     `absl::StatusOr<T>`
+  //
+  // These overloads only apply if `absl::StatusOr<T>` is constructible and
+  // assignable from `absl::StatusOr<U>` and `StatusOr<T>` cannot be directly
+  // assigned from `StatusOr<U>`.
+  template <
+      typename U,
+      absl::enable_if_t<
+          absl::conjunction<
+              absl::negation<std::is_same<T, U>>,
+              std::is_constructible<T, const U&>,
+              std::is_assignable<T, const U&>,
+              absl::negation<
+                  internal_statusor::
+                      IsConstructibleOrConvertibleOrAssignableFromStatusOr<
+                          T, U>>>::value,
+          int> = 0>
+  StatusOr& operator=(const StatusOr<U>& other) {
+    this->Assign(other);
+    return *this;
+  }
+  template <
+      typename U,
+      absl::enable_if_t<
+          absl::conjunction<
+              absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
+              std::is_assignable<T, U&&>,
+              absl::negation<
+                  internal_statusor::
+                      IsConstructibleOrConvertibleOrAssignableFromStatusOr<
+                          T, U>>>::value,
+          int> = 0>
+  StatusOr& operator=(StatusOr<U>&& other) {
+    this->Assign(std::move(other));
+    return *this;
+  }
+
+  // Constructs a new `absl::StatusOr<T>` with a non-ok status. After calling
+  // this constructor, `this->ok()` will be `false` and calls to `value()` will
+  // crash, or produce an exception if exceptions are enabled.
+  //
+  // The constructor also takes any type `U` that is convertible to
+  // `absl::Status`. This constructor is explicit if an only if `U` is not of
+  // type `absl::Status` and the conversion from `U` to `Status` is explicit.
+  //
+  // REQUIRES: !Status(std::forward<U>(v)).ok(). This requirement is DCHECKed.
+  // In optimized builds, passing absl::OkStatus() here will have the effect
+  // of passing absl::StatusCode::kInternal as a fallback.
+  template <
+      typename U = absl::Status,
+      absl::enable_if_t<
+          absl::conjunction<
+              std::is_convertible<U&&, absl::Status>,
+              std::is_constructible<absl::Status, U&&>,
+              absl::negation<std::is_same<absl::decay_t<U>, absl::StatusOr<T>>>,
+              absl::negation<std::is_same<absl::decay_t<U>, T>>,
+              absl::negation<std::is_same<absl::decay_t<U>, absl::in_place_t>>,
+              absl::negation<internal_statusor::HasConversionOperatorToStatusOr<
+                  T, U&&>>>::value,
+          int> = 0>
+  StatusOr(U&& v) : Base(std::forward<U>(v)) {}
+
+  template <
+      typename U = absl::Status,
+      absl::enable_if_t<
+          absl::conjunction<
+              absl::negation<std::is_convertible<U&&, absl::Status>>,
+              std::is_constructible<absl::Status, U&&>,
+              absl::negation<std::is_same<absl::decay_t<U>, absl::StatusOr<T>>>,
+              absl::negation<std::is_same<absl::decay_t<U>, T>>,
+              absl::negation<std::is_same<absl::decay_t<U>, absl::in_place_t>>,
+              absl::negation<internal_statusor::HasConversionOperatorToStatusOr<
+                  T, U&&>>>::value,
+          int> = 0>
+  explicit StatusOr(U&& v) : Base(std::forward<U>(v)) {}
+
+  template <
+      typename U = absl::Status,
+      absl::enable_if_t<
+          absl::conjunction<
+              std::is_convertible<U&&, absl::Status>,
+              std::is_constructible<absl::Status, U&&>,
+              absl::negation<std::is_same<absl::decay_t<U>, absl::StatusOr<T>>>,
+              absl::negation<std::is_same<absl::decay_t<U>, T>>,
+              absl::negation<std::is_same<absl::decay_t<U>, absl::in_place_t>>,
+              absl::negation<internal_statusor::HasConversionOperatorToStatusOr<
+                  T, U&&>>>::value,
+          int> = 0>
+  StatusOr& operator=(U&& v) {
+    this->AssignStatus(std::forward<U>(v));
+    return *this;
+  }
+
+  // Perfect-forwarding value assignment operator.
+
+  // If `*this` contains a `T` value before the call, the contained value is
+  // assigned from `std::forward<U>(v)`; Otherwise, it is directly-initialized
+  // from `std::forward<U>(v)`.
+  // This function does not participate in overload unless:
+  // 1. `std::is_constructible_v<T, U>` is true,
+  // 2. `std::is_assignable_v<T&, U>` is true.
+  // 3. `std::is_same_v<StatusOr<T>, std::remove_cvref_t<U>>` is false.
+  // 4. Assigning `U` to `T` is not ambiguous:
+  //  If `U` is `StatusOr<V>` and `T` is constructible and assignable from
+  //  both `StatusOr<V>` and `V`, the assignment is considered bug-prone and
+  //  ambiguous thus will fail to compile. For example:
+  //    StatusOr<bool> s1 = true;  // s1.ok() && *s1 == true
+  //    StatusOr<bool> s2 = false;  // s2.ok() && *s2 == false
+  //    s1 = s2;  // ambiguous, `s1 = *s2` or `s1 = bool(s2)`?
+  template <
+      typename U = T,
+      typename = typename std::enable_if<absl::conjunction<
+          std::is_constructible<T, U&&>, std::is_assignable<T&, U&&>,
+          absl::disjunction<
+              std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>, T>,
+              absl::conjunction<
+                  absl::negation<std::is_convertible<U&&, absl::Status>>,
+                  absl::negation<internal_statusor::
+                                     HasConversionOperatorToStatusOr<T, U&&>>>>,
+          internal_statusor::IsForwardingAssignmentValid<T, U&&>>::value>::type>
+  StatusOr& operator=(U&& v) {
+    this->Assign(std::forward<U>(v));
+    return *this;
+  }
+
+  // Constructs the inner value `T` in-place using the provided args, using the
+  // `T(args...)` constructor.
+  template <typename... Args>
+  explicit StatusOr(absl::in_place_t, Args&&... args);
+  template <typename U, typename... Args>
+  explicit StatusOr(absl::in_place_t, std::initializer_list<U> ilist,
+                    Args&&... args);
+
+  // Constructs the inner value `T` in-place using the provided args, using the
+  // `T(U)` (direct-initialization) constructor. This constructor is only valid
+  // if `T` can be constructed from a `U`. Can accept move or copy constructors.
+  //
+  // This constructor is explicit if `U` is not convertible to `T`. To avoid
+  // ambiguity, this constuctor is disabled if `U` is a `StatusOr<J>`, where `J`
+  // is convertible to `T`.
+  template <
+      typename U = T,
+      absl::enable_if_t<
+          absl::conjunction<
+              internal_statusor::IsDirectInitializationValid<T, U&&>,
+              std::is_constructible<T, U&&>, std::is_convertible<U&&, T>,
+              absl::disjunction<
+                  std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>,
+                               T>,
+                  absl::conjunction<
+                      absl::negation<std::is_convertible<U&&, absl::Status>>,
+                      absl::negation<
+                          internal_statusor::HasConversionOperatorToStatusOr<
+                              T, U&&>>>>>::value,
+          int> = 0>
+  StatusOr(U&& u)  // NOLINT
+      : StatusOr(absl::in_place, std::forward<U>(u)) {
+  }
+
+  template <
+      typename U = T,
+      absl::enable_if_t<
+          absl::conjunction<
+              internal_statusor::IsDirectInitializationValid<T, U&&>,
+              absl::disjunction<
+                  std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>,
+                               T>,
+                  absl::conjunction<
+                      absl::negation<std::is_constructible<absl::Status, U&&>>,
+                      absl::negation<
+                          internal_statusor::HasConversionOperatorToStatusOr<
+                              T, U&&>>>>,
+              std::is_constructible<T, U&&>,
+              absl::negation<std::is_convertible<U&&, T>>>::value,
+          int> = 0>
+  explicit StatusOr(U&& u)  // NOLINT
+      : StatusOr(absl::in_place, std::forward<U>(u)) {
+  }
+
+  // StatusOr<T>::ok()
+  //
+  // Returns whether or not this `absl::StatusOr<T>` holds a `T` value. This
+  // member function is analagous to `absl::Status::ok()` and should be used
+  // similarly to check the status of return values.
+  //
+  // Example:
+  //
+  // StatusOr<Foo> result = DoBigCalculationThatCouldFail();
+  // if (result.ok()) {
+  //    // Handle result
+  // else {
+  //    // Handle error
+  // }
+  ABSL_MUST_USE_RESULT bool ok() const { return this->status_.ok(); }
+
+  // StatusOr<T>::status()
+  //
+  // Returns a reference to the current `absl::Status` contained within the
+  // `absl::StatusOr<T>`. If `absl::StatusOr<T>` contains a `T`, then this
+  // function returns `absl::OkStatus()`.
+  const Status& status() const &;
+  Status status() &&;
+
+  // StatusOr<T>::value()
+  //
+  // Returns a reference to the held value if `this->ok()`. Otherwise, throws
+  // `absl::BadStatusOrAccess` if exceptions are enabled, or is guaranteed to
+  // terminate the process if exceptions are disabled.
+  //
+  // If you have already checked the status using `this->ok()`, you probably
+  // want to use `operator*()` or `operator->()` to access the value instead of
+  // `value`.
+  //
+  // Note: for value types that are cheap to copy, prefer simple code:
+  //
+  //   T value = statusor.value();
+  //
+  // Otherwise, if the value type is expensive to copy, but can be left
+  // in the StatusOr, simply assign to a reference:
+  //
+  //   T& value = statusor.value();  // or `const T&`
+  //
+  // Otherwise, if the value type supports an efficient move, it can be
+  // used as follows:
+  //
+  //   T value = std::move(statusor).value();
+  //
+  // 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&;
+  T& value() &;
+  const T&& value() const&&;
+  T&& value() &&;
+
+  // StatusOr<T>:: operator*()
+  //
+  // Returns a reference to the current value.
+  //
+  // REQUIRES: `this->ok() == true`, otherwise the behavior is undefined.
+  //
+  // Use `this->ok()` to verify that there is a current value within the
+  // `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&;
+  T& operator*() &;
+  const T&& operator*() const&&;
+  T&& operator*() &&;
+
+  // StatusOr<T>::operator->()
+  //
+  // Returns a pointer to the current value.
+  //
+  // REQUIRES: `this->ok() == true`, otherwise the behavior is undefined.
+  //
+  // Use `this->ok()` to verify that there is a current value.
+  const T* operator->() const;
+  T* operator->();
+
+  // StatusOr<T>::value_or()
+  //
+  // Returns the current value if `this->ok() == true`. Otherwise constructs a
+  // value using the provided `default_value`.
+  //
+  // Unlike `value`, this function returns by value, copying the current value
+  // if necessary. If the value type supports an efficient move, it can be used
+  // as follows:
+  //
+  //   T value = std::move(statusor).value_or(def);
+  //
+  // 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) &&;
+
+  // StatusOr<T>::IgnoreError()
+  //
+  // Ignores any errors. This method does nothing except potentially suppress
+  // complaints from any tools that are checking that errors are not dropped on
+  // the floor.
+  void IgnoreError() const;
+
+  // StatusOr<T>::emplace()
+  //
+  // Reconstructs the inner value T in-place using the provided args, using the
+  // T(args...) constructor. Returns reference to the reconstructed `T`.
+  template <typename... Args>
+  T& emplace(Args&&... args) {
+    if (ok()) {
+      this->Clear();
+      this->MakeValue(std::forward<Args>(args)...);
+    } else {
+      this->MakeValue(std::forward<Args>(args)...);
+      this->status_ = absl::OkStatus();
+    }
+    return this->data_;
+  }
+
+  template <
+      typename U, typename... Args,
+      absl::enable_if_t<
+          std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value,
+          int> = 0>
+  T& emplace(std::initializer_list<U> ilist, Args&&... args) {
+    if (ok()) {
+      this->Clear();
+      this->MakeValue(ilist, std::forward<Args>(args)...);
+    } else {
+      this->MakeValue(ilist, std::forward<Args>(args)...);
+      this->status_ = absl::OkStatus();
+    }
+    return this->data_;
+  }
+
+ private:
+  using internal_statusor::StatusOrData<T>::Assign;
+  template <typename U>
+  void Assign(const absl::StatusOr<U>& other);
+  template <typename U>
+  void Assign(absl::StatusOr<U>&& other);
+};
+
+// operator==()
+//
+// This operator checks the equality of two `absl::StatusOr<T>` objects.
+template <typename T>
+bool operator==(const StatusOr<T>& lhs, const StatusOr<T>& rhs) {
+  if (lhs.ok() && rhs.ok()) return *lhs == *rhs;
+  return lhs.status() == rhs.status();
+}
+
+// operator!=()
+//
+// This operator checks the inequality of two `absl::StatusOr<T>` objects.
+template <typename T>
+bool operator!=(const StatusOr<T>& lhs, const StatusOr<T>& rhs) {
+  return !(lhs == rhs);
+}
+
+//------------------------------------------------------------------------------
+// Implementation details for StatusOr<T>
+//------------------------------------------------------------------------------
+
+// TODO(sbenza): avoid the string here completely.
+template <typename T>
+StatusOr<T>::StatusOr() : Base(Status(absl::StatusCode::kUnknown, "")) {}
+
+template <typename T>
+template <typename U>
+inline void StatusOr<T>::Assign(const StatusOr<U>& other) {
+  if (other.ok()) {
+    this->Assign(*other);
+  } else {
+    this->AssignStatus(other.status());
+  }
+}
+
+template <typename T>
+template <typename U>
+inline void StatusOr<T>::Assign(StatusOr<U>&& other) {
+  if (other.ok()) {
+    this->Assign(*std::move(other));
+  } else {
+    this->AssignStatus(std::move(other).status());
+  }
+}
+template <typename T>
+template <typename... Args>
+StatusOr<T>::StatusOr(absl::in_place_t, Args&&... args)
+    : Base(absl::in_place, std::forward<Args>(args)...) {}
+
+template <typename T>
+template <typename U, typename... Args>
+StatusOr<T>::StatusOr(absl::in_place_t, std::initializer_list<U> ilist,
+                      Args&&... args)
+    : Base(absl::in_place, ilist, std::forward<Args>(args)...) {}
+
+template <typename T>
+const Status& StatusOr<T>::status() const & { return this->status_; }
+template <typename T>
+Status StatusOr<T>::status() && {
+  return ok() ? OkStatus() : std::move(this->status_);
+}
+
+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* StatusOr<T>::operator->() const {
+  this->EnsureOk();
+  return &this->data_;
+}
+
+template <typename T>
+T* 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
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STATUS_STATUSOR_H_
diff --git a/absl/status/statusor_test.cc b/absl/status/statusor_test.cc
new file mode 100644
index 0000000..c2e8fb7
--- /dev/null
+++ b/absl/status/statusor_test.cc
@@ -0,0 +1,1811 @@
+// 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/status/statusor.h"
+
+#include <array>
+#include <initializer_list>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/casts.h"
+#include "absl/memory/memory.h"
+#include "absl/status/status.h"
+#include "absl/types/any.h"
+#include "absl/utility/utility.h"
+
+namespace {
+
+using ::testing::AllOf;
+using ::testing::AnyWith;
+using ::testing::ElementsAre;
+using ::testing::Field;
+using ::testing::Ne;
+using ::testing::Not;
+using ::testing::Pointee;
+using ::testing::VariantWith;
+
+#ifdef GTEST_HAS_STATUS_MATCHERS
+using ::testing::status::IsOk;
+using ::testing::status::IsOkAndHolds;
+#else  // GTEST_HAS_STATUS_MATCHERS
+inline const ::absl::Status& GetStatus(const ::absl::Status& status) {
+  return status;
+}
+
+template <typename T>
+inline const ::absl::Status& GetStatus(const ::absl::StatusOr<T>& status) {
+  return status.status();
+}
+
+// Monomorphic implementation of matcher IsOkAndHolds(m).  StatusOrType is a
+// reference to StatusOr<T>.
+template <typename StatusOrType>
+class IsOkAndHoldsMatcherImpl
+    : public ::testing::MatcherInterface<StatusOrType> {
+ public:
+  typedef
+      typename std::remove_reference<StatusOrType>::type::value_type value_type;
+
+  template <typename InnerMatcher>
+  explicit IsOkAndHoldsMatcherImpl(InnerMatcher&& inner_matcher)
+      : inner_matcher_(::testing::SafeMatcherCast<const value_type&>(
+            std::forward<InnerMatcher>(inner_matcher))) {}
+
+  void DescribeTo(std::ostream* os) const override {
+    *os << "is OK and has a value that ";
+    inner_matcher_.DescribeTo(os);
+  }
+
+  void DescribeNegationTo(std::ostream* os) const override {
+    *os << "isn't OK or has a value that ";
+    inner_matcher_.DescribeNegationTo(os);
+  }
+
+  bool MatchAndExplain(
+      StatusOrType actual_value,
+      ::testing::MatchResultListener* result_listener) const override {
+    if (!actual_value.ok()) {
+      *result_listener << "which has status " << actual_value.status();
+      return false;
+    }
+
+    ::testing::StringMatchResultListener inner_listener;
+    const bool matches =
+        inner_matcher_.MatchAndExplain(*actual_value, &inner_listener);
+    const std::string inner_explanation = inner_listener.str();
+    if (!inner_explanation.empty()) {
+      *result_listener << "which contains value "
+                       << ::testing::PrintToString(*actual_value) << ", "
+                       << inner_explanation;
+    }
+    return matches;
+  }
+
+ private:
+  const ::testing::Matcher<const value_type&> inner_matcher_;
+};
+
+// Implements IsOkAndHolds(m) as a polymorphic matcher.
+template <typename InnerMatcher>
+class IsOkAndHoldsMatcher {
+ public:
+  explicit IsOkAndHoldsMatcher(InnerMatcher inner_matcher)
+      : inner_matcher_(std::move(inner_matcher)) {}
+
+  // Converts this polymorphic matcher to a monomorphic matcher of the
+  // given type.  StatusOrType can be either StatusOr<T> or a
+  // reference to StatusOr<T>.
+  template <typename StatusOrType>
+  operator ::testing::Matcher<StatusOrType>() const {  // NOLINT
+    return ::testing::Matcher<StatusOrType>(
+        new IsOkAndHoldsMatcherImpl<const StatusOrType&>(inner_matcher_));
+  }
+
+ private:
+  const InnerMatcher inner_matcher_;
+};
+
+// Monomorphic implementation of matcher IsOk() for a given type T.
+// T can be Status, StatusOr<>, or a reference to either of them.
+template <typename T>
+class MonoIsOkMatcherImpl : public ::testing::MatcherInterface<T> {
+ public:
+  void DescribeTo(std::ostream* os) const override { *os << "is OK"; }
+  void DescribeNegationTo(std::ostream* os) const override {
+    *os << "is not OK";
+  }
+  bool MatchAndExplain(T actual_value,
+                       ::testing::MatchResultListener*) const override {
+    return GetStatus(actual_value).ok();
+  }
+};
+
+// Implements IsOk() as a polymorphic matcher.
+class IsOkMatcher {
+ public:
+  template <typename T>
+  operator ::testing::Matcher<T>() const {  // NOLINT
+    return ::testing::Matcher<T>(new MonoIsOkMatcherImpl<T>());
+  }
+};
+
+// Macros for testing the results of functions that return absl::Status or
+// absl::StatusOr<T> (for any type T).
+#define EXPECT_OK(expression) EXPECT_THAT(expression, IsOk())
+
+// Returns a gMock matcher that matches a StatusOr<> whose status is
+// OK and whose value matches the inner matcher.
+template <typename InnerMatcher>
+IsOkAndHoldsMatcher<typename std::decay<InnerMatcher>::type> IsOkAndHolds(
+    InnerMatcher&& inner_matcher) {
+  return IsOkAndHoldsMatcher<typename std::decay<InnerMatcher>::type>(
+      std::forward<InnerMatcher>(inner_matcher));
+}
+
+// Returns a gMock matcher that matches a Status or StatusOr<> which is OK.
+inline IsOkMatcher IsOk() { return IsOkMatcher(); }
+#endif  // GTEST_HAS_STATUS_MATCHERS
+
+struct CopyDetector {
+  CopyDetector() = default;
+  explicit CopyDetector(int xx) : x(xx) {}
+  CopyDetector(CopyDetector&& d) noexcept
+      : x(d.x), copied(false), moved(true) {}
+  CopyDetector(const CopyDetector& d) : x(d.x), copied(true), moved(false) {}
+  CopyDetector& operator=(const CopyDetector& c) {
+    x = c.x;
+    copied = true;
+    moved = false;
+    return *this;
+  }
+  CopyDetector& operator=(CopyDetector&& c) noexcept {
+    x = c.x;
+    copied = false;
+    moved = true;
+    return *this;
+  }
+  int x = 0;
+  bool copied = false;
+  bool moved = false;
+};
+
+testing::Matcher<const CopyDetector&> CopyDetectorHas(int a, bool b, bool c) {
+  return AllOf(Field(&CopyDetector::x, a), Field(&CopyDetector::moved, b),
+               Field(&CopyDetector::copied, c));
+}
+
+class Base1 {
+ public:
+  virtual ~Base1() {}
+  int pad;
+};
+
+class Base2 {
+ public:
+  virtual ~Base2() {}
+  int yetotherpad;
+};
+
+class Derived : public Base1, public Base2 {
+ public:
+  virtual ~Derived() {}
+  int evenmorepad;
+};
+
+class CopyNoAssign {
+ public:
+  explicit CopyNoAssign(int value) : foo(value) {}
+  CopyNoAssign(const CopyNoAssign& other) : foo(other.foo) {}
+  int foo;
+
+ private:
+  const CopyNoAssign& operator=(const CopyNoAssign&);
+};
+
+absl::StatusOr<std::unique_ptr<int>> ReturnUniquePtr() {
+  // Uses implicit constructor from T&&
+  return absl::make_unique<int>(0);
+}
+
+TEST(StatusOr, ElementType) {
+  static_assert(std::is_same<absl::StatusOr<int>::value_type, int>(), "");
+  static_assert(std::is_same<absl::StatusOr<char>::value_type, char>(), "");
+}
+
+TEST(StatusOr, TestMoveOnlyInitialization) {
+  absl::StatusOr<std::unique_ptr<int>> thing(ReturnUniquePtr());
+  ASSERT_TRUE(thing.ok());
+  EXPECT_EQ(0, **thing);
+  int* previous = thing->get();
+
+  thing = ReturnUniquePtr();
+  EXPECT_TRUE(thing.ok());
+  EXPECT_EQ(0, **thing);
+  EXPECT_NE(previous, thing->get());
+}
+
+TEST(StatusOr, TestMoveOnlyValueExtraction) {
+  absl::StatusOr<std::unique_ptr<int>> thing(ReturnUniquePtr());
+  ASSERT_TRUE(thing.ok());
+  std::unique_ptr<int> ptr = *std::move(thing);
+  EXPECT_EQ(0, *ptr);
+
+  thing = std::move(ptr);
+  ptr = std::move(*thing);
+  EXPECT_EQ(0, *ptr);
+}
+
+TEST(StatusOr, TestMoveOnlyInitializationFromTemporaryByValueOrDie) {
+  std::unique_ptr<int> ptr(*ReturnUniquePtr());
+  EXPECT_EQ(0, *ptr);
+}
+
+TEST(StatusOr, TestValueOrDieOverloadForConstTemporary) {
+  static_assert(
+      std::is_same<const int&&,
+                   decltype(
+                       std::declval<const absl::StatusOr<int>&&>().value())>(),
+      "value() for const temporaries should return const T&&");
+}
+
+TEST(StatusOr, TestMoveOnlyConversion) {
+  absl::StatusOr<std::unique_ptr<const int>> const_thing(ReturnUniquePtr());
+  EXPECT_TRUE(const_thing.ok());
+  EXPECT_EQ(0, **const_thing);
+
+  // Test rvalue converting assignment
+  const int* const_previous = const_thing->get();
+  const_thing = ReturnUniquePtr();
+  EXPECT_TRUE(const_thing.ok());
+  EXPECT_EQ(0, **const_thing);
+  EXPECT_NE(const_previous, const_thing->get());
+}
+
+TEST(StatusOr, TestMoveOnlyVector) {
+  // Sanity check that absl::StatusOr<MoveOnly> works in vector.
+  std::vector<absl::StatusOr<std::unique_ptr<int>>> vec;
+  vec.push_back(ReturnUniquePtr());
+  vec.resize(2);
+  auto another_vec = std::move(vec);
+  EXPECT_EQ(0, **another_vec[0]);
+  EXPECT_EQ(absl::UnknownError(""), another_vec[1].status());
+}
+
+TEST(StatusOr, TestDefaultCtor) {
+  absl::StatusOr<int> thing;
+  EXPECT_FALSE(thing.ok());
+  EXPECT_EQ(thing.status().code(), absl::StatusCode::kUnknown);
+}
+
+TEST(StatusOr, StatusCtorForwards) {
+  absl::Status status(absl::StatusCode::kInternal, "Some error");
+
+  EXPECT_EQ(absl::StatusOr<int>(status).status().message(), "Some error");
+  EXPECT_EQ(status.message(), "Some error");
+
+  EXPECT_EQ(absl::StatusOr<int>(std::move(status)).status().message(),
+            "Some error");
+  EXPECT_NE(status.message(), "Some error");
+}
+
+// Define `EXPECT_DEATH_OR_THROW` to test the behavior of `StatusOr::value`,
+// which either throws `BadStatusOrAccess` or `LOG(FATAL)` based on whether
+// exceptions are enabled.
+#ifdef ABSL_HAVE_EXCEPTIONS
+#define EXPECT_DEATH_OR_THROW(statement, status_)    \
+  EXPECT_THROW(                                      \
+      {                                              \
+        try {                                        \
+          statement;                                 \
+        } catch (const absl::BadStatusOrAccess& e) { \
+          EXPECT_EQ(e.status(), status_);            \
+          throw;                                     \
+        }                                            \
+      },                                             \
+      absl::BadStatusOrAccess);
+#else  // ABSL_HAVE_EXCEPTIONS
+#define EXPECT_DEATH_OR_THROW(statement, status) \
+  EXPECT_DEATH_IF_SUPPORTED(statement, status.ToString());
+#endif  // ABSL_HAVE_EXCEPTIONS
+
+TEST(StatusOrDeathTest, TestDefaultCtorValue) {
+  absl::StatusOr<int> thing;
+  EXPECT_DEATH_OR_THROW(thing.value(), absl::UnknownError(""));
+  const absl::StatusOr<int> thing2;
+  EXPECT_DEATH_OR_THROW(thing2.value(), absl::UnknownError(""));
+}
+
+TEST(StatusOrDeathTest, TestValueNotOk) {
+  absl::StatusOr<int> thing(absl::CancelledError());
+  EXPECT_DEATH_OR_THROW(thing.value(), absl::CancelledError());
+}
+
+TEST(StatusOrDeathTest, TestValueNotOkConst) {
+  const absl::StatusOr<int> thing(absl::UnknownError(""));
+  EXPECT_DEATH_OR_THROW(thing.value(), absl::UnknownError(""));
+}
+
+TEST(StatusOrDeathTest, TestPointerDefaultCtorValue) {
+  absl::StatusOr<int*> thing;
+  EXPECT_DEATH_OR_THROW(thing.value(), absl::UnknownError(""));
+}
+
+TEST(StatusOrDeathTest, TestPointerValueNotOk) {
+  absl::StatusOr<int*> thing(absl::CancelledError());
+  EXPECT_DEATH_OR_THROW(thing.value(), absl::CancelledError());
+}
+
+TEST(StatusOrDeathTest, TestPointerValueNotOkConst) {
+  const absl::StatusOr<int*> thing(absl::CancelledError());
+  EXPECT_DEATH_OR_THROW(thing.value(), absl::CancelledError());
+}
+
+#if GTEST_HAS_DEATH_TEST
+TEST(StatusOrDeathTest, TestStatusCtorStatusOk) {
+  EXPECT_DEBUG_DEATH(
+      {
+        // This will DCHECK
+        absl::StatusOr<int> thing(absl::OkStatus());
+        // In optimized mode, we are actually going to get error::INTERNAL for
+        // status here, rather than crashing, so check that.
+        EXPECT_FALSE(thing.ok());
+        EXPECT_EQ(thing.status().code(), absl::StatusCode::kInternal);
+      },
+      "An OK status is not a valid constructor argument");
+}
+
+TEST(StatusOrDeathTest, TestPointerStatusCtorStatusOk) {
+  EXPECT_DEBUG_DEATH(
+      {
+        absl::StatusOr<int*> thing(absl::OkStatus());
+        // In optimized mode, we are actually going to get error::INTERNAL for
+        // status here, rather than crashing, so check that.
+        EXPECT_FALSE(thing.ok());
+        EXPECT_EQ(thing.status().code(), absl::StatusCode::kInternal);
+      },
+      "An OK status is not a valid constructor argument");
+}
+#endif
+
+TEST(StatusOr, ValueAccessor) {
+  const int kIntValue = 110;
+  {
+    absl::StatusOr<int> status_or(kIntValue);
+    EXPECT_EQ(kIntValue, status_or.value());
+    EXPECT_EQ(kIntValue, std::move(status_or).value());
+  }
+  {
+    absl::StatusOr<CopyDetector> status_or(kIntValue);
+    EXPECT_THAT(status_or,
+                IsOkAndHolds(CopyDetectorHas(kIntValue, false, false)));
+    CopyDetector copy_detector = status_or.value();
+    EXPECT_THAT(copy_detector, CopyDetectorHas(kIntValue, false, true));
+    copy_detector = std::move(status_or).value();
+    EXPECT_THAT(copy_detector, CopyDetectorHas(kIntValue, true, false));
+  }
+}
+
+TEST(StatusOr, BadValueAccess) {
+  const absl::Status kError = absl::CancelledError("message");
+  absl::StatusOr<int> status_or(kError);
+  EXPECT_DEATH_OR_THROW(status_or.value(), kError);
+}
+
+TEST(StatusOr, TestStatusCtor) {
+  absl::StatusOr<int> thing(absl::CancelledError());
+  EXPECT_FALSE(thing.ok());
+  EXPECT_EQ(thing.status().code(), absl::StatusCode::kCancelled);
+}
+
+
+
+TEST(StatusOr, TestValueCtor) {
+  const int kI = 4;
+  const absl::StatusOr<int> thing(kI);
+  EXPECT_TRUE(thing.ok());
+  EXPECT_EQ(kI, *thing);
+}
+
+struct Foo {
+  const int x;
+  explicit Foo(int y) : x(y) {}
+};
+
+TEST(StatusOr, InPlaceConstruction) {
+  EXPECT_THAT(absl::StatusOr<Foo>(absl::in_place, 10),
+              IsOkAndHolds(Field(&Foo::x, 10)));
+}
+
+struct InPlaceHelper {
+  InPlaceHelper(std::initializer_list<int> xs, std::unique_ptr<int> yy)
+      : x(xs), y(std::move(yy)) {}
+  const std::vector<int> x;
+  std::unique_ptr<int> y;
+};
+
+TEST(StatusOr, InPlaceInitListConstruction) {
+  absl::StatusOr<InPlaceHelper> status_or(absl::in_place, {10, 11, 12},
+                                          absl::make_unique<int>(13));
+  EXPECT_THAT(status_or, IsOkAndHolds(AllOf(
+                             Field(&InPlaceHelper::x, ElementsAre(10, 11, 12)),
+                             Field(&InPlaceHelper::y, Pointee(13)))));
+}
+
+TEST(StatusOr, Emplace) {
+  absl::StatusOr<Foo> status_or_foo(10);
+  status_or_foo.emplace(20);
+  EXPECT_THAT(status_or_foo, IsOkAndHolds(Field(&Foo::x, 20)));
+  status_or_foo = absl::InvalidArgumentError("msg");
+  EXPECT_FALSE(status_or_foo.ok());
+  EXPECT_EQ(status_or_foo.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(status_or_foo.status().message(), "msg");
+  status_or_foo.emplace(20);
+  EXPECT_THAT(status_or_foo, IsOkAndHolds(Field(&Foo::x, 20)));
+}
+
+TEST(StatusOr, EmplaceInitializerList) {
+  absl::StatusOr<InPlaceHelper> status_or(absl::in_place, {10, 11, 12},
+                                          absl::make_unique<int>(13));
+  status_or.emplace({1, 2, 3}, absl::make_unique<int>(4));
+  EXPECT_THAT(status_or,
+              IsOkAndHolds(AllOf(Field(&InPlaceHelper::x, ElementsAre(1, 2, 3)),
+                                 Field(&InPlaceHelper::y, Pointee(4)))));
+  status_or = absl::InvalidArgumentError("msg");
+  EXPECT_FALSE(status_or.ok());
+  EXPECT_EQ(status_or.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(status_or.status().message(), "msg");
+  status_or.emplace({1, 2, 3}, absl::make_unique<int>(4));
+  EXPECT_THAT(status_or,
+              IsOkAndHolds(AllOf(Field(&InPlaceHelper::x, ElementsAre(1, 2, 3)),
+                                 Field(&InPlaceHelper::y, Pointee(4)))));
+}
+
+TEST(StatusOr, TestCopyCtorStatusOk) {
+  const int kI = 4;
+  const absl::StatusOr<int> original(kI);
+  const absl::StatusOr<int> copy(original);
+  EXPECT_OK(copy.status());
+  EXPECT_EQ(*original, *copy);
+}
+
+TEST(StatusOr, TestCopyCtorStatusNotOk) {
+  absl::StatusOr<int> original(absl::CancelledError());
+  absl::StatusOr<int> copy(original);
+  EXPECT_EQ(copy.status().code(), absl::StatusCode::kCancelled);
+}
+
+TEST(StatusOr, TestCopyCtorNonAssignable) {
+  const int kI = 4;
+  CopyNoAssign value(kI);
+  absl::StatusOr<CopyNoAssign> original(value);
+  absl::StatusOr<CopyNoAssign> copy(original);
+  EXPECT_OK(copy.status());
+  EXPECT_EQ(original->foo, copy->foo);
+}
+
+TEST(StatusOr, TestCopyCtorStatusOKConverting) {
+  const int kI = 4;
+  absl::StatusOr<int> original(kI);
+  absl::StatusOr<double> copy(original);
+  EXPECT_OK(copy.status());
+  EXPECT_DOUBLE_EQ(*original, *copy);
+}
+
+TEST(StatusOr, TestCopyCtorStatusNotOkConverting) {
+  absl::StatusOr<int> original(absl::CancelledError());
+  absl::StatusOr<double> copy(original);
+  EXPECT_EQ(copy.status(), original.status());
+}
+
+TEST(StatusOr, TestAssignmentStatusOk) {
+  // Copy assignmment
+  {
+    const auto p = std::make_shared<int>(17);
+    absl::StatusOr<std::shared_ptr<int>> source(p);
+
+    absl::StatusOr<std::shared_ptr<int>> target;
+    target = source;
+
+    ASSERT_TRUE(target.ok());
+    EXPECT_OK(target.status());
+    EXPECT_EQ(p, *target);
+
+    ASSERT_TRUE(source.ok());
+    EXPECT_OK(source.status());
+    EXPECT_EQ(p, *source);
+  }
+
+  // Move asssignment
+  {
+    const auto p = std::make_shared<int>(17);
+    absl::StatusOr<std::shared_ptr<int>> source(p);
+
+    absl::StatusOr<std::shared_ptr<int>> target;
+    target = std::move(source);
+
+    ASSERT_TRUE(target.ok());
+    EXPECT_OK(target.status());
+    EXPECT_EQ(p, *target);
+
+    ASSERT_TRUE(source.ok());
+    EXPECT_OK(source.status());
+    EXPECT_EQ(nullptr, *source);
+  }
+}
+
+TEST(StatusOr, TestAssignmentStatusNotOk) {
+  // Copy assignment
+  {
+    const absl::Status expected = absl::CancelledError();
+    absl::StatusOr<int> source(expected);
+
+    absl::StatusOr<int> target;
+    target = source;
+
+    EXPECT_FALSE(target.ok());
+    EXPECT_EQ(expected, target.status());
+
+    EXPECT_FALSE(source.ok());
+    EXPECT_EQ(expected, source.status());
+  }
+
+  // Move assignment
+  {
+    const absl::Status expected = absl::CancelledError();
+    absl::StatusOr<int> source(expected);
+
+    absl::StatusOr<int> target;
+    target = std::move(source);
+
+    EXPECT_FALSE(target.ok());
+    EXPECT_EQ(expected, target.status());
+
+    EXPECT_FALSE(source.ok());
+    EXPECT_EQ(source.status().code(), absl::StatusCode::kInternal);
+  }
+}
+
+TEST(StatusOr, TestAssignmentStatusOKConverting) {
+  // Copy assignment
+  {
+    const int kI = 4;
+    absl::StatusOr<int> source(kI);
+
+    absl::StatusOr<double> target;
+    target = source;
+
+    ASSERT_TRUE(target.ok());
+    EXPECT_OK(target.status());
+    EXPECT_DOUBLE_EQ(kI, *target);
+
+    ASSERT_TRUE(source.ok());
+    EXPECT_OK(source.status());
+    EXPECT_DOUBLE_EQ(kI, *source);
+  }
+
+  // Move assignment
+  {
+    const auto p = new int(17);
+    absl::StatusOr<std::unique_ptr<int>> source(absl::WrapUnique(p));
+
+    absl::StatusOr<std::shared_ptr<int>> target;
+    target = std::move(source);
+
+    ASSERT_TRUE(target.ok());
+    EXPECT_OK(target.status());
+    EXPECT_EQ(p, target->get());
+
+    ASSERT_TRUE(source.ok());
+    EXPECT_OK(source.status());
+    EXPECT_EQ(nullptr, source->get());
+  }
+}
+
+struct A {
+  int x;
+};
+
+struct ImplicitConstructibleFromA {
+  int x;
+  bool moved;
+  ImplicitConstructibleFromA(const A& a)  // NOLINT
+      : x(a.x), moved(false) {}
+  ImplicitConstructibleFromA(A&& a)  // NOLINT
+      : x(a.x), moved(true) {}
+};
+
+TEST(StatusOr, ImplicitConvertingConstructor) {
+  EXPECT_THAT(
+      absl::implicit_cast<absl::StatusOr<ImplicitConstructibleFromA>>(
+          absl::StatusOr<A>(A{11})),
+      IsOkAndHolds(AllOf(Field(&ImplicitConstructibleFromA::x, 11),
+                         Field(&ImplicitConstructibleFromA::moved, true))));
+  absl::StatusOr<A> a(A{12});
+  EXPECT_THAT(
+      absl::implicit_cast<absl::StatusOr<ImplicitConstructibleFromA>>(a),
+      IsOkAndHolds(AllOf(Field(&ImplicitConstructibleFromA::x, 12),
+                         Field(&ImplicitConstructibleFromA::moved, false))));
+}
+
+struct ExplicitConstructibleFromA {
+  int x;
+  bool moved;
+  explicit ExplicitConstructibleFromA(const A& a) : x(a.x), moved(false) {}
+  explicit ExplicitConstructibleFromA(A&& a) : x(a.x), moved(true) {}
+};
+
+TEST(StatusOr, ExplicitConvertingConstructor) {
+  EXPECT_FALSE(
+      (std::is_convertible<const absl::StatusOr<A>&,
+                           absl::StatusOr<ExplicitConstructibleFromA>>::value));
+  EXPECT_FALSE(
+      (std::is_convertible<absl::StatusOr<A>&&,
+                           absl::StatusOr<ExplicitConstructibleFromA>>::value));
+  EXPECT_THAT(
+      absl::StatusOr<ExplicitConstructibleFromA>(absl::StatusOr<A>(A{11})),
+      IsOkAndHolds(AllOf(Field(&ExplicitConstructibleFromA::x, 11),
+                         Field(&ExplicitConstructibleFromA::moved, true))));
+  absl::StatusOr<A> a(A{12});
+  EXPECT_THAT(
+      absl::StatusOr<ExplicitConstructibleFromA>(a),
+      IsOkAndHolds(AllOf(Field(&ExplicitConstructibleFromA::x, 12),
+                         Field(&ExplicitConstructibleFromA::moved, false))));
+}
+
+struct ImplicitConstructibleFromBool {
+  ImplicitConstructibleFromBool(bool y) : x(y) {}  // NOLINT
+  bool x = false;
+};
+
+struct ConvertibleToBool {
+  explicit ConvertibleToBool(bool y) : x(y) {}
+  operator bool() const { return x; }  // NOLINT
+  bool x = false;
+};
+
+TEST(StatusOr, ImplicitBooleanConstructionWithImplicitCasts) {
+  EXPECT_THAT(absl::StatusOr<bool>(absl::StatusOr<ConvertibleToBool>(true)),
+              IsOkAndHolds(true));
+  EXPECT_THAT(absl::StatusOr<bool>(absl::StatusOr<ConvertibleToBool>(false)),
+              IsOkAndHolds(false));
+  EXPECT_THAT(
+      absl::implicit_cast<absl::StatusOr<ImplicitConstructibleFromBool>>(
+          absl::StatusOr<bool>(false)),
+      IsOkAndHolds(Field(&ImplicitConstructibleFromBool::x, false)));
+  EXPECT_FALSE((std::is_convertible<
+                absl::StatusOr<ConvertibleToBool>,
+                absl::StatusOr<ImplicitConstructibleFromBool>>::value));
+}
+
+TEST(StatusOr, BooleanConstructionWithImplicitCasts) {
+  EXPECT_THAT(absl::StatusOr<bool>(absl::StatusOr<ConvertibleToBool>(true)),
+              IsOkAndHolds(true));
+  EXPECT_THAT(absl::StatusOr<bool>(absl::StatusOr<ConvertibleToBool>(false)),
+              IsOkAndHolds(false));
+  EXPECT_THAT(
+      absl::StatusOr<ImplicitConstructibleFromBool>{
+          absl::StatusOr<bool>(false)},
+      IsOkAndHolds(Field(&ImplicitConstructibleFromBool::x, false)));
+  EXPECT_THAT(
+      absl::StatusOr<ImplicitConstructibleFromBool>{
+          absl::StatusOr<bool>(absl::InvalidArgumentError(""))},
+      Not(IsOk()));
+
+  EXPECT_THAT(
+      absl::StatusOr<ImplicitConstructibleFromBool>{
+          absl::StatusOr<ConvertibleToBool>(ConvertibleToBool{false})},
+      IsOkAndHolds(Field(&ImplicitConstructibleFromBool::x, false)));
+  EXPECT_THAT(
+      absl::StatusOr<ImplicitConstructibleFromBool>{
+          absl::StatusOr<ConvertibleToBool>(absl::InvalidArgumentError(""))},
+      Not(IsOk()));
+}
+
+TEST(StatusOr, ConstImplicitCast) {
+  EXPECT_THAT(absl::implicit_cast<absl::StatusOr<bool>>(
+                  absl::StatusOr<const bool>(true)),
+              IsOkAndHolds(true));
+  EXPECT_THAT(absl::implicit_cast<absl::StatusOr<bool>>(
+                  absl::StatusOr<const bool>(false)),
+              IsOkAndHolds(false));
+  EXPECT_THAT(absl::implicit_cast<absl::StatusOr<const bool>>(
+                  absl::StatusOr<bool>(true)),
+              IsOkAndHolds(true));
+  EXPECT_THAT(absl::implicit_cast<absl::StatusOr<const bool>>(
+                  absl::StatusOr<bool>(false)),
+              IsOkAndHolds(false));
+  EXPECT_THAT(absl::implicit_cast<absl::StatusOr<const std::string>>(
+                  absl::StatusOr<std::string>("foo")),
+              IsOkAndHolds("foo"));
+  EXPECT_THAT(absl::implicit_cast<absl::StatusOr<std::string>>(
+                  absl::StatusOr<const std::string>("foo")),
+              IsOkAndHolds("foo"));
+  EXPECT_THAT(
+      absl::implicit_cast<absl::StatusOr<std::shared_ptr<const std::string>>>(
+          absl::StatusOr<std::shared_ptr<std::string>>(
+              std::make_shared<std::string>("foo"))),
+      IsOkAndHolds(Pointee(std::string("foo"))));
+}
+
+TEST(StatusOr, ConstExplicitConstruction) {
+  EXPECT_THAT(absl::StatusOr<bool>(absl::StatusOr<const bool>(true)),
+              IsOkAndHolds(true));
+  EXPECT_THAT(absl::StatusOr<bool>(absl::StatusOr<const bool>(false)),
+              IsOkAndHolds(false));
+  EXPECT_THAT(absl::StatusOr<const bool>(absl::StatusOr<bool>(true)),
+              IsOkAndHolds(true));
+  EXPECT_THAT(absl::StatusOr<const bool>(absl::StatusOr<bool>(false)),
+              IsOkAndHolds(false));
+}
+
+struct ExplicitConstructibleFromInt {
+  int x;
+  explicit ExplicitConstructibleFromInt(int y) : x(y) {}
+};
+
+TEST(StatusOr, ExplicitConstruction) {
+  EXPECT_THAT(absl::StatusOr<ExplicitConstructibleFromInt>(10),
+              IsOkAndHolds(Field(&ExplicitConstructibleFromInt::x, 10)));
+}
+
+TEST(StatusOr, ImplicitConstruction) {
+  // Check implicit casting works.
+  auto status_or =
+      absl::implicit_cast<absl::StatusOr<absl::variant<int, std::string>>>(10);
+  EXPECT_THAT(status_or, IsOkAndHolds(VariantWith<int>(10)));
+}
+
+TEST(StatusOr, ImplicitConstructionFromInitliazerList) {
+  // Note: dropping the explicit std::initializer_list<int> is not supported
+  // by absl::StatusOr or absl::optional.
+  auto status_or =
+      absl::implicit_cast<absl::StatusOr<std::vector<int>>>({{10, 20, 30}});
+  EXPECT_THAT(status_or, IsOkAndHolds(ElementsAre(10, 20, 30)));
+}
+
+TEST(StatusOr, UniquePtrImplicitConstruction) {
+  auto status_or = absl::implicit_cast<absl::StatusOr<std::unique_ptr<Base1>>>(
+      absl::make_unique<Derived>());
+  EXPECT_THAT(status_or, IsOkAndHolds(Ne(nullptr)));
+}
+
+TEST(StatusOr, NestedStatusOrCopyAndMoveConstructorTests) {
+  absl::StatusOr<absl::StatusOr<CopyDetector>> status_or = CopyDetector(10);
+  absl::StatusOr<absl::StatusOr<CopyDetector>> status_error =
+      absl::InvalidArgumentError("foo");
+  EXPECT_THAT(status_or,
+              IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, true, false))));
+  absl::StatusOr<absl::StatusOr<CopyDetector>> a = status_or;
+  EXPECT_THAT(a, IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, false, true))));
+  absl::StatusOr<absl::StatusOr<CopyDetector>> a_err = status_error;
+  EXPECT_THAT(a_err, Not(IsOk()));
+
+  const absl::StatusOr<absl::StatusOr<CopyDetector>>& cref = status_or;
+  absl::StatusOr<absl::StatusOr<CopyDetector>> b = cref;  // NOLINT
+  EXPECT_THAT(b, IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, false, true))));
+  const absl::StatusOr<absl::StatusOr<CopyDetector>>& cref_err = status_error;
+  absl::StatusOr<absl::StatusOr<CopyDetector>> b_err = cref_err;  // NOLINT
+  EXPECT_THAT(b_err, Not(IsOk()));
+
+  absl::StatusOr<absl::StatusOr<CopyDetector>> c = std::move(status_or);
+  EXPECT_THAT(c, IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, true, false))));
+  absl::StatusOr<absl::StatusOr<CopyDetector>> c_err = std::move(status_error);
+  EXPECT_THAT(c_err, Not(IsOk()));
+}
+
+TEST(StatusOr, NestedStatusOrCopyAndMoveAssignment) {
+  absl::StatusOr<absl::StatusOr<CopyDetector>> status_or = CopyDetector(10);
+  absl::StatusOr<absl::StatusOr<CopyDetector>> status_error =
+      absl::InvalidArgumentError("foo");
+  absl::StatusOr<absl::StatusOr<CopyDetector>> a;
+  a = status_or;
+  EXPECT_THAT(a, IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, false, true))));
+  a = status_error;
+  EXPECT_THAT(a, Not(IsOk()));
+
+  const absl::StatusOr<absl::StatusOr<CopyDetector>>& cref = status_or;
+  a = cref;
+  EXPECT_THAT(a, IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, false, true))));
+  const absl::StatusOr<absl::StatusOr<CopyDetector>>& cref_err = status_error;
+  a = cref_err;
+  EXPECT_THAT(a, Not(IsOk()));
+  a = std::move(status_or);
+  EXPECT_THAT(a, IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, true, false))));
+  a = std::move(status_error);
+  EXPECT_THAT(a, Not(IsOk()));
+}
+
+struct Copyable {
+  Copyable() {}
+  Copyable(const Copyable&) {}
+  Copyable& operator=(const Copyable&) { return *this; }
+};
+
+struct MoveOnly {
+  MoveOnly() {}
+  MoveOnly(MoveOnly&&) {}
+  MoveOnly& operator=(MoveOnly&&) { return *this; }
+};
+
+struct NonMovable {
+  NonMovable() {}
+  NonMovable(const NonMovable&) = delete;
+  NonMovable(NonMovable&&) = delete;
+  NonMovable& operator=(const NonMovable&) = delete;
+  NonMovable& operator=(NonMovable&&) = delete;
+};
+
+TEST(StatusOr, CopyAndMoveAbility) {
+  EXPECT_TRUE(std::is_copy_constructible<Copyable>::value);
+  EXPECT_TRUE(std::is_copy_assignable<Copyable>::value);
+  EXPECT_TRUE(std::is_move_constructible<Copyable>::value);
+  EXPECT_TRUE(std::is_move_assignable<Copyable>::value);
+  EXPECT_FALSE(std::is_copy_constructible<MoveOnly>::value);
+  EXPECT_FALSE(std::is_copy_assignable<MoveOnly>::value);
+  EXPECT_TRUE(std::is_move_constructible<MoveOnly>::value);
+  EXPECT_TRUE(std::is_move_assignable<MoveOnly>::value);
+  EXPECT_FALSE(std::is_copy_constructible<NonMovable>::value);
+  EXPECT_FALSE(std::is_copy_assignable<NonMovable>::value);
+  EXPECT_FALSE(std::is_move_constructible<NonMovable>::value);
+  EXPECT_FALSE(std::is_move_assignable<NonMovable>::value);
+}
+
+TEST(StatusOr, StatusOrAnyCopyAndMoveConstructorTests) {
+  absl::StatusOr<absl::any> status_or = CopyDetector(10);
+  absl::StatusOr<absl::any> status_error = absl::InvalidArgumentError("foo");
+  EXPECT_THAT(
+      status_or,
+      IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, true, false))));
+  absl::StatusOr<absl::any> a = status_or;
+  EXPECT_THAT(
+      a, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true))));
+  absl::StatusOr<absl::any> a_err = status_error;
+  EXPECT_THAT(a_err, Not(IsOk()));
+
+  const absl::StatusOr<absl::any>& cref = status_or;
+  // No lint for no-change copy.
+  absl::StatusOr<absl::any> b = cref;  // NOLINT
+  EXPECT_THAT(
+      b, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true))));
+  const absl::StatusOr<absl::any>& cref_err = status_error;
+  // No lint for no-change copy.
+  absl::StatusOr<absl::any> b_err = cref_err;  // NOLINT
+  EXPECT_THAT(b_err, Not(IsOk()));
+
+  absl::StatusOr<absl::any> c = std::move(status_or);
+  EXPECT_THAT(
+      c, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, true, false))));
+  absl::StatusOr<absl::any> c_err = std::move(status_error);
+  EXPECT_THAT(c_err, Not(IsOk()));
+}
+
+TEST(StatusOr, StatusOrAnyCopyAndMoveAssignment) {
+  absl::StatusOr<absl::any> status_or = CopyDetector(10);
+  absl::StatusOr<absl::any> status_error = absl::InvalidArgumentError("foo");
+  absl::StatusOr<absl::any> a;
+  a = status_or;
+  EXPECT_THAT(
+      a, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true))));
+  a = status_error;
+  EXPECT_THAT(a, Not(IsOk()));
+
+  const absl::StatusOr<absl::any>& cref = status_or;
+  a = cref;
+  EXPECT_THAT(
+      a, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true))));
+  const absl::StatusOr<absl::any>& cref_err = status_error;
+  a = cref_err;
+  EXPECT_THAT(a, Not(IsOk()));
+  a = std::move(status_or);
+  EXPECT_THAT(
+      a, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, true, false))));
+  a = std::move(status_error);
+  EXPECT_THAT(a, Not(IsOk()));
+}
+
+TEST(StatusOr, StatusOrCopyAndMoveTestsConstructor) {
+  absl::StatusOr<CopyDetector> status_or(10);
+  ASSERT_THAT(status_or, IsOkAndHolds(CopyDetectorHas(10, false, false)));
+  absl::StatusOr<CopyDetector> a(status_or);
+  EXPECT_THAT(a, IsOkAndHolds(CopyDetectorHas(10, false, true)));
+  const absl::StatusOr<CopyDetector>& cref = status_or;
+  absl::StatusOr<CopyDetector> b(cref);  // NOLINT
+  EXPECT_THAT(b, IsOkAndHolds(CopyDetectorHas(10, false, true)));
+  absl::StatusOr<CopyDetector> c(std::move(status_or));
+  EXPECT_THAT(c, IsOkAndHolds(CopyDetectorHas(10, true, false)));
+}
+
+TEST(StatusOr, StatusOrCopyAndMoveTestsAssignment) {
+  absl::StatusOr<CopyDetector> status_or(10);
+  ASSERT_THAT(status_or, IsOkAndHolds(CopyDetectorHas(10, false, false)));
+  absl::StatusOr<CopyDetector> a;
+  a = status_or;
+  EXPECT_THAT(a, IsOkAndHolds(CopyDetectorHas(10, false, true)));
+  const absl::StatusOr<CopyDetector>& cref = status_or;
+  absl::StatusOr<CopyDetector> b;
+  b = cref;
+  EXPECT_THAT(b, IsOkAndHolds(CopyDetectorHas(10, false, true)));
+  absl::StatusOr<CopyDetector> c;
+  c = std::move(status_or);
+  EXPECT_THAT(c, IsOkAndHolds(CopyDetectorHas(10, true, false)));
+}
+
+TEST(StatusOr, AbslAnyAssignment) {
+  EXPECT_FALSE((std::is_assignable<absl::StatusOr<absl::any>,
+                                   absl::StatusOr<int>>::value));
+  absl::StatusOr<absl::any> status_or;
+  status_or = absl::InvalidArgumentError("foo");
+  EXPECT_THAT(status_or, Not(IsOk()));
+}
+
+TEST(StatusOr, ImplicitAssignment) {
+  absl::StatusOr<absl::variant<int, std::string>> status_or;
+  status_or = 10;
+  EXPECT_THAT(status_or, IsOkAndHolds(VariantWith<int>(10)));
+}
+
+TEST(StatusOr, SelfDirectInitAssignment) {
+  absl::StatusOr<std::vector<int>> status_or = {{10, 20, 30}};
+  status_or = *status_or;
+  EXPECT_THAT(status_or, IsOkAndHolds(ElementsAre(10, 20, 30)));
+}
+
+TEST(StatusOr, ImplicitCastFromInitializerList) {
+  absl::StatusOr<std::vector<int>> status_or = {{10, 20, 30}};
+  EXPECT_THAT(status_or, IsOkAndHolds(ElementsAre(10, 20, 30)));
+}
+
+TEST(StatusOr, UniquePtrImplicitAssignment) {
+  absl::StatusOr<std::unique_ptr<Base1>> status_or;
+  status_or = absl::make_unique<Derived>();
+  EXPECT_THAT(status_or, IsOkAndHolds(Ne(nullptr)));
+}
+
+TEST(StatusOr, Pointer) {
+  struct A {};
+  struct B : public A {};
+  struct C : private A {};
+
+  EXPECT_TRUE((std::is_constructible<absl::StatusOr<A*>, B*>::value));
+  EXPECT_TRUE((std::is_convertible<B*, absl::StatusOr<A*>>::value));
+  EXPECT_FALSE((std::is_constructible<absl::StatusOr<A*>, C*>::value));
+  EXPECT_FALSE((std::is_convertible<C*, absl::StatusOr<A*>>::value));
+}
+
+TEST(StatusOr, TestAssignmentStatusNotOkConverting) {
+  // Copy assignment
+  {
+    const absl::Status expected = absl::CancelledError();
+    absl::StatusOr<int> source(expected);
+
+    absl::StatusOr<double> target;
+    target = source;
+
+    EXPECT_FALSE(target.ok());
+    EXPECT_EQ(expected, target.status());
+
+    EXPECT_FALSE(source.ok());
+    EXPECT_EQ(expected, source.status());
+  }
+
+  // Move assignment
+  {
+    const absl::Status expected = absl::CancelledError();
+    absl::StatusOr<int> source(expected);
+
+    absl::StatusOr<double> target;
+    target = std::move(source);
+
+    EXPECT_FALSE(target.ok());
+    EXPECT_EQ(expected, target.status());
+
+    EXPECT_FALSE(source.ok());
+    EXPECT_EQ(source.status().code(), absl::StatusCode::kInternal);
+  }
+}
+
+TEST(StatusOr, SelfAssignment) {
+  // Copy-assignment, status OK
+  {
+    // A string long enough that it's likely to defeat any inline representation
+    // optimization.
+    const std::string long_str(128, 'a');
+
+    absl::StatusOr<std::string> so = long_str;
+    so = *&so;
+
+    ASSERT_TRUE(so.ok());
+    EXPECT_OK(so.status());
+    EXPECT_EQ(long_str, *so);
+  }
+
+  // Copy-assignment, error status
+  {
+    absl::StatusOr<int> so = absl::NotFoundError("taco");
+    so = *&so;
+
+    EXPECT_FALSE(so.ok());
+    EXPECT_EQ(so.status().code(), absl::StatusCode::kNotFound);
+    EXPECT_EQ(so.status().message(), "taco");
+  }
+
+  // Move-assignment with copyable type, status OK
+  {
+    absl::StatusOr<int> so = 17;
+
+    // Fool the compiler, which otherwise complains.
+    auto& same = so;
+    so = std::move(same);
+
+    ASSERT_TRUE(so.ok());
+    EXPECT_OK(so.status());
+    EXPECT_EQ(17, *so);
+  }
+
+  // Move-assignment with copyable type, error status
+  {
+    absl::StatusOr<int> so = absl::NotFoundError("taco");
+
+    // Fool the compiler, which otherwise complains.
+    auto& same = so;
+    so = std::move(same);
+
+    EXPECT_FALSE(so.ok());
+    EXPECT_EQ(so.status().code(), absl::StatusCode::kNotFound);
+    EXPECT_EQ(so.status().message(), "taco");
+  }
+
+  // Move-assignment with non-copyable type, status OK
+  {
+    const auto raw = new int(17);
+    absl::StatusOr<std::unique_ptr<int>> so = absl::WrapUnique(raw);
+
+    // Fool the compiler, which otherwise complains.
+    auto& same = so;
+    so = std::move(same);
+
+    ASSERT_TRUE(so.ok());
+    EXPECT_OK(so.status());
+    EXPECT_EQ(raw, so->get());
+  }
+
+  // Move-assignment with non-copyable type, error status
+  {
+    absl::StatusOr<std::unique_ptr<int>> so = absl::NotFoundError("taco");
+
+    // Fool the compiler, which otherwise complains.
+    auto& same = so;
+    so = std::move(same);
+
+    EXPECT_FALSE(so.ok());
+    EXPECT_EQ(so.status().code(), absl::StatusCode::kNotFound);
+    EXPECT_EQ(so.status().message(), "taco");
+  }
+}
+
+// These types form the overload sets of the constructors and the assignment
+// operators of `MockValue`. They distinguish construction from assignment,
+// lvalue from rvalue.
+struct FromConstructibleAssignableLvalue {};
+struct FromConstructibleAssignableRvalue {};
+struct FromImplicitConstructibleOnly {};
+struct FromAssignableOnly {};
+
+// This class is for testing the forwarding value assignments of `StatusOr`.
+// `from_rvalue` indicates whether the constructor or the assignment taking
+// rvalue reference is called. `from_assignment` indicates whether any
+// assignment is called.
+struct MockValue {
+  // Constructs `MockValue` from `FromConstructibleAssignableLvalue`.
+  MockValue(const FromConstructibleAssignableLvalue&)  // NOLINT
+      : from_rvalue(false), assigned(false) {}
+  // Constructs `MockValue` from `FromConstructibleAssignableRvalue`.
+  MockValue(FromConstructibleAssignableRvalue&&)  // NOLINT
+      : from_rvalue(true), assigned(false) {}
+  // Constructs `MockValue` from `FromImplicitConstructibleOnly`.
+  // `MockValue` is not assignable from `FromImplicitConstructibleOnly`.
+  MockValue(const FromImplicitConstructibleOnly&)  // NOLINT
+      : from_rvalue(false), assigned(false) {}
+  // Assigns `FromConstructibleAssignableLvalue`.
+  MockValue& operator=(const FromConstructibleAssignableLvalue&) {
+    from_rvalue = false;
+    assigned = true;
+    return *this;
+  }
+  // Assigns `FromConstructibleAssignableRvalue` (rvalue only).
+  MockValue& operator=(FromConstructibleAssignableRvalue&&) {
+    from_rvalue = true;
+    assigned = true;
+    return *this;
+  }
+  // Assigns `FromAssignableOnly`, but not constructible from
+  // `FromAssignableOnly`.
+  MockValue& operator=(const FromAssignableOnly&) {
+    from_rvalue = false;
+    assigned = true;
+    return *this;
+  }
+  bool from_rvalue;
+  bool assigned;
+};
+
+// operator=(U&&)
+TEST(StatusOr, PerfectForwardingAssignment) {
+  // U == T
+  constexpr int kValue1 = 10, kValue2 = 20;
+  absl::StatusOr<CopyDetector> status_or;
+  CopyDetector lvalue(kValue1);
+  status_or = lvalue;
+  EXPECT_THAT(status_or, IsOkAndHolds(CopyDetectorHas(kValue1, false, true)));
+  status_or = CopyDetector(kValue2);
+  EXPECT_THAT(status_or, IsOkAndHolds(CopyDetectorHas(kValue2, true, false)));
+
+  // U != T
+  EXPECT_TRUE(
+      (std::is_assignable<absl::StatusOr<MockValue>&,
+                          const FromConstructibleAssignableLvalue&>::value));
+  EXPECT_TRUE((std::is_assignable<absl::StatusOr<MockValue>&,
+                                  FromConstructibleAssignableLvalue&&>::value));
+  EXPECT_FALSE(
+      (std::is_assignable<absl::StatusOr<MockValue>&,
+                          const FromConstructibleAssignableRvalue&>::value));
+  EXPECT_TRUE((std::is_assignable<absl::StatusOr<MockValue>&,
+                                  FromConstructibleAssignableRvalue&&>::value));
+  EXPECT_TRUE(
+      (std::is_assignable<absl::StatusOr<MockValue>&,
+                          const FromImplicitConstructibleOnly&>::value));
+  EXPECT_FALSE((std::is_assignable<absl::StatusOr<MockValue>&,
+                                   const FromAssignableOnly&>::value));
+
+  absl::StatusOr<MockValue> from_lvalue(FromConstructibleAssignableLvalue{});
+  EXPECT_FALSE(from_lvalue->from_rvalue);
+  EXPECT_FALSE(from_lvalue->assigned);
+  from_lvalue = FromConstructibleAssignableLvalue{};
+  EXPECT_FALSE(from_lvalue->from_rvalue);
+  EXPECT_TRUE(from_lvalue->assigned);
+
+  absl::StatusOr<MockValue> from_rvalue(FromConstructibleAssignableRvalue{});
+  EXPECT_TRUE(from_rvalue->from_rvalue);
+  EXPECT_FALSE(from_rvalue->assigned);
+  from_rvalue = FromConstructibleAssignableRvalue{};
+  EXPECT_TRUE(from_rvalue->from_rvalue);
+  EXPECT_TRUE(from_rvalue->assigned);
+
+  absl::StatusOr<MockValue> from_implicit_constructible(
+      FromImplicitConstructibleOnly{});
+  EXPECT_FALSE(from_implicit_constructible->from_rvalue);
+  EXPECT_FALSE(from_implicit_constructible->assigned);
+  // construct a temporary `StatusOr` object and invoke the `StatusOr` move
+  // assignment operator.
+  from_implicit_constructible = FromImplicitConstructibleOnly{};
+  EXPECT_FALSE(from_implicit_constructible->from_rvalue);
+  EXPECT_FALSE(from_implicit_constructible->assigned);
+}
+
+TEST(StatusOr, TestStatus) {
+  absl::StatusOr<int> good(4);
+  EXPECT_TRUE(good.ok());
+  absl::StatusOr<int> bad(absl::CancelledError());
+  EXPECT_FALSE(bad.ok());
+  EXPECT_EQ(bad.status().code(), absl::StatusCode::kCancelled);
+}
+
+TEST(StatusOr, OperatorStarRefQualifiers) {
+  static_assert(
+      std::is_same<const int&,
+                   decltype(*std::declval<const absl::StatusOr<int>&>())>(),
+      "Unexpected ref-qualifiers");
+  static_assert(
+      std::is_same<int&, decltype(*std::declval<absl::StatusOr<int>&>())>(),
+      "Unexpected ref-qualifiers");
+  static_assert(
+      std::is_same<const int&&,
+                   decltype(*std::declval<const absl::StatusOr<int>&&>())>(),
+      "Unexpected ref-qualifiers");
+  static_assert(
+      std::is_same<int&&, decltype(*std::declval<absl::StatusOr<int>&&>())>(),
+      "Unexpected ref-qualifiers");
+}
+
+TEST(StatusOr, OperatorStar) {
+  const absl::StatusOr<std::string> const_lvalue("hello");
+  EXPECT_EQ("hello", *const_lvalue);
+
+  absl::StatusOr<std::string> lvalue("hello");
+  EXPECT_EQ("hello", *lvalue);
+
+  // Note: Recall that std::move() is equivalent to a static_cast to an rvalue
+  // reference type.
+  const absl::StatusOr<std::string> const_rvalue("hello");
+  EXPECT_EQ("hello", *std::move(const_rvalue));  // NOLINT
+
+  absl::StatusOr<std::string> rvalue("hello");
+  EXPECT_EQ("hello", *std::move(rvalue));
+}
+
+TEST(StatusOr, OperatorArrowQualifiers) {
+  static_assert(
+      std::is_same<
+          const int*,
+          decltype(std::declval<const absl::StatusOr<int>&>().operator->())>(),
+      "Unexpected qualifiers");
+  static_assert(
+      std::is_same<
+          int*, decltype(std::declval<absl::StatusOr<int>&>().operator->())>(),
+      "Unexpected qualifiers");
+  static_assert(
+      std::is_same<
+          const int*,
+          decltype(std::declval<const absl::StatusOr<int>&&>().operator->())>(),
+      "Unexpected qualifiers");
+  static_assert(
+      std::is_same<
+          int*, decltype(std::declval<absl::StatusOr<int>&&>().operator->())>(),
+      "Unexpected qualifiers");
+}
+
+TEST(StatusOr, OperatorArrow) {
+  const absl::StatusOr<std::string> const_lvalue("hello");
+  EXPECT_EQ(std::string("hello"), const_lvalue->c_str());
+
+  absl::StatusOr<std::string> lvalue("hello");
+  EXPECT_EQ(std::string("hello"), lvalue->c_str());
+}
+
+TEST(StatusOr, RValueStatus) {
+  absl::StatusOr<int> so(absl::NotFoundError("taco"));
+  const absl::Status s = std::move(so).status();
+
+  EXPECT_EQ(s.code(), absl::StatusCode::kNotFound);
+  EXPECT_EQ(s.message(), "taco");
+
+  // Check that !ok() still implies !status().ok(), even after moving out of the
+  // object. See the note on the rvalue ref-qualified status method.
+  EXPECT_FALSE(so.ok());  // NOLINT
+  EXPECT_FALSE(so.status().ok());
+  EXPECT_EQ(so.status().code(), absl::StatusCode::kInternal);
+  EXPECT_EQ(so.status().message(), "Status accessed after move.");
+}
+
+TEST(StatusOr, TestValue) {
+  const int kI = 4;
+  absl::StatusOr<int> thing(kI);
+  EXPECT_EQ(kI, *thing);
+}
+
+TEST(StatusOr, TestValueConst) {
+  const int kI = 4;
+  const absl::StatusOr<int> thing(kI);
+  EXPECT_EQ(kI, *thing);
+}
+
+TEST(StatusOr, TestPointerDefaultCtor) {
+  absl::StatusOr<int*> thing;
+  EXPECT_FALSE(thing.ok());
+  EXPECT_EQ(thing.status().code(), absl::StatusCode::kUnknown);
+}
+
+
+
+TEST(StatusOr, TestPointerStatusCtor) {
+  absl::StatusOr<int*> thing(absl::CancelledError());
+  EXPECT_FALSE(thing.ok());
+  EXPECT_EQ(thing.status().code(), absl::StatusCode::kCancelled);
+}
+
+TEST(StatusOr, TestPointerValueCtor) {
+  const int kI = 4;
+
+  // Construction from a non-null pointer
+  {
+    absl::StatusOr<const int*> so(&kI);
+    EXPECT_TRUE(so.ok());
+    EXPECT_OK(so.status());
+    EXPECT_EQ(&kI, *so);
+  }
+
+  // Construction from a null pointer constant
+  {
+    absl::StatusOr<const int*> so(nullptr);
+    EXPECT_TRUE(so.ok());
+    EXPECT_OK(so.status());
+    EXPECT_EQ(nullptr, *so);
+  }
+
+  // Construction from a non-literal null pointer
+  {
+    const int* const p = nullptr;
+
+    absl::StatusOr<const int*> so(p);
+    EXPECT_TRUE(so.ok());
+    EXPECT_OK(so.status());
+    EXPECT_EQ(nullptr, *so);
+  }
+}
+
+TEST(StatusOr, TestPointerCopyCtorStatusOk) {
+  const int kI = 0;
+  absl::StatusOr<const int*> original(&kI);
+  absl::StatusOr<const int*> copy(original);
+  EXPECT_OK(copy.status());
+  EXPECT_EQ(*original, *copy);
+}
+
+TEST(StatusOr, TestPointerCopyCtorStatusNotOk) {
+  absl::StatusOr<int*> original(absl::CancelledError());
+  absl::StatusOr<int*> copy(original);
+  EXPECT_EQ(copy.status().code(), absl::StatusCode::kCancelled);
+}
+
+TEST(StatusOr, TestPointerCopyCtorStatusOKConverting) {
+  Derived derived;
+  absl::StatusOr<Derived*> original(&derived);
+  absl::StatusOr<Base2*> copy(original);
+  EXPECT_OK(copy.status());
+  EXPECT_EQ(static_cast<const Base2*>(*original), *copy);
+}
+
+TEST(StatusOr, TestPointerCopyCtorStatusNotOkConverting) {
+  absl::StatusOr<Derived*> original(absl::CancelledError());
+  absl::StatusOr<Base2*> copy(original);
+  EXPECT_EQ(copy.status().code(), absl::StatusCode::kCancelled);
+}
+
+TEST(StatusOr, TestPointerAssignmentStatusOk) {
+  const int kI = 0;
+  absl::StatusOr<const int*> source(&kI);
+  absl::StatusOr<const int*> target;
+  target = source;
+  EXPECT_OK(target.status());
+  EXPECT_EQ(*source, *target);
+}
+
+TEST(StatusOr, TestPointerAssignmentStatusNotOk) {
+  absl::StatusOr<int*> source(absl::CancelledError());
+  absl::StatusOr<int*> target;
+  target = source;
+  EXPECT_EQ(target.status().code(), absl::StatusCode::kCancelled);
+}
+
+TEST(StatusOr, TestPointerAssignmentStatusOKConverting) {
+  Derived derived;
+  absl::StatusOr<Derived*> source(&derived);
+  absl::StatusOr<Base2*> target;
+  target = source;
+  EXPECT_OK(target.status());
+  EXPECT_EQ(static_cast<const Base2*>(*source), *target);
+}
+
+TEST(StatusOr, TestPointerAssignmentStatusNotOkConverting) {
+  absl::StatusOr<Derived*> source(absl::CancelledError());
+  absl::StatusOr<Base2*> target;
+  target = source;
+  EXPECT_EQ(target.status(), source.status());
+}
+
+TEST(StatusOr, TestPointerStatus) {
+  const int kI = 0;
+  absl::StatusOr<const int*> good(&kI);
+  EXPECT_TRUE(good.ok());
+  absl::StatusOr<const int*> bad(absl::CancelledError());
+  EXPECT_EQ(bad.status().code(), absl::StatusCode::kCancelled);
+}
+
+TEST(StatusOr, TestPointerValue) {
+  const int kI = 0;
+  absl::StatusOr<const int*> thing(&kI);
+  EXPECT_EQ(&kI, *thing);
+}
+
+TEST(StatusOr, TestPointerValueConst) {
+  const int kI = 0;
+  const absl::StatusOr<const int*> thing(&kI);
+  EXPECT_EQ(&kI, *thing);
+}
+
+TEST(StatusOr, StatusOrVectorOfUniquePointerCanReserveAndResize) {
+  using EvilType = std::vector<std::unique_ptr<int>>;
+  static_assert(std::is_copy_constructible<EvilType>::value, "");
+  std::vector<::absl::StatusOr<EvilType>> v(5);
+  v.reserve(v.capacity() + 10);
+  v.resize(v.capacity() + 10);
+}
+
+TEST(StatusOr, ConstPayload) {
+  // A reduced version of a problematic type found in the wild. All of the
+  // operations below should compile.
+  absl::StatusOr<const int> a;
+
+  // Copy-construction
+  absl::StatusOr<const int> b(a);
+
+  // Copy-assignment
+  EXPECT_FALSE(std::is_copy_assignable<absl::StatusOr<const int>>::value);
+
+  // Move-construction
+  absl::StatusOr<const int> c(std::move(a));
+
+  // Move-assignment
+  EXPECT_FALSE(std::is_move_assignable<absl::StatusOr<const int>>::value);
+}
+
+TEST(StatusOr, MapToStatusOrUniquePtr) {
+  // A reduced version of a problematic type found in the wild. All of the
+  // operations below should compile.
+  using MapType = std::map<std::string, absl::StatusOr<std::unique_ptr<int>>>;
+
+  MapType a;
+
+  // Move-construction
+  MapType b(std::move(a));
+
+  // Move-assignment
+  a = std::move(b);
+}
+
+TEST(StatusOr, ValueOrOk) {
+  const absl::StatusOr<int> status_or = 0;
+  EXPECT_EQ(status_or.value_or(-1), 0);
+}
+
+TEST(StatusOr, ValueOrDefault) {
+  const absl::StatusOr<int> status_or = absl::CancelledError();
+  EXPECT_EQ(status_or.value_or(-1), -1);
+}
+
+TEST(StatusOr, MoveOnlyValueOrOk) {
+  EXPECT_THAT(absl::StatusOr<std::unique_ptr<int>>(absl::make_unique<int>(0))
+                  .value_or(absl::make_unique<int>(-1)),
+              Pointee(0));
+}
+
+TEST(StatusOr, MoveOnlyValueOrDefault) {
+  EXPECT_THAT(absl::StatusOr<std::unique_ptr<int>>(absl::CancelledError())
+                  .value_or(absl::make_unique<int>(-1)),
+              Pointee(-1));
+}
+
+static absl::StatusOr<int> MakeStatus() { return 100; }
+
+TEST(StatusOr, TestIgnoreError) { MakeStatus().IgnoreError(); }
+
+TEST(StatusOr, EqualityOperator) {
+  constexpr int kNumCases = 4;
+  std::array<absl::StatusOr<int>, kNumCases> group1 = {
+      absl::StatusOr<int>(1), absl::StatusOr<int>(2),
+      absl::StatusOr<int>(absl::InvalidArgumentError("msg")),
+      absl::StatusOr<int>(absl::InternalError("msg"))};
+  std::array<absl::StatusOr<int>, kNumCases> group2 = {
+      absl::StatusOr<int>(1), absl::StatusOr<int>(2),
+      absl::StatusOr<int>(absl::InvalidArgumentError("msg")),
+      absl::StatusOr<int>(absl::InternalError("msg"))};
+  for (int i = 0; i < kNumCases; ++i) {
+    for (int j = 0; j < kNumCases; ++j) {
+      if (i == j) {
+        EXPECT_TRUE(group1[i] == group2[j]);
+        EXPECT_FALSE(group1[i] != group2[j]);
+      } else {
+        EXPECT_FALSE(group1[i] == group2[j]);
+        EXPECT_TRUE(group1[i] != group2[j]);
+      }
+    }
+  }
+}
+
+struct MyType {
+  bool operator==(const MyType&) const { return true; }
+};
+
+enum class ConvTraits { kNone = 0, kImplicit = 1, kExplicit = 2 };
+
+// This class has conversion operator to `StatusOr<T>` based on value of
+// `conv_traits`.
+template <typename T, ConvTraits conv_traits = ConvTraits::kNone>
+struct StatusOrConversionBase {};
+
+template <typename T>
+struct StatusOrConversionBase<T, ConvTraits::kImplicit> {
+  operator absl::StatusOr<T>() const& {  // NOLINT
+    return absl::InvalidArgumentError("conversion to absl::StatusOr");
+  }
+  operator absl::StatusOr<T>() && {  // NOLINT
+    return absl::InvalidArgumentError("conversion to absl::StatusOr");
+  }
+};
+
+template <typename T>
+struct StatusOrConversionBase<T, ConvTraits::kExplicit> {
+  explicit operator absl::StatusOr<T>() const& {
+    return absl::InvalidArgumentError("conversion to absl::StatusOr");
+  }
+  explicit operator absl::StatusOr<T>() && {
+    return absl::InvalidArgumentError("conversion to absl::StatusOr");
+  }
+};
+
+// This class has conversion operator to `T` based on the value of
+// `conv_traits`.
+template <typename T, ConvTraits conv_traits = ConvTraits::kNone>
+struct ConversionBase {};
+
+template <typename T>
+struct ConversionBase<T, ConvTraits::kImplicit> {
+  operator T() const& { return t; }         // NOLINT
+  operator T() && { return std::move(t); }  // NOLINT
+  T t;
+};
+
+template <typename T>
+struct ConversionBase<T, ConvTraits::kExplicit> {
+  explicit operator T() const& { return t; }
+  explicit operator T() && { return std::move(t); }
+  T t;
+};
+
+// This class has conversion operator to `absl::Status` based on the value of
+// `conv_traits`.
+template <ConvTraits conv_traits = ConvTraits::kNone>
+struct StatusConversionBase {};
+
+template <>
+struct StatusConversionBase<ConvTraits::kImplicit> {
+  operator absl::Status() const& {  // NOLINT
+    return absl::InternalError("conversion to Status");
+  }
+  operator absl::Status() && {  // NOLINT
+    return absl::InternalError("conversion to Status");
+  }
+};
+
+template <>
+struct StatusConversionBase<ConvTraits::kExplicit> {
+  explicit operator absl::Status() const& {  // NOLINT
+    return absl::InternalError("conversion to Status");
+  }
+  explicit operator absl::Status() && {  // NOLINT
+    return absl::InternalError("conversion to Status");
+  }
+};
+
+static constexpr int kConvToStatus = 1;
+static constexpr int kConvToStatusOr = 2;
+static constexpr int kConvToT = 4;
+static constexpr int kConvExplicit = 8;
+
+constexpr ConvTraits GetConvTraits(int bit, int config) {
+  return (config & bit) == 0
+             ? ConvTraits::kNone
+             : ((config & kConvExplicit) == 0 ? ConvTraits::kImplicit
+                                              : ConvTraits::kExplicit);
+}
+
+// This class conditionally has conversion operator to `absl::Status`, `T`,
+// `StatusOr<T>`, based on values of the template parameters.
+template <typename T, int config>
+struct CustomType
+    : StatusOrConversionBase<T, GetConvTraits(kConvToStatusOr, config)>,
+      ConversionBase<T, GetConvTraits(kConvToT, config)>,
+      StatusConversionBase<GetConvTraits(kConvToStatus, config)> {};
+
+struct ConvertibleToAnyStatusOr {
+  template <typename T>
+  operator absl::StatusOr<T>() const {  // NOLINT
+    return absl::InvalidArgumentError("Conversion to absl::StatusOr");
+  }
+};
+
+// Test the rank of overload resolution for `StatusOr<T>` constructor and
+// assignment, from highest to lowest:
+// 1. T/Status
+// 2. U that has conversion operator to absl::StatusOr<T>
+// 3. U that is convertible to Status
+// 4. U that is convertible to T
+TEST(StatusOr, ConstructionFromT) {
+  // Construct absl::StatusOr<T> from T when T is convertible to
+  // absl::StatusOr<T>
+  {
+    ConvertibleToAnyStatusOr v;
+    absl::StatusOr<ConvertibleToAnyStatusOr> statusor(v);
+    EXPECT_TRUE(statusor.ok());
+  }
+  {
+    ConvertibleToAnyStatusOr v;
+    absl::StatusOr<ConvertibleToAnyStatusOr> statusor = v;
+    EXPECT_TRUE(statusor.ok());
+  }
+  // Construct absl::StatusOr<T> from T when T is explicitly convertible to
+  // Status
+  {
+    CustomType<MyType, kConvToStatus | kConvExplicit> v;
+    absl::StatusOr<CustomType<MyType, kConvToStatus | kConvExplicit>> statusor(
+        v);
+    EXPECT_TRUE(statusor.ok());
+  }
+  {
+    CustomType<MyType, kConvToStatus | kConvExplicit> v;
+    absl::StatusOr<CustomType<MyType, kConvToStatus | kConvExplicit>> statusor =
+        v;
+    EXPECT_TRUE(statusor.ok());
+  }
+}
+
+// Construct absl::StatusOr<T> from U when U is explicitly convertible to T
+TEST(StatusOr, ConstructionFromTypeConvertibleToT) {
+  {
+    CustomType<MyType, kConvToT | kConvExplicit> v;
+    absl::StatusOr<MyType> statusor(v);
+    EXPECT_TRUE(statusor.ok());
+  }
+  {
+    CustomType<MyType, kConvToT> v;
+    absl::StatusOr<MyType> statusor = v;
+    EXPECT_TRUE(statusor.ok());
+  }
+}
+
+// Construct absl::StatusOr<T> from U when U has explicit conversion operator to
+// absl::StatusOr<T>
+TEST(StatusOr, ConstructionFromTypeWithConversionOperatorToStatusOrT) {
+  {
+    CustomType<MyType, kConvToStatusOr | kConvExplicit> v;
+    absl::StatusOr<MyType> statusor(v);
+    EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+  }
+  {
+    CustomType<MyType, kConvToT | kConvToStatusOr | kConvExplicit> v;
+    absl::StatusOr<MyType> statusor(v);
+    EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+  }
+  {
+    CustomType<MyType, kConvToStatusOr | kConvToStatus | kConvExplicit> v;
+    absl::StatusOr<MyType> statusor(v);
+    EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+  }
+  {
+    CustomType<MyType,
+               kConvToT | kConvToStatusOr | kConvToStatus | kConvExplicit>
+        v;
+    absl::StatusOr<MyType> statusor(v);
+    EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+  }
+  {
+    CustomType<MyType, kConvToStatusOr> v;
+    absl::StatusOr<MyType> statusor = v;
+    EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+  }
+  {
+    CustomType<MyType, kConvToT | kConvToStatusOr> v;
+    absl::StatusOr<MyType> statusor = v;
+    EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+  }
+  {
+    CustomType<MyType, kConvToStatusOr | kConvToStatus> v;
+    absl::StatusOr<MyType> statusor = v;
+    EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+  }
+  {
+    CustomType<MyType, kConvToT | kConvToStatusOr | kConvToStatus> v;
+    absl::StatusOr<MyType> statusor = v;
+    EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+  }
+}
+
+TEST(StatusOr, ConstructionFromTypeConvertibleToStatus) {
+  // Construction fails because conversion to `Status` is explicit.
+  {
+    CustomType<MyType, kConvToStatus | kConvExplicit> v;
+    absl::StatusOr<MyType> statusor(v);
+    EXPECT_FALSE(statusor.ok());
+    EXPECT_EQ(statusor.status(), static_cast<absl::Status>(v));
+  }
+  {
+    CustomType<MyType, kConvToT | kConvToStatus | kConvExplicit> v;
+    absl::StatusOr<MyType> statusor(v);
+    EXPECT_FALSE(statusor.ok());
+    EXPECT_EQ(statusor.status(), static_cast<absl::Status>(v));
+  }
+  {
+    CustomType<MyType, kConvToStatus> v;
+    absl::StatusOr<MyType> statusor = v;
+    EXPECT_FALSE(statusor.ok());
+    EXPECT_EQ(statusor.status(), static_cast<absl::Status>(v));
+  }
+  {
+    CustomType<MyType, kConvToT | kConvToStatus> v;
+    absl::StatusOr<MyType> statusor = v;
+    EXPECT_FALSE(statusor.ok());
+    EXPECT_EQ(statusor.status(), static_cast<absl::Status>(v));
+  }
+}
+
+TEST(StatusOr, AssignmentFromT) {
+  // Assign to absl::StatusOr<T> from T when T is convertible to
+  // absl::StatusOr<T>
+  {
+    ConvertibleToAnyStatusOr v;
+    absl::StatusOr<ConvertibleToAnyStatusOr> statusor;
+    statusor = v;
+    EXPECT_TRUE(statusor.ok());
+  }
+  // Assign to absl::StatusOr<T> from T when T is convertible to Status
+  {
+    CustomType<MyType, kConvToStatus> v;
+    absl::StatusOr<CustomType<MyType, kConvToStatus>> statusor;
+    statusor = v;
+    EXPECT_TRUE(statusor.ok());
+  }
+}
+
+TEST(StatusOr, AssignmentFromTypeConvertibleToT) {
+  // Assign to absl::StatusOr<T> from U when U is convertible to T
+  {
+    CustomType<MyType, kConvToT> v;
+    absl::StatusOr<MyType> statusor;
+    statusor = v;
+    EXPECT_TRUE(statusor.ok());
+  }
+}
+
+TEST(StatusOr, AssignmentFromTypeWithConversionOperatortoStatusOrT) {
+  // Assign to absl::StatusOr<T> from U when U has conversion operator to
+  // absl::StatusOr<T>
+  {
+    CustomType<MyType, kConvToStatusOr> v;
+    absl::StatusOr<MyType> statusor;
+    statusor = v;
+    EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+  }
+  {
+    CustomType<MyType, kConvToT | kConvToStatusOr> v;
+    absl::StatusOr<MyType> statusor;
+    statusor = v;
+    EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+  }
+  {
+    CustomType<MyType, kConvToStatusOr | kConvToStatus> v;
+    absl::StatusOr<MyType> statusor;
+    statusor = v;
+    EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+  }
+  {
+    CustomType<MyType, kConvToT | kConvToStatusOr | kConvToStatus> v;
+    absl::StatusOr<MyType> statusor;
+    statusor = v;
+    EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+  }
+}
+
+TEST(StatusOr, AssignmentFromTypeConvertibleToStatus) {
+  // Assign to absl::StatusOr<T> from U when U is convertible to Status
+  {
+    CustomType<MyType, kConvToStatus> v;
+    absl::StatusOr<MyType> statusor;
+    statusor = v;
+    EXPECT_FALSE(statusor.ok());
+    EXPECT_EQ(statusor.status(), static_cast<absl::Status>(v));
+  }
+  {
+    CustomType<MyType, kConvToT | kConvToStatus> v;
+    absl::StatusOr<MyType> statusor;
+    statusor = v;
+    EXPECT_FALSE(statusor.ok());
+    EXPECT_EQ(statusor.status(), static_cast<absl::Status>(v));
+  }
+}
+
+}  // namespace
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
index b950ec7..123b5ef 100644
--- a/absl/strings/BUILD.bazel
+++ b/absl/strings/BUILD.bazel
@@ -54,6 +54,7 @@
         "ascii.h",
         "charconv.h",
         "escaping.h",
+        "internal/string_constant.h",
         "match.h",
         "numbers.h",
         "str_cat.h",
@@ -68,7 +69,6 @@
     deps = [
         ":internal",
         "//absl/base",
-        "//absl/base:bits",
         "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:endian",
@@ -76,6 +76,7 @@
         "//absl/base:throw_delegate",
         "//absl/memory",
         "//absl/meta:type_traits",
+        "//absl/numeric:bits",
         "//absl/numeric:int128",
     ],
 )
@@ -223,6 +224,19 @@
 )
 
 cc_test(
+    name = "string_constant_test",
+    size = "small",
+    srcs = ["internal/string_constant_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/meta:type_traits",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
     name = "string_view_benchmark",
     srcs = ["string_view_benchmark.cc"],
     copts = ABSL_TEST_COPTS,
@@ -253,11 +267,31 @@
 
 cc_library(
     name = "cord_internal",
-    hdrs = ["internal/cord_internal.h"],
+    srcs = [
+        "internal/cord_internal.cc",
+        "internal/cord_rep_ring.cc",
+    ],
+    hdrs = [
+        "internal/cord_internal.h",
+        "internal/cord_rep_flat.h",
+        "internal/cord_rep_ring.h",
+        "internal/cord_rep_ring_reader.h",
+    ],
     copts = ABSL_DEFAULT_COPTS,
-    visibility = ["//visibility:private"],
+    visibility = [
+        "//visibility:private",
+    ],
     deps = [
         ":strings",
+        "//absl/base:base_internal",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/base:endian",
+        "//absl/base:raw_logging_internal",
+        "//absl/base:throw_delegate",
+        "//absl/container:compressed_tuple",
+        "//absl/container:inlined_vector",
+        "//absl/container:layout",
         "//absl/meta:type_traits",
     ],
 )
@@ -277,7 +311,6 @@
         ":str_format",
         ":strings",
         "//absl/base",
-        "//absl/base:base_internal",
         "//absl/base:core_headers",
         "//absl/base:endian",
         "//absl/base:raw_logging_internal",
@@ -285,6 +318,7 @@
         "//absl/container:inlined_vector",
         "//absl/functional:function_ref",
         "//absl/meta:type_traits",
+        "//absl/types:optional",
     ],
 )
 
@@ -309,9 +343,11 @@
     deps = [
         ":cord",
         ":cord_test_helpers",
+        ":str_format",
         ":strings",
         "//absl/base",
         "//absl/base:config",
+        "//absl/base:core_headers",
         "//absl/base:endian",
         "//absl/base:raw_logging_internal",
         "//absl/container:fixed_array",
@@ -320,6 +356,38 @@
 )
 
 cc_test(
+    name = "cord_ring_test",
+    size = "medium",
+    srcs = ["cord_ring_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":cord_internal",
+        ":strings",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/base:raw_logging_internal",
+        "//absl/debugging:leak_check",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "cord_ring_reader_test",
+    size = "medium",
+    srcs = ["cord_ring_reader_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":cord_internal",
+        ":strings",
+        "//absl/base:core_headers",
+        "//absl/debugging:leak_check",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
     name = "substitute_test",
     size = "small",
     srcs = ["substitute_test.cc"],
@@ -366,6 +434,8 @@
         ":strings",
         "//absl/base:core_headers",
         "//absl/base:dynamic_annotations",
+        "//absl/container:flat_hash_map",
+        "//absl/container:node_hash_map",
         "@com_google_googletest//:gtest_main",
     ],
 )
@@ -484,6 +554,7 @@
     copts = ABSL_TEST_COPTS,
     visibility = ["//visibility:private"],
     deps = [
+        ":internal",
         ":pow10_helper",
         ":strings",
         "//absl/base:config",
@@ -634,8 +705,12 @@
         ":strings",
         "//absl/base:config",
         "//absl/base:core_headers",
+        "//absl/functional:function_ref",
         "//absl/meta:type_traits",
+        "//absl/numeric:bits",
         "//absl/numeric:int128",
+        "//absl/numeric:representation",
+        "//absl/types:optional",
         "//absl/types:span",
     ],
 )
@@ -646,6 +721,7 @@
     copts = ABSL_TEST_COPTS,
     visibility = ["//visibility:private"],
     deps = [
+        ":cord",
         ":str_format",
         ":strings",
         "//absl/base:core_headers",
@@ -663,6 +739,7 @@
     deps = [
         ":str_format",
         ":str_format_internal",
+        ":strings",
         "@com_google_googletest//:gtest_main",
     ],
 )
@@ -709,8 +786,9 @@
     visibility = ["//visibility:private"],
     deps = [
         ":str_format_internal",
+        ":strings",
         "//absl/base:raw_logging_internal",
-        "//absl/numeric:int128",
+        "//absl/types:optional",
         "@com_google_googletest//:gtest_main",
     ],
 )
@@ -721,6 +799,7 @@
     copts = ABSL_TEST_COPTS,
     visibility = ["//visibility:private"],
     deps = [
+        ":cord",
         ":str_format_internal",
         "@com_google_googletest//:gtest_main",
     ],
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt
index fbf0f5a..3b7ae63 100644
--- a/absl/strings/CMakeLists.txt
+++ b/absl/strings/CMakeLists.txt
@@ -21,6 +21,7 @@
     "ascii.h"
     "charconv.h"
     "escaping.h"
+    "internal/string_constant.h"
     "match.h"
     "numbers.h"
     "str_cat.h"
@@ -160,6 +161,19 @@
 
 absl_cc_test(
   NAME
+    string_constant_test
+  SRCS
+    "internal/string_constant_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::strings
+    absl::type_traits
+    gmock_main
+)
+
+absl_cc_test(
+  NAME
     string_view_test
   SRCS
     "string_view_test.cc"
@@ -210,6 +224,8 @@
     absl::base
     absl::core_headers
     absl::dynamic_annotations
+    absl::flat_hash_map
+    absl::node_hash_map
     gmock_main
 )
 
@@ -284,6 +300,7 @@
     absl::raw_logging_internal
     absl::random_random
     absl::random_distributions
+    absl::strings_internal
     gmock_main
 )
 
@@ -389,9 +406,11 @@
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
+    absl::bits
     absl::strings
     absl::config
     absl::core_headers
+    absl::numeric_representation
     absl::type_traits
     absl::int128
     absl::span
@@ -406,6 +425,7 @@
     ${ABSL_TEST_COPTS}
   DEPS
     absl::str_format
+    absl::cord
     absl::strings
     absl::core_headers
     gmock_main
@@ -421,6 +441,7 @@
   DEPS
     absl::str_format
     absl::str_format_internal
+    absl::strings
     gmock_main
 )
 
@@ -469,6 +490,7 @@
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
+    absl::strings
     absl::str_format_internal
     absl::raw_logging_internal
     absl::int128
@@ -484,6 +506,7 @@
     ${ABSL_TEST_COPTS}
   DEPS
     absl::str_format_internal
+    absl::cord
     gmock_main
 )
 
@@ -534,20 +557,29 @@
     "cord.h"
   SRCS
     "cord.cc"
+    "internal/cord_internal.cc"
     "internal/cord_internal.h"
+    "internal/cord_rep_ring.h"
+    "internal/cord_rep_ring.cc"
+    "internal/cord_rep_ring_reader.h"
+    "internal/cord_rep_flat.h"
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
-    absl::strings
-    absl::strings_internal
     absl::base
     absl::base_internal
+    absl::compressed_tuple
+    absl::config
     absl::core_headers
     absl::endian
     absl::fixed_array
     absl::function_ref
     absl::inlined_vector
+    absl::optional
     absl::raw_logging_internal
+    absl::strings
+    absl::strings_internal
+    absl::throw_delegate
     absl::type_traits
   PUBLIC
 )
@@ -573,11 +605,45 @@
     ${ABSL_TEST_COPTS}
   DEPS
     absl::cord
+    absl::str_format
     absl::strings
     absl::base
     absl::config
+    absl::core_headers
     absl::endian
     absl::raw_logging_internal
     absl::fixed_array
     gmock_main
 )
+
+absl_cc_test(
+  NAME
+    cord_ring_test
+  SRCS
+    "cord_ring_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::config
+    absl::cord
+    absl::strings
+    absl::base
+    absl::core_headers
+    absl::raw_logging_internal
+    gmock_main
+)
+
+absl_cc_test(
+  NAME
+    cord_ring_reader_test
+  SRCS
+    "cord_ring_reader_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::cord
+    absl::strings
+    absl::base
+    absl::core_headers
+    gmock_main
+)
diff --git a/absl/strings/ascii_test.cc b/absl/strings/ascii_test.cc
index 5ecd23f..83af782 100644
--- a/absl/strings/ascii_test.cc
+++ b/absl/strings/ascii_test.cc
@@ -197,11 +197,15 @@
   const std::string str("GHIJKL");
   const std::string str2("MNOPQR");
   const absl::string_view sp(str2);
+  std::string mutable_str("STUVWX");
 
   EXPECT_EQ("abcdef", absl::AsciiStrToLower(buf));
   EXPECT_EQ("ghijkl", absl::AsciiStrToLower(str));
   EXPECT_EQ("mnopqr", absl::AsciiStrToLower(sp));
 
+  absl::AsciiStrToLower(&mutable_str);
+  EXPECT_EQ("stuvwx", mutable_str);
+
   char mutable_buf[] = "Mutable";
   std::transform(mutable_buf, mutable_buf + strlen(mutable_buf),
                  mutable_buf, absl::ascii_tolower);
diff --git a/absl/strings/charconv.cc b/absl/strings/charconv.cc
index bdba768..b8674c2 100644
--- a/absl/strings/charconv.cc
+++ b/absl/strings/charconv.cc
@@ -20,7 +20,7 @@
 #include <cstring>
 
 #include "absl/base/casts.h"
-#include "absl/base/internal/bits.h"
+#include "absl/numeric/bits.h"
 #include "absl/numeric/int128.h"
 #include "absl/strings/internal/charconv_bigint.h"
 #include "absl/strings/internal/charconv_parse.h"
@@ -242,11 +242,11 @@
 
 // Returns the bit width of the given uint128.  (Equivalently, returns 128
 // minus the number of leading zero bits.)
-int BitWidth(uint128 value) {
+unsigned BitWidth(uint128 value) {
   if (Uint128High64(value) == 0) {
-    return 64 - base_internal::CountLeadingZeros64(Uint128Low64(value));
+    return static_cast<unsigned>(bit_width(Uint128Low64(value)));
   }
-  return 128 - base_internal::CountLeadingZeros64(Uint128High64(value));
+  return 128 - countl_zero(Uint128High64(value));
 }
 
 // Calculates how far to the right a mantissa needs to be shifted to create a
@@ -519,7 +519,7 @@
     const strings_internal::ParsedFloat& parsed_hex) {
   uint64_t mantissa = parsed_hex.mantissa;
   int exponent = parsed_hex.exponent;
-  int mantissa_width = 64 - base_internal::CountLeadingZeros64(mantissa);
+  auto mantissa_width = static_cast<unsigned>(bit_width(mantissa));
   const int shift = NormalizedShiftSize<FloatType>(mantissa_width, exponent);
   bool result_exact;
   exponent += shift;
@@ -619,10 +619,10 @@
       // Either we failed to parse a hex float after the "0x", or we read
       // "0xinf" or "0xnan" which we don't want to match.
       //
-      // However, a std::string that begins with "0x" also begins with "0", which
+      // However, a string that begins with "0x" also begins with "0", which
       // is normally a valid match for the number zero.  So we want these
       // strings to match zero unless fmt_flags is `scientific`.  (This flag
-      // means an exponent is required, which the std::string "0" does not have.)
+      // means an exponent is required, which the string "0" does not have.)
       if (fmt_flags == chars_format::scientific) {
         result.ec = std::errc::invalid_argument;
       } else {
diff --git a/absl/strings/charconv_benchmark.cc b/absl/strings/charconv_benchmark.cc
index 644b2ab..e8c7371 100644
--- a/absl/strings/charconv_benchmark.cc
+++ b/absl/strings/charconv_benchmark.cc
@@ -132,7 +132,7 @@
 std::string MakeHardCase(int length) {
   // The number 1.1521...e-297 is exactly halfway between 12345 * 2**-1000 and
   // the next larger representable number.  The digits of this number are in
-  // the std::string below.
+  // the string below.
   const std::string digits =
       "1."
       "152113937042223790993097181572444900347587985074226836242307364987727724"
diff --git a/absl/strings/charconv_test.cc b/absl/strings/charconv_test.cc
index 9090e9c..b83de5a 100644
--- a/absl/strings/charconv_test.cc
+++ b/absl/strings/charconv_test.cc
@@ -653,7 +653,9 @@
                      negative_from_chars_float);
     EXPECT_TRUE(std::signbit(negative_from_chars_float));
     EXPECT_FALSE(Identical(negative_from_chars_float, from_chars_float));
-    from_chars_float = std::copysign(from_chars_float, -1.0);
+    // Use the (float, float) overload of std::copysign to prevent narrowing;
+    // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98251.
+    from_chars_float = std::copysign(from_chars_float, -1.0f);
     EXPECT_TRUE(Identical(negative_from_chars_float, from_chars_float));
   }
 }
diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc
index d9503ae..9353375 100644
--- a/absl/strings/cord.cc
+++ b/absl/strings/cord.cc
@@ -15,10 +15,12 @@
 #include "absl/strings/cord.h"
 
 #include <algorithm>
+#include <atomic>
 #include <cstddef>
 #include <cstdio>
 #include <cstdlib>
 #include <iomanip>
+#include <iostream>
 #include <limits>
 #include <ostream>
 #include <sstream>
@@ -28,11 +30,14 @@
 
 #include "absl/base/casts.h"
 #include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
 #include "absl/base/port.h"
 #include "absl/container/fixed_array.h"
 #include "absl/container/inlined_vector.h"
 #include "absl/strings/escaping.h"
 #include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_flat.h"
+#include "absl/strings/internal/cord_rep_ring.h"
 #include "absl/strings/internal/resize_uninitialized.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/str_format.h"
@@ -45,142 +50,20 @@
 using ::absl::cord_internal::CordRep;
 using ::absl::cord_internal::CordRepConcat;
 using ::absl::cord_internal::CordRepExternal;
+using ::absl::cord_internal::CordRepFlat;
+using ::absl::cord_internal::CordRepRing;
 using ::absl::cord_internal::CordRepSubstring;
+using ::absl::cord_internal::kMinFlatLength;
+using ::absl::cord_internal::kMaxFlatLength;
 
-// Various representations that we allow
-enum CordRepKind {
-  CONCAT        = 0,
-  EXTERNAL      = 1,
-  SUBSTRING     = 2,
+using ::absl::cord_internal::CONCAT;
+using ::absl::cord_internal::EXTERNAL;
+using ::absl::cord_internal::FLAT;
+using ::absl::cord_internal::RING;
+using ::absl::cord_internal::SUBSTRING;
 
-  // We have different tags for different sized flat arrays,
-  // starting with FLAT
-  FLAT          = 3,
-};
-
-namespace {
-
-// Type used with std::allocator for allocating and deallocating
-// `CordRepExternal`. std::allocator is used because it opaquely handles the
-// different new / delete overloads available on a given platform.
-struct alignas(absl::cord_internal::ExternalRepAlignment()) ExternalAllocType {
-  unsigned char value[absl::cord_internal::ExternalRepAlignment()];
-};
-
-// Returns the number of objects to pass in to std::allocator<ExternalAllocType>
-// allocate() and deallocate() to create enough room for `CordRepExternal` with
-// `releaser_size` bytes on the end.
-constexpr size_t GetExternalAllocNumObjects(size_t releaser_size) {
-  // Be sure to round up since `releaser_size` could be smaller than
-  // `sizeof(ExternalAllocType)`.
-  return (sizeof(CordRepExternal) + releaser_size + sizeof(ExternalAllocType) -
-          1) /
-         sizeof(ExternalAllocType);
-}
-
-// Allocates enough memory for `CordRepExternal` and a releaser with size
-// `releaser_size` bytes.
-void* AllocateExternal(size_t releaser_size) {
-  return std::allocator<ExternalAllocType>().allocate(
-      GetExternalAllocNumObjects(releaser_size));
-}
-
-// Deallocates the memory for a `CordRepExternal` assuming it was allocated with
-// a releaser of given size and alignment.
-void DeallocateExternal(CordRepExternal* p, size_t releaser_size) {
-  std::allocator<ExternalAllocType>().deallocate(
-      reinterpret_cast<ExternalAllocType*>(p),
-      GetExternalAllocNumObjects(releaser_size));
-}
-
-// Returns a pointer to the type erased releaser for the given CordRepExternal.
-void* GetExternalReleaser(CordRepExternal* rep) {
-  return rep + 1;
-}
-
-}  // namespace
-
-namespace cord_internal {
-
-inline CordRepConcat* CordRep::concat() {
-  assert(tag == CONCAT);
-  return static_cast<CordRepConcat*>(this);
-}
-
-inline const CordRepConcat* CordRep::concat() const {
-  assert(tag == CONCAT);
-  return static_cast<const CordRepConcat*>(this);
-}
-
-inline CordRepSubstring* CordRep::substring() {
-  assert(tag == SUBSTRING);
-  return static_cast<CordRepSubstring*>(this);
-}
-
-inline const CordRepSubstring* CordRep::substring() const {
-  assert(tag == SUBSTRING);
-  return static_cast<const CordRepSubstring*>(this);
-}
-
-inline CordRepExternal* CordRep::external() {
-  assert(tag == EXTERNAL);
-  return static_cast<CordRepExternal*>(this);
-}
-
-inline const CordRepExternal* CordRep::external() const {
-  assert(tag == EXTERNAL);
-  return static_cast<const CordRepExternal*>(this);
-}
-
-}  // namespace cord_internal
-
-static const size_t kFlatOverhead = offsetof(CordRep, data);
-
-static_assert(kFlatOverhead == 13, "Unittests assume kFlatOverhead == 13");
-
-// Largest and smallest flat node lengths we are willing to allocate
-// Flat allocation size is stored in tag, which currently can encode sizes up
-// to 4K, encoded as multiple of either 8 or 32 bytes.
-// If we allow for larger sizes, we need to change this to 8/64, 16/128, etc.
-static constexpr size_t kMaxFlatSize = 4096;
-static constexpr size_t kMaxFlatLength = kMaxFlatSize - kFlatOverhead;
-static constexpr size_t kMinFlatLength = 32 - kFlatOverhead;
-
-// Prefer copying blocks of at most this size, otherwise reference count.
-static const size_t kMaxBytesToCopy = 511;
-
-// Helper functions for rounded div, and rounding to exact sizes.
-static size_t DivUp(size_t n, size_t m) { return (n + m - 1) / m; }
-static size_t RoundUp(size_t n, size_t m) { return DivUp(n, m) * m; }
-
-// Returns the size to the nearest equal or larger value that can be
-// expressed exactly as a tag value.
-static size_t RoundUpForTag(size_t size) {
-  return RoundUp(size, (size <= 1024) ? 8 : 32);
-}
-
-// Converts the allocated size to a tag, rounding down if the size
-// does not exactly match a 'tag expressible' size value. The result is
-// undefined if the size exceeds the maximum size that can be encoded in
-// a tag, i.e., if size is larger than TagToAllocatedSize(<max tag>).
-static uint8_t AllocatedSizeToTag(size_t size) {
-  const size_t tag = (size <= 1024) ? size / 8 : 128 + size / 32 - 1024 / 32;
-  assert(tag <= std::numeric_limits<uint8_t>::max());
-  return tag;
-}
-
-// Converts the provided tag to the corresponding allocated size
-static constexpr size_t TagToAllocatedSize(uint8_t tag) {
-  return (tag <= 128) ? (tag * 8) : (1024 + (tag - 128) * 32);
-}
-
-// Converts the provided tag to the corresponding available data length
-static constexpr size_t TagToLength(uint8_t tag) {
-  return TagToAllocatedSize(tag) - kFlatOverhead;
-}
-
-// Enforce that kMaxFlatSize maps to a well-known exact tag value.
-static_assert(TagToAllocatedSize(224) == kMaxFlatSize, "Bad tag logic");
+using ::absl::cord_internal::kInlinedVectorSize;
+using ::absl::cord_internal::kMaxBytesToCopy;
 
 constexpr uint64_t Fibonacci(unsigned char n, uint64_t a = 0, uint64_t b = 1) {
   return n == 0 ? a : Fibonacci(n - 1, b, a + b);
@@ -195,67 +78,27 @@
 // The root node depth is allowed to become twice as large to reduce rebalancing
 // for larger strings (see IsRootBalanced).
 static constexpr uint64_t min_length[] = {
-    Fibonacci(2),
-    Fibonacci(3),
-    Fibonacci(4),
-    Fibonacci(5),
-    Fibonacci(6),
-    Fibonacci(7),
-    Fibonacci(8),
-    Fibonacci(9),
-    Fibonacci(10),
-    Fibonacci(11),
-    Fibonacci(12),
-    Fibonacci(13),
-    Fibonacci(14),
-    Fibonacci(15),
-    Fibonacci(16),
-    Fibonacci(17),
-    Fibonacci(18),
-    Fibonacci(19),
-    Fibonacci(20),
-    Fibonacci(21),
-    Fibonacci(22),
-    Fibonacci(23),
-    Fibonacci(24),
-    Fibonacci(25),
-    Fibonacci(26),
-    Fibonacci(27),
-    Fibonacci(28),
-    Fibonacci(29),
-    Fibonacci(30),
-    Fibonacci(31),
-    Fibonacci(32),
-    Fibonacci(33),
-    Fibonacci(34),
-    Fibonacci(35),
-    Fibonacci(36),
-    Fibonacci(37),
-    Fibonacci(38),
-    Fibonacci(39),
-    Fibonacci(40),
-    Fibonacci(41),
-    Fibonacci(42),
-    Fibonacci(43),
-    Fibonacci(44),
-    Fibonacci(45),
-    Fibonacci(46),
-    Fibonacci(47),
+    Fibonacci(2),          Fibonacci(3),  Fibonacci(4),  Fibonacci(5),
+    Fibonacci(6),          Fibonacci(7),  Fibonacci(8),  Fibonacci(9),
+    Fibonacci(10),         Fibonacci(11), Fibonacci(12), Fibonacci(13),
+    Fibonacci(14),         Fibonacci(15), Fibonacci(16), Fibonacci(17),
+    Fibonacci(18),         Fibonacci(19), Fibonacci(20), Fibonacci(21),
+    Fibonacci(22),         Fibonacci(23), Fibonacci(24), Fibonacci(25),
+    Fibonacci(26),         Fibonacci(27), Fibonacci(28), Fibonacci(29),
+    Fibonacci(30),         Fibonacci(31), Fibonacci(32), Fibonacci(33),
+    Fibonacci(34),         Fibonacci(35), Fibonacci(36), Fibonacci(37),
+    Fibonacci(38),         Fibonacci(39), Fibonacci(40), Fibonacci(41),
+    Fibonacci(42),         Fibonacci(43), Fibonacci(44), Fibonacci(45),
+    Fibonacci(46),         Fibonacci(47),
     0xffffffffffffffffull,  // Avoid overflow
 };
 
 static const int kMinLengthSize = ABSL_ARRAYSIZE(min_length);
 
-// The inlined size to use with absl::InlinedVector.
-//
-// Note: The InlinedVectors in this file (and in cord.h) do not need to use
-// the same value for their inlined size. The fact that they do is historical.
-// It may be desirable for each to use a different inlined size optimized for
-// that InlinedVector's usage.
-//
-// TODO(jgm): Benchmark to see if there's a more optimal value than 47 for
-// the inlined vector size (47 exists for backward compatibility).
-static const int kInlinedVectorSize = 47;
+static inline bool cord_ring_enabled() {
+  return cord_internal::cord_ring_buffer_enabled.load(
+      std::memory_order_relaxed);
+}
 
 static inline bool IsRootBalanced(CordRep* node) {
   if (node->tag != CONCAT) {
@@ -272,7 +115,8 @@
 }
 
 static CordRep* Rebalance(CordRep* node);
-static void DumpNode(CordRep* rep, bool include_data, std::ostream* os);
+static void DumpNode(CordRep* rep, bool include_data, std::ostream* os,
+                     int indent = 0);
 static bool VerifyNode(CordRep* root, CordRep* start_node,
                        bool full_validation);
 
@@ -292,100 +136,6 @@
   return node;
 }
 
-// --------------------------------------------------------------------
-// Memory management
-
-inline CordRep* Ref(CordRep* rep) {
-  if (rep != nullptr) {
-    rep->refcount.Increment();
-  }
-  return rep;
-}
-
-// This internal routine is called from the cold path of Unref below. Keeping it
-// in a separate routine allows good inlining of Unref into many profitable call
-// sites. However, the call to this function can be highly disruptive to the
-// register pressure in those callers. To minimize the cost to callers, we use
-// a special LLVM calling convention that preserves most registers. This allows
-// the call to this routine in cold paths to not disrupt the caller's register
-// pressure. This calling convention is not available on all platforms; we
-// intentionally allow LLVM to ignore the attribute rather than attempting to
-// hardcode the list of supported platforms.
-#if defined(__clang__) && !defined(__i386__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wattributes"
-__attribute__((preserve_most))
-#pragma clang diagnostic pop
-#endif
-static void UnrefInternal(CordRep* rep) {
-  assert(rep != nullptr);
-
-  absl::InlinedVector<CordRep*, kInlinedVectorSize> pending;
-  while (true) {
-    if (rep->tag == CONCAT) {
-      CordRepConcat* rep_concat = rep->concat();
-      CordRep* right = rep_concat->right;
-      if (!right->refcount.Decrement()) {
-        pending.push_back(right);
-      }
-      CordRep* left = rep_concat->left;
-      delete rep_concat;
-      rep = nullptr;
-      if (!left->refcount.Decrement()) {
-        rep = left;
-        continue;
-      }
-    } else if (rep->tag == EXTERNAL) {
-      CordRepExternal* rep_external = rep->external();
-      absl::string_view data(rep_external->base, rep->length);
-      void* releaser = GetExternalReleaser(rep_external);
-      size_t releaser_size = rep_external->releaser_invoker(releaser, data);
-      rep_external->~CordRepExternal();
-      DeallocateExternal(rep_external, releaser_size);
-      rep = nullptr;
-    } else if (rep->tag == SUBSTRING) {
-      CordRepSubstring* rep_substring = rep->substring();
-      CordRep* child = rep_substring->child;
-      delete rep_substring;
-      rep = nullptr;
-      if (!child->refcount.Decrement()) {
-        rep = child;
-        continue;
-      }
-    } else {
-      // Flat CordReps are allocated and constructed with raw ::operator new
-      // and placement new, and must be destructed and deallocated
-      // accordingly.
-#if defined(__cpp_sized_deallocation)
-      size_t size = TagToAllocatedSize(rep->tag);
-      rep->~CordRep();
-      ::operator delete(rep, size);
-#else
-      rep->~CordRep();
-      ::operator delete(rep);
-#endif
-      rep = nullptr;
-    }
-
-    if (!pending.empty()) {
-      rep = pending.back();
-      pending.pop_back();
-    } else {
-      break;
-    }
-  }
-}
-
-inline void Unref(CordRep* rep) {
-  // Fast-path for two common, hot cases: a null rep and a shared root.
-  if (ABSL_PREDICT_TRUE(rep == nullptr ||
-                        rep->refcount.DecrementExpectHighRefcount())) {
-    return;
-  }
-
-  UnrefInternal(rep);
-}
-
 // Return the depth of a node
 static int Depth(const CordRep* rep) {
   if (rep->tag == CONCAT) {
@@ -409,12 +159,14 @@
 // The returned node has a refcount of 1.
 static CordRep* RawConcat(CordRep* left, CordRep* right) {
   // Avoid making degenerate concat nodes (one child is empty)
-  if (left == nullptr || left->length == 0) {
-    Unref(left);
+  if (left == nullptr) return right;
+  if (right == nullptr) return left;
+  if (left->length == 0) {
+    CordRep::Unref(left);
     return right;
   }
-  if (right == nullptr || right->length == 0) {
-    Unref(right);
+  if (right->length == 0) {
+    CordRep::Unref(right);
     return left;
   }
 
@@ -453,20 +205,27 @@
   return reps[0];
 }
 
-// Create a new flat node.
-static CordRep* NewFlat(size_t length_hint) {
-  if (length_hint <= kMinFlatLength) {
-    length_hint = kMinFlatLength;
-  } else if (length_hint > kMaxFlatLength) {
-    length_hint = kMaxFlatLength;
-  }
+static CordRepFlat* CreateFlat(const char* data, size_t length,
+                            size_t alloc_hint) {
+  CordRepFlat* flat = CordRepFlat::New(length + alloc_hint);
+  flat->length = length;
+  memcpy(flat->Data(), data, length);
+  return flat;
+}
 
-  // Round size up so it matches a size we can exactly express in a tag.
-  const size_t size = RoundUpForTag(length_hint + kFlatOverhead);
-  void* const raw_rep = ::operator new(size);
-  CordRep* rep = new (raw_rep) CordRep();
-  rep->tag = AllocatedSizeToTag(size);
-  return VerifyTree(rep);
+// Creates a new flat or ringbuffer out of the specified array.
+// The returned node has a refcount of 1.
+static CordRep* RingNewTree(const char* data, size_t length,
+                            size_t alloc_hint) {
+  if (length <= kMaxFlatLength) {
+    return CreateFlat(data, length, alloc_hint);
+  }
+  CordRepFlat* flat = CreateFlat(data, kMaxFlatLength, 0);
+  data += kMaxFlatLength;
+  length -= kMaxFlatLength;
+  size_t extra = (length - 1) / kMaxFlatLength + 1;
+  auto* root = CordRepRing::Create(flat, extra);
+  return CordRepRing::Append(root, {data, length}, alloc_hint);
 }
 
 // Create a new tree out of the specified array.
@@ -475,13 +234,16 @@
                         size_t length,
                         size_t alloc_hint) {
   if (length == 0) return nullptr;
+  if (cord_ring_enabled()) {
+    return RingNewTree(data, length, alloc_hint);
+  }
   absl::FixedArray<CordRep*> reps((length - 1) / kMaxFlatLength + 1);
   size_t n = 0;
   do {
     const size_t len = std::min(length, kMaxFlatLength);
-    CordRep* rep = NewFlat(len + alloc_hint);
+    CordRepFlat* rep = CordRepFlat::New(len + alloc_hint);
     rep->length = len;
-    memcpy(rep->data, data, len);
+    memcpy(rep->Data(), data, len);
     reps[n++] = VerifyTree(rep);
     data += len;
     length -= len;
@@ -491,18 +253,12 @@
 
 namespace cord_internal {
 
-ExternalRepReleaserPair NewExternalWithUninitializedReleaser(
-    absl::string_view data, ExternalReleaserInvoker invoker,
-    size_t releaser_size) {
+void InitializeCordRepExternal(absl::string_view data, CordRepExternal* rep) {
   assert(!data.empty());
-
-  void* raw_rep = AllocateExternal(releaser_size);
-  auto* rep = new (raw_rep) CordRepExternal();
   rep->length = data.size();
   rep->tag = EXTERNAL;
   rep->base = data.data();
-  rep->releaser_invoker = invoker;
-  return {VerifyTree(rep), GetExternalReleaser(rep)};
+  VerifyTree(rep);
 }
 
 }  // namespace cord_internal
@@ -510,7 +266,7 @@
 static CordRep* NewSubstring(CordRep* child, size_t offset, size_t length) {
   // Never create empty substring nodes
   if (length == 0) {
-    Unref(child);
+    CordRep::Unref(child);
     return nullptr;
   } else {
     CordRepSubstring* rep = new CordRepSubstring();
@@ -526,69 +282,75 @@
 // --------------------------------------------------------------------
 // Cord::InlineRep functions
 
-// This will trigger LNK2005 in MSVC.
-#ifndef COMPILER_MSVC
-const unsigned char Cord::InlineRep::kMaxInline;
-#endif  // COMPILER_MSVC
+constexpr unsigned char Cord::InlineRep::kMaxInline;
 
 inline void Cord::InlineRep::set_data(const char* data, size_t n,
                                       bool nullify_tail) {
   static_assert(kMaxInline == 15, "set_data is hard-coded for a length of 15");
 
-  cord_internal::SmallMemmove(data_, data, n, nullify_tail);
-  data_[kMaxInline] = static_cast<char>(n);
+  cord_internal::SmallMemmove(data_.as_chars(), data, n, nullify_tail);
+  set_inline_size(n);
 }
 
 inline char* Cord::InlineRep::set_data(size_t n) {
   assert(n <= kMaxInline);
-  memset(data_, 0, sizeof(data_));
-  data_[kMaxInline] = static_cast<char>(n);
-  return data_;
+  ResetToEmpty();
+  set_inline_size(n);
+  return data_.as_chars();
 }
 
 inline CordRep* Cord::InlineRep::force_tree(size_t extra_hint) {
-  size_t len = data_[kMaxInline];
-  CordRep* result;
-  if (len > kMaxInline) {
-    memcpy(&result, data_, sizeof(result));
-  } else {
-    result = NewFlat(len + extra_hint);
-    result->length = len;
-    memcpy(result->data, data_, len);
-    set_tree(result);
+  if (data_.is_tree()) {
+    return data_.as_tree();
   }
+
+  size_t len = inline_size();
+  CordRepFlat* result = CordRepFlat::New(len + extra_hint);
+  result->length = len;
+  static_assert(kMinFlatLength >= sizeof(data_), "");
+  memcpy(result->Data(), data_.as_chars(), sizeof(data_));
+  set_tree(result);
   return result;
 }
 
 inline void Cord::InlineRep::reduce_size(size_t n) {
-  size_t tag = data_[kMaxInline];
+  size_t tag = inline_size();
   assert(tag <= kMaxInline);
   assert(tag >= n);
   tag -= n;
-  memset(data_ + tag, 0, n);
-  data_[kMaxInline] = static_cast<char>(tag);
+  memset(data_.as_chars() + tag, 0, n);
+  set_inline_size(static_cast<char>(tag));
 }
 
 inline void Cord::InlineRep::remove_prefix(size_t n) {
-  cord_internal::SmallMemmove(data_, data_ + n, data_[kMaxInline] - n);
+  cord_internal::SmallMemmove(data_.as_chars(), data_.as_chars() + n,
+                              inline_size() - n);
   reduce_size(n);
 }
 
+// Returns `rep` converted into a CordRepRing.
+// Directly returns `rep` if `rep` is already a CordRepRing.
+static CordRepRing* ForceRing(CordRep* rep, size_t extra) {
+  return (rep->tag == RING) ? rep->ring() : CordRepRing::Create(rep, extra);
+}
+
 void Cord::InlineRep::AppendTree(CordRep* tree) {
   if (tree == nullptr) return;
-  size_t len = data_[kMaxInline];
-  if (len == 0) {
+  if (data_.is_empty()) {
     set_tree(tree);
+  } else if (cord_ring_enabled()) {
+    set_tree(CordRepRing::Append(ForceRing(force_tree(0), 1), tree));
   } else {
     set_tree(Concat(force_tree(0), tree));
   }
 }
 
 void Cord::InlineRep::PrependTree(CordRep* tree) {
-  if (tree == nullptr) return;
-  size_t len = data_[kMaxInline];
-  if (len == 0) {
+  assert(tree != nullptr);
+  if (data_.is_empty()) {
     set_tree(tree);
+  } else if (cord_ring_enabled()) {
+    set_tree(CordRepRing::Prepend(ForceRing(force_tree(0), 1), tree));
   } else {
     set_tree(Concat(tree, force_tree(0)));
   }
@@ -600,6 +362,15 @@
 // written to region and the actual size increase will be written to size.
 static inline bool PrepareAppendRegion(CordRep* root, char** region,
                                        size_t* size, size_t max_length) {
+  if (root->tag == RING && root->refcount.IsOne()) {
+    Span<char> span = root->ring()->GetAppendBuffer(max_length);
+    if (!span.empty()) {
+      *region = span.data();
+      *size = span.size();
+      return true;
+    }
+  }
+
   // Search down the right-hand path for a non-full FLAT node.
   CordRep* dst = root;
   while (dst->tag == CONCAT && dst->refcount.IsOne()) {
@@ -613,7 +384,7 @@
   }
 
   const size_t in_use = dst->length;
-  const size_t capacity = TagToLength(dst->tag);
+  const size_t capacity = dst->flat()->Capacity();
   if (in_use == capacity) {
     *region = nullptr;
     *size = 0;
@@ -628,7 +399,7 @@
   }
   dst->length += size_increase;
 
-  *region = dst->data + in_use;
+  *region = dst->flat()->Data() + in_use;
   *size = size_increase;
   return true;
 }
@@ -642,12 +413,14 @@
   }
 
   // Try to fit in the inline buffer if possible.
-  size_t inline_length = data_[kMaxInline];
-  if (inline_length < kMaxInline && max_length <= kMaxInline - inline_length) {
-    *region = data_ + inline_length;
-    *size = max_length;
-    data_[kMaxInline] = static_cast<char>(inline_length + max_length);
-    return;
+  if (!is_tree()) {
+    size_t inline_length = inline_size();
+    if (max_length <= kMaxInline - inline_length) {
+      *region = data_.as_chars() + inline_length;
+      *size = max_length;
+      set_inline_size(inline_length + max_length);
+      return;
+    }
   }
 
   CordRep* root = force_tree(max_length);
@@ -657,12 +430,16 @@
   }
 
   // Allocate new node.
-  CordRep* new_node =
-      NewFlat(std::max(static_cast<size_t>(root->length), max_length));
-  new_node->length =
-      std::min(static_cast<size_t>(TagToLength(new_node->tag)), max_length);
-  *region = new_node->data;
+  CordRepFlat* new_node =
+      CordRepFlat::New(std::max(static_cast<size_t>(root->length), max_length));
+  new_node->length = std::min(new_node->Capacity(), max_length);
+  *region = new_node->Data();
   *size = new_node->length;
+
+  if (cord_ring_enabled()) {
+    replace_tree(CordRepRing::Append(ForceRing(root, 1), new_node));
+    return;
+  }
   replace_tree(Concat(root, new_node));
 }
 
@@ -670,12 +447,14 @@
   const size_t max_length = std::numeric_limits<size_t>::max();
 
   // Try to fit in the inline buffer if possible.
-  size_t inline_length = data_[kMaxInline];
-  if (inline_length < kMaxInline) {
-    *region = data_ + inline_length;
-    *size = kMaxInline - inline_length;
-    data_[kMaxInline] = kMaxInline;
-    return;
+  if (!data_.is_tree()) {
+    size_t inline_length = inline_size();
+    if (inline_length < kMaxInline) {
+      *region = data_.as_chars() + inline_length;
+      *size = kMaxInline - inline_length;
+      set_inline_size(kMaxInline);
+      return;
+    }
   }
 
   CordRep* root = force_tree(max_length);
@@ -685,10 +464,15 @@
   }
 
   // Allocate new node.
-  CordRep* new_node = NewFlat(root->length);
-  new_node->length = TagToLength(new_node->tag);
-  *region = new_node->data;
+  CordRepFlat* new_node = CordRepFlat::New(root->length);
+  new_node->length = new_node->Capacity();
+  *region = new_node->Data();
   *size = new_node->length;
+
+  if (cord_ring_enabled()) {
+    replace_tree(CordRepRing::Append(ForceRing(root, 1), new_node));
+    return;
+  }
   replace_tree(Concat(root, new_node));
 }
 
@@ -696,7 +480,7 @@
 // will return true.
 static bool RepMemoryUsageLeaf(const CordRep* rep, size_t* total_mem_usage) {
   if (rep->tag >= FLAT) {
-    *total_mem_usage += TagToAllocatedSize(rep->tag);
+    *total_mem_usage += rep->flat()->AllocatedSize();
     return true;
   }
   if (rep->tag == EXTERNAL) {
@@ -709,26 +493,24 @@
 void Cord::InlineRep::AssignSlow(const Cord::InlineRep& src) {
   ClearSlow();
 
-  memcpy(data_, src.data_, sizeof(data_));
+  data_ = src.data_;
   if (is_tree()) {
-    Ref(tree());
+    data_.set_profiled(false);
+    CordRep::Ref(tree());
+    clear_cordz_info();
   }
 }
 
 void Cord::InlineRep::ClearSlow() {
   if (is_tree()) {
-    Unref(tree());
+    CordRep::Unref(tree());
   }
-  memset(data_, 0, sizeof(data_));
+  ResetToEmpty();
 }
 
 // --------------------------------------------------------------------
 // Constructors and destructors
 
-Cord::Cord(const Cord& src) : contents_(src.contents_) {
-  Ref(contents_.tree());  // Does nothing if contents_ has embedded data
-}
-
 Cord::Cord(absl::string_view src) {
   const size_t n = src.size();
   if (n <= InlineRep::kMaxInline) {
@@ -738,17 +520,52 @@
   }
 }
 
+template <typename T, Cord::EnableIfString<T>>
+Cord::Cord(T&& src) {
+  if (
+      // String is short: copy data to avoid external block overhead.
+      src.size() <= kMaxBytesToCopy ||
+      // String is wasteful: copy data to avoid pinning too much unused memory.
+      src.size() < src.capacity() / 2
+  ) {
+    if (src.size() <= InlineRep::kMaxInline) {
+      contents_.set_data(src.data(), src.size(), false);
+    } else {
+      contents_.set_tree(NewTree(src.data(), src.size(), 0));
+    }
+  } else {
+    struct StringReleaser {
+      void operator()(absl::string_view /* data */) {}
+      std::string data;
+    };
+    const absl::string_view original_data = src;
+    auto* rep = static_cast<
+        ::absl::cord_internal::CordRepExternalImpl<StringReleaser>*>(
+        absl::cord_internal::NewExternalRep(
+            original_data, StringReleaser{std::forward<T>(src)}));
+    // Moving src may have invalidated its data pointer, so adjust it.
+    rep->base = rep->template get<0>().data.data();
+    contents_.set_tree(rep);
+  }
+}
+
+template Cord::Cord(std::string&& src);
+
 // The destruction code is separate so that the compiler can determine
 // that it does not need to call the destructor on a moved-from Cord.
 void Cord::DestroyCordSlow() {
-  Unref(VerifyTree(contents_.tree()));
+  if (CordRep* tree = contents_.tree()) {
+    CordRep::Unref(VerifyTree(tree));
+  }
 }
 
 // --------------------------------------------------------------------
 // Mutators
 
 void Cord::Clear() {
-  Unref(contents_.clear());
+  if (CordRep* tree = contents_.clear()) {
+    CordRep::Unref(tree);
+  }
 }
 
 Cord& Cord::operator=(absl::string_view src) {
@@ -759,44 +576,58 @@
   if (length <= InlineRep::kMaxInline) {
     // Embed into this->contents_
     contents_.set_data(data, length, true);
-    Unref(tree);
+    if (tree) CordRep::Unref(tree);
     return *this;
   }
   if (tree != nullptr && tree->tag >= FLAT &&
-      TagToLength(tree->tag) >= length && tree->refcount.IsOne()) {
+      tree->flat()->Capacity() >= length &&
+      tree->refcount.IsOne()) {
     // Copy in place if the existing FLAT node is reusable.
-    memmove(tree->data, data, length);
+    memmove(tree->flat()->Data(), data, length);
     tree->length = length;
     VerifyTree(tree);
     return *this;
   }
   contents_.set_tree(NewTree(data, length, 0));
-  Unref(tree);
+  if (tree) CordRep::Unref(tree);
   return *this;
 }
 
+template <typename T, Cord::EnableIfString<T>>
+Cord& Cord::operator=(T&& src) {
+  if (src.size() <= kMaxBytesToCopy) {
+    *this = absl::string_view(src);
+  } else {
+    *this = Cord(std::forward<T>(src));
+  }
+  return *this;
+}
+
+template Cord& Cord::operator=(std::string&& src);
+
 // TODO(sanjay): Move to Cord::InlineRep section of file.  For now,
 // we keep it here to make diffs easier.
 void Cord::InlineRep::AppendArray(const char* src_data, size_t src_size) {
   if (src_size == 0) return;  // memcpy(_, nullptr, 0) is undefined.
-  // Try to fit in the inline buffer if possible.
-  size_t inline_length = data_[kMaxInline];
-  if (inline_length < kMaxInline && src_size <= kMaxInline - inline_length) {
-    // Append new data to embedded array
-    data_[kMaxInline] = static_cast<char>(inline_length + src_size);
-    memcpy(data_ + inline_length, src_data, src_size);
-    return;
-  }
-
-  CordRep* root = tree();
 
   size_t appended = 0;
-  if (root) {
+  CordRep* root = nullptr;
+  if (is_tree()) {
+    root = data_.as_tree();
     char* region;
     if (PrepareAppendRegion(root, &region, &appended, src_size)) {
       memcpy(region, src_data, appended);
     }
   } else {
+    // Try to fit in the inline buffer if possible.
+    size_t inline_length = inline_size();
+    if (src_size <= kMaxInline - inline_length) {
+      // Append new data to embedded array
+      memcpy(data_.as_chars() + inline_length, src_data, src_size);
+      set_inline_size(inline_length + src_size);
+      return;
+    }
+
     // It is possible that src_data == data_, but when we transition from an
     // InlineRep to a tree we need to assign data_ = root via set_tree. To
     // avoid corrupting the source data before we copy it, delay calling
@@ -805,10 +636,11 @@
     // either double the inlined size, or the added size + 10%.
     const size_t size1 = inline_length * 2 + src_size;
     const size_t size2 = inline_length + src_size / 10;
-    root = NewFlat(std::max<size_t>(size1, size2));
-    appended = std::min(src_size, TagToLength(root->tag) - inline_length);
-    memcpy(root->data, data_, inline_length);
-    memcpy(root->data + inline_length, src_data, appended);
+    root = CordRepFlat::New(std::max<size_t>(size1, size2));
+    appended = std::min(
+        src_size, root->flat()->Capacity() - inline_length);
+    memcpy(root->flat()->Data(), data_.as_chars(), inline_length);
+    memcpy(root->flat()->Data() + inline_length, src_data, appended);
     root->length = inline_length + appended;
     set_tree(root);
   }
@@ -819,6 +651,13 @@
     return;
   }
 
+  if (cord_ring_enabled()) {
+    absl::string_view data(src_data, src_size);
+    root = ForceRing(root, (data.size() - 1) / kMaxFlatLength + 1);
+    replace_tree(CordRepRing::Append(root->ring(), data));
+    return;
+  }
+
   // Use new block(s) for any remaining bytes that were not handled above.
   // Alloc extra memory only if the right child of the root of the new tree is
   // going to be a FLAT node, which will permit further inplace appends.
@@ -835,7 +674,7 @@
 }
 
 inline CordRep* Cord::TakeRep() const& {
-  return Ref(contents_.tree());
+  return CordRep::Ref(contents_.tree());
 }
 
 inline CordRep* Cord::TakeRep() && {
@@ -864,7 +703,7 @@
     }
     if (src_tree->tag >= FLAT) {
       // src tree just has one flat node.
-      contents_.AppendArray(src_tree->data, src_size);
+      contents_.AppendArray(src_tree->flat()->Data(), src_size);
       return;
     }
     if (&src == this) {
@@ -879,6 +718,7 @@
     return;
   }
 
+  // Guaranteed to be a tree (kMaxBytesToCopy > kInlinedSize)
   contents_.AppendTree(std::forward<C>(src).TakeRep());
 }
 
@@ -886,10 +726,21 @@
 
 void Cord::Append(Cord&& src) { AppendImpl(std::move(src)); }
 
+template <typename T, Cord::EnableIfString<T>>
+void Cord::Append(T&& src) {
+  if (src.size() <= kMaxBytesToCopy) {
+    Append(absl::string_view(src));
+  } else {
+    Append(Cord(std::forward<T>(src)));
+  }
+}
+
+template void Cord::Append(std::string&& src);
+
 void Cord::Prepend(const Cord& src) {
   CordRep* src_tree = src.contents_.tree();
   if (src_tree != nullptr) {
-    Ref(src_tree);
+    CordRep::Ref(src_tree);
     contents_.PrependTree(src_tree);
     return;
   }
@@ -901,23 +752,35 @@
 
 void Cord::Prepend(absl::string_view src) {
   if (src.empty()) return;  // memcpy(_, nullptr, 0) is undefined.
-  size_t cur_size = contents_.size();
-  if (!contents_.is_tree() && cur_size + src.size() <= InlineRep::kMaxInline) {
-    // Use embedded storage.
-    char data[InlineRep::kMaxInline + 1] = {0};
-    data[InlineRep::kMaxInline] = cur_size + src.size();  // set size
-    memcpy(data, src.data(), src.size());
-    memcpy(data + src.size(), contents_.data(), cur_size);
-    memcpy(reinterpret_cast<void*>(&contents_), data,
-           InlineRep::kMaxInline + 1);
+  if (!contents_.is_tree()) {
+    size_t cur_size = contents_.inline_size();
+    if (cur_size + src.size() <= InlineRep::kMaxInline) {
+      // Use embedded storage.
+      char data[InlineRep::kMaxInline + 1] = {0};
+      memcpy(data, src.data(), src.size());
+      memcpy(data + src.size(), contents_.data(), cur_size);
+      memcpy(contents_.data_.as_chars(), data, InlineRep::kMaxInline + 1);
+      contents_.set_inline_size(cur_size + src.size());
+      return;
+    }
+  }
+  contents_.PrependTree(NewTree(src.data(), src.size(), 0));
+}
+
+template <typename T, Cord::EnableIfString<T>>
+inline void Cord::Prepend(T&& src) {
+  if (src.size() <= kMaxBytesToCopy) {
+    Prepend(absl::string_view(src));
   } else {
-    contents_.PrependTree(NewTree(src.data(), src.size(), 0));
+    Prepend(Cord(std::forward<T>(src)));
   }
 }
 
+template void Cord::Prepend(std::string&& src);
+
 static CordRep* RemovePrefixFrom(CordRep* node, size_t n) {
   if (n >= node->length) return nullptr;
-  if (n == 0) return Ref(node);
+  if (n == 0) return CordRep::Ref(node);
   absl::InlinedVector<CordRep*, kInlinedVectorSize> rhs_stack;
 
   while (node->tag == CONCAT) {
@@ -935,7 +798,7 @@
   assert(n <= node->length);
 
   if (n == 0) {
-    Ref(node);
+    CordRep::Ref(node);
   } else {
     size_t start = n;
     size_t len = node->length - n;
@@ -944,10 +807,10 @@
       start += node->substring()->start;
       node = node->substring()->child;
     }
-    node = NewSubstring(Ref(node), start, len);
+    node = NewSubstring(CordRep::Ref(node), start, len);
   }
   while (!rhs_stack.empty()) {
-    node = Concat(node, Ref(rhs_stack.back()));
+    node = Concat(node, CordRep::Ref(rhs_stack.back()));
     rhs_stack.pop_back();
   }
   return node;
@@ -958,7 +821,7 @@
 // edited in place iff that node and all its ancestors have a refcount of 1.
 static CordRep* RemoveSuffixFrom(CordRep* node, size_t n) {
   if (n >= node->length) return nullptr;
-  if (n == 0) return Ref(node);
+  if (n == 0) return CordRep::Ref(node);
   absl::InlinedVector<CordRep*, kInlinedVectorSize> lhs_stack;
   bool inplace_ok = node->refcount.IsOne();
 
@@ -978,11 +841,11 @@
   assert(n <= node->length);
 
   if (n == 0) {
-    Ref(node);
+    CordRep::Ref(node);
   } else if (inplace_ok && node->tag != EXTERNAL) {
     // Consider making a new buffer if the current node capacity is much
     // larger than the new length.
-    Ref(node);
+    CordRep::Ref(node);
     node->length -= n;
   } else {
     size_t start = 0;
@@ -991,10 +854,10 @@
       start = node->substring()->start;
       node = node->substring()->child;
     }
-    node = NewSubstring(Ref(node), start, len);
+    node = NewSubstring(CordRep::Ref(node), start, len);
   }
   while (!lhs_stack.empty()) {
-    node = Concat(Ref(lhs_stack.back()), node);
+    node = Concat(CordRep::Ref(lhs_stack.back()), node);
     lhs_stack.pop_back();
   }
   return node;
@@ -1007,9 +870,11 @@
   CordRep* tree = contents_.tree();
   if (tree == nullptr) {
     contents_.remove_prefix(n);
+  } else if (tree->tag == RING) {
+    contents_.replace_tree(CordRepRing::RemovePrefix(tree->ring(), n));
   } else {
     CordRep* newrep = RemovePrefixFrom(tree, n);
-    Unref(tree);
+    CordRep::Unref(tree);
     contents_.replace_tree(VerifyTree(newrep));
   }
 }
@@ -1021,9 +886,11 @@
   CordRep* tree = contents_.tree();
   if (tree == nullptr) {
     contents_.reduce_size(n);
+  } else if (tree->tag == RING) {
+    contents_.replace_tree(CordRepRing::RemoveSuffix(tree->ring(), n));
   } else {
     CordRep* newrep = RemoveSuffixFrom(tree, n);
-    Unref(tree);
+    CordRep::Unref(tree);
     contents_.replace_tree(VerifyTree(newrep));
   }
 }
@@ -1056,13 +923,13 @@
       results.pop_back();
       results.push_back(Concat(left, right));
     } else if (pos == 0 && n == node->length) {
-      results.push_back(Ref(node));
+      results.push_back(CordRep::Ref(node));
     } else if (node->tag != CONCAT) {
       if (node->tag == SUBSTRING) {
         pos += node->substring()->start;
         node = node->substring()->child;
       }
-      results.push_back(NewSubstring(Ref(node), pos, n));
+      results.push_back(NewSubstring(CordRep::Ref(node), pos, n));
     } else if (pos + n <= node->concat()->left->length) {
       todo.push_back(SubRange(node->concat()->left, pos, n));
     } else if (pos >= node->concat()->left->length) {
@@ -1094,7 +961,7 @@
   } else if (new_size <= InlineRep::kMaxInline) {
     Cord::ChunkIterator it = chunk_begin();
     it.AdvanceBytes(pos);
-    char* dest = sub_cord.contents_.data_;
+    char* dest = sub_cord.contents_.data_.as_chars();
     size_t remaining_size = new_size;
     while (remaining_size > it->size()) {
       cord_internal::SmallMemmove(dest, it->data(), it->size());
@@ -1103,7 +970,10 @@
       ++it;
     }
     cord_internal::SmallMemmove(dest, it->data(), remaining_size);
-    sub_cord.contents_.data_[InlineRep::kMaxInline] = new_size;
+    sub_cord.contents_.set_inline_size(new_size);
+  } else if (tree->tag == RING) {
+    tree = CordRepRing::SubRing(CordRep::Ref(tree)->ring(), pos, new_size);
+    sub_cord.contents_.set_tree(tree);
   } else {
     sub_cord.contents_.set_tree(NewSubRange(tree, pos, new_size));
   }
@@ -1140,9 +1010,9 @@
           concat_node->left = concat_freelist_;
           concat_freelist_ = concat_node;
         } else {
-          Ref(concat_node->right);
-          Ref(concat_node->left);
-          Unref(concat_node);
+          CordRep::Ref(concat_node->right);
+          CordRep::Ref(concat_node->left);
+          CordRep::Unref(concat_node);
         }
       } else {
         AddNode(node);
@@ -1175,7 +1045,7 @@
   void AddNode(CordRep* node) {
     CordRep* sum = nullptr;
 
-    // Collect together everything with which we will merge node
+    // Collect together everything with which we will merge with node
     int i = 0;
     for (; node->length > min_length[i + 1]; ++i) {
       auto& tree_at_i = trees_[i];
@@ -1292,20 +1162,23 @@
 // Helper routine. Locates the first flat chunk of the Cord without
 // initializing the iterator.
 inline absl::string_view Cord::InlineRep::FindFlatStartPiece() const {
-  size_t n = data_[kMaxInline];
-  if (n <= kMaxInline) {
-    return absl::string_view(data_, n);
+  if (!is_tree()) {
+    return absl::string_view(data_.as_chars(), data_.inline_size());
   }
 
   CordRep* node = tree();
   if (node->tag >= FLAT) {
-    return absl::string_view(node->data, node->length);
+    return absl::string_view(node->flat()->Data(), node->length);
   }
 
   if (node->tag == EXTERNAL) {
     return absl::string_view(node->external()->base, node->length);
   }
 
+  if (node->tag == RING) {
+    return node->ring()->entry_data(node->ring()->head());
+  }
+
   // Walk down the left branches until we hit a non-CONCAT node.
   while (node->tag == CONCAT) {
     node = node->concat()->left;
@@ -1322,7 +1195,7 @@
   }
 
   if (node->tag >= FLAT) {
-    return absl::string_view(node->data + offset, length);
+    return absl::string_view(node->flat()->Data() + offset, length);
   }
 
   assert((node->tag == EXTERNAL) && "Expect FLAT or EXTERNAL node here");
@@ -1505,25 +1378,22 @@
   }
 }
 
-Cord::ChunkIterator& Cord::ChunkIterator::operator++() {
-  assert(bytes_remaining_ > 0 && "Attempted to iterate past `end()`");
-  assert(bytes_remaining_ >= current_chunk_.size());
-  bytes_remaining_ -= current_chunk_.size();
-
-  if (stack_of_right_children_.empty()) {
+Cord::ChunkIterator& Cord::ChunkIterator::AdvanceStack() {
+  auto& stack_of_right_children = stack_of_right_children_;
+  if (stack_of_right_children.empty()) {
     assert(!current_chunk_.empty());  // Called on invalid iterator.
     // We have reached the end of the Cord.
     return *this;
   }
 
   // Process the next node on the stack.
-  CordRep* node = stack_of_right_children_.back();
-  stack_of_right_children_.pop_back();
+  CordRep* node = stack_of_right_children.back();
+  stack_of_right_children.pop_back();
 
   // Walk down the left branches until we hit a non-CONCAT node. Save the
   // right children to the stack for subsequent traversal.
   while (node->tag == CONCAT) {
-    stack_of_right_children_.push_back(node->concat()->right);
+    stack_of_right_children.push_back(node->concat()->right);
     node = node->concat()->left;
   }
 
@@ -1538,14 +1408,15 @@
   assert(node->tag == EXTERNAL || node->tag >= FLAT);
   assert(length != 0);
   const char* data =
-      node->tag == EXTERNAL ? node->external()->base : node->data;
+      node->tag == EXTERNAL ? node->external()->base : node->flat()->Data();
   current_chunk_ = absl::string_view(data + offset, length);
   current_leaf_ = node;
   return *this;
 }
 
 Cord Cord::ChunkIterator::AdvanceAndReadBytes(size_t n) {
-  assert(bytes_remaining_ >= n && "Attempted to iterate past `end()`");
+  ABSL_HARDENING_ASSERT(bytes_remaining_ >= n &&
+                        "Attempted to iterate past `end()`");
   Cord subcord;
 
   if (n <= InlineRep::kMaxInline) {
@@ -1565,12 +1436,32 @@
     }
     return subcord;
   }
+
+  if (ring_reader_) {
+    size_t chunk_size = current_chunk_.size();
+    if (n <= chunk_size && n <= kMaxBytesToCopy) {
+      subcord = Cord(current_chunk_.substr(0, n));
+    } else {
+      auto* ring = CordRep::Ref(ring_reader_.ring())->ring();
+      size_t offset = ring_reader_.length() - bytes_remaining_;
+      subcord.contents_.set_tree(CordRepRing::SubRing(ring, offset, n));
+    }
+    if (n < chunk_size) {
+      bytes_remaining_ -= n;
+      current_chunk_.remove_prefix(n);
+    } else {
+      AdvanceBytesRing(n);
+    }
+    return subcord;
+  }
+
+  auto& stack_of_right_children = stack_of_right_children_;
   if (n < current_chunk_.size()) {
     // Range to read is a proper subrange of the current chunk.
     assert(current_leaf_ != nullptr);
-    CordRep* subnode = Ref(current_leaf_);
-    const char* data =
-        subnode->tag == EXTERNAL ? subnode->external()->base : subnode->data;
+    CordRep* subnode = CordRep::Ref(current_leaf_);
+    const char* data = subnode->tag == EXTERNAL ? subnode->external()->base
+                                                : subnode->flat()->Data();
     subnode = NewSubstring(subnode, current_chunk_.data() - data, n);
     subcord.contents_.set_tree(VerifyTree(subnode));
     RemoveChunkPrefix(n);
@@ -1580,10 +1471,10 @@
   // Range to read begins with a proper subrange of the current chunk.
   assert(!current_chunk_.empty());
   assert(current_leaf_ != nullptr);
-  CordRep* subnode = Ref(current_leaf_);
+  CordRep* subnode = CordRep::Ref(current_leaf_);
   if (current_chunk_.size() < subnode->length) {
-    const char* data =
-        subnode->tag == EXTERNAL ? subnode->external()->base : subnode->data;
+    const char* data = subnode->tag == EXTERNAL ? subnode->external()->base
+                                                : subnode->flat()->Data();
     subnode = NewSubstring(subnode, current_chunk_.data() - data,
                            current_chunk_.size());
   }
@@ -1593,20 +1484,20 @@
   // Process the next node(s) on the stack, reading whole subtrees depending on
   // their length and how many bytes we are advancing.
   CordRep* node = nullptr;
-  while (!stack_of_right_children_.empty()) {
-    node = stack_of_right_children_.back();
-    stack_of_right_children_.pop_back();
+  while (!stack_of_right_children.empty()) {
+    node = stack_of_right_children.back();
+    stack_of_right_children.pop_back();
     if (node->length > n) break;
     // TODO(qrczak): This might unnecessarily recreate existing concat nodes.
     // Avoiding that would need pretty complicated logic (instead of
-    // current_leaf_, keep current_subtree_ which points to the highest node
+    // current_leaf, keep current_subtree_ which points to the highest node
     // such that the current leaf can be found on the path of left children
     // starting from current_subtree_; delay creating subnode while node is
     // below current_subtree_; find the proper node along the path of left
     // children starting from current_subtree_ if this loop exits while staying
     // below current_subtree_; etc.; alternatively, push parents instead of
     // right children on the stack).
-    subnode = Concat(subnode, Ref(node));
+    subnode = Concat(subnode, CordRep::Ref(node));
     n -= node->length;
     bytes_remaining_ -= node->length;
     node = nullptr;
@@ -1624,11 +1515,11 @@
   while (node->tag == CONCAT) {
     if (node->concat()->left->length > n) {
       // Push right, descend left.
-      stack_of_right_children_.push_back(node->concat()->right);
+      stack_of_right_children.push_back(node->concat()->right);
       node = node->concat()->left;
     } else {
       // Read left, descend right.
-      subnode = Concat(subnode, Ref(node->concat()->left));
+      subnode = Concat(subnode, CordRep::Ref(node->concat()->left));
       n -= node->concat()->left->length;
       bytes_remaining_ -= node->concat()->left->length;
       node = node->concat()->right;
@@ -1647,9 +1538,11 @@
   // chunk.
   assert(node->tag == EXTERNAL || node->tag >= FLAT);
   assert(length > n);
-  if (n > 0) subnode = Concat(subnode, NewSubstring(Ref(node), offset, n));
+  if (n > 0) {
+    subnode = Concat(subnode, NewSubstring(CordRep::Ref(node), offset, n));
+  }
   const char* data =
-      node->tag == EXTERNAL ? node->external()->base : node->data;
+      node->tag == EXTERNAL ? node->external()->base : node->flat()->Data();
   current_chunk_ = absl::string_view(data + offset + n, length - n);
   current_leaf_ = node;
   bytes_remaining_ -= n;
@@ -1665,12 +1558,19 @@
   n -= current_chunk_.size();
   bytes_remaining_ -= current_chunk_.size();
 
+  if (stack_of_right_children_.empty()) {
+    // We have reached the end of the Cord.
+    assert(bytes_remaining_ == 0);
+    return;
+  }
+
   // Process the next node(s) on the stack, skipping whole subtrees depending on
   // their length and how many bytes we are advancing.
   CordRep* node = nullptr;
-  while (!stack_of_right_children_.empty()) {
-    node = stack_of_right_children_.back();
-    stack_of_right_children_.pop_back();
+  auto& stack_of_right_children = stack_of_right_children_;
+  while (!stack_of_right_children.empty()) {
+    node = stack_of_right_children.back();
+    stack_of_right_children.pop_back();
     if (node->length > n) break;
     n -= node->length;
     bytes_remaining_ -= node->length;
@@ -1688,7 +1588,7 @@
   while (node->tag == CONCAT) {
     if (node->concat()->left->length > n) {
       // Push right, descend left.
-      stack_of_right_children_.push_back(node->concat()->right);
+      stack_of_right_children.push_back(node->concat()->right);
       node = node->concat()->left;
     } else {
       // Skip left, descend right.
@@ -1709,14 +1609,14 @@
   assert(node->tag == EXTERNAL || node->tag >= FLAT);
   assert(length > n);
   const char* data =
-      node->tag == EXTERNAL ? node->external()->base : node->data;
+      node->tag == EXTERNAL ? node->external()->base : node->flat()->Data();
   current_chunk_ = absl::string_view(data + offset + n, length - n);
   current_leaf_ = node;
   bytes_remaining_ -= n;
 }
 
 char Cord::operator[](size_t i) const {
-  assert(i < size());
+  ABSL_HARDENING_ASSERT(i < size());
   size_t offset = i;
   const CordRep* rep = contents_.tree();
   if (rep == nullptr) {
@@ -1727,7 +1627,9 @@
     assert(offset < rep->length);
     if (rep->tag >= FLAT) {
       // Get the "i"th character directly from the flat array.
-      return rep->data[offset];
+      return rep->flat()->Data()[offset];
+    } else if (rep->tag == RING) {
+      return rep->ring()->GetCharacter(offset);
     } else if (rep->tag == EXTERNAL) {
       // Get the "i"th character from the external array.
       return rep->external()->base[offset];
@@ -1758,9 +1660,9 @@
   // Try to put the contents into a new flat rep. If they won't fit in the
   // biggest possible flat node, use an external rep instead.
   if (total_size <= kMaxFlatLength) {
-    new_rep = NewFlat(total_size);
+    new_rep = CordRepFlat::New(total_size);
     new_rep->length = total_size;
-    new_buffer = new_rep->data;
+    new_buffer = new_rep->flat()->Data();
     CopyToArraySlowPath(new_buffer);
   } else {
     new_buffer = std::allocator<char>().allocate(total_size);
@@ -1771,7 +1673,9 @@
                                             s.size());
         });
   }
-  Unref(contents_.tree());
+  if (CordRep* tree = contents_.tree()) {
+    CordRep::Unref(tree);
+  }
   contents_.set_tree(new_rep);
   return absl::string_view(new_buffer, total_size);
 }
@@ -1779,7 +1683,7 @@
 /* static */ bool Cord::GetFlatAux(CordRep* rep, absl::string_view* fragment) {
   assert(rep != nullptr);
   if (rep->tag >= FLAT) {
-    *fragment = absl::string_view(rep->data, rep->length);
+    *fragment = absl::string_view(rep->flat()->Data(), rep->length);
     return true;
   } else if (rep->tag == EXTERNAL) {
     *fragment = absl::string_view(rep->external()->base, rep->length);
@@ -1787,8 +1691,8 @@
   } else if (rep->tag == SUBSTRING) {
     CordRep* child = rep->substring()->child;
     if (child->tag >= FLAT) {
-      *fragment =
-          absl::string_view(child->data + rep->substring()->start, rep->length);
+      *fragment = absl::string_view(
+          child->flat()->Data() + rep->substring()->start, rep->length);
       return true;
     } else if (child->tag == EXTERNAL) {
       *fragment = absl::string_view(
@@ -1802,6 +1706,15 @@
 /* static */ void Cord::ForEachChunkAux(
     absl::cord_internal::CordRep* rep,
     absl::FunctionRef<void(absl::string_view)> callback) {
+  if (rep->tag == RING) {
+    ChunkIterator it(rep), end;
+    while (it != end) {
+      callback(*it);
+      ++it;
+    }
+    return;
+  }
+
   assert(rep != nullptr);
   int stack_pos = 0;
   constexpr int stack_max = 128;
@@ -1843,9 +1756,9 @@
   }
 }
 
-static void DumpNode(CordRep* rep, bool include_data, std::ostream* os) {
+static void DumpNode(CordRep* rep, bool include_data, std::ostream* os,
+                     int indent) {
   const int kIndentStep = 1;
-  int indent = 0;
   absl::InlinedVector<CordRep*, kInlinedVectorSize> stack;
   absl::InlinedVector<int, kInlinedVectorSize> indents;
   for (;;) {
@@ -1866,17 +1779,28 @@
       *os << "SUBSTRING @ " << rep->substring()->start << "\n";
       indent += kIndentStep;
       rep = rep->substring()->child;
-    } else {  // Leaf
+    } else {  // Leaf or ring
       if (rep->tag == EXTERNAL) {
         *os << "EXTERNAL [";
         if (include_data)
           *os << absl::CEscape(std::string(rep->external()->base, rep->length));
         *os << "]\n";
-      } else {
-        *os << "FLAT cap=" << TagToLength(rep->tag) << " [";
+      } else if (rep->tag >= FLAT) {
+        *os << "FLAT cap=" << rep->flat()->Capacity()
+            << " [";
         if (include_data)
-          *os << absl::CEscape(std::string(rep->data, rep->length));
+          *os << absl::CEscape(std::string(rep->flat()->Data(), rep->length));
         *os << "]\n";
+      } else {
+        assert(rep->tag == RING);
+        auto* ring = rep->ring();
+        *os << "RING, entries = " << ring->entries() << "\n";
+        CordRepRing::index_type head = ring->head();
+        do {
+          DumpNode(ring->entry_child(head), include_data, os,
+                   indent + kIndentStep);
+          head = ring->advance(head);;
+        } while (head != ring->tail());
       }
       if (stack.empty()) break;
       rep = stack.back();
@@ -1921,8 +1845,9 @@
         worklist.push_back(node->concat()->left);
       }
     } else if (node->tag >= FLAT) {
-      ABSL_INTERNAL_CHECK(node->length <= TagToLength(node->tag),
-                          ReportError(root, node));
+      ABSL_INTERNAL_CHECK(
+          node->length <= node->flat()->Capacity(),
+          ReportError(root, node));
     } else if (node->tag == EXTERNAL) {
       ABSL_INTERNAL_CHECK(node->external()->base != nullptr,
                           ReportError(root, node));
@@ -1969,6 +1894,15 @@
         }
         next_node = right;
       }
+    } else if (cur_node->tag == RING) {
+      total_mem_usage += CordRepRing::AllocSize(cur_node->ring()->capacity());
+      const CordRepRing* ring = cur_node->ring();
+      CordRepRing::index_type pos = ring->head(), tail = ring->tail();
+      do {
+        CordRep* node = ring->entry_child(pos);
+        assert(node->tag >= FLAT || node->tag == EXTERNAL);
+        RepMemoryUsageLeaf(node, &total_mem_usage);
+      } while ((pos = ring->advance(pos)) != tail);
     } else {
       // Since cur_node is not a leaf or a concat node it must be a substring.
       assert(cur_node->tag == SUBSTRING);
@@ -1998,14 +1932,14 @@
 }
 
 namespace strings_internal {
-size_t CordTestAccess::FlatOverhead() { return kFlatOverhead; }
-size_t CordTestAccess::MaxFlatLength() { return kMaxFlatLength; }
+size_t CordTestAccess::FlatOverhead() { return cord_internal::kFlatOverhead; }
+size_t CordTestAccess::MaxFlatLength() { return cord_internal::kMaxFlatLength; }
 size_t CordTestAccess::FlatTagToLength(uint8_t tag) {
-  return TagToLength(tag);
+  return cord_internal::TagToLength(tag);
 }
 uint8_t CordTestAccess::LengthToTag(size_t s) {
   ABSL_INTERNAL_CHECK(s <= kMaxFlatLength, absl::StrCat("Invalid length ", s));
-  return AllocatedSizeToTag(s + kFlatOverhead);
+  return cord_internal::AllocatedSizeToTag(s + cord_internal::kFlatOverhead);
 }
 size_t CordTestAccess::SizeofCordRepConcat() { return sizeof(CordRepConcat); }
 size_t CordTestAccess::SizeofCordRepExternal() {
diff --git a/absl/strings/cord.h b/absl/strings/cord.h
index 40566cb..fa9cb91 100644
--- a/absl/strings/cord.h
+++ b/absl/strings/cord.h
@@ -11,25 +11,52 @@
 // 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.
-
-// A Cord is a sequence of characters with some unusual access propreties.
-// A Cord supports efficient insertions and deletions at the start and end of
-// the byte sequence, but random access reads are slower, and random access
-// modifications are not supported by the API.  Cord also provides cheap copies
-// (using a copy-on-write strategy) and cheap substring operations.
 //
-// Thread safety
-// -------------
+// -----------------------------------------------------------------------------
+// File: cord.h
+// -----------------------------------------------------------------------------
+//
+// This file defines the `absl::Cord` data structure and operations on that data
+// structure. A Cord is a string-like sequence of characters optimized for
+// specific use cases. Unlike a `std::string`, which stores an array of
+// contiguous characters, Cord data is stored in a structure consisting of
+// separate, reference-counted "chunks." (Currently, this implementation is a
+// tree structure, though that implementation may change.)
+//
+// Because a Cord consists of these chunks, data can be added to or removed from
+// a Cord during its lifetime. Chunks may also be shared between Cords. Unlike a
+// `std::string`, a Cord can therefore accommodate data that changes over its
+// lifetime, though it's not quite "mutable"; it can change only in the
+// attachment, detachment, or rearrangement of chunks of its constituent data.
+//
+// A Cord provides some benefit over `std::string` under the following (albeit
+// narrow) circumstances:
+//
+//   * Cord data is designed to grow and shrink over a Cord's lifetime. Cord
+//     provides efficient insertions and deletions at the start and end of the
+//     character sequences, avoiding copies in those cases. Static data should
+//     generally be stored as strings.
+//   * External memory consisting of string-like data can be directly added to
+//     a Cord without requiring copies or allocations.
+//   * Cord data may be shared and copied cheaply. Cord provides a copy-on-write
+//     implementation and cheap sub-Cord operations. Copying a Cord is an O(1)
+//     operation.
+//
+// As a consequence to the above, Cord data is generally large. Small data
+// should generally use strings, as construction of a Cord requires some
+// overhead. Small Cords (<= 15 bytes) are represented inline, but most small
+// Cords are expected to grow over their lifetimes.
+//
+// Note that because a Cord is made up of separate chunked data, random access
+// to character data within a Cord is slower than within a `std::string`.
+//
+// Thread Safety
+//
 // Cord has the same thread-safety properties as many other types like
 // std::string, std::vector<>, int, etc -- it is thread-compatible. In
-// particular, if no thread may call a non-const method, then it is safe to
-// concurrently call const methods. Copying a Cord produces a new instance that
-// can be used concurrently with the original in arbitrary ways.
-//
-// Implementation is similar to the "Ropes" described in:
-//    Ropes: An alternative to strings
-//    Hans J. Boehm, Russ Atkinson, Michael Plass
-//    Software Practice and Experience, December 1995
+// particular, if threads do not call non-const methods, then it is safe to call
+// const methods without synchronization. Copying a Cord produces a new instance
+// that can be used concurrently with the original in arbitrary ways.
 
 #ifndef ABSL_STRINGS_CORD_H_
 #define ABSL_STRINGS_CORD_H_
@@ -38,12 +65,12 @@
 #include <cstddef>
 #include <cstdint>
 #include <cstring>
-#include <iostream>
+#include <iosfwd>
 #include <iterator>
 #include <string>
+#include <type_traits>
 
 #include "absl/base/internal/endian.h"
-#include "absl/base/internal/invoke.h"
 #include "absl/base/internal/per_thread_tls.h"
 #include "absl/base/macros.h"
 #include "absl/base/port.h"
@@ -51,8 +78,12 @@
 #include "absl/functional/function_ref.h"
 #include "absl/meta/type_traits.h"
 #include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_ring.h"
+#include "absl/strings/internal/cord_rep_ring_reader.h"
 #include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/internal/string_constant.h"
 #include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -61,12 +92,35 @@
 template <typename Releaser>
 Cord MakeCordFromExternal(absl::string_view, Releaser&&);
 void CopyCordToString(const Cord& src, std::string* dst);
-namespace hash_internal {
-template <typename H>
-H HashFragmentedCord(H, const Cord&);
-}
 
-// A Cord is a sequence of characters.
+// Cord
+//
+// A Cord is a sequence of characters, designed to be more efficient than a
+// `std::string` in certain circumstances: namely, large string data that needs
+// to change over its lifetime or shared, especially when such data is shared
+// across API boundaries.
+//
+// A Cord stores its character data in a structure that allows efficient prepend
+// and append operations. This makes a Cord useful for large string data sent
+// over in a wire format that may need to be prepended or appended at some point
+// during the data exchange (e.g. HTTP, protocol buffers). For example, a
+// Cord is useful for storing an HTTP request, and prepending an HTTP header to
+// such a request.
+//
+// Cords should not be used for storing general string data, however. They
+// require overhead to construct and are slower than strings for random access.
+//
+// The Cord API provides the following common API operations:
+//
+// * Create or assign Cords out of existing string data, memory, or other Cords
+// * Append and prepend data to an existing Cord
+// * Create new Sub-Cords from existing Cord data
+// * Swap Cord data and compare Cord equality
+// * Write out Cord data by constructing a `std::string`
+//
+// Additionally, the API provides iterator utilities to iterate through Cord
+// data via chunks or character bytes.
+//
 class Cord {
  private:
   template <typename T>
@@ -74,51 +128,53 @@
       absl::enable_if_t<std::is_same<T, std::string>::value, int>;
 
  public:
-  // --------------------------------------------------------------------
-  // Constructors, destructors and helper factories
+  // Cord::Cord() Constructors.
 
-  // Create an empty cord
+  // Creates an empty Cord.
   constexpr Cord() noexcept;
 
-  // Cord is copyable and efficiently movable.
-  // The moved-from state is valid but unspecified.
+  // Creates a Cord from an existing Cord. Cord is copyable and efficiently
+  // movable. The moved-from state is valid but unspecified.
   Cord(const Cord& src);
   Cord(Cord&& src) noexcept;
   Cord& operator=(const Cord& x);
   Cord& operator=(Cord&& x) noexcept;
 
-  // Create a cord out of "src". This constructor is explicit on
-  // purpose so that people do not get automatic type conversions.
+  // Creates a Cord from a `src` string. This constructor is marked explicit to
+  // prevent implicit Cord constructions from arguments convertible to an
+  // `absl::string_view`.
   explicit Cord(absl::string_view src);
   Cord& operator=(absl::string_view src);
 
-  // These are templated to avoid ambiguities for types that are convertible to
-  // both `absl::string_view` and `std::string`, such as `const char*`.
-  //
-  // Note that these functions reserve the right to reuse the `string&&`'s
-  // memory and that they will do so in the future.
+  // Creates a Cord from a `std::string&&` rvalue. These constructors are
+  // templated to avoid ambiguities for types that are convertible to both
+  // `absl::string_view` and `std::string`, such as `const char*`.
   template <typename T, EnableIfString<T> = 0>
-  explicit Cord(T&& src) : Cord(absl::string_view(src)) {}
+  explicit Cord(T&& src);
   template <typename T, EnableIfString<T> = 0>
   Cord& operator=(T&& src);
 
-  // Destroy the cord
+  // Cord::~Cord()
+  //
+  // Destructs the Cord.
   ~Cord() {
     if (contents_.is_tree()) DestroyCordSlow();
   }
 
-  // Creates a Cord that takes ownership of external memory. The contents of
-  // `data` are not copied.
+  // MakeCordFromExternal()
   //
-  // This function takes a callable that is invoked when all Cords are
-  // finished with `data`. The data must remain live and unchanging until the
-  // releaser is called. The requirements for the releaser are that it:
-  //   * is move constructible,
-  //   * supports `void operator()(absl::string_view) const`,
-  //   * does not have alignment requirement greater than what is guaranteed by
-  //     ::operator new. This is dictated by alignof(std::max_align_t) before
-  //     C++17 and __STDCPP_DEFAULT_NEW_ALIGNMENT__ if compiling with C++17 or
-  //     it is supported by the implementation.
+  // Creates a Cord that takes ownership of external string memory. The
+  // contents of `data` are not copied to the Cord; instead, the external
+  // memory is added to the Cord and reference-counted. This data may not be
+  // changed for the life of the Cord, though it may be prepended or appended
+  // to.
+  //
+  // `MakeCordFromExternal()` takes a callable "releaser" that is invoked when
+  // the reference count for `data` reaches zero. As noted above, this data must
+  // remain live until the releaser is invoked. The callable releaser also must:
+  //
+  //   * be move constructible
+  //   * support `void operator()(absl::string_view) const` or `void operator()`
   //
   // Example:
   //
@@ -127,13 +183,13 @@
   //   FillBlock(block);
   //   return absl::MakeCordFromExternal(
   //       block->ToStringView(),
-  //       [pool, block](absl::string_view /*ignored*/) {
-  //         pool->FreeBlock(block);
+  //       [pool, block](absl::string_view v) {
+  //         pool->FreeBlock(block, v);
   //       });
   // }
   //
-  // WARNING: It's likely a bug if your releaser doesn't do anything.
-  // For example, consider the following:
+  // WARNING: Because a Cord can be reference-counted, it's likely a bug if your
+  // releaser doesn't do anything. For example, consider the following:
   //
   // void Foo(const char* buffer, int len) {
   //   auto c = absl::MakeCordFromExternal(absl::string_view(buffer, len),
@@ -147,97 +203,143 @@
   template <typename Releaser>
   friend Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser);
 
-  // --------------------------------------------------------------------
-  // Mutations
-
+  // Cord::Clear()
+  //
+  // Releases the Cord data. Any nodes that share data with other Cords, if
+  // applicable, will have their reference counts reduced by 1.
   void Clear();
 
+  // Cord::Append()
+  //
+  // Appends data to the Cord, which may come from another Cord or other string
+  // data.
   void Append(const Cord& src);
   void Append(Cord&& src);
   void Append(absl::string_view src);
   template <typename T, EnableIfString<T> = 0>
   void Append(T&& src);
 
+  // Cord::Prepend()
+  //
+  // Prepends data to the Cord, which may come from another Cord or other string
+  // data.
   void Prepend(const Cord& src);
   void Prepend(absl::string_view src);
   template <typename T, EnableIfString<T> = 0>
   void Prepend(T&& src);
 
+  // Cord::RemovePrefix()
+  //
+  // Removes the first `n` bytes of a Cord.
   void RemovePrefix(size_t n);
   void RemoveSuffix(size_t n);
 
-  // Returns a new cord representing the subrange [pos, pos + new_size) of
+  // Cord::Subcord()
+  //
+  // Returns a new Cord representing the subrange [pos, pos + new_size) of
   // *this. If pos >= size(), the result is empty(). If
   // (pos + new_size) >= size(), the result is the subrange [pos, size()).
   Cord Subcord(size_t pos, size_t new_size) const;
 
-  friend void swap(Cord& x, Cord& y) noexcept;
+  // Cord::swap()
+  //
+  // Swaps the contents of the Cord with `other`.
+  void swap(Cord& other) noexcept;
 
-  // --------------------------------------------------------------------
-  // Accessors
+  // swap()
+  //
+  // Swaps the contents of two Cords.
+  friend void swap(Cord& x, Cord& y) noexcept {
+    x.swap(y);
+  }
 
+  // Cord::size()
+  //
+  // Returns the size of the Cord.
   size_t size() const;
+
+  // Cord::empty()
+  //
+  // Determines whether the given Cord is empty, returning `true` is so.
   bool empty() const;
 
-  // Returns the approximate number of bytes pinned by this Cord.  Note that
-  // Cords that share memory could each be "charged" independently for the same
-  // shared memory.
+  // Cord::EstimatedMemoryUsage()
+  //
+  // Returns the *approximate* number of bytes held in full or in part by this
+  // Cord (which may not remain the same between invocations).  Note that Cords
+  // that share memory could each be "charged" independently for the same shared
+  // memory.
   size_t EstimatedMemoryUsage() const;
 
-  // --------------------------------------------------------------------
-  // Comparators
-
-  // Compares 'this' Cord with rhs. This function and its relatives
-  // treat Cords as sequences of unsigned bytes. The comparison is a
-  // straightforward lexicographic comparison. Return value:
+  // Cord::Compare()
+  //
+  // Compares 'this' Cord with rhs. This function and its relatives treat Cords
+  // as sequences of unsigned bytes. The comparison is a straightforward
+  // lexicographic comparison. `Cord::Compare()` returns values as follows:
+  //
   //   -1  'this' Cord is smaller
   //    0  two Cords are equal
   //    1  'this' Cord is larger
   int Compare(absl::string_view rhs) const;
   int Compare(const Cord& rhs) const;
 
-  // Does 'this' cord start/end with rhs
+  // Cord::StartsWith()
+  //
+  // Determines whether the Cord starts with the passed string data `rhs`.
   bool StartsWith(const Cord& rhs) const;
   bool StartsWith(absl::string_view rhs) const;
+
+  // Cord::EndsWith()
+  //
+  // Determines whether the Cord ends with the passed string data `rhs`.
   bool EndsWith(absl::string_view rhs) const;
   bool EndsWith(const Cord& rhs) const;
 
-  // --------------------------------------------------------------------
-  // Conversion to other types
-
+  // Cord::operator std::string()
+  //
+  // Converts a Cord into a `std::string()`. This operator is marked explicit to
+  // prevent unintended Cord usage in functions that take a string.
   explicit operator std::string() const;
 
-  // Copies the contents from `src` to `*dst`.
+  // CopyCordToString()
   //
-  // This function optimizes the case of reusing the destination std::string since it
+  // Copies the contents of a `src` Cord into a `*dst` string.
+  //
+  // This function optimizes the case of reusing the destination string since it
   // can reuse previously allocated capacity. However, this function does not
   // guarantee that pointers previously returned by `dst->data()` remain valid
   // even if `*dst` had enough capacity to hold `src`. If `*dst` is a new
   // object, prefer to simply use the conversion operator to `std::string`.
   friend void CopyCordToString(const Cord& src, std::string* dst);
 
-  // --------------------------------------------------------------------
-  // Iteration
-
   class CharIterator;
 
-  // Type for iterating over the chunks of a `Cord`. See comments for
-  // `Cord::chunk_begin()`, `Cord::chunk_end()` and `Cord::Chunks()` below for
-  // preferred usage.
+  //----------------------------------------------------------------------------
+  // Cord::ChunkIterator
+  //----------------------------------------------------------------------------
   //
-  // Additional notes:
+  // A `Cord::ChunkIterator` allows iteration over the constituent chunks of its
+  // Cord. Such iteration allows you to perform non-const operatons on the data
+  // of a Cord without modifying it.
+  //
+  // Generally, you do not instantiate a `Cord::ChunkIterator` directly;
+  // instead, you create one implicitly through use of the `Cord::Chunks()`
+  // member function.
+  //
+  // The `Cord::ChunkIterator` has the following properties:
+  //
+  //   * The iterator is invalidated after any non-const operation on the
+  //     Cord object over which it iterates.
   //   * The `string_view` returned by dereferencing a valid, non-`end()`
   //     iterator is guaranteed to be non-empty.
-  //   * A `ChunkIterator` object is invalidated after any non-const
-  //     operation on the `Cord` object over which it iterates.
-  //   * Two `ChunkIterator` objects can be equality compared if and only if
-  //     they remain valid and iterate over the same `Cord`.
-  //   * This is a proxy iterator. This means the `string_view` returned by the
-  //     iterator does not live inside the Cord, and its lifetime is limited to
-  //     the lifetime of the iterator itself. To help prevent issues,
-  //     `ChunkIterator::reference` is not a true reference type and is
-  //     equivalent to `value_type`.
-  //   * The iterator keeps state that can grow for `Cord`s that contain many
+  //   * Two `ChunkIterator` objects can be compared equal if and only if they
+  //     remain valid and iterate over the same Cord.
+  //   * The iterator in this case is a proxy iterator; the `string_view`
+  //     returned by the iterator does not live inside the Cord, and its
+  //     lifetime is limited to the lifetime of the iterator itself. To help
+  //     prevent lifetime issues, `ChunkIterator::reference` is not a true
+  //     reference type and is equivalent to `value_type`.
+  //   * The iterator keeps state that can grow for Cords that contain many
   //     nodes and are imbalanced due to sharing. Prefer to pass this type by
   //     const reference instead of by value.
   class ChunkIterator {
@@ -261,14 +363,38 @@
     friend class CharIterator;
 
    private:
+    using CordRep = absl::cord_internal::CordRep;
+    using CordRepRing = absl::cord_internal::CordRepRing;
+    using CordRepRingReader = absl::cord_internal::CordRepRingReader;
+
+    // Stack of right children of concat nodes that we have to visit.
+    // Keep this at the end of the structure to avoid cache-thrashing.
+    // TODO(jgm): Benchmark to see if there's a more optimal value than 47 for
+    // the inlined vector size (47 exists for backward compatibility).
+    using Stack = absl::InlinedVector<absl::cord_internal::CordRep*, 47>;
+
+    // Constructs a `begin()` iterator from `tree`. `tree` must not be null.
+    explicit ChunkIterator(cord_internal::CordRep* tree);
+
     // Constructs a `begin()` iterator from `cord`.
     explicit ChunkIterator(const Cord* cord);
 
+    // Initializes this instance from a tree. Invoked by constructors.
+    void InitTree(cord_internal::CordRep* tree);
+
     // Removes `n` bytes from `current_chunk_`. Expects `n` to be smaller than
     // `current_chunk_.size()`.
     void RemoveChunkPrefix(size_t n);
     Cord AdvanceAndReadBytes(size_t n);
     void AdvanceBytes(size_t n);
+
+    // Stack specific operator++
+    ChunkIterator& AdvanceStack();
+
+    // Ring buffer specific operator++
+    ChunkIterator& AdvanceRing();
+    void AdvanceBytesRing(size_t n);
+
     // Iterates `n` bytes, where `n` is expected to be greater than or equal to
     // `current_chunk_.size()`.
     void AdvanceBytesSlowPath(size_t n);
@@ -282,14 +408,21 @@
     absl::cord_internal::CordRep* current_leaf_ = nullptr;
     // The number of bytes left in the `Cord` over which we are iterating.
     size_t bytes_remaining_ = 0;
-    absl::InlinedVector<absl::cord_internal::CordRep*, 4>
-        stack_of_right_children_;
+
+    // Cord reader for ring buffers. Empty if not traversing a ring buffer.
+    CordRepRingReader ring_reader_;
+
+    // See 'Stack' alias definition.
+    Stack stack_of_right_children_;
   };
 
+  // Cord::ChunkIterator::chunk_begin()
+  //
   // Returns an iterator to the first chunk of the `Cord`.
   //
-  // This is useful for getting a `ChunkIterator` outside the context of a
-  // range-based for-loop (in which case see `Cord::Chunks()` below).
+  // Generally, prefer using `Cord::Chunks()` within a range-based for loop for
+  // iterating over the chunks of a Cord. This method may be useful for getting
+  // a `ChunkIterator` where range-based for-loops are not useful.
   //
   // Example:
   //
@@ -298,13 +431,28 @@
   //     return std::find(c.chunk_begin(), c.chunk_end(), s);
   //   }
   ChunkIterator chunk_begin() const;
+
+  // Cord::ChunkItertator::chunk_end()
+  //
   // Returns an iterator one increment past the last chunk of the `Cord`.
+  //
+  // Generally, prefer using `Cord::Chunks()` within a range-based for loop for
+  // iterating over the chunks of a Cord. This method may be useful for getting
+  // a `ChunkIterator` where range-based for-loops may not be available.
   ChunkIterator chunk_end() const;
 
-  // Convenience wrapper over `Cord::chunk_begin()` and `Cord::chunk_end()` to
-  // enable range-based for-loop iteration over `Cord` chunks.
+  //----------------------------------------------------------------------------
+  // Cord::ChunkIterator::ChunkRange
+  //----------------------------------------------------------------------------
   //
-  // Prefer to use `Cord::Chunks()` below instead of constructing this directly.
+  // `ChunkRange` is a helper class for iterating over the chunks of the `Cord`,
+  // producing an iterator which can be used within a range-based for loop.
+  // Construction of a `ChunkRange` will return an iterator pointing to the
+  // first chunk of the Cord. Generally, do not construct a `ChunkRange`
+  // directly; instead, prefer to use the `Cord::Chunks()` method.
+  //
+  // Implementation note: `ChunkRange` is simply a convenience wrapper over
+  // `Cord::chunk_begin()` and `Cord::chunk_end()`.
   class ChunkRange {
    public:
     explicit ChunkRange(const Cord* cord) : cord_(cord) {}
@@ -316,8 +464,11 @@
     const Cord* cord_;
   };
 
-  // Returns a range for iterating over the chunks of a `Cord` with a
-  // range-based for-loop.
+  // Cord::Chunks()
+  //
+  // Returns a `Cord::ChunkIterator::ChunkRange` for iterating over the chunks
+  // of a `Cord` with a range-based for-loop. For most iteration tasks on a
+  // Cord, use `Cord::Chunks()` to retrieve this iterator.
   //
   // Example:
   //
@@ -334,22 +485,30 @@
   //   }
   ChunkRange Chunks() const;
 
-  // Type for iterating over the characters of a `Cord`. See comments for
-  // `Cord::char_begin()`, `Cord::char_end()` and `Cord::Chars()` below for
-  // preferred usage.
+  //----------------------------------------------------------------------------
+  // Cord::CharIterator
+  //----------------------------------------------------------------------------
   //
-  // Additional notes:
-  //   * A `CharIterator` object is invalidated after any non-const
-  //     operation on the `Cord` object over which it iterates.
-  //   * Two `CharIterator` objects can be equality compared if and only if
-  //     they remain valid and iterate over the same `Cord`.
-  //   * The iterator keeps state that can grow for `Cord`s that contain many
+  // A `Cord::CharIterator` allows iteration over the constituent characters of
+  // a `Cord`.
+  //
+  // Generally, you do not instantiate a `Cord::CharIterator` directly; instead,
+  // you create one implicitly through use of the `Cord::Chars()` member
+  // function.
+  //
+  // A `Cord::CharIterator` has the following properties:
+  //
+  //   * The iterator is invalidated after any non-const operation on the
+  //     Cord object over which it iterates.
+  //   * Two `CharIterator` objects can be compared equal if and only if they
+  //     remain valid and iterate over the same Cord.
+  //   * The iterator keeps state that can grow for Cords that contain many
   //     nodes and are imbalanced due to sharing. Prefer to pass this type by
   //     const reference instead of by value.
-  //   * This type cannot be a forward iterator because a `Cord` can reuse
-  //     sections of memory. This violates the requirement that if dereferencing
-  //     two iterators returns the same object, the iterators must compare
-  //     equal.
+  //   * This type cannot act as a forward iterator because a `Cord` can reuse
+  //     sections of memory. This fact violates the requirement for forward
+  //     iterators to compare equal if dereferencing them returns the same
+  //     object.
   class CharIterator {
    public:
     using iterator_category = std::input_iterator_tag;
@@ -375,34 +534,56 @@
     ChunkIterator chunk_iterator_;
   };
 
-  // Advances `*it` by `n_bytes` and returns the bytes passed as a `Cord`.
+  // Cord::CharIterator::AdvanceAndRead()
   //
-  // `n_bytes` must be less than or equal to the number of bytes remaining for
-  // iteration. Otherwise the behavior is undefined. It is valid to pass
-  // `char_end()` and 0.
+  // Advances the `Cord::CharIterator` by `n_bytes` and returns the bytes
+  // advanced as a separate `Cord`. `n_bytes` must be less than or equal to the
+  // number of bytes within the Cord; otherwise, behavior is undefined. It is
+  // valid to pass `char_end()` and `0`.
   static Cord AdvanceAndRead(CharIterator* it, size_t n_bytes);
 
-  // Advances `*it` by `n_bytes`.
+  // Cord::CharIterator::Advance()
   //
-  // `n_bytes` must be less than or equal to the number of bytes remaining for
-  // iteration. Otherwise the behavior is undefined. It is valid to pass
-  // `char_end()` and 0.
+  // Advances the `Cord::CharIterator` by `n_bytes`. `n_bytes` must be less than
+  // or equal to the number of bytes remaining within the Cord; otherwise,
+  // behavior is undefined. It is valid to pass `char_end()` and `0`.
   static void Advance(CharIterator* it, size_t n_bytes);
 
+  // Cord::CharIterator::ChunkRemaining()
+  //
   // Returns the longest contiguous view starting at the iterator's position.
   //
   // `it` must be dereferenceable.
   static absl::string_view ChunkRemaining(const CharIterator& it);
 
+  // Cord::CharIterator::char_begin()
+  //
   // Returns an iterator to the first character of the `Cord`.
+  //
+  // Generally, prefer using `Cord::Chars()` within a range-based for loop for
+  // iterating over the chunks of a Cord. This method may be useful for getting
+  // a `CharIterator` where range-based for-loops may not be available.
   CharIterator char_begin() const;
+
+  // Cord::CharIterator::char_end()
+  //
   // Returns an iterator to one past the last character of the `Cord`.
+  //
+  // Generally, prefer using `Cord::Chars()` within a range-based for loop for
+  // iterating over the chunks of a Cord. This method may be useful for getting
+  // a `CharIterator` where range-based for-loops are not useful.
   CharIterator char_end() const;
 
-  // Convenience wrapper over `Cord::char_begin()` and `Cord::char_end()` to
-  // enable range-based for-loop iterator over the characters of a `Cord`.
+  // Cord::CharIterator::CharRange
   //
-  // Prefer to use `Cord::Chars()` below instead of constructing this directly.
+  // `CharRange` is a helper class for iterating over the characters of a
+  // producing an iterator which can be used within a range-based for loop.
+  // Construction of a `CharRange` will return an iterator pointing to the first
+  // character of the Cord. Generally, do not construct a `CharRange` directly;
+  // instead, prefer to use the `Cord::Chars()` method show below.
+  //
+  // Implementation note: `CharRange` is simply a convenience wrapper over
+  // `Cord::char_begin()` and `Cord::char_end()`.
   class CharRange {
    public:
     explicit CharRange(const Cord* cord) : cord_(cord) {}
@@ -414,8 +595,11 @@
     const Cord* cord_;
   };
 
-  // Returns a range for iterating over the characters of a `Cord` with a
-  // range-based for-loop.
+  // Cord::CharIterator::Chars()
+  //
+  // Returns a `Cord::CharIterator` for iterating over the characters of a
+  // `Cord` with a range-based for-loop. For most character-based iteration
+  // tasks on a Cord, use `Cord::Chars()` to retrieve this iterator.
   //
   // Example:
   //
@@ -432,32 +616,59 @@
   //   }
   CharRange Chars() const;
 
-  // --------------------------------------------------------------------
-  // Miscellaneous
-
-  // Get the "i"th character of 'this' and return it.
-  // NOTE: This routine is reasonably efficient.  It is roughly
-  // logarithmic in the number of nodes that make up the cord.  Still,
-  // if you need to iterate over the contents of a cord, you should
-  // use a CharIterator/CordIterator rather than call operator[] or Get()
-  //  repeatedly in a loop.
+  // Cord::operator[]
   //
-  // REQUIRES: 0 <= i < size()
+  // Gets the "i"th character of the Cord and returns it, provided that
+  // 0 <= i < Cord.size().
+  //
+  // 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()
+  // repeatedly in a loop.
   char operator[](size_t i) const;
 
+  // Cord::TryFlat()
+  //
+  // If this cord's representation is a single flat array, returns a
+  // string_view referencing that array.  Otherwise returns nullopt.
+  absl::optional<absl::string_view> TryFlat() const;
+
+  // Cord::Flatten()
+  //
   // Flattens the cord into a single array and returns a view of the data.
   //
   // If the cord was already flat, the contents are not modified.
   absl::string_view Flatten();
 
+  // Supports absl::Cord as a sink object for absl::Format().
+  friend void AbslFormatFlush(absl::Cord* cord, absl::string_view part) {
+    cord->Append(part);
+  }
+
+  template <typename H>
+  friend H AbslHashValue(H hash_state, const absl::Cord& c) {
+    absl::optional<absl::string_view> maybe_flat = c.TryFlat();
+    if (maybe_flat.has_value()) {
+      return H::combine(std::move(hash_state), *maybe_flat);
+    }
+    return c.HashFragmented(std::move(hash_state));
+  }
+
+  // Create a Cord with the contents of StringConstant<T>::value.
+  // No allocations will be done and no data will be copied.
+  // This is an INTERNAL API and subject to change or removal. This API can only
+  // be used by spelling absl::strings_internal::MakeStringConstant, which is
+  // also an internal API.
+  template <typename T>
+  explicit constexpr Cord(strings_internal::StringConstant<T>);
+
  private:
   friend class CordTestPeer;
-  template <typename H>
-  friend H absl::hash_internal::HashFragmentedCord(H, const Cord&);
   friend bool operator==(const Cord& lhs, const Cord& rhs);
   friend bool operator==(const Cord& lhs, absl::string_view rhs);
 
-  // Call the provided function once for each cord chunk, in order.  Unlike
+  // Calls the provided function once for each cord chunk, in order.  Unlike
   // Chunks(), this API will not allocate memory.
   void ForEachChunk(absl::FunctionRef<void(absl::string_view)>) const;
 
@@ -469,23 +680,20 @@
   // class so that we can isolate the bulk of cord.cc from changes
   // to the representation.
   //
-  // InlineRep holds either either a tree pointer, or an array of kMaxInline
-  // bytes.
+  // InlineRep holds either a tree pointer, or an array of kMaxInline bytes.
   class InlineRep {
    public:
-    static const unsigned char kMaxInline = 15;
+    static constexpr unsigned char kMaxInline = cord_internal::kMaxInline;
     static_assert(kMaxInline >= sizeof(absl::cord_internal::CordRep*), "");
-    // Tag byte & kMaxInline means we are storing a pointer.
-    static const unsigned char kTreeFlag = 1 << 4;
-    // Tag byte & kProfiledFlag means we are profiling the Cord.
-    static const unsigned char kProfiledFlag = 1 << 5;
 
-    constexpr InlineRep() : data_{} {}
+    constexpr InlineRep() : data_() {}
     InlineRep(const InlineRep& src);
     InlineRep(InlineRep&& src);
     InlineRep& operator=(const InlineRep& src);
     InlineRep& operator=(InlineRep&& src) noexcept;
 
+    explicit constexpr InlineRep(cord_internal::InlineData data);
+
     void Swap(InlineRep* rhs);
     bool empty() const;
     size_t size() const;
@@ -495,6 +703,7 @@
     char* set_data(size_t n);  // Write data to the result
     // Returns nullptr if holding bytes
     absl::cord_internal::CordRep* tree() const;
+    absl::cord_internal::CordRep* as_tree() const;
     // Discards old pointer, if any
     void set_tree(absl::cord_internal::CordRep* rep);
     // Replaces a tree with a new root. This is faster than set_tree, but it
@@ -502,7 +711,7 @@
     void replace_tree(absl::cord_internal::CordRep* rep);
     // Returns non-null iff was holding a pointer
     absl::cord_internal::CordRep* clear();
-    // Convert to pointer if necessary
+    // Converts to pointer if necessary.
     absl::cord_internal::CordRep* force_tree(size_t extra_hint);
     void reduce_size(size_t n);  // REQUIRES: holding data
     void remove_prefix(size_t n);  // REQUIRES: holding data
@@ -513,16 +722,16 @@
     void GetAppendRegion(char** region, size_t* size, size_t max_length);
     void GetAppendRegion(char** region, size_t* size);
     bool IsSame(const InlineRep& other) const {
-      return memcmp(data_, other.data_, sizeof(data_)) == 0;
+      return memcmp(&data_, &other.data_, sizeof(data_)) == 0;
     }
     int BitwiseCompare(const InlineRep& other) const {
       uint64_t x, y;
-      // Use memcpy to avoid anti-aliasing issues.
-      memcpy(&x, data_, sizeof(x));
-      memcpy(&y, other.data_, sizeof(y));
+      // Use memcpy to avoid aliasing issues.
+      memcpy(&x, &data_, sizeof(x));
+      memcpy(&y, &other.data_, sizeof(y));
       if (x == y) {
-        memcpy(&x, data_ + 8, sizeof(x));
-        memcpy(&y, other.data_ + 8, sizeof(y));
+        memcpy(&x, reinterpret_cast<const char*>(&data_) + 8, sizeof(x));
+        memcpy(&y, reinterpret_cast<const char*>(&other.data_) + 8, sizeof(y));
         if (x == y) return 0;
       }
       return absl::big_endian::FromHost64(x) < absl::big_endian::FromHost64(y)
@@ -531,20 +740,37 @@
     }
     void CopyTo(std::string* dst) const {
       // memcpy is much faster when operating on a known size. On most supported
-      // platforms, the small std::string optimization is large enough that resizing
+      // platforms, the small string optimization is large enough that resizing
       // to 15 bytes does not cause a memory allocation.
       absl::strings_internal::STLStringResizeUninitialized(dst,
                                                            sizeof(data_) - 1);
-      memcpy(&(*dst)[0], data_, sizeof(data_) - 1);
+      memcpy(&(*dst)[0], &data_, sizeof(data_) - 1);
       // erase is faster than resize because the logic for memory allocation is
       // not needed.
-      dst->erase(data_[kMaxInline]);
+      dst->erase(inline_size());
     }
 
     // Copies the inline contents into `dst`. Assumes the cord is not empty.
     void CopyToArray(char* dst) const;
 
-    bool is_tree() const { return data_[kMaxInline] > kMaxInline; }
+    bool is_tree() const { return data_.is_tree(); }
+
+    // Returns true if the Cord is being profiled by cordz.
+    bool is_profiled() const { return data_.is_tree() && data_.is_profiled(); }
+
+    // Returns the profiled CordzInfo, or nullptr if not sampled.
+    absl::cord_internal::CordzInfo* cordz_info() const {
+      return data_.cordz_info();
+    }
+
+    // Sets the profiled CordzInfo. `cordz_info` must not be null.
+    void set_cordz_info(cord_internal::CordzInfo* cordz_info) {
+      assert(cordz_info != nullptr);
+      data_.set_cordz_info(cordz_info);
+    }
+
+    // Resets the current cordz_info to null / empty.
+    void clear_cordz_info() { data_.clear_cordz_info(); }
 
    private:
     friend class Cord;
@@ -553,21 +779,23 @@
     // Unrefs the tree, stops profiling, and zeroes the contents
     void ClearSlow();
 
-    // If the data has length <= kMaxInline, we store it in data_[0..len-1],
-    // and store the length in data_[kMaxInline].  Else we store it in a tree
-    // and store a pointer to that tree in data_[0..sizeof(CordRep*)-1].
-    alignas(absl::cord_internal::CordRep*) char data_[kMaxInline + 1];
+    void ResetToEmpty() { data_ = {}; }
+
+    void set_inline_size(size_t size) { data_.set_inline_size(size); }
+    size_t inline_size() const { return data_.inline_size(); }
+
+    cord_internal::InlineData data_;
   };
   InlineRep contents_;
 
-  // Helper for MemoryUsage()
+  // Helper for MemoryUsage().
   static size_t MemoryUsageAux(const absl::cord_internal::CordRep* rep);
 
-  // Helper for GetFlat()
+  // Helper for GetFlat() and TryFlat().
   static bool GetFlatAux(absl::cord_internal::CordRep* rep,
                          absl::string_view* fragment);
 
-  // Helper for ForEachChunk()
+  // Helper for ForEachChunk().
   static void ForEachChunkAux(
       absl::cord_internal::CordRep* rep,
       absl::FunctionRef<void(absl::string_view)> callback);
@@ -596,9 +824,20 @@
   absl::cord_internal::CordRep* TakeRep() const&;
   absl::cord_internal::CordRep* TakeRep() &&;
 
-  // Helper for Append()
+  // Helper for Append().
   template <typename C>
   void AppendImpl(C&& src);
+
+  // Helper for AbslHashValue().
+  template <typename H>
+  H HashFragmented(H hash_state) const {
+    typename H::AbslInternalPiecewiseCombiner combiner;
+    ForEachChunk([&combiner, &hash_state](absl::string_view chunk) {
+      hash_state = combiner.add_buffer(std::move(hash_state), chunk.data(),
+                                       chunk.size());
+    });
+    return H::combine(combiner.finalize(std::move(hash_state)), size());
+  }
 };
 
 ABSL_NAMESPACE_END
@@ -655,52 +894,27 @@
   }
 }
 
-struct ExternalRepReleaserPair {
-  CordRep* rep;
-  void* releaser_address;
-};
-
-// Allocates a new external `CordRep` and returns a pointer to it and a pointer
-// to `releaser_size` bytes where the desired releaser can be constructed.
+// Does non-template-specific `CordRepExternal` initialization.
 // Expects `data` to be non-empty.
-ExternalRepReleaserPair NewExternalWithUninitializedReleaser(
-    absl::string_view data, ExternalReleaserInvoker invoker,
-    size_t releaser_size);
+void InitializeCordRepExternal(absl::string_view data, CordRepExternal* rep);
 
 // Creates a new `CordRep` that owns `data` and `releaser` and returns a pointer
 // to it, or `nullptr` if `data` was empty.
 template <typename Releaser>
 // NOLINTNEXTLINE - suppress clang-tidy raw pointer return.
 CordRep* NewExternalRep(absl::string_view data, Releaser&& releaser) {
-  static_assert(
-#if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__)
-      alignof(Releaser) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__,
-#else
-      alignof(Releaser) <= alignof(max_align_t),
-#endif
-      "Releasers with alignment requirement greater than what is returned by "
-      "default `::operator new()` are not supported.");
-
   using ReleaserType = absl::decay_t<Releaser>;
   if (data.empty()) {
     // Never create empty external nodes.
-    ::absl::base_internal::Invoke(
-        ReleaserType(std::forward<Releaser>(releaser)), data);
+    InvokeReleaser(Rank0{}, ReleaserType(std::forward<Releaser>(releaser)),
+                   data);
     return nullptr;
   }
 
-  auto releaser_invoker = [](void* type_erased_releaser, absl::string_view d) {
-    auto* my_releaser = static_cast<ReleaserType*>(type_erased_releaser);
-    ::absl::base_internal::Invoke(std::move(*my_releaser), d);
-    my_releaser->~ReleaserType();
-    return sizeof(Releaser);
-  };
-
-  ExternalRepReleaserPair external = NewExternalWithUninitializedReleaser(
-      data, releaser_invoker, sizeof(releaser));
-  ::new (external.releaser_address)
-      ReleaserType(std::forward<Releaser>(releaser));
-  return external.rep;
+  CordRepExternal* rep = new CordRepExternalImpl<ReleaserType>(
+      std::forward<Releaser>(releaser), 0);
+  InitializeCordRepExternal(data, rep);
+  return rep;
 }
 
 // Overload for function reference types that dispatches using a function
@@ -721,13 +935,20 @@
   return cord;
 }
 
-inline Cord::InlineRep::InlineRep(const Cord::InlineRep& src) {
-  cord_internal::SmallMemmove(data_, src.data_, sizeof(data_));
+constexpr Cord::InlineRep::InlineRep(cord_internal::InlineData data)
+    : data_(data) {}
+
+inline Cord::InlineRep::InlineRep(const Cord::InlineRep& src)
+    : data_(src.data_) {
+  if (is_tree()) {
+    data_.clear_cordz_info();
+    absl::cord_internal::CordRep::Ref(as_tree());
+  }
 }
 
 inline Cord::InlineRep::InlineRep(Cord::InlineRep&& src) {
-  memcpy(data_, src.data_, sizeof(data_));
-  memset(src.data_, 0, sizeof(data_));
+  data_ = src.data_;
+  src.ResetToEmpty();
 }
 
 inline Cord::InlineRep& Cord::InlineRep::operator=(const Cord::InlineRep& src) {
@@ -735,7 +956,7 @@
     return *this;
   }
   if (!is_tree() && !src.is_tree()) {
-    cord_internal::SmallMemmove(data_, src.data_, sizeof(data_));
+    data_ = src.data_;
     return *this;
   }
   AssignSlow(src);
@@ -747,8 +968,8 @@
   if (is_tree()) {
     ClearSlow();
   }
-  memcpy(data_, src.data_, sizeof(data_));
-  memset(src.data_, 0, sizeof(data_));
+  data_ = src.data_;
+  src.ResetToEmpty();
   return *this;
 }
 
@@ -756,44 +977,43 @@
   if (rhs == this) {
     return;
   }
-
-  Cord::InlineRep tmp;
-  cord_internal::SmallMemmove(tmp.data_, data_, sizeof(data_));
-  cord_internal::SmallMemmove(data_, rhs->data_, sizeof(data_));
-  cord_internal::SmallMemmove(rhs->data_, tmp.data_, sizeof(data_));
+  std::swap(data_, rhs->data_);
 }
 
 inline const char* Cord::InlineRep::data() const {
-  return is_tree() ? nullptr : data_;
+  return is_tree() ? nullptr : data_.as_chars();
+}
+
+inline absl::cord_internal::CordRep* Cord::InlineRep::as_tree() const {
+  assert(data_.is_tree());
+  return data_.as_tree();
 }
 
 inline absl::cord_internal::CordRep* Cord::InlineRep::tree() const {
   if (is_tree()) {
-    absl::cord_internal::CordRep* rep;
-    memcpy(&rep, data_, sizeof(rep));
-    return rep;
+    return as_tree();
   } else {
     return nullptr;
   }
 }
 
-inline bool Cord::InlineRep::empty() const { return data_[kMaxInline] == 0; }
+inline bool Cord::InlineRep::empty() const { return data_.is_empty(); }
 
 inline size_t Cord::InlineRep::size() const {
-  const char tag = data_[kMaxInline];
-  if (tag <= kMaxInline) return tag;
-  return static_cast<size_t>(tree()->length);
+  return is_tree() ? as_tree()->length : inline_size();
 }
 
 inline void Cord::InlineRep::set_tree(absl::cord_internal::CordRep* rep) {
   if (rep == nullptr) {
-    memset(data_, 0, sizeof(data_));
+    ResetToEmpty();
   } else {
-    bool was_tree = is_tree();
-    memcpy(data_, &rep, sizeof(rep));
-    memset(data_ + sizeof(rep), 0, sizeof(data_) - sizeof(rep) - 1);
-    if (!was_tree) {
-      data_[kMaxInline] = kTreeFlag;
+    if (data_.is_tree()) {
+      // `data_` already holds a 'tree' value and an optional cordz_info value.
+      // Replace the tree value only, leaving the cordz_info value unchanged.
+      data_.set_tree(rep);
+    } else {
+      // `data_` contains inlined data: initialize data_ to tree value `rep`.
+      data_.make_tree(rep);
     }
   }
 }
@@ -804,46 +1024,54 @@
     set_tree(rep);
     return;
   }
-  memcpy(data_, &rep, sizeof(rep));
-  memset(data_ + sizeof(rep), 0, sizeof(data_) - sizeof(rep) - 1);
+  data_.set_tree(rep);
 }
 
 inline absl::cord_internal::CordRep* Cord::InlineRep::clear() {
-  const char tag = data_[kMaxInline];
-  absl::cord_internal::CordRep* result = nullptr;
-  if (tag > kMaxInline) {
-    memcpy(&result, data_, sizeof(result));
-  }
-  memset(data_, 0, sizeof(data_));  // Clear the cord
+  absl::cord_internal::CordRep* result = tree();
+  ResetToEmpty();
   return result;
 }
 
 inline void Cord::InlineRep::CopyToArray(char* dst) const {
   assert(!is_tree());
-  size_t n = data_[kMaxInline];
+  size_t n = inline_size();
   assert(n != 0);
-  cord_internal::SmallMemmove(dst, data_, n);
+  cord_internal::SmallMemmove(dst, data_.as_chars(), n);
 }
 
 constexpr inline Cord::Cord() noexcept {}
 
+template <typename T>
+constexpr Cord::Cord(strings_internal::StringConstant<T>)
+    : contents_(strings_internal::StringConstant<T>::value.size() <=
+                        cord_internal::kMaxInline
+                    ? cord_internal::InlineData(
+                          strings_internal::StringConstant<T>::value)
+                    : cord_internal::InlineData(
+                          &cord_internal::ConstInitExternalStorage<
+                              strings_internal::StringConstant<T>>::value)) {}
+
 inline Cord& Cord::operator=(const Cord& x) {
   contents_ = x.contents_;
   return *this;
 }
 
+inline Cord::Cord(const Cord& src) : contents_(src.contents_) {}
+
 inline Cord::Cord(Cord&& src) noexcept : contents_(std::move(src.contents_)) {}
 
+inline void Cord::swap(Cord& other) noexcept {
+  contents_.Swap(&other.contents_);
+}
+
 inline Cord& Cord::operator=(Cord&& x) noexcept {
   contents_ = std::move(x.contents_);
   return *this;
 }
 
-template <typename T, Cord::EnableIfString<T>>
-inline Cord& Cord::operator=(T&& src) {
-  *this = absl::string_view(src);
-  return *this;
-}
+extern template Cord::Cord(std::string&& src);
+extern template Cord& Cord::operator=(std::string&& src);
 
 inline size_t Cord::size() const {
   // Length is 1st field in str.rep_
@@ -860,6 +1088,18 @@
   return result;
 }
 
+inline absl::optional<absl::string_view> Cord::TryFlat() const {
+  absl::cord_internal::CordRep* rep = contents_.tree();
+  if (rep == nullptr) {
+    return absl::string_view(contents_.data(), contents_.size());
+  }
+  absl::string_view fragment;
+  if (GetFlatAux(rep, &fragment)) {
+    return fragment;
+  }
+  return absl::nullopt;
+}
+
 inline absl::string_view Cord::Flatten() {
   absl::cord_internal::CordRep* rep = contents_.tree();
   if (rep == nullptr) {
@@ -877,19 +1117,8 @@
   contents_.AppendArray(src.data(), src.size());
 }
 
-template <typename T, Cord::EnableIfString<T>>
-inline void Cord::Append(T&& src) {
-  // Note that this function reserves the right to reuse the `string&&`'s
-  // memory and that it will do so in the future.
-  Append(absl::string_view(src));
-}
-
-template <typename T, Cord::EnableIfString<T>>
-inline void Cord::Prepend(T&& src) {
-  // Note that this function reserves the right to reuse the `string&&`'s
-  // memory and that it will do so in the future.
-  Prepend(absl::string_view(src));
-}
+extern template void Cord::Append(std::string&& src);
+extern template void Cord::Prepend(std::string&& src);
 
 inline int Cord::Compare(const Cord& rhs) const {
   if (!contents_.is_tree() && !rhs.contents_.is_tree()) {
@@ -913,17 +1142,64 @@
   return EqualsImpl(rhs, rhs_size);
 }
 
+inline void Cord::ChunkIterator::InitTree(cord_internal::CordRep* tree) {
+  if (tree->tag == cord_internal::RING) {
+    current_chunk_ = ring_reader_.Reset(tree->ring());
+    return;
+  }
+
+  stack_of_right_children_.push_back(tree);
+  operator++();
+}
+
+inline Cord::ChunkIterator::ChunkIterator(cord_internal::CordRep* tree)
+    : bytes_remaining_(tree->length) {
+  InitTree(tree);
+}
+
 inline Cord::ChunkIterator::ChunkIterator(const Cord* cord)
     : bytes_remaining_(cord->size()) {
-  if (cord->empty()) return;
   if (cord->contents_.is_tree()) {
-    stack_of_right_children_.push_back(cord->contents_.tree());
-    operator++();
+    InitTree(cord->contents_.as_tree());
   } else {
-    current_chunk_ = absl::string_view(cord->contents_.data(), cord->size());
+    current_chunk_ =
+        absl::string_view(cord->contents_.data(), bytes_remaining_);
   }
 }
 
+inline Cord::ChunkIterator& Cord::ChunkIterator::AdvanceRing() {
+  current_chunk_ = ring_reader_.Next();
+  return *this;
+}
+
+inline void Cord::ChunkIterator::AdvanceBytesRing(size_t n) {
+  assert(n >= current_chunk_.size());
+  bytes_remaining_ -= n;
+  if (bytes_remaining_) {
+    if (n == current_chunk_.size()) {
+      current_chunk_ = ring_reader_.Next();
+    } else {
+      size_t offset = ring_reader_.length() - bytes_remaining_;
+      current_chunk_ = ring_reader_.Seek(offset);
+    }
+  } else {
+    current_chunk_ = {};
+  }
+}
+
+inline Cord::ChunkIterator& Cord::ChunkIterator::operator++() {
+  ABSL_HARDENING_ASSERT(bytes_remaining_ > 0 &&
+                        "Attempted to iterate past `end()`");
+  assert(bytes_remaining_ >= current_chunk_.size());
+  bytes_remaining_ -= current_chunk_.size();
+  if (bytes_remaining_ > 0) {
+    return ring_reader_ ? AdvanceRing() : AdvanceStack();
+  } else {
+    current_chunk_ = {};
+  }
+  return *this;
+}
+
 inline Cord::ChunkIterator Cord::ChunkIterator::operator++(int) {
   ChunkIterator tmp(*this);
   operator++();
@@ -939,12 +1215,12 @@
 }
 
 inline Cord::ChunkIterator::reference Cord::ChunkIterator::operator*() const {
-  assert(bytes_remaining_ != 0);
+  ABSL_HARDENING_ASSERT(bytes_remaining_ != 0);
   return current_chunk_;
 }
 
 inline Cord::ChunkIterator::pointer Cord::ChunkIterator::operator->() const {
-  assert(bytes_remaining_ != 0);
+  ABSL_HARDENING_ASSERT(bytes_remaining_ != 0);
   return &current_chunk_;
 }
 
@@ -955,10 +1231,11 @@
 }
 
 inline void Cord::ChunkIterator::AdvanceBytes(size_t n) {
+  assert(bytes_remaining_ >= n);
   if (ABSL_PREDICT_TRUE(n < current_chunk_.size())) {
     RemoveChunkPrefix(n);
   } else if (n != 0) {
-    AdvanceBytesSlowPath(n);
+    ring_reader_ ? AdvanceBytesRing(n) : AdvanceBytesSlowPath(n);
   }
 }
 
@@ -1098,10 +1375,6 @@
 inline bool operator>=(const Cord& x, absl::string_view y) { return !(x < y); }
 inline bool operator>=(absl::string_view x, const Cord& y) { return !(x < y); }
 
-// Overload of swap for Cord. The use of non-const references is
-// required. :(
-inline void swap(Cord& x, Cord& y) noexcept { y.contents_.Swap(&x.contents_); }
-
 // Some internals exposed to test code.
 namespace strings_internal {
 class CordTestAccess {
diff --git a/absl/strings/cord_ring_reader_test.cc b/absl/strings/cord_ring_reader_test.cc
new file mode 100644
index 0000000..585616f
--- /dev/null
+++ b/absl/strings/cord_ring_reader_test.cc
@@ -0,0 +1,173 @@
+// 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 <cstdlib>
+#include <ctime>
+#include <memory>
+#include <random>
+#include <sstream>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/debugging/leak_check.h"
+#include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_ring.h"
+#include "absl/strings/internal/cord_rep_ring_reader.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+namespace {
+
+using testing::Eq;
+
+// Creates a flat for testing
+CordRep* MakeFlat(absl::string_view s) {
+  CordRepFlat* flat = CordRepFlat::New(s.length());
+  memcpy(flat->Data(), s.data(), s.length());
+  flat->length = s.length();
+  return flat;
+}
+
+CordRepRing* FromFlats(Span<absl::string_view const> flats) {
+  CordRepRing* ring = CordRepRing::Create(MakeFlat(flats[0]), flats.size() - 1);
+  for (int i = 1; i < flats.size(); ++i) {
+    ring = CordRepRing::Append(ring, MakeFlat(flats[i]));
+  }
+  return ring;
+}
+
+std::array<absl::string_view, 12> TestFlats() {
+  return {"abcdefghij", "klmnopqrst", "uvwxyz",     "ABCDEFGHIJ",
+          "KLMNOPQRST", "UVWXYZ",     "1234567890", "~!@#$%^&*()_",
+          "+-=",        "[]\\{}|;':", ",/<>?",      "."};
+}
+
+TEST(CordRingReaderTest, DefaultInstance) {
+  CordRepRingReader reader;
+  EXPECT_FALSE(static_cast<bool>(reader));
+  EXPECT_THAT(reader.ring(), Eq(nullptr));
+#ifndef NDEBUG
+  EXPECT_DEATH_IF_SUPPORTED(reader.length(), ".*");
+  EXPECT_DEATH_IF_SUPPORTED(reader.consumed(), ".*");
+  EXPECT_DEATH_IF_SUPPORTED(reader.remaining(), ".*");
+  EXPECT_DEATH_IF_SUPPORTED(reader.Next(), ".*");
+  EXPECT_DEATH_IF_SUPPORTED(reader.Seek(0), ".*");
+#endif
+}
+
+TEST(CordRingReaderTest, Reset) {
+  CordRepRingReader reader;
+  auto flats = TestFlats();
+  CordRepRing* ring = FromFlats(flats);
+
+  absl::string_view first = reader.Reset(ring);
+  EXPECT_THAT(first, Eq(flats[0]));
+  EXPECT_TRUE(static_cast<bool>(reader));
+  EXPECT_THAT(reader.ring(), Eq(ring));
+  EXPECT_THAT(reader.index(), Eq(ring->head()));
+  EXPECT_THAT(reader.length(), Eq(ring->length));
+  EXPECT_THAT(reader.consumed(), Eq(flats[0].length()));
+  EXPECT_THAT(reader.remaining(), Eq(ring->length - reader.consumed()));
+
+  reader.Reset();
+  EXPECT_FALSE(static_cast<bool>(reader));
+  EXPECT_THAT(reader.ring(), Eq(nullptr));
+
+  CordRep::Unref(ring);
+}
+
+TEST(CordRingReaderTest, Next) {
+  CordRepRingReader reader;
+  auto flats = TestFlats();
+  CordRepRing* ring = FromFlats(flats);
+  CordRepRing::index_type head = ring->head();
+
+  reader.Reset(ring);
+  size_t consumed = reader.consumed();
+  size_t remaining = reader.remaining();
+  for (int i = 1; i < flats.size(); ++i) {
+    consumed += flats[i].length();
+    remaining -= flats[i].length();
+    absl::string_view next = reader.Next();
+    ASSERT_THAT(next, Eq(flats[i]));
+    ASSERT_THAT(reader.index(), Eq(ring->advance(head, i)));
+    ASSERT_THAT(reader.consumed(), Eq(consumed));
+    ASSERT_THAT(reader.remaining(), Eq(remaining));
+  }
+
+#ifndef NDEBUG
+  EXPECT_DEATH_IF_SUPPORTED(reader.Next(), ".*");
+#endif
+
+  CordRep::Unref(ring);
+}
+
+TEST(CordRingReaderTest, SeekForward) {
+  CordRepRingReader reader;
+  auto flats = TestFlats();
+  CordRepRing* ring = FromFlats(flats);
+  CordRepRing::index_type head = ring->head();
+
+  reader.Reset(ring);
+  size_t consumed = 0;
+  size_t remaining = ring->length;;
+  for (int i = 0; i < flats.size(); ++i) {
+    size_t offset = consumed;
+    consumed += flats[i].length();
+    remaining -= flats[i].length();
+    for (int off = 0; off < flats[i].length(); ++off) {
+      absl::string_view chunk = reader.Seek(offset + off);
+      ASSERT_THAT(chunk, Eq(flats[i].substr(off)));
+      ASSERT_THAT(reader.index(), Eq(ring->advance(head, i)));
+      ASSERT_THAT(reader.consumed(), Eq(consumed));
+      ASSERT_THAT(reader.remaining(), Eq(remaining));
+    }
+  }
+
+  CordRep::Unref(ring);
+}
+
+TEST(CordRingReaderTest, SeekBackward) {
+  CordRepRingReader reader;
+  auto flats = TestFlats();
+  CordRepRing* ring = FromFlats(flats);
+  CordRepRing::index_type head = ring->head();
+
+  reader.Reset(ring);
+  size_t consumed = ring->length;
+  size_t remaining = 0;
+  for (int i = flats.size() - 1; i >= 0; --i) {
+    size_t offset = consumed - flats[i].length();
+    for (int off = 0; off < flats[i].length(); ++off) {
+      absl::string_view chunk = reader.Seek(offset + off);
+      ASSERT_THAT(chunk, Eq(flats[i].substr(off)));
+      ASSERT_THAT(reader.index(), Eq(ring->advance(head, i)));
+      ASSERT_THAT(reader.consumed(), Eq(consumed));
+      ASSERT_THAT(reader.remaining(), Eq(remaining));
+    }
+    consumed -= flats[i].length();
+    remaining += flats[i].length();
+  }
+#ifndef NDEBUG
+  EXPECT_DEATH_IF_SUPPORTED(reader.Seek(ring->length), ".*");
+#endif
+  CordRep::Unref(ring);
+}
+
+}  // namespace
+}  // namespace cord_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/strings/cord_ring_test.cc b/absl/strings/cord_ring_test.cc
new file mode 100644
index 0000000..7d75e10
--- /dev/null
+++ b/absl/strings/cord_ring_test.cc
@@ -0,0 +1,1572 @@
+// 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 <cstdlib>
+#include <ctime>
+#include <memory>
+#include <random>
+#include <sstream>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
+#include "absl/debugging/leak_check.h"
+#include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_ring.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+
+extern thread_local bool cord_ring;
+
+// TOOD(b/177688959): weird things happened with the original test
+#define ASAN_BUG_177688959_FIXED false
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace {
+
+using RandomEngine = std::mt19937_64;
+
+using ::absl::cord_internal::CordRep;
+using ::absl::cord_internal::CordRepConcat;
+using ::absl::cord_internal::CordRepExternal;
+using ::absl::cord_internal::CordRepFlat;
+using ::absl::cord_internal::CordRepRing;
+using ::absl::cord_internal::CordRepSubstring;
+
+using ::absl::cord_internal::CONCAT;
+using ::absl::cord_internal::EXTERNAL;
+using ::absl::cord_internal::SUBSTRING;
+
+using testing::ElementsAre;
+using testing::ElementsAreArray;
+using testing::Eq;
+using testing::Ge;
+using testing::Le;
+using testing::Lt;
+using testing::Ne;
+using testing::SizeIs;
+
+using index_type = CordRepRing::index_type;
+
+enum InputShareMode { kPrivate, kShared, kSharedIndirect };
+
+// TestParam class used by all test fixtures.
+// Not all fixtures use all possible input combinations
+struct TestParam {
+  TestParam() = default;
+  explicit TestParam(InputShareMode input_share_mode)
+      : input_share_mode(input_share_mode) {}
+
+  // Run the test with the 'rep under test' to be privately owned.
+  // Otherwise, the rep has a shared ref count of 2 or higher.
+  bool refcount_is_one = true;
+
+  // Run the test with the 'rep under test' being allocated with enough capacity
+  // to accommodate any modifications made to it. Otherwise, the rep has zero
+  // extra (reserve) capacity.
+  bool with_capacity = true;
+
+  // For test providing possibly shared input such as Append(.., CordpRep*),
+  // this field defines if that input is adopted with a refcount of one
+  // (privately owned / donated), or shared. For composite inputs such as
+  // 'substring of flat', we also have the 'shared indirect' value which means
+  // the top level node is not shared, but the contained child node is shared.
+  InputShareMode input_share_mode = kPrivate;
+
+  std::string ToString() const {
+    return absl::StrCat(refcount_is_one ? "Private" : "Shared",
+                        with_capacity ? "" : "_NoCapacity",
+                        (input_share_mode == kPrivate) ? ""
+                        : (input_share_mode == kShared)
+                            ? "_SharedInput"
+                            : "_IndirectSharedInput");
+  }
+};
+using TestParams = std::vector<TestParam>;
+
+// Matcher validating when mutable copies are required / performed.
+MATCHER_P2(EqIfPrivate, param, rep,
+           absl::StrCat("Equal 0x", absl::Hex(rep), " if private")) {
+  return param.refcount_is_one ? arg == rep : arg != rep;
+}
+
+// Matcher validating when mutable copies are required / performed.
+MATCHER_P2(EqIfPrivateAndCapacity, param, rep,
+           absl::StrCat("Equal 0x", absl::Hex(rep),
+                        " if private and capacity")) {
+  return (param.refcount_is_one && param.with_capacity) ? arg == rep
+                                                        : arg != rep;
+}
+
+MATCHER_P2(EqIfInputPrivate, param, rep, "Equal if input is private") {
+  return param.input_share_mode == kPrivate ? arg == rep : arg != rep;
+}
+
+// Matcher validating the core in-variants of the CordRepRing instance.
+MATCHER(IsValidRingBuffer, "RingBuffer is valid") {
+  std::stringstream ss;
+  if (!arg->IsValid(ss)) {
+    *result_listener << "\nERROR: " << ss.str() << "\nRING = " << *arg;
+    return false;
+  }
+  return true;
+}
+
+// Returns the flats contained in the provided CordRepRing
+std::vector<string_view> ToFlats(const CordRepRing* r) {
+  std::vector<string_view> flats;
+  flats.reserve(r->entries());
+  index_type pos = r->head();
+  do {
+    flats.push_back(r->entry_data(pos));
+  } while ((pos = r->advance(pos)) != r->tail());
+  return flats;
+}
+
+class not_a_string_view {
+ public:
+  explicit not_a_string_view(absl::string_view s)
+      : data_(s.data()), size_(s.size()) {}
+  explicit not_a_string_view(const void* data, size_t size)
+      : data_(data), size_(size) {}
+
+  not_a_string_view remove_prefix(size_t n) const {
+    return not_a_string_view(static_cast<const char*>(data_) + n, size_ - n);
+  }
+
+  not_a_string_view remove_suffix(size_t n) const {
+    return not_a_string_view(data_, size_ - n);
+  }
+
+  const void* data() const { return data_; }
+  size_t size() const { return size_; }
+
+ private:
+  const void* data_;
+  size_t size_;
+};
+
+bool operator==(not_a_string_view lhs, not_a_string_view rhs) {
+  return lhs.data() == rhs.data() && lhs.size() == rhs.size();
+}
+
+std::ostream& operator<<(std::ostream& s, not_a_string_view rhs) {
+  return s << "{ data: " << rhs.data() << " size: " << rhs.size() << "}";
+}
+
+std::vector<not_a_string_view> ToRawFlats(const CordRepRing* r) {
+  std::vector<not_a_string_view> flats;
+  flats.reserve(r->entries());
+  index_type pos = r->head();
+  do {
+    flats.emplace_back(r->entry_data(pos));
+  } while ((pos = r->advance(pos)) != r->tail());
+  return flats;
+}
+
+// Returns the value contained in the provided CordRepRing
+std::string ToString(const CordRepRing* r) {
+  std::string value;
+  value.reserve(r->length);
+  index_type pos = r->head();
+  do {
+    absl::string_view sv = r->entry_data(pos);
+    value.append(sv.data(), sv.size());
+  } while ((pos = r->advance(pos)) != r->tail());
+  return value;
+}
+
+// Creates a flat for testing
+CordRep* MakeFlat(absl::string_view s, size_t extra = 0) {
+  CordRepFlat* flat = CordRepFlat::New(s.length() + extra);
+  memcpy(flat->Data(), s.data(), s.length());
+  flat->length = s.length();
+  return flat;
+}
+
+// Creates an external node for testing
+CordRepExternal* MakeExternal(absl::string_view s) {
+  struct Rep : public CordRepExternal {
+    std::string s;
+    explicit Rep(absl::string_view s) : s(s) {
+      this->tag = EXTERNAL;
+      this->base = s.data();
+      this->length = s.length();
+      this->releaser_invoker = [](CordRepExternal* self) {
+        delete static_cast<Rep*>(self);
+      };
+    }
+  };
+  return new Rep(s);
+}
+
+CordRepExternal* MakeFakeExternal(size_t length) {
+  struct Rep : public CordRepExternal {
+    std::string s;
+    explicit Rep(size_t len) {
+      this->tag = EXTERNAL;
+      this->base = this->storage;
+      this->length = len;
+      this->releaser_invoker = [](CordRepExternal* self) {
+        delete static_cast<Rep*>(self);
+      };
+    }
+  };
+  return new Rep(length);
+}
+
+// Creates a flat or an external node for testing depending on the size.
+CordRep* MakeLeaf(absl::string_view s, size_t extra = 0) {
+  if (s.size() <= absl::cord_internal::kMaxFlatLength) {
+    return MakeFlat(s, extra);
+  } else {
+    return MakeExternal(s);
+  }
+}
+
+// Creates a substring node
+CordRepSubstring* MakeSubstring(size_t start, size_t len, CordRep* rep) {
+  auto* sub = new CordRepSubstring;
+  sub->tag = SUBSTRING;
+  sub->start = start;
+  sub->length = (len <= 0) ? rep->length - start + len : len;
+  sub->child = rep;
+  return sub;
+}
+
+// Creates a substring node removing the specified prefix
+CordRepSubstring* RemovePrefix(size_t start, CordRep* rep) {
+  return MakeSubstring(start, rep->length - start, rep);
+}
+
+// Creates a substring node removing the specified suffix
+CordRepSubstring* RemoveSuffix(size_t length, CordRep* rep) {
+  return MakeSubstring(0, rep->length - length, rep);
+}
+
+CordRepConcat* MakeConcat(CordRep* left, CordRep* right, int depth = 0) {
+  auto* concat = new CordRepConcat;
+  concat->tag = CONCAT;
+  concat->length = left->length + right->length;
+  concat->left = left;
+  concat->right = right;
+  concat->set_depth(depth);
+  return concat;
+}
+
+enum Composition { kMix, kAppend, kPrepend };
+
+Composition RandomComposition() {
+  RandomEngine rng(testing::GTEST_FLAG(random_seed));
+  return (rng() & 1) ? kMix : ((rng() & 1) ? kAppend : kPrepend);
+}
+
+absl::string_view ToString(Composition composition) {
+  switch (composition) {
+    case kAppend:
+      return "Append";
+    case kPrepend:
+      return "Prepend";
+    case kMix:
+      return "Mix";
+  }
+  assert(false);
+  return "???";
+}
+
+constexpr const char* kFox = "The quick brown fox jumps over the lazy dog";
+constexpr const char* kFoxFlats[] = {"The ", "quick ", "brown ",
+                                     "fox ", "jumps ", "over ",
+                                     "the ", "lazy ",  "dog"};
+constexpr const char* kAlphabet = "abcdefghijklmnopqrstuvwxyz";
+
+CordRepRing* FromFlats(Span<const char* const> flats,
+                       Composition composition = kAppend) {
+  if (flats.empty()) return nullptr;
+  CordRepRing* ring = nullptr;
+  switch (composition) {
+    case kAppend:
+      ring = CordRepRing::Create(MakeLeaf(flats.front()), flats.size() - 1);
+      for (int i = 1; i < flats.size(); ++i) {
+        ring = CordRepRing::Append(ring, MakeLeaf(flats[i]));
+      }
+      break;
+    case kPrepend:
+      ring = CordRepRing::Create(MakeLeaf(flats.back()), flats.size() - 1);
+      for (int i = static_cast<int>(flats.size() - 2); i >= 0; --i) {
+        ring = CordRepRing::Prepend(ring, MakeLeaf(flats[i]));
+      }
+      break;
+    case kMix:
+      size_t middle1 = flats.size() / 2, middle2 = middle1;
+      ring = CordRepRing::Create(MakeLeaf(flats[middle1]), flats.size() - 1);
+      if (!flats.empty()) {
+        if ((flats.size() & 1) == 0) {
+          ring = CordRepRing::Prepend(ring, MakeLeaf(flats[--middle1]));
+        }
+        for (int i = 1; i <= middle1; ++i) {
+          ring = CordRepRing::Prepend(ring, MakeLeaf(flats[middle1 - i]));
+          ring = CordRepRing::Append(ring, MakeLeaf(flats[middle2 + i]));
+        }
+      }
+      break;
+  }
+  EXPECT_THAT(ToFlats(ring), ElementsAreArray(flats));
+  return ring;
+}
+
+std::ostream& operator<<(std::ostream& s, const TestParam& param) {
+  return s << param.ToString();
+}
+
+std::string TestParamToString(const testing::TestParamInfo<TestParam>& info) {
+  return info.param.ToString();
+}
+
+class CordRingTest : public testing::Test {
+ public:
+  ~CordRingTest() override {
+#if ASAN_BUG_177688959_FIXED
+    for (CordRep* rep : unrefs_) {
+      CordRep::Unref(rep);
+    }
+#endif
+  }
+
+  template <typename CordRepType>
+  CordRepType* NeedsUnref(CordRepType* rep) {
+    assert(rep);
+#if ASAN_BUG_177688959_FIXED
+    unrefs_.push_back(rep);
+#endif
+    return rep;
+  }
+
+  template <typename CordRepType>
+  CordRepType* Ref(CordRepType* rep) {
+    CordRep::Ref(rep);
+    return NeedsUnref(rep);
+  }
+
+  void Unref(CordRep* rep) {
+#if !ASAN_BUG_177688959_FIXED
+    CordRep::Unref(rep);
+#endif
+  }
+
+ private:
+#if ASAN_BUG_177688959_FIXED
+  std::vector<CordRep*> unrefs_;
+#endif
+};
+
+class CordRingTestWithParam : public testing::TestWithParam<TestParam> {
+ public:
+  ~CordRingTestWithParam() override {
+#if ASAN_BUG_177688959_FIXED
+    for (CordRep* rep : unrefs_) {
+      CordRep::Unref(rep);
+    }
+#endif
+  }
+
+  CordRepRing* CreateWithCapacity(CordRep* child, size_t extra_capacity) {
+    if (!GetParam().with_capacity) extra_capacity = 0;
+    CordRepRing* ring = CordRepRing::Create(child, extra_capacity);
+    ring->SetCapacityForTesting(1 + extra_capacity);
+    return RefIfShared(ring);
+  }
+
+  bool Shared() const { return !GetParam().refcount_is_one; }
+  bool InputShared() const { return GetParam().input_share_mode == kShared; }
+  bool InputSharedIndirect() const {
+    return GetParam().input_share_mode == kSharedIndirect;
+  }
+
+  template <typename CordRepType>
+  CordRepType* NeedsUnref(CordRepType* rep) {
+    assert(rep);
+#if ASAN_BUG_177688959_FIXED
+    unrefs_.push_back(rep);
+#endif
+    return rep;
+  }
+
+  template <typename CordRepType>
+  CordRepType* Ref(CordRepType* rep) {
+    CordRep::Ref(rep);
+    return NeedsUnref(rep);
+  }
+
+  void Unref(CordRep* rep) {
+#if !ASAN_BUG_177688959_FIXED
+    CordRep::Unref(rep);
+#endif
+  }
+
+  template <typename CordRepType>
+  CordRepType* RefIfShared(CordRepType* rep) {
+    return Shared() ? Ref(rep) : rep;
+  }
+
+  void UnrefIfShared(CordRep* rep) {
+    if (Shared()) Unref(rep);
+  }
+
+  template <typename CordRepType>
+  CordRepType* RefIfInputShared(CordRepType* rep) {
+    return InputShared() ? Ref(rep) : rep;
+  }
+
+  void UnrefIfInputShared(CordRep* rep) {
+    if (InputShared()) Unref(rep);
+  }
+
+  template <typename CordRepType>
+  CordRepType* RefIfInputSharedIndirect(CordRepType* rep) {
+    return InputSharedIndirect() ? Ref(rep) : rep;
+  }
+
+  void UnrefIfInputSharedIndirect(CordRep* rep) {
+    if (InputSharedIndirect()) Unref(rep);
+  }
+
+ private:
+#if ASAN_BUG_177688959_FIXED
+  std::vector<CordRep*> unrefs_;
+#endif
+};
+
+class CordRingCreateTest : public CordRingTestWithParam {
+ public:
+  static TestParams CreateTestParams() {
+    TestParams params;
+    params.emplace_back(InputShareMode::kPrivate);
+    params.emplace_back(InputShareMode::kShared);
+    return params;
+  }
+};
+
+class CordRingSubTest : public CordRingTestWithParam {
+ public:
+  static TestParams CreateTestParams() {
+    TestParams params;
+    for (bool refcount_is_one : {true, false}) {
+      TestParam param;
+      param.refcount_is_one = refcount_is_one;
+      params.push_back(param);
+    }
+    return params;
+  }
+};
+
+class CordRingBuildTest : public CordRingTestWithParam {
+ public:
+  static TestParams CreateTestParams() {
+    TestParams params;
+    for (bool refcount_is_one : {true, false}) {
+      for (bool with_capacity : {true, false}) {
+        TestParam param;
+        param.refcount_is_one = refcount_is_one;
+        param.with_capacity = with_capacity;
+        params.push_back(param);
+      }
+    }
+    return params;
+  }
+};
+
+class CordRingCreateFromTreeTest : public CordRingTestWithParam {
+ public:
+  static TestParams CreateTestParams() {
+    TestParams params;
+    params.emplace_back(InputShareMode::kPrivate);
+    params.emplace_back(InputShareMode::kShared);
+    params.emplace_back(InputShareMode::kSharedIndirect);
+    return params;
+  }
+};
+
+class CordRingBuildInputTest : public CordRingTestWithParam {
+ public:
+  static TestParams CreateTestParams() {
+    TestParams params;
+    for (bool refcount_is_one : {true, false}) {
+      for (bool with_capacity : {true, false}) {
+        for (InputShareMode share_mode : {kPrivate, kShared, kSharedIndirect}) {
+          TestParam param;
+          param.refcount_is_one = refcount_is_one;
+          param.with_capacity = with_capacity;
+          param.input_share_mode = share_mode;
+          params.push_back(param);
+        }
+      }
+    }
+    return params;
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(WithParam, CordRingSubTest,
+                        testing::ValuesIn(CordRingSubTest::CreateTestParams()),
+                        TestParamToString);
+
+INSTANTIATE_TEST_CASE_P(
+    WithParam, CordRingCreateTest,
+    testing::ValuesIn(CordRingCreateTest::CreateTestParams()),
+    TestParamToString);
+
+INSTANTIATE_TEST_CASE_P(
+    WithParam, CordRingCreateFromTreeTest,
+    testing::ValuesIn(CordRingCreateFromTreeTest::CreateTestParams()),
+    TestParamToString);
+
+INSTANTIATE_TEST_CASE_P(
+    WithParam, CordRingBuildTest,
+    testing::ValuesIn(CordRingBuildTest::CreateTestParams()),
+    TestParamToString);
+
+INSTANTIATE_TEST_CASE_P(
+    WithParam, CordRingBuildInputTest,
+    testing::ValuesIn(CordRingBuildInputTest::CreateTestParams()),
+    TestParamToString);
+
+TEST_P(CordRingCreateTest, CreateFromFlat) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(MakeFlat(str1)));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->length, Eq(str1.size()));
+  EXPECT_THAT(ToFlats(result), ElementsAre(str1));
+  Unref(result);
+}
+
+TEST_P(CordRingCreateTest, CreateFromRing) {
+  CordRepRing* ring = RefIfShared(FromFlats(kFoxFlats));
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(ring));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAreArray(kFoxFlats));
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringRing) {
+  CordRepRing* ring = RefIfInputSharedIndirect(FromFlats(kFoxFlats));
+  CordRep* sub = RefIfInputShared(MakeSubstring(2, 11, ring));
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(sub));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfInputPrivate(GetParam(), ring));
+  EXPECT_THAT(ToString(result), string_view(kFox).substr(2, 11));
+  UnrefIfInputSharedIndirect(ring);
+  UnrefIfInputShared(sub);
+  Unref(result);
+}
+
+TEST_F(CordRingTest, CreateWithIllegalExtraCapacity) {
+  CordRep* flat = NeedsUnref(MakeFlat("Hello world"));
+#if defined(ABSL_HAVE_EXCEPTIONS)
+  try {
+    CordRepRing::Create(flat, CordRepRing::kMaxCapacity);
+    GTEST_FAIL() << "expected std::length_error exception";
+  } catch (const std::length_error&) {
+  }
+#elif defined(GTEST_HAS_DEATH_TEST)
+  EXPECT_DEATH(CordRepRing::Create(flat, CordRepRing::kMaxCapacity), ".*");
+#endif
+  Unref(flat);
+}
+
+TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringOfFlat) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  auto* flat = RefIfInputShared(MakeFlat(str1));
+  auto* child = RefIfInputSharedIndirect(MakeSubstring(4, 20, flat));
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->length, Eq(20));
+  EXPECT_THAT(ToFlats(result), ElementsAre(str1.substr(4, 20)));
+  Unref(result);
+  UnrefIfInputShared(flat);
+  UnrefIfInputSharedIndirect(child);
+}
+
+TEST_P(CordRingCreateTest, CreateFromExternal) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  auto* child = RefIfInputShared(MakeExternal(str1));
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->length, Eq(str1.size()));
+  EXPECT_THAT(ToFlats(result), ElementsAre(str1));
+  Unref(result);
+  UnrefIfInputShared(child);
+}
+
+TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringOfExternal) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  auto* external = RefIfInputShared(MakeExternal(str1));
+  auto* child = RefIfInputSharedIndirect(MakeSubstring(1, 24, external));
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->length, Eq(24));
+  EXPECT_THAT(ToFlats(result), ElementsAre(str1.substr(1, 24)));
+  Unref(result);
+  UnrefIfInputShared(external);
+  UnrefIfInputSharedIndirect(child);
+}
+
+TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringOfLargeExternal) {
+  auto* external = RefIfInputShared(MakeFakeExternal(1 << 20));
+  auto str = not_a_string_view(external->base, 1 << 20)
+                 .remove_prefix(1 << 19)
+                 .remove_suffix(6);
+  auto* child =
+      RefIfInputSharedIndirect(MakeSubstring(1 << 19, (1 << 19) - 6, external));
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->length, Eq(str.size()));
+  EXPECT_THAT(ToRawFlats(result), ElementsAre(str));
+  Unref(result);
+  UnrefIfInputShared(external);
+  UnrefIfInputSharedIndirect(child);
+}
+
+TEST_P(CordRingBuildInputTest, CreateFromConcat) {
+  CordRep* flats[] = {MakeFlat("abcdefgh"), MakeFlat("ijklm"),
+                      MakeFlat("nopqrstuv"), MakeFlat("wxyz")};
+  auto* left = MakeConcat(RefIfInputSharedIndirect(flats[0]), flats[1]);
+  auto* right = MakeConcat(flats[2], RefIfInputSharedIndirect(flats[3]));
+  auto* concat = RefIfInputShared(MakeConcat(left, right));
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(concat));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->length, Eq(26));
+  EXPECT_THAT(ToString(result), Eq(kAlphabet));
+  UnrefIfInputSharedIndirect(flats[0]);
+  UnrefIfInputSharedIndirect(flats[3]);
+  UnrefIfInputShared(concat);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, CreateFromSubstringConcat) {
+  for (size_t off = 0; off < 26; ++off) {
+    for (size_t len = 1; len < 26 - off; ++len) {
+      CordRep* flats[] = {MakeFlat("abcdefgh"), MakeFlat("ijklm"),
+                          MakeFlat("nopqrstuv"), MakeFlat("wxyz")};
+      auto* left = MakeConcat(RefIfInputSharedIndirect(flats[0]), flats[1]);
+      auto* right = MakeConcat(flats[2], RefIfInputSharedIndirect(flats[3]));
+      auto* concat = MakeConcat(left, right);
+      auto* child = RefIfInputShared(MakeSubstring(off, len, concat));
+      CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
+      ASSERT_THAT(result, IsValidRingBuffer());
+      ASSERT_THAT(result->length, Eq(len));
+      ASSERT_THAT(ToString(result), string_view(kAlphabet).substr(off, len));
+      UnrefIfInputSharedIndirect(flats[0]);
+      UnrefIfInputSharedIndirect(flats[3]);
+      UnrefIfInputShared(child);
+      Unref(result);
+    }
+  }
+}
+
+TEST_P(CordRingCreateTest, Properties) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(MakeFlat(str1), 120));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->head(), Eq(0));
+  EXPECT_THAT(result->tail(), Eq(1));
+  EXPECT_THAT(result->capacity(), Ge(120 + 1));
+  EXPECT_THAT(result->capacity(), Le(2 * 120 + 1));
+  EXPECT_THAT(result->entries(), Eq(1));
+  EXPECT_THAT(result->begin_pos(), Eq(0));
+  Unref(result);
+}
+
+TEST_P(CordRingCreateTest, EntryForNewFlat) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  CordRep* child = MakeFlat(str1);
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(child, 120));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->entry_child(0), Eq(child));
+  EXPECT_THAT(result->entry_end_pos(0), Eq(str1.length()));
+  EXPECT_THAT(result->entry_data_offset(0), Eq(0));
+  Unref(result);
+}
+
+TEST_P(CordRingCreateTest, EntryForNewFlatSubstring) {
+  absl::string_view str1 = "1234567890abcdefghijklmnopqrstuvwxyz";
+  CordRep* child = MakeFlat(str1);
+  CordRep* substring = MakeSubstring(10, 26, child);
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(substring, 1));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->entry_child(0), Eq(child));
+  EXPECT_THAT(result->entry_end_pos(0), Eq(26));
+  EXPECT_THAT(result->entry_data_offset(0), Eq(10));
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendFlat) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, MakeFlat(str2)));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
+  EXPECT_THAT(ToFlats(result), ElementsAre(str1, str2));
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, PrependFlat) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, MakeFlat(str2)));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
+  EXPECT_THAT(ToFlats(result), ElementsAre(str2, str1));
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendString) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
+  EXPECT_THAT(ToFlats(result), ElementsAre(str1, str2));
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendStringHavingExtra) {
+  absl::string_view str1 = "1234";
+  absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  CordRepRing* ring = CreateWithCapacity(MakeFlat(str1, 26), 0);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
+  EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendStringHavingPartialExtra) {
+  absl::string_view str1 = "1234";
+  absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+  // Create flat with at least one extra byte. We don't expect to have sized
+  // alloc and capacity rounding to grant us enough to not make it partial.
+  auto* flat = MakeFlat(str1, 1);
+  size_t avail = flat->flat()->Capacity() - flat->length;
+  ASSERT_THAT(avail, Lt(str2.size())) << " adjust test for larger flats!";
+
+  // Construct the flats we do expect using all of `avail`.
+  absl::string_view str1a = str2.substr(0, avail);
+  absl::string_view str2a = str2.substr(avail);
+
+  CordRepRing* ring = CreateWithCapacity(flat, 1);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  if (GetParam().refcount_is_one) {
+    EXPECT_THAT(ToFlats(result), ElementsAre(StrCat(str1, str1a), str2a));
+  } else {
+    EXPECT_THAT(ToFlats(result), ElementsAre(str1, str2));
+  }
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendStringHavingExtraInSubstring) {
+  absl::string_view str1 = "123456789_1234";
+  absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  CordRep* flat = RemovePrefix(10, MakeFlat(str1, 26));
+  CordRepRing* ring = CreateWithCapacity(flat, 0);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
+  EXPECT_THAT(result->length, Eq(4 + str2.size()));
+  if (GetParam().refcount_is_one) {
+    EXPECT_THAT(ToFlats(result), ElementsAre(StrCat("1234", str2)));
+  } else {
+    EXPECT_THAT(ToFlats(result), ElementsAre("1234", str2));
+  }
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendStringHavingSharedExtra) {
+  absl::string_view str1 = "123456789_1234";
+  absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  for (int shared_type = 0; shared_type < 2; ++shared_type) {
+    SCOPED_TRACE(absl::StrCat("Shared extra type ", shared_type));
+
+    // Create a flat that is shared in some way.
+    CordRep* flat = nullptr;
+    CordRep* flat1 = nullptr;
+    if (shared_type == 0) {
+      // Shared flat
+      flat = CordRep::Ref(MakeFlat(str1.substr(10), 100));
+    } else if (shared_type == 1) {
+      // Shared flat inside private substring
+      flat1 = CordRep::Ref(MakeFlat(str1));
+      flat = RemovePrefix(10, flat1);
+    } else {
+      // Private flat inside shared substring
+      flat = CordRep::Ref(RemovePrefix(10, MakeFlat(str1, 100)));
+    }
+
+    CordRepRing* ring = CreateWithCapacity(flat, 1);
+    CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
+    ASSERT_THAT(result, IsValidRingBuffer());
+    EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+    EXPECT_THAT(result->length, Eq(4 + str2.size()));
+    EXPECT_THAT(ToFlats(result), ElementsAre("1234", str2));
+    UnrefIfShared(ring);
+    Unref(result);
+
+    CordRep::Unref(shared_type == 1 ? flat1 : flat);
+  }
+}
+
+TEST_P(CordRingBuildTest, AppendStringWithExtra) {
+  absl::string_view str1 = "1234";
+  absl::string_view str2 = "1234567890";
+  absl::string_view str3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2, 26));
+  result = CordRepRing::Append(result, str3);
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->length, Eq(str1.size() + str2.size() + str3.size()));
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre(str1, StrCat(str2, str3)));
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, PrependString) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  // Use external rep to avoid appending to first flat
+  CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, str2));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  if (GetParam().with_capacity && GetParam().refcount_is_one) {
+    EXPECT_THAT(result, Eq(ring));
+  } else {
+    EXPECT_THAT(result, Ne(ring));
+  }
+  EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
+  EXPECT_THAT(ToFlats(result), ElementsAre(str2, str1));
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, PrependStringHavingExtra) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz1234";
+  absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  CordRep* flat = RemovePrefix(26, MakeFlat(str1));
+  CordRepRing* ring = CreateWithCapacity(flat, 0);
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, str2));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
+  EXPECT_THAT(result->length, Eq(4 + str2.size()));
+  if (GetParam().refcount_is_one) {
+    EXPECT_THAT(ToFlats(result), ElementsAre(StrCat(str2, "1234")));
+  } else {
+    EXPECT_THAT(ToFlats(result), ElementsAre(str2, "1234"));
+  }
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, PrependStringHavingSharedExtra) {
+  absl::string_view str1 = "123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  absl::string_view str2 = "abcdefghij";
+  absl::string_view str1a = str1.substr(10);
+  for (int shared_type = 1; shared_type < 2; ++shared_type) {
+    SCOPED_TRACE(absl::StrCat("Shared extra type ", shared_type));
+
+    // Create a flat that is shared in some way.
+    CordRep* flat = nullptr;
+    CordRep* flat1 = nullptr;
+    if (shared_type == 1) {
+      // Shared flat inside private substring
+      flat = RemovePrefix(10, flat1 = CordRep::Ref(MakeFlat(str1)));
+    } else {
+      // Private flat inside shared substring
+      flat = CordRep::Ref(RemovePrefix(10, MakeFlat(str1, 100)));
+    }
+
+    CordRepRing* ring = CreateWithCapacity(flat, 1);
+    CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, str2));
+    ASSERT_THAT(result, IsValidRingBuffer());
+    EXPECT_THAT(result->length, Eq(str1a.size() + str2.size()));
+    EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+    EXPECT_THAT(ToFlats(result), ElementsAre(str2, str1a));
+    UnrefIfShared(ring);
+    Unref(result);
+    CordRep::Unref(shared_type == 1 ? flat1 : flat);
+  }
+}
+
+TEST_P(CordRingBuildTest, PrependStringWithExtra) {
+  absl::string_view str1 = "1234";
+  absl::string_view str2 = "1234567890";
+  absl::string_view str3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, str2, 26));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  result = CordRepRing::Prepend(result, str3);
+  EXPECT_THAT(result->length, Eq(str1.size() + str2.size() + str3.size()));
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre(StrCat(str3, str2), str1));
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendPrependStringMix) {
+  const auto& flats = kFoxFlats;
+  CordRepRing* ring = CreateWithCapacity(MakeFlat(flats[4]), 8);
+  CordRepRing* result = ring;
+  for (int i = 1; i <= 4; ++i) {
+    result = CordRepRing::Prepend(result, flats[4 - i]);
+    result = CordRepRing::Append(result, flats[4 + i]);
+  }
+  UnrefIfShared(ring);
+  NeedsUnref(result);
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToString(result), kFox);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendPrependStringMixWithExtra) {
+  const auto& flats = kFoxFlats;
+  CordRepRing* ring = CreateWithCapacity(MakeFlat(flats[4], 100), 8);
+  CordRepRing* result = ring;
+  for (int i = 1; i <= 4; ++i) {
+    result = CordRepRing::Prepend(result, flats[4 - i], 100);
+    result = CordRepRing::Append(result, flats[4 + i], 100);
+  }
+  NeedsUnref(result);
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  if (GetParam().refcount_is_one) {
+    EXPECT_THAT(ToFlats(result),
+                ElementsAre("The quick brown fox ", "jumps over the lazy dog"));
+  } else {
+    EXPECT_THAT(ToFlats(result), ElementsAre("The quick brown fox ", "jumps ",
+                                             "over the lazy dog"));
+  }
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendPrependStringMixWithPrependedExtra) {
+  const auto& flats = kFoxFlats;
+  CordRep* flat = MakeFlat(StrCat(std::string(50, '.'), flats[4]), 50);
+  CordRepRing* ring = CreateWithCapacity(RemovePrefix(50, flat), 0);
+  CordRepRing* result = ring;
+  for (int i = 1; i <= 4; ++i) {
+    result = CordRepRing::Prepend(result, flats[4 - i], 100);
+    result = CordRepRing::Append(result, flats[4 + i], 100);
+  }
+  result = NeedsUnref(result);
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
+  if (GetParam().refcount_is_one) {
+    EXPECT_THAT(ToFlats(result), ElementsAre(kFox));
+  } else {
+    EXPECT_THAT(ToFlats(result), ElementsAre("The quick brown fox ", "jumps ",
+                                             "over the lazy dog"));
+  }
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingSubTest, SubRing) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  string_view all = kFox;
+  for (size_t offset = 0; offset < all.size() - 1; ++offset) {
+    CordRepRing* ring = RefIfShared(FromFlats(flats, composition));
+    CordRepRing* result = CordRepRing::SubRing(ring, offset, 0);
+    EXPECT_THAT(result, nullptr);
+    UnrefIfShared(ring);
+
+    for (size_t len = 1; len < all.size() - offset; ++len) {
+      ring = RefIfShared(FromFlats(flats, composition));
+      result = NeedsUnref(CordRepRing::SubRing(ring, offset, len));
+      ASSERT_THAT(result, IsValidRingBuffer());
+      ASSERT_THAT(result, EqIfPrivate(GetParam(), ring));
+      ASSERT_THAT(ToString(result), Eq(all.substr(offset, len)));
+      UnrefIfShared(ring);
+      Unref(result);
+    }
+  }
+}
+
+TEST_P(CordRingSubTest, SubRingFromLargeExternal) {
+  auto composition = RandomComposition();
+  std::string large_string(1 << 20, '.');
+  const char* flats[] = {
+      "abcdefghijklmnopqrstuvwxyz",
+      large_string.c_str(),
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+  };
+  std::string buffer = absl::StrCat(flats[0], flats[1], flats[2]);
+  absl::string_view all = buffer;
+  for (size_t offset = 0; offset < 30; ++offset) {
+    CordRepRing* ring = RefIfShared(FromFlats(flats, composition));
+    CordRepRing* result = CordRepRing::SubRing(ring, offset, 0);
+    EXPECT_THAT(result, nullptr);
+    UnrefIfShared(ring);
+
+    for (size_t len = all.size() - 30; len < all.size() - offset; ++len) {
+      ring = RefIfShared(FromFlats(flats, composition));
+      result = NeedsUnref(CordRepRing::SubRing(ring, offset, len));
+      ASSERT_THAT(result, IsValidRingBuffer());
+      ASSERT_THAT(result, EqIfPrivate(GetParam(), ring));
+      auto str = ToString(result);
+      ASSERT_THAT(str, SizeIs(len));
+      ASSERT_THAT(str, Eq(all.substr(offset, len)));
+      UnrefIfShared(ring);
+      Unref(result);
+    }
+  }
+}
+
+TEST_P(CordRingSubTest, RemovePrefix) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  string_view all = kFox;
+  CordRepRing* ring = RefIfShared(FromFlats(flats, composition));
+  CordRepRing* result = CordRepRing::RemovePrefix(ring, all.size());
+  EXPECT_THAT(result, nullptr);
+  UnrefIfShared(ring);
+
+  for (size_t len = 1; len < all.size(); ++len) {
+    ring = RefIfShared(FromFlats(flats, composition));
+    result = NeedsUnref(CordRepRing::RemovePrefix(ring, len));
+    ASSERT_THAT(result, IsValidRingBuffer());
+    EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
+    EXPECT_THAT(ToString(result), Eq(all.substr(len)));
+    UnrefIfShared(ring);
+    Unref(result);
+  }
+}
+
+TEST_P(CordRingSubTest, RemovePrefixFromLargeExternal) {
+  CordRepExternal* external1 = MakeFakeExternal(1 << 20);
+  CordRepExternal* external2 = MakeFakeExternal(1 << 20);
+  CordRepRing* ring = CordRepRing::Create(external1, 1);
+  ring = CordRepRing::Append(ring, external2);
+  CordRepRing* result = NeedsUnref(CordRepRing::RemovePrefix(ring, 1 << 16));
+  EXPECT_THAT(
+      ToRawFlats(result),
+      ElementsAre(
+          not_a_string_view(external1->base, 1 << 20).remove_prefix(1 << 16),
+          not_a_string_view(external2->base, 1 << 20)));
+  Unref(result);
+}
+
+TEST_P(CordRingSubTest, RemoveSuffix) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  string_view all = kFox;
+  CordRepRing* ring = RefIfShared(FromFlats(flats, composition));
+  CordRepRing* result = CordRepRing::RemoveSuffix(ring, all.size());
+  EXPECT_THAT(result, nullptr);
+  UnrefIfShared(ring);
+
+  for (size_t len = 1; len < all.size(); ++len) {
+    ring = RefIfShared(FromFlats(flats, composition));
+    result = NeedsUnref(CordRepRing::RemoveSuffix(ring, len));
+    ASSERT_THAT(result, IsValidRingBuffer());
+    EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
+    EXPECT_THAT(ToString(result), Eq(all.substr(0, all.size() - len)));
+    UnrefIfShared(ring);
+    Unref(result);
+  }
+}
+
+TEST_P(CordRingSubTest, AppendRing) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats).subspan(1);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat(kFoxFlats[0]), flats.size());
+  CordRepRing* child = FromFlats(flats, composition);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, child));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAreArray(kFoxFlats));
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, AppendRingWithFlatOffset) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
+  CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
+  CordRep* stripped = RemovePrefix(10, child);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("Head", "brown ", "fox ", "jumps ",
+                                           "over ", "the ", "lazy ", "dog"));
+  UnrefIfInputSharedIndirect(child);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, AppendRingWithBrokenOffset) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
+  CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
+  CordRep* stripped = RemovePrefix(21, child);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result),
+              ElementsAre("Head", "umps ", "over ", "the ", "lazy ", "dog"));
+  UnrefIfInputSharedIndirect(child);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, AppendRingWithFlatLength) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
+  CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
+  CordRep* stripped = RemoveSuffix(8, child);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("Head", "The ", "quick ", "brown ",
+                                           "fox ", "jumps ", "over ", "the "));
+  UnrefIfInputSharedIndirect(child);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendRingWithBrokenFlatLength) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
+  CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
+  CordRep* stripped = RemoveSuffix(15, child);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("Head", "The ", "quick ", "brown ",
+                                           "fox ", "jumps ", "ov"));
+  UnrefIfInputSharedIndirect(child);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendRingMiddlePiece) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
+  CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
+  CordRep* stripped = MakeSubstring(7, child->length - 27, child);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result),
+              ElementsAre("Head", "ck ", "brown ", "fox ", "jum"));
+  UnrefIfInputSharedIndirect(child);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendRingSinglePiece) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
+  CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
+  CordRep* stripped = RefIfInputShared(MakeSubstring(11, 3, child));
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("Head", "row"));
+  UnrefIfInputSharedIndirect(child);
+  UnrefIfInputShared(stripped);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, AppendRingSinglePieceWithPrefix) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  size_t extra_capacity = 1 + (GetParam().with_capacity ? flats.size() : 0);
+  CordRepRing* ring = CordRepRing::Create(MakeFlat("Head"), extra_capacity);
+  ring->SetCapacityForTesting(1 + extra_capacity);
+  ring = RefIfShared(CordRepRing::Prepend(ring, MakeFlat("Prepend")));
+  assert(ring->IsValid(std::cout));
+  CordRepRing* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
+  CordRep* stripped = RefIfInputShared(MakeSubstring(11, 3, child));
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("Prepend", "Head", "row"));
+  UnrefIfInputSharedIndirect(child);
+  UnrefIfInputShared(stripped);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, PrependRing) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto fox = MakeSpan(kFoxFlats);
+  auto flats = MakeSpan(fox).subspan(0, fox.size() - 1);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat(fox.back()), flats.size());
+  CordRepRing* child = RefIfInputShared(FromFlats(flats, composition));
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, child));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAreArray(kFoxFlats));
+  UnrefIfInputShared(child);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, PrependRingWithFlatOffset) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
+  CordRep* child = RefIfInputShared(FromFlats(flats, composition));
+  CordRep* stripped = RefIfInputSharedIndirect(RemovePrefix(10, child));
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("brown ", "fox ", "jumps ", "over ",
+                                           "the ", "lazy ", "dog", "Tail"));
+  UnrefIfInputShared(child);
+  UnrefIfInputSharedIndirect(stripped);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, PrependRingWithBrokenOffset) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
+  CordRep* child = RefIfInputShared(FromFlats(flats, composition));
+  CordRep* stripped = RefIfInputSharedIndirect(RemovePrefix(21, child));
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result),
+              ElementsAre("umps ", "over ", "the ", "lazy ", "dog", "Tail"));
+  UnrefIfInputShared(child);
+  UnrefIfInputSharedIndirect(stripped);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, PrependRingWithFlatLength) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
+  CordRep* child = RefIfInputShared(FromFlats(flats, composition));
+  CordRep* stripped = RefIfInputSharedIndirect(RemoveSuffix(8, child));
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("The ", "quick ", "brown ", "fox ",
+                                           "jumps ", "over ", "the ", "Tail"));
+  UnrefIfShared(ring);
+  UnrefIfInputShared(child);
+  UnrefIfInputSharedIndirect(stripped);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, PrependRingWithBrokenFlatLength) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
+  CordRep* child = RefIfInputShared(FromFlats(flats, composition));
+  CordRep* stripped = RefIfInputSharedIndirect(RemoveSuffix(15, child));
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("The ", "quick ", "brown ", "fox ",
+                                           "jumps ", "ov", "Tail"));
+  UnrefIfInputShared(child);
+  UnrefIfInputSharedIndirect(stripped);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, PrependRingMiddlePiece) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
+  CordRep* child = RefIfInputShared(FromFlats(flats, composition));
+  CordRep* stripped =
+      RefIfInputSharedIndirect(MakeSubstring(7, child->length - 27, child));
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result),
+              ElementsAre("ck ", "brown ", "fox ", "jum", "Tail"));
+  UnrefIfInputShared(child);
+  UnrefIfInputSharedIndirect(stripped);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, PrependRingSinglePiece) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
+  CordRep* child = RefIfInputShared(FromFlats(flats, composition));
+  CordRep* stripped = RefIfInputSharedIndirect(MakeSubstring(11, 3, child));
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("row", "Tail"));
+  UnrefIfInputShared(child);
+  UnrefIfInputSharedIndirect(stripped);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, PrependRingSinglePieceWithPrefix) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  size_t extra_capacity = 1 + (GetParam().with_capacity ? flats.size() : 0);
+  CordRepRing* ring = CordRepRing::Create(MakeFlat("Tail"), extra_capacity);
+  ring->SetCapacityForTesting(1 + extra_capacity);
+  ring = RefIfShared(CordRepRing::Prepend(ring, MakeFlat("Prepend")));
+  CordRep* child = RefIfInputShared(FromFlats(flats, composition));
+  CordRep* stripped = RefIfInputSharedIndirect(MakeSubstring(11, 3, child));
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("row", "Prepend", "Tail"));
+  UnrefIfInputShared(child);
+  UnrefIfInputSharedIndirect(stripped);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_F(CordRingTest, Find) {
+  constexpr const char* flats[] = {
+      "abcdefghij", "klmnopqrst", "uvwxyz",     "ABCDEFGHIJ",
+      "KLMNOPQRST", "UVWXYZ",     "1234567890", "~!@#$%^&*()_",
+      "+-=",        "[]\\{}|;':", ",/<>?",      "."};
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  CordRepRing* ring = NeedsUnref(FromFlats(flats, composition));
+  std::string value = ToString(ring);
+  for (int i = 0; i < value.length(); ++i) {
+    CordRepRing::Position found = ring->Find(i);
+    auto data = ring->entry_data(found.index);
+    ASSERT_THAT(found.offset, Lt(data.length()));
+    ASSERT_THAT(data[found.offset], Eq(value[i]));
+  }
+  Unref(ring);
+}
+
+TEST_F(CordRingTest, FindWithHint) {
+  constexpr const char* flats[] = {
+      "abcdefghij", "klmnopqrst", "uvwxyz",     "ABCDEFGHIJ",
+      "KLMNOPQRST", "UVWXYZ",     "1234567890", "~!@#$%^&*()_",
+      "+-=",        "[]\\{}|;':", ",/<>?",      "."};
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  CordRepRing* ring = NeedsUnref(FromFlats(flats, composition));
+  std::string value = ToString(ring);
+
+#if defined(GTEST_HAS_DEATH_TEST)
+  // Test hint beyond valid position
+  index_type head = ring->head();
+  EXPECT_DEBUG_DEATH(ring->Find(ring->advance(head), 0), ".*");
+  EXPECT_DEBUG_DEATH(ring->Find(ring->advance(head), 9), ".*");
+  EXPECT_DEBUG_DEATH(ring->Find(ring->advance(head, 3), 24), ".*");
+#endif
+
+  int flat_pos = 0;
+  size_t flat_offset = 0;
+  for (auto sflat : flats) {
+    string_view flat(sflat);
+    for (int offset = 0; offset < flat.length(); ++offset) {
+      for (int start = 0; start <= flat_pos; ++start) {
+        index_type hint = ring->advance(ring->head(), start);
+        CordRepRing::Position found = ring->Find(hint, flat_offset + offset);
+        ASSERT_THAT(found.index, Eq(ring->advance(ring->head(), flat_pos)));
+        ASSERT_THAT(found.offset, Eq(offset));
+      }
+    }
+    ++flat_pos;
+    flat_offset += flat.length();
+  }
+  Unref(ring);
+}
+
+TEST_F(CordRingTest, FindInLargeRing) {
+  constexpr const char* flats[] = {
+      "abcdefghij", "klmnopqrst", "uvwxyz",     "ABCDEFGHIJ",
+      "KLMNOPQRST", "UVWXYZ",     "1234567890", "~!@#$%^&*()_",
+      "+-=",        "[]\\{}|;':", ",/<>?",      "."};
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  CordRepRing* ring = FromFlats(flats, composition);
+  for (int i = 0; i < 13; ++i) {
+    ring = CordRepRing::Append(ring, FromFlats(flats, composition));
+  }
+  NeedsUnref(ring);
+  std::string value = ToString(ring);
+  for (int i = 0; i < value.length(); ++i) {
+    CordRepRing::Position pos = ring->Find(i);
+    auto data = ring->entry_data(pos.index);
+    ASSERT_THAT(pos.offset, Lt(data.length()));
+    ASSERT_THAT(data[pos.offset], Eq(value[i]));
+  }
+  Unref(ring);
+}
+
+TEST_F(CordRingTest, FindTail) {
+  constexpr const char* flats[] = {
+      "abcdefghij", "klmnopqrst", "uvwxyz",     "ABCDEFGHIJ",
+      "KLMNOPQRST", "UVWXYZ",     "1234567890", "~!@#$%^&*()_",
+      "+-=",        "[]\\{}|;':", ",/<>?",      "."};
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  CordRepRing* ring = NeedsUnref(FromFlats(flats, composition));
+  std::string value = ToString(ring);
+
+  for (int i = 0; i < value.length(); ++i) {
+    CordRepRing::Position pos = ring->FindTail(i + 1);
+    auto data = ring->entry_data(ring->retreat(pos.index));
+    ASSERT_THAT(pos.offset, Lt(data.length()));
+    ASSERT_THAT(data[data.length() - pos.offset - 1], Eq(value[i]));
+  }
+  Unref(ring);
+}
+
+TEST_F(CordRingTest, FindTailWithHint) {
+  constexpr const char* flats[] = {
+      "abcdefghij", "klmnopqrst", "uvwxyz",     "ABCDEFGHIJ",
+      "KLMNOPQRST", "UVWXYZ",     "1234567890", "~!@#$%^&*()_",
+      "+-=",        "[]\\{}|;':", ",/<>?",      "."};
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  CordRepRing* ring = NeedsUnref(FromFlats(flats, composition));
+  std::string value = ToString(ring);
+
+  // Test hint beyond valid position
+#if defined(GTEST_HAS_DEATH_TEST)
+  index_type head = ring->head();
+  EXPECT_DEBUG_DEATH(ring->FindTail(ring->advance(head), 1), ".*");
+  EXPECT_DEBUG_DEATH(ring->FindTail(ring->advance(head), 10), ".*");
+  EXPECT_DEBUG_DEATH(ring->FindTail(ring->advance(head, 3), 26), ".*");
+#endif
+
+  for (int i = 0; i < value.length(); ++i) {
+    CordRepRing::Position pos = ring->FindTail(i + 1);
+    auto data = ring->entry_data(ring->retreat(pos.index));
+    ASSERT_THAT(pos.offset, Lt(data.length()));
+    ASSERT_THAT(data[data.length() - pos.offset - 1], Eq(value[i]));
+  }
+  Unref(ring);
+}
+
+TEST_F(CordRingTest, FindTailInLargeRing) {
+  constexpr const char* flats[] = {
+      "abcdefghij", "klmnopqrst", "uvwxyz",     "ABCDEFGHIJ",
+      "KLMNOPQRST", "UVWXYZ",     "1234567890", "~!@#$%^&*()_",
+      "+-=",        "[]\\{}|;':", ",/<>?",      "."};
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  CordRepRing* ring = FromFlats(flats, composition);
+  for (int i = 0; i < 13; ++i) {
+    ring = CordRepRing::Append(ring, FromFlats(flats, composition));
+  }
+  NeedsUnref(ring);
+  std::string value = ToString(ring);
+  for (int i = 0; i < value.length(); ++i) {
+    CordRepRing::Position pos = ring->FindTail(i + 1);
+    auto data = ring->entry_data(ring->retreat(pos.index));
+    ASSERT_THAT(pos.offset, Lt(data.length()));
+    ASSERT_THAT(data[data.length() - pos.offset - 1], Eq(value[i]));
+  }
+  Unref(ring);
+}
+
+TEST_F(CordRingTest, GetCharacter) {
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CordRepRing::Create(MakeFlat("Tail"), flats.size());
+  CordRep* child = FromFlats(flats, kAppend);
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, child));
+  std::string value = ToString(result);
+  for (int i = 0; i < value.length(); ++i) {
+    ASSERT_THAT(result->GetCharacter(i), Eq(value[i]));
+  }
+  Unref(result);
+}
+
+TEST_F(CordRingTest, GetCharacterWithSubstring) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  auto* child = MakeSubstring(4, 20, MakeFlat(str1));
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  std::string value = ToString(result);
+  for (int i = 0; i < value.length(); ++i) {
+    ASSERT_THAT(result->GetCharacter(i), Eq(value[i]));
+  }
+  Unref(result);
+}
+
+TEST_F(CordRingTest, Dump) {
+  std::stringstream ss;
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = NeedsUnref(FromFlats(flats, kPrepend));
+  ss << *ring;
+  Unref(ring);
+}
+
+}  // namespace
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc
index 434f3a2..f998242 100644
--- a/absl/strings/cord_test.cc
+++ b/absl/strings/cord_test.cc
@@ -1,3 +1,17 @@
+// 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/strings/cord.h"
 
 #include <algorithm>
@@ -18,9 +32,11 @@
 #include "absl/base/config.h"
 #include "absl/base/internal/endian.h"
 #include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
 #include "absl/container/fixed_array.h"
 #include "absl/strings/cord_test_helpers.h"
 #include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
 #include "absl/strings/string_view.h"
 
 typedef std::mt19937_64 RandomEngine;
@@ -70,9 +86,8 @@
 static std::string RandomLowercaseString(RandomEngine* rng, size_t length) {
   std::string result(length, '\0');
   std::uniform_int_distribution<int> chars('a', 'z');
-  std::generate(result.begin(), result.end(), [&]() {
-    return static_cast<char>(chars(*rng));
-  });
+  std::generate(result.begin(), result.end(),
+                [&]() { return static_cast<char>(chars(*rng)); });
   return result;
 }
 
@@ -166,6 +181,12 @@
       const Cord& c, absl::FunctionRef<void(absl::string_view)> callback) {
     c.ForEachChunk(callback);
   }
+
+  static bool IsTree(const Cord& c) { return c.contents_.is_tree(); }
+
+  static cord_internal::CordzInfo* GetCordzInfo(const Cord& c) {
+    return c.contents_.cordz_info();
+  }
 };
 
 ABSL_NAMESPACE_END
@@ -175,7 +196,7 @@
   using absl::strings_internal::CordTestAccess;
 
   for (size_t s = 0; s < CordTestAccess::MaxFlatLength(); s++) {
-    // Make a std::string of length s.
+    // Make a string of length s.
     std::string src;
     while (src.size() < s) {
       src.push_back('a' + (src.size() % 26));
@@ -350,7 +371,7 @@
     for (size_t end_pos : positions) {
       if (end_pos < pos || end_pos > a.size()) continue;
       absl::Cord sa = a.Subcord(pos, end_pos - pos);
-      EXPECT_EQ(absl::string_view(s).substr(pos, end_pos - pos),
+      ASSERT_EQ(absl::string_view(s).substr(pos, end_pos - pos),
                 std::string(sa))
           << a;
     }
@@ -362,7 +383,7 @@
   for (size_t pos = 0; pos <= sh.size(); ++pos) {
     for (size_t n = 0; n <= sh.size() - pos; ++n) {
       absl::Cord sc = c.Subcord(pos, n);
-      EXPECT_EQ(sh.substr(pos, n), std::string(sc)) << c;
+      ASSERT_EQ(sh.substr(pos, n), std::string(sc)) << c;
     }
   }
 
@@ -372,7 +393,7 @@
   while (sa.size() > 1) {
     sa = sa.Subcord(1, sa.size() - 2);
     ss = ss.substr(1, ss.size() - 2);
-    EXPECT_EQ(ss, std::string(sa)) << a;
+    ASSERT_EQ(ss, std::string(sa)) << a;
     if (HasFailure()) break;  // halt cascade
   }
 
@@ -395,6 +416,9 @@
   swap(x, y);
   ASSERT_EQ(x, absl::Cord(b));
   ASSERT_EQ(y, absl::Cord(a));
+  x.swap(y);
+  ASSERT_EQ(x, absl::Cord(a));
+  ASSERT_EQ(y, absl::Cord(b));
 }
 
 static void VerifyCopyToString(const absl::Cord& cord) {
@@ -410,7 +434,7 @@
 
   if (cord.size() <= kInitialLength) {
     EXPECT_EQ(has_initial_contents.data(), address_before_copy)
-        << "CopyCordToString allocated new std::string storage; "
+        << "CopyCordToString allocated new string storage; "
            "has_initial_contents = \""
         << has_initial_contents << "\"";
   }
@@ -424,6 +448,50 @@
                                 "copying ", "to ", "a ", "string."}));
 }
 
+TEST(TryFlat, Empty) {
+  absl::Cord c;
+  EXPECT_EQ(c.TryFlat(), "");
+}
+
+TEST(TryFlat, Flat) {
+  absl::Cord c("hello");
+  EXPECT_EQ(c.TryFlat(), "hello");
+}
+
+TEST(TryFlat, SubstrInlined) {
+  absl::Cord c("hello");
+  c.RemovePrefix(1);
+  EXPECT_EQ(c.TryFlat(), "ello");
+}
+
+TEST(TryFlat, SubstrFlat) {
+  absl::Cord c("longer than 15 bytes");
+  c.RemovePrefix(1);
+  EXPECT_EQ(c.TryFlat(), "onger than 15 bytes");
+}
+
+TEST(TryFlat, Concat) {
+  absl::Cord c = absl::MakeFragmentedCord({"hel", "lo"});
+  EXPECT_EQ(c.TryFlat(), absl::nullopt);
+}
+
+TEST(TryFlat, External) {
+  absl::Cord c = absl::MakeCordFromExternal("hell", [](absl::string_view) {});
+  EXPECT_EQ(c.TryFlat(), "hell");
+}
+
+TEST(TryFlat, SubstrExternal) {
+  absl::Cord c = absl::MakeCordFromExternal("hell", [](absl::string_view) {});
+  c.RemovePrefix(1);
+  EXPECT_EQ(c.TryFlat(), "ell");
+}
+
+TEST(TryFlat, SubstrConcat) {
+  absl::Cord c = absl::MakeFragmentedCord({"hello", " world"});
+  c.RemovePrefix(1);
+  EXPECT_EQ(c.TryFlat(), absl::nullopt);
+}
+
 static bool IsFlat(const absl::Cord& c) {
   return c.chunk_begin() == c.chunk_end() || ++c.chunk_begin() == c.chunk_end();
 }
@@ -511,24 +579,24 @@
   for (size_t i = 0; i < d.size(); i++) {
     std::string a = d.data(i);
 
-    { // Construct from Cord
+    {  // Construct from Cord
       absl::Cord tmp(a);
       absl::Cord x(tmp);
       EXPECT_EQ(a, std::string(x)) << "'" << a << "'";
     }
 
-    { // Construct from absl::string_view
+    {  // Construct from absl::string_view
       absl::Cord x(a);
       EXPECT_EQ(a, std::string(x)) << "'" << a << "'";
     }
 
-    { // Append cord to self
+    {  // Append cord to self
       absl::Cord self(a);
       self.Append(self);
       EXPECT_EQ(a + a, std::string(self)) << "'" << a << "' + '" << a << "'";
     }
 
-    { // Prepend cord to self
+    {  // Prepend cord to self
       absl::Cord self(a);
       self.Prepend(self);
       EXPECT_EQ(a + a, std::string(self)) << "'" << a << "' + '" << a << "'";
@@ -538,40 +606,40 @@
     for (size_t j = 0; j < d.size(); j++) {
       std::string b = d.data(j);
 
-      { // CopyFrom Cord
+      {  // CopyFrom Cord
         absl::Cord x(a);
         absl::Cord y(b);
         x = y;
         EXPECT_EQ(b, std::string(x)) << "'" << a << "' + '" << b << "'";
       }
 
-      { // CopyFrom absl::string_view
+      {  // CopyFrom absl::string_view
         absl::Cord x(a);
         x = b;
         EXPECT_EQ(b, std::string(x)) << "'" << a << "' + '" << b << "'";
       }
 
-      { // Cord::Append(Cord)
+      {  // Cord::Append(Cord)
         absl::Cord x(a);
         absl::Cord y(b);
         x.Append(y);
         EXPECT_EQ(a + b, std::string(x)) << "'" << a << "' + '" << b << "'";
       }
 
-      { // Cord::Append(absl::string_view)
+      {  // Cord::Append(absl::string_view)
         absl::Cord x(a);
         x.Append(b);
         EXPECT_EQ(a + b, std::string(x)) << "'" << a << "' + '" << b << "'";
       }
 
-      { // Cord::Prepend(Cord)
+      {  // Cord::Prepend(Cord)
         absl::Cord x(a);
         absl::Cord y(b);
         x.Prepend(y);
         EXPECT_EQ(b + a, std::string(x)) << "'" << b << "' + '" << a << "'";
       }
 
-      { // Cord::Prepend(absl::string_view)
+      {  // Cord::Prepend(absl::string_view)
         absl::Cord x(a);
         x.Prepend(b);
         EXPECT_EQ(b + a, std::string(x)) << "'" << b << "' + '" << a << "'";
@@ -813,7 +881,7 @@
 }
 
 // Test CompareTo() and ComparePrefix() against string and substring
-// comparison methods from std::basic_string.
+// comparison methods from basic_string.
 static void TestCompare(const absl::Cord& c, const absl::Cord& d,
                         RandomEngine* rng) {
   typedef std::basic_string<uint8_t> ustring;
@@ -869,7 +937,7 @@
 
   EXPECT_TRUE(a == a);
   // For pointer type (i.e. `const char*`), operator== compares the address
-  // instead of the std::string, so `a == const char*("a")` isn't necessarily true.
+  // instead of the string, so `a == const char*("a")` isn't necessarily true.
   EXPECT_TRUE(std::is_pointer<T1>::value || a == T1("a"));
   EXPECT_TRUE(std::is_pointer<T2>::value || a == T2("a"));
   EXPECT_FALSE(a == b);
@@ -1032,6 +1100,19 @@
   EXPECT_TRUE(invoked);
 }
 
+TEST(ConstructFromExternal, NoArgLambda) {
+  bool invoked = false;
+  (void)absl::MakeCordFromExternal("dummy", [&invoked]() { invoked = true; });
+  EXPECT_TRUE(invoked);
+}
+
+TEST(ConstructFromExternal, StringViewArgLambda) {
+  bool invoked = false;
+  (void)absl::MakeCordFromExternal(
+      "dummy", [&invoked](absl::string_view) { invoked = true; });
+  EXPECT_TRUE(invoked);
+}
+
 TEST(ConstructFromExternal, NonTrivialReleaserDestructor) {
   struct Releaser {
     explicit Releaser(bool* destroyed) : destroyed(destroyed) {}
@@ -1076,7 +1157,7 @@
 }
 
 TEST(ExternalMemory, BasicUsage) {
-  static const char* strings[] = { "", "hello", "there" };
+  static const char* strings[] = {"", "hello", "there"};
   for (const char* str : strings) {
     absl::Cord dst("(prefix)");
     AddExternalMemory(str, &dst);
@@ -1524,3 +1605,111 @@
     }
   }
 }
+
+TEST(Cord, Format) {
+  absl::Cord c;
+  absl::Format(&c, "There were %04d little %s.", 3, "pigs");
+  EXPECT_EQ(c, "There were 0003 little pigs.");
+  absl::Format(&c, "And %-3llx bad wolf!", 1);
+  EXPECT_EQ(c, "There were 0003 little pigs.And 1   bad wolf!");
+}
+
+TEST(CordDeathTest, Hardening) {
+  absl::Cord cord("hello");
+  // These statement should abort the program in all builds modes.
+  EXPECT_DEATH_IF_SUPPORTED(cord.RemovePrefix(6), "");
+  EXPECT_DEATH_IF_SUPPORTED(cord.RemoveSuffix(6), "");
+
+  bool test_hardening = false;
+  ABSL_HARDENING_ASSERT([&]() {
+    // This only runs when ABSL_HARDENING_ASSERT is active.
+    test_hardening = true;
+    return true;
+  }());
+  if (!test_hardening) return;
+
+  EXPECT_DEATH_IF_SUPPORTED(cord[5], "");
+  EXPECT_DEATH_IF_SUPPORTED(*cord.chunk_end(), "");
+  EXPECT_DEATH_IF_SUPPORTED(static_cast<void>(cord.chunk_end()->empty()), "");
+  EXPECT_DEATH_IF_SUPPORTED(++cord.chunk_end(), "");
+}
+
+class AfterExitCordTester {
+ public:
+  bool Set(absl::Cord* cord, absl::string_view expected) {
+    cord_ = cord;
+    expected_ = expected;
+    return true;
+  }
+
+  ~AfterExitCordTester() {
+    EXPECT_EQ(*cord_, expected_);
+  }
+ private:
+  absl::Cord* cord_;
+  absl::string_view expected_;
+};
+
+template <typename Str>
+void TestConstinitConstructor(Str) {
+  const auto expected = Str::value;
+  // Defined before `cord` to be destroyed after it.
+  static AfterExitCordTester exit_tester;  // NOLINT
+  ABSL_CONST_INIT static absl::Cord cord(Str{});  // NOLINT
+  static bool init_exit_tester = exit_tester.Set(&cord, expected);
+  (void)init_exit_tester;
+
+  EXPECT_EQ(cord, expected);
+  // Copy the object and test the copy, and the original.
+  {
+    absl::Cord copy = cord;
+    EXPECT_EQ(copy, expected);
+  }
+  // The original still works
+  EXPECT_EQ(cord, expected);
+
+  // Try making adding more structure to the tree.
+  {
+    absl::Cord copy = cord;
+    std::string expected_copy(expected);
+    for (int i = 0; i < 10; ++i) {
+      copy.Append(cord);
+      absl::StrAppend(&expected_copy, expected);
+      EXPECT_EQ(copy, expected_copy);
+    }
+  }
+
+  // Make sure we are using the right branch during constant evaluation.
+  EXPECT_EQ(absl::CordTestPeer::IsTree(cord), cord.size() >= 16);
+
+  for (int i = 0; i < 10; ++i) {
+    // Make a few more Cords from the same global rep.
+    // This tests what happens when the refcount for it gets below 1.
+    EXPECT_EQ(expected, absl::Cord(Str{}));
+  }
+}
+
+constexpr int SimpleStrlen(const char* p) {
+  return *p ? 1 + SimpleStrlen(p + 1) : 0;
+}
+
+struct ShortView {
+  constexpr absl::string_view operator()() const {
+    return absl::string_view("SSO string", SimpleStrlen("SSO string"));
+  }
+};
+
+struct LongView {
+  constexpr absl::string_view operator()() const {
+    return absl::string_view("String that does not fit SSO.",
+                             SimpleStrlen("String that does not fit SSO."));
+  }
+};
+
+
+TEST(Cord, ConstinitConstructor) {
+  TestConstinitConstructor(
+      absl::strings_internal::MakeStringConstant(ShortView{}));
+  TestConstinitConstructor(
+      absl::strings_internal::MakeStringConstant(LongView{}));
+}
diff --git a/absl/strings/escaping.cc b/absl/strings/escaping.cc
index 7adc1b6..18b20b8 100644
--- a/absl/strings/escaping.cc
+++ b/absl/strings/escaping.cc
@@ -137,7 +137,7 @@
             // Copy the escape sequence for the null character
             const ptrdiff_t octal_size = p + 1 - octal_start;
             *d++ = '\\';
-            memcpy(d, octal_start, octal_size);
+            memmove(d, octal_start, octal_size);
             d += octal_size;
             break;
           }
@@ -170,7 +170,7 @@
             // Copy the escape sequence for the null character
             const ptrdiff_t hex_size = p + 1 - hex_start;
             *d++ = '\\';
-            memcpy(d, hex_start, hex_size);
+            memmove(d, hex_start, hex_size);
             d += hex_size;
             break;
           }
@@ -203,7 +203,7 @@
           if ((rune == 0) && leave_nulls_escaped) {
             // Copy the escape sequence for the null character
             *d++ = '\\';
-            memcpy(d, hex_start, 5);  // u0000
+            memmove(d, hex_start, 5);  // u0000
             d += 5;
             break;
           }
@@ -251,7 +251,7 @@
           if ((rune == 0) && leave_nulls_escaped) {
             // Copy the escape sequence for the null character
             *d++ = '\\';
-            memcpy(d, hex_start, 9);  // U00000000
+            memmove(d, hex_start, 9);  // U00000000
             d += 9;
             break;
           }
@@ -450,7 +450,7 @@
 
   // The GET_INPUT macro gets the next input character, skipping
   // over any whitespace, and stopping when we reach the end of the
-  // std::string or when we read any non-data character.  The arguments are
+  // string or when we read any non-data character.  The arguments are
   // an arbitrary identifier (used as a label for goto) and the number
   // of data bytes that must remain in the input to avoid aborting the
   // loop.
@@ -473,18 +473,18 @@
   if (dest) {
     // This loop consumes 4 input bytes and produces 3 output bytes
     // per iteration.  We can't know at the start that there is enough
-    // data left in the std::string for a full iteration, so the loop may
+    // data left in the string for a full iteration, so the loop may
     // break out in the middle; if so 'state' will be set to the
     // number of input bytes read.
 
     while (szsrc >= 4) {
       // We'll start by optimistically assuming that the next four
-      // bytes of the std::string (src[0..3]) are four good data bytes
+      // bytes of the string (src[0..3]) are four good data bytes
       // (that is, no nulls, whitespace, padding chars, or illegal
       // chars).  We need to test src[0..2] for nulls individually
       // before constructing temp to preserve the property that we
-      // never read past a null in the std::string (no matter how long
-      // szsrc claims the std::string is).
+      // never read past a null in the string (no matter how long
+      // szsrc claims the string is).
 
       if (!src[0] || !src[1] || !src[2] ||
           ((temp = ((unsigned(unbase64[src[0]]) << 18) |
@@ -509,7 +509,7 @@
         temp = (temp << 6) | decode;
       } else {
         // We really did have four good data bytes, so advance four
-        // characters in the std::string.
+        // characters in the string.
 
         szsrc -= 4;
         src += 4;
@@ -644,7 +644,7 @@
                    state);
   }
 
-  // The remainder of the std::string should be all whitespace, mixed with
+  // The remainder of the string should be all whitespace, mixed with
   // exactly 0 equals signs, or exactly 'expected_equals' equals
   // signs.  (Always accepting 0 equals signs is an Abseil extension
   // not covered in the RFC, as is accepting dot as the pad character.)
@@ -771,7 +771,7 @@
 template <typename String>
 bool Base64UnescapeInternal(const char* src, size_t slen, String* dest,
                             const signed char* unbase64) {
-  // Determine the size of the output std::string.  Base64 encodes every 3 bytes into
+  // Determine the size of the output string.  Base64 encodes every 3 bytes into
   // 4 characters.  any leftover chars are added directly for good measure.
   // This is documented in the base64 RFC: http://tools.ietf.org/html/rfc3548
   const size_t dest_len = 3 * (slen / 4) + (slen % 4);
@@ -779,7 +779,7 @@
   strings_internal::STLStringResizeUninitialized(dest, dest_len);
 
   // We are getting the destination buffer by getting the beginning of the
-  // std::string and converting it into a char *.
+  // string and converting it into a char *.
   size_t len;
   const bool ok =
       Base64UnescapeInternal(src, slen, &(*dest)[0], dest_len, unbase64, &len);
diff --git a/absl/strings/escaping_test.cc b/absl/strings/escaping_test.cc
index 1967975..45671a0 100644
--- a/absl/strings/escaping_test.cc
+++ b/absl/strings/escaping_test.cc
@@ -300,7 +300,7 @@
   absl::string_view plaintext;
   absl::string_view cyphertext;
 } const base64_tests[] = {
-    // Empty std::string.
+    // Empty string.
     {{"", 0}, {"", 0}},
     {{nullptr, 0},
      {"", 0}},  // if length is zero, plaintext ptr must be ignored!
@@ -586,7 +586,7 @@
     EXPECT_EQ(encoded, websafe);
     EXPECT_EQ(absl::WebSafeBase64Escape(tc.plaintext), websafe);
 
-    // Let's try the std::string version of the decoder
+    // Let's try the string version of the decoder
     decoded = "this junk should be ignored";
     EXPECT_TRUE(absl::WebSafeBase64Unescape(websafe, &decoded));
     EXPECT_EQ(decoded, tc.plaintext);
@@ -625,7 +625,7 @@
   std::string escaped;
   absl::Base64Escape(huge, &escaped);
 
-  // Generates the std::string that should match a base64 encoded "xxx..." std::string.
+  // Generates the string that should match a base64 encoded "xxx..." string.
   // "xxx" in base64 is "eHh4".
   std::string expected_encoding;
   expected_encoding.reserve(kSize / 3 * 4);
diff --git a/absl/strings/internal/char_map.h b/absl/strings/internal/char_map.h
index a76e603..61484de 100644
--- a/absl/strings/internal/char_map.h
+++ b/absl/strings/internal/char_map.h
@@ -72,7 +72,7 @@
                    CharMaskForWord(x, 2), CharMaskForWord(x, 3));
   }
 
-  // Containing all the chars in the C-std::string 's'.
+  // Containing all the chars in the C-string 's'.
   // Note that this is expensively recursive because of the C++11 constexpr
   // formulation. Use only in constexpr initializers.
   static constexpr Charmap FromString(const char* s) {
diff --git a/absl/strings/internal/charconv_bigint.cc b/absl/strings/internal/charconv_bigint.cc
index 66f33e7..ebf8c07 100644
--- a/absl/strings/internal/charconv_bigint.cc
+++ b/absl/strings/internal/charconv_bigint.cc
@@ -208,7 +208,7 @@
     ++dropped_digits;
   }
   if (begin < end && *std::prev(end) == '.') {
-    // If the std::string ends in '.', either before or after dropping zeroes, then
+    // If the string ends in '.', either before or after dropping zeroes, then
     // drop the decimal point and look for more digits to drop.
     dropped_digits = 0;
     --end;
diff --git a/absl/strings/internal/charconv_bigint.h b/absl/strings/internal/charconv_bigint.h
index 999e9ae..8f70297 100644
--- a/absl/strings/internal/charconv_bigint.h
+++ b/absl/strings/internal/charconv_bigint.h
@@ -66,7 +66,7 @@
                static_cast<uint32_t>(v >> 32)} {}
 
   // Constructs a BigUnsigned from the given string_view containing a decimal
-  // value.  If the input std::string is not a decimal integer, constructs a 0
+  // value.  If the input string is not a decimal integer, constructs a 0
   // instead.
   explicit BigUnsigned(absl::string_view sv) : size_(0), words_{} {
     // Check for valid input, returning a 0 otherwise.  This is reasonable
@@ -210,7 +210,7 @@
     return words_[index];
   }
 
-  // Returns this integer as a decimal std::string.  This is not used in the decimal-
+  // Returns this integer as a decimal string.  This is not used in the decimal-
   // to-binary conversion; it is intended to aid in testing.
   std::string ToString() const;
 
diff --git a/absl/strings/internal/charconv_bigint_test.cc b/absl/strings/internal/charconv_bigint_test.cc
index 363bcb0..a8b9945 100644
--- a/absl/strings/internal/charconv_bigint_test.cc
+++ b/absl/strings/internal/charconv_bigint_test.cc
@@ -69,6 +69,61 @@
     // And we should have fully rotated all bits off by now:
     EXPECT_EQ(a, BigUnsigned<84>(0u));
   }
+  {
+    // Bit shifting large and small numbers by large and small offsets.
+    // Intended to exercise bounds-checking corner on ShiftLeft() (directly
+    // and under asan).
+
+    // 2**(32*84)-1
+    const BigUnsigned<84> all_bits_one(
+        "1474444211396924248063325089479706787923460402125687709454567433186613"
+        "6228083464060749874845919674257665016359189106695900028098437021384227"
+        "3285029708032466536084583113729486015826557532750465299832071590813090"
+        "2011853039837649252477307070509704043541368002938784757296893793903797"
+        "8180292336310543540677175225040919704702800559606097685920595947397024"
+        "8303316808753252115729411497720357971050627997031988036134171378490368"
+        "6008000778741115399296162550786288457245180872759047016734959330367829"
+        "5235612397427686310674725251378116268607113017720538636924549612987647"
+        "5767411074510311386444547332882472126067840027882117834454260409440463"
+        "9345147252664893456053258463203120637089916304618696601333953616715125"
+        "2115882482473279040772264257431663818610405673876655957323083702713344"
+        "4201105427930770976052393421467136557055");
+    const BigUnsigned<84> zero(0u);
+    const BigUnsigned<84> one(1u);
+    // in bounds shifts
+    for (int i = 1; i < 84*32; ++i) {
+      // shifting all_bits_one to the left should result in a smaller number,
+      // since the high bits rotate off and the low bits are replaced with
+      // zeroes.
+      BigUnsigned<84> big_shifted = all_bits_one;
+      big_shifted.ShiftLeft(i);
+      EXPECT_GT(all_bits_one, big_shifted);
+      // Shifting 1 to the left should instead result in a larger number.
+      BigUnsigned<84> small_shifted = one;
+      small_shifted.ShiftLeft(i);
+      EXPECT_LT(one, small_shifted);
+    }
+    // Shifting by zero or a negative number has no effect
+    for (int no_op_shift : {0, -1, -84 * 32, std::numeric_limits<int>::min()}) {
+      BigUnsigned<84> big_shifted = all_bits_one;
+      big_shifted.ShiftLeft(no_op_shift);
+      EXPECT_EQ(all_bits_one, big_shifted);
+      BigUnsigned<84> small_shifted = one;
+      big_shifted.ShiftLeft(no_op_shift);
+      EXPECT_EQ(one, small_shifted);
+    }
+    // Shifting by an amount greater than the number of bits should result in
+    // zero.
+    for (int out_of_bounds_shift :
+         {84 * 32, 84 * 32 + 1, std::numeric_limits<int>::max()}) {
+      BigUnsigned<84> big_shifted = all_bits_one;
+      big_shifted.ShiftLeft(out_of_bounds_shift);
+      EXPECT_EQ(zero, big_shifted);
+      BigUnsigned<84> small_shifted = one;
+      small_shifted.ShiftLeft(out_of_bounds_shift);
+      EXPECT_EQ(zero, small_shifted);
+    }
+  }
 }
 
 TEST(BigUnsigned, MultiplyByUint32) {
diff --git a/absl/strings/internal/charconv_parse.cc b/absl/strings/internal/charconv_parse.cc
index d9a57a7..8b11868 100644
--- a/absl/strings/internal/charconv_parse.cc
+++ b/absl/strings/internal/charconv_parse.cc
@@ -246,8 +246,8 @@
 // ConsumeDigits does not protect against overflow on *out; max_digits must
 // be chosen with respect to type T to avoid the possibility of overflow.
 template <int base, typename T>
-std::size_t ConsumeDigits(const char* begin, const char* end, int max_digits,
-                          T* out, bool* dropped_nonzero_digit) {
+int ConsumeDigits(const char* begin, const char* end, int max_digits, T* out,
+                  bool* dropped_nonzero_digit) {
   if (base == 10) {
     assert(max_digits <= std::numeric_limits<T>::digits10);
   } else if (base == 16) {
@@ -282,7 +282,7 @@
     *dropped_nonzero_digit = true;
   }
   *out = accumulator;
-  return begin - original_begin;
+  return static_cast<int>(begin - original_begin);
 }
 
 // Returns true if `v` is one of the chars allowed inside parentheses following
@@ -302,7 +302,7 @@
   switch (*begin) {
     case 'i':
     case 'I': {
-      // An infinity std::string consists of the characters "inf" or "infinity",
+      // An infinity string consists of the characters "inf" or "infinity",
       // case insensitive.
       if (strings_internal::memcasecmp(begin + 1, "nf", 2) != 0) {
         return false;
@@ -326,7 +326,7 @@
       }
       out->type = strings_internal::FloatType::kNan;
       out->end = begin + 3;
-      // NaN is allowed to be followed by a parenthesized std::string, consisting of
+      // NaN is allowed to be followed by a parenthesized string, consisting of
       // only the characters [a-zA-Z0-9_].  Match that if it's present.
       begin += 3;
       if (begin < end && *begin == '(') {
@@ -372,7 +372,7 @@
 
   int exponent_adjustment = 0;
   bool mantissa_is_inexact = false;
-  std::size_t pre_decimal_digits = ConsumeDigits<base>(
+  int pre_decimal_digits = ConsumeDigits<base>(
       begin, end, MantissaDigitsMax<base>(), &mantissa, &mantissa_is_inexact);
   begin += pre_decimal_digits;
   int digits_left;
@@ -398,14 +398,14 @@
       while (begin < end && *begin == '0') {
         ++begin;
       }
-      std::size_t zeros_skipped = begin - begin_zeros;
+      int zeros_skipped = static_cast<int>(begin - begin_zeros);
       if (zeros_skipped >= DigitLimit<base>()) {
         // refuse to parse pathological inputs
         return result;
       }
       exponent_adjustment -= static_cast<int>(zeros_skipped);
     }
-    std::size_t post_decimal_digits = ConsumeDigits<base>(
+    int post_decimal_digits = ConsumeDigits<base>(
         begin, end, digits_left, &mantissa, &mantissa_is_inexact);
     begin += post_decimal_digits;
 
diff --git a/absl/strings/internal/charconv_parse_test.cc b/absl/strings/internal/charconv_parse_test.cc
index 9511c98..bc2d111 100644
--- a/absl/strings/internal/charconv_parse_test.cc
+++ b/absl/strings/internal/charconv_parse_test.cc
@@ -63,7 +63,7 @@
   }
   const std::string::size_type expected_characters_matched = s.find('$');
   ABSL_RAW_CHECK(expected_characters_matched != std::string::npos,
-                 "Input std::string must contain $");
+                 "Input string must contain $");
   s.replace(expected_characters_matched, 1, "");
 
   ParsedFloat parsed =
diff --git a/absl/strings/internal/cord_internal.cc b/absl/strings/internal/cord_internal.cc
new file mode 100644
index 0000000..905ffd0
--- /dev/null
+++ b/absl/strings/internal/cord_internal.cc
@@ -0,0 +1,83 @@
+// 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/strings/internal/cord_internal.h"
+
+#include <atomic>
+#include <cassert>
+#include <memory>
+
+#include "absl/container/inlined_vector.h"
+#include "absl/strings/internal/cord_rep_flat.h"
+#include "absl/strings/internal/cord_rep_ring.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+ABSL_CONST_INIT std::atomic<bool> cord_ring_buffer_enabled(
+    kCordEnableRingBufferDefault);
+ABSL_CONST_INIT std::atomic<bool> shallow_subcords_enabled(
+    kCordShallowSubcordsDefault);
+
+void CordRep::Destroy(CordRep* rep) {
+  assert(rep != nullptr);
+
+  absl::InlinedVector<CordRep*, Constants::kInlinedVectorSize> pending;
+  while (true) {
+    assert(!rep->refcount.IsImmortal());
+    if (rep->tag == CONCAT) {
+      CordRepConcat* rep_concat = rep->concat();
+      CordRep* right = rep_concat->right;
+      if (!right->refcount.Decrement()) {
+        pending.push_back(right);
+      }
+      CordRep* left = rep_concat->left;
+      delete rep_concat;
+      rep = nullptr;
+      if (!left->refcount.Decrement()) {
+        rep = left;
+        continue;
+      }
+    } else if (rep->tag == RING) {
+      CordRepRing::Destroy(rep->ring());
+      rep = nullptr;
+    } else if (rep->tag == EXTERNAL) {
+      CordRepExternal::Delete(rep);
+      rep = nullptr;
+    } else if (rep->tag == SUBSTRING) {
+      CordRepSubstring* rep_substring = rep->substring();
+      CordRep* child = rep_substring->child;
+      delete rep_substring;
+      rep = nullptr;
+      if (!child->refcount.Decrement()) {
+        rep = child;
+        continue;
+      }
+    } else {
+      CordRepFlat::Delete(rep);
+      rep = nullptr;
+    }
+
+    if (!pending.empty()) {
+      rep = pending.back();
+      pending.pop_back();
+    } else {
+      break;
+    }
+  }
+}
+
+}  // namespace cord_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/strings/internal/cord_internal.h b/absl/strings/internal/cord_internal.h
index 5b5d108..a1ba67f 100644
--- a/absl/strings/internal/cord_internal.h
+++ b/absl/strings/internal/cord_internal.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Abseil Authors.
+// Copyright 2021 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.
@@ -21,6 +21,11 @@
 #include <cstdint>
 #include <type_traits>
 
+#include "absl/base/config.h"
+#include "absl/base/internal/endian.h"
+#include "absl/base/internal/invoke.h"
+#include "absl/base/optimization.h"
+#include "absl/container/internal/compressed_tuple.h"
 #include "absl/meta/type_traits.h"
 #include "absl/strings/string_view.h"
 
@@ -28,17 +33,55 @@
 ABSL_NAMESPACE_BEGIN
 namespace cord_internal {
 
+class CordzInfo;
+
+// Default feature enable states for cord ring buffers
+enum CordFeatureDefaults {
+  kCordEnableRingBufferDefault = false,
+  kCordShallowSubcordsDefault = false
+};
+
+extern std::atomic<bool> cord_ring_buffer_enabled;
+extern std::atomic<bool> shallow_subcords_enabled;
+
+inline void enable_cord_ring_buffer(bool enable) {
+  cord_ring_buffer_enabled.store(enable, std::memory_order_relaxed);
+}
+
+inline void enable_shallow_subcords(bool enable) {
+  shallow_subcords_enabled.store(enable, std::memory_order_relaxed);
+}
+
+enum Constants {
+  // The inlined size to use with absl::InlinedVector.
+  //
+  // Note: The InlinedVectors in this file (and in cord.h) do not need to use
+  // the same value for their inlined size. The fact that they do is historical.
+  // It may be desirable for each to use a different inlined size optimized for
+  // that InlinedVector's usage.
+  //
+  // TODO(jgm): Benchmark to see if there's a more optimal value than 47 for
+  // the inlined vector size (47 exists for backward compatibility).
+  kInlinedVectorSize = 47,
+
+  // Prefer copying blocks of at most this size, otherwise reference count.
+  kMaxBytesToCopy = 511
+};
+
 // Wraps std::atomic for reference counting.
 class Refcount {
  public:
-  Refcount() : count_{1} {}
-  ~Refcount() {}
+  constexpr Refcount() : count_{kRefIncrement} {}
+  struct Immortal {};
+  explicit constexpr Refcount(Immortal) : count_(kImmortalTag) {}
 
-  // Increments the reference count by 1. Imposes no memory ordering.
-  inline void Increment() { count_.fetch_add(1, std::memory_order_relaxed); }
+  // Increments the reference count. Imposes no memory ordering.
+  inline void Increment() {
+    count_.fetch_add(kRefIncrement, std::memory_order_relaxed);
+  }
 
   // Asserts that the current refcount is greater than 0. If the refcount is
-  // greater than 1, decrements the reference count by 1.
+  // greater than 1, decrements the reference count.
   //
   // Returns false if there are no references outstanding; true otherwise.
   // Inserts barriers to ensure that state written before this method returns
@@ -46,19 +89,24 @@
   // false.
   inline bool Decrement() {
     int32_t refcount = count_.load(std::memory_order_acquire);
-    assert(refcount > 0);
-    return refcount != 1 && count_.fetch_sub(1, std::memory_order_acq_rel) != 1;
+    assert(refcount > 0 || refcount & kImmortalTag);
+    return refcount != kRefIncrement &&
+           count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel) !=
+               kRefIncrement;
   }
 
   // Same as Decrement but expect that refcount is greater than 1.
   inline bool DecrementExpectHighRefcount() {
-    int32_t refcount = count_.fetch_sub(1, std::memory_order_acq_rel);
-    assert(refcount > 0);
-    return refcount != 1;
+    int32_t refcount =
+        count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel);
+    assert(refcount > 0 || refcount & kImmortalTag);
+    return refcount != kRefIncrement;
   }
 
   // Returns the current reference count using acquire semantics.
-  inline int32_t Get() const { return count_.load(std::memory_order_acquire); }
+  inline int32_t Get() const {
+    return count_.load(std::memory_order_acquire) >> kImmortalShift;
+  }
 
   // Returns whether the atomic integer is 1.
   // If the reference count is used in the conventional way, a
@@ -68,9 +116,27 @@
   // performs the memory barrier needed for the owning thread
   // to act on the object, knowing that it has exclusive access to the
   // object.
-  inline bool IsOne() { return count_.load(std::memory_order_acquire) == 1; }
+  inline bool IsOne() {
+    return count_.load(std::memory_order_acquire) == kRefIncrement;
+  }
+
+  bool IsImmortal() const {
+    return (count_.load(std::memory_order_relaxed) & kImmortalTag) != 0;
+  }
 
  private:
+  // We reserve the bottom bit to tag a reference count as immortal.
+  // By making it `1` we ensure that we never reach `0` when adding/subtracting
+  // `2`, thus it never looks as if it should be destroyed.
+  // These are used for the StringConstant constructor where we do not increase
+  // the refcount at construction time (due to constinit requirements) but we
+  // will still decrease it at destruction time to avoid branching on Unref.
+  enum {
+    kImmortalShift = 1,
+    kRefIncrement = 1 << kImmortalShift,
+    kImmortalTag = kRefIncrement - 1
+  };
+
   std::atomic<int32_t> count_;
 };
 
@@ -80,34 +146,74 @@
 // functions in the base class.
 
 struct CordRepConcat;
-struct CordRepSubstring;
 struct CordRepExternal;
+struct CordRepFlat;
+struct CordRepSubstring;
+class CordRepRing;
+
+// Various representations that we allow
+enum CordRepKind {
+  CONCAT = 0,
+  EXTERNAL = 1,
+  SUBSTRING = 2,
+  RING = 3,
+
+  // We have different tags for different sized flat arrays,
+  // starting with FLAT, and limited to MAX_FLAT_TAG. The 224 value is based on
+  // the current 'size to tag' encoding of 8 / 32 bytes. If a new tag is needed
+  // in the future, then 'FLAT' and 'MAX_FLAT_TAG' should be adjusted as well
+  // as the Tag <---> Size logic so that FLAT stil represents the minimum flat
+  // allocation size. (32 bytes as of now).
+  FLAT = 4,
+  MAX_FLAT_TAG = 224
+};
 
 struct CordRep {
+  CordRep() = default;
+  constexpr CordRep(Refcount::Immortal immortal, size_t l)
+      : length(l), refcount(immortal), tag(EXTERNAL), storage{} {}
+
   // The following three fields have to be less than 32 bytes since
   // that is the smallest supported flat node size.
-  // We use uint64_t for the length even in 32-bit binaries.
-  uint64_t length;
+  size_t length;
   Refcount refcount;
   // If tag < FLAT, it represents CordRepKind and indicates the type of node.
   // Otherwise, the node type is CordRepFlat and the tag is the encoded size.
   uint8_t tag;
-  char data[1];  // Starting point for flat array: MUST BE LAST FIELD of CordRep
+  char storage[1];  // Starting point for flat array: MUST BE LAST FIELD
 
+  inline CordRepRing* ring();
+  inline const CordRepRing* ring() const;
   inline CordRepConcat* concat();
   inline const CordRepConcat* concat() const;
   inline CordRepSubstring* substring();
   inline const CordRepSubstring* substring() const;
   inline CordRepExternal* external();
   inline const CordRepExternal* external() const;
+  inline CordRepFlat* flat();
+  inline const CordRepFlat* flat() const;
+
+  // --------------------------------------------------------------------
+  // Memory management
+
+  // Destroys the provided `rep`.
+  static void Destroy(CordRep* rep);
+
+  // Increments the reference count of `rep`.
+  // Requires `rep` to be a non-null pointer value.
+  static inline CordRep* Ref(CordRep* rep);
+
+  // Decrements the reference count of `rep`. Destroys rep if count reaches
+  // zero. Requires `rep` to be a non-null pointer value.
+  static inline void Unref(CordRep* rep);
 };
 
 struct CordRepConcat : public CordRep {
   CordRep* left;
   CordRep* right;
 
-  uint8_t depth() const { return static_cast<uint8_t>(data[0]); }
-  void set_depth(uint8_t depth) { data[0] = static_cast<char>(depth); }
+  uint8_t depth() const { return static_cast<uint8_t>(storage[0]); }
+  void set_depth(uint8_t depth) { storage[0] = static_cast<char>(depth); }
 };
 
 struct CordRepSubstring : public CordRep {
@@ -115,37 +221,323 @@
   CordRep* child;
 };
 
-// TODO(strel): replace the following logic (and related functions in cord.cc)
-// with container_internal::Layout.
-
-// Alignment requirement for CordRepExternal so that the type erased releaser
-// will be stored at a suitably aligned address.
-constexpr size_t ExternalRepAlignment() {
-#if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__)
-  return __STDCPP_DEFAULT_NEW_ALIGNMENT__;
-#else
-  return alignof(max_align_t);
-#endif
-}
-
-// Type for function pointer that will invoke and destroy the type-erased
-// releaser function object. Accepts a pointer to the releaser and the
-// `string_view` that were passed in to `NewExternalRep` below. The return value
-// is the size of the `Releaser` type.
-using ExternalReleaserInvoker = size_t (*)(void*, absl::string_view);
+// Type for function pointer that will invoke the releaser function and also
+// delete the `CordRepExternalImpl` corresponding to the passed in
+// `CordRepExternal`.
+using ExternalReleaserInvoker = void (*)(CordRepExternal*);
 
 // External CordReps are allocated together with a type erased releaser. The
 // releaser is stored in the memory directly following the CordRepExternal.
-struct alignas(ExternalRepAlignment()) CordRepExternal : public CordRep {
+struct CordRepExternal : public CordRep {
+  CordRepExternal() = default;
+  explicit constexpr CordRepExternal(absl::string_view str)
+      : CordRep(Refcount::Immortal{}, str.size()),
+        base(str.data()),
+        releaser_invoker(nullptr) {}
+
   const char* base;
   // Pointer to function that knows how to call and destroy the releaser.
   ExternalReleaserInvoker releaser_invoker;
+
+  // Deletes (releases) the external rep.
+  // Requires rep != nullptr and rep->tag == EXTERNAL
+  static void Delete(CordRep* rep);
 };
 
-// TODO(strel): look into removing, it doesn't seem like anything relies on this
-static_assert(sizeof(CordRepConcat) == sizeof(CordRepSubstring), "");
+struct Rank1 {};
+struct Rank0 : Rank1 {};
+
+template <typename Releaser, typename = ::absl::base_internal::invoke_result_t<
+                                 Releaser, absl::string_view>>
+void InvokeReleaser(Rank0, Releaser&& releaser, absl::string_view data) {
+  ::absl::base_internal::invoke(std::forward<Releaser>(releaser), data);
+}
+
+template <typename Releaser,
+          typename = ::absl::base_internal::invoke_result_t<Releaser>>
+void InvokeReleaser(Rank1, Releaser&& releaser, absl::string_view) {
+  ::absl::base_internal::invoke(std::forward<Releaser>(releaser));
+}
+
+// We use CompressedTuple so that we can benefit from EBCO.
+template <typename Releaser>
+struct CordRepExternalImpl
+    : public CordRepExternal,
+      public ::absl::container_internal::CompressedTuple<Releaser> {
+  // The extra int arg is so that we can avoid interfering with copy/move
+  // constructors while still benefitting from perfect forwarding.
+  template <typename T>
+  CordRepExternalImpl(T&& releaser, int)
+      : CordRepExternalImpl::CompressedTuple(std::forward<T>(releaser)) {
+    this->releaser_invoker = &Release;
+  }
+
+  ~CordRepExternalImpl() {
+    InvokeReleaser(Rank0{}, std::move(this->template get<0>()),
+                   absl::string_view(base, length));
+  }
+
+  static void Release(CordRepExternal* rep) {
+    delete static_cast<CordRepExternalImpl*>(rep);
+  }
+};
+
+inline void CordRepExternal::Delete(CordRep* rep) {
+  assert(rep != nullptr && rep->tag == EXTERNAL);
+  auto* rep_external = static_cast<CordRepExternal*>(rep);
+  assert(rep_external->releaser_invoker != nullptr);
+  rep_external->releaser_invoker(rep_external);
+}
+
+template <typename Str>
+struct ConstInitExternalStorage {
+  ABSL_CONST_INIT static CordRepExternal value;
+};
+
+template <typename Str>
+CordRepExternal ConstInitExternalStorage<Str>::value(Str::value);
+
+enum {
+  kMaxInline = 15,
+};
+
+constexpr char GetOrNull(absl::string_view data, size_t pos) {
+  return pos < data.size() ? data[pos] : '\0';
+}
+
+// We store cordz_info as 64 bit pointer value in big endian format. This
+// guarantees that the least significant byte of cordz_info matches the last
+// byte of the inline data representation in as_chars_, which holds the inlined
+// size or the 'is_tree' bit.
+using cordz_info_t = int64_t;
+
+// Assert that the `cordz_info` pointer value perfectly overlaps the last half
+// of `as_chars_` and can hold a pointer value.
+static_assert(sizeof(cordz_info_t) * 2 == kMaxInline + 1, "");
+static_assert(sizeof(cordz_info_t) >= sizeof(intptr_t), "");
+
+// BigEndianByte() creates a big endian representation of 'value', i.e.: a big
+// endian value where the last byte in the host's representation holds 'value`,
+// with all other bytes being 0.
+static constexpr cordz_info_t BigEndianByte(unsigned char value) {
+#if defined(ABSL_IS_BIG_ENDIAN)
+  return value;
+#else
+  return static_cast<cordz_info_t>(value) << ((sizeof(cordz_info_t) - 1) * 8);
+#endif
+}
+
+class InlineData {
+ public:
+  // kNullCordzInfo holds the big endian representation of intptr_t(1)
+  // This is the 'null' / initial value of 'cordz_info'. The null value
+  // is specifically big endian 1 as with 64-bit pointers, the last
+  // byte of cordz_info overlaps with the last byte holding the tag.
+  static constexpr cordz_info_t kNullCordzInfo = BigEndianByte(1);
+
+  // kFakeCordzInfo holds a 'fake', non-null cordz-info value we use to
+  // emulate the previous 'kProfiled' tag logic in 'set_profiled' until
+  // cord code is changed to store cordz_info values in InlineData.
+  static constexpr cordz_info_t kFakeCordzInfo = BigEndianByte(9);
+
+  constexpr InlineData() : as_chars_{0} {}
+  explicit constexpr InlineData(CordRep* rep) : as_tree_(rep) {}
+  explicit constexpr InlineData(absl::string_view chars)
+      : as_chars_{
+            GetOrNull(chars, 0),  GetOrNull(chars, 1),
+            GetOrNull(chars, 2),  GetOrNull(chars, 3),
+            GetOrNull(chars, 4),  GetOrNull(chars, 5),
+            GetOrNull(chars, 6),  GetOrNull(chars, 7),
+            GetOrNull(chars, 8),  GetOrNull(chars, 9),
+            GetOrNull(chars, 10), GetOrNull(chars, 11),
+            GetOrNull(chars, 12), GetOrNull(chars, 13),
+            GetOrNull(chars, 14), static_cast<char>((chars.size() << 1))} {}
+
+  // Returns true if the current instance is empty.
+  // The 'empty value' is an inlined data value of zero length.
+  bool is_empty() const { return tag() == 0; }
+
+  // Returns true if the current instance holds a tree value.
+  bool is_tree() const { return (tag() & 1) != 0; }
+
+  // Returns true if the current instance holds a cordz_info value.
+  // Requires the current instance to hold a tree value.
+  bool is_profiled() const {
+    assert(is_tree());
+    return as_tree_.cordz_info != kNullCordzInfo;
+  }
+
+  // Returns the cordz_info sampling instance for this instance, or nullptr
+  // if the current instance is not sampled and does not have CordzInfo data.
+  // Requires the current instance to hold a tree value.
+  CordzInfo* cordz_info() const {
+    assert(is_tree());
+    intptr_t info =
+        static_cast<intptr_t>(absl::big_endian::ToHost64(as_tree_.cordz_info));
+    assert(info & 1);
+    return reinterpret_cast<CordzInfo*>(info - 1);
+  }
+
+  // Sets the current cordz_info sampling instance for this instance, or nullptr
+  // if the current instance is not sampled and does not have CordzInfo data.
+  // Requires the current instance to hold a tree value.
+  void set_cordz_info(CordzInfo* cordz_info) {
+    assert(is_tree());
+    intptr_t info = reinterpret_cast<intptr_t>(cordz_info) | 1;
+    as_tree_.cordz_info = absl::big_endian::FromHost64(info);
+  }
+
+  // Resets the current cordz_info to null / empty.
+  void clear_cordz_info() {
+    assert(is_tree());
+    as_tree_.cordz_info = kNullCordzInfo;
+  }
+
+  // Returns a read only pointer to the character data inside this instance.
+  // Requires the current instance to hold inline data.
+  const char* as_chars() const {
+    assert(!is_tree());
+    return as_chars_;
+  }
+
+  // Returns a mutable pointer to the character data inside this instance.
+  // Should be used for 'write only' operations setting an inlined value.
+  // Applications can set the value of inlined data either before or after
+  // setting the inlined size, i.e., both of the below are valid:
+  //
+  //   // Set inlined data and inline size
+  //   memcpy(data_.as_chars(), data, size);
+  //   data_.set_inline_size(size);
+  //
+  //   // Set inlined size and inline data
+  //   data_.set_inline_size(size);
+  //   memcpy(data_.as_chars(), data, size);
+  //
+  // It's an error to read from the returned pointer without a preceding write
+  // if the current instance does not hold inline data, i.e.: is_tree() == true.
+  char* as_chars() { return as_chars_; }
+
+  // Returns the tree value of this value.
+  // Requires the current instance to hold a tree value.
+  CordRep* as_tree() const {
+    assert(is_tree());
+    return as_tree_.rep;
+  }
+
+  // Initialize this instance to holding the tree value `rep`,
+  // initializing the cordz_info to null, i.e.: 'not profiled'.
+  void make_tree(CordRep* rep) {
+    as_tree_.rep = rep;
+    as_tree_.cordz_info = kNullCordzInfo;
+  }
+
+  // Set the tree value of this instance to 'rep`.
+  // Requires the current instance to already hold a tree value.
+  // Does not affect the value of cordz_info.
+  void set_tree(CordRep* rep) {
+    assert(is_tree());
+    as_tree_.rep = rep;
+  }
+
+  // Returns the size of the inlined character data inside this instance.
+  // Requires the current instance to hold inline data.
+  size_t inline_size() const {
+    assert(!is_tree());
+    return tag() >> 1;
+  }
+
+  // Sets the size of the inlined character data inside this instance.
+  // Requires `size` to be <= kMaxInline.
+  // See the documentation on 'as_chars()' for more information and examples.
+  void set_inline_size(size_t size) {
+    ABSL_ASSERT(size <= kMaxInline);
+    tag() = static_cast<char>(size << 1);
+  }
+
+  // Sets or unsets the 'is_profiled' state of this instance.
+  // Requires the current instance to hold a tree value.
+  void set_profiled(bool profiled) {
+    assert(is_tree());
+    as_tree_.cordz_info = profiled ? kFakeCordzInfo : kNullCordzInfo;
+  }
+
+ private:
+  // See cordz_info_t for forced alignment and size of `cordz_info` details.
+  struct AsTree {
+    explicit constexpr AsTree(absl::cord_internal::CordRep* tree)
+        : rep(tree), cordz_info(kNullCordzInfo) {}
+    // This union uses up extra space so that whether rep is 32 or 64 bits,
+    // cordz_info will still start at the eighth byte, and the last
+    // byte of cordz_info will still be the last byte of InlineData.
+    union {
+      absl::cord_internal::CordRep* rep;
+      cordz_info_t unused_aligner;
+    };
+    cordz_info_t cordz_info;
+  };
+
+  char& tag() { return reinterpret_cast<char*>(this)[kMaxInline]; }
+  char tag() const { return reinterpret_cast<const char*>(this)[kMaxInline]; }
+
+  // If the data has length <= kMaxInline, we store it in `as_chars_`, and
+  // store the size in the last char of `as_chars_` shifted left + 1.
+  // Else we store it in a tree and store a pointer to that tree in
+  // `as_tree_.rep` and store a tag in `tagged_size`.
+  union  {
+    char as_chars_[kMaxInline + 1];
+    AsTree as_tree_;
+  };
+};
+
+static_assert(sizeof(InlineData) == kMaxInline + 1, "");
+
+inline CordRepConcat* CordRep::concat() {
+  assert(tag == CONCAT);
+  return static_cast<CordRepConcat*>(this);
+}
+
+inline const CordRepConcat* CordRep::concat() const {
+  assert(tag == CONCAT);
+  return static_cast<const CordRepConcat*>(this);
+}
+
+inline CordRepSubstring* CordRep::substring() {
+  assert(tag == SUBSTRING);
+  return static_cast<CordRepSubstring*>(this);
+}
+
+inline const CordRepSubstring* CordRep::substring() const {
+  assert(tag == SUBSTRING);
+  return static_cast<const CordRepSubstring*>(this);
+}
+
+inline CordRepExternal* CordRep::external() {
+  assert(tag == EXTERNAL);
+  return static_cast<CordRepExternal*>(this);
+}
+
+inline const CordRepExternal* CordRep::external() const {
+  assert(tag == EXTERNAL);
+  return static_cast<const CordRepExternal*>(this);
+}
+
+inline CordRep* CordRep::Ref(CordRep* rep) {
+  assert(rep != nullptr);
+  rep->refcount.Increment();
+  return rep;
+}
+
+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);
+  }
+}
 
 }  // namespace cord_internal
+
 ABSL_NAMESPACE_END
 }  // namespace absl
 #endif  // ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_
diff --git a/absl/strings/internal/cord_rep_flat.h b/absl/strings/internal/cord_rep_flat.h
new file mode 100644
index 0000000..a98aa9d
--- /dev/null
+++ b/absl/strings/internal/cord_rep_flat.h
@@ -0,0 +1,146 @@
+// 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.
+
+#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
+#define ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+
+#include "absl/strings/internal/cord_internal.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+// Note: all constants below are never ODR used and internal to cord, we define
+// these as static constexpr to avoid 'in struct' definition and usage clutter.
+
+// Largest and smallest flat node lengths we are willing to allocate
+// Flat allocation size is stored in tag, which currently can encode sizes up
+// to 4K, encoded as multiple of either 8 or 32 bytes.
+// If we allow for larger sizes, we need to change this to 8/64, 16/128, etc.
+// kMinFlatSize is bounded by tag needing to be at least FLAT * 8 bytes, and
+// ideally a 'nice' size aligning with allocation and cacheline sizes like 32.
+// kMaxFlatSize is bounded by the size resulting in a computed tag no greater
+// than MAX_FLAT_TAG. MAX_FLAT_TAG provides for additional 'high' tag values.
+static constexpr size_t kFlatOverhead = offsetof(CordRep, storage);
+static constexpr size_t kMinFlatSize = 32;
+static constexpr size_t kMaxFlatSize = 4096;
+static constexpr size_t kMaxFlatLength = kMaxFlatSize - kFlatOverhead;
+static constexpr size_t kMinFlatLength = kMinFlatSize - kFlatOverhead;
+
+constexpr uint8_t AllocatedSizeToTagUnchecked(size_t size) {
+  return static_cast<uint8_t>((size <= 1024) ? size / 8
+                                             : 128 + size / 32 - 1024 / 32);
+}
+
+static_assert(kMinFlatSize / 8 >= FLAT, "");
+static_assert(AllocatedSizeToTagUnchecked(kMaxFlatSize) <= MAX_FLAT_TAG, "");
+
+// Helper functions for rounded div, and rounding to exact sizes.
+constexpr size_t DivUp(size_t n, size_t m) { return (n + m - 1) / m; }
+constexpr size_t RoundUp(size_t n, size_t m) { return DivUp(n, m) * m; }
+
+// Returns the size to the nearest equal or larger value that can be
+// expressed exactly as a tag value.
+inline size_t RoundUpForTag(size_t size) {
+  return RoundUp(size, (size <= 1024) ? 8 : 32);
+}
+
+// Converts the allocated size to a tag, rounding down if the size
+// does not exactly match a 'tag expressible' size value. The result is
+// undefined if the size exceeds the maximum size that can be encoded in
+// a tag, i.e., if size is larger than TagToAllocatedSize(<max tag>).
+inline uint8_t AllocatedSizeToTag(size_t size) {
+  const uint8_t tag = AllocatedSizeToTagUnchecked(size);
+  assert(tag <= MAX_FLAT_TAG);
+  return tag;
+}
+
+// Converts the provided tag to the corresponding allocated size
+constexpr size_t TagToAllocatedSize(uint8_t tag) {
+  return (tag <= 128) ? (tag * 8) : (1024 + (tag - 128) * 32);
+}
+
+// Converts the provided tag to the corresponding available data length
+constexpr size_t TagToLength(uint8_t tag) {
+  return TagToAllocatedSize(tag) - kFlatOverhead;
+}
+
+// Enforce that kMaxFlatSize maps to a well-known exact tag value.
+static_assert(TagToAllocatedSize(224) == kMaxFlatSize, "Bad tag logic");
+
+struct CordRepFlat : public CordRep {
+  // Creates a new flat node.
+  static CordRepFlat* New(size_t len) {
+    if (len <= kMinFlatLength) {
+      len = kMinFlatLength;
+    } else if (len > kMaxFlatLength) {
+      len = kMaxFlatLength;
+    }
+
+    // Round size up so it matches a size we can exactly express in a tag.
+    const size_t size = RoundUpForTag(len + kFlatOverhead);
+    void* const raw_rep = ::operator new(size);
+    CordRepFlat* rep = new (raw_rep) CordRepFlat();
+    rep->tag = AllocatedSizeToTag(size);
+    return rep;
+  }
+
+  // Deletes a CordRepFlat instance created previously through a call to New().
+  // Flat CordReps are allocated and constructed with raw ::operator new and
+  // placement new, and must be destructed and deallocated accordingly.
+  static void Delete(CordRep*rep) {
+    assert(rep->tag >= FLAT && rep->tag <= MAX_FLAT_TAG);
+
+#if defined(__cpp_sized_deallocation)
+    size_t size = TagToAllocatedSize(rep->tag);
+    rep->~CordRep();
+    ::operator delete(rep, size);
+#else
+    rep->~CordRep();
+    ::operator delete(rep);
+#endif
+  }
+
+  // Returns a pointer to the data inside this flat rep.
+  char* Data() { return storage; }
+  const char* Data() const { return storage; }
+
+  // Returns the maximum capacity (payload size) of this instance.
+  size_t Capacity() const { return TagToLength(tag); }
+
+  // Returns the allocated size (payload + overhead) of this instance.
+  size_t AllocatedSize() const { return TagToAllocatedSize(tag); }
+};
+
+// Now that CordRepFlat is defined, we can define CordRep's helper casts:
+inline CordRepFlat* CordRep::flat() {
+  assert(tag >= FLAT && tag <= MAX_FLAT_TAG);
+  return reinterpret_cast<CordRepFlat*>(this);
+}
+
+inline const CordRepFlat* CordRep::flat() const {
+  assert(tag >= FLAT && tag <= MAX_FLAT_TAG);
+  return reinterpret_cast<const CordRepFlat*>(this);
+}
+
+}  // namespace cord_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
diff --git a/absl/strings/internal/cord_rep_ring.cc b/absl/strings/internal/cord_rep_ring.cc
new file mode 100644
index 0000000..4d31d1d
--- /dev/null
+++ b/absl/strings/internal/cord_rep_ring.cc
@@ -0,0 +1,897 @@
+// 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/strings/internal/cord_rep_ring.h"
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <iostream>
+#include <limits>
+#include <memory>
+#include <string>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/base/macros.h"
+#include "absl/container/inlined_vector.h"
+#include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_flat.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+// See https://bugs.llvm.org/show_bug.cgi?id=48477
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wshadow"
+#if __has_warning("-Wshadow-field")
+#pragma clang diagnostic ignored "-Wshadow-field"
+#endif
+#endif
+
+namespace {
+
+using index_type = CordRepRing::index_type;
+
+enum class Direction { kForward, kReversed };
+
+inline bool IsFlatOrExternal(CordRep* rep) {
+  return rep->tag >= FLAT || rep->tag == EXTERNAL;
+}
+
+// Verifies that n + extra <= kMaxCapacity: throws std::length_error otherwise.
+inline void CheckCapacity(size_t n, size_t extra) {
+  if (ABSL_PREDICT_FALSE(extra > CordRepRing::kMaxCapacity - n)) {
+    base_internal::ThrowStdLengthError("Maximum capacity exceeded");
+  }
+}
+
+// Removes a reference from `rep` only.
+// Asserts that the refcount after decrement is not zero.
+inline bool UnrefNeverOne(CordRep* rep) {
+  bool result = rep->refcount.Decrement();
+  assert(result);
+  return result;
+}
+
+// Creates a flat from the provided string data, allocating up to `extra`
+// capacity in the returned flat depending on kMaxFlatLength limitations.
+// Requires `len` to be less or equal to `kMaxFlatLength`
+CordRepFlat* CreateFlat(const char* s, size_t n, size_t extra = 0) {  // NOLINT
+  assert(n <= kMaxFlatLength);
+  auto* rep = CordRepFlat::New(n + extra);
+  rep->length = n;
+  memcpy(rep->Data(), s, n);
+  return rep;
+}
+
+// Unrefs the provided `substring`, and returns `substring->child`
+// Adds or assumes a reference on `substring->child`
+CordRep* ClipSubstring(CordRepSubstring* substring) {
+  CordRep* child = substring->child;
+  if (substring->refcount.IsOne()) {
+    delete substring;
+  } else {
+    CordRep::Ref(child);
+    if (ABSL_PREDICT_FALSE(!substring->refcount.Decrement())) {
+      UnrefNeverOne(child);
+      delete substring;
+    }
+  }
+  return child;
+}
+
+// Unrefs the provided `concat`, and returns `{concat->left, concat->right}`
+// Adds or assumes a reference on `concat->left` and `concat->right`.
+std::pair<CordRep*, CordRep*> ClipConcat(CordRepConcat* concat) {
+  auto result = std::make_pair(concat->left, concat->right);
+  if (concat->refcount.IsOne()) {
+    delete concat;
+  } else {
+    CordRep::Ref(result.first);
+    CordRep::Ref(result.second);
+    if (ABSL_PREDICT_FALSE(!concat->refcount.Decrement())) {
+      UnrefNeverOne(result.first);
+      UnrefNeverOne(result.second);
+      delete concat;
+    }
+  }
+  return result;
+}
+
+// Unrefs the entries in `[head, tail)`.
+// Requires all entries to be a FLAT or EXTERNAL node.
+void UnrefEntries(const CordRepRing* rep, index_type head, index_type tail) {
+  rep->ForEach(head, tail, [rep](index_type ix) {
+    CordRep* child = rep->entry_child(ix);
+    if (!child->refcount.Decrement()) {
+      if (child->tag >= FLAT) {
+        CordRepFlat::Delete(child->flat());
+      } else {
+        CordRepExternal::Delete(child->external());
+      }
+    }
+  });
+}
+
+template <typename F>
+void Consume(Direction direction, CordRep* rep, F&& fn) {
+  size_t offset = 0;
+  size_t length = rep->length;
+  struct Entry {
+    CordRep* rep;
+    size_t offset;
+    size_t length;
+  };
+  absl::InlinedVector<Entry, 40> stack;
+
+  for (;;) {
+    if (rep->tag >= FLAT || rep->tag == EXTERNAL || rep->tag == RING) {
+      fn(rep, offset, length);
+      if (stack.empty()) return;
+
+      rep = stack.back().rep;
+      offset = stack.back().offset;
+      length = stack.back().length;
+      stack.pop_back();
+    } else if (rep->tag == SUBSTRING) {
+      offset += rep->substring()->start;
+      rep = ClipSubstring(rep->substring());
+    } else if (rep->tag == CONCAT) {
+      auto res = ClipConcat(rep->concat());
+      CordRep* left = res.first;
+      CordRep* right = res.second;
+
+      if (left->length <= offset) {
+        // Don't need left node
+        offset -= left->length;
+        CordRep::Unref(left);
+        rep = right;
+        continue;
+      }
+
+      size_t length_left = left->length - offset;
+      if (length_left >= length) {
+        // Don't need right node
+        CordRep::Unref(right);
+        rep = left;
+        continue;
+      }
+
+      // Need both nodes
+      size_t length_right = length - length_left;
+      if (direction == Direction::kReversed) {
+        stack.push_back({left, offset, length_left});
+        rep = right;
+        offset = 0;
+        length = length_right;
+      } else {
+        stack.push_back({right, 0, length_right});
+        rep = left;
+        length = length_left;
+      }
+    } else {
+      assert("Valid tag" == nullptr);
+      return;
+    }
+  }
+}
+
+template <typename F>
+void Consume(CordRep* rep, F&& fn) {
+  return Consume(Direction::kForward, rep, std::forward<F>(fn));
+}
+
+template <typename F>
+void RConsume(CordRep* rep, F&& fn) {
+  return Consume(Direction::kReversed, rep, std::forward<F>(fn));
+}
+
+}  // namespace
+
+std::ostream& operator<<(std::ostream& s, const CordRepRing& rep) {
+  // Note: 'pos' values are defined as size_t (for overflow reasons), but that
+  // prints really awkward for small prepended values such as -5. ssize_t is not
+  // portable (POSIX), so we use ptrdiff_t instead to cast to signed values.
+  s << "  CordRepRing(" << &rep << ", length = " << rep.length
+    << ", head = " << rep.head_ << ", tail = " << rep.tail_
+    << ", cap = " << rep.capacity_ << ", rc = " << rep.refcount.Get()
+    << ", begin_pos_ = " << static_cast<ptrdiff_t>(rep.begin_pos_) << ") {\n";
+  CordRepRing::index_type head = rep.head();
+  do {
+    CordRep* child = rep.entry_child(head);
+    s << " entry[" << head << "] length = " << rep.entry_length(head)
+      << ", child " << child << ", clen = " << child->length
+      << ", tag = " << static_cast<int>(child->tag)
+      << ", rc = " << child->refcount.Get()
+      << ", offset = " << rep.entry_data_offset(head)
+      << ", end_pos = " << static_cast<ptrdiff_t>(rep.entry_end_pos(head))
+      << "\n";
+    head = rep.advance(head);
+  } while (head != rep.tail());
+  return s << "}\n";
+}
+
+void CordRepRing::AddDataOffset(index_type index, size_t n) {
+  entry_data_offset()[index] += static_cast<offset_type>(n);
+}
+
+void CordRepRing::SubLength(index_type index, size_t n) {
+  entry_end_pos()[index] -= n;
+}
+
+class CordRepRing::Filler {
+ public:
+  Filler(CordRepRing* rep, index_type pos) : rep_(rep), head_(pos), pos_(pos) {}
+
+  index_type head() const { return head_; }
+  index_type pos() const { return pos_; }
+
+  void Add(CordRep* child, size_t offset, pos_type end_pos) {
+    rep_->entry_end_pos()[pos_] = end_pos;
+    rep_->entry_child()[pos_] = child;
+    rep_->entry_data_offset()[pos_] = static_cast<offset_type>(offset);
+    pos_ = rep_->advance(pos_);
+  }
+
+ private:
+  CordRepRing* rep_;
+  index_type head_;
+  index_type pos_;
+};
+
+constexpr size_t CordRepRing::kMaxCapacity; // NOLINT: needed for c++11
+
+bool CordRepRing::IsValid(std::ostream& output) const {
+  if (capacity_ == 0) {
+    output << "capacity == 0";
+    return false;
+  }
+
+  if (head_ >= capacity_ || tail_ >= capacity_) {
+    output << "head " << head_ << " and/or tail " << tail_ << "exceed capacity "
+           << capacity_;
+    return false;
+  }
+
+  const index_type back = retreat(tail_);
+  size_t pos_length = Distance(begin_pos_, entry_end_pos(back));
+  if (pos_length != length) {
+    output << "length " << length << " does not match positional length "
+           << pos_length << " from begin_pos " << begin_pos_ << " and entry["
+           << back << "].end_pos " << entry_end_pos(back);
+    return false;
+  }
+
+  index_type head = head_;
+  pos_type begin_pos = begin_pos_;
+  do {
+    pos_type end_pos = entry_end_pos(head);
+    size_t entry_length = Distance(begin_pos, end_pos);
+    if (entry_length == 0) {
+      output << "entry[" << head << "] has an invalid length " << entry_length
+             << " from begin_pos " << begin_pos << " and end_pos " << end_pos;
+      return false;
+    }
+
+    CordRep* child = entry_child(head);
+    if (child == nullptr) {
+      output << "entry[" << head << "].child == nullptr";
+      return false;
+    }
+    if (child->tag < FLAT && child->tag != EXTERNAL) {
+      output << "entry[" << head << "].child has an invalid tag "
+             << static_cast<int>(child->tag);
+      return false;
+    }
+
+    size_t offset = entry_data_offset(head);
+    if (offset >= child->length || entry_length > child->length - offset) {
+      output << "entry[" << head << "] has offset " << offset
+             << " and entry length " << entry_length
+             << " which are outside of the childs length of " << child->length;
+      return false;
+    }
+
+    begin_pos = end_pos;
+    head = advance(head);
+  } while (head != tail_);
+
+  return true;
+}
+
+#ifdef EXTRA_CORD_RING_VALIDATION
+CordRepRing* CordRepRing::Validate(CordRepRing* rep, const char* file,
+                                   int line) {
+  if (!rep->IsValid(std::cerr)) {
+    std::cerr << "\nERROR: CordRepRing corrupted";
+    if (line) std::cerr << " at line " << line;
+    if (file) std::cerr << " in file " << file;
+    std::cerr << "\nContent = " << *rep;
+    abort();
+  }
+  return rep;
+}
+#endif  // EXTRA_CORD_RING_VALIDATION
+
+CordRepRing* CordRepRing::New(size_t capacity, size_t extra) {
+  CheckCapacity(capacity, extra);
+
+  size_t size = AllocSize(capacity += extra);
+  void* mem = ::operator new(size);
+  auto* rep = new (mem) CordRepRing(static_cast<index_type>(capacity));
+  rep->tag = RING;
+  rep->capacity_ = static_cast<index_type>(capacity);
+  rep->begin_pos_ = 0;
+  return rep;
+}
+
+void CordRepRing::SetCapacityForTesting(size_t capacity) {
+  // Adjust for the changed layout
+  assert(capacity <= capacity_);
+  assert(head() == 0 || head() < tail());
+  memmove(Layout::Partial(capacity).Pointer<1>(data_) + head(),
+          Layout::Partial(capacity_).Pointer<1>(data_) + head(),
+          entries() * sizeof(Layout::ElementType<1>));
+  memmove(Layout::Partial(capacity, capacity).Pointer<2>(data_) + head(),
+          Layout::Partial(capacity_, capacity_).Pointer<2>(data_) + head(),
+          entries() * sizeof(Layout::ElementType<2>));
+  capacity_ = static_cast<index_type>(capacity);
+}
+
+void CordRepRing::Delete(CordRepRing* rep) {
+  assert(rep != nullptr && rep->tag == RING);
+#if defined(__cpp_sized_deallocation)
+  size_t size = AllocSize(rep->capacity_);
+  rep->~CordRepRing();
+  ::operator delete(rep, size);
+#else
+  rep->~CordRepRing();
+  ::operator delete(rep);
+#endif
+}
+
+void CordRepRing::Destroy(CordRepRing* rep) {
+  UnrefEntries(rep, rep->head(), rep->tail());
+  Delete(rep);
+}
+
+template <bool ref>
+void CordRepRing::Fill(const CordRepRing* src, index_type head,
+                       index_type tail) {
+  this->length = src->length;
+  head_ = 0;
+  tail_ = advance(0, src->entries(head, tail));
+  begin_pos_ = src->begin_pos_;
+
+  // TODO(mvels): there may be opportunities here for large buffers.
+  auto* dst_pos = entry_end_pos();
+  auto* dst_child = entry_child();
+  auto* dst_offset = entry_data_offset();
+  src->ForEach(head, tail, [&](index_type index) {
+    *dst_pos++ = src->entry_end_pos(index);
+    CordRep* child = src->entry_child(index);
+    *dst_child++ = ref ? CordRep::Ref(child) : child;
+    *dst_offset++ = src->entry_data_offset(index);
+  });
+}
+
+CordRepRing* CordRepRing::Copy(CordRepRing* rep, index_type head,
+                               index_type tail, size_t extra) {
+  CordRepRing* newrep = CordRepRing::New(rep->entries(head, tail), extra);
+  newrep->Fill<true>(rep, head, tail);
+  CordRep::Unref(rep);
+  return newrep;
+}
+
+CordRepRing* CordRepRing::Mutable(CordRepRing* rep, size_t extra) {
+  // Get current number of entries, and check for max capacity.
+  size_t entries = rep->entries();
+
+  size_t min_extra = (std::max)(extra, rep->capacity() * 2 - entries);
+  if (!rep->refcount.IsOne()) {
+    return Copy(rep, rep->head(), rep->tail(), min_extra);
+  } else if (entries + extra > rep->capacity()) {
+    CordRepRing* newrep = CordRepRing::New(entries, min_extra);
+    newrep->Fill<false>(rep, rep->head(), rep->tail());
+    CordRepRing::Delete(rep);
+    return newrep;
+  } else {
+    return rep;
+  }
+}
+
+Span<char> CordRepRing::GetAppendBuffer(size_t size) {
+  assert(refcount.IsOne());
+  index_type back = retreat(tail_);
+  CordRep* child = entry_child(back);
+  if (child->tag >= FLAT && child->refcount.IsOne()) {
+    size_t capacity = child->flat()->Capacity();
+    pos_type end_pos = entry_end_pos(back);
+    size_t data_offset = entry_data_offset(back);
+    size_t entry_length = Distance(entry_begin_pos(back), end_pos);
+    size_t used = data_offset + entry_length;
+    if (size_t n = (std::min)(capacity - used, size)) {
+      child->length = data_offset + entry_length + n;
+      entry_end_pos()[back] = end_pos + n;
+      this->length += n;
+      return {child->flat()->Data() + used, n};
+    }
+  }
+  return {nullptr, 0};
+}
+
+Span<char> CordRepRing::GetPrependBuffer(size_t size) {
+  assert(refcount.IsOne());
+  CordRep* child = entry_child(head_);
+  size_t data_offset = entry_data_offset(head_);
+  if (data_offset && child->refcount.IsOne() && child->tag >= FLAT) {
+    size_t n = (std::min)(data_offset, size);
+    this->length += n;
+    begin_pos_ -= n;
+    data_offset -= n;
+    entry_data_offset()[head_] = static_cast<offset_type>(data_offset);
+    return {child->flat()->Data() + data_offset, n};
+  }
+  return {nullptr, 0};
+}
+
+CordRepRing* CordRepRing::CreateFromLeaf(CordRep* child, size_t offset,
+                                         size_t length, size_t extra) {
+  CordRepRing* rep = CordRepRing::New(1, extra);
+  rep->head_ = 0;
+  rep->tail_ = rep->advance(0);
+  rep->length = length;
+  rep->entry_end_pos()[0] = length;
+  rep->entry_child()[0] = child;
+  rep->entry_data_offset()[0] = static_cast<offset_type>(offset);
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::CreateSlow(CordRep* child, size_t extra) {
+  CordRepRing* rep = nullptr;
+  Consume(child, [&](CordRep* child, size_t offset, size_t length) {
+    if (IsFlatOrExternal(child)) {
+      rep = rep ? AppendLeaf(rep, child, offset, length)
+                : CreateFromLeaf(child, offset, length, extra);
+    } else if (rep) {
+      rep = AddRing<AddMode::kAppend>(rep, child->ring(), offset, length);
+    } else if (offset == 0 && child->length == length) {
+      rep = Mutable(child->ring(), extra);
+    } else {
+      rep = SubRing(child->ring(), offset, length, extra);
+    }
+  });
+  return Validate(rep, nullptr, __LINE__);
+}
+
+CordRepRing* CordRepRing::Create(CordRep* child, size_t extra) {
+  size_t length = child->length;
+  if (IsFlatOrExternal(child)) {
+    return CreateFromLeaf(child, 0, length, extra);
+  }
+  if (child->tag == RING) {
+    return Mutable(child->ring(), extra);
+  }
+  return CreateSlow(child, extra);
+}
+
+template <CordRepRing::AddMode mode>
+CordRepRing* CordRepRing::AddRing(CordRepRing* rep, CordRepRing* ring,
+                                  size_t offset, size_t length) {
+  assert(offset < ring->length);
+  constexpr bool append = mode == AddMode::kAppend;
+  Position head = ring->Find(offset);
+  Position tail = ring->FindTail(head.index, offset + length);
+  const index_type entries = ring->entries(head.index, tail.index);
+
+  rep = Mutable(rep, entries);
+
+  // The delta for making ring[head].end_pos into 'len - offset'
+  const pos_type delta_length =
+      (append ? rep->begin_pos_ + rep->length : rep->begin_pos_ - length) -
+      ring->entry_begin_pos(head.index) - head.offset;
+
+  // Start filling at `tail`, or `entries` before `head`
+  Filler filler(rep, append ? rep->tail_ : rep->retreat(rep->head_, entries));
+
+  if (ring->refcount.IsOne()) {
+    // Copy entries from source stealing the ref and adjusting the end position.
+    // Commit the filler as this is no-op.
+    ring->ForEach(head.index, tail.index, [&](index_type ix) {
+      filler.Add(ring->entry_child(ix), ring->entry_data_offset(ix),
+                 ring->entry_end_pos(ix) + delta_length);
+    });
+
+    // Unref entries we did not copy over, and delete source.
+    if (head.index != ring->head_) UnrefEntries(ring, ring->head_, head.index);
+    if (tail.index != ring->tail_) UnrefEntries(ring, tail.index, ring->tail_);
+    CordRepRing::Delete(ring);
+  } else {
+    ring->ForEach(head.index, tail.index, [&](index_type ix) {
+      CordRep* child = ring->entry_child(ix);
+      filler.Add(child, ring->entry_data_offset(ix),
+                 ring->entry_end_pos(ix) + delta_length);
+      CordRep::Ref(child);
+    });
+    CordRepRing::Unref(ring);
+  }
+
+  if (head.offset) {
+    // Increase offset of first 'source' entry appended or prepended.
+    // This is always the entry in `filler.head()`
+    rep->AddDataOffset(filler.head(), head.offset);
+  }
+
+  if (tail.offset) {
+    // Reduce length of last 'source' entry appended or prepended.
+    // This is always the entry tailed by `filler.pos()`
+    rep->SubLength(rep->retreat(filler.pos()), tail.offset);
+  }
+
+  // Commit changes
+  rep->length += length;
+  if (append) {
+    rep->tail_ = filler.pos();
+  } else {
+    rep->head_ = filler.head();
+    rep->begin_pos_ -= length;
+  }
+
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::AppendSlow(CordRepRing* rep, CordRep* child) {
+  Consume(child, [&rep](CordRep* child, size_t offset, size_t length) {
+    if (child->tag == RING) {
+      rep = AddRing<AddMode::kAppend>(rep, child->ring(), offset, length);
+    } else {
+      rep = AppendLeaf(rep, child, offset, length);
+    }
+  });
+  return rep;
+}
+
+CordRepRing* CordRepRing::AppendLeaf(CordRepRing* rep, CordRep* child,
+                                     size_t offset, size_t length) {
+  rep = Mutable(rep, 1);
+  index_type back = rep->tail_;
+  const pos_type begin_pos = rep->begin_pos_ + rep->length;
+  rep->tail_ = rep->advance(rep->tail_);
+  rep->length += length;
+  rep->entry_end_pos()[back] = begin_pos + length;
+  rep->entry_child()[back] = child;
+  rep->entry_data_offset()[back] = static_cast<offset_type>(offset);
+  return Validate(rep, nullptr, __LINE__);
+}
+
+CordRepRing* CordRepRing::Append(CordRepRing* rep, CordRep* child) {
+  size_t length = child->length;
+  if (IsFlatOrExternal(child)) {
+    return AppendLeaf(rep, child, 0, length);
+  }
+  if (child->tag == RING) {
+    return AddRing<AddMode::kAppend>(rep, child->ring(), 0, length);
+  }
+  return AppendSlow(rep, child);
+}
+
+CordRepRing* CordRepRing::PrependSlow(CordRepRing* rep, CordRep* child) {
+  RConsume(child, [&](CordRep* child, size_t offset, size_t length) {
+    if (IsFlatOrExternal(child)) {
+      rep = PrependLeaf(rep, child, offset, length);
+    } else {
+      rep = AddRing<AddMode::kPrepend>(rep, child->ring(), offset, length);
+    }
+  });
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::PrependLeaf(CordRepRing* rep, CordRep* child,
+                                      size_t offset, size_t length) {
+  rep = Mutable(rep, 1);
+  index_type head = rep->retreat(rep->head_);
+  pos_type end_pos = rep->begin_pos_;
+  rep->head_ = head;
+  rep->length += length;
+  rep->begin_pos_ -= length;
+  rep->entry_end_pos()[head] = end_pos;
+  rep->entry_child()[head] = child;
+  rep->entry_data_offset()[head] = static_cast<offset_type>(offset);
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::Prepend(CordRepRing* rep, CordRep* child) {
+  size_t length = child->length;
+  if (IsFlatOrExternal(child)) {
+    return PrependLeaf(rep, child, 0, length);
+  }
+  if (child->tag == RING) {
+    return AddRing<AddMode::kPrepend>(rep, child->ring(), 0, length);
+  }
+  return PrependSlow(rep, child);
+}
+
+CordRepRing* CordRepRing::Append(CordRepRing* rep, absl::string_view data,
+                                 size_t extra) {
+  if (rep->refcount.IsOne()) {
+    Span<char> avail = rep->GetAppendBuffer(data.length());
+    if (!avail.empty()) {
+      memcpy(avail.data(), data.data(), avail.length());
+      data.remove_prefix(avail.length());
+    }
+  }
+  if (data.empty()) return Validate(rep);
+
+  const size_t flats = (data.length() - 1) / kMaxFlatLength + 1;
+  rep = Mutable(rep, flats);
+
+  Filler filler(rep, rep->tail_);
+  pos_type pos = rep->begin_pos_ + rep->length;
+
+  while (data.length() >= kMaxFlatLength) {
+    auto* flat = CreateFlat(data.data(), kMaxFlatLength);
+    filler.Add(flat, 0, pos += kMaxFlatLength);
+    data.remove_prefix(kMaxFlatLength);
+  }
+
+  if (data.length()) {
+    auto* flat = CreateFlat(data.data(), data.length(), extra);
+    filler.Add(flat, 0, pos += data.length());
+  }
+
+  rep->length = pos - rep->begin_pos_;
+  rep->tail_ = filler.pos();
+
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::Prepend(CordRepRing* rep, absl::string_view data,
+                                  size_t extra) {
+  if (rep->refcount.IsOne()) {
+    Span<char> avail = rep->GetPrependBuffer(data.length());
+    if (!avail.empty()) {
+      const char* tail = data.data() + data.length() - avail.length();
+      memcpy(avail.data(), tail, avail.length());
+      data.remove_suffix(avail.length());
+    }
+  }
+  if (data.empty()) return rep;
+
+  const size_t flats = (data.length() - 1) / kMaxFlatLength + 1;
+  rep = Mutable(rep, flats);
+  pos_type pos = rep->begin_pos_;
+  Filler filler(rep, rep->retreat(rep->head_, static_cast<index_type>(flats)));
+
+  size_t first_size = data.size() - (flats - 1) * kMaxFlatLength;
+  CordRepFlat* flat = CordRepFlat::New(first_size + extra);
+  flat->length = first_size + extra;
+  memcpy(flat->Data() + extra, data.data(), first_size);
+  data.remove_prefix(first_size);
+  filler.Add(flat, extra, pos);
+  pos -= first_size;
+
+  while (!data.empty()) {
+    assert(data.size() >= kMaxFlatLength);
+    flat = CreateFlat(data.data(), kMaxFlatLength);
+    filler.Add(flat, 0, pos);
+    pos -= kMaxFlatLength;
+    data.remove_prefix(kMaxFlatLength);
+  }
+
+  rep->head_ = filler.head();
+  rep->length += rep->begin_pos_ - pos;
+  rep->begin_pos_ = pos;
+
+  return Validate(rep);
+}
+
+// 32 entries is 32 * sizeof(pos_type) = 4 cache lines on x86
+static constexpr index_type kBinarySearchThreshold = 32;
+static constexpr index_type kBinarySearchEndCount = 8;
+
+template <bool wrap>
+CordRepRing::index_type CordRepRing::FindBinary(index_type head,
+                                                index_type tail,
+                                                size_t offset) const {
+  index_type count = tail + (wrap ? capacity_ : 0) - head;
+  do {
+    count = (count - 1) / 2;
+    assert(count < entries(head, tail_));
+    index_type mid = wrap ? advance(head, count) : head + count;
+    index_type after_mid = wrap ? advance(mid) : mid + 1;
+    bool larger = (offset >= entry_end_offset(mid));
+    head = larger ? after_mid : head;
+    tail = larger ? tail : mid;
+    assert(head != tail);
+  } while (ABSL_PREDICT_TRUE(count > kBinarySearchEndCount));
+  return head;
+}
+
+CordRepRing::Position CordRepRing::FindSlow(index_type head,
+                                            size_t offset) const {
+  index_type tail = tail_;
+
+  // Binary search until we are good for linear search
+  // Optimize for branchless / non wrapping ops
+  if (tail > head) {
+    index_type count = tail - head;
+    if (count > kBinarySearchThreshold) {
+      head = FindBinary<false>(head, tail, offset);
+    }
+  } else {
+    index_type count = capacity_ + tail - head;
+    if (count > kBinarySearchThreshold) {
+      head = FindBinary<true>(head, tail, offset);
+    }
+  }
+
+  pos_type pos = entry_begin_pos(head);
+  pos_type end_pos = entry_end_pos(head);
+  while (offset >= Distance(begin_pos_, end_pos)) {
+    head = advance(head);
+    pos = end_pos;
+    end_pos = entry_end_pos(head);
+  }
+
+  return {head, offset - Distance(begin_pos_, pos)};
+}
+
+CordRepRing::Position CordRepRing::FindTailSlow(index_type head,
+                                                size_t offset) const {
+  index_type tail = tail_;
+  const size_t tail_offset = offset - 1;
+
+  // Binary search until we are good for linear search
+  // Optimize for branchless / non wrapping ops
+  if (tail > head) {
+    index_type count = tail - head;
+    if (count > kBinarySearchThreshold) {
+      head = FindBinary<false>(head, tail, tail_offset);
+    }
+  } else {
+    index_type count = capacity_ + tail - head;
+    if (count > kBinarySearchThreshold) {
+      head = FindBinary<true>(head, tail, tail_offset);
+    }
+  }
+
+  size_t end_offset = entry_end_offset(head);
+  while (tail_offset >= end_offset) {
+    head = advance(head);
+    end_offset = entry_end_offset(head);
+  }
+
+  return {advance(head), end_offset - offset};
+}
+
+char CordRepRing::GetCharacter(size_t offset) const {
+  assert(offset < length);
+
+  Position pos = Find(offset);
+  size_t data_offset = entry_data_offset(pos.index) + pos.offset;
+  return GetRepData(entry_child(pos.index))[data_offset];
+}
+
+CordRepRing* CordRepRing::SubRing(CordRepRing* rep, size_t offset,
+                                  size_t length, size_t extra) {
+  assert(offset <= rep->length);
+  assert(offset <= rep->length - length);
+
+  if (length == 0) {
+    CordRep::Unref(rep);
+    return nullptr;
+  }
+
+  // Find position of first byte
+  Position head = rep->Find(offset);
+  Position tail = rep->FindTail(head.index, offset + length);
+  const size_t new_entries = rep->entries(head.index, tail.index);
+
+  if (rep->refcount.IsOne() && extra <= (rep->capacity() - new_entries)) {
+    // We adopt a privately owned rep and no extra entries needed.
+    if (head.index != rep->head_) UnrefEntries(rep, rep->head_, head.index);
+    if (tail.index != rep->tail_) UnrefEntries(rep, tail.index, rep->tail_);
+    rep->head_ = head.index;
+    rep->tail_ = tail.index;
+  } else {
+    // Copy subset to new rep
+    rep = Copy(rep, head.index, tail.index, extra);
+    head.index = rep->head_;
+    tail.index = rep->tail_;
+  }
+
+  // Adjust begin_pos and length
+  rep->length = length;
+  rep->begin_pos_ += offset;
+
+  // Adjust head and tail blocks
+  if (head.offset) {
+    rep->AddDataOffset(head.index, head.offset);
+  }
+  if (tail.offset) {
+    rep->SubLength(rep->retreat(tail.index), tail.offset);
+  }
+
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::RemovePrefix(CordRepRing* rep, size_t len,
+                                       size_t extra) {
+  assert(len <= rep->length);
+  if (len == rep->length) {
+    CordRep::Unref(rep);
+    return nullptr;
+  }
+
+  Position head = rep->Find(len);
+  if (rep->refcount.IsOne()) {
+    if (head.index != rep->head_) UnrefEntries(rep, rep->head_, head.index);
+    rep->head_ = head.index;
+  } else {
+    rep = Copy(rep, head.index, rep->tail_, extra);
+    head.index = rep->head_;
+  }
+
+  // Adjust begin_pos and length
+  rep->length -= len;
+  rep->begin_pos_ += len;
+
+  // Adjust head block
+  if (head.offset) {
+    rep->AddDataOffset(head.index, head.offset);
+  }
+
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::RemoveSuffix(CordRepRing* rep, size_t len,
+                                       size_t extra) {
+  assert(len <= rep->length);
+
+  if (len == rep->length) {
+    CordRep::Unref(rep);
+    return nullptr;
+  }
+
+  Position tail = rep->FindTail(rep->length - len);
+  if (rep->refcount.IsOne()) {
+    // We adopt a privately owned rep, scrub.
+    if (tail.index != rep->tail_) UnrefEntries(rep, tail.index, rep->tail_);
+    rep->tail_ = tail.index;
+  } else {
+    // Copy subset to new rep
+    rep = Copy(rep, rep->head_, tail.index, extra);
+    tail.index = rep->tail_;
+  }
+
+  // Adjust length
+  rep->length -= len;
+
+  // Adjust tail block
+  if (tail.offset) {
+    rep->SubLength(rep->retreat(tail.index), tail.offset);
+  }
+
+  return Validate(rep);
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+}  // namespace cord_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/strings/internal/cord_rep_ring.h b/absl/strings/internal/cord_rep_ring.h
new file mode 100644
index 0000000..c74d335
--- /dev/null
+++ b/absl/strings/internal/cord_rep_ring.h
@@ -0,0 +1,589 @@
+// 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.
+
+#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_
+#define ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <iosfwd>
+#include <limits>
+#include <memory>
+
+#include "absl/container/internal/layout.h"
+#include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_flat.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+// See https://bugs.llvm.org/show_bug.cgi?id=48477
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wshadow"
+#if __has_warning("-Wshadow-field")
+#pragma clang diagnostic ignored "-Wshadow-field"
+#endif
+#endif
+
+// All operations modifying a ring buffer are implemented as static methods
+// requiring a CordRepRing instance with a reference adopted by the method.
+//
+// The methods return the modified ring buffer, which may be equal to the input
+// if the input was not shared, and having large enough capacity to accommodate
+// any newly added node(s). Otherwise, a copy of the input rep with the new
+// node(s) added is returned.
+//
+// Any modification on non shared ring buffers with enough capacity will then
+// require minimum atomic operations. Caller should where possible provide
+// reasonable `extra` hints for both anticipated extra `flat` byte space, as
+// well as anticipated extra nodes required for complex operations.
+//
+// Example of code creating a ring buffer, adding some data to it,
+// and discarding the buffer when done:
+//
+//   void FunWithRings() {
+//     // Create ring with 3 flats
+//     CordRep* flat = CreateFlat("Hello");
+//     CordRepRing* ring = CordRepRing::Create(flat, 2);
+//     ring = CordRepRing::Append(ring, CreateFlat(" "));
+//     ring = CordRepRing::Append(ring, CreateFlat("world"));
+//     DoSomethingWithRing(ring);
+//     CordRep::Unref(ring);
+//   }
+//
+// Example of code Copying an existing ring buffer and modifying it:
+//
+//   void MoreFunWithRings(CordRepRing* src) {
+//     CordRepRing* ring = CordRep::Ref(src)->ring();
+//     ring = CordRepRing::Append(ring, CreateFlat("Hello"));
+//     ring = CordRepRing::Append(ring, CreateFlat(" "));
+//     ring = CordRepRing::Append(ring, CreateFlat("world"));
+//     DoSomethingWithRing(ring);
+//     CordRep::Unref(ring);
+//   }
+//
+class CordRepRing : public CordRep {
+ public:
+  // `pos_type` represents a 'logical position'. A CordRepRing instance has a
+  // `begin_pos` (default 0), and each node inside the buffer will have an
+  // `end_pos` which is the `end_pos` of the previous node (or `begin_pos`) plus
+  // this node's length. The purpose is to allow for a binary search on this
+  // position, while allowing O(1) prepend and append operations.
+  using pos_type = size_t;
+
+  // `index_type` is the type for the `head`, `tail` and `capacity` indexes.
+  // Ring buffers are limited to having no more than four billion entries.
+  using index_type = uint32_t;
+
+  // `offset_type` is the type for the data offset inside a child rep's data.
+  using offset_type = uint32_t;
+
+  // Position holds the node index and relative offset into the node for
+  // some physical offset in the contained data as returned by the Find()
+  // and FindTail() methods.
+  struct Position {
+    index_type index;
+    size_t offset;
+  };
+
+  // The maximum # of child nodes that can be hosted inside a CordRepRing.
+  static constexpr size_t kMaxCapacity = (std::numeric_limits<uint32_t>::max)();
+
+  // CordRepring can not be default constructed, moved, copied or assigned.
+  CordRepRing() = delete;
+  CordRepRing(const CordRepRing&) = delete;
+  CordRepRing& operator=(const CordRepRing&) = delete;
+
+  // Returns true if this instance is valid, false if some or all of the
+  // invariants are broken. Intended for debug purposes only.
+  // `output` receives an explanation of the broken invariants.
+  bool IsValid(std::ostream& output) const;
+
+  // Returns the size in bytes for a CordRepRing with `capacity' entries.
+  static constexpr size_t AllocSize(size_t capacity);
+
+  // Returns the distance in bytes from `pos` to `end_pos`.
+  static constexpr size_t Distance(pos_type pos, pos_type end_pos);
+
+  // Creates a new ring buffer from the provided `rep`. Adopts a reference
+  // on `rep`. The returned ring buffer has a capacity of at least `extra + 1`
+  static CordRepRing* Create(CordRep* child, size_t extra = 0);
+
+  // `head`, `tail` and `capacity` indexes defining the ring buffer boundaries.
+  index_type head() const { return head_; }
+  index_type tail() const { return tail_; }
+  index_type capacity() const { return capacity_; }
+
+  // Returns the number of entries in this instance.
+  index_type entries() const { return entries(head_, tail_); }
+
+  // Returns the logical begin position of this instance.
+  pos_type begin_pos() const { return begin_pos_; }
+
+  // Returns the number of entries for a given head-tail range.
+  // Requires `head` and `tail` values to be less than `capacity()`.
+  index_type entries(index_type head, index_type tail) const {
+    assert(head < capacity_ && tail < capacity_);
+    return tail - head + ((tail > head) ? 0 : capacity_);
+  }
+
+  // Returns the logical end position of entry `index`.
+  pos_type const& entry_end_pos(index_type index) const {
+    assert(IsValidIndex(index));
+    return Layout::Partial().Pointer<0>(data_)[index];
+  }
+
+  // Returns the child pointer of entry `index`.
+  CordRep* const& entry_child(index_type index) const {
+    assert(IsValidIndex(index));
+    return Layout::Partial(capacity()).Pointer<1>(data_)[index];
+  }
+
+  // Returns the data offset of entry `index`
+  offset_type const& entry_data_offset(index_type index) const {
+    assert(IsValidIndex(index));
+    return Layout::Partial(capacity(), capacity()).Pointer<2>(data_)[index];
+  }
+
+  // Appends the provided child node to the `rep` instance.
+  // Adopts a reference from `rep` and `child` which may not be null.
+  // If the provided child is a FLAT or EXTERNAL node, or a SUBSTRING node
+  // containing a FLAT or EXTERNAL node, then flat or external the node is added
+  // 'as is', with an offset added for the SUBSTRING case.
+  // If the provided child is a RING or CONCAT tree, or a SUBSTRING of a RING or
+  // CONCAT tree, then all child nodes not excluded by any start offset or
+  // length values are added recursively.
+  static CordRepRing* Append(CordRepRing* rep, CordRep* child);
+
+  // Appends the provided string data to the `rep` instance.
+  // This function will attempt to utilize any remaining capacity in the last
+  // node of the input if that node is not shared (directly or indirectly), and
+  // of type FLAT. Remaining data will be added as one or more FLAT nodes.
+  // Any last node added to the ring buffer will be allocated with up to
+  // `extra` bytes of capacity for (anticipated) subsequent append actions.
+  static CordRepRing* Append(CordRepRing* rep, string_view data,
+                             size_t extra = 0);
+
+  // Prepends the provided child node to the `rep` instance.
+  // Adopts a reference from `rep` and `child` which may not be null.
+  // If the provided child is a FLAT or EXTERNAL node, or a SUBSTRING node
+  // containing a FLAT or EXTERNAL node, then flat or external the node is
+  // prepended 'as is', with an optional offset added for the SUBSTRING case.
+  // If the provided child is a RING or CONCAT tree, or a SUBSTRING of a RING
+  // or CONCAT tree, then all child nodes not excluded by any start offset or
+  // length values are added recursively.
+  static CordRepRing* Prepend(CordRepRing* rep, CordRep* child);
+
+  // Prepends the provided string data to the `rep` instance.
+  // This function will attempt to utilize any remaining capacity in the first
+  // node of the input if that node is not shared (directly or indirectly), and
+  // of type FLAT. Remaining data will be added as one or more FLAT nodes.
+  // Any first node prepnded to the ring buffer will be allocated with up to
+  // `extra` bytes of capacity for (anticipated) subsequent prepend actions.
+  static CordRepRing* Prepend(CordRepRing* rep, string_view data,
+                              size_t extra = 0);
+
+  // Returns a span referencing potentially unused capacity in the last node.
+  // The returned span may be empty if no such capacity is available, or if the
+  // current instance is shared. Else, a span of size `n <= size` is returned.
+  // If non empty, the ring buffer is adjusted to the new length, with the newly
+  // added capacity left uninitialized. Callers should assign a value to the
+  // entire span before any other operations on this instance.
+  Span<char> GetAppendBuffer(size_t size);
+
+  // Returns a span referencing potentially unused capacity in the first node.
+  // This function is identical to GetAppendBuffer except that it returns a span
+  // referencing up to `size` capacity directly before the existing data.
+  Span<char> GetPrependBuffer(size_t size);
+
+  // Returns a cord ring buffer containing `length` bytes of data starting at
+  // `offset`. If the input is not shared, this function will remove all head
+  // and tail child nodes outside of the requested range, and adjust the new
+  // head and tail nodes as required. If the input is shared, this function
+  // returns a new instance sharing some or all of the nodes from the input.
+  static CordRepRing* SubRing(CordRepRing* r, size_t offset, size_t length,
+                              size_t extra = 0);
+
+  // Returns a cord ring buffer with the first `length` bytes removed.
+  // If the input is not shared, this function will remove all head child nodes
+  // fully inside the first `length` bytes, and adjust the new head as required.
+  // If the input is shared, this function returns a new instance sharing some
+  // or all of the nodes from the input.
+  static CordRepRing* RemoveSuffix(CordRepRing* r, size_t length,
+                                   size_t extra = 0);
+
+  // Returns a cord ring buffer with the last `length` bytes removed.
+  // If the input is not shared, this function will remove all head child nodes
+  // fully inside the first `length` bytes, and adjust the new head as required.
+  // If the input is shared, this function returns a new instance sharing some
+  // or all of the nodes from the input.
+  static CordRepRing* RemovePrefix(CordRepRing* r, size_t len,
+                                   size_t extra = 0);
+
+  // Returns the character at `offset`. Requires that `offset < length`.
+  char GetCharacter(size_t offset) const;
+
+  // Testing only: set capacity to requested capacity.
+  void SetCapacityForTesting(size_t capacity);
+
+  // Returns the CordRep data pointer for the provided CordRep.
+  // Requires that the provided `rep` is either a FLAT or EXTERNAL CordRep.
+  static const char* GetLeafData(const CordRep* rep);
+
+  // Returns the CordRep data pointer for the provided CordRep.
+  // Requires that `rep` is either a FLAT, EXTERNAL, or SUBSTRING CordRep.
+  static const char* GetRepData(const CordRep* rep);
+
+  // Advances the provided position, wrapping around capacity as needed.
+  // Requires `index` < capacity()
+  inline index_type advance(index_type index) const;
+
+  // Advances the provided position by 'n`, wrapping around capacity as needed.
+  // Requires `index` < capacity() and `n` <= capacity.
+  inline index_type advance(index_type index, index_type n) const;
+
+  // Retreats the provided position, wrapping around 0 as needed.
+  // Requires `index` < capacity()
+  inline index_type retreat(index_type index) const;
+
+  // Retreats the provided position by 'n', wrapping around 0 as needed.
+  // Requires `index` < capacity()
+  inline index_type retreat(index_type index, index_type n) const;
+
+  // Returns the logical begin position of entry `index`
+  pos_type const& entry_begin_pos(index_type index) const {
+    return (index == head_) ? begin_pos_ : entry_end_pos(retreat(index));
+  }
+
+  // Returns the physical start offset of entry `index`
+  size_t entry_start_offset(index_type index) const {
+    return Distance(begin_pos_, entry_begin_pos(index));
+  }
+
+  // Returns the physical end offset of entry `index`
+  size_t entry_end_offset(index_type index) const {
+    return Distance(begin_pos_, entry_end_pos(index));
+  }
+
+  // Returns the data length for entry `index`
+  size_t entry_length(index_type index) const {
+    return Distance(entry_begin_pos(index), entry_end_pos(index));
+  }
+
+  // Returns the data for entry `index`
+  absl::string_view entry_data(index_type index) const;
+
+  // Returns the position for `offset` as {index, prefix}. `index` holds the
+  // index of the entry at the specified offset and `prefix` holds the relative
+  // offset inside that entry.
+  // Requires `offset` < length.
+  //
+  // For example we can implement GetCharacter(offset) as:
+  //   char GetCharacter(size_t offset) {
+  //     Position pos = this->Find(offset);
+  //     return this->entry_data(pos.pos)[pos.offset];
+  //   }
+  inline Position Find(size_t offset) const;
+
+  // Find starting at `head`
+  inline Position Find(index_type head, size_t offset) const;
+
+  // Returns the tail position for `offset` as {tail index, suffix}.
+  // `tail index` holds holds the index of the entry holding the offset directly
+  // before 'offset` advanced by one. 'suffix` holds the relative offset from
+  // that relative offset in the entry to the end of the entry.
+  // For example, FindTail(length) will return {tail(), 0}, FindTail(length - 5)
+  // will return {retreat(tail), 5)} provided the preceding entry contains at
+  // least 5 bytes of data.
+  // Requires offset >= 1 && offset <= length.
+  //
+  // This function is very useful in functions that need to clip the end of some
+  // ring buffer such as 'RemovePrefix'.
+  // For example, we could implement RemovePrefix for non shared instances as:
+  //   void RemoveSuffix(size_t n) {
+  //     Position pos = FindTail(length - n);
+  //     UnrefEntries(pos.pos, this->tail_);
+  //     this->tail_ = pos.pos;
+  //     entry(retreat(pos.pos)).end_pos -= pos.offset;
+  //   }
+  inline Position FindTail(size_t offset) const;
+
+  // Find tail starting at `head`
+  inline Position FindTail(index_type head, size_t offset) const;
+
+  // Invokes f(index_type index) for each entry inside the range [head, tail>
+  template <typename F>
+  void ForEach(index_type head, index_type tail, F&& f) const {
+    index_type n1 = (tail > head) ? tail : capacity_;
+    for (index_type i = head; i < n1; ++i) f(i);
+    if (tail <= head) {
+      for (index_type i = 0; i < tail; ++i) f(i);
+    }
+  }
+
+  // Invokes f(index_type index) for each entry inside this instance.
+  template <typename F>
+  void ForEach(F&& f) const {
+    ForEach(head_, tail_, std::forward<F>(f));
+  }
+
+  // Dump this instance's data tp stream `s` in human readable format, excluding
+  // the actual data content itself. Intended for debug purposes only.
+  friend std::ostream& operator<<(std::ostream& s, const CordRepRing& rep);
+
+ private:
+  enum class AddMode { kAppend, kPrepend };
+
+  using Layout = container_internal::Layout<pos_type, CordRep*, offset_type>;
+
+  class Filler;
+  class Transaction;
+  class CreateTransaction;
+
+  static constexpr size_t kLayoutAlignment = Layout::Partial().Alignment();
+
+  // Creates a new CordRepRing.
+  explicit CordRepRing(index_type capacity) : capacity_(capacity) {}
+
+  // Returns true if `index` is a valid index into this instance.
+  bool IsValidIndex(index_type index) const;
+
+  // Debug use only: validates the provided CordRepRing invariants.
+  // Verification of all CordRepRing methods can be enabled by defining
+  // EXTRA_CORD_RING_VALIDATION, i.e.: `--copts=-DEXTRA_CORD_RING_VALIDATION`
+  // Verification is VERY expensive, so only do it for debugging purposes.
+  static CordRepRing* Validate(CordRepRing* rep, const char* file = nullptr,
+                               int line = 0);
+
+  // Allocates a CordRepRing large enough to hold `capacity + extra' entries.
+  // The returned capacity may be larger if the allocated memory allows for it.
+  // The maximum capacity of a CordRepRing is capped at kMaxCapacity.
+  // Throws `std::length_error` if `capacity + extra' exceeds kMaxCapacity.
+  static CordRepRing* New(size_t capacity, size_t extra);
+
+  // Deallocates (but does not destroy) the provided ring buffer.
+  static void Delete(CordRepRing* rep);
+
+  // Destroys the provided ring buffer, decrementing the reference count of all
+  // contained child CordReps. The provided 1\`rep` should have a ref count of
+  // one (pre decrement destroy call observing `refcount.IsOne()`) or zero (post
+  // decrement destroy call observing `!refcount.Decrement()`).
+  static void Destroy(CordRepRing* rep);
+
+  // Returns a mutable reference to the logical end position array.
+  pos_type* entry_end_pos() {
+    return Layout::Partial().Pointer<0>(data_);
+  }
+
+  // Returns a mutable reference to the child pointer array.
+  CordRep** entry_child() {
+    return Layout::Partial(capacity()).Pointer<1>(data_);
+  }
+
+  // Returns a mutable reference to the data offset array.
+  offset_type* entry_data_offset() {
+    return Layout::Partial(capacity(), capacity()).Pointer<2>(data_);
+  }
+
+  // Find implementations for the non fast path 0 / length cases.
+  Position FindSlow(index_type head, size_t offset) const;
+  Position FindTailSlow(index_type head, size_t offset) const;
+
+  // Finds the index of the first node that is inside a reasonable distance
+  // of the node at `offset` from which we can continue with a linear search.
+  template <bool wrap>
+  index_type FindBinary(index_type head, index_type tail, size_t offset) const;
+
+  // Fills the current (initialized) instance from the provided source, copying
+  // entries [head, tail). Adds a reference to copied entries if `ref` is true.
+  template <bool ref>
+  void Fill(const CordRepRing* src, index_type head, index_type tail);
+
+  // Create a copy of 'rep', copying all entries [head, tail), allocating room
+  // for `extra` entries. Adds a reference on all copied entries.
+  static CordRepRing* Copy(CordRepRing* rep, index_type head, index_type tail,
+                           size_t extra = 0);
+
+  // Returns a Mutable CordRepRing reference from `rep` with room for at least
+  // `extra` additional nodes. Adopts a reference count from `rep`.
+  // This function will return `rep` if, and only if:
+  // - rep.entries + extra <= rep.capacity
+  // - rep.refcount == 1
+  // Otherwise, this function will create a new copy of `rep` with additional
+  // capacity to satisfy `extra` extra nodes, and unref the old `rep` instance.
+  //
+  // If a new CordRepRing can not be allocated, or the new capacity would exceed
+  // the maxmimum capacity, then the input is consumed only, and an exception is
+  // thrown.
+  static CordRepRing* Mutable(CordRepRing* rep, size_t extra);
+
+  // Slow path for Append(CordRepRing* rep, CordRep* child). This function is
+  // exercised if the provided `child` in Append() is not a leaf node, i.e., a
+  // ring buffer or old (concat) cord tree.
+  static CordRepRing* AppendSlow(CordRepRing* rep, CordRep* child);
+
+  // Appends the provided leaf node. Requires `child` to be FLAT or EXTERNAL.
+  static CordRepRing* AppendLeaf(CordRepRing* rep, CordRep* child,
+                                 size_t offset, size_t length);
+
+  // Prepends the provided leaf node. Requires `child` to be FLAT or EXTERNAL.
+  static CordRepRing* PrependLeaf(CordRepRing* rep, CordRep* child,
+                                  size_t offset, size_t length);
+
+  // Slow path for Prepend(CordRepRing* rep, CordRep* child). This function is
+  // exercised if the provided `child` in Prepend() is not a leaf node, i.e., a
+  // ring buffer or old (concat) cord tree.
+  static CordRepRing* PrependSlow(CordRepRing* rep, CordRep* child);
+
+  // Slow path for Create(CordRep* child, size_t extra). This function is
+  // exercised if the provided `child` in Prepend() is not a leaf node, i.e., a
+  // ring buffer or old (concat) cord tree.
+  static CordRepRing* CreateSlow(CordRep* child, size_t extra);
+
+  // Creates a new ring buffer from the provided `child` leaf node. Requires
+  // `child` to be FLAT or EXTERNAL. on `rep`.
+  // The returned ring buffer has a capacity of at least `1 + extra`
+  static CordRepRing* CreateFromLeaf(CordRep* child, size_t offset,
+                                     size_t length, size_t extra);
+
+  // Appends or prepends (depending on AddMode) the ring buffer in `ring' to
+  // `rep` starting at `offset` with length `length`.
+  template <AddMode mode>
+  static CordRepRing* AddRing(CordRepRing* rep, CordRepRing* ring,
+                              size_t offset, size_t length);
+
+  // Increases the data offset for entry `index` by `n`.
+  void AddDataOffset(index_type index, size_t n);
+
+  // Descreases the length for entry `index` by `n`.
+  void SubLength(index_type index, size_t n);
+
+  index_type head_;
+  index_type tail_;
+  index_type capacity_;
+  pos_type begin_pos_;
+
+  alignas(kLayoutAlignment) char data_[kLayoutAlignment];
+
+  friend struct CordRep;
+};
+
+constexpr size_t CordRepRing::AllocSize(size_t capacity) {
+  return sizeof(CordRepRing) - sizeof(data_) +
+         Layout(capacity, capacity, capacity).AllocSize();
+}
+
+inline constexpr size_t CordRepRing::Distance(pos_type pos, pos_type end_pos) {
+  return (end_pos - pos);
+}
+
+inline const char* CordRepRing::GetLeafData(const CordRep* rep) {
+  return rep->tag != EXTERNAL ? rep->flat()->Data() : rep->external()->base;
+}
+
+inline const char* CordRepRing::GetRepData(const CordRep* rep) {
+  if (rep->tag >= FLAT) return rep->flat()->Data();
+  if (rep->tag == EXTERNAL) return rep->external()->base;
+  return GetLeafData(rep->substring()->child) + rep->substring()->start;
+}
+
+inline CordRepRing::index_type CordRepRing::advance(index_type index) const {
+  assert(index < capacity_);
+  return ++index == capacity_ ? 0 : index;
+}
+
+inline CordRepRing::index_type CordRepRing::advance(index_type index,
+                                                    index_type n) const {
+  assert(index < capacity_ && n <= capacity_);
+  return (index += n) >= capacity_ ? index - capacity_ : index;
+}
+
+inline CordRepRing::index_type CordRepRing::retreat(index_type index) const {
+  assert(index < capacity_);
+  return (index > 0 ? index : capacity_) - 1;
+}
+
+inline CordRepRing::index_type CordRepRing::retreat(index_type index,
+                                                    index_type n) const {
+  assert(index < capacity_ && n <= capacity_);
+  return index >= n ? index - n : capacity_ - n + index;
+}
+
+inline absl::string_view CordRepRing::entry_data(index_type index) const {
+  size_t data_offset = entry_data_offset(index);
+  return {GetRepData(entry_child(index)) + data_offset, entry_length(index)};
+}
+
+inline bool CordRepRing::IsValidIndex(index_type index) const {
+  if (index >= capacity_) return false;
+  return (tail_ > head_) ? (index >= head_ && index < tail_)
+                         : (index >= head_ || index < tail_);
+}
+
+#ifndef EXTRA_CORD_RING_VALIDATION
+inline CordRepRing* CordRepRing::Validate(CordRepRing* rep,
+                                          const char* /*file*/, int /*line*/) {
+  return rep;
+}
+#endif
+
+inline CordRepRing::Position CordRepRing::Find(size_t offset) const {
+  assert(offset < length);
+  return (offset == 0) ? Position{head_, 0} : FindSlow(head_, offset);
+}
+
+inline CordRepRing::Position CordRepRing::Find(index_type head,
+                                               size_t offset) const {
+  assert(offset < length);
+  assert(IsValidIndex(head) && offset >= entry_start_offset(head));
+  return (offset == 0) ? Position{head_, 0} : FindSlow(head, offset);
+}
+
+inline CordRepRing::Position CordRepRing::FindTail(size_t offset) const {
+  assert(offset > 0 && offset <= length);
+  return (offset == length) ? Position{tail_, 0} : FindTailSlow(head_, offset);
+}
+
+inline CordRepRing::Position CordRepRing::FindTail(index_type head,
+                                                   size_t offset) const {
+  assert(offset > 0 && offset <= length);
+  assert(IsValidIndex(head) && offset >= entry_start_offset(head) + 1);
+  return (offset == length) ? Position{tail_, 0} : FindTailSlow(head, offset);
+}
+
+// Now that CordRepRing is defined, we can define CordRep's helper casts:
+inline CordRepRing* CordRep::ring() {
+  assert(tag == RING);
+  return static_cast<CordRepRing*>(this);
+}
+
+inline const CordRepRing* CordRep::ring() const {
+  assert(tag == RING);
+  return static_cast<const CordRepRing*>(this);
+}
+
+std::ostream& operator<<(std::ostream& s, const CordRepRing& rep);
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+}  // namespace cord_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_
diff --git a/absl/strings/internal/cord_rep_ring_reader.h b/absl/strings/internal/cord_rep_ring_reader.h
new file mode 100644
index 0000000..396c0e2
--- /dev/null
+++ b/absl/strings/internal/cord_rep_ring_reader.h
@@ -0,0 +1,114 @@
+// Copyright 2021 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_CORD_REP_RING_READER_H_
+#define ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+
+#include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_ring.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+// CordRepRingReader provides basic navigation over CordRepRing data.
+class CordRepRingReader {
+ public:
+  // Returns true if this instance is not empty.
+  explicit operator bool() const { return ring_ != nullptr; }
+
+  // Returns the ring buffer reference for this instance, or nullptr if empty.
+  CordRepRing* ring() const { return ring_; }
+
+  // Returns the current node index inside the ring buffer for this instance.
+  // The returned value is undefined if this instance is empty.
+  CordRepRing::index_type index() const { return index_; }
+
+  // Returns the length of the referenced ring buffer.
+  // Requires the current instance to be non empty.
+  size_t length() const {
+    assert(ring_);
+    return ring_->length;
+  }
+
+  // Returns the end offset of the last navigated-to chunk, which represents the
+  // total bytes 'consumed' relative to the start of the ring. The returned
+  // value is never zero. For example, initializing a reader with a ring buffer
+  // with a first chunk of 19 bytes will return consumed() = 19.
+  // Requires the current instance to be non empty.
+  size_t consumed() const {
+    assert(ring_);
+    return ring_->entry_end_offset(index_);
+  }
+
+  // Returns the number of bytes remaining beyond the last navigated-to chunk.
+  // Requires the current instance to be non empty.
+  size_t remaining() const {
+    assert(ring_);
+    return length() - consumed();
+  }
+
+  // Resets this instance to an empty value
+  void Reset() { ring_ = nullptr; }
+
+  // Resets this instance to the start of `ring`. `ring` must not be null.
+  // Returns a reference into the first chunk of the provided ring.
+  absl::string_view Reset(CordRepRing* ring) {
+    assert(ring);
+    ring_ = ring;
+    index_ = ring_->head();
+    return ring_->entry_data(index_);
+  }
+
+  // Navigates to the next chunk inside the reference ring buffer.
+  // Returns a reference into the navigated-to chunk.
+  // Requires remaining() to be non zero.
+  absl::string_view Next() {
+    assert(remaining());
+    index_ = ring_->advance(index_);
+    return ring_->entry_data(index_);
+  }
+
+  // Navigates to the chunk at offset `offset`.
+  // Returns a reference into the navigated-to chunk, adjusted for the relative
+  // position of `offset` into that chunk. For example, calling Seek(13) on a
+  // ring buffer containing 2 chunks of 10 and 20 bytes respectively will return
+  // a string view into the second chunk starting at offset 3 with a size of 17.
+  // Requires `offset` to be less than `length()`
+  absl::string_view Seek(size_t offset) {
+    assert(offset < length());
+    size_t current = ring_->entry_end_offset(index_);
+    CordRepRing::index_type hint = (offset >= current) ? index_ : ring_->head();
+    const CordRepRing::Position head = ring_->Find(hint, offset);
+    index_ = head.index;
+    auto data = ring_->entry_data(head.index);
+    data.remove_prefix(head.offset);
+    return data;
+  }
+
+ private:
+  CordRepRing* ring_ = nullptr;
+  CordRepRing::index_type index_;
+};
+
+}  // namespace cord_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_
diff --git a/absl/strings/internal/numbers_test_common.h b/absl/strings/internal/numbers_test_common.h
index 1a1e50c..eaa88a8 100644
--- a/absl/strings/internal/numbers_test_common.h
+++ b/absl/strings/internal/numbers_test_common.h
@@ -170,7 +170,7 @@
 
       {"0x1234", true, 16, 0x1234},
 
-      // Base-10 std::string version.
+      // Base-10 string version.
       {"1234", true, 0, 1234},
       {nullptr, false, 0, 0},
   }};
diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc
index 4d0604e..e28a29b 100644
--- a/absl/strings/internal/str_format/arg.cc
+++ b/absl/strings/internal/str_format/arg.cc
@@ -1,3 +1,17 @@
+// 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.
+
 //
 // POSIX spec:
 //   http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html
@@ -12,14 +26,13 @@
 
 #include "absl/base/port.h"
 #include "absl/strings/internal/str_format/float_conversion.h"
+#include "absl/strings/numbers.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace str_format_internal {
 namespace {
 
-const char kDigit[2][32] = { "0123456789abcdef", "0123456789ABCDEF" };
-
 // Reduce *capacity by s.size(), clipped to a 0 minimum.
 void ReducePadding(string_view s, size_t *capacity) {
   *capacity = Excess(s.size(), *capacity);
@@ -48,125 +61,179 @@
 template <>
 struct IsSigned<absl::uint128> : std::false_type {};
 
-class ConvertedIntInfo {
+// Integral digit printer.
+// Call one of the PrintAs* routines after construction once.
+// Use with_neg_and_zero/without_neg_or_zero/is_negative to access the results.
+class IntDigits {
  public:
+  // Print the unsigned integer as octal.
+  // Supports unsigned integral types and uint128.
   template <typename T>
-  ConvertedIntInfo(T v, ConversionChar conv) {
-    using Unsigned = typename MakeUnsigned<T>::type;
-    auto u = static_cast<Unsigned>(v);
-    if (IsNeg(v)) {
-      is_neg_ = true;
-      u = Unsigned{} - u;
-    } else {
-      is_neg_ = false;
-    }
-    UnsignedToStringRight(u, conv);
+  void PrintAsOct(T v) {
+    static_assert(!IsSigned<T>::value, "");
+    char *p = storage_ + sizeof(storage_);
+    do {
+      *--p = static_cast<char>('0' + (static_cast<size_t>(v) & 7));
+      v >>= 3;
+    } while (v);
+    start_ = p;
+    size_ = storage_ + sizeof(storage_) - p;
   }
 
-  string_view digits() const {
-    return {end() - size_, static_cast<size_t>(size_)};
+  // Print the signed or unsigned integer as decimal.
+  // Supports all integral types.
+  template <typename T>
+  void PrintAsDec(T v) {
+    static_assert(std::is_integral<T>::value, "");
+    start_ = storage_;
+    size_ = numbers_internal::FastIntToBuffer(v, storage_) - storage_;
   }
-  bool is_neg() const { return is_neg_; }
+
+  void PrintAsDec(int128 v) {
+    auto u = static_cast<uint128>(v);
+    bool add_neg = false;
+    if (v < 0) {
+      add_neg = true;
+      u = uint128{} - u;
+    }
+    PrintAsDec(u, add_neg);
+  }
+
+  void PrintAsDec(uint128 v, bool add_neg = false) {
+    // This function can be sped up if needed. We can call FastIntToBuffer
+    // twice, or fix FastIntToBuffer to support uint128.
+    char *p = storage_ + sizeof(storage_);
+    do {
+      p -= 2;
+      numbers_internal::PutTwoDigits(static_cast<size_t>(v % 100), p);
+      v /= 100;
+    } while (v);
+    if (p[0] == '0') {
+      // We printed one too many hexits.
+      ++p;
+    }
+    if (add_neg) {
+      *--p = '-';
+    }
+    size_ = storage_ + sizeof(storage_) - p;
+    start_ = p;
+  }
+
+  // Print the unsigned integer as hex using lowercase.
+  // Supports unsigned integral types and uint128.
+  template <typename T>
+  void PrintAsHexLower(T v) {
+    static_assert(!IsSigned<T>::value, "");
+    char *p = storage_ + sizeof(storage_);
+
+    do {
+      p -= 2;
+      constexpr const char* table = numbers_internal::kHexTable;
+      std::memcpy(p, table + 2 * (static_cast<size_t>(v) & 0xFF), 2);
+      if (sizeof(T) == 1) break;
+      v >>= 8;
+    } while (v);
+    if (p[0] == '0') {
+      // We printed one too many digits.
+      ++p;
+    }
+    start_ = p;
+    size_ = storage_ + sizeof(storage_) - p;
+  }
+
+  // Print the unsigned integer as hex using uppercase.
+  // Supports unsigned integral types and uint128.
+  template <typename T>
+  void PrintAsHexUpper(T v) {
+    static_assert(!IsSigned<T>::value, "");
+    char *p = storage_ + sizeof(storage_);
+
+    // kHexTable is only lowercase, so do it manually for uppercase.
+    do {
+      *--p = "0123456789ABCDEF"[static_cast<size_t>(v) & 15];
+      v >>= 4;
+    } while (v);
+    start_ = p;
+    size_ = storage_ + sizeof(storage_) - p;
+  }
+
+  // The printed value including the '-' sign if available.
+  // For inputs of value `0`, this will return "0"
+  string_view with_neg_and_zero() const { return {start_, size_}; }
+
+  // The printed value not including the '-' sign.
+  // For inputs of value `0`, this will return "".
+  string_view without_neg_or_zero() const {
+    static_assert('-' < '0', "The check below verifies both.");
+    size_t advance = start_[0] <= '0' ? 1 : 0;
+    return {start_ + advance, size_ - advance};
+  }
+
+  bool is_negative() const { return start_[0] == '-'; }
 
  private:
-  template <typename T, bool IsSigned>
-  struct IsNegImpl {
-    static bool Eval(T v) { return v < 0; }
-  };
-  template <typename T>
-  struct IsNegImpl<T, false> {
-    static bool Eval(T) {
-      return false;
-    }
-  };
-
-  template <typename T>
-  bool IsNeg(T v) {
-    return IsNegImpl<T, IsSigned<T>::value>::Eval(v);
-  }
-
-  template <typename T>
-  void UnsignedToStringRight(T u, ConversionChar conv) {
-    char *p = end();
-    switch (FormatConversionCharRadix(conv)) {
-      default:
-      case 10:
-        for (; u; u /= 10)
-          *--p = static_cast<char>('0' + static_cast<size_t>(u % 10));
-        break;
-      case 8:
-        for (; u; u /= 8)
-          *--p = static_cast<char>('0' + static_cast<size_t>(u % 8));
-        break;
-      case 16: {
-        const char *digits = kDigit[FormatConversionCharIsUpper(conv) ? 1 : 0];
-        for (; u; u /= 16) *--p = digits[static_cast<size_t>(u % 16)];
-        break;
-      }
-    }
-    size_ = static_cast<int>(end() - p);
-  }
-
-  const char *end() const { return storage_ + sizeof(storage_); }
-  char *end() { return storage_ + sizeof(storage_); }
-
-  bool is_neg_;
-  int size_;
-  // Max size: 128 bit value as octal -> 43 digits
-  char storage_[128 / 3 + 1];
+  const char *start_;
+  size_t size_;
+  // Max size: 128 bit value as octal -> 43 digits, plus sign char
+  char storage_[128 / 3 + 1 + 1];
 };
 
 // Note: 'o' conversions do not have a base indicator, it's just that
 // the '#' flag is specified to modify the precision for 'o' conversions.
-string_view BaseIndicator(const ConvertedIntInfo &info,
-                          const ConversionSpec conv) {
-  bool alt = conv.flags().alt;
-  int radix = FormatConversionCharRadix(conv.conv());
-  if (conv.conv() == ConversionChar::p) alt = true;  // always show 0x for %p.
+string_view BaseIndicator(const IntDigits &as_digits,
+                          const FormatConversionSpecImpl conv) {
+  // always show 0x for %p.
+  bool alt = conv.has_alt_flag() ||
+             conv.conversion_char() == FormatConversionCharInternal::p;
+  bool hex = (conv.conversion_char() == FormatConversionCharInternal::x ||
+              conv.conversion_char() == FormatConversionCharInternal::X ||
+              conv.conversion_char() == FormatConversionCharInternal::p);
   // From the POSIX description of '#' flag:
   //   "For x or X conversion specifiers, a non-zero result shall have
   //   0x (or 0X) prefixed to it."
-  if (alt && radix == 16 && !info.digits().empty()) {
-    if (FormatConversionCharIsUpper(conv.conv())) return "0X";
-    return "0x";
+  if (alt && hex && !as_digits.without_neg_or_zero().empty()) {
+    return conv.conversion_char() == FormatConversionCharInternal::X ? "0X"
+                                                                     : "0x";
   }
   return {};
 }
 
-string_view SignColumn(bool neg, const ConversionSpec conv) {
-  if (FormatConversionCharIsSigned(conv.conv())) {
+string_view SignColumn(bool neg, const FormatConversionSpecImpl conv) {
+  if (conv.conversion_char() == FormatConversionCharInternal::d ||
+      conv.conversion_char() == FormatConversionCharInternal::i) {
     if (neg) return "-";
-    if (conv.flags().show_pos) return "+";
-    if (conv.flags().sign_col) return " ";
+    if (conv.has_show_pos_flag()) return "+";
+    if (conv.has_sign_col_flag()) return " ";
   }
   return {};
 }
 
-bool ConvertCharImpl(unsigned char v, const ConversionSpec conv,
+bool ConvertCharImpl(unsigned char v, const FormatConversionSpecImpl conv,
                      FormatSinkImpl *sink) {
   size_t fill = 0;
   if (conv.width() >= 0) fill = conv.width();
   ReducePadding(1, &fill);
-  if (!conv.flags().left) sink->Append(fill, ' ');
+  if (!conv.has_left_flag()) sink->Append(fill, ' ');
   sink->Append(1, v);
-  if (conv.flags().left) sink->Append(fill, ' ');
+  if (conv.has_left_flag()) sink->Append(fill, ' ');
   return true;
 }
 
-bool ConvertIntImplInner(const ConvertedIntInfo &info,
-                         const ConversionSpec conv, FormatSinkImpl *sink) {
+bool ConvertIntImplInnerSlow(const IntDigits &as_digits,
+                             const FormatConversionSpecImpl conv,
+                             FormatSinkImpl *sink) {
   // Print as a sequence of Substrings:
   //   [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces]
   size_t fill = 0;
   if (conv.width() >= 0) fill = conv.width();
 
-  string_view formatted = info.digits();
+  string_view formatted = as_digits.without_neg_or_zero();
   ReducePadding(formatted, &fill);
 
-  string_view sign = SignColumn(info.is_neg(), conv);
+  string_view sign = SignColumn(as_digits.is_negative(), conv);
   ReducePadding(sign, &fill);
 
-  string_view base_indicator = BaseIndicator(info, conv);
+  string_view base_indicator = BaseIndicator(as_digits, conv);
   ReducePadding(base_indicator, &fill);
 
   int precision = conv.precision();
@@ -174,7 +241,8 @@
   if (!precision_specified)
     precision = 1;
 
-  if (conv.flags().alt && conv.conv() == ConversionChar::o) {
+  if (conv.has_alt_flag() &&
+      conv.conversion_char() == FormatConversionCharInternal::o) {
     // From POSIX description of the '#' (alt) flag:
     //   "For o conversion, it increases the precision (if necessary) to
     //   force the first digit of the result to be zero."
@@ -187,13 +255,13 @@
   size_t num_zeroes = Excess(formatted.size(), precision);
   ReducePadding(num_zeroes, &fill);
 
-  size_t num_left_spaces = !conv.flags().left ? fill : 0;
-  size_t num_right_spaces = conv.flags().left ? fill : 0;
+  size_t num_left_spaces = !conv.has_left_flag() ? fill : 0;
+  size_t num_right_spaces = conv.has_left_flag() ? fill : 0;
 
   // From POSIX description of the '0' (zero) flag:
   //   "For d, i, o, u, x, and X conversion specifiers, if a precision
   //   is specified, the '0' flag is ignored."
-  if (!precision_specified && conv.flags().zero) {
+  if (!precision_specified && conv.has_zero_flag()) {
     num_zeroes += num_left_spaces;
     num_left_spaces = 0;
   }
@@ -208,71 +276,97 @@
 }
 
 template <typename T>
-bool ConvertIntImplInner(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
-  ConvertedIntInfo info(v, conv.conv());
-  if (conv.flags().basic && (conv.conv() != ConversionChar::p)) {
-    if (info.is_neg()) sink->Append(1, '-');
-    if (info.digits().empty()) {
-      sink->Append(1, '0');
-    } else {
-      sink->Append(info.digits());
-    }
+bool ConvertIntArg(T v, const FormatConversionSpecImpl conv,
+                   FormatSinkImpl *sink) {
+  using U = typename MakeUnsigned<T>::type;
+  IntDigits as_digits;
+
+  // This odd casting is due to a bug in -Wswitch behavior in gcc49 which causes
+  // it to complain about a switch/case type mismatch, even though both are
+  // FormatConverionChar.  Likely this is because at this point
+  // FormatConversionChar is declared, but not defined.
+  switch (static_cast<uint8_t>(conv.conversion_char())) {
+    case static_cast<uint8_t>(FormatConversionCharInternal::c):
+      return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);
+
+    case static_cast<uint8_t>(FormatConversionCharInternal::o):
+      as_digits.PrintAsOct(static_cast<U>(v));
+      break;
+
+    case static_cast<uint8_t>(FormatConversionCharInternal::x):
+      as_digits.PrintAsHexLower(static_cast<U>(v));
+      break;
+    case static_cast<uint8_t>(FormatConversionCharInternal::X):
+      as_digits.PrintAsHexUpper(static_cast<U>(v));
+      break;
+
+    case static_cast<uint8_t>(FormatConversionCharInternal::u):
+      as_digits.PrintAsDec(static_cast<U>(v));
+      break;
+
+    case static_cast<uint8_t>(FormatConversionCharInternal::d):
+    case static_cast<uint8_t>(FormatConversionCharInternal::i):
+      as_digits.PrintAsDec(v);
+      break;
+
+    case static_cast<uint8_t>(FormatConversionCharInternal::a):
+    case static_cast<uint8_t>(FormatConversionCharInternal::e):
+    case static_cast<uint8_t>(FormatConversionCharInternal::f):
+    case static_cast<uint8_t>(FormatConversionCharInternal::g):
+    case static_cast<uint8_t>(FormatConversionCharInternal::A):
+    case static_cast<uint8_t>(FormatConversionCharInternal::E):
+    case static_cast<uint8_t>(FormatConversionCharInternal::F):
+    case static_cast<uint8_t>(FormatConversionCharInternal::G):
+      return ConvertFloatImpl(static_cast<double>(v), conv, sink);
+
+    default:
+       ABSL_INTERNAL_ASSUME(false);
+  }
+
+  if (conv.is_basic()) {
+    sink->Append(as_digits.with_neg_and_zero());
     return true;
   }
-  return ConvertIntImplInner(info, conv, sink);
+  return ConvertIntImplInnerSlow(as_digits, conv, sink);
 }
 
 template <typename T>
-bool ConvertIntArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
-  if (FormatConversionCharIsFloat(conv.conv())) {
-    return FormatConvertImpl(static_cast<double>(v), conv, sink).value;
-  }
-  if (conv.conv() == ConversionChar::c)
-    return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);
-  if (!FormatConversionCharIsIntegral(conv.conv())) return false;
-  if (!FormatConversionCharIsSigned(conv.conv()) && IsSigned<T>::value) {
-    using U = typename MakeUnsigned<T>::type;
-    return FormatConvertImpl(static_cast<U>(v), conv, sink).value;
-  }
-  return ConvertIntImplInner(v, conv, sink);
-}
-
-template <typename T>
-bool ConvertFloatArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
-  return FormatConversionCharIsFloat(conv.conv()) &&
+bool ConvertFloatArg(T v, const FormatConversionSpecImpl conv,
+                     FormatSinkImpl *sink) {
+  return FormatConversionCharIsFloat(conv.conversion_char()) &&
          ConvertFloatImpl(v, conv, sink);
 }
 
-inline bool ConvertStringArg(string_view v, const ConversionSpec conv,
+inline bool ConvertStringArg(string_view v, const FormatConversionSpecImpl conv,
                              FormatSinkImpl *sink) {
-  if (conv.conv() != ConversionChar::s) return false;
-  if (conv.flags().basic) {
+  if (conv.is_basic()) {
     sink->Append(v);
     return true;
   }
   return sink->PutPaddedString(v, conv.width(), conv.precision(),
-                               conv.flags().left);
+                               conv.has_left_flag());
 }
 
 }  // namespace
 
 // ==================== Strings ====================
-ConvertResult<Conv::s> FormatConvertImpl(const std::string &v,
-                                         const ConversionSpec conv,
-                                         FormatSinkImpl *sink) {
+StringConvertResult FormatConvertImpl(const std::string &v,
+                                      const FormatConversionSpecImpl conv,
+                                      FormatSinkImpl *sink) {
   return {ConvertStringArg(v, conv, sink)};
 }
 
-ConvertResult<Conv::s> FormatConvertImpl(string_view v,
-                                         const ConversionSpec conv,
-                                         FormatSinkImpl *sink) {
+StringConvertResult FormatConvertImpl(string_view v,
+                                      const FormatConversionSpecImpl conv,
+                                      FormatSinkImpl *sink) {
   return {ConvertStringArg(v, conv, sink)};
 }
 
-ConvertResult<Conv::s | Conv::p> FormatConvertImpl(const char *v,
-                                                   const ConversionSpec conv,
-                                                   FormatSinkImpl *sink) {
-  if (conv.conv() == ConversionChar::p)
+ArgConvertResult<FormatConversionCharSetUnion(
+    FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
+FormatConvertImpl(const char *v, const FormatConversionSpecImpl conv,
+                  FormatSinkImpl *sink) {
+  if (conv.conversion_char() == FormatConversionCharInternal::p)
     return {FormatConvertImpl(VoidPtr(v), conv, sink).value};
   size_t len;
   if (v == nullptr) {
@@ -287,93 +381,99 @@
 }
 
 // ==================== Raw pointers ====================
-ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, const ConversionSpec conv,
-                                         FormatSinkImpl *sink) {
-  if (conv.conv() != ConversionChar::p) return {false};
+ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
+    VoidPtr v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
   if (!v.value) {
     sink->Append("(nil)");
     return {true};
   }
-  return {ConvertIntImplInner(v.value, conv, sink)};
+  IntDigits as_digits;
+  as_digits.PrintAsHexLower(v.value);
+  return {ConvertIntImplInnerSlow(as_digits, conv, sink)};
 }
 
 // ==================== Floats ====================
-FloatingConvertResult FormatConvertImpl(float v, const ConversionSpec conv,
+FloatingConvertResult FormatConvertImpl(float v,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertFloatArg(v, conv, sink)};
 }
-FloatingConvertResult FormatConvertImpl(double v, const ConversionSpec conv,
+FloatingConvertResult FormatConvertImpl(double v,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertFloatArg(v, conv, sink)};
 }
 FloatingConvertResult FormatConvertImpl(long double v,
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertFloatArg(v, conv, sink)};
 }
 
 // ==================== Chars ====================
-IntegralConvertResult FormatConvertImpl(char v, const ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(char v,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 IntegralConvertResult FormatConvertImpl(signed char v,
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 IntegralConvertResult FormatConvertImpl(unsigned char v,
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 
 // ==================== Ints ====================
 IntegralConvertResult FormatConvertImpl(short v,  // NOLINT
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 IntegralConvertResult FormatConvertImpl(unsigned short v,  // NOLINT
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
-IntegralConvertResult FormatConvertImpl(int v, const ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(int v,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
-IntegralConvertResult FormatConvertImpl(unsigned v, const ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(unsigned v,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 IntegralConvertResult FormatConvertImpl(long v,  // NOLINT
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 IntegralConvertResult FormatConvertImpl(unsigned long v,  // NOLINT
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 IntegralConvertResult FormatConvertImpl(long long v,  // NOLINT
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 IntegralConvertResult FormatConvertImpl(unsigned long long v,  // NOLINT
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 IntegralConvertResult FormatConvertImpl(absl::int128 v,
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 IntegralConvertResult FormatConvertImpl(absl::uint128 v,
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h
index 7a93756..7040c86 100644
--- a/absl/strings/internal/str_format/arg.h
+++ b/absl/strings/internal/str_format/arg.h
@@ -1,3 +1,17 @@
+// 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.
+
 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
 
@@ -25,16 +39,37 @@
 class FormatCountCapture;
 class FormatSink;
 
+template <absl::FormatConversionCharSet C>
+struct FormatConvertResult;
+class FormatConversionSpec;
+
 namespace str_format_internal {
 
 template <typename T, typename = void>
 struct HasUserDefinedConvert : std::false_type {};
 
 template <typename T>
-struct HasUserDefinedConvert<
-    T, void_t<decltype(AbslFormatConvert(
-           std::declval<const T&>(), std::declval<ConversionSpec>(),
-           std::declval<FormatSink*>()))>> : std::true_type {};
+struct HasUserDefinedConvert<T, void_t<decltype(AbslFormatConvert(
+                                    std::declval<const T&>(),
+                                    std::declval<const FormatConversionSpec&>(),
+                                    std::declval<FormatSink*>()))>>
+    : std::true_type {};
+
+void AbslFormatConvert();  // Stops the lexical name lookup
+template <typename T>
+auto FormatConvertImpl(const T& v, FormatConversionSpecImpl conv,
+                       FormatSinkImpl* sink)
+    -> decltype(AbslFormatConvert(v,
+                                  std::declval<const FormatConversionSpec&>(),
+                                  std::declval<FormatSink*>())) {
+  using FormatConversionSpecT =
+      absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatConversionSpec>;
+  using FormatSinkT =
+      absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatSink>;
+  auto fcs = conv.Wrap<FormatConversionSpecT>();
+  auto fs = sink->Wrap<FormatSinkT>();
+  return AbslFormatConvert(v, fcs, &fs);
+}
 
 template <typename T>
 class StreamedWrapper;
@@ -43,6 +78,13 @@
 // then convert it, appending to `sink` and return `true`.
 // Otherwise fail and return `false`.
 
+// AbslFormatConvert(v, conv, sink) is intended to be found by ADL on 'v'
+// as an extension mechanism. These FormatConvertImpl functions are the default
+// implementations.
+// The ADL search is augmented via the 'Sink*' parameter, which also
+// serves as a disambiguator to reject possible unintended 'AbslFormatConvert'
+// functions in the namespaces associated with 'v'.
+
 // Raw pointers.
 struct VoidPtr {
   VoidPtr() = default;
@@ -52,27 +94,45 @@
       : value(ptr ? reinterpret_cast<uintptr_t>(ptr) : 0) {}
   uintptr_t value;
 };
-ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, ConversionSpec conv,
-                                         FormatSinkImpl* sink);
+
+template <FormatConversionCharSet C>
+struct ArgConvertResult {
+  bool value;
+};
+
+template <FormatConversionCharSet C>
+constexpr FormatConversionCharSet ExtractCharSet(FormatConvertResult<C>) {
+  return C;
+}
+
+template <FormatConversionCharSet C>
+constexpr FormatConversionCharSet ExtractCharSet(ArgConvertResult<C>) {
+  return C;
+}
+
+using StringConvertResult =
+    ArgConvertResult<FormatConversionCharSetInternal::s>;
+ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
+    VoidPtr v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
 
 // Strings.
-ConvertResult<Conv::s> FormatConvertImpl(const std::string& v,
-                                         ConversionSpec conv,
-                                         FormatSinkImpl* sink);
-ConvertResult<Conv::s> FormatConvertImpl(string_view v, ConversionSpec conv,
-                                         FormatSinkImpl* sink);
-ConvertResult<Conv::s | Conv::p> FormatConvertImpl(const char* v,
-                                                   ConversionSpec conv,
-                                                   FormatSinkImpl* sink);
-template <class AbslCord,
-          typename std::enable_if<
-              std::is_same<AbslCord, absl::Cord>::value>::type* = nullptr>
-ConvertResult<Conv::s> FormatConvertImpl(const AbslCord& value,
-                                         ConversionSpec conv,
-                                         FormatSinkImpl* sink) {
-  if (conv.conv() != ConversionChar::s) return {false};
+StringConvertResult FormatConvertImpl(const std::string& v,
+                                      FormatConversionSpecImpl conv,
+                                      FormatSinkImpl* sink);
+StringConvertResult FormatConvertImpl(string_view v,
+                                      FormatConversionSpecImpl conv,
+                                      FormatSinkImpl* sink);
+ArgConvertResult<FormatConversionCharSetUnion(
+    FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
+FormatConvertImpl(const char* v, const FormatConversionSpecImpl conv,
+                  FormatSinkImpl* sink);
 
-  bool is_left = conv.flags().left;
+template <class AbslCord, typename std::enable_if<std::is_same<
+                              AbslCord, absl::Cord>::value>::type* = nullptr>
+StringConvertResult FormatConvertImpl(const AbslCord& value,
+                                      FormatConversionSpecImpl conv,
+                                      FormatSinkImpl* sink) {
+  bool is_left = conv.has_left_flag();
   size_t space_remaining = 0;
 
   int width = conv.width();
@@ -105,55 +165,63 @@
   return {true};
 }
 
-using IntegralConvertResult =
-    ConvertResult<Conv::c | Conv::numeric | Conv::star>;
-using FloatingConvertResult = ConvertResult<Conv::floating>;
+using IntegralConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
+    FormatConversionCharSetInternal::c,
+    FormatConversionCharSetInternal::kNumeric,
+    FormatConversionCharSetInternal::kStar)>;
+using FloatingConvertResult =
+    ArgConvertResult<FormatConversionCharSetInternal::kFloating>;
 
 // Floats.
-FloatingConvertResult FormatConvertImpl(float v, ConversionSpec conv,
+FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
-FloatingConvertResult FormatConvertImpl(double v, ConversionSpec conv,
+FloatingConvertResult FormatConvertImpl(double v, FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
-FloatingConvertResult FormatConvertImpl(long double v, ConversionSpec conv,
+FloatingConvertResult FormatConvertImpl(long double v,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
 
 // Chars.
-IntegralConvertResult FormatConvertImpl(char v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(signed char v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(signed char v,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(unsigned char v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(unsigned char v,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
 
 // Ints.
 IntegralConvertResult FormatConvertImpl(short v,  // NOLINT
-                                        ConversionSpec conv,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
 IntegralConvertResult FormatConvertImpl(unsigned short v,  // NOLINT
-                                        ConversionSpec conv,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(int v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(int v, FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(unsigned v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(unsigned v,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
 IntegralConvertResult FormatConvertImpl(long v,  // NOLINT
-                                        ConversionSpec conv,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
 IntegralConvertResult FormatConvertImpl(unsigned long v,  // NOLINT
-                                        ConversionSpec conv,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
 IntegralConvertResult FormatConvertImpl(long long v,  // NOLINT
-                                        ConversionSpec conv,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
 IntegralConvertResult FormatConvertImpl(unsigned long long v,  // NOLINT
-                                        ConversionSpec conv,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(int128 v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(int128 v, FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(uint128 v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(uint128 v,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
 template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0>
-IntegralConvertResult FormatConvertImpl(T v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink) {
   return FormatConvertImpl(static_cast<int>(v), conv, sink);
 }
@@ -164,12 +232,12 @@
 typename std::enable_if<std::is_enum<T>::value &&
                             !HasUserDefinedConvert<T>::value,
                         IntegralConvertResult>::type
-FormatConvertImpl(T v, ConversionSpec conv, FormatSinkImpl* sink);
+FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
 
 template <typename T>
-ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<T>& v,
-                                         ConversionSpec conv,
-                                         FormatSinkImpl* out) {
+StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v,
+                                      FormatConversionSpecImpl conv,
+                                      FormatSinkImpl* out) {
   std::ostringstream oss;
   oss << v.v_;
   if (!oss) return {false};
@@ -180,21 +248,24 @@
 // until after FormatCountCapture is fully defined.
 struct FormatCountCaptureHelper {
   template <class T = int>
-  static ConvertResult<Conv::n> ConvertHelper(const FormatCountCapture& v,
-                                              ConversionSpec conv,
-                                              FormatSinkImpl* sink) {
+  static ArgConvertResult<FormatConversionCharSetInternal::n> ConvertHelper(
+      const FormatCountCapture& v, FormatConversionSpecImpl conv,
+      FormatSinkImpl* sink) {
     const absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v;
 
-    if (conv.conv() != str_format_internal::ConversionChar::n) return {false};
+    if (conv.conversion_char() !=
+        str_format_internal::FormatConversionCharInternal::n) {
+      return {false};
+    }
     *v2.p_ = static_cast<int>(sink->size());
     return {true};
   }
 };
 
 template <class T = int>
-ConvertResult<Conv::n> FormatConvertImpl(const FormatCountCapture& v,
-                                         ConversionSpec conv,
-                                         FormatSinkImpl* sink) {
+ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl(
+    const FormatCountCapture& v, FormatConversionSpecImpl conv,
+    FormatSinkImpl* sink) {
   return FormatCountCaptureHelper::ConvertHelper(v, conv, sink);
 }
 
@@ -203,13 +274,13 @@
 struct FormatArgImplFriend {
   template <typename Arg>
   static bool ToInt(Arg arg, int* out) {
-    // A value initialized ConversionSpec has a `none` conv, which tells the
-    // dispatcher to run the `int` conversion.
+    // A value initialized FormatConversionSpecImpl has a `none` conv, which
+    // tells the dispatcher to run the `int` conversion.
     return arg.dispatcher_(arg.data_, {}, out);
   }
 
   template <typename Arg>
-  static bool Convert(Arg arg, str_format_internal::ConversionSpec conv,
+  static bool Convert(Arg arg, FormatConversionSpecImpl conv,
                       FormatSinkImpl* out) {
     return arg.dispatcher_(arg.data_, conv, out);
   }
@@ -220,6 +291,15 @@
   }
 };
 
+template <typename Arg>
+constexpr FormatConversionCharSet ArgumentToConv() {
+  return absl::str_format_internal::ExtractCharSet(
+      decltype(str_format_internal::FormatConvertImpl(
+          std::declval<const Arg&>(),
+          std::declval<const FormatConversionSpecImpl&>(),
+          std::declval<FormatSinkImpl*>())){});
+}
+
 // A type-erased handle to a format argument.
 class FormatArgImpl {
  private:
@@ -233,7 +313,7 @@
     char buf[kInlinedSpace];
   };
 
-  using Dispatcher = bool (*)(Data, ConversionSpec, void* out);
+  using Dispatcher = bool (*)(Data, FormatConversionSpecImpl, void* out);
 
   template <typename T>
   struct store_by_value
@@ -375,15 +455,20 @@
   }
 
   template <typename T>
-  static bool Dispatch(Data arg, ConversionSpec spec, void* out) {
+  static bool Dispatch(Data arg, FormatConversionSpecImpl spec, void* out) {
     // A `none` conv indicates that we want the `int` conversion.
-    if (ABSL_PREDICT_FALSE(spec.conv() == ConversionChar::none)) {
+    if (ABSL_PREDICT_FALSE(spec.conversion_char() ==
+                           FormatConversionCharInternal::kNone)) {
       return ToInt<T>(arg, static_cast<int*>(out), std::is_integral<T>(),
                       std::is_enum<T>());
     }
-
+    if (ABSL_PREDICT_FALSE(!Contains(ArgumentToConv<T>(),
+                                     spec.conversion_char()))) {
+      return false;
+    }
     return str_format_internal::FormatConvertImpl(
-               Manager<T>::Value(arg), spec, static_cast<FormatSinkImpl*>(out))
+               Manager<T>::Value(arg), spec,
+               static_cast<FormatSinkImpl*>(out))
         .value;
   }
 
@@ -391,8 +476,9 @@
   Dispatcher dispatcher_;
 };
 
-#define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \
-  E template bool FormatArgImpl::Dispatch<T>(Data, ConversionSpec, void*)
+#define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E)                     \
+  E template bool FormatArgImpl::Dispatch<T>(Data, FormatConversionSpecImpl, \
+                                             void*)
 
 #define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...)                   \
   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr,     \
diff --git a/absl/strings/internal/str_format/arg_test.cc b/absl/strings/internal/str_format/arg_test.cc
index 8d30d8b..1261937 100644
--- a/absl/strings/internal/str_format/arg_test.cc
+++ b/absl/strings/internal/str_format/arg_test.cc
@@ -6,6 +6,12 @@
 //
 //      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/str_format/arg.h"
 
 #include <ostream>
@@ -23,8 +29,17 @@
   enum Color { kRed, kGreen, kBlue };
 
   static const char *hi() { return "hi"; }
+
+  struct X {};
+
+  X x_;
 };
 
+inline FormatConvertResult<FormatConversionCharSet{}> AbslFormatConvert(
+    const FormatArgImplTest::X &, const FormatConversionSpec &, FormatSink *) {
+  return {false};
+}
+
 TEST_F(FormatArgImplTest, ToInt) {
   int out = 0;
   EXPECT_TRUE(FormatArgImplFriend::ToInt(FormatArgImpl(1), &out));
@@ -59,6 +74,7 @@
       FormatArgImpl(static_cast<int *>(nullptr)), &out));
   EXPECT_FALSE(FormatArgImplFriend::ToInt(FormatArgImpl(hi()), &out));
   EXPECT_FALSE(FormatArgImplFriend::ToInt(FormatArgImpl("hi"), &out));
+  EXPECT_FALSE(FormatArgImplFriend::ToInt(FormatArgImpl(x_), &out));
   EXPECT_TRUE(FormatArgImplFriend::ToInt(FormatArgImpl(kBlue), &out));
   EXPECT_EQ(2, out);
 }
@@ -95,8 +111,9 @@
 TEST_F(FormatArgImplTest, WorksWithCharArraysOfUnknownSize) {
   std::string s;
   FormatSinkImpl sink(&s);
-  ConversionSpec conv;
-  FormatConversionSpecImplFriend::SetConversionChar(ConversionChar::s, &conv);
+  FormatConversionSpecImpl conv;
+  FormatConversionSpecImplFriend::SetConversionChar(
+      FormatConversionCharInternal::s, &conv);
   FormatConversionSpecImplFriend::SetFlags(Flags(), &conv);
   FormatConversionSpecImplFriend::SetWidth(-1, &conv);
   FormatConversionSpecImplFriend::SetPrecision(-1, &conv);
diff --git a/absl/strings/internal/str_format/bind.cc b/absl/strings/internal/str_format/bind.cc
index 27522fd..4e68b90 100644
--- a/absl/strings/internal/str_format/bind.cc
+++ b/absl/strings/internal/str_format/bind.cc
@@ -1,3 +1,17 @@
+// 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/strings/internal/str_format/bind.h"
 
 #include <cerrno>
@@ -147,7 +161,7 @@
        << FormatConversionSpecImplFriend::FlagsToString(bound);
     if (bound.width() >= 0) ss << bound.width();
     if (bound.precision() >= 0) ss << "." << bound.precision();
-    ss << bound.conv() << "}";
+    ss << bound.conversion_char() << "}";
     Append(ss.str());
     return true;
   }
@@ -221,7 +235,7 @@
     errno = sink.error();
     return -1;
   }
-  if (sink.count() > std::numeric_limits<int>::max()) {
+  if (sink.count() > static_cast<size_t>(std::numeric_limits<int>::max())) {
     errno = EFBIG;
     return -1;
   }
diff --git a/absl/strings/internal/str_format/bind.h b/absl/strings/internal/str_format/bind.h
index cf41b19..267cc0e 100644
--- a/absl/strings/internal/str_format/bind.h
+++ b/absl/strings/internal/str_format/bind.h
@@ -1,3 +1,17 @@
+// 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.
+
 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
 
@@ -19,7 +33,7 @@
 
 namespace str_format_internal {
 
-class BoundConversion : public ConversionSpec {
+class BoundConversion : public FormatConversionSpecImpl {
  public:
   const FormatArgImpl* arg() const { return arg_; }
   void set_arg(const FormatArgImpl* a) { arg_ = a; }
@@ -60,7 +74,7 @@
   size_t size_;
 };
 
-template <typename T, typename...>
+template <typename T, FormatConversionCharSet...>
 struct MakeDependent {
   using type = T;
 };
@@ -68,7 +82,7 @@
 // Implicitly convertible from `const char*`, `string_view`, and the
 // `ExtendedParsedFormat` type. This abstraction allows all format functions to
 // operate on any without providing too many overloads.
-template <typename... Args>
+template <FormatConversionCharSet... Args>
 class FormatSpecTemplate
     : public MakeDependent<UntypedFormatSpec, Args...>::type {
   using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type;
@@ -76,11 +90,11 @@
  public:
 #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
 
-  // Honeypot overload for when the std::string is not constexpr.
+  // Honeypot overload for when the string is not constexpr.
   // We use the 'unavailable' attribute to give a better compiler error than
   // just 'method is deleted'.
   FormatSpecTemplate(...)  // NOLINT
-      __attribute__((unavailable("Format std::string is not constexpr.")));
+      __attribute__((unavailable("Format string is not constexpr.")));
 
   // Honeypot overload for when the format is constexpr and invalid.
   // We use the 'unavailable' attribute to give a better compiler error than
@@ -105,13 +119,11 @@
 
   // Good format overload.
   FormatSpecTemplate(const char* s)  // NOLINT
-      __attribute__((enable_if(ValidFormatImpl<ArgumentToConv<Args>()...>(s),
-                               "bad format trap")))
+      __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap")))
       : Base(s) {}
 
   FormatSpecTemplate(string_view s)  // NOLINT
-      __attribute__((enable_if(ValidFormatImpl<ArgumentToConv<Args>()...>(s),
-                               "bad format trap")))
+      __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap")))
       : Base(s) {}
 
 #else  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
@@ -121,19 +133,15 @@
 
 #endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
 
-  template <Conv... C, typename = typename std::enable_if<
-                           AllOf(sizeof...(C) == sizeof...(Args),
-                             Contains(ArgumentToConv<Args>(),
-                                          C)...)>::type>
+  template <
+      FormatConversionCharSet... C,
+      typename = typename std::enable_if<sizeof...(C) == sizeof...(Args)>::type,
+      typename = typename std::enable_if<AllOf(Contains(Args,
+                                                        C)...)>::type>
   FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc)  // NOLINT
       : Base(&pc) {}
 };
 
-template <typename... Args>
-struct FormatSpecDeductionBarrier {
-  using type = FormatSpecTemplate<Args...>;
-};
-
 class Streamable {
  public:
   Streamable(const UntypedFormatSpecImpl& format,
@@ -196,9 +204,9 @@
 
  private:
   template <typename S>
-  friend ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<S>& v,
-                                                  ConversionSpec conv,
-                                                  FormatSinkImpl* out);
+  friend ArgConvertResult<FormatConversionCharSetInternal::s> FormatConvertImpl(
+      const StreamedWrapper<S>& v, FormatConversionSpecImpl conv,
+      FormatSinkImpl* out);
   const T& v_;
 };
 
diff --git a/absl/strings/internal/str_format/bind_test.cc b/absl/strings/internal/str_format/bind_test.cc
index 64790a8..1eef9c4 100644
--- a/absl/strings/internal/str_format/bind_test.cc
+++ b/absl/strings/internal/str_format/bind_test.cc
@@ -1,3 +1,17 @@
+// 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/strings/internal/str_format/bind.h"
 
 #include <string.h>
diff --git a/absl/strings/internal/str_format/checker.h b/absl/strings/internal/str_format/checker.h
index 8993a79..2a2601e 100644
--- a/absl/strings/internal/str_format/checker.h
+++ b/absl/strings/internal/str_format/checker.h
@@ -1,3 +1,17 @@
+// 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.
+
 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
 
@@ -24,13 +38,6 @@
   return b && AllOf(t...);
 }
 
-template <typename Arg>
-constexpr Conv ArgumentToConv() {
-  return decltype(str_format_internal::FormatConvertImpl(
-      std::declval<const Arg&>(), std::declval<const ConversionSpec&>(),
-      std::declval<FormatSinkImpl*>()))::kConv;
-}
-
 #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
 
 constexpr bool ContainsChar(const char* chars, char c) {
@@ -39,14 +46,14 @@
 
 // A constexpr compatible list of Convs.
 struct ConvList {
-  const Conv* array;
+  const FormatConversionCharSet* array;
   int count;
 
   // We do the bound check here to avoid having to do it on the callers.
-  // Returning an empty Conv has the same effect as short circuiting because it
-  // will never match any conversion.
-  constexpr Conv operator[](int i) const {
-    return i < count ? array[i] : Conv{};
+  // Returning an empty FormatConversionCharSet has the same effect as
+  // short circuiting because it will never match any conversion.
+  constexpr FormatConversionCharSet operator[](int i) const {
+    return i < count ? array[i] : FormatConversionCharSet{};
   }
 
   constexpr ConvList without_front() const {
@@ -57,7 +64,7 @@
 template <size_t count>
 struct ConvListT {
   // Make sure the array has size > 0.
-  Conv list[count ? count : 1];
+  FormatConversionCharSet list[count ? count : 1];
 };
 
 constexpr char GetChar(string_view str, size_t index) {
@@ -310,7 +317,7 @@
   ConvList args_;
 };
 
-template <Conv... C>
+template <FormatConversionCharSet... C>
 constexpr bool ValidFormatImpl(string_view format) {
   return FormatParser(format,
                       {ConvListT<sizeof...(C)>{{C...}}.list, sizeof...(C)})
diff --git a/absl/strings/internal/str_format/checker_test.cc b/absl/strings/internal/str_format/checker_test.cc
index ea2a768..7c70f47 100644
--- a/absl/strings/internal/str_format/checker_test.cc
+++ b/absl/strings/internal/str_format/checker_test.cc
@@ -1,3 +1,17 @@
+// 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 <string>
 
 #include "gmock/gmock.h"
@@ -9,18 +23,22 @@
 namespace str_format_internal {
 namespace {
 
-std::string ConvToString(Conv conv) {
+std::string ConvToString(FormatConversionCharSet conv) {
   std::string out;
-#define CONV_SET_CASE(c) \
-  if (Contains(conv, Conv::c)) out += #c;
+#define CONV_SET_CASE(c)                                    \
+  if (Contains(conv, FormatConversionCharSetInternal::c)) { \
+    out += #c;                                              \
+  }
   ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(CONV_SET_CASE, )
 #undef CONV_SET_CASE
-  if (Contains(conv, Conv::star)) out += "*";
+  if (Contains(conv, FormatConversionCharSetInternal::kStar)) {
+    out += "*";
+  }
   return out;
 }
 
 TEST(StrFormatChecker, ArgumentToConv) {
-  Conv conv = ArgumentToConv<std::string>();
+  FormatConversionCharSet conv = ArgumentToConv<std::string>();
   EXPECT_EQ(ConvToString(conv), "s");
 
   conv = ArgumentToConv<const char*>();
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc
index cbcd7ca..926283c 100644
--- a/absl/strings/internal/str_format/convert_test.cc
+++ b/absl/strings/internal/str_format/convert_test.cc
@@ -1,20 +1,46 @@
+// 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 <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
+
 #include <cctype>
 #include <cmath>
+#include <limits>
 #include <string>
+#include <thread>  // NOLINT
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/strings/internal/str_format/bind.h"
+#include "absl/strings/match.h"
+#include "absl/types/optional.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace str_format_internal {
 namespace {
 
+struct NativePrintfTraits {
+  bool hex_float_has_glibc_rounding;
+  bool hex_float_prefers_denormal_repr;
+  bool hex_float_uses_minimal_precision_when_not_specified;
+  bool hex_float_optimizes_leading_digit_bit_count;
+};
+
 template <typename T, size_t N>
 size_t ArraySize(T (&)[N]) {
   return N;
@@ -57,7 +83,7 @@
   return oss.str();
 }
 
-void StrAppend(std::string *dst, const char *format, va_list ap) {
+void StrAppendV(std::string *dst, const char *format, va_list ap) {
   // First try with a small fixed size buffer
   static const int kSpaceLength = 1024;
   char space[kSpaceLength];
@@ -98,15 +124,79 @@
   delete[] buf;
 }
 
+void StrAppend(std::string *out, const char *format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  StrAppendV(out, format, ap);
+  va_end(ap);
+}
+
 std::string StrPrint(const char *format, ...) {
   va_list ap;
   va_start(ap, format);
   std::string result;
-  StrAppend(&result, format, ap);
+  StrAppendV(&result, format, ap);
   va_end(ap);
   return result;
 }
 
+NativePrintfTraits VerifyNativeImplementationImpl() {
+  NativePrintfTraits result;
+
+  // >>> hex_float_has_glibc_rounding. To have glibc's rounding behavior we need
+  // to meet three requirements:
+  //
+  //   - The threshold for rounding up is 8 (for e.g. MSVC uses 9).
+  //   - If the digits lower than than the 8 are non-zero then we round up.
+  //   - If the digits lower than the 8 are all zero then we round toward even.
+  //
+  // The numbers below represent all the cases covering {below,at,above} the
+  // threshold (8) with both {zero,non-zero} lower bits and both {even,odd}
+  // preceding digits.
+  const double d0079 = 65657.0;  // 0x1.0079p+16
+  const double d0179 = 65913.0;  // 0x1.0179p+16
+  const double d0080 = 65664.0;  // 0x1.0080p+16
+  const double d0180 = 65920.0;  // 0x1.0180p+16
+  const double d0081 = 65665.0;  // 0x1.0081p+16
+  const double d0181 = 65921.0;  // 0x1.0181p+16
+  result.hex_float_has_glibc_rounding =
+      StartsWith(StrPrint("%.2a", d0079), "0x1.00") &&
+      StartsWith(StrPrint("%.2a", d0179), "0x1.01") &&
+      StartsWith(StrPrint("%.2a", d0080), "0x1.00") &&
+      StartsWith(StrPrint("%.2a", d0180), "0x1.02") &&
+      StartsWith(StrPrint("%.2a", d0081), "0x1.01") &&
+      StartsWith(StrPrint("%.2a", d0181), "0x1.02");
+
+  // >>> hex_float_prefers_denormal_repr. Formatting `denormal` on glibc yields
+  // "0x0.0000000000001p-1022", whereas on std libs that don't use denormal
+  // representation it would either be 0x1p-1074 or 0x1.0000000000000-1074.
+  const double denormal = std::numeric_limits<double>::denorm_min();
+  result.hex_float_prefers_denormal_repr =
+      StartsWith(StrPrint("%a", denormal), "0x0.0000000000001");
+
+  // >>> hex_float_uses_minimal_precision_when_not_specified. Some (non-glibc)
+  // libs will format the following as "0x1.0079000000000p+16".
+  result.hex_float_uses_minimal_precision_when_not_specified =
+      (StrPrint("%a", d0079) == "0x1.0079p+16");
+
+  // >>> hex_float_optimizes_leading_digit_bit_count. The number 1.5, when
+  // formatted by glibc should yield "0x1.8p+0" for `double` and "0xcp-3" for
+  // `long double`, i.e., number of bits in the leading digit is adapted to the
+  // number of bits in the mantissa.
+  const double d_15 = 1.5;
+  const long double ld_15 = 1.5;
+  result.hex_float_optimizes_leading_digit_bit_count =
+      StartsWith(StrPrint("%a", d_15), "0x1.8") &&
+      StartsWith(StrPrint("%La", ld_15), "0xc");
+
+  return result;
+}
+
+const NativePrintfTraits &VerifyNativeImplementation() {
+  static NativePrintfTraits native_traits = VerifyNativeImplementationImpl();
+  return native_traits;
+}
+
 class FormatConvertTest : public ::testing::Test { };
 
 template <typename T>
@@ -463,17 +553,130 @@
   }
 }
 
-TEST_F(FormatConvertTest, Float) {
-#ifdef _MSC_VER
-  // MSVC has a different rounding policy than us so we can't test our
-  // implementation against the native one there.
-  return;
-#endif  // _MSC_VER
+template <typename Floating>
+void TestWithMultipleFormatsHelper(const std::vector<Floating> &floats,
+                                   const std::set<Floating> &skip_verify) {
+  const NativePrintfTraits &native_traits = VerifyNativeImplementation();
+  // Reserve the space to ensure we don't allocate memory in the output itself.
+  std::string str_format_result;
+  str_format_result.reserve(1 << 20);
+  std::string string_printf_result;
+  string_printf_result.reserve(1 << 20);
 
   const char *const kFormats[] = {
-      "%",  "%.3",  "%8.5",   "%9",   "%.60", "%.30",   "%03",    "%+",
-      "% ", "%-10", "%#15.3", "%#.0", "%.0",  "%1$*2$", "%1$.*2$"};
+      "%",  "%.3", "%8.5", "%500",   "%.5000", "%.60", "%.30",   "%03",
+      "%+", "% ",  "%-10", "%#15.3", "%#.0",   "%.0",  "%1$*2$", "%1$.*2$"};
 
+  for (const char *fmt : kFormats) {
+    for (char f : {'f', 'F',  //
+                   'g', 'G',  //
+                   'a', 'A',  //
+                   'e', 'E'}) {
+      std::string fmt_str = std::string(fmt) + f;
+
+      if (fmt == absl::string_view("%.5000") && f != 'f' && f != 'F' &&
+          f != 'a' && f != 'A') {
+        // This particular test takes way too long with snprintf.
+        // Disable for the case we are not implementing natively.
+        continue;
+      }
+
+      if ((f == 'a' || f == 'A') &&
+          !native_traits.hex_float_has_glibc_rounding) {
+        continue;
+      }
+
+      for (Floating d : floats) {
+        if (!native_traits.hex_float_prefers_denormal_repr &&
+            (f == 'a' || f == 'A') && std::fpclassify(d) == FP_SUBNORMAL) {
+          continue;
+        }
+        int i = -10;
+        FormatArgImpl args[2] = {FormatArgImpl(d), FormatArgImpl(i)};
+        UntypedFormatSpecImpl format(fmt_str);
+
+        string_printf_result.clear();
+        StrAppend(&string_printf_result, fmt_str.c_str(), d, i);
+        str_format_result.clear();
+
+        {
+          AppendPack(&str_format_result, format, absl::MakeSpan(args));
+        }
+
+#ifdef _MSC_VER
+        // MSVC has a different rounding policy than us so we can't test our
+        // implementation against the native one there.
+        continue;
+#elif defined(__APPLE__)
+        // Apple formats NaN differently (+nan) vs. (nan)
+        if (std::isnan(d)) continue;
+#endif
+        if (string_printf_result != str_format_result &&
+            skip_verify.find(d) == skip_verify.end()) {
+          // We use ASSERT_EQ here because failures are usually correlated and a
+          // bug would print way too many failed expectations causing the test
+          // to time out.
+          ASSERT_EQ(string_printf_result, str_format_result)
+              << fmt_str << " " << StrPrint("%.18g", d) << " "
+              << StrPrint("%a", d) << " " << StrPrint("%.50f", d);
+        }
+      }
+    }
+  }
+}
+
+TEST_F(FormatConvertTest, Float) {
+  std::vector<float> floats = {0.0f,
+                               -0.0f,
+                               .9999999f,
+                               9999999.f,
+                               std::numeric_limits<float>::max(),
+                               -std::numeric_limits<float>::max(),
+                               std::numeric_limits<float>::min(),
+                               -std::numeric_limits<float>::min(),
+                               std::numeric_limits<float>::lowest(),
+                               -std::numeric_limits<float>::lowest(),
+                               std::numeric_limits<float>::epsilon(),
+                               std::numeric_limits<float>::epsilon() + 1.0f,
+                               std::numeric_limits<float>::infinity(),
+                               -std::numeric_limits<float>::infinity(),
+                               std::nanf("")};
+
+  // Some regression tests.
+  floats.push_back(0.999999989f);
+
+  if (std::numeric_limits<float>::has_denorm != std::denorm_absent) {
+    floats.push_back(std::numeric_limits<float>::denorm_min());
+    floats.push_back(-std::numeric_limits<float>::denorm_min());
+  }
+
+  for (float base :
+       {1.f, 12.f, 123.f, 1234.f, 12345.f, 123456.f, 1234567.f, 12345678.f,
+        123456789.f, 1234567890.f, 12345678901.f, 12345678.f, 12345678.f}) {
+    for (int exp = -123; exp <= 123; ++exp) {
+      for (int sign : {1, -1}) {
+        floats.push_back(sign * std::ldexp(base, exp));
+      }
+    }
+  }
+
+  for (int exp = -300; exp <= 300; ++exp) {
+    const float all_ones_mantissa = 0xffffff;
+    floats.push_back(std::ldexp(all_ones_mantissa, exp));
+  }
+
+  // Remove duplicates to speed up the logic below.
+  std::sort(floats.begin(), floats.end());
+  floats.erase(std::unique(floats.begin(), floats.end()), floats.end());
+
+  TestWithMultipleFormatsHelper(floats, {});
+}
+
+TEST_F(FormatConvertTest, Double) {
+  // For values that we know won't match the standard library implementation we
+  // skip verification, but still run the algorithm to catch asserts/sanitizer
+  // bugs.
+  std::set<double> skip_verify;
   std::vector<double> doubles = {0.0,
                                  -0.0,
                                  .99999999999999,
@@ -487,12 +690,8 @@
                                  std::numeric_limits<double>::epsilon(),
                                  std::numeric_limits<double>::epsilon() + 1,
                                  std::numeric_limits<double>::infinity(),
-                                 -std::numeric_limits<double>::infinity()};
-
-#ifndef __APPLE__
-  // Apple formats NaN differently (+nan) vs. (nan)
-  doubles.push_back(std::nan(""));
-#endif
+                                 -std::numeric_limits<double>::infinity(),
+                                 std::nan("")};
 
   // Some regression tests.
   doubles.push_back(0.99999999999999989);
@@ -512,43 +711,366 @@
     }
   }
 
-  for (const char *fmt : kFormats) {
-    for (char f : {'f', 'F',  //
-                   'g', 'G',  //
-                   'a', 'A',  //
-                   'e', 'E'}) {
-      std::string fmt_str = std::string(fmt) + f;
-      for (double d : doubles) {
-        int i = -10;
-        FormatArgImpl args[2] = {FormatArgImpl(d), FormatArgImpl(i)};
-        UntypedFormatSpecImpl format(fmt_str);
-        // We use ASSERT_EQ here because failures are usually correlated and a
-        // bug would print way too many failed expectations causing the test to
-        // time out.
-        ASSERT_EQ(StrPrint(fmt_str.c_str(), d, i),
-                  FormatPack(format, absl::MakeSpan(args)))
-            << fmt_str << " " << StrPrint("%.18g", d) << " "
-            << StrPrint("%.999f", d);
-      }
+  // Workaround libc bug.
+  // https://sourceware.org/bugzilla/show_bug.cgi?id=22142
+  const bool gcc_bug_22142 =
+      StrPrint("%f", std::numeric_limits<double>::max()) !=
+      "1797693134862315708145274237317043567980705675258449965989174768031"
+      "5726078002853876058955863276687817154045895351438246423432132688946"
+      "4182768467546703537516986049910576551282076245490090389328944075868"
+      "5084551339423045832369032229481658085593321233482747978262041447231"
+      "68738177180919299881250404026184124858368.000000";
+
+  for (int exp = -300; exp <= 300; ++exp) {
+    const double all_ones_mantissa = 0x1fffffffffffff;
+    doubles.push_back(std::ldexp(all_ones_mantissa, exp));
+    if (gcc_bug_22142) {
+      skip_verify.insert(doubles.back());
+    }
+  }
+
+  if (gcc_bug_22142) {
+    using L = std::numeric_limits<double>;
+    skip_verify.insert(L::max());
+    skip_verify.insert(L::min());  // NOLINT
+    skip_verify.insert(L::denorm_min());
+    skip_verify.insert(-L::max());
+    skip_verify.insert(-L::min());  // NOLINT
+    skip_verify.insert(-L::denorm_min());
+  }
+
+  // Remove duplicates to speed up the logic below.
+  std::sort(doubles.begin(), doubles.end());
+  doubles.erase(std::unique(doubles.begin(), doubles.end()), doubles.end());
+
+  TestWithMultipleFormatsHelper(doubles, skip_verify);
+}
+
+TEST_F(FormatConvertTest, DoubleRound) {
+  std::string s;
+  const auto format = [&](const char *fmt, double d) -> std::string & {
+    s.clear();
+    FormatArgImpl args[1] = {FormatArgImpl(d)};
+    AppendPack(&s, UntypedFormatSpecImpl(fmt), absl::MakeSpan(args));
+#if !defined(_MSC_VER)
+    // MSVC has a different rounding policy than us so we can't test our
+    // implementation against the native one there.
+    EXPECT_EQ(StrPrint(fmt, d), s);
+#endif  // _MSC_VER
+
+    return s;
+  };
+  // All of these values have to be exactly represented.
+  // Otherwise we might not be testing what we think we are testing.
+
+  // These values can fit in a 64bit "fast" representation.
+  const double exact_value = 0.00000000000005684341886080801486968994140625;
+  assert(exact_value == std::pow(2, -44));
+  // Round up at a 5xx.
+  EXPECT_EQ(format("%.13f", exact_value), "0.0000000000001");
+  // Round up at a >5
+  EXPECT_EQ(format("%.14f", exact_value), "0.00000000000006");
+  // Round down at a <5
+  EXPECT_EQ(format("%.16f", exact_value), "0.0000000000000568");
+  // Nine handling
+  EXPECT_EQ(format("%.35f", exact_value),
+            "0.00000000000005684341886080801486969");
+  EXPECT_EQ(format("%.36f", exact_value),
+            "0.000000000000056843418860808014869690");
+  // Round down the last nine.
+  EXPECT_EQ(format("%.37f", exact_value),
+            "0.0000000000000568434188608080148696899");
+  EXPECT_EQ(format("%.10f", 0.000003814697265625), "0.0000038147");
+  // Round up the last nine
+  EXPECT_EQ(format("%.11f", 0.000003814697265625), "0.00000381470");
+  EXPECT_EQ(format("%.12f", 0.000003814697265625), "0.000003814697");
+
+  // Round to even (down)
+  EXPECT_EQ(format("%.43f", exact_value),
+            "0.0000000000000568434188608080148696899414062");
+  // Exact
+  EXPECT_EQ(format("%.44f", exact_value),
+            "0.00000000000005684341886080801486968994140625");
+  // Round to even (up), let make the last digits 75 instead of 25
+  EXPECT_EQ(format("%.43f", exact_value + std::pow(2, -43)),
+            "0.0000000000001705302565824240446090698242188");
+  // Exact, just to check.
+  EXPECT_EQ(format("%.44f", exact_value + std::pow(2, -43)),
+            "0.00000000000017053025658242404460906982421875");
+
+  // This value has to be small enough that it won't fit in the uint128
+  // representation for printing.
+  const double small_exact_value =
+      0.000000000000000000000000000000000000752316384526264005099991383822237233803945956334136013765601092018187046051025390625;  // NOLINT
+  assert(small_exact_value == std::pow(2, -120));
+  // Round up at a 5xx.
+  EXPECT_EQ(format("%.37f", small_exact_value),
+            "0.0000000000000000000000000000000000008");
+  // Round down at a <5
+  EXPECT_EQ(format("%.38f", small_exact_value),
+            "0.00000000000000000000000000000000000075");
+  // Round up at a >5
+  EXPECT_EQ(format("%.41f", small_exact_value),
+            "0.00000000000000000000000000000000000075232");
+  // Nine handling
+  EXPECT_EQ(format("%.55f", small_exact_value),
+            "0.0000000000000000000000000000000000007523163845262640051");
+  EXPECT_EQ(format("%.56f", small_exact_value),
+            "0.00000000000000000000000000000000000075231638452626400510");
+  EXPECT_EQ(format("%.57f", small_exact_value),
+            "0.000000000000000000000000000000000000752316384526264005100");
+  EXPECT_EQ(format("%.58f", small_exact_value),
+            "0.0000000000000000000000000000000000007523163845262640051000");
+  // Round down the last nine
+  EXPECT_EQ(format("%.59f", small_exact_value),
+            "0.00000000000000000000000000000000000075231638452626400509999");
+  // Round up the last nine
+  EXPECT_EQ(format("%.79f", small_exact_value),
+            "0.000000000000000000000000000000000000"
+            "7523163845262640050999913838222372338039460");
+
+  // Round to even (down)
+  EXPECT_EQ(format("%.119f", small_exact_value),
+            "0.000000000000000000000000000000000000"
+            "75231638452626400509999138382223723380"
+            "394595633413601376560109201818704605102539062");
+  // Exact
+  EXPECT_EQ(format("%.120f", small_exact_value),
+            "0.000000000000000000000000000000000000"
+            "75231638452626400509999138382223723380"
+            "3945956334136013765601092018187046051025390625");
+  // Round to even (up), let make the last digits 75 instead of 25
+  EXPECT_EQ(format("%.119f", small_exact_value + std::pow(2, -119)),
+            "0.000000000000000000000000000000000002"
+            "25694915357879201529997415146671170141"
+            "183786900240804129680327605456113815307617188");
+  // Exact, just to check.
+  EXPECT_EQ(format("%.120f", small_exact_value + std::pow(2, -119)),
+            "0.000000000000000000000000000000000002"
+            "25694915357879201529997415146671170141"
+            "1837869002408041296803276054561138153076171875");
+}
+
+TEST_F(FormatConvertTest, DoubleRoundA) {
+  const NativePrintfTraits &native_traits = VerifyNativeImplementation();
+  std::string s;
+  const auto format = [&](const char *fmt, double d) -> std::string & {
+    s.clear();
+    FormatArgImpl args[1] = {FormatArgImpl(d)};
+    AppendPack(&s, UntypedFormatSpecImpl(fmt), absl::MakeSpan(args));
+    if (native_traits.hex_float_has_glibc_rounding) {
+      EXPECT_EQ(StrPrint(fmt, d), s);
+    }
+    return s;
+  };
+
+  // 0x1.00018000p+100
+  const double on_boundary_odd = 1267679614447900152596896153600.0;
+  EXPECT_EQ(format("%.0a", on_boundary_odd), "0x1p+100");
+  EXPECT_EQ(format("%.1a", on_boundary_odd), "0x1.0p+100");
+  EXPECT_EQ(format("%.2a", on_boundary_odd), "0x1.00p+100");
+  EXPECT_EQ(format("%.3a", on_boundary_odd), "0x1.000p+100");
+  EXPECT_EQ(format("%.4a", on_boundary_odd), "0x1.0002p+100");  // round
+  EXPECT_EQ(format("%.5a", on_boundary_odd), "0x1.00018p+100");
+  EXPECT_EQ(format("%.6a", on_boundary_odd), "0x1.000180p+100");
+
+  // 0x1.00028000p-2
+  const double on_boundary_even = 0.250009536743164062500;
+  EXPECT_EQ(format("%.0a", on_boundary_even), "0x1p-2");
+  EXPECT_EQ(format("%.1a", on_boundary_even), "0x1.0p-2");
+  EXPECT_EQ(format("%.2a", on_boundary_even), "0x1.00p-2");
+  EXPECT_EQ(format("%.3a", on_boundary_even), "0x1.000p-2");
+  EXPECT_EQ(format("%.4a", on_boundary_even), "0x1.0002p-2");  // no round
+  EXPECT_EQ(format("%.5a", on_boundary_even), "0x1.00028p-2");
+  EXPECT_EQ(format("%.6a", on_boundary_even), "0x1.000280p-2");
+
+  // 0x1.00018001p+1
+  const double slightly_over = 2.00004577683284878730773925781250;
+  EXPECT_EQ(format("%.0a", slightly_over), "0x1p+1");
+  EXPECT_EQ(format("%.1a", slightly_over), "0x1.0p+1");
+  EXPECT_EQ(format("%.2a", slightly_over), "0x1.00p+1");
+  EXPECT_EQ(format("%.3a", slightly_over), "0x1.000p+1");
+  EXPECT_EQ(format("%.4a", slightly_over), "0x1.0002p+1");
+  EXPECT_EQ(format("%.5a", slightly_over), "0x1.00018p+1");
+  EXPECT_EQ(format("%.6a", slightly_over), "0x1.000180p+1");
+
+  // 0x1.00017fffp+0
+  const double slightly_under = 1.000022887950763106346130371093750;
+  EXPECT_EQ(format("%.0a", slightly_under), "0x1p+0");
+  EXPECT_EQ(format("%.1a", slightly_under), "0x1.0p+0");
+  EXPECT_EQ(format("%.2a", slightly_under), "0x1.00p+0");
+  EXPECT_EQ(format("%.3a", slightly_under), "0x1.000p+0");
+  EXPECT_EQ(format("%.4a", slightly_under), "0x1.0001p+0");
+  EXPECT_EQ(format("%.5a", slightly_under), "0x1.00018p+0");
+  EXPECT_EQ(format("%.6a", slightly_under), "0x1.000180p+0");
+  EXPECT_EQ(format("%.7a", slightly_under), "0x1.0001800p+0");
+
+  // 0x1.1b3829ac28058p+3
+  const double hex_value = 8.85060580848964661981881363317370414733886718750;
+  EXPECT_EQ(format("%.0a", hex_value), "0x1p+3");
+  EXPECT_EQ(format("%.1a", hex_value), "0x1.2p+3");
+  EXPECT_EQ(format("%.2a", hex_value), "0x1.1bp+3");
+  EXPECT_EQ(format("%.3a", hex_value), "0x1.1b4p+3");
+  EXPECT_EQ(format("%.4a", hex_value), "0x1.1b38p+3");
+  EXPECT_EQ(format("%.5a", hex_value), "0x1.1b383p+3");
+  EXPECT_EQ(format("%.6a", hex_value), "0x1.1b382ap+3");
+  EXPECT_EQ(format("%.7a", hex_value), "0x1.1b3829bp+3");
+  EXPECT_EQ(format("%.8a", hex_value), "0x1.1b3829acp+3");
+  EXPECT_EQ(format("%.9a", hex_value), "0x1.1b3829ac3p+3");
+  EXPECT_EQ(format("%.10a", hex_value), "0x1.1b3829ac28p+3");
+  EXPECT_EQ(format("%.11a", hex_value), "0x1.1b3829ac280p+3");
+  EXPECT_EQ(format("%.12a", hex_value), "0x1.1b3829ac2806p+3");
+  EXPECT_EQ(format("%.13a", hex_value), "0x1.1b3829ac28058p+3");
+  EXPECT_EQ(format("%.14a", hex_value), "0x1.1b3829ac280580p+3");
+  EXPECT_EQ(format("%.15a", hex_value), "0x1.1b3829ac2805800p+3");
+  EXPECT_EQ(format("%.16a", hex_value), "0x1.1b3829ac28058000p+3");
+  EXPECT_EQ(format("%.17a", hex_value), "0x1.1b3829ac280580000p+3");
+  EXPECT_EQ(format("%.18a", hex_value), "0x1.1b3829ac2805800000p+3");
+  EXPECT_EQ(format("%.19a", hex_value), "0x1.1b3829ac28058000000p+3");
+  EXPECT_EQ(format("%.20a", hex_value), "0x1.1b3829ac280580000000p+3");
+  EXPECT_EQ(format("%.21a", hex_value), "0x1.1b3829ac2805800000000p+3");
+
+  // 0x1.0818283848586p+3
+  const double hex_value2 = 8.2529488658208371987257123691961169242858886718750;
+  EXPECT_EQ(format("%.0a", hex_value2), "0x1p+3");
+  EXPECT_EQ(format("%.1a", hex_value2), "0x1.1p+3");
+  EXPECT_EQ(format("%.2a", hex_value2), "0x1.08p+3");
+  EXPECT_EQ(format("%.3a", hex_value2), "0x1.082p+3");
+  EXPECT_EQ(format("%.4a", hex_value2), "0x1.0818p+3");
+  EXPECT_EQ(format("%.5a", hex_value2), "0x1.08183p+3");
+  EXPECT_EQ(format("%.6a", hex_value2), "0x1.081828p+3");
+  EXPECT_EQ(format("%.7a", hex_value2), "0x1.0818284p+3");
+  EXPECT_EQ(format("%.8a", hex_value2), "0x1.08182838p+3");
+  EXPECT_EQ(format("%.9a", hex_value2), "0x1.081828385p+3");
+  EXPECT_EQ(format("%.10a", hex_value2), "0x1.0818283848p+3");
+  EXPECT_EQ(format("%.11a", hex_value2), "0x1.08182838486p+3");
+  EXPECT_EQ(format("%.12a", hex_value2), "0x1.081828384858p+3");
+  EXPECT_EQ(format("%.13a", hex_value2), "0x1.0818283848586p+3");
+  EXPECT_EQ(format("%.14a", hex_value2), "0x1.08182838485860p+3");
+  EXPECT_EQ(format("%.15a", hex_value2), "0x1.081828384858600p+3");
+  EXPECT_EQ(format("%.16a", hex_value2), "0x1.0818283848586000p+3");
+  EXPECT_EQ(format("%.17a", hex_value2), "0x1.08182838485860000p+3");
+  EXPECT_EQ(format("%.18a", hex_value2), "0x1.081828384858600000p+3");
+  EXPECT_EQ(format("%.19a", hex_value2), "0x1.0818283848586000000p+3");
+  EXPECT_EQ(format("%.20a", hex_value2), "0x1.08182838485860000000p+3");
+  EXPECT_EQ(format("%.21a", hex_value2), "0x1.081828384858600000000p+3");
+}
+
+TEST_F(FormatConvertTest, LongDoubleRoundA) {
+  if (std::numeric_limits<long double>::digits % 4 != 0) {
+    // This test doesn't really make sense to run on platforms where a long
+    // double has a different mantissa size (mod 4) than Prod, since then the
+    // leading digit will be formatted differently.
+    return;
+  }
+  const NativePrintfTraits &native_traits = VerifyNativeImplementation();
+  std::string s;
+  const auto format = [&](const char *fmt, long double d) -> std::string & {
+    s.clear();
+    FormatArgImpl args[1] = {FormatArgImpl(d)};
+    AppendPack(&s, UntypedFormatSpecImpl(fmt), absl::MakeSpan(args));
+    if (native_traits.hex_float_has_glibc_rounding &&
+        native_traits.hex_float_optimizes_leading_digit_bit_count) {
+      EXPECT_EQ(StrPrint(fmt, d), s);
+    }
+    return s;
+  };
+
+  // 0x8.8p+4
+  const long double on_boundary_even = 136.0;
+  EXPECT_EQ(format("%.0La", on_boundary_even), "0x8p+4");
+  EXPECT_EQ(format("%.1La", on_boundary_even), "0x8.8p+4");
+  EXPECT_EQ(format("%.2La", on_boundary_even), "0x8.80p+4");
+  EXPECT_EQ(format("%.3La", on_boundary_even), "0x8.800p+4");
+  EXPECT_EQ(format("%.4La", on_boundary_even), "0x8.8000p+4");
+  EXPECT_EQ(format("%.5La", on_boundary_even), "0x8.80000p+4");
+  EXPECT_EQ(format("%.6La", on_boundary_even), "0x8.800000p+4");
+
+  // 0x9.8p+4
+  const long double on_boundary_odd = 152.0;
+  EXPECT_EQ(format("%.0La", on_boundary_odd), "0xap+4");
+  EXPECT_EQ(format("%.1La", on_boundary_odd), "0x9.8p+4");
+  EXPECT_EQ(format("%.2La", on_boundary_odd), "0x9.80p+4");
+  EXPECT_EQ(format("%.3La", on_boundary_odd), "0x9.800p+4");
+  EXPECT_EQ(format("%.4La", on_boundary_odd), "0x9.8000p+4");
+  EXPECT_EQ(format("%.5La", on_boundary_odd), "0x9.80000p+4");
+  EXPECT_EQ(format("%.6La", on_boundary_odd), "0x9.800000p+4");
+
+  // 0x8.80001p+24
+  const long double slightly_over = 142606352.0;
+  EXPECT_EQ(format("%.0La", slightly_over), "0x9p+24");
+  EXPECT_EQ(format("%.1La", slightly_over), "0x8.8p+24");
+  EXPECT_EQ(format("%.2La", slightly_over), "0x8.80p+24");
+  EXPECT_EQ(format("%.3La", slightly_over), "0x8.800p+24");
+  EXPECT_EQ(format("%.4La", slightly_over), "0x8.8000p+24");
+  EXPECT_EQ(format("%.5La", slightly_over), "0x8.80001p+24");
+  EXPECT_EQ(format("%.6La", slightly_over), "0x8.800010p+24");
+
+  // 0x8.7ffffp+24
+  const long double slightly_under = 142606320.0;
+  EXPECT_EQ(format("%.0La", slightly_under), "0x8p+24");
+  EXPECT_EQ(format("%.1La", slightly_under), "0x8.8p+24");
+  EXPECT_EQ(format("%.2La", slightly_under), "0x8.80p+24");
+  EXPECT_EQ(format("%.3La", slightly_under), "0x8.800p+24");
+  EXPECT_EQ(format("%.4La", slightly_under), "0x8.8000p+24");
+  EXPECT_EQ(format("%.5La", slightly_under), "0x8.7ffffp+24");
+  EXPECT_EQ(format("%.6La", slightly_under), "0x8.7ffff0p+24");
+  EXPECT_EQ(format("%.7La", slightly_under), "0x8.7ffff00p+24");
+
+  // 0xc.0828384858688000p+128
+  const long double eights = 4094231060438608800781871108094404067328.0;
+  EXPECT_EQ(format("%.0La", eights), "0xcp+128");
+  EXPECT_EQ(format("%.1La", eights), "0xc.1p+128");
+  EXPECT_EQ(format("%.2La", eights), "0xc.08p+128");
+  EXPECT_EQ(format("%.3La", eights), "0xc.083p+128");
+  EXPECT_EQ(format("%.4La", eights), "0xc.0828p+128");
+  EXPECT_EQ(format("%.5La", eights), "0xc.08284p+128");
+  EXPECT_EQ(format("%.6La", eights), "0xc.082838p+128");
+  EXPECT_EQ(format("%.7La", eights), "0xc.0828385p+128");
+  EXPECT_EQ(format("%.8La", eights), "0xc.08283848p+128");
+  EXPECT_EQ(format("%.9La", eights), "0xc.082838486p+128");
+  EXPECT_EQ(format("%.10La", eights), "0xc.0828384858p+128");
+  EXPECT_EQ(format("%.11La", eights), "0xc.08283848587p+128");
+  EXPECT_EQ(format("%.12La", eights), "0xc.082838485868p+128");
+  EXPECT_EQ(format("%.13La", eights), "0xc.0828384858688p+128");
+  EXPECT_EQ(format("%.14La", eights), "0xc.08283848586880p+128");
+  EXPECT_EQ(format("%.15La", eights), "0xc.082838485868800p+128");
+  EXPECT_EQ(format("%.16La", eights), "0xc.0828384858688000p+128");
+}
+
+// We don't actually store the results. This is just to exercise the rest of the
+// machinery.
+struct NullSink {
+  friend void AbslFormatFlush(NullSink *sink, string_view str) {}
+};
+
+template <typename... T>
+bool FormatWithNullSink(absl::string_view fmt, const T &... a) {
+  NullSink sink;
+  FormatArgImpl args[] = {FormatArgImpl(a)...};
+  return FormatUntyped(&sink, UntypedFormatSpecImpl(fmt), absl::MakeSpan(args));
+}
+
+TEST_F(FormatConvertTest, ExtremeWidthPrecision) {
+  for (const char *fmt : {"f"}) {
+    for (double d : {1e-100, 1.0, 1e100}) {
+      constexpr int max = std::numeric_limits<int>::max();
+      EXPECT_TRUE(FormatWithNullSink(std::string("%.*") + fmt, max, d));
+      EXPECT_TRUE(FormatWithNullSink(std::string("%1.*") + fmt, max, d));
+      EXPECT_TRUE(FormatWithNullSink(std::string("%*") + fmt, max, d));
+      EXPECT_TRUE(FormatWithNullSink(std::string("%*.*") + fmt, max, max, d));
     }
   }
 }
 
 TEST_F(FormatConvertTest, LongDouble) {
-  const char *const kFormats[] = {"%",    "%.3", "%8.5", "%9",
+  const NativePrintfTraits &native_traits = VerifyNativeImplementation();
+  const char *const kFormats[] = {"%",    "%.3", "%8.5", "%9",  "%.5000",
                                   "%.60", "%+",  "% ",   "%-10"};
 
-  // This value is not representable in double, but it is in long double that
-  // uses the extended format.
-  // This is to verify that we are not truncating the value mistakenly through a
-  // double.
-  long double very_precise = 10000000000000000.25L;
-
   std::vector<long double> doubles = {
       0.0,
       -0.0,
-      very_precise,
-      1 / very_precise,
       std::numeric_limits<long double>::max(),
       -std::numeric_limits<long double>::max(),
       std::numeric_limits<long double>::min(),
@@ -556,28 +1078,73 @@
       std::numeric_limits<long double>::infinity(),
       -std::numeric_limits<long double>::infinity()};
 
+  for (long double base : {1.L, 12.L, 123.L, 1234.L, 12345.L, 123456.L,
+                           1234567.L, 12345678.L, 123456789.L, 1234567890.L,
+                           12345678901.L, 123456789012.L, 1234567890123.L,
+                           // This value is not representable in double, but it
+                           // is in long double that uses the extended format.
+                           // This is to verify that we are not truncating the
+                           // value mistakenly through a double.
+                           10000000000000000.25L}) {
+    for (int exp : {-1000, -500, 0, 500, 1000}) {
+      for (int sign : {1, -1}) {
+        doubles.push_back(sign * std::ldexp(base, exp));
+        doubles.push_back(sign / std::ldexp(base, exp));
+      }
+    }
+  }
+
+  // Regression tests
+  //
+  // Using a string literal because not all platforms support hex literals or it
+  // might be out of range.
+  doubles.push_back(std::strtold("-0xf.ffffffb5feafffbp-16324L", nullptr));
+
   for (const char *fmt : kFormats) {
     for (char f : {'f', 'F',  //
                    'g', 'G',  //
                    'a', 'A',  //
                    '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') {
+        // 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 (!native_traits.hex_float_has_glibc_rounding ||
+            !native_traits.hex_float_optimizes_leading_digit_bit_count) {
+          continue;
+        }
+      }
+
       for (auto d : doubles) {
         FormatArgImpl arg(d);
         UntypedFormatSpecImpl format(fmt_str);
+        std::string result = FormatPack(format, {&arg, 1});
+
+#ifdef _MSC_VER
+        // MSVC has a different rounding policy than us so we can't test our
+        // implementation against the native one there.
+        continue;
+#endif  // _MSC_VER
+
         // We use ASSERT_EQ here because failures are usually correlated and a
         // bug would print way too many failed expectations causing the test to
         // time out.
-        ASSERT_EQ(StrPrint(fmt_str.c_str(), d),
-                  FormatPack(format, {&arg, 1}))
+        ASSERT_EQ(StrPrint(fmt_str.c_str(), d), result)
             << fmt_str << " " << StrPrint("%.18Lg", d) << " "
-            << StrPrint("%.999Lf", d);
+            << StrPrint("%La", d) << " " << StrPrint("%.1080Lf", d);
       }
     }
   }
 }
 
-TEST_F(FormatConvertTest, IntAsFloat) {
+TEST_F(FormatConvertTest, IntAsDouble) {
+  const NativePrintfTraits &native_traits = VerifyNativeImplementation();
   const int kMin = std::numeric_limits<int>::min();
   const int kMax = std::numeric_limits<int>::max();
   const int ia[] = {
@@ -593,14 +1160,17 @@
       const char *fmt;
     };
     const double dx = static_cast<double>(fx);
-    const Expectation kExpect[] = {
-      { __LINE__, StrPrint("%f", dx), "%f" },
-      { __LINE__, StrPrint("%12f", dx), "%12f" },
-      { __LINE__, StrPrint("%.12f", dx), "%.12f" },
-      { __LINE__, StrPrint("%12a", dx), "%12a" },
-      { __LINE__, StrPrint("%.12a", dx), "%.12a" },
+    std::vector<Expectation> expect = {
+        {__LINE__, StrPrint("%f", dx), "%f"},
+        {__LINE__, StrPrint("%12f", dx), "%12f"},
+        {__LINE__, StrPrint("%.12f", dx), "%.12f"},
+        {__LINE__, StrPrint("%.12a", dx), "%.12a"},
     };
-    for (const Expectation &e : kExpect) {
+    if (native_traits.hex_float_uses_minimal_precision_when_not_specified) {
+      Expectation ex = {__LINE__, StrPrint("%12a", dx), "%12a"};
+      expect.push_back(ex);
+    }
+    for (const Expectation &e : expect) {
       SCOPED_TRACE(e.line);
       SCOPED_TRACE(e.fmt);
       UntypedFormatSpecImpl format(e.fmt);
@@ -645,6 +1215,25 @@
   EXPECT_TRUE(FormatFails("%*d", ""));
 }
 
+// Sanity check to make sure that we are testing what we think we're testing on
+// e.g. the x86_64+glibc platform.
+TEST_F(FormatConvertTest, GlibcHasCorrectTraits) {
+#if !defined(__GLIBC__) || !defined(__x86_64__)
+  return;
+#endif
+  const NativePrintfTraits &native_traits = VerifyNativeImplementation();
+  // If one of the following tests break then it is either because the above PP
+  // macro guards failed to exclude a new platform (likely) or because something
+  // has changed in the implemention of glibc sprintf float formatting behavior.
+  // If the latter, then the code that computes these flags needs to be
+  // revisited and/or possibly the StrFormat implementation.
+  EXPECT_TRUE(native_traits.hex_float_has_glibc_rounding);
+  EXPECT_TRUE(native_traits.hex_float_prefers_denormal_repr);
+  EXPECT_TRUE(
+      native_traits.hex_float_uses_minimal_precision_when_not_specified);
+  EXPECT_TRUE(native_traits.hex_float_optimizes_leading_digit_bit_count);
+}
+
 }  // namespace
 }  // namespace str_format_internal
 ABSL_NAMESPACE_END
diff --git a/absl/strings/internal/str_format/extension.cc b/absl/strings/internal/str_format/extension.cc
index 2e5bc2c..bb0d96c 100644
--- a/absl/strings/internal/str_format/extension.cc
+++ b/absl/strings/internal/str_format/extension.cc
@@ -33,16 +33,40 @@
   return s;
 }
 
-bool FormatSinkImpl::PutPaddedString(string_view v, int w, int p, bool l) {
+#define ABSL_INTERNAL_X_VAL(id) \
+  constexpr absl::FormatConversionChar FormatConversionCharInternal::id;
+ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
+#undef ABSL_INTERNAL_X_VAL
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr absl::FormatConversionChar FormatConversionCharInternal::kNone;
+
+#define ABSL_INTERNAL_CHAR_SET_CASE(c) \
+  constexpr FormatConversionCharSet FormatConversionCharSetInternal::c;
+ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
+#undef ABSL_INTERNAL_CHAR_SET_CASE
+
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kStar;
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kIntegral;
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kFloating;
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kNumeric;
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kPointer;
+
+bool FormatSinkImpl::PutPaddedString(string_view value, int width,
+                                     int precision, bool left) {
   size_t space_remaining = 0;
-  if (w >= 0) space_remaining = w;
-  size_t n = v.size();
-  if (p >= 0) n = std::min(n, static_cast<size_t>(p));
-  string_view shown(v.data(), n);
+  if (width >= 0) space_remaining = width;
+  size_t n = value.size();
+  if (precision >= 0) n = std::min(n, static_cast<size_t>(precision));
+  string_view shown(value.data(), n);
   space_remaining = Excess(shown.size(), space_remaining);
-  if (!l) Append(space_remaining, ' ');
+  if (!left) Append(space_remaining, ' ');
   Append(shown);
-  if (l) Append(space_remaining, ' ');
+  if (left) Append(space_remaining, ' ');
   return true;
 }
 
diff --git a/absl/strings/internal/str_format/extension.h b/absl/strings/internal/str_format/extension.h
index d166575..a9b9e13 100644
--- a/absl/strings/internal/str_format/extension.h
+++ b/absl/strings/internal/str_format/extension.h
@@ -24,11 +24,16 @@
 
 #include "absl/base/config.h"
 #include "absl/base/port.h"
+#include "absl/meta/type_traits.h"
 #include "absl/strings/internal/str_format/output.h"
 #include "absl/strings/string_view.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
+
+enum class FormatConversionChar : uint8_t;
+enum class FormatConversionCharSet : uint64_t;
+
 namespace str_format_internal {
 
 class FormatRawSinkImpl {
@@ -102,7 +107,7 @@
   size_t size() const { return size_; }
 
   // Put 'v' to 'sink' with specified width, precision, and left flag.
-  bool PutPaddedString(string_view v, int w, int p, bool l);
+  bool PutPaddedString(string_view v, int width, int precision, bool left);
 
   template <typename T>
   T Wrap() {
@@ -139,7 +144,7 @@
 // clang-format off
 #define ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \
   /* text */ \
-  X_VAL(c) X_SEP X_VAL(C) X_SEP X_VAL(s) X_SEP X_VAL(S) X_SEP \
+  X_VAL(c) X_SEP X_VAL(s) X_SEP \
   /* ints */ \
   X_VAL(d) X_SEP X_VAL(i) X_SEP X_VAL(o) X_SEP \
   X_VAL(u) X_SEP X_VAL(x) X_SEP X_VAL(X) X_SEP \
@@ -148,14 +153,39 @@
   X_VAL(g) X_SEP X_VAL(G) X_SEP X_VAL(a) X_SEP X_VAL(A) X_SEP \
   /* misc */ \
   X_VAL(n) X_SEP X_VAL(p)
+// clang-format on
 
-enum class FormatConversionChar : uint8_t {
-    c, C, s, S,              // text
+// This type should not be referenced, it exists only to provide labels
+// internally that match the values declared in FormatConversionChar in
+// str_format.h. This is meant to allow internal libraries to use the same
+// declared interface type as the public interface
+// (absl::StrFormatConversionChar) while keeping the definition in a public
+// header.
+// Internal libraries should use the form
+// `FormatConversionCharInternal::c`, `FormatConversionCharInternal::kNone` for
+// comparisons.  Use in switch statements is not recommended due to a bug in how
+// gcc 4.9 -Wswitch handles declared but undefined enums.
+struct FormatConversionCharInternal {
+  FormatConversionCharInternal() = delete;
+
+ private:
+  // clang-format off
+  enum class Enum : uint8_t {
+    c, s,                    // text
     d, i, o, u, x, X,        // int
     f, F, e, E, g, G, a, A,  // float
     n, p,                    // misc
-    kNone,
-    none = kNone
+    kNone
+  };
+  // clang-format on
+ public:
+#define ABSL_INTERNAL_X_VAL(id)              \
+  static constexpr FormatConversionChar id = \
+      static_cast<FormatConversionChar>(Enum::id);
+  ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
+#undef ABSL_INTERNAL_X_VAL
+  static constexpr FormatConversionChar kNone =
+      static_cast<FormatConversionChar>(Enum::kNone);
 };
 // clang-format on
 
@@ -163,95 +193,56 @@
   switch (c) {
 #define ABSL_INTERNAL_X_VAL(id) \
   case #id[0]:                  \
-    return FormatConversionChar::id;
+    return FormatConversionCharInternal::id;
     ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
 #undef ABSL_INTERNAL_X_VAL
   }
-  return FormatConversionChar::kNone;
-}
-
-inline int FormatConversionCharRadix(FormatConversionChar c) {
-  switch (c) {
-    case FormatConversionChar::x:
-    case FormatConversionChar::X:
-    case FormatConversionChar::a:
-    case FormatConversionChar::A:
-    case FormatConversionChar::p:
-      return 16;
-    case FormatConversionChar::o:
-      return 8;
-    default:
-      return 10;
-  }
+  return FormatConversionCharInternal::kNone;
 }
 
 inline bool FormatConversionCharIsUpper(FormatConversionChar c) {
-  switch (c) {
-    case FormatConversionChar::X:
-    case FormatConversionChar::F:
-    case FormatConversionChar::E:
-    case FormatConversionChar::G:
-    case FormatConversionChar::A:
-      return true;
-    default:
-      return false;
-  }
-}
-
-inline bool FormatConversionCharIsSigned(FormatConversionChar c) {
-  switch (c) {
-    case FormatConversionChar::d:
-    case FormatConversionChar::i:
-      return true;
-    default:
-      return false;
-  }
-}
-
-inline bool FormatConversionCharIsIntegral(FormatConversionChar c) {
-  switch (c) {
-    case FormatConversionChar::d:
-    case FormatConversionChar::i:
-    case FormatConversionChar::u:
-    case FormatConversionChar::o:
-    case FormatConversionChar::x:
-    case FormatConversionChar::X:
-      return true;
-    default:
-      return false;
+  if (c == FormatConversionCharInternal::X ||
+      c == FormatConversionCharInternal::F ||
+      c == FormatConversionCharInternal::E ||
+      c == FormatConversionCharInternal::G ||
+      c == FormatConversionCharInternal::A) {
+    return true;
+  } else {
+    return false;
   }
 }
 
 inline bool FormatConversionCharIsFloat(FormatConversionChar c) {
-  switch (c) {
-    case FormatConversionChar::a:
-    case FormatConversionChar::e:
-    case FormatConversionChar::f:
-    case FormatConversionChar::g:
-    case FormatConversionChar::A:
-    case FormatConversionChar::E:
-    case FormatConversionChar::F:
-    case FormatConversionChar::G:
-      return true;
-    default:
-      return false;
+  if (c == FormatConversionCharInternal::a ||
+      c == FormatConversionCharInternal::e ||
+      c == FormatConversionCharInternal::f ||
+      c == FormatConversionCharInternal::g ||
+      c == FormatConversionCharInternal::A ||
+      c == FormatConversionCharInternal::E ||
+      c == FormatConversionCharInternal::F ||
+      c == FormatConversionCharInternal::G) {
+    return true;
+  } else {
+    return false;
   }
 }
 
 inline char FormatConversionCharToChar(FormatConversionChar c) {
-  switch (c) {
-#define ABSL_INTERNAL_X_VAL(e)  \
-  case FormatConversionChar::e: \
+  if (c == FormatConversionCharInternal::kNone) {
+    return '\0';
+
+#define ABSL_INTERNAL_X_VAL(e)                       \
+  } else if (c == FormatConversionCharInternal::e) { \
     return #e[0];
 #define ABSL_INTERNAL_X_SEP
-    ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL,
-                                           ABSL_INTERNAL_X_SEP)
-    case FormatConversionChar::kNone:
-      return '\0';
+  ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL,
+                                         ABSL_INTERNAL_X_SEP)
+  } else {
+    return '\0';
+  }
+
 #undef ABSL_INTERNAL_X_VAL
 #undef ABSL_INTERNAL_X_SEP
-  }
-  return '\0';
 }
 
 // The associated char.
@@ -263,7 +254,7 @@
 
 struct FormatConversionSpecImplFriend;
 
-class FormatConversionSpec {
+class FormatConversionSpecImpl {
  public:
   // Width and precison are not specified, no flags are set.
   bool is_basic() const { return flags_.basic; }
@@ -276,7 +267,7 @@
   FormatConversionChar conversion_char() const {
     // Keep this field first in the struct . It generates better code when
     // accessing it when ConversionSpec is passed by value in registers.
-    static_assert(offsetof(FormatConversionSpec, conv_) == 0, "");
+    static_assert(offsetof(FormatConversionSpecImpl, conv_) == 0, "");
     return conv_;
   }
 
@@ -287,41 +278,65 @@
   // negative value.
   int precision() const { return precision_; }
 
-  // Deprecated (use has_x_flag() instead).
-  Flags flags() const { return flags_; }
-  // Deprecated
-  FormatConversionChar conv() const { return conversion_char(); }
+  template <typename T>
+  T Wrap() {
+    return T(*this);
+  }
 
  private:
   friend struct str_format_internal::FormatConversionSpecImplFriend;
-  FormatConversionChar conv_ = FormatConversionChar::kNone;
+  FormatConversionChar conv_ = FormatConversionCharInternal::kNone;
   Flags flags_;
   int width_;
   int precision_;
 };
 
 struct FormatConversionSpecImplFriend final {
-  static void SetFlags(Flags f, FormatConversionSpec* conv) {
+  static void SetFlags(Flags f, FormatConversionSpecImpl* conv) {
     conv->flags_ = f;
   }
   static void SetConversionChar(FormatConversionChar c,
-                                FormatConversionSpec* conv) {
+                                FormatConversionSpecImpl* conv) {
     conv->conv_ = c;
   }
-  static void SetWidth(int w, FormatConversionSpec* conv) { conv->width_ = w; }
-  static void SetPrecision(int p, FormatConversionSpec* conv) {
+  static void SetWidth(int w, FormatConversionSpecImpl* conv) {
+    conv->width_ = w;
+  }
+  static void SetPrecision(int p, FormatConversionSpecImpl* conv) {
     conv->precision_ = p;
   }
-  static std::string FlagsToString(const FormatConversionSpec& spec) {
+  static std::string FlagsToString(const FormatConversionSpecImpl& spec) {
     return spec.flags_.ToString();
   }
 };
 
-constexpr uint64_t FormatConversionCharToConvValue(char conv) {
+// Type safe OR operator.
+// We need this for two reasons:
+//  1. operator| on enums makes them decay to integers and the result is an
+//     integer. We need the result to stay as an enum.
+//  2. We use "enum class" which would not work even if we accepted the decay.
+constexpr FormatConversionCharSet FormatConversionCharSetUnion(
+    FormatConversionCharSet a) {
+  return a;
+}
+
+template <typename... CharSet>
+constexpr FormatConversionCharSet FormatConversionCharSetUnion(
+    FormatConversionCharSet a, CharSet... rest) {
+  return static_cast<FormatConversionCharSet>(
+      static_cast<uint64_t>(a) |
+      static_cast<uint64_t>(FormatConversionCharSetUnion(rest...)));
+}
+
+constexpr uint64_t FormatConversionCharToConvInt(FormatConversionChar c) {
+  return uint64_t{1} << (1 + static_cast<uint8_t>(c));
+}
+
+constexpr uint64_t FormatConversionCharToConvInt(char conv) {
   return
-#define ABSL_INTERNAL_CHAR_SET_CASE(c)                                       \
-  conv == #c[0]                                                              \
-      ? (uint64_t{1} << (1 + static_cast<uint8_t>(FormatConversionChar::c))) \
+#define ABSL_INTERNAL_CHAR_SET_CASE(c)                                 \
+  conv == #c[0]                                                        \
+      ? FormatConversionCharToConvInt(FormatConversionCharInternal::c) \
       :
       ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
 #undef ABSL_INTERNAL_CHAR_SET_CASE
@@ -330,28 +345,29 @@
           : 0;
 }
 
-enum class FormatConversionCharSet : uint64_t {
-#define ABSL_INTERNAL_CHAR_SET_CASE(c) \
-  c = FormatConversionCharToConvValue(#c[0]),
+constexpr FormatConversionCharSet FormatConversionCharToConvValue(char conv) {
+  return static_cast<FormatConversionCharSet>(
+      FormatConversionCharToConvInt(conv));
+}
+
+struct FormatConversionCharSetInternal {
+#define ABSL_INTERNAL_CHAR_SET_CASE(c)         \
+  static constexpr FormatConversionCharSet c = \
+      FormatConversionCharToConvValue(#c[0]);
   ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
 #undef ABSL_INTERNAL_CHAR_SET_CASE
 
   // Used for width/precision '*' specification.
-  kStar = FormatConversionCharToConvValue('*'),
-  // Some predefined values:
-  kIntegral = d | i | u | o | x | X,
-  kFloating = a | e | f | g | A | E | F | G,
-  kNumeric = kIntegral | kFloating,
-  kString = s,
-  kPointer = p,
+  static constexpr FormatConversionCharSet kStar =
+      FormatConversionCharToConvValue('*');
 
-  // The following are deprecated
-  star = kStar,
-  integral = kIntegral,
-  floating = kFloating,
-  numeric = kNumeric,
-  string = kString,
-  pointer = kPointer
+  static constexpr FormatConversionCharSet kIntegral =
+      FormatConversionCharSetUnion(d, i, u, o, x, X);
+  static constexpr FormatConversionCharSet kFloating =
+      FormatConversionCharSetUnion(a, e, f, g, A, E, F, G);
+  static constexpr FormatConversionCharSet kNumeric =
+      FormatConversionCharSetUnion(kIntegral, kFloating);
+  static constexpr FormatConversionCharSet kPointer = p;
 };
 
 // Type safe OR operator.
@@ -361,18 +377,29 @@
 //  2. We use "enum class" which would not work even if we accepted the decay.
 constexpr FormatConversionCharSet operator|(FormatConversionCharSet a,
                                             FormatConversionCharSet b) {
-  return FormatConversionCharSet(static_cast<uint64_t>(a) |
-                                 static_cast<uint64_t>(b));
+  return FormatConversionCharSetUnion(a, b);
+}
+
+// Overloaded conversion functions to support absl::ParsedFormat.
+// Get a conversion with a single character in it.
+constexpr FormatConversionCharSet ToFormatConversionCharSet(char c) {
+  return static_cast<FormatConversionCharSet>(
+      FormatConversionCharToConvValue(c));
 }
 
 // Get a conversion with a single character in it.
-constexpr FormatConversionCharSet ConversionCharToConv(char c) {
-  return FormatConversionCharSet(FormatConversionCharToConvValue(c));
+constexpr FormatConversionCharSet ToFormatConversionCharSet(
+    FormatConversionCharSet c) {
+  return c;
 }
 
+template <typename T>
+void ToFormatConversionCharSet(T) = delete;
+
 // Checks whether `c` exists in `set`.
 constexpr bool Contains(FormatConversionCharSet set, char c) {
-  return (static_cast<uint64_t>(set) & FormatConversionCharToConvValue(c)) != 0;
+  return (static_cast<uint64_t>(set) &
+          static_cast<uint64_t>(FormatConversionCharToConvValue(c))) != 0;
 }
 
 // Checks whether all the characters in `c` are contained in `set`
@@ -382,31 +409,16 @@
          static_cast<uint64_t>(c);
 }
 
-// Return type of the AbslFormatConvert() functions.
-// The FormatConversionCharSet template parameter is used to inform the
-// framework of what conversion characters are supported by that
-// AbslFormatConvert routine.
-template <FormatConversionCharSet C>
-struct FormatConvertResult {
-  static constexpr FormatConversionCharSet kConv = C;
-  bool value;
-};
-
-template <FormatConversionCharSet C>
-constexpr FormatConversionCharSet FormatConvertResult<C>::kConv;
+// Checks whether all the characters in `c` are contained in `set`
+constexpr bool Contains(FormatConversionCharSet set, FormatConversionChar c) {
+  return (static_cast<uint64_t>(set) & FormatConversionCharToConvInt(c)) != 0;
+}
 
 // Return capacity - used, clipped to a minimum of 0.
 inline size_t Excess(size_t used, size_t capacity) {
   return used < capacity ? capacity - used : 0;
 }
 
-// Type alias for use during migration.
-using ConversionChar = FormatConversionChar;
-using ConversionSpec = FormatConversionSpec;
-using Conv = FormatConversionCharSet;
-template <FormatConversionCharSet C>
-using ConvertResult = FormatConvertResult<C>;
-
 }  // namespace str_format_internal
 
 ABSL_NAMESPACE_END
diff --git a/absl/strings/internal/str_format/extension_test.cc b/absl/strings/internal/str_format/extension_test.cc
index 4e23fef..1c93fdb 100644
--- a/absl/strings/internal/str_format/extension_test.cc
+++ b/absl/strings/internal/str_format/extension_test.cc
@@ -19,9 +19,26 @@
 #include <random>
 #include <string>
 
-#include "absl/strings/str_format.h"
-
 #include "gtest/gtest.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/string_view.h"
+
+namespace my_namespace {
+class UserDefinedType {
+ public:
+  UserDefinedType() = default;
+
+  void Append(absl::string_view str) { value_.append(str.data(), str.size()); }
+  const std::string& Value() const { return value_; }
+
+  friend void AbslFormatFlush(UserDefinedType* x, absl::string_view str) {
+    x->Append(str);
+  }
+
+ private:
+  std::string value_;
+};
+}  // namespace my_namespace
 
 namespace {
 
@@ -63,4 +80,19 @@
     EXPECT_EQ(actual, expected);
   }
 }
+
+TEST(FormatExtensionTest, VerifyEnumEquality) {
+#define X_VAL(id)                           \
+  EXPECT_EQ(absl::FormatConversionChar::id, \
+            absl::str_format_internal::FormatConversionCharInternal::id);
+  ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, );
+#undef X_VAL
+
+#define X_VAL(id)                              \
+  EXPECT_EQ(absl::FormatConversionCharSet::id, \
+            absl::str_format_internal::FormatConversionCharSetInternal::id);
+  ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, );
+#undef X_VAL
+}
+
 }  // namespace
diff --git a/absl/strings/internal/str_format/float_conversion.cc b/absl/strings/internal/str_format/float_conversion.cc
index d4c647c..b1c4068 100644
--- a/absl/strings/internal/str_format/float_conversion.cc
+++ b/absl/strings/internal/str_format/float_conversion.cc
@@ -1,12 +1,38 @@
+// 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/strings/internal/str_format/float_conversion.h"
 
 #include <string.h>
+
 #include <algorithm>
 #include <cassert>
 #include <cmath>
+#include <limits>
 #include <string>
 
+#include "absl/base/attributes.h"
 #include "absl/base/config.h"
+#include "absl/base/optimization.h"
+#include "absl/functional/function_ref.h"
+#include "absl/meta/type_traits.h"
+#include "absl/numeric/bits.h"
+#include "absl/numeric/int128.h"
+#include "absl/numeric/internal/representation.h"
+#include "absl/strings/numbers.h"
+#include "absl/types/optional.h"
+#include "absl/types/span.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -14,13 +40,905 @@
 
 namespace {
 
-char *CopyStringTo(string_view v, char *out) {
+using ::absl::numeric_internal::IsDoubleDouble;
+
+// The code below wants to avoid heap allocations.
+// To do so it needs to allocate memory on the stack.
+// `StackArray` will allocate memory on the stack in the form of a uint32_t
+// array and call the provided callback with said memory.
+// It will allocate memory in increments of 512 bytes. We could allocate the
+// largest needed unconditionally, but that is more than we need in most of
+// cases. This way we use less stack in the common cases.
+class StackArray {
+  using Func = absl::FunctionRef<void(absl::Span<uint32_t>)>;
+  static constexpr size_t kStep = 512 / sizeof(uint32_t);
+  // 5 steps is 2560 bytes, which is enough to hold a long double with the
+  // largest/smallest exponents.
+  // The operations below will static_assert their particular maximum.
+  static constexpr size_t kNumSteps = 5;
+
+  // We do not want this function to be inlined.
+  // Otherwise the caller will allocate the stack space unnecessarily for all
+  // the variants even though it only calls one.
+  template <size_t steps>
+  ABSL_ATTRIBUTE_NOINLINE static void RunWithCapacityImpl(Func f) {
+    uint32_t values[steps * kStep]{};
+    f(absl::MakeSpan(values));
+  }
+
+ public:
+  static constexpr size_t kMaxCapacity = kStep * kNumSteps;
+
+  static void RunWithCapacity(size_t capacity, Func f) {
+    assert(capacity <= kMaxCapacity);
+    const size_t step = (capacity + kStep - 1) / kStep;
+    assert(step <= kNumSteps);
+    switch (step) {
+      case 1:
+        return RunWithCapacityImpl<1>(f);
+      case 2:
+        return RunWithCapacityImpl<2>(f);
+      case 3:
+        return RunWithCapacityImpl<3>(f);
+      case 4:
+        return RunWithCapacityImpl<4>(f);
+      case 5:
+        return RunWithCapacityImpl<5>(f);
+    }
+
+    assert(false && "Invalid capacity");
+  }
+};
+
+// Calculates `10 * (*v) + carry` and stores the result in `*v` and returns
+// the carry.
+template <typename Int>
+inline Int MultiplyBy10WithCarry(Int *v, Int carry) {
+  using BiggerInt = absl::conditional_t<sizeof(Int) == 4, uint64_t, uint128>;
+  BiggerInt tmp = 10 * static_cast<BiggerInt>(*v) + carry;
+  *v = static_cast<Int>(tmp);
+  return static_cast<Int>(tmp >> (sizeof(Int) * 8));
+}
+
+// Calculates `(2^64 * carry + *v) / 10`.
+// Stores the quotient in `*v` and returns the remainder.
+// Requires: `0 <= carry <= 9`
+inline uint64_t DivideBy10WithCarry(uint64_t *v, uint64_t carry) {
+  constexpr uint64_t divisor = 10;
+  // 2^64 / divisor = chunk_quotient + chunk_remainder / divisor
+  constexpr uint64_t chunk_quotient = (uint64_t{1} << 63) / (divisor / 2);
+  constexpr uint64_t chunk_remainder = uint64_t{} - chunk_quotient * divisor;
+
+  const uint64_t mod = *v % divisor;
+  const uint64_t next_carry = chunk_remainder * carry + mod;
+  *v = *v / divisor + carry * chunk_quotient + next_carry / divisor;
+  return next_carry % divisor;
+}
+
+using MaxFloatType =
+    typename std::conditional<IsDoubleDouble(), double, long double>::type;
+
+// Generates the decimal representation for an integer of the form `v * 2^exp`,
+// where `v` and `exp` are both positive integers.
+// It generates the digits from the left (ie the most significant digit first)
+// to allow for direct printing into the sink.
+//
+// Requires `0 <= exp` and `exp <= numeric_limits<MaxFloatType>::max_exponent`.
+class BinaryToDecimal {
+  static constexpr int ChunksNeeded(int exp) {
+    // We will left shift a uint128 by `exp` bits, so we need `128+exp` total
+    // bits. Round up to 32.
+    // See constructor for details about adding `10%` to the value.
+    return (128 + exp + 31) / 32 * 11 / 10;
+  }
+
+ public:
+  // Run the conversion for `v * 2^exp` and call `f(binary_to_decimal)`.
+  // This function will allocate enough stack space to perform the conversion.
+  static void RunConversion(uint128 v, int exp,
+                            absl::FunctionRef<void(BinaryToDecimal)> f) {
+    assert(exp > 0);
+    assert(exp <= std::numeric_limits<MaxFloatType>::max_exponent);
+    static_assert(
+        static_cast<int>(StackArray::kMaxCapacity) >=
+            ChunksNeeded(std::numeric_limits<MaxFloatType>::max_exponent),
+        "");
+
+    StackArray::RunWithCapacity(
+        ChunksNeeded(exp),
+        [=](absl::Span<uint32_t> input) { f(BinaryToDecimal(input, v, exp)); });
+  }
+
+  int TotalDigits() const {
+    return static_cast<int>((decimal_end_ - decimal_start_) * kDigitsPerChunk +
+                            CurrentDigits().size());
+  }
+
+  // See the current block of digits.
+  absl::string_view CurrentDigits() const {
+    return absl::string_view(digits_ + kDigitsPerChunk - size_, size_);
+  }
+
+  // Advance the current view of digits.
+  // Returns `false` when no more digits are available.
+  bool AdvanceDigits() {
+    if (decimal_start_ >= decimal_end_) return false;
+
+    uint32_t w = data_[decimal_start_++];
+    for (size_ = 0; size_ < kDigitsPerChunk; w /= 10) {
+      digits_[kDigitsPerChunk - ++size_] = w % 10 + '0';
+    }
+    return true;
+  }
+
+ private:
+  BinaryToDecimal(absl::Span<uint32_t> data, uint128 v, int exp) : data_(data) {
+    // We need to print the digits directly into the sink object without
+    // buffering them all first. To do this we need two things:
+    // - to know the total number of digits to do padding when necessary
+    // - to generate the decimal digits from the left.
+    //
+    // In order to do this, we do a two pass conversion.
+    // On the first pass we convert the binary representation of the value into
+    // a decimal representation in which each uint32_t chunk holds up to 9
+    // decimal digits.  In the second pass we take each decimal-holding-uint32_t
+    // value and generate the ascii decimal digits into `digits_`.
+    //
+    // The binary and decimal representations actually share the same memory
+    // region. As we go converting the chunks from binary to decimal we free
+    // them up and reuse them for the decimal representation. One caveat is that
+    // the decimal representation is around 7% less efficient in space than the
+    // binary one. We allocate an extra 10% memory to account for this. See
+    // ChunksNeeded for this calculation.
+    int chunk_index = exp / 32;
+    decimal_start_ = decimal_end_ = ChunksNeeded(exp);
+    const int offset = exp % 32;
+    // Left shift v by exp bits.
+    data_[chunk_index] = static_cast<uint32_t>(v << offset);
+    for (v >>= (32 - offset); v; v >>= 32)
+      data_[++chunk_index] = static_cast<uint32_t>(v);
+
+    while (chunk_index >= 0) {
+      // While we have more than one chunk available, go in steps of 1e9.
+      // `data_[chunk_index]` holds the highest non-zero binary chunk, so keep
+      // the variable updated.
+      uint32_t carry = 0;
+      for (int i = chunk_index; i >= 0; --i) {
+        uint64_t tmp = uint64_t{data_[i]} + (uint64_t{carry} << 32);
+        data_[i] = static_cast<uint32_t>(tmp / uint64_t{1000000000});
+        carry = static_cast<uint32_t>(tmp % uint64_t{1000000000});
+      }
+
+      // If the highest chunk is now empty, remove it from view.
+      if (data_[chunk_index] == 0) --chunk_index;
+
+      --decimal_start_;
+      assert(decimal_start_ != chunk_index);
+      data_[decimal_start_] = carry;
+    }
+
+    // Fill the first set of digits. The first chunk might not be complete, so
+    // handle differently.
+    for (uint32_t first = data_[decimal_start_++]; first != 0; first /= 10) {
+      digits_[kDigitsPerChunk - ++size_] = first % 10 + '0';
+    }
+  }
+
+ private:
+  static constexpr int kDigitsPerChunk = 9;
+
+  int decimal_start_;
+  int decimal_end_;
+
+  char digits_[kDigitsPerChunk];
+  int size_ = 0;
+
+  absl::Span<uint32_t> data_;
+};
+
+// Converts a value of the form `x * 2^-exp` into a sequence of decimal digits.
+// Requires `-exp < 0` and
+// `-exp >= limits<MaxFloatType>::min_exponent - limits<MaxFloatType>::digits`.
+class FractionalDigitGenerator {
+ public:
+  // Run the conversion for `v * 2^exp` and call `f(generator)`.
+  // This function will allocate enough stack space to perform the conversion.
+  static void RunConversion(
+      uint128 v, int exp, absl::FunctionRef<void(FractionalDigitGenerator)> f) {
+    using Limits = std::numeric_limits<MaxFloatType>;
+    assert(-exp < 0);
+    assert(-exp >= Limits::min_exponent - 128);
+    static_assert(StackArray::kMaxCapacity >=
+                      (Limits::digits + 128 - Limits::min_exponent + 31) / 32,
+                  "");
+    StackArray::RunWithCapacity((Limits::digits + exp + 31) / 32,
+                                [=](absl::Span<uint32_t> input) {
+                                  f(FractionalDigitGenerator(input, v, exp));
+                                });
+  }
+
+  // Returns true if there are any more non-zero digits left.
+  bool HasMoreDigits() const { return next_digit_ != 0 || chunk_index_ >= 0; }
+
+  // Returns true if the remainder digits are greater than 5000...
+  bool IsGreaterThanHalf() const {
+    return next_digit_ > 5 || (next_digit_ == 5 && chunk_index_ >= 0);
+  }
+  // Returns true if the remainder digits are exactly 5000...
+  bool IsExactlyHalf() const { return next_digit_ == 5 && chunk_index_ < 0; }
+
+  struct Digits {
+    int digit_before_nine;
+    int num_nines;
+  };
+
+  // Get the next set of digits.
+  // They are composed by a non-9 digit followed by a runs of zero or more 9s.
+  Digits GetDigits() {
+    Digits digits{next_digit_, 0};
+
+    next_digit_ = GetOneDigit();
+    while (next_digit_ == 9) {
+      ++digits.num_nines;
+      next_digit_ = GetOneDigit();
+    }
+
+    return digits;
+  }
+
+ private:
+  // Return the next digit.
+  int GetOneDigit() {
+    if (chunk_index_ < 0) return 0;
+
+    uint32_t carry = 0;
+    for (int i = chunk_index_; i >= 0; --i) {
+      carry = MultiplyBy10WithCarry(&data_[i], carry);
+    }
+    // If the lowest chunk is now empty, remove it from view.
+    if (data_[chunk_index_] == 0) --chunk_index_;
+    return carry;
+  }
+
+  FractionalDigitGenerator(absl::Span<uint32_t> data, uint128 v, int exp)
+      : chunk_index_(exp / 32), data_(data) {
+    const int offset = exp % 32;
+    // Right shift `v` by `exp` bits.
+    data_[chunk_index_] = static_cast<uint32_t>(v << (32 - offset));
+    v >>= offset;
+    // Make sure we don't overflow the data. We already calculated that
+    // non-zero bits fit, so we might not have space for leading zero bits.
+    for (int pos = chunk_index_; v; v >>= 32)
+      data_[--pos] = static_cast<uint32_t>(v);
+
+    // Fill next_digit_, as GetDigits expects it to be populated always.
+    next_digit_ = GetOneDigit();
+  }
+
+  int next_digit_;
+  int chunk_index_;
+  absl::Span<uint32_t> data_;
+};
+
+// Count the number of leading zero bits.
+int LeadingZeros(uint64_t v) { return countl_zero(v); }
+int LeadingZeros(uint128 v) {
+  auto high = static_cast<uint64_t>(v >> 64);
+  auto low = static_cast<uint64_t>(v);
+  return high != 0 ? countl_zero(high) : 64 + countl_zero(low);
+}
+
+// Round up the text digits starting at `p`.
+// The buffer must have an extra digit that is known to not need rounding.
+// This is done below by having an extra '0' digit on the left.
+void RoundUp(char *p) {
+  while (*p == '9' || *p == '.') {
+    if (*p == '9') *p = '0';
+    --p;
+  }
+  ++*p;
+}
+
+// Check the previous digit and round up or down to follow the round-to-even
+// policy.
+void RoundToEven(char *p) {
+  if (*p == '.') --p;
+  if (*p % 2 == 1) RoundUp(p);
+}
+
+// Simple integral decimal digit printing for values that fit in 64-bits.
+// Returns the pointer to the last written digit.
+char *PrintIntegralDigitsFromRightFast(uint64_t v, char *p) {
+  do {
+    *--p = DivideBy10WithCarry(&v, 0) + '0';
+  } while (v != 0);
+  return p;
+}
+
+// Simple integral decimal digit printing for values that fit in 128-bits.
+// Returns the pointer to the last written digit.
+char *PrintIntegralDigitsFromRightFast(uint128 v, char *p) {
+  auto high = static_cast<uint64_t>(v >> 64);
+  auto low = static_cast<uint64_t>(v);
+
+  while (high != 0) {
+    uint64_t carry = DivideBy10WithCarry(&high, 0);
+    carry = DivideBy10WithCarry(&low, carry);
+    *--p = carry + '0';
+  }
+  return PrintIntegralDigitsFromRightFast(low, p);
+}
+
+// Simple fractional decimal digit printing for values that fir in 64-bits after
+// shifting.
+// Performs rounding if necessary to fit within `precision`.
+// Returns the pointer to one after the last character written.
+char *PrintFractionalDigitsFast(uint64_t v, char *start, int exp,
+                                int precision) {
+  char *p = start;
+  v <<= (64 - exp);
+  while (precision > 0) {
+    if (!v) return p;
+    *p++ = MultiplyBy10WithCarry(&v, uint64_t{0}) + '0';
+    --precision;
+  }
+
+  // We need to round.
+  if (v < 0x8000000000000000) {
+    // We round down, so nothing to do.
+  } else if (v > 0x8000000000000000) {
+    // We round up.
+    RoundUp(p - 1);
+  } else {
+    RoundToEven(p - 1);
+  }
+
+  assert(precision == 0);
+  // Precision can only be zero here.
+  return p;
+}
+
+// Simple fractional decimal digit printing for values that fir in 128-bits
+// after shifting.
+// Performs rounding if necessary to fit within `precision`.
+// Returns the pointer to one after the last character written.
+char *PrintFractionalDigitsFast(uint128 v, char *start, int exp,
+                                int precision) {
+  char *p = start;
+  v <<= (128 - exp);
+  auto high = static_cast<uint64_t>(v >> 64);
+  auto low = static_cast<uint64_t>(v);
+
+  // While we have digits to print and `low` is not empty, do the long
+  // multiplication.
+  while (precision > 0 && low != 0) {
+    uint64_t carry = MultiplyBy10WithCarry(&low, uint64_t{0});
+    carry = MultiplyBy10WithCarry(&high, carry);
+
+    *p++ = carry + '0';
+    --precision;
+  }
+
+  // Now `low` is empty, so use a faster approach for the rest of the digits.
+  // This block is pretty much the same as the main loop for the 64-bit case
+  // above.
+  while (precision > 0) {
+    if (!high) return p;
+    *p++ = MultiplyBy10WithCarry(&high, uint64_t{0}) + '0';
+    --precision;
+  }
+
+  // We need to round.
+  if (high < 0x8000000000000000) {
+    // We round down, so nothing to do.
+  } else if (high > 0x8000000000000000 || low != 0) {
+    // We round up.
+    RoundUp(p - 1);
+  } else {
+    RoundToEven(p - 1);
+  }
+
+  assert(precision == 0);
+  // Precision can only be zero here.
+  return p;
+}
+
+struct FormatState {
+  char sign_char;
+  int precision;
+  const FormatConversionSpecImpl &conv;
+  FormatSinkImpl *sink;
+
+  // In `alt` mode (flag #) we keep the `.` even if there are no fractional
+  // digits. In non-alt mode, we strip it.
+  bool ShouldPrintDot() const { return precision != 0 || conv.has_alt_flag(); }
+};
+
+struct Padding {
+  int left_spaces;
+  int zeros;
+  int right_spaces;
+};
+
+Padding ExtraWidthToPadding(size_t total_size, const FormatState &state) {
+  if (state.conv.width() < 0 ||
+      static_cast<size_t>(state.conv.width()) <= total_size) {
+    return {0, 0, 0};
+  }
+  int missing_chars = state.conv.width() - total_size;
+  if (state.conv.has_left_flag()) {
+    return {0, 0, missing_chars};
+  } else if (state.conv.has_zero_flag()) {
+    return {0, missing_chars, 0};
+  } else {
+    return {missing_chars, 0, 0};
+  }
+}
+
+void FinalPrint(const FormatState &state, absl::string_view data,
+                int padding_offset, int trailing_zeros,
+                absl::string_view data_postfix) {
+  if (state.conv.width() < 0) {
+    // No width specified. Fast-path.
+    if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+    state.sink->Append(data);
+    state.sink->Append(trailing_zeros, '0');
+    state.sink->Append(data_postfix);
+    return;
+  }
+
+  auto padding = ExtraWidthToPadding((state.sign_char != '\0' ? 1 : 0) +
+                                         data.size() + data_postfix.size() +
+                                         static_cast<size_t>(trailing_zeros),
+                                     state);
+
+  state.sink->Append(padding.left_spaces, ' ');
+  if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+  // Padding in general needs to be inserted somewhere in the middle of `data`.
+  state.sink->Append(data.substr(0, padding_offset));
+  state.sink->Append(padding.zeros, '0');
+  state.sink->Append(data.substr(padding_offset));
+  state.sink->Append(trailing_zeros, '0');
+  state.sink->Append(data_postfix);
+  state.sink->Append(padding.right_spaces, ' ');
+}
+
+// Fastpath %f formatter for when the shifted value fits in a simple integral
+// type.
+// Prints `v*2^exp` with the options from `state`.
+template <typename Int>
+void FormatFFast(Int v, int exp, const FormatState &state) {
+  constexpr int input_bits = sizeof(Int) * 8;
+
+  static constexpr size_t integral_size =
+      /* in case we need to round up an extra digit */ 1 +
+      /* decimal digits for uint128 */ 40 + 1;
+  char buffer[integral_size + /* . */ 1 + /* max digits uint128 */ 128];
+  buffer[integral_size] = '.';
+  char *const integral_digits_end = buffer + integral_size;
+  char *integral_digits_start;
+  char *const fractional_digits_start = buffer + integral_size + 1;
+  char *fractional_digits_end = fractional_digits_start;
+
+  if (exp >= 0) {
+    const int total_bits = input_bits - LeadingZeros(v) + exp;
+    integral_digits_start =
+        total_bits <= 64
+            ? PrintIntegralDigitsFromRightFast(static_cast<uint64_t>(v) << exp,
+                                               integral_digits_end)
+            : PrintIntegralDigitsFromRightFast(static_cast<uint128>(v) << exp,
+                                               integral_digits_end);
+  } else {
+    exp = -exp;
+
+    integral_digits_start = PrintIntegralDigitsFromRightFast(
+        exp < input_bits ? v >> exp : 0, integral_digits_end);
+    // PrintFractionalDigits may pull a carried 1 all the way up through the
+    // integral portion.
+    integral_digits_start[-1] = '0';
+
+    fractional_digits_end =
+        exp <= 64 ? PrintFractionalDigitsFast(v, fractional_digits_start, exp,
+                                              state.precision)
+                  : PrintFractionalDigitsFast(static_cast<uint128>(v),
+                                              fractional_digits_start, exp,
+                                              state.precision);
+    // There was a carry, so include the first digit too.
+    if (integral_digits_start[-1] != '0') --integral_digits_start;
+  }
+
+  size_t size = fractional_digits_end - integral_digits_start;
+
+  // In `alt` mode (flag #) we keep the `.` even if there are no fractional
+  // digits. In non-alt mode, we strip it.
+  if (!state.ShouldPrintDot()) --size;
+  FinalPrint(state, absl::string_view(integral_digits_start, size),
+             /*padding_offset=*/0,
+             static_cast<int>(state.precision - (fractional_digits_end -
+                                                 fractional_digits_start)),
+             /*data_postfix=*/"");
+}
+
+// Slow %f formatter for when the shifted value does not fit in a uint128, and
+// `exp > 0`.
+// Prints `v*2^exp` with the options from `state`.
+// This one is guaranteed to not have fractional digits, so we don't have to
+// worry about anything after the `.`.
+void FormatFPositiveExpSlow(uint128 v, int exp, const FormatState &state) {
+  BinaryToDecimal::RunConversion(v, exp, [&](BinaryToDecimal btd) {
+    const size_t total_digits =
+        btd.TotalDigits() +
+        (state.ShouldPrintDot() ? static_cast<size_t>(state.precision) + 1 : 0);
+
+    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(padding.zeros, '0');
+
+    do {
+      state.sink->Append(btd.CurrentDigits());
+    } while (btd.AdvanceDigits());
+
+    if (state.ShouldPrintDot()) state.sink->Append(1, '.');
+    state.sink->Append(state.precision, '0');
+    state.sink->Append(padding.right_spaces, ' ');
+  });
+}
+
+// Slow %f formatter for when the shifted value does not fit in a uint128, and
+// `exp < 0`.
+// Prints `v*2^exp` with the options from `state`.
+// This one is guaranteed to be < 1.0, so we don't have to worry about integral
+// digits.
+void FormatFNegativeExpSlow(uint128 v, int exp, const FormatState &state) {
+  const size_t total_digits =
+      /* 0 */ 1 +
+      (state.ShouldPrintDot() ? static_cast<size_t>(state.precision) + 1 : 0);
+  auto padding =
+      ExtraWidthToPadding(total_digits + (state.sign_char ? 1 : 0), state);
+  padding.zeros += 1;
+  state.sink->Append(padding.left_spaces, ' ');
+  if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+  state.sink->Append(padding.zeros, '0');
+
+  if (state.ShouldPrintDot()) state.sink->Append(1, '.');
+
+  // Print digits
+  int digits_to_go = state.precision;
+
+  FractionalDigitGenerator::RunConversion(
+      v, exp, [&](FractionalDigitGenerator digit_gen) {
+        // There are no digits to print here.
+        if (state.precision == 0) return;
+
+        // We go one digit at a time, while keeping track of runs of nines.
+        // The runs of nines are used to perform rounding when necessary.
+
+        while (digits_to_go > 0 && digit_gen.HasMoreDigits()) {
+          auto digits = digit_gen.GetDigits();
+
+          // Now we have a digit and a run of nines.
+          // See if we can print them all.
+          if (digits.num_nines + 1 < digits_to_go) {
+            // We don't have to round yet, so print them.
+            state.sink->Append(1, digits.digit_before_nine + '0');
+            state.sink->Append(digits.num_nines, '9');
+            digits_to_go -= digits.num_nines + 1;
+
+          } else {
+            // We can't print all the nines, see where we have to truncate.
+
+            bool round_up = false;
+            if (digits.num_nines + 1 > digits_to_go) {
+              // We round up at a nine. No need to print them.
+              round_up = true;
+            } else {
+              // We can fit all the nines, but truncate just after it.
+              if (digit_gen.IsGreaterThanHalf()) {
+                round_up = true;
+              } else if (digit_gen.IsExactlyHalf()) {
+                // Round to even
+                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;
+              // The rest will be zeros.
+            } else {
+              state.sink->Append(1, digits.digit_before_nine + '0');
+              state.sink->Append(digits_to_go - 1, '9');
+              digits_to_go = 0;
+            }
+            return;
+          }
+        }
+      });
+
+  state.sink->Append(digits_to_go, '0');
+  state.sink->Append(padding.right_spaces, ' ');
+}
+
+template <typename Int>
+void FormatF(Int mantissa, int exp, const FormatState &state) {
+  if (exp >= 0) {
+    const int total_bits = sizeof(Int) * 8 - LeadingZeros(mantissa) + exp;
+
+    // Fallback to the slow stack-based approach if we can't do it in a 64 or
+    // 128 bit state.
+    if (ABSL_PREDICT_FALSE(total_bits > 128)) {
+      return FormatFPositiveExpSlow(mantissa, exp, state);
+    }
+  } else {
+    // Fallback to the slow stack-based approach if we can't do it in a 64 or
+    // 128 bit state.
+    if (ABSL_PREDICT_FALSE(exp < -128)) {
+      return FormatFNegativeExpSlow(mantissa, -exp, state);
+    }
+  }
+  return FormatFFast(mantissa, exp, state);
+}
+
+// Grab the group of four bits (nibble) from `n`. E.g., nibble 1 corresponds to
+// bits 4-7.
+template <typename Int>
+uint8_t GetNibble(Int n, int nibble_index) {
+  constexpr Int mask_low_nibble = Int{0xf};
+  int shift = nibble_index * 4;
+  n &= mask_low_nibble << shift;
+  return static_cast<uint8_t>((n >> shift) & 0xf);
+}
+
+// Add one to the given nibble, applying carry to higher nibbles. Returns true
+// if overflow, false otherwise.
+template <typename Int>
+bool IncrementNibble(int nibble_index, Int *n) {
+  constexpr int kShift = sizeof(Int) * 8 - 1;
+  constexpr int kNumNibbles = sizeof(Int) * 8 / 4;
+  Int before = *n >> kShift;
+  // Here we essentially want to take the number 1 and move it into the requsted
+  // nibble, then add it to *n to effectively increment the nibble. However,
+  // ASan will complain if we try to shift the 1 beyond the limits of the Int,
+  // i.e., if the nibble_index is out of range. So therefore we check for this
+  // and if we are out of range we just add 0 which leaves *n unchanged, which
+  // seems like the reasonable thing to do in that case.
+  *n += ((nibble_index >= kNumNibbles) ? 0 : (Int{1} << (nibble_index * 4)));
+  Int after = *n >> kShift;
+  return (before && !after) || (nibble_index >= kNumNibbles);
+}
+
+// Return a mask with 1's in the given nibble and all lower nibbles.
+template <typename Int>
+Int MaskUpToNibbleInclusive(int nibble_index) {
+  constexpr int kNumNibbles = sizeof(Int) * 8 / 4;
+  static const Int ones = ~Int{0};
+  return ones >> std::max(0, 4 * (kNumNibbles - nibble_index - 1));
+}
+
+// Return a mask with 1's below the given nibble.
+template <typename Int>
+Int MaskUpToNibbleExclusive(int nibble_index) {
+  return nibble_index <= 0 ? 0 : MaskUpToNibbleInclusive<Int>(nibble_index - 1);
+}
+
+template <typename Int>
+Int MoveToNibble(uint8_t nibble, int nibble_index) {
+  return Int{nibble} << (4 * nibble_index);
+}
+
+// Given mantissa size, find optimal # of mantissa bits to put in initial digit.
+//
+// In the hex representation we keep a single hex digit to the left of the dot.
+// However, the question as to how many bits of the mantissa should be put into
+// that hex digit in theory is arbitrary, but in practice it is optimal to
+// choose based on the size of the mantissa. E.g., for a `double`, there are 53
+// mantissa bits, so that means that we should put 1 bit to the left of the dot,
+// thereby leaving 52 bits to the right, which is evenly divisible by four and
+// thus all fractional digits represent actual precision. For a `long double`,
+// on the other hand, there are 64 bits of mantissa, thus we can use all four
+// bits for the initial hex digit and still have a number left over (60) that is
+// a multiple of four. Once again, the goal is to have all fractional digits
+// represent real precision.
+template <typename Float>
+constexpr int HexFloatLeadingDigitSizeInBits() {
+  return std::numeric_limits<Float>::digits % 4 > 0
+             ? std::numeric_limits<Float>::digits % 4
+             : 4;
+}
+
+// This function captures the rounding behavior of glibc for hex float
+// representations. E.g. when rounding 0x1.ab800000 to a precision of .2
+// ("%.2a") glibc will round up because it rounds toward the even number (since
+// 0xb is an odd number, it will round up to 0xc). However, when rounding at a
+// point that is not followed by 800000..., it disregards the parity and rounds
+// up if > 8 and rounds down if < 8.
+template <typename Int>
+bool HexFloatNeedsRoundUp(Int mantissa, int final_nibble_displayed,
+                          uint8_t leading) {
+  // If the last nibble (hex digit) to be displayed is the lowest on in the
+  // mantissa then that means that we don't have any further nibbles to inform
+  // rounding, so don't round.
+  if (final_nibble_displayed <= 0) {
+    return false;
+  }
+  int rounding_nibble_idx = final_nibble_displayed - 1;
+  constexpr int kTotalNibbles = sizeof(Int) * 8 / 4;
+  assert(final_nibble_displayed <= kTotalNibbles);
+  Int mantissa_up_to_rounding_nibble_inclusive =
+      mantissa & MaskUpToNibbleInclusive<Int>(rounding_nibble_idx);
+  Int eight = MoveToNibble<Int>(8, rounding_nibble_idx);
+  if (mantissa_up_to_rounding_nibble_inclusive != eight) {
+    return mantissa_up_to_rounding_nibble_inclusive > eight;
+  }
+  // Nibble in question == 8.
+  uint8_t round_if_odd = (final_nibble_displayed == kTotalNibbles)
+                             ? leading
+                             : GetNibble(mantissa, final_nibble_displayed);
+  return round_if_odd % 2 == 1;
+}
+
+// Stores values associated with a Float type needed by the FormatA
+// implementation in order to avoid templatizing that function by the Float
+// type.
+struct HexFloatTypeParams {
+  template <typename Float>
+  explicit HexFloatTypeParams(Float)
+      : min_exponent(std::numeric_limits<Float>::min_exponent - 1),
+        leading_digit_size_bits(HexFloatLeadingDigitSizeInBits<Float>()) {
+    assert(leading_digit_size_bits >= 1 && leading_digit_size_bits <= 4);
+  }
+
+  int min_exponent;
+  int leading_digit_size_bits;
+};
+
+// Hex Float Rounding. First check if we need to round; if so, then we do that
+// by manipulating (incrementing) the mantissa, that way we can later print the
+// mantissa digits by iterating through them in the same way regardless of
+// whether a rounding happened.
+template <typename Int>
+void FormatARound(bool precision_specified, const FormatState &state,
+                  uint8_t *leading, Int *mantissa, int *exp) {
+  constexpr int kTotalNibbles = sizeof(Int) * 8 / 4;
+  // Index of the last nibble that we could display given precision.
+  int final_nibble_displayed =
+      precision_specified ? std::max(0, (kTotalNibbles - state.precision)) : 0;
+  if (HexFloatNeedsRoundUp(*mantissa, final_nibble_displayed, *leading)) {
+    // Need to round up.
+    bool overflow = IncrementNibble(final_nibble_displayed, mantissa);
+    *leading += (overflow ? 1 : 0);
+    if (ABSL_PREDICT_FALSE(*leading > 15)) {
+      // We have overflowed the leading digit. This would mean that we would
+      // need two hex digits to the left of the dot, which is not allowed. So
+      // adjust the mantissa and exponent so that the result is always 1.0eXXX.
+      *leading = 1;
+      *mantissa = 0;
+      *exp += 4;
+    }
+  }
+  // Now that we have handled a possible round-up we can go ahead and zero out
+  // all the nibbles of the mantissa that we won't need.
+  if (precision_specified) {
+    *mantissa &= ~MaskUpToNibbleExclusive<Int>(final_nibble_displayed);
+  }
+}
+
+template <typename Int>
+void FormatANormalize(const HexFloatTypeParams float_traits, uint8_t *leading,
+                      Int *mantissa, int *exp) {
+  constexpr int kIntBits = sizeof(Int) * 8;
+  static const Int kHighIntBit = Int{1} << (kIntBits - 1);
+  const int kLeadDigitBitsCount = float_traits.leading_digit_size_bits;
+  // Normalize mantissa so that highest bit set is in MSB position, unless we
+  // get interrupted by the exponent threshold.
+  while (*mantissa && !(*mantissa & kHighIntBit)) {
+    if (ABSL_PREDICT_FALSE(*exp - 1 < float_traits.min_exponent)) {
+      *mantissa >>= (float_traits.min_exponent - *exp);
+      *exp = float_traits.min_exponent;
+      return;
+    }
+    *mantissa <<= 1;
+    --*exp;
+  }
+  // Extract bits for leading digit then shift them away leaving the
+  // fractional part.
+  *leading =
+      static_cast<uint8_t>(*mantissa >> (kIntBits - kLeadDigitBitsCount));
+  *exp -= (*mantissa != 0) ? kLeadDigitBitsCount : *exp;
+  *mantissa <<= kLeadDigitBitsCount;
+}
+
+template <typename Int>
+void FormatA(const HexFloatTypeParams float_traits, Int mantissa, int exp,
+             bool uppercase, const FormatState &state) {
+  // Int properties.
+  constexpr int kIntBits = sizeof(Int) * 8;
+  constexpr int kTotalNibbles = sizeof(Int) * 8 / 4;
+  // Did the user specify a precision explicitly?
+  const bool precision_specified = state.conv.precision() >= 0;
+
+  // ========== Normalize/Denormalize ==========
+  exp += kIntBits;  // make all digits fractional digits.
+  // This holds the (up to four) bits of leading digit, i.e., the '1' in the
+  // number 0x1.e6fp+2. It's always > 0 unless number is zero or denormal.
+  uint8_t leading = 0;
+  FormatANormalize(float_traits, &leading, &mantissa, &exp);
+
+  // =============== Rounding ==================
+  // Check if we need to round; if so, then we do that by manipulating
+  // (incrementing) the mantissa before beginning to print characters.
+  FormatARound(precision_specified, state, &leading, &mantissa, &exp);
+
+  // ============= Format Result ===============
+  // This buffer holds the "0x1.ab1de3" portion of "0x1.ab1de3pe+2". Compute the
+  // size with long double which is the largest of the floats.
+  constexpr size_t kBufSizeForHexFloatRepr =
+      2                                                // 0x
+      + std::numeric_limits<MaxFloatType>::digits / 4  // number of hex digits
+      + 1                                              // round up
+      + 1;                                             // "." (dot)
+  char digits_buffer[kBufSizeForHexFloatRepr];
+  char *digits_iter = digits_buffer;
+  const char *const digits =
+      static_cast<const char *>("0123456789ABCDEF0123456789abcdef") +
+      (uppercase ? 0 : 16);
+
+  // =============== Hex Prefix ================
+  *digits_iter++ = '0';
+  *digits_iter++ = uppercase ? 'X' : 'x';
+
+  // ========== Non-Fractional Digit ===========
+  *digits_iter++ = digits[leading];
+
+  // ================== Dot ====================
+  // There are three reasons we might need a dot. Keep in mind that, at this
+  // point, the mantissa holds only the fractional part.
+  if ((precision_specified && state.precision > 0) ||
+      (!precision_specified && mantissa > 0) || state.conv.has_alt_flag()) {
+    *digits_iter++ = '.';
+  }
+
+  // ============ Fractional Digits ============
+  int digits_emitted = 0;
+  while (mantissa > 0) {
+    *digits_iter++ = digits[GetNibble(mantissa, kTotalNibbles - 1)];
+    mantissa <<= 4;
+    ++digits_emitted;
+  }
+  int trailing_zeros =
+      precision_specified ? state.precision - digits_emitted : 0;
+  assert(trailing_zeros >= 0);
+  auto digits_result = string_view(digits_buffer, digits_iter - digits_buffer);
+
+  // =============== Exponent ==================
+  constexpr size_t kBufSizeForExpDecRepr =
+      numbers_internal::kFastToBufferSize  // requred for FastIntToBuffer
+      + 1                                  // 'p' or 'P'
+      + 1;                                 // '+' or '-'
+  char exp_buffer[kBufSizeForExpDecRepr];
+  exp_buffer[0] = uppercase ? 'P' : 'p';
+  exp_buffer[1] = exp >= 0 ? '+' : '-';
+  numbers_internal::FastIntToBuffer(exp < 0 ? -exp : exp, exp_buffer + 2);
+
+  // ============ Assemble Result ==============
+  FinalPrint(state,           //
+             digits_result,   // 0xN.NNN...
+             2,               // offset in `data` to start padding if needed.
+             trailing_zeros,  // num remaining mantissa padding zeros
+             exp_buffer);     // exponent
+}
+
+char *CopyStringTo(absl::string_view v, char *out) {
   std::memcpy(out, v.data(), v.size());
   return out + v.size();
 }
 
 template <typename Float>
-bool FallbackToSnprintf(const Float v, const ConversionSpec &conv,
+bool FallbackToSnprintf(const Float v, const FormatConversionSpecImpl &conv,
                         FormatSinkImpl *sink) {
   int w = conv.width() >= 0 ? conv.width() : 0;
   int p = conv.precision() >= 0 ? conv.precision() : -1;
@@ -33,17 +951,17 @@
     if (std::is_same<long double, Float>()) {
       *fp++ = 'L';
     }
-    *fp++ = FormatConversionCharToChar(conv.conv());
+    *fp++ = FormatConversionCharToChar(conv.conversion_char());
     *fp = 0;
     assert(fp < fmt + sizeof(fmt));
   }
   std::string space(512, '\0');
-  string_view result;
+  absl::string_view result;
   while (true) {
     int n = snprintf(&space[0], space.size(), fmt, w, p, v);
     if (n < 0) return false;
     if (static_cast<size_t>(n) < space.size()) {
-      result = string_view(space.data(), n);
+      result = absl::string_view(space.data(), n);
       break;
     }
     space.resize(n + 1);
@@ -96,21 +1014,24 @@
 // Otherwise, return false.
 template <typename Float>
 bool ConvertNonNumericFloats(char sign_char, Float v,
-                             const ConversionSpec &conv, FormatSinkImpl *sink) {
+                             const FormatConversionSpecImpl &conv,
+                             FormatSinkImpl *sink) {
   char text[4], *ptr = text;
-  if (sign_char) *ptr++ = sign_char;
+  if (sign_char != '\0') *ptr++ = sign_char;
   if (std::isnan(v)) {
-    ptr = std::copy_n(FormatConversionCharIsUpper(conv.conv()) ? "NAN" : "nan",
-                      3, ptr);
+    ptr = std::copy_n(
+        FormatConversionCharIsUpper(conv.conversion_char()) ? "NAN" : "nan", 3,
+        ptr);
   } else if (std::isinf(v)) {
-    ptr = std::copy_n(FormatConversionCharIsUpper(conv.conv()) ? "INF" : "inf",
-                      3, ptr);
+    ptr = std::copy_n(
+        FormatConversionCharIsUpper(conv.conversion_char()) ? "INF" : "inf", 3,
+        ptr);
   } else {
     return false;
   }
 
   return sink->PutPaddedString(string_view(text, ptr - text), conv.width(), -1,
-                               conv.flags().left);
+                               conv.has_left_flag());
 }
 
 // Round up the last digit of the value.
@@ -170,7 +1091,12 @@
 
 template <typename Float>
 struct Decomposed {
-  Float mantissa;
+  using MantissaType =
+      absl::conditional_t<std::is_same<long double, Float>::value, uint128,
+                          uint64_t>;
+  static_assert(std::numeric_limits<Float>::digits <= sizeof(MantissaType) * 8,
+                "");
+  MantissaType mantissa;
   int exponent;
 };
 
@@ -181,7 +1107,8 @@
   Float m = std::frexp(v, &exp);
   m = std::ldexp(m, std::numeric_limits<Float>::digits);
   exp -= std::numeric_limits<Float>::digits;
-  return {m, exp};
+
+  return {static_cast<typename Decomposed<Float>::MantissaType>(m), exp};
 }
 
 // Print 'digits' as decimal.
@@ -350,31 +1277,32 @@
   return false;
 }
 
-void WriteBufferToSink(char sign_char, string_view str,
-                       const ConversionSpec &conv, FormatSinkImpl *sink) {
+void WriteBufferToSink(char sign_char, absl::string_view str,
+                       const FormatConversionSpecImpl &conv,
+                       FormatSinkImpl *sink) {
   int left_spaces = 0, zeros = 0, right_spaces = 0;
   int missing_chars =
       conv.width() >= 0 ? std::max(conv.width() - static_cast<int>(str.size()) -
                                        static_cast<int>(sign_char != 0),
                                    0)
                         : 0;
-  if (conv.flags().left) {
+  if (conv.has_left_flag()) {
     right_spaces = missing_chars;
-  } else if (conv.flags().zero) {
+  } else if (conv.has_zero_flag()) {
     zeros = missing_chars;
   } else {
     left_spaces = missing_chars;
   }
 
   sink->Append(left_spaces, ' ');
-  if (sign_char) sink->Append(1, sign_char);
+  if (sign_char != '\0') sink->Append(1, sign_char);
   sink->Append(zeros, '0');
   sink->Append(str);
   sink->Append(right_spaces, ' ');
 }
 
 template <typename Float>
-bool FloatToSink(const Float v, const ConversionSpec &conv,
+bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv,
                  FormatSinkImpl *sink) {
   // Print the sign or the sign column.
   Float abs_v = v;
@@ -382,9 +1310,9 @@
   if (std::signbit(abs_v)) {
     sign_char = '-';
     abs_v = -abs_v;
-  } else if (conv.flags().show_pos) {
+  } else if (conv.has_show_pos_flag()) {
     sign_char = '+';
-  } else if (conv.flags().sign_col) {
+  } else if (conv.has_sign_col_flag()) {
     sign_char = ' ';
   }
 
@@ -401,89 +1329,91 @@
 
   Buffer buffer;
 
-  switch (conv.conv()) {
-    case ConversionChar::f:
-    case ConversionChar::F:
-      if (!FloatToBuffer<FormatStyle::Fixed>(decomposed, precision, &buffer,
-                                             nullptr)) {
-        return FallbackToSnprintf(v, conv, sink);
-      }
-      if (!conv.flags().alt && buffer.back() == '.') buffer.pop_back();
-      break;
+  FormatConversionChar c = conv.conversion_char();
 
-    case ConversionChar::e:
-    case ConversionChar::E:
-      if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
-                                                 &exp)) {
-        return FallbackToSnprintf(v, conv, sink);
-      }
-      if (!conv.flags().alt && buffer.back() == '.') buffer.pop_back();
-      PrintExponent(exp, FormatConversionCharIsUpper(conv.conv()) ? 'E' : 'e',
-                    &buffer);
-      break;
-
-    case ConversionChar::g:
-    case ConversionChar::G:
-      precision = std::max(0, precision - 1);
-      if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
-                                                 &exp)) {
-        return FallbackToSnprintf(v, conv, sink);
-      }
-      if (precision + 1 > exp && exp >= -4) {
-        if (exp < 0) {
-          // Have 1.23456, needs 0.00123456
-          // Move the first digit
-          buffer.begin[1] = *buffer.begin;
-          // Add some zeros
-          for (; exp < -1; ++exp) *buffer.begin-- = '0';
-          *buffer.begin-- = '.';
-          *buffer.begin = '0';
-        } else if (exp > 0) {
-          // Have 1.23456, needs 1234.56
-          // Move the '.' exp positions to the right.
-          std::rotate(buffer.begin + 1, buffer.begin + 2,
-                      buffer.begin + exp + 2);
-        }
-        exp = 0;
-      }
-      if (!conv.flags().alt) {
-        while (buffer.back() == '0') buffer.pop_back();
-        if (buffer.back() == '.') buffer.pop_back();
-      }
-      if (exp) {
-        PrintExponent(exp, FormatConversionCharIsUpper(conv.conv()) ? 'E' : 'e',
-                      &buffer);
-      }
-      break;
-
-    case ConversionChar::a:
-    case ConversionChar::A:
+  if (c == FormatConversionCharInternal::f ||
+      c == FormatConversionCharInternal::F) {
+    FormatF(decomposed.mantissa, decomposed.exponent,
+            {sign_char, precision, conv, sink});
+    return true;
+  } else if (c == FormatConversionCharInternal::e ||
+             c == FormatConversionCharInternal::E) {
+    if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
+                                               &exp)) {
       return FallbackToSnprintf(v, conv, sink);
-
-    default:
-      return false;
+    }
+    if (!conv.has_alt_flag() && buffer.back() == '.') buffer.pop_back();
+    PrintExponent(
+        exp, FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e',
+        &buffer);
+  } else if (c == FormatConversionCharInternal::g ||
+             c == FormatConversionCharInternal::G) {
+    precision = std::max(0, precision - 1);
+    if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
+                                               &exp)) {
+      return FallbackToSnprintf(v, conv, sink);
+    }
+    if (precision + 1 > exp && exp >= -4) {
+      if (exp < 0) {
+        // Have 1.23456, needs 0.00123456
+        // Move the first digit
+        buffer.begin[1] = *buffer.begin;
+        // Add some zeros
+        for (; exp < -1; ++exp) *buffer.begin-- = '0';
+        *buffer.begin-- = '.';
+        *buffer.begin = '0';
+      } else if (exp > 0) {
+        // Have 1.23456, needs 1234.56
+        // Move the '.' exp positions to the right.
+        std::rotate(buffer.begin + 1, buffer.begin + 2, buffer.begin + exp + 2);
+      }
+      exp = 0;
+    }
+    if (!conv.has_alt_flag()) {
+      while (buffer.back() == '0') buffer.pop_back();
+      if (buffer.back() == '.') buffer.pop_back();
+    }
+    if (exp) {
+      PrintExponent(
+          exp, FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e',
+          &buffer);
+    }
+  } else if (c == FormatConversionCharInternal::a ||
+             c == FormatConversionCharInternal::A) {
+    bool uppercase = (c == FormatConversionCharInternal::A);
+    FormatA(HexFloatTypeParams(Float{}), decomposed.mantissa,
+            decomposed.exponent, uppercase, {sign_char, precision, conv, sink});
+    return true;
+  } else {
+    return false;
   }
 
   WriteBufferToSink(sign_char,
-                    string_view(buffer.begin, buffer.end - buffer.begin), conv,
-                    sink);
+                    absl::string_view(buffer.begin, buffer.end - buffer.begin),
+                    conv, sink);
 
   return true;
 }
 
 }  // namespace
 
-bool ConvertFloatImpl(long double v, const ConversionSpec &conv,
+bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv,
                       FormatSinkImpl *sink) {
+  if (IsDoubleDouble()) {
+    // This is the `double-double` representation of `long double`. We do not
+    // handle it natively. Fallback to snprintf.
+    return FallbackToSnprintf(v, conv, sink);
+  }
+
   return FloatToSink(v, conv, sink);
 }
 
-bool ConvertFloatImpl(float v, const ConversionSpec &conv,
+bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv,
                       FormatSinkImpl *sink) {
-  return FloatToSink(v, conv, sink);
+  return FloatToSink(static_cast<double>(v), conv, sink);
 }
 
-bool ConvertFloatImpl(double v, const ConversionSpec &conv,
+bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv,
                       FormatSinkImpl *sink) {
   return FloatToSink(v, conv, sink);
 }
diff --git a/absl/strings/internal/str_format/float_conversion.h b/absl/strings/internal/str_format/float_conversion.h
index 49a6a63..71100e7 100644
--- a/absl/strings/internal/str_format/float_conversion.h
+++ b/absl/strings/internal/str_format/float_conversion.h
@@ -1,3 +1,17 @@
+// 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.
+
 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
 
@@ -7,13 +21,13 @@
 ABSL_NAMESPACE_BEGIN
 namespace str_format_internal {
 
-bool ConvertFloatImpl(float v, const ConversionSpec &conv,
+bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv,
                       FormatSinkImpl *sink);
 
-bool ConvertFloatImpl(double v, const ConversionSpec &conv,
+bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv,
                       FormatSinkImpl *sink);
 
-bool ConvertFloatImpl(long double v, const ConversionSpec &conv,
+bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv,
                       FormatSinkImpl *sink);
 
 }  // namespace str_format_internal
diff --git a/absl/strings/internal/str_format/output.h b/absl/strings/internal/str_format/output.h
index 28b288b..8030dae 100644
--- a/absl/strings/internal/str_format/output.h
+++ b/absl/strings/internal/str_format/output.h
@@ -30,9 +30,6 @@
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
-
-class Cord;
-
 namespace str_format_internal {
 
 // RawSink implementation that writes into a char* buffer.
@@ -77,12 +74,6 @@
   out->write(s.data(), s.size());
 }
 
-template <class AbslCord, typename = typename std::enable_if<
-                              std::is_same<AbslCord, absl::Cord>::value>::type>
-inline void AbslFormatFlush(AbslCord* out, string_view s) {
-  out->Append(s);
-}
-
 inline void AbslFormatFlush(FILERawSink* sink, string_view v) {
   sink->Write(v);
 }
@@ -91,10 +82,11 @@
   sink->Write(v);
 }
 
+// This is a SFINAE to get a better compiler error message when the type
+// is not supported.
 template <typename T>
-auto InvokeFlush(T* out, string_view s)
-    -> decltype(str_format_internal::AbslFormatFlush(out, s)) {
-  str_format_internal::AbslFormatFlush(out, s);
+auto InvokeFlush(T* out, string_view s) -> decltype(AbslFormatFlush(out, s)) {
+  AbslFormatFlush(out, s);
 }
 
 }  // namespace str_format_internal
diff --git a/absl/strings/internal/str_format/output_test.cc b/absl/strings/internal/str_format/output_test.cc
index e54e6f7..ce2e91a 100644
--- a/absl/strings/internal/str_format/output_test.cc
+++ b/absl/strings/internal/str_format/output_test.cc
@@ -19,6 +19,7 @@
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/strings/cord.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -37,6 +38,12 @@
   EXPECT_EQ(str.str(), "ABCDEF");
 }
 
+TEST(InvokeFlush, Cord) {
+  absl::Cord str("ABC");
+  str_format_internal::InvokeFlush(&str, "DEF");
+  EXPECT_EQ(str, "ABCDEF");
+}
+
 TEST(BufferRawSink, Limits) {
   char buf[16];
   {
@@ -70,4 +77,3 @@
 }  // namespace
 ABSL_NAMESPACE_END
 }  // namespace absl
-
diff --git a/absl/strings/internal/str_format/parser.cc b/absl/strings/internal/str_format/parser.cc
index aab68db..f308d02 100644
--- a/absl/strings/internal/str_format/parser.cc
+++ b/absl/strings/internal/str_format/parser.cc
@@ -1,3 +1,17 @@
+// 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/strings/internal/str_format/parser.h"
 
 #include <assert.h>
@@ -17,7 +31,7 @@
 ABSL_NAMESPACE_BEGIN
 namespace str_format_internal {
 
-using CC = ConversionChar;
+using CC = FormatConversionCharInternal;
 using LM = LengthMod;
 
 ABSL_CONST_INIT const ConvTag kTags[256] = {
@@ -29,9 +43,9 @@
     {},    {},    {},    {},    {},    {},    {},    {},     // 28-2f
     {},    {},    {},    {},    {},    {},    {},    {},     // 30-37
     {},    {},    {},    {},    {},    {},    {},    {},     // 38-3f
-    {},    CC::A, {},    CC::C, {},    CC::E, CC::F, CC::G,  // @ABCDEFG
+    {},    CC::A, {},    {},    {},    CC::E, CC::F, CC::G,  // @ABCDEFG
     {},    {},    {},    {},    LM::L, {},    {},    {},     // HIJKLMNO
-    {},    {},    {},    CC::S, {},    {},    {},    {},     // PQRSTUVW
+    {},    {},    {},    {},    {},    {},    {},    {},     // PQRSTUVW
     CC::X, {},    {},    {},    {},    {},    {},    {},     // XYZ[\]^_
     {},    CC::a, {},    CC::c, CC::d, CC::e, CC::f, CC::g,  // `abcdefg
     LM::h, CC::i, LM::j, {},    LM::l, {},    CC::n, CC::o,  // hijklmno
@@ -296,15 +310,17 @@
   char* data_pos;
 };
 
-ParsedFormatBase::ParsedFormatBase(string_view format, bool allow_ignored,
-                                   std::initializer_list<Conv> convs)
+ParsedFormatBase::ParsedFormatBase(
+    string_view format, bool allow_ignored,
+    std::initializer_list<FormatConversionCharSet> convs)
     : data_(format.empty() ? nullptr : new char[format.size()]) {
   has_error_ = !ParseFormatString(format, ParsedFormatConsumer(this)) ||
                !MatchesConversions(allow_ignored, convs);
 }
 
 bool ParsedFormatBase::MatchesConversions(
-    bool allow_ignored, std::initializer_list<Conv> convs) const {
+    bool allow_ignored,
+    std::initializer_list<FormatConversionCharSet> convs) const {
   std::unordered_set<int> used;
   auto add_if_valid_conv = [&](int pos, char c) {
       if (static_cast<size_t>(pos) > convs.size() ||
diff --git a/absl/strings/internal/str_format/parser.h b/absl/strings/internal/str_format/parser.h
index 45c90d1..6504dd3 100644
--- a/absl/strings/internal/str_format/parser.h
+++ b/absl/strings/internal/str_format/parser.h
@@ -1,3 +1,17 @@
+// 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.
+
 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
 
@@ -67,7 +81,7 @@
 
   Flags flags;
   LengthMod length_mod = LengthMod::none;
-  ConversionChar conv = FormatConversionChar::kNone;
+  FormatConversionChar conv = FormatConversionCharInternal::kNone;
 };
 
 // Consume conversion spec prefix (not including '%') of [p, end) if valid.
@@ -83,7 +97,7 @@
 // conversions.
 class ConvTag {
  public:
-  constexpr ConvTag(ConversionChar conversion_char)  // NOLINT
+  constexpr ConvTag(FormatConversionChar conversion_char)  // NOLINT
       : tag_(static_cast<int8_t>(conversion_char)) {}
   // We invert the length modifiers to make them negative so that we can easily
   // test for them.
@@ -94,9 +108,9 @@
 
   bool is_conv() const { return tag_ >= 0; }
   bool is_length() const { return tag_ < 0 && tag_ != -128; }
-  ConversionChar as_conv() const {
+  FormatConversionChar as_conv() const {
     assert(is_conv());
-    return static_cast<ConversionChar>(tag_);
+    return static_cast<FormatConversionChar>(tag_);
   }
   LengthMod as_length() const {
     assert(is_length());
@@ -143,7 +157,7 @@
     auto tag = GetTagForChar(percent[1]);
     if (tag.is_conv()) {
       if (ABSL_PREDICT_FALSE(next_arg < 0)) {
-        // This indicates an error in the format std::string.
+        // This indicates an error in the format string.
         // The only way to get `next_arg < 0` here is to have a positional
         // argument first which sets next_arg to -1 and then a non-positional
         // argument.
@@ -186,8 +200,9 @@
 
 class ParsedFormatBase {
  public:
-  explicit ParsedFormatBase(string_view format, bool allow_ignored,
-                            std::initializer_list<Conv> convs);
+  explicit ParsedFormatBase(
+      string_view format, bool allow_ignored,
+      std::initializer_list<FormatConversionCharSet> convs);
 
   ParsedFormatBase(const ParsedFormatBase& other) { *this = other; }
 
@@ -234,8 +249,9 @@
  private:
   // Returns whether the conversions match and if !allow_ignored it verifies
   // that all conversions are used by the format.
-  bool MatchesConversions(bool allow_ignored,
-                          std::initializer_list<Conv> convs) const;
+  bool MatchesConversions(
+      bool allow_ignored,
+      std::initializer_list<FormatConversionCharSet> convs) const;
 
   struct ParsedFormatConsumer;
 
@@ -280,14 +296,14 @@
 // This is the only API that allows the user to pass a runtime specified format
 // string. These factory functions will return NULL if the format does not match
 // the conversions requested by the user.
-template <str_format_internal::Conv... C>
+template <FormatConversionCharSet... C>
 class ExtendedParsedFormat : public str_format_internal::ParsedFormatBase {
  public:
   explicit ExtendedParsedFormat(string_view format)
 #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
       __attribute__((
           enable_if(str_format_internal::EnsureConstexpr(format),
-                    "Format std::string is not constexpr."),
+                    "Format string is not constexpr."),
           enable_if(str_format_internal::ValidFormatImpl<C...>(format),
                     "Format specified does not match the template arguments.")))
 #endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
diff --git a/absl/strings/internal/str_format/parser_test.cc b/absl/strings/internal/str_format/parser_test.cc
index 1b1ee03..a5fa1c7 100644
--- a/absl/strings/internal/str_format/parser_test.cc
+++ b/absl/strings/internal/str_format/parser_test.cc
@@ -1,3 +1,17 @@
+// 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/strings/internal/str_format/parser.h"
 
 #include <string.h>
@@ -41,23 +55,23 @@
 
 TEST(ConversionCharTest, Names) {
   struct Expectation {
-    ConversionChar id;
+    FormatConversionChar id;
     char name;
   };
   // clang-format off
   const Expectation kExpect[] = {
-#define X(c) {ConversionChar::c, #c[0]}
-    X(c), X(C), X(s), X(S),                          // text
+#define X(c) {FormatConversionCharInternal::c, #c[0]}
+    X(c), X(s),                                      // text
     X(d), X(i), X(o), X(u), X(x), X(X),              // int
     X(f), X(F), X(e), X(E), X(g), X(G), X(a), X(A),  // float
     X(n), X(p),                                      // misc
 #undef X
-    {ConversionChar::none, '\0'},
+    {FormatConversionCharInternal::kNone, '\0'},
   };
   // clang-format on
   for (auto e : kExpect) {
     SCOPED_TRACE(e.name);
-    ConversionChar v = e.id;
+    FormatConversionChar v = e.id;
     EXPECT_EQ(e.name, FormatConversionCharToChar(v));
   }
 }
@@ -349,7 +363,8 @@
   ParsedFormatBase p2 = p1;  // copy construct (empty)
   EXPECT_EQ(SummarizeParsedFormat(p1), SummarizeParsedFormat(p2));
 
-  p1 = ParsedFormatBase("hello%s", true, {Conv::s});  // move assign
+  p1 = ParsedFormatBase("hello%s", true,
+                        {FormatConversionCharSetInternal::s});  // move assign
   EXPECT_EQ("[hello]{s:1$s}", SummarizeParsedFormat(p1));
 
   ParsedFormatBase p3 = p1;  // copy construct (nonempty)
@@ -367,7 +382,7 @@
 
 struct ExpectParse {
   const char* in;
-  std::initializer_list<Conv> conv_set;
+  std::initializer_list<FormatConversionCharSet> conv_set;
   const char* out;
 };
 
@@ -377,9 +392,9 @@
   const ExpectParse kExpect[] = {
       {"", {}, ""},
       {"ab", {}, "[ab]"},
-      {"a%d", {Conv::d}, "[a]{d:1$d}"},
-      {"a%+d", {Conv::d}, "[a]{+d:1$d}"},
-      {"a% d", {Conv::d}, "[a]{ d:1$d}"},
+      {"a%d", {FormatConversionCharSetInternal::d}, "[a]{d:1$d}"},
+      {"a%+d", {FormatConversionCharSetInternal::d}, "[a]{+d:1$d}"},
+      {"a% d", {FormatConversionCharSetInternal::d}, "[a]{ d:1$d}"},
       {"a%b %d", {}, "[a]!"},  // stop after error
   };
   for (const auto& e : kExpect) {
@@ -391,13 +406,13 @@
 
 TEST_F(ParsedFormatTest, ParsingFlagOrder) {
   const ExpectParse kExpect[] = {
-      {"a%+ 0d", {Conv::d}, "[a]{+ 0d:1$d}"},
-      {"a%+0 d", {Conv::d}, "[a]{+0 d:1$d}"},
-      {"a%0+ d", {Conv::d}, "[a]{0+ d:1$d}"},
-      {"a% +0d", {Conv::d}, "[a]{ +0d:1$d}"},
-      {"a%0 +d", {Conv::d}, "[a]{0 +d:1$d}"},
-      {"a% 0+d", {Conv::d}, "[a]{ 0+d:1$d}"},
-      {"a%+   0+d", {Conv::d}, "[a]{+   0+d:1$d}"},
+      {"a%+ 0d", {FormatConversionCharSetInternal::d}, "[a]{+ 0d:1$d}"},
+      {"a%+0 d", {FormatConversionCharSetInternal::d}, "[a]{+0 d:1$d}"},
+      {"a%0+ d", {FormatConversionCharSetInternal::d}, "[a]{0+ d:1$d}"},
+      {"a% +0d", {FormatConversionCharSetInternal::d}, "[a]{ +0d:1$d}"},
+      {"a%0 +d", {FormatConversionCharSetInternal::d}, "[a]{0 +d:1$d}"},
+      {"a% 0+d", {FormatConversionCharSetInternal::d}, "[a]{ 0+d:1$d}"},
+      {"a%+   0+d", {FormatConversionCharSetInternal::d}, "[a]{+   0+d:1$d}"},
   };
   for (const auto& e : kExpect) {
     SCOPED_TRACE(e.in);
diff --git a/absl/strings/internal/str_split_internal.h b/absl/strings/internal/str_split_internal.h
index b54f6eb..a2f41c1 100644
--- a/absl/strings/internal/str_split_internal.h
+++ b/absl/strings/internal/str_split_internal.h
@@ -51,9 +51,9 @@
 namespace strings_internal {
 
 // This class is implicitly constructible from everything that absl::string_view
-// is implicitly constructible from. If it's constructed from a temporary
-// string, the data is moved into a data member so its lifetime matches that of
-// the ConvertibleToStringView instance.
+// is implicitly constructible from, except for rvalue strings.  This means it
+// can be used as a function parameter in places where passing a temporary
+// string might cause memory lifetime issues.
 class ConvertibleToStringView {
  public:
   ConvertibleToStringView(const char* s)  // NOLINT(runtime/explicit)
@@ -65,41 +65,12 @@
       : value_(s) {}
 
   // Matches rvalue strings and moves their data to a member.
-ConvertibleToStringView(std::string&& s)  // NOLINT(runtime/explicit)
-    : copy_(std::move(s)), value_(copy_) {}
-
-  ConvertibleToStringView(const ConvertibleToStringView& other)
-      : copy_(other.copy_),
-        value_(other.IsSelfReferential() ? copy_ : other.value_) {}
-
-  ConvertibleToStringView(ConvertibleToStringView&& other) {
-    StealMembers(std::move(other));
-  }
-
-  ConvertibleToStringView& operator=(ConvertibleToStringView other) {
-    StealMembers(std::move(other));
-    return *this;
-  }
+  ConvertibleToStringView(std::string&& s) = delete;
+  ConvertibleToStringView(const std::string&& s) = delete;
 
   absl::string_view value() const { return value_; }
 
  private:
-  // Returns true if ctsp's value refers to its internal copy_ member.
-  bool IsSelfReferential() const { return value_.data() == copy_.data(); }
-
-  void StealMembers(ConvertibleToStringView&& other) {
-    if (other.IsSelfReferential()) {
-      copy_ = std::move(other.copy_);
-      value_ = copy_;
-      other.value_ = other.copy_;
-    } else {
-      value_ = other.value_;
-    }
-  }
-
-  // Holds the data moved from temporary std::string arguments. Declared first
-  // so that 'value' can refer to 'copy_'.
-  std::string copy_;
   absl::string_view value_;
 };
 
@@ -273,7 +244,11 @@
 // the split strings: only strings for which the predicate returns true will be
 // kept. A Predicate object is any unary functor that takes an absl::string_view
 // and returns bool.
-template <typename Delimiter, typename Predicate>
+//
+// The StringType parameter can be either string_view or string, depending on
+// whether the Splitter refers to a string stored elsewhere, or if the string
+// resides inside the Splitter itself.
+template <typename Delimiter, typename Predicate, typename StringType>
 class Splitter {
  public:
   using DelimiterType = Delimiter;
@@ -281,12 +256,12 @@
   using const_iterator = strings_internal::SplitIterator<Splitter>;
   using value_type = typename std::iterator_traits<const_iterator>::value_type;
 
-  Splitter(ConvertibleToStringView input_text, Delimiter d, Predicate p)
+  Splitter(StringType input_text, Delimiter d, Predicate p)
       : text_(std::move(input_text)),
         delimiter_(std::move(d)),
         predicate_(std::move(p)) {}
 
-  absl::string_view text() const { return text_.value(); }
+  absl::string_view text() const { return text_; }
   const Delimiter& delimiter() const { return delimiter_; }
   const Predicate& predicate() const { return predicate_; }
 
@@ -336,7 +311,7 @@
     Container operator()(const Splitter& splitter) const {
       Container c;
       auto it = std::inserter(c, c.end());
-      for (const auto sp : splitter) {
+      for (const auto& sp : splitter) {
         *it++ = ValueType(sp);
       }
       return c;
@@ -401,7 +376,7 @@
       Container m;
       typename Container::iterator it;
       bool insert = true;
-      for (const auto sp : splitter) {
+      for (const auto& sp : splitter) {
         if (insert) {
           it = Inserter<Container>::Insert(&m, First(sp), Second());
         } else {
@@ -443,7 +418,7 @@
     };
   };
 
-  ConvertibleToStringView text_;
+  StringType text_;
   Delimiter delimiter_;
   Predicate predicate_;
 };
diff --git a/absl/strings/internal/string_constant.h b/absl/strings/internal/string_constant.h
new file mode 100644
index 0000000..a11336b
--- /dev/null
+++ b/absl/strings/internal/string_constant.h
@@ -0,0 +1,64 @@
+// 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.
+
+#ifndef ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_
+#define ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_
+
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+// StringConstant<T> represents a compile time string constant.
+// It can be accessed via its `absl::string_view value` static member.
+// It is guaranteed that the `string_view` returned has constant `.data()`,
+// constant `.size()` and constant `value[i]` for all `0 <= i < .size()`
+//
+// The `T` is an opaque type. It is guaranteed that different string constants
+// will have different values of `T`. This allows users to associate the string
+// constant with other static state at compile time.
+//
+// Instances should be made using the `MakeStringConstant()` factory function
+// below.
+template <typename T>
+struct StringConstant {
+  static constexpr absl::string_view value = T{}();
+  constexpr absl::string_view operator()() const { return value; }
+
+  // Check to be sure `view` points to constant data.
+  // Otherwise, it can't be constant evaluated.
+  static_assert(value.empty() || 2 * value[0] != 1,
+                "The input string_view must point to constant data.");
+};
+
+template <typename T>
+constexpr absl::string_view StringConstant<T>::value;  // NOLINT
+
+// Factory function for `StringConstant` instances.
+// It supports callables that have a constexpr default constructor and a
+// constexpr operator().
+// It must return an `absl::string_view` or `const char*` pointing to constant
+// data. This is validated at compile time.
+template <typename T>
+constexpr StringConstant<T> MakeStringConstant(T) {
+  return {};
+}
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_
diff --git a/absl/strings/internal/string_constant_test.cc b/absl/strings/internal/string_constant_test.cc
new file mode 100644
index 0000000..392833c
--- /dev/null
+++ b/absl/strings/internal/string_constant_test.cc
@@ -0,0 +1,60 @@
+// 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/strings/internal/string_constant.h"
+
+#include "absl/meta/type_traits.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+using absl::strings_internal::MakeStringConstant;
+
+struct Callable {
+  constexpr absl::string_view operator()() const {
+    return absl::string_view("Callable", 8);
+  }
+};
+
+TEST(StringConstant, Traits) {
+  constexpr auto str = MakeStringConstant(Callable{});
+  using T = decltype(str);
+
+  EXPECT_TRUE(std::is_empty<T>::value);
+  EXPECT_TRUE(std::is_trivial<T>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<T>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<T>::value);
+  EXPECT_TRUE(absl::is_trivially_move_constructible<T>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<T>::value);
+}
+
+TEST(StringConstant, MakeFromCallable) {
+  constexpr auto str = MakeStringConstant(Callable{});
+  using T = decltype(str);
+  EXPECT_EQ(Callable{}(), T::value);
+  EXPECT_EQ(Callable{}(), str());
+}
+
+TEST(StringConstant, MakeFromStringConstant) {
+  // We want to make sure the StringConstant itself is a valid input to the
+  // factory function.
+  constexpr auto str = MakeStringConstant(Callable{});
+  constexpr auto str2 = MakeStringConstant(str);
+  using T = decltype(str2);
+  EXPECT_EQ(Callable{}(), T::value);
+  EXPECT_EQ(Callable{}(), str2());
+}
+
+}  // namespace
diff --git a/absl/strings/match.cc b/absl/strings/match.cc
index 8127cb0..2d67250 100644
--- a/absl/strings/match.cc
+++ b/absl/strings/match.cc
@@ -19,19 +19,22 @@
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
-bool EqualsIgnoreCase(absl::string_view piece1, absl::string_view piece2) {
+bool EqualsIgnoreCase(absl::string_view piece1,
+                      absl::string_view piece2) noexcept {
   return (piece1.size() == piece2.size() &&
           0 == absl::strings_internal::memcasecmp(piece1.data(), piece2.data(),
                                                   piece1.size()));
   // memcasecmp uses absl::ascii_tolower().
 }
 
-bool StartsWithIgnoreCase(absl::string_view text, absl::string_view prefix) {
+bool StartsWithIgnoreCase(absl::string_view text,
+                          absl::string_view prefix) noexcept {
   return (text.size() >= prefix.size()) &&
          EqualsIgnoreCase(text.substr(0, prefix.size()), prefix);
 }
 
-bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix) {
+bool EndsWithIgnoreCase(absl::string_view text,
+                        absl::string_view suffix) noexcept {
   return (text.size() >= suffix.size()) &&
          EqualsIgnoreCase(text.substr(text.size() - suffix.size()), suffix);
 }
diff --git a/absl/strings/match.h b/absl/strings/match.h
index 90fca98..038cbb3 100644
--- a/absl/strings/match.h
+++ b/absl/strings/match.h
@@ -43,14 +43,20 @@
 // StrContains()
 //
 // Returns whether a given string `haystack` contains the substring `needle`.
-inline bool StrContains(absl::string_view haystack, absl::string_view needle) {
+inline bool StrContains(absl::string_view haystack,
+                        absl::string_view needle) noexcept {
   return haystack.find(needle, 0) != haystack.npos;
 }
 
+inline bool StrContains(absl::string_view haystack, char needle) noexcept {
+  return haystack.find(needle) != haystack.npos;
+}
+
 // StartsWith()
 //
 // Returns whether a given string `text` begins with `prefix`.
-inline bool StartsWith(absl::string_view text, absl::string_view prefix) {
+inline bool StartsWith(absl::string_view text,
+                       absl::string_view prefix) noexcept {
   return prefix.empty() ||
          (text.size() >= prefix.size() &&
           memcmp(text.data(), prefix.data(), prefix.size()) == 0);
@@ -59,7 +65,8 @@
 // EndsWith()
 //
 // Returns whether a given string `text` ends with `suffix`.
-inline bool EndsWith(absl::string_view text, absl::string_view suffix) {
+inline bool EndsWith(absl::string_view text,
+                     absl::string_view suffix) noexcept {
   return suffix.empty() ||
          (text.size() >= suffix.size() &&
           memcmp(text.data() + (text.size() - suffix.size()), suffix.data(),
@@ -70,19 +77,22 @@
 //
 // Returns whether given ASCII strings `piece1` and `piece2` are equal, ignoring
 // case in the comparison.
-bool EqualsIgnoreCase(absl::string_view piece1, absl::string_view piece2);
+bool EqualsIgnoreCase(absl::string_view piece1,
+                      absl::string_view piece2) noexcept;
 
 // StartsWithIgnoreCase()
 //
 // Returns whether a given ASCII string `text` starts with `prefix`,
 // ignoring case in the comparison.
-bool StartsWithIgnoreCase(absl::string_view text, absl::string_view prefix);
+bool StartsWithIgnoreCase(absl::string_view text,
+                          absl::string_view prefix) noexcept;
 
 // EndsWithIgnoreCase()
 //
 // Returns whether a given ASCII string `text` ends with `suffix`, ignoring
 // case in the comparison.
-bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix);
+bool EndsWithIgnoreCase(absl::string_view text,
+                        absl::string_view suffix) noexcept;
 
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/strings/match_test.cc b/absl/strings/match_test.cc
index 4c313dd..5841bc1 100644
--- a/absl/strings/match_test.cc
+++ b/absl/strings/match_test.cc
@@ -66,6 +66,23 @@
   EXPECT_FALSE(absl::StrContains("", "a"));
 }
 
+TEST(MatchTest, ContainsChar) {
+  absl::string_view a("abcdefg");
+  absl::string_view b("abcd");
+  EXPECT_TRUE(absl::StrContains(a, 'a'));
+  EXPECT_TRUE(absl::StrContains(a, 'b'));
+  EXPECT_TRUE(absl::StrContains(a, 'e'));
+  EXPECT_FALSE(absl::StrContains(a, 'h'));
+
+  EXPECT_TRUE(absl::StrContains(b, 'a'));
+  EXPECT_TRUE(absl::StrContains(b, 'b'));
+  EXPECT_FALSE(absl::StrContains(b, 'e'));
+  EXPECT_FALSE(absl::StrContains(b, 'h'));
+
+  EXPECT_FALSE(absl::StrContains("", 'a'));
+  EXPECT_FALSE(absl::StrContains("", 'a'));
+}
+
 TEST(MatchTest, ContainsNull) {
   const std::string s = "foo";
   const char* cs = "foo";
diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc
index 68c26dd..966d94b 100644
--- a/absl/strings/numbers.cc
+++ b/absl/strings/numbers.cc
@@ -31,8 +31,8 @@
 #include <utility>
 
 #include "absl/base/attributes.h"
-#include "absl/base/internal/bits.h"
 #include "absl/base/internal/raw_logging.h"
+#include "absl/numeric/bits.h"
 #include "absl/strings/ascii.h"
 #include "absl/strings/charconv.h"
 #include "absl/strings/escaping.h"
@@ -46,8 +46,13 @@
 bool SimpleAtof(absl::string_view str, float* out) {
   *out = 0.0;
   str = StripAsciiWhitespace(str);
+  // 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] == '+') {
     str.remove_prefix(1);
+    if (!str.empty() && str[0] == '-') {
+      return false;
+    }
   }
   auto result = absl::from_chars(str.data(), str.data() + str.size(), *out);
   if (result.ec == std::errc::invalid_argument) {
@@ -72,8 +77,13 @@
 bool SimpleAtod(absl::string_view str, double* out) {
   *out = 0.0;
   str = StripAsciiWhitespace(str);
+  // 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] == '+') {
     str.remove_prefix(1);
+    if (!str.empty() && str[0] == '-') {
+      return false;
+    }
   }
   auto result = absl::from_chars(str.data(), str.data() + str.size(), *out);
   if (result.ec == std::errc::invalid_argument) {
@@ -303,7 +313,7 @@
   uint64_t bits128_up = (bits96_127 >> 32) + (bits64_127 < bits64_95);
   if (bits128_up == 0) return {bits64_127, bits0_63};
 
-  int shift = 64 - base_internal::CountLeadingZeros64(bits128_up);
+  auto shift = static_cast<unsigned>(bit_width(bits128_up));
   uint64_t lo = (bits0_63 >> shift) + (bits64_127 << (64 - shift));
   uint64_t hi = (bits64_127 >> shift) + (bits128_up << (64 - shift));
   return {hi, lo};
@@ -334,7 +344,7 @@
       5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
       5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5};
   result = Mul32(result, powers_of_five[expfive & 15]);
-  int shift = base_internal::CountLeadingZeros64(result.first);
+  int shift = countl_zero(result.first);
   if (shift != 0) {
     result.first = (result.first << shift) + (result.second >> (64 - shift));
     result.second = (result.second << shift);
@@ -736,9 +746,18 @@
         X / 35, X / 36,                                                   \
   }
 
+// This kVmaxOverBase is generated with
+//  for (int base = 2; base < 37; ++base) {
+//    absl::uint128 max = std::numeric_limits<absl::uint128>::max();
+//    auto result = max / base;
+//    std::cout << "    MakeUint128(" << absl::Uint128High64(result) << "u, "
+//              << absl::Uint128Low64(result) << "u),\n";
+//  }
+// See https://godbolt.org/z/aneYsb
+//
 // uint128& operator/=(uint128) is not constexpr, so hardcode the resulting
 // array to avoid a static initializer.
-template <>
+template<>
 const uint128 LookupTables<uint128>::kVmaxOverBase[] = {
     0,
     0,
@@ -779,6 +798,111 @@
     MakeUint128(512409557603043100u, 8198552921648689607u),
 };
 
+// This kVmaxOverBase generated with
+//   for (int base = 2; base < 37; ++base) {
+//    absl::int128 max = std::numeric_limits<absl::int128>::max();
+//    auto result = max / base;
+//    std::cout << "\tMakeInt128(" << absl::Int128High64(result) << ", "
+//              << absl::Int128Low64(result) << "u),\n";
+//  }
+// See https://godbolt.org/z/7djYWz
+//
+// int128& operator/=(int128) is not constexpr, so hardcode the resulting array
+// to avoid a static initializer.
+template<>
+const int128 LookupTables<int128>::kVmaxOverBase[] = {
+    0,
+    0,
+    MakeInt128(4611686018427387903, 18446744073709551615u),
+    MakeInt128(3074457345618258602, 12297829382473034410u),
+    MakeInt128(2305843009213693951, 18446744073709551615u),
+    MakeInt128(1844674407370955161, 11068046444225730969u),
+    MakeInt128(1537228672809129301, 6148914691236517205u),
+    MakeInt128(1317624576693539401, 2635249153387078802u),
+    MakeInt128(1152921504606846975, 18446744073709551615u),
+    MakeInt128(1024819115206086200, 16397105843297379214u),
+    MakeInt128(922337203685477580, 14757395258967641292u),
+    MakeInt128(838488366986797800, 13415813871788764811u),
+    MakeInt128(768614336404564650, 12297829382473034410u),
+    MakeInt128(709490156681136600, 11351842506898185609u),
+    MakeInt128(658812288346769700, 10540996613548315209u),
+    MakeInt128(614891469123651720, 9838263505978427528u),
+    MakeInt128(576460752303423487, 18446744073709551615u),
+    MakeInt128(542551296285575047, 9765923333140350855u),
+    MakeInt128(512409557603043100, 8198552921648689607u),
+    MakeInt128(485440633518672410, 17475862806672206794u),
+    MakeInt128(461168601842738790, 7378697629483820646u),
+    MakeInt128(439208192231179800, 7027331075698876806u),
+    MakeInt128(419244183493398900, 6707906935894382405u),
+    MakeInt128(401016175515425035, 2406097053092550210u),
+    MakeInt128(384307168202282325, 6148914691236517205u),
+    MakeInt128(368934881474191032, 5902958103587056517u),
+    MakeInt128(354745078340568300, 5675921253449092804u),
+    MakeInt128(341606371735362066, 17763531330238827482u),
+    MakeInt128(329406144173384850, 5270498306774157604u),
+    MakeInt128(318047311615681924, 7633135478776366185u),
+    MakeInt128(307445734561825860, 4919131752989213764u),
+    MakeInt128(297528130221121800, 4760450083537948804u),
+    MakeInt128(288230376151711743, 18446744073709551615u),
+    MakeInt128(279496122328932600, 4471937957262921603u),
+    MakeInt128(271275648142787523, 14106333703424951235u),
+    MakeInt128(263524915338707880, 4216398645419326083u),
+    MakeInt128(256204778801521550, 4099276460824344803u),
+};
+
+// This kVminOverBase generated with
+//  for (int base = 2; base < 37; ++base) {
+//    absl::int128 min = std::numeric_limits<absl::int128>::min();
+//    auto result = min / base;
+//    std::cout << "\tMakeInt128(" << absl::Int128High64(result) << ", "
+//              << absl::Int128Low64(result) << "u),\n";
+//  }
+//
+// See https://godbolt.org/z/7djYWz
+//
+// int128& operator/=(int128) is not constexpr, so hardcode the resulting array
+// to avoid a static initializer.
+template<>
+const int128 LookupTables<int128>::kVminOverBase[] = {
+    0,
+    0,
+    MakeInt128(-4611686018427387904, 0u),
+    MakeInt128(-3074457345618258603, 6148914691236517206u),
+    MakeInt128(-2305843009213693952, 0u),
+    MakeInt128(-1844674407370955162, 7378697629483820647u),
+    MakeInt128(-1537228672809129302, 12297829382473034411u),
+    MakeInt128(-1317624576693539402, 15811494920322472814u),
+    MakeInt128(-1152921504606846976, 0u),
+    MakeInt128(-1024819115206086201, 2049638230412172402u),
+    MakeInt128(-922337203685477581, 3689348814741910324u),
+    MakeInt128(-838488366986797801, 5030930201920786805u),
+    MakeInt128(-768614336404564651, 6148914691236517206u),
+    MakeInt128(-709490156681136601, 7094901566811366007u),
+    MakeInt128(-658812288346769701, 7905747460161236407u),
+    MakeInt128(-614891469123651721, 8608480567731124088u),
+    MakeInt128(-576460752303423488, 0u),
+    MakeInt128(-542551296285575048, 8680820740569200761u),
+    MakeInt128(-512409557603043101, 10248191152060862009u),
+    MakeInt128(-485440633518672411, 970881267037344822u),
+    MakeInt128(-461168601842738791, 11068046444225730970u),
+    MakeInt128(-439208192231179801, 11419412998010674810u),
+    MakeInt128(-419244183493398901, 11738837137815169211u),
+    MakeInt128(-401016175515425036, 16040647020617001406u),
+    MakeInt128(-384307168202282326, 12297829382473034411u),
+    MakeInt128(-368934881474191033, 12543785970122495099u),
+    MakeInt128(-354745078340568301, 12770822820260458812u),
+    MakeInt128(-341606371735362067, 683212743470724134u),
+    MakeInt128(-329406144173384851, 13176245766935394012u),
+    MakeInt128(-318047311615681925, 10813608594933185431u),
+    MakeInt128(-307445734561825861, 13527612320720337852u),
+    MakeInt128(-297528130221121801, 13686293990171602812u),
+    MakeInt128(-288230376151711744, 0u),
+    MakeInt128(-279496122328932601, 13974806116446630013u),
+    MakeInt128(-271275648142787524, 4340410370284600381u),
+    MakeInt128(-263524915338707881, 14230345428290225533u),
+    MakeInt128(-256204778801521551, 14347467612885206813u),
+};
+
 template <typename IntType>
 const IntType LookupTables<IntType>::kVmaxOverBase[] =
     X_OVER_BASE_INITIALIZER(std::numeric_limits<IntType>::max());
@@ -948,6 +1072,10 @@
   return safe_int_internal<int64_t>(text, value, base);
 }
 
+bool safe_strto128_base(absl::string_view text, int128* value, int base) {
+  return safe_int_internal<absl::int128>(text, value, base);
+}
+
 bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base) {
   return safe_uint_internal<uint32_t>(text, value, base);
 }
diff --git a/absl/strings/numbers.h b/absl/strings/numbers.h
index d872cca..1780bb4 100644
--- a/absl/strings/numbers.h
+++ b/absl/strings/numbers.h
@@ -1,4 +1,3 @@
-//
 // Copyright 2017 The Abseil Authors.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
@@ -37,7 +36,6 @@
 #include <type_traits>
 
 #include "absl/base/config.h"
-#include "absl/base/internal/bits.h"
 #ifdef __SSE4_2__
 // TODO(jorg): Remove this when we figure out the right way
 // to swap bytes on SSE 4.2 that works with the compilers
@@ -48,6 +46,7 @@
 #endif
 #include "absl/base/macros.h"
 #include "absl/base/port.h"
+#include "absl/numeric/bits.h"
 #include "absl/numeric/int128.h"
 #include "absl/strings/string_view.h"
 
@@ -125,8 +124,11 @@
 }
 
 // safe_strto?() functions for implementing SimpleAtoi()
+
 bool safe_strto32_base(absl::string_view text, int32_t* value, int base);
 bool safe_strto64_base(absl::string_view text, int64_t* value, int base);
+bool safe_strto128_base(absl::string_view text, absl::int128* value,
+                         int base);
 bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base);
 bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base);
 bool safe_strtou128_base(absl::string_view text, absl::uint128* value,
@@ -238,24 +240,22 @@
   }
 #endif
   // | 0x1 so that even 0 has 1 digit.
-  return 16 - absl::base_internal::CountLeadingZeros64(val | 0x1) / 4;
+  return 16 - countl_zero(val | 0x1) / 4;
 }
 
 }  // namespace numbers_internal
 
-// SimpleAtoi()
-//
-// Converts a string to an integer, using `safe_strto?()` functions for actual
-// parsing, returning `true` if successful. The `safe_strto?()` functions apply
-// strict checking; the string must be a base-10 integer, optionally followed or
-// preceded by ASCII whitespace, with a value in the range of the corresponding
-// integer type.
 template <typename int_type>
 ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type* out) {
   return numbers_internal::safe_strtoi_base(str, out, 10);
 }
 
 ABSL_MUST_USE_RESULT inline bool SimpleAtoi(absl::string_view str,
+                                            absl::int128* out) {
+  return numbers_internal::safe_strto128_base(str, out, 10);
+}
+
+ABSL_MUST_USE_RESULT inline bool SimpleAtoi(absl::string_view str,
                                             absl::uint128* out) {
   return numbers_internal::safe_strtou128_base(str, out, 10);
 }
diff --git a/absl/strings/numbers_test.cc b/absl/strings/numbers_test.cc
index 68229b1..f310310 100644
--- a/absl/strings/numbers_test.cc
+++ b/absl/strings/numbers_test.cc
@@ -40,11 +40,13 @@
 #include "absl/random/distributions.h"
 #include "absl/random/random.h"
 #include "absl/strings/internal/numbers_test_common.h"
+#include "absl/strings/internal/ostringstream.h"
 #include "absl/strings/internal/pow10_helper.h"
 #include "absl/strings/str_cat.h"
 
 namespace {
 
+using absl::SimpleAtoi;
 using absl::numbers_internal::kSixDigitsToBufferSize;
 using absl::numbers_internal::safe_strto32_base;
 using absl::numbers_internal::safe_strto64_base;
@@ -54,7 +56,6 @@
 using absl::strings_internal::Itoa;
 using absl::strings_internal::strtouint32_test_cases;
 using absl::strings_internal::strtouint64_test_cases;
-using absl::SimpleAtoi;
 using testing::Eq;
 using testing::MatchesRegex;
 
@@ -250,7 +251,7 @@
 template <typename int_type, typename in_val_type>
 void VerifySimpleAtoiGood(in_val_type in_value, int_type exp_value) {
   std::string s;
-  // uint128 can be streamed but not StrCat'd
+  // (u)int128 can be streamed but not StrCat'd.
   absl::strings_internal::OStringStream(&s) << in_value;
   int_type x = static_cast<int_type>(~exp_value);
   EXPECT_TRUE(SimpleAtoi(s, &x))
@@ -263,7 +264,9 @@
 
 template <typename int_type, typename in_val_type>
 void VerifySimpleAtoiBad(in_val_type in_value) {
-  std::string s = absl::StrCat(in_value);
+  std::string s;
+  // (u)int128 can be streamed but not StrCat'd.
+  absl::strings_internal::OStringStream(&s) << in_value;
   int_type x;
   EXPECT_FALSE(SimpleAtoi(s, &x));
   EXPECT_FALSE(SimpleAtoi(s.c_str(), &x));
@@ -346,18 +349,71 @@
       std::numeric_limits<absl::uint128>::max(),
       std::numeric_limits<absl::uint128>::max());
 
+  // SimpleAtoi(absl::string_view, absl::int128)
+  VerifySimpleAtoiGood<absl::int128>(0, 0);
+  VerifySimpleAtoiGood<absl::int128>(42, 42);
+  VerifySimpleAtoiGood<absl::int128>(-42, -42);
+
+  VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<int32_t>::min(),
+                                      std::numeric_limits<int32_t>::min());
+  VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<int32_t>::max(),
+                                      std::numeric_limits<int32_t>::max());
+  VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<uint32_t>::max(),
+                                      std::numeric_limits<uint32_t>::max());
+  VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<int64_t>::min(),
+                                      std::numeric_limits<int64_t>::min());
+  VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<int64_t>::max(),
+                                      std::numeric_limits<int64_t>::max());
+  VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<uint64_t>::max(),
+                                      std::numeric_limits<uint64_t>::max());
+  VerifySimpleAtoiGood<absl::int128>(
+      std::numeric_limits<absl::int128>::min(),
+      std::numeric_limits<absl::int128>::min());
+  VerifySimpleAtoiGood<absl::int128>(
+      std::numeric_limits<absl::int128>::max(),
+      std::numeric_limits<absl::int128>::max());
+  VerifySimpleAtoiBad<absl::int128>(std::numeric_limits<absl::uint128>::max());
+
   // Some other types
   VerifySimpleAtoiGood<int>(-42, -42);
   VerifySimpleAtoiGood<int32_t>(-42, -42);
   VerifySimpleAtoiGood<uint32_t>(42, 42);
   VerifySimpleAtoiGood<unsigned int>(42, 42);
   VerifySimpleAtoiGood<int64_t>(-42, -42);
-  VerifySimpleAtoiGood<long>(-42, -42);  // NOLINT(runtime/int)
+  VerifySimpleAtoiGood<long>(-42, -42);  // NOLINT: runtime-int
   VerifySimpleAtoiGood<uint64_t>(42, 42);
   VerifySimpleAtoiGood<size_t>(42, 42);
   VerifySimpleAtoiGood<std::string::size_type>(42, 42);
 }
 
+TEST(NumbersTest, Atod) {
+  double d;
+  EXPECT_TRUE(absl::SimpleAtod("nan", &d));
+  EXPECT_TRUE(std::isnan(d));
+}
+
+TEST(NumbersTest, Prefixes) {
+  double d;
+  EXPECT_FALSE(absl::SimpleAtod("++1", &d));
+  EXPECT_FALSE(absl::SimpleAtod("+-1", &d));
+  EXPECT_FALSE(absl::SimpleAtod("-+1", &d));
+  EXPECT_FALSE(absl::SimpleAtod("--1", &d));
+  EXPECT_TRUE(absl::SimpleAtod("-1", &d));
+  EXPECT_EQ(d, -1.);
+  EXPECT_TRUE(absl::SimpleAtod("+1", &d));
+  EXPECT_EQ(d, +1.);
+
+  float f;
+  EXPECT_FALSE(absl::SimpleAtof("++1", &f));
+  EXPECT_FALSE(absl::SimpleAtof("+-1", &f));
+  EXPECT_FALSE(absl::SimpleAtof("-+1", &f));
+  EXPECT_FALSE(absl::SimpleAtof("--1", &f));
+  EXPECT_TRUE(absl::SimpleAtof("-1", &f));
+  EXPECT_EQ(f, -1.f);
+  EXPECT_TRUE(absl::SimpleAtof("+1", &f));
+  EXPECT_EQ(f, +1.f);
+}
+
 TEST(NumbersTest, Atoenum) {
   enum E01 {
     E01_zero = 0,
@@ -481,7 +537,7 @@
   EXPECT_TRUE(safe_strto32_base(std::string("0x1234"), &value, 16));
   EXPECT_EQ(0x1234, value);
 
-  // Base-10 std::string version.
+  // Base-10 string version.
   EXPECT_TRUE(safe_strto32_base("1234", &value, 10));
   EXPECT_EQ(1234, value);
 }
@@ -622,7 +678,7 @@
   EXPECT_TRUE(safe_strto64_base(std::string("0x1234"), &value, 16));
   EXPECT_EQ(0x1234, value);
 
-  // Base-10 std::string version.
+  // Base-10 string version.
   EXPECT_TRUE(safe_strto64_base("1234", &value, 10));
   EXPECT_EQ(1234, value);
 }
@@ -718,6 +774,51 @@
     EXPECT_FALSE(parse_func(s, &parsed_value, base));
   }
 }
+TEST(stringtest, safe_strto128_random) {
+  // random number generators don't work for int128, and
+  // int128 can be streamed but not StrCat'd, so this code must be custom
+  // implemented for int128, but is generally the same as what's above.
+  // test_random_integer_parse_base<absl::int128>(
+  //     &absl::numbers_internal::safe_strto128_base);
+  using RandomEngine = std::minstd_rand0;
+  using IntType = absl::int128;
+  constexpr auto parse_func = &absl::numbers_internal::safe_strto128_base;
+
+  std::random_device rd;
+  RandomEngine rng(rd());
+  std::uniform_int_distribution<int64_t> random_int64(
+      std::numeric_limits<int64_t>::min());
+  std::uniform_int_distribution<uint64_t> random_uint64(
+      std::numeric_limits<uint64_t>::min());
+  std::uniform_int_distribution<int> random_base(2, 35);
+
+  for (size_t i = 0; i < kNumRandomTests; ++i) {
+    int64_t high = random_int64(rng);
+    uint64_t low = random_uint64(rng);
+    IntType value = absl::MakeInt128(high, low);
+
+    int base = random_base(rng);
+    std::string str_value;
+    EXPECT_TRUE(Itoa<IntType>(value, base, &str_value));
+    IntType parsed_value;
+
+    // Test successful parse
+    EXPECT_TRUE(parse_func(str_value, &parsed_value, base));
+    EXPECT_EQ(parsed_value, value);
+
+    // Test overflow
+    std::string s;
+    absl::strings_internal::OStringStream(&s)
+        << std::numeric_limits<IntType>::max() << value;
+    EXPECT_FALSE(parse_func(s, &parsed_value, base));
+
+    // Test underflow
+    s.clear();
+    absl::strings_internal::OStringStream(&s)
+        << std::numeric_limits<IntType>::min() << value;
+    EXPECT_FALSE(parse_func(s, &parsed_value, base));
+  }
+}
 
 TEST(stringtest, safe_strtou32_base) {
   for (int i = 0; strtouint32_test_cases()[i].str != nullptr; ++i) {
diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc
index d9afe2f..dd5d25b 100644
--- a/absl/strings/str_cat.cc
+++ b/absl/strings/str_cat.cc
@@ -141,12 +141,12 @@
 std::string CatPieces(std::initializer_list<absl::string_view> pieces) {
   std::string result;
   size_t total_size = 0;
-  for (const absl::string_view piece : pieces) total_size += piece.size();
+  for (const absl::string_view& piece : pieces) total_size += piece.size();
   strings_internal::STLStringResizeUninitialized(&result, total_size);
 
   char* const begin = &result[0];
   char* out = begin;
-  for (const absl::string_view piece : pieces) {
+  for (const absl::string_view& piece : pieces) {
     const size_t this_size = piece.size();
     if (this_size != 0) {
       memcpy(out, piece.data(), this_size);
@@ -170,7 +170,7 @@
                   std::initializer_list<absl::string_view> pieces) {
   size_t old_size = dest->size();
   size_t total_size = old_size;
-  for (const absl::string_view piece : pieces) {
+  for (const absl::string_view& piece : pieces) {
     ASSERT_NO_OVERLAP(*dest, piece);
     total_size += piece.size();
   }
@@ -178,7 +178,7 @@
 
   char* const begin = &(*dest)[0];
   char* out = begin + old_size;
-  for (const absl::string_view piece : pieces) {
+  for (const absl::string_view& piece : pieces) {
     const size_t this_size = piece.size();
     if (this_size != 0) {
       memcpy(out, piece.data(), this_size);
diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h
index 292fa23..a8a85c7 100644
--- a/absl/strings/str_cat.h
+++ b/absl/strings/str_cat.h
@@ -253,7 +253,7 @@
       const std::basic_string<char, std::char_traits<char>, Allocator>& str)
       : piece_(str) {}
 
-  // Use std::string literals ":" instead of character literals ':'.
+  // Use string literals ":" instead of character literals ':'.
   AlphaNum(char c) = delete;  // NOLINT(runtime/explicit)
 
   AlphaNum(const AlphaNum&) = delete;
diff --git a/absl/strings/str_cat_benchmark.cc b/absl/strings/str_cat_benchmark.cc
index 14c63b3..02c4dbe 100644
--- a/absl/strings/str_cat_benchmark.cc
+++ b/absl/strings/str_cat_benchmark.cc
@@ -23,7 +23,7 @@
 namespace {
 
 const char kStringOne[] = "Once Upon A Time, ";
-const char kStringTwo[] = "There was a std::string benchmark";
+const char kStringTwo[] = "There was a string benchmark";
 
 // We want to include negative numbers in the benchmark, so this function
 // is used to count 0, 1, -1, 2, -2, 3, -3, ...
@@ -137,4 +137,51 @@
 }
 BENCHMARK(BM_DoubleToString_By_SixDigits);
 
+template <typename... Chunks>
+void BM_StrAppendImpl(benchmark::State& state, size_t total_bytes,
+                      Chunks... chunks) {
+  for (auto s : state) {
+    std::string result;
+    while (result.size() < total_bytes) {
+      absl::StrAppend(&result, chunks...);
+      benchmark::DoNotOptimize(result);
+    }
+  }
+}
+
+void BM_StrAppend(benchmark::State& state) {
+  const int total_bytes = state.range(0);
+  const int chunks_at_a_time = state.range(1);
+  const absl::string_view kChunk = "0123456789";
+
+  switch (chunks_at_a_time) {
+    case 1:
+      return BM_StrAppendImpl(state, total_bytes, kChunk);
+    case 2:
+      return BM_StrAppendImpl(state, total_bytes, kChunk, kChunk);
+    case 4:
+      return BM_StrAppendImpl(state, total_bytes, kChunk, kChunk, kChunk,
+                              kChunk);
+    case 8:
+      return BM_StrAppendImpl(state, total_bytes, kChunk, kChunk, kChunk,
+                              kChunk, kChunk, kChunk, kChunk, kChunk);
+    default:
+      std::abort();
+  }
+}
+
+template <typename B>
+void StrAppendConfig(B* benchmark) {
+  for (int bytes : {10, 100, 1000, 10000}) {
+    for (int chunks : {1, 2, 4, 8}) {
+      // Only add the ones that divide properly. Otherwise we are over counting.
+      if (bytes % (10 * chunks) == 0) {
+        benchmark->Args({bytes, chunks});
+      }
+    }
+  }
+}
+
+BENCHMARK(BM_StrAppend)->Apply(StrAppendConfig);
+
 }  // namespace
diff --git a/absl/strings/str_cat_test.cc b/absl/strings/str_cat_test.cc
index be39880..f3770dc 100644
--- a/absl/strings/str_cat_test.cc
+++ b/absl/strings/str_cat_test.cc
@@ -162,7 +162,7 @@
   EXPECT_EQ(result, "12345678910, 10987654321!");
 
   std::string one =
-      "1";  // Actually, it's the size of this std::string that we want; a
+      "1";  // Actually, it's the size of this string that we want; a
             // 64-bit build distinguishes between size_t and uint64_t,
             // even though they're both unsigned 64-bit values.
   result = absl::StrCat("And a ", one.size(), " and a ",
@@ -375,7 +375,7 @@
   EXPECT_EQ(result.substr(old_size), "12345678910, 10987654321!");
 
   std::string one =
-      "1";  // Actually, it's the size of this std::string that we want; a
+      "1";  // Actually, it's the size of this string that we want; a
             // 64-bit build distinguishes between size_t and uint64_t,
             // even though they're both unsigned 64-bit values.
   old_size = result.size();
@@ -463,7 +463,7 @@
 }
 
 TEST(StrAppend, CornerCasesNonEmptyAppend) {
-  for (std::string result : {"hello", "a std::string too long to fit in the SSO"}) {
+  for (std::string result : {"hello", "a string too long to fit in the SSO"}) {
     const std::string expected = result;
     absl::StrAppend(&result, "");
     EXPECT_EQ(result, expected);
diff --git a/absl/strings/str_format.h b/absl/strings/str_format.h
index 2f9b4b2..0146510 100644
--- a/absl/strings/str_format.h
+++ b/absl/strings/str_format.h
@@ -19,7 +19,7 @@
 //
 // The `str_format` library is a typesafe replacement for the family of
 // `printf()` string formatting routines within the `<cstdio>` standard library
-// header. Like the `printf` family, the `str_format` uses a "format string" to
+// header. Like the `printf` family, `str_format` uses a "format string" to
 // perform argument substitutions based on types. See the `FormatSpec` section
 // below for format string documentation.
 //
@@ -57,8 +57,7 @@
 // arbitrary sink types:
 //
 //   * A generic `Format()` function to write outputs to arbitrary sink types,
-//     which must implement a `RawSinkFormat` interface. (See
-//     `str_format_sink.h` for more information.)
+//     which must implement a `FormatRawSink` interface.
 //
 //   * A `FormatUntyped()` function that is similar to `Format()` except it is
 //     loosely typed. `FormatUntyped()` is not a template and does not perform
@@ -66,8 +65,7 @@
 //     boolean from a runtime check.
 //
 // In addition, the `str_format` library provides extension points for
-// augmenting formatting to new types. These extensions are fully documented
-// within the `str_format_extension.h` header file.
+// augmenting formatting to new types.  See "StrFormat Extensions" below.
 
 #ifndef ABSL_STRINGS_STR_FORMAT_H_
 #define ABSL_STRINGS_STR_FORMAT_H_
@@ -255,8 +253,8 @@
 // argument, etc.
 
 template <typename... Args>
-using FormatSpec =
-    typename str_format_internal::FormatSpecDeductionBarrier<Args...>::type;
+using FormatSpec = str_format_internal::FormatSpecTemplate<
+    str_format_internal::ArgumentToConv<Args>()...>;
 
 // ParsedFormat
 //
@@ -283,9 +281,36 @@
 //   } else {
 //     ... error case ...
 //   }
+
+#if defined(__cpp_nontype_template_parameter_auto)
+// If C++17 is available, an 'extended' format is also allowed that can specify
+// multiple conversion characters per format argument, using a combination of
+// `absl::FormatConversionCharSet` enum values (logically a set union)
+//  via the `|` operator. (Single character-based arguments are still accepted,
+// but cannot be combined). Some common conversions also have predefined enum
+// values, such as `absl::FormatConversionCharSet::kIntegral`.
+//
+// Example:
+//   // Extended format supports multiple conversion characters per argument,
+//   // specified via a combination of `FormatConversionCharSet` enums.
+//   using MyFormat = absl::ParsedFormat<absl::FormatConversionCharSet::d |
+//                                       absl::FormatConversionCharSet::x>;
+//   MyFormat GetFormat(bool use_hex) {
+//     if (use_hex) return MyFormat("foo %x bar");
+//     return MyFormat("foo %d bar");
+//   }
+//   // `format` can be used with any value that supports 'd' and 'x',
+//   // like `int`.
+//   auto format = GetFormat(use_hex);
+//   value = StringF(format, i);
+template <auto... Conv>
+using ParsedFormat = absl::str_format_internal::ExtendedParsedFormat<
+    absl::str_format_internal::ToFormatConversionCharSet(Conv)...>;
+#else
 template <char... Conv>
 using ParsedFormat = str_format_internal::ExtendedParsedFormat<
-    str_format_internal::ConversionCharToConv(Conv)...>;
+    absl::str_format_internal::ToFormatConversionCharSet(Conv)...>;
+#endif  // defined(__cpp_nontype_template_parameter_auto)
 
 // StrFormat()
 //
@@ -432,6 +457,16 @@
 //
 // FormatRawSink is a type erased wrapper around arbitrary sink objects
 // specifically used as an argument to `Format()`.
+//
+// All the object has to do define an overload of `AbslFormatFlush()` for the
+// sink, usually by adding a ADL-based free function in the same namespace as
+// the sink:
+//
+//   void AbslFormatFlush(MySink* dest, absl::string_view part);
+//
+// where `dest` is the pointer passed to `absl::Format()`. The function should
+// append `part` to `dest`.
+//
 // FormatRawSink does not own the passed sink object. The passed object must
 // outlive the FormatRawSink.
 class FormatRawSink {
@@ -455,12 +490,13 @@
 // `absl::FormatRawSink` interface), using a format string and zero or more
 // additional arguments.
 //
-// By default, `std::string` and `std::ostream` are supported as destination
-// objects. If a `std::string` is used the formatted string is appended to it.
+// By default, `std::string`, `std::ostream`, and `absl::Cord` are supported as
+// destination objects. If a `std::string` is used the formatted string is
+// appended to it.
 //
-// `absl::Format()` is a generic version of `absl::StrFormat(), for custom
-// sinks. The format string, like format strings for `StrFormat()`, is checked
-// at compile-time.
+// `absl::Format()` is a generic version of `absl::StrAppendFormat()`, for
+// custom sinks. The format string, like format strings for `StrFormat()`, is
+// checked at compile-time.
 //
 // On failure, this function returns `false` and the state of the sink is
 // unspecified.
@@ -531,6 +567,246 @@
       str_format_internal::UntypedFormatSpecImpl::Extract(format), args);
 }
 
+//------------------------------------------------------------------------------
+// StrFormat Extensions
+//------------------------------------------------------------------------------
+//
+// AbslFormatConvert()
+//
+// The StrFormat library provides a customization API for formatting
+// user-defined types using absl::StrFormat(). The API relies on detecting an
+// overload in the user-defined type's namespace of a free (non-member)
+// `AbslFormatConvert()` function, usually as a friend definition with the
+// following signature:
+//
+// absl::FormatConvertResult<...> AbslFormatConvert(
+//     const X& value,
+//     const absl::FormatConversionSpec& spec,
+//     absl::FormatSink *sink);
+//
+// An `AbslFormatConvert()` overload for a type should only be declared in the
+// same file and namespace as said type.
+//
+// The abstractions within this definition include:
+//
+// * An `absl::FormatConversionSpec` to specify the fields to pull from a
+//   user-defined type's format string
+// * An `absl::FormatSink` to hold the converted string data during the
+//   conversion process.
+// * An `absl::FormatConvertResult` to hold the status of the returned
+//   formatting operation
+//
+// The return type encodes all the conversion characters that your
+// AbslFormatConvert() routine accepts.  The return value should be {true}.
+// A return value of {false} will result in `StrFormat()` returning
+// an empty string.  This result will be propagated to the result of
+// `FormatUntyped`.
+//
+// Example:
+//
+// struct Point {
+//   // To add formatting support to `Point`, we simply need to add a free
+//   // (non-member) function `AbslFormatConvert()`.  This method interprets
+//   // `spec` to print in the request format. The allowed conversion characters
+//   // can be restricted via the type of the result, in this example
+//   // string and integral formatting are allowed (but not, for instance
+//   // floating point characters like "%f").  You can add such a free function
+//   // using a friend declaration within the body of the class:
+//   friend absl::FormatConvertResult<absl::FormatConversionCharSet::kString |
+//                                    absl::FormatConversionCharSet::kIntegral>
+//   AbslFormatConvert(const Point& p, const absl::FormatConversionSpec& spec,
+//                     absl::FormatSink* s) {
+//     if (spec.conversion_char() == absl::FormatConversionChar::s) {
+//       s->Append(absl::StrCat("x=", p.x, " y=", p.y));
+//     } else {
+//       s->Append(absl::StrCat(p.x, ",", p.y));
+//     }
+//     return {true};
+//   }
+//
+//   int x;
+//   int y;
+// };
+
+// clang-format off
+
+// FormatConversionChar
+//
+// Specifies the formatting character provided in the format string
+// passed to `StrFormat()`.
+enum class FormatConversionChar : uint8_t {
+  c, s,                    // text
+  d, i, o, u, x, X,        // int
+  f, F, e, E, g, G, a, A,  // float
+  n, p                     // misc
+};
+// clang-format on
+
+// FormatConversionSpec
+//
+// Specifies modifications to the conversion of the format string, through use
+// of one or more format flags in the source format string.
+class FormatConversionSpec {
+ public:
+  // FormatConversionSpec::is_basic()
+  //
+  // Indicates that width and precision are not specified, and no additional
+  // flags are set for this conversion character in the format string.
+  bool is_basic() const { return impl_.is_basic(); }
+
+  // FormatConversionSpec::has_left_flag()
+  //
+  // Indicates whether the result should be left justified for this conversion
+  // character in the format string. This flag is set through use of a '-'
+  // character in the format string. E.g. "%-s"
+  bool has_left_flag() const { return impl_.has_left_flag(); }
+
+  // FormatConversionSpec::has_show_pos_flag()
+  //
+  // Indicates whether a sign column is prepended to the result for this
+  // conversion character in the format string, even if the result is positive.
+  // This flag is set through use of a '+' character in the format string.
+  // E.g. "%+d"
+  bool has_show_pos_flag() const { return impl_.has_show_pos_flag(); }
+
+  // FormatConversionSpec::has_sign_col_flag()
+  //
+  // Indicates whether a mandatory sign column is added to the result for this
+  // conversion character. This flag is set through use of a space character
+  // (' ') in the format string. E.g. "% i"
+  bool has_sign_col_flag() const { return impl_.has_sign_col_flag(); }
+
+  // FormatConversionSpec::has_alt_flag()
+  //
+  // Indicates whether an "alternate" format is applied to the result for this
+  // conversion character. Alternative forms depend on the type of conversion
+  // character, and unallowed alternatives are undefined. This flag is set
+  // through use of a '#' character in the format string. E.g. "%#h"
+  bool has_alt_flag() const { return impl_.has_alt_flag(); }
+
+  // FormatConversionSpec::has_zero_flag()
+  //
+  // Indicates whether zeroes should be prepended to the result for this
+  // conversion character instead of spaces. This flag is set through use of the
+  // '0' character in the format string. E.g. "%0f"
+  bool has_zero_flag() const { return impl_.has_zero_flag(); }
+
+  // FormatConversionSpec::conversion_char()
+  //
+  // Returns the underlying conversion character.
+  FormatConversionChar conversion_char() const {
+    return impl_.conversion_char();
+  }
+
+  // FormatConversionSpec::width()
+  //
+  // Returns the specified width (indicated through use of a non-zero integer
+  // value or '*' character) of the conversion character. If width is
+  // unspecified, it returns a negative value.
+  int width() const { return impl_.width(); }
+
+  // FormatConversionSpec::precision()
+  //
+  // Returns the specified precision (through use of the '.' character followed
+  // by a non-zero integer value or '*' character) of the conversion character.
+  // If precision is unspecified, it returns a negative value.
+  int precision() const { return impl_.precision(); }
+
+ private:
+  explicit FormatConversionSpec(
+      str_format_internal::FormatConversionSpecImpl impl)
+      : impl_(impl) {}
+
+  friend str_format_internal::FormatConversionSpecImpl;
+
+  absl::str_format_internal::FormatConversionSpecImpl impl_;
+};
+
+// Type safe OR operator for FormatConversionCharSet to allow accepting multiple
+// conversion chars in custom format converters.
+constexpr FormatConversionCharSet operator|(FormatConversionCharSet a,
+                                            FormatConversionCharSet b) {
+  return static_cast<FormatConversionCharSet>(static_cast<uint64_t>(a) |
+                                              static_cast<uint64_t>(b));
+}
+
+// FormatConversionCharSet
+//
+// Specifies the _accepted_ conversion types as a template parameter to
+// FormatConvertResult for custom implementations of `AbslFormatConvert`.
+// Note the helper predefined alias definitions (kIntegral, etc.) below.
+enum class FormatConversionCharSet : uint64_t {
+  // text
+  c = str_format_internal::FormatConversionCharToConvInt('c'),
+  s = str_format_internal::FormatConversionCharToConvInt('s'),
+  // integer
+  d = str_format_internal::FormatConversionCharToConvInt('d'),
+  i = str_format_internal::FormatConversionCharToConvInt('i'),
+  o = str_format_internal::FormatConversionCharToConvInt('o'),
+  u = str_format_internal::FormatConversionCharToConvInt('u'),
+  x = str_format_internal::FormatConversionCharToConvInt('x'),
+  X = str_format_internal::FormatConversionCharToConvInt('X'),
+  // Float
+  f = str_format_internal::FormatConversionCharToConvInt('f'),
+  F = str_format_internal::FormatConversionCharToConvInt('F'),
+  e = str_format_internal::FormatConversionCharToConvInt('e'),
+  E = str_format_internal::FormatConversionCharToConvInt('E'),
+  g = str_format_internal::FormatConversionCharToConvInt('g'),
+  G = str_format_internal::FormatConversionCharToConvInt('G'),
+  a = str_format_internal::FormatConversionCharToConvInt('a'),
+  A = str_format_internal::FormatConversionCharToConvInt('A'),
+  // misc
+  n = str_format_internal::FormatConversionCharToConvInt('n'),
+  p = str_format_internal::FormatConversionCharToConvInt('p'),
+
+  // Used for width/precision '*' specification.
+  kStar = static_cast<uint64_t>(
+      absl::str_format_internal::FormatConversionCharSetInternal::kStar),
+  // Some predefined values:
+  kIntegral = d | i | u | o | x | X,
+  kFloating = a | e | f | g | A | E | F | G,
+  kNumeric = kIntegral | kFloating,
+  kString = s,
+  kPointer = p,
+};
+
+// FormatSink
+//
+// An abstraction to which conversions write their string data.
+//
+class FormatSink {
+ public:
+  // Appends `count` copies of `ch`.
+  void Append(size_t count, char ch) { sink_->Append(count, ch); }
+
+  void Append(string_view v) { sink_->Append(v); }
+
+  // Appends the first `precision` bytes of `v`. If this is less than
+  // `width`, spaces will be appended first (if `left` is false), or
+  // after (if `left` is true) to ensure the total amount appended is
+  // at least `width`.
+  bool PutPaddedString(string_view v, int width, int precision, bool left) {
+    return sink_->PutPaddedString(v, width, precision, left);
+  }
+
+ private:
+  friend str_format_internal::FormatSinkImpl;
+  explicit FormatSink(str_format_internal::FormatSinkImpl* s) : sink_(s) {}
+  str_format_internal::FormatSinkImpl* sink_;
+};
+
+// FormatConvertResult
+//
+// Indicates whether a call to AbslFormatConvert() was successful.
+// This return type informs the StrFormat extension framework (through
+// ADL but using the return type) of what conversion characters are supported.
+// It is strongly discouraged to return {false}, as this will result in an
+// empty string in StrFormat.
+template <FormatConversionCharSet C>
+struct FormatConvertResult {
+  bool value;
+};
+
 ABSL_NAMESPACE_END
 }  // namespace absl
 
diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc
index acbdbf4..c60027a 100644
--- a/absl/strings/str_format_test.cc
+++ b/absl/strings/str_format_test.cc
@@ -1,3 +1,18 @@
+// 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/strings/str_format.h"
 
 #include <cstdarg>
 #include <cstdint>
@@ -6,7 +21,8 @@
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
-#include "absl/strings/str_format.h"
+#include "absl/strings/cord.h"
+#include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
 
 namespace absl {
@@ -242,7 +258,7 @@
 
   std::FILE* file() const { return file_; }
 
-  // Read the file into a std::string.
+  // Read the file into a string.
   std::string ReadFile() {
     std::fseek(file_, 0, SEEK_END);
     int size = std::ftell(file_);
@@ -345,11 +361,12 @@
   EXPECT_EQ(StrFormat("%c", int{'a'}), "a");
   EXPECT_EQ(StrFormat("%c", long{'a'}), "a");  // NOLINT
   EXPECT_EQ(StrFormat("%c", uint64_t{'a'}), "a");
-  //     "s" - std::string       Eg: "C" -> "C", std::string("C++") -> "C++"
+  //     "s" - string       Eg: "C" -> "C", std::string("C++") -> "C++"
   //           Formats std::string, char*, string_view, and Cord.
   EXPECT_EQ(StrFormat("%s", "C"), "C");
   EXPECT_EQ(StrFormat("%s", std::string("C++")), "C++");
   EXPECT_EQ(StrFormat("%s", string_view("view")), "view");
+  EXPECT_EQ(StrFormat("%s", absl::Cord("cord")), "cord");
   // Integral Conversion
   //     These format integral types: char, int, long, uint64_t, etc.
   EXPECT_EQ(StrFormat("%d", char{10}), "10");
@@ -450,7 +467,7 @@
     if (conv.precision.is_from_arg()) {
       *out += "." + std::to_string(conv.precision.get_from_arg()) + "$*";
     }
-    *out += FormatConversionCharToChar(conv.conv);
+    *out += str_format_internal::FormatConversionCharToChar(conv.conv);
     *out += "}";
     return true;
   }
@@ -532,76 +549,152 @@
   EXPECT_FALSE((ParsedFormat<'s', 'd', 'g'>::New(format)));
 }
 
-using str_format_internal::Conv;
+#if defined(__cpp_nontype_template_parameter_auto)
+
+template <auto T>
+std::true_type IsValidParsedFormatArgTest(ParsedFormat<T>*);
+
+template <auto T>
+std::false_type IsValidParsedFormatArgTest(...);
+
+template <auto T>
+using IsValidParsedFormatArg = decltype(IsValidParsedFormatArgTest<T>(nullptr));
+
+TEST_F(ParsedFormatTest, OnlyValidTypesAllowed) {
+  ASSERT_TRUE(IsValidParsedFormatArg<'c'>::value);
+
+  ASSERT_TRUE(IsValidParsedFormatArg<FormatConversionCharSet::d>::value);
+
+  ASSERT_TRUE(IsValidParsedFormatArg<absl::FormatConversionCharSet::d |
+                                     absl::FormatConversionCharSet::x>::value);
+  ASSERT_TRUE(
+      IsValidParsedFormatArg<absl::FormatConversionCharSet::kIntegral>::value);
+
+  // This is an easy mistake to make, however, this will reduce to an integer
+  // which has no meaning, so we need to ensure it doesn't compile.
+  ASSERT_FALSE(IsValidParsedFormatArg<'x' | 'd'>::value);
+
+  // For now, we disallow construction based on ConversionChar (rather than
+  // CharSet)
+  ASSERT_FALSE(IsValidParsedFormatArg<absl::FormatConversionChar::d>::value);
+}
+
+TEST_F(ParsedFormatTest, ExtendedTyping) {
+  EXPECT_FALSE(ParsedFormat<FormatConversionCharSet::d>::New(""));
+  ASSERT_TRUE(ParsedFormat<absl::FormatConversionCharSet::d>::New("%d"));
+  auto v1 = ParsedFormat<'d', absl::FormatConversionCharSet::s>::New("%d%s");
+  ASSERT_TRUE(v1);
+  auto v2 = ParsedFormat<absl::FormatConversionCharSet::d, 's'>::New("%d%s");
+  ASSERT_TRUE(v2);
+  auto v3 = ParsedFormat<absl::FormatConversionCharSet::d |
+                             absl::FormatConversionCharSet::s,
+                         's'>::New("%d%s");
+  ASSERT_TRUE(v3);
+  auto v4 = ParsedFormat<absl::FormatConversionCharSet::d |
+                             absl::FormatConversionCharSet::s,
+                         's'>::New("%s%s");
+  ASSERT_TRUE(v4);
+}
+#endif
 
 TEST_F(ParsedFormatTest, UncheckedCorrect) {
-  auto f = ExtendedParsedFormat<Conv::d>::New("ABC%dDEF");
+  auto f =
+      ExtendedParsedFormat<absl::FormatConversionCharSet::d>::New("ABC%dDEF");
   ASSERT_TRUE(f);
   EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f));
 
   std::string format = "%sFFF%dZZZ%f";
-  auto f2 =
-      ExtendedParsedFormat<Conv::string, Conv::d, Conv::floating>::New(format);
+  auto f2 = ExtendedParsedFormat<
+      absl::FormatConversionCharSet::kString, absl::FormatConversionCharSet::d,
+      absl::FormatConversionCharSet::kFloating>::New(format);
 
   ASSERT_TRUE(f2);
   EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
 
-  f2 = ExtendedParsedFormat<Conv::string, Conv::d, Conv::floating>::New(
-      "%s %d %f");
+  f2 = ExtendedParsedFormat<
+      absl::FormatConversionCharSet::kString, absl::FormatConversionCharSet::d,
+      absl::FormatConversionCharSet::kFloating>::New("%s %d %f");
 
   ASSERT_TRUE(f2);
   EXPECT_EQ("{s:1$s}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
 
-  auto star = ExtendedParsedFormat<Conv::star, Conv::d>::New("%*d");
+  auto star =
+      ExtendedParsedFormat<absl::FormatConversionCharSet::kStar,
+                           absl::FormatConversionCharSet::d>::New("%*d");
   ASSERT_TRUE(star);
   EXPECT_EQ("{*d:2$1$*d}", SummarizeParsedFormat(*star));
 
-  auto dollar = ExtendedParsedFormat<Conv::d, Conv::s>::New("%2$s %1$d");
+  auto dollar =
+      ExtendedParsedFormat<absl::FormatConversionCharSet::d,
+                           absl::FormatConversionCharSet::s>::New("%2$s %1$d");
   ASSERT_TRUE(dollar);
   EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}", SummarizeParsedFormat(*dollar));
   // with reuse
-  dollar = ExtendedParsedFormat<Conv::d, Conv::s>::New("%2$s %1$d %1$d");
+  dollar = ExtendedParsedFormat<
+      absl::FormatConversionCharSet::d,
+      absl::FormatConversionCharSet::s>::New("%2$s %1$d %1$d");
   ASSERT_TRUE(dollar);
   EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}[ ]{1$d:1$d}",
             SummarizeParsedFormat(*dollar));
 }
 
 TEST_F(ParsedFormatTest, UncheckedIgnoredArgs) {
-  EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("ABC")));
-  EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("%dABC")));
-  EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("ABC%2$s")));
-  auto f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("ABC");
+  EXPECT_FALSE(
+      (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
+                            absl::FormatConversionCharSet::s>::New("ABC")));
+  EXPECT_FALSE(
+      (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
+                            absl::FormatConversionCharSet::s>::New("%dABC")));
+  EXPECT_FALSE(
+      (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
+                            absl::FormatConversionCharSet::s>::New("ABC%2$s")));
+  auto f = ExtendedParsedFormat<
+      absl::FormatConversionCharSet::d,
+      absl::FormatConversionCharSet::s>::NewAllowIgnored("ABC");
   ASSERT_TRUE(f);
   EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
-  f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("%dABC");
+  f = ExtendedParsedFormat<
+      absl::FormatConversionCharSet::d,
+      absl::FormatConversionCharSet::s>::NewAllowIgnored("%dABC");
   ASSERT_TRUE(f);
   EXPECT_EQ("{d:1$d}[ABC]", SummarizeParsedFormat(*f));
-  f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("ABC%2$s");
+  f = ExtendedParsedFormat<
+      absl::FormatConversionCharSet::d,
+      absl::FormatConversionCharSet::s>::NewAllowIgnored("ABC%2$s");
   ASSERT_TRUE(f);
   EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f));
 }
 
 TEST_F(ParsedFormatTest, UncheckedMultipleTypes) {
-  auto dx = ExtendedParsedFormat<Conv::d | Conv::x>::New("%1$d %1$x");
+  auto dx =
+      ExtendedParsedFormat<absl::FormatConversionCharSet::d |
+                           absl::FormatConversionCharSet::x>::New("%1$d %1$x");
   EXPECT_TRUE(dx);
   EXPECT_EQ("{1$d:1$d}[ ]{1$x:1$x}", SummarizeParsedFormat(*dx));
 
-  dx = ExtendedParsedFormat<Conv::d | Conv::x>::New("%1$d");
+  dx = ExtendedParsedFormat<absl::FormatConversionCharSet::d |
+                            absl::FormatConversionCharSet::x>::New("%1$d");
   EXPECT_TRUE(dx);
   EXPECT_EQ("{1$d:1$d}", SummarizeParsedFormat(*dx));
 }
 
 TEST_F(ParsedFormatTest, UncheckedIncorrect) {
-  EXPECT_FALSE(ExtendedParsedFormat<Conv::d>::New(""));
+  EXPECT_FALSE(ExtendedParsedFormat<absl::FormatConversionCharSet::d>::New(""));
 
-  EXPECT_FALSE(ExtendedParsedFormat<Conv::d>::New("ABC%dDEF%d"));
+  EXPECT_FALSE(ExtendedParsedFormat<absl::FormatConversionCharSet::d>::New(
+      "ABC%dDEF%d"));
 
   std::string format = "%sFFF%dZZZ%f";
-  EXPECT_FALSE((ExtendedParsedFormat<Conv::s, Conv::d, Conv::g>::New(format)));
+  EXPECT_FALSE(
+      (ExtendedParsedFormat<absl::FormatConversionCharSet::s,
+                            absl::FormatConversionCharSet::d,
+                            absl::FormatConversionCharSet::g>::New(format)));
 }
 
 TEST_F(ParsedFormatTest, RegressionMixPositional) {
-  EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::o>::New("%1$d %o")));
+  EXPECT_FALSE(
+      (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
+                            absl::FormatConversionCharSet::o>::New("%1$d %o")));
 }
 
 using FormatWrapperTest = ::testing::Test;
@@ -626,6 +719,38 @@
 ABSL_NAMESPACE_END
 }  // namespace absl
 
+using FormatExtensionTest = ::testing::Test;
+
+struct Point {
+  friend absl::FormatConvertResult<absl::FormatConversionCharSet::kString |
+                                   absl::FormatConversionCharSet::kIntegral>
+  AbslFormatConvert(const Point& p, const absl::FormatConversionSpec& spec,
+                    absl::FormatSink* s) {
+    if (spec.conversion_char() == absl::FormatConversionChar::s) {
+      s->Append(absl::StrCat("x=", p.x, " y=", p.y));
+    } else {
+      s->Append(absl::StrCat(p.x, ",", p.y));
+    }
+    return {true};
+  }
+
+  int x = 10;
+  int y = 20;
+};
+
+TEST_F(FormatExtensionTest, AbslFormatConvertExample) {
+  Point p;
+  EXPECT_EQ(absl::StrFormat("a %s z", p), "a x=10 y=20 z");
+  EXPECT_EQ(absl::StrFormat("a %d z", p), "a 10,20 z");
+
+  // Typed formatting will fail to compile an invalid format.
+  // StrFormat("%f", p);  // Does not compile.
+  std::string actual;
+  absl::UntypedFormatSpec f1("%f");
+  // FormatUntyped will return false for bad character.
+  EXPECT_FALSE(absl::FormatUntyped(&actual, f1, {absl::FormatArg(p)}));
+}
+
 // Some codegen thunks that we can use to easily dump the generated assembly for
 // different StrFormat calls.
 
diff --git a/absl/strings/str_join.h b/absl/strings/str_join.h
index ae5731a..3353453 100644
--- a/absl/strings/str_join.h
+++ b/absl/strings/str_join.h
@@ -144,7 +144,7 @@
       std::forward<Formatter>(f));
 }
 
-// Function overload of `DererefenceFormatter()` for using a default
+// Function overload of `DereferenceFormatter()` for using a default
 // `AlphaNumFormatter()`.
 inline strings_internal::DereferenceFormatterImpl<
     strings_internal::AlphaNumFormatterImpl>
diff --git a/absl/strings/str_join_test.cc b/absl/strings/str_join_test.cc
index 921d9c2..2be6256 100644
--- a/absl/strings/str_join_test.cc
+++ b/absl/strings/str_join_test.cc
@@ -134,26 +134,26 @@
   //
 
   {
-    // Empty range yields an empty std::string.
+    // Empty range yields an empty string.
     std::vector<std::string> v;
     EXPECT_EQ("", absl::StrJoin(v, "-"));
   }
 
   {
-    // A range of 1 element gives a std::string with that element but no
+    // A range of 1 element gives a string with that element but no
     // separator.
     std::vector<std::string> v = {"foo"};
     EXPECT_EQ("foo", absl::StrJoin(v, "-"));
   }
 
   {
-    // A range with a single empty std::string element
+    // A range with a single empty string element
     std::vector<std::string> v = {""};
     EXPECT_EQ("", absl::StrJoin(v, "-"));
   }
 
   {
-    // A range with 2 elements, one of which is an empty std::string
+    // A range with 2 elements, one of which is an empty string
     std::vector<std::string> v = {"a", ""};
     EXPECT_EQ("a-", absl::StrJoin(v, "-"));
   }
diff --git a/absl/strings/str_replace_benchmark.cc b/absl/strings/str_replace_benchmark.cc
index 95b2dc1..01331da 100644
--- a/absl/strings/str_replace_benchmark.cc
+++ b/absl/strings/str_replace_benchmark.cc
@@ -62,7 +62,7 @@
       }
     }
     // big_string->resize(50);
-    // OK, we've set up the std::string, now let's set up expectations - first by
+    // OK, we've set up the string, now let's set up expectations - first by
     // just replacing "the" with "box"
     after_replacing_the = new std::string(*big_string);
     for (size_t pos = 0;
diff --git a/absl/strings/str_replace_test.cc b/absl/strings/str_replace_test.cc
index 1ca23af..9d8c7f7 100644
--- a/absl/strings/str_replace_test.cc
+++ b/absl/strings/str_replace_test.cc
@@ -25,7 +25,7 @@
 TEST(StrReplaceAll, OneReplacement) {
   std::string s;
 
-  // Empty std::string.
+  // Empty string.
   s = absl::StrReplaceAll(s, {{"", ""}});
   EXPECT_EQ(s, "");
   s = absl::StrReplaceAll(s, {{"x", ""}});
@@ -47,7 +47,7 @@
   s = absl::StrReplaceAll("abc", {{"xyz", "123"}});
   EXPECT_EQ(s, "abc");
 
-  // Replace entire std::string.
+  // Replace entire string.
   s = absl::StrReplaceAll("abc", {{"abc", "xyz"}});
   EXPECT_EQ(s, "xyz");
 
@@ -88,7 +88,7 @@
 TEST(StrReplaceAll, ManyReplacements) {
   std::string s;
 
-  // Empty std::string.
+  // Empty string.
   s = absl::StrReplaceAll("", {{"", ""}, {"x", ""}, {"", "y"}, {"x", "y"}});
   EXPECT_EQ(s, "");
 
@@ -96,7 +96,7 @@
   s = absl::StrReplaceAll("abc", {{"", ""}, {"", "y"}, {"x", ""}});
   EXPECT_EQ(s, "abc");
 
-  // Replace entire std::string, one char at a time
+  // Replace entire string, one char at a time
   s = absl::StrReplaceAll("abc", {{"a", "x"}, {"b", "y"}, {"c", "z"}});
   EXPECT_EQ(s, "xyz");
   s = absl::StrReplaceAll("zxy", {{"z", "x"}, {"x", "y"}, {"y", "z"}});
@@ -264,7 +264,7 @@
   std::string s;
   int reps;
 
-  // Empty std::string.
+  // Empty string.
   s = "";
   reps = absl::StrReplaceAll({{"", ""}, {"x", ""}, {"", "y"}, {"x", "y"}}, &s);
   EXPECT_EQ(reps, 0);
@@ -276,7 +276,7 @@
   EXPECT_EQ(reps, 0);
   EXPECT_EQ(s, "abc");
 
-  // Replace entire std::string, one char at a time
+  // Replace entire string, one char at a time
   s = "abc";
   reps = absl::StrReplaceAll({{"a", "x"}, {"b", "y"}, {"c", "z"}}, &s);
   EXPECT_EQ(reps, 3);
diff --git a/absl/strings/str_split.cc b/absl/strings/str_split.cc
index d0f8666..e08c26b 100644
--- a/absl/strings/str_split.cc
+++ b/absl/strings/str_split.cc
@@ -42,7 +42,7 @@
                               absl::string_view delimiter, size_t pos,
                               FindPolicy find_policy) {
   if (delimiter.empty() && text.length() > 0) {
-    // Special case for empty std::string delimiters: always return a zero-length
+    // Special case for empty string delimiters: always return a zero-length
     // absl::string_view referring to the item at position 1 past pos.
     return absl::string_view(text.data() + pos + 1, 0);
   }
@@ -127,7 +127,7 @@
                                       size_t pos) const {
   pos = std::min(pos, text.size());  // truncate `pos`
   absl::string_view substr = text.substr(pos);
-  // If the std::string is shorter than the chunk size we say we
+  // If the string is shorter than the chunk size we say we
   // "can't find the delimiter" so this will be the last chunk.
   if (substr.length() <= static_cast<size_t>(length_))
     return absl::string_view(text.data() + text.size(), 0);
diff --git a/absl/strings/str_split.h b/absl/strings/str_split.h
index a79cd4a..bfbca42 100644
--- a/absl/strings/str_split.h
+++ b/absl/strings/str_split.h
@@ -44,6 +44,7 @@
 #include <vector>
 
 #include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
 #include "absl/strings/internal/str_split_internal.h"
 #include "absl/strings/string_view.h"
 #include "absl/strings/strip.h"
@@ -368,6 +369,12 @@
   }
 };
 
+template <typename T>
+using EnableSplitIfString =
+    typename std::enable_if<std::is_same<T, std::string>::value ||
+                            std::is_same<T, const std::string>::value,
+                            int>::type;
+
 //------------------------------------------------------------------------------
 //                                  StrSplit()
 //------------------------------------------------------------------------------
@@ -488,22 +495,50 @@
 // Try not to depend on this distinction because the bug may one day be fixed.
 template <typename Delimiter>
 strings_internal::Splitter<
-    typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty>
+    typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty,
+    absl::string_view>
 StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d) {
   using DelimiterType =
       typename strings_internal::SelectDelimiter<Delimiter>::type;
-  return strings_internal::Splitter<DelimiterType, AllowEmpty>(
+  return strings_internal::Splitter<DelimiterType, AllowEmpty,
+                                    absl::string_view>(
+      text.value(), DelimiterType(d), AllowEmpty());
+}
+
+template <typename Delimiter, typename StringType,
+          EnableSplitIfString<StringType> = 0>
+strings_internal::Splitter<
+    typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty,
+    std::string>
+StrSplit(StringType&& text, Delimiter d) {
+  using DelimiterType =
+      typename strings_internal::SelectDelimiter<Delimiter>::type;
+  return strings_internal::Splitter<DelimiterType, AllowEmpty, std::string>(
       std::move(text), DelimiterType(d), AllowEmpty());
 }
 
 template <typename Delimiter, typename Predicate>
 strings_internal::Splitter<
-    typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate>
+    typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate,
+    absl::string_view>
 StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d,
          Predicate p) {
   using DelimiterType =
       typename strings_internal::SelectDelimiter<Delimiter>::type;
-  return strings_internal::Splitter<DelimiterType, Predicate>(
+  return strings_internal::Splitter<DelimiterType, Predicate,
+                                    absl::string_view>(
+      text.value(), DelimiterType(d), std::move(p));
+}
+
+template <typename Delimiter, typename Predicate, typename StringType,
+          EnableSplitIfString<StringType> = 0>
+strings_internal::Splitter<
+    typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate,
+    std::string>
+StrSplit(StringType&& text, Delimiter d, Predicate p) {
+  using DelimiterType =
+      typename strings_internal::SelectDelimiter<Delimiter>::type;
+  return strings_internal::Splitter<DelimiterType, Predicate, std::string>(
       std::move(text), DelimiterType(d), std::move(p));
 }
 
diff --git a/absl/strings/str_split_test.cc b/absl/strings/str_split_test.cc
index 02f27bc..7f7c097 100644
--- a/absl/strings/str_split_test.cc
+++ b/absl/strings/str_split_test.cc
@@ -27,8 +27,10 @@
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
-#include "absl/base/dynamic_annotations.h"  // for RunningOnValgrind
+#include "absl/base/dynamic_annotations.h"
 #include "absl/base/macros.h"
+#include "absl/container/flat_hash_map.h"
+#include "absl/container/node_hash_map.h"
 #include "absl/strings/numbers.h"
 
 namespace {
@@ -71,7 +73,7 @@
 // namespaces just like callers will need to use.
 TEST(Split, APIExamples) {
   {
-    // Passes std::string delimiter. Assumes the default of ByString.
+    // Passes string delimiter. Assumes the default of ByString.
     std::vector<std::string> v = absl::StrSplit("a,b,c", ",");  // NOLINT
     EXPECT_THAT(v, ElementsAre("a", "b", "c"));
 
@@ -97,7 +99,7 @@
   }
 
   {
-    // Uses the Literal std::string "=>" as the delimiter.
+    // Uses the Literal string "=>" as the delimiter.
     const std::vector<std::string> v = absl::StrSplit("a=>b=>c", "=>");
     EXPECT_THAT(v, ElementsAre("a", "b", "c"));
   }
@@ -121,17 +123,17 @@
   }
 
   {
-    // Splits the input std::string into individual characters by using an empty
-    // std::string as the delimiter.
+    // Splits the input string into individual characters by using an empty
+    // string as the delimiter.
     std::vector<std::string> v = absl::StrSplit("abc", "");
     EXPECT_THAT(v, ElementsAre("a", "b", "c"));
   }
 
   {
-    // Splits std::string data with embedded NUL characters, using NUL as the
+    // Splits string data with embedded NUL characters, using NUL as the
     // delimiter. A simple delimiter of "\0" doesn't work because strlen() will
-    // say that's the empty std::string when constructing the absl::string_view
-    // delimiter. Instead, a non-empty std::string containing NUL can be used as the
+    // say that's the empty string when constructing the absl::string_view
+    // delimiter. Instead, a non-empty string containing NUL can be used as the
     // delimiter.
     std::string embedded_nulls("a\0b\0c", 5);
     std::string null_delim("\0", 1);
@@ -365,7 +367,7 @@
 TEST(Splitter, RangeIterators) {
   auto splitter = absl::StrSplit("a,b,c", ',');
   std::vector<absl::string_view> output;
-  for (const absl::string_view p : splitter) {
+  for (const absl::string_view& p : splitter) {
     output.push_back(p);
   }
   EXPECT_THAT(output, ElementsAre("a", "b", "c"));
@@ -421,6 +423,18 @@
   TestMapConversionOperator<std::multimap<std::string, std::string>>(splitter);
   TestMapConversionOperator<std::unordered_map<std::string, std::string>>(
       splitter);
+  TestMapConversionOperator<
+      absl::node_hash_map<absl::string_view, absl::string_view>>(splitter);
+  TestMapConversionOperator<
+      absl::node_hash_map<absl::string_view, std::string>>(splitter);
+  TestMapConversionOperator<
+      absl::node_hash_map<std::string, absl::string_view>>(splitter);
+  TestMapConversionOperator<
+      absl::flat_hash_map<absl::string_view, absl::string_view>>(splitter);
+  TestMapConversionOperator<
+      absl::flat_hash_map<absl::string_view, std::string>>(splitter);
+  TestMapConversionOperator<
+      absl::flat_hash_map<std::string, absl::string_view>>(splitter);
 
   // Tests conversion to std::pair
 
@@ -436,7 +450,7 @@
 // less-than, equal-to, and more-than 2 strings.
 TEST(Splitter, ToPair) {
   {
-    // Empty std::string
+    // Empty string
     std::pair<std::string, std::string> p = absl::StrSplit("", ',');
     EXPECT_EQ("", p.first);
     EXPECT_EQ("", p.second);
@@ -565,7 +579,7 @@
 
 TEST(Split, Temporary) {
   // Use a std::string longer than the SSO length, so that when the temporary is
-  // destroyed, if the splitter keeps a reference to the std::string's contents,
+  // destroyed, if the splitter keeps a reference to the string's contents,
   // it'll reference freed memory instead of just dead on-stack memory.
   const char input[] = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u";
   EXPECT_LT(sizeof(std::string), ABSL_ARRAYSIZE(input))
@@ -651,14 +665,14 @@
   // Tests splitting utf8 strings and utf8 delimiters.
   std::string utf8_string = u8"\u03BA\u1F79\u03C3\u03BC\u03B5";
   {
-    // A utf8 input std::string with an ascii delimiter.
+    // A utf8 input string with an ascii delimiter.
     std::string to_split = "a," + utf8_string;
     std::vector<absl::string_view> v = absl::StrSplit(to_split, ',');
     EXPECT_THAT(v, ElementsAre("a", utf8_string));
   }
 
   {
-    // A utf8 input std::string and a utf8 delimiter.
+    // A utf8 input string and a utf8 delimiter.
     std::string to_split = "a," + utf8_string + ",b";
     std::string unicode_delimiter = "," + utf8_string + ",";
     std::vector<absl::string_view> v =
@@ -667,7 +681,7 @@
   }
 
   {
-    // A utf8 input std::string and ByAnyChar with ascii chars.
+    // A utf8 input string and ByAnyChar with ascii chars.
     std::vector<absl::string_view> v =
         absl::StrSplit(u8"Foo h\u00E4llo th\u4E1Ere", absl::ByAnyChar(" \t"));
     EXPECT_THAT(v, ElementsAre("Foo", u8"h\u00E4llo", u8"th\u4E1Ere"));
@@ -814,10 +828,10 @@
   ByString comma_string(",");
   TestComma(comma_string);
 
-  // The first occurrence of empty std::string ("") in a std::string is at position 0.
+  // The first occurrence of empty string ("") in a string is at position 0.
   // There is a test below that demonstrates this for absl::string_view::find().
   // If the ByString delimiter returned position 0 for this, there would
-  // be an infinite loop in the SplitIterator code. To avoid this, empty std::string
+  // be an infinite loop in the SplitIterator code. To avoid this, empty string
   // is a special case in that it always returns the item at position 1.
   absl::string_view abc("abc");
   EXPECT_EQ(0, abc.find(""));  // "" is found at position 0
@@ -876,7 +890,7 @@
   EXPECT_FALSE(IsFoundAt("=", two_delims, -1));
 
   // ByAnyChar behaves just like ByString when given a delimiter of empty
-  // std::string. That is, it always returns a zero-length absl::string_view
+  // string. That is, it always returns a zero-length absl::string_view
   // referring to the item at position 1, not position 0.
   ByAnyChar empty("");
   EXPECT_FALSE(IsFoundAt("", empty, 0));
@@ -913,7 +927,7 @@
     std::vector<absl::string_view> v = absl::StrSplit(s, '-');
     EXPECT_EQ(2, v.size());
     // The first element will contain 2G of 'x's.
-    // testing::StartsWith is too slow with a 2G std::string.
+    // testing::StartsWith is too slow with a 2G string.
     EXPECT_EQ('x', v[0][0]);
     EXPECT_EQ('x', v[0][1]);
     EXPECT_EQ('x', v[0][3]);
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h
index 1861ea6..5260b5b 100644
--- a/absl/strings/string_view.h
+++ b/absl/strings/string_view.h
@@ -48,7 +48,7 @@
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
-using std::string_view;
+using string_view = std::string_view;
 ABSL_NAMESPACE_END
 }  // namespace absl
 
@@ -111,6 +111,11 @@
 // 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
@@ -283,7 +288,7 @@
   // 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 {
-    return ABSL_ASSERT(i < size()), ptr_[i];
+    return ABSL_HARDENING_ASSERT(i < size()), ptr_[i];
   }
 
   // string_view::at()
@@ -303,14 +308,14 @@
   //
   // Returns the first element of a `string_view`.
   constexpr const_reference front() const {
-    return ABSL_ASSERT(!empty()), ptr_[0];
+    return ABSL_HARDENING_ASSERT(!empty()), ptr_[0];
   }
 
   // string_view::back()
   //
   // Returns the last element of a `string_view`.
   constexpr const_reference back() const {
-    return ABSL_ASSERT(!empty()), ptr_[size() - 1];
+    return ABSL_HARDENING_ASSERT(!empty()), ptr_[size() - 1];
   }
 
   // string_view::data()
@@ -319,7 +324,7 @@
   // 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
-  // std::string.
+  // string.
   constexpr const_pointer data() const noexcept { return ptr_; }
 
   // Modifiers
@@ -327,9 +332,9 @@
   // string_view::remove_prefix()
   //
   // Removes the first `n` characters from the `string_view`. Note that the
-  // underlying std::string is not changed, only the view.
+  // underlying string is not changed, only the view.
   void remove_prefix(size_type n) {
-    assert(n <= length_);
+    ABSL_HARDENING_ASSERT(n <= length_);
     ptr_ += n;
     length_ -= n;
   }
@@ -337,9 +342,9 @@
   // string_view::remove_suffix()
   //
   // Removes the last `n` characters from the `string_view`. Note that the
-  // underlying std::string is not changed, only the view.
+  // underlying string is not changed, only the view.
   void remove_suffix(size_type n) {
-    assert(n <= length_);
+    ABSL_HARDENING_ASSERT(n <= length_);
     length_ -= n;
   }
 
@@ -382,18 +387,20 @@
   // 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`.
-  string_view substr(size_type pos, size_type n = npos) const {
-    if (ABSL_PREDICT_FALSE(pos > length_))
-      base_internal::ThrowStdOutOfRange("absl::string_view::substr");
-    n = (std::min)(n, length_ - pos);
-    return string_view(ptr_ + pos, n);
+  // Use absl::ClippedSubstr if you need a truncating substr operation.
+  constexpr string_view substr(size_type pos, size_type n = npos) const {
+    return ABSL_PREDICT_FALSE(pos > length_)
+               ? (base_internal::ThrowStdOutOfRange(
+                      "absl::string_view::substr"),
+                  string_view())
+               : string_view(ptr_ + pos, Min(n, length_ - pos));
   }
 
   // string_view::compare()
   //
   // Performs a lexicographical comparison between the `string_view` and
   // another `absl::string_view`, returning -1 if `this` is less than, 0 if
-  // `this` is equal to, and 1 if `this` is greater than the passed std::string
+  // `this` is equal to, and 1 if `this` is greater than the passed string
   // view. Note that in the case of data equality, a further comparison is made
   // on the respective sizes of the two `string_view`s to determine which is
   // smaller, equal, or greater.
@@ -419,17 +426,17 @@
   }
 
   // Overload of `string_view::compare()` for comparing a `string_view` and a
-  // a different  C-style std::string `s`.
+  // a different  C-style string `s`.
   int compare(const char* s) const { return compare(string_view(s)); }
 
   // Overload of `string_view::compare()` for comparing a substring of the
-  // `string_view` and a different std::string C-style std::string `s`.
+  // `string_view` and a different string C-style string `s`.
   int compare(size_type pos1, size_type count1, const char* 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 std::string `s`.
+  // `string_view` and a substring of a different C-style string `s`.
   int compare(size_type pos1, size_type count1, const char* s,
               size_type count2) const {
     return substr(pos1, count1).compare(string_view(s, count2));
@@ -519,7 +526,7 @@
       (std::numeric_limits<difference_type>::max)();
 
   static constexpr size_type CheckLengthInternal(size_type len) {
-    return (void)ABSL_ASSERT(len <= kMaxSize), len;
+    return ABSL_HARDENING_ASSERT(len <= kMaxSize), len;
   }
 
   static constexpr size_type StrlenInternal(const char* str) {
diff --git a/absl/strings/string_view_test.cc b/absl/strings/string_view_test.cc
index 7b1d56f..643af8f 100644
--- a/absl/strings/string_view_test.cc
+++ b/absl/strings/string_view_test.cc
@@ -28,6 +28,7 @@
 #include "gtest/gtest.h"
 #include "absl/base/config.h"
 #include "absl/base/dynamic_annotations.h"
+#include "absl/base/options.h"
 
 #if defined(ABSL_HAVE_STD_STRING_VIEW) || defined(__ANDROID__)
 // We don't control the death messaging when using std::string_view.
@@ -410,7 +411,7 @@
   EXPECT_EQ(a.find(e, 17), 17);
   absl::string_view g("xx not found bb");
   EXPECT_EQ(a.find(g), absl::string_view::npos);
-  // empty std::string nonsense
+  // 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);
@@ -438,7 +439,7 @@
   EXPECT_EQ(g.find('o', 4), 4);
   EXPECT_EQ(g.find('o', 5), 8);
   EXPECT_EQ(a.find('b', 5), absl::string_view::npos);
-  // empty std::string nonsense
+  // 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);
@@ -465,7 +466,7 @@
   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 std::string nonsense
+  // 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()));
@@ -484,7 +485,7 @@
   EXPECT_EQ(f.rfind('\0', 12), 3);
   EXPECT_EQ(f.rfind('3'), 2);
   EXPECT_EQ(f.rfind('5'), 5);
-  // empty std::string nonsense
+  // 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);
@@ -520,7 +521,7 @@
   EXPECT_EQ(g.find_first_of(c), 0);
   EXPECT_EQ(a.find_first_of(f), absl::string_view::npos);
   EXPECT_EQ(f.find_first_of(a), absl::string_view::npos);
-  // empty std::string nonsense
+  // 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);
@@ -538,7 +539,7 @@
   EXPECT_EQ(a.find_first_not_of(f), 0);
   EXPECT_EQ(a.find_first_not_of(d), 0);
   EXPECT_EQ(a.find_first_not_of(e), 0);
-  // empty std::string nonsense
+  // empty string nonsense
   EXPECT_EQ(a.find_first_not_of(d), 0);
   EXPECT_EQ(a.find_first_not_of(e), 0);
   EXPECT_EQ(a.find_first_not_of(d, 1), 1);
@@ -566,7 +567,7 @@
   EXPECT_EQ(f.find_first_not_of('\0'), 0);
   EXPECT_EQ(f.find_first_not_of('\0', 3), 4);
   EXPECT_EQ(f.find_first_not_of('\0', 2), 2);
-  // empty std::string nonsense
+  // 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);
@@ -606,7 +607,7 @@
   EXPECT_EQ(f.find_last_of(i, 5), 5);
   EXPECT_EQ(f.find_last_of(i, 6), 6);
   EXPECT_EQ(f.find_last_of(a, 4), absl::string_view::npos);
-  // empty std::string nonsense
+  // 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);
@@ -632,7 +633,7 @@
   EXPECT_EQ(a.find_last_not_of(c, 24), 22);
   EXPECT_EQ(a.find_last_not_of(b, 3), 3);
   EXPECT_EQ(a.find_last_not_of(b, 2), absl::string_view::npos);
-  // empty std::string nonsense
+  // 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), 4);
@@ -656,7 +657,7 @@
   EXPECT_EQ(h.find_last_not_of('x', 2), 2);
   EXPECT_EQ(h.find_last_not_of('=', 2), absl::string_view::npos);
   EXPECT_EQ(b.find_last_not_of('b', 1), 0);
-  // empty std::string nonsense
+  // 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);
@@ -678,7 +679,7 @@
   EXPECT_EQ(a.substr(23, 99), c);
   EXPECT_EQ(a.substr(0), a);
   EXPECT_EQ(a.substr(3, 2), "de");
-  // empty std::string nonsense
+  // empty string nonsense
   EXPECT_EQ(d.substr(0, 99), e);
   // use of npos
   EXPECT_EQ(a.substr(0, absl::string_view::npos), a);
@@ -820,7 +821,7 @@
 
 TEST(StringViewTest, FrontBackEmpty) {
 #ifndef ABSL_USES_STD_STRING_VIEW
-#ifndef NDEBUG
+#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;
@@ -859,7 +860,7 @@
   EXPECT_EQ(s.size(), 0);
 
   // .ToString() on a absl::string_view with nullptr should produce the empty
-  // std::string.
+  // string.
   EXPECT_EQ("", std::string(s));
 #endif  // ABSL_HAVE_STRING_VIEW_FROM_NULLPTR
 }
@@ -914,9 +915,9 @@
   EXPECT_EQ(abc.at(1), 'b');
   EXPECT_EQ(abc.at(2), 'c');
 #ifdef ABSL_HAVE_EXCEPTIONS
-  EXPECT_THROW(abc.at(3), std::out_of_range);
+  EXPECT_THROW((void)abc.at(3), std::out_of_range);
 #else
-  ABSL_EXPECT_DEATH_IF_SUPPORTED(abc.at(3), "absl::string_view::at");
+  ABSL_EXPECT_DEATH_IF_SUPPORTED((void)abc.at(3), "absl::string_view::at");
 #endif
 }
 
@@ -977,7 +978,7 @@
 
 #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 std::string
+  // 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
@@ -1086,6 +1087,14 @@
   EXPECT_EQ(sp_npos, -1);
 }
 
+TEST(StringViewTest, ConstexprSubstr) {
+  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));
@@ -1122,7 +1131,7 @@
 
 TEST(StringViewTest, BoundsCheck) {
 #ifndef ABSL_USES_STD_STRING_VIEW
-#ifndef NDEBUG
+#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], "");
@@ -1168,11 +1177,11 @@
   EXPECT_EQ(absl::string_view::npos, a.rfind('x'));
 }
 
-#ifndef THREAD_SANITIZER  // Allocates too much memory for tsan.
+#ifndef ABSL_HAVE_THREAD_SANITIZER  // Allocates too much memory for tsan.
 TEST(HugeStringView, TwoPointTwoGB) {
-  if (sizeof(size_t) <= 4 || RunningOnValgrind())
+  if (sizeof(size_t) <= 4)
     return;
-  // Try a huge std::string piece.
+  // Try a huge string piece.
   const size_t size = size_t{2200} * 1000 * 1000;
   std::string s(size, 'a');
   absl::string_view sp(s);
@@ -1182,7 +1191,7 @@
   sp.remove_suffix(2);
   EXPECT_EQ(size - 1 - 2, sp.length());
 }
-#endif  // THREAD_SANITIZER
+#endif  // ABSL_HAVE_THREAD_SANITIZER
 
 #if !defined(NDEBUG) && !defined(ABSL_USES_STD_STRING_VIEW)
 TEST(NonNegativeLenTest, NonNegativeLen) {
diff --git a/absl/strings/substitute.cc b/absl/strings/substitute.cc
index 5b69a3e..1f3c740 100644
--- a/absl/strings/substitute.cc
+++ b/absl/strings/substitute.cc
@@ -36,7 +36,7 @@
       if (i + 1 >= format.size()) {
 #ifndef NDEBUG
         ABSL_RAW_LOG(FATAL,
-                     "Invalid absl::Substitute() format std::string: \"%s\".",
+                     "Invalid absl::Substitute() format string: \"%s\".",
                      absl::CEscape(format).c_str());
 #endif
         return;
@@ -46,8 +46,8 @@
 #ifndef NDEBUG
           ABSL_RAW_LOG(
               FATAL,
-              "Invalid absl::Substitute() format std::string: asked for \"$"
-              "%d\", but only %d args were given.  Full format std::string was: "
+              "Invalid absl::Substitute() format string: asked for \"$"
+              "%d\", but only %d args were given.  Full format string was: "
               "\"%s\".",
               index, static_cast<int>(num_args), absl::CEscape(format).c_str());
 #endif
@@ -61,7 +61,7 @@
       } else {
 #ifndef NDEBUG
         ABSL_RAW_LOG(FATAL,
-                     "Invalid absl::Substitute() format std::string: \"%s\".",
+                     "Invalid absl::Substitute() format string: \"%s\".",
                      absl::CEscape(format).c_str());
 #endif
         return;
@@ -73,7 +73,7 @@
 
   if (size == 0) return;
 
-  // Build the std::string.
+  // Build the string.
   size_t original_size = output->size();
   strings_internal::STLStringResizeUninitialized(output, original_size + size);
   char* target = &(*output)[original_size];
diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h
index 4d0984d..c6da4dc 100644
--- a/absl/strings/substitute.h
+++ b/absl/strings/substitute.h
@@ -50,7 +50,7 @@
 //
 // Supported types:
 //   * absl::string_view, std::string, const char* (null is equivalent to "")
-//   * int32_t, int64_t, uint32_t, uint64
+//   * int32_t, int64_t, uint32_t, uint64_t
 //   * float, double
 //   * bool (Printed as "true" or "false")
 //   * pointer types other than char* (Printed as "0x<lower case hex string>",
@@ -99,7 +99,7 @@
 // This class has implicit constructors.
 class Arg {
  public:
-  // Overloads for std::string-y things
+  // Overloads for string-y things
   //
   // Explicitly overload `const char*` so the compiler doesn't cast to `bool`.
   Arg(const char* value)  // NOLINT(runtime/explicit)
@@ -120,7 +120,9 @@
   // representation. However, we can't really know, so we make the caller decide
   // what to do.
   Arg(char value)  // NOLINT(runtime/explicit)
-      : piece_(scratch_, 1) { scratch_[0] = value; }
+      : piece_(scratch_, 1) {
+    scratch_[0] = value;
+  }
   Arg(short value)  // NOLINT(*)
       : piece_(scratch_,
                numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
@@ -203,10 +205,11 @@
 }
 
 constexpr int PlaceholderBitmask(const char* format) {
-  return !*format ? 0 : *format != '$'
-                             ? PlaceholderBitmask(format + 1)
-                             : (CalculateOneBit(format + 1) |
-                                   PlaceholderBitmask(SkipNumber(format + 1)));
+  return !*format
+             ? 0
+             : *format != '$' ? PlaceholderBitmask(format + 1)
+                              : (CalculateOneBit(format + 1) |
+                                 PlaceholderBitmask(SkipNumber(format + 1)));
 }
 #endif  // ABSL_BAD_CALL_IF
 
@@ -360,13 +363,13 @@
 void SubstituteAndAppend(std::string* output, const char* format)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0,
                      "There were no substitution arguments "
-                     "but this format std::string has a $[0-9] in it");
+                     "but this format string has a $[0-9] in it");
 
 void SubstituteAndAppend(std::string* output, const char* format,
                          const substitute_internal::Arg& a0)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1,
                      "There was 1 substitution argument given, but "
-                     "this format std::string is either missing its $0, or "
+                     "this format string is either missing its $0, or "
                      "contains one of $1-$9");
 
 void SubstituteAndAppend(std::string* output, const char* format,
@@ -374,7 +377,7 @@
                          const substitute_internal::Arg& a1)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 3,
                      "There were 2 substitution arguments given, but "
-                     "this format std::string is either missing its $0/$1, or "
+                     "this format string is either missing its $0/$1, or "
                      "contains one of $2-$9");
 
 void SubstituteAndAppend(std::string* output, const char* format,
@@ -383,7 +386,7 @@
                          const substitute_internal::Arg& a2)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 7,
                      "There were 3 substitution arguments given, but "
-                     "this format std::string is either missing its $0/$1/$2, or "
+                     "this format string is either missing its $0/$1/$2, or "
                      "contains one of $3-$9");
 
 void SubstituteAndAppend(std::string* output, const char* format,
@@ -393,7 +396,7 @@
                          const substitute_internal::Arg& a3)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 15,
                      "There were 4 substitution arguments given, but "
-                     "this format std::string is either missing its $0-$3, or "
+                     "this format string is either missing its $0-$3, or "
                      "contains one of $4-$9");
 
 void SubstituteAndAppend(std::string* output, const char* format,
@@ -404,7 +407,7 @@
                          const substitute_internal::Arg& a4)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 31,
                      "There were 5 substitution arguments given, but "
-                     "this format std::string is either missing its $0-$4, or "
+                     "this format string is either missing its $0-$4, or "
                      "contains one of $5-$9");
 
 void SubstituteAndAppend(std::string* output, const char* format,
@@ -416,7 +419,7 @@
                          const substitute_internal::Arg& a5)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 63,
                      "There were 6 substitution arguments given, but "
-                     "this format std::string is either missing its $0-$5, or "
+                     "this format string is either missing its $0-$5, or "
                      "contains one of $6-$9");
 
 void SubstituteAndAppend(
@@ -426,7 +429,7 @@
     const substitute_internal::Arg& a5, const substitute_internal::Arg& a6)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 127,
                      "There were 7 substitution arguments given, but "
-                     "this format std::string is either missing its $0-$6, or "
+                     "this format string is either missing its $0-$6, or "
                      "contains one of $7-$9");
 
 void SubstituteAndAppend(
@@ -437,7 +440,7 @@
     const substitute_internal::Arg& a7)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 255,
                      "There were 8 substitution arguments given, but "
-                     "this format std::string is either missing its $0-$7, or "
+                     "this format string is either missing its $0-$7, or "
                      "contains one of $8-$9");
 
 void SubstituteAndAppend(
@@ -449,7 +452,7 @@
     ABSL_BAD_CALL_IF(
         substitute_internal::PlaceholderBitmask(format) != 511,
         "There were 9 substitution arguments given, but "
-        "this format std::string is either missing its $0-$8, or contains a $9");
+        "this format string is either missing its $0-$8, or contains a $9");
 
 void SubstituteAndAppend(
     std::string* output, const char* format, const substitute_internal::Arg& a0,
@@ -460,7 +463,7 @@
     const substitute_internal::Arg& a9)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1023,
                      "There were 10 substitution arguments given, but this "
-                     "format std::string doesn't contain all of $0 through $9");
+                     "format string doesn't contain all of $0 through $9");
 #endif  // ABSL_BAD_CALL_IF
 
 // Substitute()
@@ -586,19 +589,19 @@
 std::string Substitute(const char* format)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0,
                      "There were no substitution arguments "
-                     "but this format std::string has a $[0-9] in it");
+                     "but this format string has a $[0-9] in it");
 
 std::string Substitute(const char* format, const substitute_internal::Arg& a0)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1,
                      "There was 1 substitution argument given, but "
-                     "this format std::string is either missing its $0, or "
+                     "this format string is either missing its $0, or "
                      "contains one of $1-$9");
 
 std::string Substitute(const char* format, const substitute_internal::Arg& a0,
                        const substitute_internal::Arg& a1)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 3,
                      "There were 2 substitution arguments given, but "
-                     "this format std::string is either missing its $0/$1, or "
+                     "this format string is either missing its $0/$1, or "
                      "contains one of $2-$9");
 
 std::string Substitute(const char* format, const substitute_internal::Arg& a0,
@@ -606,7 +609,7 @@
                        const substitute_internal::Arg& a2)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 7,
                      "There were 3 substitution arguments given, but "
-                     "this format std::string is either missing its $0/$1/$2, or "
+                     "this format string is either missing its $0/$1/$2, or "
                      "contains one of $3-$9");
 
 std::string Substitute(const char* format, const substitute_internal::Arg& a0,
@@ -615,7 +618,7 @@
                        const substitute_internal::Arg& a3)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 15,
                      "There were 4 substitution arguments given, but "
-                     "this format std::string is either missing its $0-$3, or "
+                     "this format string is either missing its $0-$3, or "
                      "contains one of $4-$9");
 
 std::string Substitute(const char* format, const substitute_internal::Arg& a0,
@@ -625,7 +628,7 @@
                        const substitute_internal::Arg& a4)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 31,
                      "There were 5 substitution arguments given, but "
-                     "this format std::string is either missing its $0-$4, or "
+                     "this format string is either missing its $0-$4, or "
                      "contains one of $5-$9");
 
 std::string Substitute(const char* format, const substitute_internal::Arg& a0,
@@ -636,7 +639,7 @@
                        const substitute_internal::Arg& a5)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 63,
                      "There were 6 substitution arguments given, but "
-                     "this format std::string is either missing its $0-$5, or "
+                     "this format string is either missing its $0-$5, or "
                      "contains one of $6-$9");
 
 std::string Substitute(const char* format, const substitute_internal::Arg& a0,
@@ -648,7 +651,7 @@
                        const substitute_internal::Arg& a6)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 127,
                      "There were 7 substitution arguments given, but "
-                     "this format std::string is either missing its $0-$6, or "
+                     "this format string is either missing its $0-$6, or "
                      "contains one of $7-$9");
 
 std::string Substitute(const char* format, const substitute_internal::Arg& a0,
@@ -661,7 +664,7 @@
                        const substitute_internal::Arg& a7)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 255,
                      "There were 8 substitution arguments given, but "
-                     "this format std::string is either missing its $0-$7, or "
+                     "this format string is either missing its $0-$7, or "
                      "contains one of $8-$9");
 
 std::string Substitute(
@@ -673,7 +676,7 @@
     ABSL_BAD_CALL_IF(
         substitute_internal::PlaceholderBitmask(format) != 511,
         "There were 9 substitution arguments given, but "
-        "this format std::string is either missing its $0-$8, or contains a $9");
+        "this format string is either missing its $0-$8, or contains a $9");
 
 std::string Substitute(
     const char* format, const substitute_internal::Arg& a0,
@@ -684,7 +687,7 @@
     const substitute_internal::Arg& a9)
     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1023,
                      "There were 10 substitution arguments given, but this "
-                     "format std::string doesn't contain all of $0 through $9");
+                     "format string doesn't contain all of $0 through $9");
 #endif  // ABSL_BAD_CALL_IF
 
 ABSL_NAMESPACE_END
diff --git a/absl/strings/substitute_test.cc b/absl/strings/substitute_test.cc
index 450cd2b..442c921 100644
--- a/absl/strings/substitute_test.cc
+++ b/absl/strings/substitute_test.cc
@@ -89,7 +89,7 @@
   str = absl::Substitute("$0", char_buf);
   EXPECT_EQ("print me too", str);
 
-  // null char* is "doubly" special. Represented as the empty std::string.
+  // null char* is "doubly" special. Represented as the empty string.
   char_p = nullptr;
   str = absl::Substitute("$0", char_p);
   EXPECT_EQ("", str);
@@ -189,14 +189,14 @@
 TEST(SubstituteDeathTest, SubstituteDeath) {
   EXPECT_DEBUG_DEATH(
       static_cast<void>(absl::Substitute(absl::string_view("-$2"), "a", "b")),
-      "Invalid absl::Substitute\\(\\) format std::string: asked for \"\\$2\", "
+      "Invalid absl::Substitute\\(\\) format string: asked for \"\\$2\", "
       "but only 2 args were given.");
   EXPECT_DEBUG_DEATH(
       static_cast<void>(absl::Substitute(absl::string_view("-$z-"))),
-      "Invalid absl::Substitute\\(\\) format std::string: \"-\\$z-\"");
+      "Invalid absl::Substitute\\(\\) format string: \"-\\$z-\"");
   EXPECT_DEBUG_DEATH(
       static_cast<void>(absl::Substitute(absl::string_view("-$"))),
-      "Invalid absl::Substitute\\(\\) format std::string: \"-\\$\"");
+      "Invalid absl::Substitute\\(\\) format string: \"-\\$\"");
 }
 
 #endif  // GTEST_HAS_DEATH_TEST
diff --git a/absl/strings/testdata/getline-1.txt b/absl/strings/testdata/getline-1.txt
deleted file mode 100644
index 19b9097..0000000
--- a/absl/strings/testdata/getline-1.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-alpha
-
-beta gamma
diff --git a/absl/strings/testdata/getline-2.txt b/absl/strings/testdata/getline-2.txt
deleted file mode 100644
index d6842d8..0000000
--- a/absl/strings/testdata/getline-2.txt
+++ /dev/null
@@ -1 +0,0 @@
-one.two.three
diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel
index 3f876b9..5ce1695 100644
--- a/absl/synchronization/BUILD.bazel
+++ b/absl/synchronization/BUILD.bazel
@@ -24,7 +24,7 @@
 
 package(default_visibility = ["//visibility:public"])
 
-licenses(["notice"])  # Apache 2.0
+licenses(["notice"])
 
 # Internal data structure for efficiently detecting mutex dependency cycles
 cc_library(
@@ -73,15 +73,14 @@
         "internal/create_thread_identity.cc",
         "internal/per_thread_sem.cc",
         "internal/waiter.cc",
+        "mutex.cc",
         "notification.cc",
-    ] + select({
-        "//conditions:default": ["mutex.cc"],
-    }),
+    ],
     hdrs = [
         "barrier.h",
         "blocking_counter.h",
         "internal/create_thread_identity.h",
-        "internal/mutex_nonprod.inc",
+        "internal/futex.h",
         "internal/per_thread_sem.h",
         "internal/waiter.h",
         "mutex.h",
@@ -89,7 +88,9 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = select({
-        "//absl:windows": [],
+        "//absl:msvc_compiler": [],
+        "//absl:clang-cl_compiler": [],
+        "//absl:wasm": [],
         "//conditions:default": ["-pthread"],
     }) + ABSL_DEFAULT_LINKOPTS,
     deps = [
@@ -189,6 +190,7 @@
         ":synchronization",
         ":thread_pool",
         "//absl/base",
+        "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:raw_logging_internal",
         "//absl/memory",
@@ -210,6 +212,7 @@
         ":synchronization",
         ":thread_pool",
         "//absl/base",
+        "//absl/base:config",
         "@com_github_google_benchmark//:benchmark_main",
     ],
     alwayslink = 1,
@@ -248,6 +251,7 @@
     deps = [
         ":synchronization",
         "//absl/base",
+        "//absl/base:config",
         "//absl/strings",
         "//absl/time",
         "@com_google_googletest//:gtest",
diff --git a/absl/synchronization/CMakeLists.txt b/absl/synchronization/CMakeLists.txt
index dfe5d05..e633d0b 100644
--- a/absl/synchronization/CMakeLists.txt
+++ b/absl/synchronization/CMakeLists.txt
@@ -52,7 +52,7 @@
     "barrier.h"
     "blocking_counter.h"
     "internal/create_thread_identity.h"
-    "internal/mutex_nonprod.inc"
+    "internal/futex.h"
     "internal/per_thread_sem.h"
     "internal/waiter.h"
     "mutex.h"
@@ -149,6 +149,7 @@
     absl::synchronization
     absl::thread_pool
     absl::base
+    absl::config
     absl::core_headers
     absl::memory
     absl::raw_logging_internal
@@ -179,6 +180,7 @@
   DEPS
     absl::synchronization
     absl::base
+    absl::config
     absl::strings
     absl::time
     gmock
diff --git a/absl/synchronization/internal/create_thread_identity.cc b/absl/synchronization/internal/create_thread_identity.cc
index fa0070a..53a71b3 100644
--- a/absl/synchronization/internal/create_thread_identity.cc
+++ b/absl/synchronization/internal/create_thread_identity.cc
@@ -32,9 +32,9 @@
 
 // ThreadIdentity storage is persistent, we maintain a free-list of previously
 // released ThreadIdentity objects.
-static base_internal::SpinLock freelist_lock(
-    base_internal::kLinkerInitialized);
-static base_internal::ThreadIdentity* thread_identity_freelist;
+ABSL_CONST_INIT static base_internal::SpinLock freelist_lock(
+    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+ABSL_CONST_INIT static base_internal::ThreadIdentity* thread_identity_freelist;
 
 // A per-thread destructor for reclaiming associated ThreadIdentity objects.
 // Since we must preserve their storage we cache them for re-use.
diff --git a/absl/synchronization/internal/futex.h b/absl/synchronization/internal/futex.h
new file mode 100644
index 0000000..06fbd6d
--- /dev/null
+++ b/absl/synchronization/internal/futex.h
@@ -0,0 +1,154 @@
+// 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.
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
+
+#include "absl/base/config.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+#ifdef __linux__
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <atomic>
+#include <cstdint>
+
+#include "absl/base/optimization.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+
+#ifdef ABSL_INTERNAL_HAVE_FUTEX
+#error ABSL_INTERNAL_HAVE_FUTEX may not be set on the command line
+#elif defined(__BIONIC__)
+// Bionic supports all the futex operations we need even when some of the futex
+// definitions are missing.
+#define ABSL_INTERNAL_HAVE_FUTEX
+#elif defined(__linux__) && defined(FUTEX_CLOCK_REALTIME)
+// FUTEX_CLOCK_REALTIME requires Linux >= 2.6.28.
+#define ABSL_INTERNAL_HAVE_FUTEX
+#endif
+
+#ifdef ABSL_INTERNAL_HAVE_FUTEX
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace synchronization_internal {
+
+// Some Android headers are missing these definitions even though they
+// support these futex operations.
+#ifdef __BIONIC__
+#ifndef SYS_futex
+#define SYS_futex __NR_futex
+#endif
+#ifndef FUTEX_WAIT_BITSET
+#define FUTEX_WAIT_BITSET 9
+#endif
+#ifndef FUTEX_PRIVATE_FLAG
+#define FUTEX_PRIVATE_FLAG 128
+#endif
+#ifndef FUTEX_CLOCK_REALTIME
+#define FUTEX_CLOCK_REALTIME 256
+#endif
+#ifndef FUTEX_BITSET_MATCH_ANY
+#define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF
+#endif
+#endif
+
+#if defined(__NR_futex_time64) && !defined(SYS_futex_time64)
+#define SYS_futex_time64 __NR_futex_time64
+#endif
+
+#if defined(SYS_futex_time64) && !defined(SYS_futex)
+#define SYS_futex SYS_futex_time64
+#endif
+
+class FutexImpl {
+ public:
+  static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
+                       KernelTimeout t) {
+    int err = 0;
+    if (t.has_timeout()) {
+      // https://locklessinc.com/articles/futex_cheat_sheet/
+      // Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time.
+      struct timespec abs_timeout = t.MakeAbsTimespec();
+      // Atomically check that the futex value is still 0, and if it
+      // is, sleep until abs_timeout or until woken by FUTEX_WAKE.
+      err = syscall(
+          SYS_futex, reinterpret_cast<int32_t *>(v),
+          FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val,
+          &abs_timeout, nullptr, FUTEX_BITSET_MATCH_ANY);
+    } else {
+      // Atomically check that the futex value is still 0, and if it
+      // is, sleep until woken by FUTEX_WAKE.
+      err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+                    FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr);
+    }
+    if (ABSL_PREDICT_FALSE(err != 0)) {
+      err = -errno;
+    }
+    return err;
+  }
+
+  static int WaitBitsetAbsoluteTimeout(std::atomic<int32_t> *v, int32_t val,
+                                       int32_t bits,
+                                       const struct timespec *abstime) {
+    int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+                      FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG, val, abstime,
+                      nullptr, bits);
+    if (ABSL_PREDICT_FALSE(err != 0)) {
+      err = -errno;
+    }
+    return err;
+  }
+
+  static int Wake(std::atomic<int32_t> *v, int32_t count) {
+    int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+                      FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count);
+    if (ABSL_PREDICT_FALSE(err < 0)) {
+      err = -errno;
+    }
+    return err;
+  }
+
+  // FUTEX_WAKE_BITSET
+  static int WakeBitset(std::atomic<int32_t> *v, int32_t count, int32_t bits) {
+    int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+                      FUTEX_WAKE_BITSET | FUTEX_PRIVATE_FLAG, count, nullptr,
+                      nullptr, bits);
+    if (ABSL_PREDICT_FALSE(err < 0)) {
+      err = -errno;
+    }
+    return err;
+  }
+};
+
+class Futex : public FutexImpl {};
+
+}  // namespace synchronization_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_INTERNAL_HAVE_FUTEX
+
+#endif  // ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
diff --git a/absl/synchronization/internal/graphcycles.cc b/absl/synchronization/internal/graphcycles.cc
index 6a2bcdf..27fec21 100644
--- a/absl/synchronization/internal/graphcycles.cc
+++ b/absl/synchronization/internal/graphcycles.cc
@@ -37,6 +37,7 @@
 
 #include <algorithm>
 #include <array>
+#include <limits>
 #include "absl/base/internal/hide_ptr.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/internal/spinlock.h"
@@ -51,9 +52,9 @@
 
 // Avoid LowLevelAlloc's default arena since it calls malloc hooks in
 // which people are doing things like acquiring Mutexes.
-static absl::base_internal::SpinLock arena_mu(
-    absl::base_internal::kLinkerInitialized);
-static base_internal::LowLevelAlloc::Arena* arena;
+ABSL_CONST_INIT static absl::base_internal::SpinLock arena_mu(
+    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+ABSL_CONST_INIT static base_internal::LowLevelAlloc::Arena* arena;
 
 static void InitArenaIfNecessary() {
   arena_mu.Lock();
diff --git a/absl/synchronization/internal/kernel_timeout.h b/absl/synchronization/internal/kernel_timeout.h
index d6ac5db..bbd4d2d 100644
--- a/absl/synchronization/internal/kernel_timeout.h
+++ b/absl/synchronization/internal/kernel_timeout.h
@@ -26,6 +26,7 @@
 #define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
 
 #include <time.h>
+
 #include <algorithm>
 #include <limits>
 
@@ -57,6 +58,10 @@
 
   bool has_timeout() const { return ns_ != 0; }
 
+  // Convert to parameter for sem_timedwait/futex/similar.  Only for approved
+  // users.  Do not call if !has_timeout.
+  struct timespec MakeAbsTimespec();
+
  private:
   // internal rep, not user visible: ns after unix epoch.
   // zero = no timeout.
@@ -82,34 +87,6 @@
     return x;
   }
 
-  // Convert to parameter for sem_timedwait/futex/similar.  Only for approved
-  // users.  Do not call if !has_timeout.
-  struct timespec MakeAbsTimespec() {
-    int64_t n = ns_;
-    static const int64_t kNanosPerSecond = 1000 * 1000 * 1000;
-    if (n == 0) {
-      ABSL_RAW_LOG(
-          ERROR,
-          "Tried to create a timespec from a non-timeout; never do this.");
-      // But we'll try to continue sanely.  no-timeout ~= saturated timeout.
-      n = (std::numeric_limits<int64_t>::max)();
-    }
-
-    // Kernel APIs validate timespecs as being at or after the epoch,
-    // despite the kernel time type being signed.  However, no one can
-    // tell the difference between a timeout at or before the epoch (since
-    // all such timeouts have expired!)
-    if (n < 0) n = 0;
-
-    struct timespec abstime;
-    int64_t seconds = (std::min)(n / kNanosPerSecond,
-                               int64_t{(std::numeric_limits<time_t>::max)()});
-    abstime.tv_sec = static_cast<time_t>(seconds);
-    abstime.tv_nsec =
-        static_cast<decltype(abstime.tv_nsec)>(n % kNanosPerSecond);
-    return abstime;
-  }
-
 #ifdef _WIN32
   // Converts to milliseconds from now, or INFINITE when
   // !has_timeout(). For use by SleepConditionVariableSRW on
@@ -148,6 +125,30 @@
   friend class Waiter;
 };
 
+inline struct timespec KernelTimeout::MakeAbsTimespec() {
+  int64_t n = ns_;
+  static const int64_t kNanosPerSecond = 1000 * 1000 * 1000;
+  if (n == 0) {
+    ABSL_RAW_LOG(
+        ERROR, "Tried to create a timespec from a non-timeout; never do this.");
+    // But we'll try to continue sanely.  no-timeout ~= saturated timeout.
+    n = (std::numeric_limits<int64_t>::max)();
+  }
+
+  // Kernel APIs validate timespecs as being at or after the epoch,
+  // despite the kernel time type being signed.  However, no one can
+  // tell the difference between a timeout at or before the epoch (since
+  // all such timeouts have expired!)
+  if (n < 0) n = 0;
+
+  struct timespec abstime;
+  int64_t seconds = (std::min)(n / kNanosPerSecond,
+                               int64_t{(std::numeric_limits<time_t>::max)()});
+  abstime.tv_sec = static_cast<time_t>(seconds);
+  abstime.tv_nsec = static_cast<decltype(abstime.tv_nsec)>(n % kNanosPerSecond);
+  return abstime;
+}
+
 }  // namespace synchronization_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/synchronization/internal/mutex_nonprod.cc b/absl/synchronization/internal/mutex_nonprod.cc
deleted file mode 100644
index 4590b98..0000000
--- a/absl/synchronization/internal/mutex_nonprod.cc
+++ /dev/null
@@ -1,320 +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.
-
-// Implementation of a small subset of Mutex and CondVar functionality
-// for platforms where the production implementation hasn't been fully
-// ported yet.
-
-#include "absl/synchronization/mutex.h"
-
-#if defined(_WIN32)
-#include <chrono>  // NOLINT(build/c++11)
-#else
-#include <sys/time.h>
-#include <time.h>
-#endif
-
-#include <algorithm>
-
-#include "absl/base/internal/raw_logging.h"
-#include "absl/time/time.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace synchronization_internal {
-
-namespace {
-
-// Return the current time plus the timeout.
-absl::Time DeadlineFromTimeout(absl::Duration timeout) {
-  return absl::Now() + timeout;
-}
-
-// Limit the deadline to a positive, 32-bit time_t value to accommodate
-// implementation restrictions.  This also deals with InfinitePast and
-// InfiniteFuture.
-absl::Time LimitedDeadline(absl::Time deadline) {
-  deadline = std::max(absl::FromTimeT(0), deadline);
-  deadline = std::min(deadline, absl::FromTimeT(0x7fffffff));
-  return deadline;
-}
-
-}  // namespace
-
-#if defined(_WIN32)
-
-MutexImpl::MutexImpl() {}
-
-MutexImpl::~MutexImpl() {
-  if (locked_) {
-    std_mutex_.unlock();
-  }
-}
-
-void MutexImpl::Lock() {
-  std_mutex_.lock();
-  locked_ = true;
-}
-
-bool MutexImpl::TryLock() {
-  bool locked = std_mutex_.try_lock();
-  if (locked) locked_ = true;
-  return locked;
-}
-
-void MutexImpl::Unlock() {
-  locked_ = false;
-  released_.SignalAll();
-  std_mutex_.unlock();
-}
-
-CondVarImpl::CondVarImpl() {}
-
-CondVarImpl::~CondVarImpl() {}
-
-void CondVarImpl::Signal() { std_cv_.notify_one(); }
-
-void CondVarImpl::SignalAll() { std_cv_.notify_all(); }
-
-void CondVarImpl::Wait(MutexImpl* mu) {
-  mu->released_.SignalAll();
-  std_cv_.wait(mu->std_mutex_);
-}
-
-bool CondVarImpl::WaitWithDeadline(MutexImpl* mu, absl::Time deadline) {
-  mu->released_.SignalAll();
-  time_t when = ToTimeT(deadline);
-  int64_t nanos = ToInt64Nanoseconds(deadline - absl::FromTimeT(when));
-  std::chrono::system_clock::time_point deadline_tp =
-      std::chrono::system_clock::from_time_t(when) +
-      std::chrono::duration_cast<std::chrono::system_clock::duration>(
-          std::chrono::nanoseconds(nanos));
-  auto deadline_since_epoch =
-      std::chrono::duration_cast<std::chrono::duration<double>>(
-          deadline_tp - std::chrono::system_clock::from_time_t(0));
-  return std_cv_.wait_until(mu->std_mutex_, deadline_tp) ==
-         std::cv_status::timeout;
-}
-
-#else  // ! _WIN32
-
-MutexImpl::MutexImpl() {
-  ABSL_RAW_CHECK(pthread_mutex_init(&pthread_mutex_, nullptr) == 0,
-                 "pthread error");
-}
-
-MutexImpl::~MutexImpl() {
-  if (locked_) {
-    ABSL_RAW_CHECK(pthread_mutex_unlock(&pthread_mutex_) == 0, "pthread error");
-  }
-  ABSL_RAW_CHECK(pthread_mutex_destroy(&pthread_mutex_) == 0, "pthread error");
-}
-
-void MutexImpl::Lock() {
-  ABSL_RAW_CHECK(pthread_mutex_lock(&pthread_mutex_) == 0, "pthread error");
-  locked_ = true;
-}
-
-bool MutexImpl::TryLock() {
-  bool locked = (0 == pthread_mutex_trylock(&pthread_mutex_));
-  if (locked) locked_ = true;
-  return locked;
-}
-
-void MutexImpl::Unlock() {
-  locked_ = false;
-  released_.SignalAll();
-  ABSL_RAW_CHECK(pthread_mutex_unlock(&pthread_mutex_) == 0, "pthread error");
-}
-
-CondVarImpl::CondVarImpl() {
-  ABSL_RAW_CHECK(pthread_cond_init(&pthread_cv_, nullptr) == 0,
-                 "pthread error");
-}
-
-CondVarImpl::~CondVarImpl() {
-  ABSL_RAW_CHECK(pthread_cond_destroy(&pthread_cv_) == 0, "pthread error");
-}
-
-void CondVarImpl::Signal() {
-  ABSL_RAW_CHECK(pthread_cond_signal(&pthread_cv_) == 0, "pthread error");
-}
-
-void CondVarImpl::SignalAll() {
-  ABSL_RAW_CHECK(pthread_cond_broadcast(&pthread_cv_) == 0, "pthread error");
-}
-
-void CondVarImpl::Wait(MutexImpl* mu) {
-  mu->released_.SignalAll();
-  ABSL_RAW_CHECK(pthread_cond_wait(&pthread_cv_, &mu->pthread_mutex_) == 0,
-                 "pthread error");
-}
-
-bool CondVarImpl::WaitWithDeadline(MutexImpl* mu, absl::Time deadline) {
-  mu->released_.SignalAll();
-  struct timespec ts = ToTimespec(deadline);
-  int rc = pthread_cond_timedwait(&pthread_cv_, &mu->pthread_mutex_, &ts);
-  if (rc == ETIMEDOUT) return true;
-  ABSL_RAW_CHECK(rc == 0, "pthread error");
-  return false;
-}
-
-#endif  // ! _WIN32
-
-void MutexImpl::Await(const Condition& cond) {
-  if (cond.Eval()) return;
-  released_.SignalAll();
-  do {
-    released_.Wait(this);
-  } while (!cond.Eval());
-}
-
-bool MutexImpl::AwaitWithDeadline(const Condition& cond, absl::Time deadline) {
-  if (cond.Eval()) return true;
-  released_.SignalAll();
-  while (true) {
-    if (released_.WaitWithDeadline(this, deadline)) return false;
-    if (cond.Eval()) return true;
-  }
-}
-
-}  // namespace synchronization_internal
-
-Mutex::Mutex() {}
-
-Mutex::~Mutex() {}
-
-void Mutex::Lock() { impl()->Lock(); }
-
-void Mutex::Unlock() { impl()->Unlock(); }
-
-bool Mutex::TryLock() { return impl()->TryLock(); }
-
-void Mutex::ReaderLock() { Lock(); }
-
-void Mutex::ReaderUnlock() { Unlock(); }
-
-void Mutex::Await(const Condition& cond) { impl()->Await(cond); }
-
-void Mutex::LockWhen(const Condition& cond) {
-  Lock();
-  Await(cond);
-}
-
-bool Mutex::AwaitWithDeadline(const Condition& cond, absl::Time deadline) {
-  return impl()->AwaitWithDeadline(
-      cond, synchronization_internal::LimitedDeadline(deadline));
-}
-
-bool Mutex::AwaitWithTimeout(const Condition& cond, absl::Duration timeout) {
-  return AwaitWithDeadline(
-      cond, synchronization_internal::DeadlineFromTimeout(timeout));
-}
-
-bool Mutex::LockWhenWithDeadline(const Condition& cond, absl::Time deadline) {
-  Lock();
-  return AwaitWithDeadline(cond, deadline);
-}
-
-bool Mutex::LockWhenWithTimeout(const Condition& cond, absl::Duration timeout) {
-  return LockWhenWithDeadline(
-      cond, synchronization_internal::DeadlineFromTimeout(timeout));
-}
-
-void Mutex::ReaderLockWhen(const Condition& cond) {
-  ReaderLock();
-  Await(cond);
-}
-
-bool Mutex::ReaderLockWhenWithTimeout(const Condition& cond,
-                                      absl::Duration timeout) {
-  return LockWhenWithTimeout(cond, timeout);
-}
-bool Mutex::ReaderLockWhenWithDeadline(const Condition& cond,
-                                       absl::Time deadline) {
-  return LockWhenWithDeadline(cond, deadline);
-}
-
-void Mutex::EnableDebugLog(const char*) {}
-void Mutex::EnableInvariantDebugging(void (*)(void*), void*) {}
-void Mutex::ForgetDeadlockInfo() {}
-void Mutex::AssertHeld() const {}
-void Mutex::AssertReaderHeld() const {}
-void Mutex::AssertNotHeld() const {}
-
-CondVar::CondVar() {}
-
-CondVar::~CondVar() {}
-
-void CondVar::Signal() { impl()->Signal(); }
-
-void CondVar::SignalAll() { impl()->SignalAll(); }
-
-void CondVar::Wait(Mutex* mu) { return impl()->Wait(mu->impl()); }
-
-bool CondVar::WaitWithDeadline(Mutex* mu, absl::Time deadline) {
-  return impl()->WaitWithDeadline(
-      mu->impl(), synchronization_internal::LimitedDeadline(deadline));
-}
-
-bool CondVar::WaitWithTimeout(Mutex* mu, absl::Duration timeout) {
-  return WaitWithDeadline(mu, absl::Now() + timeout);
-}
-
-void CondVar::EnableDebugLog(const char*) {}
-
-#ifdef THREAD_SANITIZER
-extern "C" void __tsan_read1(void *addr);
-#else
-#define __tsan_read1(addr)  // do nothing if TSan not enabled
-#endif
-
-// A function that just returns its argument, dereferenced
-static bool Dereference(void *arg) {
-  // ThreadSanitizer does not instrument this file for memory accesses.
-  // This function dereferences a user variable that can participate
-  // in a data race, so we need to manually tell TSan about this memory access.
-  __tsan_read1(arg);
-  return *(static_cast<bool *>(arg));
-}
-
-Condition::Condition() {}   // null constructor, used for kTrue only
-const Condition Condition::kTrue;
-
-Condition::Condition(bool (*func)(void *), void *arg)
-    : eval_(&CallVoidPtrFunction),
-      function_(func),
-      method_(nullptr),
-      arg_(arg) {}
-
-bool Condition::CallVoidPtrFunction(const Condition *c) {
-  return (*c->function_)(c->arg_);
-}
-
-Condition::Condition(const bool *cond)
-    : eval_(CallVoidPtrFunction),
-      function_(Dereference),
-      method_(nullptr),
-      // const_cast is safe since Dereference does not modify arg
-      arg_(const_cast<bool *>(cond)) {}
-
-bool Condition::Eval() const {
-  // eval_ == null for kTrue
-  return (this->eval_ == nullptr) || (*this->eval_)(this);
-}
-
-void RegisterSymbolizer(bool (*)(const void*, char*, int)) {}
-
-ABSL_NAMESPACE_END
-}  // namespace absl
diff --git a/absl/synchronization/internal/mutex_nonprod.inc b/absl/synchronization/internal/mutex_nonprod.inc
deleted file mode 100644
index a1502e7..0000000
--- a/absl/synchronization/internal/mutex_nonprod.inc
+++ /dev/null
@@ -1,261 +0,0 @@
-// Do not include.  This is an implementation detail of base/mutex.h.
-//
-// Declares three classes:
-//
-// base::internal::MutexImpl - implementation helper for Mutex
-// base::internal::CondVarImpl - implementation helper for CondVar
-// base::internal::SynchronizationStorage<T> - implementation helper for
-//                                             Mutex, CondVar
-
-#include <type_traits>
-
-#if defined(_WIN32)
-#include <condition_variable>
-#include <mutex>
-#else
-#include <pthread.h>
-#endif
-
-#include "absl/base/call_once.h"
-#include "absl/time/time.h"
-
-// Declare that Mutex::ReaderLock is actually Lock().  Intended primarily
-// for tests, and even then as a last resort.
-#ifdef ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE
-#error ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE cannot be directly set
-#else
-#define ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE 1
-#endif
-
-// Declare that Mutex::EnableInvariantDebugging is not implemented.
-// Intended primarily for tests, and even then as a last resort.
-#ifdef ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED
-#error ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED cannot be directly set
-#else
-#define ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED 1
-#endif
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-class Condition;
-
-namespace synchronization_internal {
-
-class MutexImpl;
-
-// Do not use this implementation detail of CondVar. Provides most of the
-// implementation, but should not be placed directly in static storage
-// because it will not linker initialize properly. See
-// SynchronizationStorage<T> below for what we mean by linker
-// initialization.
-class CondVarImpl {
- public:
-  CondVarImpl();
-  CondVarImpl(const CondVarImpl&) = delete;
-  CondVarImpl& operator=(const CondVarImpl&) = delete;
-  ~CondVarImpl();
-
-  void Signal();
-  void SignalAll();
-  void Wait(MutexImpl* mutex);
-  bool WaitWithDeadline(MutexImpl* mutex, absl::Time deadline);
-
- private:
-#if defined(_WIN32)
-  std::condition_variable_any std_cv_;
-#else
-  pthread_cond_t pthread_cv_;
-#endif
-};
-
-// Do not use this implementation detail of Mutex. Provides most of the
-// implementation, but should not be placed directly in static storage
-// because it will not linker initialize properly. See
-// SynchronizationStorage<T> below for what we mean by linker
-// initialization.
-class MutexImpl {
- public:
-  MutexImpl();
-  MutexImpl(const MutexImpl&) = delete;
-  MutexImpl& operator=(const MutexImpl&) = delete;
-  ~MutexImpl();
-
-  void Lock();
-  bool TryLock();
-  void Unlock();
-  void Await(const Condition& cond);
-  bool AwaitWithDeadline(const Condition& cond, absl::Time deadline);
-
- private:
-  friend class CondVarImpl;
-
-#if defined(_WIN32)
-  std::mutex std_mutex_;
-#else
-  pthread_mutex_t pthread_mutex_;
-#endif
-
-  // True if the underlying mutex is locked.  If the destructor is entered
-  // while locked_, the underlying mutex is unlocked.  Mutex supports
-  // destruction while locked, but the same is undefined behavior for both
-  // pthread_mutex_t and std::mutex.
-  bool locked_ = false;
-
-  // Signaled before releasing the lock, in support of Await.
-  CondVarImpl released_;
-};
-
-// Do not use this implementation detail of CondVar and Mutex.  A storage
-// space for T that supports a LinkerInitialized constructor. T must
-// have a default constructor, which is called by the first call to
-// get(). T's destructor is never called if the LinkerInitialized
-// constructor is called.
-//
-// Objects constructed with the default constructor are constructed and
-// destructed like any other object, and should never be allocated in
-// static storage.
-//
-// Objects constructed with the LinkerInitialized constructor should
-// always be in static storage. For such objects, calls to get() are always
-// valid, except from signal handlers.
-//
-// Note that this implementation relies on undefined language behavior that
-// are known to hold for the set of supported compilers. An analysis
-// follows.
-//
-// From the C++11 standard:
-//
-// [basic.life] says an object has non-trivial initialization if it is of
-// class type and it is initialized by a constructor other than a trivial
-// default constructor.  (the LinkerInitialized constructor is
-// non-trivial)
-//
-// [basic.life] says the lifetime of an object with a non-trivial
-// constructor begins when the call to the constructor is complete.
-//
-// [basic.life] says the lifetime of an object with non-trivial destructor
-// ends when the call to the destructor begins.
-//
-// [basic.life] p5 specifies undefined behavior when accessing non-static
-// members of an instance outside its
-// lifetime. (SynchronizationStorage::get() access non-static members)
-//
-// So, LinkerInitialized object of SynchronizationStorage uses a
-// non-trivial constructor, which is called at some point during dynamic
-// initialization, and is therefore subject to order of dynamic
-// initialization bugs, where get() is called before the object's
-// constructor is, resulting in undefined behavior.
-//
-// Similarly, a LinkerInitialized SynchronizationStorage object has a
-// non-trivial destructor, and so its lifetime ends at some point during
-// destruction of objects with static storage duration [basic.start.term]
-// p4. There is a window where other exit code could call get() after this
-// occurs, resulting in undefined behavior.
-//
-// Combined, these statements imply that LinkerInitialized instances
-// of SynchronizationStorage<T> rely on undefined behavior.
-//
-// However, in practice, the implementation works on all supported
-// compilers. Specifically, we rely on:
-//
-// a) zero-initialization being sufficient to initialize
-// LinkerInitialized instances for the purposes of calling
-// get(), regardless of when the constructor is called. This is
-// because the is_dynamic_ boolean is correctly zero-initialized to
-// false.
-//
-// b) the LinkerInitialized constructor is a NOP, and immaterial to
-// even to concurrent calls to get().
-//
-// c) the destructor being a NOP for LinkerInitialized objects
-// (guaranteed by a check for !is_dynamic_), and so any concurrent and
-// subsequent calls to get() functioning as if the destructor were not
-// called, by virtue of the instances' storage remaining valid after the
-// destructor runs.
-//
-// d) That a-c apply transitively when SynchronizationStorage<T> is the
-// only member of a class allocated in static storage.
-//
-// Nothing in the language standard guarantees that a-d hold.  In practice,
-// these hold in all supported compilers.
-//
-// Future direction:
-//
-// Ideally, we would simply use std::mutex or a similar class, which when
-// allocated statically would support use immediately after static
-// initialization up until static storage is reclaimed (i.e. the properties
-// we require of all "linker initialized" instances).
-//
-// Regarding construction in static storage, std::mutex is required to
-// provide a constexpr default constructor [thread.mutex.class], which
-// ensures the instance's lifetime begins with static initialization
-// [basic.start.init], and so is immune to any problems caused by the order
-// of dynamic initialization. However, as of this writing Microsoft's
-// Visual Studio does not provide a constexpr constructor for std::mutex.
-// See
-// https://blogs.msdn.microsoft.com/vcblog/2015/06/02/constexpr-complete-for-vs-2015-rtm-c11-compiler-c17-stl/
-//
-// Regarding destruction of instances in static storage, [basic.life] does
-// say an object ends when storage in which the occupies is released, in
-// the case of non-trivial destructor. However, std::mutex is not specified
-// to have a trivial destructor.
-//
-// So, we would need a class with a constexpr default constructor and a
-// trivial destructor. Today, we can achieve neither desired property using
-// std::mutex directly.
-template <typename T>
-class SynchronizationStorage {
- public:
-  // Instances allocated on the heap or on the stack should use the default
-  // constructor.
-  SynchronizationStorage()
-      : is_dynamic_(true), once_() {}
-
-  // Instances allocated in static storage (not on the heap, not on the
-  // stack) should use this constructor.
-  explicit SynchronizationStorage(base_internal::LinkerInitialized) {}
-
-  constexpr explicit SynchronizationStorage(absl::ConstInitType)
-      : is_dynamic_(false), once_(), space_{{0}} {}
-
-  SynchronizationStorage(SynchronizationStorage&) = delete;
-  SynchronizationStorage& operator=(SynchronizationStorage&) = delete;
-
-  ~SynchronizationStorage() {
-    if (is_dynamic_) {
-      get()->~T();
-    }
-  }
-
-  // Retrieve the object in storage. This is fast and thread safe, but does
-  // incur the cost of absl::call_once().
-  //
-  // For instances in static storage constructed with the
-  // LinkerInitialized constructor, may be called at any time without
-  // regard for order of dynamic initialization or destruction of objects
-  // in static storage. See the class comment for caveats.
-  T* get() {
-    absl::call_once(once_, SynchronizationStorage::Construct, this);
-    return reinterpret_cast<T*>(&space_);
-  }
-
- private:
-  static void Construct(SynchronizationStorage<T>* self) {
-    new (&self->space_) T();
-  }
-
-  // When true, T's destructor is run when this is destructed.
-  //
-  // The LinkerInitialized constructor assumes this value will be set
-  // false by static initialization.
-  bool is_dynamic_;
-
-  absl::once_flag once_;
-
-  // An aligned space for the T.
-  alignas(T) unsigned char space_[sizeof(T)];
-};
-
-}  // namespace synchronization_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
diff --git a/absl/synchronization/internal/per_thread_sem.cc b/absl/synchronization/internal/per_thread_sem.cc
index 821ca9b..a603178 100644
--- a/absl/synchronization/internal/per_thread_sem.cc
+++ b/absl/synchronization/internal/per_thread_sem.cc
@@ -68,12 +68,12 @@
 
 extern "C" {
 
-ABSL_ATTRIBUTE_WEAK void AbslInternalPerThreadSemPost(
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemPost)(
     absl::base_internal::ThreadIdentity *identity) {
   absl::synchronization_internal::Waiter::GetWaiter(identity)->Post();
 }
 
-ABSL_ATTRIBUTE_WEAK bool AbslInternalPerThreadSemWait(
+ABSL_ATTRIBUTE_WEAK bool ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemWait)(
     absl::synchronization_internal::KernelTimeout t) {
   bool timeout = false;
   absl::base_internal::ThreadIdentity *identity;
diff --git a/absl/synchronization/internal/per_thread_sem.h b/absl/synchronization/internal/per_thread_sem.h
index 8ab4391..7beae8e 100644
--- a/absl/synchronization/internal/per_thread_sem.h
+++ b/absl/synchronization/internal/per_thread_sem.h
@@ -78,7 +78,7 @@
   // !t.has_timeout() => Wait(t) will return true.
   static inline bool Wait(KernelTimeout t);
 
-  // White-listed callers.
+  // Permitted callers.
   friend class PerThreadSemTest;
   friend class absl::Mutex;
   friend absl::base_internal::ThreadIdentity* CreateThreadIdentity();
@@ -96,20 +96,20 @@
 // By changing our extension points to be extern "C", we dodge this
 // check.
 extern "C" {
-void AbslInternalPerThreadSemPost(
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemPost)(
     absl::base_internal::ThreadIdentity* identity);
-bool AbslInternalPerThreadSemWait(
+bool ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemWait)(
     absl::synchronization_internal::KernelTimeout t);
 }  // extern "C"
 
 void absl::synchronization_internal::PerThreadSem::Post(
     absl::base_internal::ThreadIdentity* identity) {
-  AbslInternalPerThreadSemPost(identity);
+  ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemPost)(identity);
 }
 
 bool absl::synchronization_internal::PerThreadSem::Wait(
     absl::synchronization_internal::KernelTimeout t) {
-  return AbslInternalPerThreadSemWait(t);
+  return ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemWait)(t);
 }
 
 #endif  // ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_
diff --git a/absl/synchronization/internal/per_thread_sem_test.cc b/absl/synchronization/internal/per_thread_sem_test.cc
index b5a2f6d..8cf59e6 100644
--- a/absl/synchronization/internal/per_thread_sem_test.cc
+++ b/absl/synchronization/internal/per_thread_sem_test.cc
@@ -23,6 +23,7 @@
 #include <thread>              // NOLINT(build/c++11)
 
 #include "gtest/gtest.h"
+#include "absl/base/config.h"
 #include "absl/base/internal/cycleclock.h"
 #include "absl/base/internal/thread_identity.h"
 #include "absl/strings/str_cat.h"
diff --git a/absl/synchronization/internal/waiter.cc b/absl/synchronization/internal/waiter.cc
index 2949f5a..2123be6 100644
--- a/absl/synchronization/internal/waiter.cc
+++ b/absl/synchronization/internal/waiter.cc
@@ -48,6 +48,7 @@
 #include "absl/base/optimization.h"
 #include "absl/synchronization/internal/kernel_timeout.h"
 
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace synchronization_internal {
@@ -66,63 +67,6 @@
 
 #if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX
 
-// Some Android headers are missing these definitions even though they
-// support these futex operations.
-#ifdef __BIONIC__
-#ifndef SYS_futex
-#define SYS_futex __NR_futex
-#endif
-#ifndef FUTEX_WAIT_BITSET
-#define FUTEX_WAIT_BITSET 9
-#endif
-#ifndef FUTEX_PRIVATE_FLAG
-#define FUTEX_PRIVATE_FLAG 128
-#endif
-#ifndef FUTEX_CLOCK_REALTIME
-#define FUTEX_CLOCK_REALTIME 256
-#endif
-#ifndef FUTEX_BITSET_MATCH_ANY
-#define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF
-#endif
-#endif
-
-class Futex {
- public:
-  static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
-                       KernelTimeout t) {
-    int err = 0;
-    if (t.has_timeout()) {
-      // https://locklessinc.com/articles/futex_cheat_sheet/
-      // Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time.
-      struct timespec abs_timeout = t.MakeAbsTimespec();
-      // Atomically check that the futex value is still 0, and if it
-      // is, sleep until abs_timeout or until woken by FUTEX_WAKE.
-      err = syscall(
-          SYS_futex, reinterpret_cast<int32_t *>(v),
-          FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val,
-          &abs_timeout, nullptr, FUTEX_BITSET_MATCH_ANY);
-    } else {
-      // Atomically check that the futex value is still 0, and if it
-      // is, sleep until woken by FUTEX_WAKE.
-      err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
-                    FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr);
-    }
-    if (err != 0) {
-      err = -errno;
-    }
-    return err;
-  }
-
-  static int Wake(std::atomic<int32_t> *v, int32_t count) {
-    int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
-                      FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count);
-    if (ABSL_PREDICT_FALSE(err < 0)) {
-      err = -errno;
-    }
-    return err;
-  }
-};
-
 Waiter::Waiter() {
   futex_.store(0, std::memory_order_relaxed);
 }
diff --git a/absl/synchronization/internal/waiter.h b/absl/synchronization/internal/waiter.h
index a6e6d4c..be3df18 100644
--- a/absl/synchronization/internal/waiter.h
+++ b/absl/synchronization/internal/waiter.h
@@ -36,6 +36,7 @@
 #include <cstdint>
 
 #include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/futex.h"
 #include "absl/synchronization/internal/kernel_timeout.h"
 
 // May be chosen at compile time via -DABSL_FORCE_WAITER_MODE=<index>
@@ -48,12 +49,7 @@
 #define ABSL_WAITER_MODE ABSL_FORCE_WAITER_MODE
 #elif defined(_WIN32) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
 #define ABSL_WAITER_MODE ABSL_WAITER_MODE_WIN32
-#elif defined(__BIONIC__)
-// Bionic supports all the futex operations we need even when some of the futex
-// definitions are missing.
-#define ABSL_WAITER_MODE ABSL_WAITER_MODE_FUTEX
-#elif defined(__linux__) && defined(FUTEX_CLOCK_REALTIME)
-// FUTEX_CLOCK_REALTIME requires Linux >= 2.6.28.
+#elif defined(ABSL_INTERNAL_HAVE_FUTEX)
 #define ABSL_WAITER_MODE ABSL_WAITER_MODE_FUTEX
 #elif defined(ABSL_HAVE_SEMAPHORE_H)
 #define ABSL_WAITER_MODE ABSL_WAITER_MODE_SEM
@@ -100,8 +96,8 @@
   }
 
   // How many periods to remain idle before releasing resources
-#ifndef THREAD_SANITIZER
-  static const int kIdlePeriods = 60;
+#ifndef ABSL_HAVE_THREAD_SANITIZER
+  static constexpr int kIdlePeriods = 60;
 #else
   // Memory consumption under ThreadSanitizer is a serious concern,
   // so we release resources sooner. The value of 1 leads to 1 to 2 second
diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc
index e0879b0..76ad41f 100644
--- a/absl/synchronization/mutex.cc
+++ b/absl/synchronization/mutex.cc
@@ -39,6 +39,7 @@
 #include <thread>  // NOLINT(build/c++11)
 
 #include "absl/base/attributes.h"
+#include "absl/base/call_once.h"
 #include "absl/base/config.h"
 #include "absl/base/dynamic_annotations.h"
 #include "absl/base/internal/atomic_hook.h"
@@ -49,6 +50,7 @@
 #include "absl/base/internal/spinlock.h"
 #include "absl/base/internal/sysinfo.h"
 #include "absl/base/internal/thread_identity.h"
+#include "absl/base/internal/tsan_mutex_interface.h"
 #include "absl/base/port.h"
 #include "absl/debugging/stacktrace.h"
 #include "absl/debugging/symbolize.h"
@@ -58,6 +60,7 @@
 
 using absl::base_internal::CurrentThreadIdentityIfPresent;
 using absl::base_internal::PerThreadSynch;
+using absl::base_internal::SchedulingGuard;
 using absl::base_internal::ThreadIdentity;
 using absl::synchronization_internal::GetOrCreateCurrentThreadIdentity;
 using absl::synchronization_internal::GraphCycles;
@@ -67,7 +70,9 @@
 using absl::synchronization_internal::PerThreadSem;
 
 extern "C" {
-ABSL_ATTRIBUTE_WEAK void AbslInternalMutexYield() { std::this_thread::yield(); }
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalMutexYield)() {
+  std::this_thread::yield();
+}
 }  // extern "C"
 
 namespace absl {
@@ -75,7 +80,7 @@
 
 namespace {
 
-#if defined(THREAD_SANITIZER)
+#if defined(ABSL_HAVE_THREAD_SANITIZER)
 constexpr OnDeadlockCycle kDeadlockDetectionDefault = OnDeadlockCycle::kIgnore;
 #else
 constexpr OnDeadlockCycle kDeadlockDetectionDefault = OnDeadlockCycle::kAbort;
@@ -85,31 +90,9 @@
     kDeadlockDetectionDefault);
 ABSL_CONST_INIT std::atomic<bool> synch_check_invariants(false);
 
-// ------------------------------------------ spinlock support
-
-// Make sure read-only globals used in the Mutex code are contained on the
-// same cacheline and cacheline aligned to eliminate any false sharing with
-// other globals from this and other modules.
-static struct MutexGlobals {
-  MutexGlobals() {
-    // Find machine-specific data needed for Delay() and
-    // TryAcquireWithSpinning(). This runs in the global constructor
-    // sequence, and before that zeros are safe values.
-    num_cpus = absl::base_internal::NumCPUs();
-    spinloop_iterations = num_cpus > 1 ? 1500 : 0;
-  }
-  int num_cpus;
-  int spinloop_iterations;
-  // Pad this struct to a full cacheline to prevent false sharing.
-  char padding[ABSL_CACHELINE_SIZE - 2 * sizeof(int)];
-} ABSL_CACHELINE_ALIGNED mutex_globals;
-static_assert(
-    sizeof(MutexGlobals) == ABSL_CACHELINE_SIZE,
-    "MutexGlobals must occupy an entire cacheline to prevent false sharing");
-
 ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
-    absl::base_internal::AtomicHook<void (*)(int64_t wait_cycles)>
-        submit_profile_data;
+absl::base_internal::AtomicHook<void (*)(int64_t wait_cycles)>
+    submit_profile_data;
 ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook<void (*)(
     const char *msg, const void *obj, int64_t wait_cycles)>
     mutex_tracer;
@@ -143,33 +126,64 @@
   symbolizer.Store(fn);
 }
 
-// spinlock delay on iteration c.  Returns new c.
 namespace {
-  enum DelayMode { AGGRESSIVE, GENTLE };
+// Represents the strategy for spin and yield.
+// See the comment in GetMutexGlobals() for more information.
+enum DelayMode { AGGRESSIVE, GENTLE };
+
+struct ABSL_CACHELINE_ALIGNED MutexGlobals {
+  absl::once_flag once;
+  int spinloop_iterations = 0;
+  int32_t mutex_sleep_limit[2] = {};
 };
-static int Delay(int32_t c, DelayMode mode) {
-  // If this a uniprocessor, only yield/sleep.  Otherwise, if the mode is
-  // aggressive then spin many times before yielding.  If the mode is
-  // gentle then spin only a few times before yielding.  Aggressive spinning is
-  // used to ensure that an Unlock() call, which  must get the spin lock for
-  // any thread to make progress gets it without undue delay.
-  int32_t limit = (mutex_globals.num_cpus > 1) ?
-      ((mode == AGGRESSIVE) ? 5000 : 250) : 0;
+
+const MutexGlobals &GetMutexGlobals() {
+  ABSL_CONST_INIT static MutexGlobals data;
+  absl::base_internal::LowLevelCallOnce(&data.once, [&]() {
+    const int num_cpus = absl::base_internal::NumCPUs();
+    data.spinloop_iterations = num_cpus > 1 ? 1500 : 0;
+    // If this a uniprocessor, only yield/sleep.  Otherwise, if the mode is
+    // aggressive then spin many times before yielding.  If the mode is
+    // gentle then spin only a few times before yielding.  Aggressive spinning
+    // is used to ensure that an Unlock() call, which must get the spin lock
+    // for any thread to make progress gets it without undue delay.
+    if (num_cpus > 1) {
+      data.mutex_sleep_limit[AGGRESSIVE] = 5000;
+      data.mutex_sleep_limit[GENTLE] = 250;
+    } else {
+      data.mutex_sleep_limit[AGGRESSIVE] = 0;
+      data.mutex_sleep_limit[GENTLE] = 0;
+    }
+  });
+  return data;
+}
+}  // namespace
+
+namespace synchronization_internal {
+// Returns the Mutex delay on iteration `c` depending on the given `mode`.
+// The returned value should be used as `c` for the next call to `MutexDelay`.
+int MutexDelay(int32_t c, int mode) {
+  const int32_t limit = GetMutexGlobals().mutex_sleep_limit[mode];
   if (c < limit) {
-    c++;               // spin
+    // Spin.
+    c++;
   } else {
+    SchedulingGuard::ScopedEnable enable_rescheduling;
     ABSL_TSAN_MUTEX_PRE_DIVERT(nullptr, 0);
-    if (c == limit) {  // yield once
-      AbslInternalMutexYield();
+    if (c == limit) {
+      // Yield once.
+      ABSL_INTERNAL_C_SYMBOL(AbslInternalMutexYield)();
       c++;
-    } else {           // then wait
+    } else {
+      // Then wait.
       absl::SleepFor(absl::Microseconds(10));
       c = 0;
     }
     ABSL_TSAN_MUTEX_POST_DIVERT(nullptr, 0);
   }
-  return (c);
+  return c;
 }
+}  // namespace synchronization_internal
 
 // --------------------------Generic atomic ops
 // Ensure that "(*pv & bits) == bits" by doing an atomic update of "*pv" to
@@ -207,12 +221,12 @@
 //------------------------------------------------------------------
 
 // Data for doing deadlock detection.
-static absl::base_internal::SpinLock deadlock_graph_mu(
-    absl::base_internal::kLinkerInitialized);
+ABSL_CONST_INIT static absl::base_internal::SpinLock deadlock_graph_mu(
+    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
 
-// graph used to detect deadlocks.
-static GraphCycles *deadlock_graph ABSL_GUARDED_BY(deadlock_graph_mu)
-    ABSL_PT_GUARDED_BY(deadlock_graph_mu);
+// Graph used to detect deadlocks.
+ABSL_CONST_INIT static GraphCycles *deadlock_graph
+    ABSL_GUARDED_BY(deadlock_graph_mu) ABSL_PT_GUARDED_BY(deadlock_graph_mu);
 
 //------------------------------------------------------------------
 // An event mechanism for debugging mutex use.
@@ -273,13 +287,12 @@
     {0, "SignalAll on "},
 };
 
-static absl::base_internal::SpinLock synch_event_mu(
-    absl::base_internal::kLinkerInitialized);
-// protects synch_event
+ABSL_CONST_INIT static absl::base_internal::SpinLock synch_event_mu(
+    absl::kConstInit, 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.
-static const uint32_t kNSynchEvent = 1031;
+static constexpr uint32_t kNSynchEvent = 1031;
 
 static struct SynchEvent {     // this is a trivial hash table for the events
   // struct is freed when refcount reaches 0
@@ -299,7 +312,7 @@
   bool log;             // logging turned on
 
   // Constant after initialization
-  char name[1];         // actually longer---NUL-terminated std::string
+  char name[1];         // actually longer---NUL-terminated string
 } * synch_event[kNSynchEvent] ABSL_GUARDED_BY(synch_event_mu);
 
 // Ensure that the object at "addr" has a SynchEvent struct associated with it,
@@ -490,7 +503,7 @@
   std::atomic<intptr_t> *cv_word;
 
   int64_t contention_start_cycles;  // Time (in cycles) when this thread started
-                                  // to contend for the mutex.
+                                    // to contend for the mutex.
 };
 
 struct SynchLocksHeld {
@@ -546,7 +559,7 @@
 }
 
 // Post on "w"'s associated PerThreadSem.
-inline void Mutex::IncrementSynchSem(Mutex *mu, PerThreadSynch *w) {
+void Mutex::IncrementSynchSem(Mutex *mu, PerThreadSynch *w) {
   if (mu) {
     ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0);
   }
@@ -704,7 +717,7 @@
 static constexpr bool kDebugMode = true;
 #endif
 
-#ifdef THREAD_SANITIZER
+#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
 static unsigned TsanFlags(Mutex::MuHow how) {
   return how == kShared ? __tsan_mutex_read_lock : 0;
 }
@@ -750,11 +763,13 @@
   synch_deadlock_detection.store(mode, std::memory_order_release);
 }
 
-// Return true iff threads x and y are waiting on the same condition for the
-// same type of lock.  Requires that x and y be waiting on the same Mutex
-// queue.
-static bool MuSameCondition(PerThreadSynch *x, PerThreadSynch *y) {
-  return x->waitp->how == y->waitp->how &&
+// Return true iff threads x and y are part of the same equivalence
+// class of waiters. An equivalence class is defined as the set of
+// waiters with the same condition, type of lock, and thread priority.
+//
+// Requires that x and y be waiting on the same Mutex queue.
+static bool MuEquivalentWaiter(PerThreadSynch *x, PerThreadSynch *y) {
+  return x->waitp->how == y->waitp->how && x->priority == y->priority &&
          Condition::GuaranteedEqual(x->waitp->cond, y->waitp->cond);
 }
 
@@ -773,18 +788,19 @@
 //     - invalid (iff x is not in a Mutex wait queue),
 //     - null, or
 //     - a pointer to a distinct thread waiting later in the same Mutex queue
-//       such that all threads in [x, x->skip] have the same condition and
-//       lock type (MuSameCondition() is true for all pairs in [x, x->skip]).
+//       such that all threads in [x, x->skip] have the same condition, priority
+//       and lock type (MuEquivalentWaiter() is true for all pairs in [x,
+//       x->skip]).
 // In addition, if x->skip is  valid, (x->may_skip || x->skip == null)
 //
-// By the spec of MuSameCondition(), it is not necessary when removing the
+// By the spec of MuEquivalentWaiter(), it is not necessary when removing the
 // first runnable thread y from the front a Mutex queue to adjust the skip
 // field of another thread x because if x->skip==y, x->skip must (have) become
 // invalid before y is removed.  The function TryRemove can remove a specified
 // thread from an arbitrary position in the queue whether runnable or not, so
 // it fixes up skip fields that would otherwise be left dangling.
 // The statement
-//     if (x->may_skip && MuSameCondition(x, x->next)) { x->skip = x->next; }
+//     if (x->may_skip && MuEquivalentWaiter(x, x->next)) { x->skip = x->next; }
 // maintains the invariant provided x is not the last waiter in a Mutex queue
 // The statement
 //          if (x->skip != null) { x->skip = x->skip->skip; }
@@ -918,24 +934,17 @@
     if (s->priority > head->priority) {  // s's priority is above head's
       // try to put s in priority-fifo order, or failing that at the front.
       if (!head->maybe_unlocking) {
-        // No unlocker can be scanning the queue, so we can insert between
-        // skip-chains, and within a skip-chain if it has the same condition as
-        // s.  We insert in priority-fifo order, examining the end of every
-        // skip-chain, plus every element with the same condition as s.
+        // No unlocker can be scanning the queue, so we can insert into the
+        // middle of the queue.
+        //
+        // Within a skip chain, all waiters have the same priority, so we can
+        // skip forward through the chains until we find one with a lower
+        // priority than the waiter to be enqueued.
         PerThreadSynch *advance_to = head;    // next value of enqueue_after
-        PerThreadSynch *cur;                  // successor of enqueue_after
         do {
           enqueue_after = advance_to;
-          cur = enqueue_after->next;  // this advance ensures progress
-          advance_to = Skip(cur);   // normally, advance to end of skip chain
-                                    // (side-effect: optimizes skip chain)
-          if (advance_to != cur && s->priority > advance_to->priority &&
-              MuSameCondition(s, cur)) {
-            // but this skip chain is not a singleton, s has higher priority
-            // than its tail and has the same condition as the chain,
-            // so we can insert within the skip-chain
-            advance_to = cur;         // advance by just one
-          }
+          // (side-effect: optimizes skip chain)
+          advance_to = Skip(enqueue_after->next);
         } while (s->priority <= advance_to->priority);
               // termination guaranteed because s->priority > head->priority
               // and head is the end of a skip chain
@@ -954,21 +963,21 @@
 
       // enqueue_after can be: head, Skip(...), or cur.
       // The first two imply enqueue_after->skip == nullptr, and
-      // the last is used only if MuSameCondition(s, cur).
+      // the last is used only if MuEquivalentWaiter(s, cur).
       // We require this because clearing enqueue_after->skip
       // is impossible; enqueue_after's predecessors might also
       // incorrectly skip over s if we were to allow other
       // insertion points.
-      ABSL_RAW_CHECK(
-          enqueue_after->skip == nullptr || MuSameCondition(enqueue_after, s),
-          "Mutex Enqueue failure");
+      ABSL_RAW_CHECK(enqueue_after->skip == nullptr ||
+                         MuEquivalentWaiter(enqueue_after, s),
+                     "Mutex Enqueue failure");
 
       if (enqueue_after != head && enqueue_after->may_skip &&
-          MuSameCondition(enqueue_after, enqueue_after->next)) {
+          MuEquivalentWaiter(enqueue_after, enqueue_after->next)) {
         // enqueue_after can skip to its new successor, s
         enqueue_after->skip = enqueue_after->next;
       }
-      if (MuSameCondition(s, s->next)) {  // s->may_skip is known to be true
+      if (MuEquivalentWaiter(s, s->next)) {  // s->may_skip is known to be true
         s->skip = s->next;                // s may skip to its successor
       }
     } else {   // enqueue not done any other way, so
@@ -978,7 +987,7 @@
       head->next = s;
       s->readers = head->readers;  // reader count is from previous head
       s->maybe_unlocking = head->maybe_unlocking;  // same for unlock hint
-      if (head->may_skip && MuSameCondition(head, s)) {
+      if (head->may_skip && MuEquivalentWaiter(head, s)) {
         // head now has successor; may skip
         head->skip = s;
       }
@@ -998,7 +1007,7 @@
   pw->next = w->next;         // snip w out of list
   if (head == w) {            // we removed the head
     head = (pw == w) ? nullptr : pw;  // either emptied list, or pw is new head
-  } else if (pw != head && MuSameCondition(pw, pw->next)) {
+  } else if (pw != head && MuEquivalentWaiter(pw, pw->next)) {
     // pw can skip to its new successor
     if (pw->next->skip !=
         nullptr) {  // either skip to its successors skip target
@@ -1055,6 +1064,7 @@
 // Try to remove thread s from the list of waiters on this mutex.
 // Does nothing if s is not on the waiter list.
 void Mutex::TryRemove(PerThreadSynch *s) {
+  SchedulingGuard::ScopedDisable disable_rescheduling;
   intptr_t v = mu_.load(std::memory_order_relaxed);
   // acquire spinlock & lock
   if ((v & (kMuWait | kMuSpin | kMuWriter | kMuReader)) == kMuWait &&
@@ -1067,11 +1077,13 @@
       PerThreadSynch *w;
       if ((w = pw->next) != s) {  // search for thread,
         do {                      // processing at least one element
-          if (!MuSameCondition(s, w)) {  // seeking different condition
+          // If the current element isn't equivalent to the waiter to be
+          // removed, we can skip the entire chain.
+          if (!MuEquivalentWaiter(s, w)) {
             pw = Skip(w);                // so skip all that won't match
             // we don't have to worry about dangling skip fields
             // in the threads we skipped; none can point to s
-            // because their condition differs from s
+            // because they are in a different equivalence class.
           } else {          // seeking same condition
             FixSkip(w, s);  // fix up any skip pointer from w to s
             pw = w;
@@ -1119,7 +1131,7 @@
       this->TryRemove(s);
       int c = 0;
       while (s->next != nullptr) {
-        c = Delay(c, GENTLE);
+        c = synchronization_internal::MutexDelay(c, GENTLE);
         this->TryRemove(s);
       }
       if (kDebugMode) {
@@ -1362,7 +1374,9 @@
           len += static_cast<int>(strlen(&b->buf[len]));
         }
       }
-      ABSL_RAW_LOG(ERROR, "Acquiring %p    Mutexes held: %s",
+      ABSL_RAW_LOG(ERROR,
+                   "Acquiring absl::Mutex %p while holding %s; a cycle in the "
+                   "historical lock ordering graph has been observed",
                    static_cast<void *>(mu), b->buf);
       ABSL_RAW_LOG(ERROR, "Cycle: ");
       int path_len = deadlock_graph->FindPath(
@@ -1438,21 +1452,19 @@
 // Attempt to acquire *mu, and return whether successful.  The implementation
 // may spin for a short while if the lock cannot be acquired immediately.
 static bool TryAcquireWithSpinning(std::atomic<intptr_t>* mu) {
-  int c = mutex_globals.spinloop_iterations;
-  int result = -1;  // result of operation:  0=false, 1=true, -1=unknown
-
+  int c = GetMutexGlobals().spinloop_iterations;
   do {  // do/while somewhat faster on AMD
     intptr_t v = mu->load(std::memory_order_relaxed);
-    if ((v & (kMuReader|kMuEvent)) != 0) {  // a reader or tracing -> give up
-      result = 0;
+    if ((v & (kMuReader|kMuEvent)) != 0) {
+      return false;  // a reader or tracing -> give up
     } else if (((v & kMuWriter) == 0) &&  // no holder -> try to acquire
                mu->compare_exchange_strong(v, kMuWriter | v,
                                            std::memory_order_acquire,
                                            std::memory_order_relaxed)) {
-      result = 1;
+      return true;
     }
-  } while (result == -1 && --c > 0);
-  return result == 1;
+  } while (--c > 0);
+  return false;
 }
 
 ABSL_XRAY_LOG_ARGS(1) void Mutex::Lock() {
@@ -1751,7 +1763,8 @@
 };
 
 // Internal version of LockWhen().  See LockSlowWithDeadline()
-void Mutex::LockSlow(MuHow how, const Condition *cond, int flags) {
+ABSL_ATTRIBUTE_NOINLINE void Mutex::LockSlow(MuHow how, const Condition *cond,
+                                             int flags) {
   ABSL_RAW_CHECK(
       this->LockSlowWithDeadline(how, cond, KernelTimeout::Never(), flags),
       "condition untrue on return from LockSlow");
@@ -1766,7 +1779,7 @@
   // All memory accesses are ignored inside of mutex operations + for unlock
   // operation tsan considers that we've already released the mutex.
   bool res = false;
-#ifdef THREAD_SANITIZER
+#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
   const int flags = read_lock ? __tsan_mutex_read_lock : 0;
   const int tryflags = flags | (trylock ? __tsan_mutex_try_lock : 0);
 #endif
@@ -1816,9 +1829,9 @@
   // So we "divert" (which un-ignores both memory accesses and synchronization)
   // and then separately turn on ignores of memory accesses.
   ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0);
-  ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
+  ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
   bool res = cond->Eval();
-  ANNOTATE_IGNORE_READS_AND_WRITES_END();
+  ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END();
   ABSL_TSAN_MUTEX_POST_DIVERT(mu, 0);
   static_cast<void>(mu);  // Prevent unused param warning in non-TSAN builds.
   return res;
@@ -1899,6 +1912,7 @@
 }
 
 void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) {
+  SchedulingGuard::ScopedDisable disable_rescheduling;
   int c = 0;
   intptr_t v = mu_.load(std::memory_order_relaxed);
   if ((v & kMuEvent) != 0) {
@@ -2000,7 +2014,8 @@
     ABSL_RAW_CHECK(
         waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors,
         "detected illegal recursion into Mutex code");
-    c = Delay(c, GENTLE);          // delay, then try again
+    // delay, then try again
+    c = synchronization_internal::MutexDelay(c, GENTLE);
   }
   ABSL_RAW_CHECK(
       waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors,
@@ -2017,7 +2032,8 @@
 // which holds the lock but is not runnable because its condition is false
 // or it is in the process of blocking on a condition variable; it must requeue
 // itself on the mutex/condvar to wait for its condition to become true.
-void Mutex::UnlockSlow(SynchWaitParams *waitp) {
+ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) {
+  SchedulingGuard::ScopedDisable disable_rescheduling;
   intptr_t v = mu_.load(std::memory_order_relaxed);
   this->AssertReaderHeld();
   CheckForMutexCorruption(v, "Unlock");
@@ -2134,7 +2150,7 @@
           !old_h->may_skip) {                  // we used old_h as a terminator
         old_h->may_skip = true;                // allow old_h to skip once more
         ABSL_RAW_CHECK(old_h->skip == nullptr, "illegal skip from head");
-        if (h != old_h && MuSameCondition(old_h, old_h->next)) {
+        if (h != old_h && MuEquivalentWaiter(old_h, old_h->next)) {
           old_h->skip = old_h->next;  // old_h not head & can skip to successor
         }
       }
@@ -2294,7 +2310,8 @@
       mu_.store(nv, std::memory_order_release);
       break;  // out of for(;;)-loop
     }
-    c = Delay(c, AGGRESSIVE);  // aggressive here; no one can proceed till we do
+    // aggressive here; no one can proceed till we do
+    c = synchronization_internal::MutexDelay(c, AGGRESSIVE);
   }                            // end of for(;;)-loop
 
   if (wake_list != kPerThreadSynchNull) {
@@ -2306,7 +2323,8 @@
     if (!cond_waiter) {
       // Sample lock contention events only if the (first) waiter was trying to
       // acquire the lock, not waiting on a condition variable or Condition.
-      int64_t wait_cycles = base_internal::CycleClock::Now() - enqueue_timestamp;
+      int64_t wait_cycles =
+          base_internal::CycleClock::Now() - enqueue_timestamp;
       mutex_tracer("slow release", this, wait_cycles);
       ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
       submit_profile_data(enqueue_timestamp);
@@ -2333,6 +2351,7 @@
 // It will later acquire the mutex with high probability.  Otherwise, we
 // enqueue thread w on this mutex.
 void Mutex::Fer(PerThreadSynch *w) {
+  SchedulingGuard::ScopedDisable disable_rescheduling;
   int c = 0;
   ABSL_RAW_CHECK(w->waitp->cond == nullptr,
                  "Mutex::Fer while waiting on Condition");
@@ -2382,7 +2401,7 @@
         return;
       }
     }
-    c = Delay(c, GENTLE);
+    c = synchronization_internal::MutexDelay(c, GENTLE);
   }
 }
 
@@ -2431,6 +2450,7 @@
 
 // Remove thread s from the list of waiters on this condition variable.
 void CondVar::Remove(PerThreadSynch *s) {
+  SchedulingGuard::ScopedDisable disable_rescheduling;
   intptr_t v;
   int c = 0;
   for (v = cv_.load(std::memory_order_relaxed);;
@@ -2459,7 +2479,8 @@
                 std::memory_order_release);
       return;
     } else {
-      c = Delay(c, GENTLE);            // try again after a delay
+      // try again after a delay
+      c = synchronization_internal::MutexDelay(c, GENTLE);
     }
   }
 }
@@ -2492,7 +2513,7 @@
          !cv_word->compare_exchange_weak(v, v | kCvSpin,
                                          std::memory_order_acquire,
                                          std::memory_order_relaxed)) {
-    c = Delay(c, GENTLE);
+    c = synchronization_internal::MutexDelay(c, GENTLE);
     v = cv_word->load(std::memory_order_relaxed);
   }
   ABSL_RAW_CHECK(waitp->thread->waitp == nullptr, "waiting when shouldn't be");
@@ -2591,6 +2612,7 @@
 }
 
 void CondVar::Signal() {
+  SchedulingGuard::ScopedDisable disable_rescheduling;
   ABSL_TSAN_MUTEX_PRE_SIGNAL(nullptr, 0);
   intptr_t v;
   int c = 0;
@@ -2623,7 +2645,7 @@
       ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
       return;
     } else {
-      c = Delay(c, GENTLE);
+      c = synchronization_internal::MutexDelay(c, GENTLE);
     }
   }
   ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
@@ -2660,7 +2682,8 @@
       ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
       return;
     } else {
-      c = Delay(c, GENTLE);           // try again after a delay
+      // try again after a delay
+      c = synchronization_internal::MutexDelay(c, GENTLE);
     }
   }
   ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
@@ -2673,7 +2696,7 @@
   this->mu_ = nullptr;
 }
 
-#ifdef THREAD_SANITIZER
+#ifdef ABSL_HAVE_THREAD_SANITIZER
 extern "C" void __tsan_read1(void *addr);
 #else
 #define __tsan_read1(addr)  // do nothing if TSan not enabled
diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h
index 8c70c4c..f49e0c8 100644
--- a/absl/synchronization/mutex.h
+++ b/absl/synchronization/mutex.h
@@ -31,22 +31,23 @@
 //
 //  MutexLock - An RAII wrapper to acquire and release a `Mutex` for exclusive/
 //              write access within the current scope.
+//
 //  ReaderMutexLock
 //            - An RAII wrapper to acquire and release a `Mutex` for shared/read
 //              access within the current scope.
 //
 //  WriterMutexLock
-//            - Alias for `MutexLock` above, designed for use in distinguishing
-//              reader and writer locks within code.
+//            - Effectively an alias for `MutexLock` above, designed for use in
+//              distinguishing reader and writer locks within code.
 //
 // In addition to simple mutex locks, this file also defines ways to perform
 // locking under certain conditions.
 //
-//  Condition   - (Preferred) Used to wait for a particular predicate that
-//                depends on state protected by the `Mutex` to become true.
-//  CondVar     - A lower-level variant of `Condition` that relies on
-//                application code to explicitly signal the `CondVar` when
-//                a condition has been met.
+//  Condition - (Preferred) Used to wait for a particular predicate that
+//              depends on state protected by the `Mutex` to become true.
+//  CondVar   - A lower-level variant of `Condition` that relies on
+//              application code to explicitly signal the `CondVar` when
+//              a condition has been met.
 //
 // See below for more information on using `Condition` or `CondVar`.
 //
@@ -72,15 +73,6 @@
 #include "absl/synchronization/internal/per_thread_sem.h"
 #include "absl/time/time.h"
 
-// Decide if we should use the non-production implementation because
-// the production implementation hasn't been fully ported yet.
-#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
-#error ABSL_INTERNAL_USE_NONPROD_MUTEX cannot be directly set
-#elif defined(ABSL_LOW_LEVEL_ALLOC_MISSING)
-#define ABSL_INTERNAL_USE_NONPROD_MUTEX 1
-#include "absl/synchronization/internal/mutex_nonprod.inc"
-#endif
-
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
@@ -155,7 +147,7 @@
   //
   // Example usage:
   //   namespace foo {
-  //   ABSL_CONST_INIT Mutex mu(absl::kConstInit);
+  //   ABSL_CONST_INIT absl::Mutex mu(absl::kConstInit);
   //   }
   explicit constexpr Mutex(absl::ConstInitType);
 
@@ -170,7 +162,7 @@
   // Mutex::Unlock()
   //
   // Releases this `Mutex` and returns it from the exclusive/write state to the
-  // free state. Caller must hold the `Mutex` exclusively.
+  // free state. Calling thread must hold the `Mutex` exclusively.
   void Unlock() ABSL_UNLOCK_FUNCTION();
 
   // Mutex::TryLock()
@@ -331,17 +323,16 @@
   // Mutex::AwaitWithTimeout()
   // Mutex::AwaitWithDeadline()
   //
-  // If `cond` is initially true, do nothing, or act as though `cond` is
-  // initially false.
-  //
-  // If `cond` is initially false, unlock this `Mutex` and block until
-  // simultaneously:
+  // Unlocks this `Mutex` and blocks until simultaneously:
   //   - either `cond` is true or the {timeout has expired, deadline has passed}
   //     and
   //   - this `Mutex` can be reacquired,
   // then reacquire this `Mutex` in the same mode in which it was previously
   // held, returning `true` iff `cond` is `true` on return.
   //
+  // If the condition is initially `true`, the implementation *may* skip the
+  // release/re-acquire step and return immediately.
+  //
   // Deadlines in the past are equivalent to an immediate deadline.
   // Negative timeouts are equivalent to a zero timeout.
   //
@@ -462,24 +453,13 @@
   static void InternalAttemptToUseMutexInFatalSignalHandler();
 
  private:
-#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
-  friend class CondVar;
-
-  synchronization_internal::MutexImpl *impl() { return impl_.get(); }
-
-  synchronization_internal::SynchronizationStorage<
-      synchronization_internal::MutexImpl>
-      impl_;
-#else
   std::atomic<intptr_t> mu_;  // The Mutex state.
 
   // Post()/Wait() versus associated PerThreadSem; in class for required
   // friendship with PerThreadSem.
-  static inline void IncrementSynchSem(Mutex *mu,
-                                       base_internal::PerThreadSynch *w);
-  static inline bool DecrementSynchSem(
-      Mutex *mu, base_internal::PerThreadSynch *w,
-      synchronization_internal::KernelTimeout t);
+  static void IncrementSynchSem(Mutex *mu, base_internal::PerThreadSynch *w);
+  static bool DecrementSynchSem(Mutex *mu, base_internal::PerThreadSynch *w,
+                                synchronization_internal::KernelTimeout t);
 
   // slow path acquire
   void LockSlowLoop(SynchWaitParams *waitp, int flags);
@@ -505,7 +485,6 @@
   void Trans(MuHow how);  // used for CondVar->Mutex transfer
   void Fer(
       base_internal::PerThreadSynch *w);  // used for CondVar->Mutex transfer
-#endif
 
   // Catch the error of writing Mutex when intending MutexLock.
   Mutex(const volatile Mutex * /*ignored*/) {}  // NOLINT(runtime/explicit)
@@ -526,22 +505,36 @@
 // Example:
 //
 // Class Foo {
-//
+//  public:
 //   Foo::Bar* Baz() {
-//     MutexLock l(&lock_);
+//     MutexLock lock(&mu_);
 //     ...
 //     return bar;
 //   }
 //
 // private:
-//   Mutex lock_;
+//   Mutex mu_;
 // };
 class ABSL_SCOPED_LOCKABLE MutexLock {
  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 *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 *mu, const Condition &cond)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    this->mu_->LockWhen(cond);
+  }
+
   MutexLock(const MutexLock &) = delete;  // NOLINT(runtime/mutex)
   MutexLock(MutexLock&&) = delete;  // NOLINT(runtime/mutex)
   MutexLock& operator=(const MutexLock&) = delete;
@@ -563,6 +556,12 @@
     mu->ReaderLock();
   }
 
+  explicit ReaderMutexLock(Mutex *mu, const Condition &cond)
+      ABSL_SHARED_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    mu->ReaderLockWhen(cond);
+  }
+
   ReaderMutexLock(const ReaderMutexLock&) = delete;
   ReaderMutexLock(ReaderMutexLock&&) = delete;
   ReaderMutexLock& operator=(const ReaderMutexLock&) = delete;
@@ -585,6 +584,12 @@
     mu->WriterLock();
   }
 
+  explicit WriterMutexLock(Mutex *mu, const Condition &cond)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    mu->WriterLockWhen(cond);
+  }
+
   WriterMutexLock(const WriterMutexLock&) = delete;
   WriterMutexLock(WriterMutexLock&&) = delete;
   WriterMutexLock& operator=(const WriterMutexLock&) = delete;
@@ -623,16 +628,26 @@
 // `noexcept`; until then this requirement cannot be enforced in the
 // type system.)
 //
-// Note: to use a `Condition`, you need only construct it and pass it within the
-// appropriate `Mutex' member function, such as `Mutex::Await()`.
+// Note: to use a `Condition`, you need only construct it and pass it to a
+// suitable `Mutex' member function, such as `Mutex::Await()`, or to the
+// constructor of one of the scope guard classes.
 //
-// Example:
+// Example using LockWhen/Unlock:
 //
 //   // assume count_ is not internal reference count
 //   int count_ ABSL_GUARDED_BY(mu_);
+//   Condition count_is_zero(+[](int *count) { return *count == 0; }, &count_);
 //
-//   mu_.LockWhen(Condition(+[](int* count) { return *count == 0; },
-//         &count_));
+//   mu_.LockWhen(count_is_zero);
+//   // ...
+//   mu_.Unlock();
+//
+// Example using a scope guard:
+//
+//   {
+//     MutexLock lock(&mu_, count_is_zero);
+//     // ...
+//   }
 //
 // When multiple threads are waiting on exactly the same condition, make sure
 // that they are constructed with the same parameters (same pointer to function
@@ -686,6 +701,11 @@
   //     return processed_ >= current;
   //   };
   //   mu_.Await(Condition(&reached));
+  //
+  // NOTE: never use "mu_.AssertHeld()" instead of "mu_.AssertReaderHeld()" in
+  // the lambda as it may be called when the mutex is being unlocked from a
+  // scope holding only a reader lock, which will make the assertion not
+  // fulfilled and crash the binary.
 
   // See class comment for performance advice. In particular, if there
   // might be more than one waiter for the same condition, make sure
@@ -770,6 +790,8 @@
 //
 class CondVar {
  public:
+  // A `CondVar` allocated on the heap or on the stack can use the this
+  // constructor.
   CondVar();
   ~CondVar();
 
@@ -832,17 +854,10 @@
   void EnableDebugLog(const char *name);
 
  private:
-#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
-  synchronization_internal::CondVarImpl *impl() { return impl_.get(); }
-  synchronization_internal::SynchronizationStorage<
-      synchronization_internal::CondVarImpl>
-      impl_;
-#else
   bool WaitCommon(Mutex *mutex, synchronization_internal::KernelTimeout t);
   void Remove(base_internal::PerThreadSynch *s);
   void Wakeup(base_internal::PerThreadSynch *w);
   std::atomic<intptr_t> cv_;  // Condition variable state.
-#endif
   CondVar(const CondVar&) = delete;
   CondVar& operator=(const CondVar&) = delete;
 };
@@ -864,6 +879,15 @@
       this->mu_->Lock();
     }
   }
+
+  explicit MutexLockMaybe(Mutex *mu, const Condition &cond)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    if (this->mu_ != nullptr) {
+      this->mu_->LockWhen(cond);
+    }
+  }
+
   ~MutexLockMaybe() ABSL_UNLOCK_FUNCTION() {
     if (this->mu_ != nullptr) { this->mu_->Unlock(); }
   }
@@ -886,6 +910,13 @@
       : mu_(mu) {
     this->mu_->Lock();
   }
+
+  explicit ReleasableMutexLock(Mutex *mu, const Condition &cond)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    this->mu_->LockWhen(cond);
+  }
+
   ~ReleasableMutexLock() ABSL_UNLOCK_FUNCTION() {
     if (this->mu_ != nullptr) { this->mu_->Unlock(); }
   }
@@ -900,10 +931,6 @@
   ReleasableMutexLock& operator=(ReleasableMutexLock&&) = delete;
 };
 
-#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
-inline constexpr Mutex::Mutex(absl::ConstInitType) : impl_(absl::kConstInit) {}
-
-#else
 inline Mutex::Mutex() : mu_(0) {
   ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
 }
@@ -911,7 +938,6 @@
 inline constexpr Mutex::Mutex(absl::ConstInitType) : mu_(0) {}
 
 inline CondVar::CondVar() : cv_(0) {}
-#endif
 
 // static
 template <typename T>
@@ -979,7 +1005,7 @@
 //
 // This has the same memory ordering concerns as RegisterMutexProfiler() above.
 void RegisterMutexTracer(void (*fn)(const char *msg, const void *obj,
-                              int64_t wait_cycles));
+                                    int64_t wait_cycles));
 
 // TODO(gfalcon): Combine RegisterMutexProfiler() and RegisterMutexTracer()
 // into a single interface, since they are only ever called in pairs.
@@ -1050,7 +1076,7 @@
 // By changing our extension points to be extern "C", we dodge this
 // check.
 extern "C" {
-void AbslInternalMutexYield();
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalMutexYield)();
 }  // extern "C"
 
 #endif  // ABSL_SYNCHRONIZATION_MUTEX_H_
diff --git a/absl/synchronization/mutex_benchmark.cc b/absl/synchronization/mutex_benchmark.cc
index ab18800..e35aed8 100644
--- a/absl/synchronization/mutex_benchmark.cc
+++ b/absl/synchronization/mutex_benchmark.cc
@@ -16,6 +16,7 @@
 #include <mutex>  // NOLINT(build/c++11)
 #include <vector>
 
+#include "absl/base/config.h"
 #include "absl/base/internal/cycleclock.h"
 #include "absl/base/internal/spinlock.h"
 #include "absl/synchronization/blocking_counter.h"
@@ -60,8 +61,124 @@
   std::mutex* mu_;
 };
 
+// RAII object to change the Mutex priority of the running thread.
+class ScopedThreadMutexPriority {
+ public:
+  explicit ScopedThreadMutexPriority(int priority) {
+    absl::base_internal::ThreadIdentity* identity =
+        absl::synchronization_internal::GetOrCreateCurrentThreadIdentity();
+    identity->per_thread_synch.priority = priority;
+    // Bump next_priority_read_cycles to the infinite future so that the
+    // implementation doesn't re-read the thread's actual scheduler priority
+    // and replace our temporary scoped priority.
+    identity->per_thread_synch.next_priority_read_cycles =
+        std::numeric_limits<int64_t>::max();
+  }
+  ~ScopedThreadMutexPriority() {
+    // Reset the "next priority read time" back to the infinite past so that
+    // the next time the Mutex implementation wants to know this thread's
+    // priority, it re-reads it from the OS instead of using our overridden
+    // priority.
+    absl::synchronization_internal::GetOrCreateCurrentThreadIdentity()
+        ->per_thread_synch.next_priority_read_cycles =
+        std::numeric_limits<int64_t>::min();
+  }
+};
+
+void BM_MutexEnqueue(benchmark::State& state) {
+  // In the "multiple priorities" variant of the benchmark, one of the
+  // threads runs with Mutex priority 0 while the rest run at elevated priority.
+  // This benchmarks the performance impact of the presence of a low priority
+  // waiter when a higher priority waiter adds itself of the queue
+  // (b/175224064).
+  //
+  // NOTE: The actual scheduler priority is not modified in this benchmark:
+  // all of the threads get CPU slices with the same priority. Only the
+  // Mutex queueing behavior is modified.
+  const bool multiple_priorities = state.range(0);
+  ScopedThreadMutexPriority priority_setter(
+      (multiple_priorities && state.thread_index != 0) ? 1 : 0);
+
+  struct Shared {
+    absl::Mutex mu;
+    std::atomic<int> looping_threads{0};
+    std::atomic<int> blocked_threads{0};
+    std::atomic<bool> thread_has_mutex{false};
+  };
+  static Shared* shared = new Shared;
+
+  // Set up 'blocked_threads' to count how many threads are currently blocked
+  // in Abseil synchronization code.
+  //
+  // NOTE: Blocking done within the Google Benchmark library itself (e.g.
+  // the barrier which synchronizes threads entering and exiting the benchmark
+  // loop) does _not_ get registered in this counter. This is because Google
+  // Benchmark uses its own synchronization primitives based on std::mutex, not
+  // Abseil synchronization primitives. If at some point the benchmark library
+  // merges into Abseil, this code may break.
+  absl::synchronization_internal::PerThreadSem::SetThreadBlockedCounter(
+      &shared->blocked_threads);
+
+  // The benchmark framework may run several iterations in the same process,
+  // reusing the same static-initialized 'shared' object. Given the semantics
+  // of the members, here, we expect everything to be reset to zero by the
+  // end of any iteration. Assert that's the case, just to be sure.
+  ABSL_RAW_CHECK(
+      shared->looping_threads.load(std::memory_order_relaxed) == 0 &&
+          shared->blocked_threads.load(std::memory_order_relaxed) == 0 &&
+          !shared->thread_has_mutex.load(std::memory_order_relaxed),
+      "Shared state isn't zeroed at start of benchmark iteration");
+
+  static constexpr int kBatchSize = 1000;
+  while (state.KeepRunningBatch(kBatchSize)) {
+    shared->looping_threads.fetch_add(1);
+    for (int i = 0; i < kBatchSize; i++) {
+      {
+        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
+        // at its maximal length to benchmark the performance of queueing on
+        // a highly contended mutex.
+        while (shared->looping_threads.load(std::memory_order_relaxed) -
+                   shared->blocked_threads.load(std::memory_order_relaxed) !=
+               1) {
+        }
+        shared->thread_has_mutex.store(false);
+      }
+      // Spin until some other thread has acquired the mutex before we block
+      // again. This ensures that we always go through the slow (queueing)
+      // acquisition path rather than reacquiring the mutex we just released.
+      while (!shared->thread_has_mutex.load(std::memory_order_relaxed) &&
+             shared->looping_threads.load(std::memory_order_relaxed) > 1) {
+      }
+    }
+    // The benchmark framework uses a barrier to ensure that all of the threads
+    // complete their benchmark loop together before any of the threads exit
+    // the loop. So, we need to remove ourselves from the "looping threads"
+    // counter here before potentially blocking on that barrier. Otherwise,
+    // another thread spinning above might wait forever for this thread to
+    // block on the mutex while we in fact are waiting to exit.
+    shared->looping_threads.fetch_add(-1);
+  }
+  absl::synchronization_internal::PerThreadSem::SetThreadBlockedCounter(
+      nullptr);
+}
+
+BENCHMARK(BM_MutexEnqueue)
+    ->Threads(4)
+    ->Threads(64)
+    ->Threads(128)
+    ->Threads(512)
+    ->ArgName("multiple_priorities")
+    ->Arg(false)
+    ->Arg(true);
+
 template <typename MutexType>
 void BM_Contended(benchmark::State& state) {
+  int priority = state.thread_index % state.range(1);
+  ScopedThreadMutexPriority priority_setter(priority);
+
   struct Shared {
     MutexType mu;
     int data = 0;
@@ -84,81 +201,51 @@
     DelayNs(state.range(0), &shared->data);
   }
 }
+void SetupBenchmarkArgs(benchmark::internal::Benchmark* bm,
+                        bool do_test_priorities) {
+  const int max_num_priorities = do_test_priorities ? 2 : 1;
+  bm->UseRealTime()
+      // ThreadPerCpu poorly handles non-power-of-two CPU counts.
+      ->Threads(1)
+      ->Threads(2)
+      ->Threads(4)
+      ->Threads(6)
+      ->Threads(8)
+      ->Threads(12)
+      ->Threads(16)
+      ->Threads(24)
+      ->Threads(32)
+      ->Threads(48)
+      ->Threads(64)
+      ->Threads(96)
+      ->Threads(128)
+      ->Threads(192)
+      ->Threads(256)
+      ->ArgNames({"cs_ns", "num_prios"});
+  // Some empirically chosen amounts of work in critical section.
+  // 1 is low contention, 2000 is high contention and few values in between.
+  for (int critical_section_ns : {1, 20, 50, 200, 2000}) {
+    for (int num_priorities = 1; num_priorities <= max_num_priorities;
+         num_priorities++) {
+      bm->ArgPair(critical_section_ns, num_priorities);
+    }
+  }
+}
 
 BENCHMARK_TEMPLATE(BM_Contended, absl::Mutex)
-    ->UseRealTime()
-    // ThreadPerCpu poorly handles non-power-of-two CPU counts.
-    ->Threads(1)
-    ->Threads(2)
-    ->Threads(4)
-    ->Threads(6)
-    ->Threads(8)
-    ->Threads(12)
-    ->Threads(16)
-    ->Threads(24)
-    ->Threads(32)
-    ->Threads(48)
-    ->Threads(64)
-    ->Threads(96)
-    ->Threads(128)
-    ->Threads(192)
-    ->Threads(256)
-    // Some empirically chosen amounts of work in critical section.
-    // 1 is low contention, 200 is high contention and few values in between.
-    ->Arg(1)
-    ->Arg(20)
-    ->Arg(50)
-    ->Arg(200);
+    ->Apply([](benchmark::internal::Benchmark* bm) {
+      SetupBenchmarkArgs(bm, /*do_test_priorities=*/true);
+    });
 
 BENCHMARK_TEMPLATE(BM_Contended, absl::base_internal::SpinLock)
-    ->UseRealTime()
-    // ThreadPerCpu poorly handles non-power-of-two CPU counts.
-    ->Threads(1)
-    ->Threads(2)
-    ->Threads(4)
-    ->Threads(6)
-    ->Threads(8)
-    ->Threads(12)
-    ->Threads(16)
-    ->Threads(24)
-    ->Threads(32)
-    ->Threads(48)
-    ->Threads(64)
-    ->Threads(96)
-    ->Threads(128)
-    ->Threads(192)
-    ->Threads(256)
-    // Some empirically chosen amounts of work in critical section.
-    // 1 is low contention, 200 is high contention and few values in between.
-    ->Arg(1)
-    ->Arg(20)
-    ->Arg(50)
-    ->Arg(200);
+    ->Apply([](benchmark::internal::Benchmark* bm) {
+      SetupBenchmarkArgs(bm, /*do_test_priorities=*/false);
+    });
 
 BENCHMARK_TEMPLATE(BM_Contended, std::mutex)
-    ->UseRealTime()
-    // ThreadPerCpu poorly handles non-power-of-two CPU counts.
-    ->Threads(1)
-    ->Threads(2)
-    ->Threads(4)
-    ->Threads(6)
-    ->Threads(8)
-    ->Threads(12)
-    ->Threads(16)
-    ->Threads(24)
-    ->Threads(32)
-    ->Threads(48)
-    ->Threads(64)
-    ->Threads(96)
-    ->Threads(128)
-    ->Threads(192)
-    ->Threads(256)
-    // Some empirically chosen amounts of work in critical section.
-    // 1 is low contention, 200 is high contention and few values in between.
-    ->Arg(1)
-    ->Arg(20)
-    ->Arg(50)
-    ->Arg(200);
+    ->Apply([](benchmark::internal::Benchmark* bm) {
+      SetupBenchmarkArgs(bm, /*do_test_priorities=*/false);
+    });
 
 // Measure the overhead of conditions on mutex release (when they must be
 // evaluated).  Mutex has (some) support for equivalence classes allowing
@@ -213,7 +300,7 @@
 }
 
 // Some configurations have higher thread limits than others.
-#if defined(__linux__) && !defined(THREAD_SANITIZER)
+#if defined(__linux__) && !defined(ABSL_HAVE_THREAD_SANITIZER)
 constexpr int kMaxConditionWaiters = 8192;
 #else
 constexpr int kMaxConditionWaiters = 1024;
diff --git a/absl/synchronization/mutex_test.cc b/absl/synchronization/mutex_test.cc
index afb363a..f8fbf94 100644
--- a/absl/synchronization/mutex_test.cc
+++ b/absl/synchronization/mutex_test.cc
@@ -30,6 +30,7 @@
 
 #include "gtest/gtest.h"
 #include "absl/base/attributes.h"
+#include "absl/base/config.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/internal/sysinfo.h"
 #include "absl/memory/memory.h"
@@ -706,6 +707,40 @@
   t.join();
 }
 
+TEST(Mutex, LockWhenGuard) {
+  absl::Mutex mu;
+  int n = 30;
+  bool done = false;
+
+  // We don't inline the lambda because the conversion is ambiguous in MSVC.
+  bool (*cond_eq_10)(int *) = [](int *p) { return *p == 10; };
+  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));
+    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));
+      ++n;
+    });
+  }
+
+  {
+    absl::MutexLock lock(&mu);
+    n = 0;
+  }
+
+  for (std::thread &t : t2) t.join();
+  t1.join();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(n, 10);
+}
+
 // --------------------------------------------------------
 // The following test requires Mutex::ReaderLock to be a real shared
 // lock, which is not the case in all builds.
@@ -815,9 +850,9 @@
 
 // Test that we correctly handle the situation when a lock is
 // held and then destroyed (w/o unlocking).
-#ifdef THREAD_SANITIZER
+#ifdef ABSL_HAVE_THREAD_SANITIZER
 // TSAN reports errors when locked Mutexes are destroyed.
-TEST(Mutex, DISABLED_LockedMutexDestructionBug) NO_THREAD_SAFETY_ANALYSIS {
+TEST(Mutex, DISABLED_LockedMutexDestructionBug) ABSL_NO_THREAD_SAFETY_ANALYSIS {
 #else
 TEST(Mutex, LockedMutexDestructionBug) ABSL_NO_THREAD_SAFETY_ANALYSIS {
 #endif
@@ -1001,9 +1036,6 @@
   x.mu0.Unlock();
 }
 
-// The deadlock detector is not part of non-prod builds, so do not test it.
-#if !defined(ABSL_INTERNAL_USE_NONPROD_MUTEX)
-
 TEST(Mutex, DeadlockDetector) {
   absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);
 
@@ -1067,7 +1099,7 @@
 const char ScopedDisableBazelTestWarnings::kVarName[] =
     "TEST_WARNINGS_OUTPUT_FILE";
 
-#ifdef THREAD_SANITIZER
+#ifdef ABSL_HAVE_THREAD_SANITIZER
 // This test intentionally creates deadlocks to test the deadlock detector.
 TEST(Mutex, DISABLED_DeadlockDetectorBazelWarning) {
 #else
@@ -1101,7 +1133,7 @@
 // annotation-based static thread-safety analysis is not currently
 // predicate-aware and cannot tell if the two for-loops that acquire and
 // release the locks have the same predicates.
-TEST(Mutex, DeadlockDetectorStessTest) ABSL_NO_THREAD_SAFETY_ANALYSIS {
+TEST(Mutex, DeadlockDetectorStressTest) ABSL_NO_THREAD_SAFETY_ANALYSIS {
   // Stress test: Here we create a large number of locks and use all of them.
   // If a deadlock detector keeps a full graph of lock acquisition order,
   // it will likely be too slow for this test to pass.
@@ -1119,9 +1151,9 @@
   }
 }
 
-#ifdef THREAD_SANITIZER
+#ifdef ABSL_HAVE_THREAD_SANITIZER
 // TSAN reports errors when locked Mutexes are destroyed.
-TEST(Mutex, DISABLED_DeadlockIdBug) NO_THREAD_SAFETY_ANALYSIS {
+TEST(Mutex, DISABLED_DeadlockIdBug) ABSL_NO_THREAD_SAFETY_ANALYSIS {
 #else
 TEST(Mutex, DeadlockIdBug) ABSL_NO_THREAD_SAFETY_ANALYSIS {
 #endif
@@ -1157,7 +1189,6 @@
   c.Lock();
   c.Unlock();
 }
-#endif  // !defined(ABSL_INTERNAL_USE_NONPROD_MUTEX)
 
 // --------------------------------------------------------
 // Test for timeouts/deadlines on condition waits that are specified using
diff --git a/absl/time/BUILD.bazel b/absl/time/BUILD.bazel
index 9ab2adb..3e25ca2 100644
--- a/absl/time/BUILD.bazel
+++ b/absl/time/BUILD.bazel
@@ -24,7 +24,7 @@
 
 package(default_visibility = ["//visibility:public"])
 
-licenses(["notice"])  # Apache 2.0
+licenses(["notice"])
 
 cc_library(
     name = "time",
@@ -70,6 +70,7 @@
     ],
     deps = [
         ":time",
+        "//absl/base:config",
         "//absl/base:raw_logging_internal",
         "//absl/time/internal/cctz:time_zone",
         "@com_google_googletest//:gtest",
@@ -118,6 +119,7 @@
         ":time",
         "//absl/base",
         "//absl/base:core_headers",
+        "//absl/flags:flag",
         "//absl/hash",
         "@com_github_google_benchmark//:benchmark_main",
     ],
diff --git a/absl/time/CMakeLists.txt b/absl/time/CMakeLists.txt
index 853563e..00bdd49 100644
--- a/absl/time/CMakeLists.txt
+++ b/absl/time/CMakeLists.txt
@@ -99,6 +99,7 @@
     ${ABSL_DEFAULT_COPTS}
   DEPS
     absl::time
+    absl::config
     absl::raw_logging_internal
     absl::time_zone
     gmock
diff --git a/absl/time/civil_time.cc b/absl/time/civil_time.cc
index ada82cb..bdfe9ce 100644
--- a/absl/time/civil_time.cc
+++ b/absl/time/civil_time.cc
@@ -38,7 +38,7 @@
   const CivilSecond ncs(NormalizeYear(cs.year()), cs.month(), cs.day(),
                         cs.hour(), cs.minute(), cs.second());
   const TimeZone utc = UTCTimeZone();
-  // TODO(absl-team): Avoid conversion of fmt std::string.
+  // TODO(absl-team): Avoid conversion of fmt string.
   return StrCat(cs.year(),
                 FormatTime(std::string(fmt), FromCivil(ncs, utc), utc));
 }
@@ -47,7 +47,7 @@
 bool ParseYearAnd(string_view fmt, string_view s, CivilT* c) {
   // Civil times support a larger year range than absl::Time, so we need to
   // parse the year separately, normalize it, then use absl::ParseTime on the
-  // normalized std::string.
+  // normalized string.
   const std::string ss = std::string(s);  // TODO(absl-team): Avoid conversion.
   const char* const np = ss.c_str();
   char* endp;
@@ -82,7 +82,7 @@
 
 template <typename CivilT>
 bool ParseLenient(string_view s, CivilT* c) {
-  // A fastpath for when the given std::string data parses exactly into the given
+  // A fastpath for when the given string data parses exactly into the given
   // type T (e.g., s="YYYY-MM-DD" and CivilT=CivilDay).
   if (ParseCivilTime(s, c)) return true;
   // Try parsing as each of the 6 types, trying the most common types first
@@ -98,26 +98,26 @@
 }  // namespace
 
 std::string FormatCivilTime(CivilSecond c) {
-  return FormatYearAnd("-%m-%dT%H:%M:%S", c);
+  return FormatYearAnd("-%m-%d%ET%H:%M:%S", c);
 }
 std::string FormatCivilTime(CivilMinute c) {
-  return FormatYearAnd("-%m-%dT%H:%M", c);
+  return FormatYearAnd("-%m-%d%ET%H:%M", c);
 }
 std::string FormatCivilTime(CivilHour c) {
-  return FormatYearAnd("-%m-%dT%H", c);
+  return FormatYearAnd("-%m-%d%ET%H", c);
 }
 std::string FormatCivilTime(CivilDay c) { return FormatYearAnd("-%m-%d", c); }
 std::string FormatCivilTime(CivilMonth c) { return FormatYearAnd("-%m", c); }
 std::string FormatCivilTime(CivilYear c) { return FormatYearAnd("", c); }
 
 bool ParseCivilTime(string_view s, CivilSecond* c) {
-  return ParseYearAnd("-%m-%dT%H:%M:%S", s, c);
+  return ParseYearAnd("-%m-%d%ET%H:%M:%S", s, c);
 }
 bool ParseCivilTime(string_view s, CivilMinute* c) {
-  return ParseYearAnd("-%m-%dT%H:%M", s, c);
+  return ParseYearAnd("-%m-%d%ET%H:%M", s, c);
 }
 bool ParseCivilTime(string_view s, CivilHour* c) {
-  return ParseYearAnd("-%m-%dT%H", s, c);
+  return ParseYearAnd("-%m-%d%ET%H", s, c);
 }
 bool ParseCivilTime(string_view s, CivilDay* c) {
   return ParseYearAnd("-%m-%d", s, c);
diff --git a/absl/time/clock.cc b/absl/time/clock.cc
index 3b895c3..7b204c4 100644
--- a/absl/time/clock.cc
+++ b/absl/time/clock.cc
@@ -15,6 +15,7 @@
 #include "absl/time/clock.h"
 
 #include "absl/base/attributes.h"
+#include "absl/base/optimization.h"
 
 #ifdef _WIN32
 #include <windows.h>
@@ -74,9 +75,7 @@
 #if !ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
 namespace absl {
 ABSL_NAMESPACE_BEGIN
-int64_t GetCurrentTimeNanos() {
-  return GET_CURRENT_TIME_NANOS_FROM_SYSTEM();
-}
+int64_t GetCurrentTimeNanos() { return GET_CURRENT_TIME_NANOS_FROM_SYSTEM(); }
 ABSL_NAMESPACE_END
 }  // namespace absl
 #else  // Use the cyclecounter-based implementation below.
@@ -87,13 +86,6 @@
   ::absl::time_internal::UnscaledCycleClockWrapperForGetCurrentTime::Now()
 #endif
 
-// The following counters are used only by the test code.
-static int64_t stats_initializations;
-static int64_t stats_reinitializations;
-static int64_t stats_calibrations;
-static int64_t stats_slow_paths;
-static int64_t stats_fast_slow_paths;
-
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace time_internal {
@@ -107,72 +99,6 @@
 
 // uint64_t is used in this module to provide an extra bit in multiplications
 
-// Return the time in ns as told by the kernel interface.  Place in *cycleclock
-// the value of the cycleclock at about the time of the syscall.
-// This call represents the time base that this module synchronizes to.
-// Ensures that *cycleclock does not step back by up to (1 << 16) from
-// last_cycleclock, to discard small backward counter steps.  (Larger steps are
-// 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) {
-  // We try to read clock values at about the same time as the kernel clock.
-  // This value gets adjusted up or down as estimate of how long that should
-  // take, so we can reject attempts that take unusually long.
-  static std::atomic<uint64_t> approx_syscall_time_in_cycles{10 * 1000};
-
-  uint64_t local_approx_syscall_time_in_cycles =  // local copy
-      approx_syscall_time_in_cycles.load(std::memory_order_relaxed);
-
-  int64_t current_time_nanos_from_system;
-  uint64_t before_cycles;
-  uint64_t after_cycles;
-  uint64_t elapsed_cycles;
-  int loops = 0;
-  do {
-    before_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW();
-    current_time_nanos_from_system = GET_CURRENT_TIME_NANOS_FROM_SYSTEM();
-    after_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW();
-    // elapsed_cycles is unsigned, so is large on overflow
-    elapsed_cycles = after_cycles - before_cycles;
-    if (elapsed_cycles >= local_approx_syscall_time_in_cycles &&
-        ++loops == 20) {  // clock changed frequencies?  Back off.
-      loops = 0;
-      if (local_approx_syscall_time_in_cycles < 1000 * 1000) {
-        local_approx_syscall_time_in_cycles =
-            (local_approx_syscall_time_in_cycles + 1) << 1;
-      }
-      approx_syscall_time_in_cycles.store(
-          local_approx_syscall_time_in_cycles,
-          std::memory_order_relaxed);
-    }
-  } while (elapsed_cycles >= local_approx_syscall_time_in_cycles ||
-           last_cycleclock - after_cycles < (static_cast<uint64_t>(1) << 16));
-
-  // Number of times in a row we've seen a kernel time call take substantially
-  // less than approx_syscall_time_in_cycles.
-  static std::atomic<uint32_t> seen_smaller{ 0 };
-
-  // Adjust approx_syscall_time_in_cycles to be within a factor of 2
-  // of the typical time to execute one iteration of the loop above.
-  if ((local_approx_syscall_time_in_cycles >> 1) < elapsed_cycles) {
-    // measured time is no smaller than half current approximation
-    seen_smaller.store(0, std::memory_order_relaxed);
-  } else if (seen_smaller.fetch_add(1, std::memory_order_relaxed) >= 3) {
-    // smaller delays several times in a row; reduce approximation by 12.5%
-    const uint64_t new_approximation =
-        local_approx_syscall_time_in_cycles -
-        (local_approx_syscall_time_in_cycles >> 3);
-    approx_syscall_time_in_cycles.store(new_approximation,
-                                        std::memory_order_relaxed);
-    seen_smaller.store(0, std::memory_order_relaxed);
-  }
-
-  *cycleclock = after_cycles;
-  return current_time_nanos_from_system;
-}
-
-
 // ---------------------------------------------------------------------
 // An implementation of reader-write locks that use no atomic ops in the read
 // case.  This is a generalization of Lamport's method for reading a multiword
@@ -224,32 +150,110 @@
                kMinNSBetweenSamples,
                "cannot represent kMaxBetweenSamplesNSScaled");
 
-// A reader-writer lock protecting the static locations below.
-// See SeqAcquire() and SeqRelease() above.
-static absl::base_internal::SpinLock lock(
-    absl::base_internal::kLinkerInitialized);
-static std::atomic<uint64_t> seq(0);
-
 // data from a sample of the kernel's time value
 struct TimeSampleAtomic {
-  std::atomic<uint64_t> raw_ns;              // raw kernel time
-  std::atomic<uint64_t> base_ns;             // our estimate of time
-  std::atomic<uint64_t> base_cycles;         // cycle counter reading
-  std::atomic<uint64_t> nsscaled_per_cycle;  // cycle period
+  std::atomic<uint64_t> raw_ns{0};              // raw kernel time
+  std::atomic<uint64_t> base_ns{0};             // our estimate of time
+  std::atomic<uint64_t> base_cycles{0};         // cycle counter reading
+  std::atomic<uint64_t> nsscaled_per_cycle{0};  // cycle period
   // cycles before we'll sample again (a scaled reciprocal of the period,
   // to avoid a division on the fast path).
-  std::atomic<uint64_t> min_cycles_per_sample;
+  std::atomic<uint64_t> min_cycles_per_sample{0};
 };
 // Same again, but with non-atomic types
 struct TimeSample {
-  uint64_t raw_ns;                 // raw kernel time
-  uint64_t base_ns;                // our estimate of time
-  uint64_t base_cycles;            // cycle counter reading
-  uint64_t nsscaled_per_cycle;     // cycle period
-  uint64_t min_cycles_per_sample;  // approx cycles before next sample
+  uint64_t raw_ns = 0;                 // raw kernel time
+  uint64_t base_ns = 0;                // our estimate of time
+  uint64_t base_cycles = 0;            // cycle counter reading
+  uint64_t nsscaled_per_cycle = 0;     // cycle period
+  uint64_t min_cycles_per_sample = 0;  // approx cycles before next sample
 };
 
-static struct TimeSampleAtomic last_sample;   // the last sample; under seq
+struct ABSL_CACHELINE_ALIGNED TimeState {
+  std::atomic<uint64_t> seq{0};
+  TimeSampleAtomic last_sample;  // the last sample; under seq
+
+  // The following counters are used only by the test code.
+  int64_t stats_initializations{0};
+  int64_t stats_reinitializations{0};
+  int64_t stats_calibrations{0};
+  int64_t stats_slow_paths{0};
+  int64_t stats_fast_slow_paths{0};
+
+  uint64_t last_now_cycles ABSL_GUARDED_BY(lock){0};
+
+  // Used by GetCurrentTimeNanosFromKernel().
+  // We try to read clock values at about the same time as the kernel clock.
+  // This value gets adjusted up or down as estimate of how long that should
+  // take, so we can reject attempts that take unusually long.
+  std::atomic<uint64_t> approx_syscall_time_in_cycles{10 * 1000};
+  // Number of times in a row we've seen a kernel time call take substantially
+  // less than approx_syscall_time_in_cycles.
+  std::atomic<uint32_t> kernel_time_seen_smaller{0};
+
+  // 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_CONST_INIT static TimeState time_state{};
+
+// Return the time in ns as told by the kernel interface.  Place in *cycleclock
+// the value of the cycleclock at about the time of the syscall.
+// This call represents the time base that this module synchronizes to.
+// Ensures that *cycleclock does not step back by up to (1 << 16) from
+// last_cycleclock, to discard small backward counter steps.  (Larger steps are
+// 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)
+    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);
+
+  int64_t current_time_nanos_from_system;
+  uint64_t before_cycles;
+  uint64_t after_cycles;
+  uint64_t elapsed_cycles;
+  int loops = 0;
+  do {
+    before_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW();
+    current_time_nanos_from_system = GET_CURRENT_TIME_NANOS_FROM_SYSTEM();
+    after_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW();
+    // elapsed_cycles is unsigned, so is large on overflow
+    elapsed_cycles = after_cycles - before_cycles;
+    if (elapsed_cycles >= local_approx_syscall_time_in_cycles &&
+        ++loops == 20) {  // clock changed frequencies?  Back off.
+      loops = 0;
+      if (local_approx_syscall_time_in_cycles < 1000 * 1000) {
+        local_approx_syscall_time_in_cycles =
+            (local_approx_syscall_time_in_cycles + 1) << 1;
+      }
+      time_state.approx_syscall_time_in_cycles.store(
+          local_approx_syscall_time_in_cycles, std::memory_order_relaxed);
+    }
+  } while (elapsed_cycles >= local_approx_syscall_time_in_cycles ||
+           last_cycleclock - after_cycles < (static_cast<uint64_t>(1) << 16));
+
+  // Adjust approx_syscall_time_in_cycles to be within a factor of 2
+  // of the typical time to execute one iteration of the loop above.
+  if ((local_approx_syscall_time_in_cycles >> 1) < elapsed_cycles) {
+    // measured time is no smaller than half current approximation
+    time_state.kernel_time_seen_smaller.store(0, std::memory_order_relaxed);
+  } else if (time_state.kernel_time_seen_smaller.fetch_add(
+                 1, std::memory_order_relaxed) >= 3) {
+    // smaller delays several times in a row; reduce approximation by 12.5%
+    const uint64_t new_approximation =
+        local_approx_syscall_time_in_cycles -
+        (local_approx_syscall_time_in_cycles >> 3);
+    time_state.approx_syscall_time_in_cycles.store(new_approximation,
+                                                   std::memory_order_relaxed);
+    time_state.kernel_time_seen_smaller.store(0, std::memory_order_relaxed);
+  }
+
+  *cycleclock = after_cycles;
+  return current_time_nanos_from_system;
+}
 
 static int64_t GetCurrentTimeNanosSlowPath() ABSL_ATTRIBUTE_COLD;
 
@@ -317,14 +321,15 @@
   // Acquire pairs with the barrier in SeqRelease - if this load sees that
   // store, the shared-data reads necessarily see that SeqRelease's updates
   // to the same shared data.
-  seq_read0 = seq.load(std::memory_order_acquire);
+  seq_read0 = time_state.seq.load(std::memory_order_acquire);
 
-  base_ns = last_sample.base_ns.load(std::memory_order_relaxed);
-  base_cycles = last_sample.base_cycles.load(std::memory_order_relaxed);
+  base_ns = time_state.last_sample.base_ns.load(std::memory_order_relaxed);
+  base_cycles =
+      time_state.last_sample.base_cycles.load(std::memory_order_relaxed);
   nsscaled_per_cycle =
-      last_sample.nsscaled_per_cycle.load(std::memory_order_relaxed);
-  min_cycles_per_sample =
-      last_sample.min_cycles_per_sample.load(std::memory_order_relaxed);
+      time_state.last_sample.nsscaled_per_cycle.load(std::memory_order_relaxed);
+  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
@@ -335,7 +340,7 @@
   // shared-data writes are effectively release ordered. Therefore if our
   // shared-data reads see any of a particular update's shared-data writes,
   // seq_read1 is guaranteed to see that update's SeqAcquire.
-  seq_read1 = seq.load(std::memory_order_relaxed);
+  seq_read1 = time_state.seq.load(std::memory_order_relaxed);
 
   // Fast path.  Return if min_cycles_per_sample has not yet elapsed since the
   // last sample, and we read a consistent sample.  The fast path activates
@@ -348,9 +353,9 @@
   // last_sample was updated). This is harmless, because delta_cycles will wrap
   // and report a time much much bigger than min_cycles_per_sample. In that case
   // we will take the slow path.
-  uint64_t delta_cycles = now_cycles - base_cycles;
+  uint64_t delta_cycles;
   if (seq_read0 == seq_read1 && (seq_read0 & 1) == 0 &&
-      delta_cycles < min_cycles_per_sample) {
+      (delta_cycles = now_cycles - base_cycles) < min_cycles_per_sample) {
     return base_ns + ((delta_cycles * nsscaled_per_cycle) >> kScale);
   }
   return GetCurrentTimeNanosSlowPath();
@@ -390,24 +395,25 @@
 // TODO(absl-team): Remove this attribute when our compiler is smart enough
 // to do the right thing.
 ABSL_ATTRIBUTE_NOINLINE
-static int64_t GetCurrentTimeNanosSlowPath() ABSL_LOCKS_EXCLUDED(lock) {
+static int64_t GetCurrentTimeNanosSlowPath()
+    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.
-  lock.Lock();
+  time_state.lock.Lock();
 
   // Sample the kernel time base.  This is the definition of
   // "now" if we take the slow path.
-  static uint64_t last_now_cycles;  // protected by lock
   uint64_t now_cycles;
-  uint64_t now_ns = GetCurrentTimeNanosFromKernel(last_now_cycles, &now_cycles);
-  last_now_cycles = now_cycles;
+  uint64_t now_ns =
+      GetCurrentTimeNanosFromKernel(time_state.last_now_cycles, &now_cycles);
+  time_state.last_now_cycles = now_cycles;
 
   uint64_t estimated_base_ns;
 
   // ----------
   // Read the "last_sample" values again; this time holding the write lock.
   struct TimeSample sample;
-  ReadTimeSampleAtomic(&last_sample, &sample);
+  ReadTimeSampleAtomic(&time_state.last_sample, &sample);
 
   // ----------
   // Try running the fast path again; another thread may have updated the
@@ -418,13 +424,13 @@
     // so that blocked readers can make progress without blocking new readers.
     estimated_base_ns = sample.base_ns +
         ((delta_cycles * sample.nsscaled_per_cycle) >> kScale);
-    stats_fast_slow_paths++;
+    time_state.stats_fast_slow_paths++;
   } else {
     estimated_base_ns =
         UpdateLastSample(now_cycles, now_ns, delta_cycles, &sample);
   }
 
-  lock.Unlock();
+  time_state.lock.Unlock();
 
   return estimated_base_ns;
 }
@@ -435,9 +441,10 @@
 static uint64_t UpdateLastSample(uint64_t now_cycles, uint64_t now_ns,
                                  uint64_t delta_cycles,
                                  const struct TimeSample *sample)
-    ABSL_EXCLUSIVE_LOCKS_REQUIRED(lock) {
+    ABSL_EXCLUSIVE_LOCKS_REQUIRED(time_state.lock) {
   uint64_t estimated_base_ns = now_ns;
-  uint64_t lock_value = SeqAcquire(&seq);  // acquire seqlock to block readers
+  uint64_t lock_value =
+      SeqAcquire(&time_state.seq);  // acquire seqlock to block readers
 
   // The 5s in the next if-statement limits the time for which we will trust
   // the cycle counter and our last sample to give a reasonable result.
@@ -447,12 +454,16 @@
       sample->raw_ns + static_cast<uint64_t>(5) * 1000 * 1000 * 1000 < now_ns ||
       now_ns < sample->raw_ns || now_cycles < sample->base_cycles) {
     // record this sample, and forget any previously known slope.
-    last_sample.raw_ns.store(now_ns, std::memory_order_relaxed);
-    last_sample.base_ns.store(estimated_base_ns, std::memory_order_relaxed);
-    last_sample.base_cycles.store(now_cycles, std::memory_order_relaxed);
-    last_sample.nsscaled_per_cycle.store(0, std::memory_order_relaxed);
-    last_sample.min_cycles_per_sample.store(0, std::memory_order_relaxed);
-    stats_initializations++;
+    time_state.last_sample.raw_ns.store(now_ns, std::memory_order_relaxed);
+    time_state.last_sample.base_ns.store(estimated_base_ns,
+                                         std::memory_order_relaxed);
+    time_state.last_sample.base_cycles.store(now_cycles,
+                                             std::memory_order_relaxed);
+    time_state.last_sample.nsscaled_per_cycle.store(0,
+                                                    std::memory_order_relaxed);
+    time_state.last_sample.min_cycles_per_sample.store(
+        0, std::memory_order_relaxed);
+    time_state.stats_initializations++;
   } else if (sample->raw_ns + 500 * 1000 * 1000 < now_ns &&
              sample->base_cycles + 50 < now_cycles) {
     // Enough time has passed to compute the cycle time.
@@ -495,28 +506,32 @@
     if (new_nsscaled_per_cycle != 0 &&
         diff_ns < 100 * 1000 * 1000 && -diff_ns < 100 * 1000 * 1000) {
       // record the cycle time measurement
-      last_sample.nsscaled_per_cycle.store(
+      time_state.last_sample.nsscaled_per_cycle.store(
           new_nsscaled_per_cycle, std::memory_order_relaxed);
       uint64_t new_min_cycles_per_sample =
           SafeDivideAndScale(kMinNSBetweenSamples, new_nsscaled_per_cycle);
-      last_sample.min_cycles_per_sample.store(
+      time_state.last_sample.min_cycles_per_sample.store(
           new_min_cycles_per_sample, std::memory_order_relaxed);
-      stats_calibrations++;
+      time_state.stats_calibrations++;
     } else {  // something went wrong; forget the slope
-      last_sample.nsscaled_per_cycle.store(0, std::memory_order_relaxed);
-      last_sample.min_cycles_per_sample.store(0, std::memory_order_relaxed);
+      time_state.last_sample.nsscaled_per_cycle.store(
+          0, std::memory_order_relaxed);
+      time_state.last_sample.min_cycles_per_sample.store(
+          0, std::memory_order_relaxed);
       estimated_base_ns = now_ns;
-      stats_reinitializations++;
+      time_state.stats_reinitializations++;
     }
-    last_sample.raw_ns.store(now_ns, std::memory_order_relaxed);
-    last_sample.base_ns.store(estimated_base_ns, std::memory_order_relaxed);
-    last_sample.base_cycles.store(now_cycles, std::memory_order_relaxed);
+    time_state.last_sample.raw_ns.store(now_ns, std::memory_order_relaxed);
+    time_state.last_sample.base_ns.store(estimated_base_ns,
+                                         std::memory_order_relaxed);
+    time_state.last_sample.base_cycles.store(now_cycles,
+                                             std::memory_order_relaxed);
   } else {
     // have a sample, but no slope; waiting for enough time for a calibration
-    stats_slow_paths++;
+    time_state.stats_slow_paths++;
   }
 
-  SeqRelease(&seq, lock_value);  // release the readers
+  SeqRelease(&time_state.seq, lock_value);  // release the readers
 
   return estimated_base_ns;
 }
@@ -558,7 +573,8 @@
 
 extern "C" {
 
-ABSL_ATTRIBUTE_WEAK void AbslInternalSleepFor(absl::Duration duration) {
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSleepFor)(
+    absl::Duration duration) {
   while (duration > absl::ZeroDuration()) {
     absl::Duration to_sleep = std::min(duration, absl::MaxSleep());
     absl::SleepOnce(to_sleep);
diff --git a/absl/time/clock.h b/absl/time/clock.h
index 27764a9..5fe244d 100644
--- a/absl/time/clock.h
+++ b/absl/time/clock.h
@@ -64,11 +64,11 @@
 // By changing our extension points to be extern "C", we dodge this
 // check.
 extern "C" {
-void AbslInternalSleepFor(absl::Duration duration);
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalSleepFor)(absl::Duration duration);
 }  // extern "C"
 
 inline void absl::SleepFor(absl::Duration duration) {
-  AbslInternalSleepFor(duration);
+  ABSL_INTERNAL_C_SYMBOL(AbslInternalSleepFor)(duration);
 }
 
 #endif  // ABSL_TIME_CLOCK_H_
diff --git a/absl/time/duration.cc b/absl/time/duration.cc
index b1af840..4443109 100644
--- a/absl/time/duration.cc
+++ b/absl/time/duration.cc
@@ -67,7 +67,10 @@
 #include <string>
 
 #include "absl/base/casts.h"
+#include "absl/base/macros.h"
 #include "absl/numeric/int128.h"
+#include "absl/strings/string_view.h"
+#include "absl/strings/strip.h"
 #include "absl/time/time.h"
 
 namespace absl {
@@ -353,7 +356,7 @@
 // the remainder.  If it does not saturate, the remainder remain accurate,
 // but the returned quotient will over/underflow int64_t and should not be used.
 int64_t IDivDuration(bool satq, const Duration num, const Duration den,
-                   Duration* rem) {
+                     Duration* rem) {
   int64_t q = 0;
   if (IDivFastPath(num, den, &q, rem)) {
     return q;
@@ -708,16 +711,17 @@
 // fractional digits, because it is in the noise of what a Duration can
 // represent.
 struct DisplayUnit {
-  const char* abbr;
+  absl::string_view abbr;
   int prec;
   double pow10;
 };
-const DisplayUnit kDisplayNano = {"ns", 2, 1e2};
-const DisplayUnit kDisplayMicro = {"us", 5, 1e5};
-const DisplayUnit kDisplayMilli = {"ms", 8, 1e8};
-const DisplayUnit kDisplaySec = {"s", 11, 1e11};
-const DisplayUnit kDisplayMin = {"m", -1, 0.0};   // prec ignored
-const DisplayUnit kDisplayHour = {"h", -1, 0.0};  // prec ignored
+ABSL_CONST_INIT const DisplayUnit kDisplayNano = {"ns", 2, 1e2};
+ABSL_CONST_INIT const DisplayUnit kDisplayMicro = {"us", 5, 1e5};
+ABSL_CONST_INIT const DisplayUnit kDisplayMilli = {"ms", 8, 1e8};
+ABSL_CONST_INIT const DisplayUnit kDisplaySec = {"s", 11, 1e11};
+ABSL_CONST_INIT const DisplayUnit kDisplayMin = {"m", -1, 0.0};  // prec ignored
+ABSL_CONST_INIT const DisplayUnit kDisplayHour = {"h", -1,
+                                                  0.0};  // prec ignored
 
 void AppendNumberUnit(std::string* out, int64_t n, DisplayUnit unit) {
   char buf[sizeof("2562047788015216")];  // hours in max duration
@@ -725,16 +729,16 @@
   char* bp = Format64(ep, 0, n);
   if (*bp != '0' || bp + 1 != ep) {
     out->append(bp, ep - bp);
-    out->append(unit.abbr);
+    out->append(unit.abbr.data(), unit.abbr.size());
   }
 }
 
 // Note: unit.prec is limited to double's digits10 value (typically 15) so it
 // always fits in buf[].
 void AppendNumberUnit(std::string* out, double n, DisplayUnit unit) {
-  const int buf_size = std::numeric_limits<double>::digits10;
-  const int prec = std::min(buf_size, unit.prec);
-  char buf[buf_size];  // also large enough to hold integer part
+  constexpr int kBufferSize = std::numeric_limits<double>::digits10;
+  const int prec = std::min(kBufferSize, unit.prec);
+  char buf[kBufferSize];  // also large enough to hold integer part
   char* ep = buf + sizeof(buf);
   double d = 0;
   int64_t frac_part = Round(std::modf(n, &d) * unit.pow10);
@@ -748,7 +752,7 @@
       while (ep[-1] == '0') --ep;
       out->append(bp, ep - bp);
     }
-    out->append(unit.abbr);
+    out->append(unit.abbr.data(), unit.abbr.size());
   }
 }
 
@@ -759,7 +763,8 @@
 //   form "72h3m0.5s". Leading zero units are omitted.  As a special
 //   case, durations less than one second format use a smaller unit
 //   (milli-, micro-, or nanoseconds) to ensure that the leading digit
-//   is non-zero.  The zero duration formats as 0, with no unit.
+//   is non-zero.
+// Unlike Go, we format the zero duration as 0, with no unit.
 std::string FormatDuration(Duration d) {
   const Duration min_duration = Seconds(kint64min);
   if (d == min_duration) {
@@ -800,23 +805,27 @@
 // A helper for ParseDuration() that parses a leading number from the given
 // string and stores the result in *int_part/*frac_part/*frac_scale.  The
 // given string pointer is modified to point to the first unconsumed char.
-bool ConsumeDurationNumber(const char** dpp, int64_t* int_part,
+bool ConsumeDurationNumber(const char** dpp, const char* ep, int64_t* int_part,
                            int64_t* frac_part, int64_t* frac_scale) {
   *int_part = 0;
   *frac_part = 0;
   *frac_scale = 1;  // invariant: *frac_part < *frac_scale
   const char* start = *dpp;
-  for (; std::isdigit(**dpp); *dpp += 1) {
+  for (; *dpp != ep; *dpp += 1) {
     const int d = **dpp - '0';  // contiguous digits
+    if (d < 0 || 10 <= d) break;
+
     if (*int_part > kint64max / 10) return false;
     *int_part *= 10;
     if (*int_part > kint64max - d) return false;
     *int_part += d;
   }
   const bool int_part_empty = (*dpp == start);
-  if (**dpp != '.') return !int_part_empty;
-  for (*dpp += 1; std::isdigit(**dpp); *dpp += 1) {
+  if (*dpp == ep || **dpp != '.') return !int_part_empty;
+
+  for (*dpp += 1; *dpp != ep; *dpp += 1) {
     const int d = **dpp - '0';  // contiguous digits
+    if (d < 0 || 10 <= d) break;
     if (*frac_scale <= kint64max / 10) {
       *frac_part *= 10;
       *frac_part += d;
@@ -830,32 +839,56 @@
 // ns, us, ms, s, m, h) from the given string and stores the resulting unit
 // in "*unit".  The given string pointer is modified to point to the first
 // unconsumed char.
-bool ConsumeDurationUnit(const char** start, Duration* unit) {
-  const char *s = *start;
-  bool ok = true;
-  if (strncmp(s, "ns", 2) == 0) {
-    s += 2;
-    *unit = Nanoseconds(1);
-  } else if (strncmp(s, "us", 2) == 0) {
-    s += 2;
-    *unit = Microseconds(1);
-  } else if (strncmp(s, "ms", 2) == 0) {
-    s += 2;
-    *unit = Milliseconds(1);
-  } else if (strncmp(s, "s", 1) == 0) {
-    s += 1;
-    *unit = Seconds(1);
-  } else if (strncmp(s, "m", 1) == 0) {
-    s += 1;
-    *unit = Minutes(1);
-  } else if (strncmp(s, "h", 1) == 0) {
-    s += 1;
-    *unit = Hours(1);
-  } else {
-    ok = false;
+bool ConsumeDurationUnit(const char** start, const char* end, Duration* unit) {
+  size_t size = end - *start;
+  switch (size) {
+    case 0:
+      return false;
+    default:
+      switch (**start) {
+        case 'n':
+          if (*(*start + 1) == 's') {
+            *start += 2;
+            *unit = Nanoseconds(1);
+            return true;
+          }
+          break;
+        case 'u':
+          if (*(*start + 1) == 's') {
+            *start += 2;
+            *unit = Microseconds(1);
+            return true;
+          }
+          break;
+        case 'm':
+          if (*(*start + 1) == 's') {
+            *start += 2;
+            *unit = Milliseconds(1);
+            return true;
+          }
+          break;
+        default:
+          break;
+      }
+      ABSL_FALLTHROUGH_INTENDED;
+    case 1:
+      switch (**start) {
+        case 's':
+          *unit = Seconds(1);
+          *start += 1;
+          return true;
+        case 'm':
+          *unit = Minutes(1);
+          *start += 1;
+          return true;
+        case 'h':
+          *unit = Hours(1);
+          *start += 1;
+          return true;
+        default:
+          return false;
+      }
   }
-  *start = s;
-  return ok;
 }
 
 }  // namespace
@@ -865,39 +898,38 @@
 //   a possibly signed sequence of decimal numbers, each with optional
 //   fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m".
 //   Valid time units are "ns", "us" "ms", "s", "m", "h".
-bool ParseDuration(const std::string& dur_string, Duration* d) {
-  const char* start = dur_string.c_str();
+bool ParseDuration(absl::string_view dur_sv, Duration* d) {
   int sign = 1;
-
-  if (*start == '-' || *start == '+') {
-    sign = *start == '-' ? -1 : 1;
-    ++start;
+  if (absl::ConsumePrefix(&dur_sv, "-")) {
+    sign = -1;
+  } else {
+    absl::ConsumePrefix(&dur_sv, "+");
   }
+  if (dur_sv.empty()) return false;
 
-  // Can't parse a duration from an empty std::string.
-  if (*start == '\0') {
-    return false;
-  }
-
-  // Special case for a std::string of "0".
-  if (*start == '0' && *(start + 1) == '\0') {
+  // Special case for a string of "0".
+  if (dur_sv == "0") {
     *d = ZeroDuration();
     return true;
   }
 
-  if (strcmp(start, "inf") == 0) {
+  if (dur_sv == "inf") {
     *d = sign * InfiniteDuration();
     return true;
   }
 
+  const char* start = dur_sv.data();
+  const char* end = start + dur_sv.size();
+
   Duration dur;
-  while (*start != '\0') {
+  while (start != end) {
     int64_t int_part;
     int64_t frac_part;
     int64_t frac_scale;
     Duration unit;
-    if (!ConsumeDurationNumber(&start, &int_part, &frac_part, &frac_scale) ||
-        !ConsumeDurationUnit(&start, &unit)) {
+    if (!ConsumeDurationNumber(&start, end, &int_part, &frac_part,
+                               &frac_scale) ||
+        !ConsumeDurationUnit(&start, end, &unit)) {
       return false;
     }
     if (int_part != 0) dur += sign * int_part * unit;
@@ -908,7 +940,7 @@
 }
 
 bool AbslParseFlag(absl::string_view text, Duration* dst, std::string*) {
-  return ParseDuration(std::string(text), dst);
+  return ParseDuration(text, dst);
 }
 
 std::string AbslUnparseFlag(Duration d) { return FormatDuration(d); }
diff --git a/absl/time/duration_benchmark.cc b/absl/time/duration_benchmark.cc
index 83a836c..56820f3 100644
--- a/absl/time/duration_benchmark.cc
+++ b/absl/time/duration_benchmark.cc
@@ -18,9 +18,14 @@
 #include <string>
 
 #include "absl/base/attributes.h"
+#include "absl/flags/flag.h"
 #include "absl/time/time.h"
 #include "benchmark/benchmark.h"
 
+ABSL_FLAG(absl::Duration, absl_duration_flag_for_benchmark,
+          absl::Milliseconds(1),
+          "Flag to use for benchmarking duration flag access speed.");
+
 namespace {
 
 //
@@ -425,4 +430,15 @@
 }
 BENCHMARK(BM_Duration_ParseDuration)->DenseRange(0, kNumDurations - 1);
 
+//
+// Flag access
+//
+void BM_Duration_GetFlag(benchmark::State& state) {
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(
+        absl::GetFlag(FLAGS_absl_duration_flag_for_benchmark));
+  }
+}
+BENCHMARK(BM_Duration_GetFlag);
+
 }  // namespace
diff --git a/absl/time/duration_test.cc b/absl/time/duration_test.cc
index 4d85a2c..fb28fa9 100644
--- a/absl/time/duration_test.cc
+++ b/absl/time/duration_test.cc
@@ -1369,10 +1369,13 @@
   EXPECT_THAT(ToTimeval(absl::Nanoseconds(2000)), TimevalMatcher(tv));
 }
 
-void VerifySameAsMul(double time_as_seconds, int* const misses) {
+void VerifyApproxSameAsMul(double time_as_seconds, int* const misses) {
   auto direct_seconds = absl::Seconds(time_as_seconds);
   auto mul_by_one_second = time_as_seconds * absl::Seconds(1);
-  if (direct_seconds != mul_by_one_second) {
+  // These are expected to differ by up to one tick due to fused multiply/add
+  // contraction.
+  if (absl::AbsDuration(direct_seconds - mul_by_one_second) >
+      absl::time_internal::MakeDuration(0, 1u)) {
     if (*misses > 10) return;
     ASSERT_LE(++(*misses), 10) << "Too many errors, not reporting more.";
     EXPECT_EQ(direct_seconds, mul_by_one_second)
@@ -1384,7 +1387,8 @@
 // For a variety of interesting durations, we find the exact point
 // where one double converts to that duration, and the very next double
 // converts to the next duration.  For both of those points, verify that
-// Seconds(point) returns the same duration as point * Seconds(1.0)
+// Seconds(point) returns a duration near point * Seconds(1.0). (They may
+// not be exactly equal due to fused multiply/add contraction.)
 TEST(Duration, ToDoubleSecondsCheckEdgeCases) {
   constexpr uint32_t kTicksPerSecond = absl::time_internal::kTicksPerSecond;
   constexpr auto duration_tick = absl::time_internal::MakeDuration(0, 1u);
@@ -1423,8 +1427,8 @@
         }
         // Now low_edge is the highest double that converts to Duration d,
         // and high_edge is the lowest double that converts to Duration after_d.
-        VerifySameAsMul(low_edge, &misses);
-        VerifySameAsMul(high_edge, &misses);
+        VerifyApproxSameAsMul(low_edge, &misses);
+        VerifyApproxSameAsMul(high_edge, &misses);
       }
     }
   }
@@ -1444,8 +1448,8 @@
   int misses = 0;
   for (int i = 0; i < 1000000; ++i) {
     double d = std::exp(uniform(gen));
-    VerifySameAsMul(d, &misses);
-    VerifySameAsMul(-d, &misses);
+    VerifyApproxSameAsMul(d, &misses);
+    VerifyApproxSameAsMul(-d, &misses);
   }
 }
 
diff --git a/absl/time/format.cc b/absl/time/format.cc
index ee088f3..4005fb7 100644
--- a/absl/time/format.cc
+++ b/absl/time/format.cc
@@ -13,9 +13,12 @@
 // limitations under the License.
 
 #include <string.h>
+
 #include <cctype>
 #include <cstdint>
 
+#include "absl/strings/match.h"
+#include "absl/strings/string_view.h"
 #include "absl/time/internal/cctz/include/cctz/time_zone.h"
 #include "absl/time/time.h"
 
@@ -24,14 +27,11 @@
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
-ABSL_DLL extern const char RFC3339_full[] =
-    "%Y-%m-%dT%H:%M:%E*S%Ez";
-ABSL_DLL extern const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez";
+ABSL_DLL extern const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez";
+ABSL_DLL extern const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
 
-ABSL_DLL extern const char RFC1123_full[] =
-    "%a, %d %b %E4Y %H:%M:%S %z";
-ABSL_DLL extern const char RFC1123_no_wday[] =
-    "%d %b %E4Y %H:%M:%S %z";
+ABSL_DLL extern const char RFC1123_full[] = "%a, %d %b %E4Y %H:%M:%S %z";
+ABSL_DLL extern const char RFC1123_no_wday[] = "%d %b %E4Y %H:%M:%S %z";
 
 namespace {
 
@@ -71,12 +71,12 @@
 
 }  // namespace
 
-std::string FormatTime(const std::string& format, absl::Time t,
+std::string FormatTime(absl::string_view format, absl::Time t,
                        absl::TimeZone tz) {
-  if (t == absl::InfiniteFuture()) return kInfiniteFutureStr;
-  if (t == absl::InfinitePast()) return kInfinitePastStr;
+  if (t == absl::InfiniteFuture()) return std::string(kInfiniteFutureStr);
+  if (t == absl::InfinitePast()) return std::string(kInfinitePastStr);
   const auto parts = Split(t);
-  return cctz::detail::format(format, parts.sec, parts.fem,
+  return cctz::detail::format(std::string(format), parts.sec, parts.fem,
                               cctz::time_zone(tz));
 }
 
@@ -88,42 +88,50 @@
   return absl::FormatTime(RFC3339_full, t, absl::LocalTimeZone());
 }
 
-bool ParseTime(const std::string& format, const std::string& input,
+bool ParseTime(absl::string_view format, absl::string_view input,
                absl::Time* time, std::string* err) {
   return absl::ParseTime(format, input, absl::UTCTimeZone(), time, err);
 }
 
 // If the input string does not contain an explicit UTC offset, interpret
 // the fields with respect to the given TimeZone.
-bool ParseTime(const std::string& format, const std::string& input,
+bool ParseTime(absl::string_view format, absl::string_view input,
                absl::TimeZone tz, absl::Time* time, std::string* err) {
-  const char* data = input.c_str();
-  while (std::isspace(*data)) ++data;
-
-  size_t inf_size = strlen(kInfiniteFutureStr);
-  if (strncmp(data, kInfiniteFutureStr, inf_size) == 0) {
-    const char* new_data = data + inf_size;
-    while (std::isspace(*new_data)) ++new_data;
-    if (*new_data == '\0') {
-      *time = InfiniteFuture();
-      return true;
+  auto strip_leading_space = [](absl::string_view* sv) {
+    while (!sv->empty()) {
+      if (!std::isspace(sv->front())) return;
+      sv->remove_prefix(1);
     }
-  }
+  };
 
-  inf_size = strlen(kInfinitePastStr);
-  if (strncmp(data, kInfinitePastStr, inf_size) == 0) {
-    const char* new_data = data + inf_size;
-    while (std::isspace(*new_data)) ++new_data;
-    if (*new_data == '\0') {
-      *time = InfinitePast();
-      return true;
+  // Portable toolchains means we don't get nice constexpr here.
+  struct Literal {
+    const char* name;
+    size_t size;
+    absl::Time value;
+  };
+  static Literal literals[] = {
+      {kInfiniteFutureStr, strlen(kInfiniteFutureStr), InfiniteFuture()},
+      {kInfinitePastStr, strlen(kInfinitePastStr), InfinitePast()},
+  };
+  strip_leading_space(&input);
+  for (const auto& lit : literals) {
+    if (absl::StartsWith(input, absl::string_view(lit.name, lit.size))) {
+      absl::string_view tail = input;
+      tail.remove_prefix(lit.size);
+      strip_leading_space(&tail);
+      if (tail.empty()) {
+        *time = lit.value;
+        return true;
+      }
     }
   }
 
   std::string error;
   cctz_parts parts;
-  const bool b = cctz::detail::parse(format, input, cctz::time_zone(tz),
-                                     &parts.sec, &parts.fem, &error);
+  const bool b =
+      cctz::detail::parse(std::string(format), std::string(input),
+                          cctz::time_zone(tz), &parts.sec, &parts.fem, &error);
   if (b) {
     *time = Join(parts);
   } else if (err != nullptr) {
@@ -134,8 +142,7 @@
 
 // Functions required to support absl::Time flags.
 bool AbslParseFlag(absl::string_view text, absl::Time* t, std::string* error) {
-  return absl::ParseTime(RFC3339_full, std::string(text), absl::UTCTimeZone(),
-                         t, error);
+  return absl::ParseTime(RFC3339_full, text, absl::UTCTimeZone(), t, error);
 }
 
 std::string AbslUnparseFlag(absl::Time t) {
diff --git a/absl/time/format_benchmark.cc b/absl/time/format_benchmark.cc
index 249c51d..19e481d 100644
--- a/absl/time/format_benchmark.cc
+++ b/absl/time/format_benchmark.cc
@@ -26,7 +26,7 @@
     absl::RFC1123_no_wday,  // 1
     absl::RFC3339_full,     // 2
     absl::RFC3339_sec,      // 3
-    "%Y-%m-%dT%H:%M:%S",    // 4
+    "%Y-%m-%d%ET%H:%M:%S",  // 4
     "%Y-%m-%d",             // 5
 };
 const int kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
diff --git a/absl/time/format_test.cc b/absl/time/format_test.cc
index ab1f305..a9a1eb8 100644
--- a/absl/time/format_test.cc
+++ b/absl/time/format_test.cc
@@ -173,7 +173,7 @@
   absl::Time t;
   std::string e;
 
-  // We can parse a std::string without a UTC offset if we supply a timezone.
+  // We can parse a string without a UTC offset if we supply a timezone.
   EXPECT_TRUE(
       absl::ParseTime("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &t, &e))
       << e;
@@ -327,7 +327,7 @@
   EXPECT_TRUE(absl::ParseTime("%H:%M blah", "  infinite-past  ", &t, &err));
   EXPECT_EQ(absl::InfinitePast(), t);
 
-  // "infinite-future" as literal std::string
+  // "infinite-future" as literal string
   absl::TimeZone tz = absl::UTCTimeZone();
   EXPECT_TRUE(absl::ParseTime("infinite-future %H:%M", "infinite-future 03:04",
                               &t, &err));
@@ -335,7 +335,7 @@
   EXPECT_EQ(3, tz.At(t).cs.hour());
   EXPECT_EQ(4, tz.At(t).cs.minute());
 
-  // "infinite-past" as literal std::string
+  // "infinite-past" as literal string
   EXPECT_TRUE(
       absl::ParseTime("infinite-past %H:%M", "infinite-past 03:04", &t, &err));
   EXPECT_NE(absl::InfinitePast(), t);
diff --git a/absl/time/internal/cctz/BUILD.bazel b/absl/time/internal/cctz/BUILD.bazel
index 7a53c81..45a9529 100644
--- a/absl/time/internal/cctz/BUILD.bazel
+++ b/absl/time/internal/cctz/BUILD.bazel
@@ -16,7 +16,7 @@
 
 package(features = ["-parse_headers"])
 
-licenses(["notice"])  # Apache License
+licenses(["notice"])
 
 filegroup(
     name = "zoneinfo",
@@ -92,6 +92,11 @@
 
 ### tests
 
+test_suite(
+    name = "all_tests",
+    visibility = ["//visibility:public"],
+)
+
 cc_test(
     name = "civil_time_test",
     size = "small",
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 4cde96f..8aadde5 100644
--- a/absl/time/internal/cctz/include/cctz/civil_time_detail.h
+++ b/absl/time/internal/cctz/include/cctz/civil_time_detail.h
@@ -106,54 +106,64 @@
 
 CONSTEXPR_F fields n_day(year_t y, month_t m, diff_t d, diff_t cd, hour_t hh,
                          minute_t mm, second_t ss) noexcept {
-  y += (cd / 146097) * 400;
+  year_t ey = y % 400;
+  const year_t oey = ey;
+  ey += (cd / 146097) * 400;
   cd %= 146097;
   if (cd < 0) {
-    y -= 400;
+    ey -= 400;
     cd += 146097;
   }
-  y += (d / 146097) * 400;
+  ey += (d / 146097) * 400;
   d = d % 146097 + cd;
   if (d > 0) {
     if (d > 146097) {
-      y += 400;
+      ey += 400;
       d -= 146097;
     }
   } else {
     if (d > -365) {
       // We often hit the previous year when stepping a civil time backwards,
       // so special case it to avoid counting up by 100/4/1-year chunks.
-      y -= 1;
-      d += days_per_year(y, m);
+      ey -= 1;
+      d += days_per_year(ey, m);
     } else {
-      y -= 400;
+      ey -= 400;
       d += 146097;
     }
   }
   if (d > 365) {
-    for (int n = days_per_century(y, m); d > n; n = days_per_century(y, m)) {
+    for (;;) {
+      int n = days_per_century(ey, m);
+      if (d <= n) break;
       d -= n;
-      y += 100;
+      ey += 100;
     }
-    for (int n = days_per_4years(y, m); d > n; n = days_per_4years(y, m)) {
+    for (;;) {
+      int n = days_per_4years(ey, m);
+      if (d <= n) break;
       d -= n;
-      y += 4;
+      ey += 4;
     }
-    for (int n = days_per_year(y, m); d > n; n = days_per_year(y, m)) {
+    for (;;) {
+      int n = days_per_year(ey, m);
+      if (d <= n) break;
       d -= n;
-      ++y;
+      ++ey;
     }
   }
   if (d > 28) {
-    for (int n = days_per_month(y, m); d > n; n = days_per_month(y, m)) {
+    for (;;) {
+      int n = days_per_month(ey, m);
+      if (d <= n) break;
       d -= n;
       if (++m > 12) {
-        ++y;
+        ++ey;
         m = 1;
       }
     }
   }
-  return fields(y, m, static_cast<day_t>(d), hh, mm, ss);
+  return fields(y + (ey - oey), m, static_cast<day_t>(d), hh, mm, ss);
 }
 CONSTEXPR_F fields n_mon(year_t y, diff_t m, diff_t d, diff_t cd, hour_t hh,
                          minute_t mm, second_t ss) noexcept {
@@ -406,16 +416,10 @@
 
   // Assigning arithmetic.
   CONSTEXPR_M civil_time& operator+=(diff_t n) noexcept {
-    f_ = step(T{}, f_, n);
-    return *this;
+    return *this = *this + n;
   }
   CONSTEXPR_M civil_time& operator-=(diff_t n) noexcept {
-    if (n != (std::numeric_limits<diff_t>::min)()) {
-      f_ = step(T{}, f_, -n);
-    } else {
-      f_ = step(T{}, step(T{}, f_, -(n + 1)), 1);
-    }
-    return *this;
+    return *this = *this - n;
   }
   CONSTEXPR_M civil_time& operator++() noexcept { return *this += 1; }
   CONSTEXPR_M civil_time operator++(int) noexcept {
@@ -432,13 +436,15 @@
 
   // Binary arithmetic operators.
   friend CONSTEXPR_F civil_time operator+(civil_time a, diff_t n) noexcept {
-    return a += n;
+    return civil_time(step(T{}, a.f_, n));
   }
   friend CONSTEXPR_F civil_time operator+(diff_t n, civil_time a) noexcept {
-    return a += n;
+    return a + n;
   }
   friend CONSTEXPR_F civil_time operator-(civil_time a, diff_t n) noexcept {
-    return a -= n;
+    return n != (std::numeric_limits<diff_t>::min)()
+               ? civil_time(step(T{}, a.f_, -n))
+               : civil_time(step(T{}, step(T{}, a.f_, -(n + 1)), 1));
   }
   friend CONSTEXPR_F diff_t operator-(civil_time lhs, civil_time rhs) noexcept {
     return difference(T{}, lhs.f_, rhs.f_);
diff --git a/absl/time/internal/cctz/include/cctz/time_zone.h b/absl/time/internal/cctz/include/cctz/time_zone.h
index d05147a..5562a37 100644
--- a/absl/time/internal/cctz/include/cctz/time_zone.h
+++ b/absl/time/internal/cctz/include/cctz/time_zone.h
@@ -209,7 +209,7 @@
   // version() and description() provide additional information about the
   // time zone. The content of each of the returned strings is unspecified,
   // however, when the IANA Time Zone Database is the underlying data source
-  // the version() std::string will be in the familar form (e.g, "2018e") or
+  // the version() string will be in the familar form (e.g, "2018e") or
   // empty when unavailable.
   //
   // Note: These functions are for informational or testing purposes only.
@@ -292,6 +292,7 @@
 //   - %E#f - Fractional seconds with # digits of precision
 //   - %E*f - Fractional seconds with full precision (a literal '*')
 //   - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
+//   - %ET  - The RFC3339 "date-time" separator "T"
 //
 // Note that %E0S behaves like %S, and %E0f produces no characters. In
 // contrast %E*f always produces at least one digit, which may be '0'.
@@ -321,7 +322,8 @@
 // returns the corresponding time_point. Uses strftime()-like formatting
 // options, with the same extensions as cctz::format(), but with the
 // exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez
-// and %E*z also accept the same inputs.
+// and %E*z also accept the same inputs, which (along with %z) includes
+// 'z' and 'Z' as synonyms for +00:00.  %ET accepts either 'T' or 't'.
 //
 // %Y consumes as many numeric characters as it can, so the matching data
 // should always be terminated with a non-numeric. %E4Y always consumes
diff --git a/absl/time/internal/cctz/include/cctz/zone_info_source.h b/absl/time/internal/cctz/include/cctz/zone_info_source.h
index 912b44b..012eb4e 100644
--- a/absl/time/internal/cctz/include/cctz/zone_info_source.h
+++ b/absl/time/internal/cctz/include/cctz/zone_info_source.h
@@ -37,7 +37,7 @@
 
   // Until the zoneinfo data supports versioning information, we provide
   // a way for a ZoneInfoSource to indicate it out-of-band.  The default
-  // implementation returns an empty std::string.
+  // implementation returns an empty string.
   virtual std::string Version() const;
 };
 
diff --git a/absl/time/internal/cctz/src/cctz_benchmark.cc b/absl/time/internal/cctz/src/cctz_benchmark.cc
index d30a644..4e39188 100644
--- a/absl/time/internal/cctz/src/cctz_benchmark.cc
+++ b/absl/time/internal/cctz/src/cctz_benchmark.cc
@@ -97,8 +97,8 @@
 }
 BENCHMARK(BM_PrevWeekday);
 
-const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez";
-const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez";
+const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez";
+const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
 
 const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z";
 const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z";
@@ -280,6 +280,7 @@
                                       "America/North_Dakota/Beulah",
                                       "America/North_Dakota/Center",
                                       "America/North_Dakota/New_Salem",
+                                      "America/Nuuk",
                                       "America/Ojinaga",
                                       "America/Panama",
                                       "America/Pangnirtung",
@@ -990,12 +991,12 @@
 BENCHMARK(BM_Time_FromCivilDay0_Libc);
 
 const char* const kFormats[] = {
-    RFC1123_full,         // 0
-    RFC1123_no_wday,      // 1
-    RFC3339_full,         // 2
-    RFC3339_sec,          // 3
-    "%Y-%m-%dT%H:%M:%S",  // 4
-    "%Y-%m-%d",           // 5
+    RFC1123_full,           // 0
+    RFC1123_no_wday,        // 1
+    RFC3339_full,           // 2
+    RFC3339_sec,            // 3
+    "%Y-%m-%d%ET%H:%M:%S",  // 4
+    "%Y-%m-%d",             // 5
 };
 const int kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
 
diff --git a/absl/time/internal/cctz/src/civil_time_test.cc b/absl/time/internal/cctz/src/civil_time_test.cc
index be894d7..a5a7123 100644
--- a/absl/time/internal/cctz/src/civil_time_test.cc
+++ b/absl/time/internal/cctz/src/civil_time_test.cc
@@ -235,6 +235,16 @@
 }
 
 // NOTE: Run this with --copt=-ftrapv to detect overflow problems.
+TEST(CivilTime, ConstructionWithHugeYear) {
+  constexpr civil_hour h(-9223372036854775807, 1, 1, -1);
+  static_assert(h.year() == -9223372036854775807 - 1,
+                "ConstructionWithHugeYear");
+  static_assert(h.month() == 12, "ConstructionWithHugeYear");
+  static_assert(h.day() == 31, "ConstructionWithHugeYear");
+  static_assert(h.hour() == 23, "ConstructionWithHugeYear");
+}
+
+// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
 TEST(CivilTime, DifferenceWithHugeYear) {
   {
     constexpr civil_day d1(9223372036854775807, 1, 1);
diff --git a/absl/time/internal/cctz/src/time_zone_format.cc b/absl/time/internal/cctz/src/time_zone_format.cc
index 950b23a..d8cb047 100644
--- a/absl/time/internal/cctz/src/time_zone_format.cc
+++ b/absl/time/internal/cctz/src/time_zone_format.cc
@@ -67,6 +67,48 @@
 }
 #endif
 
+// Convert a cctz::weekday to a tm_wday value (0-6, Sunday = 0).
+int ToTmWday(weekday wd) {
+  switch (wd) {
+    case weekday::sunday:
+      return 0;
+    case weekday::monday:
+      return 1;
+    case weekday::tuesday:
+      return 2;
+    case weekday::wednesday:
+      return 3;
+    case weekday::thursday:
+      return 4;
+    case weekday::friday:
+      return 5;
+    case weekday::saturday:
+      return 6;
+  }
+  return 0; /*NOTREACHED*/
+}
+
+// Convert a tm_wday value (0-6, Sunday = 0) to a cctz::weekday.
+weekday FromTmWday(int tm_wday) {
+  switch (tm_wday) {
+    case 0:
+      return weekday::sunday;
+    case 1:
+      return weekday::monday;
+    case 2:
+      return weekday::tuesday;
+    case 3:
+      return weekday::wednesday;
+    case 4:
+      return weekday::thursday;
+    case 5:
+      return weekday::friday;
+    case 6:
+      return weekday::saturday;
+  }
+  return weekday::sunday; /*NOTREACHED*/
+}
+
 std::tm ToTM(const time_zone::absolute_lookup& al) {
   std::tm tm{};
   tm.tm_sec = al.cs.second();
@@ -84,34 +126,19 @@
     tm.tm_year = static_cast<int>(al.cs.year() - 1900);
   }
 
-  switch (get_weekday(al.cs)) {
-    case weekday::sunday:
-      tm.tm_wday = 0;
-      break;
-    case weekday::monday:
-      tm.tm_wday = 1;
-      break;
-    case weekday::tuesday:
-      tm.tm_wday = 2;
-      break;
-    case weekday::wednesday:
-      tm.tm_wday = 3;
-      break;
-    case weekday::thursday:
-      tm.tm_wday = 4;
-      break;
-    case weekday::friday:
-      tm.tm_wday = 5;
-      break;
-    case weekday::saturday:
-      tm.tm_wday = 6;
-      break;
-  }
+  tm.tm_wday = ToTmWday(get_weekday(al.cs));
   tm.tm_yday = get_yearday(al.cs) - 1;
   tm.tm_isdst = al.is_dst ? 1 : 0;
   return tm;
 }
 
+// Returns the week of the year [0:53] given a civil day and the day on
+// which weeks are defined to start.
+int ToWeek(const civil_day& cd, weekday week_start) {
+  const civil_day d(cd.year() % 400, cd.month(), cd.day());
+  return static_cast<int>((d - prev_weekday(civil_year(d), week_start)) / 7);
+}
+
 const char kDigits[] = "0123456789";
 
 // Formats a 64-bit integer in the given field width.  Note that it is up
@@ -189,7 +216,7 @@
   // strftime(3) returns the number of characters placed in the output
   // array (which may be 0 characters).  It also returns 0 to indicate
   // an error, like the array wasn't large enough.  To accommodate this,
-  // the following code grows the buffer size from 2x the format std::string
+  // the following code grows the buffer size from 2x the format string
   // length up to 32x.
   for (std::size_t i = 2; i != 32; i *= 2) {
     std::size_t buf_size = fmt.size() * i;
@@ -290,6 +317,7 @@
 //   - %E#S - Seconds with # digits of fractional precision
 //   - %E*S - Seconds with full fractional precision (a literal '*')
 //   - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
+//   - %ET  - The RFC3339 "date-time" separator "T"
 //
 // The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
 // handled internally for performance reasons.  strftime(3) is slow due to
@@ -354,7 +382,7 @@
     if (cur == end || (cur - percent) % 2 == 0) continue;
 
     // Simple specifiers that we handle ourselves.
-    if (strchr("YmdeHMSzZs%", *cur)) {
+    if (strchr("YmdeUuWwHMSzZs%", *cur)) {
       if (cur - 1 != pending) {
         FormatTM(&result, std::string(pending, cur - 1), tm);
       }
@@ -375,6 +403,22 @@
           if (*cur == 'e' && *bp == '0') *bp = ' ';  // for Windows
           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));
+          break;
+        case 'u':
+          bp = Format64(ep, 0, tm.tm_wday ? tm.tm_wday : 7);
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'W':
+          bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::monday));
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'w':
+          bp = Format64(ep, 0, tm.tm_wday);
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
         case 'H':
           bp = Format02d(ep, al.cs.hour());
           result.append(bp, static_cast<std::size_t>(ep - bp));
@@ -448,7 +492,14 @@
     if (*cur != 'E' || ++cur == end) continue;
 
     // Format our extensions.
-    if (*cur == 'z') {
+    if (*cur == 'T') {
+      // Formats %ET.
+      if (cur - 2 != pending) {
+        FormatTM(&result, std::string(pending, cur - 2), tm);
+      }
+      result.append("T");
+      pending = ++cur;
+    } else if (*cur == 'z') {
       // Formats %Ez.
       if (cur - 2 != pending) {
         FormatTM(&result, std::string(pending, cur - 2), tm);
@@ -551,7 +602,7 @@
       } else {
         dp = nullptr;
       }
-    } else if (first == 'Z') {  // Zulu
+    } else if (first == 'Z' || first == 'z') {  // Zulu
       *offset = 0;
     } else {
       dp = nullptr;
@@ -602,12 +653,32 @@
   return dp;
 }
 
+// Sets year, tm_mon and tm_mday given the year, week_num, and tm_wday,
+// and the day on which weeks are defined to start.  Returns false if year
+// would need to move outside its bounds.
+bool FromWeek(int week_num, weekday week_start, year_t* year, std::tm* tm) {
+  const civil_year y(*year % 400);
+  civil_day cd = prev_weekday(y, week_start);  // week 0
+  cd = next_weekday(cd - 1, FromTmWday(tm->tm_wday)) + (week_num * 7);
+  if (const year_t shift = cd.year() - y.year()) {
+    if (shift > 0) {
+      if (*year > std::numeric_limits<year_t>::max() - shift) return false;
+    } else {
+      if (*year < std::numeric_limits<year_t>::min() - shift) return false;
+    }
+    *year += shift;
+  }
+  tm->tm_mon = cd.month() - 1;
+  tm->tm_mday = cd.day();
+  return true;
+}
+
 }  // namespace
 
 // Uses strptime(3) to parse the given input.  Supports the same extended
 // format specifiers as format(), although %E#S and %E*S are treated
 // identically (and similarly for %E#f and %E*f).  %Ez and %E*z also accept
-// the same inputs.
+// the same inputs. %ET accepts either 'T' or 't'.
 //
 // The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
 // handled internally so that we can normally avoid strptime() altogether
@@ -651,6 +722,8 @@
   const char* fmt = format.c_str();  // NUL terminated
   bool twelve_hour = false;
   bool afternoon = false;
+  int week_num = -1;
+  weekday week_start = weekday::sunday;
 
   bool saw_percent_s = false;
   std::int_fast64_t percent_s = 0;
@@ -689,10 +762,27 @@
       case 'm':
         data = ParseInt(data, 2, 1, 12, &tm.tm_mon);
         if (data != nullptr) tm.tm_mon -= 1;
+        week_num = -1;
         continue;
       case 'd':
       case 'e':
         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;
+        continue;
+      case 'W':
+        data = ParseInt(data, 0, 0, 53, &week_num);
+        week_start = weekday::monday;
+        continue;
+      case 'u':
+        data = ParseInt(data, 0, 1, 7, &tm.tm_wday);
+        if (data != nullptr) tm.tm_wday %= 7;
+        continue;
+      case 'w':
+        data = ParseInt(data, 0, 0, 6, &tm.tm_wday);
         continue;
       case 'H':
         data = ParseInt(data, 2, 0, 23, &tm.tm_hour);
@@ -742,6 +832,15 @@
         data = (*data == '%' ? data + 1 : nullptr);
         continue;
       case 'E':
+        if (fmt[0] == 'T') {
+          if (*data == 'T' || *data == 't') {
+            ++data;
+            ++fmt;
+          } else {
+            data = nullptr;
+          }
+          continue;
+        }
         if (fmt[0] == 'z' || (fmt[0] == '*' && fmt[1] == 'z')) {
           data = ParseOffset(data, ":", &offset);
           if (data != nullptr) saw_offset = true;
@@ -839,7 +938,7 @@
   // Skip any remaining whitespace.
   while (std::isspace(*data)) ++data;
 
-  // parse() must consume the entire input std::string.
+  // parse() must consume the entire input string.
   if (*data != '\0') {
     if (err != nullptr) *err = "Illegal trailing data in input string";
     return false;
@@ -874,6 +973,14 @@
     year += 1900;
   }
 
+  // Compute year, tm.tm_mon and tm.tm_mday if we parsed a week number.
+  if (week_num != -1) {
+    if (!FromWeek(week_num, week_start, &year, &tm)) {
+      if (err != nullptr) *err = "Out-of-range field";
+      return false;
+    }
+  }
+
   const int month = tm.tm_mon + 1;
   civil_second cs(year, month, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
 
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 caebcc4..a11f93e 100644
--- a/absl/time/internal/cctz/src/time_zone_format_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_format_test.cc
@@ -48,8 +48,8 @@
     EXPECT_STREQ(zone, al.abbr);                                  \
   } while (0)
 
-const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez";
-const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez";
+const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez";
+const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
 
 const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z";
 const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z";
@@ -679,6 +679,34 @@
   EXPECT_EQ("28 Jun 1977 09:08:07 -0700", format(RFC1123_no_wday, tp, tz));
 }
 
+TEST(Format, Week) {
+  const time_zone utc = utc_time_zone();
+
+  auto tp = convert(civil_second(2017, 1, 1, 0, 0, 0), utc);
+  EXPECT_EQ("2017-01-7", format("%Y-%U-%u", tp, utc));
+  EXPECT_EQ("2017-00-0", format("%Y-%W-%w", tp, utc));
+
+  tp = convert(civil_second(2017, 12, 31, 0, 0, 0), utc);
+  EXPECT_EQ("2017-53-7", format("%Y-%U-%u", tp, utc));
+  EXPECT_EQ("2017-52-0", format("%Y-%W-%w", tp, utc));
+
+  tp = convert(civil_second(2018, 1, 1, 0, 0, 0), utc);
+  EXPECT_EQ("2018-00-1", format("%Y-%U-%u", tp, utc));
+  EXPECT_EQ("2018-01-1", format("%Y-%W-%w", tp, utc));
+
+  tp = convert(civil_second(2018, 12, 31, 0, 0, 0), utc);
+  EXPECT_EQ("2018-52-1", format("%Y-%U-%u", tp, utc));
+  EXPECT_EQ("2018-53-1", format("%Y-%W-%w", tp, utc));
+
+  tp = convert(civil_second(2019, 1, 1, 0, 0, 0), utc);
+  EXPECT_EQ("2019-00-2", format("%Y-%U-%u", tp, utc));
+  EXPECT_EQ("2019-00-2", format("%Y-%W-%w", tp, utc));
+
+  tp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
+  EXPECT_EQ("2019-52-2", format("%Y-%U-%u", tp, utc));
+  EXPECT_EQ("2019-52-2", format("%Y-%W-%w", tp, utc));
+}
+
 //
 // Testing parse()
 //
@@ -767,7 +795,7 @@
   EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
   time_point<chrono::nanoseconds> tp;
 
-  // We can parse a std::string without a UTC offset if we supply a timezone.
+  // We can parse a string without a UTC offset if we supply a timezone.
   EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &tp));
   ExpectTime(tp, tz, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true, "PDT");
 
@@ -1379,10 +1407,85 @@
   EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00+00:00", tz, &tp));
   ExpectTime(tp, tz, 2014, 2, 12, 20, 21, 0, 0, false, "UTC");
 
-  // Check that %Ez also accepts "Z" as a synonym for "+00:00".
+  // Check that %ET also accepts "t".
   time_point<chrono::nanoseconds> tp2;
-  EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00Z", tz, &tp2));
+  EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12t20:21:00+00:00", tz, &tp2));
   EXPECT_EQ(tp, tp2);
+
+  // Check that %Ez also accepts "Z" as a synonym for "+00:00".
+  time_point<chrono::nanoseconds> tp3;
+  EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00Z", tz, &tp3));
+  EXPECT_EQ(tp, tp3);
+
+  // Check that %Ez also accepts "z" as a synonym for "+00:00".
+  time_point<chrono::nanoseconds> tp4;
+  EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00z", tz, &tp4));
+  EXPECT_EQ(tp, tp4);
+}
+
+TEST(Parse, Week) {
+  const time_zone utc = utc_time_zone();
+  time_point<absl::time_internal::cctz::seconds> tp;
+
+  auto exp = convert(civil_second(2017, 1, 1, 0, 0, 0), utc);
+  EXPECT_TRUE(parse("%Y-%U-%u", "2017-01-7", utc, &tp));
+  EXPECT_EQ(exp, tp);
+  EXPECT_TRUE(parse("%Y-%W-%w", "2017-00-0", utc, &tp));
+  EXPECT_EQ(exp, tp);
+
+  exp = convert(civil_second(2017, 12, 31, 0, 0, 0), utc);
+  EXPECT_TRUE(parse("%Y-%U-%u", "2017-53-7", utc, &tp));
+  EXPECT_EQ(exp, tp);
+  EXPECT_TRUE(parse("%Y-%W-%w", "2017-52-0", utc, &tp));
+  EXPECT_EQ(exp, tp);
+
+  exp = convert(civil_second(2018, 1, 1, 0, 0, 0), utc);
+  EXPECT_TRUE(parse("%Y-%U-%u", "2018-00-1", utc, &tp));
+  EXPECT_EQ(exp, tp);
+  EXPECT_TRUE(parse("%Y-%W-%w", "2018-01-1", utc, &tp));
+  EXPECT_EQ(exp, tp);
+
+  exp = convert(civil_second(2018, 12, 31, 0, 0, 0), utc);
+  EXPECT_TRUE(parse("%Y-%U-%u", "2018-52-1", utc, &tp));
+  EXPECT_EQ(exp, tp);
+  EXPECT_TRUE(parse("%Y-%W-%w", "2018-53-1", utc, &tp));
+  EXPECT_EQ(exp, tp);
+
+  exp = convert(civil_second(2019, 1, 1, 0, 0, 0), utc);
+  EXPECT_TRUE(parse("%Y-%U-%u", "2019-00-2", utc, &tp));
+  EXPECT_EQ(exp, tp);
+  EXPECT_TRUE(parse("%Y-%W-%w", "2019-00-2", utc, &tp));
+  EXPECT_EQ(exp, tp);
+
+  exp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
+  EXPECT_TRUE(parse("%Y-%U-%u", "2019-52-2", utc, &tp));
+  EXPECT_EQ(exp, tp);
+  EXPECT_TRUE(parse("%Y-%W-%w", "2019-52-2", utc, &tp));
+  EXPECT_EQ(exp, tp);
+}
+
+TEST(Parse, WeekYearShift) {
+  // %U/%W conversions with week values in {0, 52, 53} can slip
+  // into the previous/following calendar years.
+  const time_zone utc = utc_time_zone();
+  time_point<absl::time_internal::cctz::seconds> tp;
+
+  auto exp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
+  EXPECT_TRUE(parse("%Y-%U-%u", "2020-00-2", utc, &tp));
+  EXPECT_EQ(exp, tp);
+  EXPECT_TRUE(parse("%Y-%W-%w", "2020-00-2", utc, &tp));
+  EXPECT_EQ(exp, tp);
+
+  exp = convert(civil_second(2021, 1, 1, 0, 0, 0), utc);
+  EXPECT_TRUE(parse("%Y-%U-%u", "2020-52-5", utc, &tp));
+  EXPECT_EQ(exp, tp);
+  EXPECT_TRUE(parse("%Y-%W-%w", "2020-52-5", utc, &tp));
+  EXPECT_EQ(exp, tp);
+
+  // Slipping into the previous/following calendar years should fail when
+  // we're already at the extremes.
+  EXPECT_FALSE(parse("%Y-%U-%u", "-9223372036854775808-0-7", utc, &tp));
+  EXPECT_FALSE(parse("%Y-%U-%u", "9223372036854775807-53-7", utc, &tp));
 }
 
 TEST(Parse, MaxRange) {
diff --git a/absl/time/internal/cctz/src/time_zone_impl.cc b/absl/time/internal/cctz/src/time_zone_impl.cc
index 030ae0e..f34e3ae 100644
--- a/absl/time/internal/cctz/src/time_zone_impl.cc
+++ b/absl/time/internal/cctz/src/time_zone_impl.cc
@@ -15,6 +15,7 @@
 #include "time_zone_impl.h"
 
 #include <deque>
+#include <memory>
 #include <mutex>
 #include <string>
 #include <unordered_map>
@@ -48,17 +49,16 @@
 time_zone time_zone::Impl::UTC() { return time_zone(UTCImpl()); }
 
 bool time_zone::Impl::LoadTimeZone(const std::string& name, time_zone* tz) {
-  const time_zone::Impl* const utc_impl = UTCImpl();
+  const Impl* const utc_impl = UTCImpl();
 
-  // First check for UTC (which is never a key in time_zone_map).
+  // Check for UTC (which is never a key in time_zone_map).
   auto offset = seconds::zero();
   if (FixedOffsetFromName(name, &offset) && offset == seconds::zero()) {
     *tz = time_zone(utc_impl);
     return true;
   }
 
-  // Then check, under a shared lock, whether the time zone has already
-  // been loaded. This is the common path. TODO: Move to shared_mutex.
+  // Check whether the time zone has already been loaded.
   {
     std::lock_guard<std::mutex> lock(TimeZoneMutex());
     if (time_zone_map != nullptr) {
@@ -70,20 +70,15 @@
     }
   }
 
-  // Now check again, under an exclusive lock.
+  // Load the new time zone (outside the lock).
+  std::unique_ptr<const Impl> new_impl(new Impl(name));
+
+  // Add the new time zone to the map.
   std::lock_guard<std::mutex> lock(TimeZoneMutex());
   if (time_zone_map == nullptr) time_zone_map = new TimeZoneImplByName;
   const Impl*& impl = (*time_zone_map)[name];
-  if (impl == nullptr) {
-    // The first thread in loads the new time zone.
-    Impl* new_impl = new Impl(name);
-    new_impl->zone_ = TimeZoneIf::Load(new_impl->name_);
-    if (new_impl->zone_ == nullptr) {
-      delete new_impl;  // free the nascent Impl
-      impl = utc_impl;  // and fallback to UTC
-    } else {
-      impl = new_impl;  // install new time zone
-    }
+  if (impl == nullptr) {  // this thread won any load race
+    impl = new_impl->zone_ ? new_impl.release() : utc_impl;
   }
   *tz = time_zone(impl);
   return impl != utc_impl;
@@ -104,14 +99,11 @@
   }
 }
 
-time_zone::Impl::Impl(const std::string& name) : name_(name) {}
+time_zone::Impl::Impl(const std::string& name)
+    : name_(name), zone_(TimeZoneIf::Load(name_)) {}
 
 const time_zone::Impl* time_zone::Impl::UTCImpl() {
-  static Impl* utc_impl = [] {
-    Impl* impl = new Impl("UTC");
-    impl->zone_ = TimeZoneIf::Load(impl->name_);  // never fails
-    return impl;
-  }();
+  static const Impl* utc_impl = new Impl("UTC");  // never fails
   return utc_impl;
 }
 
diff --git a/absl/time/internal/cctz/src/time_zone_impl.h b/absl/time/internal/cctz/src/time_zone_impl.h
index 69806c1..7d747ba 100644
--- a/absl/time/internal/cctz/src/time_zone_impl.h
+++ b/absl/time/internal/cctz/src/time_zone_impl.h
@@ -71,7 +71,7 @@
     return zone_->PrevTransition(tp, trans);
   }
 
-  // Returns an implementation-defined version std::string for this time zone.
+  // Returns an implementation-defined version string for this time zone.
   std::string Version() const { return zone_->Version(); }
 
   // Returns an implementation-defined description of this time zone.
diff --git a/absl/time/internal/cctz/src/time_zone_info.cc b/absl/time/internal/cctz/src/time_zone_info.cc
index f1697cd..8039353 100644
--- a/absl/time/internal/cctz/src/time_zone_info.cc
+++ b/absl/time/internal/cctz/src/time_zone_info.cc
@@ -40,7 +40,6 @@
 #include <cstdlib>
 #include <cstring>
 #include <functional>
-#include <iostream>
 #include <memory>
 #include <sstream>
 #include <string>
@@ -83,6 +82,27 @@
     366 * kSecsPerDay,
 };
 
+// Convert a cctz::weekday to a POSIX TZ weekday number (0==Sun, ..., 6=Sat).
+inline int ToPosixWeekday(weekday wd) {
+  switch (wd) {
+    case weekday::sunday:
+      return 0;
+    case weekday::monday:
+      return 1;
+    case weekday::tuesday:
+      return 2;
+    case weekday::wednesday:
+      return 3;
+    case weekday::thursday:
+      return 4;
+    case weekday::friday:
+      return 5;
+    case weekday::saturday:
+      return 6;
+  }
+  return 0; /*NOTREACHED*/
+}
+
 // Single-byte, unsigned numeric values are encoded directly.
 inline std::uint_fast8_t Decode8(const char* cp) {
   return static_cast<std::uint_fast8_t>(*cp) & 0xff;
@@ -188,15 +208,13 @@
   tt.is_dst = false;
   tt.abbr_index = 0;
 
-  // We temporarily add some redundant, contemporary (2013 through 2023)
+  // We temporarily add some redundant, contemporary (2015 through 2025)
   // transitions for performance reasons.  See TimeZoneInfo::LocalTime().
   // TODO: Fix the performance issue and remove the extra transitions.
   transitions_.clear();
   transitions_.reserve(12);
   for (const std::int_fast64_t unix_time : {
-           -(1LL << 59),  // BIG_BANG
-           1356998400LL,  // 2013-01-01T00:00:00+00:00
-           1388534400LL,  // 2014-01-01T00:00:00+00:00
+           -(1LL << 59),  // a "first half" transition
            1420070400LL,  // 2015-01-01T00:00:00+00:00
            1451606400LL,  // 2016-01-01T00:00:00+00:00
            1483228800LL,  // 2017-01-01T00:00:00+00:00
@@ -206,7 +224,8 @@
            1609459200LL,  // 2021-01-01T00:00:00+00:00
            1640995200LL,  // 2022-01-01T00:00:00+00:00
            1672531200LL,  // 2023-01-01T00:00:00+00:00
-           2147483647LL,  // 2^31 - 1
+           1704067200LL,  // 2024-01-01T00:00:00+00:00
+           1735689600LL,  // 2025-01-01T00:00:00+00:00
        }) {
     Transition& tr(*transitions_.emplace(transitions_.end()));
     tr.unix_time = unix_time;
@@ -217,8 +236,8 @@
 
   default_transition_type_ = 0;
   abbreviations_ = FixedOffsetToAbbr(offset);
-  abbreviations_.append(1, '\0');  // add NUL
-  future_spec_.clear();            // never needed for a fixed-offset zone
+  abbreviations_.append(1, '\0');
+  future_spec_.clear();  // never needed for a fixed-offset zone
   extended_ = false;
 
   tt.civil_max = LocalTime(seconds::max().count(), tt).cs;
@@ -259,21 +278,6 @@
   return len;
 }
 
-// Check that the TransitionType has the expected offset/is_dst/abbreviation.
-void TimeZoneInfo::CheckTransition(const std::string& name,
-                                   const TransitionType& tt,
-                                   std::int_fast32_t offset, bool is_dst,
-                                   const std::string& abbr) const {
-  if (tt.utc_offset != offset || tt.is_dst != is_dst ||
-      &abbreviations_[tt.abbr_index] != abbr) {
-    std::clog << name << ": Transition"
-              << " offset=" << tt.utc_offset << "/"
-              << (tt.is_dst ? "DST" : "STD")
-              << "/abbr=" << &abbreviations_[tt.abbr_index]
-              << " does not match POSIX spec '" << future_spec_ << "'\n";
-  }
-}
-
 // zic(8) can generate no-op transitions when a zone changes rules at an
 // instant when there is actually no discontinuity.  So we check whether
 // two transitions have equivalent types (same offset/is_dst/abbr).
@@ -282,117 +286,108 @@
   if (tt1_index == tt2_index) return true;
   const TransitionType& tt1(transition_types_[tt1_index]);
   const TransitionType& tt2(transition_types_[tt2_index]);
-  if (tt1.is_dst != tt2.is_dst) return false;
   if (tt1.utc_offset != tt2.utc_offset) return false;
+  if (tt1.is_dst != tt2.is_dst) return false;
   if (tt1.abbr_index != tt2.abbr_index) return false;
   return true;
 }
 
+// Find/make a transition type with these attributes.
+bool TimeZoneInfo::GetTransitionType(std::int_fast32_t utc_offset, bool is_dst,
+                                     const std::string& abbr,
+                                     std::uint_least8_t* index) {
+  std::size_t type_index = 0;
+  std::size_t abbr_index = abbreviations_.size();
+  for (; type_index != transition_types_.size(); ++type_index) {
+    const TransitionType& tt(transition_types_[type_index]);
+    const char* tt_abbr = &abbreviations_[tt.abbr_index];
+    if (tt_abbr == abbr) abbr_index = tt.abbr_index;
+    if (tt.utc_offset == utc_offset && tt.is_dst == is_dst) {
+      if (abbr_index == tt.abbr_index) break;  // reuse
+    }
+  }
+  if (type_index > 255 || abbr_index > 255) {
+    // No index space (8 bits) available for a new type or abbreviation.
+    return false;
+  }
+  if (type_index == transition_types_.size()) {
+    TransitionType& tt(*transition_types_.emplace(transition_types_.end()));
+    tt.utc_offset = static_cast<std::int_least32_t>(utc_offset);
+    tt.is_dst = is_dst;
+    if (abbr_index == abbreviations_.size()) {
+      abbreviations_.append(abbr);
+      abbreviations_.append(1, '\0');
+    }
+    tt.abbr_index = static_cast<std::uint_least8_t>(abbr_index);
+  }
+  *index = static_cast<std::uint_least8_t>(type_index);
+  return true;
+}
+
 // Use the POSIX-TZ-environment-variable-style string to handle times
 // in years after the last transition stored in the zoneinfo data.
-void TimeZoneInfo::ExtendTransitions(const std::string& name,
-                                     const Header& hdr) {
+bool TimeZoneInfo::ExtendTransitions() {
   extended_ = false;
-  bool extending = !future_spec_.empty();
+  if (future_spec_.empty()) return true;  // last transition prevails
 
   PosixTimeZone posix;
-  if (extending && !ParsePosixSpec(future_spec_, &posix)) {
-    std::clog << name << ": Failed to parse '" << future_spec_ << "'\n";
-    extending = false;
+  if (!ParsePosixSpec(future_spec_, &posix)) return false;
+
+  // Find transition type for the future std specification.
+  std::uint_least8_t std_ti;
+  if (!GetTransitionType(posix.std_offset, false, posix.std_abbr, &std_ti))
+    return false;
+
+  if (posix.dst_abbr.empty()) {  // std only
+    // The future specification should match the last transition, and
+    // that means that handling the future will fall out naturally.
+    return EquivTransitions(transitions_.back().type_index, std_ti);
   }
 
-  if (extending && posix.dst_abbr.empty()) {  // std only
-    // The future specification should match the last/default transition,
-    // and that means that handling the future will fall out naturally.
-    std::uint_fast8_t index = default_transition_type_;
-    if (hdr.timecnt != 0) index = transitions_[hdr.timecnt - 1].type_index;
-    const TransitionType& tt(transition_types_[index]);
-    CheckTransition(name, tt, posix.std_offset, false, posix.std_abbr);
-    extending = false;
-  }
-
-  if (extending && hdr.timecnt < 2) {
-    std::clog << name << ": Too few transitions for POSIX spec\n";
-    extending = false;
-  }
-
-  if (!extending) {
-    // Ensure that there is always a transition in the second half of the
-    // time line (the BIG_BANG transition is in the first half) so that the
-    // signed difference between a civil_second and the civil_second of its
-    // previous transition is always representable, without overflow.
-    const Transition& last(transitions_.back());
-    if (last.unix_time < 0) {
-      const std::uint_fast8_t type_index = last.type_index;
-      Transition& tr(*transitions_.emplace(transitions_.end()));
-      tr.unix_time = 2147483647;  // 2038-01-19T03:14:07+00:00
-      tr.type_index = type_index;
-    }
-    return;  // last transition wins
-  }
+  // Find transition type for the future dst specification.
+  std::uint_least8_t dst_ti;
+  if (!GetTransitionType(posix.dst_offset, true, posix.dst_abbr, &dst_ti))
+    return false;
 
   // Extend the transitions for an additional 400 years using the
   // future specification. Years beyond those can be handled by
   // mapping back to a cycle-equivalent year within that range.
-  // zic(8) should probably do this so that we don't have to.
-  // TODO: Reduce the extension by the number of compatible
-  // transitions already in place.
-  transitions_.reserve(hdr.timecnt + 400 * 2 + 1);
-  transitions_.resize(hdr.timecnt + 400 * 2);
+  // We may need two additional transitions for the current year.
+  transitions_.reserve(transitions_.size() + 400 * 2 + 2);
   extended_ = true;
 
-  // The future specification should match the last two transitions,
-  // and those transitions should have different is_dst flags.  Note
-  // that nothing says the UTC offset used by the is_dst transition
-  // must be greater than that used by the !is_dst transition.  (See
-  // Europe/Dublin, for example.)
-  const Transition* tr0 = &transitions_[hdr.timecnt - 1];
-  const Transition* tr1 = &transitions_[hdr.timecnt - 2];
-  const TransitionType* tt0 = &transition_types_[tr0->type_index];
-  const TransitionType* tt1 = &transition_types_[tr1->type_index];
-  const TransitionType& dst(tt0->is_dst ? *tt0 : *tt1);
-  const TransitionType& std(tt0->is_dst ? *tt1 : *tt0);
-  CheckTransition(name, dst, posix.dst_offset, true, posix.dst_abbr);
-  CheckTransition(name, std, posix.std_offset, false, posix.std_abbr);
-
-  // Add the transitions to tr1 and back to tr0 for each extra year.
-  last_year_ = LocalTime(tr0->unix_time, *tt0).cs.year();
+  const Transition& last(transitions_.back());
+  const std::int_fast64_t last_time = last.unix_time;
+  const TransitionType& last_tt(transition_types_[last.type_index]);
+  last_year_ = LocalTime(last_time, last_tt).cs.year();
   bool leap_year = IsLeap(last_year_);
-  const civil_day jan1(last_year_, 1, 1);
-  std::int_fast64_t jan1_time = civil_second(jan1) - civil_second();
-  int jan1_weekday = (static_cast<int>(get_weekday(jan1)) + 1) % 7;
-  Transition* tr = &transitions_[hdr.timecnt];  // next trans to fill
-  if (LocalTime(tr1->unix_time, *tt1).cs.year() != last_year_) {
-    // Add a single extra transition to align to a calendar year.
-    transitions_.resize(transitions_.size() + 1);
-    assert(tr == &transitions_[hdr.timecnt]);  // no reallocation
-    const PosixTransition& pt1(tt0->is_dst ? posix.dst_end : posix.dst_start);
-    std::int_fast64_t tr1_offset = TransOffset(leap_year, jan1_weekday, pt1);
-    tr->unix_time = jan1_time + tr1_offset - tt0->utc_offset;
-    tr++->type_index = tr1->type_index;
-    tr0 = &transitions_[hdr.timecnt];
-    tr1 = &transitions_[hdr.timecnt - 1];
-    tt0 = &transition_types_[tr0->type_index];
-    tt1 = &transition_types_[tr1->type_index];
-  }
-  const PosixTransition& pt1(tt0->is_dst ? posix.dst_end : posix.dst_start);
-  const PosixTransition& pt0(tt0->is_dst ? posix.dst_start : posix.dst_end);
-  for (const year_t limit = last_year_ + 400; last_year_ < limit;) {
-    last_year_ += 1;  // an additional year of generated transitions
+  const civil_second jan1(last_year_);
+  std::int_fast64_t jan1_time = jan1 - civil_second();
+  int jan1_weekday = ToPosixWeekday(get_weekday(jan1));
+
+  Transition dst = {0, dst_ti, civil_second(), civil_second()};
+  Transition std = {0, std_ti, civil_second(), civil_second()};
+  for (const year_t limit = last_year_ + 400;; ++last_year_) {
+    auto dst_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_start);
+    auto std_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_end);
+    dst.unix_time = jan1_time + dst_trans_off - posix.std_offset;
+    std.unix_time = jan1_time + std_trans_off - posix.dst_offset;
+    const auto* ta = dst.unix_time < std.unix_time ? &dst : &std;
+    const auto* tb = dst.unix_time < std.unix_time ? &std : &dst;
+    if (last_time < tb->unix_time) {
+      if (last_time < ta->unix_time) transitions_.push_back(*ta);
+      transitions_.push_back(*tb);
+    }
+    if (last_year_ == limit) break;
     jan1_time += kSecsPerYear[leap_year];
     jan1_weekday = (jan1_weekday + kDaysPerYear[leap_year]) % 7;
-    leap_year = !leap_year && IsLeap(last_year_);
-    std::int_fast64_t tr1_offset = TransOffset(leap_year, jan1_weekday, pt1);
-    tr->unix_time = jan1_time + tr1_offset - tt0->utc_offset;
-    tr++->type_index = tr1->type_index;
-    std::int_fast64_t tr0_offset = TransOffset(leap_year, jan1_weekday, pt0);
-    tr->unix_time = jan1_time + tr0_offset - tt1->utc_offset;
-    tr++->type_index = tr0->type_index;
+    leap_year = !leap_year && IsLeap(last_year_ + 1);
   }
-  assert(tr == &transitions_[0] + transitions_.size());
+
+  return true;
 }
 
-bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
+bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
   // Read and validate the header.
   tzhead tzh;
   if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false;
@@ -430,7 +425,7 @@
   const char* bp = tbuf.data();
 
   // Decode and validate the transitions.
-  transitions_.reserve(hdr.timecnt + 2);  // We might add a couple.
+  transitions_.reserve(hdr.timecnt + 2);
   transitions_.resize(hdr.timecnt);
   for (std::size_t i = 0; i != hdr.timecnt; ++i) {
     transitions_[i].unix_time = (time_len == 4) ? Decode32(bp) : Decode64(bp);
@@ -449,6 +444,7 @@
   }
 
   // Decode and validate the transition types.
+  transition_types_.reserve(hdr.typecnt + 2);
   transition_types_.resize(hdr.typecnt);
   for (std::size_t i = 0; i != hdr.typecnt; ++i) {
     transition_types_[i].utc_offset =
@@ -475,6 +471,7 @@
   }
 
   // Copy all the abbreviations.
+  abbreviations_.reserve(hdr.charcnt + 10);
   abbreviations_.assign(bp, hdr.charcnt);
   bp += hdr.charcnt;
 
@@ -506,7 +503,7 @@
 
   // If we did not find version information during the standard loading
   // process (as of tzh_version '3' that is unsupported), then ask the
-  // ZoneInfoSource for any out-of-bound version std::string it may be privy to.
+  // ZoneInfoSource for any out-of-bound version string it may be privy to.
   if (version_.empty()) {
     version_ = zip->Version();
   }
@@ -525,19 +522,29 @@
   transitions_.resize(hdr.timecnt);
 
   // Ensure that there is always a transition in the first half of the
-  // time line (the second half is handled in ExtendTransitions()) so that
-  // the signed difference between a civil_second and the civil_second of
-  // its previous transition is always representable, without overflow.
-  // A contemporary zic will usually have already done this for us.
+  // time line (the second half is handled below) so that the signed
+  // difference between a civil_second and the civil_second of its
+  // previous transition is always representable, without overflow.
   if (transitions_.empty() || transitions_.front().unix_time >= 0) {
     Transition& tr(*transitions_.emplace(transitions_.begin()));
-    tr.unix_time = -(1LL << 59);  // see tz/zic.c "BIG_BANG"
+    tr.unix_time = -(1LL << 59);  // -18267312070-10-26T17:01:52+00:00
     tr.type_index = default_transition_type_;
-    hdr.timecnt += 1;
   }
 
   // Extend the transitions using the future specification.
-  ExtendTransitions(name, hdr);
+  if (!ExtendTransitions()) return false;
+
+  // Ensure that there is always a transition in the second half of the
+  // time line (the first half is handled above) so that the signed
+  // difference between a civil_second and the civil_second of its
+  // previous transition is always representable, without overflow.
+  const Transition& last(transitions_.back());
+  if (last.unix_time < 0) {
+    const std::uint_fast8_t type_index = last.type_index;
+    Transition& tr(*transitions_.emplace(transitions_.end()));
+    tr.unix_time = 2147483647;  // 2038-01-19T03:14:07+00:00
+    tr.type_index = type_index;
+  }
 
   // Compute the local civil time for each transition and the preceding
   // second. These will be used for reverse conversions in MakeTime().
@@ -718,12 +725,12 @@
 
   // Find and use a ZoneInfoSource to load the named zone.
   auto zip = cctz_extension::zone_info_source_factory(
-      name, [](const std::string& name) -> std::unique_ptr<ZoneInfoSource> {
-        if (auto zip = FileZoneInfoSource::Open(name)) return zip;
-        if (auto zip = AndroidZoneInfoSource::Open(name)) return zip;
+      name, [](const std::string& n) -> std::unique_ptr<ZoneInfoSource> {
+        if (auto z = FileZoneInfoSource::Open(n)) return z;
+        if (auto z = AndroidZoneInfoSource::Open(n)) return z;
         return nullptr;
       });
-  return zip != nullptr && Load(name, zip.get());
+  return zip != nullptr && Load(zip.get());
 }
 
 // BreakTime() translation for a particular transition type.
@@ -897,8 +904,8 @@
   const Transition* begin = &transitions_[0];
   const Transition* end = begin + transitions_.size();
   if (begin->unix_time <= -(1LL << 59)) {
-    // Do not report the BIG_BANG found in recent zoneinfo data as it is
-    // really a sentinel, not a transition.  See tz/zic.c.
+    // Do not report the BIG_BANG found in some zoneinfo data as it is
+    // really a sentinel, not a transition.  See pre-2018f tz/zic.c.
     ++begin;
   }
   std::int_fast64_t unix_time = ToUnixSeconds(tp);
@@ -923,8 +930,8 @@
   const Transition* begin = &transitions_[0];
   const Transition* end = begin + transitions_.size();
   if (begin->unix_time <= -(1LL << 59)) {
-    // Do not report the BIG_BANG found in recent zoneinfo data as it is
-    // really a sentinel, not a transition.  See tz/zic.c.
+    // Do not report the BIG_BANG found in some zoneinfo data as it is
+    // really a sentinel, not a transition.  See pre-2018f tz/zic.c.
     ++begin;
   }
   std::int_fast64_t unix_time = ToUnixSeconds(tp);
diff --git a/absl/time/internal/cctz/src/time_zone_info.h b/absl/time/internal/cctz/src/time_zone_info.h
index 2a10c06..2467ff5 100644
--- a/absl/time/internal/cctz/src/time_zone_info.h
+++ b/absl/time/internal/cctz/src/time_zone_info.h
@@ -95,15 +95,14 @@
     std::size_t DataLength(std::size_t time_len) const;
   };
 
-  void CheckTransition(const std::string& name, const TransitionType& tt,
-                       std::int_fast32_t offset, bool is_dst,
-                       const std::string& abbr) const;
+  bool GetTransitionType(std::int_fast32_t utc_offset, bool is_dst,
+                         const std::string& abbr, std::uint_least8_t* index);
   bool EquivTransitions(std::uint_fast8_t tt1_index,
                         std::uint_fast8_t tt2_index) const;
-  void ExtendTransitions(const std::string& name, const Header& hdr);
+  bool ExtendTransitions();
 
   bool ResetToBuiltinUTC(const seconds& offset);
-  bool Load(const std::string& name, ZoneInfoSource* zip);
+  bool Load(ZoneInfoSource* zip);
 
   // Helpers for BreakTime() and MakeTime().
   time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc
index 47cf84c..887dd09 100644
--- a/absl/time/internal/cctz/src/time_zone_libc.cc
+++ b/absl/time/internal/cctz/src/time_zone_libc.cc
@@ -27,6 +27,12 @@
 #include "absl/time/internal/cctz/include/cctz/civil_time.h"
 #include "absl/time/internal/cctz/include/cctz/time_zone.h"
 
+#if defined(_AIX)
+extern "C" {
+extern long altzone;
+}
+#endif
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace time_internal {
@@ -44,7 +50,7 @@
   const bool is_dst = tm.tm_isdst > 0;
   return _tzname[is_dst];
 }
-#elif defined(__sun)
+#elif defined(__sun) || defined(_AIX)
 // Uses the globals: 'timezone', 'altzone' and 'tzname'.
 auto tm_gmtoff(const std::tm& tm) -> decltype(timezone) {
   const bool is_dst = tm.tm_isdst > 0;
@@ -153,7 +159,8 @@
   std::tm tm;
   while (lo + 1 != hi) {
     const std::time_t mid = lo + (hi - lo) / 2;
-    if (std::tm* tmp = local_time(&mid, &tm)) {
+    std::tm* tmp = local_time(&mid, &tm);
+    if (tmp != nullptr) {
       if (tm_gmtoff(*tmp) == offset) {
         hi = mid;
       } else {
@@ -163,7 +170,8 @@
       // If std::tm cannot hold some result we resort to a linear search,
       // ignoring all failed conversions.  Slow, but never really happens.
       while (++lo != hi) {
-        if (std::tm* tmp = local_time(&lo, &tm)) {
+        tmp = local_time(&lo, &tm);
+        if (tmp != nullptr) {
           if (tm_gmtoff(*tmp) == offset) break;
         }
       }
@@ -223,11 +231,10 @@
         civil_second() + ToUnixSeconds(time_point<seconds>::min());
     static const civil_second max_tp_cs =
         civil_second() + ToUnixSeconds(time_point<seconds>::max());
-    const time_point<seconds> tp =
-        (cs < min_tp_cs)
-            ? time_point<seconds>::min()
-            : (cs > max_tp_cs) ? time_point<seconds>::max()
-                               : FromUnixSeconds(cs - civil_second());
+    const time_point<seconds> tp = (cs < min_tp_cs) ? time_point<seconds>::min()
+                                   : (cs > max_tp_cs)
+                                       ? time_point<seconds>::max()
+                                       : FromUnixSeconds(cs - civil_second());
     return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
   }
 
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 99137a0..9a1a8d6 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -211,6 +211,7 @@
                                       "America/North_Dakota/Beulah",
                                       "America/North_Dakota/Center",
                                       "America/North_Dakota/New_Salem",
+                                      "America/Nuuk",
                                       "America/Ojinaga",
                                       "America/Panama",
                                       "America/Pangnirtung",
@@ -749,7 +750,7 @@
   EXPECT_EQ(chrono::system_clock::from_time_t(0),
             convert(civil_second(1970, 1, 1, 0, 0, 0), tz));  // UTC
 
-  // Loading an empty std::string timezone should fail.
+  // Loading an empty string timezone should fail.
   tz = LoadZone("America/Los_Angeles");
   EXPECT_FALSE(load_time_zone("", &tz));
   EXPECT_EQ(chrono::system_clock::from_time_t(0),
@@ -932,7 +933,7 @@
 
 // NOTE: Run this with -ftrapv to detect overflow problems.
 TEST(MakeTime, SysSecondsLimits) {
-  const char RFC3339[] = "%Y-%m-%dT%H:%M:%S%Ez";
+  const char RFC3339[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
   const time_zone utc = utc_time_zone();
   const time_zone east = fixed_time_zone(chrono::hours(14));
   const time_zone west = fixed_time_zone(-chrono::hours(14));
@@ -1003,13 +1004,17 @@
 #if defined(_WIN32) || defined(_WIN64)
     // localtime_s() and gmtime_s() don't believe in years outside [1970:3000].
 #else
-    const time_zone utc = LoadZone("libc:UTC");
+    const time_zone cut = LoadZone("libc:UTC");
     const year_t max_tm_year = year_t{std::numeric_limits<int>::max()} + 1900;
-    tp = convert(civil_second(max_tm_year, 12, 31, 23, 59, 59), utc);
-    EXPECT_EQ("2147485547-12-31T23:59:59+00:00", format(RFC3339, tp, utc));
+    tp = convert(civil_second(max_tm_year, 12, 31, 23, 59, 59), cut);
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+    // The BSD gmtime_r() fails on extreme positive tm_year values.
+#else
+    EXPECT_EQ("2147485547-12-31T23:59:59+00:00", format(RFC3339, tp, cut));
+#endif
     const year_t min_tm_year = year_t{std::numeric_limits<int>::min()} + 1900;
-    tp = convert(civil_second(min_tm_year, 1, 1, 0, 0, 0), utc);
-    EXPECT_EQ("-2147481748-01-01T00:00:00+00:00", format(RFC3339, tp, utc));
+    tp = convert(civil_second(min_tm_year, 1, 1, 0, 0, 0), cut);
+    EXPECT_EQ("-2147481748-01-01T00:00:00+00:00", format(RFC3339, tp, cut));
 #endif
   }
 }
diff --git a/absl/time/internal/cctz/src/tzfile.h b/absl/time/internal/cctz/src/tzfile.h
index 1ed55e0..269fa36 100644
--- a/absl/time/internal/cctz/src/tzfile.h
+++ b/absl/time/internal/cctz/src/tzfile.h
@@ -83,13 +83,13 @@
 ** If tzh_version is '2' or greater, the above is followed by a second instance
 ** of tzhead and a second instance of the data in which each coded transition
 ** time uses 8 rather than 4 chars,
-** then a POSIX-TZ-environment-variable-style std::string for use in handling
+** then a POSIX-TZ-environment-variable-style string for use in handling
 ** instants after the last transition time stored in the file
 ** (with nothing between the newlines if there is no POSIX representation for
 ** such instants).
 **
 ** If tz_version is '3' or greater, the above is extended as follows.
-** First, the POSIX TZ std::string's hour offset may range from -167
+** First, the POSIX TZ string's hour offset may range from -167
 ** through 167 as compared to the POSIX-required 0 through 24.
 ** Second, its DST start time may be January 1 at 00:00 and its stop
 ** time December 31 at 24:00 plus the difference between DST and
diff --git a/absl/time/internal/cctz/src/zone_info_source.cc b/absl/time/internal/cctz/src/zone_info_source.cc
index 98ea161..7209533 100644
--- a/absl/time/internal/cctz/src/zone_info_source.cc
+++ b/absl/time/internal/cctz/src/zone_info_source.cc
@@ -83,7 +83,8 @@
     "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS                                   \
     "@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
     "@@ZA")
-#elif defined(_M_IA_64) || defined(_M_AMD64) || defined(_M_ARM64)
+#elif defined(_M_IA_64) || defined(_M_AMD64) || defined(_M_ARM) || \
+    defined(_M_ARM64)
 #pragma comment(                                                                                                          \
     linker,                                                                                                               \
     "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@" ABSL_INTERNAL_MANGLED_NS                     \
diff --git a/absl/time/internal/cctz/testdata/version b/absl/time/internal/cctz/testdata/version
index db18f83..1d59095 100644
--- a/absl/time/internal/cctz/testdata/version
+++ b/absl/time/internal/cctz/testdata/version
@@ -1 +1 @@
-2019c
+2021a
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan
index 28b32ab..8906e88 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra
index 697b993..c39ae38 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa
index 9a2918f..5f4ebcb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers
index ae04342..56a4dd2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara
index 9a2918f..5f4ebcb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera
index 9a2918f..5f4ebcb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako
index 28b32ab..8906e88 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui
index 0c80137..3d7a71b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul
index 28b32ab..8906e88 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau
index 82ea5aa..0da1d1e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre
index 52753c0..651e5cf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville
index 0c80137..3d7a71b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura
index 52753c0..651e5cf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo
index d3f8196..ea38c97 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
index 245f4eb..0263c90 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta
index 850c8f0..a461dce 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry
index 28b32ab..8906e88 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar
index 28b32ab..8906e88 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam
index 9a2918f..5f4ebcb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti
index 9a2918f..5f4ebcb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala
index 0c80137..3d7a71b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun b/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
index a91f65f..772e23c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown
index 28b32ab..8906e88 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone
index 52753c0..651e5cf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare
index 52753c0..651e5cf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg
index b1c425d..bada063 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba
index 625b1ac..0aba9ff 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala
index 9a2918f..5f4ebcb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum
index 8ee8cb9..3f8e44b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali
index 52753c0..651e5cf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa
index 0c80137..3d7a71b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos
index 0c80137..3d7a71b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville
index 0c80137..3d7a71b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome
index 28b32ab..8906e88 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda
index 0c80137..3d7a71b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi
index 52753c0..651e5cf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka
index 52753c0..651e5cf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo
index 0c80137..3d7a71b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo
index 52753c0..651e5cf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru
index b1c425d..bada063 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane
index b1c425d..bada063 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu
index 9a2918f..5f4ebcb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia
index 6d68850..8377809 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi
index 9a2918f..5f4ebcb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena
index a968845..ecbc096 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey
index 0c80137..3d7a71b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott
index 28b32ab..8906e88 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou
index 28b32ab..8906e88 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo
index 0c80137..3d7a71b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome
index 59f3759..425ad3f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu
index 28b32ab..8906e88 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli
index 07b393b..e0c8997 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis
index 427fa56..ca324cb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek
index abecd13..0edc52b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Adak b/absl/time/internal/cctz/testdata/zoneinfo/America/Adak
index 4323649..b1497bd 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Adak
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Adak
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage b/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage
index 9bbb2fd..cdf0572 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla b/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla
index 697cf5b..f4fe590 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua b/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua
index 697cf5b..f4fe590 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina b/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina
index 49381b4..f66c9f7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires
index 260f86a..d6f999b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca
index 0ae222a..1dcc8d8 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia
index 0ae222a..1dcc8d8 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba
index da4c23a..35a52e5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy
index 604b856..b275f27 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja
index 2218e36..23fca12 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza
index f9e677f..691c569 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos
index c36587e..991d1fa 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta
index 0e797f2..58863e0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan
index 2698495..7eba33c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis
index fe50f62..0a81cbd 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman
index c954000..10556d5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia
index 3643628..e031750 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba b/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba
index f7ab6ef..d6ddf7d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion b/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion
index 2f3bbda..6225036 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan b/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan
index 629ed42..c828715 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Atka b/absl/time/internal/cctz/testdata/zoneinfo/America/Atka
index 4323649..b1497bd 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Atka
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Atka
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia
index 15808d3..7969e30 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas
index 896af3f..cbe22a7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados b/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados
index 9b90e30..9d3afa6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Belem b/absl/time/internal/cctz/testdata/zoneinfo/America/Belem
index 60b5924..e0d7653 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Belem
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Belem
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Belize b/absl/time/internal/cctz/testdata/zoneinfo/America/Belize
index 851051a..bfc19f4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Belize
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Belize
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon b/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon
index f9f13a1..7096b69 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista b/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista
index 978c331..fca9720 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota b/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota
index b2647d7..6cb53d4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Boise b/absl/time/internal/cctz/testdata/zoneinfo/America/Boise
index f8d54e2..72fec9e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Boise
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Boise
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires b/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires
index 260f86a..d6f999b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay b/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay
index f8db4b6..0a22252 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande b/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande
index 8120624..6855e4e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun b/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun
index f907f0a..640b259 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas b/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas
index eedf725..8dbe6ff 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca b/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca
index 0ae222a..1dcc8d8 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne
index e5bc06f..cd49f05 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman
index 9964b9a..9154643 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago b/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago
index a5b1617..b016880 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua b/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua
index 8ed5f93..e1780a5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour b/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour
index 629ed42..c828715 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba b/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba
index da4c23a..35a52e5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica b/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica
index 37cb85e..08f0128 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Creston b/absl/time/internal/cctz/testdata/zoneinfo/America/Creston
index ca64857..9d69a0a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Creston
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Creston
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba b/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba
index 9bea3d4..c09a875 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao b/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao
index f7ab6ef..d6ddf7d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn b/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn
index 9549adc..8718efc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson b/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson
index db9cead..07e4c5f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek b/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek
index db9e339..761d1d9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Denver b/absl/time/internal/cctz/testdata/zoneinfo/America/Denver
index 5fbe26b..09e54e5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Denver
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Denver
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit b/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit
index e104faa..6eb3ac4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica b/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica
index 697cf5b..f4fe590 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton b/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton
index cd78a6f..645ee94 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe b/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe
index 39d6dae..7da4b98 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador b/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador
index e2f2230..4348411 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada b/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada
index ada6bf7..19ccd35 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/Fort_Nelson b/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson
index 5a0b7f1..2a49c6c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne b/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne
index 09511cc..6b08d15 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza b/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza
index be57dc2..092e40d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay b/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay
index 48412a4..f85eb34 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab b/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab
index 0160308..4ddc99d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay b/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay
index a3f2990..820e0dd 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk b/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk
index b9bb063..9d90e74 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada b/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada
index 697cf5b..f4fe590 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe b/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe
index 697cf5b..f4fe590 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala b/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala
index 407138c..8aa8e58 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil b/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil
index 0559a7a..381ae6c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana b/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana
index d5dab14..ebd85d0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax b/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax
index 756099a..9fa850a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Havana b/absl/time/internal/cctz/testdata/zoneinfo/America/Havana
index b69ac45..e06629d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Havana
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Havana
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo b/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo
index 791a9fa..8283239 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis
index 09511cc..6b08d15 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox
index fcd408d..b187d5f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo
index 1abf75e..a730fe6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg
index 0133548..341a023 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City
index 7bbb653..76e1f62 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay
index d236b7c..f2acf6c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes
index c818929..c255f89 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac
index 630935c..8700ed9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis b/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis
index 09511cc..6b08d15 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik b/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik
index 87bb355..af3107d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit b/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit
index c8138bd..eb2c99c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica b/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica
index 2a9b7fd..be6b1b6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy b/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy
index 604b856..b275f27 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau b/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau
index 451f349..e347b36 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville b/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville
index 177836e..f2136d6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello b/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello
index 438e3ea..d9f54a1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN b/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN
index fcd408d..b187d5f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk b/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk
index f7ab6ef..d6ddf7d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz b/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz
index a101372..68ddaae 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Lima b/absl/time/internal/cctz/testdata/zoneinfo/America/Lima
index 3c6529b..b643c55 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Lima
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Lima
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles b/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles
index 9dad4f4..aaf0778 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville b/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville
index 177836e..f2136d6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes b/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes
index f7ab6ef..d6ddf7d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio b/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio
index bc8b951..dbb8d57 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Managua b/absl/time/internal/cctz/testdata/zoneinfo/America/Managua
index e0242bf..86ef76b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Managua
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Managua
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus b/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus
index 63d58f8..59c952e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot b/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot
index 697cf5b..f4fe590 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique b/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique
index 8df43dc..25c0232 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros b/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros
index 047968d..722751b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan b/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan
index e4a7857..4c819fa 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza b/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza
index f9e677f..691c569 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee b/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee
index 3146138..28d2c56 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Merida b/absl/time/internal/cctz/testdata/zoneinfo/America/Merida
index ea852da..d3b0ca1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Merida
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Merida
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla b/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla
index 1e94be3..9fefee3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City b/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City
index e7fb6f2..ffcf8be 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon b/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon
index b924b71..3b62585 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton b/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton
index 9df8d0f..ecb69ef 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey b/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey
index a8928c8..dea9e3f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo b/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo
index 2f357bc..4b2fb3e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal b/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal
index 6752c5b..fe6be8e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat b/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat
index 697cf5b..f4fe590 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau b/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau
index 33cc6c6..2ef2aa8 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/New_York b/absl/time/internal/cctz/testdata/zoneinfo/America/New_York
index 2f75480..2b6c2ee 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/New_York
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/New_York
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon b/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon
index f6a856e..b9f67a9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Nome b/absl/time/internal/cctz/testdata/zoneinfo/America/Nome
index 10998df..23ead1c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Nome
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Nome
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha b/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha
index f140726..9e74745 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah
index 246345d..becf438 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center
index 1fa0703..d03bda0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem
index 123f2ae..ecefc15 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Nuuk b/absl/time/internal/cctz/testdata/zoneinfo/America/Nuuk
new file mode 100644
index 0000000..4ddc99d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Nuuk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga b/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga
index fc4a03e..da0909c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Panama b/absl/time/internal/cctz/testdata/zoneinfo/America/Panama
index 9964b9a..9154643 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Panama
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Panama
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung b/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung
index 3e4e0db..5be6f9b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo b/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo
index bc8a6ed..24f925a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix b/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix
index ac6bb0c..c2bd2f9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince b/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince
index 287f143..3e75731 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain b/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain
index 697cf5b..f4fe590 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre
index a374cb4..fb5185c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho
index 2e873a5..7f8047d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico b/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico
index a662a57..47b4dc3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas b/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas
index a5a8af5..5c9a20b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River b/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River
index ea66099..d6ddda4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet b/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet
index 3a70587..92e2ed2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Recife b/absl/time/internal/cctz/testdata/zoneinfo/America/Recife
index d7abb16..305abcb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Recife
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Recife
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Regina b/absl/time/internal/cctz/testdata/zoneinfo/America/Regina
index 20c9c84..a3f8217 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Regina
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Regina
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute b/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute
index 0a73b75..a84d1df 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco b/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco
index a374cb4..fb5185c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario b/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario
index da4c23a..35a52e5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario
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 ada6bf7..19ccd35 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/Santarem b/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem
index c28f360..f81d144 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago b/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago
index 816a042..8d60322 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo b/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo
index 4fe36fd..3e07850 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo b/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo
index 13ff083..a16da2c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund b/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund
index e20e9e1..6db4912 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock b/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock
index 5fbe26b..09e54e5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka b/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka
index 31f7061..36681ed 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy
index 697cf5b..f4fe590 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns
index 65a5b0c..e5f2aec 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts
index 697cf5b..f4fe590 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia
index 697cf5b..f4fe590 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas
index 697cf5b..f4fe590 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent
index 697cf5b..f4fe590 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current b/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current
index 8e9ef25..bdbb494 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa b/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa
index 2adacb2..38036a3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Thule b/absl/time/internal/cctz/testdata/zoneinfo/America/Thule
index 6f802f1..f38dc56 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Thule
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Thule
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay b/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay
index e504c9a..fcb0328 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana b/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana
index ada6bf7..19ccd35 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/America/Toronto b/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto
index 6752c5b..fe6be8e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola b/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola
index 697cf5b..f4fe590 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver b/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver
index bb60cbc..c998491 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin b/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin
index 697cf5b..f4fe590 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse b/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse
index fb3cd71..878b6a9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg b/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg
index ac40299..7e646d1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat b/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat
index da209f9..773feba 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife b/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife
index e6afa39..c779cef 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey
index f100f47..30315cc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis
index 916f2c2..3ec3222 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville
index a71b39c..c0cfc85 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie
index 616afd9..3fc1f23 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson
index b32e7fd..05e4c6c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo
index 6575fdc..afb3929 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer
index 3dd85f8..32c1941 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera
index 8b2430a..ea49c00 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole
index 6575fdc..afb3929 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa
index 254af7d..97d80d7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll
index 5e565da..4e31aff 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok
index 7283053..6e32907 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen b/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen
index 15a34c3..dfc5095 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden
index 2aea25f..01c47cc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty
index a4b0077..3ec4fc8 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman
index c9e8707..1bd09fe 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr
index 6ed8b7c..551884d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau
index e2d0f91..3a40d11 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe
index 06f0a13..62c5840 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat
index 73891af..8482167 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad
index 73891af..8482167 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau
index 8b5153e..cb2c82f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad
index f7162ed..a3ce975 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain
index 63188b2..7409d74 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku
index a0de74b..96203d7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok
index c292ac5..ed687d2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul
index 759592a..ff976dd 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut
index fb266ed..55dce57 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek
index f6e20dd..fe7832c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei
index 3dab0ab..e67b411 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta
index 0014046..00bc80a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita
index c4149c0..9d49cd3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan
index e48daa8..0a948c2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing
index 3c0bef2..d6b6698 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking
index 3c0bef2..d6b6698 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo
index 62c64d8..3eeb1b7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca
index b11c928..2813680 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus
index d9104a7..168ef9b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka
index b11c928..2813680 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili
index 30943bb..bb7be9f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai
index fc0a589..58d75bc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe
index 82d85b8..d83fb07 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta
index 653b146..cc44179 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza
index 592b632..58e9fdf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin
index 3c0bef2..d6b6698 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron
index ae82f9b..aeda06b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh
index e2934e3..7ca9972 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong
index 23d0375..c80e364 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd
index 4cb800a..6e08a26 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk
index 4dcbbb7..550e2a0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul
index 508446b..c891866 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta
index 5baa3a8..c9752d2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura
index 3002c82..7c22f53 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem
index 440ef06..4c49bbf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul
index d19b9bd..660ce4c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka
index 3e80b4e..c651554 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi
index ba65c0e..e56d5af 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar
index faa14d9..69ff7f6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu
index a5d5107..3a0d330 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu
index a5d5107..3a0d330 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga
index 72bea64..aeb7332 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata
index 0014046..00bc80a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk
index 30c6f16..e0d4fcb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur
index 612b01e..e93dd51 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching
index c86750c..59bc6e4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait
index 2aea25f..01c47cc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao
index cac6506..c22f75e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau
index cac6506..c22f75e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan
index b4fcac1..16bac84 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar
index 556ba86..5990010 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila
index f4f4b04..3c3584e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat
index fc0a589..58d75bc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia
index f7f10ab..c210d0a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk
index d983276..9378d50 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk
index e0ee5fc..65a9fa2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk
index b29b769..dc0ed42 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral
index ad1f9ca..25a63ec 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh
index c292ac5..ed687d2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak
index 12ce24c..285bed2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang
index 7ad7e0b..57240cf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar
index 63188b2..7409d74 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay
index 73b9d96..ff6fe61 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda
index c2fe4c1..fe4d6c6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon
index dd77395..14b2ad0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh
index 2aea25f..01c47cc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon
index e2934e3..7ca9972 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin
index 485459c..69f0faa 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand
index 030d47c..c43e27c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul
index 96199e7..1755147 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai
index 3c0bef2..d6b6698 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore
index 2364b21..350d77e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk
index 261a983..7fdee5c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei
index 24c4344..35d89d0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent
index 32a9d7d..65ee428 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi
index b608d79..166e434 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran
index 8cec5ad..f1555f0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv
index 440ef06..4c49bbf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu
index fe409c7..0edc72c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu
index fe409c7..0edc72c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo
index 26f4d34..1aa066c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk
index 670e2ad..c3c307d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang
index 556ba86..5990010 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar
index 2e20cc3..6f5d3a1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator
index 2e20cc3..6f5d3a1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi
index faa14d9..69ff7f6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera
index 9e4a78f..c39331e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane
index c292ac5..ed687d2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok
index 8ab253c..72a3d4e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk
index c815e99..336f932 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon
index dd77395..14b2ad0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg
index 6958d7e..a3bf7f2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan
index 250bfe0..6dd927c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores
index 56593db..b7f75a9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda
index 419c660..abc75ea 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary
index f319215..5ab3243 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde
index e2a49d2..8f7de1c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe
index 4dab7ef..9558bf7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe
index 4dab7ef..9558bf7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen
index 15a34c3..dfc5095 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira
index 5213761..7c3a49c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik
index 10e0fc8..2451aca 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia
index 4466608..7fa5f46 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena
index 28b32ab..8906e88 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley
index 88077f1..1a4c8ea 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT b/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT
index 7636592..1975a3a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide
index 0b1252a..3bfbbc5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane
index 3021bdb..dc9a980 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill
index 1ac3fc8..947b509 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra
index 7636592..1975a3a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie
index f65a990..dc2ef55 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin
index 1cf5029..a6a6730 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla
index 98ae557..9080f5c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart
index 02b07ca..dc2ef55 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI b/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI
index 9e04a80..4d4ec8c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman
index eab0fb9..131d77b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe
index 9e04a80..4d4ec8c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne
index ba45733..d3f195a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW b/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW
index 7636592..1975a3a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/North b/absl/time/internal/cctz/testdata/zoneinfo/Australia/North
index 1cf5029..a6a6730 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/North
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/North
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth
index a876b9e..4f77182 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland
index 3021bdb..dc9a980 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/South b/absl/time/internal/cctz/testdata/zoneinfo/Australia/South
index 0b1252a..3bfbbc5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/South
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/South
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney
index 7636592..1975a3a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania
index 02b07ca..dc2ef55 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria
index ba45733..d3f195a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/West b/absl/time/internal/cctz/testdata/zoneinfo/Australia/West
index a876b9e..4f77182 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/West
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/West
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna
index 1ac3fc8..947b509 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre
index a374cb4..fb5185c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha
index f140726..9e74745 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East
index 13ff083..a16da2c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West
index 63d58f8..59c952e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/CET b/absl/time/internal/cctz/testdata/zoneinfo/CET
index 122e934..546748d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/CET
+++ b/absl/time/internal/cctz/testdata/zoneinfo/CET
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT b/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT
index ca67929..d931558 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic
index 756099a..9fa850a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central
index ac40299..7e646d1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern
index 6752c5b..fe6be8e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain
index cd78a6f..645ee94 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland
index 65a5b0c..e5f2aec 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific
index bb60cbc..c998491 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan
index 20c9c84..a3f8217 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon
index fb3cd71..878b6a9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental b/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental
index 816a042..8d60322 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland b/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland
index cae3744..d29bcd6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Cuba b/absl/time/internal/cctz/testdata/zoneinfo/Cuba
index b69ac45..e06629d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Cuba
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Cuba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/EET b/absl/time/internal/cctz/testdata/zoneinfo/EET
index cbdb71d..378919e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/EET
+++ b/absl/time/internal/cctz/testdata/zoneinfo/EET
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/EST b/absl/time/internal/cctz/testdata/zoneinfo/EST
index 21ebc00..3ae9691 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/EST
+++ b/absl/time/internal/cctz/testdata/zoneinfo/EST
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT b/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT
index 9bce500..50c95e0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Egypt b/absl/time/internal/cctz/testdata/zoneinfo/Egypt
index d3f8196..ea38c97 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Egypt
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Egypt
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Eire b/absl/time/internal/cctz/testdata/zoneinfo/Eire
index 1d99490..4a45ea8 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Eire
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Eire
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT
index c634746..157573b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0
index c634746..157573b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1
index 4dab6f9..98d5dcf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10
index c749290..ecb287e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11
index d969982..e941412 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12
index cdeec90..9c95bd0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2
index fbd2a94..6d5ce3d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3
index ee246ef..5ef7be7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4
index 5a25ff2..75f1621 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5
index c0b745f..589990a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6
index 06e777d..fcb60ca 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7
index 4e0b53a..c0427a4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8
index 714b0c5..9bdc228 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9
index 78b9daa..ca7a81f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0
index c634746..157573b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1
index a838beb..cb45601 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10
index 68ff77d..11d988e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11
index 66af5a4..f4c5d5c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12
index 17ba505..cd397b0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13
index 5f3706c..8fad7c6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14
index 7e9f9c4..a595e60 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2
index fcef6d9..97b44a9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3
index 27973bc..4eb17ff 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4
index 1efd841..13aef80 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5
index 1f76184..83a2816 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6
index 952681e..79a983e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7
index cefc912..e136690 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8
index afb093d..bc70fe4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9
index 9265fb7..d18cedd 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0
index c634746..157573b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich
index c634746..157573b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT
index 91558be..00841a6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC
index 91558be..00841a6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal
index 91558be..00841a6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu
index 91558be..00841a6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam
index c3ff07b..4a6fa1d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra
index 5962550..38685d4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan
index 73a4d01..aff8d82 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens
index 9f3a067..231bf9c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast
index ac02a81..323cd38 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade
index 27de456..a1bf928 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin
index 7f6d958..465546b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava
index ce8f433..fb7c145 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels
index 40d7124..3197327 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest
index 4303b90..efa689b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest
index 6b94a4f..940be46 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen
index ad6cf59..388df29 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau
index 5ee23fe..6970b14 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen
index 776be6e..45984a7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin
index 1d99490..4a45ea8 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar
index 117aadb..017bb2e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey
index ac02a81..323cd38 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki
index b4f8f9c..ff5e565 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man
index ac02a81..323cd38 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul
index 508446b..c891866 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey
index ac02a81..323cd38 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad
index cc99bea..0ec4756 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev
index 9337c9e..8f83cef 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov
index a3b5320..d1c93c5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon
index 355817b..6484166 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana
index 27de456..a1bf928 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/London b/absl/time/internal/cctz/testdata/zoneinfo/Europe/London
index ac02a81..323cd38 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/London
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/London
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg
index c4ca733..682bcbf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid
index 16f6420..60bdf4d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta
index bf2452d..27539c2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn
index b4f8f9c..ff5e565 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk
index 453306c..30d3a67 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco
index 686ae88..f30dfc7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow
index ddb3f4e..5e6b6de 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia
index f7f10ab..c210d0a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo
index 15a34c3..dfc5095 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris
index ca85435..00a2726 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica
index 27de456..a1bf928 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague
index ce8f433..fb7c145 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga
index 8db477d..26af4c9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome
index ac4c163..639ca3b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara
index 97d5dd9..8d0c26e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino b/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino
index ac4c163..639ca3b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo
index 27de456..a1bf928 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov
index 8fd5f6d..2684d8f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol
index 432e831..88a6f3b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje
index 27de456..a1bf928 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia
index 0e4d879..eabc972 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm
index f3e0c7f..dd3eb32 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn
index b5acca3..5321bbd 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane
index 0b86017..743a733 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol
index 5ee23fe..6970b14 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk
index 7b61bdc..bb842cb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod
index 66ae8d6..a575568 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz
index ad6cf59..388df29 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican
index ac4c163..639ca3b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna
index 3582bb1..75339e9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius
index 7abd63f..75b2eeb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd
index d1cfac0..c517002 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw
index e33cf67..efe1a40 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb
index 27de456..a1bf928 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye
index e42edfc..4ea8dae 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich
index ad6cf59..388df29 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Factory b/absl/time/internal/cctz/testdata/zoneinfo/Factory
index 60aa2a0..b4dd773 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Factory
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Factory
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GB b/absl/time/internal/cctz/testdata/zoneinfo/GB
index ac02a81..323cd38 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/GB
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GB
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire b/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire
index ac02a81..323cd38 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT b/absl/time/internal/cctz/testdata/zoneinfo/GMT
index c634746..157573b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/GMT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT+0 b/absl/time/internal/cctz/testdata/zoneinfo/GMT+0
index c634746..157573b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/GMT+0
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT+0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT-0 b/absl/time/internal/cctz/testdata/zoneinfo/GMT-0
index c634746..157573b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/GMT-0
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT-0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT0 b/absl/time/internal/cctz/testdata/zoneinfo/GMT0
index c634746..157573b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/GMT0
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Greenwich b/absl/time/internal/cctz/testdata/zoneinfo/Greenwich
index c634746..157573b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Greenwich
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Greenwich
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/HST b/absl/time/internal/cctz/testdata/zoneinfo/HST
index cccd45e..160a53e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/HST
+++ b/absl/time/internal/cctz/testdata/zoneinfo/HST
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Hongkong b/absl/time/internal/cctz/testdata/zoneinfo/Hongkong
index 23d0375..c80e364 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Hongkong
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Hongkong
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Iceland b/absl/time/internal/cctz/testdata/zoneinfo/Iceland
index 10e0fc8..2451aca 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Iceland
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Iceland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo
index 9a2918f..5f4ebcb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos
index 93d6dda..8b8ce22 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas
index d18c381..766024b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos
index f8116e7..1175034 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro
index 9a2918f..5f4ebcb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen
index cde4cf7..8ce93e0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe
index cba7dfe..e7fccf8 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives
index 7c839cf..58a82e4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius
index 17f2616..7c11134 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte
index 9a2918f..5f4ebcb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion
index dfe0831..248a7c9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Iran b/absl/time/internal/cctz/testdata/zoneinfo/Iran
index 8cec5ad..f1555f0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Iran
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Iran
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Israel b/absl/time/internal/cctz/testdata/zoneinfo/Israel
index 440ef06..4c49bbf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Israel
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Israel
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Jamaica b/absl/time/internal/cctz/testdata/zoneinfo/Jamaica
index 2a9b7fd..be6b1b6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Jamaica
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Jamaica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Japan b/absl/time/internal/cctz/testdata/zoneinfo/Japan
index 26f4d34..1aa066c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Japan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Japan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein b/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein
index 1a7975f..9416d52 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Libya b/absl/time/internal/cctz/testdata/zoneinfo/Libya
index 07b393b..e0c8997 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Libya
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Libya
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/MET b/absl/time/internal/cctz/testdata/zoneinfo/MET
index 4a826bb..6f0558c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/MET
+++ b/absl/time/internal/cctz/testdata/zoneinfo/MET
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/MST b/absl/time/internal/cctz/testdata/zoneinfo/MST
index c93a58e..a0953d1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/MST
+++ b/absl/time/internal/cctz/testdata/zoneinfo/MST
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT b/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT
index 4506a6e..137867c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte
index ada6bf7..19ccd35 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/Mexico/BajaSur b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur
index e4a7857..4c819fa 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General
index e7fb6f2..ffcf8be 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/NZ b/absl/time/internal/cctz/testdata/zoneinfo/NZ
index 6575fdc..afb3929 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/NZ
+++ b/absl/time/internal/cctz/testdata/zoneinfo/NZ
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT b/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT
index c004109..f06065e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Navajo b/absl/time/internal/cctz/testdata/zoneinfo/Navajo
index 5fbe26b..09e54e5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Navajo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Navajo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/PRC b/absl/time/internal/cctz/testdata/zoneinfo/PRC
index 3c0bef2..d6b6698 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/PRC
+++ b/absl/time/internal/cctz/testdata/zoneinfo/PRC
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT b/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT
index 99d246b..fde4833 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia
index dab1f3f..244af26 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland
index 6575fdc..afb3929 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville
index 2892d26..7c66709 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham
index c004109..f06065e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk
index 07c84b7..ea3fb5c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter
index cae3744..d29bcd6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate
index 6015017..bf7471d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury
index f0b8252..b22ab14 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo
index e40307f..b7b3021 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji
index d39bf53..e3934e4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti
index ea72863..78ab35b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos
index 31f0921..a9403ec 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier
index e1fc3da..ddfc34f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal
index 7e9d10a..720c679 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam
index 66490d2..bf9a2d9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu
index c7cd060..40e3d49 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston
index c7cd060..40e3d49 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati
index 7cae0cb..2f676d3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae
index a584aae..f5d5824 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein
index 1a7975f..9416d52 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro
index 9ef8374..9228ee0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas
index 74d6792..6ea24b7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway
index cb56709..001289c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru
index acec042..ae13aac 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue
index 684b010..7b35793 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk
index 53c1aad..79e2a94 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea
index 931a1a3..824f814 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago
index cb56709..001289c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau
index 146b351..bc8eb7a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn
index ef91b06..8a4ba4d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei
index c298ddd..b92b254 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape
index c298ddd..b92b254 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby
index 920ad27..5d8fc3a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga
index da6b0fa..143a188 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan
index 66490d2..bf9a2d9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa
index cb56709..001289c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti
index 442b8eb..50a064f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa
index 3db6c75..6bc2168 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu
index 5553c60..54aeb0f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk
index 07c84b7..ea3fb5c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake
index c9e3106..71cca88 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis
index b35344b..4bce893 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap
index 07c84b7..ea3fb5c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Poland b/absl/time/internal/cctz/testdata/zoneinfo/Poland
index e33cf67..efe1a40 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Poland
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Poland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Portugal b/absl/time/internal/cctz/testdata/zoneinfo/Portugal
index 355817b..6484166 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Portugal
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Portugal
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/ROC b/absl/time/internal/cctz/testdata/zoneinfo/ROC
index 24c4344..35d89d0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/ROC
+++ b/absl/time/internal/cctz/testdata/zoneinfo/ROC
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/ROK b/absl/time/internal/cctz/testdata/zoneinfo/ROK
index 96199e7..1755147 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/ROK
+++ b/absl/time/internal/cctz/testdata/zoneinfo/ROK
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Singapore b/absl/time/internal/cctz/testdata/zoneinfo/Singapore
index 2364b21..350d77e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Singapore
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Singapore
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Turkey b/absl/time/internal/cctz/testdata/zoneinfo/Turkey
index 508446b..c891866 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Turkey
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Turkey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/UCT b/absl/time/internal/cctz/testdata/zoneinfo/UCT
index 91558be..00841a6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/UCT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/UCT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska b/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska
index 9bbb2fd..cdf0572 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian b/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian
index 4323649..b1497bd 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona b/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona
index ac6bb0c..c2bd2f9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Central b/absl/time/internal/cctz/testdata/zoneinfo/US/Central
index a5b1617..b016880 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Central
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Central
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana b/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana
index 09511cc..6b08d15 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern b/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern
index 2f75480..2b6c2ee 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii b/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii
index c7cd060..40e3d49 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke b/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke
index fcd408d..b187d5f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan b/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan
index e104faa..6eb3ac4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain b/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain
index 5fbe26b..09e54e5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific b/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific
index 9dad4f4..aaf0778 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa b/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa
index cb56709..001289c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/UTC b/absl/time/internal/cctz/testdata/zoneinfo/UTC
index 91558be..00841a6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/UTC
+++ b/absl/time/internal/cctz/testdata/zoneinfo/UTC
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Universal b/absl/time/internal/cctz/testdata/zoneinfo/Universal
index 91558be..00841a6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Universal
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Universal
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/W-SU b/absl/time/internal/cctz/testdata/zoneinfo/W-SU
index ddb3f4e..5e6b6de 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/W-SU
+++ b/absl/time/internal/cctz/testdata/zoneinfo/W-SU
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/WET b/absl/time/internal/cctz/testdata/zoneinfo/WET
index c27390b..423c6c2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/WET
+++ b/absl/time/internal/cctz/testdata/zoneinfo/WET
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Zulu b/absl/time/internal/cctz/testdata/zoneinfo/Zulu
index 91558be..00841a6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Zulu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Zulu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab b/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
index 822ffa1..396e4d3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
+++ b/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
@@ -63,8 +63,7 @@
 AT	+4813+01620	Europe/Vienna
 AU	-3133+15905	Australia/Lord_Howe	Lord Howe Island
 AU	-5430+15857	Antarctica/Macquarie	Macquarie Island
-AU	-4253+14719	Australia/Hobart	Tasmania (most areas)
-AU	-3956+14352	Australia/Currie	Tasmania (King Island)
+AU	-4253+14719	Australia/Hobart	Tasmania
 AU	-3749+14458	Australia/Melbourne	Victoria
 AU	-3352+15113	Australia/Sydney	New South Wales (most areas)
 AU	-3157+14127	Australia/Broken_Hill	New South Wales (Yancowinna)
@@ -127,9 +126,9 @@
 CA	+4906-11631	America/Creston	MST - BC (Creston)
 CA	+5946-12014	America/Dawson_Creek	MST - BC (Dawson Cr, Ft St John)
 CA	+5848-12242	America/Fort_Nelson	MST - BC (Ft Nelson)
+CA	+6043-13503	America/Whitehorse	MST - Yukon (east)
+CA	+6404-13925	America/Dawson	MST - Yukon (west)
 CA	+4916-12307	America/Vancouver	Pacific - BC (most areas)
-CA	+6043-13503	America/Whitehorse	Pacific - Yukon (south)
-CA	+6404-13925	America/Dawson	Pacific - Yukon (north)
 CC	-1210+09655	Indian/Cocos
 CH,DE,LI	+4723+00832	Europe/Zurich	Swiss time
 CI,BF,GM,GN,ML,MR,SH,SL,SN,TG	+0519-00402	Africa/Abidjan
@@ -173,7 +172,7 @@
 GF	+0456-05220	America/Cayenne
 GH	+0533-00013	Africa/Accra
 GI	+3608-00521	Europe/Gibraltar
-GL	+6411-05144	America/Godthab	Greenland (most areas)
+GL	+6411-05144	America/Nuuk	Greenland (most areas)
 GL	+7646-01840	America/Danmarkshavn	National Park (east coast)
 GL	+7029-02158	America/Scoresbysund	Scoresbysund/Ittoqqortoormiit
 GL	+7634-06847	America/Thule	Thule/Pituffik
@@ -290,10 +289,10 @@
 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.
-RU,UA	+4457+03406	Europe/Simferopol	MSK+00 - Crimea
+RU,UA	+4457+03406	Europe/Simferopol	Crimea
 RU	+5836+04939	Europe/Kirov	MSK+00 - Kirov
+RU	+4844+04425	Europe/Volgograd	MSK+00 - Volgograd
 RU	+4621+04803	Europe/Astrakhan	MSK+01 - Astrakhan
-RU	+4844+04425	Europe/Volgograd	MSK+01 - Volgograd
 RU	+5134+04602	Europe/Saratov	MSK+01 - Saratov
 RU	+5420+04824	Europe/Ulyanovsk	MSK+01 - Ulyanovsk
 RU	+5312+05009	Europe/Samara	MSK+01 - Samara, Udmurtia
@@ -341,8 +340,8 @@
 TV	-0831+17913	Pacific/Funafuti
 TW	+2503+12130	Asia/Taipei
 UA	+5026+03031	Europe/Kiev	Ukraine (most areas)
-UA	+4837+02218	Europe/Uzhgorod	Ruthenia
-UA	+4750+03510	Europe/Zaporozhye	Zaporozh'ye/Zaporizhia; Lugansk/Luhansk (east)
+UA	+4837+02218	Europe/Uzhgorod	Transcarpathia
+UA	+4750+03510	Europe/Zaporozhye	Zaporozhye and east Lugansk
 UM	+1917+16637	Pacific/Wake	Wake Island
 US	+404251-0740023	America/New_York	Eastern (most areas)
 US	+421953-0830245	America/Detroit	Eastern - MI (most areas)
diff --git a/absl/time/internal/test_util.cc b/absl/time/internal/test_util.cc
index 9bffe12..9a485a0 100644
--- a/absl/time/internal/test_util.cc
+++ b/absl/time/internal/test_util.cc
@@ -18,6 +18,7 @@
 #include <cstddef>
 #include <cstring>
 
+#include "absl/base/config.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/time/internal/cctz/include/cctz/zone_info_source.h"
 
diff --git a/absl/time/time.cc b/absl/time/time.cc
index 6bb36cb..1ec2026 100644
--- a/absl/time/time.cc
+++ b/absl/time/time.cc
@@ -60,9 +60,10 @@
 inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) {
   absl::Duration rem;
   int64_t q = absl::IDivDuration(d, unit, &rem);
-  return (q > 0 ||
-          rem >= ZeroDuration() ||
-          q == std::numeric_limits<int64_t>::min()) ? q : q - 1;
+  return (q > 0 || rem >= ZeroDuration() ||
+          q == std::numeric_limits<int64_t>::min())
+             ? q
+             : q - 1;
 }
 
 inline absl::Time::Breakdown InfiniteFutureBreakdown() {
diff --git a/absl/time/time.h b/absl/time/time.h
index 33a4a63..2df6858 100644
--- a/absl/time/time.h
+++ b/absl/time/time.h
@@ -458,12 +458,12 @@
 //
 //   absl::Duration d = absl::Milliseconds(1500);
 //   int64_t isec = absl::ToInt64Seconds(d);  // isec == 1
-int64_t ToInt64Nanoseconds(Duration d);
-int64_t ToInt64Microseconds(Duration d);
-int64_t ToInt64Milliseconds(Duration d);
-int64_t ToInt64Seconds(Duration d);
-int64_t ToInt64Minutes(Duration d);
-int64_t ToInt64Hours(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Nanoseconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Microseconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Milliseconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Seconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Minutes(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Hours(Duration d);
 
 // ToDoubleNanoSeconds()
 // ToDoubleMicroseconds()
@@ -480,12 +480,12 @@
 //
 //   absl::Duration d = absl::Milliseconds(1500);
 //   double dsec = absl::ToDoubleSeconds(d);  // dsec == 1.5
-double ToDoubleNanoseconds(Duration d);
-double ToDoubleMicroseconds(Duration d);
-double ToDoubleMilliseconds(Duration d);
-double ToDoubleSeconds(Duration d);
-double ToDoubleMinutes(Duration d);
-double ToDoubleHours(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION double ToDoubleNanoseconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION double ToDoubleMicroseconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION double ToDoubleMilliseconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION double ToDoubleSeconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION double ToDoubleMinutes(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION double ToDoubleHours(Duration d);
 
 // FromChrono()
 //
@@ -545,7 +545,7 @@
 // suffix.  The valid suffixes are "ns", "us" "ms", "s", "m", and "h".
 // Simple examples include "300ms", "-1.5h", and "2h45m".  Parses "0" as
 // `ZeroDuration()`. Parses "inf" and "-inf" as +/- `InfiniteDuration()`.
-bool ParseDuration(const std::string& dur_string, Duration* d);
+bool ParseDuration(absl::string_view dur_string, Duration* d);
 
 // Support for flag values of type Duration. Duration flags must be specified
 // in a format that is valid input for absl::ParseDuration().
@@ -639,7 +639,7 @@
   // Deprecated. Use `absl::TimeZone::CivilInfo`.
   struct
       Breakdown {
-    int64_t year;          // year (e.g., 2013)
+    int64_t year;        // year (e.g., 2013)
     int month;           // month of year [1:12]
     int day;             // day of month [1:31]
     int hour;            // hour of day [0:23]
@@ -1021,13 +1021,13 @@
 // Loads the named zone. May perform I/O on the initial load of the named
 // zone. If the name is invalid, or some other kind of error occurs, returns
 // `false` and `*tz` is set to the UTC time zone.
-inline bool LoadTimeZone(const std::string& name, TimeZone* tz) {
+inline bool LoadTimeZone(absl::string_view name, TimeZone* tz) {
   if (name == "localtime") {
     *tz = TimeZone(time_internal::cctz::local_time_zone());
     return true;
   }
   time_internal::cctz::time_zone cz;
-  const bool b = time_internal::cctz::load_time_zone(name, &cz);
+  const bool b = time_internal::cctz::load_time_zone(std::string(name), &cz);
   *tz = TimeZone(cz);
   return b;
 }
@@ -1180,11 +1180,15 @@
 //
 // Converts the `tm_year`, `tm_mon`, `tm_mday`, `tm_hour`, `tm_min`, and
 // `tm_sec` fields to an `absl::Time` using the given time zone. See ctime(3)
-// for a description of the expected values of the tm fields. If the indicated
-// time instant is not unique (see `absl::TimeZone::At(absl::CivilSecond)`
-// above), the `tm_isdst` field is consulted to select the desired instant
-// (`tm_isdst` > 0 means DST, `tm_isdst` == 0 means no DST, `tm_isdst` < 0
-// means use the post-transition offset).
+// for a description of the expected values of the tm fields. If the civil time
+// is unique (see `absl::TimeZone::At(absl::CivilSecond)` above), the matching
+// time instant is returned.  Otherwise, the `tm_isdst` field is consulted to
+// choose between the possible results.  For a repeated civil time, `tm_isdst !=
+// 0` returns the matching DST instant, while `tm_isdst == 0` returns the
+// matching non-DST instant.  For a skipped civil time there is no matching
+// instant, so `tm_isdst != 0` returns the DST instant, and `tm_isdst == 0`
+// returns the non-DST instant, that would have matched if the transition never
+// happened.
 Time FromTM(const struct tm& tm, TimeZone tz);
 
 // ToTM()
@@ -1203,18 +1207,15 @@
 // time with UTC offset.  Also note the use of "%Y": RFC3339 mandates that
 // years have exactly four digits, but we allow them to take their natural
 // width.
-ABSL_DLL extern const char
-    RFC3339_full[];  // %Y-%m-%dT%H:%M:%E*S%Ez
-ABSL_DLL extern const char RFC3339_sec[];  // %Y-%m-%dT%H:%M:%S%Ez
+ABSL_DLL extern const char RFC3339_full[];  // %Y-%m-%d%ET%H:%M:%E*S%Ez
+ABSL_DLL extern const char RFC3339_sec[];   // %Y-%m-%d%ET%H:%M:%S%Ez
 
 // RFC1123_full
 // RFC1123_no_wday
 //
 // FormatTime()/ParseTime() format specifiers for RFC1123 date/time strings.
-ABSL_DLL extern const char
-    RFC1123_full[];  // %a, %d %b %E4Y %H:%M:%S %z
-ABSL_DLL extern const char
-    RFC1123_no_wday[];  // %d %b %E4Y %H:%M:%S %z
+ABSL_DLL extern const char RFC1123_full[];     // %a, %d %b %E4Y %H:%M:%S %z
+ABSL_DLL extern const char RFC1123_no_wday[];  // %d %b %E4Y %H:%M:%S %z
 
 // FormatTime()
 //
@@ -1229,6 +1230,7 @@
 //   - %E#f - Fractional seconds with # digits of precision
 //   - %E*f - Fractional seconds with full precision (a literal '*')
 //   - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
+//   - %ET  - The RFC3339 "date-time" separator "T"
 //
 // Note that %E0S behaves like %S, and %E0f produces no characters.  In
 // contrast %E*f always produces at least one digit, which may be '0'.
@@ -1252,7 +1254,7 @@
 // `absl::InfinitePast()`, the returned string will be exactly "infinite-past".
 // In both cases the given format string and `absl::TimeZone` are ignored.
 //
-std::string FormatTime(const std::string& format, Time t, TimeZone tz);
+std::string FormatTime(absl::string_view format, Time t, TimeZone tz);
 
 // Convenience functions that format the given time using the RFC3339_full
 // format.  The first overload uses the provided TimeZone, while the second
@@ -1271,7 +1273,8 @@
 // returns the corresponding `absl::Time`. Uses strftime()-like formatting
 // options, with the same extensions as FormatTime(), but with the
 // exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f.  %Ez
-// and %E*z also accept the same inputs.
+// and %E*z also accept the same inputs, which (along with %z) includes
+// 'z' and 'Z' as synonyms for +00:00.  %ET accepts either 'T' or 't'.
 //
 // %Y consumes as many numeric characters as it can, so the matching data
 // should always be terminated with a non-numeric.  %E4Y always consumes
@@ -1313,7 +1316,7 @@
 // If the input string is "infinite-past", the returned `absl::Time` will be
 // `absl::InfinitePast()` and `true` will be returned.
 //
-bool ParseTime(const std::string& format, const std::string& input, Time* time,
+bool ParseTime(absl::string_view format, absl::string_view input, Time* time,
                std::string* err);
 
 // Like ParseTime() above, but if the format string does not contain a UTC
@@ -1323,7 +1326,7 @@
 // of ambiguity or non-existence, in which case the "pre" time (as defined
 // by TimeZone::TimeInfo) is returned.  For these reasons we recommend that
 // all date/time strings include a UTC offset so they're context independent.
-bool ParseTime(const std::string& format, const std::string& input, TimeZone tz,
+bool ParseTime(absl::string_view format, absl::string_view input, TimeZone tz,
                Time* time, std::string* err);
 
 // ============================================================================
@@ -1348,8 +1351,8 @@
 // it's positive and can be converted to int64_t without risk of UB.
 inline Duration MakePosDoubleDuration(double n) {
   const int64_t int_secs = static_cast<int64_t>(n);
-  const uint32_t ticks =
-      static_cast<uint32_t>((n - int_secs) * kTicksPerSecond + 0.5);
+  const uint32_t ticks = static_cast<uint32_t>(
+      (n - static_cast<double>(int_secs)) * kTicksPerSecond + 0.5);
   return ticks < kTicksPerSecond
              ? MakeDuration(int_secs, ticks)
              : MakeDuration(int_secs + 1, ticks - kTicksPerSecond);
@@ -1495,12 +1498,10 @@
 constexpr bool operator<(Duration lhs, Duration rhs) {
   return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs)
              ? time_internal::GetRepHi(lhs) < time_internal::GetRepHi(rhs)
-             : time_internal::GetRepHi(lhs) ==
-                       (std::numeric_limits<int64_t>::min)()
-                   ? time_internal::GetRepLo(lhs) + 1 <
-                         time_internal::GetRepLo(rhs) + 1
-                   : time_internal::GetRepLo(lhs) <
-                         time_internal::GetRepLo(rhs);
+         : time_internal::GetRepHi(lhs) == (std::numeric_limits<int64_t>::min)()
+             ? time_internal::GetRepLo(lhs) + 1 <
+                   time_internal::GetRepLo(rhs) + 1
+             : time_internal::GetRepLo(lhs) < time_internal::GetRepLo(rhs);
 }
 
 constexpr bool operator==(Duration lhs, Duration rhs) {
diff --git a/absl/time/time_test.cc b/absl/time/time_test.cc
index 6f89672..cde9423 100644
--- a/absl/time/time_test.cc
+++ b/absl/time/time_test.cc
@@ -58,8 +58,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;
@@ -69,8 +68,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;
@@ -103,7 +101,7 @@
   EXPECT_EQ(a, b);
   EXPECT_EQ(a, c);
   EXPECT_EQ(b, c);
-  b = c;       // Assignment
+  b = c;  // Assignment
   EXPECT_EQ(a, b);
   EXPECT_EQ(a, c);
   EXPECT_EQ(b, c);
@@ -228,6 +226,9 @@
   constexpr absl::Time t = absl::UnixEpoch();  // Any finite time.
   static_assert(t < ifuture, "");
   static_assert(t > ipast, "");
+
+  EXPECT_EQ(ifuture, t + absl::InfiniteDuration());
+  EXPECT_EQ(ipast, t - absl::InfiniteDuration());
 }
 
 TEST(Time, FloorConversion) {
@@ -358,19 +359,21 @@
   const int64_t min_plus_1 = std::numeric_limits<int64_t>::min() + 1;
   EXPECT_EQ(min_plus_1, absl::ToUnixSeconds(absl::FromUnixSeconds(min_plus_1)));
   EXPECT_EQ(std::numeric_limits<int64_t>::min(),
-            absl::ToUnixSeconds(
-                absl::FromUnixSeconds(min_plus_1) - absl::Nanoseconds(1) / 2));
+            absl::ToUnixSeconds(absl::FromUnixSeconds(min_plus_1) -
+                                absl::Nanoseconds(1) / 2));
 
   // Tests flooring near positive infinity.
   EXPECT_EQ(std::numeric_limits<int64_t>::max(),
-            absl::ToUnixSeconds(absl::FromUnixSeconds(
-                std::numeric_limits<int64_t>::max()) + absl::Nanoseconds(1) / 2));
+            absl::ToUnixSeconds(
+                absl::FromUnixSeconds(std::numeric_limits<int64_t>::max()) +
+                absl::Nanoseconds(1) / 2));
   EXPECT_EQ(std::numeric_limits<int64_t>::max(),
             absl::ToUnixSeconds(
                 absl::FromUnixSeconds(std::numeric_limits<int64_t>::max())));
   EXPECT_EQ(std::numeric_limits<int64_t>::max() - 1,
-            absl::ToUnixSeconds(absl::FromUnixSeconds(
-                std::numeric_limits<int64_t>::max()) - absl::Nanoseconds(1) / 2));
+            absl::ToUnixSeconds(
+                absl::FromUnixSeconds(std::numeric_limits<int64_t>::max()) -
+                absl::Nanoseconds(1) / 2));
 }
 
 TEST(Time, RoundtripConversion) {
@@ -1045,15 +1048,15 @@
 
   // Checks how TimeZone::At() saturates on infinities.
   auto ci = utc.At(absl::InfiniteFuture());
-  EXPECT_CIVIL_INFO(ci, std::numeric_limits<int64_t>::max(), 12, 31, 23,
-                            59, 59, 0, false);
+  EXPECT_CIVIL_INFO(ci, std::numeric_limits<int64_t>::max(), 12, 31, 23, 59, 59,
+                    0, false);
   EXPECT_EQ(absl::InfiniteDuration(), ci.subsecond);
   EXPECT_EQ(absl::Weekday::thursday, absl::GetWeekday(ci.cs));
   EXPECT_EQ(365, absl::GetYearDay(ci.cs));
   EXPECT_STREQ("-00", ci.zone_abbr);  // artifact of TimeZone::At()
   ci = utc.At(absl::InfinitePast());
-  EXPECT_CIVIL_INFO(ci, std::numeric_limits<int64_t>::min(), 1, 1, 0, 0,
-                            0, 0, false);
+  EXPECT_CIVIL_INFO(ci, std::numeric_limits<int64_t>::min(), 1, 1, 0, 0, 0, 0,
+                    false);
   EXPECT_EQ(-absl::InfiniteDuration(), ci.subsecond);
   EXPECT_EQ(absl::Weekday::sunday, absl::GetWeekday(ci.cs));
   EXPECT_EQ(1, absl::GetYearDay(ci.cs));
@@ -1067,7 +1070,8 @@
   EXPECT_EQ("292277026596-12-04T15:30:07+00:00",
             absl::FormatTime(absl::RFC3339_full, t, utc));
   EXPECT_EQ(
-      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), t);
+      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()),
+      t);
 
   // Checks that we can also get the maximal Time value for a far-east zone.
   const absl::TimeZone plus14 = absl::FixedTimeZone(14 * 60 * 60);
@@ -1075,7 +1079,8 @@
   EXPECT_EQ("292277026596-12-05T05:30:07+14:00",
             absl::FormatTime(absl::RFC3339_full, t, plus14));
   EXPECT_EQ(
-      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), t);
+      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()),
+      t);
 
   // One second later should push us to infinity.
   t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 15, 30, 8), utc);
@@ -1089,7 +1094,8 @@
   EXPECT_EQ("-292277022657-01-27T08:29:52+00:00",
             absl::FormatTime(absl::RFC3339_full, t, utc));
   EXPECT_EQ(
-      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), t);
+      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()),
+      t);
 
   // Checks that we can also get the minimal Time value for a far-west zone.
   const absl::TimeZone minus12 = absl::FixedTimeZone(-12 * 60 * 60);
@@ -1098,7 +1104,8 @@
   EXPECT_EQ("-292277022657-01-26T20:29:52-12:00",
             absl::FormatTime(absl::RFC3339_full, t, minus12));
   EXPECT_EQ(
-      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), t);
+      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()),
+      t);
 
   // One second before should push us to -infinity.
   t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 27, 8, 29, 51), utc);
@@ -1171,14 +1178,13 @@
   const int kMin = std::numeric_limits<int>::min();
   absl::Time t;
 
-  t = absl::FromDateTime(std::numeric_limits<absl::civil_year_t>::max(),
-                         kMax, kMax, kMax, kMax, kMax, utc);
+  t = absl::FromDateTime(std::numeric_limits<absl::civil_year_t>::max(), kMax,
+                         kMax, kMax, kMax, kMax, utc);
   EXPECT_EQ("infinite-future",
             absl::FormatTime(ymdhms, t, utc));  // no overflow
-  t = absl::FromDateTime(std::numeric_limits<absl::civil_year_t>::min(),
-                         kMin, kMin, kMin, kMin, kMin, utc);
-  EXPECT_EQ("infinite-past",
-            absl::FormatTime(ymdhms, t, utc));  // no overflow
+  t = absl::FromDateTime(std::numeric_limits<absl::civil_year_t>::min(), kMin,
+                         kMin, kMin, kMin, kMin, utc);
+  EXPECT_EQ("infinite-past", absl::FormatTime(ymdhms, t, utc));  // no overflow
 
   // Check normalization.
   EXPECT_TRUE(absl::ConvertDateTime(2013, 10, 32, 8, 30, 0, utc).normalized);
diff --git a/absl/time/time_zone_test.cc b/absl/time/time_zone_test.cc
index 8f1e74a..229fcfc 100644
--- a/absl/time/time_zone_test.cc
+++ b/absl/time/time_zone_test.cc
@@ -88,7 +88,7 @@
   EXPECT_FALSE(LoadTimeZone("Invalid/TimeZone", &tz));
   EXPECT_EQ(absl::UTCTimeZone(), tz);  // guaranteed fallback to UTC
 
-  // Loading an empty std::string timezone should fail.
+  // Loading an empty string timezone should fail.
   tz = absl::time_internal::LoadTimeZone("America/Los_Angeles");
   EXPECT_FALSE(LoadTimeZone("", &tz));
   EXPECT_EQ(absl::UTCTimeZone(), tz);  // guaranteed fallback to UTC
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel
index f2ea9f3..83be936 100644
--- a/absl/types/BUILD.bazel
+++ b/absl/types/BUILD.bazel
@@ -12,7 +12,6 @@
 # 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.
-#
 
 load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
 load(
@@ -24,7 +23,7 @@
 
 package(default_visibility = ["//visibility:public"])
 
-licenses(["notice"])  # Apache 2.0
+licenses(["notice"])
 
 cc_library(
     name = "any",
@@ -35,6 +34,7 @@
         ":bad_any_cast",
         "//absl/base:config",
         "//absl/base:core_headers",
+        "//absl/base:fast_type_id",
         "//absl/meta:type_traits",
         "//absl/utility",
     ],
@@ -215,11 +215,15 @@
         "internal/conformance_aliases.h",
         "internal/conformance_archetype.h",
         "internal/conformance_profile.h",
+        "internal/conformance_testing.h",
+        "internal/conformance_testing_helpers.h",
+        "internal/parentheses.h",
+        "internal/transform_args.h",
     ],
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
-        "//absl/debugging:demangle_internal",
+        "//absl/algorithm:container",
         "//absl/meta:type_traits",
         "//absl/strings",
         "//absl/utility",
diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt
index c7c8825..c356b21 100644
--- a/absl/types/CMakeLists.txt
+++ b/absl/types/CMakeLists.txt
@@ -24,6 +24,7 @@
     absl::bad_any_cast
     absl::config
     absl::core_headers
+    absl::fast_type_id
     absl::type_traits
     absl::utility
   PUBLIC
@@ -245,15 +246,20 @@
     "internal/conformance_aliases.h"
     "internal/conformance_archetype.h"
     "internal/conformance_profile.h"
+    "internal/conformance_testing.h"
+    "internal/conformance_testing_helpers.h"
+    "internal/parentheses.h"
+    "internal/transform_args.h"
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
+    absl::algorithm
     absl::debugging
     absl::type_traits
     absl::strings
     absl::utility
     gmock_main
-  PUBLIC
+  TESTONLY
 )
 
 absl_cc_test(
@@ -281,6 +287,7 @@
     ${ABSL_TEST_COPTS}
   DEPS
     absl::conformance_testing
+    absl::type_traits
     gmock_main
 )
 
@@ -346,9 +353,6 @@
     gmock_main
 )
 
-# TODO(cohenjon,zhangxy) Figure out why this test is failing on gcc 4.8
-if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
-else()
 absl_cc_test(
   NAME
     variant_exception_safety_test
@@ -363,4 +367,3 @@
     absl::memory
     gmock_main
 )
-endif()
diff --git a/absl/types/any.h b/absl/types/any.h
index 16bda79..fc5a074 100644
--- a/absl/types/any.h
+++ b/absl/types/any.h
@@ -47,9 +47,9 @@
 // this abstraction, make sure that you should not instead be rewriting your
 // code to be more specific.
 //
-// Abseil expects to release an `absl::variant` type shortly (a C++11 compatible
-// version of the C++17 `std::variant), which is generally preferred for use
-// over `absl::any`.
+// Abseil has also released an `absl::variant` type (a C++11 compatible version
+// of the C++17 `std::variant`), which is generally preferred for use over
+// `absl::any`.
 #ifndef ABSL_TYPES_ANY_H_
 #define ABSL_TYPES_ANY_H_
 
@@ -80,6 +80,7 @@
 #include <typeinfo>
 #include <utility>
 
+#include "absl/base/internal/fast_type_id.h"
 #include "absl/base/macros.h"
 #include "absl/meta/type_traits.h"
 #include "absl/types/bad_any_cast.h"
@@ -95,26 +96,6 @@
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
-namespace any_internal {
-
-template <typename Type>
-struct TypeTag {
-  constexpr static char dummy_var = 0;
-};
-
-template <typename Type>
-constexpr char TypeTag<Type>::dummy_var;
-
-// FastTypeId<Type>() evaluates at compile/link-time to a unique pointer for the
-// passed in type. These are meant to be good match for keys into maps or
-// straight up comparisons.
-template<typename Type>
-constexpr inline const void* FastTypeId() {
-  return &TypeTag<Type>::dummy_var;
-}
-
-}  // namespace any_internal
-
 class any;
 
 // swap()
@@ -423,11 +404,11 @@
     using NormalizedType =
         typename std::remove_cv<typename std::remove_reference<T>::type>::type;
 
-    return any_internal::FastTypeId<NormalizedType>();
+    return base_internal::FastTypeId<NormalizedType>();
   }
 
   const void* GetObjTypeId() const {
-    return obj_ ? obj_->ObjTypeId() : any_internal::FastTypeId<void>();
+    return obj_ ? obj_->ObjTypeId() : base_internal::FastTypeId<void>();
   }
 
   // `absl::any` nonmember functions //
diff --git a/absl/types/compare.h b/absl/types/compare.h
index 62ca70f..19b076e 100644
--- a/absl/types/compare.h
+++ b/absl/types/compare.h
@@ -86,7 +86,8 @@
 // incomplete types so they need to be defined after the types are complete.
 #ifdef __cpp_inline_variables
 
-#define ABSL_COMPARE_INLINE_BASECLASS_DECL(name)
+// 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
@@ -99,7 +100,8 @@
 #define ABSL_COMPARE_INLINE_BASECLASS_DECL(name) \
   ABSL_CONST_INIT static const T name
 
-#define ABSL_COMPARE_INLINE_SUBCLASS_DECL(type, name)
+// A no-op expansion that can be followed by a semicolon at class level.
+#define ABSL_COMPARE_INLINE_SUBCLASS_DECL(type, name) static_assert(true, "")
 
 #define ABSL_COMPARE_INLINE_INIT(type, name, init) \
   template <typename T>                            \
diff --git a/absl/types/internal/conformance_profile.h b/absl/types/internal/conformance_profile.h
index e62004f..cf64ff4 100644
--- a/absl/types/internal/conformance_profile.h
+++ b/absl/types/internal/conformance_profile.h
@@ -36,10 +36,19 @@
 #ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_PROFILE_H_
 #define ABSL_TYPES_INTERNAL_CONFORMANCE_PROFILE_H_
 
+#include <set>
 #include <type_traits>
 #include <utility>
+#include <vector>
 
+#include "gtest/gtest.h"
+#include "absl/algorithm/container.h"
 #include "absl/meta/type_traits.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/internal/conformance_testing_helpers.h"
+#include "absl/utility/utility.h"
 
 // TODO(calabrese) Add support for extending profiles.
 
@@ -47,6 +56,187 @@
 ABSL_NAMESPACE_BEGIN
 namespace types_internal {
 
+// Converts an enum to its underlying integral value.
+template <typename Enum>
+constexpr absl::underlying_type_t<Enum> UnderlyingValue(Enum value) {
+  return static_cast<absl::underlying_type_t<Enum>>(value);
+}
+
+// A tag type used in place of a matcher when checking that an assertion result
+// does not actually contain any errors.
+struct NoError {};
+
+// -----------------------------------------------------------------------------
+// ConformanceErrors
+// -----------------------------------------------------------------------------
+class ConformanceErrors {
+ public:
+  // Setup the error reporting mechanism by seeding it with the name of the type
+  // that is being tested.
+  explicit ConformanceErrors(std::string type_name)
+      : assertion_result_(false), type_name_(std::move(type_name)) {
+    assertion_result_ << "\n\n"
+                         "Assuming the following type alias:\n"
+                         "\n"
+                         "  using _T = "
+                      << type_name_ << ";\n\n";
+    outputDivider();
+  }
+
+  // Adds the test name to the list of successfully run tests iff it was not
+  // previously reported as failing. This behavior is useful for tests that
+  // have multiple parts, where failures and successes are reported individually
+  // with the same test name.
+  void addTestSuccess(absl::string_view test_name) {
+    auto normalized_test_name = absl::AsciiStrToLower(test_name);
+
+    // If the test is already reported as failing, do not add it to the list of
+    // successes.
+    if (test_failures_.find(normalized_test_name) == test_failures_.end()) {
+      test_successes_.insert(std::move(normalized_test_name));
+    }
+  }
+
+  // Streams a single error description into the internal buffer (a visual
+  // divider is automatically inserted after the error so that multiple errors
+  // are visibly distinct).
+  //
+  // This function increases the error count by 1.
+  //
+  // TODO(calabrese) Determine desired behavior when if this function throws.
+  template <class... P>
+  void addTestFailure(absl::string_view test_name, const P&... args) {
+    // Output a message related to the test failure.
+    assertion_result_ << "\n\n"
+                         "Failed test: "
+                      << test_name << "\n\n";
+    addTestFailureImpl(args...);
+    assertion_result_ << "\n\n";
+    outputDivider();
+
+    auto normalized_test_name = absl::AsciiStrToLower(test_name);
+
+    // If previous parts of this test succeeded, remove it from that set.
+    test_successes_.erase(normalized_test_name);
+
+    // Add the test name to the list of failed tests.
+    test_failures_.insert(std::move(normalized_test_name));
+
+    has_error_ = true;
+  }
+
+  // Convert this object into a testing::AssertionResult instance such that it
+  // can be used with gtest.
+  ::testing::AssertionResult assertionResult() const {
+    return has_error_ ? assertion_result_ : ::testing::AssertionSuccess();
+  }
+
+  // Convert this object into a testing::AssertionResult instance such that it
+  // can be used with gtest. This overload expects errors, using the specified
+  // matcher.
+  ::testing::AssertionResult expectFailedTests(
+      const std::set<std::string>& test_names) const {
+    // Since we are expecting nonconformance, output an error message when the
+    // type actually conformed to the specified profile.
+    if (!has_error_) {
+      return ::testing::AssertionFailure()
+             << "Unexpected conformance of type:\n"
+                "    "
+             << type_name_ << "\n\n";
+    }
+
+    // Get a list of all expected failures that did not actually fail
+    // (or that were not run).
+    std::vector<std::string> nonfailing_tests;
+    absl::c_set_difference(test_names, test_failures_,
+                           std::back_inserter(nonfailing_tests));
+
+    // Get a list of all "expected failures" that were never actually run.
+    std::vector<std::string> unrun_tests;
+    absl::c_set_difference(nonfailing_tests, test_successes_,
+                           std::back_inserter(unrun_tests));
+
+    // Report when the user specified tests that were not run.
+    if (!unrun_tests.empty()) {
+      const bool tests_were_run =
+          !(test_failures_.empty() && test_successes_.empty());
+
+      // Prepare an assertion result used in the case that tests pass that were
+      // expected to fail.
+      ::testing::AssertionResult result = ::testing::AssertionFailure();
+      result << "When testing type:\n    " << type_name_
+             << "\n\nThe following tests were expected to fail but were not "
+                "run";
+
+      if (tests_were_run) result << " (was the test name spelled correctly?)";
+
+      result << ":\n\n";
+
+      // List all of the tests that unexpectedly passed.
+      for (const auto& test_name : unrun_tests) {
+        result << "    " << test_name << "\n";
+      }
+
+      if (!tests_were_run) result << "\nNo tests were run.";
+
+      if (!test_failures_.empty()) {
+        // List test failures
+        result << "\nThe tests that were run and failed are:\n\n";
+        for (const auto& test_name : test_failures_) {
+          result << "    " << test_name << "\n";
+        }
+      }
+
+      if (!test_successes_.empty()) {
+        // List test successes
+        result << "\nThe tests that were run and succeeded are:\n\n";
+        for (const auto& test_name : test_successes_) {
+          result << "    " << test_name << "\n";
+        }
+      }
+
+      return result;
+    }
+
+    // If some tests passed when they were expected to fail, alert the caller.
+    if (nonfailing_tests.empty()) return ::testing::AssertionSuccess();
+
+    // Prepare an assertion result used in the case that tests pass that were
+    // expected to fail.
+    ::testing::AssertionResult unexpected_successes =
+        ::testing::AssertionFailure();
+    unexpected_successes << "When testing type:\n    " << type_name_
+                         << "\n\nThe following tests passed when they were "
+                            "expected to fail:\n\n";
+
+    // List all of the tests that unexpectedly passed.
+    for (const auto& test_name : nonfailing_tests) {
+      unexpected_successes << "    " << test_name << "\n";
+    }
+
+    return unexpected_successes;
+  }
+
+ private:
+  void outputDivider() {
+    assertion_result_ << "========================================";
+  }
+
+  void addTestFailureImpl() {}
+
+  template <class H, class... T>
+  void addTestFailureImpl(const H& head, const T&... tail) {
+    assertion_result_ << head;
+    addTestFailureImpl(tail...);
+  }
+
+  ::testing::AssertionResult assertion_result_;
+  std::set<std::string> test_failures_;
+  std::set<std::string> test_successes_;
+  std::string type_name_;
+  bool has_error_ = false;
+};
+
 template <class T, class /*Enabler*/ = void>
 struct PropertiesOfImpl {};
 
@@ -70,31 +260,100 @@
 // standard trait names, which is useful since it allows us to match up each
 // enum name with a corresponding trait name in macro definitions.
 
-enum class function_kind { maybe, yes, nothrow, trivial };
+// An enum that describes the various expectations on an operations existence.
+enum class function_support { maybe, yes, nothrow, trivial };
 
-#define ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(name) \
-  enum class name { maybe, yes, nothrow, trivial }
+constexpr const char* PessimisticPropertyDescription(function_support v) {
+  return v == function_support::maybe
+             ? "no"
+             : v == function_support::yes
+                   ? "yes, potentially throwing"
+                   : v == function_support::nothrow ? "yes, nothrow"
+                                                    : "yes, trivial";
+}
 
-ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(default_constructible);
-ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(move_constructible);
-ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(copy_constructible);
-ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(move_assignable);
-ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(copy_assignable);
-ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(destructible);
+// Return a string that describes the kind of property support that was
+// expected.
+inline std::string ExpectedFunctionKindList(function_support min,
+                                            function_support max) {
+  if (min == max) {
+    std::string result =
+        absl::StrCat("Expected:\n  ",
+                     PessimisticPropertyDescription(
+                         static_cast<function_support>(UnderlyingValue(min))),
+                     "\n");
+    return result;
+  }
+
+  std::string result = "Expected one of:\n";
+  for (auto curr_support = UnderlyingValue(min);
+       curr_support <= UnderlyingValue(max); ++curr_support) {
+    absl::StrAppend(&result, "  ",
+                    PessimisticPropertyDescription(
+                        static_cast<function_support>(curr_support)),
+                    "\n");
+  }
+
+  return result;
+}
+
+template <class Enum>
+void ExpectModelOfImpl(ConformanceErrors* errors, Enum min_support,
+                       Enum max_support, Enum kind) {
+  const auto kind_value = UnderlyingValue(kind);
+  const auto min_support_value = UnderlyingValue(min_support);
+  const auto max_support_value = UnderlyingValue(max_support);
+
+  if (!(kind_value >= min_support_value && kind_value <= max_support_value)) {
+    errors->addTestFailure(
+        PropertyName(kind), "**Failed property expectation**\n\n",
+        ExpectedFunctionKindList(
+            static_cast<function_support>(min_support_value),
+            static_cast<function_support>(max_support_value)),
+        '\n', "Actual:\n  ",
+        PessimisticPropertyDescription(
+            static_cast<function_support>(kind_value)));
+  } else {
+    errors->addTestSuccess(PropertyName(kind));
+  }
+}
+
+#define ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(description, name) \
+  enum class name { maybe, yes, nothrow, trivial };                   \
+                                                                      \
+  constexpr const char* PropertyName(name v) { return description; }  \
+  static_assert(true, "")  // Force a semicolon when using this macro.
+
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM("support for default construction",
+                                           default_constructible);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM("support for move construction",
+                                           move_constructible);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM("support for copy construction",
+                                           copy_constructible);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM("support for move assignment",
+                                           move_assignable);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM("support for copy assignment",
+                                           copy_assignable);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM("support for destruction",
+                                           destructible);
 
 #undef ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM
 
-#define ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(name) \
-  enum class name { maybe, yes, nothrow }
+#define ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(description, name)     \
+  enum class name { maybe, yes, nothrow };                           \
+                                                                     \
+  constexpr const char* PropertyName(name v) { return description; } \
+  static_assert(true, "")  // Force a semicolon when using this macro.
 
-ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(equality_comparable);
-ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(inequality_comparable);
-ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(less_than_comparable);
-ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(less_equal_comparable);
-ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(greater_equal_comparable);
-ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(greater_than_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for ==", equality_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for !=", inequality_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for <", less_than_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for <=", less_equal_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for >=",
+                                      greater_equal_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for >", greater_than_comparable);
 
-ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(swappable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for swap", swappable);
 
 #undef ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM
 
@@ -104,6 +363,184 @@
   return "support for std::hash";
 }
 
+template <class T>
+using AlwaysFalse = std::false_type;
+
+#define ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(name, property)   \
+  template <class T>                                                        \
+  constexpr property property##_support_of() {                              \
+    return std::is_##property<T>::value                                     \
+               ? std::is_nothrow_##property<T>::value                       \
+                     ? absl::is_trivially_##property<T>::value              \
+                           ? property::trivial                              \
+                           : property::nothrow                              \
+                     : property::yes                                        \
+               : property::maybe;                                           \
+  }                                                                         \
+                                                                            \
+  template <class T, class MinProf, class MaxProf>                          \
+  void ExpectModelOf##name(ConformanceErrors* errors) {                     \
+    (ExpectModelOfImpl)(errors, PropertiesOfT<MinProf>::property##_support, \
+                        PropertiesOfT<MaxProf>::property##_support,         \
+                        property##_support_of<T>());                        \
+  }
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(DefaultConstructible,
+                                                  default_constructible);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(MoveConstructible,
+                                                  move_constructible);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(CopyConstructible,
+                                                  copy_constructible);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(MoveAssignable,
+                                                  move_assignable);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(CopyAssignable,
+                                                  copy_assignable);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(Destructible, destructible);
+
+#undef ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER
+
+void BoolFunction(bool) noexcept;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction for checking if an operation exists through SFINAE.
+//
+// `T` is the type to test and Op is an alias containing the expression to test.
+template <class T, template <class...> class Op, class = void>
+struct IsOpableImpl : std::false_type {};
+
+template <class T, template <class...> class Op>
+struct IsOpableImpl<T, Op, absl::void_t<Op<T>>> : std::true_type {};
+
+template <template <class...> class Op>
+struct IsOpable {
+  template <class T>
+  using apply = typename IsOpableImpl<T, Op>::type;
+};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction for checking if an operation exists and is also noexcept
+// through SFINAE and the noexcept operator.
+///
+// `T` is the type to test and Op is an alias containing the expression to test.
+template <class T, template <class...> class Op, class = void>
+struct IsNothrowOpableImpl : std::false_type {};
+
+template <class T, template <class...> class Op>
+struct IsNothrowOpableImpl<T, Op, absl::enable_if_t<Op<T>::value>>
+    : std::true_type {};
+
+template <template <class...> class Op>
+struct IsNothrowOpable {
+  template <class T>
+  using apply = typename IsNothrowOpableImpl<T, Op>::type;
+};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A macro that produces the necessary function for reporting what kind of
+// support a specific comparison operation has and a function for reporting an
+// error if a given type's support for that operation does not meet the expected
+// requirements.
+#define ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(name, property, op)      \
+  template <class T,                                                           \
+            class Result = std::integral_constant<                             \
+                bool, noexcept((BoolFunction)(std::declval<const T&>() op      \
+                                                  std::declval<const T&>()))>> \
+  using name = Result;                                                         \
+                                                                               \
+  template <class T>                                                           \
+  constexpr property property##_support_of() {                                 \
+    return IsOpable<name>::apply<T>::value                                     \
+               ? IsNothrowOpable<name>::apply<T>::value ? property::nothrow    \
+                                                        : property::yes        \
+               : property::maybe;                                              \
+  }                                                                            \
+                                                                               \
+  template <class T, class MinProf, class MaxProf>                             \
+  void ExpectModelOf##name(ConformanceErrors* errors) {                        \
+    (ExpectModelOfImpl)(errors, PropertiesOfT<MinProf>::property##_support,    \
+                        PropertiesOfT<MaxProf>::property##_support,            \
+                        property##_support_of<T>());                           \
+  }
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Generate the necessary support-checking and error reporting functions for
+// each of the comparison operators.
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(EqualityComparable,
+                                              equality_comparable, ==);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(InequalityComparable,
+                                              inequality_comparable, !=);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(LessThanComparable,
+                                              less_than_comparable, <);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(LessEqualComparable,
+                                              less_equal_comparable, <=);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(GreaterEqualComparable,
+                                              greater_equal_comparable, >=);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(GreaterThanComparable,
+                                              greater_than_comparable, >);
+
+#undef ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// The necessary support-checking and error-reporting functions for swap.
+template <class T>
+constexpr swappable swappable_support_of() {
+  return type_traits_internal::IsSwappable<T>::value
+             ? type_traits_internal::IsNothrowSwappable<T>::value
+                   ? swappable::nothrow
+                   : swappable::yes
+             : swappable::maybe;
+}
+
+template <class T, class MinProf, class MaxProf>
+void ExpectModelOfSwappable(ConformanceErrors* errors) {
+  (ExpectModelOfImpl)(errors, PropertiesOfT<MinProf>::swappable_support,
+                      PropertiesOfT<MaxProf>::swappable_support,
+                      swappable_support_of<T>());
+}
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// The necessary support-checking and error-reporting functions for std::hash.
+template <class T>
+constexpr hashable hashable_support_of() {
+  return type_traits_internal::IsHashable<T>::value ? hashable::yes
+                                                    : hashable::maybe;
+}
+
+template <class T, class MinProf, class MaxProf>
+void ExpectModelOfHashable(ConformanceErrors* errors) {
+  (ExpectModelOfImpl)(errors, PropertiesOfT<MinProf>::hashable_support,
+                      PropertiesOfT<MaxProf>::hashable_support,
+                      hashable_support_of<T>());
+}
+//
+////////////////////////////////////////////////////////////////////////////////
+
 template <
     default_constructible DefaultConstructibleValue =
         default_constructible::maybe,
@@ -216,6 +653,45 @@
       HashableValue != hashable::maybe;
 };
 
+////////////////////////////////////////////////////////////////////////////////
+//
+// Compliant SFINAE-friendliness is not always present on the standard library
+// implementations that we support. This helper-struct (and associated enum) is
+// used as a means to conditionally check the hashability support of a type.
+enum class CheckHashability { no, yes };
+
+template <class T, CheckHashability ShouldCheckHashability>
+struct conservative_hashable_support_of;
+
+template <class T>
+struct conservative_hashable_support_of<T, CheckHashability::no> {
+  static constexpr hashable Invoke() { return hashable::maybe; }
+};
+
+template <class T>
+struct conservative_hashable_support_of<T, CheckHashability::yes> {
+  static constexpr hashable Invoke() { return hashable_support_of<T>(); }
+};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// The ConformanceProfile that is expected based on introspection into the type
+// by way of trait checks.
+template <class T, CheckHashability ShouldCheckHashability>
+struct SyntacticConformanceProfileOf {
+  using properties = ConformanceProfile<
+      default_constructible_support_of<T>(), move_constructible_support_of<T>(),
+      copy_constructible_support_of<T>(), move_assignable_support_of<T>(),
+      copy_assignable_support_of<T>(), destructible_support_of<T>(),
+      equality_comparable_support_of<T>(),
+      inequality_comparable_support_of<T>(),
+      less_than_comparable_support_of<T>(),
+      less_equal_comparable_support_of<T>(),
+      greater_equal_comparable_support_of<T>(),
+      greater_than_comparable_support_of<T>(), swappable_support_of<T>(),
+      conservative_hashable_support_of<T, ShouldCheckHashability>::Invoke()>;
+};
+
 #define ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL(type, name)     \
   template <default_constructible DefaultConstructibleValue,                   \
             move_constructible MoveConstructibleValue,                         \
@@ -261,12 +737,80 @@
 #undef ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF
 #undef ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL
 
-// Converts an enum to its underlying integral value.
-template <class Enum>
-constexpr absl::underlying_type_t<Enum> UnderlyingValue(Enum value) {
-  return static_cast<absl::underlying_type_t<Enum>>(value);
+// Retrieve the enum with the minimum underlying value.
+// Note: std::min is not constexpr in C++11, which is why this is necessary.
+template <class H>
+constexpr H MinEnum(H head) {
+  return head;
 }
 
+template <class H, class N, class... T>
+constexpr H MinEnum(H head, N next, T... tail) {
+  return (UnderlyingValue)(head) < (UnderlyingValue)(next)
+             ? (MinEnum)(head, tail...)
+             : (MinEnum)(next, tail...);
+}
+
+template <class... Profs>
+struct MinimalProfiles {
+  static constexpr default_constructible
+      default_constructible_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::default_constructible_support...);
+
+  static constexpr move_constructible move_constructible_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::move_constructible_support...);
+
+  static constexpr copy_constructible copy_constructible_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::copy_constructible_support...);
+
+  static constexpr move_assignable move_assignable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::move_assignable_support...);
+
+  static constexpr copy_assignable copy_assignable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::copy_assignable_support...);
+
+  static constexpr destructible destructible_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::destructible_support...);
+
+  static constexpr equality_comparable equality_comparable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::equality_comparable_support...);
+
+  static constexpr inequality_comparable
+      inequality_comparable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::inequality_comparable_support...);
+
+  static constexpr less_than_comparable
+      less_than_comparable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::less_than_comparable_support...);
+
+  static constexpr less_equal_comparable
+      less_equal_comparable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::less_equal_comparable_support...);
+
+  static constexpr greater_equal_comparable
+      greater_equal_comparable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::greater_equal_comparable_support...);
+
+  static constexpr greater_than_comparable
+      greater_than_comparable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::greater_than_comparable_support...);
+
+  static constexpr swappable swappable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::swappable_support...);
+
+  static constexpr hashable hashable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::hashable_support...);
+
+  using properties = ConformanceProfile<
+      default_constructible_support, move_constructible_support,
+      copy_constructible_support, move_assignable_support,
+      copy_assignable_support, destructible_support,
+      equality_comparable_support, inequality_comparable_support,
+      less_than_comparable_support, less_equal_comparable_support,
+      greater_equal_comparable_support, greater_than_comparable_support,
+      swappable_support, hashable_support>;
+};
+
 // Retrieve the enum with the greatest underlying value.
 // Note: std::max is not constexpr in C++11, which is why this is necessary.
 template <class H>
@@ -369,6 +913,17 @@
 template <class T>
 struct IsProfile : IsProfileImpl<T>::type {};
 
+// A tag that describes which set of properties we will check when the user
+// requires a strict match in conformance (as opposed to a loose match which
+// allows more-refined support of any given operation).
+//
+// Currently only the RegularityDomain exists and it includes all operations
+// that the conformance testing suite knows about. The intent is that if the
+// suite is expanded to support extension, such as for checking conformance of
+// concepts like Iterators or Containers, additional corresponding domains can
+// be created.
+struct RegularityDomain {};
+
 }  // namespace types_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/types/internal/conformance_testing.h b/absl/types/internal/conformance_testing.h
new file mode 100644
index 0000000..487b0f7
--- /dev/null
+++ b/absl/types/internal/conformance_testing.h
@@ -0,0 +1,1386 @@
+// Copyright 2019 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.
+//
+// -----------------------------------------------------------------------------
+// conformance_testing.h
+// -----------------------------------------------------------------------------
+//
+
+#ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_H_
+#define ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_H_
+
+////////////////////////////////////////////////////////////////////////////////
+//                                                                            //
+// Many templates in this file take a `T` and a `Prof` type as explicit       //
+// template arguments. These are a type to be checked and a                   //
+// "Regularity Profile" that describes what operations that type `T` is       //
+// expected to support. See "regularity_profiles.h" for more details          //
+// regarding Regularity Profiles.                                             //
+//                                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
+#include <cstddef>
+#include <set>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/internal/conformance_aliases.h"
+#include "absl/types/internal/conformance_archetype.h"
+#include "absl/types/internal/conformance_profile.h"
+#include "absl/types/internal/conformance_testing_helpers.h"
+#include "absl/types/internal/parentheses.h"
+#include "absl/types/internal/transform_args.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace types_internal {
+
+// Returns true if the compiler incorrectly greedily instantiates constexpr
+// templates in any unevaluated context.
+constexpr bool constexpr_instantiation_when_unevaluated() {
+#if defined(__apple_build_version__)  // TODO(calabrese) Make more specific
+  return true;
+#elif defined(__clang__)
+  return __clang_major__ < 4;
+#elif defined(__GNUC__)
+  // TODO(calabrese) Figure out why gcc 7 fails (seems like a different bug)
+  return __GNUC__ < 5 || (__GNUC__ == 5 && __GNUC_MINOR__ < 2) || __GNUC__ >= 7;
+#else
+  return false;
+#endif
+}
+
+// Returns true if the standard library being used incorrectly produces an error
+// when instantiating the definition of a poisoned std::hash specialization.
+constexpr bool poisoned_hash_fails_instantiation() {
+#if defined(_MSC_VER) && !defined(_LIBCPP_VERSION)
+  return _MSC_VER < 1914;
+#else
+  return false;
+#endif
+}
+
+template <class Fun>
+struct GeneratorType {
+  decltype(std::declval<const Fun&>()()) operator()() const
+      noexcept(noexcept(std::declval<const Fun&>()())) {
+    return fun();
+  }
+
+  Fun fun;
+  const char* description;
+};
+
+// A "make" function for the GeneratorType template that deduces the function
+// object type.
+template <class Fun,
+          absl::enable_if_t<IsNullaryCallable<Fun>::value>** = nullptr>
+GeneratorType<Fun> Generator(Fun fun, const char* description) {
+  return GeneratorType<Fun>{absl::move(fun), description};
+}
+
+// A type that contains a set of nullary function objects that each return an
+// instance of the same type and value (though possibly different
+// representations, such as +0 and -0 or two vectors with the same elements but
+// with different capacities).
+template <class... Funs>
+struct EquivalenceClassType {
+  std::tuple<GeneratorType<Funs>...> generators;
+};
+
+// A "make" function for the EquivalenceClassType template that deduces the
+// function object types and is constrained such that a user can only pass in
+// function objects that all have the same return type.
+template <class... Funs, absl::enable_if_t<AreGeneratorsWithTheSameReturnType<
+                             Funs...>::value>** = nullptr>
+EquivalenceClassType<Funs...> EquivalenceClass(GeneratorType<Funs>... funs) {
+  return {std::make_tuple(absl::move(funs)...)};
+}
+
+// A type that contains an ordered series of EquivalenceClassTypes, from
+// smallest value to largest value.
+template <class... EqClasses>
+struct OrderedEquivalenceClasses {
+  std::tuple<EqClasses...> eq_classes;
+};
+
+// An object containing the parts of a given (name, initialization expression),
+// and is capable of generating a string that describes the given.
+struct GivenDeclaration {
+  std::string outputDeclaration(std::size_t width) const {
+    const std::size_t indent_size = 2;
+    std::string result = absl::StrCat("  ", name);
+
+    if (!expression.empty()) {
+      // Indent
+      result.resize(indent_size + width, ' ');
+      absl::StrAppend(&result, " = ", expression, ";\n");
+    } else {
+      absl::StrAppend(&result, ";\n");
+    }
+
+    return result;
+  }
+
+  std::string name;
+  std::string expression;
+};
+
+// Produce a string that contains all of the givens of an error report.
+template <class... Decls>
+std::string PrepareGivenContext(const Decls&... decls) {
+  const std::size_t width = (std::max)({decls.name.size()...});
+  return absl::StrCat("Given:\n", decls.outputDeclaration(width)..., "\n");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Function objects that perform a check for each comparison operator         //
+////////////////////////////////////////////////////////////////////////////////
+
+#define ABSL_INTERNAL_EXPECT_OP(name, op)                                   \
+  struct Expect##name {                                                     \
+    template <class T>                                                      \
+    void operator()(absl::string_view test_name, absl::string_view context, \
+                    const T& lhs, const T& rhs, absl::string_view lhs_name, \
+                    absl::string_view rhs_name) const {                     \
+      if (!static_cast<bool>(lhs op rhs)) {                                 \
+        errors->addTestFailure(                                             \
+            test_name, absl::StrCat(context,                                \
+                                    "**Unexpected comparison result**\n"    \
+                                    "\n"                                    \
+                                    "Expression:\n"                         \
+                                    "  ",                                   \
+                                    lhs_name, " " #op " ", rhs_name,        \
+                                    "\n"                                    \
+                                    "\n"                                    \
+                                    "Expected: true\n"                      \
+                                    "  Actual: false"));                    \
+      } else {                                                              \
+        errors->addTestSuccess(test_name);                                  \
+      }                                                                     \
+    }                                                                       \
+                                                                            \
+    ConformanceErrors* errors;                                              \
+  };                                                                        \
+                                                                            \
+  struct ExpectNot##name {                                                  \
+    template <class T>                                                      \
+    void operator()(absl::string_view test_name, absl::string_view context, \
+                    const T& lhs, const T& rhs, absl::string_view lhs_name, \
+                    absl::string_view rhs_name) const {                     \
+      if (lhs op rhs) {                                                     \
+        errors->addTestFailure(                                             \
+            test_name, absl::StrCat(context,                                \
+                                    "**Unexpected comparison result**\n"    \
+                                    "\n"                                    \
+                                    "Expression:\n"                         \
+                                    "  ",                                   \
+                                    lhs_name, " " #op " ", rhs_name,        \
+                                    "\n"                                    \
+                                    "\n"                                    \
+                                    "Expected: false\n"                     \
+                                    "  Actual: true"));                     \
+      } else {                                                              \
+        errors->addTestSuccess(test_name);                                  \
+      }                                                                     \
+    }                                                                       \
+                                                                            \
+    ConformanceErrors* errors;                                              \
+  }
+
+ABSL_INTERNAL_EXPECT_OP(Eq, ==);
+ABSL_INTERNAL_EXPECT_OP(Ne, !=);
+ABSL_INTERNAL_EXPECT_OP(Lt, <);
+ABSL_INTERNAL_EXPECT_OP(Le, <=);
+ABSL_INTERNAL_EXPECT_OP(Ge, >=);
+ABSL_INTERNAL_EXPECT_OP(Gt, >);
+
+#undef ABSL_INTERNAL_EXPECT_OP
+
+// A function object that verifies that two objects hash to the same value by
+// way of the std::hash specialization.
+struct ExpectSameHash {
+  template <class T>
+  void operator()(absl::string_view test_name, absl::string_view context,
+                  const T& lhs, const T& rhs, absl::string_view lhs_name,
+                  absl::string_view rhs_name) const {
+    if (std::hash<T>()(lhs) != std::hash<T>()(rhs)) {
+      errors->addTestFailure(
+          test_name, absl::StrCat(context,
+                                  "**Unexpected hash result**\n"
+                                  "\n"
+                                  "Expression:\n"
+                                  "  std::hash<T>()(",
+                                  lhs_name, ") == std::hash<T>()(", rhs_name,
+                                  ")\n"
+                                  "\n"
+                                  "Expected: true\n"
+                                  "  Actual: false"));
+    } else {
+      errors->addTestSuccess(test_name);
+    }
+  }
+
+  ConformanceErrors* errors;
+};
+
+// A function template that takes two objects and verifies that each comparison
+// operator behaves in a way that is consistent with equality. It has "OneWay"
+// in the name because the first argument will always be the left-hand operand
+// of the corresponding comparison operator and the second argument will
+// always be the right-hand operand. It will never switch that order.
+// At a higher level in the test suite, the one-way form is called once for each
+// of the two possible orders whenever lhs and rhs are not the same initializer.
+template <class T, class Prof>
+void ExpectOneWayEquality(ConformanceErrors* errors,
+                          absl::string_view test_name,
+                          absl::string_view context, const T& lhs, const T& rhs,
+                          absl::string_view lhs_name,
+                          absl::string_view rhs_name) {
+  If<PropertiesOfT<Prof>::is_equality_comparable>::Invoke(
+      ExpectEq{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
+
+  If<PropertiesOfT<Prof>::is_inequality_comparable>::Invoke(
+      ExpectNotNe{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
+
+  If<PropertiesOfT<Prof>::is_less_than_comparable>::Invoke(
+      ExpectNotLt{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
+
+  If<PropertiesOfT<Prof>::is_less_equal_comparable>::Invoke(
+      ExpectLe{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
+
+  If<PropertiesOfT<Prof>::is_greater_equal_comparable>::Invoke(
+      ExpectGe{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
+
+  If<PropertiesOfT<Prof>::is_greater_than_comparable>::Invoke(
+      ExpectNotGt{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
+
+  If<PropertiesOfT<Prof>::is_hashable>::Invoke(
+      ExpectSameHash{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
+}
+
+// A function template that takes two objects and verifies that each comparison
+// operator behaves in a way that is consistent with equality. This function
+// differs from ExpectOneWayEquality in that this will do checks with argument
+// order reversed in addition to in-order.
+template <class T, class Prof>
+void ExpectEquality(ConformanceErrors* errors, absl::string_view test_name,
+                    absl::string_view context, const T& lhs, const T& rhs,
+                    absl::string_view lhs_name, absl::string_view rhs_name) {
+  (ExpectOneWayEquality<T, Prof>)(errors, test_name, context, lhs, rhs,
+                                  lhs_name, rhs_name);
+  (ExpectOneWayEquality<T, Prof>)(errors, test_name, context, rhs, lhs,
+                                  rhs_name, lhs_name);
+}
+
+// Given a generator, makes sure that a generated value and a moved-from
+// generated value are equal.
+template <class T, class Prof>
+struct ExpectMoveConstructOneGenerator {
+  template <class Fun>
+  void operator()(const Fun& generator) const {
+    const T object = generator();
+    const T moved_object = absl::move(generator());  // Force no elision.
+
+    (ExpectEquality<T, Prof>)(errors, "Move construction",
+                              PrepareGivenContext(
+                                  GivenDeclaration{"const _T object",
+                                                   generator.description},
+                                  GivenDeclaration{"const _T moved_object",
+                                                   std::string("std::move(") +
+                                                       generator.description +
+                                                       ")"}),
+                              object, moved_object, "object", "moved_object");
+  }
+
+  ConformanceErrors* errors;
+};
+
+// Given a generator, makes sure that a generated value and a copied-from
+// generated value are equal.
+template <class T, class Prof>
+struct ExpectCopyConstructOneGenerator {
+  template <class Fun>
+  void operator()(const Fun& generator) const {
+    const T object = generator();
+    const T copied_object = static_cast<const T&>(generator());
+
+    (ExpectEquality<T, Prof>)(errors, "Copy construction",
+                              PrepareGivenContext(
+                                  GivenDeclaration{"const _T object",
+                                                   generator.description},
+                                  GivenDeclaration{
+                                      "const _T copied_object",
+                                      std::string("static_cast<const _T&>(") +
+                                          generator.description + ")"}),
+                              object, copied_object, "object", "copied_object");
+  }
+
+  ConformanceErrors* errors;
+};
+
+// Default-construct and do nothing before destruction.
+//
+// This is useful in exercising the codepath of default construction followed by
+// destruction, but does not explicitly test anything. An example of where this
+// might fail is a default destructor that default-initializes a scalar and a
+// destructor reads the value of that member. Sanitizers can catch this as long
+// as our test attempts to execute such a case.
+template <class T>
+struct ExpectDefaultConstructWithDestruct {
+  void operator()() const {
+    // Scoped so that destructor gets called before reporting success.
+    {
+      T object;
+      static_cast<void>(object);
+    }
+
+    errors->addTestSuccess("Default construction");
+  }
+
+  ConformanceErrors* errors;
+};
+
+// Check move-assign into a default-constructed object.
+template <class T, class Prof>
+struct ExpectDefaultConstructWithMoveAssign {
+  template <class Fun>
+  void operator()(const Fun& generator) const {
+    const T source_of_truth = generator();
+    T object;
+    object = generator();
+
+    (ExpectEquality<T, Prof>)(errors, "Move assignment",
+                              PrepareGivenContext(
+                                  GivenDeclaration{"const _T object",
+                                                   generator.description},
+                                  GivenDeclaration{"_T object", ""},
+                                  GivenDeclaration{"object",
+                                                   generator.description}),
+                              object, source_of_truth, "std::as_const(object)",
+                              "source_of_truth");
+  }
+
+  ConformanceErrors* errors;
+};
+
+// Check copy-assign into a default-constructed object.
+template <class T, class Prof>
+struct ExpectDefaultConstructWithCopyAssign {
+  template <class Fun>
+  void operator()(const Fun& generator) const {
+    const T source_of_truth = generator();
+    T object;
+    object = static_cast<const T&>(generator());
+
+    (ExpectEquality<T, Prof>)(errors, "Copy assignment",
+                              PrepareGivenContext(
+                                  GivenDeclaration{"const _T source_of_truth",
+                                                   generator.description},
+                                  GivenDeclaration{"_T object", ""},
+                                  GivenDeclaration{
+                                      "object",
+                                      std::string("static_cast<const _T&>(") +
+                                          generator.description + ")"}),
+                              object, source_of_truth, "std::as_const(object)",
+                              "source_of_truth");
+  }
+
+  ConformanceErrors* errors;
+};
+
+// Perform a self move-assign.
+template <class T, class Prof>
+struct ExpectSelfMoveAssign {
+  template <class Fun>
+  void operator()(const Fun& generator) const {
+    T object = generator();
+    object = absl::move(object);
+
+    // NOTE: Self move-assign results in a valid-but-unspecified state.
+
+    (ExpectEquality<T, Prof>)(errors, "Move assignment",
+                              PrepareGivenContext(
+                                  GivenDeclaration{"_T object",
+                                                   generator.description},
+                                  GivenDeclaration{"object",
+                                                   "std::move(object)"}),
+                              object, object, "object", "object");
+  }
+
+  ConformanceErrors* errors;
+};
+
+// Perform a self copy-assign.
+template <class T, class Prof>
+struct ExpectSelfCopyAssign {
+  template <class Fun>
+  void operator()(const Fun& generator) const {
+    const T source_of_truth = generator();
+    T object = generator();
+    const T& const_object = object;
+    object = const_object;
+
+    (ExpectEquality<T, Prof>)(errors, "Copy assignment",
+                              PrepareGivenContext(
+                                  GivenDeclaration{"const _T source_of_truth",
+                                                   generator.description},
+                                  GivenDeclaration{"_T object",
+                                                   generator.description},
+                                  GivenDeclaration{"object",
+                                                   "std::as_const(object)"}),
+                              const_object, source_of_truth,
+                              "std::as_const(object)", "source_of_truth");
+  }
+
+  ConformanceErrors* errors;
+};
+
+// Perform a self-swap.
+template <class T, class Prof>
+struct ExpectSelfSwap {
+  template <class Fun>
+  void operator()(const Fun& generator) const {
+    const T source_of_truth = generator();
+    T object = generator();
+
+    type_traits_internal::Swap(object, object);
+
+    std::string preliminary_info = absl::StrCat(
+        PrepareGivenContext(
+            GivenDeclaration{"const _T source_of_truth", generator.description},
+            GivenDeclaration{"_T object", generator.description}),
+        "After performing a self-swap:\n"
+        "  using std::swap;\n"
+        "  swap(object, object);\n"
+        "\n");
+
+    (ExpectEquality<T, Prof>)(errors, "Swap", std::move(preliminary_info),
+                              object, source_of_truth, "std::as_const(object)",
+                              "source_of_truth");
+  }
+
+  ConformanceErrors* errors;
+};
+
+// Perform each of the single-generator checks when necessary operations are
+// supported.
+template <class T, class Prof>
+struct ExpectSelfComparison {
+  template <class Fun>
+  void operator()(const Fun& generator) const {
+    const T object = generator();
+    (ExpectOneWayEquality<T, Prof>)(errors, "Comparison",
+                                    PrepareGivenContext(GivenDeclaration{
+                                        "const _T object",
+                                        generator.description}),
+                                    object, object, "object", "object");
+  }
+
+  ConformanceErrors* errors;
+};
+
+// Perform each of the single-generator checks when necessary operations are
+// supported.
+template <class T, class Prof>
+struct ExpectConsistency {
+  template <class Fun>
+  void operator()(const Fun& generator) const {
+    If<PropertiesOfT<Prof>::is_move_constructible>::Invoke(
+        ExpectMoveConstructOneGenerator<T, Prof>{errors}, generator);
+
+    If<PropertiesOfT<Prof>::is_copy_constructible>::Invoke(
+        ExpectCopyConstructOneGenerator<T, Prof>{errors}, generator);
+
+    If<PropertiesOfT<Prof>::is_default_constructible &&
+       PropertiesOfT<Prof>::is_move_assignable>::
+        Invoke(ExpectDefaultConstructWithMoveAssign<T, Prof>{errors},
+               generator);
+
+    If<PropertiesOfT<Prof>::is_default_constructible &&
+       PropertiesOfT<Prof>::is_copy_assignable>::
+        Invoke(ExpectDefaultConstructWithCopyAssign<T, Prof>{errors},
+               generator);
+
+    If<PropertiesOfT<Prof>::is_move_assignable>::Invoke(
+        ExpectSelfMoveAssign<T, Prof>{errors}, generator);
+
+    If<PropertiesOfT<Prof>::is_copy_assignable>::Invoke(
+        ExpectSelfCopyAssign<T, Prof>{errors}, generator);
+
+    If<PropertiesOfT<Prof>::is_swappable>::Invoke(
+        ExpectSelfSwap<T, Prof>{errors}, generator);
+  }
+
+  ConformanceErrors* errors;
+};
+
+// Check move-assign with two different values.
+template <class T, class Prof>
+struct ExpectMoveAssign {
+  template <class Fun0, class Fun1>
+  void operator()(const Fun0& generator0, const Fun1& generator1) const {
+    const T source_of_truth1 = generator1();
+    T object = generator0();
+    object = generator1();
+
+    (ExpectEquality<T, Prof>)(errors, "Move assignment",
+                              PrepareGivenContext(
+                                  GivenDeclaration{"const _T source_of_truth1",
+                                                   generator1.description},
+                                  GivenDeclaration{"_T object",
+                                                   generator0.description},
+                                  GivenDeclaration{"object",
+                                                   generator1.description}),
+                              object, source_of_truth1, "std::as_const(object)",
+                              "source_of_truth1");
+  }
+
+  ConformanceErrors* errors;
+};
+
+// Check copy-assign with two different values.
+template <class T, class Prof>
+struct ExpectCopyAssign {
+  template <class Fun0, class Fun1>
+  void operator()(const Fun0& generator0, const Fun1& generator1) const {
+    const T source_of_truth1 = generator1();
+    T object = generator0();
+    object = static_cast<const T&>(generator1());
+
+    (ExpectEquality<T, Prof>)(errors, "Copy assignment",
+                              PrepareGivenContext(
+                                  GivenDeclaration{"const _T source_of_truth1",
+                                                   generator1.description},
+                                  GivenDeclaration{"_T object",
+                                                   generator0.description},
+                                  GivenDeclaration{
+                                      "object",
+                                      std::string("static_cast<const _T&>(") +
+                                          generator1.description + ")"}),
+                              object, source_of_truth1, "std::as_const(object)",
+                              "source_of_truth1");
+  }
+
+  ConformanceErrors* errors;
+};
+
+// Check swap with two different values.
+template <class T, class Prof>
+struct ExpectSwap {
+  template <class Fun0, class Fun1>
+  void operator()(const Fun0& generator0, const Fun1& generator1) const {
+    const T source_of_truth0 = generator0();
+    const T source_of_truth1 = generator1();
+    T object0 = generator0();
+    T object1 = generator1();
+
+    type_traits_internal::Swap(object0, object1);
+
+    const std::string context =
+        PrepareGivenContext(
+            GivenDeclaration{"const _T source_of_truth0",
+                             generator0.description},
+            GivenDeclaration{"const _T source_of_truth1",
+                             generator1.description},
+            GivenDeclaration{"_T object0", generator0.description},
+            GivenDeclaration{"_T object1", generator1.description}) +
+        "After performing a swap:\n"
+        "  using std::swap;\n"
+        "  swap(object0, object1);\n"
+        "\n";
+
+    (ExpectEquality<T, Prof>)(errors, "Swap", context, object0,
+                              source_of_truth1, "std::as_const(object0)",
+                              "source_of_truth1");
+    (ExpectEquality<T, Prof>)(errors, "Swap", context, object1,
+                              source_of_truth0, "std::as_const(object1)",
+                              "source_of_truth0");
+  }
+
+  ConformanceErrors* errors;
+};
+
+// Validate that `generator0` and `generator1` produce values that are equal.
+template <class T, class Prof>
+struct ExpectEquivalenceClassComparison {
+  template <class Fun0, class Fun1>
+  void operator()(const Fun0& generator0, const Fun1& generator1) const {
+    const T object0 = generator0();
+    const T object1 = generator1();
+
+    (ExpectEquality<T, Prof>)(errors, "Comparison",
+                              PrepareGivenContext(
+                                  GivenDeclaration{"const _T object0",
+                                                   generator0.description},
+                                  GivenDeclaration{"const _T object1",
+                                                   generator1.description}),
+                              object0, object1, "object0", "object1");
+  }
+
+  ConformanceErrors* errors;
+};
+
+// Validate that all objects in the same equivalence-class have the same value.
+template <class T, class Prof>
+struct ExpectEquivalenceClassConsistency {
+  template <class Fun0, class Fun1>
+  void operator()(const Fun0& generator0, const Fun1& generator1) const {
+    If<PropertiesOfT<Prof>::is_move_assignable>::Invoke(
+        ExpectMoveAssign<T, Prof>{errors}, generator0, generator1);
+
+    If<PropertiesOfT<Prof>::is_copy_assignable>::Invoke(
+        ExpectCopyAssign<T, Prof>{errors}, generator0, generator1);
+
+    If<PropertiesOfT<Prof>::is_swappable>::Invoke(ExpectSwap<T, Prof>{errors},
+                                                  generator0, generator1);
+  }
+
+  ConformanceErrors* errors;
+};
+
+// Given a "lesser" object and a "greater" object, perform every combination of
+// comparison operators supported for the type, expecting consistent results.
+template <class T, class Prof>
+void ExpectOrdered(ConformanceErrors* errors, absl::string_view context,
+                   const T& small, const T& big, absl::string_view small_name,
+                   absl::string_view big_name) {
+  const absl::string_view test_name = "Comparison";
+
+  If<PropertiesOfT<Prof>::is_equality_comparable>::Invoke(
+      ExpectNotEq{errors}, test_name, context, small, big, small_name,
+      big_name);
+  If<PropertiesOfT<Prof>::is_equality_comparable>::Invoke(
+      ExpectNotEq{errors}, test_name, context, big, small, big_name,
+      small_name);
+
+  If<PropertiesOfT<Prof>::is_inequality_comparable>::Invoke(
+      ExpectNe{errors}, test_name, context, small, big, small_name, big_name);
+  If<PropertiesOfT<Prof>::is_inequality_comparable>::Invoke(
+      ExpectNe{errors}, test_name, context, big, small, big_name, small_name);
+
+  If<PropertiesOfT<Prof>::is_less_than_comparable>::Invoke(
+      ExpectLt{errors}, test_name, context, small, big, small_name, big_name);
+  If<PropertiesOfT<Prof>::is_less_than_comparable>::Invoke(
+      ExpectNotLt{errors}, test_name, context, big, small, big_name,
+      small_name);
+
+  If<PropertiesOfT<Prof>::is_less_equal_comparable>::Invoke(
+      ExpectLe{errors}, test_name, context, small, big, small_name, big_name);
+  If<PropertiesOfT<Prof>::is_less_equal_comparable>::Invoke(
+      ExpectNotLe{errors}, test_name, context, big, small, big_name,
+      small_name);
+
+  If<PropertiesOfT<Prof>::is_greater_equal_comparable>::Invoke(
+      ExpectNotGe{errors}, test_name, context, small, big, small_name,
+      big_name);
+  If<PropertiesOfT<Prof>::is_greater_equal_comparable>::Invoke(
+      ExpectGe{errors}, test_name, context, big, small, big_name, small_name);
+
+  If<PropertiesOfT<Prof>::is_greater_than_comparable>::Invoke(
+      ExpectNotGt{errors}, test_name, context, small, big, small_name,
+      big_name);
+  If<PropertiesOfT<Prof>::is_greater_than_comparable>::Invoke(
+      ExpectGt{errors}, test_name, context, big, small, big_name, small_name);
+}
+
+// For every two elements of an equivalence class, makes sure that those two
+// elements compare equal, including checks with the same argument passed as
+// both operands.
+template <class T, class Prof>
+struct ExpectEquivalenceClassComparisons {
+  template <class... Funs>
+  void operator()(EquivalenceClassType<Funs...> eq_class) const {
+    (ForEachTupleElement)(ExpectSelfComparison<T, Prof>{errors},
+                          eq_class.generators);
+
+    (ForEveryTwo)(ExpectEquivalenceClassComparison<T, Prof>{errors},
+                  eq_class.generators);
+  }
+
+  ConformanceErrors* errors;
+};
+
+// For every element of an equivalence class, makes sure that the element is
+// self-consistent (in other words, if any of move/copy/swap are defined,
+// perform those operations and make such that results and operands still
+// compare equal to known values whenever it is required for that operation.
+template <class T, class Prof>
+struct ExpectEquivalenceClass {
+  template <class... Funs>
+  void operator()(EquivalenceClassType<Funs...> eq_class) const {
+    (ForEachTupleElement)(ExpectConsistency<T, Prof>{errors},
+                          eq_class.generators);
+
+    (ForEveryTwo)(ExpectEquivalenceClassConsistency<T, Prof>{errors},
+                  eq_class.generators);
+  }
+
+  ConformanceErrors* errors;
+};
+
+// Validate that the passed-in argument is a generator of a greater value than
+// the one produced by the "small_gen" datamember with respect to all of the
+// comparison operators that Prof requires, with both argument orders to test.
+template <class T, class Prof, class SmallGenerator>
+struct ExpectBiggerGeneratorThanComparisons {
+  template <class BigGenerator>
+  void operator()(BigGenerator big_gen) const {
+    const T small = small_gen();
+    const T big = big_gen();
+
+    (ExpectOrdered<T, Prof>)(errors,
+                             PrepareGivenContext(
+                                 GivenDeclaration{"const _T small",
+                                                  small_gen.description},
+                                 GivenDeclaration{"const _T big",
+                                                  big_gen.description}),
+                             small, big, "small", "big");
+  }
+
+  SmallGenerator small_gen;
+  ConformanceErrors* errors;
+};
+
+// Perform all of the move, copy, and swap checks on the value generated by
+// `small_gen` and the value generated by `big_gen`.
+template <class T, class Prof, class SmallGenerator>
+struct ExpectBiggerGeneratorThan {
+  template <class BigGenerator>
+  void operator()(BigGenerator big_gen) const {
+    If<PropertiesOfT<Prof>::is_move_assignable>::Invoke(
+        ExpectMoveAssign<T, Prof>{errors}, small_gen, big_gen);
+    If<PropertiesOfT<Prof>::is_move_assignable>::Invoke(
+        ExpectMoveAssign<T, Prof>{errors}, big_gen, small_gen);
+
+    If<PropertiesOfT<Prof>::is_copy_assignable>::Invoke(
+        ExpectCopyAssign<T, Prof>{errors}, small_gen, big_gen);
+    If<PropertiesOfT<Prof>::is_copy_assignable>::Invoke(
+        ExpectCopyAssign<T, Prof>{errors}, big_gen, small_gen);
+
+    If<PropertiesOfT<Prof>::is_swappable>::Invoke(ExpectSwap<T, Prof>{errors},
+                                                  small_gen, big_gen);
+  }
+
+  SmallGenerator small_gen;
+  ConformanceErrors* errors;
+};
+
+// Validate that the result of a generator is greater than the results of all
+// generators in an equivalence class with respect to comparisons.
+template <class T, class Prof, class SmallGenerator>
+struct ExpectBiggerGeneratorThanEqClassesComparisons {
+  template <class BigEqClass>
+  void operator()(BigEqClass big_eq_class) const {
+    (ForEachTupleElement)(
+        ExpectBiggerGeneratorThanComparisons<T, Prof, SmallGenerator>{small_gen,
+                                                                      errors},
+        big_eq_class.generators);
+  }
+
+  SmallGenerator small_gen;
+  ConformanceErrors* errors;
+};
+
+// Validate that the non-comparison binary operations required by Prof are
+// correct for the result of each generator of big_eq_class and a generator of
+// the logically smaller value returned by small_gen.
+template <class T, class Prof, class SmallGenerator>
+struct ExpectBiggerGeneratorThanEqClasses {
+  template <class BigEqClass>
+  void operator()(BigEqClass big_eq_class) const {
+    (ForEachTupleElement)(
+        ExpectBiggerGeneratorThan<T, Prof, SmallGenerator>{small_gen, errors},
+        big_eq_class.generators);
+  }
+
+  SmallGenerator small_gen;
+  ConformanceErrors* errors;
+};
+
+// Validate that each equivalence class that is passed is logically less than
+// the equivalence classes that comes later on in the argument list.
+template <class T, class Prof>
+struct ExpectOrderedEquivalenceClassesComparisons {
+  template <class... BigEqClasses>
+  struct Impl {
+    // Validate that the value produced by `small_gen` is less than all of the
+    // values generated by those of the logically larger equivalence classes.
+    template <class SmallGenerator>
+    void operator()(SmallGenerator small_gen) const {
+      (ForEachTupleElement)(ExpectBiggerGeneratorThanEqClassesComparisons<
+                                T, Prof, SmallGenerator>{small_gen, errors},
+                            big_eq_classes);
+    }
+
+    std::tuple<BigEqClasses...> big_eq_classes;
+    ConformanceErrors* errors;
+  };
+
+  // When given no equivalence classes, no validation is necessary.
+  void operator()() const {}
+
+  template <class SmallEqClass, class... BigEqClasses>
+  void operator()(SmallEqClass small_eq_class,
+                  BigEqClasses... big_eq_classes) const {
+    // For each generator in the first equivalence class, make sure that it is
+    // less than each of those in the logically greater equivalence classes.
+    (ForEachTupleElement)(
+        Impl<BigEqClasses...>{std::make_tuple(absl::move(big_eq_classes)...),
+                              errors},
+        small_eq_class.generators);
+
+    // Recurse so that all equivalence class combinations are checked.
+    (*this)(absl::move(big_eq_classes)...);
+  }
+
+  ConformanceErrors* errors;
+};
+
+// Validate that the non-comparison binary operations required by Prof are
+// correct for the result of each generator of big_eq_classes and a generator of
+// the logically smaller value returned by small_gen.
+template <class T, class Prof>
+struct ExpectOrderedEquivalenceClasses {
+  template <class... BigEqClasses>
+  struct Impl {
+    template <class SmallGenerator>
+    void operator()(SmallGenerator small_gen) const {
+      (ForEachTupleElement)(
+          ExpectBiggerGeneratorThanEqClasses<T, Prof, SmallGenerator>{small_gen,
+                                                                      errors},
+          big_eq_classes);
+    }
+
+    std::tuple<BigEqClasses...> big_eq_classes;
+    ConformanceErrors* errors;
+  };
+
+  // Check that small_eq_class is logically consistent and also is logically
+  // less than all values in big_eq_classes.
+  template <class SmallEqClass, class... BigEqClasses>
+  void operator()(SmallEqClass small_eq_class,
+                  BigEqClasses... big_eq_classes) const {
+    (ForEachTupleElement)(
+        Impl<BigEqClasses...>{std::make_tuple(absl::move(big_eq_classes)...),
+                              errors},
+        small_eq_class.generators);
+
+    (*this)(absl::move(big_eq_classes)...);
+  }
+
+  // Terminating case of operator().
+  void operator()() const {}
+
+  ConformanceErrors* errors;
+};
+
+// Validate that a type meets the syntactic requirements of std::hash if the
+// range of profiles requires it.
+template <class T, class MinProf, class MaxProf>
+struct ExpectHashable {
+  void operator()() const {
+    ExpectModelOfHashable<T, MinProf, MaxProf>(errors);
+  }
+
+  ConformanceErrors* errors;
+};
+
+// Validate that the type `T` meets all of the requirements associated with
+// `MinProf` and without going beyond the syntactic properties of `MaxProf`.
+template <class T, class MinProf, class MaxProf>
+struct ExpectModels {
+  void operator()(ConformanceErrors* errors) const {
+    ExpectModelOfDefaultConstructible<T, MinProf, MaxProf>(errors);
+    ExpectModelOfMoveConstructible<T, MinProf, MaxProf>(errors);
+    ExpectModelOfCopyConstructible<T, MinProf, MaxProf>(errors);
+    ExpectModelOfMoveAssignable<T, MinProf, MaxProf>(errors);
+    ExpectModelOfCopyAssignable<T, MinProf, MaxProf>(errors);
+    ExpectModelOfDestructible<T, MinProf, MaxProf>(errors);
+    ExpectModelOfEqualityComparable<T, MinProf, MaxProf>(errors);
+    ExpectModelOfInequalityComparable<T, MinProf, MaxProf>(errors);
+    ExpectModelOfLessThanComparable<T, MinProf, MaxProf>(errors);
+    ExpectModelOfLessEqualComparable<T, MinProf, MaxProf>(errors);
+    ExpectModelOfGreaterEqualComparable<T, MinProf, MaxProf>(errors);
+    ExpectModelOfGreaterThanComparable<T, MinProf, MaxProf>(errors);
+    ExpectModelOfSwappable<T, MinProf, MaxProf>(errors);
+
+    // Only check hashability on compilers that have a compliant default-hash.
+    If<!poisoned_hash_fails_instantiation()>::Invoke(
+        ExpectHashable<T, MinProf, MaxProf>{errors});
+  }
+};
+
+// A metafunction that yields a Profile matching the set of properties that are
+// safe to be checked (lack-of-hashability is only checked on standard library
+// implementations that are standards compliant in that they provide a std::hash
+// primary template that is SFINAE-friendly)
+template <class LogicalProf, class T>
+struct MinimalCheckableProfile {
+  using type =
+      MinimalProfiles<PropertiesOfT<LogicalProf>,
+                      PropertiesOfT<SyntacticConformanceProfileOf<
+                          T, !PropertiesOfT<LogicalProf>::is_hashable &&
+                                     poisoned_hash_fails_instantiation()
+                                 ? CheckHashability::no
+                                 : CheckHashability::yes>>>;
+};
+
+// An identity metafunction
+template <class T>
+struct Always {
+  using type = T;
+};
+
+// Validate the T meets all of the necessary requirements of LogicalProf, with
+// syntactic requirements defined by the profile range [MinProf, MaxProf].
+template <class T, class LogicalProf, class MinProf, class MaxProf,
+          class... EqClasses>
+ConformanceErrors ExpectRegularityImpl(
+    OrderedEquivalenceClasses<EqClasses...> vals) {
+  ConformanceErrors errors((NameOf<T>()));
+
+  If<!constexpr_instantiation_when_unevaluated()>::Invoke(
+      ExpectModels<T, MinProf, MaxProf>(), &errors);
+
+  using minimal_profile = typename absl::conditional_t<
+      constexpr_instantiation_when_unevaluated(), Always<LogicalProf>,
+      MinimalCheckableProfile<LogicalProf, T>>::type;
+
+  If<PropertiesOfT<minimal_profile>::is_default_constructible>::Invoke(
+      ExpectDefaultConstructWithDestruct<T>{&errors});
+
+  //////////////////////////////////////////////////////////////////////////////
+  // Perform all comparison checks first, since later checks depend on their
+  // correctness.
+  //
+  // Check all of the comparisons for all values in the same equivalence
+  // class (equal with respect to comparison operators and hash the same).
+  (ForEachTupleElement)(
+      ExpectEquivalenceClassComparisons<T, minimal_profile>{&errors},
+      vals.eq_classes);
+
+  // Check all of the comparisons for each combination of values that are in
+  // different equivalence classes (not equal with respect to comparison
+  // operators).
+  absl::apply(
+      ExpectOrderedEquivalenceClassesComparisons<T, minimal_profile>{&errors},
+      vals.eq_classes);
+  //
+  //////////////////////////////////////////////////////////////////////////////
+
+  // Perform remaining checks, relying on comparisons.
+  // TODO(calabrese) short circuit if any comparisons above failed.
+  (ForEachTupleElement)(ExpectEquivalenceClass<T, minimal_profile>{&errors},
+                        vals.eq_classes);
+
+  absl::apply(ExpectOrderedEquivalenceClasses<T, minimal_profile>{&errors},
+              vals.eq_classes);
+
+  return errors;
+}
+
+// A type that represents a range of profiles that are acceptable to be matched.
+//
+// `MinProf` is the minimum set of syntactic requirements that must be met.
+//
+// `MaxProf` is the maximum set of syntactic requirements that must be met.
+// This maximum is particularly useful for certain "strictness" checking. Some
+// examples for when this is useful:
+//
+// * Making sure that a type is move-only (rather than simply movable)
+//
+// * Making sure that a member function is *not* noexcept in cases where it
+//   cannot be noexcept, such as if a dependent datamember has certain
+//   operations that are not noexcept.
+//
+// * Making sure that a type tightly matches a spec, such as the standard.
+//
+// `LogicalProf` is the Profile for which run-time testing is to take place.
+//
+// Note: The reason for `LogicalProf` is because it is often the case, when
+// dealing with templates, that a declaration of a given operation is specified,
+// but whose body would fail to instantiate. Examples include the
+// copy-constructor of a standard container when the element-type is move-only,
+// or the comparison operators of a standard container when the element-type
+// does not have the necessary comparison operations defined. The `LogicalProf`
+// parameter allows us to capture the intent of what should be tested at
+// run-time, even in the cases where syntactically it might otherwise appear as
+// though the type undergoing testing supports more than it actually does.
+template <class LogicalProf, class MinProf = LogicalProf,
+          class MaxProf = MinProf>
+struct ProfileRange {
+  using logical_profile = LogicalProf;
+  using min_profile = MinProf;
+  using max_profile = MaxProf;
+};
+
+// Similar to ProfileRange except that it creates a profile range that is
+// coupled with a Domain and is used when testing that a type matches exactly
+// the "minimum" requirements of LogicalProf.
+template <class StrictnessDomain, class LogicalProf,
+          class MinProf = LogicalProf, class MaxProf = MinProf>
+struct StrictProfileRange {
+  // We do not yet support extension.
+  static_assert(
+      std::is_same<StrictnessDomain, RegularityDomain>::value,
+      "Currently, the only valid StrictnessDomain is RegularityDomain.");
+  using strictness_domain = StrictnessDomain;
+  using logical_profile = LogicalProf;
+  using min_profile = MinProf;
+  using max_profile = MaxProf;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction that creates a StrictProfileRange from a Domain and either a
+// Profile or ProfileRange.
+template <class StrictnessDomain, class ProfOrRange>
+struct MakeStrictProfileRange;
+
+template <class StrictnessDomain, class LogicalProf>
+struct MakeStrictProfileRange {
+  using type = StrictProfileRange<StrictnessDomain, LogicalProf>;
+};
+
+template <class StrictnessDomain, class LogicalProf, class MinProf,
+          class MaxProf>
+struct MakeStrictProfileRange<StrictnessDomain,
+                              ProfileRange<LogicalProf, MinProf, MaxProf>> {
+  using type =
+      StrictProfileRange<StrictnessDomain, LogicalProf, MinProf, MaxProf>;
+};
+
+template <class StrictnessDomain, class ProfOrRange>
+using MakeStrictProfileRangeT =
+    typename MakeStrictProfileRange<StrictnessDomain, ProfOrRange>::type;
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// A profile in the RegularityDomain with the strongest possible requirements.
+using MostStrictProfile =
+    CombineProfiles<TriviallyCompleteProfile, NothrowComparableProfile>;
+
+// Forms a ProfileRange that treats the Profile as the bare minimum requirements
+// of a type.
+template <class LogicalProf, class MinProf = LogicalProf>
+using LooseProfileRange = StrictProfileRange<RegularityDomain, LogicalProf,
+                                             MinProf, MostStrictProfile>;
+
+template <class Prof>
+using MakeLooseProfileRangeT = Prof;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// The following classes implement the metafunction ProfileRangeOfT<T> that
+// takes either a Profile or ProfileRange and yields the ProfileRange to be
+// used during testing.
+//
+template <class T, class /*Enabler*/ = void>
+struct ProfileRangeOfImpl;
+
+template <class T>
+struct ProfileRangeOfImpl<T, absl::void_t<PropertiesOfT<T>>> {
+  using type = LooseProfileRange<T>;
+};
+
+template <class T>
+struct ProfileRangeOf : ProfileRangeOfImpl<T> {};
+
+template <class StrictnessDomain, class LogicalProf, class MinProf,
+          class MaxProf>
+struct ProfileRangeOf<
+    StrictProfileRange<StrictnessDomain, LogicalProf, MinProf, MaxProf>> {
+  using type =
+      StrictProfileRange<StrictnessDomain, LogicalProf, MinProf, MaxProf>;
+};
+
+template <class T>
+using ProfileRangeOfT = typename ProfileRangeOf<T>::type;
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// Extract the logical profile of a range (what will be runtime tested).
+template <class T>
+using LogicalProfileOfT = typename ProfileRangeOfT<T>::logical_profile;
+
+// Extract the minimal syntactic profile of a range (error if not at least).
+template <class T>
+using MinProfileOfT = typename ProfileRangeOfT<T>::min_profile;
+
+// Extract the maximum syntactic profile of a range (error if more than).
+template <class T>
+using MaxProfileOfT = typename ProfileRangeOfT<T>::max_profile;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+template <class T>
+struct IsProfileOrProfileRange : IsProfile<T>::type {};
+
+template <class StrictnessDomain, class LogicalProf, class MinProf,
+          class MaxProf>
+struct IsProfileOrProfileRange<
+    StrictProfileRange<StrictnessDomain, LogicalProf, MinProf, MaxProf>>
+    : std::true_type {};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// TODO(calabrese): Consider naming the functions in this class the same as
+// the macros (defined later on) so that auto-complete leads to the correct name
+// and so that a user cannot accidentally call a function rather than the macro
+// form.
+template <bool ExpectSuccess, class T, class... EqClasses>
+struct ExpectConformanceOf {
+  // Add a value to be tested. Subsequent calls to this function on the same
+  // object must specify logically "larger" values with respect to the
+  // comparison operators of the type, if any.
+  //
+  // NOTE: This function should not be called directly. A stateless lambda is
+  // implicitly formed and passed when using the INITIALIZER macro at the bottom
+  // of this file.
+  template <class Fun,
+            absl::enable_if_t<std::is_same<
+                ResultOfGeneratorT<GeneratorType<Fun>>, T>::value>** = nullptr>
+  ABSL_MUST_USE_RESULT ExpectConformanceOf<ExpectSuccess, T, EqClasses...,
+                                           EquivalenceClassType<Fun>>
+  initializer(GeneratorType<Fun> fun) && {
+    return {
+        {std::tuple_cat(absl::move(ordered_vals.eq_classes),
+                        std::make_tuple((EquivalenceClass)(absl::move(fun))))},
+        std::move(expected_failed_tests)};
+  }
+
+  template <class... TestNames,
+            absl::enable_if_t<!ExpectSuccess && sizeof...(EqClasses) == 0 &&
+                              absl::conjunction<std::is_convertible<
+                                  TestNames, absl::string_view>...>::value>** =
+                nullptr>
+  ABSL_MUST_USE_RESULT ExpectConformanceOf<ExpectSuccess, T, EqClasses...>
+  due_to(TestNames&&... test_names) && {
+    (InsertEach)(&expected_failed_tests,
+                 absl::AsciiStrToLower(absl::string_view(test_names))...);
+
+    return {absl::move(ordered_vals), std::move(expected_failed_tests)};
+  }
+
+  template <class... TestNames, int = 0,  // MSVC disambiguator
+            absl::enable_if_t<ExpectSuccess && sizeof...(EqClasses) == 0 &&
+                              absl::conjunction<std::is_convertible<
+                                  TestNames, absl::string_view>...>::value>** =
+                nullptr>
+  ABSL_MUST_USE_RESULT ExpectConformanceOf<ExpectSuccess, T, EqClasses...>
+  due_to(TestNames&&... test_names) && {
+    // TODO(calabrese) Instead have DUE_TO only exist via a CRTP base.
+    // This would produce better errors messages than the static_assert.
+    static_assert(!ExpectSuccess,
+                  "DUE_TO cannot be called when conformance is expected -- did "
+                  "you mean to use ASSERT_NONCONFORMANCE_OF?");
+  }
+
+  // Add a value to be tested. Subsequent calls to this function on the same
+  // object must specify logically "larger" values with respect to the
+  // comparison operators of the type, if any.
+  //
+  // NOTE: This function should not be called directly. A stateful lambda is
+  // implicitly formed and passed when using the INITIALIZER macro at the bottom
+  // of this file.
+  template <class Fun,
+            absl::enable_if_t<std::is_same<
+                ResultOfGeneratorT<GeneratorType<Fun>>, T>::value>** = nullptr>
+  ABSL_MUST_USE_RESULT ExpectConformanceOf<ExpectSuccess, T, EqClasses...,
+                                           EquivalenceClassType<Fun>>
+  dont_class_directly_stateful_initializer(GeneratorType<Fun> fun) && {
+    return {
+        {std::tuple_cat(absl::move(ordered_vals.eq_classes),
+                        std::make_tuple((EquivalenceClass)(absl::move(fun))))},
+        std::move(expected_failed_tests)};
+  }
+
+  // Add a set of value to be tested, where each value is equal with respect to
+  // the comparison operators and std::hash specialization, if defined.
+  template <
+      class... Funs,
+      absl::void_t<absl::enable_if_t<std::is_same<
+          ResultOfGeneratorT<GeneratorType<Funs>>, T>::value>...>** = nullptr>
+  ABSL_MUST_USE_RESULT ExpectConformanceOf<ExpectSuccess, T, EqClasses...,
+                                           EquivalenceClassType<Funs...>>
+  equivalence_class(GeneratorType<Funs>... funs) && {
+    return {{std::tuple_cat(
+                absl::move(ordered_vals.eq_classes),
+                std::make_tuple((EquivalenceClass)(absl::move(funs)...)))},
+            std::move(expected_failed_tests)};
+  }
+
+  // Execute the tests for the captured set of values, strictly matching a range
+  // of expected profiles in a given domain.
+  template <
+      class ProfRange,
+      absl::enable_if_t<IsProfileOrProfileRange<ProfRange>::value>** = nullptr>
+  ABSL_MUST_USE_RESULT ::testing::AssertionResult with_strict_profile(
+      ProfRange /*profile*/) {
+    ConformanceErrors test_result =
+        (ExpectRegularityImpl<
+            T, LogicalProfileOfT<ProfRange>, MinProfileOfT<ProfRange>,
+            MaxProfileOfT<ProfRange>>)(absl::move(ordered_vals));
+
+    return ExpectSuccess ? test_result.assertionResult()
+                         : test_result.expectFailedTests(expected_failed_tests);
+  }
+
+  // Execute the tests for the captured set of values, loosely matching a range
+  // of expected profiles (loose in that an interface is allowed to be more
+  // refined that a profile suggests, such as a type having a noexcept copy
+  // constructor when all that is required is that the copy constructor exists).
+  template <class Prof, absl::enable_if_t<IsProfile<Prof>::value>** = nullptr>
+  ABSL_MUST_USE_RESULT ::testing::AssertionResult with_loose_profile(
+      Prof /*profile*/) {
+    ConformanceErrors test_result =
+        (ExpectRegularityImpl<
+            T, Prof, Prof,
+            CombineProfiles<TriviallyCompleteProfile,
+                            NothrowComparableProfile>>)(absl::
+                                                            move(ordered_vals));
+
+    return ExpectSuccess ? test_result.assertionResult()
+                         : test_result.expectFailedTests(expected_failed_tests);
+  }
+
+  OrderedEquivalenceClasses<EqClasses...> ordered_vals;
+  std::set<std::string> expected_failed_tests;
+};
+
+template <class T>
+using ExpectConformanceOfType = ExpectConformanceOf</*ExpectSuccess=*/true, T>;
+
+template <class T>
+using ExpectNonconformanceOfType =
+    ExpectConformanceOf</*ExpectSuccess=*/false, T>;
+
+struct EquivalenceClassMaker {
+  // TODO(calabrese) Constrain to callable
+  template <class Fun>
+  static GeneratorType<Fun> initializer(GeneratorType<Fun> fun) {
+    return fun;
+  }
+};
+
+// A top-level macro that begins the builder pattern.
+//
+// The argument here takes the datatype to be tested.
+#define ABSL_INTERNAL_ASSERT_CONFORMANCE_OF(...)                            \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_                                             \
+  if ABSL_INTERNAL_LPAREN                                                   \
+  const ::testing::AssertionResult gtest_ar =                               \
+      ABSL_INTERNAL_LPAREN ::absl::types_internal::ExpectConformanceOfType< \
+          __VA_ARGS__>()
+
+// Akin to ASSERT_CONFORMANCE_OF except that it expects failure and tries to
+// match text.
+#define ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(...)                            \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_                                                \
+  if ABSL_INTERNAL_LPAREN                                                      \
+  const ::testing::AssertionResult gtest_ar =                                  \
+      ABSL_INTERNAL_LPAREN ::absl::types_internal::ExpectNonconformanceOfType< \
+          __VA_ARGS__>()
+
+////////////////////////////////////////////////////////////////////////////////
+// NOTE: The following macros look like they are recursive, but are not (macros
+// cannot recurse). These actually refer to member functions of the same name.
+// This is done intentionally so that a user cannot accidentally invoke a
+// member function of the conformance-testing suite without going through the
+// macro.
+////////////////////////////////////////////////////////////////////////////////
+
+// Specify expected test failures as comma-separated strings.
+#define DUE_TO(...) due_to(__VA_ARGS__)
+
+// Specify a value to be tested.
+//
+// Note: Internally, this takes an expression and turns it into the return value
+// of lambda that captures no data. The expression is stringized during
+// preprocessing so that it can be used in error reports.
+#define INITIALIZER(...)                         \
+  initializer(::absl::types_internal::Generator( \
+      [] { return __VA_ARGS__; }, ABSL_INTERNAL_STRINGIZE(__VA_ARGS__)))
+
+// Specify a value to be tested.
+//
+// Note: Internally, this takes an expression and turns it into the return value
+// of lambda that captures data by reference. The expression is stringized
+// during preprocessing so that it can be used in error reports.
+#define STATEFUL_INITIALIZER(...)                         \
+  stateful_initializer(::absl::types_internal::Generator( \
+      [&] { return __VA_ARGS__; }, ABSL_INTERNAL_STRINGIZE(__VA_ARGS__)))
+
+// Used in the builder-pattern.
+//
+// Takes a series of INITIALIZER and/or STATEFUL_INITIALIZER invocations and
+// forwards them along to be tested, grouping them such that the testing suite
+// knows that they are supposed to represent the same logical value (the values
+// compare the same, hash the same, etc.).
+#define EQUIVALENCE_CLASS(...)                    \
+  equivalence_class(ABSL_INTERNAL_TRANSFORM_ARGS( \
+      ABSL_INTERNAL_PREPEND_EQ_MAKER, __VA_ARGS__))
+
+// An invocation of this or WITH_STRICT_PROFILE must end the builder-pattern.
+// It takes a Profile as its argument.
+//
+// This executes the tests and allows types that are "more referined" than the
+// profile specifies, but not less. For instance, if the Profile specifies
+// noexcept copy-constructiblity, the test will fail if the copy-constructor is
+// not noexcept, however, it will succeed if the copy constructor is trivial.
+//
+// This is useful for testing that a type meets some minimum set of
+// requirements.
+#define WITH_LOOSE_PROFILE(...)                                      \
+  with_loose_profile(                                                \
+      ::absl::types_internal::MakeLooseProfileRangeT<__VA_ARGS__>()) \
+      ABSL_INTERNAL_RPAREN ABSL_INTERNAL_RPAREN;                     \
+  else GTEST_FATAL_FAILURE_(gtest_ar.failure_message())  // NOLINT
+
+// An invocation of this or WITH_STRICT_PROFILE must end the builder-pattern.
+// It takes a Domain and a Profile as its arguments.
+//
+// This executes the tests and disallows types that differ at all from the
+// properties of the Profile. For instance, if the Profile specifies noexcept
+// copy-constructiblity, the test will fail if the copy constructor is trivial.
+//
+// This is useful for testing that a type does not do anything more than a
+// specification requires, such as to minimize things like Hyrum's Law, or more
+// commonly, to prevent a type from being "accidentally" copy-constructible in
+// a way that may produce incorrect results, simply because the user forget to
+// delete that operation.
+#define WITH_STRICT_PROFILE(...)                                      \
+  with_strict_profile(                                                \
+      ::absl::types_internal::MakeStrictProfileRangeT<__VA_ARGS__>()) \
+      ABSL_INTERNAL_RPAREN ABSL_INTERNAL_RPAREN;                      \
+  else GTEST_FATAL_FAILURE_(gtest_ar.failure_message())  // NOLINT
+
+// Internal macro that is used in the internals of the EDSL when forming
+// equivalence classes.
+#define ABSL_INTERNAL_PREPEND_EQ_MAKER(arg) \
+  ::absl::types_internal::EquivalenceClassMaker().arg
+
+}  // namespace types_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_H_
diff --git a/absl/types/internal/conformance_testing_helpers.h b/absl/types/internal/conformance_testing_helpers.h
new file mode 100644
index 0000000..00775f9
--- /dev/null
+++ b/absl/types/internal/conformance_testing_helpers.h
@@ -0,0 +1,391 @@
+// Copyright 2019 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_TYPES_INTERNAL_CONFORMANCE_TESTING_HELPERS_H_
+#define ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_HELPERS_H_
+
+// Checks to determine whether or not we can use abi::__cxa_demangle
+#if (defined(__ANDROID__) || defined(ANDROID)) && !defined(OS_ANDROID)
+#define ABSL_INTERNAL_OS_ANDROID
+#endif
+
+// We support certain compilers only.  See demangle.h for details.
+#if defined(OS_ANDROID) && (defined(__i386__) || defined(__x86_64__))
+#define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 0
+#elif (__GNUC__ >= 4 || (__GNUC__ >= 3 && __GNUC_MINOR__ >= 4)) && \
+    !defined(__mips__)
+#define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 1
+#elif defined(__clang__) && !defined(_MSC_VER)
+#define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 1
+#else
+#define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 0
+#endif
+
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+#include "absl/utility/utility.h"
+
+#if ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE
+#include <cxxabi.h>
+
+#include <cstdlib>
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace types_internal {
+
+// Return a readable name for type T.
+template <class T>
+absl::string_view NameOfImpl() {
+// TODO(calabrese) Investigate using debugging:internal_demangle as a fallback.
+#if ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE
+  int status = 0;
+  char* demangled_name = nullptr;
+
+  demangled_name =
+      abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, &status);
+
+  if (status == 0 && demangled_name != nullptr) {
+    return demangled_name;
+  } else {
+    return typeid(T).name();
+  }
+#else
+  return typeid(T).name();
+#endif
+  // NOTE: We intentionally leak demangled_name so that it remains valid
+  // throughout the remainder of the program.
+}
+
+// Given a type, returns as nice of a type name as we can produce (demangled).
+//
+// Note: This currently strips cv-qualifiers and references, but that is okay
+// because we only use this internally with unqualified object types.
+template <class T>
+std::string NameOf() {
+  static const absl::string_view result = NameOfImpl<T>();
+  return std::string(result);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Metafunction to check if a type is callable with no explicit arguments
+template <class Fun, class /*Enabler*/ = void>
+struct IsNullaryCallableImpl : std::false_type {};
+
+template <class Fun>
+struct IsNullaryCallableImpl<
+    Fun, absl::void_t<decltype(std::declval<const Fun&>()())>>
+    : std::true_type {
+  using result_type = decltype(std::declval<const Fun&>()());
+
+  template <class ValueType>
+  using for_type = std::is_same<ValueType, result_type>;
+
+  using void_if_true = void;
+};
+
+template <class Fun>
+struct IsNullaryCallable : IsNullaryCallableImpl<Fun> {};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// A type that contains a function object that returns an instance of a type
+// that is undergoing conformance testing. This function is required to always
+// return the same value upon invocation.
+template <class Fun>
+struct GeneratorType;
+
+// A type that contains a tuple of GeneratorType<Fun> where each Fun has the
+// same return type. The result of each of the different generators should all
+// be equal values, though the underlying object representation may differ (such
+// as if one returns 0.0 and another return -0.0, or if one returns an empty
+// vector and another returns an empty vector with a different capacity.
+template <class... Funs>
+struct EquivalenceClassType;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction to check if a type is a specialization of EquivalenceClassType
+template <class T>
+struct IsEquivalenceClass : std::false_type {};
+
+template <>
+struct IsEquivalenceClass<EquivalenceClassType<>> : std::true_type {
+  using self = IsEquivalenceClass;
+
+  // A metafunction to check if this EquivalenceClassType is a valid
+  // EquivalenceClassType for a type `ValueType` that is undergoing testing
+  template <class ValueType>
+  using for_type = std::true_type;
+};
+
+template <class Head, class... Tail>
+struct IsEquivalenceClass<EquivalenceClassType<Head, Tail...>>
+    : std::true_type {
+  using self = IsEquivalenceClass;
+
+  // The type undergoing conformance testing that this EquivalenceClass
+  // corresponds to
+  using result_type = typename IsNullaryCallable<Head>::result_type;
+
+  // A metafunction to check if this EquivalenceClassType is a valid
+  // EquivalenceClassType for a type `ValueType` that is undergoing testing
+  template <class ValueType>
+  using for_type = std::is_same<ValueType, result_type>;
+};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// A type that contains an ordered series of EquivalenceClassTypes, where the
+// the function object of each underlying GeneratorType has the same return type
+//
+// These equivalence classes are required to be in a logical ascending order
+// that is consistent with comparison operators that are defined for the return
+// type of each GeneratorType, if any.
+template <class... EqClasses>
+struct OrderedEquivalenceClasses;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction to determine the return type of the function object contained
+// in a GeneratorType specialization.
+template <class T>
+struct ResultOfGenerator {};
+
+template <class Fun>
+struct ResultOfGenerator<GeneratorType<Fun>> {
+  using type = decltype(std::declval<const Fun&>()());
+};
+
+template <class Fun>
+using ResultOfGeneratorT = typename ResultOfGenerator<GeneratorType<Fun>>::type;
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction that yields true iff each of Funs is a GeneratorType
+// specialization and they all contain functions with the same return type
+template <class /*Enabler*/, class... Funs>
+struct AreGeneratorsWithTheSameReturnTypeImpl : std::false_type {};
+
+template <>
+struct AreGeneratorsWithTheSameReturnTypeImpl<void> : std::true_type {};
+
+template <class Head, class... Tail>
+struct AreGeneratorsWithTheSameReturnTypeImpl<
+    typename std::enable_if<absl::conjunction<std::is_same<
+        ResultOfGeneratorT<Head>, ResultOfGeneratorT<Tail>>...>::value>::type,
+    Head, Tail...> : std::true_type {};
+
+template <class... Funs>
+struct AreGeneratorsWithTheSameReturnType
+    : AreGeneratorsWithTheSameReturnTypeImpl<void, Funs...>::type {};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction that yields true iff each of Funs is an EquivalenceClassType
+// specialization and they all contain GeneratorType specializations that have
+// the same return type
+template <class... EqClasses>
+struct AreEquivalenceClassesOfTheSameType {
+  static_assert(sizeof...(EqClasses) != sizeof...(EqClasses), "");
+};
+
+template <>
+struct AreEquivalenceClassesOfTheSameType<> : std::true_type {
+  using self = AreEquivalenceClassesOfTheSameType;
+
+  // Metafunction to check that a type is the same as all of the equivalence
+  // classes, if any.
+  // Note: In this specialization there are no equivalence classes, so the
+  // value type is always compatible.
+  template <class /*ValueType*/>
+  using for_type = std::true_type;
+};
+
+template <class... Funs>
+struct AreEquivalenceClassesOfTheSameType<EquivalenceClassType<Funs...>>
+    : std::true_type {
+  using self = AreEquivalenceClassesOfTheSameType;
+
+  // Metafunction to check that a type is the same as all of the equivalence
+  // classes, if any.
+  template <class ValueType>
+  using for_type = typename IsEquivalenceClass<
+      EquivalenceClassType<Funs...>>::template for_type<ValueType>;
+};
+
+template <class... TailEqClasses>
+struct AreEquivalenceClassesOfTheSameType<
+    EquivalenceClassType<>, EquivalenceClassType<>, TailEqClasses...>
+    : AreEquivalenceClassesOfTheSameType<TailEqClasses...>::self {};
+
+template <class HeadNextFun, class... TailNextFuns, class... TailEqClasses>
+struct AreEquivalenceClassesOfTheSameType<
+    EquivalenceClassType<>, EquivalenceClassType<HeadNextFun, TailNextFuns...>,
+    TailEqClasses...>
+    : AreEquivalenceClassesOfTheSameType<
+          EquivalenceClassType<HeadNextFun, TailNextFuns...>,
+          TailEqClasses...>::self {};
+
+template <class HeadHeadFun, class... TailHeadFuns, class... TailEqClasses>
+struct AreEquivalenceClassesOfTheSameType<
+    EquivalenceClassType<HeadHeadFun, TailHeadFuns...>, EquivalenceClassType<>,
+    TailEqClasses...>
+    : AreEquivalenceClassesOfTheSameType<
+          EquivalenceClassType<HeadHeadFun, TailHeadFuns...>,
+          TailEqClasses...>::self {};
+
+template <class HeadHeadFun, class... TailHeadFuns, class HeadNextFun,
+          class... TailNextFuns, class... TailEqClasses>
+struct AreEquivalenceClassesOfTheSameType<
+    EquivalenceClassType<HeadHeadFun, TailHeadFuns...>,
+    EquivalenceClassType<HeadNextFun, TailNextFuns...>, TailEqClasses...>
+    : absl::conditional_t<
+          IsNullaryCallable<HeadNextFun>::template for_type<
+              typename IsNullaryCallable<HeadHeadFun>::result_type>::value,
+          AreEquivalenceClassesOfTheSameType<
+              EquivalenceClassType<HeadHeadFun, TailHeadFuns...>,
+              TailEqClasses...>,
+          std::false_type> {};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// Execute a function for each passed-in parameter.
+template <class Fun, class... Cases>
+void ForEachParameter(const Fun& fun, const Cases&... cases) {
+  const std::initializer_list<bool> results = {
+      (static_cast<void>(fun(cases)), true)...};
+
+  (void)results;
+}
+
+// Execute a function on each passed-in parameter (using a bound function).
+template <class Fun>
+struct ForEachParameterFun {
+  template <class... T>
+  void operator()(const T&... cases) const {
+    (ForEachParameter)(fun, cases...);
+  }
+
+  Fun fun;
+};
+
+// Execute a function on each element of a tuple.
+template <class Fun, class Tup>
+void ForEachTupleElement(const Fun& fun, const Tup& tup) {
+  absl::apply(ForEachParameterFun<Fun>{fun}, tup);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Execute a function for each combination of two elements of a tuple, including
+// combinations of an element with itself.
+template <class Fun, class... T>
+struct ForEveryTwoImpl {
+  template <class Lhs>
+  struct WithBoundLhs {
+    template <class Rhs>
+    void operator()(const Rhs& rhs) const {
+      fun(lhs, rhs);
+    }
+
+    Fun fun;
+    Lhs lhs;
+  };
+
+  template <class Lhs>
+  void operator()(const Lhs& lhs) const {
+    (ForEachTupleElement)(WithBoundLhs<Lhs>{fun, lhs}, args);
+  }
+
+  Fun fun;
+  std::tuple<T...> args;
+};
+
+template <class Fun, class... T>
+void ForEveryTwo(const Fun& fun, std::tuple<T...> args) {
+  (ForEachTupleElement)(ForEveryTwoImpl<Fun, T...>{fun, args}, args);
+}
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Insert all values into an associative container
+template<class Container>
+void InsertEach(Container* cont) {
+}
+
+template<class Container, class H, class... T>
+void InsertEach(Container* cont, H&& head, T&&... tail) {
+  cont->insert(head);
+  (InsertEach)(cont, tail...);
+}
+//
+////////////////////////////////////////////////////////////////////////////////
+// A template with a nested "Invoke" static-member-function that executes a
+// passed-in Callable when `Condition` is true, otherwise it ignores the
+// Callable. This is useful for executing a function object with a condition
+// that corresponds to whether or not the Callable can be safely instantiated.
+// It has some overlapping uses with C++17 `if constexpr`.
+template <bool Condition>
+struct If;
+
+template <>
+struct If</*Condition =*/false> {
+  template <class Fun, class... P>
+  static void Invoke(const Fun& /*fun*/, P&&... /*args*/) {}
+};
+
+template <>
+struct If</*Condition =*/true> {
+  template <class Fun, class... P>
+  static void Invoke(const Fun& fun, P&&... args) {
+    // TODO(calabrese) Use std::invoke equivalent instead of function-call.
+    fun(absl::forward<P>(args)...);
+  }
+};
+
+//
+// ABSL_INTERNAL_STRINGIZE(...)
+//
+// This variadic macro transforms its arguments into a c-string literal after
+// expansion.
+//
+// Example:
+//
+//   ABSL_INTERNAL_STRINGIZE(std::array<int, 10>)
+//
+// Results in:
+//
+//   "std::array<int, 10>"
+#define ABSL_INTERNAL_STRINGIZE(...) ABSL_INTERNAL_STRINGIZE_IMPL((__VA_ARGS__))
+#define ABSL_INTERNAL_STRINGIZE_IMPL(arg) ABSL_INTERNAL_STRINGIZE_IMPL2 arg
+#define ABSL_INTERNAL_STRINGIZE_IMPL2(...) #__VA_ARGS__
+
+}  // namespace types_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_HELPERS_H_
diff --git a/absl/types/internal/conformance_testing_test.cc b/absl/types/internal/conformance_testing_test.cc
index 3dcf530..cf262fa 100644
--- a/absl/types/internal/conformance_testing_test.cc
+++ b/absl/types/internal/conformance_testing_test.cc
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "absl/types/internal/conformance_testing.h"
+
 #include <new>
 #include <type_traits>
 #include <utility>
@@ -19,6 +21,7 @@
 #include "gtest/gtest.h"
 #include "absl/meta/type_traits.h"
 #include "absl/types/internal/conformance_aliases.h"
+#include "absl/types/internal/conformance_profile.h"
 
 namespace {
 
@@ -1181,6 +1184,373 @@
                                CommonComparableProfilesToTest);
 INSTANTIATE_TYPED_TEST_SUITE_P(Trivial, ProfileTest, TrivialProfilesToTest);
 
-// TODO(calabrese) Test runtime results
+TEST(ConformanceTestingTest, Basic) {
+  using profile = ti::CombineProfiles<ti::TriviallyCompleteProfile,
+                                      ti::NothrowComparableProfile>;
+
+  using lim = std::numeric_limits<float>;
+
+  ABSL_INTERNAL_ASSERT_CONFORMANCE_OF(float)
+      .INITIALIZER(-lim::infinity())
+      .INITIALIZER(lim::lowest())
+      .INITIALIZER(-1.f)
+      .INITIALIZER(-lim::min())
+      .EQUIVALENCE_CLASS(INITIALIZER(-0.f), INITIALIZER(0.f))
+      .INITIALIZER(lim::min())
+      .INITIALIZER(1.f)
+      .INITIALIZER(lim::max())
+      .INITIALIZER(lim::infinity())
+      .WITH_STRICT_PROFILE(absl::types_internal::RegularityDomain, profile);
+}
+
+struct BadMoveConstruct {
+  BadMoveConstruct() = default;
+  BadMoveConstruct(BadMoveConstruct&& other) noexcept
+      : value(other.value + 1) {}
+  BadMoveConstruct& operator=(BadMoveConstruct&& other) noexcept = default;
+  int value = 0;
+
+  friend bool operator==(BadMoveConstruct const& lhs,
+                         BadMoveConstruct const& rhs) {
+    return lhs.value == rhs.value;
+  }
+  friend bool operator!=(BadMoveConstruct const& lhs,
+                         BadMoveConstruct const& rhs) {
+    return lhs.value != rhs.value;
+  }
+};
+
+struct BadMoveAssign {
+  BadMoveAssign() = default;
+  BadMoveAssign(BadMoveAssign&& other) noexcept = default;
+  BadMoveAssign& operator=(BadMoveAssign&& other) noexcept {
+    int new_value = other.value + 1;
+    value = new_value;
+    return *this;
+  }
+  int value = 0;
+
+  friend bool operator==(BadMoveAssign const& lhs, BadMoveAssign const& rhs) {
+    return lhs.value == rhs.value;
+  }
+  friend bool operator!=(BadMoveAssign const& lhs, BadMoveAssign const& rhs) {
+    return lhs.value != rhs.value;
+  }
+};
+
+enum class WhichCompIsBad { eq, ne, lt, le, ge, gt };
+
+template <WhichCompIsBad Which>
+struct BadCompare {
+  int value;
+
+  friend bool operator==(BadCompare const& lhs, BadCompare const& rhs) {
+    return Which == WhichCompIsBad::eq ? lhs.value != rhs.value
+                                       : lhs.value == rhs.value;
+  }
+
+  friend bool operator!=(BadCompare const& lhs, BadCompare const& rhs) {
+    return Which == WhichCompIsBad::ne ? lhs.value == rhs.value
+                                       : lhs.value != rhs.value;
+  }
+
+  friend bool operator<(BadCompare const& lhs, BadCompare const& rhs) {
+    return Which == WhichCompIsBad::lt ? lhs.value >= rhs.value
+                                       : lhs.value < rhs.value;
+  }
+
+  friend bool operator<=(BadCompare const& lhs, BadCompare const& rhs) {
+    return Which == WhichCompIsBad::le ? lhs.value > rhs.value
+                                       : lhs.value <= rhs.value;
+  }
+
+  friend bool operator>=(BadCompare const& lhs, BadCompare const& rhs) {
+    return Which == WhichCompIsBad::ge ? lhs.value < rhs.value
+                                       : lhs.value >= rhs.value;
+  }
+
+  friend bool operator>(BadCompare const& lhs, BadCompare const& rhs) {
+    return Which == WhichCompIsBad::gt ? lhs.value <= rhs.value
+                                       : lhs.value > rhs.value;
+  }
+};
+
+TEST(ConformanceTestingDeathTest, Failures) {
+  {
+    using profile = ti::CombineProfiles<ti::TriviallyCompleteProfile,
+                                        ti::NothrowComparableProfile>;
+
+    // Note: The initializers are intentionally in the wrong order.
+    ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(float)
+        .INITIALIZER(1.f)
+        .INITIALIZER(0.f)
+        .WITH_LOOSE_PROFILE(profile);
+  }
+
+  {
+    using profile =
+        ti::CombineProfiles<ti::NothrowMovableProfile, ti::EquatableProfile>;
+
+    ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadMoveConstruct)
+        .DUE_TO("Move construction")
+        .INITIALIZER(BadMoveConstruct())
+        .WITH_LOOSE_PROFILE(profile);
+  }
+
+  {
+    using profile =
+        ti::CombineProfiles<ti::NothrowMovableProfile, ti::EquatableProfile>;
+
+    ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadMoveAssign)
+        .DUE_TO("Move assignment")
+        .INITIALIZER(BadMoveAssign())
+        .WITH_LOOSE_PROFILE(profile);
+  }
+}
+
+TEST(ConformanceTestingDeathTest, CompFailures) {
+  using profile = ti::ComparableProfile;
+
+  {
+    using BadComp = BadCompare<WhichCompIsBad::eq>;
+
+    ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadComp)
+        .DUE_TO("Comparison")
+        .INITIALIZER(BadComp{0})
+        .INITIALIZER(BadComp{1})
+        .WITH_LOOSE_PROFILE(profile);
+  }
+
+  {
+    using BadComp = BadCompare<WhichCompIsBad::ne>;
+
+    ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadComp)
+        .DUE_TO("Comparison")
+        .INITIALIZER(BadComp{0})
+        .INITIALIZER(BadComp{1})
+        .WITH_LOOSE_PROFILE(profile);
+  }
+
+  {
+    using BadComp = BadCompare<WhichCompIsBad::lt>;
+
+    ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadComp)
+        .DUE_TO("Comparison")
+        .INITIALIZER(BadComp{0})
+        .INITIALIZER(BadComp{1})
+        .WITH_LOOSE_PROFILE(profile);
+  }
+
+  {
+    using BadComp = BadCompare<WhichCompIsBad::le>;
+
+    ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadComp)
+        .DUE_TO("Comparison")
+        .INITIALIZER(BadComp{0})
+        .INITIALIZER(BadComp{1})
+        .WITH_LOOSE_PROFILE(profile);
+  }
+
+  {
+    using BadComp = BadCompare<WhichCompIsBad::ge>;
+
+    ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadComp)
+        .DUE_TO("Comparison")
+        .INITIALIZER(BadComp{0})
+        .INITIALIZER(BadComp{1})
+        .WITH_LOOSE_PROFILE(profile);
+  }
+
+  {
+    using BadComp = BadCompare<WhichCompIsBad::gt>;
+
+    ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadComp)
+        .DUE_TO("Comparison")
+        .INITIALIZER(BadComp{0})
+        .INITIALIZER(BadComp{1})
+        .WITH_LOOSE_PROFILE(profile);
+  }
+}
+
+struct BadSelfMove {
+  BadSelfMove() = default;
+  BadSelfMove(BadSelfMove&&) = default;
+  BadSelfMove& operator=(BadSelfMove&& other) noexcept {
+    if (this == &other) {
+      broken_state = true;
+    }
+    return *this;
+  }
+
+  friend bool operator==(const BadSelfMove& lhs, const BadSelfMove& rhs) {
+    return !(lhs.broken_state || rhs.broken_state);
+  }
+
+  friend bool operator!=(const BadSelfMove& lhs, const BadSelfMove& rhs) {
+    return lhs.broken_state || rhs.broken_state;
+  }
+
+  bool broken_state = false;
+};
+
+TEST(ConformanceTestingDeathTest, SelfMoveFailure) {
+  using profile = ti::EquatableNothrowMovableProfile;
+
+  {
+    ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadSelfMove)
+        .DUE_TO("Move assignment")
+        .INITIALIZER(BadSelfMove())
+        .WITH_LOOSE_PROFILE(profile);
+  }
+}
+
+struct BadSelfCopy {
+  BadSelfCopy() = default;
+  BadSelfCopy(BadSelfCopy&&) = default;
+  BadSelfCopy(const BadSelfCopy&) = default;
+  BadSelfCopy& operator=(BadSelfCopy&&) = default;
+  BadSelfCopy& operator=(BadSelfCopy const& other) {
+    if (this == &other) {
+      broken_state = true;
+    }
+    return *this;
+  }
+
+  friend bool operator==(const BadSelfCopy& lhs, const BadSelfCopy& rhs) {
+    return !(lhs.broken_state || rhs.broken_state);
+  }
+
+  friend bool operator!=(const BadSelfCopy& lhs, const BadSelfCopy& rhs) {
+    return lhs.broken_state || rhs.broken_state;
+  }
+
+  bool broken_state = false;
+};
+
+TEST(ConformanceTestingDeathTest, SelfCopyFailure) {
+  using profile = ti::EquatableValueProfile;
+
+  {
+    ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadSelfCopy)
+        .DUE_TO("Copy assignment")
+        .INITIALIZER(BadSelfCopy())
+        .WITH_LOOSE_PROFILE(profile);
+  }
+}
+
+struct BadSelfSwap {
+  friend void swap(BadSelfSwap& lhs, BadSelfSwap& rhs) noexcept {
+    if (&lhs == &rhs) lhs.broken_state = true;
+  }
+
+  friend bool operator==(const BadSelfSwap& lhs, const BadSelfSwap& rhs) {
+    return !(lhs.broken_state || rhs.broken_state);
+  }
+
+  friend bool operator!=(const BadSelfSwap& lhs, const BadSelfSwap& rhs) {
+    return lhs.broken_state || rhs.broken_state;
+  }
+
+  bool broken_state = false;
+};
+
+TEST(ConformanceTestingDeathTest, SelfSwapFailure) {
+  using profile = ti::EquatableNothrowMovableProfile;
+
+  {
+    ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadSelfSwap)
+        .DUE_TO("Swap")
+        .INITIALIZER(BadSelfSwap())
+        .WITH_LOOSE_PROFILE(profile);
+  }
+}
+
+struct BadDefaultInitializedMoveAssign {
+  BadDefaultInitializedMoveAssign() : default_initialized(true) {}
+  explicit BadDefaultInitializedMoveAssign(int v) : value(v) {}
+  BadDefaultInitializedMoveAssign(
+      BadDefaultInitializedMoveAssign&& other) noexcept
+      : value(other.value) {}
+  BadDefaultInitializedMoveAssign& operator=(
+      BadDefaultInitializedMoveAssign&& other) noexcept {
+    value = other.value;
+    if (default_initialized) ++value;  // Bad move if lhs is default initialized
+    return *this;
+  }
+
+  friend bool operator==(const BadDefaultInitializedMoveAssign& lhs,
+                         const BadDefaultInitializedMoveAssign& rhs) {
+    return lhs.value == rhs.value;
+  }
+
+  friend bool operator!=(const BadDefaultInitializedMoveAssign& lhs,
+                         const BadDefaultInitializedMoveAssign& rhs) {
+    return lhs.value != rhs.value;
+  }
+
+  bool default_initialized = false;
+  int value = 0;
+};
+
+TEST(ConformanceTestingDeathTest, DefaultInitializedMoveAssignFailure) {
+  using profile =
+      ti::CombineProfiles<ti::DefaultConstructibleNothrowMovableProfile,
+                          ti::EquatableProfile>;
+
+  {
+    ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadDefaultInitializedMoveAssign)
+        .DUE_TO("move assignment")
+        .INITIALIZER(BadDefaultInitializedMoveAssign(0))
+        .WITH_LOOSE_PROFILE(profile);
+  }
+}
+
+struct BadDefaultInitializedCopyAssign {
+  BadDefaultInitializedCopyAssign() : default_initialized(true) {}
+  explicit BadDefaultInitializedCopyAssign(int v) : value(v) {}
+  BadDefaultInitializedCopyAssign(
+      BadDefaultInitializedCopyAssign&& other) noexcept
+      : value(other.value) {}
+  BadDefaultInitializedCopyAssign(const BadDefaultInitializedCopyAssign& other)
+      : value(other.value) {}
+
+  BadDefaultInitializedCopyAssign& operator=(
+      BadDefaultInitializedCopyAssign&& other) noexcept {
+    value = other.value;
+    return *this;
+  }
+
+  BadDefaultInitializedCopyAssign& operator=(
+      const BadDefaultInitializedCopyAssign& other) {
+    value = other.value;
+    if (default_initialized) ++value;  // Bad move if lhs is default initialized
+    return *this;
+  }
+
+  friend bool operator==(const BadDefaultInitializedCopyAssign& lhs,
+                         const BadDefaultInitializedCopyAssign& rhs) {
+    return lhs.value == rhs.value;
+  }
+
+  friend bool operator!=(const BadDefaultInitializedCopyAssign& lhs,
+                         const BadDefaultInitializedCopyAssign& rhs) {
+    return lhs.value != rhs.value;
+  }
+
+  bool default_initialized = false;
+  int value = 0;
+};
+
+TEST(ConformanceTestingDeathTest, DefaultInitializedAssignFailure) {
+  using profile = ti::CombineProfiles<ti::DefaultConstructibleValueProfile,
+                                      ti::EquatableProfile>;
+
+  {
+    ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadDefaultInitializedCopyAssign)
+        .DUE_TO("copy assignment")
+        .INITIALIZER(BadDefaultInitializedCopyAssign(0))
+        .WITH_LOOSE_PROFILE(profile);
+  }
+}
 
 }  // namespace
diff --git a/absl/types/internal/parentheses.h b/absl/types/internal/parentheses.h
new file mode 100644
index 0000000..5aebee8
--- /dev/null
+++ b/absl/types/internal/parentheses.h
@@ -0,0 +1,34 @@
+// Copyright 2019 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.
+//
+// -----------------------------------------------------------------------------
+// parentheses.h
+// -----------------------------------------------------------------------------
+//
+// This file contains macros that expand to a left parenthesis and a right
+// parenthesis. These are in their own file and are generated from macros
+// because otherwise clang-format gets confused and clang-format off directives
+// do not help.
+//
+// The parentheses macros are used when wanting to require a rescan before
+// expansion of parenthesized text appearing after a function-style macro name.
+
+#ifndef ABSL_TYPES_INTERNAL_PARENTHESES_H_
+#define ABSL_TYPES_INTERNAL_PARENTHESES_H_
+
+#define ABSL_INTERNAL_LPAREN (
+
+#define ABSL_INTERNAL_RPAREN )
+
+#endif  // ABSL_TYPES_INTERNAL_PARENTHESES_H_
diff --git a/absl/types/internal/transform_args.h b/absl/types/internal/transform_args.h
new file mode 100644
index 0000000..4a0ab42
--- /dev/null
+++ b/absl/types/internal/transform_args.h
@@ -0,0 +1,246 @@
+// Copyright 2019 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.
+//
+// -----------------------------------------------------------------------------
+// transform_args.h
+// -----------------------------------------------------------------------------
+//
+// This file contains a higher-order macro that "transforms" each element of a
+// a variadic argument by a provided secondary macro.
+
+#ifndef ABSL_TYPES_INTERNAL_TRANSFORM_ARGS_H_
+#define ABSL_TYPES_INTERNAL_TRANSFORM_ARGS_H_
+
+//
+// ABSL_INTERNAL_CAT(a, b)
+//
+// This macro takes two arguments and concatenates them together via ## after
+// expansion.
+//
+// Example:
+//
+//   ABSL_INTERNAL_CAT(foo_, bar)
+//
+// Results in:
+//
+//   foo_bar
+#define ABSL_INTERNAL_CAT(a, b) ABSL_INTERNAL_CAT_IMPL(a, b)
+#define ABSL_INTERNAL_CAT_IMPL(a, b) a##b
+
+//
+// ABSL_INTERNAL_TRANSFORM_ARGS(m, ...)
+//
+// This macro takes another macro as an argument followed by a trailing series
+// of additional parameters (up to 32 additional arguments). It invokes the
+// passed-in macro once for each of the additional arguments, with the
+// expansions separated by commas.
+//
+// Example:
+//
+//   ABSL_INTERNAL_TRANSFORM_ARGS(MY_MACRO, a, b, c)
+//
+// Results in:
+//
+//   MY_MACRO(a), MY_MACRO(b), MY_MACRO(c)
+//
+// TODO(calabrese) Handle no arguments as a special case.
+#define ABSL_INTERNAL_TRANSFORM_ARGS(m, ...)             \
+  ABSL_INTERNAL_CAT(ABSL_INTERNAL_TRANSFORM_ARGS,        \
+                    ABSL_INTERNAL_NUM_ARGS(__VA_ARGS__)) \
+  (m, __VA_ARGS__)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS1(m, a0) m(a0)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS2(m, a0, a1) m(a0), m(a1)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS3(m, a0, a1, a2) m(a0), m(a1), m(a2)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS4(m, a0, a1, a2, a3) \
+  m(a0), m(a1), m(a2), m(a3)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS5(m, a0, a1, a2, a3, a4) \
+  m(a0), m(a1), m(a2), m(a3), m(a4)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS6(m, a0, a1, a2, a3, a4, a5) \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS7(m, a0, a1, a2, a3, a4, a5, a6) \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS8(m, a0, a1, a2, a3, a4, a5, a6, a7) \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS9(m, a0, a1, a2, a3, a4, a5, a6, a7, a8) \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS10(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9)                                    \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS11(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10)                               \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), m(a10)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS12(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11)                          \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS13(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12)                     \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS14(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13)                \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS15(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14)           \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS16(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14, a15)      \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS17(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14, a15, a16) \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS18(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14, a15, a16, \
+                                       a17)                                   \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS19(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14, a15, a16, \
+                                       a17, a18)                              \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS20(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14, a15, a16, \
+                                       a17, a18, a19)                         \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS21(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14, a15, a16, \
+                                       a17, a18, a19, a20)                    \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19), m(a20)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS22(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14, a15, a16, \
+                                       a17, a18, a19, a20, a21)               \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19), m(a20), m(a21)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS23(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14, a15, a16, \
+                                       a17, a18, a19, a20, a21, a22)          \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19), m(a20), m(a21), m(a22)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS24(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14, a15, a16, \
+                                       a17, a18, a19, a20, a21, a22, a23)     \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19), m(a20), m(a21), m(a22), m(a23)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS25(m, a0, a1, a2, a3, a4, a5, a6, a7, a8,  \
+                                       a9, a10, a11, a12, a13, a14, a15, a16,  \
+                                       a17, a18, a19, a20, a21, a22, a23, a24) \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),        \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18),  \
+      m(a19), m(a20), m(a21), m(a22), m(a23), m(a24)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS26(                                       \
+    m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15,  \
+    a16, a17, a18, a19, a20, a21, a22, a23, a24, a25)                         \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS27(                                       \
+    m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15,  \
+    a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26)                    \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25), m(a26)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS28(                                       \
+    m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15,  \
+    a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27)               \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25), m(a26), m(a27)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS29(                                       \
+    m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15,  \
+    a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28)          \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25), m(a26), m(a27), \
+      m(a28)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS30(                                       \
+    m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15,  \
+    a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29)     \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25), m(a26), m(a27), \
+      m(a28), m(a29)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS31(                                        \
+    m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15,   \
+    a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30) \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),        \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18),  \
+      m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25), m(a26), m(a27),  \
+      m(a28), m(a29), m(a30)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS32(m, a0, a1, a2, a3, a4, a5, a6, a7, a8,  \
+                                       a9, a10, a11, a12, a13, a14, a15, a16,  \
+                                       a17, a18, a19, a20, a21, a22, a23, a24, \
+                                       a25, a26, a27, a28, a29, a30, a31)      \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),        \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18),  \
+      m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25), m(a26), m(a27),  \
+      m(a28), m(a29), m(a30), m(a31)
+
+#define ABSL_INTERNAL_NUM_ARGS_IMPL(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9,    \
+                                    a10, a11, a12, a13, a14, a15, a16, a17,    \
+                                    a18, a19, a20, a21, a22, a23, a24, a25,    \
+                                    a26, a27, a28, a29, a30, a31, result, ...) \
+  result
+
+#define ABSL_INTERNAL_FORCE_EXPANSION(...) __VA_ARGS__
+
+#define ABSL_INTERNAL_NUM_ARGS(...)                                            \
+  ABSL_INTERNAL_FORCE_EXPANSION(ABSL_INTERNAL_NUM_ARGS_IMPL(                   \
+      __VA_ARGS__, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, \
+      17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, ))
+
+#endif  // ABSL_TYPES_INTERNAL_TRANSFORM_ARGS_H_
diff --git a/absl/types/internal/variant.h b/absl/types/internal/variant.h
index 71bd3ad..772008c 100644
--- a/absl/types/internal/variant.h
+++ b/absl/types/internal/variant.h
@@ -45,7 +45,7 @@
 template <class... Types>
 class variant;
 
-ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1);
+ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, static_cast<size_t>(-1));
 
 template <class T>
 struct variant_size;
@@ -292,7 +292,7 @@
 template <class Op, std::size_t I>
 struct ReachableSwitchCase {
   static VisitIndicesResultT<Op, std::size_t> Run(Op&& op) {
-    return absl::base_internal::Invoke(absl::forward<Op>(op), SizeT<I>());
+    return absl::base_internal::invoke(absl::forward<Op>(op), SizeT<I>());
   }
 };
 
@@ -424,7 +424,7 @@
         return PickCase<Op, 32, EndIndex>::Run(absl::forward<Op>(op));
       default:
         ABSL_ASSERT(i == variant_npos);
-        return absl::base_internal::Invoke(absl::forward<Op>(op), NPos());
+        return absl::base_internal::invoke(absl::forward<Op>(op), NPos());
     }
   }
 };
@@ -488,7 +488,7 @@
     template <std::size_t I>
     VisitIndicesResultT<Op, decltype(EndIndices)...> operator()(
         SizeT<I> /*index*/) && {
-      return base_internal::Invoke(
+      return base_internal::invoke(
           absl::forward<Op>(op),
           SizeT<UnflattenIndex<I, N, (EndIndices + 1)...>::value -
                 std::size_t{1}>()...);
@@ -930,7 +930,7 @@
                      absl::result_of_t<Op(VariantAccessResult<
                                           Is, QualifiedVariants>...)>>::value,
         "All visitation overloads must have the same return type.");
-    return absl::base_internal::Invoke(
+    return absl::base_internal::invoke(
         absl::forward<Op>(op),
         VariantCoreAccess::Access<Is>(
             absl::forward<QualifiedVariants>(std::get<TupIs>(variant_tup)))...);
diff --git a/absl/types/optional.h b/absl/types/optional.h
index 2025e29..61540cf 100644
--- a/absl/types/optional.h
+++ b/absl/types/optional.h
@@ -136,10 +136,10 @@
   constexpr optional(nullopt_t) noexcept {}  // NOLINT(runtime/explicit)
 
   // Copy constructor, standard semantics
-  optional(const optional& src) = default;
+  optional(const optional&) = default;
 
   // Move constructor, standard semantics
-  optional(optional&& src) = default;
+  optional(optional&&) = default;
 
   // Constructs a non-empty `optional` direct-initialized value of type `T` from
   // the arguments `std::forward<Args>(args)...`  within the `optional`.
@@ -412,11 +412,11 @@
   //
   // If you need myOpt->foo in constexpr, use (*myOpt).foo instead.
   const T* operator->() const {
-    assert(this->engaged_);
+    ABSL_HARDENING_ASSERT(this->engaged_);
     return std::addressof(this->data_);
   }
   T* operator->() {
-    assert(this->engaged_);
+    ABSL_HARDENING_ASSERT(this->engaged_);
     return std::addressof(this->data_);
   }
 
@@ -425,17 +425,17 @@
   // Accesses the underlying `T` value of an `optional`. If the `optional` is
   // empty, behavior is undefined.
   constexpr const T& operator*() const& {
-    return ABSL_ASSERT(this->engaged_), reference();
+    return ABSL_HARDENING_ASSERT(this->engaged_), reference();
   }
   T& operator*() & {
-    assert(this->engaged_);
+    ABSL_HARDENING_ASSERT(this->engaged_);
     return reference();
   }
   constexpr const T&& operator*() const && {
-    return absl::move(reference());
+    return ABSL_HARDENING_ASSERT(this->engaged_), absl::move(reference());
   }
   T&& operator*() && {
-    assert(this->engaged_);
+    ABSL_HARDENING_ASSERT(this->engaged_);
     return std::move(reference());
   }
 
@@ -444,7 +444,7 @@
   // Returns false if and only if the `optional` is empty.
   //
   //   if (opt) {
-  //     // do something with opt.value();
+  //     // do something with *opt or opt->;
   //   } else {
   //     // opt is empty.
   //   }
diff --git a/absl/types/optional_test.cc b/absl/types/optional_test.cc
index 47d5c8a..7ef142c 100644
--- a/absl/types/optional_test.cc
+++ b/absl/types/optional_test.cc
@@ -1051,14 +1051,13 @@
 #ifdef ABSL_HAVE_EXCEPTIONS
   EXPECT_THROW((void)empty.value(), absl::bad_optional_access);
 #else
-  EXPECT_DEATH((void)empty.value(), "Bad optional access");
+  EXPECT_DEATH_IF_SUPPORTED((void)empty.value(), "Bad optional access");
 #endif
 
   // test constexpr value()
   constexpr absl::optional<int> o1(1);
   static_assert(1 == o1.value(), "");  // const &
-#if !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG) && \
-    !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
+#if !defined(_MSC_VER) && !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
   using COI = const absl::optional<int>;
   static_assert(2 == COI(2).value(), "");  // const &&
 #endif
@@ -1098,8 +1097,7 @@
 
   constexpr absl::optional<int> opt1(1);
   static_assert(*opt1 == 1, "");
-#if !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG) && \
-    !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
+#if !defined(_MSC_VER) && !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
   using COI = const absl::optional<int>;
   static_assert(*COI(2) == 2, "");
 #endif
diff --git a/absl/types/span.h b/absl/types/span.h
index 3283145..95fe792 100644
--- a/absl/types/span.h
+++ b/absl/types/span.h
@@ -17,32 +17,30 @@
 // span.h
 // -----------------------------------------------------------------------------
 //
-// This header file defines a `Span<T>` type for holding a view of an existing
-// array of data. The `Span` object, much like the `absl::string_view` object,
-// does not own such data itself. A span provides a lightweight way to pass
-// around view of such data.
+// This header file defines a `Span<T>` type for holding a reference to existing
+// array data. The `Span` object, much like the `absl::string_view` object,
+// does not own such data itself, and the data being referenced by the span must
+// outlive the span itself. Unlike `view` type references, a span can hold a
+// reference to mutable data (and can mutate it for underlying types of
+// non-const T.) A span provides a lightweight way to pass a reference to such
+// data.
 //
 // Additionally, this header file defines `MakeSpan()` and `MakeConstSpan()`
 // factory functions, for clearly creating spans of type `Span<T>` or read-only
 // `Span<const T>` when such types may be difficult to identify due to issues
 // with implicit conversion.
 //
-// The C++ standards committee currently has a proposal for a `std::span` type,
-// (http://wg21.link/p0122), which is not yet part of the standard (though may
-// become part of C++20). As of August 2017, the differences between
-// `absl::Span` and this proposal are:
-//    * `absl::Span` uses `size_t` for `size_type`
-//    * `absl::Span` has no `operator()`
-//    * `absl::Span` has no constructors for `std::unique_ptr` or
-//      `std::shared_ptr`
+// The C++20 draft standard includes a `std::span` type. As of June 2020, the
+// differences between `absl::Span` and `std::span` are:
+//    * `absl::Span` has `operator==` (which is likely a design bug,
+//       per https://abseil.io/blog/20180531-regular-types)
 //    * `absl::Span` has the factory functions `MakeSpan()` and
 //      `MakeConstSpan()`
-//    * `absl::Span` has `front()` and `back()` methods
 //    * bounds-checked access to `absl::Span` is accomplished with `at()`
 //    * `absl::Span` has compiler-provided move and copy constructors and
 //      assignment. This is due to them being specified as `constexpr`, but that
 //      implies const in C++11.
-//    * `absl::Span` has no `element_type` or `index_type` typedefs
+//    * `absl::Span` has no `element_type` typedef
 //    * A read-only `absl::Span<const T>` can be implicitly constructed from an
 //      initializer list.
 //    * `absl::Span` has no `bytes()`, `size_bytes()`, `as_bytes()`, or
@@ -77,9 +75,9 @@
 // Span
 //------------------------------------------------------------------------------
 //
-// A `Span` is an "array view" type for holding a view of a contiguous data
-// array; the `Span` object does not and cannot own such data itself. A span
-// provides an easy way to provide overloads for anything operating on
+// A `Span` is an "array reference" type for holding a reference of contiguous
+// array data; the `Span` object does not and cannot own such data itself. A
+// span provides an easy way to provide overloads for anything operating on
 // contiguous sequences without needing to manage pointers and array lengths
 // manually.
 
@@ -97,7 +95,8 @@
 // constructors.
 //
 // A `Span<T>` is somewhat analogous to an `absl::string_view`, but for an array
-// of elements of type `T`. A user of `Span` must ensure that the data being
+// of elements of type `T`, and unlike an `absl::string_view`, a span can hold a
+// reference to mutable data. A user of `Span` must ensure that the data being
 // pointed to outlives the `Span` itself.
 //
 // You can construct a `Span<T>` in several ways:
@@ -127,7 +126,7 @@
 // Note that `Span` objects, in addition to requiring that the memory they
 // point to remains alive, must also ensure that such memory does not get
 // reallocated. Therefore, to avoid undefined behavior, containers with
-// associated span views should not invoke operations that may reallocate memory
+// associated spans should not invoke operations that may reallocate memory
 // (such as resizing) or invalidate iterators into the container.
 //
 // One common use for a `Span` is when passing arguments to a routine that can
@@ -276,7 +275,7 @@
   // Returns a reference to the i'th element of this span.
   constexpr reference operator[](size_type i) const noexcept {
     // MSVC 2015 accepts this as constexpr, but not ptr_[i]
-    return *(data() + i);
+    return ABSL_HARDENING_ASSERT(i < size()), *(data() + i);
   }
 
   // Span::at()
@@ -292,60 +291,74 @@
 
   // Span::front()
   //
-  // Returns a reference to the first element of this span.
+  // Returns a reference to the first element of this span. The span must not
+  // be empty.
   constexpr reference front() const noexcept {
-    return ABSL_ASSERT(size() > 0), *data();
+    return ABSL_HARDENING_ASSERT(size() > 0), *data();
   }
 
   // Span::back()
   //
-  // Returns a reference to the last element of this span.
+  // Returns a reference to the last element of this span. The span must not
+  // be empty.
   constexpr reference back() const noexcept {
-    return ABSL_ASSERT(size() > 0), *(data() + size() - 1);
+    return ABSL_HARDENING_ASSERT(size() > 0), *(data() + size() - 1);
   }
 
   // Span::begin()
   //
-  // Returns an iterator to the first element of this span.
+  // Returns an iterator pointing to the first element of this span, or `end()`
+  // if the span is empty.
   constexpr iterator begin() const noexcept { return data(); }
 
   // Span::cbegin()
   //
-  // Returns a const iterator to the first element of this span.
+  // Returns a const iterator pointing to the first element of this span, or
+  // `end()` if the span is empty.
   constexpr const_iterator cbegin() const noexcept { return begin(); }
 
   // Span::end()
   //
-  // Returns an iterator to the last element of this span.
+  // Returns an iterator pointing just beyond the last element at the
+  // end of this span. This iterator acts as a placeholder; attempting to
+  // access it results in undefined behavior.
   constexpr iterator end() const noexcept { return data() + size(); }
 
   // Span::cend()
   //
-  // Returns a const iterator to the last element of this span.
+  // Returns a const iterator pointing just beyond the last element at the
+  // end of this span. This iterator acts as a placeholder; attempting to
+  // access it results in undefined behavior.
   constexpr const_iterator cend() const noexcept { return end(); }
 
   // Span::rbegin()
   //
-  // Returns a reverse iterator starting at the last element of this span.
+  // Returns a reverse iterator pointing to the last element at the end of this
+  // span, or `rend()` if the span is empty.
   constexpr reverse_iterator rbegin() const noexcept {
     return reverse_iterator(end());
   }
 
   // Span::crbegin()
   //
-  // Returns a reverse const iterator starting at the last element of this span.
+  // Returns a const reverse iterator pointing to the last element at the end of
+  // this span, or `crend()` if the span is empty.
   constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); }
 
   // Span::rend()
   //
-  // Returns a reverse iterator starting at the first element of this span.
+  // Returns a reverse iterator pointing just before the first element
+  // at the beginning of this span. This pointer acts as a placeholder;
+  // attempting to access its element results in undefined behavior.
   constexpr reverse_iterator rend() const noexcept {
     return reverse_iterator(begin());
   }
 
   // Span::crend()
   //
-  // Returns a reverse iterator starting at the first element of this span.
+  // Returns a reverse const iterator pointing just before the first element
+  // at the beginning of this span. This pointer acts as a placeholder;
+  // attempting to access its element results in undefined behavior.
   constexpr const_reverse_iterator crend() const noexcept { return rend(); }
 
   // Span mutations
@@ -354,7 +367,7 @@
   //
   // Removes the first `n` elements from the span.
   void remove_prefix(size_type n) noexcept {
-    assert(size() >= n);
+    ABSL_HARDENING_ASSERT(size() >= n);
     ptr_ += n;
     len_ -= n;
   }
@@ -363,7 +376,7 @@
   //
   // Removes the last `n` elements from the span.
   void remove_suffix(size_type n) noexcept {
-    assert(size() >= n);
+    ABSL_HARDENING_ASSERT(size() >= n);
     len_ -= n;
   }
 
@@ -651,7 +664,7 @@
 
 template <int&... ExplicitArgumentBarrier, typename T>
 Span<T> MakeSpan(T* begin, T* end) noexcept {
-  return ABSL_ASSERT(begin <= end), Span<T>(begin, end - begin);
+  return ABSL_HARDENING_ASSERT(begin <= end), Span<T>(begin, end - begin);
 }
 
 template <int&... ExplicitArgumentBarrier, typename C>
@@ -696,7 +709,7 @@
 
 template <int&... ExplicitArgumentBarrier, typename T>
 Span<const T> MakeConstSpan(T* begin, T* end) noexcept {
-  return ABSL_ASSERT(begin <= end), Span<const T>(begin, end - begin);
+  return ABSL_HARDENING_ASSERT(begin <= end), Span<const T>(begin, end - begin);
 }
 
 template <int&... ExplicitArgumentBarrier, typename C>
diff --git a/absl/types/span_test.cc b/absl/types/span_test.cc
index 22467a0..2584339 100644
--- a/absl/types/span_test.cc
+++ b/absl/types/span_test.cc
@@ -27,6 +27,7 @@
 #include "absl/base/attributes.h"
 #include "absl/base/config.h"
 #include "absl/base/internal/exception_testing.h"
+#include "absl/base/options.h"
 #include "absl/container/fixed_array.h"
 #include "absl/container/inlined_vector.h"
 #include "absl/hash/hash_testing.h"
@@ -232,6 +233,11 @@
 
   EXPECT_EQ(s.front(), s[0]);
   EXPECT_EQ(s.back(), s[9]);
+
+#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
+  EXPECT_DEATH_IF_SUPPORTED(s[-1], "");
+  EXPECT_DEATH_IF_SUPPORTED(s[10], "");
+#endif
 }
 
 TEST(IntSpan, AtThrows) {
@@ -268,6 +274,13 @@
   EXPECT_EQ(s.size(), 0);
 
   EXPECT_EQ(v, MakeRamp(20, 1));
+
+#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
+  absl::Span<int> prefix_death(v);
+  EXPECT_DEATH_IF_SUPPORTED(prefix_death.remove_prefix(21), "");
+  absl::Span<int> suffix_death(v);
+  EXPECT_DEATH_IF_SUPPORTED(suffix_death.remove_suffix(21), "");
+#endif
 }
 
 TEST(IntSpan, Subspan) {
diff --git a/absl/types/variant.h b/absl/types/variant.h
index 776d19a..ac93464 100644
--- a/absl/types/variant.h
+++ b/absl/types/variant.h
@@ -604,7 +604,10 @@
 
   // emplace() Functions
 
-  // Constructs a value of the given alternative type T within the variant.
+  // Constructs a value of the given alternative type T within the variant. The
+  // existing value of the variant is destroyed first (provided that
+  // `absl::valueless_by_exception()` is false). Requires that T is unambiguous
+  // in the variant.
   //
   // Example:
   //
@@ -624,7 +627,9 @@
   }
 
   // Constructs a value of the given alternative type T within the variant using
-  // an initializer list.
+  // an initializer list. The existing value of the variant is destroyed first
+  // (provided that `absl::valueless_by_exception()` is false). Requires that T
+  // is unambiguous in the variant.
   //
   // Example:
   //
@@ -643,7 +648,7 @@
   }
 
   // Destroys the current value of the variant (provided that
-  // `absl::valueless_by_exception()` is false, and constructs a new value at
+  // `absl::valueless_by_exception()` is false) and constructs a new value at
   // the given index.
   //
   // Example:
@@ -662,7 +667,7 @@
   }
 
   // Destroys the current value of the variant (provided that
-  // `absl::valueless_by_exception()` is false, and constructs a new value at
+  // `absl::valueless_by_exception()` is false) and constructs a new value at
   // the given index using an initializer list and the provided arguments.
   //
   // Example:
diff --git a/absl/types/variant_test.cc b/absl/types/variant_test.cc
index 9639333..cf23733 100644
--- a/absl/types/variant_test.cc
+++ b/absl/types/variant_test.cc
@@ -50,7 +50,7 @@
 #else
 
 #define ABSL_VARIANT_TEST_EXPECT_FAIL(expr, exception_t, text) \
-  EXPECT_DEATH(expr, text)
+  EXPECT_DEATH_IF_SUPPORTED(expr, text)
 
 #endif  // ABSL_HAVE_EXCEPTIONS
 
@@ -679,7 +679,7 @@
   object.operator=(object);
   EXPECT_EQ(0, counter);
 
-  // A std::string long enough that it's likely to defeat any inline representation
+  // A string long enough that it's likely to defeat any inline representation
   // optimization.
   const std::string long_str(128, 'a');
 
@@ -2311,7 +2311,8 @@
   ASSERT_TRUE(absl::holds_alternative<int32_t>(variant2));
   EXPECT_EQ(42, absl::get<int32_t>(variant2));
 
-  variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
+  variant2 =
+      ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
   ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2));
   EXPECT_EQ(42, absl::get<uint32_t>(variant2));
 #endif  // !ABSL_USES_STD_VARIANT
@@ -2453,7 +2454,8 @@
       ConvertVariantTo<variant<int32_t, uint32_t>>(variant<int32_t>(42)));
   EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42));
 
-  variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
+  variant2 =
+      ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
   EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42));
 #endif
 
diff --git a/absl/utility/BUILD.bazel b/absl/utility/BUILD.bazel
index 6881f93..02b2c40 100644
--- a/absl/utility/BUILD.bazel
+++ b/absl/utility/BUILD.bazel
@@ -24,7 +24,7 @@
 
 package(default_visibility = ["//visibility:public"])
 
-licenses(["notice"])  # Apache 2.0
+licenses(["notice"])
 
 cc_library(
     name = "utility",
diff --git a/absl/utility/utility.h b/absl/utility/utility.h
index e6647c7..bf92322 100644
--- a/absl/utility/utility.h
+++ b/absl/utility/utility.h
@@ -236,10 +236,10 @@
 // Helper method for expanding tuple into a called method.
 template <typename Functor, typename Tuple, std::size_t... Indexes>
 auto apply_helper(Functor&& functor, Tuple&& t, index_sequence<Indexes...>)
-    -> decltype(absl::base_internal::Invoke(
+    -> decltype(absl::base_internal::invoke(
         absl::forward<Functor>(functor),
         std::get<Indexes>(absl::forward<Tuple>(t))...)) {
-  return absl::base_internal::Invoke(
+  return absl::base_internal::invoke(
       absl::forward<Functor>(functor),
       std::get<Indexes>(absl::forward<Tuple>(t))...);
 }
diff --git a/ci/absl_alternate_options.h b/ci/absl_alternate_options.h
index f0c21fe..29b020d 100644
--- a/ci/absl_alternate_options.h
+++ b/ci/absl_alternate_options.h
@@ -1,6 +1,3 @@
-#ifndef ABSL_BASE_OPTIONS_H_
-#define ABSL_BASE_OPTIONS_H_
-
 // Copyright 2019 The Abseil Authors.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,11 +15,15 @@
 // Alternate options.h file, used in continuous integration testing to exercise
 // option settings not used by default.
 
+#ifndef ABSL_BASE_OPTIONS_H_
+#define ABSL_BASE_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_INLINE_NAMESPACE 1
 #define ABSL_OPTION_INLINE_NAMESPACE_NAME ns
+#define ABSL_OPTION_HARDENED 1
 
 #endif  // ABSL_BASE_OPTIONS_H_
diff --git a/ci/cmake_common.sh b/ci/cmake_common.sh
new file mode 100644
index 0000000..aec8a11
--- /dev/null
+++ b/ci/cmake_common.sh
@@ -0,0 +1,25 @@
+# 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.
+
+# The commit of GoogleTest to be used in the CMake tests in this directory.
+# Keep this in sync with the commit in the WORKSPACE file.
+readonly ABSL_GOOGLETEST_COMMIT="8567b09290fe402cf01923e2131c5635b8ed851b"
+
+# Avoid depending on GitHub by looking for a cached copy of the commit first.
+if [[ -r "${KOKORO_GFILE_DIR:-}/distdir/${ABSL_GOOGLETEST_COMMIT}.zip" ]]; then
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
+  ABSL_GOOGLETEST_DOWNLOAD_URL="file:///distdir/${ABSL_GOOGLETEST_COMMIT}.zip"
+else
+  ABSL_GOOGLETEST_DOWNLOAD_URL="https://github.com/google/googletest/archive/${ABSL_GOOGLETEST_COMMIT}.zip"
+fi
diff --git a/ci/cmake_install_test.sh b/ci/cmake_install_test.sh
index 55fb4f1..ffc6b51 100755
--- a/ci/cmake_install_test.sh
+++ b/ci/cmake_install_test.sh
@@ -16,17 +16,28 @@
 
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
-time docker run \
-    --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
-    --workdir=/abseil-cpp \
+if [[ -z ${LINK_TYPE:-} ]]; then
+  LINK_TYPE="STATIC DYNAMIC"
+fi
+
+source "${ABSEIL_ROOT}/ci/cmake_common.sh"
+
+source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
+readonly DOCKER_CONTAINER=${LINUX_GCC_LATEST_CONTAINER}
+
+for link_type in ${LINK_TYPE}; do
+  time docker run \
+    --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp-ro,readonly \
     --tmpfs=/buildfs:exec \
+    --tmpfs=/abseil-cpp:exec \
+    --workdir=/abseil-cpp \
     --cap-add=SYS_PTRACE \
+    -e "LINK_TYPE=${link_type}" \
     --rm \
-    -e CFLAGS="-Werror" \
-    -e CXXFLAGS="-Werror" \
-    gcr.io/google.com/absl-177019/linux_gcc-latest:20200106 \
-    /bin/bash CMake/install_test_project/test.sh $@
+    ${DOCKER_CONTAINER} \
+    /bin/bash -c "cp -r /abseil-cpp-ro/* . && CMake/install_test_project/test.sh"
+done
diff --git a/ci/linux_clang-latest_libcxx_asan_bazel.sh b/ci/linux_clang-latest_libcxx_asan_bazel.sh
index 24efe3b..ffbb832 100755
--- a/ci/linux_clang-latest_libcxx_asan_bazel.sh
+++ b/ci/linux_clang-latest_libcxx_asan_bazel.sh
@@ -20,28 +20,29 @@
 
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
-if [ -z ${STD:-} ]; then
-  STD="c++11 c++14 c++17"
+if [[ -z ${STD:-} ]]; then
+  STD="c++11 c++14 c++17 c++20"
 fi
 
-if [ -z ${COMPILATION_MODE:-} ]; then
+if [[ -z ${COMPILATION_MODE:-} ]]; then
   COMPILATION_MODE="fastbuild opt"
 fi
 
-if [ -z ${EXCEPTIONS_MODE:-} ]; then
+if [[ -z ${EXCEPTIONS_MODE:-} ]]; then
   EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
 fi
 
-readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20200102"
+source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
+readonly DOCKER_CONTAINER=${LINUX_CLANG_LATEST_CONTAINER}
 
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
-if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
-  DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
   # Bazel doesn't track changes to tools outside of the workspace
   # (e.g. /usr/bin/gcc), so by appending the docker container to the
   # remote_http_cache url, we make changes to the container part of
@@ -50,17 +51,24 @@
   BAZEL_EXTRA_ARGS="--remote_http_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}"
 fi
 
+# Avoid depending on external sites like GitHub by checking --distdir for
+# external dependencies first.
+# https://docs.bazel.build/versions/master/guide.html#distdir
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
+  BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
+fi
+
 for std in ${STD}; do
   for compilation_mode in ${COMPILATION_MODE}; do
     for exceptions_mode in ${EXCEPTIONS_MODE}; do
       echo "--------------------------------------------------------------------"
       time docker run \
-        --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+        --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
         --workdir=/abseil-cpp \
         --cap-add=SYS_PTRACE \
         --rm \
         -e CC="/opt/llvm/clang/bin/clang" \
-        -e BAZEL_COMPILER="llvm" \
         -e BAZEL_CXXOPTS="-std=${std}:-nostdinc++" \
         -e BAZEL_LINKOPTS="-L/opt/llvm/libcxx/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx/lib" \
         -e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx/include/c++/v1" \
@@ -69,9 +77,6 @@
         /usr/local/bin/bazel test ... \
           --compilation_mode="${compilation_mode}" \
           --copt="${exceptions_mode}" \
-          --copt="-DDYNAMIC_ANNOTATIONS_ENABLED=1" \
-          --copt="-DADDRESS_SANITIZER" \
-          --copt="-DUNDEFINED_BEHAVIOR_SANITIZER" \
           --copt="-fsanitize=address" \
           --copt="-fsanitize=float-divide-by-zero" \
           --copt="-fsanitize=nullability" \
diff --git a/ci/linux_clang-latest_libcxx_bazel.sh b/ci/linux_clang-latest_libcxx_bazel.sh
index 127e7bc..f6a2221 100755
--- a/ci/linux_clang-latest_libcxx_bazel.sh
+++ b/ci/linux_clang-latest_libcxx_bazel.sh
@@ -20,28 +20,29 @@
 
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
-if [ -z ${STD:-} ]; then
-  STD="c++11 c++14 c++17"
+if [[ -z ${STD:-} ]]; then
+  STD="c++11 c++14 c++17 c++20"
 fi
 
-if [ -z ${COMPILATION_MODE:-} ]; then
+if [[ -z ${COMPILATION_MODE:-} ]]; then
   COMPILATION_MODE="fastbuild opt"
 fi
 
-if [ -z ${EXCEPTIONS_MODE:-} ]; then
+if [[ -z ${EXCEPTIONS_MODE:-} ]]; then
   EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
 fi
 
-readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20200102"
+source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
+readonly DOCKER_CONTAINER=${LINUX_CLANG_LATEST_CONTAINER}
 
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
-if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
-  DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
   # Bazel doesn't track changes to tools outside of the workspace
   # (e.g. /usr/bin/gcc), so by appending the docker container to the
   # remote_http_cache url, we make changes to the container part of
@@ -50,18 +51,25 @@
   BAZEL_EXTRA_ARGS="--remote_http_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}"
 fi
 
+# Avoid depending on external sites like GitHub by checking --distdir for
+# external dependencies first.
+# https://docs.bazel.build/versions/master/guide.html#distdir
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
+  BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
+fi
+
 for std in ${STD}; do
   for compilation_mode in ${COMPILATION_MODE}; do
     for exceptions_mode in ${EXCEPTIONS_MODE}; do
       echo "--------------------------------------------------------------------"
       time docker run \
-        --volume="${ABSEIL_ROOT}:/abseil-cpp-ro:ro" \
+        --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp-ro,readonly \
         --tmpfs=/abseil-cpp \
         --workdir=/abseil-cpp \
         --cap-add=SYS_PTRACE \
         --rm \
         -e CC="/opt/llvm/clang/bin/clang" \
-        -e BAZEL_COMPILER="llvm" \
         -e BAZEL_CXXOPTS="-std=${std}:-nostdinc++" \
         -e BAZEL_LINKOPTS="-L/opt/llvm/libcxx/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx/lib" \
         -e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx/include/c++/v1" \
diff --git a/ci/linux_clang-latest_libcxx_tsan_bazel.sh b/ci/linux_clang-latest_libcxx_tsan_bazel.sh
index 00257b3..e70e821 100755
--- a/ci/linux_clang-latest_libcxx_tsan_bazel.sh
+++ b/ci/linux_clang-latest_libcxx_tsan_bazel.sh
@@ -20,28 +20,29 @@
 
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
-if [ -z ${STD:-} ]; then
-  STD="c++11 c++14 c++17"
+if [[ -z ${STD:-} ]]; then
+  STD="c++11 c++14 c++17 c++20"
 fi
 
-if [ -z ${COMPILATION_MODE:-} ]; then
+if [[ -z ${COMPILATION_MODE:-} ]]; then
   COMPILATION_MODE="fastbuild opt"
 fi
 
-if [ -z ${EXCEPTIONS_MODE:-} ]; then
+if [[ -z ${EXCEPTIONS_MODE:-} ]]; then
   EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
 fi
 
-readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20200102"
+source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
+readonly DOCKER_CONTAINER=${LINUX_CLANG_LATEST_CONTAINER}
 
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
-if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
-  DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
   # Bazel doesn't track changes to tools outside of the workspace
   # (e.g. /usr/bin/gcc), so by appending the docker container to the
   # remote_http_cache url, we make changes to the container part of
@@ -50,17 +51,24 @@
   BAZEL_EXTRA_ARGS="--remote_http_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}"
 fi
 
+# Avoid depending on external sites like GitHub by checking --distdir for
+# external dependencies first.
+# https://docs.bazel.build/versions/master/guide.html#distdir
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
+  BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
+fi
+
 for std in ${STD}; do
   for compilation_mode in ${COMPILATION_MODE}; do
     for exceptions_mode in ${EXCEPTIONS_MODE}; do
       echo "--------------------------------------------------------------------"
       time docker run \
-        --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+        --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
         --workdir=/abseil-cpp \
         --cap-add=SYS_PTRACE \
         --rm \
         -e CC="/opt/llvm/clang/bin/clang" \
-        -e BAZEL_COMPILER="llvm" \
         -e BAZEL_CXXOPTS="-std=${std}:-nostdinc++" \
         -e BAZEL_LINKOPTS="-L/opt/llvm/libcxx-tsan/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx-tsan/lib" \
         -e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx-tsan/include/c++/v1" \
@@ -70,8 +78,6 @@
           --build_tag_filters="-notsan" \
           --compilation_mode="${compilation_mode}" \
           --copt="${exceptions_mode}" \
-          --copt="-DDYNAMIC_ANNOTATIONS_ENABLED=1" \
-          --copt="-DTHREAD_SANITIZER" \
           --copt="-fsanitize=thread" \
           --copt="-fno-sanitize-blacklist" \
           --copt=-Werror \
diff --git a/ci/linux_clang-latest_libstdcxx_bazel.sh b/ci/linux_clang-latest_libstdcxx_bazel.sh
index 9fe71d3..0986ff4 100755
--- a/ci/linux_clang-latest_libstdcxx_bazel.sh
+++ b/ci/linux_clang-latest_libstdcxx_bazel.sh
@@ -20,28 +20,29 @@
 
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
-if [ -z ${STD:-} ]; then
-  STD="c++11 c++14 c++17"
+if [[ -z ${STD:-} ]]; then
+  STD="c++11 c++14 c++17 c++20"
 fi
 
-if [ -z ${COMPILATION_MODE:-} ]; then
+if [[ -z ${COMPILATION_MODE:-} ]]; then
   COMPILATION_MODE="fastbuild opt"
 fi
 
-if [ -z ${EXCEPTIONS_MODE:-} ]; then
+if [[ -z ${EXCEPTIONS_MODE:-} ]]; then
   EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
 fi
 
-readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20200102"
+source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
+readonly DOCKER_CONTAINER=${LINUX_CLANG_LATEST_CONTAINER}
 
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
-if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
-  DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
   # Bazel doesn't track changes to tools outside of the workspace
   # (e.g. /usr/bin/gcc), so by appending the docker container to the
   # remote_http_cache url, we make changes to the container part of
@@ -50,27 +51,35 @@
   BAZEL_EXTRA_ARGS="--remote_http_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}"
 fi
 
+# Avoid depending on external sites like GitHub by checking --distdir for
+# external dependencies first.
+# https://docs.bazel.build/versions/master/guide.html#distdir
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
+  BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
+fi
+
 for std in ${STD}; do
   for compilation_mode in ${COMPILATION_MODE}; do
     for exceptions_mode in ${EXCEPTIONS_MODE}; do
       echo "--------------------------------------------------------------------"
       time docker run \
-        --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+        --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
         --workdir=/abseil-cpp \
         --cap-add=SYS_PTRACE \
         --rm \
         -e CC="/opt/llvm/clang/bin/clang" \
-        -e BAZEL_COMPILER="llvm" \
         -e BAZEL_CXXOPTS="-std=${std}" \
-        -e CPLUS_INCLUDE_PATH="/usr/include/c++/6" \
         ${DOCKER_EXTRA_ARGS:-} \
         ${DOCKER_CONTAINER} \
         /usr/local/bin/bazel test ... \
           --compilation_mode="${compilation_mode}" \
+          --copt="--gcc-toolchain=/usr/local" \
           --copt="${exceptions_mode}" \
           --copt=-Werror \
           --define="absl=1" \
           --keep_going \
+          --linkopt="--gcc-toolchain=/usr/local" \
           --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
new file mode 100644
index 0000000..1c29d9a
--- /dev/null
+++ b/ci/linux_docker_containers.sh
@@ -0,0 +1,21 @@
+# Copyright 2019 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 file contains Docker container identifiers currently used by test scripts.
+# Test scripts should source this file to get the identifiers.
+
+readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20201026"
+readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20201008"
+readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20201008"
+readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20201015"
diff --git a/ci/linux_gcc-4.9_libstdcxx_bazel.sh b/ci/linux_gcc-floor_libstdcxx_bazel.sh
similarity index 77%
rename from ci/linux_gcc-4.9_libstdcxx_bazel.sh
rename to ci/linux_gcc-floor_libstdcxx_bazel.sh
index f8102cc..224aef8 100755
--- a/ci/linux_gcc-4.9_libstdcxx_bazel.sh
+++ b/ci/linux_gcc-floor_libstdcxx_bazel.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 #
-# Copyright 2019 The Abseil Authors.
+# 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.
@@ -20,27 +20,28 @@
 
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
-if [ -z ${STD:-} ]; then
+if [[ -z ${STD:-} ]]; then
   STD="c++11 c++14"
 fi
 
-if [ -z ${COMPILATION_MODE:-} ]; then
+if [[ -z ${COMPILATION_MODE:-} ]]; then
   COMPILATION_MODE="fastbuild opt"
 fi
 
-if [ -z ${EXCEPTIONS_MODE:-} ]; then
+if [[ -z ${EXCEPTIONS_MODE:-} ]]; then
   EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
 fi
 
-readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-4.9:20191018"
+source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
+readonly DOCKER_CONTAINER=${LINUX_GCC_FLOOR_CONTAINER}
 
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
-if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
+if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
   DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
   # Bazel doesn't track changes to tools outside of the workspace
   # (e.g. /usr/bin/gcc), so by appending the docker container to the
@@ -50,6 +51,14 @@
   BAZEL_EXTRA_ARGS="--remote_http_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}"
 fi
 
+# Avoid depending on external sites like GitHub by checking --distdir for
+# external dependencies first.
+# https://docs.bazel.build/versions/master/guide.html#distdir
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
+  DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
+  BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
+fi
+
 for std in ${STD}; do
   for compilation_mode in ${COMPILATION_MODE}; do
     for exceptions_mode in ${EXCEPTIONS_MODE}; do
@@ -59,7 +68,7 @@
         --workdir=/abseil-cpp \
         --cap-add=SYS_PTRACE \
         --rm \
-        -e CC="/usr/bin/gcc-4.9" \
+        -e CC="/usr/local/bin/gcc" \
         -e BAZEL_CXXOPTS="-std=${std}" \
         ${DOCKER_EXTRA_ARGS:-} \
         ${DOCKER_CONTAINER} \
diff --git a/ci/linux_gcc-latest_libstdcxx_bazel.sh b/ci/linux_gcc-latest_libstdcxx_bazel.sh
index 5964703..37d89d9 100755
--- a/ci/linux_gcc-latest_libstdcxx_bazel.sh
+++ b/ci/linux_gcc-latest_libstdcxx_bazel.sh
@@ -20,28 +20,29 @@
 
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
-if [ -z ${STD:-} ]; then
-  STD="c++11 c++14 c++17"
+if [[ -z ${STD:-} ]]; then
+  STD="c++11 c++14 c++17 c++20"
 fi
 
-if [ -z ${COMPILATION_MODE:-} ]; then
+if [[ -z ${COMPILATION_MODE:-} ]]; then
   COMPILATION_MODE="fastbuild opt"
 fi
 
-if [ -z ${EXCEPTIONS_MODE:-} ]; then
+if [[ -z ${EXCEPTIONS_MODE:-} ]]; then
   EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
 fi
 
-readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-latest:20200106"
+source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
+readonly DOCKER_CONTAINER=${LINUX_GCC_LATEST_CONTAINER}
 
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
-if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
-  DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
   # Bazel doesn't track changes to tools outside of the workspace
   # (e.g. /usr/bin/gcc), so by appending the docker container to the
   # remote_http_cache url, we make changes to the container part of
@@ -50,12 +51,20 @@
   BAZEL_EXTRA_ARGS="--remote_http_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}"
 fi
 
+# Avoid depending on external sites like GitHub by checking --distdir for
+# external dependencies first.
+# https://docs.bazel.build/versions/master/guide.html#distdir
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
+  BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
+fi
+
 for std in ${STD}; do
   for compilation_mode in ${COMPILATION_MODE}; do
     for exceptions_mode in ${EXCEPTIONS_MODE}; do
       echo "--------------------------------------------------------------------"
       time docker run \
-        --volume="${ABSEIL_ROOT}:/abseil-cpp-ro:ro" \
+        --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp-ro,readonly \
         --tmpfs=/abseil-cpp \
         --workdir=/abseil-cpp \
         --cap-add=SYS_PTRACE \
diff --git a/ci/linux_gcc-latest_libstdcxx_cmake.sh b/ci/linux_gcc-latest_libstdcxx_cmake.sh
index 38ad99f..ab06aa0 100755
--- a/ci/linux_gcc-latest_libstdcxx_cmake.sh
+++ b/ci/linux_gcc-latest_libstdcxx_cmake.sh
@@ -14,48 +14,52 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# TODO(absl-team): This script isn't fully hermetic because
-# -DABSL_USE_GOOGLETEST_HEAD=ON means that this script isn't pinned to a fixed
-# version of GoogleTest. This means that an upstream change to GoogleTest could
-# break this test. Fix this by allowing this script to pin to a known-good
-# version of GoogleTest.
-
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
-if [ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]; then
-  ABSL_CMAKE_CXX_STANDARDS="11 14 17"
+source "${ABSEIL_ROOT}/ci/cmake_common.sh"
+
+if [[ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]]; then
+  ABSL_CMAKE_CXX_STANDARDS="11 14 17 20"
 fi
 
-if [ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]; then
+if [[ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]]; then
   ABSL_CMAKE_BUILD_TYPES="Debug Release"
 fi
 
+if [[ -z ${ABSL_CMAKE_BUILD_SHARED:-} ]]; then
+  ABSL_CMAKE_BUILD_SHARED="OFF ON"
+fi
+
+source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
+readonly DOCKER_CONTAINER=${LINUX_GCC_LATEST_CONTAINER}
+
 for std in ${ABSL_CMAKE_CXX_STANDARDS}; do
   for compilation_mode in ${ABSL_CMAKE_BUILD_TYPES}; do
-    echo "--------------------------------------------------------------------"
-    echo "Testing with CMAKE_BUILD_TYPE=${compilation_mode} and -std=c++${std}"
-
-    time docker run \
-      --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
-      --workdir=/abseil-cpp \
-      --tmpfs=/buildfs:exec \
-      --cap-add=SYS_PTRACE \
-      --rm \
-      -e CFLAGS="-Werror" \
-      -e CXXFLAGS="-Werror" \
-      gcr.io/google.com/absl-177019/linux_gcc-latest:20200106 \
-      /bin/bash -c "
-        cd /buildfs && \
-        cmake /abseil-cpp \
-          -DABSL_USE_GOOGLETEST_HEAD=ON \
-          -DABSL_RUN_TESTS=ON \
-          -DCMAKE_BUILD_TYPE=${compilation_mode} \
-          -DCMAKE_CXX_STANDARD=${std} && \
-        make -j$(nproc) && \
-        ctest -j$(nproc) --output-on-failure"
+    for build_shared in ${ABSL_CMAKE_BUILD_SHARED}; do
+      time docker run \
+        --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
+        --tmpfs=/buildfs:exec \
+        --workdir=/buildfs \
+        --cap-add=SYS_PTRACE \
+        --rm \
+        -e CFLAGS="-Werror" \
+        -e CXXFLAGS="-Werror" \
+        ${DOCKER_EXTRA_ARGS:-} \
+        "${DOCKER_CONTAINER}" \
+        /bin/bash -c "
+          cmake /abseil-cpp \
+            -DABSL_GOOGLETEST_DOWNLOAD_URL=${ABSL_GOOGLETEST_DOWNLOAD_URL} \
+            -DBUILD_SHARED_LIBS=${build_shared} \
+            -DBUILD_TESTING=ON \
+            -DCMAKE_BUILD_TYPE=${compilation_mode} \
+            -DCMAKE_CXX_STANDARD=${std} \
+            -DCMAKE_MODULE_LINKER_FLAGS=\"-Wl,--no-undefined\" && \
+          make -j$(nproc) && \
+          ctest -j$(nproc) --output-on-failure"
+    done
   done
 done
diff --git a/ci/linux_gcc_alpine_cmake.sh b/ci/linux_gcc_alpine_cmake.sh
index 830a136..bce27d2 100755
--- a/ci/linux_gcc_alpine_cmake.sh
+++ b/ci/linux_gcc_alpine_cmake.sh
@@ -14,50 +14,51 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# TODO(absl-team): This script isn't fully hermetic because
-# -DABSL_USE_GOOGLETEST_HEAD=ON means that this script isn't pinned to a fixed
-# version of GoogleTest. This means that an upstream change to GoogleTest could
-# break this test. Fix this by allowing this script to pin to a known-good
-# version of GoogleTest.
-
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
-if [ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]; then
+source "${ABSEIL_ROOT}/ci/cmake_common.sh"
+
+if [[ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]]; then
   ABSL_CMAKE_CXX_STANDARDS="11 14 17"
 fi
 
-if [ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]; then
+if [[ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]]; then
   ABSL_CMAKE_BUILD_TYPES="Debug Release"
 fi
 
-readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/alpine:20191016"
+if [[ -z ${ABSL_CMAKE_BUILD_SHARED:-} ]]; then
+  ABSL_CMAKE_BUILD_SHARED="OFF ON"
+fi
+
+source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
+readonly DOCKER_CONTAINER=${LINUX_ALPINE_CONTAINER}
 
 for std in ${ABSL_CMAKE_CXX_STANDARDS}; do
   for compilation_mode in ${ABSL_CMAKE_BUILD_TYPES}; do
-    echo "--------------------------------------------------------------------"
-    echo "Testing with CMAKE_BUILD_TYPE=${compilation_mode} and -std=c++${std}"
-
-    time docker run \
-      --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
-      --workdir=/abseil-cpp \
-      --tmpfs=/buildfs:exec \
-      --cap-add=SYS_PTRACE \
-      --rm \
-      -e CFLAGS="-Werror" \
-      -e CXXFLAGS="-Werror" \
-      "${DOCKER_CONTAINER}" \
-      /bin/sh -c "
-        cd /buildfs && \
-        cmake /abseil-cpp \
-          -DABSL_USE_GOOGLETEST_HEAD=ON \
-          -DABSL_RUN_TESTS=ON \
-          -DCMAKE_BUILD_TYPE=${compilation_mode} \
-          -DCMAKE_CXX_STANDARD=${std} && \
-        make -j$(nproc) && \
-        ctest -j$(nproc) --output-on-failure"
+    for build_shared in ${ABSL_CMAKE_BUILD_SHARED}; do
+      time docker run \
+        --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
+        --tmpfs=/buildfs:exec \
+        --workdir=/buildfs \
+        --cap-add=SYS_PTRACE \
+        --rm \
+        -e CFLAGS="-Werror" \
+        -e CXXFLAGS="-Werror" \
+        ${DOCKER_EXTRA_ARGS:-} \
+        "${DOCKER_CONTAINER}" \
+        /bin/sh -c "
+          cmake /abseil-cpp \
+            -DABSL_GOOGLETEST_DOWNLOAD_URL=${ABSL_GOOGLETEST_DOWNLOAD_URL} \
+            -DBUILD_TESTING=ON \
+            -DCMAKE_BUILD_TYPE=${compilation_mode} \
+            -DCMAKE_CXX_STANDARD=${std} \
+            -DCMAKE_MODULE_LINKER_FLAGS=\"-Wl,--no-undefined\" && \
+          make -j$(nproc) && \
+          ctest -j$(nproc) --output-on-failure"
+    done
   done
 done
diff --git a/ci/macos_xcode_bazel.sh b/ci/macos_xcode_bazel.sh
index f5f2d75..738adf9 100755
--- a/ci/macos_xcode_bazel.sh
+++ b/ci/macos_xcode_bazel.sh
@@ -19,13 +19,13 @@
 
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
 # If we are running on Kokoro, check for a versioned Bazel binary.
 KOKORO_GFILE_BAZEL_BIN="bazel-2.0.0-darwin-x86_64"
-if [ ${KOKORO_GFILE_DIR:-} ] && [ -f ${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN} ]; then
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f ${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN} ]]; then
   BAZEL_BIN="${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN}"
   chmod +x ${BAZEL_BIN}
 else
@@ -41,7 +41,7 @@
 
 cd ${ABSEIL_ROOT}
 
-if [ -n "${ALTERNATE_OPTIONS:-}" ]; then
+if [[ -n "${ALTERNATE_OPTIONS:-}" ]]; then
   cp ${ALTERNATE_OPTIONS:-} absl/base/options.h || exit 1
 fi
 
diff --git a/ci/macos_xcode_cmake.sh b/ci/macos_xcode_cmake.sh
index a1f4a85..2a870cf 100755
--- a/ci/macos_xcode_cmake.sh
+++ b/ci/macos_xcode_cmake.sh
@@ -14,31 +14,43 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# This script is invoked on Kokoro to test Abseil on macOS.
-# It is not hermetic and may break when Kokoro is updated.
-
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(dirname ${0})/.."
 fi
 ABSEIL_ROOT=$(realpath ${ABSEIL_ROOT})
 
-if [ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]; then
+source "${ABSEIL_ROOT}/ci/cmake_common.sh"
+
+# The MacOS build doesn't run in a docker container, so we have to override ABSL_GOOGLETEST_DOWNLOAD_URL.
+if [[ -r "${KOKORO_GFILE_DIR}/distdir/${ABSL_GOOGLETEST_COMMIT}.zip" ]]; then
+  ABSL_GOOGLETEST_DOWNLOAD_URL="file://${KOKORO_GFILE_DIR}/distdir/${ABSL_GOOGLETEST_COMMIT}.zip"
+fi
+
+if [[ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]]; then
   ABSL_CMAKE_BUILD_TYPES="Debug"
 fi
 
-for compilation_mode in ${ABSL_CMAKE_BUILD_TYPES}; do
-  BUILD_DIR=$(mktemp -d ${compilation_mode}.XXXXXXXX)
-  cd ${BUILD_DIR}
+if [[ -z ${ABSL_CMAKE_BUILD_SHARED:-} ]]; then
+  ABSL_CMAKE_BUILD_SHARED="OFF ON"
+fi
 
-  # TODO(absl-team): Enable -Werror once all warnings are fixed.
-  time cmake ${ABSEIL_ROOT} \
-    -GXcode \
-    -DCMAKE_BUILD_TYPE=${compilation_mode} \
-    -DCMAKE_CXX_STANDARD=11 \
-    -DABSL_USE_GOOGLETEST_HEAD=ON \
-    -DABSL_RUN_TESTS=ON
-  time cmake --build .
-  time ctest -C ${compilation_mode} --output-on-failure
+for compilation_mode in ${ABSL_CMAKE_BUILD_TYPES}; do
+  for build_shared in ${ABSL_CMAKE_BUILD_SHARED}; do
+    BUILD_DIR=$(mktemp -d ${compilation_mode}.XXXXXXXX)
+    cd ${BUILD_DIR}
+
+    # TODO(absl-team): Enable -Werror once all warnings are fixed.
+    time cmake ${ABSEIL_ROOT} \
+      -GXcode \
+      -DBUILD_SHARED_LIBS=${build_shared} \
+      -DBUILD_TESTING=ON \
+      -DCMAKE_BUILD_TYPE=${compilation_mode} \
+      -DCMAKE_CXX_STANDARD=11 \
+      -DCMAKE_MODULE_LINKER_FLAGS="-Wl,--no-undefined" \
+      -DABSL_GOOGLETEST_DOWNLOAD_URL="${ABSL_GOOGLETEST_DOWNLOAD_URL}"
+    time cmake --build .
+    time ctest -C ${compilation_mode} --output-on-failure
+  done
 done
diff --git a/conanfile.py b/conanfile.py
old mode 100644
new mode 100755
diff --git a/create_lts.py b/create_lts.py
new file mode 100755
index 0000000..a98c76b
--- /dev/null
+++ b/create_lts.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+#
+# Copyright 2021 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.
+"""A script to do source transformations to create a new LTS release.
+
+   Usage: ./create_lts.py YYYYMMDD
+"""
+
+import sys
+
+
+def ReplaceStringsInFile(filename, replacement_dict):
+  """Performs textual replacements in a file.
+
+  Rewrites filename with the keys in replacement_dict replaced with
+  their values. This function assumes the file can fit in memory.
+
+  Args:
+    filename: the filename to perform the replacement on
+    replacement_dict: a dictionary of key strings to be replaced with their
+      values
+
+  Raises:
+    Exception: A failure occured
+  """
+  f = open(filename, 'r')
+  content = f.read()
+  f.close()
+
+  for key, value in replacement_dict.items():
+    original = content
+    content = content.replace(key, value)
+    if content == original:
+      raise Exception('Failed to find {} in {}'.format(key, filename))
+
+  f = open(filename, 'w')
+  f.write(content)
+  f.close()
+
+
+def StripContentBetweenTags(filename, strip_begin_tag, strip_end_tag):
+  """Strip contents from a file.
+
+  Rewrites filename with by removing all content between
+  strip_begin_tag and strip_end_tag, including the tags themselves.
+
+  Args:
+    filename: the filename to perform the replacement on
+    strip_begin_tag: the start of the content to be removed
+    strip_end_tag: the end of the content to be removed
+
+  Raises:
+    Exception: A failure occured
+  """
+  f = open(filename, 'r')
+  content = f.read()
+  f.close()
+
+  while True:
+    begin = content.find(strip_begin_tag)
+    if begin == -1:
+      break
+    end = content.find(strip_end_tag, begin + len(strip_begin_tag))
+    if end == -1:
+      raise Exception('{}: imbalanced strip begin ({}) and '
+                      'end ({}) tags'.format(filename, strip_begin_tag,
+                                             strip_end_tag))
+    content = content.replace(content[begin:end + len(strip_end_tag)], '')
+
+  f = open(filename, 'w')
+  f.write(content)
+  f.close()
+
+
+def main(argv):
+  if len(argv) != 2:
+    print('Usage: {} YYYYMMDD'.format(sys.argv[0], file=sys.stderr))
+    sys.exit(1)
+
+  datestamp = sys.argv[1]
+  if len(datestamp) != 8 or not datestamp.isdigit():
+    raise Exception(
+        'datestamp={} is not in the YYYYMMDD format'.format(datestamp))
+
+  # Replacement directives go here.
+  ReplaceStringsInFile(
+      'absl/base/options.h', {
+          '#define ABSL_OPTION_USE_INLINE_NAMESPACE 0':
+              '#define ABSL_OPTION_USE_INLINE_NAMESPACE 1',
+          '#define ABSL_OPTION_INLINE_NAMESPACE_NAME head':
+              '#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_{}'.format(
+                  datestamp)
+      })
+  ReplaceStringsInFile(
+      'CMakeLists.txt', {
+          'project(absl LANGUAGES CXX)':
+              'project(absl LANGUAGES CXX VERSION {})'.format(datestamp)
+      })
+  # Set the SOVERSION to YYYYMMDD.0.0 - The first 0 means we only have
+  # ABI compatible changes, and the second 0 means we can increment it
+  # to mark changes as ABI-compatible, for patch releases.
+  ReplaceStringsInFile('CMake/AbseilHelpers.cmake',
+                       {'SOVERSION 0': 'SOVERSION "{}.0.0"'.format(datestamp)})
+  StripContentBetweenTags('CMakeLists.txt', '# absl:lts-remove-begin',
+                          '# absl:lts-remove-end')
+
+
+if __name__ == '__main__':
+  main(sys.argv)