about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--absl/BUILD.bazel7
-rw-r--r--absl/algorithm/container.h18
-rw-r--r--absl/algorithm/container_test.cc6
-rw-r--r--absl/base/BUILD.bazel16
-rw-r--r--absl/base/CMakeLists.txt9
-rw-r--r--absl/base/attributes.h1
-rw-r--r--absl/container/inlined_vector_exception_safety_test.cc4
-rw-r--r--absl/container/internal/common.h4
-rw-r--r--absl/container/internal/raw_hash_set.h11
-rw-r--r--absl/copts/configure_copts.bzl2
-rw-r--r--absl/debugging/CMakeLists.txt2
-rw-r--r--absl/debugging/internal/stack_consumption.cc12
-rw-r--r--absl/flags/BUILD.bazel3
-rw-r--r--absl/flags/flag.cc4
-rw-r--r--absl/flags/flag.h8
-rw-r--r--absl/flags/internal/commandlineflag.cc6
-rw-r--r--absl/flags/internal/commandlineflag.h24
-rw-r--r--absl/flags/internal/flag.h85
-rw-r--r--absl/flags/internal/registry.cc106
-rw-r--r--absl/random/BUILD.bazel2
-rw-r--r--absl/random/distribution_format_traits.h22
-rw-r--r--absl/random/distributions.h56
-rw-r--r--absl/random/internal/distributions.h30
-rw-r--r--absl/random/internal/uniform_helper.h12
-rw-r--r--absl/strings/BUILD.bazel1
-rw-r--r--absl/strings/CMakeLists.txt1
-rw-r--r--absl/strings/charconv_test.cc7
-rw-r--r--absl/strings/internal/charconv_parse.cc6
-rw-r--r--absl/strings/internal/str_format/convert_test.cc110
-rw-r--r--absl/strings/numbers_test.cc14
-rw-r--r--absl/strings/string_view.h62
-rw-r--r--absl/strings/string_view_test.cc23
-rw-r--r--absl/synchronization/internal/waiter.cc27
-rw-r--r--absl/synchronization/internal/waiter.h2
-rw-r--r--absl/synchronization/mutex.h2
-rw-r--r--absl/time/duration.cc5
-rw-r--r--absl/time/format.cc8
-rw-r--r--absl/time/internal/cctz/src/time_zone_impl.cc11
-rw-r--r--absl/time/time.cc14
-rw-r--r--absl/time/time.h9
-rw-r--r--absl/time/time_test.cc24
41 files changed, 485 insertions, 291 deletions
diff --git a/absl/BUILD.bazel b/absl/BUILD.bazel
index 853330d447eb..5a03acf87ca8 100644
--- a/absl/BUILD.bazel
+++ b/absl/BUILD.bazel
@@ -14,12 +14,15 @@
 # limitations under the License.
 #
 
+load(
+    ":compiler_config_setting.bzl",
+    "create_llvm_config",
+)
+
 package(default_visibility = ["//visibility:public"])
 
 licenses(["notice"])  # Apache 2.0
 
-load(":compiler_config_setting.bzl", "create_llvm_config")
-
 create_llvm_config(
     name = "llvm_compiler",
     visibility = [":__subpackages__"],
diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h
index c84de461ac28..adcea8a79995 100644
--- a/absl/algorithm/container.h
+++ b/absl/algorithm/container.h
@@ -112,6 +112,18 @@ template <class Key, class Hash, class KeyEqual, class Allocator>
 struct IsUnorderedContainer<std::unordered_set<Key, Hash, KeyEqual, Allocator>>
     : std::true_type {};
 
+// container_algorithm_internal::c_size. It is meant for internal use only.
+
+template <class C>
+auto c_size(C& c) -> decltype(c.size()) {
+  return c.size();
+}
+
+template <class T, std::size_t N>
+constexpr std::size_t c_size(T (&)[N]) {
+  return N;
+}
+
 }  // namespace container_algorithm_internal
 
 // PUBLIC API
@@ -365,7 +377,8 @@ c_mismatch(C1& c1, C2& c2, BinaryPredicate&& pred) {
 
 template <typename C1, typename C2>
 bool c_equal(const C1& c1, const C2& c2) {
-  return ((c1.size() == c2.size()) &&
+  return ((container_algorithm_internal::c_size(c1) ==
+           container_algorithm_internal::c_size(c2)) &&
           std::equal(container_algorithm_internal::c_begin(c1),
                      container_algorithm_internal::c_end(c1),
                      container_algorithm_internal::c_begin(c2)));
@@ -375,7 +388,8 @@ bool c_equal(const C1& c1, const C2& c2) {
 // the function's test condition.
 template <typename C1, typename C2, typename BinaryPredicate>
 bool c_equal(const C1& c1, const C2& c2, BinaryPredicate&& pred) {
-  return ((c1.size() == c2.size()) &&
+  return ((container_algorithm_internal::c_size(c1) ==
+           container_algorithm_internal::c_size(c2)) &&
           std::equal(container_algorithm_internal::c_begin(c1),
                      container_algorithm_internal::c_end(c1),
                      container_algorithm_internal::c_begin(c2),
diff --git a/absl/algorithm/container_test.cc b/absl/algorithm/container_test.cc
index 86bf9d3ea327..0a4abe946272 100644
--- a/absl/algorithm/container_test.cc
+++ b/absl/algorithm/container_test.cc
@@ -163,23 +163,29 @@ TEST_F(NonMutatingTest, MismatchWithPredicate) {
 TEST_F(NonMutatingTest, Equal) {
   EXPECT_TRUE(absl::c_equal(vector_, sequence_));
   EXPECT_TRUE(absl::c_equal(sequence_, vector_));
+  EXPECT_TRUE(absl::c_equal(sequence_, array_));
+  EXPECT_TRUE(absl::c_equal(array_, vector_));
 
   // Test that behavior appropriately differs from that of equal().
   std::vector<int> vector_plus = {1, 2, 3};
   vector_plus.push_back(4);
   EXPECT_FALSE(absl::c_equal(vector_plus, sequence_));
   EXPECT_FALSE(absl::c_equal(sequence_, vector_plus));
+  EXPECT_FALSE(absl::c_equal(array_, vector_plus));
 }
 
 TEST_F(NonMutatingTest, EqualWithPredicate) {
   EXPECT_TRUE(absl::c_equal(vector_, sequence_, Equals));
   EXPECT_TRUE(absl::c_equal(sequence_, vector_, Equals));
+  EXPECT_TRUE(absl::c_equal(array_, sequence_, Equals));
+  EXPECT_TRUE(absl::c_equal(vector_, array_, Equals));
 
   // Test that behavior appropriately differs from that of equal().
   std::vector<int> vector_plus = {1, 2, 3};
   vector_plus.push_back(4);
   EXPECT_FALSE(absl::c_equal(vector_plus, sequence_, Equals));
   EXPECT_FALSE(absl::c_equal(sequence_, vector_plus, Equals));
+  EXPECT_FALSE(absl::c_equal(vector_plus, array_, Equals));
 }
 
 TEST_F(NonMutatingTest, IsPermutation) {
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index 1e1f0d2de318..d74bac631a61 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -71,16 +71,16 @@ cc_library(
         "internal/spinlock_wait.cc",
         "internal/spinlock_win32.inc",
     ],
-    hdrs = [
-        "internal/scheduling_mode.h",
-        "internal/spinlock_wait.h",
-    ],
+    hdrs = ["internal/spinlock_wait.h"],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl/base:__pkg__",
     ],
-    deps = [":core_headers"],
+    deps = [
+        ":base_internal",
+        ":core_headers",
+    ],
 )
 
 cc_library(
@@ -141,11 +141,11 @@ cc_library(
     ],
     deps = [
         ":base",
+        ":base_internal",
         ":config",
         ":core_headers",
         ":dynamic_annotations",
         ":raw_logging_internal",
-        ":spinlock_wait",
     ],
 )
 
@@ -369,8 +369,8 @@ cc_library(
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":base",
+        ":base_internal",
         ":core_headers",
-        ":spinlock_wait",
         "//absl/synchronization",
         "@com_google_googletest//:gtest",
     ],
@@ -385,8 +385,8 @@ cc_test(
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":base",
+        ":base_internal",
         ":core_headers",
-        ":spinlock_wait",
         "//absl/synchronization",
         "@com_google_googletest//:gtest_main",
     ],
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index 51705a5a102c..79ee5b93ed71 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -56,7 +56,6 @@ absl_cc_library(
   NAME
     spinlock_wait
   HDRS
-    "internal/scheduling_mode.h"
     "internal/spinlock_wait.h"
   SRCS
     "internal/spinlock_akaros.inc"
@@ -67,6 +66,7 @@ absl_cc_library(
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
+    absl::base_internal
     absl::core_headers
 )
 
@@ -125,11 +125,11 @@ absl_cc_library(
     ${ABSL_DEFAULT_COPTS}
   DEPS
     absl::base
+    absl::base_internal
     absl::config
     absl::core_headers
     absl::dynamic_annotations
     absl::raw_logging_internal
-    absl::spinlock_wait
     Threads::Threads
 )
 
@@ -141,6 +141,7 @@ absl_cc_library(
     "internal/identity.h"
     "internal/inline_variable.h"
     "internal/invoke.h"
+    "internal/scheduling_mode.h"
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
@@ -348,8 +349,8 @@ absl_cc_library(
     ${ABSL_TEST_COPTS}
   DEPS
     absl::base
+    absl::base_internal
     absl::core_headers
-    absl::spinlock_wait
     absl::synchronization
     gtest
   TESTONLY
@@ -365,8 +366,8 @@ absl_cc_test(
     ${ABSL_TEST_COPTS}
   DEPS
     absl::base
+    absl::base_internal
     absl::core_headers
-    absl::spinlock_wait
     absl::synchronization
     gtest_main
 )
diff --git a/absl/base/attributes.h b/absl/base/attributes.h
index f298297e9942..7b7656a859b8 100644
--- a/absl/base/attributes.h
+++ b/absl/base/attributes.h
@@ -599,7 +599,6 @@
 //
 // Note that this attribute is redundant if the variable is declared constexpr.
 #if ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
-// NOLINTNEXTLINE(whitespace/braces)
 #define ABSL_CONST_INIT [[clang::require_constant_initialization]]
 #else
 #define ABSL_CONST_INIT
diff --git a/absl/container/inlined_vector_exception_safety_test.cc b/absl/container/inlined_vector_exception_safety_test.cc
index 25994f1685a2..937e43a5bf21 100644
--- a/absl/container/inlined_vector_exception_safety_test.cc
+++ b/absl/container/inlined_vector_exception_safety_test.cc
@@ -16,7 +16,7 @@
 
 #include "absl/base/config.h"
 
-#ifdef ABSL_HAVE_EXCEPTIONS
+#if defined(ABSL_HAVE_EXCEPTIONS)
 
 #include <array>
 #include <initializer_list>
@@ -493,4 +493,4 @@ TYPED_TEST(TwoSizeTest, Swap) {
 
 }  // namespace
 
-#endif  // ABSL_HAVE_EXCEPTIONS
+#endif  // defined(ABSL_HAVE_EXCEPTIONS)
diff --git a/absl/container/internal/common.h b/absl/container/internal/common.h
index 591d3ea11fa2..4bd5d469746b 100644
--- a/absl/container/internal/common.h
+++ b/absl/container/internal/common.h
@@ -117,7 +117,7 @@ class node_handle_base {
 template <typename Policy, typename PolicyTraits, typename Alloc,
           typename = void>
 class node_handle : public node_handle_base<PolicyTraits, Alloc> {
-  using Base = typename node_handle::node_handle_base;
+  using Base = node_handle_base<PolicyTraits, Alloc>;
 
  public:
   using value_type = typename PolicyTraits::value_type;
@@ -137,7 +137,7 @@ template <typename Policy, typename PolicyTraits, typename Alloc>
 class node_handle<Policy, PolicyTraits, Alloc,
                   absl::void_t<typename Policy::mapped_type>>
     : public node_handle_base<PolicyTraits, Alloc> {
-  using Base = typename node_handle::node_handle_base;
+  using Base = node_handle_base<PolicyTraits, Alloc>;
 
  public:
   using key_type = typename Policy::key_type;
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index 2e6f4dd3e66e..42b3c4681133 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -938,8 +938,11 @@ class raw_hash_set {
   //
   //   flat_hash_map<std::string, int> m;
   //   m.insert(std::make_pair("abc", 42));
+  // TODO(cheshire): A type alias T2 is introduced as a workaround for the nvcc
+  // bug.
   template <class T, RequiresInsertable<T> = 0,
-            typename std::enable_if<IsDecomposable<T>::value, int>::type = 0,
+            class T2 = T,
+            typename std::enable_if<IsDecomposable<T2>::value, int>::type = 0,
             T* = nullptr>
   std::pair<iterator, bool> insert(T&& value) {
     return emplace(std::forward<T>(value));
@@ -975,8 +978,10 @@ class raw_hash_set {
     return emplace(std::move(value));
   }
 
-  template <class T, RequiresInsertable<T> = 0,
-            typename std::enable_if<IsDecomposable<T>::value, int>::type = 0,
+  // TODO(cheshire): A type alias T2 is introduced as a workaround for the nvcc
+  // bug.
+  template <class T, RequiresInsertable<T> = 0, class T2 = T,
+            typename std::enable_if<IsDecomposable<T2>::value, int>::type = 0,
             T* = nullptr>
   iterator insert(const_iterator, T&& value) {
     return insert(std::forward<T>(value)).first;
diff --git a/absl/copts/configure_copts.bzl b/absl/copts/configure_copts.bzl
index 2829e4ec6e6f..9dd6bd0ae4fe 100644
--- a/absl/copts/configure_copts.bzl
+++ b/absl/copts/configure_copts.bzl
@@ -6,6 +6,8 @@ change Abseil copts, edit absl/copts/copts.py
 
 load(
     "//absl:copts/GENERATED_copts.bzl",
+    "ABSL_CLANG_CL_FLAGS",
+    "ABSL_CLANG_CL_TEST_FLAGS",
     "ABSL_GCC_FLAGS",
     "ABSL_GCC_TEST_FLAGS",
     "ABSL_LLVM_FLAGS",
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt
index c409e33e39c6..81492c0c0f30 100644
--- a/absl/debugging/CMakeLists.txt
+++ b/absl/debugging/CMakeLists.txt
@@ -238,7 +238,7 @@ absl_cc_test(
   SRCS
     "leak_check_test.cc"
   COPTS
-    ${ABSL_DEFAULT_COPTS}
+    ${ABSL_TEST_COPTS}
     "$<$<BOOL:${ABSL_HAVE_LSAN}>:-DABSL_EXPECT_LEAK_SANITIZER>"
   LINKOPTS
     "${ABSL_LSAN_LINKOPTS}"
diff --git a/absl/debugging/internal/stack_consumption.cc b/absl/debugging/internal/stack_consumption.cc
index 4b05f4955ee0..d4703264a666 100644
--- a/absl/debugging/internal/stack_consumption.cc
+++ b/absl/debugging/internal/stack_consumption.cc
@@ -115,10 +115,11 @@ int GetSignalHandlerStackConsumption(void (*signal_handler)(int)) {
   // Set up the alt-signal-stack (and save the older one).
   stack_t sigstk;
   memset(&sigstk, 0, sizeof(sigstk));
-  stack_t old_sigstk;
   sigstk.ss_sp = altstack;
   sigstk.ss_size = kAlternateStackSize;
   sigstk.ss_flags = 0;
+  stack_t old_sigstk;
+  memset(&old_sigstk, 0, sizeof(old_sigstk));
   ABSL_RAW_CHECK(sigaltstack(&sigstk, &old_sigstk) == 0,
                  "sigaltstack() failed");
 
@@ -152,6 +153,15 @@ int GetSignalHandlerStackConsumption(void (*signal_handler)(int)) {
   int signal_handler_stack_consumption = GetStackConsumption(altstack);
 
   // Now restore the old alt-signal-stack and signal handlers.
+  if (old_sigstk.ss_sp == nullptr && old_sigstk.ss_size == 0 &&
+      (old_sigstk.ss_flags & SS_DISABLE)) {
+    // https://git.musl-libc.org/cgit/musl/commit/src/signal/sigaltstack.c?id=7829f42a2c8944555439380498ab8b924d0f2070
+    // The original stack has ss_size==0 and ss_flags==SS_DISABLE, but some
+    // versions of musl have a bug that rejects ss_size==0. Work around this by
+    // setting ss_size to MINSIGSTKSZ, which should be ignored by the kernel
+    // when SS_DISABLE is set.
+    old_sigstk.ss_size = MINSIGSTKSZ;
+  }
   ABSL_RAW_CHECK(sigaltstack(&old_sigstk, nullptr) == 0,
                  "sigaltstack() failed");
   ABSL_RAW_CHECK(sigaction(SIGUSR1, &old_sa1, nullptr) == 0,
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel
index 2bf562f898c7..2e0dc3891f56 100644
--- a/absl/flags/BUILD.bazel
+++ b/absl/flags/BUILD.bazel
@@ -40,6 +40,8 @@ cc_library(
     deps = [
         ":handle",
         ":registry",
+        "//absl/memory",
+        "//absl/strings",
         "//absl/synchronization",
     ],
 )
@@ -184,6 +186,7 @@ cc_library(
         ":marshalling",
         "//absl/base",
         "//absl/base:core_headers",
+        "//absl/memory",
         "//absl/strings",
     ],
 )
diff --git a/absl/flags/flag.cc b/absl/flags/flag.cc
index a02d069e9b00..69038bbf48a0 100644
--- a/absl/flags/flag.cc
+++ b/absl/flags/flag.cc
@@ -49,9 +49,7 @@ namespace flags_internal {
 
 ABSL_CONST_INIT static absl::Mutex construction_guard(absl::kConstInit);
 
-void LockGlobalConstructionGuard() { construction_guard.Lock(); }
-
-void UnlockGlobalConstructionGuard() { construction_guard.Unlock(); }
+absl::Mutex* GetGlobalConstructionGuard() { return &construction_guard; }
 
 }  // namespace flags_internal
 
diff --git a/absl/flags/flag.h b/absl/flags/flag.h
index 86ad59dd9f16..4927757b8fbe 100644
--- a/absl/flags/flag.h
+++ b/absl/flags/flag.h
@@ -80,8 +80,7 @@ using Flag = flags_internal::Flag<T>;
 // if two threads attempt to construct the flag concurrently only one wins.
 
 namespace flags_internal {
-void LockGlobalConstructionGuard();
-void UnlockGlobalConstructionGuard();
+absl::Mutex* GetGlobalConstructionGuard();
 }  // namespace flags_internal
 
 template <typename T>
@@ -100,7 +99,7 @@ class Flag {
 
   flags_internal::Flag<T>* GetImpl() const {
     if (!inited_.load(std::memory_order_acquire)) {
-      flags_internal::LockGlobalConstructionGuard();
+      absl::MutexLock l(flags_internal::GetGlobalConstructionGuard());
 
       if (inited_.load(std::memory_order_acquire)) {
         return impl_;
@@ -109,8 +108,6 @@ class Flag {
       impl_ = new flags_internal::Flag<T>(name_, help_gen_, filename_,
                                           marshalling_op_, initial_value_gen_);
       inited_.store(true, std::memory_order_release);
-
-      flags_internal::UnlockGlobalConstructionGuard();
     }
 
     return impl_;
@@ -130,7 +127,6 @@ class Flag {
   std::string Filename() const { return GetImpl()->Filename(); }
   std::string DefaultValue() const { return GetImpl()->DefaultValue(); }
   std::string CurrentValue() const { return GetImpl()->CurrentValue(); }
-  bool HasValidatorFn() const { return GetImpl()->HasValidatorFn(); }
   bool InvokeValidator(const void* value) const {
     return GetImpl()->InvokeValidator(value);
   }
diff --git a/absl/flags/internal/commandlineflag.cc b/absl/flags/internal/commandlineflag.cc
index 53e2b84ecc13..99f73611d8f1 100644
--- a/absl/flags/internal/commandlineflag.cc
+++ b/absl/flags/internal/commandlineflag.cc
@@ -149,6 +149,12 @@ std::string CommandLineFlag::CurrentValue() const {
   return Unparse(marshalling_op_, cur_);
 }
 
+int64_t CommandLineFlag::MutationCounter() const {
+  absl::MutexLock l(InitFlagIfNecessary());
+
+  return counter_;
+}
+
 // Attempts to parse supplied `value` string using parsing routine in the `flag`
 // argument. If parsing is successful, it will try to validate that the parsed
 // value is valid for the specified 'flag'. Finally this function stores the
diff --git a/absl/flags/internal/commandlineflag.h b/absl/flags/internal/commandlineflag.h
index 284286b6be18..528d3106bfa8 100644
--- a/absl/flags/internal/commandlineflag.h
+++ b/absl/flags/internal/commandlineflag.h
@@ -17,6 +17,7 @@
 #define ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
 
 #include <atomic>
+#include <memory>
 
 #include "absl/base/macros.h"
 #include "absl/flags/marshalling.h"
@@ -186,6 +187,16 @@ class HelpText {
   const char* help_message_;
 };
 
+// Handle to FlagState objects. Specific flag state objects will restore state
+// of a flag produced this flag state from method CommandLineFlag::SaveState().
+class FlagStateInterface {
+ public:
+  virtual ~FlagStateInterface() {}
+
+  // Restores the flag originated this object to the saved state.
+  virtual void Restore() const = 0;
+};
+
 // Holds all information for a flag.
 class CommandLineFlag {
  public:
@@ -239,7 +250,6 @@ class CommandLineFlag {
   virtual void StoreAtomic() {}
 
   // Interfaces to operate on validators.
-  virtual bool HasValidatorFn() const { return false; }
   virtual bool InvokeValidator(const void* /*value*/) const { return true; }
   // Invoke the flag validators for old flags.
   // TODO(rogeeff): implement proper validators for Abseil Flags
@@ -264,6 +274,10 @@ class CommandLineFlag {
     return res;
   }
 
+  // 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;
+
   // Interfaces to overate on callbacks.
   virtual void InvokeCallback() {}
 
@@ -285,6 +299,9 @@ class CommandLineFlag {
  protected:
   ~CommandLineFlag() = default;
 
+  // Thread safe access to mutation counter.
+  int64_t MutationCounter() const;
+
   const char* const name_;
   const HelpText help_;
   const char* const filename_;
@@ -323,11 +340,6 @@ class CommandLineFlag {
   friend bool TryParseLocked(CommandLineFlag* flag, void* dst,
                              absl::string_view value, std::string* err);
   friend absl::Mutex* InitFlag(CommandLineFlag* flag);
-
-  // This is a short term, until we completely rework persistent state
-  // storage API.
-  virtual void* GetValidator() const { return nullptr; }
-  virtual bool SetValidator(void*) { return false; }
 };
 
 // Update any copy of the flag value that is stored in an atomic word.
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index 16330380f548..2b21c4407363 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -20,12 +20,44 @@
 
 #include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/registry.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/str_cat.h"
 
 namespace absl {
 namespace flags_internal {
 
 constexpr int64_t AtomicInit() { return 0xababababababababll; }
 
+template <typename T>
+class Flag;
+
+template <typename T>
+class FlagState : public flags_internal::FlagStateInterface {
+ public:
+  FlagState(Flag<T>* flag, T&& cur, bool modified, bool on_command_line,
+            int64_t counter)
+      : flag_(flag),
+        cur_value_(std::move(cur)),
+        modified_(modified),
+        on_command_line_(on_command_line),
+        counter_(counter) {}
+
+  ~FlagState() override = default;
+
+ private:
+  friend class Flag<T>;
+
+  // Restores the flag to the saved state.
+  void Restore() const override;
+
+  // Flag and saved flag data.
+  Flag<T>* flag_;
+  T cur_value_;
+  bool modified_;
+  bool on_command_line_;
+  int64_t counter_;
+};
+
 // Signature for the mutation callback used by watched Flags
 // The callback is noexcept.
 // TODO(rogeeff): add noexcept after C++17 support is added.
@@ -98,15 +130,12 @@ class Flag final : public flags_internal::CommandLineFlag {
 
     InvokeCallback();
   }
-  void InvokeCallback() override
-      ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
-    flags_internal::InvokeCallback(&locks_->primary_mu, &locks_->callback_mu,
-                                   callback_);
-  }
 
  private:
+  friend class FlagState<T>;
+
   void Destroy() const override {
-    // Values are heap allocated Abseil Flags.
+    // Values are heap allocated for Abseil Flags.
     if (cur_) Delete(op_, cur_);
     if (def_) Delete(op_, def_);
 
@@ -121,6 +150,41 @@ class Flag final : public flags_internal::CommandLineFlag {
     }
   }
 
+  // Interfaces to save and restore flags to/from persistent state.
+  // Returns current flag state or nullptr if flag does not support
+  // saving and restoring a state.
+  std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override {
+    T curr_value = Get();
+
+    absl::MutexLock l(InitFlagIfNecessary());
+
+    return absl::make_unique<flags_internal::FlagState<T>>(
+        this, std::move(curr_value), modified_, on_command_line_, counter_);
+  }
+
+  // Restores the flag state to the supplied state object. If there is
+  // nothing to restore returns false. Otherwise returns true.
+  bool RestoreState(const flags_internal::FlagState<T>& flag_state) {
+    if (MutationCounter() == flag_state.counter_) return false;
+
+    Set(flag_state.cur_value_);
+
+    // Race condition here? This should disappear once we move the rest of the
+    // flag's data into Flag's internals.
+
+    absl::MutexLock l(InitFlagIfNecessary());
+    modified_ = flag_state.modified_;
+    on_command_line_ = flag_state.on_command_line_;
+    return true;
+  }
+
+  // Interfaces to overate on callbacks.
+  void InvokeCallback() override
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
+    flags_internal::InvokeCallback(&locks_->primary_mu, &locks_->callback_mu,
+                                   callback_);
+  }
+
   // Flag's data
   // For some types, a copy of the current value is kept in an atomically
   // accessible field.
@@ -128,6 +192,15 @@ class Flag final : public flags_internal::CommandLineFlag {
   FlagCallback callback_;  // Mutation callback
 };
 
+template <typename T>
+inline void FlagState<T>::Restore() const {
+  if (flag_->RestoreState(*this)) {
+    ABSL_INTERNAL_LOG(INFO,
+                      absl::StrCat("Restore saved value of ", flag_->Name(),
+                                   " to: ", flag_->CurrentValue()));
+  }
+}
+
 // This class facilitates Flag object registration and tail expression-based
 // flag definition, for example:
 // ABSL_FLAG(int, foo, 42, "Foo help").OnUpdate(NotifyFooWatcher);
diff --git a/absl/flags/internal/registry.cc b/absl/flags/internal/registry.cc
index 4bea313bb1eb..6b2564d13a78 100644
--- a/absl/flags/internal/registry.cc
+++ b/absl/flags/internal/registry.cc
@@ -188,114 +188,34 @@ CommandLineFlag* FlagRegistry::FindRetiredFlagLocked(absl::string_view name) {
 
 class FlagSaverImpl {
  public:
-  // Constructs an empty FlagSaverImpl object.
-  FlagSaverImpl() {}
-  ~FlagSaverImpl() {
-    // reclaim memory from each of our CommandLineFlags
-    for (const SavedFlag& src : backup_registry_) {
-      Delete(src.op, src.current);
-      Delete(src.op, src.default_value);
-    }
-  }
+  FlagSaverImpl() = default;
+  FlagSaverImpl(const FlagSaverImpl&) = delete;
+  void operator=(const FlagSaverImpl&) = delete;
 
   // Saves the flag states from the flag registry into this object.
   // It's an error to call this more than once.
-  // Must be called when the registry mutex is not held.
   void SaveFromRegistry() {
     assert(backup_registry_.empty());  // call only once!
-    SavedFlag saved;
     flags_internal::ForEachFlag([&](flags_internal::CommandLineFlag* flag) {
-      if (flag->IsRetired()) return;
-
-      saved.name = flag->Name();
-      saved.op = flag->op_;
-      saved.marshalling_op = flag->marshalling_op_;
-      {
-        absl::MutexLock l(flag->InitFlagIfNecessary());
-        saved.validator = flag->GetValidator();
-        saved.modified = flag->modified_;
-        saved.on_command_line = flag->on_command_line_;
-        saved.current = Clone(saved.op, flag->cur_);
-        saved.default_value = Clone(saved.op, flag->def_);
-        saved.counter = flag->counter_;
+      if (auto flag_state = flag->SaveState()) {
+        backup_registry_.emplace_back(std::move(flag_state));
       }
-      backup_registry_.push_back(saved);
     });
   }
 
-  // Restores the saved flag states into the flag registry.  We
-  // assume no flags were added or deleted from the registry since
-  // the SaveFromRegistry; if they were, that's trouble!  Must be
-  // called when the registry mutex is not held.
+  // Restores the saved flag states into the flag registry.
   void RestoreToRegistry() {
-    FlagRegistry* const global_registry = FlagRegistry::GlobalRegistry();
-    FlagRegistryLock frl(global_registry);
-    for (const SavedFlag& src : backup_registry_) {
-      CommandLineFlag* flag = global_registry->FindFlagLocked(src.name);
-      // If null, flag got deleted from registry.
-      if (!flag) continue;
-
-      bool restored = false;
-      {
-        // This function encapsulate the lock.
-        flag->SetValidator(src.validator);
-
-        absl::MutexLock l(flag->InitFlagIfNecessary());
-        flag->modified_ = src.modified;
-        flag->on_command_line_ = src.on_command_line;
-        if (flag->counter_ != src.counter ||
-            ChangedDirectly(flag, src.default_value, flag->def_)) {
-          restored = true;
-          Copy(src.op, src.default_value, flag->def_);
-        }
-        if (flag->counter_ != src.counter ||
-            ChangedDirectly(flag, src.current, flag->cur_)) {
-          restored = true;
-          Copy(src.op, src.current, flag->cur_);
-          UpdateCopy(flag);
-          flag->InvokeCallback();
-        }
-      }
-
-      if (restored) {
-        flag->counter_++;
-
-        // Revalidate the flag because the validator might store state based
-        // on the flag's value, which just changed due to the restore.
-        // Failing validation is ignored because it's assumed that the flag
-        // was valid previously and there's little that can be done about it
-        // here, anyway.
-        flag->ValidateInputValue(flag->CurrentValue());
-
-        ABSL_INTERNAL_LOG(
-            INFO, absl::StrCat("Restore saved value of ", flag->Name(), ": ",
-                               Unparse(src.marshalling_op, src.current)));
-      }
+    for (const auto& flag_state : backup_registry_) {
+      flag_state->Restore();
     }
   }
 
  private:
-  struct SavedFlag {
-    absl::string_view name;
-    FlagOpFn op;
-    FlagMarshallingOpFn marshalling_op;
-    int64_t counter;
-    void* validator;
-    bool modified;
-    bool on_command_line;
-    const void* current;        // nullptr after restore
-    const void* default_value;  // nullptr after restore
-  };
-
-  std::vector<SavedFlag> backup_registry_;
-
-  FlagSaverImpl(const FlagSaverImpl&);  // no copying!
-  void operator=(const FlagSaverImpl&);
+  std::vector<std::unique_ptr<flags_internal::FlagStateInterface>>
+      backup_registry_;
 };
 
-FlagSaver::FlagSaver() : impl_(new FlagSaverImpl()) {
-  impl_->SaveFromRegistry();
-}
+FlagSaver::FlagSaver() : impl_(new FlagSaverImpl) { impl_->SaveFromRegistry(); }
 
 void FlagSaver::Ignore() {
   delete impl_;
@@ -376,6 +296,10 @@ class RetiredFlagObj final : public flags_internal::CommandLineFlag {
 
     delete this;
   }
+
+  std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override {
+    return nullptr;
+  }
 };
 
 }  // namespace
diff --git a/absl/random/BUILD.bazel b/absl/random/BUILD.bazel
index c904618da2a0..92111827c150 100644
--- a/absl/random/BUILD.bazel
+++ b/absl/random/BUILD.bazel
@@ -26,7 +26,7 @@ load(
 
 package(default_visibility = ["//visibility:public"])
 
-licenses(["notice"])  # Apache 2.0
+licenses(["notice"])
 
 cc_library(
     name = "random",
diff --git a/absl/random/distribution_format_traits.h b/absl/random/distribution_format_traits.h
index 3298c2cdb64b..f9f070589f00 100644
--- a/absl/random/distribution_format_traits.h
+++ b/absl/random/distribution_format_traits.h
@@ -249,12 +249,12 @@ struct DistributionFormatTraits<absl::log_uniform_int_distribution<R>> {
   }
 };
 
-template <typename TagType, typename NumType>
+template <typename NumType>
 struct UniformDistributionWrapper;
 
-template <typename TagType, typename NumType>
-struct DistributionFormatTraits<UniformDistributionWrapper<TagType, NumType>> {
-  using distribution_t = UniformDistributionWrapper<TagType, NumType>;
+template <typename NumType>
+struct DistributionFormatTraits<UniformDistributionWrapper<NumType>> {
+  using distribution_t = UniformDistributionWrapper<NumType>;
   using result_t = NumType;
 
   static constexpr const char* Name() { return "Uniform"; }
@@ -263,19 +263,7 @@ struct DistributionFormatTraits<UniformDistributionWrapper<TagType, NumType>> {
     return absl::StrCat(Name(), "<", ScalarTypeName<NumType>(), ">");
   }
   static std::string FormatArgs(const distribution_t& d) {
-    absl::string_view tag;
-    if (std::is_same<TagType, IntervalClosedClosedTag>::value) {
-      tag = "IntervalClosedClosed";
-    } else if (std::is_same<TagType, IntervalClosedOpenTag>::value) {
-      tag = "IntervalClosedOpen";
-    } else if (std::is_same<TagType, IntervalOpenClosedTag>::value) {
-      tag = "IntervalOpenClosed";
-    } else if (std::is_same<TagType, IntervalOpenOpenTag>::value) {
-      tag = "IntervalOpenOpen";
-    } else {
-      tag = "[[unknown tag type]]";
-    }
-    return absl::StrCat(tag, ", ", (d.min)(), ", ", (d.max)());
+    return absl::StrCat((d.min)(), ", ", (d.max)());
   }
   static std::string FormatResults(absl::Span<const result_t> results) {
     return absl::StrJoin(results, ", ");
diff --git a/absl/random/distributions.h b/absl/random/distributions.h
index 3a4e93abfa2f..6ced60616158 100644
--- a/absl/random/distributions.h
+++ b/absl/random/distributions.h
@@ -124,7 +124,15 @@ Uniform(TagType tag,
         URBG&& urbg,  // NOLINT(runtime/references)
         R lo, R hi) {
   using gen_t = absl::decay_t<URBG>;
-  return random_internal::UniformImpl<R, TagType, gen_t>(tag, urbg, lo, hi);
+  using distribution_t = random_internal::UniformDistributionWrapper<R>;
+  using format_t = random_internal::DistributionFormatTraits<distribution_t>;
+
+  auto a = random_internal::uniform_lower_bound(tag, lo, hi);
+  auto b = random_internal::uniform_upper_bound(tag, lo, hi);
+  if (a > b) return a;
+
+  return random_internal::DistributionCaller<gen_t>::template Call<
+      distribution_t, format_t>(&urbg, tag, lo, hi);
 }
 
 // absl::Uniform<T>(bitgen, lo, hi)
@@ -135,11 +143,17 @@ template <typename R = void, typename URBG>
 typename absl::enable_if_t<!std::is_same<R, void>::value, R>  //
 Uniform(URBG&& urbg,  // NOLINT(runtime/references)
         R lo, R hi) {
-  constexpr auto tag = absl::IntervalClosedOpen;
-  using tag_t = decltype(tag);
   using gen_t = absl::decay_t<URBG>;
+  using distribution_t = random_internal::UniformDistributionWrapper<R>;
+  using format_t = random_internal::DistributionFormatTraits<distribution_t>;
+
+  constexpr auto tag = absl::IntervalClosedOpen;
+  auto a = random_internal::uniform_lower_bound(tag, lo, hi);
+  auto b = random_internal::uniform_upper_bound(tag, lo, hi);
+  if (a > b) return a;
 
-  return random_internal::UniformImpl<R, tag_t, gen_t>(tag, urbg, lo, hi);
+  return random_internal::DistributionCaller<gen_t>::template Call<
+      distribution_t, format_t>(&urbg, lo, hi);
 }
 
 // absl::Uniform(tag, bitgen, lo, hi)
@@ -156,9 +170,16 @@ Uniform(TagType tag,
         A lo, B hi) {
   using gen_t = absl::decay_t<URBG>;
   using return_t = typename random_internal::uniform_inferred_return_t<A, B>;
+  using distribution_t = random_internal::UniformDistributionWrapper<return_t>;
+  using format_t = random_internal::DistributionFormatTraits<distribution_t>;
 
-  return random_internal::UniformImpl<return_t, TagType, gen_t>(tag, urbg, lo,
-                                                                hi);
+  auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi);
+  auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi);
+  if (a > b) return a;
+
+  return random_internal::DistributionCaller<gen_t>::template Call<
+      distribution_t, format_t>(&urbg, tag, static_cast<return_t>(lo),
+                                static_cast<return_t>(hi));
 }
 
 // absl::Uniform(bitgen, lo, hi)
@@ -171,13 +192,19 @@ typename absl::enable_if_t<std::is_same<R, void>::value,
                            random_internal::uniform_inferred_return_t<A, B>>
 Uniform(URBG&& urbg,  // NOLINT(runtime/references)
         A lo, B hi) {
-  constexpr auto tag = absl::IntervalClosedOpen;
-  using tag_t = decltype(tag);
   using gen_t = absl::decay_t<URBG>;
   using return_t = typename random_internal::uniform_inferred_return_t<A, B>;
+  using distribution_t = random_internal::UniformDistributionWrapper<return_t>;
+  using format_t = random_internal::DistributionFormatTraits<distribution_t>;
 
-  return random_internal::UniformImpl<return_t, tag_t, gen_t>(tag, urbg, lo,
-                                                              hi);
+  constexpr auto tag = absl::IntervalClosedOpen;
+  auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi);
+  auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi);
+  if (a > b) return a;
+
+  return random_internal::DistributionCaller<gen_t>::template Call<
+      distribution_t, format_t>(&urbg, static_cast<return_t>(lo),
+                                static_cast<return_t>(hi));
 }
 
 // absl::Uniform<unsigned T>(bitgen)
@@ -187,13 +214,12 @@ Uniform(URBG&& urbg,  // NOLINT(runtime/references)
 template <typename R, typename URBG>
 typename absl::enable_if_t<!std::is_signed<R>::value, R>  //
 Uniform(URBG&& urbg) {  // NOLINT(runtime/references)
-  constexpr auto tag = absl::IntervalClosedClosed;
-  constexpr auto lo = std::numeric_limits<R>::lowest();
-  constexpr auto hi = (std::numeric_limits<R>::max)();
-  using tag_t = decltype(tag);
   using gen_t = absl::decay_t<URBG>;
+  using distribution_t = random_internal::UniformDistributionWrapper<R>;
+  using format_t = random_internal::DistributionFormatTraits<distribution_t>;
 
-  return random_internal::UniformImpl<R, tag_t, gen_t>(tag, urbg, lo, hi);
+  return random_internal::DistributionCaller<gen_t>::template Call<
+      distribution_t, format_t>(&urbg);
 }
 
 // -----------------------------------------------------------------------------
diff --git a/absl/random/internal/distributions.h b/absl/random/internal/distributions.h
index 96f8bae3918f..c8cec02b7fbc 100644
--- a/absl/random/internal/distributions.h
+++ b/absl/random/internal/distributions.h
@@ -24,36 +24,6 @@
 
 namespace absl {
 namespace random_internal {
-template <typename D>
-struct DistributionFormatTraits;
-
-// UniformImpl implements the core logic of the Uniform<T> call, which is to
-// select the correct distribution type, compute the bounds based on the
-// interval tag, and then generate a value.
-template <typename NumType, typename TagType, typename URBG>
-NumType UniformImpl(TagType tag,
-                    URBG& urbg,  // NOLINT(runtime/references)
-                    NumType lo, NumType hi) {
-  static_assert(
-      std::is_arithmetic<NumType>::value,
-      "absl::Uniform<T>() must use an integer or real parameter type.");
-
-  using distribution_t =
-      UniformDistributionWrapper<absl::decay_t<TagType>, NumType>;
-  using format_t = random_internal::DistributionFormatTraits<distribution_t>;
-  auto a = uniform_lower_bound(tag, lo, hi);
-  auto b = uniform_upper_bound(tag, lo, hi);
-
-  // TODO(lar): it doesn't make a lot of sense to ask for a random number in an
-  // empty range.  Right now we just return a boundary--even though that
-  // boundary is not an acceptable value!  Is there something better we can do
-  // here?
-  if (a > b) return a;
-
-  using gen_t = absl::decay_t<URBG>;
-  return DistributionCaller<gen_t>::template Call<distribution_t, format_t>(
-      &urbg, tag, lo, hi);
-}
 
 // In the absence of an explicitly provided return-type, the template
 // "uniform_inferred_return_t<A, B>" is used to derive a suitable type, based on
diff --git a/absl/random/internal/uniform_helper.h b/absl/random/internal/uniform_helper.h
index 2929407e1497..f68b1823ef00 100644
--- a/absl/random/internal/uniform_helper.h
+++ b/absl/random/internal/uniform_helper.h
@@ -154,12 +154,22 @@ using UniformDistribution =
                               absl::uniform_int_distribution<NumType>,
                               absl::uniform_real_distribution<NumType>>::type;
 
-template <typename TagType, typename NumType>
+template <typename NumType>
 struct UniformDistributionWrapper : public UniformDistribution<NumType> {
+  template <typename TagType>
   explicit UniformDistributionWrapper(TagType, NumType lo, NumType hi)
       : UniformDistribution<NumType>(
             uniform_lower_bound<NumType>(TagType{}, lo, hi),
             uniform_upper_bound<NumType>(TagType{}, lo, hi)) {}
+
+  explicit UniformDistributionWrapper(NumType lo, NumType hi)
+      : UniformDistribution<NumType>(
+            uniform_lower_bound<NumType>(IntervalClosedOpenTag(), lo, hi),
+            uniform_upper_bound<NumType>(IntervalClosedOpenTag(), lo, hi)) {}
+
+  explicit UniformDistributionWrapper()
+      : UniformDistribution<NumType>(std::numeric_limits<NumType>::lowest(),
+                                     (std::numeric_limits<NumType>::max)()) {}
 };
 
 }  // namespace random_internal
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
index 729bdd761f0f..4863ead2992e 100644
--- a/absl/strings/BUILD.bazel
+++ b/absl/strings/BUILD.bazel
@@ -630,6 +630,7 @@ cc_test(
     visibility = ["//visibility:private"],
     deps = [
         ":str_format_internal",
+        "//absl/base:raw_logging_internal",
         "//absl/numeric:int128",
         "@com_google_googletest//:gtest_main",
     ],
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt
index ccff44419341..3f9079575011 100644
--- a/absl/strings/CMakeLists.txt
+++ b/absl/strings/CMakeLists.txt
@@ -461,6 +461,7 @@ absl_cc_test(
     ${ABSL_TEST_COPTS}
   DEPS
     absl::str_format_internal
+    absl::raw_logging_internal
     absl::int128
     gmock_main
 )
diff --git a/absl/strings/charconv_test.cc b/absl/strings/charconv_test.cc
index b58fad269d8b..9090e9c89c50 100644
--- a/absl/strings/charconv_test.cc
+++ b/absl/strings/charconv_test.cc
@@ -511,6 +511,13 @@ TEST(FromChars, Overflow) {
   EXPECT_EQ(f, std::numeric_limits<float>::max());
 }
 
+TEST(FromChars, RegressionTestsFromFuzzer) {
+  absl::string_view src = "0x21900000p00000000099";
+  float f;
+  auto result = absl::from_chars(src.data(), src.data() + src.size(), f);
+  EXPECT_EQ(result.ec, std::errc::result_out_of_range);
+}
+
 TEST(FromChars, ReturnValuePtr) {
   // Check that `ptr` points one past the number scanned, even if that number
   // is not representable.
diff --git a/absl/strings/internal/charconv_parse.cc b/absl/strings/internal/charconv_parse.cc
index f3c7232403a1..fa9a8965fe6b 100644
--- a/absl/strings/internal/charconv_parse.cc
+++ b/absl/strings/internal/charconv_parse.cc
@@ -253,6 +253,12 @@ std::size_t ConsumeDigits(const char* begin, const char* end, int max_digits,
     assert(max_digits * 4 <= std::numeric_limits<T>::digits);
   }
   const char* const original_begin = begin;
+
+  // Skip leading zeros, but only if *out is zero.
+  // They don't cause an overflow so we don't have to count them for
+  // `max_digits`.
+  while (!*out && end != begin && *begin == '0') ++begin;
+
   T accumulator = *out;
   const char* significant_digits_end =
       (end - begin > max_digits) ? begin + max_digits : end;
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc
index 814ccf4c65e6..ab8d53914119 100644
--- a/absl/strings/internal/str_format/convert_test.cc
+++ b/absl/strings/internal/str_format/convert_test.cc
@@ -5,7 +5,9 @@
 #include <cmath>
 #include <string>
 
+#include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
 #include "absl/strings/internal/str_format/bind.h"
 
 namespace absl {
@@ -157,12 +159,20 @@ TEST_F(FormatConvertTest, StringPrecision) {
   EXPECT_EQ("ABC", FormatPack(format2, {FormatArgImpl(p)}));
 }
 
+// Pointer formatting is implementation defined. This checks that the argument
+// can be matched to `ptr`.
+MATCHER_P(MatchesPointerString, ptr, "") {
+  if (ptr == nullptr && arg == "(nil)") {
+    return true;
+  }
+  void* parsed = nullptr;
+  if (sscanf(arg.c_str(), "%p", &parsed) != 1) {
+    ABSL_RAW_LOG(FATAL, "Could not parse %s", arg.c_str());
+  }
+  return ptr == parsed;
+}
+
 TEST_F(FormatConvertTest, Pointer) {
-#ifdef _MSC_VER
-  // MSVC's printf implementation prints pointers differently. We can't easily
-  // compare our implementation to theirs.
-  return;
-#endif
   static int x = 0;
   const int *xp = &x;
   char c = 'h';
@@ -173,48 +183,62 @@ TEST_F(FormatConvertTest, Pointer) {
   using VoidF = void (*)();
   VoidF fp = [] {}, fnil = nullptr;
   volatile char vc;
-  volatile char* vcp = &vc;
-  volatile char* vcnil = nullptr;
-  const FormatArgImpl args[] = {
+  volatile char *vcp = &vc;
+  volatile char *vcnil = nullptr;
+  const FormatArgImpl args_array[] = {
       FormatArgImpl(xp),   FormatArgImpl(cp),  FormatArgImpl(inil),
       FormatArgImpl(cnil), FormatArgImpl(mcp), FormatArgImpl(fp),
       FormatArgImpl(fnil), FormatArgImpl(vcp), FormatArgImpl(vcnil),
   };
-  struct Expectation {
-    std::string out;
-    const char *fmt;
-  };
-  const Expectation kExpect[] = {
-      {StrPrint("%p", &x), "%p"},
-      {StrPrint("%20p", &x), "%20p"},
-      {StrPrint("%.1p", &x), "%.1p"},
-      {StrPrint("%.20p", &x), "%.20p"},
-      {StrPrint("%30.20p", &x), "%30.20p"},
-
-      {StrPrint("%-p", &x), "%-p"},
-      {StrPrint("%-20p", &x), "%-20p"},
-      {StrPrint("%-.1p", &x), "%-.1p"},
-      {StrPrint("%.20p", &x), "%.20p"},
-      {StrPrint("%-30.20p", &x), "%-30.20p"},
-
-      {StrPrint("%p", cp), "%2$p"},   // const char*
-      {"(nil)", "%3$p"},              // null const char *
-      {"(nil)", "%4$p"},              // null const int *
-      {StrPrint("%p", mcp), "%5$p"},  // nonconst char*
-
-      {StrPrint("%p", fp), "%6$p"},   // function pointer
-      {StrPrint("%p", vcp), "%8$p"},  // function pointer
-
-#ifndef __APPLE__
-      // Apple's printf differs here (0x0 vs. nil)
-      {StrPrint("%p", fnil), "%7$p"},   // null function pointer
-      {StrPrint("%p", vcnil), "%9$p"},  // null function pointer
-#endif
-  };
-  for (const Expectation &e : kExpect) {
-    UntypedFormatSpecImpl format(e.fmt);
-    EXPECT_EQ(e.out, FormatPack(format, absl::MakeSpan(args))) << e.fmt;
-  }
+  auto args = absl::MakeConstSpan(args_array);
+
+  EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%p"), args),
+              MatchesPointerString(&x));
+  EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%20p"), args),
+              MatchesPointerString(&x));
+  EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%.1p"), args),
+              MatchesPointerString(&x));
+  EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%.20p"), args),
+              MatchesPointerString(&x));
+  EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%30.20p"), args),
+              MatchesPointerString(&x));
+
+  EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-p"), args),
+              MatchesPointerString(&x));
+  EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-20p"), args),
+              MatchesPointerString(&x));
+  EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-.1p"), args),
+              MatchesPointerString(&x));
+  EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%.20p"), args),
+              MatchesPointerString(&x));
+  EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-30.20p"), args),
+              MatchesPointerString(&x));
+
+  // const char*
+  EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%2$p"), args),
+              MatchesPointerString(cp));
+  // null const int*
+  EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%3$p"), args),
+              MatchesPointerString(nullptr));
+  // null const char*
+  EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%4$p"), args),
+              MatchesPointerString(nullptr));
+  // nonconst char*
+  EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%5$p"), args),
+              MatchesPointerString(mcp));
+
+  // function pointers
+  EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%6$p"), args),
+              MatchesPointerString(reinterpret_cast<const void*>(fp)));
+  EXPECT_THAT(
+      FormatPack(UntypedFormatSpecImpl("%8$p"), args),
+      MatchesPointerString(reinterpret_cast<volatile const void *>(vcp)));
+
+  // null function pointers
+  EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%7$p"), args),
+              MatchesPointerString(nullptr));
+  EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%9$p"), args),
+              MatchesPointerString(nullptr));
 }
 
 struct Cardinal {
diff --git a/absl/strings/numbers_test.cc b/absl/strings/numbers_test.cc
index 77d7e7835b8b..4edf8891be3a 100644
--- a/absl/strings/numbers_test.cc
+++ b/absl/strings/numbers_test.cc
@@ -713,11 +713,11 @@ TEST(stringtest, safe_strtou64_base_length_delimited) {
   }
 }
 
-// feenableexcept() and fedisableexcept() are missing on macOS, MSVC,
-// and WebAssembly.
-#if defined(_MSC_VER) || defined(__APPLE__) || defined(__EMSCRIPTEN__)
-#define ABSL_MISSING_FEENABLEEXCEPT 1
-#define ABSL_MISSING_FEDISABLEEXCEPT 1
+// feenableexcept() and fedisableexcept() are extensions supported by some libc
+// implementations.
+#if defined(__GLIBC__) || defined(__BIONIC__)
+#define ABSL_HAVE_FEENABLEEXCEPT 1
+#define ABSL_HAVE_FEDISABLEEXCEPT 1
 #endif
 
 class SimpleDtoaTest : public testing::Test {
@@ -725,7 +725,7 @@ class SimpleDtoaTest : public testing::Test {
   void SetUp() override {
     // Store the current floating point env & clear away any pending exceptions.
     feholdexcept(&fp_env_);
-#ifndef ABSL_MISSING_FEENABLEEXCEPT
+#ifdef ABSL_HAVE_FEENABLEEXCEPT
     // Turn on floating point exceptions.
     feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
 #endif
@@ -735,7 +735,7 @@ class SimpleDtoaTest : public testing::Test {
     // Restore the floating point environment to the original state.
     // In theory fedisableexcept is unnecessary; fesetenv will also do it.
     // In practice, our toolchains have subtle bugs.
-#ifndef ABSL_MISSING_FEDISABLEEXCEPT
+#ifdef ABSL_HAVE_FEDISABLEEXCEPT
     fedisableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
 #endif
     fesetenv(&fp_env_);
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h
index 82344eb246b3..3438ccc12a7d 100644
--- a/absl/strings/string_view.h
+++ b/absl/strings/string_view.h
@@ -40,6 +40,13 @@ using std::string_view;
 
 #else  // ABSL_HAVE_STD_STRING_VIEW
 
+#if ABSL_HAVE_BUILTIN(__builtin_memcmp) || \
+    (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_INTERNAL_STRING_VIEW_MEMCMP __builtin_memcmp
+#else  // ABSL_HAVE_BUILTIN(__builtin_memcmp)
+#define ABSL_INTERNAL_STRING_VIEW_MEMCMP memcmp
+#endif  // ABSL_HAVE_BUILTIN(__builtin_memcmp)
+
 #include <cassert>
 #include <cstddef>
 #include <cstring>
@@ -381,16 +388,13 @@ class string_view {
   // view. Note that in the case of data equality, a further comparison is made
   // on the respective sizes of the two `string_view`s to determine which is
   // smaller, equal, or greater.
-  int compare(string_view x) const noexcept {
-    auto min_length = (std::min)(length_, x.length_);
-    if (min_length > 0) {
-      int r = memcmp(ptr_, x.ptr_, min_length);
-      if (r < 0) return -1;
-      if (r > 0) return 1;
-    }
-    if (length_ < x.length_) return -1;
-    if (length_ > x.length_) return 1;
-    return 0;
+  constexpr int compare(string_view x) const noexcept {
+    return CompareImpl(
+        length_, x.length_,
+        length_ == 0 || x.length_ == 0
+            ? 0
+            : ABSL_INTERNAL_STRING_VIEW_MEMCMP(
+                  ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_));
   }
 
   // Overload of `string_view::compare()` for comparing a substring of the
@@ -528,6 +532,14 @@ class string_view {
 #endif
   }
 
+  static constexpr int CompareImpl(size_type length_a, size_type length_b,
+                                   int compare_result) {
+    return compare_result == 0 ? static_cast<int>(length_a > length_b) -
+                                     static_cast<int>(length_a < length_b)
+                               : static_cast<int>(compare_result > 0) -
+                                     static_cast<int>(compare_result < 0);
+  }
+
   const char* ptr_;
   size_type length_;
 };
@@ -535,33 +547,29 @@ class string_view {
 // This large function is defined inline so that in a fairly common case where
 // one of the arguments is a literal, the compiler can elide a lot of the
 // following comparisons.
-inline bool operator==(string_view x, string_view y) noexcept {
-  auto len = x.size();
-  if (len != y.size()) {
-    return false;
-  }
-
-  return x.data() == y.data() || len <= 0 ||
-         memcmp(x.data(), y.data(), len) == 0;
+constexpr bool operator==(string_view x, string_view y) noexcept {
+  return x.size() == y.size() &&
+         (x.empty() ||
+          ABSL_INTERNAL_STRING_VIEW_MEMCMP(x.data(), y.data(), x.size()) == 0);
 }
 
-inline bool operator!=(string_view x, string_view y) noexcept {
+constexpr bool operator!=(string_view x, string_view y) noexcept {
   return !(x == y);
 }
 
-inline bool operator<(string_view x, string_view y) noexcept {
-  auto min_size = (std::min)(x.size(), y.size());
-  const int r = min_size == 0 ? 0 : memcmp(x.data(), y.data(), min_size);
-  return (r < 0) || (r == 0 && x.size() < y.size());
+constexpr bool operator<(string_view x, string_view y) noexcept {
+  return x.compare(y) < 0;
 }
 
-inline bool operator>(string_view x, string_view y) noexcept { return y < x; }
+constexpr bool operator>(string_view x, string_view y) noexcept {
+  return y < x;
+}
 
-inline bool operator<=(string_view x, string_view y) noexcept {
+constexpr bool operator<=(string_view x, string_view y) noexcept {
   return !(y < x);
 }
 
-inline bool operator>=(string_view x, string_view y) noexcept {
+constexpr bool operator>=(string_view x, string_view y) noexcept {
   return !(x < y);
 }
 
@@ -570,6 +578,8 @@ std::ostream& operator<<(std::ostream& o, string_view piece);
 
 }  // namespace absl
 
+#undef ABSL_INTERNAL_STRING_VIEW_MEMCMP
+
 #endif  // ABSL_HAVE_STD_STRING_VIEW
 
 namespace absl {
diff --git a/absl/strings/string_view_test.cc b/absl/strings/string_view_test.cc
index eb8b170bbbde..86f2fbcd003a 100644
--- a/absl/strings/string_view_test.cc
+++ b/absl/strings/string_view_test.cc
@@ -974,6 +974,29 @@ TEST(StringViewTest, ConstexprCompiles) {
   EXPECT_EQ(cstr_strlen.length(), 3);
   constexpr absl::string_view cstr_strlen2 = "bar";
   EXPECT_EQ(cstr_strlen2, "bar");
+
+#if ABSL_HAVE_BUILTIN(__builtin_memcmp) || \
+    (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_COMPARISON 1
+#endif
+#ifdef ABSL_HAVE_CONSTEXPR_STRING_VIEW_COMPARISON
+  constexpr absl::string_view foo = "foo";
+  constexpr absl::string_view bar = "bar";
+  constexpr bool foo_eq_bar = foo == bar;
+  constexpr bool foo_ne_bar = foo != bar;
+  constexpr bool foo_lt_bar = foo < bar;
+  constexpr bool foo_le_bar = foo <= bar;
+  constexpr bool foo_gt_bar = foo > bar;
+  constexpr bool foo_ge_bar = foo >= bar;
+  constexpr int foo_compare_bar = foo.compare(bar);
+  EXPECT_FALSE(foo_eq_bar);
+  EXPECT_TRUE(foo_ne_bar);
+  EXPECT_FALSE(foo_lt_bar);
+  EXPECT_FALSE(foo_le_bar);
+  EXPECT_TRUE(foo_gt_bar);
+  EXPECT_TRUE(foo_ge_bar);
+  EXPECT_GT(foo_compare_bar, 0);
+#endif
 #endif
 
 #if !defined(__clang__) || 3 < __clang_major__ || \
diff --git a/absl/synchronization/internal/waiter.cc b/absl/synchronization/internal/waiter.cc
index 961457809f12..d83d8087f8d5 100644
--- a/absl/synchronization/internal/waiter.cc
+++ b/absl/synchronization/internal/waiter.cc
@@ -129,6 +129,9 @@ void Waiter::Init() {
 bool Waiter::Wait(KernelTimeout t) {
   // Loop until we can atomically decrement futex from a positive
   // value, waiting on a futex while we believe it is zero.
+  // Note that, since the thread ticker is just reset, we don't need to check
+  // whether the thread is idle on the very first pass of the loop.
+  bool first_pass = true;
   while (true) {
     int32_t x = futex_.load(std::memory_order_relaxed);
     if (x != 0) {
@@ -140,6 +143,8 @@ bool Waiter::Wait(KernelTimeout t) {
       return true;  // Consumed a wakeup, we are done.
     }
 
+
+    if (!first_pass) MaybeBecomeIdle();
     const int err = Futex::WaitUntil(&futex_, 0, t);
     if (err != 0) {
       if (err == -EINTR || err == -EWOULDBLOCK) {
@@ -150,8 +155,7 @@ bool Waiter::Wait(KernelTimeout t) {
         ABSL_RAW_LOG(FATAL, "Futex operation failed with error %d\n", err);
       }
     }
-
-    MaybeBecomeIdle();
+    first_pass = false;
   }
 }
 
@@ -219,6 +223,9 @@ bool Waiter::Wait(KernelTimeout t) {
   PthreadMutexHolder h(&mu_);
   waiter_count_.fetch_add(1, std::memory_order_relaxed);
   // Loop until we find a wakeup to consume or timeout.
+  // Note that, since the thread ticker is just reset, we don't need to check
+  // whether the thread is idle on the very first pass of the loop.
+  bool first_pass = true;
   while (true) {
     int x = wakeup_count_.load(std::memory_order_relaxed);
     if (x != 0) {
@@ -232,6 +239,7 @@ bool Waiter::Wait(KernelTimeout t) {
       return true;
     }
 
+    if (!first_pass) MaybeBecomeIdle();
     // No wakeups available, time to wait.
     if (!t.has_timeout()) {
       const int err = pthread_cond_wait(&cv_, &mu_);
@@ -248,7 +256,7 @@ bool Waiter::Wait(KernelTimeout t) {
         ABSL_RAW_LOG(FATAL, "pthread_cond_wait failed: %d", err);
       }
     }
-    MaybeBecomeIdle();
+    first_pass = false;
   }
 }
 
@@ -288,6 +296,9 @@ bool Waiter::Wait(KernelTimeout t) {
   }
 
   // Loop until we timeout or consume a wakeup.
+  // Note that, since the thread ticker is just reset, we don't need to check
+  // whether the thread is idle on the very first pass of the loop.
+  bool first_pass = true;
   while (true) {
     int x = wakeups_.load(std::memory_order_relaxed);
     if (x != 0) {
@@ -300,6 +311,7 @@ bool Waiter::Wait(KernelTimeout t) {
       return true;
     }
 
+    if (!first_pass) MaybeBecomeIdle();
     // Nothing to consume, wait (looping on EINTR).
     while (true) {
       if (!t.has_timeout()) {
@@ -313,7 +325,7 @@ bool Waiter::Wait(KernelTimeout t) {
         ABSL_RAW_LOG(FATAL, "sem_timedwait failed: %d", errno);
       }
     }
-    MaybeBecomeIdle();
+    first_pass = false;
   }
 }
 
@@ -401,6 +413,9 @@ bool Waiter::Wait(KernelTimeout t) {
   waiter_count_.fetch_add(1, std::memory_order_relaxed);
 
   // Loop until we find a wakeup to consume or timeout.
+  // Note that, since the thread ticker is just reset, we don't need to check
+  // whether the thread is idle on the very first pass of the loop.
+  bool first_pass = true;
   while (true) {
     int x = wakeup_count_.load(std::memory_order_relaxed);
     if (x != 0) {
@@ -414,6 +429,7 @@ bool Waiter::Wait(KernelTimeout t) {
       return true;
     }
 
+    if (!first_pass) MaybeBecomeIdle();
     // No wakeups available, time to wait.
     if (!SleepConditionVariableSRW(cv, mu, t.InMillisecondsFromNow(), 0)) {
       // GetLastError() returns a Win32 DWORD, but we assign to
@@ -427,8 +443,7 @@ bool Waiter::Wait(KernelTimeout t) {
         ABSL_RAW_LOG(FATAL, "SleepConditionVariableSRW failed: %lu", err);
       }
     }
-
-    MaybeBecomeIdle();
+    first_pass = false;
   }
 }
 
diff --git a/absl/synchronization/internal/waiter.h b/absl/synchronization/internal/waiter.h
index 0757b91d79da..099935453bee 100644
--- a/absl/synchronization/internal/waiter.h
+++ b/absl/synchronization/internal/waiter.h
@@ -19,7 +19,7 @@
 #include "absl/base/config.h"
 
 #ifdef _WIN32
-#include <SdkDdkVer.h>
+#include <sdkddkver.h>
 #else
 #include <pthread.h>
 #endif
diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h
index d33318d347df..ccd94618d4a5 100644
--- a/absl/synchronization/mutex.h
+++ b/absl/synchronization/mutex.h
@@ -628,7 +628,7 @@ class ABSL_SCOPED_LOCKABLE WriterMutexLock {
 // Example:
 //
 //   // assume count_ is not internal reference count
-//   int count_ GUARDED_BY(mu_);
+//   int count_ ABSL_GUARDED_BY(mu_);
 //
 //   mu_.LockWhen(Condition(+[](int* count) { return *count == 0; },
 //         &count_));
diff --git a/absl/time/duration.cc b/absl/time/duration.cc
index a3ac61a91894..9a8768113f31 100644
--- a/absl/time/duration.cc
+++ b/absl/time/duration.cc
@@ -906,6 +906,11 @@ bool ParseDuration(const std::string& dur_string, Duration* d) {
   return true;
 }
 
+bool AbslParseFlag(absl::string_view text, Duration* dst, std::string*) {
+  return ParseDuration(std::string(text), dst);
+}
+
+std::string AbslUnparseFlag(Duration d) { return FormatDuration(d); }
 bool ParseFlag(const std::string& text, Duration* dst, std::string* ) {
   return ParseDuration(text, dst);
 }
diff --git a/absl/time/format.cc b/absl/time/format.cc
index d6ca860038dc..ebe872cf7402 100644
--- a/absl/time/format.cc
+++ b/absl/time/format.cc
@@ -129,6 +129,14 @@ bool ParseTime(const std::string& format, const std::string& input,
 }
 
 // Functions required to support absl::Time flags.
+bool AbslParseFlag(absl::string_view text, absl::Time* t, std::string* error) {
+  return absl::ParseTime(RFC3339_full, std::string(text), absl::UTCTimeZone(),
+                         t, error);
+}
+
+std::string AbslUnparseFlag(absl::Time t) {
+  return absl::FormatTime(RFC3339_full, t, absl::UTCTimeZone());
+}
 bool ParseFlag(const std::string& text, absl::Time* t, std::string* error) {
   return absl::ParseTime(RFC3339_full, text, absl::UTCTimeZone(), t, error);
 }
diff --git a/absl/time/internal/cctz/src/time_zone_impl.cc b/absl/time/internal/cctz/src/time_zone_impl.cc
index a26151d3e917..a241e951d1fb 100644
--- a/absl/time/internal/cctz/src/time_zone_impl.cc
+++ b/absl/time/internal/cctz/src/time_zone_impl.cc
@@ -14,6 +14,7 @@
 
 #include "time_zone_impl.h"
 
+#include <deque>
 #include <mutex>
 #include <string>
 #include <unordered_map>
@@ -91,8 +92,14 @@ bool time_zone::Impl::LoadTimeZone(const std::string& name, time_zone* tz) {
 void time_zone::Impl::ClearTimeZoneMapTestOnly() {
   std::lock_guard<std::mutex> lock(TimeZoneMutex());
   if (time_zone_map != nullptr) {
-    // Existing time_zone::Impl* entries are in the wild, so we simply
-    // leak them.  Future requests will result in reloading the data.
+    // Existing time_zone::Impl* entries are in the wild, so we can't delete
+    // them. Instead, we move them to a private container, where they are
+    // logically unreachable but not "leaked".  Future requests will result
+    // in reloading the data.
+    static auto* cleared = new std::deque<const time_zone::Impl*>;
+    for (const auto& element : *time_zone_map) {
+      cleared->push_back(element.second);
+    }
     time_zone_map->clear();
   }
 }
diff --git a/absl/time/time.cc b/absl/time/time.cc
index 6a387bcee61f..60382be7b801 100644
--- a/absl/time/time.cc
+++ b/absl/time/time.cc
@@ -430,9 +430,17 @@ absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,
 }
 
 absl::Time FromTM(const struct tm& tm, absl::TimeZone tz) {
-  const CivilSecond cs(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
-                       tm.tm_hour, tm.tm_min, tm.tm_sec);
-  const auto ti = tz.At(cs);
+  civil_year_t tm_year = tm.tm_year;
+  // Avoids years that are too extreme for CivilSecond to normalize.
+  if (tm_year > 300000000000ll) return InfiniteFuture();
+  if (tm_year < -300000000000ll) return InfinitePast();
+  int tm_mon = tm.tm_mon;
+  if (tm_mon == std::numeric_limits<int>::max()) {
+    tm_mon -= 12;
+    tm_year += 1;
+  }
+  const auto ti = tz.At(CivilSecond(tm_year + 1900, tm_mon + 1, tm.tm_mday,
+                                    tm.tm_hour, tm.tm_min, tm.tm_sec));
   return tm.tm_isdst == 0 ? ti.post : ti.pre;
 }
 
diff --git a/absl/time/time.h b/absl/time/time.h
index 9c8f31774ac6..0b7312ee983d 100644
--- a/absl/time/time.h
+++ b/absl/time/time.h
@@ -83,6 +83,7 @@ struct timeval;
 #include <type_traits>
 #include <utility>
 
+#include "absl/base/macros.h"
 #include "absl/strings/string_view.h"
 #include "absl/time/civil_time.h"
 #include "absl/time/internal/cctz/include/cctz/time_zone.h"
@@ -545,7 +546,11 @@ bool ParseDuration(const std::string& dur_string, Duration* d);
 
 // Support for flag values of type Duration. Duration flags must be specified
 // in a format that is valid input for absl::ParseDuration().
+bool AbslParseFlag(absl::string_view text, Duration* dst, std::string* error);
+std::string AbslUnparseFlag(Duration d);
+ABSL_DEPRECATED("Use AbslParseFlag() instead.")
 bool ParseFlag(const std::string& text, Duration* dst, std::string* error);
+ABSL_DEPRECATED("Use AbslUnparseFlag() instead.")
 std::string UnparseFlag(Duration d);
 
 // Time
@@ -815,7 +820,11 @@ std::chrono::system_clock::time_point ToChronoTime(Time);
 // Additionally, if you'd like to specify a time as a count of
 // seconds/milliseconds/etc from the Unix epoch, use an absl::Duration flag
 // and add that duration to absl::UnixEpoch() to get an absl::Time.
+bool AbslParseFlag(absl::string_view text, Time* t, std::string* error);
+std::string AbslUnparseFlag(Time t);
+ABSL_DEPRECATED("Use AbslParseFlag() instead.")
 bool ParseFlag(const std::string& text, Time* t, std::string* error);
+ABSL_DEPRECATED("Use AbslUnparseFlag() instead.")
 std::string UnparseFlag(Time t);
 
 // TimeZone
diff --git a/absl/time/time_test.cc b/absl/time/time_test.cc
index 37af39d99830..9c4709e6b469 100644
--- a/absl/time/time_test.cc
+++ b/absl/time/time_test.cc
@@ -795,6 +795,30 @@ TEST(Time, FromTM) {
   tm.tm_isdst = 1;
   t = FromTM(tm, nyc);
   EXPECT_EQ("2014-03-09T03:30:42-04:00", absl::FormatTime(t, nyc));  // DST
+
+  // Adjusts tm to refer to a time with a year larger than 2147483647.
+  tm.tm_year = 2147483647 - 1900 + 1;
+  tm.tm_mon = 6 - 1;
+  tm.tm_mday = 28;
+  tm.tm_hour = 1;
+  tm.tm_min = 2;
+  tm.tm_sec = 3;
+  tm.tm_isdst = -1;
+  t = FromTM(tm, absl::UTCTimeZone());
+  EXPECT_EQ("2147483648-06-28T01:02:03+00:00",
+            absl::FormatTime(t, absl::UTCTimeZone()));
+
+  // Adjusts tm to refer to a time with a very large month.
+  tm.tm_year = 2019 - 1900;
+  tm.tm_mon = 2147483647;
+  tm.tm_mday = 28;
+  tm.tm_hour = 1;
+  tm.tm_min = 2;
+  tm.tm_sec = 3;
+  tm.tm_isdst = -1;
+  t = FromTM(tm, absl::UTCTimeZone());
+  EXPECT_EQ("178958989-08-28T01:02:03+00:00",
+            absl::FormatTime(t, absl::UTCTimeZone()));
 }
 
 TEST(Time, TMRoundTrip) {