diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake
index 90c9f1f..7646c15 100644
--- a/CMake/AbseilDll.cmake
+++ b/CMake/AbseilDll.cmake
@@ -19,6 +19,7 @@
   "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"
@@ -128,7 +131,6 @@
   "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"
diff --git a/CMake/Googletest/DownloadGTest.cmake b/CMake/Googletest/DownloadGTest.cmake
index 6552e1d..9d071c9 100644
--- a/CMake/Googletest/DownloadGTest.cmake
+++ b/CMake/Googletest/DownloadGTest.cmake
@@ -38,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/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index bae7942..1af9e45 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -307,6 +307,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":errno_saver",
+        ":strerror",
         "@com_google_googletest//:gtest_main",
     ],
 )
@@ -451,6 +452,7 @@
     testonly = 1,
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
+    tags = ["benchmark"],
     visibility = ["//visibility:private"],
     deps = [
         ":spinlock_benchmark_common",
@@ -705,3 +707,71 @@
         "@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",
+    ],
+)
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index 14c52ea..5454992 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -326,6 +326,7 @@
     ${ABSL_TEST_COPTS}
   DEPS
     absl::errno_saver
+    absl::strerror
     gmock
     gtest_main
 )
@@ -642,3 +643,59 @@
     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
+)
diff --git a/absl/base/config.h b/absl/base/config.h
index ee99f94..f54466d 100644
--- a/absl/base/config.h
+++ b/absl/base/config.h
@@ -262,13 +262,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
diff --git a/absl/base/internal/bits.h b/absl/base/internal/bits.h
index 8b03453..14c51d8 100644
--- a/absl/base/internal/bits.h
+++ b/absl/base/internal/bits.h
@@ -24,7 +24,7 @@
 
 // Clang on Windows has __builtin_clzll; otherwise we need to use the
 // windows intrinsic functions.
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && !defined(__clang__)
 #include <intrin.h>
 #if defined(_M_X64)
 #pragma intrinsic(_BitScanReverse64)
@@ -36,7 +36,7 @@
 
 #include "absl/base/attributes.h"
 
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && !defined(__clang__)
 // 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.
@@ -73,14 +73,14 @@
 }
 
 ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) {
-#if defined(_MSC_VER) && defined(_M_X64)
+#if defined(_MSC_VER) && !defined(__clang__) && 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)
+#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 ((n >> 32) && _BitScanReverse(&result, n >> 32)) {
@@ -90,7 +90,7 @@
     return 63 - result;
   }
   return 64;
-#elif defined(__GNUC__)
+#elif defined(__GNUC__) || defined(__clang__)
   // Use __builtin_clzll, which uses the following instructions:
   //  x86: bsr
   //  ARM64: clz
@@ -126,13 +126,13 @@
 }
 
 ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32(uint32_t n) {
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && !defined(__clang__)
   unsigned long result = 0;  // NOLINT(runtime/int)
   if (_BitScanReverse(&result, n)) {
     return 31 - result;
   }
   return 32;
-#elif defined(__GNUC__)
+#elif defined(__GNUC__) || defined(__clang__)
   // Use __builtin_clz, which uses the following instructions:
   //  x86: bsr
   //  ARM64: clz
@@ -163,11 +163,11 @@
 }
 
 ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64(uint64_t n) {
-#if defined(_MSC_VER) && defined(_M_X64)
+#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_X64)
   unsigned long result = 0;  // NOLINT(runtime/int)
   _BitScanForward64(&result, n);
   return result;
-#elif defined(_MSC_VER)
+#elif defined(_MSC_VER) && !defined(__clang__)
   unsigned long result = 0;  // NOLINT(runtime/int)
   if (static_cast<uint32_t>(n) == 0) {
     _BitScanForward(&result, n >> 32);
@@ -175,7 +175,7 @@
   }
   _BitScanForward(&result, n);
   return result;
-#elif defined(__GNUC__)
+#elif defined(__GNUC__) || defined(__clang__)
   static_assert(sizeof(unsigned long long) == sizeof(n),  // NOLINT(runtime/int)
                 "__builtin_ctzll does not take 64-bit arg");
   return __builtin_ctzll(n);
@@ -196,11 +196,11 @@
 }
 
 ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32(uint32_t n) {
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && !defined(__clang__)
   unsigned long result = 0;  // NOLINT(runtime/int)
   _BitScanForward(&result, n);
   return result;
-#elif defined(__GNUC__)
+#elif defined(__GNUC__) || defined(__clang__)
   static_assert(sizeof(int) == sizeof(n),
                 "__builtin_ctz does not take 32-bit arg");
   return __builtin_ctz(n);
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/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/spinlock.cc b/absl/base/internal/spinlock.cc
index 830d472..fd0c733 100644
--- a/absl/base/internal/spinlock.cc
+++ b/absl/base/internal/spinlock.cc
@@ -190,30 +190,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 +226,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..89e93aa 100644
--- a/absl/base/internal/spinlock.h
+++ b/absl/base/internal/spinlock.h
@@ -148,12 +148,13 @@
   // bit[1] encodes whether a lock uses cooperative scheduling.
   // bit[2] encodes whether a lock disables scheduling.
   // 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) };
+  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(
diff --git a/absl/base/internal/strerror.cc b/absl/base/internal/strerror.cc
new file mode 100644
index 0000000..af18151
--- /dev/null
+++ b/absl/base/internal/strerror.cc
@@ -0,0 +1,75 @@
+// 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 <cerrno>
+#include <cstddef>
+#include <cstdio>
+#include <cstring>
+#include <string>
+#include <type_traits>
+
+#include "absl/base/attributes.h"
+#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
+#if defined(__GLIBC__) || defined(__APPLE__)
+  // Use the BSD sys_errlist API provided by GNU glibc and others to
+  // avoid any need to copy the message into the local buffer first.
+  if (0 <= errnum && errnum < sys_nerr) {
+    if (const char* p = sys_errlist[errnum]) {
+      return p;
+    }
+  }
+#endif
+  // 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
+}
+}  // namespace
+
+std::string StrError(int errnum) {
+  absl::base_internal::ErrnoSaver errno_saver;
+  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;
+}
+
+}  // 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/base/internal/strerror_benchmark.cc b/absl/base/internal/strerror_benchmark.cc
new file mode 100644
index 0000000..d8ca86b
--- /dev/null
+++ b/absl/base/internal/strerror_benchmark.cc
@@ -0,0 +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 <cerrno>
+#include <cstdio>
+#include <string>
+
+#include "absl/base/internal/strerror.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+#if defined(__GLIBC__) || defined(__APPLE__)
+void BM_SysErrList(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(std::string(sys_errlist[ERANGE]));
+  }
+}
+BENCHMARK(BM_SysErrList);
+#endif
+
+void BM_AbslStrError(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(absl::base_internal::StrError(ERANGE));
+  }
+}
+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..a53da97
--- /dev/null
+++ b/absl/base/internal/strerror_test.cc
@@ -0,0 +1,86 @@
+// 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);
+      // 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(absl::base_internal::StrError(i), Eq(expected_strings[i]));
+      }
+      EXPECT_THAT(errno, Eq(ERANGE));
+    }
+  };
+
+  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/macros.h b/absl/base/macros.h
index 547f93b..2c4e357 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"
 
@@ -207,6 +208,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 (...)
diff --git a/absl/base/options.h b/absl/base/options.h
index 234137c..230bf1e 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
@@ -208,4 +208,31 @@
 #define ABSL_OPTION_USE_INLINE_NAMESPACE 0
 #define ABSL_OPTION_INLINE_NAMESPACE_NAME head
 
+// 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/container/BUILD.bazel b/absl/container/BUILD.bazel
index 7098564..1b0710b 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",
@@ -74,6 +74,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":fixed_array",
+        "//absl/base:config",
         "//absl/base:exception_testing",
         "//absl/hash:hash_testing",
         "//absl/memory",
@@ -153,6 +154,7 @@
         ":counting_allocator",
         ":inlined_vector",
         ":test_instance_tracker",
+        "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:exception_testing",
         "//absl/base:raw_logging_internal",
@@ -364,6 +366,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         "//absl/memory",
+        "//absl/meta:type_traits",
         "//absl/utility",
     ],
 )
@@ -376,6 +379,7 @@
     tags = NOTEST_TAGS_NONMOBILE,
     deps = [
         ":container_memory",
+        ":test_instance_tracker",
         "//absl/strings",
         "@com_google_googletest//:gtest_main",
     ],
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt
index 99a8e9c..d79fa12 100644
--- a/absl/container/CMakeLists.txt
+++ b/absl/container/CMakeLists.txt
@@ -147,6 +147,7 @@
     ${ABSL_TEST_COPTS}
   DEPS
     absl::fixed_array
+    absl::config
     absl::exception_testing
     absl::hash_testing
     absl::memory
@@ -221,6 +222,7 @@
     absl::counting_allocator
     absl::inlined_vector
     absl::test_instance_tracker
+    absl::config
     absl::core_headers
     absl::exception_testing
     absl::hash_testing
@@ -419,6 +421,7 @@
     ${ABSL_DEFAULT_COPTS}
   DEPS
     absl::memory
+    absl::type_traits
     absl::utility
   PUBLIC
 )
@@ -433,6 +436,7 @@
   DEPS
     absl::container_memory
     absl::strings
+    absl::test_instance_tracker
     gmock_main
 )
 
diff --git a/absl/container/btree_benchmark.cc b/absl/container/btree_benchmark.cc
index ca4d575..4679867 100644
--- a/absl/container/btree_benchmark.cc
+++ b/absl/container/btree_benchmark.cc
@@ -134,6 +134,27 @@
   }
 }
 
+// Benchmark inserting the first few elements in a container. In b-tree, this is
+// when the root node grows.
+template <typename T>
+void BM_InsertSmall(benchmark::State& state) {
+  using V = typename remove_pair_const<typename T::value_type>::type;
+
+  const int kSize = 8;
+  std::vector<V> values = GenerateValues<V>(kSize);
+  T container;
+
+  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();
+  }
+}
+
 template <typename T>
 void BM_LookupImpl(benchmark::State& state, bool sorted) {
   using V = typename remove_pair_const<typename T::value_type>::type;
@@ -493,6 +514,7 @@
   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);            \
diff --git a/absl/container/fixed_array.h b/absl/container/fixed_array.h
index a9ce99b..796dd62 100644
--- a/absl/container/fixed_array.h
+++ b/absl/container/fixed_array.h
@@ -217,7 +217,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,7 +225,7 @@
   // 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];
   }
 
@@ -252,20 +252,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()
   //
diff --git a/absl/container/fixed_array_test.cc b/absl/container/fixed_array_test.cc
index c960fe5..9b1c224 100644
--- a/absl/container/fixed_array_test.cc
+++ b/absl/container/fixed_array_test.cc
@@ -28,6 +28,7 @@
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "absl/base/internal/exception_testing.h"
+#include "absl/base/options.h"
 #include "absl/hash/hash_testing.h"
 #include "absl/memory/memory.h"
 
@@ -188,6 +189,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);
diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h
index 2388d47..5f6f615 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"
@@ -307,16 +308,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 +330,6 @@
       base_internal::ThrowStdOutOfRange(
           "`InlinedVector::at(size_type)` failed bounds check");
     }
-
     return data()[i];
   }
 
@@ -345,7 +343,6 @@
       base_internal::ThrowStdOutOfRange(
           "`InlinedVector::at(size_type) const` failed bounds check");
     }
-
     return data()[i];
   }
 
@@ -353,16 +350,14 @@
   //
   // Returns a `reference` to the first element of the inlined vector.
   reference front() {
-    assert(!empty());
-
+    ABSL_HARDENING_ASSERT(!empty());
     return at(0);
   }
 
   // Overload of `InlinedVector::front()` that returns a `const_reference` to
   // the first element of the inlined vector.
   const_reference front() const {
-    assert(!empty());
-
+    ABSL_HARDENING_ASSERT(!empty());
     return at(0);
   }
 
@@ -370,16 +365,14 @@
   //
   // Returns a `reference` to the last element of the inlined vector.
   reference back() {
-    assert(!empty());
-
+    ABSL_HARDENING_ASSERT(!empty());
     return at(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());
-
+    ABSL_HARDENING_ASSERT(!empty());
     return at(size() - 1);
   }
 
@@ -573,8 +566,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 +593,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 +612,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 +629,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 +663,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 +676,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 +688,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_test.cc b/absl/container/inlined_vector_test.cc
index 5965eac..415c60d 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.
diff --git a/absl/container/internal/btree.h b/absl/container/internal/btree.h
index d986f81..4504e9c 100644
--- a/absl/container/internal/btree.h
+++ b/absl/container/internal/btree.h
@@ -776,9 +776,6 @@
   // delimiting key in the parent node onto itself.
   void merge(btree_node *src, allocator_type *alloc);
 
-  // Swaps the contents of `this` and `other`.
-  void swap(btree_node *other, allocator_type *alloc);
-
   // Node allocation/deletion routines.
   void init_leaf(btree_node *parent, int max_count) {
     set_parent(parent);
@@ -820,6 +817,14 @@
     absl::container_internal::SanitizerPoisonObject(slot(i));
   }
 
+  // Transfers value from slot `src_i` in `src` to slot `dest_i` in `this`.
+  void transfer(const size_type dest_i, const size_type src_i, btree_node *src,
+                allocator_type *alloc) {
+    absl::container_internal::SanitizerUnpoisonObject(slot(dest_i));
+    params_type::transfer(alloc, slot(dest_i), src->slot(src_i));
+    absl::container_internal::SanitizerPoisonObject(src->slot(src_i));
+  }
+
   // Move n values starting at value i in this node into the values starting at
   // value j in dest_node.
   void uninitialized_move_n(const size_type n, const size_type i,
@@ -932,8 +937,13 @@
   }
 
   // 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();
@@ -1752,54 +1762,6 @@
   parent()->remove_value(position(), alloc);
 }
 
-template <typename P>
-void btree_node<P>::swap(btree_node *other, allocator_type *alloc) {
-  using std::swap;
-  assert(leaf() == other->leaf());
-
-  // Determine which is the smaller/larger node.
-  btree_node *smaller = this, *larger = other;
-  if (smaller->count() > larger->count()) {
-    swap(smaller, larger);
-  }
-
-  // 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);
-  }
-
-  // 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(), other->mutable_finish());
-}
-
 ////
 // btree_iterator methods
 template <typename N, typename R, typename P>
@@ -1812,6 +1774,7 @@
       position = node->position();
       node = node->parent();
     }
+    // TODO(ezb): assert we aren't incrementing end() instead of handling.
     if (position == node->finish()) {
       *this = save;
     }
@@ -1835,6 +1798,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;
     }
@@ -2492,6 +2456,7 @@
     ++iter.position;
   }
   const int 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) {
@@ -2500,15 +2465,21 @@
       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() = rightmost_ = iter.node;
+      // Transfer the values from the old root to the new root.
+      node_type *old_root = root();
+      node_type *new_root = iter.node;
+      for (int i = old_root->start(), f = old_root->finish(); i < f; ++i) {
+        new_root->transfer(i, i, old_root, alloc);
+      }
+      new_root->set_finish(old_root->finish());
+      old_root->set_finish(old_root->start());
+      delete_leaf_node(old_root);
+      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;
 }
diff --git a/absl/container/internal/common.h b/absl/container/internal/common.h
index 5037d80..8990f29 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,7 +146,7 @@
 
   constexpr node_handle() {}
 
-  auto key() const -> decltype(PolicyTraits::key(this->slot())) {
+  auto key() const -> decltype(PolicyTraits::key(std::declval<slot_type*>())) {
     return PolicyTraits::key(this->slot());
   }
 
diff --git a/absl/container/internal/container_memory.h b/absl/container/internal/container_memory.h
index d24b0f8..3487ac1 100644
--- a/absl/container/internal/container_memory.h
+++ b/absl/container/internal/container_memory.h
@@ -31,12 +31,16 @@
 #include <utility>
 
 #include "absl/memory/memory.h"
+#include "absl/meta/type_traits.h"
 #include "absl/utility/utility.h"
 
 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,7 +52,7 @@
 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);
@@ -64,7 +68,7 @@
 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);
@@ -316,11 +320,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>
diff --git a/absl/container/internal/container_memory_test.cc b/absl/container/internal/container_memory_test.cc
index 7942c7b..6a7fcd2 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>;
 
@@ -184,6 +225,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/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index fb47f62..e47e1fe 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -104,6 +104,7 @@
 
 #include "absl/base/internal/bits.h"
 #include "absl/base/internal/endian.h"
+#include "absl/base/macros.h"
 #include "absl/base/port.h"
 #include "absl/container/internal/common.h"
 #include "absl/container/internal/compressed_tuple.h"
@@ -651,9 +652,9 @@
     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_full() const { ABSL_HARDENING_ASSERT(IsFull(*ctrl_)); }
     void assert_is_valid() const {
-      assert(!ctrl_ || IsFull(*ctrl_) || *ctrl_ == kSentinel);
+      ABSL_HARDENING_ASSERT(!ctrl_ || IsFull(*ctrl_) || *ctrl_ == kSentinel);
     }
 
     void skip_empty_or_deleted() {
diff --git a/absl/copts/AbseilConfigureCopts.cmake b/absl/copts/AbseilConfigureCopts.cmake
index 390a07a..9557e36 100644
--- a/absl/copts/AbseilConfigureCopts.cmake
+++ b/absl/copts/AbseilConfigureCopts.cmake
@@ -63,3 +63,5 @@
   set(ABSL_DEFAULT_COPTS "")
   set(ABSL_TEST_COPTS "")
 endif()
+
+set(ABSL_CXX_STANDARD "${CMAKE_CXX_STANDARD}")
diff --git a/absl/copts/configure_copts.bzl b/absl/copts/configure_copts.bzl
index 9dd6bd0..ff9a5ea 100644
--- a/absl/copts/configure_copts.bzl
+++ b/absl/copts/configure_copts.bzl
@@ -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/debugging/internal/stacktrace_aarch64-inl.inc b/absl/debugging/internal/stacktrace_aarch64-inl.inc
index 411ea30..14a76f1 100644
--- a/absl/debugging/internal/stacktrace_aarch64-inl.inc
+++ b/absl/debugging/internal/stacktrace_aarch64-inl.inc
@@ -74,6 +74,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 +125,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/flags/BUILD.bazel b/absl/flags/BUILD.bazel
index 9166f74..4b51d9d 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",
@@ -147,6 +147,7 @@
         ":marshalling",
         "//absl/base:config",
         "//absl/base:core_headers",
+        "//absl/base:fast_type_id",
         "//absl/strings",
         "//absl/types:optional",
     ],
diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt
index 01cf09b..2204b0f 100644
--- a/absl/flags/CMakeLists.txt
+++ b/absl/flags/CMakeLists.txt
@@ -128,6 +128,7 @@
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
     absl::config
+    absl::fast_type_id
     absl::flags_config
     absl::flags_marshalling
     absl::core_headers
diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc
index 1e01b49..377e3b2 100644
--- a/absl/flags/flag_test.cc
+++ b/absl/flags/flag_test.cc
@@ -91,30 +91,30 @@
 };
 
 TEST_F(FlagTest, Traits) {
-  EXPECT_EQ(flags::FlagValue::Kind<int>(),
+  EXPECT_EQ(flags::StorageKind<int>(),
             flags::FlagValueStorageKind::kOneWordAtomic);
-  EXPECT_EQ(flags::FlagValue::Kind<bool>(),
+  EXPECT_EQ(flags::StorageKind<bool>(),
             flags::FlagValueStorageKind::kOneWordAtomic);
-  EXPECT_EQ(flags::FlagValue::Kind<double>(),
+  EXPECT_EQ(flags::StorageKind<double>(),
             flags::FlagValueStorageKind::kOneWordAtomic);
-  EXPECT_EQ(flags::FlagValue::Kind<int64_t>(),
+  EXPECT_EQ(flags::StorageKind<int64_t>(),
             flags::FlagValueStorageKind::kOneWordAtomic);
 
 #if defined(ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD)
-  EXPECT_EQ(flags::FlagValue::Kind<S1>(),
+  EXPECT_EQ(flags::StorageKind<S1>(),
             flags::FlagValueStorageKind::kTwoWordsAtomic);
-  EXPECT_EQ(flags::FlagValue::Kind<S2>(),
+  EXPECT_EQ(flags::StorageKind<S2>(),
             flags::FlagValueStorageKind::kTwoWordsAtomic);
 #else
-  EXPECT_EQ(flags::FlagValue::Kind<S1>(),
+  EXPECT_EQ(flags::StorageKind<S1>(),
             flags::FlagValueStorageKind::kHeapAllocated);
-  EXPECT_EQ(flags::FlagValue::Kind<S2>(),
+  EXPECT_EQ(flags::StorageKind<S2>(),
             flags::FlagValueStorageKind::kHeapAllocated);
 #endif
 
-  EXPECT_EQ(flags::FlagValue::Kind<std::string>(),
+  EXPECT_EQ(flags::StorageKind<std::string>(),
             flags::FlagValueStorageKind::kHeapAllocated);
-  EXPECT_EQ(flags::FlagValue::Kind<std::vector<std::string>>(),
+  EXPECT_EQ(flags::StorageKind<std::vector<std::string>>(),
             flags::FlagValueStorageKind::kHeapAllocated);
 }
 
@@ -293,6 +293,18 @@
 // --------------------------------------------------------------------
 
 TEST_F(FlagTest, TestDefault) {
+  EXPECT_EQ(FLAGS_test_flag_01.DefaultValue(), "true");
+  EXPECT_EQ(FLAGS_test_flag_02.DefaultValue(), "1234");
+  EXPECT_EQ(FLAGS_test_flag_03.DefaultValue(), "-34");
+  EXPECT_EQ(FLAGS_test_flag_04.DefaultValue(), "189");
+  EXPECT_EQ(FLAGS_test_flag_05.DefaultValue(), "10765");
+  EXPECT_EQ(FLAGS_test_flag_06.DefaultValue(), "40000");
+  EXPECT_EQ(FLAGS_test_flag_07.DefaultValue(), "-1234567");
+  EXPECT_EQ(FLAGS_test_flag_08.DefaultValue(), "9876543");
+  EXPECT_EQ(FLAGS_test_flag_09.DefaultValue(), "-9.876e-50");
+  EXPECT_EQ(FLAGS_test_flag_10.DefaultValue(), "1.234e+12");
+  EXPECT_EQ(FLAGS_test_flag_11.DefaultValue(), "");
+
   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);
@@ -308,6 +320,61 @@
 
 // --------------------------------------------------------------------
 
+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(FLAGS_test_flag_eb_01.DefaultValue(), "false");
+  EXPECT_EQ(FLAGS_test_flag_eb_02.DefaultValue(), "0");
+  EXPECT_EQ(FLAGS_test_flag_eb_03.DefaultValue(), "0");
+  EXPECT_EQ(FLAGS_test_flag_eb_04.DefaultValue(), "0");
+  EXPECT_EQ(FLAGS_test_flag_eb_05.DefaultValue(), "");
+  EXPECT_EQ(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{});
+}
+
+// --------------------------------------------------------------------
+
 TEST_F(FlagTest, TestGetSet) {
   absl::SetFlag(&FLAGS_test_flag_01, false);
   EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), false);
@@ -557,10 +624,10 @@
   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"));
diff --git a/absl/flags/internal/commandlineflag.h b/absl/flags/internal/commandlineflag.h
index 9a740d5..ef992f7 100644
--- a/absl/flags/internal/commandlineflag.h
+++ b/absl/flags/internal/commandlineflag.h
@@ -24,6 +24,7 @@
 #include <typeinfo>
 
 #include "absl/base/config.h"
+#include "absl/base/internal/fast_type_id.h"
 #include "absl/base/macros.h"
 #include "absl/flags/config.h"
 #include "absl/flags/marshalling.h"
@@ -34,23 +35,12 @@
 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
+// simialarly 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 = base_internal::FastTypeIdType;
 
 // Options that control SetCommandLineOptionWithMode.
 enum FlagSettingMode {
@@ -65,7 +55,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,
@@ -97,7 +87,7 @@
   // Return true iff flag has type T.
   template <typename T>
   inline bool IsOfType() const {
-    return TypeId() == &flags_internal::FlagStaticTypeIdGen<T>;
+    return TypeId() == base_internal::FastTypeId<T>();
   }
 
   // Attempts to retrieve the flag value. Returns value on success,
@@ -150,7 +140,7 @@
   // Returns true iff this is a handle to an Abseil Flag.
   virtual bool IsAbseilFlag() const;
   // Returns id of the flag's value type.
-  virtual FlagStaticTypeId TypeId() const = 0;
+  virtual FlagFastTypeId TypeId() const = 0;
   virtual bool IsModified() const = 0;
   virtual bool IsSpecifiedOnCommandLine() const = 0;
   virtual std::string DefaultValue() const = 0;
@@ -171,10 +161,10 @@
   //  * 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;
+  virtual bool ParseFrom(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 string and back to the
   // flag's value type.
diff --git a/absl/flags/internal/commandlineflag_test.cc b/absl/flags/internal/commandlineflag_test.cc
index 0e8bc31..c1142b7 100644
--- a/absl/flags/internal/commandlineflag_test.cc
+++ b/absl/flags/internal/commandlineflag_test.cc
@@ -119,99 +119,99 @@
 
 // --------------------------------------------------------------------
 
-TEST_F(CommandLineFlagTest, TestSetFromStringCurrentValue) {
+TEST_F(CommandLineFlagTest, TestParseFromCurrentValue) {
   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_TRUE(flag_01->ParseFrom("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_TRUE(flag_01->ParseFrom("-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_TRUE(!flag_01->ParseFrom("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_TRUE(!flag_01->ParseFrom("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_TRUE(flag_01->ParseFrom("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_TRUE(flag_01->ParseFrom("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_TRUE(!flag_01->ParseFrom("", 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_TRUE(flag_02->ParseFrom("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_TRUE(flag_02->ParseFrom("", flags::SET_FLAGS_VALUE,
+                                 flags::kProgrammaticChange, &err));
   EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "");
 }
 
 // --------------------------------------------------------------------
 
-TEST_F(CommandLineFlagTest, TestSetFromStringDefaultValue) {
+TEST_F(CommandLineFlagTest, TestParseFromDefaultValue) {
   std::string err;
 
   auto* flag_01 = flags::FindCommandLineFlag("int_flag");
 
-  EXPECT_TRUE(flag_01->SetFromString("111", flags::SET_FLAGS_DEFAULT,
-                                     flags::kProgrammaticChange, &err));
+  EXPECT_TRUE(flag_01->ParseFrom("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_TRUE(flag_02->ParseFrom("abc", flags::SET_FLAGS_DEFAULT,
+                                 flags::kProgrammaticChange, &err));
   EXPECT_EQ(flag_02->DefaultValue(), "abc");
 }
 
 // --------------------------------------------------------------------
 
-TEST_F(CommandLineFlagTest, TestSetFromStringIfDefault) {
+TEST_F(CommandLineFlagTest, TestParseFromIfDefault) {
   std::string err;
 
   auto* flag_01 = flags::FindCommandLineFlag("int_flag");
 
-  EXPECT_TRUE(flag_01->SetFromString("22", flags::SET_FLAG_IF_DEFAULT,
-                                     flags::kProgrammaticChange, &err))
+  EXPECT_TRUE(flag_01->ParseFrom("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_TRUE(flag_01->ParseFrom("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->ParseFrom("201", flags::SET_FLAGS_VALUE,
+                                 flags::kProgrammaticChange, &err));
 
-  EXPECT_TRUE(flag_01->SetFromString("33", flags::SET_FLAG_IF_DEFAULT,
-                                     flags::kProgrammaticChange, &err));
+  EXPECT_TRUE(flag_01->ParseFrom("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");
 }
diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc
index a12fe7c..f3c424a 100644
--- a/absl/flags/internal/flag.cc
+++ b/absl/flags/internal/flag.cc
@@ -25,6 +25,7 @@
 #include <vector>
 
 #include "absl/base/attributes.h"
+#include "absl/base/casts.h"
 #include "absl/base/config.h"
 #include "absl/base/const_init.h"
 #include "absl/base/optimization.h"
@@ -47,9 +48,9 @@
 namespace {
 
 // Currently we only validate flag values for user-defined flag types.
-bool ShouldValidateFlagValue(FlagStaticTypeId flag_type_id) {
+bool ShouldValidateFlagValue(FlagFastTypeId flag_type_id) {
 #define DONT_VALIDATE(T) \
-  if (flag_type_id == &FlagStaticTypeIdGen<T>) return false;
+  if (flag_type_id == base_internal::FastTypeId<T>()) return false;
   ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(DONT_VALIDATE)
 #undef DONT_VALIDATE
 
@@ -74,6 +75,59 @@
 
 }  // 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::kHeapAllocated)
+      return;
+    flags_internal::Delete(flag_impl_->op_, value_.dynamic);
+  }
+
+ 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) : dynamic(v) {}
+    explicit SavedValue(int64_t v) : one_word(v) {}
+    explicit SavedValue(flags_internal::AlignedTwoWords v) : two_words(v) {}
+
+    void* dynamic;
+    int64_t one_word;
+    flags_internal::AlignedTwoWords two_words;
+  } value_;
+  bool modified_;
+  bool on_command_line_;
+  int64_t counter_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Flag implementation, which does not depend on flag value type.
+
 void FlagImpl::Init() {
   new (&data_guard_) absl::Mutex;
 
@@ -82,18 +136,18 @@
       (*default_value_.gen_func)(), DynValueDeleter{op_});
   switch (ValueStorageKind()) {
     case FlagValueStorageKind::kHeapAllocated:
-      value_.dynamic = init_value.release();
+      HeapAllocatedValue() = init_value.release();
       break;
     case FlagValueStorageKind::kOneWordAtomic: {
       int64_t atomic_value;
       std::memcpy(&atomic_value, init_value.get(), Sizeof(op_));
-      value_.one_word_atomic.store(atomic_value, std::memory_order_release);
+      OneWordValue().store(atomic_value, std::memory_order_release);
       break;
     }
     case FlagValueStorageKind::kTwoWordsAtomic: {
       AlignedTwoWords atomic_value{0, 0};
       std::memcpy(&atomic_value, init_value.get(), Sizeof(op_));
-      value_.two_words_atomic.store(atomic_value, std::memory_order_release);
+      TwoWordsValue().store(atomic_value, std::memory_order_release);
       break;
     }
   }
@@ -107,24 +161,24 @@
   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(
@@ -145,18 +199,18 @@
 void FlagImpl::StoreValue(const void* src) {
   switch (ValueStorageKind()) {
     case FlagValueStorageKind::kHeapAllocated:
-      Copy(op_, src, value_.dynamic);
+      Copy(op_, src, HeapAllocatedValue());
       break;
     case FlagValueStorageKind::kOneWordAtomic: {
-      int64_t one_word_val;
+      int64_t one_word_val = 0;
       std::memcpy(&one_word_val, src, Sizeof(op_));
-      value_.one_word_atomic.store(one_word_val, std::memory_order_release);
+      OneWordValue().store(one_word_val, std::memory_order_release);
       break;
     }
     case FlagValueStorageKind::kTwoWordsAtomic: {
       AlignedTwoWords two_words_val{0, 0};
       std::memcpy(&two_words_val, src, Sizeof(op_));
-      value_.two_words_atomic.store(two_words_val, std::memory_order_release);
+      TwoWordsValue().store(two_words_val, std::memory_order_release);
       break;
     }
   }
@@ -172,11 +226,17 @@
   return flags_internal::GetUsageConfig().normalize_filename(filename_);
 }
 
+absl::string_view FlagImpl::Typename() const { return ""; }
+
 std::string FlagImpl::Help() const {
   return HelpSourceKind() == FlagHelpKind::kLiteral ? help_.literal
                                                     : help_.gen_func();
 }
 
+FlagFastTypeId FlagImpl::TypeId() const {
+  return flags_internal::FastTypeId(op_);
+}
+
 bool FlagImpl::IsModified() const {
   absl::MutexLock l(DataGuard());
   return modified_;
@@ -195,21 +255,23 @@
 }
 
 std::string FlagImpl::CurrentValue() const {
-  DataGuard();  // Make sure flag initialized
+  auto* guard = DataGuard();  // Make sure flag initialized
   switch (ValueStorageKind()) {
     case FlagValueStorageKind::kHeapAllocated: {
-      absl::MutexLock l(DataGuard());
-      return flags_internal::Unparse(op_, value_.dynamic);
+      absl::MutexLock l(guard);
+      return flags_internal::Unparse(op_, HeapAllocatedValue());
     }
     case FlagValueStorageKind::kOneWordAtomic: {
       const auto one_word_val =
-          value_.one_word_atomic.load(std::memory_order_acquire);
-      return flags_internal::Unparse(op_, &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::kTwoWordsAtomic: {
       const auto two_words_val =
-          value_.two_words_atomic.load(std::memory_order_acquire);
-      return flags_internal::Unparse(op_, &two_words_val);
+          absl::bit_cast<std::array<char, sizeof(AlignedTwoWords)>>(
+              TwoWordsValue().load(std::memory_order_acquire));
+      return flags_internal::Unparse(op_, two_words_val.data());
     }
   }
 
@@ -250,26 +312,78 @@
   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::kHeapAllocated: {
+      return absl::make_unique<FlagState>(
+          this, flags_internal::Clone(op_, HeapAllocatedValue()), modified,
+          on_command_line, counter_);
+    }
+    case FlagValueStorageKind::kOneWordAtomic: {
+      return absl::make_unique<FlagState>(
+          this, OneWordValue().load(std::memory_order_acquire), modified,
+          on_command_line, counter_);
+    }
+    case FlagValueStorageKind::kTwoWordsAtomic: {
+      return absl::make_unique<FlagState>(
+          this, TwoWordsValue().load(std::memory_order_acquire), modified,
+          on_command_line, counter_);
+    }
+  }
+  return nullptr;
+}
+
+bool FlagImpl::RestoreState(const FlagState& flag_state) {
+  absl::MutexLock l(DataGuard());
+
+  if (flag_state.counter_ == counter_) {
+    return false;
   }
 
-  Write(value);
-
-  {
-    absl::MutexLock l(DataGuard());
-
-    modified_ = modified;
-    on_command_line_ = on_command_line;
+  switch (ValueStorageKind()) {
+    case FlagValueStorageKind::kHeapAllocated:
+      StoreValue(flag_state.value_.dynamic);
+      break;
+    case FlagValueStorageKind::kOneWordAtomic:
+      StoreValue(&flag_state.value_.one_word);
+      break;
+    case FlagValueStorageKind::kTwoWordsAtomic:
+      StoreValue(&flag_state.value_.two_words);
+      break;
   }
 
+  modified_ = flag_state.modified_;
+  on_command_line_ = flag_state.on_command_line_;
+
   return true;
 }
 
+template <typename StorageT>
+typename StorageT::value_type& 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)->value;
+}
+
+void*& FlagImpl::HeapAllocatedValue() const {
+  assert(ValueStorageKind() == FlagValueStorageKind::kHeapAllocated);
+  return OffsetValue<FlagHeapAllocatedValue>();
+}
+std::atomic<int64_t>& FlagImpl::OneWordValue() const {
+  assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic);
+  return OffsetValue<FlagOneWordValue>();
+}
+std::atomic<AlignedTwoWords>& FlagImpl::TwoWordsValue() const {
+  assert(ValueStorageKind() == FlagValueStorageKind::kTwoWordsAtomic);
+  return OffsetValue<FlagTwoWordsValue>();
+}
+
 // 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
@@ -290,23 +404,22 @@
 }
 
 void FlagImpl::Read(void* dst) const {
-  DataGuard();  // Make sure flag initialized
+  auto* guard = DataGuard();  // Make sure flag initialized
   switch (ValueStorageKind()) {
     case FlagValueStorageKind::kHeapAllocated: {
-      absl::MutexLock l(DataGuard());
-
-      flags_internal::CopyConstruct(op_, value_.dynamic, dst);
+      absl::MutexLock l(guard);
+      flags_internal::CopyConstruct(op_, HeapAllocatedValue(), dst);
       break;
     }
     case FlagValueStorageKind::kOneWordAtomic: {
-      const auto one_word_val =
-          value_.one_word_atomic.load(std::memory_order_acquire);
+      const int64_t one_word_val =
+          OneWordValue().load(std::memory_order_acquire);
       std::memcpy(dst, &one_word_val, Sizeof(op_));
       break;
     }
     case FlagValueStorageKind::kTwoWordsAtomic: {
-      const auto two_words_val =
-          value_.two_words_atomic.load(std::memory_order_acquire);
+      const AlignedTwoWords two_words_val =
+          TwoWordsValue().load(std::memory_order_acquire);
       std::memcpy(dst, &two_words_val, Sizeof(op_));
       break;
     }
@@ -316,7 +429,7 @@
 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;
@@ -338,8 +451,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) {
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index 344e31f..c1bf865 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -23,6 +23,7 @@
 #include <memory>
 #include <string>
 #include <type_traits>
+#include <typeinfo>
 
 #include "absl/base/call_once.h"
 #include "absl/base/config.h"
@@ -40,9 +41,6 @@
 ABSL_NAMESPACE_BEGIN
 namespace flags_internal {
 
-template <typename T>
-class Flag;
-
 ///////////////////////////////////////////////////////////////////////////////
 // Flag value type operations, eg., parsing, copying, etc. are provided
 // by function specific to that type with a signature matching FlagOpFn.
@@ -53,50 +51,17 @@
   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) {
@@ -133,41 +98,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.
@@ -263,6 +223,10 @@
 struct alignas(16) AlignedTwoWords {
   int64_t first;
   int64_t second;
+
+  bool IsInitialized() const {
+    return first != flags_internal::UninitializedFlagValue();
+  }
 };
 
 template <typename T>
@@ -272,8 +236,14 @@
 #else
 // This is actually unused and only here to avoid ifdefs in other palces.
 struct AlignedTwoWords {
-  constexpr AlignedTwoWords() = default;
-  constexpr AlignedTwoWords(int64_t, int64_t) {}
+  constexpr AlignedTwoWords() noexcept : dummy() {}
+  constexpr AlignedTwoWords(int64_t, int64_t) noexcept : dummy() {}
+  char dummy;
+
+  bool IsInitialized() const {
+    std::abort();
+    return true;
+  }
 };
 
 // This trait should be type dependent, otherwise SFINAE below will fail
@@ -293,23 +263,70 @@
   kTwoWordsAtomic = 2
 };
 
-union FlagValue {
-  constexpr explicit FlagValue(int64_t v) : one_word_atomic(v) {}
+template <typename T>
+static constexpr FlagValueStorageKind StorageKind() {
+  return FlagUseHeapStorage<T>::value
+             ? FlagValueStorageKind::kHeapAllocated
+             : FlagUseOneWordStorage<T>::value
+                   ? FlagValueStorageKind::kOneWordAtomic
+                   : FlagUseTwoWordsStorage<T>::value
+                         ? FlagValueStorageKind::kTwoWordsAtomic
+                         : FlagValueStorageKind::kHeapAllocated;
+}
 
-  template <typename T>
-  static constexpr FlagValueStorageKind Kind() {
-    return FlagUseHeapStorage<T>::value
-               ? FlagValueStorageKind::kHeapAllocated
-               : FlagUseOneWordStorage<T>::value
-                     ? FlagValueStorageKind::kOneWordAtomic
-                     : FlagUseTwoWordsStorage<T>::value
-                           ? FlagValueStorageKind::kTwoWordsAtomic
-                           : FlagValueStorageKind::kHeapAllocated;
+struct FlagHeapAllocatedValue {
+  using value_type = void*;
+
+  value_type value;
+};
+
+struct FlagOneWordValue {
+  using value_type = std::atomic<int64_t>;
+  constexpr FlagOneWordValue() : value(UninitializedFlagValue()) {}
+
+  value_type value;
+};
+
+struct FlagTwoWordsValue {
+  using value_type = std::atomic<AlignedTwoWords>;
+  constexpr FlagTwoWordsValue()
+      : value(AlignedTwoWords{UninitializedFlagValue(), 0}) {}
+
+  value_type value;
+};
+
+template <typename T,
+          FlagValueStorageKind Kind = flags_internal::StorageKind<T>()>
+struct FlagValue;
+
+template <typename T>
+struct FlagValue<T, FlagValueStorageKind::kHeapAllocated>
+    : FlagHeapAllocatedValue {
+  bool Get(T*) const { return false; }
+};
+
+template <typename T>
+struct FlagValue<T, FlagValueStorageKind::kOneWordAtomic> : FlagOneWordValue {
+  bool Get(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;
   }
+};
 
-  void* dynamic;
-  std::atomic<int64_t> one_word_atomic;
-  std::atomic<flags_internal::AlignedTwoWords> two_words_atomic;
+template <typename T>
+struct FlagValue<T, FlagValueStorageKind::kTwoWordsAtomic> : FlagTwoWordsValue {
+  bool Get(T* dst) const {
+    AlignedTwoWords two_words_val = value.load(std::memory_order_acquire);
+    if (ABSL_PREDICT_FALSE(!two_words_val.IsInitialized())) {
+      return false;
+    }
+    std::memcpy(dst, static_cast<const void*>(&two_words_val), sizeof(T));
+    return true;
+  }
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -332,13 +349,15 @@
 struct DynValueDeleter {
   explicit DynValueDeleter(FlagOpFn op_arg = nullptr) : op(op_arg) {}
   void operator()(void* ptr) const {
-    if (op != nullptr) Delete(op, ptr);
+    if (op != nullptr) flags_internal::Delete(op, ptr);
   }
 
   FlagOpFn op;
 };
 
-class FlagImpl {
+class FlagState;
+
+class FlagImpl final : public flags_internal::CommandLineFlag {
  public:
   constexpr FlagImpl(const char* name, const char* filename, FlagOpFn op,
                      FlagHelpArg help, FlagValueStorageKind value_kind,
@@ -355,83 +374,33 @@
         counter_(0),
         callback_(nullptr),
         default_value_(default_value_gen),
-        value_(flags_internal::UninitializedFlagValue()),
         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<FlagUseHeapStorage<T>::value,
-                                                int>::type = 0>
-  void Get(T* dst) const {
-    Read(dst);
-  }
-  template <typename T, typename std::enable_if<FlagUseOneWordStorage<T>::value,
-                                                int>::type = 0>
-  void Get(T* dst) const {
-    int64_t one_word_val =
-        value_.one_word_atomic.load(std::memory_order_acquire);
-    if (ABSL_PREDICT_FALSE(one_word_val == UninitializedFlagValue())) {
-      DataGuard();  // Make sure flag initialized
-      one_word_val = value_.one_word_atomic.load(std::memory_order_acquire);
-    }
-    std::memcpy(dst, static_cast<const void*>(&one_word_val), sizeof(T));
-  }
-  template <typename T, typename std::enable_if<
-                            FlagUseTwoWordsStorage<T>::value, int>::type = 0>
-  void Get(T* dst) const {
-    DataGuard();  // Make sure flag initialized
-    const auto two_words_val =
-        value_.two_words_atomic.load(std::memory_order_acquire);
-    std::memcpy(dst, &two_words_val, sizeof(T));
-  }
+  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());
 
   // 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 `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;
+  // 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_);
   // Returns heap allocated value of type T initialized with default value.
@@ -439,6 +408,25 @@
       ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
   // Flag initialization called via absl::call_once.
   void Init();
+
+  // 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>
+  typename StorageT::value_type& OffsetValue() const;
+  // This is an accessor for a value stored in heap allocated storage.
+  // Returns a mutable reference to a pointer to allow vlaue mutation.
+  void*& HeapAllocatedValue() 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;
+  // This is an accessor for a value stored as two words atomic. Returns a
+  // mutable reference to an atomic value.
+  std::atomic<AlignedTwoWords>& TwoWordsValue() 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,
@@ -458,6 +446,37 @@
     return static_cast<FlagDefaultKind>(def_kind_);
   }
 
+  // CommandLineFlag interface implementation
+  absl::string_view Name() const override;
+  std::string Filename() const override;
+  absl::string_view Typename() const override;
+  std::string Help() const override;
+  FlagFastTypeId TypeId() const override;
+  bool IsModified() const override ABSL_LOCKS_EXCLUDED(*DataGuard());
+  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());
+
+  // 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.
 
   // Flags name passed to ABSL_FLAG as second arg.
@@ -505,13 +524,6 @@
   // these two cases.
   FlagDefaultSrc default_value_;
 
-  // Atomically mutable flag's state
-
-  // Flag's value. This can be either the atomically stored small value or
-  // pointer to the heap allocated dynamic value. value_storage_kind_ is used
-  // to distinguish these cases.
-  FlagValue value_;
-
   // This is reserved space for an absl::Mutex to guard flag data. It will be
   // initialized in FlagImpl::Init via placement new.
   // We can't use "absl::Mutex data_guard_", since this class is not literal.
@@ -527,12 +539,13 @@
 // 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, FlagValue::Kind<T>(),
-              default_value_gen) {}
+      : impl_(name, filename, &FlagOps<T>, help,
+              flags_internal::StorageKind<T>(), default_value_gen),
+        value_() {}
 
   T Get() const {
     // See implementation notes in CommandLineFlag::Get().
@@ -544,14 +557,14 @@
     U u;
 
 #if !defined(NDEBUG)
-    impl_.AssertValidType(&flags_internal::FlagStaticTypeIdGen<T>);
+    impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>);
 #endif
 
-    impl_.Get(&u.value);
+    if (!value_.Get(&u.value)) impl_.Read(&u.value);
     return std::move(u.value);
   }
   void Set(const T& v) {
-    impl_.AssertValidType(&flags_internal::FlagStaticTypeIdGen<T>);
+    impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>);
     impl_.Write(&v);
   }
   void SetCallback(const FlagCallbackFunc mutation_callback) {
@@ -559,60 +572,79 @@
   }
 
   // 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 {
+  absl::string_view Name() const { return impl_.Name(); }
+  std::string Filename() const { return impl_.Filename(); }
+  absl::string_view Typename() const { return ""; }
+  std::string Help() const { return impl_.Help(); }
+  bool IsModified() const { return impl_.IsModified(); }
+  bool IsSpecifiedOnCommandLine() const {
     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();
-  }
+  std::string DefaultValue() const { return impl_.DefaultValue(); }
+  std::string CurrentValue() const { return impl_.CurrentValue(); }
 
  private:
-  friend class FlagState<T>;
-
-  void Read(void* dst) const override { impl_.Read(dst); }
-  FlagStaticTypeId TypeId() const override { return &FlagStaticTypeIdGen<T>; }
+  template <typename U, bool do_register>
+  friend class FlagRegistrar;
 
   // 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_;
 };
 
+///////////////////////////////////////////////////////////////////////////////
+// Implementation of Flag value specific operations routine.
 template <typename T>
-void FlagState<T>::Restore() const {
-  if (flag_->RestoreState(*this)) {
-    ABSL_INTERNAL_LOG(INFO,
-                      absl::StrCat("Restore saved value of ", flag_->Name(),
-                                   " to: ", flag_->CurrentValue()));
+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*>(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);
@@ -620,7 +652,7 @@
 class FlagRegistrar {
  public:
   explicit FlagRegistrar(Flag<T>* flag) : flag_(flag) {
-    if (do_register) flags_internal::RegisterCommandLineFlag(flag_);
+    if (do_register) flags_internal::RegisterCommandLineFlag(&flag_->impl_);
   }
 
   FlagRegistrar& OnUpdate(FlagCallbackFunc cb) && {
@@ -647,7 +679,7 @@
 
 template <typename T>
 T* MakeFromDefaultValue(EmptyBraces) {
-  return new T;
+  return new T{};
 }
 
 }  // namespace flags_internal
diff --git a/absl/flags/internal/registry.cc b/absl/flags/internal/registry.cc
index e434a85..eb619c7 100644
--- a/absl/flags/internal/registry.cc
+++ b/absl/flags/internal/registry.cc
@@ -284,14 +284,14 @@
 
 class RetiredFlagObj final : public flags_internal::CommandLineFlag {
  public:
-  constexpr RetiredFlagObj(const char* name, FlagStaticTypeId type_id)
+  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 { return "RETIRED"; }
   absl::string_view Typename() const override { return ""; }
-  FlagStaticTypeId TypeId() const override { return type_id_; }
+  FlagFastTypeId TypeId() const override { return type_id_; }
   std::string Help() const override { return ""; }
   bool IsRetired() const override { return true; }
   bool IsModified() const override { return false; }
@@ -306,8 +306,8 @@
     return nullptr;
   }
 
-  bool SetFromString(absl::string_view, flags_internal::FlagSettingMode,
-                     flags_internal::ValueSource, std::string*) override {
+  bool ParseFrom(absl::string_view, flags_internal::FlagSettingMode,
+                 flags_internal::ValueSource, std::string*) override {
     return false;
   }
 
@@ -317,7 +317,7 @@
 
   // Data members
   const char* const name_;
-  const FlagStaticTypeId type_id_;
+  const FlagFastTypeId type_id_;
 };
 
 void DestroyRetiredFlag(flags_internal::CommandLineFlag* flag) {
@@ -327,7 +327,7 @@
 
 }  // namespace
 
-bool Retire(const char* name, FlagStaticTypeId type_id) {
+bool Retire(const char* name, FlagFastTypeId type_id) {
   auto* flag = new flags_internal::RetiredFlagObj(name, type_id);
   FlagRegistry::GlobalRegistry()->RegisterFlag(flag);
   return true;
diff --git a/absl/flags/internal/registry.h b/absl/flags/internal/registry.h
index 69ff889..af8ed6b 100644
--- a/absl/flags/internal/registry.h
+++ b/absl/flags/internal/registry.h
@@ -79,12 +79,12 @@
 //
 
 // Retire flag with name "name" and type indicated by ops.
-bool Retire(const char* name, FlagStaticTypeId type_id);
+bool Retire(const char* name, FlagFastTypeId type_id);
 
 // 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>);
+  return flags_internal::Retire(flag_name, base_internal::FastTypeId<T>());
 }
 
 // If the flag is retired, returns true and indicates in |*type_is_bool|
diff --git a/absl/flags/internal/type_erased.cc b/absl/flags/internal/type_erased.cc
index 490bc4e..75b4cdf 100644
--- a/absl/flags/internal/type_erased.cc
+++ b/absl/flags/internal/type_erased.cc
@@ -56,7 +56,7 @@
   if (!flag || flag->IsRetired()) return false;
 
   std::string error;
-  if (!flag->SetFromString(value, set_mode, kProgrammaticChange, &error)) {
+  if (!flag->ParseFrom(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);
diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc
index af5fb12..b60b36f 100644
--- a/absl/flags/parse.cc
+++ b/absl/flags/parse.cc
@@ -696,7 +696,7 @@
     if (flag->IsRetired()) continue;
 
     std::string error;
-    if (!flag->SetFromString(value, SET_FLAGS_VALUE, kCommandLine, &error)) {
+    if (!flag->ParseFrom(value, SET_FLAGS_VALUE, kCommandLine, &error)) {
       flags_internal::ReportUsageError(error, true);
       success = false;
     }
diff --git a/absl/random/BUILD.bazel b/absl/random/BUILD.bazel
index f78fbc7..4d94e1b 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",
@@ -141,16 +140,12 @@
 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",
         "//absl/container:flat_hash_map",
         "//absl/meta:type_traits",
         "//absl/random/internal:distribution_caller",
diff --git a/absl/random/CMakeLists.txt b/absl/random/CMakeLists.txt
index efa55d8..69bedbd 100644
--- a/absl/random/CMakeLists.txt
+++ b/absl/random/CMakeLists.txt
@@ -102,8 +102,6 @@
   HDRS
     "mock_distributions.h"
     "mocking_bit_gen.h"
-  SRCS
-    "mocking_bit_gen.cc"
   COPTS
     ${ABSL_DEFAULT_COPTS}
   LINKOPTS
@@ -168,7 +166,6 @@
     "bernoulli_distribution.h"
     "beta_distribution.h"
     "discrete_distribution.h"
-    "distribution_format_traits.h"
     "distributions.h"
     "exponential_distribution.h"
     "gaussian_distribution.h"
diff --git a/absl/random/bit_gen_ref.h b/absl/random/bit_gen_ref.h
index e877116..59591a4 100644
--- a/absl/random/bit_gen_ref.h
+++ b/absl/random/bit_gen_ref.h
@@ -132,7 +132,7 @@
 
 template <>
 struct DistributionCaller<absl::BitGenRef> {
-  template <typename DistrT, typename FormatT, typename... Args>
+  template <typename DistrT, typename... Args>
   static typename DistrT::result_type Call(absl::BitGenRef* gen_ref,
                                            Args&&... args) {
     auto* mock_ptr = gen_ref->mocked_gen_ptr_;
@@ -140,8 +140,7 @@
       DistrT dist(std::forward<Args>(args)...);
       return dist(*gen_ref);
     } else {
-      return mock_ptr->template Call<DistrT, FormatT>(
-          std::forward<Args>(args)...);
+      return mock_ptr->template Call<DistrT>(std::forward<Args>(args)...);
     }
   }
 };
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..8680f6a 100644
--- a/absl/random/distributions.h
+++ b/absl/random/distributions.h
@@ -55,7 +55,6 @@
 #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
@@ -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;
 
   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,7 +144,6 @@
         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);
@@ -154,7 +151,7 @@
   if (a > b) return a;
 
   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;
 
   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,7 +192,6 @@
   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);
@@ -204,7 +199,7 @@
   if (a > b) return a;
 
   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/internal/distribution_caller.h b/absl/random/internal/distribution_caller.h
index 02603cf..4e07244 100644
--- a/absl/random/internal/distribution_caller.h
+++ b/absl/random/internal/distribution_caller.h
@@ -33,20 +33,7 @@
   // Call the provided distribution type. The parameters are expected
   // to be explicitly specified.
   // DistrT is the distribution type.
-  // FormatT is the formatter type:
-  //
-  // 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>
+  template <typename DistrT, typename... Args>
   static typename DistrT::result_type Call(URBG* urbg, Args&&... args) {
     DistrT dist(std::forward<Args>(args)...);
     return dist(*urbg);
diff --git a/absl/random/internal/mocking_bit_gen_base.h b/absl/random/internal/mocking_bit_gen_base.h
index eeeae9d..23ecaf6 100644
--- a/absl/random/internal/mocking_bit_gen_base.h
+++ b/absl/random/internal/mocking_bit_gen_base.h
@@ -16,8 +16,6 @@
 #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>
 
@@ -28,27 +26,6 @@
 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;
@@ -61,14 +38,9 @@
   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.
@@ -81,10 +53,9 @@
   }
 
   // Call the generating distribution function.
-  // Invoked by DistributionCaller<>::Call<DistT, FormatT>.
+  // Invoked by DistributionCaller<>::Call<DistT>.
   // DistT is the distribution type.
-  // FormatT is the distribution formatter traits type.
-  template <typename DistrT, typename FormatT, typename... Args>
+  template <typename DistrT, 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>...>;
@@ -100,17 +71,11 @@
       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
diff --git a/absl/random/mocking_bit_gen.cc b/absl/random/mocking_bit_gen.cc
deleted file mode 100644
index 6bb1e41..0000000
--- a/absl/random/mocking_bit_gen.cc
+++ /dev/null
@@ -1,30 +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/random/mocking_bit_gen.h"
-
-#include <string>
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-MockingBitGen::~MockingBitGen() {
-
-  for (const auto& del : deleters_) {
-    del();
-  }
-}
-
-ABSL_NAMESPACE_END
-}  // namespace absl
diff --git a/absl/random/mocking_bit_gen.h b/absl/random/mocking_bit_gen.h
index 36cef91..3d8a979 100644
--- a/absl/random/mocking_bit_gen.h
+++ b/absl/random/mocking_bit_gen.h
@@ -100,7 +100,9 @@
  public:
   MockingBitGen() {}
 
-  ~MockingBitGen() override;
+  ~MockingBitGen() override {
+    for (const auto& del : deleters_) del();
+  }
 
  private:
   template <typename DistrT, typename... Args>
@@ -182,10 +184,10 @@
 
 template <>
 struct DistributionCaller<absl::MockingBitGen> {
-  template <typename DistrT, typename FormatT, typename... Args>
+  template <typename DistrT, typename... Args>
   static typename DistrT::result_type Call(absl::MockingBitGen* gen,
                                            Args&&... args) {
-    return gen->template Call<DistrT, FormatT>(std::forward<Args>(args)...);
+    return gen->template Call<DistrT>(std::forward<Args>(args)...);
   }
 };
 
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
index e72db82..3890112 100644
--- a/absl/strings/BUILD.bazel
+++ b/absl/strings/BUILD.bazel
@@ -313,6 +313,7 @@
         ":strings",
         "//absl/base",
         "//absl/base:config",
+        "//absl/base:core_headers",
         "//absl/base:endian",
         "//absl/base:raw_logging_internal",
         "//absl/container:fixed_array",
@@ -485,6 +486,7 @@
     copts = ABSL_TEST_COPTS,
     visibility = ["//visibility:private"],
     deps = [
+        ":internal",
         ":pow10_helper",
         ":strings",
         "//absl/base:config",
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt
index 668d722..d3a8bd7 100644
--- a/absl/strings/CMakeLists.txt
+++ b/absl/strings/CMakeLists.txt
@@ -284,6 +284,7 @@
     absl::raw_logging_internal
     absl::random_random
     absl::random_distributions
+    absl::strings_internal
     gmock_main
 )
 
@@ -577,6 +578,7 @@
     absl::strings
     absl::base
     absl::config
+    absl::core_headers
     absl::endian
     absl::raw_logging_internal
     absl::fixed_array
diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc
index 415b239..7de7766 100644
--- a/absl/strings/cord.cc
+++ b/absl/strings/cord.cc
@@ -28,6 +28,7 @@
 
 #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/strings/escaping.h"
@@ -713,6 +714,14 @@
   memset(data_, 0, sizeof(data_));
 }
 
+inline Cord::InternalChunkIterator Cord::internal_chunk_begin() const {
+  return InternalChunkIterator(this);
+}
+
+inline Cord::InternalChunkRange Cord::InternalChunks() const {
+  return InternalChunkRange(this);
+}
+
 // --------------------------------------------------------------------
 // Constructors and destructors
 
@@ -1087,7 +1096,7 @@
   } else if (new_size == 0) {
     // We want to return empty subcord, so nothing to do.
   } else if (new_size <= InlineRep::kMaxInline) {
-    Cord::ChunkIterator it = chunk_begin();
+    Cord::InternalChunkIterator it = internal_chunk_begin();
     it.AdvanceBytes(pos);
     char* dest = sub_cord.contents_.data_;
     size_t remaining_size = new_size;
@@ -1325,7 +1334,7 @@
 
 inline int Cord::CompareSlowPath(absl::string_view rhs, size_t compared_size,
                                  size_t size_to_compare) const {
-  auto advance = [](Cord::ChunkIterator* it, absl::string_view* chunk) {
+  auto advance = [](Cord::InternalChunkIterator* it, absl::string_view* chunk) {
     if (!chunk->empty()) return true;
     ++*it;
     if (it->bytes_remaining_ == 0) return false;
@@ -1333,7 +1342,7 @@
     return true;
   };
 
-  Cord::ChunkIterator lhs_it = chunk_begin();
+  Cord::InternalChunkIterator lhs_it = internal_chunk_begin();
 
   // compared_size is inside first chunk.
   absl::string_view lhs_chunk =
@@ -1355,7 +1364,7 @@
 
 inline int Cord::CompareSlowPath(const Cord& rhs, size_t compared_size,
                                  size_t size_to_compare) const {
-  auto advance = [](Cord::ChunkIterator* it, absl::string_view* chunk) {
+  auto advance = [](Cord::InternalChunkIterator* it, absl::string_view* chunk) {
     if (!chunk->empty()) return true;
     ++*it;
     if (it->bytes_remaining_ == 0) return false;
@@ -1363,8 +1372,8 @@
     return true;
   };
 
-  Cord::ChunkIterator lhs_it = chunk_begin();
-  Cord::ChunkIterator rhs_it = rhs.chunk_begin();
+  Cord::InternalChunkIterator lhs_it = internal_chunk_begin();
+  Cord::InternalChunkIterator rhs_it = rhs.internal_chunk_begin();
 
   // compared_size is inside both first chunks.
   absl::string_view lhs_chunk =
@@ -1498,8 +1507,11 @@
   }
 }
 
-Cord::ChunkIterator& Cord::ChunkIterator::operator++() {
-  assert(bytes_remaining_ > 0 && "Attempted to iterate past `end()`");
+template <typename StorageType>
+Cord::GenericChunkIterator<StorageType>&
+Cord::GenericChunkIterator<StorageType>::operator++() {
+  ABSL_HARDENING_ASSERT(bytes_remaining_ > 0 &&
+                        "Attempted to iterate past `end()`");
   assert(bytes_remaining_ >= current_chunk_.size());
   bytes_remaining_ -= current_chunk_.size();
 
@@ -1537,8 +1549,10 @@
   return *this;
 }
 
-Cord Cord::ChunkIterator::AdvanceAndReadBytes(size_t n) {
-  assert(bytes_remaining_ >= n && "Attempted to iterate past `end()`");
+template <typename StorageType>
+Cord Cord::GenericChunkIterator<StorageType>::AdvanceAndReadBytes(size_t n) {
+  ABSL_HARDENING_ASSERT(bytes_remaining_ >= n &&
+                        "Attempted to iterate past `end()`");
   Cord subcord;
 
   if (n <= InlineRep::kMaxInline) {
@@ -1650,7 +1664,8 @@
   return subcord;
 }
 
-void Cord::ChunkIterator::AdvanceBytesSlowPath(size_t n) {
+template <typename StorageType>
+void Cord::GenericChunkIterator<StorageType>::AdvanceBytesSlowPath(size_t n) {
   assert(bytes_remaining_ >= n && "Attempted to iterate past `end()`");
   assert(n >= current_chunk_.size());  // This should only be called when
                                        // iterating to a new node.
@@ -1709,7 +1724,7 @@
 }
 
 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) {
@@ -1990,6 +2005,9 @@
   return out;
 }
 
+template class Cord::GenericChunkIterator<cord_internal::CordTreeMutablePath>;
+template class Cord::GenericChunkIterator<cord_internal::CordTreeDynamicPath>;
+
 namespace strings_internal {
 size_t CordTestAccess::FlatOverhead() { return kFlatOverhead; }
 size_t CordTestAccess::MaxFlatLength() { return kMaxFlatLength; }
diff --git a/absl/strings/cord.h b/absl/strings/cord.h
index eb236e5..3ab3cb8 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 accomodate 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_
@@ -48,6 +75,7 @@
 #include "absl/base/internal/per_thread_tls.h"
 #include "absl/base/macros.h"
 #include "absl/base/port.h"
+#include "absl/container/inlined_vector.h"
 #include "absl/functional/function_ref.h"
 #include "absl/meta/type_traits.h"
 #include "absl/strings/internal/cord_internal.h"
@@ -67,11 +95,40 @@
 H HashFragmentedCord(H, const Cord&);
 }
 
+// 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.
+//
+
 namespace cord_internal {
 
-// It's expensive to keep a tree perfectly balanced, so instead we keep trees
-// approximately balanced.  A tree node N of depth D(N) that contains a string
-// of L(N) characters is considered balanced if L >= Fibonacci(D + 2).
+// It's expensive to keep a Cord's tree perfectly balanced, so instead we keep
+// trees approximately balanced.  A tree node N of depth D(N) that contains a
+// string of L(N) characters is considered balanced if L >= Fibonacci(D + 2).
 // The "+ 2" is used to ensure that every balanced leaf node contains at least
 //  one character. Here we presume that
 //   Fibonacci(0) = 0
@@ -113,7 +170,13 @@
   size_t size_ = 0;
 };
 
+// Fixed length container for mutable "path" in cord tree, which can hold any
+// possible valid path in cord tree.
 using CordTreeMutablePath = CordTreePath<CordRep*, MaxCordDepth()>;
+// Variable length container for mutable "path" in cord tree. It starts with
+// capacity for 15 elements and grow if necessary.
+using CordTreeDynamicPath =
+    absl::InlinedVector<absl::cord_internal::CordRep*, 15>;
 }  // namespace cord_internal
 
 // A Cord is a sequence of characters.
@@ -123,175 +186,14 @@
   using EnableIfString =
       absl::enable_if_t<std::is_same<T, std::string>::value, int>;
 
- public:
-  // --------------------------------------------------------------------
-  // Constructors, destructors and helper factories
-
-  // Create an empty cord
-  constexpr Cord() noexcept;
-
-  // 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.
-  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*`.
+  //----------------------------------------------------------------------------
+  // Cord::GenericChunkIterator
+  //----------------------------------------------------------------------------
   //
-  // Note that these functions reserve the right to reuse the `string&&`'s
-  // memory and that they will do so in the future.
-  template <typename T, EnableIfString<T> = 0>
-  explicit Cord(T&& src) : Cord(absl::string_view(src)) {}
-  template <typename T, EnableIfString<T> = 0>
-  Cord& operator=(T&& src);
-
-  // Destroy the cord
-  ~Cord() {
-    if (contents_.is_tree()) DestroyCordSlow();
-  }
-
-  // Creates a Cord that takes ownership of external memory. The contents of
-  // `data` are not copied.
-  //
-  // 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` or
-  //     `void operator()() 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.
-  //
-  // Example:
-  //
-  // Cord MakeCord(BlockPool* pool) {
-  //   Block* block = pool->NewBlock();
-  //   FillBlock(block);
-  //   return absl::MakeCordFromExternal(
-  //       block->ToStringView(),
-  //       [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:
-  //
-  // void Foo(const char* buffer, int len) {
-  //   auto c = absl::MakeCordFromExternal(absl::string_view(buffer, len),
-  //                                       [](absl::string_view) {});
-  //
-  //   // BUG: If Bar() copies its cord for any reason, including keeping a
-  //   // substring of it, the lifetime of buffer might be extended beyond
-  //   // when Foo() returns.
-  //   Bar(c);
-  // }
-  template <typename Releaser>
-  friend Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser);
-
-  // --------------------------------------------------------------------
-  // Mutations
-
-  void Clear();
-
-  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);
-
-  void Prepend(const Cord& src);
-  void Prepend(absl::string_view src);
-  template <typename T, EnableIfString<T> = 0>
-  void Prepend(T&& src);
-
-  void RemovePrefix(size_t n);
-  void RemoveSuffix(size_t n);
-
-  // 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;
-
-  // --------------------------------------------------------------------
-  // Accessors
-
-  size_t size() const;
-  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.
-  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:
-  //   -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
-  bool StartsWith(const Cord& rhs) const;
-  bool StartsWith(absl::string_view rhs) const;
-  bool EndsWith(absl::string_view rhs) const;
-  bool EndsWith(const Cord& rhs) const;
-
-  // --------------------------------------------------------------------
-  // Conversion to other types
-
-  explicit operator std::string() const;
-
-  // Copies the contents from `src` to `*dst`.
-  //
-  // 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.
-  //
-  // Additional notes:
-  //   * 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
-  //     nodes and are imbalanced due to sharing. Prefer to pass this type by
-  //     const reference instead of by value.
-  class ChunkIterator {
+  // A `Cord::GenericChunkIterator` provides an interface for the standard
+  // `Cord::ChunkIterator` as well as some private implementations.
+  template <typename StorageType>
+  class GenericChunkIterator {
    public:
     using iterator_category = std::input_iterator_tag;
     using value_type = absl::string_view;
@@ -299,12 +201,12 @@
     using pointer = const value_type*;
     using reference = value_type;
 
-    ChunkIterator() = default;
+    GenericChunkIterator() = default;
 
-    ChunkIterator& operator++();
-    ChunkIterator operator++(int);
-    bool operator==(const ChunkIterator& other) const;
-    bool operator!=(const ChunkIterator& other) const;
+    GenericChunkIterator& operator++();
+    GenericChunkIterator operator++(int);
+    bool operator==(const GenericChunkIterator& other) const;
+    bool operator!=(const GenericChunkIterator& other) const;
     reference operator*() const;
     pointer operator->() const;
 
@@ -313,7 +215,7 @@
 
    private:
     // Constructs a `begin()` iterator from `cord`.
-    explicit ChunkIterator(const Cord* cord);
+    explicit GenericChunkIterator(const Cord* cord);
 
     // Removes `n` bytes from `current_chunk_`. Expects `n` to be smaller than
     // `current_chunk_.size()`.
@@ -330,16 +232,248 @@
     // The current leaf, or `nullptr` if the iterator points to short data.
     // If the current chunk is a substring node, current_leaf_ points to the
     // underlying flat or external node.
-    absl::cord_internal::CordRep* current_leaf_ = nullptr;
+    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::cord_internal::CordTreeMutablePath stack_of_right_children_;
+    StorageType stack_of_right_children_;
+  };
+  template <typename IteratorType>
+  class GenericChunkRange {
+   public:
+    explicit GenericChunkRange(const Cord* cord) : cord_(cord) {}
+
+    IteratorType begin() const { return IteratorType(cord_); }
+    IteratorType end() const { return IteratorType(); }
+
+   private:
+    const Cord* cord_;
   };
 
+ public:
+  // Cord::Cord() Constructors
+
+  // Creates an empty Cord
+  constexpr Cord() noexcept;
+
+  // 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;
+
+  // 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);
+
+  // 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*`.
+  //
+  // Note that these functions reserve the right to use the `string&&`'s
+  // memory and that they will do so in the future.
+  template <typename T, EnableIfString<T> = 0>
+  explicit Cord(T&& src) : Cord(absl::string_view(src)) {}
+  template <typename T, EnableIfString<T> = 0>
+  Cord& operator=(T&& src);
+
+  // Cord::~Cord()
+  //
+  // Destructs the Cord
+  ~Cord() {
+    if (contents_.is_tree()) DestroyCordSlow();
+  }
+
+  // Cord::MakeCordFromExternal(data, callable)
+  //
+  // 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()`
+  //   * not have alignment requirement greater than what is guaranteed by
+  //     `::operator new`. This alignment is dictated by
+  //     `alignof(std::max_align_t)` (pre-C++17 code) or
+  //     `__STDCPP_DEFAULT_NEW_ALIGNMENT__` (C++17 code).
+  //
+  // Example:
+  //
+  // Cord MakeCord(BlockPool* pool) {
+  //   Block* block = pool->NewBlock();
+  //   FillBlock(block);
+  //   return absl::MakeCordFromExternal(
+  //       block->ToStringView(),
+  //       [pool, block](absl::string_view v) {
+  //         pool->FreeBlock(block, v);
+  //       });
+  // }
+  //
+  // 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),
+  //                                       [](absl::string_view) {});
+  //
+  //   // BUG: If Bar() copies its cord for any reason, including keeping a
+  //   // substring of it, the lifetime of buffer might be extended beyond
+  //   // when Foo() returns.
+  //   Bar(c);
+  // }
+  template <typename Releaser>
+  friend Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser);
+
+  // 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);
+
+  // 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;
+
+  // swap()
+  //
+  // Swaps the data of Cord `x` with Cord `y`.
+  friend void swap(Cord& x, Cord& y) noexcept;
+
+  // 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;
+
+  // 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;
+
+  // 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;
+
+  // 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::EndsWidth()
+  //
+  // Determines whether the Cord ends with the passed string data `rhs`.
+  bool EndsWith(absl::string_view rhs) const;
+  bool EndsWith(const Cord& rhs) const;
+
+  // 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;
+
+  // CopyCordToString()
+  //
+  // 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);
+
+  class CharIterator;
+
+  //----------------------------------------------------------------------------
+  // Cord::ChunkIterator
+  //----------------------------------------------------------------------------
+  //
+  // 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.
+  //   * 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.
+  using ChunkIterator =
+      GenericChunkIterator<cord_internal::CordTreeDynamicPath>;
+
+  // 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:
   //
@@ -348,26 +482,35 @@
   //     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.
-  class ChunkRange {
-   public:
-    explicit ChunkRange(const Cord* cord) : cord_(cord) {}
+  // `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()`.
+  using ChunkRange = GenericChunkRange<ChunkIterator>;
 
-    ChunkIterator begin() const;
-    ChunkIterator end() const;
-
-   private:
-    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:
   //
@@ -384,22 +527,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;
@@ -425,34 +576,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) {}
@@ -464,8 +637,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:
   //
@@ -482,23 +658,26 @@
   //   }
   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()
+  // Get 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, return a
   // string_view referencing that array.  Otherwise return 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.
@@ -621,6 +800,14 @@
   static bool GetFlatAux(absl::cord_internal::CordRep* rep,
                          absl::string_view* fragment);
 
+  // Iterators for use inside Cord implementation
+  using InternalChunkIterator =
+      GenericChunkIterator<cord_internal::CordTreeMutablePath>;
+  using InternalChunkRange = GenericChunkRange<InternalChunkIterator>;
+
+  InternalChunkIterator internal_chunk_begin() const;
+  InternalChunkRange InternalChunks() const;
+
   // Helper for ForEachChunk()
   static void ForEachChunkAux(
       absl::cord_internal::CordRep* rep,
@@ -655,6 +842,11 @@
   void AppendImpl(C&& src);
 };
 
+extern template class Cord::GenericChunkIterator<
+    cord_internal::CordTreeMutablePath>;
+extern template class Cord::GenericChunkIterator<
+    cord_internal::CordTreeDynamicPath>;
+
 ABSL_NAMESPACE_END
 }  // namespace absl
 
@@ -994,7 +1186,9 @@
   return EqualsImpl(rhs, rhs_size);
 }
 
-inline Cord::ChunkIterator::ChunkIterator(const Cord* cord)
+template <typename StorageType>
+inline Cord::GenericChunkIterator<StorageType>::GenericChunkIterator(
+    const Cord* cord)
     : bytes_remaining_(cord->size()) {
   if (cord->empty()) return;
   if (cord->contents_.is_tree()) {
@@ -1005,37 +1199,50 @@
   }
 }
 
-inline Cord::ChunkIterator Cord::ChunkIterator::operator++(int) {
-  ChunkIterator tmp(*this);
+template <typename StorageType>
+inline Cord::GenericChunkIterator<StorageType>
+Cord::GenericChunkIterator<StorageType>::operator++(int) {
+  GenericChunkIterator tmp(*this);
   operator++();
   return tmp;
 }
 
-inline bool Cord::ChunkIterator::operator==(const ChunkIterator& other) const {
+template <typename StorageType>
+inline bool Cord::GenericChunkIterator<StorageType>::operator==(
+    const GenericChunkIterator<StorageType>& other) const {
   return bytes_remaining_ == other.bytes_remaining_;
 }
 
-inline bool Cord::ChunkIterator::operator!=(const ChunkIterator& other) const {
+template <typename StorageType>
+inline bool Cord::GenericChunkIterator<StorageType>::operator!=(
+    const GenericChunkIterator<StorageType>& other) const {
   return !(*this == other);
 }
 
-inline Cord::ChunkIterator::reference Cord::ChunkIterator::operator*() const {
-  assert(bytes_remaining_ != 0);
+template <typename StorageType>
+inline typename Cord::GenericChunkIterator<StorageType>::reference
+Cord::GenericChunkIterator<StorageType>::operator*() const {
+  ABSL_HARDENING_ASSERT(bytes_remaining_ != 0);
   return current_chunk_;
 }
 
-inline Cord::ChunkIterator::pointer Cord::ChunkIterator::operator->() const {
-  assert(bytes_remaining_ != 0);
+template <typename StorageType>
+inline typename Cord::GenericChunkIterator<StorageType>::pointer
+Cord::GenericChunkIterator<StorageType>::operator->() const {
+  ABSL_HARDENING_ASSERT(bytes_remaining_ != 0);
   return &current_chunk_;
 }
 
-inline void Cord::ChunkIterator::RemoveChunkPrefix(size_t n) {
+template <typename StorageType>
+inline void Cord::GenericChunkIterator<StorageType>::RemoveChunkPrefix(
+    size_t n) {
   assert(n < current_chunk_.size());
   current_chunk_.remove_prefix(n);
   bytes_remaining_ -= n;
 }
 
-inline void Cord::ChunkIterator::AdvanceBytes(size_t n) {
+template <typename StorageType>
+inline void Cord::GenericChunkIterator<StorageType>::AdvanceBytes(size_t n) {
   if (ABSL_PREDICT_TRUE(n < current_chunk_.size())) {
     RemoveChunkPrefix(n);
   } else if (n != 0) {
@@ -1049,14 +1256,6 @@
 
 inline Cord::ChunkIterator Cord::chunk_end() const { return ChunkIterator(); }
 
-inline Cord::ChunkIterator Cord::ChunkRange::begin() const {
-  return cord_->chunk_begin();
-}
-
-inline Cord::ChunkIterator Cord::ChunkRange::end() const {
-  return cord_->chunk_end();
-}
-
 inline Cord::ChunkRange Cord::Chunks() const { return ChunkRange(this); }
 
 inline Cord::CharIterator& Cord::CharIterator::operator++() {
diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc
index f2d81d4..0ec93b4 100644
--- a/absl/strings/cord_test.cc
+++ b/absl/strings/cord_test.cc
@@ -18,6 +18,7 @@
 #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"
@@ -1627,3 +1628,23 @@
     }
   }
 }
+
+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(), "");
+}
diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc
index 4d0604e..3aa0296 100644
--- a/absl/strings/internal/str_format/arg.cc
+++ b/absl/strings/internal/str_format/arg.cc
@@ -120,24 +120,25 @@
 // 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.
+  bool alt = conv.has_alt_flag();
+  int radix = FormatConversionCharRadix(conv.conversion_char());
+  if (conv.conversion_char() == ConversionChar::p)
+    alt = true;  // always show 0x for %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";
+    if (FormatConversionCharIsUpper(conv.conversion_char())) return "0X";
     return "0x";
   }
   return {};
 }
 
 string_view SignColumn(bool neg, const ConversionSpec conv) {
-  if (FormatConversionCharIsSigned(conv.conv())) {
+  if (FormatConversionCharIsSigned(conv.conversion_char())) {
     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 {};
 }
@@ -147,9 +148,9 @@
   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;
 }
 
@@ -174,7 +175,7 @@
   if (!precision_specified)
     precision = 1;
 
-  if (conv.flags().alt && conv.conv() == ConversionChar::o) {
+  if (conv.has_alt_flag() && conv.conversion_char() == ConversionChar::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 +188,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;
   }
@@ -209,8 +210,8 @@
 
 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)) {
+  ConvertedIntInfo info(v, conv.conversion_char());
+  if (conv.is_basic() && (conv.conversion_char() != ConversionChar::p)) {
     if (info.is_neg()) sink->Append(1, '-');
     if (info.digits().empty()) {
       sink->Append(1, '0');
@@ -224,13 +225,14 @@
 
 template <typename T>
 bool ConvertIntArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
-  if (FormatConversionCharIsFloat(conv.conv())) {
+  if (FormatConversionCharIsFloat(conv.conversion_char())) {
     return FormatConvertImpl(static_cast<double>(v), conv, sink).value;
   }
-  if (conv.conv() == ConversionChar::c)
+  if (conv.conversion_char() == ConversionChar::c)
     return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);
-  if (!FormatConversionCharIsIntegral(conv.conv())) return false;
-  if (!FormatConversionCharIsSigned(conv.conv()) && IsSigned<T>::value) {
+  if (!FormatConversionCharIsIntegral(conv.conversion_char())) return false;
+  if (!FormatConversionCharIsSigned(conv.conversion_char()) &&
+      IsSigned<T>::value) {
     using U = typename MakeUnsigned<T>::type;
     return FormatConvertImpl(static_cast<U>(v), conv, sink).value;
   }
@@ -239,19 +241,19 @@
 
 template <typename T>
 bool ConvertFloatArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
-  return FormatConversionCharIsFloat(conv.conv()) &&
+  return FormatConversionCharIsFloat(conv.conversion_char()) &&
          ConvertFloatImpl(v, conv, sink);
 }
 
 inline bool ConvertStringArg(string_view v, const ConversionSpec conv,
                              FormatSinkImpl *sink) {
-  if (conv.conv() != ConversionChar::s) return false;
-  if (conv.flags().basic) {
+  if (conv.conversion_char() != ConversionChar::s) return false;
+  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
@@ -272,7 +274,7 @@
 ConvertResult<Conv::s | Conv::p> FormatConvertImpl(const char *v,
                                                    const ConversionSpec conv,
                                                    FormatSinkImpl *sink) {
-  if (conv.conv() == ConversionChar::p)
+  if (conv.conversion_char() == ConversionChar::p)
     return {FormatConvertImpl(VoidPtr(v), conv, sink).value};
   size_t len;
   if (v == nullptr) {
@@ -289,7 +291,7 @@
 // ==================== Raw pointers ====================
 ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, const ConversionSpec conv,
                                          FormatSinkImpl *sink) {
-  if (conv.conv() != ConversionChar::p) return {false};
+  if (conv.conversion_char() != ConversionChar::p) return {false};
   if (!v.value) {
     sink->Append("(nil)");
     return {true};
diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h
index 7a93756..1c36e30 100644
--- a/absl/strings/internal/str_format/arg.h
+++ b/absl/strings/internal/str_format/arg.h
@@ -70,9 +70,11 @@
 ConvertResult<Conv::s> FormatConvertImpl(const AbslCord& value,
                                          ConversionSpec conv,
                                          FormatSinkImpl* sink) {
-  if (conv.conv() != ConversionChar::s) return {false};
+  if (conv.conversion_char() != ConversionChar::s) {
+    return {false};
+  }
 
-  bool is_left = conv.flags().left;
+  bool is_left = conv.has_left_flag();
   size_t space_remaining = 0;
 
   int width = conv.width();
@@ -106,8 +108,8 @@
 }
 
 using IntegralConvertResult =
-    ConvertResult<Conv::c | Conv::numeric | Conv::star>;
-using FloatingConvertResult = ConvertResult<Conv::floating>;
+    ConvertResult<Conv::c | Conv::kNumeric | Conv::kStar>;
+using FloatingConvertResult = ConvertResult<Conv::kFloating>;
 
 // Floats.
 FloatingConvertResult FormatConvertImpl(float v, ConversionSpec conv,
@@ -185,7 +187,9 @@
                                               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::ConversionChar::n) {
+      return {false};
+    }
     *v2.p_ = static_cast<int>(sink->size());
     return {true};
   }
@@ -377,7 +381,7 @@
   template <typename T>
   static bool Dispatch(Data arg, ConversionSpec 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() == ConversionChar::kNone)) {
       return ToInt<T>(arg, static_cast<int*>(out), std::is_integral<T>(),
                       std::is_enum<T>());
     }
diff --git a/absl/strings/internal/str_format/bind.cc b/absl/strings/internal/str_format/bind.cc
index 27522fd..6980ed1 100644
--- a/absl/strings/internal/str_format/bind.cc
+++ b/absl/strings/internal/str_format/bind.cc
@@ -147,7 +147,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;
   }
diff --git a/absl/strings/internal/str_format/checker_test.cc b/absl/strings/internal/str_format/checker_test.cc
index ea2a768..49a24b4 100644
--- a/absl/strings/internal/str_format/checker_test.cc
+++ b/absl/strings/internal/str_format/checker_test.cc
@@ -9,13 +9,17 @@
 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;
+  if (Contains(conv, FormatConversionCharSet::c)) { \
+    out += #c; \
+  }
   ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(CONV_SET_CASE, )
 #undef CONV_SET_CASE
-  if (Contains(conv, Conv::star)) out += "*";
+  if (Contains(conv, FormatConversionCharSet::kStar)) {
+    out += "*";
+  }
   return out;
 }
 
diff --git a/absl/strings/internal/str_format/extension.h b/absl/strings/internal/str_format/extension.h
index d166575..bae2c07 100644
--- a/absl/strings/internal/str_format/extension.h
+++ b/absl/strings/internal/str_format/extension.h
@@ -24,6 +24,7 @@
 
 #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"
 
@@ -154,8 +155,7 @@
     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
 
@@ -287,11 +287,6 @@
   // 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(); }
-
  private:
   friend struct str_format_internal::FormatConversionSpecImplFriend;
   FormatConversionChar conv_ = FormatConversionChar::kNone;
@@ -343,15 +338,7 @@
   kFloating = a | e | f | g | A | E | F | G,
   kNumeric = kIntegral | kFloating,
   kString = s,
-  kPointer = p,
-
-  // The following are deprecated
-  star = kStar,
-  integral = kIntegral,
-  floating = kFloating,
-  numeric = kNumeric,
-  string = kString,
-  pointer = kPointer
+  kPointer = p
 };
 
 // Type safe OR operator.
@@ -365,11 +352,22 @@
                                  static_cast<uint64_t>(b));
 }
 
+// Overloaded conversion functions to support absl::ParsedFormat.
 // Get a conversion with a single character in it.
-constexpr FormatConversionCharSet ConversionCharToConv(char c) {
-  return FormatConversionCharSet(FormatConversionCharToConvValue(c));
+constexpr FormatConversionCharSet ToFormatConversionCharSet(char c) {
+  return static_cast<FormatConversionCharSet>(
+      FormatConversionCharToConvValue(c));
 }
 
+// Get a conversion with a single character in it.
+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;
diff --git a/absl/strings/internal/str_format/float_conversion.cc b/absl/strings/internal/str_format/float_conversion.cc
index d4c647c..d5a1ee4 100644
--- a/absl/strings/internal/str_format/float_conversion.cc
+++ b/absl/strings/internal/str_format/float_conversion.cc
@@ -33,7 +33,7 @@
     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));
   }
@@ -100,17 +100,19 @@
   char text[4], *ptr = text;
   if (sign_char) *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.
@@ -358,9 +360,9 @@
                                        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;
@@ -382,9 +384,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,14 +403,14 @@
 
   Buffer buffer;
 
-  switch (conv.conv()) {
+  switch (conv.conversion_char()) {
     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();
+      if (!conv.has_alt_flag() && buffer.back() == '.') buffer.pop_back();
       break;
 
     case ConversionChar::e:
@@ -417,9 +419,10 @@
                                                  &exp)) {
         return FallbackToSnprintf(v, conv, sink);
       }
-      if (!conv.flags().alt && buffer.back() == '.') buffer.pop_back();
-      PrintExponent(exp, FormatConversionCharIsUpper(conv.conv()) ? 'E' : 'e',
-                    &buffer);
+      if (!conv.has_alt_flag() && buffer.back() == '.') buffer.pop_back();
+      PrintExponent(
+          exp, FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e',
+          &buffer);
       break;
 
     case ConversionChar::g:
@@ -446,13 +449,15 @@
         }
         exp = 0;
       }
-      if (!conv.flags().alt) {
+      if (!conv.has_alt_flag()) {
         while (buffer.back() == '0') buffer.pop_back();
         if (buffer.back() == '.') buffer.pop_back();
       }
       if (exp) {
-        PrintExponent(exp, FormatConversionCharIsUpper(conv.conv()) ? 'E' : 'e',
-                      &buffer);
+        PrintExponent(
+            exp,
+            FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e',
+            &buffer);
       }
       break;
 
diff --git a/absl/strings/internal/str_format/parser_test.cc b/absl/strings/internal/str_format/parser_test.cc
index 1b1ee03..51eb53f 100644
--- a/absl/strings/internal/str_format/parser_test.cc
+++ b/absl/strings/internal/str_format/parser_test.cc
@@ -52,7 +52,7 @@
     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'},
+    {ConversionChar::kNone, '\0'},
   };
   // clang-format on
   for (auto e : kExpect) {
diff --git a/absl/strings/numbers_test.cc b/absl/strings/numbers_test.cc
index bd4e116..7db85e7 100644
--- a/absl/strings/numbers_test.cc
+++ b/absl/strings/numbers_test.cc
@@ -40,6 +40,7 @@
 #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"
 
diff --git a/absl/strings/str_format.h b/absl/strings/str_format.h
index 2f9b4b2..d40fca1 100644
--- a/absl/strings/str_format.h
+++ b/absl/strings/str_format.h
@@ -285,7 +285,7 @@
 //   }
 template <char... Conv>
 using ParsedFormat = str_format_internal::ExtendedParsedFormat<
-    str_format_internal::ConversionCharToConv(Conv)...>;
+    absl::str_format_internal::ToFormatConversionCharSet(Conv)...>;
 
 // StrFormat()
 //
diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc
index 554dca7..f0d1f0a 100644
--- a/absl/strings/str_format_test.cc
+++ b/absl/strings/str_format_test.cc
@@ -540,19 +540,19 @@
   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<Conv::kString, Conv::d, Conv::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(
+  f2 = ExtendedParsedFormat<Conv::kString, Conv::d, Conv::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<Conv::kStar, Conv::d>::New("%*d");
   ASSERT_TRUE(star);
   EXPECT_EQ("{*d:2$1$*d}", SummarizeParsedFormat(*star));
 
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h
index b314bc3..8a9db8c 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
 
@@ -283,7 +283,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 +303,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()
@@ -329,7 +329,7 @@
   // Removes the first `n` characters from the `string_view`. Note that the
   // 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;
   }
@@ -339,7 +339,7 @@
   // Removes the last `n` characters from the `string_view`. Note that the
   // underlying string is not changed, only the view.
   void remove_suffix(size_type n) {
-    assert(n <= length_);
+    ABSL_HARDENING_ASSERT(n <= length_);
     length_ -= n;
   }
 
@@ -520,7 +520,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 6ba0614..ff31b51 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.
@@ -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;
@@ -1130,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], "");
diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc
index 426558e..6ee5f23 100644
--- a/absl/synchronization/mutex.cc
+++ b/absl/synchronization/mutex.cc
@@ -1751,7 +1751,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");
@@ -2017,7 +2018,7 @@
 // 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) {
   intptr_t v = mu_.load(std::memory_order_relaxed);
   this->AssertReaderHeld();
   CheckForMutexCorruption(v, "Unlock");
diff --git a/absl/types/optional.h b/absl/types/optional.h
index 01d747d..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());
   }
 
diff --git a/absl/types/optional_test.cc b/absl/types/optional_test.cc
index 47d5c8a..874334e 100644
--- a/absl/types/optional_test.cc
+++ b/absl/types/optional_test.cc
@@ -1057,8 +1057,7 @@
   // 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 21cda34..734db69 100644
--- a/absl/types/span.h
+++ b/absl/types/span.h
@@ -276,7 +276,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 ABSL_ASSERT(i < size()), *(data() + i);
+    return ABSL_HARDENING_ASSERT(i < size()), *(data() + i);
   }
 
   // Span::at()
@@ -295,7 +295,7 @@
   // 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()
@@ -303,7 +303,7 @@
   // 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()
@@ -368,7 +368,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;
   }
@@ -377,7 +377,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;
   }
 
@@ -665,7 +665,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>
@@ -710,7 +710,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 6ac234d..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"
@@ -233,7 +234,7 @@
   EXPECT_EQ(s.front(), s[0]);
   EXPECT_EQ(s.back(), s[9]);
 
-#ifndef NDEBUG
+#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
   EXPECT_DEATH_IF_SUPPORTED(s[-1], "");
   EXPECT_DEATH_IF_SUPPORTED(s[10], "");
 #endif
@@ -273,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/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_install_test.sh b/ci/cmake_install_test.sh
index 55fb4f1..4c748eb 100755
--- a/ci/cmake_install_test.sh
+++ b/ci/cmake_install_test.sh
@@ -20,6 +20,9 @@
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
+source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
+readonly DOCKER_CONTAINER=${LINUX_GCC_LATEST_CONTAINER}
+
 time docker run \
     --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
     --workdir=/abseil-cpp \
@@ -28,5 +31,5 @@
     --rm \
     -e CFLAGS="-Werror" \
     -e CXXFLAGS="-Werror" \
-    gcr.io/google.com/absl-177019/linux_gcc-latest:20200106 \
+    ${DOCKER_CONTAINER} \
     /bin/bash CMake/install_test_project/test.sh $@
diff --git a/ci/linux_clang-latest_libcxx_asan_bazel.sh b/ci/linux_clang-latest_libcxx_asan_bazel.sh
index 24efe3b..03463e2 100755
--- a/ci/linux_clang-latest_libcxx_asan_bazel.sh
+++ b/ci/linux_clang-latest_libcxx_asan_bazel.sh
@@ -36,7 +36,8 @@
   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.
@@ -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 [ -z ${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
diff --git a/ci/linux_clang-latest_libcxx_bazel.sh b/ci/linux_clang-latest_libcxx_bazel.sh
index 127e7bc..050a98c 100755
--- a/ci/linux_clang-latest_libcxx_bazel.sh
+++ b/ci/linux_clang-latest_libcxx_bazel.sh
@@ -36,7 +36,8 @@
   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.
@@ -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 [ -z ${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
diff --git a/ci/linux_clang-latest_libcxx_tsan_bazel.sh b/ci/linux_clang-latest_libcxx_tsan_bazel.sh
index 00257b3..2f5fb12 100755
--- a/ci/linux_clang-latest_libcxx_tsan_bazel.sh
+++ b/ci/linux_clang-latest_libcxx_tsan_bazel.sh
@@ -36,7 +36,8 @@
   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.
@@ -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 [ -z ${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
diff --git a/ci/linux_clang-latest_libstdcxx_bazel.sh b/ci/linux_clang-latest_libstdcxx_bazel.sh
index 9fe71d3..087f59b 100755
--- a/ci/linux_clang-latest_libstdcxx_bazel.sh
+++ b/ci/linux_clang-latest_libstdcxx_bazel.sh
@@ -36,7 +36,8 @@
   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.
@@ -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 [ -z ${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
diff --git a/ci/linux_docker_containers.sh b/ci/linux_docker_containers.sh
new file mode 100644
index 0000000..cf056b3
--- /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:20191016"
+readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20200319"
+readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-latest:20200319"
+readonly LINUX_GCC_49_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-4.9:20191018"
diff --git a/ci/linux_gcc-4.9_libstdcxx_bazel.sh b/ci/linux_gcc-4.9_libstdcxx_bazel.sh
index f8102cc..622ea84 100755
--- a/ci/linux_gcc-4.9_libstdcxx_bazel.sh
+++ b/ci/linux_gcc-4.9_libstdcxx_bazel.sh
@@ -36,7 +36,8 @@
   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_49_CONTAINER}
 
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
@@ -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 [ -z ${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
diff --git a/ci/linux_gcc-latest_libstdcxx_bazel.sh b/ci/linux_gcc-latest_libstdcxx_bazel.sh
index 5964703..f7dbd19 100755
--- a/ci/linux_gcc-latest_libstdcxx_bazel.sh
+++ b/ci/linux_gcc-latest_libstdcxx_bazel.sh
@@ -36,7 +36,8 @@
   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.
@@ -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 [ -z ${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
diff --git a/ci/linux_gcc-latest_libstdcxx_cmake.sh b/ci/linux_gcc-latest_libstdcxx_cmake.sh
index 38ad99f..b501544 100755
--- a/ci/linux_gcc-latest_libstdcxx_cmake.sh
+++ b/ci/linux_gcc-latest_libstdcxx_cmake.sh
@@ -34,6 +34,9 @@
   ABSL_CMAKE_BUILD_TYPES="Debug Release"
 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 "--------------------------------------------------------------------"
@@ -47,7 +50,7 @@
       --rm \
       -e CFLAGS="-Werror" \
       -e CXXFLAGS="-Werror" \
-      gcr.io/google.com/absl-177019/linux_gcc-latest:20200106 \
+      ${DOCKER_CONTAINER} \
       /bin/bash -c "
         cd /buildfs && \
         cmake /abseil-cpp \
diff --git a/ci/linux_gcc_alpine_cmake.sh b/ci/linux_gcc_alpine_cmake.sh
index 830a136..4496f8d 100755
--- a/ci/linux_gcc_alpine_cmake.sh
+++ b/ci/linux_gcc_alpine_cmake.sh
@@ -34,7 +34,8 @@
   ABSL_CMAKE_BUILD_TYPES="Debug Release"
 fi
 
-readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/alpine:20191016"
+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
diff --git a/ci/macos_xcode_cmake.sh b/ci/macos_xcode_cmake.sh
index aa9ee15..a1f4a85 100755
--- a/ci/macos_xcode_cmake.sh
+++ b/ci/macos_xcode_cmake.sh
@@ -36,7 +36,7 @@
   time cmake ${ABSEIL_ROOT} \
     -GXcode \
     -DCMAKE_BUILD_TYPE=${compilation_mode} \
-    -DCMAKE_CXX_FLAGS=-std=c++14 \
+    -DCMAKE_CXX_STANDARD=11 \
     -DABSL_USE_GOOGLETEST_HEAD=ON \
     -DABSL_RUN_TESTS=ON
   time cmake --build .