diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index 1af9e45..816e592 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -118,7 +118,6 @@
     srcs = ["dynamic_annotations.cc"],
     hdrs = ["dynamic_annotations.h"],
     copts = ABSL_DEFAULT_COPTS,
-    defines = ["__CLANG_SUPPORT_DYN_ANNOTATION__"],
     linkopts = ABSL_DEFAULT_LINKOPTS,
 )
 
@@ -541,7 +540,10 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     tags = ["no_test_ios_x86_64"],
-    deps = [":malloc_internal"],
+    deps = [
+        ":malloc_internal",
+        "//absl/container:node_hash_map",
+    ],
 )
 
 cc_test(
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index a63b591..292998b 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -108,8 +108,6 @@
     "dynamic_annotations.cc"
   COPTS
     ${ABSL_DEFAULT_COPTS}
-  DEFINES
-    "__CLANG_SUPPORT_DYN_ANNOTATION__"
   PUBLIC
 )
 
@@ -497,6 +495,7 @@
     ${ABSL_TEST_COPTS}
   DEPS
     absl::malloc_internal
+    absl::node_hash_map
     Threads::Threads
 )
 
diff --git a/absl/base/attributes.h b/absl/base/attributes.h
index b4bb6cf..c4fd81b 100644
--- a/absl/base/attributes.h
+++ b/absl/base/attributes.h
@@ -45,9 +45,9 @@
 //
 //   * `ADDRESS_SANITIZER` + `-fsanitize=address` (Clang, GCC 4.8)
 //   * `MEMORY_SANITIZER` + `-fsanitize=memory` (Clang-only)
-//   * `THREAD_SANITIZER + `-fsanitize=thread` (Clang, GCC 4.8+)
+//   * `THREAD_SANITIZER` + `-fsanitize=thread` (Clang, GCC 4.8+)
 //   * `UNDEFINED_BEHAVIOR_SANITIZER` + `-fsanitize=undefined` (Clang, GCC 4.9+)
-//   * `CONTROL_FLOW_INTEGRITY` + -fsanitize=cfi (Clang-only)
+//   * `CONTROL_FLOW_INTEGRITY` + `-fsanitize=cfi` (Clang-only)
 //
 // Example:
 //
diff --git a/absl/base/dynamic_annotations.h b/absl/base/dynamic_annotations.h
index 65a54b4..2d98526 100644
--- a/absl/base/dynamic_annotations.h
+++ b/absl/base/dynamic_annotations.h
@@ -140,10 +140,7 @@
   #define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) /* empty */
 #endif  /* DYNAMIC_ANNOTATIONS_ENABLED || MEMORY_SANITIZER */
 
-/* TODO(delesley) -- Replace __CLANG_SUPPORT_DYN_ANNOTATION__ with the
-   appropriate feature ID. */
-#if defined(__clang__) && (!defined(SWIG)) \
-    && defined(__CLANG_SUPPORT_DYN_ANNOTATION__)
+#if defined(__clang__) && !defined(SWIG)
 
   #if DYNAMIC_ANNOTATIONS_ENABLED == 0
     #define ANNOTALYSIS_ENABLED
diff --git a/absl/base/internal/low_level_alloc_test.cc b/absl/base/internal/low_level_alloc_test.cc
index 7abbbf9..2f2eaff 100644
--- a/absl/base/internal/low_level_alloc_test.cc
+++ b/absl/base/internal/low_level_alloc_test.cc
@@ -21,6 +21,8 @@
 #include <unordered_map>
 #include <utility>
 
+#include "absl/container/node_hash_map.h"
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace base_internal {
@@ -75,7 +77,7 @@
 // allocations and deallocations are reported via the MallocHook
 // interface.
 static void Test(bool use_new_arena, bool call_malloc_hook, int n) {
-  typedef std::unordered_map<int, BlockDesc> AllocMap;
+  typedef absl::node_hash_map<int, BlockDesc> AllocMap;
   AllocMap allocated;
   AllocMap::iterator it;
   BlockDesc block_desc;
diff --git a/absl/base/internal/spinlock.cc b/absl/base/internal/spinlock.cc
index fd0c733..7cac72f 100644
--- a/absl/base/internal/spinlock.cc
+++ b/absl/base/internal/spinlock.cc
@@ -66,6 +66,13 @@
   submit_profile_data.Store(fn);
 }
 
+// Static member variable definitions.
+constexpr uint32_t SpinLock::kSpinLockHeld;
+constexpr uint32_t SpinLock::kSpinLockCooperative;
+constexpr uint32_t SpinLock::kSpinLockDisabledScheduling;
+constexpr uint32_t SpinLock::kSpinLockSleeper;
+constexpr uint32_t SpinLock::kWaitTimeMask;
+
 // Uncommon constructors.
 SpinLock::SpinLock(base_internal::SchedulingMode mode)
     : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {
diff --git a/absl/base/internal/spinlock.h b/absl/base/internal/spinlock.h
index 89e93aa..2b08a2d 100644
--- a/absl/base/internal/spinlock.h
+++ b/absl/base/internal/spinlock.h
@@ -36,6 +36,7 @@
 #include <atomic>
 
 #include "absl/base/attributes.h"
+#include "absl/base/const_init.h"
 #include "absl/base/dynamic_annotations.h"
 #include "absl/base/internal/low_level_scheduling.h"
 #include "absl/base/internal/raw_logging.h"
@@ -77,6 +78,10 @@
   SpinLock(base_internal::LinkerInitialized,
            base_internal::SchedulingMode mode);
 
+  // Constructor for global SpinLock instances.  See absl/base/const_init.h.
+  constexpr SpinLock(absl::ConstInitType, base_internal::SchedulingMode mode)
+      : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {}
+
   ~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); }
 
   // Acquire this SpinLock.
diff --git a/absl/base/internal/sysinfo.cc b/absl/base/internal/sysinfo.cc
index 72f9f17..6c69683 100644
--- a/absl/base/internal/sysinfo.cc
+++ b/absl/base/internal/sysinfo.cc
@@ -53,6 +53,7 @@
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/internal/spinlock.h"
 #include "absl/base/internal/unscaledcycleclock.h"
+#include "absl/base/thread_annotations.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -343,15 +344,16 @@
 #else
 
 // Fallback implementation of GetTID using pthread_getspecific.
-static once_flag tid_once;
-static pthread_key_t tid_key;
-static absl::base_internal::SpinLock tid_lock(
-    absl::base_internal::kLinkerInitialized);
+ABSL_CONST_INIT static once_flag tid_once;
+ABSL_CONST_INIT static pthread_key_t tid_key;
+ABSL_CONST_INIT static absl::base_internal::SpinLock tid_lock(
+    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
 
 // We set a bit per thread in this array to indicate that an ID is in
 // use. ID 0 is unused because it is the default value returned by
 // pthread_getspecific().
-static std::vector<uint32_t>* tid_array GUARDED_BY(tid_lock) = nullptr;
+ABSL_CONST_INIT static std::vector<uint32_t> *tid_array
+    ABSL_GUARDED_BY(tid_lock) = nullptr;
 static constexpr int kBitsPerWord = 32;  // tid_array is uint32_t.
 
 // Returns the TID to tid_array.
diff --git a/absl/base/internal/thread_identity_test.cc b/absl/base/internal/thread_identity_test.cc
index 3685779..624d5b9 100644
--- a/absl/base/internal/thread_identity_test.cc
+++ b/absl/base/internal/thread_identity_test.cc
@@ -21,6 +21,7 @@
 #include "absl/base/attributes.h"
 #include "absl/base/internal/spinlock.h"
 #include "absl/base/macros.h"
+#include "absl/base/thread_annotations.h"
 #include "absl/synchronization/internal/per_thread_sem.h"
 #include "absl/synchronization/mutex.h"
 
@@ -29,10 +30,9 @@
 namespace base_internal {
 namespace {
 
-// protects num_identities_reused
-static absl::base_internal::SpinLock map_lock(
-    absl::base_internal::kLinkerInitialized);
-static int num_identities_reused;
+ABSL_CONST_INIT static absl::base_internal::SpinLock map_lock(
+    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+ABSL_CONST_INIT static int num_identities_reused ABSL_GUARDED_BY(map_lock);
 
 static const void* const kCheckNoIdentity = reinterpret_cast<void*>(1);
 
@@ -90,6 +90,7 @@
   // We should have recycled ThreadIdentity objects above; while (external)
   // library threads allocating their own identities may preclude some
   // reuse, we should have sufficient repetitions to exclude this.
+  absl::base_internal::SpinLockHolder l(&map_lock);
   EXPECT_LT(kNumThreads, num_identities_reused);
 }
 
diff --git a/absl/base/spinlock_test_common.cc b/absl/base/spinlock_test_common.cc
index 08f61ba..b68c51a 100644
--- a/absl/base/spinlock_test_common.cc
+++ b/absl/base/spinlock_test_common.cc
@@ -56,12 +56,10 @@
 static constexpr int kArrayLength = 10;
 static uint32_t values[kArrayLength];
 
-static SpinLock static_spinlock(base_internal::kLinkerInitialized);
-static SpinLock static_cooperative_spinlock(
-    base_internal::kLinkerInitialized,
-    base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL);
-static SpinLock static_noncooperative_spinlock(
-    base_internal::kLinkerInitialized, base_internal::SCHEDULE_KERNEL_ONLY);
+ABSL_CONST_INIT static SpinLock static_cooperative_spinlock(
+    absl::kConstInit, base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL);
+ABSL_CONST_INIT static SpinLock static_noncooperative_spinlock(
+    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
 
 // Simple integer hash function based on the public domain lookup2 hash.
 // http://burtleburtle.net/bob/c/lookup2.c
@@ -191,10 +189,6 @@
   EXPECT_GT(expected_max_value_decoded, before_max_value_decoded);
 }
 
-TEST(SpinLockWithThreads, StaticSpinLock) {
-  ThreadedTest(&static_spinlock);
-}
-
 TEST(SpinLockWithThreads, StackSpinLock) {
   SpinLock spinlock;
   ThreadedTest(&spinlock);
diff --git a/absl/container/internal/container_memory.h b/absl/container/internal/container_memory.h
index 3487ac1..536ea39 100644
--- a/absl/container/internal/container_memory.h
+++ b/absl/container/internal/container_memory.h
@@ -250,8 +250,8 @@
 // type, which is non-portable.
 template <class Pair, class = std::true_type>
 struct OffsetOf {
-  static constexpr size_t kFirst = -1;
-  static constexpr size_t kSecond = -1;
+  static constexpr size_t kFirst = static_cast<size_t>(-1);
+  static constexpr size_t kSecond = static_cast<size_t>(-1);
 };
 
 template <class Pair>
diff --git a/absl/container/node_hash_map.h b/absl/container/node_hash_map.h
index fccea18..174b971 100644
--- a/absl/container/node_hash_map.h
+++ b/absl/container/node_hash_map.h
@@ -514,12 +514,6 @@
   //
   // Returns the function used for comparing keys equality.
   using Base::key_eq;
-
-  ABSL_DEPRECATED("Call `hash_function()` instead.")
-  typename Base::hasher hash_funct() { return this->hash_function(); }
-
-  ABSL_DEPRECATED("Call `rehash()` instead.")
-  void resize(typename Base::size_type hint) { this->rehash(hint); }
 };
 
 // erase_if(node_hash_map<>, Pred)
diff --git a/absl/container/node_hash_set.h b/absl/container/node_hash_set.h
index ad54b6d..56bab5c 100644
--- a/absl/container/node_hash_set.h
+++ b/absl/container/node_hash_set.h
@@ -427,12 +427,6 @@
   //
   // Returns the function used for comparing keys equality.
   using Base::key_eq;
-
-  ABSL_DEPRECATED("Call `hash_function()` instead.")
-  typename Base::hasher hash_funct() { return this->hash_function(); }
-
-  ABSL_DEPRECATED("Call `rehash()` instead.")
-  void resize(typename Base::size_type hint) { this->rehash(hint); }
 };
 
 // erase_if(node_hash_set<>, Pred)
diff --git a/absl/debugging/internal/stacktrace_arm-inl.inc b/absl/debugging/internal/stacktrace_arm-inl.inc
index fffda96..2a1bf2e 100644
--- a/absl/debugging/internal/stacktrace_arm-inl.inc
+++ b/absl/debugging/internal/stacktrace_arm-inl.inc
@@ -1,9 +1,18 @@
-// Copyright 2011 and onwards Google Inc.
-// All rights reserved.
+// Copyright 2017 The Abseil Authors.
 //
-// Author: Doug Kwan
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
 // This is inspired by Craig Silverstein's PowerPC stacktrace code.
-//
 
 #ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_
 #define ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_
diff --git a/absl/debugging/internal/stacktrace_generic-inl.inc b/absl/debugging/internal/stacktrace_generic-inl.inc
index ac034c9..b2792a1 100644
--- a/absl/debugging/internal/stacktrace_generic-inl.inc
+++ b/absl/debugging/internal/stacktrace_generic-inl.inc
@@ -1,7 +1,16 @@
-// Copyright 2000 - 2007 Google Inc.
-// All rights reserved.
+// Copyright 2017 The Abseil Authors.
 //
-// Author: Sanjay Ghemawat
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 //
 // Portable implementation - just use glibc
 //
diff --git a/absl/debugging/symbolize_elf.inc b/absl/debugging/symbolize_elf.inc
index fe1d36e..ec86f9a 100644
--- a/absl/debugging/symbolize_elf.inc
+++ b/absl/debugging/symbolize_elf.inc
@@ -149,13 +149,15 @@
 // Moreover, we are using only TryLock(), if the decorator list
 // is being modified (is busy), we skip all decorators, and possibly
 // loose some info. Sorry, that's the best we could do.
-base_internal::SpinLock g_decorators_mu(base_internal::kLinkerInitialized);
+ABSL_CONST_INIT absl::base_internal::SpinLock g_decorators_mu(
+    absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY);
 
 const int kMaxFileMappingHints = 8;
 int g_num_file_mapping_hints;
 FileMappingHint g_file_mapping_hints[kMaxFileMappingHints];
 // Protects g_file_mapping_hints.
-base_internal::SpinLock g_file_mapping_mu(base_internal::kLinkerInitialized);
+ABSL_CONST_INIT absl::base_internal::SpinLock g_file_mapping_mu(
+    absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY);
 
 // Async-signal-safe function to zero a buffer.
 // memset() is not guaranteed to be async-signal-safe.
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel
index 685e395..3681082 100644
--- a/absl/flags/BUILD.bazel
+++ b/absl/flags/BUILD.bazel
@@ -40,6 +40,7 @@
     deps = [
         ":config",
         ":handle",
+        ":marshalling",
         ":registry",
         "//absl/base",
         "//absl/base:config",
@@ -143,8 +144,6 @@
         "//absl/flags:__pkg__",
     ],
     deps = [
-        ":config",
-        ":marshalling",
         "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:fast_type_id",
@@ -154,6 +153,22 @@
 )
 
 cc_library(
+    name = "private_handle_accessor",
+    srcs = [
+        "internal/private_handle_accessor.cc",
+    ],
+    hdrs = [
+        "internal/private_handle_accessor.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl/flags:__pkg__",
+    ],
+    deps = [":handle"],
+)
+
+cc_library(
     name = "registry",
     srcs = [
         "internal/registry.cc",
@@ -171,6 +186,7 @@
     deps = [
         ":config",
         ":handle",
+        ":private_handle_accessor",
         "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:raw_logging_internal",
@@ -222,6 +238,7 @@
         ":flag_internal",
         ":handle",
         ":path_util",
+        ":private_handle_accessor",
         ":program_name",
         ":registry",
         "//absl/base:config",
@@ -263,6 +280,7 @@
         ":flag",
         ":flag_internal",
         ":handle",
+        ":private_handle_accessor",
         ":program_name",
         ":registry",
         ":usage",
@@ -289,6 +307,7 @@
         ":config",
         ":flag",
         ":handle",
+        ":private_handle_accessor",
         ":registry",
         "//absl/memory",
         "//absl/strings",
diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt
index ec82ee1..e6b17c9 100644
--- a/absl/flags/CMakeLists.txt
+++ b/absl/flags/CMakeLists.txt
@@ -31,6 +31,7 @@
     absl::config
     absl::flags_config
     absl::flags_handle
+    absl::flags_marshalling
     absl::flags_registry
     absl::synchronization
     absl::meta
@@ -129,8 +130,6 @@
   DEPS
     absl::config
     absl::fast_type_id
-    absl::flags_config
-    absl::flags_marshalling
     absl::core_headers
     absl::optional
     absl::raw_logging_internal
@@ -141,6 +140,22 @@
 # Internal-only target, do not depend on directly.
 absl_cc_library(
   NAME
+    flags_private_handle_accessor
+  SRCS
+    "internal/private_handle_accessor.cc"
+  HDRS
+    "internal/private_handle_accessor.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+    absl::flags_handle
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+  NAME
     flags_registry
   SRCS
     "internal/registry.cc"
@@ -156,6 +171,7 @@
     absl::config
     absl::flags_config
     absl::flags_handle
+    absl::flags_private_handle_accessor
     absl::core_headers
     absl::raw_logging_internal
     absl::strings
@@ -203,6 +219,7 @@
     absl::flags_config
     absl::flags
     absl::flags_handle
+    absl::flags_private_handle_accessor
     absl::flags_internal
     absl::flags_path_util
     absl::flags_program_name
@@ -248,6 +265,7 @@
     absl::flags_config
     absl::flags
     absl::flags_handle
+    absl::flags_private_handle_accessor
     absl::flags_internal
     absl::flags_program_name
     absl::flags_registry
@@ -270,6 +288,7 @@
     absl::flags
     absl::flags_config
     absl::flags_handle
+    absl::flags_private_handle_accessor
     absl::flags_registry
     absl::memory
     absl::strings
diff --git a/absl/flags/flag.h b/absl/flags/flag.h
index 194a9d3..8dd1b9b 100644
--- a/absl/flags/flag.h
+++ b/absl/flags/flag.h
@@ -118,11 +118,12 @@
         return impl_;
       }
 
-      impl_ =
-          new flags_internal::Flag<T>(name_, filename_,
-                                      {flags_internal::FlagHelpMsg(help_gen_),
-                                       flags_internal::FlagHelpKind::kGenFunc},
-                                      default_value_gen_);
+      impl_ = new flags_internal::Flag<T>(
+          name_, filename_,
+          {flags_internal::FlagHelpMsg(help_gen_),
+           flags_internal::FlagHelpKind::kGenFunc},
+          {flags_internal::FlagDefaultSrc(default_value_gen_),
+           flags_internal::FlagDefaultKind::kGenFunc});
       inited_.store(true, std::memory_order_release);
     }
 
@@ -132,14 +133,12 @@
   // Public methods of `absl::Flag<T>` are NOT part of the Abseil Flags API.
   // See https://abseil.io/docs/cpp/guides/flags
   bool IsRetired() const { return GetImpl()->IsRetired(); }
-  bool IsAbseilFlag() const { return GetImpl()->IsAbseilFlag(); }
   absl::string_view Name() const { return GetImpl()->Name(); }
   std::string Help() const { return GetImpl()->Help(); }
   bool IsModified() const { return GetImpl()->IsModified(); }
   bool IsSpecifiedOnCommandLine() const {
     return GetImpl()->IsSpecifiedOnCommandLine();
   }
-  absl::string_view Typename() const { return GetImpl()->Typename(); }
   std::string Filename() const { return GetImpl()->Filename(); }
   std::string DefaultValue() const { return GetImpl()->DefaultValue(); }
   std::string CurrentValue() const { return GetImpl()->CurrentValue(); }
@@ -311,9 +310,12 @@
     static std::string NonConst() { return ABSL_FLAG_IMPL_FLAGHELP(txt); } \
   }
 
-#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \
-  static void AbslFlagsInitFlag##name(void* dst) {                        \
-    absl::flags_internal::MakeFromDefaultValue<Type>(dst, default_value); \
+#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value)     \
+  struct AbslFlagDefaultGenFor##name {                                        \
+    Type value = absl::flags_internal::InitDefaultValue<Type>(default_value); \
+    static void Gen(void* p) {                                                \
+      new (p) Type(AbslFlagDefaultGenFor##name{}.value);                      \
+    }                                                                         \
   }
 
 // ABSL_FLAG_IMPL
@@ -322,29 +324,30 @@
 // global name for FLAGS_no<flag_name> symbol, thus preventing the possibility
 // of defining two flags with names foo and nofoo.
 #if !defined(_MSC_VER) || defined(__clang__)
-#define ABSL_FLAG_IMPL(Type, name, default_value, help)             \
-  namespace absl /* block flags in namespaces */ {}                 \
-  ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \
-  ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help);                  \
-  ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{                    \
-      ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(),    \
-      absl::flags_internal::HelpArg<AbslFlagHelpGenFor##name>(0),   \
-      &AbslFlagsInitFlag##name};                                    \
-  extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name;   \
-  absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name =         \
+
+#define ABSL_FLAG_IMPL(Type, name, default_value, help)                        \
+  namespace absl /* block flags in namespaces */ {}                            \
+  ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value);           \
+  ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help);                             \
+  ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{                               \
+      ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(),               \
+      absl::flags_internal::HelpArg<AbslFlagHelpGenFor##name>(0),              \
+      absl::flags_internal::DefaultArg<Type, AbslFlagDefaultGenFor##name>(0)}; \
+  extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name;              \
+  absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name =                    \
       ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)
 #else
 // MSVC version uses aggregate initialization. We also do not try to
 // optimize away help wrapper.
-#define ABSL_FLAG_IMPL(Type, name, default_value, help)               \
-  namespace absl /* block flags in namespaces */ {}                   \
-  ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value)   \
-  ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help);                    \
-  ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{                      \
-      ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(),      \
-      &AbslFlagHelpGenFor##name::NonConst, &AbslFlagsInitFlag##name}; \
-  extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name;     \
-  absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name =           \
+#define ABSL_FLAG_IMPL(Type, name, default_value, help)                        \
+  namespace absl /* block flags in namespaces */ {}                            \
+  ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value);           \
+  ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help);                             \
+  ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{                               \
+      ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(),               \
+      &AbslFlagHelpGenFor##name::NonConst, &AbslFlagDefaultGenFor##name::Gen}; \
+  extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name;              \
+  absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name =                    \
       ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)
 #endif
 
diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc
index 6fa178f..015b1fc 100644
--- a/absl/flags/flag_test.cc
+++ b/absl/flags/flag_test.cc
@@ -128,26 +128,27 @@
 
 using String = std::string;
 
-#define DEFINE_CONSTRUCTED_FLAG(T)                                          \
-  constexpr flags::Flag<T> f1##T("f1", "file", help_arg, &TestMakeDflt<T>); \
-  ABSL_CONST_INIT flags::Flag<T> f2##T(                                     \
-      "f2", "file",                                                         \
-      {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc},    \
-      &TestMakeDflt<T>)
+#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind)                      \
+  constexpr flags::FlagDefaultArg f1default##T{                          \
+      flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind};   \
+  constexpr flags::Flag<T> f1##T("f1", "file", help_arg, f1default##T);  \
+  ABSL_CONST_INIT flags::Flag<T> f2##T(                                  \
+      "f2", "file",                                                      \
+      {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc}, \
+      flags::FlagDefaultArg{flags::FlagDefaultSrc(&TestMakeDflt<T>),     \
+                            flags::FlagDefaultKind::kGenFunc})
 
-#define TEST_CONSTRUCTED_FLAG(T) TestConstructionFor(f1##T, &f2##T);
-
-DEFINE_CONSTRUCTED_FLAG(bool);
-DEFINE_CONSTRUCTED_FLAG(int16_t);
-DEFINE_CONSTRUCTED_FLAG(uint16_t);
-DEFINE_CONSTRUCTED_FLAG(int32_t);
-DEFINE_CONSTRUCTED_FLAG(uint32_t);
-DEFINE_CONSTRUCTED_FLAG(int64_t);
-DEFINE_CONSTRUCTED_FLAG(uint64_t);
-DEFINE_CONSTRUCTED_FLAG(float);
-DEFINE_CONSTRUCTED_FLAG(double);
-DEFINE_CONSTRUCTED_FLAG(String);
-DEFINE_CONSTRUCTED_FLAG(UDT);
+DEFINE_CONSTRUCTED_FLAG(bool, true, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(int16_t, 1, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(uint16_t, 2, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(int32_t, 3, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(uint32_t, 4, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(int64_t, 5, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(uint64_t, 6, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(float, 7.8, kFloat);
+DEFINE_CONSTRUCTED_FLAG(double, 9.10, kDouble);
+DEFINE_CONSTRUCTED_FLAG(String, &TestMakeDflt<String>, kGenFunc);
+DEFINE_CONSTRUCTED_FLAG(UDT, &TestMakeDflt<UDT>, kGenFunc);
 
 template <typename T>
 bool TestConstructionFor(const flags::Flag<T>& f1, flags::Flag<T>* f2) {
@@ -164,6 +165,8 @@
   return true;
 }
 
+#define TEST_CONSTRUCTED_FLAG(T) TestConstructionFor(f1##T, &f2##T);
+
 TEST_F(FlagTest, TestConstruction) {
   TEST_CONSTRUCTED_FLAG(bool);
   TEST_CONSTRUCTED_FLAG(int16_t);
@@ -443,29 +446,29 @@
 
 TEST_F(FlagTest, TestGetViaReflection) {
   auto* handle = flags::FindCommandLineFlag("test_flag_01");
-  EXPECT_EQ(*handle->Get<bool>(), true);
+  EXPECT_EQ(*handle->TryGet<bool>(), true);
   handle = flags::FindCommandLineFlag("test_flag_02");
-  EXPECT_EQ(*handle->Get<int>(), 1234);
+  EXPECT_EQ(*handle->TryGet<int>(), 1234);
   handle = flags::FindCommandLineFlag("test_flag_03");
-  EXPECT_EQ(*handle->Get<int16_t>(), -34);
+  EXPECT_EQ(*handle->TryGet<int16_t>(), -34);
   handle = flags::FindCommandLineFlag("test_flag_04");
-  EXPECT_EQ(*handle->Get<uint16_t>(), 189);
+  EXPECT_EQ(*handle->TryGet<uint16_t>(), 189);
   handle = flags::FindCommandLineFlag("test_flag_05");
-  EXPECT_EQ(*handle->Get<int32_t>(), 10765);
+  EXPECT_EQ(*handle->TryGet<int32_t>(), 10765);
   handle = flags::FindCommandLineFlag("test_flag_06");
-  EXPECT_EQ(*handle->Get<uint32_t>(), 40000);
+  EXPECT_EQ(*handle->TryGet<uint32_t>(), 40000);
   handle = flags::FindCommandLineFlag("test_flag_07");
-  EXPECT_EQ(*handle->Get<int64_t>(), -1234567);
+  EXPECT_EQ(*handle->TryGet<int64_t>(), -1234567);
   handle = flags::FindCommandLineFlag("test_flag_08");
-  EXPECT_EQ(*handle->Get<uint64_t>(), 9876543);
+  EXPECT_EQ(*handle->TryGet<uint64_t>(), 9876543);
   handle = flags::FindCommandLineFlag("test_flag_09");
-  EXPECT_NEAR(*handle->Get<double>(), -9.876e-50, 1e-55);
+  EXPECT_NEAR(*handle->TryGet<double>(), -9.876e-50, 1e-55);
   handle = flags::FindCommandLineFlag("test_flag_10");
-  EXPECT_NEAR(*handle->Get<float>(), 1.234e12f, 1e5f);
+  EXPECT_NEAR(*handle->TryGet<float>(), 1.234e12f, 1e5f);
   handle = flags::FindCommandLineFlag("test_flag_11");
-  EXPECT_EQ(*handle->Get<std::string>(), "");
+  EXPECT_EQ(*handle->TryGet<std::string>(), "");
   handle = flags::FindCommandLineFlag("test_flag_12");
-  EXPECT_EQ(*handle->Get<absl::Duration>(), absl::Minutes(10));
+  EXPECT_EQ(*handle->TryGet<absl::Duration>(), absl::Minutes(10));
 }
 
 // --------------------------------------------------------------------
diff --git a/absl/flags/internal/commandlineflag.cc b/absl/flags/internal/commandlineflag.cc
index 90765a3..8411243 100644
--- a/absl/flags/internal/commandlineflag.cc
+++ b/absl/flags/internal/commandlineflag.cc
@@ -22,7 +22,11 @@
 FlagStateInterface::~FlagStateInterface() {}
 
 bool CommandLineFlag::IsRetired() const { return false; }
-bool CommandLineFlag::IsAbseilFlag() const { return true; }
+
+bool CommandLineFlag::ParseFrom(absl::string_view value, std::string* error) {
+  return ParseFrom(value, flags_internal::SET_FLAGS_VALUE,
+                   flags_internal::kProgrammaticChange, error);
+}
 
 }  // namespace flags_internal
 ABSL_NAMESPACE_END
diff --git a/absl/flags/internal/commandlineflag.h b/absl/flags/internal/commandlineflag.h
index ef992f7..2d3b794 100644
--- a/absl/flags/internal/commandlineflag.h
+++ b/absl/flags/internal/commandlineflag.h
@@ -16,18 +16,12 @@
 #ifndef ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
 #define ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
 
-#include <stddef.h>
-#include <stdint.h>
-
 #include <memory>
 #include <string>
-#include <typeinfo>
 
 #include "absl/base/config.h"
 #include "absl/base/internal/fast_type_id.h"
 #include "absl/base/macros.h"
-#include "absl/flags/config.h"
-#include "absl/flags/marshalling.h"
 #include "absl/strings/string_view.h"
 #include "absl/types/optional.h"
 
@@ -93,7 +87,7 @@
   // Attempts to retrieve the flag value. Returns value on success,
   // absl::nullopt otherwise.
   template <typename T>
-  absl::optional<T> Get() const {
+  absl::optional<T> TryGet() const {
     if (IsRetired() || !IsOfType<T>()) {
       return absl::nullopt;
     }
@@ -130,28 +124,24 @@
   virtual absl::string_view Name() const = 0;
   // Returns name of the file where this flag is defined.
   virtual std::string Filename() const = 0;
-  // Returns name of the flag's value type for some built-in types or empty
-  // string.
-  virtual absl::string_view Typename() const = 0;
   // Returns help message associated with this flag.
   virtual std::string Help() const = 0;
   // Returns true iff this object corresponds to retired flag.
   virtual bool IsRetired() const;
-  // Returns true iff this is a handle to an Abseil Flag.
-  virtual bool IsAbseilFlag() const;
-  // Returns id of the flag's value type.
-  virtual FlagFastTypeId TypeId() const = 0;
-  virtual bool IsModified() const = 0;
   virtual bool IsSpecifiedOnCommandLine() const = 0;
   virtual std::string DefaultValue() const = 0;
   virtual std::string CurrentValue() const = 0;
 
-  // Interfaces to operate on validators.
-  virtual bool ValidateInputValue(absl::string_view value) const = 0;
+  // Sets the value of the flag based on specified string `value`. If the flag
+  // was successfully set to new value, it returns true. Otherwise, sets `error`
+  // to indicate the error, leaves the flag unchanged, and returns false.
+  bool ParseFrom(absl::string_view value, std::string* error);
 
-  // Interface to save flag to some persistent state. Returns current flag state
-  // or nullptr if flag does not support saving and restoring a state.
-  virtual std::unique_ptr<FlagStateInterface> SaveState() = 0;
+ protected:
+  ~CommandLineFlag() = default;
+
+ private:
+  friend class PrivateHandleAccessor;
 
   // Sets the value of the flag based on specified string `value`. If the flag
   // was successfully set to new value, it returns true. Otherwise, sets `error`
@@ -166,17 +156,23 @@
                          flags_internal::ValueSource source,
                          std::string* error) = 0;
 
-  // Checks that flags default value can be converted to string and back to the
-  // flag's value type.
-  virtual void CheckDefaultValueParsingRoundtrip() const = 0;
+  // Returns id of the flag's value type.
+  virtual FlagFastTypeId TypeId() const = 0;
 
- protected:
-  ~CommandLineFlag() = default;
+  // Interface to save flag to some persistent state. Returns current flag state
+  // or nullptr if flag does not support saving and restoring a state.
+  virtual std::unique_ptr<FlagStateInterface> SaveState() = 0;
 
- private:
   // Copy-construct a new value of the flag's type in a memory referenced by
   // the dst based on the current flag's value.
   virtual void Read(void* dst) const = 0;
+
+  // Validates supplied value usign validator or parseflag routine
+  virtual bool ValidateInputValue(absl::string_view value) const = 0;
+
+  // Checks that flags default value can be converted to string and back to the
+  // flag's value type.
+  virtual void CheckDefaultValueParsingRoundtrip() const = 0;
 };
 
 // This macro is the "source of truth" for the list of supported flag built-in
diff --git a/absl/flags/internal/commandlineflag_test.cc b/absl/flags/internal/commandlineflag_test.cc
index c1142b7..54d50ff 100644
--- a/absl/flags/internal/commandlineflag_test.cc
+++ b/absl/flags/internal/commandlineflag_test.cc
@@ -20,6 +20,7 @@
 
 #include "gtest/gtest.h"
 #include "absl/flags/flag.h"
+#include "absl/flags/internal/private_handle_accessor.h"
 #include "absl/flags/internal/registry.h"
 #include "absl/flags/usage_config.h"
 #include "absl/memory/memory.h"
@@ -67,7 +68,6 @@
   ASSERT_TRUE(flag_01);
   EXPECT_EQ(flag_01->Name(), "int_flag");
   EXPECT_EQ(flag_01->Help(), "int_flag help");
-  EXPECT_EQ(flag_01->Typename(), "");
   EXPECT_TRUE(!flag_01->IsRetired());
   EXPECT_TRUE(flag_01->IsOfType<int>());
   EXPECT_TRUE(
@@ -80,7 +80,6 @@
   ASSERT_TRUE(flag_02);
   EXPECT_EQ(flag_02->Name(), "string_flag");
   EXPECT_EQ(flag_02->Help(), "string_flag help");
-  EXPECT_EQ(flag_02->Typename(), "");
   EXPECT_TRUE(!flag_02->IsRetired());
   EXPECT_TRUE(flag_02->IsOfType<std::string>());
   EXPECT_TRUE(
@@ -93,7 +92,6 @@
   ASSERT_TRUE(flag_03);
   EXPECT_EQ(flag_03->Name(), "bool_retired_flag");
   EXPECT_EQ(flag_03->Help(), "");
-  EXPECT_EQ(flag_03->Typename(), "");
   EXPECT_TRUE(flag_03->IsRetired());
   EXPECT_TRUE(flag_03->IsOfType<bool>());
   EXPECT_EQ(flag_03->Filename(), "RETIRED");
@@ -125,49 +123,53 @@
   auto* flag_01 = flags::FindCommandLineFlag("int_flag");
   EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
 
-  EXPECT_TRUE(flag_01->ParseFrom("11", flags::SET_FLAGS_VALUE,
-                                 flags::kProgrammaticChange, &err));
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      flag_01, "11", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, &err));
   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11);
   EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
 
-  EXPECT_TRUE(flag_01->ParseFrom("-123", flags::SET_FLAGS_VALUE,
-                                 flags::kProgrammaticChange, &err));
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      flag_01, "-123", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
+      &err));
   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
   EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
 
-  EXPECT_TRUE(!flag_01->ParseFrom("xyz", flags::SET_FLAGS_VALUE,
-                                  flags::kProgrammaticChange, &err));
+  EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom(
+      flag_01, "xyz", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
+      &err));
   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
   EXPECT_EQ(err, "Illegal value 'xyz' specified for flag 'int_flag'");
   EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
 
-  EXPECT_TRUE(!flag_01->ParseFrom("A1", flags::SET_FLAGS_VALUE,
-                                  flags::kProgrammaticChange, &err));
+  EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom(
+      flag_01, "A1", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, &err));
   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
   EXPECT_EQ(err, "Illegal value 'A1' specified for flag 'int_flag'");
   EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
 
-  EXPECT_TRUE(flag_01->ParseFrom("0x10", flags::SET_FLAGS_VALUE,
-                                 flags::kProgrammaticChange, &err));
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      flag_01, "0x10", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
+      &err));
   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 16);
   EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
 
-  EXPECT_TRUE(flag_01->ParseFrom("011", flags::SET_FLAGS_VALUE,
-                                 flags::kCommandLine, &err));
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      flag_01, "011", flags::SET_FLAGS_VALUE, flags::kCommandLine, &err));
   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11);
   EXPECT_TRUE(flag_01->IsSpecifiedOnCommandLine());
 
-  EXPECT_TRUE(!flag_01->ParseFrom("", flags::SET_FLAGS_VALUE,
-                                  flags::kProgrammaticChange, &err));
+  EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom(
+      flag_01, "", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, &err));
   EXPECT_EQ(err, "Illegal value '' specified for flag 'int_flag'");
 
   auto* flag_02 = flags::FindCommandLineFlag("string_flag");
-  EXPECT_TRUE(flag_02->ParseFrom("xyz", flags::SET_FLAGS_VALUE,
-                                 flags::kProgrammaticChange, &err));
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      flag_02, "xyz", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
+      &err));
   EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "xyz");
 
-  EXPECT_TRUE(flag_02->ParseFrom("", flags::SET_FLAGS_VALUE,
-                                 flags::kProgrammaticChange, &err));
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      flag_02, "", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, &err));
   EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "");
 }
 
@@ -178,14 +180,16 @@
 
   auto* flag_01 = flags::FindCommandLineFlag("int_flag");
 
-  EXPECT_TRUE(flag_01->ParseFrom("111", flags::SET_FLAGS_DEFAULT,
-                                 flags::kProgrammaticChange, &err));
+  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");
 
-  EXPECT_TRUE(flag_02->ParseFrom("abc", flags::SET_FLAGS_DEFAULT,
-                                 flags::kProgrammaticChange, &err));
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      flag_02, "abc", flags::SET_FLAGS_DEFAULT, flags::kProgrammaticChange,
+      &err));
   EXPECT_EQ(flag_02->DefaultValue(), "abc");
 }
 
@@ -196,22 +200,26 @@
 
   auto* flag_01 = flags::FindCommandLineFlag("int_flag");
 
-  EXPECT_TRUE(flag_01->ParseFrom("22", flags::SET_FLAG_IF_DEFAULT,
-                                 flags::kProgrammaticChange, &err))
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      flag_01, "22", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange,
+      &err))
       << err;
   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22);
 
-  EXPECT_TRUE(flag_01->ParseFrom("33", flags::SET_FLAG_IF_DEFAULT,
-                                 flags::kProgrammaticChange, &err));
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      flag_01, "33", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange,
+      &err));
   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22);
   // EXPECT_EQ(err, "ERROR: int_flag is already set to 22");
 
   // Reset back to default value
-  EXPECT_TRUE(flag_01->ParseFrom("201", flags::SET_FLAGS_VALUE,
-                                 flags::kProgrammaticChange, &err));
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      flag_01, "201", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
+      &err));
 
-  EXPECT_TRUE(flag_01->ParseFrom("33", flags::SET_FLAG_IF_DEFAULT,
-                                 flags::kProgrammaticChange, &err));
+  EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+      flag_01, "33", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange,
+      &err));
   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 201);
   // EXPECT_EQ(err, "ERROR: int_flag is already set to 201");
 }
diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc
index 089567f..8f0777f 100644
--- a/absl/flags/internal/flag.cc
+++ b/absl/flags/internal/flag.cc
@@ -139,19 +139,43 @@
 void FlagImpl::Init() {
   new (&data_guard_) absl::Mutex;
 
-  // At this point the default_value_ always points to gen_func.
+  auto def_kind = static_cast<FlagDefaultKind>(def_kind_);
+
   switch (ValueStorageKind()) {
     case FlagValueStorageKind::kAlignedBuffer:
+      // For this storage kind the default_value_ always points to gen_func
+      // during initialization.
+      assert(def_kind == FlagDefaultKind::kGenFunc);
       (*default_value_.gen_func)(AlignedBufferValue());
       break;
     case FlagValueStorageKind::kOneWordAtomic: {
       alignas(int64_t) std::array<char, sizeof(int64_t)> buf{};
-      (*default_value_.gen_func)(buf.data());
-      auto value = absl::bit_cast<int64_t>(buf);
-      OneWordValue().store(value, std::memory_order_release);
+      switch (def_kind) {
+        case FlagDefaultKind::kOneWord:
+          std::memcpy(buf.data(), &default_value_.one_word,
+                      sizeof(default_value_.one_word));
+          break;
+        case FlagDefaultKind::kFloat:
+          std::memcpy(buf.data(), &default_value_.float_value,
+                      sizeof(default_value_.float_value));
+          break;
+        case FlagDefaultKind::kDouble:
+          std::memcpy(buf.data(), &default_value_.double_value,
+                      sizeof(default_value_.double_value));
+          break;
+        default:
+          assert(def_kind == FlagDefaultKind::kGenFunc);
+          (*default_value_.gen_func)(buf.data());
+          break;
+      }
+      OneWordValue().store(absl::bit_cast<int64_t>(buf),
+                           std::memory_order_release);
       break;
     }
     case FlagValueStorageKind::kTwoWordsAtomic: {
+      // For this storage kind the default_value_ always points to gen_func
+      // during initialization.
+      assert(def_kind == FlagDefaultKind::kGenFunc);
       alignas(AlignedTwoWords) std::array<char, sizeof(AlignedTwoWords)> buf{};
       (*default_value_.gen_func)(buf.data());
       auto atomic_value = absl::bit_cast<AlignedTwoWords>(buf);
@@ -196,11 +220,23 @@
 
 std::unique_ptr<void, DynValueDeleter> FlagImpl::MakeInitValue() const {
   void* res = nullptr;
-  if (DefaultKind() == FlagDefaultKind::kDynamicValue) {
-    res = flags_internal::Clone(op_, default_value_.dynamic_value);
-  } else {
-    res = flags_internal::Alloc(op_);
-    (*default_value_.gen_func)(res);
+  switch (DefaultKind()) {
+    case FlagDefaultKind::kDynamicValue:
+      res = flags_internal::Clone(op_, default_value_.dynamic_value);
+      break;
+    case FlagDefaultKind::kGenFunc:
+      res = flags_internal::Alloc(op_);
+      (*default_value_.gen_func)(res);
+      break;
+    case FlagDefaultKind::kOneWord:
+      res = flags_internal::Clone(op_, &default_value_.one_word);
+      break;
+    case FlagDefaultKind::kFloat:
+      res = flags_internal::Clone(op_, &default_value_.float_value);
+      break;
+    case FlagDefaultKind::kDouble:
+      res = flags_internal::Clone(op_, &default_value_.double_value);
+      break;
   }
   return {res, DynValueDeleter{op_}};
 }
@@ -235,8 +271,6 @@
   return flags_internal::GetUsageConfig().normalize_filename(filename_);
 }
 
-absl::string_view FlagImpl::Typename() const { return ""; }
-
 std::string FlagImpl::Help() const {
   return HelpSourceKind() == FlagHelpKind::kLiteral ? help_.literal
                                                     : help_.gen_func();
@@ -246,11 +280,6 @@
   return flags_internal::FastTypeId(op_);
 }
 
-bool FlagImpl::IsModified() const {
-  absl::MutexLock l(DataGuard());
-  return modified_;
-}
-
 bool FlagImpl::IsSpecifiedOnCommandLine() const {
   absl::MutexLock l(DataGuard());
   return on_command_line_;
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index 6da25aa..f53f484 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -31,6 +31,7 @@
 #include "absl/flags/config.h"
 #include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/registry.h"
+#include "absl/flags/marshalling.h"
 #include "absl/memory/memory.h"
 #include "absl/meta/type_traits.h"
 #include "absl/strings/str_cat.h"
@@ -206,12 +207,72 @@
 union FlagDefaultSrc {
   constexpr explicit FlagDefaultSrc(FlagDfltGenFunc gen_func_arg)
       : gen_func(gen_func_arg) {}
+  template <typename T>
+  constexpr explicit FlagDefaultSrc(T one_word_value)
+      : one_word(static_cast<int64_t>(one_word_value)) {}
+  constexpr explicit FlagDefaultSrc(float f) : float_value(f) {}
+  constexpr explicit FlagDefaultSrc(double d) : double_value(d) {}
 
   void* dynamic_value;
   FlagDfltGenFunc gen_func;
+  int64_t one_word;
+  float float_value;
+  double double_value;
 };
 
-enum class FlagDefaultKind : uint8_t { kDynamicValue = 0, kGenFunc = 1 };
+enum class FlagDefaultKind : uint8_t {
+  kDynamicValue = 0,
+  kGenFunc = 1,
+  kOneWord = 2,
+  kFloat = 3,
+  kDouble = 4
+};
+
+struct FlagDefaultArg {
+  FlagDefaultSrc source;
+  FlagDefaultKind kind;
+};
+
+// This struct and corresponding overload to InitDefaultValue are used to
+// facilitate usage of {} as default value in ABSL_FLAG macro.
+// TODO(rogeeff): Fix handling types with explicit constructors.
+struct EmptyBraces {};
+
+template <typename T>
+constexpr T InitDefaultValue(T t) {
+  return t;
+}
+
+template <typename T>
+constexpr T InitDefaultValue(EmptyBraces) {
+  return T{};
+}
+
+template <typename ValueT, typename GenT,
+          typename std::enable_if<std::is_integral<ValueT>::value, int>::type =
+              (GenT{}, 0)>
+constexpr FlagDefaultArg DefaultArg(int) {
+  return {FlagDefaultSrc(GenT{}.value), FlagDefaultKind::kOneWord};
+}
+
+template <typename ValueT, typename GenT,
+          typename std::enable_if<std::is_same<ValueT, float>::value,
+                                  int>::type = (GenT{}, 0)>
+constexpr FlagDefaultArg DefaultArg(int) {
+  return {FlagDefaultSrc(GenT{}.value), FlagDefaultKind::kFloat};
+}
+
+template <typename ValueT, typename GenT,
+          typename std::enable_if<std::is_same<ValueT, double>::value,
+                                  int>::type = (GenT{}, 0)>
+constexpr FlagDefaultArg DefaultArg(int) {
+  return {FlagDefaultSrc(GenT{}.value), FlagDefaultKind::kDouble};
+}
+
+template <typename ValueT, typename GenT>
+constexpr FlagDefaultArg DefaultArg(char) {
+  return {FlagDefaultSrc(&GenT::Gen), FlagDefaultKind::kGenFunc};
+}
 
 ///////////////////////////////////////////////////////////////////////////////
 // Flag current value auxiliary structs.
@@ -356,19 +417,19 @@
  public:
   constexpr FlagImpl(const char* name, const char* filename, FlagOpFn op,
                      FlagHelpArg help, FlagValueStorageKind value_kind,
-                     FlagDfltGenFunc default_value_gen)
+                     FlagDefaultArg default_arg)
       : name_(name),
         filename_(filename),
         op_(op),
         help_(help.source),
         help_source_kind_(static_cast<uint8_t>(help.kind)),
         value_storage_kind_(static_cast<uint8_t>(value_kind)),
-        def_kind_(static_cast<uint8_t>(FlagDefaultKind::kGenFunc)),
+        def_kind_(static_cast<uint8_t>(default_arg.kind)),
         modified_(false),
         on_command_line_(false),
         counter_(0),
         callback_(nullptr),
-        default_value_(default_value_gen),
+        default_value_(default_arg.source),
         data_guard_{} {}
 
   // Constant access methods
@@ -444,10 +505,8 @@
   // CommandLineFlag interface implementation
   absl::string_view Name() const override;
   std::string Filename() const override;
-  absl::string_view Typename() const override;
   std::string Help() const override;
   FlagFastTypeId TypeId() const override;
-  bool IsModified() const override ABSL_LOCKS_EXCLUDED(*DataGuard());
   bool IsSpecifiedOnCommandLine() const override
       ABSL_LOCKS_EXCLUDED(*DataGuard());
   std::string DefaultValue() const override ABSL_LOCKS_EXCLUDED(*DataGuard());
@@ -492,9 +551,10 @@
 
   // Mutable flag's state (guarded by `data_guard_`).
 
-  // If def_kind_ == kDynamicValue, default_value_ holds a dynamically allocated
-  // value.
-  uint8_t def_kind_ : 1 ABSL_GUARDED_BY(*DataGuard());
+  // def_kind_ is not guard by DataGuard() since it is accessed in Init without
+  // locks. If necessary we can decrease number of bits used to 2 by folding
+  // one_word storage cases.
+  uint8_t def_kind_ : 3;
   // Has this flag's value been modified?
   bool modified_ : 1 ABSL_GUARDED_BY(*DataGuard());
   // Has this flag been specified on command line.
@@ -530,10 +590,10 @@
 template <typename T>
 class Flag {
  public:
-  constexpr Flag(const char* name, const char* filename, const FlagHelpArg help,
-                 const FlagDfltGenFunc default_value_gen)
+  constexpr Flag(const char* name, const char* filename, FlagHelpArg help,
+                 const FlagDefaultArg default_arg)
       : impl_(name, filename, &FlagOps<T>, help,
-              flags_internal::StorageKind<T>(), default_value_gen),
+              flags_internal::StorageKind<T>(), default_arg),
         value_() {}
 
   T Get() const {
@@ -560,9 +620,7 @@
   // CommandLineFlag interface
   absl::string_view Name() const { return impl_.Name(); }
   std::string Filename() const { return impl_.Filename(); }
-  absl::string_view Typename() const { return ""; }
   std::string Help() const { return impl_.Help(); }
-  bool IsModified() const { return impl_.IsModified(); }
   bool IsSpecifiedOnCommandLine() const {
     return impl_.IsSpecifiedOnCommandLine();
   }
@@ -662,20 +720,6 @@
   Flag<T>* flag_;  // Flag being registered (not owned).
 };
 
-// This struct and corresponding overload to MakeDefaultValue are used to
-// facilitate usage of {} as default value in ABSL_FLAG macro.
-struct EmptyBraces {};
-
-template <typename T>
-void MakeFromDefaultValue(void* dst, T t) {
-  new (dst) T(std::move(t));
-}
-
-template <typename T>
-void MakeFromDefaultValue(void* dst, EmptyBraces) {
-  new (dst) T{};
-}
-
 }  // namespace flags_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/flags/internal/private_handle_accessor.cc b/absl/flags/internal/private_handle_accessor.cc
new file mode 100644
index 0000000..ec5776b
--- /dev/null
+++ b/absl/flags/internal/private_handle_accessor.cc
@@ -0,0 +1,52 @@
+//
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/flags/internal/private_handle_accessor.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace flags_internal {
+
+FlagFastTypeId PrivateHandleAccessor::TypeId(const CommandLineFlag& flag) {
+  return flag.TypeId();
+}
+
+std::unique_ptr<FlagStateInterface> PrivateHandleAccessor::SaveState(
+    CommandLineFlag* flag) {
+  return flag->SaveState();
+}
+
+bool PrivateHandleAccessor::ValidateInputValue(const CommandLineFlag& flag,
+                                               absl::string_view value) {
+  return flag.ValidateInputValue(value);
+}
+
+void PrivateHandleAccessor::CheckDefaultValueParsingRoundtrip(
+    const CommandLineFlag& flag) {
+  flag.CheckDefaultValueParsingRoundtrip();
+}
+
+bool PrivateHandleAccessor::ParseFrom(CommandLineFlag* flag,
+                                      absl::string_view value,
+                                      flags_internal::FlagSettingMode set_mode,
+                                      flags_internal::ValueSource source,
+                                      std::string* error) {
+  return flag->ParseFrom(value, set_mode, source, error);
+}
+
+}  // namespace flags_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
diff --git a/absl/flags/internal/private_handle_accessor.h b/absl/flags/internal/private_handle_accessor.h
new file mode 100644
index 0000000..fbb4409
--- /dev/null
+++ b/absl/flags/internal/private_handle_accessor.h
@@ -0,0 +1,52 @@
+//
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_FLAGS_INTERNAL_PRIVATE_HANDLE_ACCESSOR_H_
+#define ABSL_FLAGS_INTERNAL_PRIVATE_HANDLE_ACCESSOR_H_
+
+#include "absl/flags/internal/commandlineflag.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace flags_internal {
+
+// This class serves as a trampoline to access private methods of
+// CommandLineFlag. This class is intended for use exclusively internally inside
+// of the Abseil Flags implementation.
+class PrivateHandleAccessor {
+ public:
+  // Access to CommandLineFlag::TypeId.
+  static FlagFastTypeId TypeId(const CommandLineFlag& flag);
+
+  // Access to CommandLineFlag::SaveState.
+  static std::unique_ptr<FlagStateInterface> SaveState(CommandLineFlag* flag);
+
+  // Access to CommandLineFlag::ValidateInputValue.
+  static bool ValidateInputValue(const CommandLineFlag& flag,
+                                 absl::string_view value);
+
+  // Access to CommandLineFlag::CheckDefaultValueParsingRoundtrip.
+  static void CheckDefaultValueParsingRoundtrip(const CommandLineFlag& flag);
+
+  static bool ParseFrom(CommandLineFlag* flag, absl::string_view value,
+                        flags_internal::FlagSettingMode set_mode,
+                        flags_internal::ValueSource source, std::string* error);
+};
+
+}  // namespace flags_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_FLAGS_INTERNAL_PRIVATE_HANDLE_ACCESSOR_H_
diff --git a/absl/flags/internal/registry.cc b/absl/flags/internal/registry.cc
index eb619c7..3b941f0 100644
--- a/absl/flags/internal/registry.cc
+++ b/absl/flags/internal/registry.cc
@@ -29,6 +29,7 @@
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/thread_annotations.h"
 #include "absl/flags/internal/commandlineflag.h"
+#include "absl/flags/internal/private_handle_accessor.h"
 #include "absl/flags/usage_config.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
@@ -127,14 +128,13 @@
               (flag->IsRetired() ? old_flag->Filename() : flag->Filename()),
               "'."),
           true);
-    } else if (flag->TypeId() != old_flag->TypeId()) {
+    } else if (flags_internal::PrivateHandleAccessor::TypeId(*flag) !=
+               flags_internal::PrivateHandleAccessor::TypeId(*old_flag)) {
       flags_internal::ReportUsageError(
           absl::StrCat("Flag '", flag->Name(),
                        "' was defined more than once but with "
                        "differing types. Defined in files '",
-                       old_flag->Filename(), "' and '", flag->Filename(),
-                       "' with types '", old_flag->Typename(), "' and '",
-                       flag->Typename(), "', respectively."),
+                       old_flag->Filename(), "' and '", flag->Filename(), "'."),
           true);
     } else if (old_flag->IsRetired()) {
       // Retired flag can just be deleted.
@@ -206,7 +206,8 @@
   void SaveFromRegistry() {
     assert(backup_registry_.empty());  // call only once!
     flags_internal::ForEachFlag([&](flags_internal::CommandLineFlag* flag) {
-      if (auto flag_state = flag->SaveState()) {
+      if (auto flag_state =
+              flags_internal::PrivateHandleAccessor::SaveState(flag)) {
         backup_registry_.emplace_back(std::move(flag_state));
       }
     });
@@ -290,11 +291,9 @@
  private:
   absl::string_view Name() const override { return name_; }
   std::string Filename() const override { return "RETIRED"; }
-  absl::string_view Typename() const override { return ""; }
   FlagFastTypeId TypeId() const override { return type_id_; }
   std::string Help() const override { return ""; }
   bool IsRetired() const override { return true; }
-  bool IsModified() const override { return false; }
   bool IsSpecifiedOnCommandLine() const override { return false; }
   std::string DefaultValue() const override { return ""; }
   std::string CurrentValue() const override { return ""; }
diff --git a/absl/flags/internal/type_erased.cc b/absl/flags/internal/type_erased.cc
index 75b4cdf..3cfc9b2 100644
--- a/absl/flags/internal/type_erased.cc
+++ b/absl/flags/internal/type_erased.cc
@@ -22,6 +22,7 @@
 #include "absl/base/config.h"
 #include "absl/base/internal/raw_logging.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/string_view.h"
@@ -56,7 +57,8 @@
   if (!flag || flag->IsRetired()) return false;
 
   std::string error;
-  if (!flag->ParseFrom(value, set_mode, kProgrammaticChange, &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);
@@ -72,7 +74,9 @@
   CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
 
   return flag != nullptr &&
-         (flag->IsRetired() || flag->ValidateInputValue(value));
+         (flag->IsRetired() ||
+          flags_internal::PrivateHandleAccessor::ValidateInputValue(*flag,
+                                                                    value));
 }
 
 // --------------------------------------------------------------------
diff --git a/absl/flags/internal/type_erased.h b/absl/flags/internal/type_erased.h
index 188429c..ffe319b 100644
--- a/absl/flags/internal/type_erased.h
+++ b/absl/flags/internal/type_erased.h
@@ -75,7 +75,7 @@
   CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
   if (!flag) return false;
 
-  if (auto val = flag->Get<T>()) {
+  if (auto val = flag->TryGet<T>()) {
     *dst = *val;
     return true;
   }
diff --git a/absl/flags/internal/usage.cc b/absl/flags/internal/usage.cc
index a9a5cba..10accc4 100644
--- a/absl/flags/internal/usage.cc
+++ b/absl/flags/internal/usage.cc
@@ -27,6 +27,7 @@
 #include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/flag.h"
 #include "absl/flags/internal/path_util.h"
+#include "absl/flags/internal/private_handle_accessor.h"
 #include "absl/flags/internal/program_name.h"
 #include "absl/flags/internal/registry.h"
 #include "absl/flags/usage_config.h"
@@ -54,27 +55,6 @@
 namespace flags_internal {
 namespace {
 
-absl::string_view TypenameForHelp(const flags_internal::CommandLineFlag& flag) {
-  // Only report names of v1 built-in types
-#define HANDLE_V1_BUILTIN_TYPE(t) \
-  if (flag.IsOfType<t>()) {       \
-    return #t;                    \
-  }
-
-  HANDLE_V1_BUILTIN_TYPE(bool);
-  HANDLE_V1_BUILTIN_TYPE(int32_t);
-  HANDLE_V1_BUILTIN_TYPE(int64_t);
-  HANDLE_V1_BUILTIN_TYPE(uint64_t);
-  HANDLE_V1_BUILTIN_TYPE(double);
-#undef HANDLE_V1_BUILTIN_TYPE
-
-  if (flag.IsOfType<std::string>()) {
-    return "string";
-  }
-
-  return "";
-}
-
 // This class is used to emit an XML element with `tag` and `text`.
 // It adds opening and closing tags and escapes special characters in the text.
 // For example:
@@ -212,23 +192,20 @@
   // Flag help.
   printer.Write(absl::StrCat("(", flag.Help(), ");"), /*wrap_line=*/true);
 
-  // Flag data type (for V1 flags only).
-  if (!flag.IsAbseilFlag() && !flag.IsRetired()) {
-    printer.Write(absl::StrCat("type: ", TypenameForHelp(flag), ";"));
-  }
-
   // The listed default value will be the actual default from the flag
   // definition in the originating source file, unless the value has
   // subsequently been modified using SetCommandLineOption() with mode
   // SET_FLAGS_DEFAULT.
   std::string dflt_val = flag.DefaultValue();
+  std::string curr_val = flag.CurrentValue();
+  bool is_modified = curr_val != dflt_val;
+
   if (flag.IsOfType<std::string>()) {
     dflt_val = absl::StrCat("\"", dflt_val, "\"");
   }
   printer.Write(absl::StrCat("default: ", dflt_val, ";"));
 
-  if (flag.IsModified()) {
-    std::string curr_val = flag.CurrentValue();
+  if (is_modified) {
     if (flag.IsOfType<std::string>()) {
       curr_val = absl::StrCat("\"", curr_val, "\"");
     }
diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc
index b60b36f..66a28a9 100644
--- a/absl/flags/parse.cc
+++ b/absl/flags/parse.cc
@@ -39,6 +39,7 @@
 #include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/flag.h"
 #include "absl/flags/internal/parse.h"
+#include "absl/flags/internal/private_handle_accessor.h"
 #include "absl/flags/internal/program_name.h"
 #include "absl/flags/internal/registry.h"
 #include "absl/flags/internal/usage.h"
@@ -298,7 +299,8 @@
     ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(IGNORE_TYPE)
 #undef IGNORE_TYPE
 
-    flag->CheckDefaultValueParsingRoundtrip();
+    flags_internal::PrivateHandleAccessor::CheckDefaultValueParsingRoundtrip(
+        *flag);
   });
 #endif
 }
@@ -696,7 +698,8 @@
     if (flag->IsRetired()) continue;
 
     std::string error;
-    if (!flag->ParseFrom(value, SET_FLAGS_VALUE, kCommandLine, &error)) {
+    if (!flags_internal::PrivateHandleAccessor::ParseFrom(
+            flag, value, SET_FLAGS_VALUE, kCommandLine, &error)) {
       flags_internal::ReportUsageError(error, true);
       success = false;
     }
diff --git a/absl/hash/hash.h b/absl/hash/hash.h
index 3dbeab6..d7386f6 100644
--- a/absl/hash/hash.h
+++ b/absl/hash/hash.h
@@ -37,8 +37,11 @@
 // types. Hashing of that combined state is separately done by `absl::Hash`.
 //
 // One should assume that a hash algorithm is chosen randomly at the start of
-// each process.  E.g., absl::Hash<int>()(9) in one process and
-// absl::Hash<int>()(9) in another process are likely to differ.
+// each process.  E.g., `absl::Hash<int>{}(9)` in one process and
+// `absl::Hash<int>{}(9)` in another process are likely to differ.
+//
+// `absl::Hash` is intended to strongly mix input bits with a target of passing
+// an [Avalanche Test](https://en.wikipedia.org/wiki/Avalanche_effect).
 //
 // Example:
 //
diff --git a/absl/random/gaussian_distribution_test.cc b/absl/random/gaussian_distribution_test.cc
index 49c0751..398f013 100644
--- a/absl/random/gaussian_distribution_test.cc
+++ b/absl/random/gaussian_distribution_test.cc
@@ -130,12 +130,15 @@
         ss >> after;
 
 #if defined(__powerpc64__) || defined(__PPC64__) || defined(__powerpc__) || \
-    defined(__ppc__) || defined(__PPC__)
+    defined(__ppc__) || defined(__PPC__) || defined(__EMSCRIPTEN__)
         if (std::is_same<TypeParam, long double>::value) {
           // Roundtripping floating point values requires sufficient precision
           // to reconstruct the exact value.  It turns out that long double
           // has some errors doing this on ppc, particularly for values
           // near {1.0 +/- epsilon}.
+          //
+          // Emscripten is even worse, implementing long double as a 128-bit
+          // type, but shipping with a strtold() that doesn't support that.
           if (mean <= std::numeric_limits<double>::max() &&
               mean >= std::numeric_limits<double>::lowest()) {
             EXPECT_EQ(static_cast<double>(before.mean()),
diff --git a/absl/random/internal/wide_multiply_test.cc b/absl/random/internal/wide_multiply_test.cc
index 922603f..ca8ce92 100644
--- a/absl/random/internal/wide_multiply_test.cc
+++ b/absl/random/internal/wide_multiply_test.cc
@@ -28,7 +28,7 @@
 
   EXPECT_EQ(absl::uint128(0), MultiplyU64ToU128(0, 0));
 
-  // Max uint64
+  // Max uint64_t
   EXPECT_EQ(MultiplyU64ToU128(kMax, kMax),
             absl::MakeUint128(0xfffffffffffffffe, 0x0000000000000001));
   EXPECT_EQ(absl::MakeUint128(0, kMax), MultiplyU64ToU128(kMax, 1));
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
index 8aecbe5..8220896 100644
--- a/absl/strings/BUILD.bazel
+++ b/absl/strings/BUILD.bazel
@@ -638,10 +638,13 @@
     visibility = ["//visibility:private"],
     deps = [
         ":strings",
+        "//absl/base:bits",
         "//absl/base:config",
         "//absl/base:core_headers",
+        "//absl/functional:function_ref",
         "//absl/meta:type_traits",
         "//absl/numeric:int128",
+        "//absl/types:optional",
         "//absl/types:span",
     ],
 )
@@ -718,7 +721,7 @@
     deps = [
         ":str_format_internal",
         "//absl/base:raw_logging_internal",
-        "//absl/numeric:int128",
+        "//absl/types:optional",
         "@com_google_googletest//:gtest_main",
     ],
 )
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt
index 003794f..c0ea0c8 100644
--- a/absl/strings/CMakeLists.txt
+++ b/absl/strings/CMakeLists.txt
@@ -392,6 +392,7 @@
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
+    absl::bits
     absl::strings
     absl::config
     absl::core_headers
diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc
index fa490c1..0403cc6 100644
--- a/absl/strings/cord.cc
+++ b/absl/strings/cord.cc
@@ -15,6 +15,7 @@
 #include "absl/strings/cord.h"
 
 #include <algorithm>
+#include <atomic>
 #include <cstddef>
 #include <cstdio>
 #include <cstdlib>
diff --git a/absl/strings/cord.h b/absl/strings/cord.h
index ae3d2e7..86ae76f 100644
--- a/absl/strings/cord.h
+++ b/absl/strings/cord.h
@@ -162,7 +162,7 @@
     if (contents_.is_tree()) DestroyCordSlow();
   }
 
-  // Cord::MakeCordFromExternal(data, callable)
+  // MakeCordFromExternal()
   //
   // Creates a Cord that takes ownership of external string memory. The
   // contents of `data` are not copied to the Cord; instead, the external
@@ -246,10 +246,17 @@
   // (pos + new_size) >= size(), the result is the subrange [pos, size()).
   Cord Subcord(size_t pos, size_t new_size) const;
 
+  // Cord::swap()
+  //
+  // Swaps the contents of the Cord with `other`.
+  void swap(Cord& other) noexcept;
+
   // swap()
   //
-  // Swaps the data of Cord `x` with Cord `y`.
-  friend void swap(Cord& x, Cord& y) noexcept;
+  // Swaps the contents of two Cords.
+  friend void swap(Cord& x, Cord& y) noexcept {
+    x.swap(y);
+  }
 
   // Cord::size()
   //
@@ -1032,6 +1039,10 @@
 
 inline Cord::Cord(Cord&& src) noexcept : contents_(std::move(src.contents_)) {}
 
+inline void Cord::swap(Cord& other) noexcept {
+  contents_.Swap(&other.contents_);
+}
+
 inline Cord& Cord::operator=(Cord&& x) noexcept {
   contents_ = std::move(x.contents_);
   return *this;
@@ -1308,10 +1319,6 @@
 inline bool operator>=(const Cord& x, absl::string_view y) { return !(x < y); }
 inline bool operator>=(absl::string_view x, const Cord& y) { return !(x < y); }
 
-// Overload of swap for Cord. The use of non-const references is
-// required. :(
-inline void swap(Cord& x, Cord& y) noexcept { y.contents_.Swap(&x.contents_); }
-
 // Some internals exposed to test code.
 namespace strings_internal {
 class CordTestAccess {
diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc
index 336cedd..4443c82 100644
--- a/absl/strings/cord_test.cc
+++ b/absl/strings/cord_test.cc
@@ -396,6 +396,9 @@
   swap(x, y);
   ASSERT_EQ(x, absl::Cord(b));
   ASSERT_EQ(y, absl::Cord(a));
+  x.swap(y);
+  ASSERT_EQ(x, absl::Cord(a));
+  ASSERT_EQ(y, absl::Cord(b));
 }
 
 static void VerifyCopyToString(const absl::Cord& cord) {
diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc
index 1284227..964f25f 100644
--- a/absl/strings/internal/str_format/arg.cc
+++ b/absl/strings/internal/str_format/arg.cc
@@ -167,24 +167,26 @@
 // Note: 'o' conversions do not have a base indicator, it's just that
 // the '#' flag is specified to modify the precision for 'o' conversions.
 string_view BaseIndicator(const IntDigits &as_digits,
-                          const ConversionSpec conv) {
+                          const FormatConversionSpecImpl conv) {
   // always show 0x for %p.
-  bool alt = conv.has_alt_flag() || conv.conversion_char() == ConversionChar::p;
-  bool hex = (conv.conversion_char() == FormatConversionChar::x ||
-              conv.conversion_char() == FormatConversionChar::X ||
-              conv.conversion_char() == FormatConversionChar::p);
+  bool alt = conv.has_alt_flag() ||
+             conv.conversion_char() == FormatConversionCharInternal::p;
+  bool hex = (conv.conversion_char() == FormatConversionCharInternal::x ||
+              conv.conversion_char() == FormatConversionCharInternal::X ||
+              conv.conversion_char() == FormatConversionCharInternal::p);
   // From the POSIX description of '#' flag:
   //   "For x or X conversion specifiers, a non-zero result shall have
   //   0x (or 0X) prefixed to it."
   if (alt && hex && !as_digits.without_neg_or_zero().empty()) {
-    return conv.conversion_char() == FormatConversionChar::X ? "0X" : "0x";
+    return conv.conversion_char() == FormatConversionCharInternal::X ? "0X"
+                                                                     : "0x";
   }
   return {};
 }
 
-string_view SignColumn(bool neg, const ConversionSpec conv) {
-  if (conv.conversion_char() == FormatConversionChar::d ||
-      conv.conversion_char() == FormatConversionChar::i) {
+string_view SignColumn(bool neg, const FormatConversionSpecImpl conv) {
+  if (conv.conversion_char() == FormatConversionCharInternal::d ||
+      conv.conversion_char() == FormatConversionCharInternal::i) {
     if (neg) return "-";
     if (conv.has_show_pos_flag()) return "+";
     if (conv.has_sign_col_flag()) return " ";
@@ -192,7 +194,7 @@
   return {};
 }
 
-bool ConvertCharImpl(unsigned char v, const ConversionSpec conv,
+bool ConvertCharImpl(unsigned char v, const FormatConversionSpecImpl conv,
                      FormatSinkImpl *sink) {
   size_t fill = 0;
   if (conv.width() >= 0) fill = conv.width();
@@ -204,7 +206,8 @@
 }
 
 bool ConvertIntImplInnerSlow(const IntDigits &as_digits,
-                             const ConversionSpec conv, FormatSinkImpl *sink) {
+                             const FormatConversionSpecImpl conv,
+                             FormatSinkImpl *sink) {
   // Print as a sequence of Substrings:
   //   [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces]
   size_t fill = 0;
@@ -224,7 +227,8 @@
   if (!precision_specified)
     precision = 1;
 
-  if (conv.has_alt_flag() && conv.conversion_char() == ConversionChar::o) {
+  if (conv.has_alt_flag() &&
+      conv.conversion_char() == FormatConversionCharInternal::o) {
     // From POSIX description of the '#' (alt) flag:
     //   "For o conversion, it increases the precision (if necessary) to
     //   force the first digit of the result to be zero."
@@ -258,42 +262,43 @@
 }
 
 template <typename T>
-bool ConvertIntArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
+bool ConvertIntArg(T v, const FormatConversionSpecImpl conv,
+                   FormatSinkImpl *sink) {
   using U = typename MakeUnsigned<T>::type;
   IntDigits as_digits;
 
   switch (conv.conversion_char()) {
-    case FormatConversionChar::c:
+    case FormatConversionCharInternal::c:
       return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);
 
-    case FormatConversionChar::o:
+    case FormatConversionCharInternal::o:
       as_digits.PrintAsOct(static_cast<U>(v));
       break;
 
-    case FormatConversionChar::x:
+    case FormatConversionCharInternal::x:
       as_digits.PrintAsHexLower(static_cast<U>(v));
       break;
-    case FormatConversionChar::X:
+    case FormatConversionCharInternal::X:
       as_digits.PrintAsHexUpper(static_cast<U>(v));
       break;
 
-    case FormatConversionChar::u:
+    case FormatConversionCharInternal::u:
       as_digits.PrintAsDec(static_cast<U>(v));
       break;
 
-    case FormatConversionChar::d:
-    case FormatConversionChar::i:
+    case FormatConversionCharInternal::d:
+    case FormatConversionCharInternal::i:
       as_digits.PrintAsDec(v);
       break;
 
-    case FormatConversionChar::a:
-    case FormatConversionChar::e:
-    case FormatConversionChar::f:
-    case FormatConversionChar::g:
-    case FormatConversionChar::A:
-    case FormatConversionChar::E:
-    case FormatConversionChar::F:
-    case FormatConversionChar::G:
+    case FormatConversionCharInternal::a:
+    case FormatConversionCharInternal::e:
+    case FormatConversionCharInternal::f:
+    case FormatConversionCharInternal::g:
+    case FormatConversionCharInternal::A:
+    case FormatConversionCharInternal::E:
+    case FormatConversionCharInternal::F:
+    case FormatConversionCharInternal::G:
       return ConvertFloatImpl(static_cast<double>(v), conv, sink);
 
     default:
@@ -308,14 +313,15 @@
 }
 
 template <typename T>
-bool ConvertFloatArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
+bool ConvertFloatArg(T v, const FormatConversionSpecImpl conv,
+                     FormatSinkImpl *sink) {
   return FormatConversionCharIsFloat(conv.conversion_char()) &&
          ConvertFloatImpl(v, conv, sink);
 }
 
-inline bool ConvertStringArg(string_view v, const ConversionSpec conv,
+inline bool ConvertStringArg(string_view v, const FormatConversionSpecImpl conv,
                              FormatSinkImpl *sink) {
-  if (conv.conversion_char() != ConversionChar::s) return false;
+  if (conv.conversion_char() != FormatConversionCharInternal::s) return false;
   if (conv.is_basic()) {
     sink->Append(v);
     return true;
@@ -327,22 +333,23 @@
 }  // namespace
 
 // ==================== Strings ====================
-ConvertResult<Conv::s> FormatConvertImpl(const std::string &v,
-                                         const ConversionSpec conv,
-                                         FormatSinkImpl *sink) {
+StringConvertResult FormatConvertImpl(const std::string &v,
+                                      const FormatConversionSpecImpl conv,
+                                      FormatSinkImpl *sink) {
   return {ConvertStringArg(v, conv, sink)};
 }
 
-ConvertResult<Conv::s> FormatConvertImpl(string_view v,
-                                         const ConversionSpec conv,
-                                         FormatSinkImpl *sink) {
+StringConvertResult FormatConvertImpl(string_view v,
+                                      const FormatConversionSpecImpl conv,
+                                      FormatSinkImpl *sink) {
   return {ConvertStringArg(v, conv, sink)};
 }
 
-ConvertResult<Conv::s | Conv::p> FormatConvertImpl(const char *v,
-                                                   const ConversionSpec conv,
-                                                   FormatSinkImpl *sink) {
-  if (conv.conversion_char() == ConversionChar::p)
+ArgConvertResult<FormatConversionCharSetUnion(
+    FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
+FormatConvertImpl(const char *v, const FormatConversionSpecImpl conv,
+                  FormatSinkImpl *sink) {
+  if (conv.conversion_char() == FormatConversionCharInternal::p)
     return {FormatConvertImpl(VoidPtr(v), conv, sink).value};
   size_t len;
   if (v == nullptr) {
@@ -357,9 +364,9 @@
 }
 
 // ==================== Raw pointers ====================
-ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, const ConversionSpec conv,
-                                         FormatSinkImpl *sink) {
-  if (conv.conversion_char() != ConversionChar::p) return {false};
+ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
+    VoidPtr v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
+  if (conv.conversion_char() != FormatConversionCharInternal::p) return {false};
   if (!v.value) {
     sink->Append("(nil)");
     return {true};
@@ -370,82 +377,87 @@
 }
 
 // ==================== Floats ====================
-FloatingConvertResult FormatConvertImpl(float v, const ConversionSpec conv,
+FloatingConvertResult FormatConvertImpl(float v,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertFloatArg(v, conv, sink)};
 }
-FloatingConvertResult FormatConvertImpl(double v, const ConversionSpec conv,
+FloatingConvertResult FormatConvertImpl(double v,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertFloatArg(v, conv, sink)};
 }
 FloatingConvertResult FormatConvertImpl(long double v,
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertFloatArg(v, conv, sink)};
 }
 
 // ==================== Chars ====================
-IntegralConvertResult FormatConvertImpl(char v, const ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(char v,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 IntegralConvertResult FormatConvertImpl(signed char v,
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 IntegralConvertResult FormatConvertImpl(unsigned char v,
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 
 // ==================== Ints ====================
 IntegralConvertResult FormatConvertImpl(short v,  // NOLINT
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 IntegralConvertResult FormatConvertImpl(unsigned short v,  // NOLINT
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
-IntegralConvertResult FormatConvertImpl(int v, const ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(int v,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
-IntegralConvertResult FormatConvertImpl(unsigned v, const ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(unsigned v,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 IntegralConvertResult FormatConvertImpl(long v,  // NOLINT
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 IntegralConvertResult FormatConvertImpl(unsigned long v,  // NOLINT
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 IntegralConvertResult FormatConvertImpl(long long v,  // NOLINT
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 IntegralConvertResult FormatConvertImpl(unsigned long long v,  // NOLINT
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 IntegralConvertResult FormatConvertImpl(absl::int128 v,
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
 IntegralConvertResult FormatConvertImpl(absl::uint128 v,
-                                        const ConversionSpec conv,
+                                        const FormatConversionSpecImpl conv,
                                         FormatSinkImpl *sink) {
   return {ConvertIntArg(v, conv, sink)};
 }
diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h
index 1c36e30..9a1e5ef 100644
--- a/absl/strings/internal/str_format/arg.h
+++ b/absl/strings/internal/str_format/arg.h
@@ -31,10 +31,11 @@
 struct HasUserDefinedConvert : std::false_type {};
 
 template <typename T>
-struct HasUserDefinedConvert<
-    T, void_t<decltype(AbslFormatConvert(
-           std::declval<const T&>(), std::declval<ConversionSpec>(),
-           std::declval<FormatSink*>()))>> : std::true_type {};
+struct HasUserDefinedConvert<T, void_t<decltype(AbslFormatConvert(
+                                    std::declval<const T&>(),
+                                    std::declval<const FormatConversionSpec&>(),
+                                    std::declval<FormatSink*>()))>>
+    : std::true_type {};
 
 template <typename T>
 class StreamedWrapper;
@@ -52,25 +53,40 @@
       : value(ptr ? reinterpret_cast<uintptr_t>(ptr) : 0) {}
   uintptr_t value;
 };
-ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, ConversionSpec conv,
-                                         FormatSinkImpl* sink);
+
+template <FormatConversionCharSet C>
+struct ArgConvertResult {
+  bool value;
+};
+
+template <FormatConversionCharSet C>
+constexpr FormatConversionCharSet ExtractCharSet(ArgConvertResult<C>) {
+  return C;
+}
+
+using StringConvertResult =
+    ArgConvertResult<FormatConversionCharSetInternal::s>;
+ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
+    VoidPtr v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
 
 // Strings.
-ConvertResult<Conv::s> FormatConvertImpl(const std::string& v,
-                                         ConversionSpec conv,
-                                         FormatSinkImpl* sink);
-ConvertResult<Conv::s> FormatConvertImpl(string_view v, ConversionSpec conv,
-                                         FormatSinkImpl* sink);
-ConvertResult<Conv::s | Conv::p> FormatConvertImpl(const char* v,
-                                                   ConversionSpec conv,
-                                                   FormatSinkImpl* sink);
-template <class AbslCord,
-          typename std::enable_if<
-              std::is_same<AbslCord, absl::Cord>::value>::type* = nullptr>
-ConvertResult<Conv::s> FormatConvertImpl(const AbslCord& value,
-                                         ConversionSpec conv,
-                                         FormatSinkImpl* sink) {
-  if (conv.conversion_char() != ConversionChar::s) {
+StringConvertResult FormatConvertImpl(const std::string& v,
+                                      FormatConversionSpecImpl conv,
+                                      FormatSinkImpl* sink);
+StringConvertResult FormatConvertImpl(string_view v,
+                                      FormatConversionSpecImpl conv,
+                                      FormatSinkImpl* sink);
+ArgConvertResult<FormatConversionCharSetUnion(
+    FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
+FormatConvertImpl(const char* v, const FormatConversionSpecImpl conv,
+                  FormatSinkImpl* sink);
+
+template <class AbslCord, typename std::enable_if<std::is_same<
+                              AbslCord, absl::Cord>::value>::type* = nullptr>
+StringConvertResult FormatConvertImpl(const AbslCord& value,
+                                      FormatConversionSpecImpl conv,
+                                      FormatSinkImpl* sink) {
+  if (conv.conversion_char() != FormatConversionCharInternal::s) {
     return {false};
   }
 
@@ -107,55 +123,63 @@
   return {true};
 }
 
-using IntegralConvertResult =
-    ConvertResult<Conv::c | Conv::kNumeric | Conv::kStar>;
-using FloatingConvertResult = ConvertResult<Conv::kFloating>;
+using IntegralConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
+    FormatConversionCharSetInternal::c,
+    FormatConversionCharSetInternal::kNumeric,
+    FormatConversionCharSetInternal::kStar)>;
+using FloatingConvertResult =
+    ArgConvertResult<FormatConversionCharSetInternal::kFloating>;
 
 // Floats.
-FloatingConvertResult FormatConvertImpl(float v, ConversionSpec conv,
+FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
-FloatingConvertResult FormatConvertImpl(double v, ConversionSpec conv,
+FloatingConvertResult FormatConvertImpl(double v, FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
-FloatingConvertResult FormatConvertImpl(long double v, ConversionSpec conv,
+FloatingConvertResult FormatConvertImpl(long double v,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
 
 // Chars.
-IntegralConvertResult FormatConvertImpl(char v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(signed char v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(signed char v,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(unsigned char v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(unsigned char v,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
 
 // Ints.
 IntegralConvertResult FormatConvertImpl(short v,  // NOLINT
-                                        ConversionSpec conv,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
 IntegralConvertResult FormatConvertImpl(unsigned short v,  // NOLINT
-                                        ConversionSpec conv,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(int v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(int v, FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(unsigned v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(unsigned v,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
 IntegralConvertResult FormatConvertImpl(long v,  // NOLINT
-                                        ConversionSpec conv,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
 IntegralConvertResult FormatConvertImpl(unsigned long v,  // NOLINT
-                                        ConversionSpec conv,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
 IntegralConvertResult FormatConvertImpl(long long v,  // NOLINT
-                                        ConversionSpec conv,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
 IntegralConvertResult FormatConvertImpl(unsigned long long v,  // NOLINT
-                                        ConversionSpec conv,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(int128 v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(int128 v, FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(uint128 v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(uint128 v,
+                                        FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
 template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0>
-IntegralConvertResult FormatConvertImpl(T v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink) {
   return FormatConvertImpl(static_cast<int>(v), conv, sink);
 }
@@ -166,12 +190,12 @@
 typename std::enable_if<std::is_enum<T>::value &&
                             !HasUserDefinedConvert<T>::value,
                         IntegralConvertResult>::type
-FormatConvertImpl(T v, ConversionSpec conv, FormatSinkImpl* sink);
+FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
 
 template <typename T>
-ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<T>& v,
-                                         ConversionSpec conv,
-                                         FormatSinkImpl* out) {
+StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v,
+                                      FormatConversionSpecImpl conv,
+                                      FormatSinkImpl* out) {
   std::ostringstream oss;
   oss << v.v_;
   if (!oss) return {false};
@@ -182,12 +206,13 @@
 // until after FormatCountCapture is fully defined.
 struct FormatCountCaptureHelper {
   template <class T = int>
-  static ConvertResult<Conv::n> ConvertHelper(const FormatCountCapture& v,
-                                              ConversionSpec conv,
-                                              FormatSinkImpl* sink) {
+  static ArgConvertResult<FormatConversionCharSetInternal::n> ConvertHelper(
+      const FormatCountCapture& v, FormatConversionSpecImpl conv,
+      FormatSinkImpl* sink) {
     const absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v;
 
-    if (conv.conversion_char() != str_format_internal::ConversionChar::n) {
+    if (conv.conversion_char() !=
+        str_format_internal::FormatConversionCharInternal::n) {
       return {false};
     }
     *v2.p_ = static_cast<int>(sink->size());
@@ -196,9 +221,9 @@
 };
 
 template <class T = int>
-ConvertResult<Conv::n> FormatConvertImpl(const FormatCountCapture& v,
-                                         ConversionSpec conv,
-                                         FormatSinkImpl* sink) {
+ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl(
+    const FormatCountCapture& v, FormatConversionSpecImpl conv,
+    FormatSinkImpl* sink) {
   return FormatCountCaptureHelper::ConvertHelper(v, conv, sink);
 }
 
@@ -207,13 +232,13 @@
 struct FormatArgImplFriend {
   template <typename Arg>
   static bool ToInt(Arg arg, int* out) {
-    // A value initialized ConversionSpec has a `none` conv, which tells the
-    // dispatcher to run the `int` conversion.
+    // A value initialized FormatConversionSpecImpl has a `none` conv, which
+    // tells the dispatcher to run the `int` conversion.
     return arg.dispatcher_(arg.data_, {}, out);
   }
 
   template <typename Arg>
-  static bool Convert(Arg arg, str_format_internal::ConversionSpec conv,
+  static bool Convert(Arg arg, FormatConversionSpecImpl conv,
                       FormatSinkImpl* out) {
     return arg.dispatcher_(arg.data_, conv, out);
   }
@@ -237,7 +262,7 @@
     char buf[kInlinedSpace];
   };
 
-  using Dispatcher = bool (*)(Data, ConversionSpec, void* out);
+  using Dispatcher = bool (*)(Data, FormatConversionSpecImpl, void* out);
 
   template <typename T>
   struct store_by_value
@@ -379,9 +404,10 @@
   }
 
   template <typename T>
-  static bool Dispatch(Data arg, ConversionSpec spec, void* out) {
+  static bool Dispatch(Data arg, FormatConversionSpecImpl spec, void* out) {
     // A `none` conv indicates that we want the `int` conversion.
-    if (ABSL_PREDICT_FALSE(spec.conversion_char() == ConversionChar::kNone)) {
+    if (ABSL_PREDICT_FALSE(spec.conversion_char() ==
+                           FormatConversionCharInternal::kNone)) {
       return ToInt<T>(arg, static_cast<int*>(out), std::is_integral<T>(),
                       std::is_enum<T>());
     }
@@ -395,8 +421,9 @@
   Dispatcher dispatcher_;
 };
 
-#define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \
-  E template bool FormatArgImpl::Dispatch<T>(Data, ConversionSpec, void*)
+#define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E)                     \
+  E template bool FormatArgImpl::Dispatch<T>(Data, FormatConversionSpecImpl, \
+                                             void*)
 
 #define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...)                   \
   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr,     \
diff --git a/absl/strings/internal/str_format/arg_test.cc b/absl/strings/internal/str_format/arg_test.cc
index 8d30d8b..37e5b75 100644
--- a/absl/strings/internal/str_format/arg_test.cc
+++ b/absl/strings/internal/str_format/arg_test.cc
@@ -95,8 +95,9 @@
 TEST_F(FormatArgImplTest, WorksWithCharArraysOfUnknownSize) {
   std::string s;
   FormatSinkImpl sink(&s);
-  ConversionSpec conv;
-  FormatConversionSpecImplFriend::SetConversionChar(ConversionChar::s, &conv);
+  FormatConversionSpecImpl conv;
+  FormatConversionSpecImplFriend::SetConversionChar(FormatConversionChar::s,
+                                                    &conv);
   FormatConversionSpecImplFriend::SetFlags(Flags(), &conv);
   FormatConversionSpecImplFriend::SetWidth(-1, &conv);
   FormatConversionSpecImplFriend::SetPrecision(-1, &conv);
diff --git a/absl/strings/internal/str_format/bind.h b/absl/strings/internal/str_format/bind.h
index d30fdf5..585246e 100644
--- a/absl/strings/internal/str_format/bind.h
+++ b/absl/strings/internal/str_format/bind.h
@@ -19,7 +19,7 @@
 
 namespace str_format_internal {
 
-class BoundConversion : public ConversionSpec {
+class BoundConversion : public FormatConversionSpecImpl {
  public:
   const FormatArgImpl* arg() const { return arg_; }
   void set_arg(const FormatArgImpl* a) { arg_ = a; }
@@ -119,7 +119,7 @@
 
 #endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
 
-  template <Conv... C,
+  template <FormatConversionCharSet... C,
             typename = typename std::enable_if<
                 AllOf(sizeof...(C) == sizeof...(Args), Contains(Args,
                                                                 C)...)>::type>
@@ -189,9 +189,9 @@
 
  private:
   template <typename S>
-  friend ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<S>& v,
-                                                  ConversionSpec conv,
-                                                  FormatSinkImpl* out);
+  friend ArgConvertResult<FormatConversionCharSetInternal::s> FormatConvertImpl(
+      const StreamedWrapper<S>& v, FormatConversionSpecImpl conv,
+      FormatSinkImpl* out);
   const T& v_;
 };
 
diff --git a/absl/strings/internal/str_format/checker.h b/absl/strings/internal/str_format/checker.h
index 8993a79..73ef05f 100644
--- a/absl/strings/internal/str_format/checker.h
+++ b/absl/strings/internal/str_format/checker.h
@@ -25,10 +25,12 @@
 }
 
 template <typename Arg>
-constexpr Conv ArgumentToConv() {
-  return decltype(str_format_internal::FormatConvertImpl(
-      std::declval<const Arg&>(), std::declval<const ConversionSpec&>(),
-      std::declval<FormatSinkImpl*>()))::kConv;
+constexpr FormatConversionCharSet ArgumentToConv() {
+  return absl::str_format_internal::ExtractCharSet(
+      decltype(str_format_internal::FormatConvertImpl(
+          std::declval<const Arg&>(),
+          std::declval<const FormatConversionSpecImpl&>(),
+          std::declval<FormatSinkImpl*>())){});
 }
 
 #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
@@ -39,14 +41,14 @@
 
 // A constexpr compatible list of Convs.
 struct ConvList {
-  const Conv* array;
+  const FormatConversionCharSet* array;
   int count;
 
   // We do the bound check here to avoid having to do it on the callers.
-  // Returning an empty Conv has the same effect as short circuiting because it
-  // will never match any conversion.
-  constexpr Conv operator[](int i) const {
-    return i < count ? array[i] : Conv{};
+  // Returning an empty FormatConversionCharSet has the same effect as
+  // short circuiting because it will never match any conversion.
+  constexpr FormatConversionCharSet operator[](int i) const {
+    return i < count ? array[i] : FormatConversionCharSet{};
   }
 
   constexpr ConvList without_front() const {
@@ -57,7 +59,7 @@
 template <size_t count>
 struct ConvListT {
   // Make sure the array has size > 0.
-  Conv list[count ? count : 1];
+  FormatConversionCharSet list[count ? count : 1];
 };
 
 constexpr char GetChar(string_view str, size_t index) {
@@ -310,7 +312,7 @@
   ConvList args_;
 };
 
-template <Conv... C>
+template <FormatConversionCharSet... C>
 constexpr bool ValidFormatImpl(string_view format) {
   return FormatParser(format,
                       {ConvListT<sizeof...(C)>{{C...}}.list, sizeof...(C)})
diff --git a/absl/strings/internal/str_format/checker_test.cc b/absl/strings/internal/str_format/checker_test.cc
index 49a24b4..2334817 100644
--- a/absl/strings/internal/str_format/checker_test.cc
+++ b/absl/strings/internal/str_format/checker_test.cc
@@ -24,7 +24,7 @@
 }
 
 TEST(StrFormatChecker, ArgumentToConv) {
-  Conv conv = ArgumentToConv<std::string>();
+  FormatConversionCharSet conv = ArgumentToConv<std::string>();
   EXPECT_EQ(ConvToString(conv), "s");
 
   conv = ArgumentToConv<const char*>();
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc
index cbcd7ca..20c6229 100644
--- a/absl/strings/internal/str_format/convert_test.cc
+++ b/absl/strings/internal/str_format/convert_test.cc
@@ -1,14 +1,18 @@
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
+
 #include <cctype>
 #include <cmath>
+#include <limits>
 #include <string>
+#include <thread>  // NOLINT
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/strings/internal/str_format/bind.h"
+#include "absl/types/optional.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -57,7 +61,7 @@
   return oss.str();
 }
 
-void StrAppend(std::string *dst, const char *format, va_list ap) {
+void StrAppendV(std::string *dst, const char *format, va_list ap) {
   // First try with a small fixed size buffer
   static const int kSpaceLength = 1024;
   char space[kSpaceLength];
@@ -98,11 +102,18 @@
   delete[] buf;
 }
 
+void StrAppend(std::string *out, const char *format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  StrAppendV(out, format, ap);
+  va_end(ap);
+}
+
 std::string StrPrint(const char *format, ...) {
   va_list ap;
   va_start(ap, format);
   std::string result;
-  StrAppend(&result, format, ap);
+  StrAppendV(&result, format, ap);
   va_end(ap);
   return result;
 }
@@ -471,8 +482,8 @@
 #endif  // _MSC_VER
 
   const char *const kFormats[] = {
-      "%",  "%.3",  "%8.5",   "%9",   "%.60", "%.30",   "%03",    "%+",
-      "% ", "%-10", "%#15.3", "%#.0", "%.0",  "%1$*2$", "%1$.*2$"};
+      "%",  "%.3", "%8.5", "%500",   "%.5000", "%.60", "%.30",   "%03",
+      "%+", "% ",  "%-10", "%#15.3", "%#.0",   "%.0",  "%1$*2$", "%1$.*2$"};
 
   std::vector<double> doubles = {0.0,
                                  -0.0,
@@ -489,11 +500,6 @@
                                  std::numeric_limits<double>::infinity(),
                                  -std::numeric_limits<double>::infinity()};
 
-#ifndef __APPLE__
-  // Apple formats NaN differently (+nan) vs. (nan)
-  doubles.push_back(std::nan(""));
-#endif
-
   // Some regression tests.
   doubles.push_back(0.99999999999999989);
 
@@ -512,43 +518,229 @@
     }
   }
 
+  // Workaround libc bug.
+  // https://sourceware.org/bugzilla/show_bug.cgi?id=22142
+  const bool gcc_bug_22142 =
+      StrPrint("%f", std::numeric_limits<double>::max()) !=
+      "1797693134862315708145274237317043567980705675258449965989174768031"
+      "5726078002853876058955863276687817154045895351438246423432132688946"
+      "4182768467546703537516986049910576551282076245490090389328944075868"
+      "5084551339423045832369032229481658085593321233482747978262041447231"
+      "68738177180919299881250404026184124858368.000000";
+
+  if (!gcc_bug_22142) {
+    for (int exp = -300; exp <= 300; ++exp) {
+      const double all_ones_mantissa = 0x1fffffffffffff;
+      doubles.push_back(std::ldexp(all_ones_mantissa, exp));
+    }
+  }
+
+  if (gcc_bug_22142) {
+    for (auto &d : doubles) {
+      using L = std::numeric_limits<double>;
+      double d2 = std::abs(d);
+      if (d2 == L::max() || d2 == L::min() || d2 == L::denorm_min()) {
+        d = 0;
+      }
+    }
+  }
+
+  // Remove duplicates to speed up the logic below.
+  std::sort(doubles.begin(), doubles.end());
+  doubles.erase(std::unique(doubles.begin(), doubles.end()), doubles.end());
+
+#ifndef __APPLE__
+  // Apple formats NaN differently (+nan) vs. (nan)
+  doubles.push_back(std::nan(""));
+#endif
+
+  // Reserve the space to ensure we don't allocate memory in the output itself.
+  std::string str_format_result;
+  str_format_result.reserve(1 << 20);
+  std::string string_printf_result;
+  string_printf_result.reserve(1 << 20);
+
   for (const char *fmt : kFormats) {
     for (char f : {'f', 'F',  //
                    'g', 'G',  //
                    'a', 'A',  //
                    'e', 'E'}) {
       std::string fmt_str = std::string(fmt) + f;
+
+      if (fmt == absl::string_view("%.5000") && f != 'f' && f != 'F') {
+        // This particular test takes way too long with snprintf.
+        // Disable for the case we are not implementing natively.
+        continue;
+      }
+
       for (double d : doubles) {
         int i = -10;
         FormatArgImpl args[2] = {FormatArgImpl(d), FormatArgImpl(i)};
         UntypedFormatSpecImpl format(fmt_str);
-        // We use ASSERT_EQ here because failures are usually correlated and a
-        // bug would print way too many failed expectations causing the test to
-        // time out.
-        ASSERT_EQ(StrPrint(fmt_str.c_str(), d, i),
-                  FormatPack(format, absl::MakeSpan(args)))
-            << fmt_str << " " << StrPrint("%.18g", d) << " "
-            << StrPrint("%.999f", d);
+
+        string_printf_result.clear();
+        StrAppend(&string_printf_result, fmt_str.c_str(), d, i);
+        str_format_result.clear();
+
+        {
+          AppendPack(&str_format_result, format, absl::MakeSpan(args));
+        }
+
+        if (string_printf_result != str_format_result) {
+          // We use ASSERT_EQ here because failures are usually correlated and a
+          // bug would print way too many failed expectations causing the test
+          // to time out.
+          ASSERT_EQ(string_printf_result, str_format_result)
+              << fmt_str << " " << StrPrint("%.18g", d) << " "
+              << StrPrint("%a", d) << " " << StrPrint("%.1080f", d);
+        }
       }
     }
   }
 }
 
-TEST_F(FormatConvertTest, LongDouble) {
-  const char *const kFormats[] = {"%",    "%.3", "%8.5", "%9",
-                                  "%.60", "%+",  "% ",   "%-10"};
+TEST_F(FormatConvertTest, FloatRound) {
+  std::string s;
+  const auto format = [&](const char *fmt, double d) -> std::string & {
+    s.clear();
+    FormatArgImpl args[1] = {FormatArgImpl(d)};
+    AppendPack(&s, UntypedFormatSpecImpl(fmt), absl::MakeSpan(args));
+#if !defined(_MSC_VER)
+    // MSVC has a different rounding policy than us so we can't test our
+    // implementation against the native one there.
+    EXPECT_EQ(StrPrint(fmt, d), s);
+#endif  // _MSC_VER
 
-  // This value is not representable in double, but it is in long double that
-  // uses the extended format.
-  // This is to verify that we are not truncating the value mistakenly through a
-  // double.
-  long double very_precise = 10000000000000000.25L;
+    return s;
+  };
+  // All of these values have to be exactly represented.
+  // Otherwise we might not be testing what we think we are testing.
+
+  // These values can fit in a 64bit "fast" representation.
+  const double exact_value = 0.00000000000005684341886080801486968994140625;
+  assert(exact_value == std::pow(2, -44));
+  // Round up at a 5xx.
+  EXPECT_EQ(format("%.13f", exact_value), "0.0000000000001");
+  // Round up at a >5
+  EXPECT_EQ(format("%.14f", exact_value), "0.00000000000006");
+  // Round down at a <5
+  EXPECT_EQ(format("%.16f", exact_value), "0.0000000000000568");
+  // Nine handling
+  EXPECT_EQ(format("%.35f", exact_value),
+            "0.00000000000005684341886080801486969");
+  EXPECT_EQ(format("%.36f", exact_value),
+            "0.000000000000056843418860808014869690");
+  // Round down the last nine.
+  EXPECT_EQ(format("%.37f", exact_value),
+            "0.0000000000000568434188608080148696899");
+  EXPECT_EQ(format("%.10f", 0.000003814697265625), "0.0000038147");
+  // Round up the last nine
+  EXPECT_EQ(format("%.11f", 0.000003814697265625), "0.00000381470");
+  EXPECT_EQ(format("%.12f", 0.000003814697265625), "0.000003814697");
+
+  // Round to even (down)
+  EXPECT_EQ(format("%.43f", exact_value),
+            "0.0000000000000568434188608080148696899414062");
+  // Exact
+  EXPECT_EQ(format("%.44f", exact_value),
+            "0.00000000000005684341886080801486968994140625");
+  // Round to even (up), let make the last digits 75 instead of 25
+  EXPECT_EQ(format("%.43f", exact_value + std::pow(2, -43)),
+            "0.0000000000001705302565824240446090698242188");
+  // Exact, just to check.
+  EXPECT_EQ(format("%.44f", exact_value + std::pow(2, -43)),
+            "0.00000000000017053025658242404460906982421875");
+
+  // This value has to be small enough that it won't fit in the uint128
+  // representation for printing.
+  const double small_exact_value =
+      0.000000000000000000000000000000000000752316384526264005099991383822237233803945956334136013765601092018187046051025390625;  // NOLINT
+  assert(small_exact_value == std::pow(2, -120));
+  // Round up at a 5xx.
+  EXPECT_EQ(format("%.37f", small_exact_value),
+            "0.0000000000000000000000000000000000008");
+  // Round down at a <5
+  EXPECT_EQ(format("%.38f", small_exact_value),
+            "0.00000000000000000000000000000000000075");
+  // Round up at a >5
+  EXPECT_EQ(format("%.41f", small_exact_value),
+            "0.00000000000000000000000000000000000075232");
+  // Nine handling
+  EXPECT_EQ(format("%.55f", small_exact_value),
+            "0.0000000000000000000000000000000000007523163845262640051");
+  EXPECT_EQ(format("%.56f", small_exact_value),
+            "0.00000000000000000000000000000000000075231638452626400510");
+  EXPECT_EQ(format("%.57f", small_exact_value),
+            "0.000000000000000000000000000000000000752316384526264005100");
+  EXPECT_EQ(format("%.58f", small_exact_value),
+            "0.0000000000000000000000000000000000007523163845262640051000");
+  // Round down the last nine
+  EXPECT_EQ(format("%.59f", small_exact_value),
+            "0.00000000000000000000000000000000000075231638452626400509999");
+  // Round up the last nine
+  EXPECT_EQ(format("%.79f", small_exact_value),
+            "0.000000000000000000000000000000000000"
+            "7523163845262640050999913838222372338039460");
+
+  // Round to even (down)
+  EXPECT_EQ(format("%.119f", small_exact_value),
+            "0.000000000000000000000000000000000000"
+            "75231638452626400509999138382223723380"
+            "394595633413601376560109201818704605102539062");
+  // Exact
+  EXPECT_EQ(format("%.120f", small_exact_value),
+            "0.000000000000000000000000000000000000"
+            "75231638452626400509999138382223723380"
+            "3945956334136013765601092018187046051025390625");
+  // Round to even (up), let make the last digits 75 instead of 25
+  EXPECT_EQ(format("%.119f", small_exact_value + std::pow(2, -119)),
+            "0.000000000000000000000000000000000002"
+            "25694915357879201529997415146671170141"
+            "183786900240804129680327605456113815307617188");
+  // Exact, just to check.
+  EXPECT_EQ(format("%.120f", small_exact_value + std::pow(2, -119)),
+            "0.000000000000000000000000000000000002"
+            "25694915357879201529997415146671170141"
+            "1837869002408041296803276054561138153076171875");
+}
+
+// We don't actually store the results. This is just to exercise the rest of the
+// machinery.
+struct NullSink {
+  friend void AbslFormatFlush(NullSink *sink, string_view str) {}
+};
+
+template <typename... T>
+bool FormatWithNullSink(absl::string_view fmt, const T &... a) {
+  NullSink sink;
+  FormatArgImpl args[] = {FormatArgImpl(a)...};
+  return FormatUntyped(&sink, UntypedFormatSpecImpl(fmt), absl::MakeSpan(args));
+}
+
+TEST_F(FormatConvertTest, ExtremeWidthPrecision) {
+  for (const char *fmt : {"f"}) {
+    for (double d : {1e-100, 1.0, 1e100}) {
+      constexpr int max = std::numeric_limits<int>::max();
+      EXPECT_TRUE(FormatWithNullSink(std::string("%.*") + fmt, max, d));
+      EXPECT_TRUE(FormatWithNullSink(std::string("%1.*") + fmt, max, d));
+      EXPECT_TRUE(FormatWithNullSink(std::string("%*") + fmt, max, d));
+      EXPECT_TRUE(FormatWithNullSink(std::string("%*.*") + fmt, max, max, d));
+    }
+  }
+}
+
+TEST_F(FormatConvertTest, LongDouble) {
+#ifdef _MSC_VER
+  // MSVC has a different rounding policy than us so we can't test our
+  // implementation against the native one there.
+  return;
+#endif  // _MSC_VER
+  const char *const kFormats[] = {"%",    "%.3", "%8.5", "%9",  "%.5000",
+                                  "%.60", "%+",  "% ",   "%-10"};
 
   std::vector<long double> doubles = {
       0.0,
       -0.0,
-      very_precise,
-      1 / very_precise,
       std::numeric_limits<long double>::max(),
       -std::numeric_limits<long double>::max(),
       std::numeric_limits<long double>::min(),
@@ -556,22 +748,44 @@
       std::numeric_limits<long double>::infinity(),
       -std::numeric_limits<long double>::infinity()};
 
+  for (long double base : {1.L, 12.L, 123.L, 1234.L, 12345.L, 123456.L,
+                           1234567.L, 12345678.L, 123456789.L, 1234567890.L,
+                           12345678901.L, 123456789012.L, 1234567890123.L,
+                           // This value is not representable in double, but it
+                           // is in long double that uses the extended format.
+                           // This is to verify that we are not truncating the
+                           // value mistakenly through a double.
+                           10000000000000000.25L}) {
+    for (int exp : {-1000, -500, 0, 500, 1000}) {
+      for (int sign : {1, -1}) {
+        doubles.push_back(sign * std::ldexp(base, exp));
+        doubles.push_back(sign / std::ldexp(base, exp));
+      }
+    }
+  }
+
   for (const char *fmt : kFormats) {
     for (char f : {'f', 'F',  //
                    'g', 'G',  //
                    'a', 'A',  //
                    'e', 'E'}) {
       std::string fmt_str = std::string(fmt) + 'L' + f;
+
+      if (fmt == absl::string_view("%.5000") && f != 'f' && f != 'F') {
+        // This particular test takes way too long with snprintf.
+        // Disable for the case we are not implementing natively.
+        continue;
+      }
+
       for (auto d : doubles) {
         FormatArgImpl arg(d);
         UntypedFormatSpecImpl format(fmt_str);
         // We use ASSERT_EQ here because failures are usually correlated and a
         // bug would print way too many failed expectations causing the test to
         // time out.
-        ASSERT_EQ(StrPrint(fmt_str.c_str(), d),
-                  FormatPack(format, {&arg, 1}))
+        ASSERT_EQ(StrPrint(fmt_str.c_str(), d), FormatPack(format, {&arg, 1}))
             << fmt_str << " " << StrPrint("%.18Lg", d) << " "
-            << StrPrint("%.999Lf", d);
+            << StrPrint("%La", d) << " " << StrPrint("%.1080Lf", d);
       }
     }
   }
diff --git a/absl/strings/internal/str_format/extension.h b/absl/strings/internal/str_format/extension.h
index fb31a9d..ce78a02 100644
--- a/absl/strings/internal/str_format/extension.h
+++ b/absl/strings/internal/str_format/extension.h
@@ -30,7 +30,10 @@
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
+
 namespace str_format_internal {
+enum class FormatConversionCharSet : uint64_t;
+enum class FormatConversionChar : uint8_t;
 
 class FormatRawSinkImpl {
  public:
@@ -140,7 +143,7 @@
 // clang-format off
 #define ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \
   /* text */ \
-  X_VAL(c) X_SEP X_VAL(C) X_SEP X_VAL(s) X_SEP X_VAL(S) X_SEP \
+  X_VAL(c) X_SEP X_VAL(s) X_SEP \
   /* ints */ \
   X_VAL(d) X_SEP X_VAL(i) X_SEP X_VAL(o) X_SEP \
   X_VAL(u) X_SEP X_VAL(x) X_SEP X_VAL(X) X_SEP \
@@ -149,13 +152,39 @@
   X_VAL(g) X_SEP X_VAL(G) X_SEP X_VAL(a) X_SEP X_VAL(A) X_SEP \
   /* misc */ \
   X_VAL(n) X_SEP X_VAL(p)
+// clang-format on
 
-enum class FormatConversionChar : uint8_t {
-    c, C, s, S,              // text
+// This type should not be referenced, it exists only to provide labels
+// internally that match the values declared in FormatConversionChar in
+// str_format.h. This is meant to allow internal libraries to use the same
+// declared interface type as the public interface
+// (absl::StrFormatConversionChar) while keeping the definition in a public
+// header.
+// Internal libraries should use the form
+// `FormatConversionCharInternal::c`, `FormatConversionCharInternal::kNone` for
+// comparisons.  Use in switch statements is not recommended due to a bug in how
+// gcc 4.9 -Wswitch handles declared but undefined enums.
+struct FormatConversionCharInternal {
+  FormatConversionCharInternal() = delete;
+
+ private:
+  // clang-format off
+  enum class Enum : uint8_t {
+    c, s,                    // text
     d, i, o, u, x, X,        // int
     f, F, e, E, g, G, a, A,  // float
     n, p,                    // misc
     kNone
+  };
+  // clang-format on
+ public:
+#define ABSL_INTERNAL_X_VAL(id)              \
+  static constexpr FormatConversionChar id = \
+      static_cast<FormatConversionChar>(Enum::id);
+  ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
+#undef ABSL_INTERNAL_X_VAL
+  static constexpr FormatConversionChar kNone =
+      static_cast<FormatConversionChar>(Enum::kNone);
 };
 // clang-format on
 
@@ -163,56 +192,56 @@
   switch (c) {
 #define ABSL_INTERNAL_X_VAL(id) \
   case #id[0]:                  \
-    return FormatConversionChar::id;
+    return FormatConversionCharInternal::id;
     ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
 #undef ABSL_INTERNAL_X_VAL
   }
-  return FormatConversionChar::kNone;
+  return FormatConversionCharInternal::kNone;
 }
 
 inline bool FormatConversionCharIsUpper(FormatConversionChar c) {
-  switch (c) {
-    case FormatConversionChar::X:
-    case FormatConversionChar::F:
-    case FormatConversionChar::E:
-    case FormatConversionChar::G:
-    case FormatConversionChar::A:
-      return true;
-    default:
-      return false;
+  if (c == FormatConversionCharInternal::X ||
+      c == FormatConversionCharInternal::F ||
+      c == FormatConversionCharInternal::E ||
+      c == FormatConversionCharInternal::G ||
+      c == FormatConversionCharInternal::A) {
+    return true;
+  } else {
+    return false;
   }
 }
 
 inline bool FormatConversionCharIsFloat(FormatConversionChar c) {
-  switch (c) {
-    case FormatConversionChar::a:
-    case FormatConversionChar::e:
-    case FormatConversionChar::f:
-    case FormatConversionChar::g:
-    case FormatConversionChar::A:
-    case FormatConversionChar::E:
-    case FormatConversionChar::F:
-    case FormatConversionChar::G:
-      return true;
-    default:
-      return false;
+  if (c == FormatConversionCharInternal::a ||
+      c == FormatConversionCharInternal::e ||
+      c == FormatConversionCharInternal::f ||
+      c == FormatConversionCharInternal::g ||
+      c == FormatConversionCharInternal::A ||
+      c == FormatConversionCharInternal::E ||
+      c == FormatConversionCharInternal::F ||
+      c == FormatConversionCharInternal::G) {
+    return true;
+  } else {
+    return false;
   }
 }
 
 inline char FormatConversionCharToChar(FormatConversionChar c) {
-  switch (c) {
-#define ABSL_INTERNAL_X_VAL(e)  \
-  case FormatConversionChar::e: \
+  if (c == FormatConversionCharInternal::kNone) {
+    return '\0';
+
+#define ABSL_INTERNAL_X_VAL(e)                       \
+  } else if (c == FormatConversionCharInternal::e) { \
     return #e[0];
 #define ABSL_INTERNAL_X_SEP
-    ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL,
-                                           ABSL_INTERNAL_X_SEP)
-    case FormatConversionChar::kNone:
-      return '\0';
+  ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL,
+                                         ABSL_INTERNAL_X_SEP)
+  } else {
+    return '\0';
+  }
+
 #undef ABSL_INTERNAL_X_VAL
 #undef ABSL_INTERNAL_X_SEP
-  }
-  return '\0';
 }
 
 // The associated char.
@@ -224,7 +253,7 @@
 
 struct FormatConversionSpecImplFriend;
 
-class FormatConversionSpec {
+class FormatConversionSpecImpl {
  public:
   // Width and precison are not specified, no flags are set.
   bool is_basic() const { return flags_.basic; }
@@ -237,7 +266,7 @@
   FormatConversionChar conversion_char() const {
     // Keep this field first in the struct . It generates better code when
     // accessing it when ConversionSpec is passed by value in registers.
-    static_assert(offsetof(FormatConversionSpec, conv_) == 0, "");
+    static_assert(offsetof(FormatConversionSpecImpl, conv_) == 0, "");
     return conv_;
   }
 
@@ -248,37 +277,62 @@
   // negative value.
   int precision() const { return precision_; }
 
+  template <typename T>
+  T Wrap() {
+    return T(*this);
+  }
+
  private:
   friend struct str_format_internal::FormatConversionSpecImplFriend;
-  FormatConversionChar conv_ = FormatConversionChar::kNone;
+  FormatConversionChar conv_ = FormatConversionCharInternal::kNone;
   Flags flags_;
   int width_;
   int precision_;
 };
 
 struct FormatConversionSpecImplFriend final {
-  static void SetFlags(Flags f, FormatConversionSpec* conv) {
+  static void SetFlags(Flags f, FormatConversionSpecImpl* conv) {
     conv->flags_ = f;
   }
   static void SetConversionChar(FormatConversionChar c,
-                                FormatConversionSpec* conv) {
+                                FormatConversionSpecImpl* conv) {
     conv->conv_ = c;
   }
-  static void SetWidth(int w, FormatConversionSpec* conv) { conv->width_ = w; }
-  static void SetPrecision(int p, FormatConversionSpec* conv) {
+  static void SetWidth(int w, FormatConversionSpecImpl* conv) {
+    conv->width_ = w;
+  }
+  static void SetPrecision(int p, FormatConversionSpecImpl* conv) {
     conv->precision_ = p;
   }
-  static std::string FlagsToString(const FormatConversionSpec& spec) {
+  static std::string FlagsToString(const FormatConversionSpecImpl& spec) {
     return spec.flags_.ToString();
   }
 };
 
-constexpr uint64_t FormatConversionCharToConvValue(char conv) {
+// Type safe OR operator.
+// We need this for two reasons:
+//  1. operator| on enums makes them decay to integers and the result is an
+//     integer. We need the result to stay as an enum.
+//  2. We use "enum class" which would not work even if we accepted the decay.
+constexpr FormatConversionCharSet FormatConversionCharSetUnion(
+    FormatConversionCharSet a) {
+  return a;
+}
+
+template <typename... CharSet>
+constexpr FormatConversionCharSet FormatConversionCharSetUnion(
+    FormatConversionCharSet a, CharSet... rest) {
+  return static_cast<FormatConversionCharSet>(
+      static_cast<uint64_t>(a) |
+      static_cast<uint64_t>(FormatConversionCharSetUnion(rest...)));
+}
+
+constexpr uint64_t FormatConversionCharToConvInt(char conv) {
   return
-#define ABSL_INTERNAL_CHAR_SET_CASE(c)                                       \
-  conv == #c[0]                                                              \
-      ? (uint64_t{1} << (1 + static_cast<uint8_t>(FormatConversionChar::c))) \
-      :
+#define ABSL_INTERNAL_CHAR_SET_CASE(c)                                        \
+  conv == #c[0] ? (uint64_t{1} << (1 + static_cast<uint8_t>(                  \
+                                           FormatConversionCharInternal::c))) \
+                :
       ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
 #undef ABSL_INTERNAL_CHAR_SET_CASE
                   conv == '*'
@@ -286,20 +340,31 @@
           : 0;
 }
 
-enum class FormatConversionCharSet : uint64_t {
-#define ABSL_INTERNAL_CHAR_SET_CASE(c) \
-  c = FormatConversionCharToConvValue(#c[0]),
+constexpr FormatConversionCharSet FormatConversionCharToConvValue(char conv) {
+  return static_cast<FormatConversionCharSet>(
+      FormatConversionCharToConvInt(conv));
+}
+
+struct FormatConversionCharSetInternal {
+#define ABSL_INTERNAL_CHAR_SET_CASE(c)         \
+  static constexpr FormatConversionCharSet c = \
+      FormatConversionCharToConvValue(#c[0]);
   ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
 #undef ABSL_INTERNAL_CHAR_SET_CASE
 
   // Used for width/precision '*' specification.
-  kStar = FormatConversionCharToConvValue('*'),
-  // Some predefined values:
-  kIntegral = d | i | u | o | x | X,
-  kFloating = a | e | f | g | A | E | F | G,
-  kNumeric = kIntegral | kFloating,
-  kString = s,
-  kPointer = p
+  static constexpr FormatConversionCharSet kStar =
+      FormatConversionCharToConvValue('*');
+
+  // Some predefined values (TODO(matthewbr), delete any that are unused).
+  static constexpr FormatConversionCharSet kIntegral =
+      FormatConversionCharSetUnion(d, i, u, o, x, X);
+  static constexpr FormatConversionCharSet kFloating =
+      FormatConversionCharSetUnion(a, e, f, g, A, E, F, G);
+  static constexpr FormatConversionCharSet kNumeric =
+      FormatConversionCharSetUnion(kIntegral, kFloating);
+  static constexpr FormatConversionCharSet kString = s;
+  static constexpr FormatConversionCharSet kPointer = p;
 };
 
 // Type safe OR operator.
@@ -309,8 +374,7 @@
 //  2. We use "enum class" which would not work even if we accepted the decay.
 constexpr FormatConversionCharSet operator|(FormatConversionCharSet a,
                                             FormatConversionCharSet b) {
-  return FormatConversionCharSet(static_cast<uint64_t>(a) |
-                                 static_cast<uint64_t>(b));
+  return FormatConversionCharSetUnion(a, b);
 }
 
 // Overloaded conversion functions to support absl::ParsedFormat.
@@ -331,7 +395,8 @@
 
 // Checks whether `c` exists in `set`.
 constexpr bool Contains(FormatConversionCharSet set, char c) {
-  return (static_cast<uint64_t>(set) & FormatConversionCharToConvValue(c)) != 0;
+  return (static_cast<uint64_t>(set) &
+          static_cast<uint64_t>(FormatConversionCharToConvValue(c))) != 0;
 }
 
 // Checks whether all the characters in `c` are contained in `set`
@@ -341,30 +406,85 @@
          static_cast<uint64_t>(c);
 }
 
-// Return type of the AbslFormatConvert() functions.
-// The FormatConversionCharSet template parameter is used to inform the
-// framework of what conversion characters are supported by that
-// AbslFormatConvert routine.
-template <FormatConversionCharSet C>
-struct FormatConvertResult {
-  static constexpr FormatConversionCharSet kConv = C;
-  bool value;
-};
-
-template <FormatConversionCharSet C>
-constexpr FormatConversionCharSet FormatConvertResult<C>::kConv;
-
 // Return capacity - used, clipped to a minimum of 0.
 inline size_t Excess(size_t used, size_t capacity) {
   return used < capacity ? capacity - used : 0;
 }
 
-// Type alias for use during migration.
-using ConversionChar = FormatConversionChar;
-using ConversionSpec = FormatConversionSpec;
-using Conv = FormatConversionCharSet;
-template <FormatConversionCharSet C>
-using ConvertResult = FormatConvertResult<C>;
+class FormatConversionSpec {
+ public:
+  // Width and precison are not specified, no flags are set.
+  bool is_basic() const { return impl_.is_basic(); }
+  bool has_left_flag() const { return impl_.has_left_flag(); }
+  bool has_show_pos_flag() const { return impl_.has_show_pos_flag(); }
+  bool has_sign_col_flag() const { return impl_.has_sign_col_flag(); }
+  bool has_alt_flag() const { return impl_.has_alt_flag(); }
+  bool has_zero_flag() const { return impl_.has_zero_flag(); }
+
+  FormatConversionChar conversion_char() const {
+    return impl_.conversion_char();
+  }
+
+  // Returns the specified width. If width is unspecfied, it returns a negative
+  // value.
+  int width() const { return impl_.width(); }
+  // Returns the specified precision. If precision is unspecfied, it returns a
+  // negative value.
+  int precision() const { return impl_.precision(); }
+
+ private:
+  explicit FormatConversionSpec(
+      str_format_internal::FormatConversionSpecImpl impl)
+      : impl_(impl) {}
+
+  friend str_format_internal::FormatConversionSpecImpl;
+
+  absl::str_format_internal::FormatConversionSpecImpl impl_;
+};
+
+// clang-format off
+enum class FormatConversionChar : uint8_t {
+  c, s,                    // text
+  d, i, o, u, x, X,        // int
+  f, F, e, E, g, G, a, A,  // float
+  n, p                     // misc
+};
+// clang-format on
+
+enum class FormatConversionCharSet : uint64_t {
+  // text
+  c = str_format_internal::FormatConversionCharToConvInt('c'),
+  s = str_format_internal::FormatConversionCharToConvInt('s'),
+  // integer
+  d = str_format_internal::FormatConversionCharToConvInt('d'),
+  i = str_format_internal::FormatConversionCharToConvInt('i'),
+  o = str_format_internal::FormatConversionCharToConvInt('o'),
+  u = str_format_internal::FormatConversionCharToConvInt('u'),
+  x = str_format_internal::FormatConversionCharToConvInt('x'),
+  X = str_format_internal::FormatConversionCharToConvInt('X'),
+  // Float
+  f = str_format_internal::FormatConversionCharToConvInt('f'),
+  F = str_format_internal::FormatConversionCharToConvInt('F'),
+  e = str_format_internal::FormatConversionCharToConvInt('e'),
+  E = str_format_internal::FormatConversionCharToConvInt('E'),
+  g = str_format_internal::FormatConversionCharToConvInt('g'),
+  G = str_format_internal::FormatConversionCharToConvInt('G'),
+  a = str_format_internal::FormatConversionCharToConvInt('a'),
+  A = str_format_internal::FormatConversionCharToConvInt('A'),
+  // misc
+  n = str_format_internal::FormatConversionCharToConvInt('n'),
+  p = str_format_internal::FormatConversionCharToConvInt('p'),
+
+  // Used for width/precision '*' specification.
+  kStar = str_format_internal::FormatConversionCharToConvInt('*'),
+
+  // Some predefined values:
+  kIntegral = d | i | u | o | x | X,
+  kFloating = a | e | f | g | A | E | F | G,
+  kNumeric = kIntegral | kFloating,
+  kString = s,
+  kPointer = p,
+};
 
 }  // namespace str_format_internal
 
diff --git a/absl/strings/internal/str_format/extension_test.cc b/absl/strings/internal/str_format/extension_test.cc
index 561eaa3..0a023f9 100644
--- a/absl/strings/internal/str_format/extension_test.cc
+++ b/absl/strings/internal/str_format/extension_test.cc
@@ -80,13 +80,4 @@
     EXPECT_EQ(actual, expected);
   }
 }
-
-TEST(FormatExtensionTest, CustomSink) {
-  my_namespace::UserDefinedType sink;
-  absl::Format(&sink, "There were %04d little %s.", 3, "pigs");
-  EXPECT_EQ("There were 0003 little pigs.", sink.Value());
-  absl::Format(&sink, "And %-3llx bad wolf!", 1);
-  EXPECT_EQ("There were 0003 little pigs.And 1   bad wolf!", sink.Value());
-}
-
 }  // namespace
diff --git a/absl/strings/internal/str_format/float_conversion.cc b/absl/strings/internal/str_format/float_conversion.cc
index d5a1ee4..a761a5a 100644
--- a/absl/strings/internal/str_format/float_conversion.cc
+++ b/absl/strings/internal/str_format/float_conversion.cc
@@ -1,12 +1,22 @@
 #include "absl/strings/internal/str_format/float_conversion.h"
 
 #include <string.h>
+
 #include <algorithm>
 #include <cassert>
 #include <cmath>
+#include <limits>
 #include <string>
 
+#include "absl/base/attributes.h"
 #include "absl/base/config.h"
+#include "absl/base/internal/bits.h"
+#include "absl/base/optimization.h"
+#include "absl/functional/function_ref.h"
+#include "absl/meta/type_traits.h"
+#include "absl/numeric/int128.h"
+#include "absl/types/optional.h"
+#include "absl/types/span.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -14,13 +24,644 @@
 
 namespace {
 
-char *CopyStringTo(string_view v, char *out) {
+// The code below wants to avoid heap allocations.
+// To do so it needs to allocate memory on the stack.
+// `StackArray` will allocate memory on the stack in the form of a uint32_t
+// array and call the provided callback with said memory.
+// It will allocate memory in increments of 512 bytes. We could allocate the
+// largest needed unconditionally, but that is more than we need in most of
+// cases. This way we use less stack in the common cases.
+class StackArray {
+  using Func = absl::FunctionRef<void(absl::Span<uint32_t>)>;
+  static constexpr size_t kStep = 512 / sizeof(uint32_t);
+  // 5 steps is 2560 bytes, which is enough to hold a long double with the
+  // largest/smallest exponents.
+  // The operations below will static_assert their particular maximum.
+  static constexpr size_t kNumSteps = 5;
+
+  // We do not want this function to be inlined.
+  // Otherwise the caller will allocate the stack space unnecessarily for all
+  // the variants even though it only calls one.
+  template <size_t steps>
+  ABSL_ATTRIBUTE_NOINLINE static void RunWithCapacityImpl(Func f) {
+    uint32_t values[steps * kStep]{};
+    f(absl::MakeSpan(values));
+  }
+
+ public:
+  static constexpr size_t kMaxCapacity = kStep * kNumSteps;
+
+  static void RunWithCapacity(size_t capacity, Func f) {
+    assert(capacity <= kMaxCapacity);
+    const size_t step = (capacity + kStep - 1) / kStep;
+    assert(step <= kNumSteps);
+    switch (step) {
+      case 1:
+        return RunWithCapacityImpl<1>(f);
+      case 2:
+        return RunWithCapacityImpl<2>(f);
+      case 3:
+        return RunWithCapacityImpl<3>(f);
+      case 4:
+        return RunWithCapacityImpl<4>(f);
+      case 5:
+        return RunWithCapacityImpl<5>(f);
+    }
+
+    assert(false && "Invalid capacity");
+  }
+};
+
+// Calculates `10 * (*v) + carry` and stores the result in `*v` and returns
+// the carry.
+template <typename Int>
+inline Int MultiplyBy10WithCarry(Int *v, Int carry) {
+  using BiggerInt = absl::conditional_t<sizeof(Int) == 4, uint64_t, uint128>;
+  BiggerInt tmp = 10 * static_cast<BiggerInt>(*v) + carry;
+  *v = static_cast<Int>(tmp);
+  return static_cast<Int>(tmp >> (sizeof(Int) * 8));
+}
+
+// Calculates `(2^64 * carry + *v) / 10`.
+// Stores the quotient in `*v` and returns the remainder.
+// Requires: `0 <= carry <= 9`
+inline uint64_t DivideBy10WithCarry(uint64_t *v, uint64_t carry) {
+  constexpr uint64_t divisor = 10;
+  // 2^64 / divisor = chunk_quotient + chunk_remainder / divisor
+  constexpr uint64_t chunk_quotient = (uint64_t{1} << 63) / (divisor / 2);
+  constexpr uint64_t chunk_remainder = uint64_t{} - chunk_quotient * divisor;
+
+  const uint64_t mod = *v % divisor;
+  const uint64_t next_carry = chunk_remainder * carry + mod;
+  *v = *v / divisor + carry * chunk_quotient + next_carry / divisor;
+  return next_carry % divisor;
+}
+
+// Generates the decimal representation for an integer of the form `v * 2^exp`,
+// where `v` and `exp` are both positive integers.
+// It generates the digits from the left (ie the most significant digit first)
+// to allow for direct printing into the sink.
+//
+// Requires `0 <= exp` and `exp <= numeric_limits<long double>::max_exponent`.
+class BinaryToDecimal {
+  static constexpr int ChunksNeeded(int exp) {
+    // We will left shift a uint128 by `exp` bits, so we need `128+exp` total
+    // bits. Round up to 32.
+    // See constructor for details about adding `10%` to the value.
+    return (128 + exp + 31) / 32 * 11 / 10;
+  }
+
+ public:
+  // Run the conversion for `v * 2^exp` and call `f(binary_to_decimal)`.
+  // This function will allocate enough stack space to perform the conversion.
+  static void RunConversion(uint128 v, int exp,
+                            absl::FunctionRef<void(BinaryToDecimal)> f) {
+    assert(exp > 0);
+    assert(exp <= std::numeric_limits<long double>::max_exponent);
+    static_assert(
+        StackArray::kMaxCapacity >=
+            ChunksNeeded(std::numeric_limits<long double>::max_exponent),
+        "");
+
+    StackArray::RunWithCapacity(
+        ChunksNeeded(exp),
+        [=](absl::Span<uint32_t> input) { f(BinaryToDecimal(input, v, exp)); });
+  }
+
+  int TotalDigits() const {
+    return static_cast<int>((decimal_end_ - decimal_start_) * kDigitsPerChunk +
+                            CurrentDigits().size());
+  }
+
+  // See the current block of digits.
+  absl::string_view CurrentDigits() const {
+    return absl::string_view(digits_ + kDigitsPerChunk - size_, size_);
+  }
+
+  // Advance the current view of digits.
+  // Returns `false` when no more digits are available.
+  bool AdvanceDigits() {
+    if (decimal_start_ >= decimal_end_) return false;
+
+    uint32_t w = data_[decimal_start_++];
+    for (size_ = 0; size_ < kDigitsPerChunk; w /= 10) {
+      digits_[kDigitsPerChunk - ++size_] = w % 10 + '0';
+    }
+    return true;
+  }
+
+ private:
+  BinaryToDecimal(absl::Span<uint32_t> data, uint128 v, int exp) : data_(data) {
+    // We need to print the digits directly into the sink object without
+    // buffering them all first. To do this we need two things:
+    // - to know the total number of digits to do padding when necessary
+    // - to generate the decimal digits from the left.
+    //
+    // In order to do this, we do a two pass conversion.
+    // On the first pass we convert the binary representation of the value into
+    // a decimal representation in which each uint32_t chunk holds up to 9
+    // decimal digits.  In the second pass we take each decimal-holding-uint32_t
+    // value and generate the ascii decimal digits into `digits_`.
+    //
+    // The binary and decimal representations actually share the same memory
+    // region. As we go converting the chunks from binary to decimal we free
+    // them up and reuse them for the decimal representation. One caveat is that
+    // the decimal representation is around 7% less efficient in space than the
+    // binary one. We allocate an extra 10% memory to account for this. See
+    // ChunksNeeded for this calculation.
+    int chunk_index = exp / 32;
+    decimal_start_ = decimal_end_ = ChunksNeeded(exp);
+    const int offset = exp % 32;
+    // Left shift v by exp bits.
+    data_[chunk_index] = static_cast<uint32_t>(v << offset);
+    for (v >>= (32 - offset); v; v >>= 32)
+      data_[++chunk_index] = static_cast<uint32_t>(v);
+
+    while (chunk_index >= 0) {
+      // While we have more than one chunk available, go in steps of 1e9.
+      // `data_[chunk_index]` holds the highest non-zero binary chunk, so keep
+      // the variable updated.
+      uint32_t carry = 0;
+      for (int i = chunk_index; i >= 0; --i) {
+        uint64_t tmp = uint64_t{data_[i]} + (uint64_t{carry} << 32);
+        data_[i] = static_cast<uint32_t>(tmp / uint64_t{1000000000});
+        carry = static_cast<uint32_t>(tmp % uint64_t{1000000000});
+      }
+
+      // If the highest chunk is now empty, remove it from view.
+      if (data_[chunk_index] == 0) --chunk_index;
+
+      --decimal_start_;
+      assert(decimal_start_ != chunk_index);
+      data_[decimal_start_] = carry;
+    }
+
+    // Fill the first set of digits. The first chunk might not be complete, so
+    // handle differently.
+    for (uint32_t first = data_[decimal_start_++]; first != 0; first /= 10) {
+      digits_[kDigitsPerChunk - ++size_] = first % 10 + '0';
+    }
+  }
+
+ private:
+  static constexpr size_t kDigitsPerChunk = 9;
+
+  int decimal_start_;
+  int decimal_end_;
+
+  char digits_[kDigitsPerChunk];
+  int size_ = 0;
+
+  absl::Span<uint32_t> data_;
+};
+
+// Converts a value of the form `x * 2^-exp` into a sequence of decimal digits.
+// Requires `-exp < 0` and
+// `-exp >= limits<long double>::min_exponent - limits<long double>::digits`.
+class FractionalDigitGenerator {
+ public:
+  // Run the conversion for `v * 2^exp` and call `f(generator)`.
+  // This function will allocate enough stack space to perform the conversion.
+  static void RunConversion(
+      uint128 v, int exp, absl::FunctionRef<void(FractionalDigitGenerator)> f) {
+    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,
+                                [=](absl::Span<uint32_t> input) {
+                                  f(FractionalDigitGenerator(input, v, exp));
+                                });
+  }
+
+  // Returns true if there are any more non-zero digits left.
+  bool HasMoreDigits() const { return next_digit_ != 0 || chunk_index_ >= 0; }
+
+  // Returns true if the remainder digits are greater than 5000...
+  bool IsGreaterThanHalf() const {
+    return next_digit_ > 5 || (next_digit_ == 5 && chunk_index_ >= 0);
+  }
+  // Returns true if the remainder digits are exactly 5000...
+  bool IsExactlyHalf() const { return next_digit_ == 5 && chunk_index_ < 0; }
+
+  struct Digits {
+    int digit_before_nine;
+    int num_nines;
+  };
+
+  // Get the next set of digits.
+  // They are composed by a non-9 digit followed by a runs of zero or more 9s.
+  Digits GetDigits() {
+    Digits digits{next_digit_, 0};
+
+    next_digit_ = GetOneDigit();
+    while (next_digit_ == 9) {
+      ++digits.num_nines;
+      next_digit_ = GetOneDigit();
+    }
+
+    return digits;
+  }
+
+ private:
+  // Return the next digit.
+  int GetOneDigit() {
+    if (chunk_index_ < 0) return 0;
+
+    uint32_t carry = 0;
+    for (int i = chunk_index_; i >= 0; --i) {
+      carry = MultiplyBy10WithCarry(&data_[i], carry);
+    }
+    // If the lowest chunk is now empty, remove it from view.
+    if (data_[chunk_index_] == 0) --chunk_index_;
+    return carry;
+  }
+
+  FractionalDigitGenerator(absl::Span<uint32_t> data, uint128 v, int exp)
+      : chunk_index_(exp / 32), data_(data) {
+    const int offset = exp % 32;
+    // Right shift `v` by `exp` bits.
+    data_[chunk_index_] = static_cast<uint32_t>(v << (32 - offset));
+    v >>= offset;
+    // Make sure we don't overflow the data. We already calculated that
+    // non-zero bits fit, so we might not have space for leading zero bits.
+    for (int pos = chunk_index_; v; v >>= 32)
+      data_[--pos] = static_cast<uint32_t>(v);
+
+    // Fill next_digit_, as GetDigits expects it to be populated always.
+    next_digit_ = GetOneDigit();
+  }
+
+  int next_digit_;
+  int chunk_index_;
+  absl::Span<uint32_t> data_;
+};
+
+// Count the number of leading zero bits.
+int LeadingZeros(uint64_t v) { return base_internal::CountLeadingZeros64(v); }
+int LeadingZeros(uint128 v) {
+  auto high = static_cast<uint64_t>(v >> 64);
+  auto low = static_cast<uint64_t>(v);
+  return high != 0 ? base_internal::CountLeadingZeros64(high)
+                   : 64 + base_internal::CountLeadingZeros64(low);
+}
+
+// Round up the text digits starting at `p`.
+// The buffer must have an extra digit that is known to not need rounding.
+// This is done below by having an extra '0' digit on the left.
+void RoundUp(char *p) {
+  while (*p == '9' || *p == '.') {
+    if (*p == '9') *p = '0';
+    --p;
+  }
+  ++*p;
+}
+
+// Check the previous digit and round up or down to follow the round-to-even
+// policy.
+void RoundToEven(char *p) {
+  if (*p == '.') --p;
+  if (*p % 2 == 1) RoundUp(p);
+}
+
+// Simple integral decimal digit printing for values that fit in 64-bits.
+// Returns the pointer to the last written digit.
+char *PrintIntegralDigitsFromRightFast(uint64_t v, char *p) {
+  do {
+    *--p = DivideBy10WithCarry(&v, 0) + '0';
+  } while (v != 0);
+  return p;
+}
+
+// Simple integral decimal digit printing for values that fit in 128-bits.
+// Returns the pointer to the last written digit.
+char *PrintIntegralDigitsFromRightFast(uint128 v, char *p) {
+  auto high = static_cast<uint64_t>(v >> 64);
+  auto low = static_cast<uint64_t>(v);
+
+  while (high != 0) {
+    uint64_t carry = DivideBy10WithCarry(&high, 0);
+    carry = DivideBy10WithCarry(&low, carry);
+    *--p = carry + '0';
+  }
+  return PrintIntegralDigitsFromRightFast(low, p);
+}
+
+// Simple fractional decimal digit printing for values that fir in 64-bits after
+// shifting.
+// Performs rounding if necessary to fit within `precision`.
+// Returns the pointer to one after the last character written.
+char *PrintFractionalDigitsFast(uint64_t v, char *start, int exp,
+                                int precision) {
+  char *p = start;
+  v <<= (64 - exp);
+  while (precision > 0) {
+    if (!v) return p;
+    *p++ = MultiplyBy10WithCarry(&v, uint64_t{0}) + '0';
+    --precision;
+  }
+
+  // We need to round.
+  if (v < 0x8000000000000000) {
+    // We round down, so nothing to do.
+  } else if (v > 0x8000000000000000) {
+    // We round up.
+    RoundUp(p - 1);
+  } else {
+    RoundToEven(p - 1);
+  }
+
+  assert(precision == 0);
+  // Precision can only be zero here.
+  return p;
+}
+
+// Simple fractional decimal digit printing for values that fir in 128-bits
+// after shifting.
+// Performs rounding if necessary to fit within `precision`.
+// Returns the pointer to one after the last character written.
+char *PrintFractionalDigitsFast(uint128 v, char *start, int exp,
+                                int precision) {
+  char *p = start;
+  v <<= (128 - exp);
+  auto high = static_cast<uint64_t>(v >> 64);
+  auto low = static_cast<uint64_t>(v);
+
+  // While we have digits to print and `low` is not empty, do the long
+  // multiplication.
+  while (precision > 0 && low != 0) {
+    uint64_t carry = MultiplyBy10WithCarry(&low, uint64_t{0});
+    carry = MultiplyBy10WithCarry(&high, carry);
+
+    *p++ = carry + '0';
+    --precision;
+  }
+
+  // Now `low` is empty, so use a faster approach for the rest of the digits.
+  // This block is pretty much the same as the main loop for the 64-bit case
+  // above.
+  while (precision > 0) {
+    if (!high) return p;
+    *p++ = MultiplyBy10WithCarry(&high, uint64_t{0}) + '0';
+    --precision;
+  }
+
+  // We need to round.
+  if (high < 0x8000000000000000) {
+    // We round down, so nothing to do.
+  } else if (high > 0x8000000000000000 || low != 0) {
+    // We round up.
+    RoundUp(p - 1);
+  } else {
+    RoundToEven(p - 1);
+  }
+
+  assert(precision == 0);
+  // Precision can only be zero here.
+  return p;
+}
+
+struct FormatState {
+  char sign_char;
+  int precision;
+  const FormatConversionSpecImpl &conv;
+  FormatSinkImpl *sink;
+
+  // In `alt` mode (flag #) we keep the `.` even if there are no fractional
+  // digits. In non-alt mode, we strip it.
+  bool ShouldPrintDot() const { return precision != 0 || conv.has_alt_flag(); }
+};
+
+struct Padding {
+  int left_spaces;
+  int zeros;
+  int right_spaces;
+};
+
+Padding ExtraWidthToPadding(size_t total_size, const FormatState &state) {
+  if (state.conv.width() < 0 || state.conv.width() <= total_size)
+    return {0, 0, 0};
+  int missing_chars = state.conv.width() - total_size;
+  if (state.conv.has_left_flag()) {
+    return {0, 0, missing_chars};
+  } else if (state.conv.has_zero_flag()) {
+    return {0, missing_chars, 0};
+  } else {
+    return {missing_chars, 0, 0};
+  }
+}
+
+void FinalPrint(absl::string_view data, int trailing_zeros,
+                const FormatState &state) {
+  if (state.conv.width() < 0) {
+    // No width specified. Fast-path.
+    if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+    state.sink->Append(data);
+    state.sink->Append(trailing_zeros, '0');
+    return;
+  }
+
+  auto padding =
+      ExtraWidthToPadding((state.sign_char != '\0' ? 1 : 0) + data.size() +
+                              static_cast<size_t>(trailing_zeros),
+                          state);
+
+  state.sink->Append(padding.left_spaces, ' ');
+  if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+  state.sink->Append(padding.zeros, '0');
+  state.sink->Append(data);
+  state.sink->Append(trailing_zeros, '0');
+  state.sink->Append(padding.right_spaces, ' ');
+}
+
+// Fastpath %f formatter for when the shifted value fits in a simple integral
+// type.
+// Prints `v*2^exp` with the options from `state`.
+template <typename Int>
+void FormatFFast(Int v, int exp, const FormatState &state) {
+  constexpr int input_bits = sizeof(Int) * 8;
+
+  static constexpr size_t integral_size =
+      /* in case we need to round up an extra digit */ 1 +
+      /* decimal digits for uint128 */ 40 + 1;
+  char buffer[integral_size + /* . */ 1 + /* max digits uint128 */ 128];
+  buffer[integral_size] = '.';
+  char *const integral_digits_end = buffer + integral_size;
+  char *integral_digits_start;
+  char *const fractional_digits_start = buffer + integral_size + 1;
+  char *fractional_digits_end = fractional_digits_start;
+
+  if (exp >= 0) {
+    const int total_bits = input_bits - LeadingZeros(v) + exp;
+    integral_digits_start =
+        total_bits <= 64
+            ? PrintIntegralDigitsFromRightFast(static_cast<uint64_t>(v) << exp,
+                                               integral_digits_end)
+            : PrintIntegralDigitsFromRightFast(static_cast<uint128>(v) << exp,
+                                               integral_digits_end);
+  } else {
+    exp = -exp;
+
+    integral_digits_start = PrintIntegralDigitsFromRightFast(
+        exp < input_bits ? v >> exp : 0, integral_digits_end);
+    // PrintFractionalDigits may pull a carried 1 all the way up through the
+    // integral portion.
+    integral_digits_start[-1] = '0';
+
+    fractional_digits_end =
+        exp <= 64 ? PrintFractionalDigitsFast(v, fractional_digits_start, exp,
+                                              state.precision)
+                  : PrintFractionalDigitsFast(static_cast<uint128>(v),
+                                              fractional_digits_start, exp,
+                                              state.precision);
+    // There was a carry, so include the first digit too.
+    if (integral_digits_start[-1] != '0') --integral_digits_start;
+  }
+
+  size_t size = fractional_digits_end - integral_digits_start;
+
+  // In `alt` mode (flag #) we keep the `.` even if there are no fractional
+  // digits. In non-alt mode, we strip it.
+  if (!state.ShouldPrintDot()) --size;
+  FinalPrint(absl::string_view(integral_digits_start, size),
+             static_cast<int>(state.precision - (fractional_digits_end -
+                                                 fractional_digits_start)),
+             state);
+}
+
+// Slow %f formatter for when the shifted value does not fit in a uint128, and
+// `exp > 0`.
+// Prints `v*2^exp` with the options from `state`.
+// This one is guaranteed to not have fractional digits, so we don't have to
+// worry about anything after the `.`.
+void FormatFPositiveExpSlow(uint128 v, int exp, const FormatState &state) {
+  BinaryToDecimal::RunConversion(v, exp, [&](BinaryToDecimal btd) {
+    const size_t total_digits =
+        btd.TotalDigits() +
+        (state.ShouldPrintDot() ? static_cast<size_t>(state.precision) + 1 : 0);
+
+    const auto padding = ExtraWidthToPadding(
+        total_digits + (state.sign_char != '\0' ? 1 : 0), state);
+
+    state.sink->Append(padding.left_spaces, ' ');
+    if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+    state.sink->Append(padding.zeros, '0');
+
+    do {
+      state.sink->Append(btd.CurrentDigits());
+    } while (btd.AdvanceDigits());
+
+    if (state.ShouldPrintDot()) state.sink->Append(1, '.');
+    state.sink->Append(state.precision, '0');
+    state.sink->Append(padding.right_spaces, ' ');
+  });
+}
+
+// Slow %f formatter for when the shifted value does not fit in a uint128, and
+// `exp < 0`.
+// Prints `v*2^exp` with the options from `state`.
+// This one is guaranteed to be < 1.0, so we don't have to worry about integral
+// digits.
+void FormatFNegativeExpSlow(uint128 v, int exp, const FormatState &state) {
+  const size_t total_digits =
+      /* 0 */ 1 +
+      (state.ShouldPrintDot() ? static_cast<size_t>(state.precision) + 1 : 0);
+  auto padding =
+      ExtraWidthToPadding(total_digits + (state.sign_char ? 1 : 0), state);
+  padding.zeros += 1;
+  state.sink->Append(padding.left_spaces, ' ');
+  if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+  state.sink->Append(padding.zeros, '0');
+
+  if (state.ShouldPrintDot()) state.sink->Append(1, '.');
+
+  // Print digits
+  int digits_to_go = state.precision;
+
+  FractionalDigitGenerator::RunConversion(
+      v, exp, [&](FractionalDigitGenerator digit_gen) {
+        // There are no digits to print here.
+        if (state.precision == 0) return;
+
+        // We go one digit at a time, while keeping track of runs of nines.
+        // The runs of nines are used to perform rounding when necessary.
+
+        while (digits_to_go > 0 && digit_gen.HasMoreDigits()) {
+          auto digits = digit_gen.GetDigits();
+
+          // Now we have a digit and a run of nines.
+          // See if we can print them all.
+          if (digits.num_nines + 1 < digits_to_go) {
+            // We don't have to round yet, so print them.
+            state.sink->Append(1, digits.digit_before_nine + '0');
+            state.sink->Append(digits.num_nines, '9');
+            digits_to_go -= digits.num_nines + 1;
+
+          } else {
+            // We can't print all the nines, see where we have to truncate.
+
+            bool round_up = false;
+            if (digits.num_nines + 1 > digits_to_go) {
+              // We round up at a nine. No need to print them.
+              round_up = true;
+            } else {
+              // We can fit all the nines, but truncate just after it.
+              if (digit_gen.IsGreaterThanHalf()) {
+                round_up = true;
+              } else if (digit_gen.IsExactlyHalf()) {
+                // Round to even
+                round_up =
+                    digits.num_nines != 0 || digits.digit_before_nine % 2 == 1;
+              }
+            }
+
+            if (round_up) {
+              state.sink->Append(1, digits.digit_before_nine + '1');
+              --digits_to_go;
+              // The rest will be zeros.
+            } else {
+              state.sink->Append(1, digits.digit_before_nine + '0');
+              state.sink->Append(digits_to_go - 1, '9');
+              digits_to_go = 0;
+            }
+            return;
+          }
+        }
+      });
+
+  state.sink->Append(digits_to_go, '0');
+  state.sink->Append(padding.right_spaces, ' ');
+}
+
+template <typename Int>
+void FormatF(Int mantissa, int exp, const FormatState &state) {
+  if (exp >= 0) {
+    const int total_bits = sizeof(Int) * 8 - LeadingZeros(mantissa) + exp;
+
+    // Fallback to the slow stack-based approach if we can't do it in a 64 or
+    // 128 bit state.
+    if (ABSL_PREDICT_FALSE(total_bits > 128)) {
+      return FormatFPositiveExpSlow(mantissa, exp, state);
+    }
+  } else {
+    // Fallback to the slow stack-based approach if we can't do it in a 64 or
+    // 128 bit state.
+    if (ABSL_PREDICT_FALSE(exp < -128)) {
+      return FormatFNegativeExpSlow(mantissa, -exp, state);
+    }
+  }
+  return FormatFFast(mantissa, exp, state);
+}
+
+char *CopyStringTo(absl::string_view v, char *out) {
   std::memcpy(out, v.data(), v.size());
   return out + v.size();
 }
 
 template <typename Float>
-bool FallbackToSnprintf(const Float v, const ConversionSpec &conv,
+bool FallbackToSnprintf(const Float v, const FormatConversionSpecImpl &conv,
                         FormatSinkImpl *sink) {
   int w = conv.width() >= 0 ? conv.width() : 0;
   int p = conv.precision() >= 0 ? conv.precision() : -1;
@@ -38,12 +679,12 @@
     assert(fp < fmt + sizeof(fmt));
   }
   std::string space(512, '\0');
-  string_view result;
+  absl::string_view result;
   while (true) {
     int n = snprintf(&space[0], space.size(), fmt, w, p, v);
     if (n < 0) return false;
     if (static_cast<size_t>(n) < space.size()) {
-      result = string_view(space.data(), n);
+      result = absl::string_view(space.data(), n);
       break;
     }
     space.resize(n + 1);
@@ -96,9 +737,10 @@
 // Otherwise, return false.
 template <typename Float>
 bool ConvertNonNumericFloats(char sign_char, Float v,
-                             const ConversionSpec &conv, FormatSinkImpl *sink) {
+                             const FormatConversionSpecImpl &conv,
+                             FormatSinkImpl *sink) {
   char text[4], *ptr = text;
-  if (sign_char) *ptr++ = sign_char;
+  if (sign_char != '\0') *ptr++ = sign_char;
   if (std::isnan(v)) {
     ptr = std::copy_n(
         FormatConversionCharIsUpper(conv.conversion_char()) ? "NAN" : "nan", 3,
@@ -172,7 +814,12 @@
 
 template <typename Float>
 struct Decomposed {
-  Float mantissa;
+  using MantissaType =
+      absl::conditional_t<std::is_same<long double, Float>::value, uint128,
+                          uint64_t>;
+  static_assert(std::numeric_limits<Float>::digits <= sizeof(MantissaType) * 8,
+                "");
+  MantissaType mantissa;
   int exponent;
 };
 
@@ -183,7 +830,8 @@
   Float m = std::frexp(v, &exp);
   m = std::ldexp(m, std::numeric_limits<Float>::digits);
   exp -= std::numeric_limits<Float>::digits;
-  return {m, exp};
+
+  return {static_cast<typename Decomposed<Float>::MantissaType>(m), exp};
 }
 
 // Print 'digits' as decimal.
@@ -352,8 +1000,9 @@
   return false;
 }
 
-void WriteBufferToSink(char sign_char, string_view str,
-                       const ConversionSpec &conv, FormatSinkImpl *sink) {
+void WriteBufferToSink(char sign_char, absl::string_view str,
+                       const FormatConversionSpecImpl &conv,
+                       FormatSinkImpl *sink) {
   int left_spaces = 0, zeros = 0, right_spaces = 0;
   int missing_chars =
       conv.width() >= 0 ? std::max(conv.width() - static_cast<int>(str.size()) -
@@ -369,14 +1018,14 @@
   }
 
   sink->Append(left_spaces, ' ');
-  if (sign_char) sink->Append(1, sign_char);
+  if (sign_char != '\0') sink->Append(1, sign_char);
   sink->Append(zeros, '0');
   sink->Append(str);
   sink->Append(right_spaces, ' ');
 }
 
 template <typename Float>
-bool FloatToSink(const Float v, const ConversionSpec &conv,
+bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv,
                  FormatSinkImpl *sink) {
   // Print the sign or the sign column.
   Float abs_v = v;
@@ -403,92 +1052,89 @@
 
   Buffer buffer;
 
-  switch (conv.conversion_char()) {
-    case ConversionChar::f:
-    case ConversionChar::F:
-      if (!FloatToBuffer<FormatStyle::Fixed>(decomposed, precision, &buffer,
-                                             nullptr)) {
-        return FallbackToSnprintf(v, conv, sink);
-      }
-      if (!conv.has_alt_flag() && buffer.back() == '.') buffer.pop_back();
-      break;
+  FormatConversionChar c = conv.conversion_char();
 
-    case ConversionChar::e:
-    case ConversionChar::E:
-      if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
-                                                 &exp)) {
-        return FallbackToSnprintf(v, conv, sink);
+  if (c == FormatConversionCharInternal::f ||
+      c == FormatConversionCharInternal::F) {
+    FormatF(decomposed.mantissa, decomposed.exponent,
+            {sign_char, precision, conv, sink});
+    return true;
+  } else if (c == FormatConversionCharInternal::e ||
+             c == FormatConversionCharInternal::E) {
+    if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
+                                               &exp)) {
+      return FallbackToSnprintf(v, conv, sink);
+    }
+    if (!conv.has_alt_flag() && buffer.back() == '.') buffer.pop_back();
+    PrintExponent(
+        exp, FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e',
+        &buffer);
+  } else if (c == FormatConversionCharInternal::g ||
+             c == FormatConversionCharInternal::G) {
+    precision = std::max(0, precision - 1);
+    if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
+                                               &exp)) {
+      return FallbackToSnprintf(v, conv, sink);
+    }
+    if (precision + 1 > exp && exp >= -4) {
+      if (exp < 0) {
+        // Have 1.23456, needs 0.00123456
+        // Move the first digit
+        buffer.begin[1] = *buffer.begin;
+        // Add some zeros
+        for (; exp < -1; ++exp) *buffer.begin-- = '0';
+        *buffer.begin-- = '.';
+        *buffer.begin = '0';
+      } else if (exp > 0) {
+        // Have 1.23456, needs 1234.56
+        // Move the '.' exp positions to the right.
+        std::rotate(buffer.begin + 1, buffer.begin + 2, buffer.begin + exp + 2);
       }
-      if (!conv.has_alt_flag() && buffer.back() == '.') buffer.pop_back();
+      exp = 0;
+    }
+    if (!conv.has_alt_flag()) {
+      while (buffer.back() == '0') buffer.pop_back();
+      if (buffer.back() == '.') buffer.pop_back();
+    }
+    if (exp) {
       PrintExponent(
           exp, FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e',
           &buffer);
-      break;
-
-    case ConversionChar::g:
-    case ConversionChar::G:
-      precision = std::max(0, precision - 1);
-      if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
-                                                 &exp)) {
-        return FallbackToSnprintf(v, conv, sink);
-      }
-      if (precision + 1 > exp && exp >= -4) {
-        if (exp < 0) {
-          // Have 1.23456, needs 0.00123456
-          // Move the first digit
-          buffer.begin[1] = *buffer.begin;
-          // Add some zeros
-          for (; exp < -1; ++exp) *buffer.begin-- = '0';
-          *buffer.begin-- = '.';
-          *buffer.begin = '0';
-        } else if (exp > 0) {
-          // Have 1.23456, needs 1234.56
-          // Move the '.' exp positions to the right.
-          std::rotate(buffer.begin + 1, buffer.begin + 2,
-                      buffer.begin + exp + 2);
-        }
-        exp = 0;
-      }
-      if (!conv.has_alt_flag()) {
-        while (buffer.back() == '0') buffer.pop_back();
-        if (buffer.back() == '.') buffer.pop_back();
-      }
-      if (exp) {
-        PrintExponent(
-            exp,
-            FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e',
-            &buffer);
-      }
-      break;
-
-    case ConversionChar::a:
-    case ConversionChar::A:
-      return FallbackToSnprintf(v, conv, sink);
-
-    default:
-      return false;
+    }
+  } else if (c == FormatConversionCharInternal::a ||
+             c == FormatConversionCharInternal::A) {
+    return FallbackToSnprintf(v, conv, sink);
+  } else {
+    return false;
   }
 
   WriteBufferToSink(sign_char,
-                    string_view(buffer.begin, buffer.end - buffer.begin), conv,
-                    sink);
+                    absl::string_view(buffer.begin, buffer.end - buffer.begin),
+                    conv, sink);
 
   return true;
 }
 
 }  // namespace
 
-bool ConvertFloatImpl(long double v, const ConversionSpec &conv,
+bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv,
+                      FormatSinkImpl *sink) {
+  if (std::numeric_limits<long double>::digits ==
+      2 * std::numeric_limits<double>::digits) {
+    // This is the `double-double` representation of `long double`.
+    // We do not handle it natively. Fallback to snprintf.
+    return FallbackToSnprintf(v, conv, sink);
+  }
+
+  return FloatToSink(v, conv, sink);
+}
+
+bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv,
                       FormatSinkImpl *sink) {
   return FloatToSink(v, conv, sink);
 }
 
-bool ConvertFloatImpl(float v, const ConversionSpec &conv,
-                      FormatSinkImpl *sink) {
-  return FloatToSink(v, conv, sink);
-}
-
-bool ConvertFloatImpl(double v, const ConversionSpec &conv,
+bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv,
                       FormatSinkImpl *sink) {
   return FloatToSink(v, conv, sink);
 }
diff --git a/absl/strings/internal/str_format/float_conversion.h b/absl/strings/internal/str_format/float_conversion.h
index 49a6a63..e78bc19 100644
--- a/absl/strings/internal/str_format/float_conversion.h
+++ b/absl/strings/internal/str_format/float_conversion.h
@@ -7,13 +7,13 @@
 ABSL_NAMESPACE_BEGIN
 namespace str_format_internal {
 
-bool ConvertFloatImpl(float v, const ConversionSpec &conv,
+bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv,
                       FormatSinkImpl *sink);
 
-bool ConvertFloatImpl(double v, const ConversionSpec &conv,
+bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv,
                       FormatSinkImpl *sink);
 
-bool ConvertFloatImpl(long double v, const ConversionSpec &conv,
+bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv,
                       FormatSinkImpl *sink);
 
 }  // namespace str_format_internal
diff --git a/absl/strings/internal/str_format/parser.cc b/absl/strings/internal/str_format/parser.cc
index aab68db..cc55dfa 100644
--- a/absl/strings/internal/str_format/parser.cc
+++ b/absl/strings/internal/str_format/parser.cc
@@ -17,7 +17,7 @@
 ABSL_NAMESPACE_BEGIN
 namespace str_format_internal {
 
-using CC = ConversionChar;
+using CC = FormatConversionCharInternal;
 using LM = LengthMod;
 
 ABSL_CONST_INIT const ConvTag kTags[256] = {
@@ -29,9 +29,9 @@
     {},    {},    {},    {},    {},    {},    {},    {},     // 28-2f
     {},    {},    {},    {},    {},    {},    {},    {},     // 30-37
     {},    {},    {},    {},    {},    {},    {},    {},     // 38-3f
-    {},    CC::A, {},    CC::C, {},    CC::E, CC::F, CC::G,  // @ABCDEFG
+    {},    CC::A, {},    {},    {},    CC::E, CC::F, CC::G,  // @ABCDEFG
     {},    {},    {},    {},    LM::L, {},    {},    {},     // HIJKLMNO
-    {},    {},    {},    CC::S, {},    {},    {},    {},     // PQRSTUVW
+    {},    {},    {},    {},    {},    {},    {},    {},     // PQRSTUVW
     CC::X, {},    {},    {},    {},    {},    {},    {},     // XYZ[\]^_
     {},    CC::a, {},    CC::c, CC::d, CC::e, CC::f, CC::g,  // `abcdefg
     LM::h, CC::i, LM::j, {},    LM::l, {},    CC::n, CC::o,  // hijklmno
@@ -296,15 +296,17 @@
   char* data_pos;
 };
 
-ParsedFormatBase::ParsedFormatBase(string_view format, bool allow_ignored,
-                                   std::initializer_list<Conv> convs)
+ParsedFormatBase::ParsedFormatBase(
+    string_view format, bool allow_ignored,
+    std::initializer_list<FormatConversionCharSet> convs)
     : data_(format.empty() ? nullptr : new char[format.size()]) {
   has_error_ = !ParseFormatString(format, ParsedFormatConsumer(this)) ||
                !MatchesConversions(allow_ignored, convs);
 }
 
 bool ParsedFormatBase::MatchesConversions(
-    bool allow_ignored, std::initializer_list<Conv> convs) const {
+    bool allow_ignored,
+    std::initializer_list<FormatConversionCharSet> convs) const {
   std::unordered_set<int> used;
   auto add_if_valid_conv = [&](int pos, char c) {
       if (static_cast<size_t>(pos) > convs.size() ||
diff --git a/absl/strings/internal/str_format/parser.h b/absl/strings/internal/str_format/parser.h
index 7d96651..fffed04 100644
--- a/absl/strings/internal/str_format/parser.h
+++ b/absl/strings/internal/str_format/parser.h
@@ -67,7 +67,7 @@
 
   Flags flags;
   LengthMod length_mod = LengthMod::none;
-  ConversionChar conv = FormatConversionChar::kNone;
+  FormatConversionChar conv = FormatConversionCharInternal::kNone;
 };
 
 // Consume conversion spec prefix (not including '%') of [p, end) if valid.
@@ -83,7 +83,7 @@
 // conversions.
 class ConvTag {
  public:
-  constexpr ConvTag(ConversionChar conversion_char)  // NOLINT
+  constexpr ConvTag(FormatConversionChar conversion_char)  // NOLINT
       : tag_(static_cast<int8_t>(conversion_char)) {}
   // We invert the length modifiers to make them negative so that we can easily
   // test for them.
@@ -94,9 +94,9 @@
 
   bool is_conv() const { return tag_ >= 0; }
   bool is_length() const { return tag_ < 0 && tag_ != -128; }
-  ConversionChar as_conv() const {
+  FormatConversionChar as_conv() const {
     assert(is_conv());
-    return static_cast<ConversionChar>(tag_);
+    return static_cast<FormatConversionChar>(tag_);
   }
   LengthMod as_length() const {
     assert(is_length());
@@ -186,8 +186,9 @@
 
 class ParsedFormatBase {
  public:
-  explicit ParsedFormatBase(string_view format, bool allow_ignored,
-                            std::initializer_list<Conv> convs);
+  explicit ParsedFormatBase(
+      string_view format, bool allow_ignored,
+      std::initializer_list<FormatConversionCharSet> convs);
 
   ParsedFormatBase(const ParsedFormatBase& other) { *this = other; }
 
@@ -234,8 +235,9 @@
  private:
   // Returns whether the conversions match and if !allow_ignored it verifies
   // that all conversions are used by the format.
-  bool MatchesConversions(bool allow_ignored,
-                          std::initializer_list<Conv> convs) const;
+  bool MatchesConversions(
+      bool allow_ignored,
+      std::initializer_list<FormatConversionCharSet> convs) const;
 
   struct ParsedFormatConsumer;
 
@@ -280,7 +282,7 @@
 // This is the only API that allows the user to pass a runtime specified format
 // string. These factory functions will return NULL if the format does not match
 // the conversions requested by the user.
-template <str_format_internal::Conv... C>
+template <FormatConversionCharSet... C>
 class ExtendedParsedFormat : public str_format_internal::ParsedFormatBase {
  public:
   explicit ExtendedParsedFormat(string_view format)
diff --git a/absl/strings/internal/str_format/parser_test.cc b/absl/strings/internal/str_format/parser_test.cc
index 51eb53f..5aced98 100644
--- a/absl/strings/internal/str_format/parser_test.cc
+++ b/absl/strings/internal/str_format/parser_test.cc
@@ -41,23 +41,23 @@
 
 TEST(ConversionCharTest, Names) {
   struct Expectation {
-    ConversionChar id;
+    FormatConversionChar id;
     char name;
   };
   // clang-format off
   const Expectation kExpect[] = {
-#define X(c) {ConversionChar::c, #c[0]}
-    X(c), X(C), X(s), X(S),                          // text
+#define X(c) {FormatConversionCharInternal::c, #c[0]}
+    X(c), X(s),                                      // text
     X(d), X(i), X(o), X(u), X(x), X(X),              // int
     X(f), X(F), X(e), X(E), X(g), X(G), X(a), X(A),  // float
     X(n), X(p),                                      // misc
 #undef X
-    {ConversionChar::kNone, '\0'},
+    {FormatConversionCharInternal::kNone, '\0'},
   };
   // clang-format on
   for (auto e : kExpect) {
     SCOPED_TRACE(e.name);
-    ConversionChar v = e.id;
+    FormatConversionChar v = e.id;
     EXPECT_EQ(e.name, FormatConversionCharToChar(v));
   }
 }
@@ -349,7 +349,8 @@
   ParsedFormatBase p2 = p1;  // copy construct (empty)
   EXPECT_EQ(SummarizeParsedFormat(p1), SummarizeParsedFormat(p2));
 
-  p1 = ParsedFormatBase("hello%s", true, {Conv::s});  // move assign
+  p1 = ParsedFormatBase("hello%s", true,
+                        {FormatConversionCharSetInternal::s});  // move assign
   EXPECT_EQ("[hello]{s:1$s}", SummarizeParsedFormat(p1));
 
   ParsedFormatBase p3 = p1;  // copy construct (nonempty)
@@ -367,7 +368,7 @@
 
 struct ExpectParse {
   const char* in;
-  std::initializer_list<Conv> conv_set;
+  std::initializer_list<FormatConversionCharSet> conv_set;
   const char* out;
 };
 
@@ -377,9 +378,9 @@
   const ExpectParse kExpect[] = {
       {"", {}, ""},
       {"ab", {}, "[ab]"},
-      {"a%d", {Conv::d}, "[a]{d:1$d}"},
-      {"a%+d", {Conv::d}, "[a]{+d:1$d}"},
-      {"a% d", {Conv::d}, "[a]{ d:1$d}"},
+      {"a%d", {FormatConversionCharSetInternal::d}, "[a]{d:1$d}"},
+      {"a%+d", {FormatConversionCharSetInternal::d}, "[a]{+d:1$d}"},
+      {"a% d", {FormatConversionCharSetInternal::d}, "[a]{ d:1$d}"},
       {"a%b %d", {}, "[a]!"},  // stop after error
   };
   for (const auto& e : kExpect) {
@@ -391,13 +392,13 @@
 
 TEST_F(ParsedFormatTest, ParsingFlagOrder) {
   const ExpectParse kExpect[] = {
-      {"a%+ 0d", {Conv::d}, "[a]{+ 0d:1$d}"},
-      {"a%+0 d", {Conv::d}, "[a]{+0 d:1$d}"},
-      {"a%0+ d", {Conv::d}, "[a]{0+ d:1$d}"},
-      {"a% +0d", {Conv::d}, "[a]{ +0d:1$d}"},
-      {"a%0 +d", {Conv::d}, "[a]{0 +d:1$d}"},
-      {"a% 0+d", {Conv::d}, "[a]{ 0+d:1$d}"},
-      {"a%+   0+d", {Conv::d}, "[a]{+   0+d:1$d}"},
+      {"a%+ 0d", {FormatConversionCharSetInternal::d}, "[a]{+ 0d:1$d}"},
+      {"a%+0 d", {FormatConversionCharSetInternal::d}, "[a]{+0 d:1$d}"},
+      {"a%0+ d", {FormatConversionCharSetInternal::d}, "[a]{0+ d:1$d}"},
+      {"a% +0d", {FormatConversionCharSetInternal::d}, "[a]{ +0d:1$d}"},
+      {"a%0 +d", {FormatConversionCharSetInternal::d}, "[a]{0 +d:1$d}"},
+      {"a% 0+d", {FormatConversionCharSetInternal::d}, "[a]{ 0+d:1$d}"},
+      {"a%+   0+d", {FormatConversionCharSetInternal::d}, "[a]{+   0+d:1$d}"},
   };
   for (const auto& e : kExpect) {
     SCOPED_TRACE(e.in);
diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc
index f0d1f0a..3f14dba 100644
--- a/absl/strings/str_format_test.cc
+++ b/absl/strings/str_format_test.cc
@@ -450,7 +450,7 @@
     if (conv.precision.is_from_arg()) {
       *out += "." + std::to_string(conv.precision.get_from_arg()) + "$*";
     }
-    *out += FormatConversionCharToChar(conv.conv);
+    *out += str_format_internal::FormatConversionCharToChar(conv.conv);
     *out += "}";
     return true;
   }
@@ -532,76 +532,103 @@
   EXPECT_FALSE((ParsedFormat<'s', 'd', 'g'>::New(format)));
 }
 
-using str_format_internal::Conv;
+using absl::str_format_internal::FormatConversionCharSet;
 
 TEST_F(ParsedFormatTest, UncheckedCorrect) {
-  auto f = ExtendedParsedFormat<Conv::d>::New("ABC%dDEF");
+  auto f = ExtendedParsedFormat<FormatConversionCharSet::d>::New("ABC%dDEF");
   ASSERT_TRUE(f);
   EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f));
 
   std::string format = "%sFFF%dZZZ%f";
-  auto f2 = ExtendedParsedFormat<Conv::kString, Conv::d, Conv::kFloating>::New(
-      format);
+  auto f2 =
+      ExtendedParsedFormat<FormatConversionCharSet::kString,
+                           FormatConversionCharSet::d,
+                           FormatConversionCharSet::kFloating>::New(format);
 
   ASSERT_TRUE(f2);
   EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
 
-  f2 = ExtendedParsedFormat<Conv::kString, Conv::d, Conv::kFloating>::New(
-      "%s %d %f");
+  f2 =
+      ExtendedParsedFormat<FormatConversionCharSet::kString,
+                           FormatConversionCharSet::d,
+                           FormatConversionCharSet::kFloating>::New("%s %d %f");
 
   ASSERT_TRUE(f2);
   EXPECT_EQ("{s:1$s}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
 
-  auto star = ExtendedParsedFormat<Conv::kStar, Conv::d>::New("%*d");
+  auto star = ExtendedParsedFormat<FormatConversionCharSet::kStar,
+                                   FormatConversionCharSet::d>::New("%*d");
   ASSERT_TRUE(star);
   EXPECT_EQ("{*d:2$1$*d}", SummarizeParsedFormat(*star));
 
-  auto dollar = ExtendedParsedFormat<Conv::d, Conv::s>::New("%2$s %1$d");
+  auto dollar =
+      ExtendedParsedFormat<FormatConversionCharSet::d,
+                           FormatConversionCharSet::s>::New("%2$s %1$d");
   ASSERT_TRUE(dollar);
   EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}", SummarizeParsedFormat(*dollar));
   // with reuse
-  dollar = ExtendedParsedFormat<Conv::d, Conv::s>::New("%2$s %1$d %1$d");
+  dollar =
+      ExtendedParsedFormat<FormatConversionCharSet::d,
+                           FormatConversionCharSet::s>::New("%2$s %1$d %1$d");
   ASSERT_TRUE(dollar);
   EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}[ ]{1$d:1$d}",
             SummarizeParsedFormat(*dollar));
 }
 
 TEST_F(ParsedFormatTest, UncheckedIgnoredArgs) {
-  EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("ABC")));
-  EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("%dABC")));
-  EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("ABC%2$s")));
-  auto f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("ABC");
+  EXPECT_FALSE((ExtendedParsedFormat<FormatConversionCharSet::d,
+                                     FormatConversionCharSet::s>::New("ABC")));
+  EXPECT_FALSE(
+      (ExtendedParsedFormat<FormatConversionCharSet::d,
+                            FormatConversionCharSet::s>::New("%dABC")));
+  EXPECT_FALSE(
+      (ExtendedParsedFormat<FormatConversionCharSet::d,
+                            FormatConversionCharSet::s>::New("ABC%2$s")));
+  auto f =
+      ExtendedParsedFormat<FormatConversionCharSet::d,
+                           FormatConversionCharSet::s>::NewAllowIgnored("ABC");
   ASSERT_TRUE(f);
   EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
-  f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("%dABC");
+  f = ExtendedParsedFormat<
+      FormatConversionCharSet::d,
+      FormatConversionCharSet::s>::NewAllowIgnored("%dABC");
   ASSERT_TRUE(f);
   EXPECT_EQ("{d:1$d}[ABC]", SummarizeParsedFormat(*f));
-  f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("ABC%2$s");
+  f = ExtendedParsedFormat<
+      FormatConversionCharSet::d,
+      FormatConversionCharSet::s>::NewAllowIgnored("ABC%2$s");
   ASSERT_TRUE(f);
   EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f));
 }
 
 TEST_F(ParsedFormatTest, UncheckedMultipleTypes) {
-  auto dx = ExtendedParsedFormat<Conv::d | Conv::x>::New("%1$d %1$x");
+  auto dx = ExtendedParsedFormat<FormatConversionCharSet::d |
+                                 FormatConversionCharSet::x>::New("%1$d %1$x");
   EXPECT_TRUE(dx);
   EXPECT_EQ("{1$d:1$d}[ ]{1$x:1$x}", SummarizeParsedFormat(*dx));
 
-  dx = ExtendedParsedFormat<Conv::d | Conv::x>::New("%1$d");
+  dx = ExtendedParsedFormat<FormatConversionCharSet::d |
+                            FormatConversionCharSet::x>::New("%1$d");
   EXPECT_TRUE(dx);
   EXPECT_EQ("{1$d:1$d}", SummarizeParsedFormat(*dx));
 }
 
 TEST_F(ParsedFormatTest, UncheckedIncorrect) {
-  EXPECT_FALSE(ExtendedParsedFormat<Conv::d>::New(""));
+  EXPECT_FALSE(ExtendedParsedFormat<FormatConversionCharSet::d>::New(""));
 
-  EXPECT_FALSE(ExtendedParsedFormat<Conv::d>::New("ABC%dDEF%d"));
+  EXPECT_FALSE(
+      ExtendedParsedFormat<FormatConversionCharSet::d>::New("ABC%dDEF%d"));
 
   std::string format = "%sFFF%dZZZ%f";
-  EXPECT_FALSE((ExtendedParsedFormat<Conv::s, Conv::d, Conv::g>::New(format)));
+  EXPECT_FALSE((ExtendedParsedFormat<FormatConversionCharSet::s,
+                                     FormatConversionCharSet::d,
+                                     FormatConversionCharSet::g>::New(format)));
 }
 
 TEST_F(ParsedFormatTest, RegressionMixPositional) {
-  EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::o>::New("%1$d %o")));
+  EXPECT_FALSE(
+      (ExtendedParsedFormat<FormatConversionCharSet::d,
+                            FormatConversionCharSet::o>::New("%1$d %o")));
 }
 
 using FormatWrapperTest = ::testing::Test;
diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h
index e7b4c1e..92c4723 100644
--- a/absl/strings/substitute.h
+++ b/absl/strings/substitute.h
@@ -50,7 +50,7 @@
 //
 // Supported types:
 //   * absl::string_view, std::string, const char* (null is equivalent to "")
-//   * int32_t, int64_t, uint32_t, uint64
+//   * int32_t, int64_t, uint32_t, uint64_t
 //   * float, double
 //   * bool (Printed as "true" or "false")
 //   * pointer types other than char* (Printed as "0x<lower case hex string>",
diff --git a/absl/synchronization/internal/create_thread_identity.cc b/absl/synchronization/internal/create_thread_identity.cc
index fa0070a..53a71b3 100644
--- a/absl/synchronization/internal/create_thread_identity.cc
+++ b/absl/synchronization/internal/create_thread_identity.cc
@@ -32,9 +32,9 @@
 
 // ThreadIdentity storage is persistent, we maintain a free-list of previously
 // released ThreadIdentity objects.
-static base_internal::SpinLock freelist_lock(
-    base_internal::kLinkerInitialized);
-static base_internal::ThreadIdentity* thread_identity_freelist;
+ABSL_CONST_INIT static base_internal::SpinLock freelist_lock(
+    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+ABSL_CONST_INIT static base_internal::ThreadIdentity* thread_identity_freelist;
 
 // A per-thread destructor for reclaiming associated ThreadIdentity objects.
 // Since we must preserve their storage we cache them for re-use.
diff --git a/absl/synchronization/internal/graphcycles.cc b/absl/synchronization/internal/graphcycles.cc
index 6a2bcdf..19f9aab 100644
--- a/absl/synchronization/internal/graphcycles.cc
+++ b/absl/synchronization/internal/graphcycles.cc
@@ -51,9 +51,9 @@
 
 // Avoid LowLevelAlloc's default arena since it calls malloc hooks in
 // which people are doing things like acquiring Mutexes.
-static absl::base_internal::SpinLock arena_mu(
-    absl::base_internal::kLinkerInitialized);
-static base_internal::LowLevelAlloc::Arena* arena;
+ABSL_CONST_INIT static absl::base_internal::SpinLock arena_mu(
+    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+ABSL_CONST_INIT static base_internal::LowLevelAlloc::Arena* arena;
 
 static void InitArenaIfNecessary() {
   arena_mu.Lock();
diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc
index 8cda5a1..1f8a696 100644
--- a/absl/synchronization/mutex.cc
+++ b/absl/synchronization/mutex.cc
@@ -207,12 +207,12 @@
 //------------------------------------------------------------------
 
 // Data for doing deadlock detection.
-static absl::base_internal::SpinLock deadlock_graph_mu(
-    absl::base_internal::kLinkerInitialized);
+ABSL_CONST_INIT static absl::base_internal::SpinLock deadlock_graph_mu(
+    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
 
-// graph used to detect deadlocks.
-static GraphCycles *deadlock_graph ABSL_GUARDED_BY(deadlock_graph_mu)
-    ABSL_PT_GUARDED_BY(deadlock_graph_mu);
+// Graph used to detect deadlocks.
+ABSL_CONST_INIT static GraphCycles *deadlock_graph
+    ABSL_GUARDED_BY(deadlock_graph_mu) ABSL_PT_GUARDED_BY(deadlock_graph_mu);
 
 //------------------------------------------------------------------
 // An event mechanism for debugging mutex use.
@@ -273,13 +273,12 @@
     {0, "SignalAll on "},
 };
 
-static absl::base_internal::SpinLock synch_event_mu(
-    absl::base_internal::kLinkerInitialized);
-// protects synch_event
+ABSL_CONST_INIT static absl::base_internal::SpinLock synch_event_mu(
+    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
 
 // Hash table size; should be prime > 2.
 // Can't be too small, as it's used for deadlock detection information.
-static const uint32_t kNSynchEvent = 1031;
+static constexpr uint32_t kNSynchEvent = 1031;
 
 static struct SynchEvent {     // this is a trivial hash table for the events
   // struct is freed when refcount reaches 0
diff --git a/absl/time/clock.cc b/absl/time/clock.cc
index 3b895c3..e5c423c 100644
--- a/absl/time/clock.cc
+++ b/absl/time/clock.cc
@@ -226,9 +226,9 @@
 
 // A reader-writer lock protecting the static locations below.
 // See SeqAcquire() and SeqRelease() above.
-static absl::base_internal::SpinLock lock(
-    absl::base_internal::kLinkerInitialized);
-static std::atomic<uint64_t> seq(0);
+ABSL_CONST_INIT static absl::base_internal::SpinLock lock(
+    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+ABSL_CONST_INIT static std::atomic<uint64_t> seq(0);
 
 // data from a sample of the kernel's time value
 struct TimeSampleAtomic {
diff --git a/absl/time/internal/cctz/src/cctz_benchmark.cc b/absl/time/internal/cctz/src/cctz_benchmark.cc
index d30a644..a402760 100644
--- a/absl/time/internal/cctz/src/cctz_benchmark.cc
+++ b/absl/time/internal/cctz/src/cctz_benchmark.cc
@@ -280,6 +280,7 @@
                                       "America/North_Dakota/Beulah",
                                       "America/North_Dakota/Center",
                                       "America/North_Dakota/New_Salem",
+                                      "America/Nuuk",
                                       "America/Ojinaga",
                                       "America/Panama",
                                       "America/Pangnirtung",
diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
index 35911ce..0b0c1a3 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -211,6 +211,7 @@
                                       "America/North_Dakota/Beulah",
                                       "America/North_Dakota/Center",
                                       "America/North_Dakota/New_Salem",
+                                      "America/Nuuk",
                                       "America/Ojinaga",
                                       "America/Panama",
                                       "America/Pangnirtung",
diff --git a/absl/time/internal/cctz/testdata/version b/absl/time/internal/cctz/testdata/version
index db18f83..7f680ee 100644
--- a/absl/time/internal/cctz/testdata/version
+++ b/absl/time/internal/cctz/testdata/version
@@ -1 +1 @@
-2019c
+2020a
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
index 245f4eb..d39016b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun b/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
index a91f65f..066fbed 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson b/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson
index db9cead..2b6c3ee 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Nuuk b/absl/time/internal/cctz/testdata/zoneinfo/America/Nuuk
new file mode 100644
index 0000000..0160308
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Nuuk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse b/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse
index fb3cd71..062b58c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing
index 3c0bef2..91f6f8b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking
index 3c0bef2..91f6f8b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin
index 3c0bef2..91f6f8b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai
index 3c0bef2..91f6f8b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon
index fb3cd71..062b58c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/PRC b/absl/time/internal/cctz/testdata/zoneinfo/PRC
index 3c0bef2..91f6f8b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/PRC
+++ b/absl/time/internal/cctz/testdata/zoneinfo/PRC
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab b/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
index 822ffa1..53ee77e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
+++ b/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
@@ -128,8 +128,8 @@
 CA	+5946-12014	America/Dawson_Creek	MST - BC (Dawson Cr, Ft St John)
 CA	+5848-12242	America/Fort_Nelson	MST - BC (Ft Nelson)
 CA	+4916-12307	America/Vancouver	Pacific - BC (most areas)
-CA	+6043-13503	America/Whitehorse	Pacific - Yukon (south)
-CA	+6404-13925	America/Dawson	Pacific - Yukon (north)
+CA	+6043-13503	America/Whitehorse	Pacific - Yukon (east)
+CA	+6404-13925	America/Dawson	Pacific - Yukon (west)
 CC	-1210+09655	Indian/Cocos
 CH,DE,LI	+4723+00832	Europe/Zurich	Swiss time
 CI,BF,GM,GN,ML,MR,SH,SL,SN,TG	+0519-00402	Africa/Abidjan
@@ -173,7 +173,7 @@
 GF	+0456-05220	America/Cayenne
 GH	+0533-00013	Africa/Accra
 GI	+3608-00521	Europe/Gibraltar
-GL	+6411-05144	America/Godthab	Greenland (most areas)
+GL	+6411-05144	America/Nuuk	Greenland (most areas)
 GL	+7646-01840	America/Danmarkshavn	National Park (east coast)
 GL	+7029-02158	America/Scoresbysund	Scoresbysund/Ittoqqortoormiit
 GL	+7634-06847	America/Thule	Thule/Pituffik
@@ -290,7 +290,7 @@
 RU	+5443+02030	Europe/Kaliningrad	MSK-01 - Kaliningrad
 RU	+554521+0373704	Europe/Moscow	MSK+00 - Moscow area
 # Mention RU and UA alphabetically.  See "territorial claims" above.
-RU,UA	+4457+03406	Europe/Simferopol	MSK+00 - Crimea
+RU,UA	+4457+03406	Europe/Simferopol	Crimea
 RU	+5836+04939	Europe/Kirov	MSK+00 - Kirov
 RU	+4621+04803	Europe/Astrakhan	MSK+01 - Astrakhan
 RU	+4844+04425	Europe/Volgograd	MSK+01 - Volgograd
@@ -341,8 +341,8 @@
 TV	-0831+17913	Pacific/Funafuti
 TW	+2503+12130	Asia/Taipei
 UA	+5026+03031	Europe/Kiev	Ukraine (most areas)
-UA	+4837+02218	Europe/Uzhgorod	Ruthenia
-UA	+4750+03510	Europe/Zaporozhye	Zaporozh'ye/Zaporizhia; Lugansk/Luhansk (east)
+UA	+4837+02218	Europe/Uzhgorod	Transcarpathia
+UA	+4750+03510	Europe/Zaporozhye	Zaporozhye and east Lugansk
 UM	+1917+16637	Pacific/Wake	Wake Island
 US	+404251-0740023	America/New_York	Eastern (most areas)
 US	+421953-0830245	America/Detroit	Eastern - MI (most areas)