diff --git a/absl/base/attributes.h b/absl/base/attributes.h
index b7826e7..91bf954 100644
--- a/absl/base/attributes.h
+++ b/absl/base/attributes.h
@@ -779,4 +779,18 @@
 #define ABSL_ATTRIBUTE_TRIVIAL_ABI
 #endif
 
+// ABSL_ATTRIBUTE_NO_UNIQUE_ADDRESS
+//
+// Indicates a data member can be optimized to occupy no space (if it is empty)
+// and/or its tail padding can be used for other members.
+//
+// For code that is assured to only build with C++20 or later, prefer using
+// the standard attribute `[[no_unique_address]]` directly instead of this
+// macro.
+#if ABSL_HAVE_CPP_ATTRIBUTE(no_unique_address)
+#define ABSL_ATTRIBUTE_NO_UNIQUE_ADDRESS [[no_unique_address]]
+#else
+#define ABSL_ATTRIBUTE_NO_UNIQUE_ADDRESS
+#endif
+
 #endif  // ABSL_BASE_ATTRIBUTES_H_
diff --git a/absl/base/internal/thread_identity.h b/absl/base/internal/thread_identity.h
index 463acbc..b99c957 100644
--- a/absl/base/internal/thread_identity.h
+++ b/absl/base/internal/thread_identity.h
@@ -170,7 +170,10 @@
 //
 // Does not malloc(*), and is async-signal safe.
 // [*] Technically pthread_setspecific() does malloc on first use; however this
-// is handled internally within tcmalloc's initialization already.
+// is handled internally within tcmalloc's initialization already. Note that
+// darwin does *not* use tcmalloc, so this can catch you if using MallocHooks
+// on Apple platforms. Whatever function is calling your MallocHooks will need
+// to watch for recursion on Apple platforms.
 //
 // New ThreadIdentity objects can be constructed and associated with a thread
 // by calling GetOrCreateCurrentThreadIdentity() in per-thread-sem.h.
diff --git a/absl/crc/internal/crc.cc b/absl/crc/internal/crc.cc
index 337a173..8720216 100644
--- a/absl/crc/internal/crc.cc
+++ b/absl/crc/internal/crc.cc
@@ -261,7 +261,7 @@
   const uint8_t* e = p + length;
   uint32_t l = *crc;
 
-  auto step_one_byte = [this, &p, &l] () {
+  auto step_one_byte = [this, &p, &l]() {
     int c = (l & 0xff) ^ *p++;
     l = this->table0_[c] ^ (l >> 8);
   };
@@ -359,7 +359,7 @@
 
 void CRC32::ExtendByZeroesImpl(uint32_t* crc, size_t length,
                                const uint32_t zeroes_table[256],
-                               const uint32_t poly_table[256]) const {
+                               const uint32_t poly_table[256]) {
   if (length != 0) {
     uint32_t l = *crc;
     // For each ZEROES_BASE_LG bits in length
diff --git a/absl/crc/internal/crc_internal.h b/absl/crc/internal/crc_internal.h
index 9f08091..3a04788 100644
--- a/absl/crc/internal/crc_internal.h
+++ b/absl/crc/internal/crc_internal.h
@@ -118,9 +118,9 @@
   //
   // These will be set to reverse_zeroes_ and reverse_table0_ for Unextend, and
   // CRC32::zeroes_ and CRC32::table0_ for Extend.
-  void ExtendByZeroesImpl(uint32_t* crc, size_t length,
-                          const uint32_t zeroes_table[256],
-                          const uint32_t poly_table[256]) const;
+  static void ExtendByZeroesImpl(uint32_t* crc, size_t length,
+                                 const uint32_t zeroes_table[256],
+                                 const uint32_t poly_table[256]);
 
   uint32_t table0_[256];  // table of byte extensions
   uint32_t zeroes_[256];  // table of zero extensions
diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc
index 768652d..236d31b 100644
--- a/absl/flags/parse.cc
+++ b/absl/flags/parse.cc
@@ -19,9 +19,9 @@
 
 #include <algorithm>
 #include <cstdint>
+#include <cstdlib>
 #include <fstream>
 #include <iostream>
-#include <iterator>
 #include <string>
 #include <tuple>
 #include <utility>
@@ -278,7 +278,7 @@
     return std::make_tuple("", "", false);
   }
 
-  auto equal_sign_pos = arg.find("=");
+  auto equal_sign_pos = arg.find('=');
 
   absl::string_view flag_name = arg.substr(0, equal_sign_pos);
 
@@ -599,6 +599,34 @@
   return false;
 }
 
+// --------------------------------------------------------------------
+
+void ReportUnrecognizedFlags(
+    const std::vector<UnrecognizedFlag>& unrecognized_flags,
+    bool report_as_fatal_error) {
+  for (const auto& unrecognized : unrecognized_flags) {
+    // Verify if flag_name has the "no" already removed
+    std::vector<std::string> misspelling_hints;
+    if (unrecognized.source == UnrecognizedFlag::kFromArgv) {
+      misspelling_hints =
+          flags_internal::GetMisspellingHints(unrecognized.flag_name);
+    }
+
+    if (misspelling_hints.empty()) {
+      flags_internal::ReportUsageError(
+          absl::StrCat("Unknown command line flag '", unrecognized.flag_name,
+                       "'"),
+          report_as_fatal_error);
+    } else {
+      flags_internal::ReportUsageError(
+          absl::StrCat("Unknown command line flag '", unrecognized.flag_name,
+                       "'. Did you mean: ",
+                       absl::StrJoin(misspelling_hints, ", "), " ?"),
+          report_as_fatal_error);
+    }
+  }
+}
+
 }  // namespace
 
 // --------------------------------------------------------------------
@@ -664,40 +692,79 @@
 // --------------------------------------------------------------------
 
 std::vector<char*> ParseCommandLineImpl(int argc, char* argv[],
-                                        UsageFlagsAction usage_flag_act,
-                                        OnUndefinedFlag on_undef_flag) {
+                                        UsageFlagsAction usage_flag_action,
+                                        OnUndefinedFlag undef_flag_action) {
+  std::vector<char*> positional_args;
+  std::vector<UnrecognizedFlag> unrecognized_flags;
+
+  bool parse_successful = absl::ParseAbseilFlagsOnly(
+      argc, argv, positional_args, unrecognized_flags);
+
+  if (undef_flag_action != OnUndefinedFlag::kIgnoreUndefined) {
+    if (parse_successful &&
+        undef_flag_action == OnUndefinedFlag::kAbortIfUndefined) {
+      if (!unrecognized_flags.empty()) { parse_successful = false; }
+    }
+
+    flags_internal::ReportUnrecognizedFlags(
+        unrecognized_flags,
+        !parse_successful &&
+            (undef_flag_action == OnUndefinedFlag::kAbortIfUndefined));
+  }
+
+#if ABSL_FLAGS_STRIP_NAMES
+  if (!parse_successful) {
+    ReportUsageError("NOTE: command line flags are disabled in this build",
+                     true);
+  }
+#endif
+
+  if (!parse_successful) {
+    HandleUsageFlags(std::cout, ProgramUsageMessage());
+    std::exit(1);
+  }
+
+  if (usage_flag_action == UsageFlagsAction::kHandleUsage) {
+    int exit_code = HandleUsageFlags(std::cout, ProgramUsageMessage());
+
+    if (exit_code != -1) {
+      std::exit(exit_code);
+    }
+  }
+
+  return positional_args;
+}
+
+// --------------------------------------------------------------------
+
+}  // namespace flags_internal
+
+bool ParseAbseilFlagsOnly(int argc, char* argv[],
+                          std::vector<char*>& positional_args,
+                          std::vector<UnrecognizedFlag>& unrecognized_flags) {
   ABSL_INTERNAL_CHECK(argc > 0, "Missing argv[0]");
 
-  // Once parsing has started we will not have more flag registrations.
-  // If we did, they would be missing during parsing, which is a problem on
-  // itself.
+  using flags_internal::ArgsList;
+  using flags_internal::specified_flags;
+
+  std::vector<std::string> flagfile_value;
+  std::vector<ArgsList> input_args;
+
+  // Once parsing has started we will not allow more flag registrations.
   flags_internal::FinalizeRegistry();
 
   // This routine does not return anything since we abort on failure.
-  CheckDefaultValuesParsingRoundtrip();
+  flags_internal::CheckDefaultValuesParsingRoundtrip();
 
-  std::vector<std::string> flagfile_value;
-
-  std::vector<ArgsList> input_args;
-  input_args.emplace_back(argc, argv);
-
-  std::vector<char*> output_args;
-  std::vector<char*> positional_args;
-  output_args.reserve(static_cast<size_t>(argc));
-
-  // This is the list of undefined flags. The element of the list is the pair
-  // consisting of boolean indicating if flag came from command line (vs from
-  // some flag file we've read) and flag name.
-  // TODO(rogeeff): Eliminate the first element in the pair after cleanup.
-  std::vector<std::pair<bool, std::string>> undefined_flag_names;
+  input_args.push_back(ArgsList(argc, argv));
 
   // Set program invocation name if it is not set before.
-  if (ProgramInvocationName() == "UNKNOWN") {
+  if (flags_internal::ProgramInvocationName() == "UNKNOWN") {
     flags_internal::SetProgramInvocationName(argv[0]);
   }
-  output_args.push_back(argv[0]);
+  positional_args.push_back(argv[0]);
 
-  absl::MutexLock l(&specified_flags_guard);
+  absl::MutexLock l(&flags_internal::specified_flags_guard);
   if (specified_flags == nullptr) {
     specified_flags = new std::vector<const CommandLineFlag*>;
   } else {
@@ -709,13 +776,15 @@
   // recursive parsing of flagfile(s).
   bool success = true;
   while (!input_args.empty()) {
-    // 10. First we process the built-in generator flags.
-    success &= HandleGeneratorFlags(input_args, flagfile_value);
+    // First we process the built-in generator flags.
+    success &= flags_internal::HandleGeneratorFlags(input_args, flagfile_value);
 
-    // 30. Select top-most (most recent) arguments list. If it is empty drop it
+    // Select top-most (most recent) arguments list. If it is empty drop it
     // and re-try.
     ArgsList& curr_list = input_args.back();
 
+    // Every ArgsList starts with real or fake program name, so we can always
+    // start by skipping it.
     curr_list.PopFront();
 
     if (curr_list.Size() == 0) {
@@ -723,13 +792,13 @@
       continue;
     }
 
-    // 40. Pick up the front remaining argument in the current list. If current
-    // stack of argument lists contains only one element - we are processing an
-    // argument from the original argv.
+    // Handle the next argument in the current list. If the stack of argument
+    // lists contains only one element - we are processing an argument from the
+    // original argv.
     absl::string_view arg(curr_list.Front());
     bool arg_from_argv = input_args.size() == 1;
 
-    // 50. If argument does not start with - or is just "-" - this is
+    // If argument does not start with '-' or is just "-" - this is
     // positional argument.
     if (!absl::ConsumePrefix(&arg, "-") || arg.empty()) {
       ABSL_INTERNAL_CHECK(arg_from_argv,
@@ -739,8 +808,8 @@
       continue;
     }
 
-    // 60. Split the current argument on '=' to figure out the argument
-    // name and value. If flag name is empty it means we've got "--". value
+    // Split the current argument on '=' to deduce the argument flag name and
+    // value. If flag name is empty it means we've got an "--" argument. Value
     // can be empty either if there were no '=' in argument string at all or
     // an argument looked like "--foo=". In a latter case is_empty_value is
     // true.
@@ -748,10 +817,11 @@
     absl::string_view value;
     bool is_empty_value = false;
 
-    std::tie(flag_name, value, is_empty_value) = SplitNameAndValue(arg);
+    std::tie(flag_name, value, is_empty_value) =
+        flags_internal::SplitNameAndValue(arg);
 
-    // 70. "--" alone means what it does for GNU: stop flags parsing. We do
-    // not support positional arguments in flagfiles, so we just drop them.
+    // Standalone "--" argument indicates that the rest of the arguments are
+    // positional. We do not support positional arguments in flagfiles.
     if (flag_name.empty()) {
       ABSL_INTERNAL_CHECK(arg_from_argv,
                           "Flagfile cannot contain positional argument");
@@ -760,36 +830,36 @@
       break;
     }
 
-    // 80. Locate the flag based on flag name. Handle both --foo and --nofoo
+    // Locate the flag based on flag name. Handle both --foo and --nofoo.
     CommandLineFlag* flag = nullptr;
     bool is_negative = false;
-    std::tie(flag, is_negative) = LocateFlag(flag_name);
+    std::tie(flag, is_negative) = flags_internal::LocateFlag(flag_name);
 
     if (flag == nullptr) {
       // Usage flags are not modeled as Abseil flags. Locate them separately.
       if (flags_internal::DeduceUsageFlags(flag_name, value)) {
         continue;
       }
-
-      if (on_undef_flag != OnUndefinedFlag::kIgnoreUndefined) {
-        undefined_flag_names.emplace_back(arg_from_argv,
-                                          std::string(flag_name));
-      }
+      unrecognized_flags.emplace_back(arg_from_argv
+                                          ? UnrecognizedFlag::kFromArgv
+                                          : UnrecognizedFlag::kFromFlagfile,
+                                      flag_name);
       continue;
     }
 
-    // 90. Deduce flag's value (from this or next argument)
+    // Deduce flag's value (from this or next argument).
     bool value_success = true;
-    std::tie(value_success, value) =
-        DeduceFlagValue(*flag, value, is_negative, is_empty_value, &curr_list);
+    std::tie(value_success, value) = flags_internal::DeduceFlagValue(
+        *flag, value, is_negative, is_empty_value, &curr_list);
     success &= value_success;
 
-    // 100. Set the located flag to a new new value, unless it is retired.
-    // Setting retired flag fails, but we ignoring it here while also reporting
-    // access to retired flag.
+    // Set the located flag to a new value, unless it is retired. Setting
+    // retired flag fails, but we ignoring it here while also reporting access
+    // to retired flag.
     std::string error;
     if (!flags_internal::PrivateHandleAccessor::ParseFrom(
-            *flag, value, SET_FLAGS_VALUE, kCommandLine, error)) {
+            *flag, value, flags_internal::SET_FLAGS_VALUE,
+            flags_internal::kCommandLine, error)) {
       if (flag->IsRetired()) continue;
 
       flags_internal::ReportUsageError(error, true);
@@ -799,71 +869,41 @@
     }
   }
 
-  for (const auto& flag_name : undefined_flag_names) {
-    if (CanIgnoreUndefinedFlag(flag_name.second)) continue;
-    // Verify if flag_name has the "no" already removed
-    std::vector<std::string> flags;
-    if (flag_name.first) flags = GetMisspellingHints(flag_name.second);
-    if (flags.empty()) {
-      flags_internal::ReportUsageError(
-          absl::StrCat("Unknown command line flag '", flag_name.second, "'"),
-          true);
-    } else {
-      flags_internal::ReportUsageError(
-          absl::StrCat("Unknown command line flag '", flag_name.second,
-                       "'. Did you mean: ", absl::StrJoin(flags, ", "), " ?"),
-          true);
-    }
-
-    success = false;
-  }
-
-#if ABSL_FLAGS_STRIP_NAMES
-  if (!success) {
-    flags_internal::ReportUsageError(
-        "NOTE: command line flags are disabled in this build", true);
-  }
-#endif
-
-  if (!success) {
-    flags_internal::HandleUsageFlags(std::cout,
-                                     ProgramUsageMessage());
-    std::exit(1);
-  }
-
-  if (usage_flag_act == UsageFlagsAction::kHandleUsage) {
-    int exit_code = flags_internal::HandleUsageFlags(
-        std::cout, ProgramUsageMessage());
-
-    if (exit_code != -1) {
-      std::exit(exit_code);
-    }
-  }
-
-  ResetGeneratorFlags(flagfile_value);
-
-  // Reinstate positional args which were intermixed with flags in the arguments
-  // list.
-  for (auto arg : positional_args) {
-    output_args.push_back(arg);
-  }
+  flags_internal::ResetGeneratorFlags(flagfile_value);
 
   // All the remaining arguments are positional.
   if (!input_args.empty()) {
     for (size_t arg_index = input_args.back().FrontIndex();
          arg_index < static_cast<size_t>(argc); ++arg_index) {
-      output_args.push_back(argv[arg_index]);
+      positional_args.push_back(argv[arg_index]);
     }
   }
 
   // Trim and sort the vector.
   specified_flags->shrink_to_fit();
   std::sort(specified_flags->begin(), specified_flags->end(),
-            SpecifiedFlagsCompare{});
-  return output_args;
+            flags_internal::SpecifiedFlagsCompare{});
+
+  // Filter out unrecognized flags, which are ok to ignore.
+  std::vector<UnrecognizedFlag> filtered;
+  filtered.reserve(unrecognized_flags.size());
+  for (const auto& unrecognized : unrecognized_flags) {
+    if (flags_internal::CanIgnoreUndefinedFlag(unrecognized.flag_name))
+      continue;
+    filtered.push_back(unrecognized);
+  }
+
+  std::swap(unrecognized_flags, filtered);
+
+  return success;
 }
 
-}  // namespace flags_internal
+// --------------------------------------------------------------------
+
+void ReportUnrecognizedFlags(
+    const std::vector<UnrecognizedFlag>& unrecognized_flags) {
+  flags_internal::ReportUnrecognizedFlags(unrecognized_flags, true);
+}
 
 // --------------------------------------------------------------------
 
diff --git a/absl/flags/parse.h b/absl/flags/parse.h
index 929de2c..9732727 100644
--- a/absl/flags/parse.h
+++ b/absl/flags/parse.h
@@ -23,35 +23,96 @@
 #ifndef ABSL_FLAGS_PARSE_H_
 #define ABSL_FLAGS_PARSE_H_
 
+#include <string>
 #include <vector>
 
 #include "absl/base/config.h"
 #include "absl/flags/internal/parse.h"
+#include "absl/strings/string_view.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
+// This type represent information about an unrecognized flag in the command
+// line.
+struct UnrecognizedFlag {
+  enum Source { kFromArgv, kFromFlagfile };
+
+  explicit UnrecognizedFlag(Source s, absl::string_view f)
+      : source(s), flag_name(f) {}
+  // This field indicates where we found this flag: on the original command line
+  // or read in some flag file.
+  Source source;
+  // Name of the flag we did not recognize in --flag_name=value or --flag_name.
+  std::string flag_name;
+};
+
+inline bool operator==(const UnrecognizedFlag& lhs,
+                       const UnrecognizedFlag& rhs) {
+  return lhs.source == rhs.source && lhs.flag_name == rhs.flag_name;
+}
+
+// ParseAbseilFlagsOnly()
+//
+// Parses a list of command-line arguments, passed in the `argc` and `argv[]`
+// parameters, into a set of Abseil Flag values, returning any unparsed
+// arguments in `positional_args` and `unrecognized_flags` output parameters.
+//
+// This function classifies all the arguments (including content of the
+// flagfiles, if any) into one of the following groups:
+//
+//   * arguments specified as "--flag=value" or "--flag value" that match
+//     registered or built-in Abseil Flags. These are "Abseil Flag arguments."
+//   * arguments specified as "--flag" that are unrecognized as Abseil Flags
+//   * arguments that are not specified as "--flag" are positional arguments
+//   * arguments that follow the flag-terminating delimiter (`--`) are also
+//     treated as positional arguments regardless of their syntax.
+//
+// All of the deduced Abseil Flag arguments are then parsed into their
+// corresponding flag values.
+//
+// All the remaining positional arguments including original program name
+// (argv[0]) are are returned in the `positional_args` output parameter.
+//
+// All unrecognized flags that are not otherwise ignored are returned in the
+// `unrecognized_flags` output parameter. Note that the special `undefok`
+// flag allows you to specify flags which can be safely ignored; `undefok`
+// specifies these flags as a comma-separated list. Any unrecognized flags
+// that appear within `undefok` will therefore be ignored and not included in
+// the `unrecognized_flag` output parameter.
+//
+// This function returns true if no syntax errors were found on the command line
+// or in the referenced flag files. Unrecognized flags do not cause this routine
+// to return false.
+bool ParseAbseilFlagsOnly(int argc, char* argv[],
+                          std::vector<char*>& positional_args,
+                          std::vector<UnrecognizedFlag>& unrecognized_flags);
+
+// ReportUnrecognizedFlags()
+//
+// Reports an error to `stderr` for all non-ignored unrecognized flags in
+// the provided `unrecognized_flags` list.
+void ReportUnrecognizedFlags(
+    const std::vector<UnrecognizedFlag>& unrecognized_flags);
+
 // ParseCommandLine()
 //
-// Parses the set of command-line arguments passed in the `argc` (argument
-// count) and `argv[]` (argument vector) parameters from `main()`, assigning
-// values to any defined Abseil flags. (Any arguments passed after the
-// flag-terminating delimiter (`--`) are treated as positional arguments and
-// ignored.)
+// First parses Abseil Flags only from the command line according to the
+// description in `ParseAbseilFlagsOnly`. In addition this function handles
+// unrecognized and usage flags.
 //
-// Any command-line flags (and arguments to those flags) are parsed into Abseil
-// Flag values, if those flags are defined. Any undefined flags will either
-// return an error, or be ignored if that flag is designated using `undefok` to
-// indicate "undefined is OK."
+// If any unrecognized flags are located they are reported using
+// `ReportUnrecognizedFlags`.
 //
-// Any command-line positional arguments not part of any command-line flag (or
-// arguments to a flag) are returned in a vector, with the program invocation
-// name at position 0 of that vector. (Note that this includes positional
-// arguments after the flag-terminating delimiter `--`.)
+// If any errors detected during command line parsing, this routine reports a
+// usage message and aborts the program.
 //
-// After all flags and flag arguments are parsed, this function looks for any
-// built-in usage flags (e.g. `--help`), and if any were specified, it reports
-// help messages and then exits the program.
+// If any built-in usage flags were specified on the command line (e.g.
+// `--help`), this function reports help messages and then gracefully exits the
+// program.
+//
+// This function returns all the remaining positional arguments collected by
+// `ParseAbseilFlagsOnly`.
 std::vector<char*> ParseCommandLine(int argc, char* argv[]);
 
 ABSL_NAMESPACE_END
diff --git a/absl/flags/parse_test.cc b/absl/flags/parse_test.cc
index 18a0137..c46bb46 100644
--- a/absl/flags/parse_test.cc
+++ b/absl/flags/parse_test.cc
@@ -20,13 +20,13 @@
 #include <cstddef>
 #include <fstream>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/internal/scoped_set_env.h"
-#include "absl/flags/declare.h"
 #include "absl/flags/flag.h"
 #include "absl/flags/internal/parse.h"
 #include "absl/flags/internal/usage.h"
@@ -199,7 +199,7 @@
 // Builds flagfile flag in the flagfile_flag buffer and returns it. This
 // function also creates a temporary flagfile based on FlagfileData input.
 // We create a flagfile in a temporary directory with the name specified in
-// FlagfileData and populate it with lines specifed in FlagfileData. If $0 is
+// FlagfileData and populate it with lines specified in FlagfileData. If $0 is
 // referenced in any of the lines in FlagfileData they are replaced with
 // temporary directory location. This way we can test inclusion of one flagfile
 // from another flagfile.
@@ -257,6 +257,17 @@
 // --------------------------------------------------------------------
 
 template <int N>
+bool InvokeParseAbslOnly(const char* (&in_argv)[N]) {
+  std::vector<char*> positional_args;
+  std::vector<absl::UnrecognizedFlag> unrecognized_flags;
+
+  return absl::ParseAbseilFlagsOnly(N, const_cast<char**>(in_argv),
+                                    positional_args, unrecognized_flags);
+}
+
+// --------------------------------------------------------------------
+
+template <int N>
 void TestParse(const char* (&in_argv)[N], int int_flag_value,
                double double_flag_val, absl::string_view string_flag_val,
                bool bool_flag_val, int exp_position_args = 0) {
@@ -854,26 +865,6 @@
 
 // --------------------------------------------------------------------
 
-TEST_F(ParseTest, TestIgnoreUndefinedFlags) {
-  const char* in_args1[] = {
-      "testbin",
-      "arg1",
-      "--undef_flag=aa",
-      "--int_flag=21",
-  };
-
-  auto out_args1 = flags::ParseCommandLineImpl(
-      4, const_cast<char**>(in_args1), flags::UsageFlagsAction::kHandleUsage,
-      flags::OnUndefinedFlag::kIgnoreUndefined);
-
-  EXPECT_THAT(out_args1, ElementsAreArray({absl::string_view("testbin"),
-                                           absl::string_view("arg1")}));
-
-  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 21);
-}
-
-// --------------------------------------------------------------------
-
 TEST_F(ParseDeathTest, TestSimpleHelpFlagHandling) {
   const char* in_args1[] = {
       "testbin",
@@ -888,12 +879,16 @@
       "--int_flag=3",
   };
 
-  auto out_args2 = flags::ParseCommandLineImpl(
-      3, const_cast<char**>(in_args2), flags::UsageFlagsAction::kIgnoreUsage,
-      flags::OnUndefinedFlag::kAbortIfUndefined);
+  InvokeParseAbslOnly(in_args2);
 
   EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kImportant);
   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 3);
+
+  const char* in_args3[] = {"testbin", "--help", "some_positional_arg"};
+
+  InvokeParseAbslOnly(in_args3);
+
+  EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kImportant);
 }
 
 // --------------------------------------------------------------------
@@ -904,20 +899,10 @@
       "--help=abcd",
   };
 
-  auto out_args1 = flags::ParseCommandLineImpl(
-      2, const_cast<char**>(in_args1), flags::UsageFlagsAction::kIgnoreUsage,
-      flags::OnUndefinedFlag::kAbortIfUndefined);
+  InvokeParseAbslOnly(in_args1);
 
   EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kMatch);
   EXPECT_EQ(flags::GetFlagsHelpMatchSubstr(), "abcd");
-
-  const char* in_args2[] = {"testbin", "--help", "some_positional_arg"};
-
-  auto out_args2 = flags::ParseCommandLineImpl(
-      3, const_cast<char**>(in_args2), flags::UsageFlagsAction::kIgnoreUsage,
-      flags::OnUndefinedFlag::kAbortIfUndefined);
-
-  EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kImportant);
 }
 
 // --------------------------------------------------------------------
@@ -942,4 +927,106 @@
 
 // --------------------------------------------------------------------
 
+TEST_F(ParseTest, ParseAbseilFlagsOnlySuccess) {
+  const char* in_args[] = {
+      "testbin",
+      "arg1",
+      "--bool_flag",
+      "--int_flag=211",
+      "arg2",
+      "--double_flag=1.1",
+      "--undef_flag1",
+      "--undef_flag2=123",
+      "--string_flag",
+      "asd",
+      "--",
+      "--some_flag",
+      "arg4",
+  };
+
+  std::vector<char*> positional_args;
+  std::vector<absl::UnrecognizedFlag> unrecognized_flags;
+
+  EXPECT_TRUE(absl::ParseAbseilFlagsOnly(13, const_cast<char**>(in_args),
+                                         positional_args, unrecognized_flags));
+  EXPECT_THAT(positional_args,
+              ElementsAreArray(
+                  {absl::string_view("testbin"), absl::string_view("arg1"),
+                   absl::string_view("arg2"), absl::string_view("--some_flag"),
+                   absl::string_view("arg4")}));
+  EXPECT_THAT(unrecognized_flags,
+              ElementsAreArray(
+                  {absl::UnrecognizedFlag(absl::UnrecognizedFlag::kFromArgv,
+                                          "undef_flag1"),
+                   absl::UnrecognizedFlag(absl::UnrecognizedFlag::kFromArgv,
+                                          "undef_flag2")}));
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, ParseAbseilFlagsOnlyFailure) {
+  const char* in_args[] = {
+      "testbin",
+      "--int_flag=21.1",
+  };
+
+  std::vector<char*> positional_args;
+  std::vector<absl::UnrecognizedFlag> unrecognized_flags;
+
+  EXPECT_FALSE(absl::ParseAbseilFlagsOnly(2, const_cast<char**>(in_args),
+                                          positional_args, unrecognized_flags));
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, UndefOkFlagsAreIgnored) {
+  const char* in_args[] = {
+      "testbin",           "--undef_flag1",
+      "--undef_flag2=123", "--undefok=undef_flag2",
+      "--undef_flag3",     "value",
+  };
+
+  std::vector<char*> positional_args;
+  std::vector<absl::UnrecognizedFlag> unrecognized_flags;
+
+  EXPECT_TRUE(absl::ParseAbseilFlagsOnly(6, const_cast<char**>(in_args),
+                                         positional_args, unrecognized_flags));
+  EXPECT_THAT(positional_args, ElementsAreArray({absl::string_view("testbin"),
+                                                 absl::string_view("value")}));
+  EXPECT_THAT(unrecognized_flags,
+              ElementsAreArray(
+                  {absl::UnrecognizedFlag(absl::UnrecognizedFlag::kFromArgv,
+                                          "undef_flag1"),
+                   absl::UnrecognizedFlag(absl::UnrecognizedFlag::kFromArgv,
+                                          "undef_flag3")}));
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, AllUndefOkFlagsAreIgnored) {
+  const char* in_args[] = {
+      "testbin",
+      "--undef_flag1",
+      "--undef_flag2=123",
+      "--undefok=undef_flag2,undef_flag1,undef_flag3",
+      "--undef_flag3",
+      "value",
+      "--",
+      "--undef_flag4",
+  };
+
+  std::vector<char*> positional_args;
+  std::vector<absl::UnrecognizedFlag> unrecognized_flags;
+
+  EXPECT_TRUE(absl::ParseAbseilFlagsOnly(8, const_cast<char**>(in_args),
+                                         positional_args, unrecognized_flags));
+  EXPECT_THAT(positional_args,
+              ElementsAreArray({absl::string_view("testbin"),
+                                absl::string_view("value"),
+                                absl::string_view("--undef_flag4")}));
+  EXPECT_THAT(unrecognized_flags, testing::IsEmpty());
+}
+
+// --------------------------------------------------------------------
+
 }  // namespace
diff --git a/absl/hash/hash.h b/absl/hash/hash.h
index 74e2d7c..956befa 100644
--- a/absl/hash/hash.h
+++ b/absl/hash/hash.h
@@ -110,9 +110,10 @@
 //   * std::unique_ptr and std::shared_ptr
 //   * All string-like types including:
 //     * absl::Cord
-//     * std::string
-//     * std::string_view (as well as any instance of std::basic_string that
-//       uses char and std::char_traits)
+//     * std::string (as well as any instance of std::basic_string that
+//       uses one of {char, wchar_t, char16_t, char32_t} and its associated
+//       std::char_traits)
+//     * std::string_view
 //  * All the standard sequence containers (provided the elements are hashable)
 //  * All the standard associative containers (provided the elements are
 //    hashable)
diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h
index 61970e0..a22a537 100644
--- a/absl/hash/internal/hash.h
+++ b/absl/hash/internal/hash.h
@@ -516,14 +516,14 @@
 // the same character sequence. These types are:
 //
 //  - `absl::Cord`
-//  - `std::string` (and std::basic_string<char, std::char_traits<char>, A> for
-//      any allocator A)
+//  - `std::string` (and std::basic_string<T, std::char_traits<T>, A> for
+//      any allocator A and any T in {char, wchar_t, char16_t, char32_t})
 //  - `absl::string_view` and `std::string_view`
 //
-// For simplicity, we currently support only `char` strings. This support may
-// be broadened, if necessary, but with some caution - this overload would
-// misbehave in cases where the traits' `eq()` member isn't equivalent to `==`
-// on the underlying character type.
+// For simplicity, we currently support only strings built on `char`, `wchar_t`,
+// `char16_t`, or `char32_t`. This support may be broadened, if necessary, but
+// with some caution - this overload would misbehave in cases where the traits'
+// `eq()` member isn't equivalent to `==` on the underlying character type.
 template <typename H>
 H AbslHashValue(H hash_state, absl::string_view str) {
   return H::combine(
diff --git a/absl/strings/ascii.cc b/absl/strings/ascii.cc
index 868df2d..16c9689 100644
--- a/absl/strings/ascii.cc
+++ b/absl/strings/ascii.cc
@@ -14,6 +14,10 @@
 
 #include "absl/strings/ascii.h"
 
+#include <climits>
+#include <cstring>
+#include <string>
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace ascii_internal {
@@ -153,18 +157,62 @@
 };
 // clang-format on
 
-}  // namespace ascii_internal
+template <bool ToUpper>
+constexpr void AsciiStrCaseFold(char* p, char* end) {
+  // The upper- and lowercase versions of ASCII characters differ by only 1 bit.
+  // When we need to flip the case, we can xor with this bit to achieve the
+  // desired result. Note that the choice of 'a' and 'A' here is arbitrary. We
+  // could have chosen 'z' and 'Z', or any other pair of characters as they all
+  // have the same single bit difference.
+  constexpr unsigned char kAsciiCaseBitFlip = 'a' ^ 'A';
 
-void AsciiStrToLower(std::string* s) {
-  for (auto& ch : *s) {
-    ch = absl::ascii_tolower(static_cast<unsigned char>(ch));
+  constexpr char ch_a = ToUpper ? 'a' : 'A';
+  constexpr char ch_z = ToUpper ? 'z' : 'Z';
+  for (; p < end; ++p) {
+    unsigned char v = static_cast<unsigned char>(*p);
+    // We use & instead of && to ensure this always stays branchless
+    // We use static_cast<int> to suppress -Wbitwise-instead-of-logical
+    bool is_in_range = static_cast<bool>(static_cast<int>(ch_a <= v) &
+                                         static_cast<int>(v <= ch_z));
+    v ^= is_in_range ? kAsciiCaseBitFlip : 0;
+    *p = static_cast<char>(v);
   }
 }
 
-void AsciiStrToUpper(std::string* s) {
-  for (auto& ch : *s) {
-    ch = absl::ascii_toupper(static_cast<unsigned char>(ch));
+static constexpr size_t ValidateAsciiCasefold() {
+  constexpr size_t num_chars = 1 + CHAR_MAX - CHAR_MIN;
+  size_t incorrect_index = 0;
+  char lowered[num_chars] = {};
+  char uppered[num_chars] = {};
+  for (unsigned int i = 0; i < num_chars; ++i) {
+    uppered[i] = lowered[i] = static_cast<char>(i);
   }
+  AsciiStrCaseFold<false>(&lowered[0], &lowered[num_chars]);
+  AsciiStrCaseFold<true>(&uppered[0], &uppered[num_chars]);
+  for (size_t i = 0; i < num_chars; ++i) {
+    const char ch = static_cast<char>(i),
+               ch_upper = ('a' <= ch && ch <= 'z' ? 'A' + (ch - 'a') : ch),
+               ch_lower = ('A' <= ch && ch <= 'Z' ? 'a' + (ch - 'A') : ch);
+    if (uppered[i] != ch_upper || lowered[i] != ch_lower) {
+      incorrect_index = i > 0 ? i : num_chars;
+      break;
+    }
+  }
+  return incorrect_index;
+}
+
+static_assert(ValidateAsciiCasefold() == 0, "error in case conversion");
+
+}  // namespace ascii_internal
+
+void AsciiStrToLower(std::string* s) {
+  char* p = &(*s)[0];  // Guaranteed to be valid for empty strings
+  return ascii_internal::AsciiStrCaseFold<false>(p, p + s->size());
+}
+
+void AsciiStrToUpper(std::string* s) {
+  char* p = &(*s)[0];  // Guaranteed to be valid for empty strings
+  return ascii_internal::AsciiStrCaseFold<true>(p, p + s->size());
 }
 
 void RemoveExtraAsciiWhitespace(std::string* str) {
diff --git a/absl/strings/ascii_test.cc b/absl/strings/ascii_test.cc
index dfed114..4ea262f 100644
--- a/absl/strings/ascii_test.cc
+++ b/absl/strings/ascii_test.cc
@@ -14,6 +14,7 @@
 
 #include "absl/strings/ascii.h"
 
+#include <algorithm>
 #include <cctype>
 #include <clocale>
 #include <cstring>
@@ -189,14 +190,14 @@
   const std::string str("GHIJKL");
   const std::string str2("MNOPQR");
   const absl::string_view sp(str2);
-  std::string mutable_str("STUVWX");
+  std::string mutable_str("_`?@[{AMNOPQRSTUVWXYZ");
 
   EXPECT_EQ("abcdef", absl::AsciiStrToLower(buf));
   EXPECT_EQ("ghijkl", absl::AsciiStrToLower(str));
   EXPECT_EQ("mnopqr", absl::AsciiStrToLower(sp));
 
   absl::AsciiStrToLower(&mutable_str);
-  EXPECT_EQ("stuvwx", mutable_str);
+  EXPECT_EQ("_`?@[{amnopqrstuvwxyz", mutable_str);
 
   char mutable_buf[] = "Mutable";
   std::transform(mutable_buf, mutable_buf + strlen(mutable_buf),
@@ -207,12 +208,12 @@
 TEST(AsciiStrTo, Upper) {
   const char buf[] = "abcdef";
   const std::string str("ghijkl");
-  const std::string str2("mnopqr");
+  const std::string str2("_`?@[{amnopqrstuvwxyz");
   const absl::string_view sp(str2);
 
   EXPECT_EQ("ABCDEF", absl::AsciiStrToUpper(buf));
   EXPECT_EQ("GHIJKL", absl::AsciiStrToUpper(str));
-  EXPECT_EQ("MNOPQR", absl::AsciiStrToUpper(sp));
+  EXPECT_EQ("_`?@[{AMNOPQRSTUVWXYZ", absl::AsciiStrToUpper(sp));
 
   char mutable_buf[] = "Mutable";
   std::transform(mutable_buf, mutable_buf + strlen(mutable_buf),
diff --git a/absl/strings/cord_buffer.h b/absl/strings/cord_buffer.h
index a3600ac..bc0e4e4 100644
--- a/absl/strings/cord_buffer.h
+++ b/absl/strings/cord_buffer.h
@@ -160,7 +160,6 @@
   // for more information on buffer capacities and intended usage.
   static CordBuffer CreateWithDefaultLimit(size_t capacity);
 
-
   // CordBuffer::CreateWithCustomLimit()
   //
   // Creates a CordBuffer instance of the desired `capacity` rounded to an
@@ -336,7 +335,7 @@
     }
 
     // Returns the available area of the internal SSO data
-    absl::Span<char> long_available() {
+    absl::Span<char> long_available() const {
       assert(!is_short());
       const size_t length = long_rep.rep->length;
       return absl::Span<char>(long_rep.rep->Data() + length,
diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc
index 5603e94..3fe3967 100644
--- a/absl/strings/cord_test.cc
+++ b/absl/strings/cord_test.cc
@@ -58,6 +58,8 @@
 using absl::cord_internal::CordzUpdateTracker;
 using absl::cord_internal::kFlatOverhead;
 using absl::cord_internal::kMaxFlatLength;
+using ::testing::ElementsAre;
+using ::testing::Le;
 
 static std::string RandomLowercaseString(RandomEngine* rng);
 static std::string RandomLowercaseString(RandomEngine* rng, size_t length);
@@ -618,7 +620,7 @@
 TEST_P(CordTest, AppendSmallBuffer) {
   absl::Cord cord;
   absl::CordBuffer buffer = absl::CordBuffer::CreateWithDefaultLimit(3);
-  ASSERT_THAT(buffer.capacity(), ::testing::Le(15));
+  ASSERT_THAT(buffer.capacity(), Le(15));
   memcpy(buffer.data(), "Abc", 3);
   buffer.SetLength(3);
   cord.Append(std::move(buffer));
@@ -632,7 +634,7 @@
   EXPECT_EQ(buffer.length(), 0);    // NOLINT
   EXPECT_GT(buffer.capacity(), 0);  // NOLINT
 
-  EXPECT_THAT(cord.Chunks(), ::testing::ElementsAre("Abcdefgh"));
+  EXPECT_THAT(cord.Chunks(), ElementsAre("Abcdefgh"));
 }
 
 TEST_P(CordTest, AppendAndPrependBufferArePrecise) {
@@ -671,7 +673,7 @@
 TEST_P(CordTest, PrependSmallBuffer) {
   absl::Cord cord;
   absl::CordBuffer buffer = absl::CordBuffer::CreateWithDefaultLimit(3);
-  ASSERT_THAT(buffer.capacity(), ::testing::Le(15));
+  ASSERT_THAT(buffer.capacity(), Le(15));
   memcpy(buffer.data(), "Abc", 3);
   buffer.SetLength(3);
   cord.Prepend(std::move(buffer));
@@ -685,7 +687,7 @@
   EXPECT_EQ(buffer.length(), 0);    // NOLINT
   EXPECT_GT(buffer.capacity(), 0);  // NOLINT
 
-  EXPECT_THAT(cord.Chunks(), ::testing::ElementsAre("defghAbc"));
+  EXPECT_THAT(cord.Chunks(), ElementsAre("defghAbc"));
 }
 
 TEST_P(CordTest, AppendLargeBuffer) {
@@ -707,7 +709,7 @@
   EXPECT_EQ(buffer.length(), 0);    // NOLINT
   EXPECT_GT(buffer.capacity(), 0);  // NOLINT
 
-  EXPECT_THAT(cord.Chunks(), ::testing::ElementsAre(s1, s2));
+  EXPECT_THAT(cord.Chunks(), ElementsAre(s1, s2));
 }
 
 TEST_P(CordTest, PrependLargeBuffer) {
@@ -729,7 +731,7 @@
   EXPECT_EQ(buffer.length(), 0);    // NOLINT
   EXPECT_GT(buffer.capacity(), 0);  // NOLINT
 
-  EXPECT_THAT(cord.Chunks(), ::testing::ElementsAre(s2, s1));
+  EXPECT_THAT(cord.Chunks(), ElementsAre(s2, s1));
 }
 
 class CordAppendBufferTest : public testing::TestWithParam<bool> {
diff --git a/absl/strings/internal/str_format/float_conversion.cc b/absl/strings/internal/str_format/float_conversion.cc
index fe0ad4b..f1490e5 100644
--- a/absl/strings/internal/str_format/float_conversion.cc
+++ b/absl/strings/internal/str_format/float_conversion.cc
@@ -1015,7 +1015,7 @@
     --end;
   }
 
-  char &back() {
+  char &back() const {
     assert(begin < end);
     return end[-1];
   }
diff --git a/absl/strings/str_split.cc b/absl/strings/str_split.cc
index e08c26b..72ba7c0 100644
--- a/absl/strings/str_split.cc
+++ b/absl/strings/str_split.cc
@@ -60,19 +60,23 @@
 // Finds using absl::string_view::find(), therefore the length of the found
 // delimiter is delimiter.length().
 struct LiteralPolicy {
-  size_t Find(absl::string_view text, absl::string_view delimiter, size_t pos) {
+  static size_t Find(absl::string_view text, absl::string_view delimiter,
+                     size_t pos) {
     return text.find(delimiter, pos);
   }
-  size_t Length(absl::string_view delimiter) { return delimiter.length(); }
+  static size_t Length(absl::string_view delimiter) {
+    return delimiter.length();
+  }
 };
 
 // Finds using absl::string_view::find_first_of(), therefore the length of the
 // found delimiter is 1.
 struct AnyOfPolicy {
-  size_t Find(absl::string_view text, absl::string_view delimiter, size_t pos) {
+  static size_t Find(absl::string_view text, absl::string_view delimiter,
+                     size_t pos) {
     return text.find_first_of(delimiter, pos);
   }
-  size_t Length(absl::string_view /* delimiter */) { return 1; }
+  static size_t Length(absl::string_view /* delimiter */) { return 1; }
 };
 
 }  // namespace
@@ -123,8 +127,7 @@
   ABSL_RAW_CHECK(length > 0, "");
 }
 
-absl::string_view ByLength::Find(absl::string_view text,
-                                      size_t pos) const {
+absl::string_view ByLength::Find(absl::string_view text, size_t pos) const {
   pos = std::min(pos, text.size());  // truncate `pos`
   absl::string_view substr = text.substr(pos);
   // If the string is shorter than the chunk size we say we
diff --git a/absl/synchronization/internal/futex.h b/absl/synchronization/internal/futex.h
index 9cf9841..8d97326 100644
--- a/absl/synchronization/internal/futex.h
+++ b/absl/synchronization/internal/futex.h
@@ -16,9 +16,7 @@
 
 #include "absl/base/config.h"
 
-#ifdef _WIN32
-#include <windows.h>
-#else
+#ifndef _WIN32
 #include <sys/time.h>
 #include <unistd.h>
 #endif
@@ -85,34 +83,70 @@
 
 class FutexImpl {
  public:
-  static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
+  // Atomically check that `*v == val`, and if it is, then sleep until the
+  // timeout `t` has been reached, or until woken by `Wake()`.
+  static int WaitUntil(std::atomic<int32_t>* v, int32_t val,
                        KernelTimeout t) {
-    long err = 0;  // NOLINT(runtime/int)
-    if (t.has_timeout()) {
-      // https://locklessinc.com/articles/futex_cheat_sheet/
-      // Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time.
-      struct timespec abs_timeout = t.MakeAbsTimespec();
-      // Atomically check that the futex value is still 0, and if it
-      // is, sleep until abs_timeout or until woken by FUTEX_WAKE.
-      err = syscall(
-          SYS_futex, reinterpret_cast<int32_t *>(v),
-          FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val,
-          &abs_timeout, nullptr, FUTEX_BITSET_MATCH_ANY);
+    // Monotonic waits are disabled for production builds because go/btm
+    // requires synchronized clocks.
+    // TODO(b/160682823): Find a way to enable this when BTM is not enabled
+    // since production builds don't always run on Borg.
+#if defined(CLOCK_MONOTONIC) && !defined(__GOOGLE_GRTE_VERSION__)
+    constexpr bool kRelativeTimeoutSupported = true;
+#else
+    constexpr bool kRelativeTimeoutSupported = false;
+#endif
+
+    if (!t.has_timeout()) {
+      return Wait(v, val);
+    } else if (kRelativeTimeoutSupported && t.is_relative_timeout()) {
+      auto rel_timespec = t.MakeRelativeTimespec();
+      return WaitRelativeTimeout(v, val, &rel_timespec);
     } else {
-      // Atomically check that the futex value is still 0, and if it
-      // is, sleep until woken by FUTEX_WAKE.
-      err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
-                    FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr);
+      auto abs_timespec = t.MakeAbsTimespec();
+      return WaitAbsoluteTimeout(v, val, &abs_timespec);
     }
-    if (ABSL_PREDICT_FALSE(err != 0)) {
+  }
+
+  // Atomically check that `*v == val`, and if it is, then sleep until the until
+  // woken by `Wake()`.
+  static int Wait(std::atomic<int32_t>* v, int32_t val) {
+    return WaitAbsoluteTimeout(v, val, nullptr);
+  }
+
+  // Atomically check that `*v == val`, and if it is, then sleep until
+  // CLOCK_REALTIME reaches `*abs_timeout`, or until woken by `Wake()`.
+  static int WaitAbsoluteTimeout(std::atomic<int32_t>* v, int32_t val,
+                                 const struct timespec* abs_timeout) {
+    // https://locklessinc.com/articles/futex_cheat_sheet/
+    // Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time.
+    auto err =
+        syscall(SYS_futex, reinterpret_cast<int32_t*>(v),
+                FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME,
+                val, abs_timeout, nullptr, FUTEX_BITSET_MATCH_ANY);
+    if (err != 0) {
       return -errno;
     }
     return 0;
   }
 
-  static int Wake(std::atomic<int32_t> *v, int32_t count) {
-    // NOLINTNEXTLINE(runtime/int)
-    long err = syscall(SYS_futex, reinterpret_cast<int32_t*>(v),
+  // Atomically check that `*v == val`, and if it is, then sleep until
+  // `*rel_timeout` has elapsed, or until woken by `Wake()`.
+  static int WaitRelativeTimeout(std::atomic<int32_t>* v, int32_t val,
+                                 const struct timespec* rel_timeout) {
+    // Atomically check that the futex value is still 0, and if it
+    // is, sleep until abs_timeout or until woken by FUTEX_WAKE.
+    auto err = syscall(SYS_futex, reinterpret_cast<int32_t*>(v),
+                       FUTEX_PRIVATE_FLAG, val, rel_timeout);
+    if (err != 0) {
+      return -errno;
+    }
+    return 0;
+  }
+
+  // Wakes at most `count` waiters that have entered the sleep state on `v`.
+  static int Wake(std::atomic<int32_t>* v, int32_t count) {
+    auto err = syscall(SYS_futex, reinterpret_cast<int32_t*>(v),
                        FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count);
     if (ABSL_PREDICT_FALSE(err < 0)) {
       return -errno;
diff --git a/absl/synchronization/internal/kernel_timeout.cc b/absl/synchronization/internal/kernel_timeout.cc
index 548a8fc..2e48509 100644
--- a/absl/synchronization/internal/kernel_timeout.cc
+++ b/absl/synchronization/internal/kernel_timeout.cc
@@ -32,6 +32,18 @@
 constexpr int64_t KernelTimeout::kMaxNanos;
 #endif
 
+int64_t KernelTimeout::SteadyClockNow() {
+#ifdef __GOOGLE_GRTE_VERSION__
+  // go/btm requires synchronized clocks, so we have to use the system
+  // clock.
+  return absl::GetCurrentTimeNanos();
+#else
+  return std::chrono::duration_cast<std::chrono::nanoseconds>(
+             std::chrono::steady_clock::now().time_since_epoch())
+      .count();
+#endif
+}
+
 KernelTimeout::KernelTimeout(absl::Time t) {
   // `absl::InfiniteFuture()` is a common "no timeout" value and cheaper to
   // compare than convert.
@@ -73,12 +85,14 @@
     nanos = 0;
   }
 
-  // Values greater than or equal to kMaxNanos are converted to infinite.
-  if (nanos >= kMaxNanos) {
+  int64_t now = SteadyClockNow();
+  if (nanos > kMaxNanos - now) {
+    // Durations that would be greater than kMaxNanos are converted to infinite.
     rep_ = kNoTimeout;
     return;
   }
 
+  nanos += now;
   rep_ = (static_cast<uint64_t>(nanos) << 1) | uint64_t{1};
 }
 
@@ -90,6 +104,9 @@
   int64_t nanos = RawNanos();
 
   if (is_relative_timeout()) {
+    // We need to change epochs, because the relative timeout might be
+    // represented by an absolute timestamp from another clock.
+    nanos = std::max<int64_t>(nanos - SteadyClockNow(), 0);
     int64_t now = absl::GetCurrentTimeNanos();
     if (nanos > kMaxNanos - now) {
       // Overflow.
@@ -106,27 +123,24 @@
   return nanos;
 }
 
+int64_t KernelTimeout::InNanosecondsFromNow() const {
+  if (!has_timeout()) {
+    return kMaxNanos;
+  }
+
+  int64_t nanos = RawNanos();
+  if (is_absolute_timeout()) {
+    return std::max<int64_t>(nanos - absl::GetCurrentTimeNanos(), 0);
+  }
+  return std::max<int64_t>(nanos - SteadyClockNow(), 0);
+}
+
 struct timespec KernelTimeout::MakeAbsTimespec() const {
   return absl::ToTimespec(absl::Nanoseconds(MakeAbsNanos()));
 }
 
 struct timespec KernelTimeout::MakeRelativeTimespec() const {
-  if (!has_timeout()) {
-    return absl::ToTimespec(absl::Nanoseconds(kMaxNanos));
-  }
-  if (is_relative_timeout()) {
-    return absl::ToTimespec(absl::Nanoseconds(RawNanos()));
-  }
-
-  int64_t nanos = RawNanos();
-  int64_t now = absl::GetCurrentTimeNanos();
-  if (now > nanos) {
-    // Convert past values to 0 to be safe.
-    nanos = 0;
-  } else {
-    nanos -= now;
-  }
-  return absl::ToTimespec(absl::Nanoseconds(nanos));
+  return absl::ToTimespec(absl::Nanoseconds(InNanosecondsFromNow()));
 }
 
 KernelTimeout::DWord KernelTimeout::InMillisecondsFromNow() const {
@@ -136,32 +150,21 @@
     return kInfinite;
   }
 
-  const int64_t nanos = RawNanos();
-  constexpr uint64_t kNanosInMillis = uint64_t{1000000};
+  constexpr uint64_t kNanosInMillis = uint64_t{1'000'000};
+  constexpr uint64_t kMaxValueNanos =
+      std::numeric_limits<int64_t>::max() - kNanosInMillis + 1;
 
-  if (is_relative_timeout()) {
-    uint64_t ms = static_cast<uint64_t>(nanos) / kNanosInMillis;
-    if (ms > static_cast<uint64_t>(kInfinite)) {
-      ms = static_cast<uint64_t>(kInfinite);
-    }
-    return static_cast<DWord>(ms);
+  uint64_t ns_from_now = static_cast<uint64_t>(InNanosecondsFromNow());
+  if (ns_from_now >= kMaxValueNanos) {
+    // Rounding up would overflow.
+    return kInfinite;
   }
-
-  int64_t now = absl::GetCurrentTimeNanos();
-  if (nanos >= now) {
-    // Round up so that now + ms_from_now >= nanos.
-    constexpr uint64_t kMaxValueNanos =
-        std::numeric_limits<int64_t>::max() - kNanosInMillis + 1;
-    uint64_t ms_from_now =
-        (std::min(kMaxValueNanos, static_cast<uint64_t>(nanos - now)) +
-         kNanosInMillis - 1) /
-        kNanosInMillis;
-    if (ms_from_now > kInfinite) {
-      return kInfinite;
-    }
-    return static_cast<DWord>(ms_from_now);
+  // Convert to milliseconds, always rounding up.
+  uint64_t ms_from_now = (ns_from_now + kNanosInMillis - 1) / kNanosInMillis;
+  if (ms_from_now > kInfinite) {
+    return kInfinite;
   }
-  return DWord{0};
+  return static_cast<DWord>(ms_from_now);
 }
 
 std::chrono::time_point<std::chrono::system_clock>
@@ -174,16 +177,7 @@
   // std::ratio used by std::chrono::steady_clock doesn't convert to
   // std::nanoseconds, so it doesn't compile.
   auto micros = std::chrono::duration_cast<std::chrono::microseconds>(
-      std::chrono::nanoseconds(RawNanos()));
-  if (is_relative_timeout()) {
-    auto now = std::chrono::system_clock::now();
-    if (micros >
-        std::chrono::time_point<std::chrono::system_clock>::max() - now) {
-      // Overflow.
-      return std::chrono::time_point<std::chrono::system_clock>::max();
-    }
-    return now + micros;
-  }
+      std::chrono::nanoseconds(MakeAbsNanos()));
   return std::chrono::system_clock::from_time_t(0) + micros;
 }
 
@@ -191,17 +185,7 @@
   if (!has_timeout()) {
     return std::chrono::nanoseconds::max();
   }
-  if (is_absolute_timeout()) {
-    auto d = std::chrono::duration_cast<std::chrono::nanoseconds>(
-        std::chrono::nanoseconds(RawNanos()) -
-        (std::chrono::system_clock::now() -
-         std::chrono::system_clock::from_time_t(0)));
-    if (d < std::chrono::nanoseconds(0)) {
-      d = std::chrono::nanoseconds(0);
-    }
-    return d;
-  }
-  return std::chrono::nanoseconds(RawNanos());
+  return std::chrono::nanoseconds(InNanosecondsFromNow());
 }
 
 }  // namespace synchronization_internal
diff --git a/absl/synchronization/internal/kernel_timeout.h b/absl/synchronization/internal/kernel_timeout.h
index f7c4033..e2cf3c2 100644
--- a/absl/synchronization/internal/kernel_timeout.h
+++ b/absl/synchronization/internal/kernel_timeout.h
@@ -75,7 +75,9 @@
   // Convert to `struct timespec` for interfaces that expect a relative
   // timeout. If !has_timeout() or is_absolute_timeout(), attempts to convert to
   // a reasonable relative timeout, but callers should to test has_timeout() and
-  // is_absolute_timeout() and prefer to use a more appropriate interface.
+  // is_absolute_timeout() and prefer to use a more appropriate interface. Since
+  // the return value is a relative duration, it should be recomputed by calling
+  // this method in the case of a spurious wakeup.
   struct timespec MakeRelativeTimespec() const;
 
   // Convert to unix epoch nanos for interfaces that expect an absolute timeout
@@ -107,17 +109,24 @@
   // timeout, like std::condition_variable::wait_for(). If !has_timeout() or
   // is_absolute_timeout(), attempts to convert to a reasonable relative
   // timeout, but callers should test has_timeout() and is_absolute_timeout()
-  // and prefer to use a more appropriate interface.
+  // and prefer to use a more appropriate interface. Since the return value is a
+  // relative duration, it should be recomputed by calling this method in the
+  // case of a spurious wakeup.
   std::chrono::nanoseconds ToChronoDuration() const;
 
  private:
+  // Returns the current time, expressed as a count of nanoseconds since the
+  // epoch used by an arbitrary clock. The implementation tries to use a steady
+  // (monotonic) clock if one is available.
+  static int64_t SteadyClockNow();
+
   // Internal representation.
   //   - If the value is kNoTimeout, then the timeout is infinite, and
   //     has_timeout() will return true.
-  //   - If the low bit is 0, then the high 63 bits is number of nanoseconds
+  //   - If the low bit is 0, then the high 63 bits is the number of nanoseconds
   //     after the unix epoch.
-  //   - If the low bit is 1, then the high 63 bits is a relative duration in
-  //     nanoseconds.
+  //   - If the low bit is 1, then the high 63 bits is the number of nanoseconds
+  //     after the epoch used by SteadyClockNow().
   uint64_t rep_;
 
   // Returns the number of nanoseconds stored in the internal representation.
@@ -125,6 +134,11 @@
   // value is used to compute when the timeout should occur.
   int64_t RawNanos() const { return static_cast<int64_t>(rep_ >> 1); }
 
+  // Converts to nanoseconds from now. Since the return value is a relative
+  // duration, it should be recomputed by calling this method in the case of a
+  // spurious wakeup.
+  int64_t InNanosecondsFromNow() const;
+
   // A value that represents no timeout (or an infinite timeout).
   static constexpr uint64_t kNoTimeout = (std::numeric_limits<uint64_t>::max)();
 
diff --git a/absl/synchronization/internal/kernel_timeout_test.cc b/absl/synchronization/internal/kernel_timeout_test.cc
index 431ffcf..a96f806 100644
--- a/absl/synchronization/internal/kernel_timeout_test.cc
+++ b/absl/synchronization/internal/kernel_timeout_test.cc
@@ -62,9 +62,6 @@
     EXPECT_TRUE(t.is_absolute_timeout());
     EXPECT_FALSE(t.is_relative_timeout());
     EXPECT_EQ(absl::TimeFromTimespec(t.MakeAbsTimespec()), when);
-    // MakeRelativeTimespec() doesn't quite round trip when using an absolute
-    // time, but it should get pretty close. Past times are converted to zero
-    // durations.
     EXPECT_LE(
         absl::AbsDuration(absl::DurationFromTimespec(t.MakeRelativeTimespec()) -
                           std::max(duration, absl::ZeroDuration())),
@@ -201,7 +198,10 @@
     EXPECT_LE(absl::AbsDuration(absl::Now() + duration -
                                 absl::TimeFromTimespec(t.MakeAbsTimespec())),
               absl::Milliseconds(5));
-    EXPECT_EQ(absl::DurationFromTimespec(t.MakeRelativeTimespec()), duration);
+    EXPECT_LE(
+        absl::AbsDuration(absl::DurationFromTimespec(t.MakeRelativeTimespec()) -
+                          duration),
+        kTimingBound);
     EXPECT_LE(absl::AbsDuration(absl::Now() + duration -
                                 absl::FromUnixNanos(t.MakeAbsNanos())),
               absl::Milliseconds(5));
@@ -210,7 +210,9 @@
     EXPECT_LE(absl::AbsDuration(absl::Now() + duration -
                                 absl::FromChrono(t.ToChronoTimePoint())),
               kTimingBound);
-    EXPECT_EQ(absl::FromChrono(t.ToChronoDuration()), duration);
+    EXPECT_LE(
+        absl::AbsDuration(absl::FromChrono(t.ToChronoDuration()) - duration),
+        kTimingBound);
   }
 }
 
@@ -298,7 +300,6 @@
   int64_t limit = std::numeric_limits<int64_t>::max() - now_nanos;
   absl::Duration duration = absl::Nanoseconds(limit) + absl::Seconds(1);
   KernelTimeout t(duration);
-  EXPECT_TRUE(t.has_timeout());
   // Timeouts should still be far in the future.
   EXPECT_GT(absl::TimeFromTimespec(t.MakeAbsTimespec()),
             absl::Now() + absl::Hours(100000));
diff --git a/absl/synchronization/internal/waiter.cc b/absl/synchronization/internal/waiter.cc
index f2051d6..1b8d8d0 100644
--- a/absl/synchronization/internal/waiter.cc
+++ b/absl/synchronization/internal/waiter.cc
@@ -48,7 +48,6 @@
 #include "absl/base/optimization.h"
 #include "absl/synchronization/internal/kernel_timeout.h"
 
-
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace synchronization_internal {
@@ -67,9 +66,7 @@
 
 #if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX
 
-Waiter::Waiter() {
-  futex_.store(0, std::memory_order_relaxed);
-}
+Waiter::Waiter() : futex_(0) {}
 
 bool Waiter::Wait(KernelTimeout t) {
   // Loop until we can atomically decrement futex from a positive
diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc
index ef6d063..a891161 100644
--- a/absl/synchronization/mutex.cc
+++ b/absl/synchronization/mutex.cc
@@ -635,21 +635,6 @@
                                  std::memory_order_release);
 }
 
-// --------------------------time support
-
-// Return the current time plus the timeout.  Use the same clock as
-// PerThreadSem::Wait() for consistency.  Unfortunately, we don't have
-// such a choice when a deadline is given directly.
-static absl::Time DeadlineFromTimeout(absl::Duration timeout) {
-#ifndef _WIN32
-  struct timeval tv;
-  gettimeofday(&tv, nullptr);
-  return absl::TimeFromTimeval(tv) + timeout;
-#else
-  return absl::Now() + timeout;
-#endif
-}
-
 // --------------------------Mutexes
 
 // In the layout below, the msb of the bottom byte is currently unused.  Also,
@@ -1549,7 +1534,13 @@
 }
 
 bool Mutex::LockWhenWithTimeout(const Condition &cond, absl::Duration timeout) {
-  return LockWhenWithDeadline(cond, DeadlineFromTimeout(timeout));
+  ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
+  GraphId id = DebugOnlyDeadlockCheck(this);
+  bool res = LockSlowWithDeadline(kExclusive, &cond,
+                                  KernelTimeout(timeout), 0);
+  DebugOnlyLockEnter(this, id);
+  ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
+  return res;
 }
 
 bool Mutex::LockWhenWithDeadline(const Condition &cond, absl::Time deadline) {
@@ -1572,7 +1563,12 @@
 
 bool Mutex::ReaderLockWhenWithTimeout(const Condition &cond,
                                       absl::Duration timeout) {
-  return ReaderLockWhenWithDeadline(cond, DeadlineFromTimeout(timeout));
+  ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_read_lock);
+  GraphId id = DebugOnlyDeadlockCheck(this);
+  bool res = LockSlowWithDeadline(kShared, &cond, KernelTimeout(timeout), 0);
+  DebugOnlyLockEnter(this, id);
+  ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_read_lock, 0);
+  return res;
 }
 
 bool Mutex::ReaderLockWhenWithDeadline(const Condition &cond,
@@ -1597,7 +1593,18 @@
 }
 
 bool Mutex::AwaitWithTimeout(const Condition &cond, absl::Duration timeout) {
-  return AwaitWithDeadline(cond, DeadlineFromTimeout(timeout));
+  if (cond.Eval()) {      // condition already true; nothing to do
+    if (kDebugMode) {
+      this->AssertReaderHeld();
+    }
+    return true;
+  }
+
+  KernelTimeout t{timeout};
+  bool res = this->AwaitCommon(cond, t);
+  ABSL_RAW_CHECK(res || t.has_timeout(),
+                 "condition untrue on return from Await");
+  return res;
 }
 
 bool Mutex::AwaitWithDeadline(const Condition &cond, absl::Time deadline) {
@@ -2663,7 +2670,7 @@
 }
 
 bool CondVar::WaitWithTimeout(Mutex *mu, absl::Duration timeout) {
-  return WaitWithDeadline(mu, DeadlineFromTimeout(timeout));
+  return WaitCommon(mu, KernelTimeout(timeout));
 }
 
 bool CondVar::WaitWithDeadline(Mutex *mu, absl::Time deadline) {
diff --git a/absl/time/BUILD.bazel b/absl/time/BUILD.bazel
index c7b07c2..88d2088 100644
--- a/absl/time/BUILD.bazel
+++ b/absl/time/BUILD.bazel
@@ -91,6 +91,7 @@
         "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/numeric:int128",
+        "//absl/strings:str_format",
         "//absl/time/internal/cctz:time_zone",
         "@com_google_googletest//:gtest_main",
     ],
diff --git a/absl/time/CMakeLists.txt b/absl/time/CMakeLists.txt
index 7b72054..b312425 100644
--- a/absl/time/CMakeLists.txt
+++ b/absl/time/CMakeLists.txt
@@ -122,6 +122,8 @@
     absl::time
     absl::config
     absl::core_headers
+    absl::strings
+    absl::str_format
     absl::time_zone
     GTest::gmock_main
 )
diff --git a/absl/time/duration_test.cc b/absl/time/duration_test.cc
index b7abf4b..76d3217 100644
--- a/absl/time/duration_test.cc
+++ b/absl/time/duration_test.cc
@@ -16,8 +16,8 @@
 #include <winsock2.h>  // for timeval
 #endif
 
-#include <chrono>  // NOLINT(build/c++11)
 #include <cfloat>
+#include <chrono>  // NOLINT(build/c++11)
 #include <cmath>
 #include <cstdint>
 #include <ctime>
@@ -28,6 +28,7 @@
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/strings/str_format.h"
 #include "absl/time/time.h"
 
 namespace {
@@ -1853,4 +1854,11 @@
 #undef TEST_PARSE_ROUNDTRIP
 }
 
+TEST(Duration, AbslStringify) {
+  // FormatDuration is already well tested, so just use one test case here to
+  // verify that StrFormat("%v", d) works as expected.
+  absl::Duration d = absl::Seconds(1);
+  EXPECT_EQ(absl::StrFormat("%v", d), absl::FormatDuration(d));
+}
+
 }  // namespace
diff --git a/absl/time/time.h b/absl/time/time.h
index cc39008..01b5532 100644
--- a/absl/time/time.h
+++ b/absl/time/time.h
@@ -609,6 +609,12 @@
   return os << FormatDuration(d);
 }
 
+// Support for StrFormat(), StrCat() etc.
+template <typename Sink>
+void AbslStringify(Sink& sink, Duration d) {
+  sink.Append(FormatDuration(d));
+}
+
 // ParseDuration()
 //
 // Parses a duration string consisting of a possibly signed sequence of
@@ -1386,6 +1392,12 @@
   return os << FormatTime(t);
 }
 
+// Support for StrFormat(), StrCat() etc.
+template <typename Sink>
+void AbslStringify(Sink& sink, Time t) {
+  sink.Append(FormatTime(t));
+}
+
 // ParseTime()
 //
 // Parses an input string according to the provided format string and
diff --git a/absl/time/time_test.cc b/absl/time/time_test.cc
index d235e9a..6a89399 100644
--- a/absl/time/time_test.cc
+++ b/absl/time/time_test.cc
@@ -28,6 +28,7 @@
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "absl/numeric/int128.h"
+#include "absl/strings/str_format.h"
 #include "absl/time/clock.h"
 #include "absl/time/internal/test_util.h"
 
@@ -1287,4 +1288,11 @@
   // We have a transition but we don't know which one.
 }
 
+TEST(Time, AbslStringify) {
+  // FormatTime is already well tested, so just use one test case here to
+  // verify that StrFormat("%v", t) works as expected.
+  absl::Time t = absl::Now();
+  EXPECT_EQ(absl::StrFormat("%v", t), absl::FormatTime(t));
+}
+
 }  // namespace