Roll abseil_revision da3a87690c..2eba343b51

Change Log:
https://chromium.googlesource.com/external/github.com/abseil/abseil-cpp/+log/da3a87690c..2eba343b51
Full diff:
https://chromium.googlesource.com/external/github.com/abseil/abseil-cpp/+/da3a87690c..2eba343b51

Bug: None
Change-Id: Iabbf435113fb589f252cf671a4c0485f10d77b8e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2238829
Reviewed-by: Mirko Bonadei <mbonadei@chromium.org>
Commit-Queue: Danil Chapovalov <danilchap@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#777298}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: cb5db97e7651d3bf15de528ea99732678d7c30f8
diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake
index 8e93e79..07ae20f 100644
--- a/CMake/AbseilDll.cmake
+++ b/CMake/AbseilDll.cmake
@@ -147,7 +147,6 @@
   "random/internal/platform.h"
   "random/internal/pool_urbg.cc"
   "random/internal/pool_urbg.h"
-  "random/internal/randen_round_keys.cc"
   "random/internal/randen.cc"
   "random/internal/randen.h"
   "random/internal/randen_detect.cc"
@@ -155,6 +154,7 @@
   "random/internal/randen_engine.h"
   "random/internal/randen_hwaes.cc"
   "random/internal/randen_hwaes.h"
+  "random/internal/randen_round_keys.cc"
   "random/internal/randen_slow.cc"
   "random/internal/randen_slow.h"
   "random/internal/randen_traits.h"
diff --git a/README.chromium b/README.chromium
index bd1485c..aecf5ed 100644
--- a/README.chromium
+++ b/README.chromium
@@ -4,7 +4,7 @@
 License: Apache 2.0
 License File: LICENSE
 Version: 0
-Revision: da3a87690c56f965705b6a233d25ba5a3294067c
+Revision: 2eba343b51e0923cd3fb919a6abd6120590fc059
 Security Critical: yes
 
 Description:
diff --git a/absl/container/internal/btree.h b/absl/container/internal/btree.h
index b23138f..f52fe23 100644
--- a/absl/container/internal/btree.h
+++ b/absl/container/internal/btree.h
@@ -817,33 +817,52 @@
     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) {
+  // Transfers value from slot `src_i` in `src_node` to slot `dest_i` in `this`.
+  void transfer(const size_type dest_i, const size_type src_i,
+                btree_node *src_node, allocator_type *alloc) {
     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));
+    params_type::transfer(alloc, slot(dest_i), src_node->slot(src_i));
+    absl::container_internal::SanitizerPoisonObject(src_node->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,
-                            const size_type j, btree_node *dest_node,
-                            allocator_type *alloc) {
+  // Transfers `n` values starting at value `src_i` in `src_node` into the
+  // values starting at value `dest_i` in `this`.
+  void transfer_n(const size_type n, const size_type dest_i,
+                  const size_type src_i, btree_node *src_node,
+                  allocator_type *alloc) {
     absl::container_internal::SanitizerUnpoisonMemoryRegion(
-        dest_node->slot(j), n * sizeof(slot_type));
-    for (slot_type *src = slot(i), *end = src + n, *dest = dest_node->slot(j);
+        slot(dest_i), n * sizeof(slot_type));
+    for (slot_type *src = src_node->slot(src_i), *end = src + n,
+                   *dest = slot(dest_i);
          src != end; ++src, ++dest) {
-      params_type::construct(alloc, dest, src);
+      params_type::transfer(alloc, dest, src);
     }
+    // We take care to avoid poisoning transferred-to nodes in case of overlap.
+    const size_type overlap =
+        this == src_node ? (std::max)(src_i, dest_i + n) - src_i : 0;
+    assert(n >= overlap);
+    absl::container_internal::SanitizerPoisonMemoryRegion(
+        src_node->slot(src_i + overlap), (n - overlap) * sizeof(slot_type));
   }
 
-  // Destroys a range of n values, starting at index i.
-  void value_destroy_n(const size_type i, const size_type n,
-                       allocator_type *alloc) {
-    for (int j = 0; j < n; ++j) {
-      value_destroy(i + j, alloc);
+  // Same as above, except that we start at the end and work our way to the
+  // beginning.
+  void transfer_n_backward(const size_type n, const size_type dest_i,
+                           const size_type src_i, btree_node *src_node,
+                           allocator_type *alloc) {
+    absl::container_internal::SanitizerUnpoisonMemoryRegion(
+        slot(dest_i), n * sizeof(slot_type));
+    for (slot_type *src = src_node->slot(src_i + n - 1), *end = src - n,
+                   *dest = slot(dest_i + n - 1);
+         src != end; --src, --dest) {
+      params_type::transfer(alloc, dest, src);
     }
+    // We take care to avoid poisoning transferred-to nodes in case of overlap.
+    assert(this != src_node || dest_i >= src_i);
+    const size_type num_to_poison =
+        this == src_node ? (std::min)(n, dest_i - src_i) : n;
+    absl::container_internal::SanitizerPoisonMemoryRegion(
+        src_node->slot(src_i), num_to_poison * sizeof(slot_type));
   }
 
   template <typename P>
@@ -1531,10 +1550,8 @@
   // Shift old values to create space for new value and then construct it in
   // place.
   if (i < finish()) {
-    value_init(finish(), alloc, slot(finish() - 1));
-    for (size_type j = finish() - 1; j > i; --j)
-      params_type::move(alloc, slot(j - 1), slot(j));
-    value_destroy(i, alloc);
+    transfer_n_backward(finish() - i, /*dest_i=*/i + 1, /*src_i=*/i, this,
+                        alloc);
   }
   value_init(i, alloc, std::forward<Args>(args)...);
   set_finish(finish() + 1);
@@ -1564,7 +1581,9 @@
 inline void btree_node<P>::remove_values_ignore_children(
     const int i, const int to_erase, allocator_type *alloc) {
   params_type::move(alloc, slot(i + to_erase), finish_slot(), slot(i));
-  value_destroy_n(finish() - to_erase, to_erase, alloc);
+  for (int j = finish() - to_erase; j < finish(); ++j) {
+    value_destroy(j, alloc);
+  }
   set_finish(finish() - to_erase);
 }
 
@@ -1579,22 +1598,17 @@
   assert(to_move <= right->count());
 
   // 1) Move the delimiting value in the parent to the left node.
-  value_init(finish(), alloc, parent()->slot(position()));
+  transfer(finish(), position(), parent(), alloc);
 
   // 2) Move the (to_move - 1) values from the right node to the left node.
-  right->uninitialized_move_n(to_move - 1, right->start(), finish() + 1, this,
-                              alloc);
+  transfer_n(to_move - 1, finish() + 1, right->start(), right, alloc);
 
   // 3) Move the new delimiting value to the parent from the right node.
-  params_type::move(alloc, right->slot(to_move - 1),
-                    parent()->slot(position()));
+  parent()->transfer(position(), right->start() + to_move - 1, right, alloc);
 
-  // 4) Shift the values in the right node to their correct position.
-  params_type::move(alloc, right->slot(to_move), right->finish_slot(),
-                    right->start_slot());
-
-  // 5) Destroy the now-empty to_move entries in the right node.
-  right->value_destroy_n(right->finish() - to_move, to_move, alloc);
+  // 4) Shift the values in the right node to their correct positions.
+  right->transfer_n(right->count() - to_move, right->start(),
+                    right->start() + to_move, right, alloc);
 
   if (!leaf()) {
     // Move the child pointers from the right to the left node.
@@ -1629,54 +1643,19 @@
   // Lastly, a new delimiting value is moved from the left node into the
   // parent, and the remaining empty left node entries are destroyed.
 
-  if (right->count() >= to_move) {
-    // The original location of the right->count() values are sufficient to hold
-    // the new to_move entries from the parent and left node.
+  // 1) Shift existing values in the right node to their correct positions.
+  right->transfer_n_backward(right->count(), right->start() + to_move,
+                             right->start(), right, alloc);
 
-    // 1) Shift existing values in the right node to their correct positions.
-    right->uninitialized_move_n(to_move, right->finish() - to_move,
-                                right->finish(), right, alloc);
-    for (slot_type *src = right->slot(right->finish() - to_move - 1),
-                   *dest = right->slot(right->finish() - 1),
-                   *end = right->start_slot();
-         src >= end; --src, --dest) {
-      params_type::move(alloc, src, dest);
-    }
+  // 2) Move the delimiting value in the parent to the right node.
+  right->transfer(right->start() + to_move - 1, position(), parent(), alloc);
 
-    // 2) Move the delimiting value in the parent to the right node.
-    params_type::move(alloc, parent()->slot(position()),
-                      right->slot(to_move - 1));
-
-    // 3) Move the (to_move - 1) values from the left node to the right node.
-    params_type::move(alloc, slot(finish() - (to_move - 1)), finish_slot(),
-                      right->start_slot());
-  } else {
-    // The right node does not have enough initialized space to hold the new
-    // to_move entries, so part of them will move to uninitialized space.
-
-    // 1) Shift existing values in the right node to their correct positions.
-    right->uninitialized_move_n(right->count(), right->start(),
-                                right->start() + to_move, right, alloc);
-
-    // 2) Move the delimiting value in the parent to the right node.
-    right->value_init(to_move - 1, alloc, parent()->slot(position()));
-
-    // 3) Move the (to_move - 1) values from the left node to the right node.
-    const size_type uninitialized_remaining = to_move - right->count() - 1;
-    uninitialized_move_n(uninitialized_remaining,
-                         finish() - uninitialized_remaining, right->finish(),
-                         right, alloc);
-    params_type::move(alloc, slot(finish() - (to_move - 1)),
-                      slot(finish() - uninitialized_remaining),
-                      right->start_slot());
-  }
+  // 3) Move the (to_move - 1) values from the left node to the right node.
+  right->transfer_n(to_move - 1, right->start(), finish() - (to_move - 1), this,
+                    alloc);
 
   // 4) Move the new delimiting value to the parent from the left node.
-  params_type::move(alloc, slot(finish() - to_move),
-                    parent()->slot(position()));
-
-  // 5) Destroy the now-empty to_move entries in the left node.
-  value_destroy_n(finish() - to_move, to_move, alloc);
+  parent()->transfer(position(), finish() - to_move, this, alloc);
 
   if (!leaf()) {
     // Move the child pointers from the left to the right node.
@@ -1716,10 +1695,7 @@
   assert(count() >= 1);
 
   // Move values from the left sibling to the right sibling.
-  uninitialized_move_n(dest->count(), finish(), dest->start(), dest, alloc);
-
-  // Destroy the now-empty entries in the left node.
-  value_destroy_n(finish(), dest->count(), alloc);
+  dest->transfer_n(dest->count(), dest->start(), finish(), this, alloc);
 
   // The split key is the largest value in the left sibling.
   --mutable_finish();
@@ -1746,11 +1722,7 @@
   value_init(finish(), alloc, parent()->slot(position()));
 
   // Move the values from the right to the left node.
-  src->uninitialized_move_n(src->count(), src->start(), finish() + 1, this,
-                            alloc);
-
-  // Destroy the now-empty entries in the right node.
-  src->value_destroy_n(src->start(), src->count(), alloc);
+  transfer_n(src->count(), finish() + 1, src->start(), src, alloc);
 
   if (!leaf()) {
     // Move the child pointers from the right to the left node.
@@ -2474,9 +2446,8 @@
       // 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->transfer_n(old_root->count(), new_root->start(),
+                           old_root->start(), old_root, alloc);
       new_root->set_finish(old_root->finish());
       old_root->set_finish(old_root->start());
       delete_leaf_node(old_root);
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel
index 8f521be..ff62792 100644
--- a/absl/debugging/BUILD.bazel
+++ b/absl/debugging/BUILD.bazel
@@ -55,6 +55,7 @@
     name = "symbolize",
     srcs = [
         "symbolize.cc",
+        "symbolize_darwin.inc",
         "symbolize_elf.inc",
         "symbolize_unimplemented.inc",
         "symbolize_win32.inc",
@@ -77,6 +78,7 @@
         "//absl/base:dynamic_annotations",
         "//absl/base:malloc_internal",
         "//absl/base:raw_logging_internal",
+        "//absl/strings",
     ],
 )
 
diff --git a/absl/debugging/BUILD.gn b/absl/debugging/BUILD.gn
index 3a37cdb..05b400e 100644
--- a/absl/debugging/BUILD.gn
+++ b/absl/debugging/BUILD.gn
@@ -29,6 +29,7 @@
 absl_source_set("symbolize") {
   sources = [
     "symbolize.cc",
+    "symbolize_darwin.inc",
     "symbolize_elf.inc",
     "symbolize_unimplemented.inc",
     "symbolize_win32.inc",
@@ -46,6 +47,7 @@
     "//third_party/abseil-cpp/absl/base:dynamic_annotations",
     "//third_party/abseil-cpp/absl/base:malloc_internal",
     "//third_party/abseil-cpp/absl/base:raw_logging_internal",
+    "//third_party/abseil-cpp/absl/strings",
   ]
 
   # TODO(mbonadei): The bazel file has:
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt
index 7733615..995e888 100644
--- a/absl/debugging/CMakeLists.txt
+++ b/absl/debugging/CMakeLists.txt
@@ -46,6 +46,7 @@
     "internal/symbolize.h"
   SRCS
     "symbolize.cc"
+    "symbolize_darwin.inc"
     "symbolize_elf.inc"
     "symbolize_unimplemented.inc"
     "symbolize_win32.inc"
@@ -63,6 +64,7 @@
     absl::dynamic_annotations
     absl::malloc_internal
     absl::raw_logging_internal
+    absl::strings
   PUBLIC
 )
 
diff --git a/absl/debugging/internal/examine_stack.cc b/absl/debugging/internal/examine_stack.cc
index a3dd893..6e5ff1f 100644
--- a/absl/debugging/internal/examine_stack.cc
+++ b/absl/debugging/internal/examine_stack.cc
@@ -20,6 +20,10 @@
 #include <unistd.h>
 #endif
 
+#ifdef __APPLE__
+#include <sys/ucontext.h>
+#endif
+
 #include <csignal>
 #include <cstdio>
 
@@ -66,6 +70,32 @@
 #error "Undefined Architecture."
 #endif
   }
+#elif defined(__APPLE__)
+  if (vuc != nullptr) {
+    ucontext_t* signal_ucontext = reinterpret_cast<ucontext_t*>(vuc);
+#if defined(__aarch64__)
+    return reinterpret_cast<void*>(
+        __darwin_arm_thread_state64_get_pc(signal_ucontext->uc_mcontext->__ss));
+#elif defined(__arm__)
+#if __DARWIN_UNIX03
+    return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__pc);
+#else
+    return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.pc);
+#endif
+#elif defined(__i386__)
+#if __DARWIN_UNIX03
+    return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__eip);
+#else
+    return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.eip);
+#endif
+#elif defined(__x86_64__)
+#if __DARWIN_UNIX03
+    return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__rip);
+#else
+    return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.rip);
+#endif
+#endif
+  }
 #elif defined(__akaros__)
   auto* ctx = reinterpret_cast<struct user_context*>(vuc);
   return reinterpret_cast<void*>(get_user_ctx_pc(ctx));
diff --git a/absl/debugging/internal/stacktrace_config.h b/absl/debugging/internal/stacktrace_config.h
index d4e8480..d5cc174 100644
--- a/absl/debugging/internal/stacktrace_config.h
+++ b/absl/debugging/internal/stacktrace_config.h
@@ -28,6 +28,27 @@
 #define ABSL_STACKTRACE_INL_HEADER \
     "absl/debugging/internal/stacktrace_win32-inl.inc"
 
+#elif defined(__APPLE__)
+// Thread local support required for UnwindImpl.
+// Notes:
+// * Xcode's clang did not support `thread_local` until version 8, and
+//   even then not for all iOS < 9.0.
+// * Xcode 9.3 started disallowing `thread_local` for 32-bit iOS simulator
+//   targeting iOS 9.x.
+// * Xcode 10 moves the deployment target check for iOS < 9.0 to link time
+//   making __has_feature unreliable there.
+//
+// Otherwise, `__has_feature` is only supported by Clang so it has be inside
+// `defined(__APPLE__)` check.
+#if __has_feature(cxx_thread_local) && \
+    !(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
+#define ABSL_STACKTRACE_INL_HEADER \
+  "absl/debugging/internal/stacktrace_generic-inl.inc"
+#else
+#define ABSL_STACKTRACE_INL_HEADER \
+  "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
+#endif
+
 #elif defined(__linux__) && !defined(__ANDROID__)
 
 #if !defined(NO_FRAME_POINTER)
@@ -40,7 +61,7 @@
 # elif defined(__aarch64__)
 #define ABSL_STACKTRACE_INL_HEADER \
     "absl/debugging/internal/stacktrace_aarch64-inl.inc"
-# elif defined(__arm__)
+#elif defined(__arm__) && defined(__GLIBC__)
 // Note: When using glibc this may require -funwind-tables to function properly.
 #define ABSL_STACKTRACE_INL_HEADER \
   "absl/debugging/internal/stacktrace_generic-inl.inc"
diff --git a/absl/debugging/internal/symbolize.h b/absl/debugging/internal/symbolize.h
index 5d0858b..8789e69 100644
--- a/absl/debugging/internal/symbolize.h
+++ b/absl/debugging/internal/symbolize.h
@@ -59,6 +59,12 @@
 
 #endif  // ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
 
+#ifdef ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE
+#error ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE cannot be directly set
+#elif defined(__APPLE__)
+#define ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE 1
+#endif
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace debugging_internal {
diff --git a/absl/debugging/symbolize.cc b/absl/debugging/symbolize.cc
index 54ed970..eec7a6e 100644
--- a/absl/debugging/symbolize.cc
+++ b/absl/debugging/symbolize.cc
@@ -20,6 +20,8 @@
 // The Windows Symbolizer only works if PDB files containing the debug info
 // are available to the program at runtime.
 #include "absl/debugging/symbolize_win32.inc"
+#elif defined(__APPLE__)
+#include "absl/debugging/symbolize_darwin.inc"
 #else
 #include "absl/debugging/symbolize_unimplemented.inc"
 #endif
diff --git a/absl/debugging/symbolize_darwin.inc b/absl/debugging/symbolize_darwin.inc
new file mode 100644
index 0000000..cdadd40
--- /dev/null
+++ b/absl/debugging/symbolize_darwin.inc
@@ -0,0 +1,101 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <cxxabi.h>
+#include <execinfo.h>
+
+#include <algorithm>
+#include <cstring>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/debugging/internal/demangle.h"
+#include "absl/strings/numbers.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+void InitializeSymbolizer(const char*) {}
+
+namespace debugging_internal {
+namespace {
+
+static std::string GetSymbolString(absl::string_view backtrace_line) {
+  // Example Backtrace lines:
+  // 0   libimaging_shared.dylib             0x018c152a
+  // _ZNSt11_Deque_baseIN3nik7mediadb4PageESaIS2_EE17_M_initialize_mapEm + 3478
+  //
+  // or
+  // 0   libimaging_shared.dylib             0x0000000001895c39
+  // _ZN3nik4util19register_shared_ptrINS_3gpu7TextureEEEvPKvS5_ + 39
+  //
+  // or
+  // 0   mysterious_app                      0x0124000120120009 main + 17
+  auto address_pos = backtrace_line.find(" 0x");
+  if (address_pos == absl::string_view::npos) return std::string();
+  absl::string_view symbol_view = backtrace_line.substr(address_pos + 1);
+
+  auto space_pos = symbol_view.find(" ");
+  if (space_pos == absl::string_view::npos) return std::string();
+  symbol_view = symbol_view.substr(space_pos + 1);  // to mangled symbol
+
+  auto plus_pos = symbol_view.find(" + ");
+  if (plus_pos == absl::string_view::npos) return std::string();
+  symbol_view = symbol_view.substr(0, plus_pos);  // strip remainng
+
+  return std::string(symbol_view);
+}
+
+}  // namespace
+}  // namespace debugging_internal
+
+bool Symbolize(const void* pc, char* out, int out_size) {
+  if (out_size <= 0 || pc == nullptr) {
+    out = nullptr;
+    return false;
+  }
+
+  // This allocates a char* array.
+  char** frame_strings = backtrace_symbols(const_cast<void**>(&pc), 1);
+
+  if (frame_strings == nullptr) return false;
+
+  std::string symbol = debugging_internal::GetSymbolString(frame_strings[0]);
+  free(frame_strings);
+
+  char tmp_buf[1024];
+  if (debugging_internal::Demangle(symbol.c_str(), tmp_buf, sizeof(tmp_buf))) {
+    int len = strlen(tmp_buf);
+    if (len + 1 <= out_size) {  // +1 for '\0'
+      assert(len < sizeof(tmp_buf));
+      memmove(out, tmp_buf, len + 1);
+    }
+  } else {
+    strncpy(out, symbol.c_str(), out_size);
+  }
+
+  if (out[out_size - 1] != '\0') {
+    // strncpy() does not '\0' terminate when it truncates.
+    static constexpr char kEllipsis[] = "...";
+    int ellipsis_size = std::min<int>(sizeof(kEllipsis) - 1, out_size - 1);
+    memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size);
+    out[out_size - 1] = '\0';
+  }
+
+  return true;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc
index a1d03aa..e476d82 100644
--- a/absl/debugging/symbolize_test.cc
+++ b/absl/debugging/symbolize_test.cc
@@ -144,7 +144,8 @@
   return TrySymbolizeWithLimit(pc, sizeof(try_symbolize_buffer));
 }
 
-#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) || \
+    defined(ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE)
 
 TEST(Symbolize, Cached) {
   // Compilers should give us pointers to them.
@@ -258,6 +259,7 @@
 
 #endif  // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
 
+#ifndef ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE
 // Use a 64K page size for PPC.
 const size_t kPageSize = 64 << 10;
 // We place a read-only symbols into the .text section and verify that we can
@@ -413,6 +415,7 @@
 
   close(fd);
 }
+#endif  // !ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE
 
 // x86 specific tests.  Uses some inline assembler.
 extern "C" {
@@ -541,7 +544,8 @@
   absl::InitializeSymbolizer(argv[0]);
   testing::InitGoogleTest(&argc, argv);
 
-#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) || \
+    defined(ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE)
   TestWithPCInsideInlineFunction();
   TestWithPCInsideNonInlineFunction();
   TestWithReturnAddress();
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel
index 6ffd07c..37c9a10 100644
--- a/absl/flags/BUILD.bazel
+++ b/absl/flags/BUILD.bazel
@@ -159,14 +159,13 @@
 )
 
 cc_library(
-    name = "registry",
+    name = "reflection",
     srcs = [
-        "internal/registry.cc",
-        "internal/type_erased.cc",
+        "reflection.cc",
     ],
     hdrs = [
         "internal/registry.h",
-        "internal/type_erased.h",
+        "reflection.h",
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
@@ -180,7 +179,6 @@
         ":private_handle_accessor",
         "//absl/base:config",
         "//absl/base:core_headers",
-        "//absl/base:raw_logging_internal",
         "//absl/strings",
         "//absl/synchronization",
     ],
@@ -202,7 +200,7 @@
         ":commandlineflag_internal",
         ":config",
         ":marshalling",
-        ":registry",
+        ":reflection",
         "//absl/base",
         "//absl/base:config",
         "//absl/base:core_headers",
@@ -228,7 +226,7 @@
     deps = [
         ":config",
         ":flag_internal",
-        ":registry",
+        ":reflection",
         "//absl/base",
         "//absl/base:config",
         "//absl/base:core_headers",
@@ -257,7 +255,7 @@
         ":path_util",
         ":private_handle_accessor",
         ":program_name",
-        ":registry",
+        ":reflection",
         "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/strings",
@@ -300,7 +298,7 @@
         ":flag_internal",
         ":private_handle_accessor",
         ":program_name",
-        ":registry",
+        ":reflection",
         ":usage",
         ":usage_internal",
         "//absl/base:config",
@@ -327,7 +325,7 @@
         ":config",
         ":flag",
         ":private_handle_accessor",
-        ":registry",
+        ":reflection",
         "//absl/memory",
         "//absl/strings",
         "@com_google_googletest//:gtest_main",
@@ -362,7 +360,7 @@
         ":flag",
         ":flag_internal",
         ":marshalling",
-        ":registry",
+        ":reflection",
         "//absl/base:core_headers",
         "//absl/base:malloc_internal",
         "//absl/strings",
@@ -415,7 +413,7 @@
     deps = [
         ":flag",
         ":parse",
-        ":registry",
+        ":reflection",
         "//absl/base:raw_logging_internal",
         "//absl/base:scoped_set_env",
         "//absl/strings",
@@ -454,17 +452,18 @@
 )
 
 cc_test(
-    name = "type_erased_test",
+    name = "reflection_test",
     size = "small",
     srcs = [
-        "internal/type_erased_test.cc",
+        "reflection_test.cc",
     ],
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":commandlineflag_internal",
         ":flag",
-        ":registry",
+        ":marshalling",
+        ":reflection",
         "//absl/memory",
         "@com_google_googletest//:gtest_main",
     ],
@@ -501,7 +500,7 @@
         ":parse",
         ":path_util",
         ":program_name",
-        ":registry",
+        ":reflection",
         ":usage",
         ":usage_internal",
         "//absl/strings",
diff --git a/absl/flags/BUILD.gn b/absl/flags/BUILD.gn
index 3a6eca1..537acc6 100644
--- a/absl/flags/BUILD.gn
+++ b/absl/flags/BUILD.gn
@@ -103,15 +103,12 @@
   visibility += [ ":*" ]
 }
 
-absl_source_set("registry") {
+absl_source_set("reflection") {
   testonly = true
-  sources = [
-    "internal/registry.cc",
-    "internal/type_erased.cc",
-  ]
+  sources = [ "reflection.cc" ]
   public = [
     "internal/registry.h",
-    "internal/type_erased.h",
+    "reflection.h",
   ]
   deps = [
     ":commandlineflag",
@@ -120,7 +117,6 @@
     ":private_handle_accessor",
     "//third_party/abseil-cpp/absl/base:config",
     "//third_party/abseil-cpp/absl/base:core_headers",
-    "//third_party/abseil-cpp/absl/base:raw_logging_internal",
     "//third_party/abseil-cpp/absl/strings",
     "//third_party/abseil-cpp/absl/synchronization",
   ]
@@ -137,7 +133,7 @@
     ":commandlineflag_internal",
     ":config",
     ":marshalling",
-    ":registry",
+    ":reflection",
     "//third_party/abseil-cpp/absl/base",
     "//third_party/abseil-cpp/absl/base:config",
     "//third_party/abseil-cpp/absl/base:core_headers",
@@ -164,7 +160,7 @@
   deps = [
     ":config",
     ":flag_internal",
-    ":registry",
+    ":reflection",
     "//third_party/abseil-cpp/absl/base",
     "//third_party/abseil-cpp/absl/base:config",
     "//third_party/abseil-cpp/absl/base:core_headers",
@@ -184,7 +180,7 @@
     ":path_util",
     ":private_handle_accessor",
     ":program_name",
-    ":registry",
+    ":reflection",
     "//third_party/abseil-cpp/absl/base:config",
     "//third_party/abseil-cpp/absl/base:core_headers",
     "//third_party/abseil-cpp/absl/strings",
@@ -221,7 +217,7 @@
     ":flag_internal",
     ":private_handle_accessor",
     ":program_name",
-    ":registry",
+    ":reflection",
     ":usage",
     ":usage_internal",
     "//third_party/abseil-cpp/absl/base:config",
diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt
index 2dc7cf4..ef75db8 100644
--- a/absl/flags/CMakeLists.txt
+++ b/absl/flags/CMakeLists.txt
@@ -144,16 +144,14 @@
     absl::strings
 )
 
-# Internal-only target, do not depend on directly.
 absl_cc_library(
   NAME
-    flags_registry
+    flags_reflection
   SRCS
-    "internal/registry.cc"
-    "internal/type_erased.cc"
+    "reflection.cc"
   HDRS
+    "reflection.h"
     "internal/registry.h"
-    "internal/type_erased.h"
   COPTS
     ${ABSL_DEFAULT_COPTS}
   LINKOPTS
@@ -161,10 +159,8 @@
   DEPS
     absl::config
     absl::flags_commandlineflag
-    absl::flags_config
     absl::flags_private_handle_accessor
-    absl::core_headers
-    absl::raw_logging_internal
+    absl::flags_config
     absl::strings
     absl::synchronization
 )
@@ -187,7 +183,6 @@
     absl::flags_commandlineflag_internal
     absl::flags_config
     absl::flags_marshalling
-    absl::flags_registry
     absl::synchronization
     absl::meta
     absl::utility
@@ -211,7 +206,7 @@
     absl::flags_commandlineflag
     absl::flags_config
     absl::flags_internal
-    absl::flags_registry
+    absl::flags_reflection
     absl::base
     absl::core_headers
     absl::strings
@@ -238,7 +233,7 @@
     absl::flags_path_util
     absl::flags_private_handle_accessor
     absl::flags_program_name
-    absl::flags_registry
+    absl::flags_reflection
     absl::strings
     absl::synchronization
 )
@@ -284,7 +279,7 @@
     absl::flags_internal
     absl::flags_private_handle_accessor
     absl::flags_program_name
-    absl::flags_registry
+    absl::flags_reflection
     absl::flags_usage
     absl::strings
     absl::synchronization
@@ -306,7 +301,7 @@
     absl::flags_commandlineflag_internal
     absl::flags_config
     absl::flags_private_handle_accessor
-    absl::flags_registry
+    absl::flags_reflection
     absl::memory
     absl::strings
     gtest_main
@@ -338,7 +333,7 @@
     absl::flags_config
     absl::flags_internal
     absl::flags_marshalling
-    absl::flags_registry
+    absl::flags_reflection
     absl::strings
     absl::time
     gtest_main
@@ -366,7 +361,7 @@
   DEPS
     absl::flags
     absl::flags_parse
-    absl::flags_registry
+    absl::flags_reflection
     absl::raw_logging_internal
     absl::scoped_set_env
     absl::span
@@ -401,15 +396,15 @@
 
 absl_cc_test(
   NAME
-    flags_type_erased_test
+    flags_reflection_test
   SRCS
-    "internal/type_erased_test.cc"
+    "reflection_test.cc"
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
     absl::flags_commandlineflag_internal
     absl::flags
-    absl::flags_registry
+    absl::flags_reflection
     absl::memory
     absl::strings
     gtest_main
@@ -443,7 +438,7 @@
     absl::flags_path_util
     absl::flags_program_name
     absl::flags_parse
-    absl::flags_registry
+    absl::flags_reflection
     absl::flags_usage
     absl::strings
     gtest
diff --git a/absl/flags/commandlineflag_test.cc b/absl/flags/commandlineflag_test.cc
index 570bbe2..585db4b 100644
--- a/absl/flags/commandlineflag_test.cc
+++ b/absl/flags/commandlineflag_test.cc
@@ -22,7 +22,7 @@
 #include "absl/flags/flag.h"
 #include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/private_handle_accessor.h"
-#include "absl/flags/internal/registry.h"
+#include "absl/flags/reflection.h"
 #include "absl/flags/usage_config.h"
 #include "absl/memory/memory.h"
 #include "absl/strings/match.h"
@@ -34,6 +34,10 @@
           absl::StrCat("string_flag", " help"));
 ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
 
+// These are only used to test default values.
+ABSL_FLAG(int, int_flag2, 201, "");
+ABSL_FLAG(std::string, string_flag2, "dflt", "");
+
 namespace {
 
 namespace flags = absl::flags_internal;
@@ -47,7 +51,7 @@
     absl::SetFlagsUsageConfig(default_config);
   }
 
-  void SetUp() override { flag_saver_ = absl::make_unique<flags::FlagSaver>(); }
+  void SetUp() override { flag_saver_ = absl::make_unique<absl::FlagSaver>(); }
   void TearDown() override { flag_saver_.reset(); }
 
  private:
@@ -60,11 +64,11 @@
     return std::string(fname);
   }
 
-  std::unique_ptr<flags::FlagSaver> flag_saver_;
+  std::unique_ptr<absl::FlagSaver> flag_saver_;
 };
 
 TEST_F(CommandLineFlagTest, TestAttributesAccessMethods) {
-  auto* flag_01 = flags::FindCommandLineFlag("int_flag");
+  auto* flag_01 = absl::FindCommandLineFlag("int_flag");
 
   ASSERT_TRUE(flag_01);
   EXPECT_EQ(flag_01->Name(), "int_flag");
@@ -77,7 +81,7 @@
                              "absl/flags/commandlineflag_test.cc"))
       << flag_01->Filename();
 
-  auto* flag_02 = flags::FindCommandLineFlag("string_flag");
+  auto* flag_02 = absl::FindCommandLineFlag("string_flag");
 
   ASSERT_TRUE(flag_02);
   EXPECT_EQ(flag_02->Name(), "string_flag");
@@ -89,31 +93,20 @@
   EXPECT_TRUE(absl::EndsWith(flag_02->Filename(),
                              "absl/flags/commandlineflag_test.cc"))
       << flag_02->Filename();
-
-  auto* flag_03 = flags::FindRetiredFlag("bool_retired_flag");
-
-  ASSERT_TRUE(flag_03);
-  EXPECT_EQ(flag_03->Name(), "bool_retired_flag");
-  EXPECT_EQ(flag_03->Help(), "");
-  EXPECT_TRUE(flag_03->IsRetired());
-  EXPECT_TRUE(flag_03->IsOfType<bool>());
-  EXPECT_TRUE(!flag_03->IsOfType<int>());
-  EXPECT_TRUE(!flag_03->IsOfType<std::string>());
-  EXPECT_EQ(flag_03->Filename(), "RETIRED");
 }
 
 // --------------------------------------------------------------------
 
 TEST_F(CommandLineFlagTest, TestValueAccessMethods) {
-  absl::SetFlag(&FLAGS_int_flag, 301);
-  auto* flag_01 = flags::FindCommandLineFlag("int_flag");
+  absl::SetFlag(&FLAGS_int_flag2, 301);
+  auto* flag_01 = absl::FindCommandLineFlag("int_flag2");
 
   ASSERT_TRUE(flag_01);
   EXPECT_EQ(flag_01->CurrentValue(), "301");
   EXPECT_EQ(flag_01->DefaultValue(), "201");
 
-  absl::SetFlag(&FLAGS_string_flag, "new_str_value");
-  auto* flag_02 = flags::FindCommandLineFlag("string_flag");
+  absl::SetFlag(&FLAGS_string_flag2, "new_str_value");
+  auto* flag_02 = absl::FindCommandLineFlag("string_flag2");
 
   ASSERT_TRUE(flag_02);
   EXPECT_EQ(flag_02->CurrentValue(), "new_str_value");
@@ -125,7 +118,7 @@
 TEST_F(CommandLineFlagTest, TestParseFromCurrentValue) {
   std::string err;
 
-  auto* flag_01 = flags::FindCommandLineFlag("int_flag");
+  auto* flag_01 = absl::FindCommandLineFlag("int_flag");
   EXPECT_FALSE(
       flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
 
@@ -173,7 +166,7 @@
       *flag_01, "", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err));
   EXPECT_EQ(err, "Illegal value '' specified for flag 'int_flag'");
 
-  auto* flag_02 = flags::FindCommandLineFlag("string_flag");
+  auto* flag_02 = absl::FindCommandLineFlag("string_flag");
   EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
       *flag_02, "xyz", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
       err));
@@ -189,14 +182,14 @@
 TEST_F(CommandLineFlagTest, TestParseFromDefaultValue) {
   std::string err;
 
-  auto* flag_01 = flags::FindCommandLineFlag("int_flag");
+  auto* flag_01 = absl::FindCommandLineFlag("int_flag");
 
   EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
       *flag_01, "111", flags::SET_FLAGS_DEFAULT, flags::kProgrammaticChange,
       err));
   EXPECT_EQ(flag_01->DefaultValue(), "111");
 
-  auto* flag_02 = flags::FindCommandLineFlag("string_flag");
+  auto* flag_02 = absl::FindCommandLineFlag("string_flag");
 
   EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
       *flag_02, "abc", flags::SET_FLAGS_DEFAULT, flags::kProgrammaticChange,
@@ -209,7 +202,7 @@
 TEST_F(CommandLineFlagTest, TestParseFromIfDefault) {
   std::string err;
 
-  auto* flag_01 = flags::FindCommandLineFlag("int_flag");
+  auto* flag_01 = absl::FindCommandLineFlag("int_flag");
 
   EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
       *flag_01, "22", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange,
diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc
index 71661d3..2eb2ba7 100644
--- a/absl/flags/flag_test.cc
+++ b/absl/flags/flag_test.cc
@@ -29,8 +29,8 @@
 #include "absl/flags/config.h"
 #include "absl/flags/declare.h"
 #include "absl/flags/internal/flag.h"
-#include "absl/flags/internal/registry.h"
 #include "absl/flags/marshalling.h"
+#include "absl/flags/reflection.h"
 #include "absl/flags/usage_config.h"
 #include "absl/strings/match.h"
 #include "absl/strings/numbers.h"
@@ -81,7 +81,7 @@
 #endif
     return std::string(fname);
   }
-  flags::FlagSaver flag_saver_;
+  absl::FlagSaver flag_saver_;
 };
 
 struct S1 {
@@ -555,29 +555,29 @@
 // --------------------------------------------------------------------
 
 TEST_F(FlagTest, TestGetViaReflection) {
-  auto* handle = flags::FindCommandLineFlag("test_flag_01");
+  auto* handle = absl::FindCommandLineFlag("test_flag_01");
   EXPECT_EQ(*handle->TryGet<bool>(), true);
-  handle = flags::FindCommandLineFlag("test_flag_02");
+  handle = absl::FindCommandLineFlag("test_flag_02");
   EXPECT_EQ(*handle->TryGet<int>(), 1234);
-  handle = flags::FindCommandLineFlag("test_flag_03");
+  handle = absl::FindCommandLineFlag("test_flag_03");
   EXPECT_EQ(*handle->TryGet<int16_t>(), -34);
-  handle = flags::FindCommandLineFlag("test_flag_04");
+  handle = absl::FindCommandLineFlag("test_flag_04");
   EXPECT_EQ(*handle->TryGet<uint16_t>(), 189);
-  handle = flags::FindCommandLineFlag("test_flag_05");
+  handle = absl::FindCommandLineFlag("test_flag_05");
   EXPECT_EQ(*handle->TryGet<int32_t>(), 10765);
-  handle = flags::FindCommandLineFlag("test_flag_06");
+  handle = absl::FindCommandLineFlag("test_flag_06");
   EXPECT_EQ(*handle->TryGet<uint32_t>(), 40000);
-  handle = flags::FindCommandLineFlag("test_flag_07");
+  handle = absl::FindCommandLineFlag("test_flag_07");
   EXPECT_EQ(*handle->TryGet<int64_t>(), -1234567);
-  handle = flags::FindCommandLineFlag("test_flag_08");
+  handle = absl::FindCommandLineFlag("test_flag_08");
   EXPECT_EQ(*handle->TryGet<uint64_t>(), 9876543);
-  handle = flags::FindCommandLineFlag("test_flag_09");
+  handle = absl::FindCommandLineFlag("test_flag_09");
   EXPECT_NEAR(*handle->TryGet<double>(), -9.876e-50, 1e-55);
-  handle = flags::FindCommandLineFlag("test_flag_10");
+  handle = absl::FindCommandLineFlag("test_flag_10");
   EXPECT_NEAR(*handle->TryGet<float>(), 1.234e12f, 1e5f);
-  handle = flags::FindCommandLineFlag("test_flag_11");
+  handle = absl::FindCommandLineFlag("test_flag_11");
   EXPECT_EQ(*handle->TryGet<std::string>(), "");
-  handle = flags::FindCommandLineFlag("test_flag_12");
+  handle = absl::FindCommandLineFlag("test_flag_12");
   EXPECT_EQ(*handle->TryGet<absl::Duration>(), absl::Minutes(10));
 }
 
@@ -815,14 +815,15 @@
 namespace {
 
 TEST_F(FlagTest, TestRetiredFlagRegistration) {
-  bool is_bool = false;
-  EXPECT_TRUE(flags::IsRetiredFlag("old_bool_flag", &is_bool));
-  EXPECT_TRUE(is_bool);
-  EXPECT_TRUE(flags::IsRetiredFlag("old_int_flag", &is_bool));
-  EXPECT_FALSE(is_bool);
-  EXPECT_TRUE(flags::IsRetiredFlag("old_str_flag", &is_bool));
-  EXPECT_FALSE(is_bool);
-  EXPECT_FALSE(flags::IsRetiredFlag("some_other_flag", &is_bool));
+  auto* handle = absl::FindCommandLineFlag("old_bool_flag");
+  EXPECT_TRUE(handle->IsOfType<bool>());
+  EXPECT_TRUE(handle->IsRetired());
+  handle = absl::FindCommandLineFlag("old_int_flag");
+  EXPECT_TRUE(handle->IsOfType<int>());
+  EXPECT_TRUE(handle->IsRetired());
+  handle = absl::FindCommandLineFlag("old_str_flag");
+  EXPECT_TRUE(handle->IsOfType<std::string>());
+  EXPECT_TRUE(handle->IsRetired());
 }
 
 }  // namespace
diff --git a/absl/flags/internal/program_name_test.cc b/absl/flags/internal/program_name_test.cc
index 269142f..aff9f63 100644
--- a/absl/flags/internal/program_name_test.cc
+++ b/absl/flags/internal/program_name_test.cc
@@ -25,7 +25,7 @@
 
 namespace flags = absl::flags_internal;
 
-TEST(FlagsPathUtilTest, TestInitialProgamName) {
+TEST(FlagsPathUtilTest, TestProgamNameInterfaces) {
   flags::SetProgramInvocationName("absl/flags/program_name_test");
   std::string program_name = flags::ProgramInvocationName();
   for (char& c : program_name)
@@ -43,9 +43,7 @@
 
   EXPECT_TRUE(absl::EndsWith(program_name, expect_name)) << program_name;
   EXPECT_EQ(flags::ShortProgramInvocationName(), expect_basename);
-}
 
-TEST(FlagsPathUtilTest, TestProgamNameInterfaces) {
   flags::SetProgramInvocationName("a/my_test");
 
   EXPECT_EQ(flags::ProgramInvocationName(), "a/my_test");
diff --git a/absl/flags/internal/registry.h b/absl/flags/internal/registry.h
index d207c22..c72eebe 100644
--- a/absl/flags/internal/registry.h
+++ b/absl/flags/internal/registry.h
@@ -28,10 +28,14 @@
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
+
+// TODO(rogeeff): remove this declaration
+CommandLineFlag* FindCommandLineFlag(absl::string_view name);
+
 namespace flags_internal {
 
-CommandLineFlag* FindCommandLineFlag(absl::string_view name);
-CommandLineFlag* FindRetiredFlag(absl::string_view name);
+// TODO(rogeeff): remove this alias
+using absl::FindCommandLineFlag;
 
 // Executes specified visitor for each non-retired flag in the registry.
 // Requires the caller hold the registry lock.
@@ -85,36 +89,6 @@
   return flags_internal::Retire(flag_name, base_internal::FastTypeId<T>());
 }
 
-// If the flag is retired, returns true and indicates in |*type_is_bool|
-// whether the type of the retired flag is a bool.
-// Only to be called by code that needs to explicitly ignore retired flags.
-bool IsRetiredFlag(absl::string_view name, bool* type_is_bool);
-
-//-----------------------------------------------------------------------------
-// Saves the states (value, default value, whether the user has set
-// the flag, registered validators, etc) of all flags, and restores
-// them when the FlagSaver is destroyed.
-//
-// This class is thread-safe.  However, its destructor writes to
-// exactly the set of flags that have changed value during its
-// lifetime, so concurrent _direct_ access to those flags
-// (i.e. FLAGS_foo instead of {Get,Set}CommandLineOption()) is unsafe.
-
-class FlagSaver {
- public:
-  FlagSaver();
-  ~FlagSaver();
-
-  FlagSaver(const FlagSaver&) = delete;
-  void operator=(const FlagSaver&) = delete;
-
-  // Prevents saver from restoring the saved state of flags.
-  void Ignore();
-
- private:
-  class FlagSaverImpl* impl_;  // we use pimpl here to keep API steady
-};
-
 }  // namespace flags_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/flags/internal/type_erased.cc b/absl/flags/internal/type_erased.cc
deleted file mode 100644
index b2523b2..0000000
--- a/absl/flags/internal/type_erased.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-//
-// Copyright 2019 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/flags/internal/type_erased.h"
-
-#include <assert.h>
-
-#include <string>
-
-#include "absl/base/config.h"
-#include "absl/base/internal/raw_logging.h"
-#include "absl/flags/commandlineflag.h"
-#include "absl/flags/internal/private_handle_accessor.h"
-#include "absl/flags/internal/registry.h"
-#include "absl/flags/usage_config.h"
-#include "absl/strings/string_view.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace flags_internal {
-
-bool GetCommandLineOption(absl::string_view name, std::string* value) {
-  if (name.empty()) return false;
-  assert(value);
-
-  CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
-  if (flag == nullptr || flag->IsRetired()) {
-    return false;
-  }
-
-  *value = flag->CurrentValue();
-  return true;
-}
-
-bool SetCommandLineOption(absl::string_view name, absl::string_view value) {
-  return SetCommandLineOptionWithMode(name, value,
-                                      flags_internal::SET_FLAGS_VALUE);
-}
-
-bool SetCommandLineOptionWithMode(absl::string_view name,
-                                  absl::string_view value,
-                                  FlagSettingMode set_mode) {
-  CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
-
-  if (!flag || flag->IsRetired()) return false;
-
-  std::string error;
-  if (!flags_internal::PrivateHandleAccessor::ParseFrom(
-          *flag, value, set_mode, kProgrammaticChange, error)) {
-    // Errors here are all of the form: the provided name was a recognized
-    // flag, but the value was invalid (bad type, or validation failed).
-    flags_internal::ReportUsageError(error, false);
-    return false;
-  }
-
-  return true;
-}
-
-// --------------------------------------------------------------------
-
-bool IsValidFlagValue(absl::string_view name, absl::string_view value) {
-  CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
-
-  return flag != nullptr &&
-         (flag->IsRetired() ||
-          flags_internal::PrivateHandleAccessor::ValidateInputValue(*flag,
-                                                                    value));
-}
-
-// --------------------------------------------------------------------
-
-}  // namespace flags_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
diff --git a/absl/flags/internal/type_erased.h b/absl/flags/internal/type_erased.h
deleted file mode 100644
index 437a8c2..0000000
--- a/absl/flags/internal/type_erased.h
+++ /dev/null
@@ -1,80 +0,0 @@
-//
-// Copyright 2019 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef ABSL_FLAGS_INTERNAL_TYPE_ERASED_H_
-#define ABSL_FLAGS_INTERNAL_TYPE_ERASED_H_
-
-#include <string>
-
-#include "absl/base/config.h"
-#include "absl/flags/commandlineflag.h"
-#include "absl/flags/internal/commandlineflag.h"
-#include "absl/flags/internal/registry.h"
-#include "absl/strings/string_view.h"
-
-// --------------------------------------------------------------------
-// Registry interfaces operating on type erased handles.
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace flags_internal {
-
-// If a flag named "name" exists, store its current value in *OUTPUT
-// and return true.  Else return false without changing *OUTPUT.
-// Thread-safe.
-bool GetCommandLineOption(absl::string_view name, std::string* value);
-
-// Set the value of the flag named "name" to value.  If successful,
-// returns true.  If not successful (e.g., the flag was not found or
-// the value is not a valid value), returns false.
-// Thread-safe.
-bool SetCommandLineOption(absl::string_view name, absl::string_view value);
-
-bool SetCommandLineOptionWithMode(absl::string_view name,
-                                  absl::string_view value,
-                                  FlagSettingMode set_mode);
-
-//-----------------------------------------------------------------------------
-
-// Returns true iff all of the following conditions are true:
-// (a) "name" names a registered flag
-// (b) "value" can be parsed succesfully according to the type of the flag
-// (c) parsed value passes any validator associated with the flag
-bool IsValidFlagValue(absl::string_view name, absl::string_view value);
-
-//-----------------------------------------------------------------------------
-
-// If a flag with specified "name" exists and has type T, store
-// its current value in *dst and return true.  Else return false
-// without touching *dst.  T must obey all of the requirements for
-// types passed to DEFINE_FLAG.
-template <typename T>
-inline bool GetByName(absl::string_view name, T* dst) {
-  CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
-  if (!flag) return false;
-
-  if (auto val = flag->TryGet<T>()) {
-    *dst = *val;
-    return true;
-  }
-
-  return false;
-}
-
-}  // namespace flags_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#endif  // ABSL_FLAGS_INTERNAL_TYPE_ERASED_H_
diff --git a/absl/flags/internal/type_erased_test.cc b/absl/flags/internal/type_erased_test.cc
deleted file mode 100644
index 42f374d..0000000
--- a/absl/flags/internal/type_erased_test.cc
+++ /dev/null
@@ -1,156 +0,0 @@
-//
-//  Copyright 2019 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/flags/internal/type_erased.h"
-
-#include <memory>
-#include <string>
-
-#include "gtest/gtest.h"
-#include "absl/flags/flag.h"
-#include "absl/flags/internal/commandlineflag.h"
-#include "absl/flags/internal/registry.h"
-#include "absl/memory/memory.h"
-
-ABSL_FLAG(int, int_flag, 1, "int_flag help");
-ABSL_FLAG(std::string, string_flag, "dflt", "string_flag help");
-ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
-
-namespace {
-
-namespace flags = absl::flags_internal;
-
-class TypeErasedTest : public testing::Test {
- protected:
-  void SetUp() override { flag_saver_ = absl::make_unique<flags::FlagSaver>(); }
-  void TearDown() override { flag_saver_.reset(); }
-
- private:
-  std::unique_ptr<flags::FlagSaver> flag_saver_;
-};
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestGetCommandLineOption) {
-  std::string value;
-  EXPECT_TRUE(flags::GetCommandLineOption("int_flag", &value));
-  EXPECT_EQ(value, "1");
-
-  EXPECT_TRUE(flags::GetCommandLineOption("string_flag", &value));
-  EXPECT_EQ(value, "dflt");
-
-  EXPECT_FALSE(flags::GetCommandLineOption("bool_retired_flag", &value));
-
-  EXPECT_FALSE(flags::GetCommandLineOption("unknown_flag", &value));
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestSetCommandLineOption) {
-  EXPECT_TRUE(flags::SetCommandLineOption("int_flag", "101"));
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
-
-  EXPECT_TRUE(flags::SetCommandLineOption("string_flag", "asdfgh"));
-  EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
-
-  EXPECT_FALSE(flags::SetCommandLineOption("bool_retired_flag", "true"));
-
-  EXPECT_FALSE(flags::SetCommandLineOption("unknown_flag", "true"));
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestSetCommandLineOptionWithMode_SET_FLAGS_VALUE) {
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "101",
-                                                  flags::SET_FLAGS_VALUE));
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
-
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("string_flag", "asdfgh",
-                                                  flags::SET_FLAGS_VALUE));
-  EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
-
-  EXPECT_FALSE(flags::SetCommandLineOptionWithMode("bool_retired_flag", "true",
-                                                   flags::SET_FLAGS_VALUE));
-
-  EXPECT_FALSE(flags::SetCommandLineOptionWithMode("unknown_flag", "true",
-                                                   flags::SET_FLAGS_VALUE));
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestSetCommandLineOptionWithMode_SET_FLAG_IF_DEFAULT) {
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "101",
-                                                  flags::SET_FLAG_IF_DEFAULT));
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
-
-  // This semantic is broken. We return true instead of false. Value is not
-  // updated.
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "202",
-                                                  flags::SET_FLAG_IF_DEFAULT));
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
-
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("string_flag", "asdfgh",
-                                                  flags::SET_FLAG_IF_DEFAULT));
-  EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
-
-  EXPECT_FALSE(flags::SetCommandLineOptionWithMode("bool_retired_flag", "true",
-                                                   flags::SET_FLAG_IF_DEFAULT));
-
-  EXPECT_FALSE(flags::SetCommandLineOptionWithMode("unknown_flag", "true",
-                                                   flags::SET_FLAG_IF_DEFAULT));
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestSetCommandLineOptionWithMode_SET_FLAGS_DEFAULT) {
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "101",
-                                                  flags::SET_FLAGS_DEFAULT));
-
-  // Set it again to ensure that resetting logic is covered.
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "102",
-                                                  flags::SET_FLAGS_DEFAULT));
-
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "103",
-                                                  flags::SET_FLAGS_DEFAULT));
-
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("string_flag", "asdfgh",
-                                                  flags::SET_FLAGS_DEFAULT));
-  EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
-
-  EXPECT_FALSE(flags::SetCommandLineOptionWithMode("bool_retired_flag", "true",
-                                                   flags::SET_FLAGS_DEFAULT));
-
-  EXPECT_FALSE(flags::SetCommandLineOptionWithMode("unknown_flag", "true",
-                                                   flags::SET_FLAGS_DEFAULT));
-
-  // This should be successfull, since flag is still is not set
-  EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "202",
-                                                  flags::SET_FLAG_IF_DEFAULT));
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 202);
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestIsValidFlagValue) {
-  EXPECT_TRUE(flags::IsValidFlagValue("int_flag", "57"));
-  EXPECT_TRUE(flags::IsValidFlagValue("int_flag", "-101"));
-  EXPECT_FALSE(flags::IsValidFlagValue("int_flag", "1.1"));
-
-  EXPECT_TRUE(flags::IsValidFlagValue("string_flag", "#%^#%^$%DGHDG$W%adsf"));
-
-  EXPECT_TRUE(flags::IsValidFlagValue("bool_retired_flag", "true"));
-}
-
-}  // namespace
diff --git a/absl/flags/internal/usage_test.cc b/absl/flags/internal/usage_test.cc
index 53b4d98..6e583fb 100644
--- a/absl/flags/internal/usage_test.cc
+++ b/absl/flags/internal/usage_test.cc
@@ -25,7 +25,7 @@
 #include "absl/flags/internal/parse.h"
 #include "absl/flags/internal/path_util.h"
 #include "absl/flags/internal/program_name.h"
-#include "absl/flags/internal/registry.h"
+#include "absl/flags/reflection.h"
 #include "absl/flags/usage.h"
 #include "absl/flags/usage_config.h"
 #include "absl/strings/match.h"
@@ -89,7 +89,7 @@
   }
 
  private:
-  flags::FlagSaver flag_saver_;
+  absl::FlagSaver flag_saver_;
 };
 
 // --------------------------------------------------------------------
@@ -110,7 +110,7 @@
 // --------------------------------------------------------------------
 
 TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_01) {
-  const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_01");
+  const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_01");
   std::stringstream test_buf;
 
   flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
@@ -122,7 +122,7 @@
 }
 
 TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_02) {
-  const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_02");
+  const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_02");
   std::stringstream test_buf;
 
   flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
@@ -134,7 +134,7 @@
 }
 
 TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_03) {
-  const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_03");
+  const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_03");
   std::stringstream test_buf;
 
   flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
@@ -146,7 +146,7 @@
 }
 
 TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_04) {
-  const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_04");
+  const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_04");
   std::stringstream test_buf;
 
   flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
@@ -158,7 +158,7 @@
 }
 
 TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_05) {
-  const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_05");
+  const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_05");
   std::stringstream test_buf;
 
   flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc
index f0a131f..e2c88ff 100644
--- a/absl/flags/parse.cc
+++ b/absl/flags/parse.cc
@@ -42,8 +42,8 @@
 #include "absl/flags/internal/parse.h"
 #include "absl/flags/internal/private_handle_accessor.h"
 #include "absl/flags/internal/program_name.h"
-#include "absl/flags/internal/registry.h"
 #include "absl/flags/internal/usage.h"
+#include "absl/flags/reflection.h"
 #include "absl/flags/usage.h"
 #include "absl/flags/usage_config.h"
 #include "absl/strings/ascii.h"
@@ -290,11 +290,11 @@
 //  found flag or nullptr
 //  is negative in case of --nofoo
 std::tuple<CommandLineFlag*, bool> LocateFlag(absl::string_view flag_name) {
-  CommandLineFlag* flag = flags_internal::FindCommandLineFlag(flag_name);
+  CommandLineFlag* flag = absl::FindCommandLineFlag(flag_name);
   bool is_negative = false;
 
   if (!flag && absl::ConsumePrefix(&flag_name, "no")) {
-    flag = flags_internal::FindCommandLineFlag(flag_name);
+    flag = absl::FindCommandLineFlag(flag_name);
     is_negative = true;
   }
 
diff --git a/absl/flags/parse_test.cc b/absl/flags/parse_test.cc
index aea068e..d35a6e4 100644
--- a/absl/flags/parse_test.cc
+++ b/absl/flags/parse_test.cc
@@ -28,7 +28,7 @@
 #include "absl/flags/declare.h"
 #include "absl/flags/flag.h"
 #include "absl/flags/internal/parse.h"
-#include "absl/flags/internal/registry.h"
+#include "absl/flags/reflection.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
 #include "absl/strings/substitute.h"
@@ -208,7 +208,7 @@
 
 class ParseTest : public testing::Test {
  private:
-  flags::FlagSaver flag_saver_;
+  absl::FlagSaver flag_saver_;
 };
 
 // --------------------------------------------------------------------
@@ -637,6 +637,10 @@
       "--flagfile=$0/parse_test.ff2",
   };
 
+  GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)},
+                   {"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
+                      flagfile_flag);
+
   const char* in_args1[] = {
       "testbin",
       GetFlagfileFlag({{"parse_test.ff3", absl::MakeConstSpan(ff3_data)}},
diff --git a/absl/flags/internal/registry.cc b/absl/flags/reflection.cc
similarity index 81%
rename from absl/flags/internal/registry.cc
rename to absl/flags/reflection.cc
index e582d79..5fc945f 100644
--- a/absl/flags/internal/registry.cc
+++ b/absl/flags/reflection.cc
@@ -1,5 +1,5 @@
 //
-// Copyright 2019 The Abseil Authors.
+//  Copyright 2020 The Abseil Authors.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -13,47 +13,34 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "absl/flags/internal/registry.h"
+#include "absl/flags/reflection.h"
 
 #include <assert.h>
-#include <stdlib.h>
 
-#include <functional>
 #include <map>
-#include <memory>
 #include <string>
-#include <utility>
-#include <vector>
 
 #include "absl/base/config.h"
-#include "absl/base/internal/raw_logging.h"
 #include "absl/base/thread_annotations.h"
 #include "absl/flags/commandlineflag.h"
-#include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/private_handle_accessor.h"
+#include "absl/flags/internal/registry.h"
 #include "absl/flags/usage_config.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
 #include "absl/synchronization/mutex.h"
 
-// --------------------------------------------------------------------
-// FlagRegistry implementation
-//    A FlagRegistry holds all flag objects indexed
-//    by their names so that if you know a flag's name you can access or
-//    set it.
-
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace flags_internal {
 
 // --------------------------------------------------------------------
 // FlagRegistry
-//    A FlagRegistry singleton object holds all flag objects indexed
-//    by their names so that if you know a flag's name (as a C
-//    string), you can access or set it.  If the function is named
-//    FooLocked(), you must own the registry lock before calling
-//    the function; otherwise, you should *not* hold the lock, and
-//    the function will acquire it itself if needed.
+//    A FlagRegistry singleton object holds all flag objects indexed by their
+//    names so that if you know a flag's name, you can access or set it. If the
+//    function is named FooLocked(), you must own the registry lock before
+//    calling the function; otherwise, you should *not* hold the lock, and the
+//    function will acquire it itself if needed.
 // --------------------------------------------------------------------
 
 class FlagRegistry {
@@ -78,7 +65,8 @@
   static FlagRegistry& GlobalRegistry();  // returns a singleton registry
 
  private:
-  friend class FlagSaverImpl;  // reads all the flags in order to copy them
+  friend class flags_internal::FlagSaverImpl;  // reads all the flags in order
+                                               // to copy them
   friend void ForEachFlagUnlocked(
       std::function<void(CommandLineFlag&)> visitor);
 
@@ -95,9 +83,27 @@
   FlagRegistry& operator=(const FlagRegistry&);
 };
 
-FlagRegistry& FlagRegistry::GlobalRegistry() {
-  static FlagRegistry* global_registry = new FlagRegistry;
-  return *global_registry;
+CommandLineFlag* FlagRegistry::FindFlagLocked(absl::string_view name) {
+  FlagConstIterator i = flags_.find(name);
+  if (i == flags_.end()) {
+    return nullptr;
+  }
+
+  if (i->second->IsRetired()) {
+    flags_internal::ReportUsageError(
+        absl::StrCat("Accessing retired flag '", name, "'"), false);
+  }
+
+  return i->second;
+}
+
+CommandLineFlag* FlagRegistry::FindRetiredFlagLocked(absl::string_view name) {
+  FlagConstIterator i = flags_.find(name);
+  if (i == flags_.end() || !i->second->IsRetired()) {
+    return nullptr;
+  }
+
+  return i->second;
 }
 
 namespace {
@@ -161,98 +167,9 @@
   }
 }
 
-CommandLineFlag* FlagRegistry::FindFlagLocked(absl::string_view name) {
-  FlagConstIterator i = flags_.find(name);
-  if (i == flags_.end()) {
-    return nullptr;
-  }
-
-  if (i->second->IsRetired()) {
-    flags_internal::ReportUsageError(
-        absl::StrCat("Accessing retired flag '", name, "'"), false);
-  }
-
-  return i->second;
-}
-
-CommandLineFlag* FlagRegistry::FindRetiredFlagLocked(absl::string_view name) {
-  FlagConstIterator i = flags_.find(name);
-  if (i == flags_.end() || !i->second->IsRetired()) {
-    return nullptr;
-  }
-
-  return i->second;
-}
-
-// --------------------------------------------------------------------
-// FlagSaver
-// FlagSaverImpl
-//    This class stores the states of all flags at construct time,
-//    and restores all flags to that state at destruct time.
-//    Its major implementation challenge is that it never modifies
-//    pointers in the 'main' registry, so global FLAG_* vars always
-//    point to the right place.
-// --------------------------------------------------------------------
-
-class FlagSaverImpl {
- public:
-  FlagSaverImpl() = default;
-  FlagSaverImpl(const FlagSaverImpl&) = delete;
-  void operator=(const FlagSaverImpl&) = delete;
-
-  // Saves the flag states from the flag registry into this object.
-  // It's an error to call this more than once.
-  void SaveFromRegistry() {
-    assert(backup_registry_.empty());  // call only once!
-    flags_internal::ForEachFlag([&](CommandLineFlag& flag) {
-      if (auto flag_state =
-              flags_internal::PrivateHandleAccessor::SaveState(flag)) {
-        backup_registry_.emplace_back(std::move(flag_state));
-      }
-    });
-  }
-
-  // Restores the saved flag states into the flag registry.
-  void RestoreToRegistry() {
-    for (const auto& flag_state : backup_registry_) {
-      flag_state->Restore();
-    }
-  }
-
- private:
-  std::vector<std::unique_ptr<flags_internal::FlagStateInterface>>
-      backup_registry_;
-};
-
-FlagSaver::FlagSaver() : impl_(new FlagSaverImpl) { impl_->SaveFromRegistry(); }
-
-void FlagSaver::Ignore() {
-  delete impl_;
-  impl_ = nullptr;
-}
-
-FlagSaver::~FlagSaver() {
-  if (!impl_) return;
-
-  impl_->RestoreToRegistry();
-  delete impl_;
-}
-
-// --------------------------------------------------------------------
-
-CommandLineFlag* FindCommandLineFlag(absl::string_view name) {
-  if (name.empty()) return nullptr;
-  FlagRegistry& registry = FlagRegistry::GlobalRegistry();
-  FlagRegistryLock frl(registry);
-
-  return registry.FindFlagLocked(name);
-}
-
-CommandLineFlag* FindRetiredFlag(absl::string_view name) {
-  FlagRegistry& registry = FlagRegistry::GlobalRegistry();
-  FlagRegistryLock frl(registry);
-
-  return registry.FindRetiredFlagLocked(name);
+FlagRegistry& FlagRegistry::GlobalRegistry() {
+  static FlagRegistry* global_registry = new FlagRegistry;
+  return *global_registry;
 }
 
 // --------------------------------------------------------------------
@@ -333,17 +250,59 @@
 
 // --------------------------------------------------------------------
 
-bool IsRetiredFlag(absl::string_view name, bool* type_is_bool) {
-  assert(!name.empty());
-  CommandLineFlag* flag = flags_internal::FindRetiredFlag(name);
-  if (flag == nullptr) {
-    return false;
+class FlagSaverImpl {
+ public:
+  FlagSaverImpl() = default;
+  FlagSaverImpl(const FlagSaverImpl&) = delete;
+  void operator=(const FlagSaverImpl&) = delete;
+
+  // Saves the flag states from the flag registry into this object.
+  // It's an error to call this more than once.
+  void SaveFromRegistry() {
+    assert(backup_registry_.empty());  // call only once!
+    flags_internal::ForEachFlag([&](CommandLineFlag& flag) {
+      if (auto flag_state =
+              flags_internal::PrivateHandleAccessor::SaveState(flag)) {
+        backup_registry_.emplace_back(std::move(flag_state));
+      }
+    });
   }
-  assert(type_is_bool);
-  *type_is_bool = flag->IsOfType<bool>();
-  return true;
-}
+
+  // Restores the saved flag states into the flag registry.
+  void RestoreToRegistry() {
+    for (const auto& flag_state : backup_registry_) {
+      flag_state->Restore();
+    }
+  }
+
+ private:
+  std::vector<std::unique_ptr<flags_internal::FlagStateInterface>>
+      backup_registry_;
+};
 
 }  // namespace flags_internal
+
+FlagSaver::FlagSaver() : impl_(new flags_internal::FlagSaverImpl) {
+  impl_->SaveFromRegistry();
+}
+
+FlagSaver::~FlagSaver() {
+  if (!impl_) return;
+
+  impl_->RestoreToRegistry();
+  delete impl_;
+}
+
+// --------------------------------------------------------------------
+
+CommandLineFlag* FindCommandLineFlag(absl::string_view name) {
+  if (name.empty()) return nullptr;
+  flags_internal::FlagRegistry& registry =
+      flags_internal::FlagRegistry::GlobalRegistry();
+  flags_internal::FlagRegistryLock frl(registry);
+
+  return registry.FindFlagLocked(name);
+}
+
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/flags/reflection.h b/absl/flags/reflection.h
new file mode 100644
index 0000000..045f978
--- /dev/null
+++ b/absl/flags/reflection.h
@@ -0,0 +1,85 @@
+//
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: reflection.h
+// -----------------------------------------------------------------------------
+//
+// This file defines the routines to access and operate on an Abseil Flag's
+// reflection handle.
+
+#ifndef ABSL_FLAGS_REFLECTION_H_
+#define ABSL_FLAGS_REFLECTION_H_
+
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/flags/commandlineflag.h"
+#include "absl/flags/internal/commandlineflag.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace flags_internal {
+class FlagSaverImpl;
+}  // namespace flags_internal
+
+// FindCommandLineFlag()
+//
+// Returns the reflection handle of an Abseil flag of the specified name, or
+// `nullptr` if not found. This function will emit a warning if the name of a
+// 'retired' flag is specified.
+CommandLineFlag* FindCommandLineFlag(absl::string_view name);
+
+//------------------------------------------------------------------------------
+// FlagSaver
+//------------------------------------------------------------------------------
+//
+// A FlagSaver object stores the state of flags in the scope where the FlagSaver
+// is defined, allowing modification of those flags within that scope and
+// automatic restoration of the flags to their previous state upon leaving the
+// scope.
+//
+// A FlagSaver can be used within tests to temporarily change the test
+// environment and restore the test case to its previous state.
+//
+// Example:
+//
+//   void MyFunc() {
+//    absl::FlagSaver fs;
+//    ...
+//    absl::SetFlag(FLAGS_myFlag, otherValue);
+//    ...
+//  } // scope of FlagSaver left, flags return to previous state
+//
+// This class is thread-safe.
+
+class FlagSaver {
+ public:
+  FlagSaver();
+  ~FlagSaver();
+
+  FlagSaver(const FlagSaver&) = delete;
+  void operator=(const FlagSaver&) = delete;
+
+ private:
+  flags_internal::FlagSaverImpl* impl_;
+};
+
+//-----------------------------------------------------------------------------
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_FLAGS_REFLECTION_H_
diff --git a/absl/flags/reflection_test.cc b/absl/flags/reflection_test.cc
new file mode 100644
index 0000000..9781e59
--- /dev/null
+++ b/absl/flags/reflection_test.cc
@@ -0,0 +1,60 @@
+//
+//  Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/flags/reflection.h"
+
+#include <memory>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "absl/flags/flag.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/flags/marshalling.h"
+#include "absl/memory/memory.h"
+
+ABSL_FLAG(int, int_flag, 1, "int_flag help");
+ABSL_FLAG(std::string, string_flag, "dflt", "string_flag help");
+ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
+
+namespace {
+
+namespace flags = absl::flags_internal;
+
+class ReflectionTest : public testing::Test {
+ protected:
+  void SetUp() override { flag_saver_ = absl::make_unique<absl::FlagSaver>(); }
+  void TearDown() override { flag_saver_.reset(); }
+
+ private:
+  std::unique_ptr<absl::FlagSaver> flag_saver_;
+};
+
+// --------------------------------------------------------------------
+
+TEST_F(ReflectionTest, TestFindCommandLineFlag) {
+  auto* handle = absl::FindCommandLineFlag("some_flag");
+  EXPECT_EQ(handle, nullptr);
+
+  handle = absl::FindCommandLineFlag("int_flag");
+  EXPECT_NE(handle, nullptr);
+
+  handle = absl::FindCommandLineFlag("string_flag");
+  EXPECT_NE(handle, nullptr);
+
+  handle = absl::FindCommandLineFlag("bool_retired_flag");
+  EXPECT_NE(handle, nullptr);
+}
+
+}  // namespace
diff --git a/absl/random/BUILD.bazel b/absl/random/BUILD.bazel
index 4b804c8..694331c 100644
--- a/absl/random/BUILD.bazel
+++ b/absl/random/BUILD.bazel
@@ -115,11 +115,12 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        ":random",
         "//absl/base:core_headers",
+        "//absl/base:fast_type_id",
         "//absl/meta:type_traits",
         "//absl/random/internal:distribution_caller",
         "//absl/random/internal:fast_uniform_bits",
-        "//absl/random/internal:mocking_bit_gen_base",
     ],
 )
 
@@ -145,10 +146,11 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":distributions",
+        ":random",
+        "//absl/base:fast_type_id",
         "//absl/container:flat_hash_map",
         "//absl/meta:type_traits",
         "//absl/random/internal:distribution_caller",
-        "//absl/random/internal:mocking_bit_gen_base",
         "//absl/strings",
         "//absl/types:span",
         "//absl/types:variant",
@@ -410,6 +412,7 @@
     deps = [
         ":bit_gen_ref",
         ":random",
+        "//absl/base:fast_type_id",
         "//absl/random/internal:sequence_urbg",
         "@com_google_googletest//:gtest_main",
     ],
diff --git a/absl/random/BUILD.gn b/absl/random/BUILD.gn
index 12037e3..e3143ae 100644
--- a/absl/random/BUILD.gn
+++ b/absl/random/BUILD.gn
@@ -74,10 +74,11 @@
 absl_source_set("bit_gen_ref") {
   public = [ "bit_gen_ref.h" ]
   deps = [
+    ":random",
     "//third_party/abseil-cpp/absl/base:core_headers",
+    "//third_party/abseil-cpp/absl/base:fast_type_id",
     "//third_party/abseil-cpp/absl/meta:type_traits",
     "//third_party/abseil-cpp/absl/random/internal:distribution_caller",
     "//third_party/abseil-cpp/absl/random/internal:fast_uniform_bits",
-    "//third_party/abseil-cpp/absl/random/internal:mocking_bit_gen_base",
   ]
 }
diff --git a/absl/random/CMakeLists.txt b/absl/random/CMakeLists.txt
index 85a2ea3..8875b30 100644
--- a/absl/random/CMakeLists.txt
+++ b/absl/random/CMakeLists.txt
@@ -45,7 +45,6 @@
     absl::core_headers
     absl::random_internal_distribution_caller
     absl::random_internal_fast_uniform_bits
-    absl::random_internal_mocking_bit_gen_base
     absl::type_traits
 )
 
@@ -62,6 +61,7 @@
     absl::random_bit_gen_ref
     absl::random_random
     absl::random_internal_sequence_urbg
+    absl::fast_type_id
     gmock
     gtest_main
 )
@@ -69,21 +69,6 @@
 # Internal-only target, do not depend on directly.
 absl_cc_library(
   NAME
-    random_internal_mocking_bit_gen_base
-  HDRS
-    "internal/mocking_bit_gen_base.h"
-  COPTS
-    ${ABSL_DEFAULT_COPTS}
-  LINKOPTS
-    ${ABSL_DEFAULT_LINKOPTS}
-  DEPS
-    absl::random_random
-    absl::strings
-)
-
-# Internal-only target, do not depend on directly.
-absl_cc_library(
-  NAME
     random_internal_mock_overload_set
   HDRS
     "internal/mock_overload_set.h"
@@ -93,6 +78,7 @@
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
     absl::random_mocking_bit_gen
+    absl::fast_type_id
   TESTONLY
 )
 
@@ -111,8 +97,8 @@
     absl::raw_logging_internal
     absl::random_distributions
     absl::random_internal_distribution_caller
-    absl::random_internal_mocking_bit_gen_base
     absl::random_internal_mock_overload_set
+    absl::random_random
     absl::strings
     absl::span
     absl::type_traits
@@ -533,6 +519,8 @@
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
     absl::config
+    absl::utility
+    absl::fast_type_id
 )
 
 # Internal-only target, do not depend on directly.
diff --git a/absl/random/bit_gen_ref.h b/absl/random/bit_gen_ref.h
index 59591a4..00e3624 100644
--- a/absl/random/bit_gen_ref.h
+++ b/absl/random/bit_gen_ref.h
@@ -24,11 +24,11 @@
 #ifndef ABSL_RANDOM_BIT_GEN_REF_H_
 #define ABSL_RANDOM_BIT_GEN_REF_H_
 
+#include "absl/base/internal/fast_type_id.h"
 #include "absl/base/macros.h"
 #include "absl/meta/type_traits.h"
 #include "absl/random/internal/distribution_caller.h"
 #include "absl/random/internal/fast_uniform_bits.h"
-#include "absl/random/internal/mocking_bit_gen_base.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -51,6 +51,9 @@
         typename std::decay<decltype(std::declval<URBG>()())>::type>::value>>
     : std::true_type {};
 
+template <typename>
+struct DistributionCaller;
+
 }  // namespace random_internal
 
 // -----------------------------------------------------------------------------
@@ -77,23 +80,50 @@
 //    }
 //
 class BitGenRef {
- public:
-  using result_type = uint64_t;
+  // SFINAE to detect whether the URBG type includes a member matching
+  // bool InvokeMock(base_internal::FastTypeIdType, void*, void*).
+  //
+  // These live inside BitGenRef so that they have friend access
+  // to MockingBitGen. (see similar methods in DistributionCaller).
+  template <template <class...> class Trait, class AlwaysVoid, class... Args>
+  struct detector : std::false_type {};
+  template <template <class...> class Trait, class... Args>
+  struct detector<Trait, absl::void_t<Trait<Args...>>, Args...>
+      : std::true_type {};
 
-  BitGenRef(const absl::BitGenRef&) = default;
-  BitGenRef(absl::BitGenRef&&) = default;
-  BitGenRef& operator=(const absl::BitGenRef&) = default;
-  BitGenRef& operator=(absl::BitGenRef&&) = default;
+  template <class T>
+  using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock(
+      std::declval<base_internal::FastTypeIdType>(), std::declval<void*>(),
+      std::declval<void*>()));
+
+  template <typename T>
+  using HasInvokeMock = typename detector<invoke_mock_t, void, T>::type;
+
+ public:
+  BitGenRef(const BitGenRef&) = default;
+  BitGenRef(BitGenRef&&) = default;
+  BitGenRef& operator=(const BitGenRef&) = default;
+  BitGenRef& operator=(BitGenRef&&) = default;
+
+  template <typename URBG, typename absl::enable_if_t<
+                               (!std::is_same<URBG, BitGenRef>::value &&
+                                random_internal::is_urbg<URBG>::value &&
+                                !HasInvokeMock<URBG>::value)>* = nullptr>
+  BitGenRef(URBG& gen)  // NOLINT
+      : t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
+        mock_call_(NotAMock),
+        generate_impl_fn_(ImplFn<URBG>) {}
 
   template <typename URBG,
-            typename absl::enable_if_t<
-                (!std::is_same<URBG, BitGenRef>::value &&
-                 random_internal::is_urbg<URBG>::value)>* = nullptr>
+            typename absl::enable_if_t<(!std::is_same<URBG, BitGenRef>::value &&
+                                        random_internal::is_urbg<URBG>::value &&
+                                        HasInvokeMock<URBG>::value)>* = nullptr>
   BitGenRef(URBG& gen)  // NOLINT
-      : mocked_gen_ptr_(MakeMockPointer(&gen)),
-        t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
-        generate_impl_fn_(ImplFn<URBG>) {
-  }
+      : t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
+        mock_call_(&MockCall<URBG>),
+        generate_impl_fn_(ImplFn<URBG>) {}
+
+  using result_type = uint64_t;
 
   static constexpr result_type(min)() {
     return (std::numeric_limits<result_type>::min)();
@@ -106,14 +136,9 @@
   result_type operator()() { return generate_impl_fn_(t_erased_gen_ptr_); }
 
  private:
-  friend struct absl::random_internal::DistributionCaller<absl::BitGenRef>;
   using impl_fn = result_type (*)(uintptr_t);
-  using mocker_base_t = absl::random_internal::MockingBitGenBase;
-
-  // Convert an arbitrary URBG pointer into either a valid mocker_base_t
-  // pointer or a nullptr.
-  static inline mocker_base_t* MakeMockPointer(mocker_base_t* t) { return t; }
-  static inline mocker_base_t* MakeMockPointer(void*) { return nullptr; }
+  using mock_call_fn = bool (*)(uintptr_t, base_internal::FastTypeIdType, void*,
+                                void*);
 
   template <typename URBG>
   static result_type ImplFn(uintptr_t ptr) {
@@ -123,29 +148,31 @@
     return fast_uniform_bits(*reinterpret_cast<URBG*>(ptr));
   }
 
-  mocker_base_t* mocked_gen_ptr_;
-  uintptr_t t_erased_gen_ptr_;
-  impl_fn generate_impl_fn_;
-};
-
-namespace random_internal {
-
-template <>
-struct DistributionCaller<absl::BitGenRef> {
-  template <typename DistrT, typename... Args>
-  static typename DistrT::result_type Call(absl::BitGenRef* gen_ref,
-                                           Args&&... args) {
-    auto* mock_ptr = gen_ref->mocked_gen_ptr_;
-    if (mock_ptr == nullptr) {
-      DistrT dist(std::forward<Args>(args)...);
-      return dist(*gen_ref);
-    } else {
-      return mock_ptr->template Call<DistrT>(std::forward<Args>(args)...);
-    }
+  // Get a type-erased InvokeMock pointer.
+  template <typename URBG>
+  static bool MockCall(uintptr_t gen_ptr, base_internal::FastTypeIdType type,
+                       void* result, void* arg_tuple) {
+    return reinterpret_cast<URBG*>(gen_ptr)->InvokeMock(type, result,
+                                                        arg_tuple);
   }
+  static bool NotAMock(uintptr_t, base_internal::FastTypeIdType, void*, void*) {
+    return false;
+  }
+
+  inline bool InvokeMock(base_internal::FastTypeIdType type, void* args_tuple,
+                         void* result) {
+    if (mock_call_ == NotAMock) return false;  // avoids an indirect call.
+    return mock_call_(t_erased_gen_ptr_, type, args_tuple, result);
+  }
+
+  uintptr_t t_erased_gen_ptr_;
+  mock_call_fn mock_call_;
+  impl_fn generate_impl_fn_;
+
+  template <typename>
+  friend struct ::absl::random_internal::DistributionCaller;  // for InvokeMock
 };
 
-}  // namespace random_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
 
diff --git a/absl/random/bit_gen_ref_test.cc b/absl/random/bit_gen_ref_test.cc
index ca0e4d7..1135cf2 100644
--- a/absl/random/bit_gen_ref_test.cc
+++ b/absl/random/bit_gen_ref_test.cc
@@ -17,30 +17,31 @@
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/base/internal/fast_type_id.h"
 #include "absl/random/internal/sequence_urbg.h"
 #include "absl/random/random.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
-class ConstBitGen : public absl::random_internal::MockingBitGenBase {
-  bool CallImpl(const std::type_info&, void*, void* result) override {
+class ConstBitGen {
+ public:
+  // URBG interface
+  using result_type = absl::BitGen::result_type;
+
+  static constexpr result_type(min)() { return (absl::BitGen::min)(); }
+  static constexpr result_type(max)() { return (absl::BitGen::max)(); }
+  result_type operator()() { return 1; }
+
+  // InvokeMock method
+  bool InvokeMock(base_internal::FastTypeIdType index, void*, void* result) {
     *static_cast<int*>(result) = 42;
     return true;
   }
 };
 
-namespace random_internal {
-template <>
-struct DistributionCaller<ConstBitGen> {
-  template <typename DistrT, typename FormatT, typename... Args>
-  static typename DistrT::result_type Call(ConstBitGen* gen, Args&&... args) {
-    return gen->template Call<DistrT, FormatT>(std::forward<Args>(args)...);
-  }
-};
-}  // namespace random_internal
-
 namespace {
+
 int FnTest(absl::BitGenRef gen_ref) { return absl::Uniform(gen_ref, 1, 7); }
 
 template <typename T>
diff --git a/absl/random/internal/BUILD.bazel b/absl/random/internal/BUILD.bazel
index 813d926..3ab1177 100644
--- a/absl/random/internal/BUILD.bazel
+++ b/absl/random/internal/BUILD.bazel
@@ -45,7 +45,11 @@
     hdrs = ["distribution_caller.h"],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
-    deps = ["//absl/base:config"],
+    deps = [
+        "//absl/base:config",
+        "//absl/base:fast_type_id",
+        "//absl/utility",
+    ],
 )
 
 cc_library(
@@ -481,20 +485,11 @@
 )
 
 cc_library(
-    name = "mocking_bit_gen_base",
-    hdrs = ["mocking_bit_gen_base.h"],
-    linkopts = ABSL_DEFAULT_LINKOPTS,
-    deps = [
-        "//absl/random",
-        "//absl/strings",
-    ],
-)
-
-cc_library(
     name = "mock_overload_set",
     testonly = 1,
     hdrs = ["mock_overload_set.h"],
     deps = [
+        "//absl/base:fast_type_id",
         "//absl/random:mocking_bit_gen",
         "@com_google_googletest//:gtest",
     ],
diff --git a/absl/random/internal/BUILD.gn b/absl/random/internal/BUILD.gn
index ede20e9..62f67b4 100644
--- a/absl/random/internal/BUILD.gn
+++ b/absl/random/internal/BUILD.gn
@@ -11,7 +11,11 @@
 
 absl_source_set("distribution_caller") {
   public = [ "distribution_caller.h" ]
-  deps = [ "//third_party/abseil-cpp/absl/base:config" ]
+  deps = [
+    "//third_party/abseil-cpp/absl/base:config",
+    "//third_party/abseil-cpp/absl/base:fast_type_id",
+    "//third_party/abseil-cpp/absl/utility",
+  ]
 }
 
 absl_source_set("fast_uniform_bits") {
@@ -225,14 +229,6 @@
   ]
 }
 
-absl_source_set("mocking_bit_gen_base") {
-  public = [ "mocking_bit_gen_base.h" ]
-  deps = [
-    "//third_party/abseil-cpp/absl/random",
-    "//third_party/abseil-cpp/absl/strings",
-  ]
-}
-
 absl_source_set("nanobenchmark") {
   sources = [ "nanobenchmark.cc" ]
   deps = [
@@ -249,6 +245,6 @@
   deps = [
     ":traits",
     "//third_party/abseil-cpp/absl/base:config",
-    "//third_party/abseil-cpp/absl/meta:type_traits"
+    "//third_party/abseil-cpp/absl/meta:type_traits",
   ]
 }
diff --git a/absl/random/internal/distribution_caller.h b/absl/random/internal/distribution_caller.h
index 4e07244..87a7684 100644
--- a/absl/random/internal/distribution_caller.h
+++ b/absl/random/internal/distribution_caller.h
@@ -20,6 +20,8 @@
 #include <utility>
 
 #include "absl/base/config.h"
+#include "absl/base/internal/fast_type_id.h"
+#include "absl/utility/utility.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -30,14 +32,55 @@
 // to intercept such calls.
 template <typename URBG>
 struct DistributionCaller {
-  // Call the provided distribution type. The parameters are expected
-  // to be explicitly specified.
-  // DistrT is the distribution type.
+  // SFINAE to detect whether the URBG type includes a member matching
+  // bool InvokeMock(base_internal::FastTypeIdType, void*, void*).
+  //
+  // These live inside BitGenRef so that they have friend access
+  // to MockingBitGen. (see similar methods in DistributionCaller).
+  template <template <class...> class Trait, class AlwaysVoid, class... Args>
+  struct detector : std::false_type {};
+  template <template <class...> class Trait, class... Args>
+  struct detector<Trait, absl::void_t<Trait<Args...>>, Args...>
+      : std::true_type {};
+
+  template <class T>
+  using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock(
+      std::declval<::absl::base_internal::FastTypeIdType>(),
+      std::declval<void*>(), std::declval<void*>()));
+
+  using HasInvokeMock = typename detector<invoke_mock_t, void, URBG>::type;
+
+  // Default implementation of distribution caller.
   template <typename DistrT, typename... Args>
-  static typename DistrT::result_type Call(URBG* urbg, Args&&... args) {
+  static inline typename DistrT::result_type Impl(std::false_type, URBG* urbg,
+                                                  Args&&... args) {
     DistrT dist(std::forward<Args>(args)...);
     return dist(*urbg);
   }
+
+  // Mock implementation of distribution caller.
+  template <typename DistrT, typename... Args>
+  static inline typename DistrT::result_type Impl(std::true_type, URBG* urbg,
+                                                  Args&&... args) {
+    using ResultT = typename DistrT::result_type;
+    using ArgTupleT = std::tuple<absl::decay_t<Args>...>;
+    ArgTupleT arg_tuple(std::forward<Args>(args)...);
+    ResultT result;
+    if (!urbg->InvokeMock(
+            ::absl::base_internal::FastTypeId<ResultT(DistrT, ArgTupleT)>(),
+            &arg_tuple, &result)) {
+      auto dist = absl::make_from_tuple<DistrT>(arg_tuple);
+      result = dist(*urbg);
+    }
+    return result;
+  }
+
+  // Default implementation of distribution caller.
+  template <typename DistrT, typename... Args>
+  static inline typename DistrT::result_type Call(URBG* urbg, Args&&... args) {
+    return Impl<DistrT, Args...>(HasInvokeMock{}, urbg,
+                                 std::forward<Args>(args)...);
+  }
 };
 
 }  // namespace random_internal
diff --git a/absl/random/internal/mock_overload_set.h b/absl/random/internal/mock_overload_set.h
index c2a30d8..60561b5 100644
--- a/absl/random/internal/mock_overload_set.h
+++ b/absl/random/internal/mock_overload_set.h
@@ -20,6 +20,7 @@
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/base/internal/fast_type_id.h"
 #include "absl/random/mocking_bit_gen.h"
 
 namespace absl {
@@ -35,17 +36,23 @@
 // EXPECT_CALL(mock_single_overload, Call(...))` will expand to a call to
 // `mock_single_overload.gmock_Call(...)`. Because expectations are stored on
 // the MockingBitGen (an argument passed inside `Call(...)`), this forwards to
-// arguments to Mocking::Register.
+// arguments to MockingBitGen::Register.
 template <typename DistrT, typename Ret, typename... Args>
 struct MockSingleOverload<DistrT, Ret(MockingBitGen&, Args...)> {
   static_assert(std::is_same<typename DistrT::result_type, Ret>::value,
                 "Overload signature must have return type matching the "
-                "distributions result type.");
+                "distribution result_type.");
+  using ArgTupleT = std::tuple<Args...>;
   auto gmock_Call(
       absl::MockingBitGen& gen,  // NOLINT(google-runtime-references)
-      const ::testing::Matcher<Args>&... args)
-      -> decltype(gen.Register<DistrT, Args...>(args...)) {
-    return gen.Register<DistrT, Args...>(args...);
+      const ::testing::Matcher<Args>&... matchers)
+      -> decltype(gen.RegisterMock<Ret, ArgTupleT>(
+                         std::declval<::absl::base_internal::FastTypeIdType>())
+                      .gmock_Call(matchers...)) {
+    return gen
+        .RegisterMock<Ret, ArgTupleT>(
+            ::absl::base_internal::FastTypeId<Ret(DistrT, ArgTupleT)>())
+        .gmock_Call(matchers...);
   }
 };
 
@@ -53,13 +60,19 @@
 struct MockSingleOverload<DistrT, Ret(Arg, MockingBitGen&, Args...)> {
   static_assert(std::is_same<typename DistrT::result_type, Ret>::value,
                 "Overload signature must have return type matching the "
-                "distributions result type.");
+                "distribution result_type.");
+  using ArgTupleT = std::tuple<Arg, Args...>;
   auto gmock_Call(
-      const ::testing::Matcher<Arg>& arg,
+      const ::testing::Matcher<Arg>& matcher,
       absl::MockingBitGen& gen,  // NOLINT(google-runtime-references)
-      const ::testing::Matcher<Args>&... args)
-      -> decltype(gen.Register<DistrT, Arg, Args...>(arg, args...)) {
-    return gen.Register<DistrT, Arg, Args...>(arg, args...);
+      const ::testing::Matcher<Args>&... matchers)
+      -> decltype(gen.RegisterMock<Ret, ArgTupleT>(
+                         std::declval<::absl::base_internal::FastTypeIdType>())
+                      .gmock_Call(matcher, matchers...)) {
+    return gen
+        .RegisterMock<Ret, ArgTupleT>(
+            ::absl::base_internal::FastTypeId<Ret(DistrT, ArgTupleT)>())
+        .gmock_Call(matcher, matchers...);
   }
 };
 
diff --git a/absl/random/internal/mocking_bit_gen_base.h b/absl/random/internal/mocking_bit_gen_base.h
deleted file mode 100644
index 23ecaf6..0000000
--- a/absl/random/internal/mocking_bit_gen_base.h
+++ /dev/null
@@ -1,85 +0,0 @@
-//
-// Copyright 2018 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-#ifndef ABSL_RANDOM_INTERNAL_MOCKING_BIT_GEN_BASE_H_
-#define ABSL_RANDOM_INTERNAL_MOCKING_BIT_GEN_BASE_H_
-
-#include <string>
-#include <typeinfo>
-
-#include "absl/random/random.h"
-#include "absl/strings/str_cat.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace random_internal {
-
-class MockingBitGenBase {
-  template <typename>
-  friend struct DistributionCaller;
-  using generator_type = absl::BitGen;
-
- public:
-  // URBG interface
-  using result_type = generator_type::result_type;
-  static constexpr result_type(min)() { return (generator_type::min)(); }
-  static constexpr result_type(max)() { return (generator_type::max)(); }
-  result_type operator()() { return gen_(); }
-
-  virtual ~MockingBitGenBase() = default;
-
- protected:
-  // CallImpl is the type-erased virtual dispatch.
-  // The type of dist is always distribution<T>,
-  // The type of result is always distribution<T>::result_type.
-  virtual bool CallImpl(const std::type_info& distr_type, void* dist_args,
-                        void* result) = 0;
-
-  template <typename DistrT, typename ArgTupleT>
-  static const std::type_info& GetTypeId() {
-    return typeid(std::pair<absl::decay_t<DistrT>, absl::decay_t<ArgTupleT>>);
-  }
-
-  // Call the generating distribution function.
-  // Invoked by DistributionCaller<>::Call<DistT>.
-  // DistT is the distribution type.
-  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>...>;
-
-    ArgTupleT arg_tuple(std::forward<Args>(args)...);
-    auto dist = absl::make_from_tuple<DistrT>(arg_tuple);
-
-    distr_result_type result{};
-    bool found_match =
-        CallImpl(GetTypeId<DistrT, ArgTupleT>(), &arg_tuple, &result);
-
-    if (!found_match) {
-      result = dist(gen_);
-    }
-
-    return result;
-  }
-
- private:
-  generator_type gen_;
-};  // namespace random_internal
-
-}  // namespace random_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#endif  // ABSL_RANDOM_INTERNAL_MOCKING_BIT_GEN_BASE_H_
diff --git a/absl/random/mock_distributions.h b/absl/random/mock_distributions.h
index d36d5ba..764ab37 100644
--- a/absl/random/mock_distributions.h
+++ b/absl/random/mock_distributions.h
@@ -27,6 +27,11 @@
 // More information about the Googletest testing framework is available at
 // https://github.com/google/googletest
 //
+// EXPECT_CALL and ON_CALL need to be made within the same DLL component as
+// the call to absl::Uniform and related methods, otherwise mocking will fail
+// since the  underlying implementation creates a type-specific pointer which
+// will be distinct across different DLL boundaries.
+//
 // Example:
 //
 //   absl::MockingBitGen mock;
diff --git a/absl/random/mocking_bit_gen.h b/absl/random/mocking_bit_gen.h
index 3d8a979..c3c7d44 100644
--- a/absl/random/mocking_bit_gen.h
+++ b/absl/random/mocking_bit_gen.h
@@ -33,17 +33,16 @@
 #include <memory>
 #include <tuple>
 #include <type_traits>
-#include <typeindex>
-#include <typeinfo>
 #include <utility>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/base/internal/fast_type_id.h"
 #include "absl/container/flat_hash_map.h"
 #include "absl/meta/type_traits.h"
 #include "absl/random/distributions.h"
 #include "absl/random/internal/distribution_caller.h"
-#include "absl/random/internal/mocking_bit_gen_base.h"
+#include "absl/random/random.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/str_join.h"
 #include "absl/types/span.h"
@@ -54,11 +53,13 @@
 ABSL_NAMESPACE_BEGIN
 
 namespace random_internal {
-
 template <typename, typename>
 struct MockSingleOverload;
+template <typename>
+struct DistributionCaller;
 
 }  // namespace random_internal
+class BitGenRef;
 
 // MockingBitGen
 //
@@ -96,102 +97,132 @@
 // At this time, only mock distributions supplied within the Abseil random
 // library are officially supported.
 //
-class MockingBitGen : public absl::random_internal::MockingBitGenBase {
+// EXPECT_CALL and ON_CALL need to be made within the same DLL component as
+// the call to absl::Uniform and related methods, otherwise mocking will fail
+// since the  underlying implementation creates a type-specific pointer which
+// will be distinct across different DLL boundaries.
+//
+class MockingBitGen {
  public:
-  MockingBitGen() {}
+  MockingBitGen() = default;
 
-  ~MockingBitGen() override {
+  ~MockingBitGen() {
     for (const auto& del : deleters_) del();
   }
 
+  // URBG interface
+  using result_type = absl::BitGen::result_type;
+
+  static constexpr result_type(min)() { return (absl::BitGen::min)(); }
+  static constexpr result_type(max)() { return (absl::BitGen::max)(); }
+  result_type operator()() { return gen_(); }
+
  private:
-  template <typename DistrT, typename... Args>
-  using MockFnType =
-      ::testing::MockFunction<typename DistrT::result_type(Args...)>;
-
-  // MockingBitGen::Register
-  //
-  // Register<DistrT, FormatT, ArgTupleT> is the main extension point for
-  // extending the MockingBitGen framework. It provides a mechanism to install a
-  // mock expectation for the distribution `distr_t` onto the MockingBitGen
-  // context.
-  //
-  // The returned MockFunction<...> type can be used to setup additional
-  // distribution parameters of the expectation.
-  template <typename DistrT, typename... Args, typename... Ms>
-  decltype(std::declval<MockFnType<DistrT, Args...>>().gmock_Call(
-      std::declval<Ms>()...))
-  Register(Ms&&... matchers) {
-    auto& mock =
-        mocks_[std::type_index(GetTypeId<DistrT, std::tuple<Args...>>())];
-
-    if (!mock.mock_fn) {
-      auto* mock_fn = new MockFnType<DistrT, Args...>;
-      mock.mock_fn = mock_fn;
-      mock.match_impl = &MatchImpl<DistrT, Args...>;
-      deleters_.emplace_back([mock_fn] { delete mock_fn; });
-    }
-
-    return static_cast<MockFnType<DistrT, Args...>*>(mock.mock_fn)
-        ->gmock_Call(std::forward<Ms>(matchers)...);
-  }
-
-  mutable std::vector<std::function<void()>> deleters_;
-
-  using match_impl_fn = void (*)(void* mock_fn, void* t_erased_dist_args,
+  using match_impl_fn = void (*)(void* mock_fn, void* t_erased_arg_tuple,
                                  void* t_erased_result);
+
   struct MockData {
     void* mock_fn = nullptr;
     match_impl_fn match_impl = nullptr;
   };
 
-  mutable absl::flat_hash_map<std::type_index, MockData> mocks_;
+  // GetMockFnType returns the testing::MockFunction for a result and tuple.
+  // This method only exists for type deduction and is otherwise unimplemented.
+  template <typename ResultT, typename... Args>
+  static auto GetMockFnType(ResultT, std::tuple<Args...>)
+      -> ::testing::MockFunction<ResultT(Args...)>;
 
-  template <typename DistrT, typename... Args>
-  static void MatchImpl(void* mock_fn, void* dist_args, void* result) {
-    using result_type = typename DistrT::result_type;
-    *static_cast<result_type*>(result) = absl::apply(
-        [mock_fn](Args... args) -> result_type {
-          return (*static_cast<MockFnType<DistrT, Args...>*>(mock_fn))
-              .Call(std::move(args)...);
-        },
-        *static_cast<std::tuple<Args...>*>(dist_args));
+  // MockFnCaller is a helper method for use with absl::apply to
+  // apply an ArgTupleT to a compatible MockFunction.
+  // NOTE: MockFnCaller is essentially equivalent to the lambda:
+  // [fn](auto... args) { return fn->Call(std::move(args)...)}
+  // however that fails to build on some supported platforms.
+  template <typename ResultT, typename MockFnType, typename Tuple>
+  struct MockFnCaller;
+  // specialization for std::tuple.
+  template <typename ResultT, typename MockFnType, typename... Args>
+  struct MockFnCaller<ResultT, MockFnType, std::tuple<Args...>> {
+    MockFnType* fn;
+    inline ResultT operator()(Args... args) {
+      return fn->Call(std::move(args)...);
+    }
+  };
+
+  // MockingBitGen::RegisterMock
+  //
+  // RegisterMock<ResultT, ArgTupleT>(FastTypeIdType) is the main extension
+  // point for extending the MockingBitGen framework. It provides a mechanism to
+  // install a mock expectation for a function like ResultT(Args...) keyed by
+  // type_idex onto the MockingBitGen context. The key is that the type_index
+  // used to register must match the type index used to call the mock.
+  //
+  // The returned MockFunction<...> type can be used to setup additional
+  // distribution parameters of the expectation.
+  template <typename ResultT, typename ArgTupleT>
+  auto RegisterMock(base_internal::FastTypeIdType type)
+      -> decltype(GetMockFnType(std::declval<ResultT>(),
+                                std::declval<ArgTupleT>()))& {
+    using MockFnType = decltype(
+        GetMockFnType(std::declval<ResultT>(), std::declval<ArgTupleT>()));
+    auto& mock = mocks_[type];
+    if (!mock.mock_fn) {
+      auto* mock_fn = new MockFnType;
+      mock.mock_fn = mock_fn;
+      mock.match_impl = &MatchImpl<ResultT, ArgTupleT>;
+      deleters_.emplace_back([mock_fn] { delete mock_fn; });
+    }
+    return *static_cast<MockFnType*>(mock.mock_fn);
   }
 
-  // Looks for an appropriate mock - Returns the mocked result if one is found.
-  // Otherwise, returns a random value generated by the underlying URBG.
-  bool CallImpl(const std::type_info& key_type, void* dist_args,
-                void* result) override {
+  // MockingBitGen::MatchImpl<> is a dispatch function which converts the
+  // generic type-erased parameters into a specific mock invocation call.
+  // Requires tuple_args to point to a ArgTupleT, which is a std::tuple<Args...>
+  // used to invoke the mock function.
+  // Requires result to point to a ResultT, which is the result of the call.
+  template <typename ResultT, typename ArgTupleT>
+  static void MatchImpl(/*MockFnType<ResultT, Args...>*/ void* mock_fn,
+                        /*ArgTupleT*/ void* args_tuple,
+                        /*ResultT*/ void* result) {
+    using MockFnType = decltype(
+        GetMockFnType(std::declval<ResultT>(), std::declval<ArgTupleT>()));
+    *static_cast<ResultT*>(result) = absl::apply(
+        MockFnCaller<ResultT, MockFnType, ArgTupleT>{
+            static_cast<MockFnType*>(mock_fn)},
+        *static_cast<ArgTupleT*>(args_tuple));
+  }
+
+  // MockingBitGen::InvokeMock
+  //
+  // InvokeMock(FastTypeIdType, args, result) is the entrypoint for invoking
+  // mocks registered on MockingBitGen.
+  //
+  // When no mocks are registered on the provided FastTypeIdType, returns false.
+  // Otherwise attempts to invoke the mock function ResultT(Args...) that
+  // was previously registered via the type_index.
+  // Requires tuple_args to point to a ArgTupleT, which is a std::tuple<Args...>
+  // used to invoke the mock function.
+  // Requires result to point to a ResultT, which is the result of the call.
+  inline bool InvokeMock(base_internal::FastTypeIdType type, void* args_tuple,
+                         void* result) {
     // Trigger a mock, if there exists one that matches `param`.
-    auto it = mocks_.find(std::type_index(key_type));
+    auto it = mocks_.find(type);
     if (it == mocks_.end()) return false;
     auto* mock_data = static_cast<MockData*>(&it->second);
-    mock_data->match_impl(mock_data->mock_fn, dist_args, result);
+    mock_data->match_impl(mock_data->mock_fn, args_tuple, result);
     return true;
   }
 
+  absl::flat_hash_map<base_internal::FastTypeIdType, MockData> mocks_;
+  std::vector<std::function<void()>> deleters_;
+  absl::BitGen gen_;
+
   template <typename, typename>
-  friend struct ::absl::random_internal::MockSingleOverload;
-  friend struct ::absl::random_internal::DistributionCaller<
-      absl::MockingBitGen>;
+  friend struct ::absl::random_internal::MockSingleOverload;  // for Register
+  template <typename>
+  friend struct ::absl::random_internal::DistributionCaller;  // for InvokeMock
+  friend class ::absl::BitGenRef;                             // for InvokeMock
 };
 
-// -----------------------------------------------------------------------------
-// Implementation Details Only Below
-// -----------------------------------------------------------------------------
-
-namespace random_internal {
-
-template <>
-struct DistributionCaller<absl::MockingBitGen> {
-  template <typename DistrT, typename... Args>
-  static typename DistrT::result_type Call(absl::MockingBitGen* gen,
-                                           Args&&... args) {
-    return gen->template Call<DistrT>(std::forward<Args>(args)...);
-  }
-};
-
-}  // namespace random_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
 
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc
index 20c6229..0e8535c 100644
--- a/absl/strings/internal/str_format/convert_test.cc
+++ b/absl/strings/internal/str_format/convert_test.cc
@@ -764,6 +764,12 @@
     }
   }
 
+  // Regression tests
+  //
+  // Using a string literal because not all platforms support hex literals or it
+  // might be out of range.
+  doubles.push_back(std::strtold("-0xf.ffffffb5feafffbp-16324L", nullptr));
+
   for (const char *fmt : kFormats) {
     for (char f : {'f', 'F',  //
                    'g', 'G',  //
diff --git a/absl/strings/internal/str_format/float_conversion.cc b/absl/strings/internal/str_format/float_conversion.cc
index a761a5a..10e4695 100644
--- a/absl/strings/internal/str_format/float_conversion.cc
+++ b/absl/strings/internal/str_format/float_conversion.cc
@@ -224,13 +224,13 @@
   // This function will allocate enough stack space to perform the conversion.
   static void RunConversion(
       uint128 v, int exp, absl::FunctionRef<void(FractionalDigitGenerator)> f) {
+    using Limits = std::numeric_limits<long double>;
     assert(-exp < 0);
-    assert(-exp >= std::numeric_limits<long double>::min_exponent - 128);
-    static_assert(
-        StackArray::kMaxCapacity >=
-            (128 - std::numeric_limits<long double>::min_exponent + 31) / 32,
-        "");
-    StackArray::RunWithCapacity((exp + 31) / 32,
+    assert(-exp >= Limits::min_exponent - 128);
+    static_assert(StackArray::kMaxCapacity >=
+                      (Limits::digits + 128 - Limits::min_exponent + 31) / 32,
+                  "");
+    StackArray::RunWithCapacity((Limits::digits + exp + 31) / 32,
                                 [=](absl::Span<uint32_t> input) {
                                   f(FractionalDigitGenerator(input, v, exp));
                                 });
diff --git a/absl/strings/str_format.h b/absl/strings/str_format.h
index f833a80..36bd84a 100644
--- a/absl/strings/str_format.h
+++ b/absl/strings/str_format.h
@@ -19,7 +19,7 @@
 //
 // The `str_format` library is a typesafe replacement for the family of
 // `printf()` string formatting routines within the `<cstdio>` standard library
-// header. Like the `printf` family, the `str_format` uses a "format string" to
+// header. Like the `printf` family, `str_format` uses a "format string" to
 // perform argument substitutions based on types. See the `FormatSpec` section
 // below for format string documentation.
 //
diff --git a/absl/time/internal/cctz/src/time_zone_format.cc b/absl/time/internal/cctz/src/time_zone_format.cc
index a442863..2e02233 100644
--- a/absl/time/internal/cctz/src/time_zone_format.cc
+++ b/absl/time/internal/cctz/src/time_zone_format.cc
@@ -67,6 +67,48 @@
 }
 #endif
 
+// Convert a cctz::weekday to a tm_wday value (0-6, Sunday = 0).
+int ToTmWday(weekday wd) {
+  switch (wd) {
+    case weekday::sunday:
+      return 0;
+    case weekday::monday:
+      return 1;
+    case weekday::tuesday:
+      return 2;
+    case weekday::wednesday:
+      return 3;
+    case weekday::thursday:
+      return 4;
+    case weekday::friday:
+      return 5;
+    case weekday::saturday:
+      return 6;
+  }
+  return 0; /*NOTREACHED*/
+}
+
+// Convert a tm_wday value (0-6, Sunday = 0) to a cctz::weekday.
+weekday FromTmWday(int tm_wday) {
+  switch (tm_wday) {
+    case 0:
+      return weekday::sunday;
+    case 1:
+      return weekday::monday;
+    case 2:
+      return weekday::tuesday;
+    case 3:
+      return weekday::wednesday;
+    case 4:
+      return weekday::thursday;
+    case 5:
+      return weekday::friday;
+    case 6:
+      return weekday::saturday;
+  }
+  return weekday::sunday; /*NOTREACHED*/
+}
+
 std::tm ToTM(const time_zone::absolute_lookup& al) {
   std::tm tm{};
   tm.tm_sec = al.cs.second();
@@ -84,34 +126,19 @@
     tm.tm_year = static_cast<int>(al.cs.year() - 1900);
   }
 
-  switch (get_weekday(al.cs)) {
-    case weekday::sunday:
-      tm.tm_wday = 0;
-      break;
-    case weekday::monday:
-      tm.tm_wday = 1;
-      break;
-    case weekday::tuesday:
-      tm.tm_wday = 2;
-      break;
-    case weekday::wednesday:
-      tm.tm_wday = 3;
-      break;
-    case weekday::thursday:
-      tm.tm_wday = 4;
-      break;
-    case weekday::friday:
-      tm.tm_wday = 5;
-      break;
-    case weekday::saturday:
-      tm.tm_wday = 6;
-      break;
-  }
+  tm.tm_wday = ToTmWday(get_weekday(al.cs));
   tm.tm_yday = get_yearday(al.cs) - 1;
   tm.tm_isdst = al.is_dst ? 1 : 0;
   return tm;
 }
 
+// Returns the week of the year [0:53] given a civil day and the day on
+// which weeks are defined to start.
+int ToWeek(const civil_day& cd, weekday week_start) {
+  const civil_day d(cd.year() % 400, cd.month(), cd.day());
+  return static_cast<int>((d - prev_weekday(civil_year(d), week_start)) / 7);
+}
+
 const char kDigits[] = "0123456789";
 
 // Formats a 64-bit integer in the given field width.  Note that it is up
@@ -355,7 +382,7 @@
     if (cur == end || (cur - percent) % 2 == 0) continue;
 
     // Simple specifiers that we handle ourselves.
-    if (strchr("YmdeHMSzZs%", *cur)) {
+    if (strchr("YmdeUuWwHMSzZs%", *cur)) {
       if (cur - 1 != pending) {
         FormatTM(&result, std::string(pending, cur - 1), tm);
       }
@@ -376,6 +403,22 @@
           if (*cur == 'e' && *bp == '0') *bp = ' ';  // for Windows
           result.append(bp, static_cast<std::size_t>(ep - bp));
           break;
+        case 'U':
+          bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::sunday));
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'u':
+          bp = Format64(ep, 0, tm.tm_wday ? tm.tm_wday : 7);
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'W':
+          bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::monday));
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'w':
+          bp = Format64(ep, 0, tm.tm_wday);
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
         case 'H':
           bp = Format02d(ep, al.cs.hour());
           result.append(bp, static_cast<std::size_t>(ep - bp));
@@ -610,6 +653,17 @@
   return dp;
 }
 
+// Sets year, tm_mon and tm_mday given the year, week_num, and tm_wday,
+// and the day on which weeks are defined to start.
+void FromWeek(int week_num, weekday week_start, year_t* year, std::tm* tm) {
+  const civil_year y(*year % 400);
+  civil_day cd = prev_weekday(y, week_start);  // week 0
+  cd = next_weekday(cd - 1, FromTmWday(tm->tm_wday)) + (week_num * 7);
+  *year += cd.year() - y.year();
+  tm->tm_mon = cd.month() - 1;
+  tm->tm_mday = cd.day();
+}
+
 }  // namespace
 
 // Uses strptime(3) to parse the given input.  Supports the same extended
@@ -659,6 +713,8 @@
   const char* fmt = format.c_str();  // NUL terminated
   bool twelve_hour = false;
   bool afternoon = false;
+  int week_num = -1;
+  weekday week_start = weekday::sunday;
 
   bool saw_percent_s = false;
   std::int_fast64_t percent_s = 0;
@@ -697,10 +753,27 @@
       case 'm':
         data = ParseInt(data, 2, 1, 12, &tm.tm_mon);
         if (data != nullptr) tm.tm_mon -= 1;
+        week_num = -1;
         continue;
       case 'd':
       case 'e':
         data = ParseInt(data, 2, 1, 31, &tm.tm_mday);
+        week_num = -1;
+        continue;
+      case 'U':
+        data = ParseInt(data, 0, 0, 53, &week_num);
+        week_start = weekday::sunday;
+        continue;
+      case 'W':
+        data = ParseInt(data, 0, 0, 53, &week_num);
+        week_start = weekday::monday;
+        continue;
+      case 'u':
+        data = ParseInt(data, 0, 1, 7, &tm.tm_wday);
+        if (data != nullptr) tm.tm_wday %= 7;
+        continue;
+      case 'w':
+        data = ParseInt(data, 0, 0, 6, &tm.tm_wday);
         continue;
       case 'H':
         data = ParseInt(data, 2, 0, 23, &tm.tm_hour);
@@ -891,6 +964,9 @@
     year += 1900;
   }
 
+  // Compute year, tm.tm_mon and tm.tm_mday if we parsed a week number.
+  if (week_num != -1) FromWeek(week_num, week_start, &year, &tm);
+
   const int month = tm.tm_mon + 1;
   civil_second cs(year, month, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
 
diff --git a/absl/time/internal/cctz/src/time_zone_format_test.cc b/absl/time/internal/cctz/src/time_zone_format_test.cc
index 13a4227..e625a83 100644
--- a/absl/time/internal/cctz/src/time_zone_format_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_format_test.cc
@@ -679,6 +679,34 @@
   EXPECT_EQ("28 Jun 1977 09:08:07 -0700", format(RFC1123_no_wday, tp, tz));
 }
 
+TEST(Format, Week) {
+  const time_zone utc = utc_time_zone();
+
+  auto tp = convert(civil_second(2017, 1, 1, 0, 0, 0), utc);
+  EXPECT_EQ("2017-01-7", format("%Y-%U-%u", tp, utc));
+  EXPECT_EQ("2017-00-0", format("%Y-%W-%w", tp, utc));
+
+  tp = convert(civil_second(2017, 12, 31, 0, 0, 0), utc);
+  EXPECT_EQ("2017-53-7", format("%Y-%U-%u", tp, utc));
+  EXPECT_EQ("2017-52-0", format("%Y-%W-%w", tp, utc));
+
+  tp = convert(civil_second(2018, 1, 1, 0, 0, 0), utc);
+  EXPECT_EQ("2018-00-1", format("%Y-%U-%u", tp, utc));
+  EXPECT_EQ("2018-01-1", format("%Y-%W-%w", tp, utc));
+
+  tp = convert(civil_second(2018, 12, 31, 0, 0, 0), utc);
+  EXPECT_EQ("2018-52-1", format("%Y-%U-%u", tp, utc));
+  EXPECT_EQ("2018-53-1", format("%Y-%W-%w", tp, utc));
+
+  tp = convert(civil_second(2019, 1, 1, 0, 0, 0), utc);
+  EXPECT_EQ("2019-00-2", format("%Y-%U-%u", tp, utc));
+  EXPECT_EQ("2019-00-2", format("%Y-%W-%w", tp, utc));
+
+  tp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
+  EXPECT_EQ("2019-52-2", format("%Y-%U-%u", tp, utc));
+  EXPECT_EQ("2019-52-2", format("%Y-%W-%w", tp, utc));
+}
+
 //
 // Testing parse()
 //
@@ -1395,6 +1423,66 @@
   EXPECT_EQ(tp, tp4);
 }
 
+TEST(Parse, Week) {
+  const time_zone utc = utc_time_zone();
+  time_point<absl::time_internal::cctz::seconds> tp;
+
+  auto exp = convert(civil_second(2017, 1, 1, 0, 0, 0), utc);
+  EXPECT_TRUE(parse("%Y-%U-%u", "2017-01-7", utc, &tp));
+  EXPECT_EQ(exp, tp);
+  EXPECT_TRUE(parse("%Y-%W-%w", "2017-00-0", utc, &tp));
+  EXPECT_EQ(exp, tp);
+
+  exp = convert(civil_second(2017, 12, 31, 0, 0, 0), utc);
+  EXPECT_TRUE(parse("%Y-%U-%u", "2017-53-7", utc, &tp));
+  EXPECT_EQ(exp, tp);
+  EXPECT_TRUE(parse("%Y-%W-%w", "2017-52-0", utc, &tp));
+  EXPECT_EQ(exp, tp);
+
+  exp = convert(civil_second(2018, 1, 1, 0, 0, 0), utc);
+  EXPECT_TRUE(parse("%Y-%U-%u", "2018-00-1", utc, &tp));
+  EXPECT_EQ(exp, tp);
+  EXPECT_TRUE(parse("%Y-%W-%w", "2018-01-1", utc, &tp));
+  EXPECT_EQ(exp, tp);
+
+  exp = convert(civil_second(2018, 12, 31, 0, 0, 0), utc);
+  EXPECT_TRUE(parse("%Y-%U-%u", "2018-52-1", utc, &tp));
+  EXPECT_EQ(exp, tp);
+  EXPECT_TRUE(parse("%Y-%W-%w", "2018-53-1", utc, &tp));
+  EXPECT_EQ(exp, tp);
+
+  exp = convert(civil_second(2019, 1, 1, 0, 0, 0), utc);
+  EXPECT_TRUE(parse("%Y-%U-%u", "2019-00-2", utc, &tp));
+  EXPECT_EQ(exp, tp);
+  EXPECT_TRUE(parse("%Y-%W-%w", "2019-00-2", utc, &tp));
+  EXPECT_EQ(exp, tp);
+
+  exp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
+  EXPECT_TRUE(parse("%Y-%U-%u", "2019-52-2", utc, &tp));
+  EXPECT_EQ(exp, tp);
+  EXPECT_TRUE(parse("%Y-%W-%w", "2019-52-2", utc, &tp));
+  EXPECT_EQ(exp, tp);
+}
+
+TEST(Parse, WeekYearShift) {
+  // %U/%W conversions with week values in {0, 52, 53} can slip
+  // into the previous/following calendar years.
+  const time_zone utc = utc_time_zone();
+  time_point<absl::time_internal::cctz::seconds> tp;
+
+  auto exp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
+  EXPECT_TRUE(parse("%Y-%U-%u", "2020-00-2", utc, &tp));
+  EXPECT_EQ(exp, tp);
+  EXPECT_TRUE(parse("%Y-%W-%w", "2020-00-2", utc, &tp));
+  EXPECT_EQ(exp, tp);
+
+  exp = convert(civil_second(2021, 1, 1, 0, 0, 0), utc);
+  EXPECT_TRUE(parse("%Y-%U-%u", "2020-52-5", utc, &tp));
+  EXPECT_EQ(exp, tp);
+  EXPECT_TRUE(parse("%Y-%W-%w", "2020-52-5", utc, &tp));
+  EXPECT_EQ(exp, tp);
+}
+
 TEST(Parse, MaxRange) {
   const time_zone utc = utc_time_zone();
   time_point<absl::time_internal::cctz::seconds> tp;
diff --git a/absl/time/internal/cctz/src/time_zone_impl.cc b/absl/time/internal/cctz/src/time_zone_impl.cc
index 030ae0e..f34e3ae 100644
--- a/absl/time/internal/cctz/src/time_zone_impl.cc
+++ b/absl/time/internal/cctz/src/time_zone_impl.cc
@@ -15,6 +15,7 @@
 #include "time_zone_impl.h"
 
 #include <deque>
+#include <memory>
 #include <mutex>
 #include <string>
 #include <unordered_map>
@@ -48,17 +49,16 @@
 time_zone time_zone::Impl::UTC() { return time_zone(UTCImpl()); }
 
 bool time_zone::Impl::LoadTimeZone(const std::string& name, time_zone* tz) {
-  const time_zone::Impl* const utc_impl = UTCImpl();
+  const Impl* const utc_impl = UTCImpl();
 
-  // First check for UTC (which is never a key in time_zone_map).
+  // Check for UTC (which is never a key in time_zone_map).
   auto offset = seconds::zero();
   if (FixedOffsetFromName(name, &offset) && offset == seconds::zero()) {
     *tz = time_zone(utc_impl);
     return true;
   }
 
-  // Then check, under a shared lock, whether the time zone has already
-  // been loaded. This is the common path. TODO: Move to shared_mutex.
+  // Check whether the time zone has already been loaded.
   {
     std::lock_guard<std::mutex> lock(TimeZoneMutex());
     if (time_zone_map != nullptr) {
@@ -70,20 +70,15 @@
     }
   }
 
-  // Now check again, under an exclusive lock.
+  // Load the new time zone (outside the lock).
+  std::unique_ptr<const Impl> new_impl(new Impl(name));
+
+  // Add the new time zone to the map.
   std::lock_guard<std::mutex> lock(TimeZoneMutex());
   if (time_zone_map == nullptr) time_zone_map = new TimeZoneImplByName;
   const Impl*& impl = (*time_zone_map)[name];
-  if (impl == nullptr) {
-    // The first thread in loads the new time zone.
-    Impl* new_impl = new Impl(name);
-    new_impl->zone_ = TimeZoneIf::Load(new_impl->name_);
-    if (new_impl->zone_ == nullptr) {
-      delete new_impl;  // free the nascent Impl
-      impl = utc_impl;  // and fallback to UTC
-    } else {
-      impl = new_impl;  // install new time zone
-    }
+  if (impl == nullptr) {  // this thread won any load race
+    impl = new_impl->zone_ ? new_impl.release() : utc_impl;
   }
   *tz = time_zone(impl);
   return impl != utc_impl;
@@ -104,14 +99,11 @@
   }
 }
 
-time_zone::Impl::Impl(const std::string& name) : name_(name) {}
+time_zone::Impl::Impl(const std::string& name)
+    : name_(name), zone_(TimeZoneIf::Load(name_)) {}
 
 const time_zone::Impl* time_zone::Impl::UTCImpl() {
-  static Impl* utc_impl = [] {
-    Impl* impl = new Impl("UTC");
-    impl->zone_ = TimeZoneIf::Load(impl->name_);  // never fails
-    return impl;
-  }();
+  static const Impl* utc_impl = new Impl("UTC");  // never fails
   return utc_impl;
 }