Roll abseil_revision 436ba6c4a0..27c30ec671.

Change Log:
https://chromium.googlesource.com/external/github.com/abseil/abseil-cpp/+log/436ba6c4a0..27c30ec671
Full diff:
https://chromium.googlesource.com/external/github.com/abseil/abseil-cpp/+/436ba6c4a0..27c30ec671

Bug: None
Change-Id: Iafc0aabd56d9f5506774a37427718f616bdff7d9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1626859
Reviewed-by: Nico Weber <thakis@chromium.org>
Commit-Queue: Mirko Bonadei <mbonadei@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#662640}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 8f6f8bc75db2ca8e45cc7f3956b096b170049a33
diff --git a/README.chromium b/README.chromium
index 332c140..2edc12f 100644
--- a/README.chromium
+++ b/README.chromium
@@ -4,7 +4,7 @@
 License: Apache 2.0
 License File: LICENSE
 Version: 0
-Revision: 436ba6c4a0ea3a06eca6e055f9c8d296bf3bae12
+Revision: 27c30ec671cb7b5ba84c4e79feff7fd0b0ac6338
 Security Critical: yes
 
 Description:
diff --git a/absl/base/call_once.h b/absl/base/call_once.h
index 8c4f297..e7fc230 100644
--- a/absl/base/call_once.h
+++ b/absl/base/call_once.h
@@ -29,6 +29,7 @@
 #include <atomic>
 #include <cstdint>
 #include <type_traits>
+#include <utility>
 
 #include "absl/base/internal/invoke.h"
 #include "absl/base/internal/low_level_scheduling.h"
@@ -36,6 +37,7 @@
 #include "absl/base/internal/scheduling_mode.h"
 #include "absl/base/internal/spinlock_wait.h"
 #include "absl/base/macros.h"
+#include "absl/base/optimization.h"
 #include "absl/base/port.h"
 
 namespace absl {
diff --git a/absl/base/casts.h b/absl/base/casts.h
index a381c42..aba0178 100644
--- a/absl/base/casts.h
+++ b/absl/base/casts.h
@@ -27,6 +27,7 @@
 #include <cstring>
 #include <memory>
 #include <type_traits>
+#include <utility>
 
 #include "absl/base/internal/identity.h"
 #include "absl/base/macros.h"
diff --git a/absl/base/internal/low_level_alloc.cc b/absl/base/internal/low_level_alloc.cc
index 1356167..cd526b3 100644
--- a/absl/base/internal/low_level_alloc.cc
+++ b/absl/base/internal/low_level_alloc.cc
@@ -294,7 +294,10 @@
     arena_->mu.Unlock();
 #ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
     if (mask_valid_) {
-      pthread_sigmask(SIG_SETMASK, &mask_, nullptr);
+      const int err = pthread_sigmask(SIG_SETMASK, &mask_, nullptr);
+      if (err != 0) {
+        ABSL_RAW_LOG(FATAL, "pthread_sigmask failed: %d", err);
+      }
     }
 #endif
     left_ = true;
diff --git a/absl/base/internal/low_level_alloc.h b/absl/base/internal/low_level_alloc.h
index b35673d..c98cdb3 100644
--- a/absl/base/internal/low_level_alloc.h
+++ b/absl/base/internal/low_level_alloc.h
@@ -25,6 +25,7 @@
 // IWYU pragma: private, include "base/low_level_alloc.h"
 
 #include <sys/types.h>
+
 #include <cstdint>
 
 #include "absl/base/attributes.h"
diff --git a/absl/base/internal/spinlock.h b/absl/base/internal/spinlock.h
index f05ad83..ecda792 100644
--- a/absl/base/internal/spinlock.h
+++ b/absl/base/internal/spinlock.h
@@ -32,6 +32,7 @@
 
 #include <stdint.h>
 #include <sys/types.h>
+
 #include <atomic>
 
 #include "absl/base/attributes.h"
@@ -57,8 +58,10 @@
   //
   //    static SpinLock lock(base_internal::kLinkerInitialized);
   //
-  // When intialized using this constructor, we depend on the fact
-  // that the linker has already initialized the memory appropriately.
+  // When initialized using this constructor, we depend on the fact
+  // that the linker has already initialized the memory appropriately. The lock
+  // is initialized in non-cooperative mode.
+  //
   // A SpinLock constructed like this can be freely used from global
   // initializers without worrying about the order in which global
   // initializers run.
diff --git a/absl/base/macros.h b/absl/base/macros.h
index ca62079..606a90a 100644
--- a/absl/base/macros.h
+++ b/absl/base/macros.h
@@ -31,6 +31,7 @@
 #include <cassert>
 #include <cstddef>
 
+#include "absl/base/optimization.h"
 #include "absl/base/port.h"
 
 // ABSL_ARRAYSIZE()
diff --git a/absl/base/optimization.h b/absl/base/optimization.h
index 6974f1f..0dcbef3 100644
--- a/absl/base/optimization.h
+++ b/absl/base/optimization.h
@@ -163,6 +163,12 @@
 // Compilers can use the information that a certain branch is not likely to be
 // taken (for instance, a CHECK failure) to optimize for the common case in
 // the absence of better information (ie. compiling gcc with `-fprofile-arcs`).
+//
+// Recommendation: Modern CPUs dynamically predict branch execution paths,
+// typically with accuracy greater than 97%. As a result, annotating every
+// branch in a codebase is likely counterproductive; however, annotating
+// specific branches that are both hot and consistently mispredicted is likely
+// to yield performance improvements.
 #if ABSL_HAVE_BUILTIN(__builtin_expect) || \
     (defined(__GNUC__) && !defined(__clang__))
 #define ABSL_PREDICT_FALSE(x) (__builtin_expect(x, 0))
diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h
index 61e0cfb..564c953 100644
--- a/absl/container/inlined_vector.h
+++ b/absl/container/inlined_vector.h
@@ -155,7 +155,7 @@
 
   // Creates a copy of an `other` inlined vector using `other`'s allocator.
   InlinedVector(const InlinedVector& other)
-      : InlinedVector(other, other.storage_.GetAllocator()) {}
+      : InlinedVector(other, *other.storage_.GetAllocPtr()) {}
 
   // Creates a copy of an `other` inlined vector using a specified allocator.
   InlinedVector(const InlinedVector& other, const allocator_type& alloc)
@@ -189,7 +189,7 @@
   InlinedVector(InlinedVector&& other) noexcept(
       absl::allocator_is_nothrow<allocator_type>::value ||
       std::is_nothrow_move_constructible<value_type>::value)
-      : storage_(other.storage_.GetAllocator()) {
+      : storage_(*other.storage_.GetAllocPtr()) {
     if (other.storage_.GetIsAllocated()) {
       // We can just steal the underlying buffer from the source.
       // That leaves the source empty, so we clear its size.
@@ -224,7 +224,7 @@
       absl::allocator_is_nothrow<allocator_type>::value)
       : storage_(alloc) {
     if (other.storage_.GetIsAllocated()) {
-      if (alloc == other.storage_.GetAllocator()) {
+      if (*storage_.GetAllocPtr() == *other.storage_.GetAllocPtr()) {
         // We can just steal the allocation from the source.
         storage_.SetAllocatedSize(other.size());
         storage_.SetAllocatedData(other.storage_.GetAllocatedData());
@@ -437,7 +437,7 @@
   // `InlinedVector::get_allocator()`
   //
   // Returns a copy of the allocator of the inlined vector.
-  allocator_type get_allocator() const { return storage_.GetAllocator(); }
+  allocator_type get_allocator() const { return *storage_.GetAllocPtr(); }
 
   // ---------------------------------------------------------------------------
   // InlinedVector Member Mutators
@@ -448,24 +448,16 @@
   // Replaces the contents of the inlined vector with copies of the elements in
   // the provided `std::initializer_list`.
   InlinedVector& operator=(std::initializer_list<value_type> list) {
-    AssignForwardRange(list.begin(), list.end());
+    assign(list.begin(), list.end());
     return *this;
   }
 
   // Overload of `InlinedVector::operator=()` to replace the contents of the
   // inlined vector with the contents of `other`.
   InlinedVector& operator=(const InlinedVector& other) {
-    if (ABSL_PREDICT_FALSE(this == std::addressof(other))) return *this;
-
-    // Optimized to avoid reallocation.
-    // Prefer reassignment to copy construction for elements.
-    if (size() < other.size()) {  // grow
-      reserve(other.size());
-      std::copy(other.begin(), other.begin() + size(), begin());
-      std::copy(other.begin() + size(), other.end(), std::back_inserter(*this));
-    } else {  // maybe shrink
-      erase(begin() + other.size(), end());
-      std::copy(other.begin(), other.end(), begin());
+    if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
+      const_pointer other_data = other.data();
+      assign(other_data, other_data + other.size());
     }
     return *this;
   }
@@ -528,7 +520,7 @@
   // inlined vector with copies of the values in the provided
   // `std::initializer_list`.
   void assign(std::initializer_list<value_type> list) {
-    AssignForwardRange(list.begin(), list.end());
+    assign(list.begin(), list.end());
   }
 
   // Overload of `InlinedVector::assign()` to replace the contents of the
@@ -536,7 +528,24 @@
   template <typename ForwardIterator,
             EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
   void assign(ForwardIterator first, ForwardIterator last) {
-    AssignForwardRange(first, last);
+    auto length = std::distance(first, last);
+
+    // Prefer reassignment to copy construction for elements.
+    if (static_cast<size_type>(length) <= size()) {
+      erase(std::copy(first, last, begin()), end());
+      return;
+    }
+
+    reserve(length);
+    iterator out = begin();
+    for (; out != end(); ++first, ++out) *out = *first;
+    if (storage_.GetIsAllocated()) {
+      UninitializedCopy(first, last, out);
+      storage_.SetAllocatedSize(length);
+    } else {
+      UninitializedCopy(first, last, out);
+      storage_.SetInlinedSize(length);
+    }
   }
 
   // Overload of `InlinedVector::assign()` to replace the contents of the
@@ -785,19 +794,15 @@
   // deallocates the heap allocation if the inlined vector was allocated.
   void clear() noexcept {
     const bool is_allocated = storage_.GetIsAllocated();
-
     pointer the_data =
         is_allocated ? storage_.GetAllocatedData() : storage_.GetInlinedData();
-
-    inlined_vector_internal::DestroyElements(storage_.GetAllocator(), the_data,
+    inlined_vector_internal::DestroyElements(storage_.GetAllocPtr(), the_data,
                                              storage_.GetSize());
-
+    storage_.SetInlinedSize(0);
     if (is_allocated) {
-      AllocatorTraits::deallocate(storage_.GetAllocator(), the_data,
+      AllocatorTraits::deallocate(*storage_.GetAllocPtr(), the_data,
                                   storage_.GetAllocatedCapacity());
     }
-
-    storage_.SetInlinedSize(/* size = */ 0);
   }
 
   // `InlinedVector::reserve()`
@@ -845,7 +850,7 @@
     // Reallocate storage and move elements.
     // We can't simply use the same approach as above, because `assign()` would
     // call into `reserve()` internally and reserve larger capacity than we need
-    pointer new_data = AllocatorTraits::allocate(storage_.GetAllocator(), s);
+    pointer new_data = AllocatorTraits::allocate(*storage_.GetAllocPtr(), s);
     UninitializedCopy(std::make_move_iterator(storage_.GetAllocatedData()),
                       std::make_move_iterator(storage_.GetAllocatedData() + s),
                       new_data);
@@ -871,7 +876,7 @@
       Destroy(storage_.GetAllocatedData(),
               storage_.GetAllocatedData() + size());
       assert(begin() == storage_.GetAllocatedData());
-      AllocatorTraits::deallocate(storage_.GetAllocator(),
+      AllocatorTraits::deallocate(*storage_.GetAllocPtr(),
                                   storage_.GetAllocatedData(),
                                   storage_.GetAllocatedCapacity());
     } else {
@@ -886,7 +891,7 @@
   template <typename... Args>
   reference Construct(pointer p, Args&&... args) {
     std::allocator_traits<allocator_type>::construct(
-        storage_.GetAllocator(), p, std::forward<Args>(args)...);
+        *storage_.GetAllocPtr(), p, std::forward<Args>(args)...);
     return *p;
   }
 
@@ -903,7 +908,7 @@
   // Destroy [`from`, `to`) in place.
   void Destroy(pointer from, pointer to) {
     for (pointer cur = from; cur != to; ++cur) {
-      std::allocator_traits<allocator_type>::destroy(storage_.GetAllocator(),
+      std::allocator_traits<allocator_type>::destroy(*storage_.GetAllocPtr(),
                                                      cur);
     }
 #if !defined(NDEBUG)
@@ -934,7 +939,7 @@
     }
 
     pointer new_data =
-        AllocatorTraits::allocate(storage_.GetAllocator(), new_capacity);
+        AllocatorTraits::allocate(*storage_.GetAllocPtr(), new_capacity);
 
     UninitializedCopy(std::make_move_iterator(data()),
                       std::make_move_iterator(data() + s), new_data);
@@ -966,7 +971,7 @@
       // Move everyone into the new allocation, leaving a gap of `n` for the
       // requested shift.
       pointer new_data =
-          AllocatorTraits::allocate(storage_.GetAllocator(), new_capacity);
+          AllocatorTraits::allocate(*storage_.GetAllocPtr(), new_capacity);
       size_type index = position - begin();
       UninitializedCopy(std::make_move_iterator(data()),
                         std::make_move_iterator(data() + index), new_data);
@@ -1015,7 +1020,7 @@
 
     size_type new_capacity = 2 * capacity();
     pointer new_data =
-        AllocatorTraits::allocate(storage_.GetAllocator(), new_capacity);
+        AllocatorTraits::allocate(*storage_.GetAllocPtr(), new_capacity);
 
     reference new_element =
         Construct(new_data + s, std::forward<Args>(args)...);
@@ -1029,7 +1034,7 @@
 
   void InitAssign(size_type n) {
     if (n > static_cast<size_type>(N)) {
-      pointer new_data = AllocatorTraits::allocate(storage_.GetAllocator(), n);
+      pointer new_data = AllocatorTraits::allocate(*storage_.GetAllocPtr(), n);
       storage_.SetAllocatedData(new_data);
       storage_.SetAllocatedCapacity(n);
       UninitializedFill(storage_.GetAllocatedData(),
@@ -1044,7 +1049,7 @@
 
   void InitAssign(size_type n, const_reference v) {
     if (n > static_cast<size_type>(N)) {
-      pointer new_data = AllocatorTraits::allocate(storage_.GetAllocator(), n);
+      pointer new_data = AllocatorTraits::allocate(*storage_.GetAllocPtr(), n);
       storage_.SetAllocatedData(new_data);
       storage_.SetAllocatedCapacity(n);
       UninitializedFill(storage_.GetAllocatedData(),
@@ -1058,32 +1063,6 @@
   }
 
   template <typename ForwardIt>
-  void AssignForwardRange(ForwardIt first, ForwardIt last) {
-    static_assert(absl::inlined_vector_internal::IsAtLeastForwardIterator<
-                      ForwardIt>::value,
-                  "");
-
-    auto length = std::distance(first, last);
-
-    // Prefer reassignment to copy construction for elements.
-    if (static_cast<size_type>(length) <= size()) {
-      erase(std::copy(first, last, begin()), end());
-      return;
-    }
-
-    reserve(length);
-    iterator out = begin();
-    for (; out != end(); ++first, ++out) *out = *first;
-    if (storage_.GetIsAllocated()) {
-      UninitializedCopy(first, last, out);
-      storage_.SetAllocatedSize(length);
-    } else {
-      UninitializedCopy(first, last, out);
-      storage_.SetInlinedSize(length);
-    }
-  }
-
-  template <typename ForwardIt>
   void AppendForwardRange(ForwardIt first, ForwardIt last) {
     static_assert(absl::inlined_vector_internal::IsAtLeastForwardIterator<
                       ForwardIt>::value,
@@ -1143,7 +1122,7 @@
       // Both out of line, so just swap the tag, allocation, and allocator.
       storage_.SwapSizeAndIsAllocated(std::addressof(other.storage_));
       storage_.SwapAllocatedSizeAndCapacity(std::addressof(other.storage_));
-      swap(storage_.GetAllocator(), other.storage_.GetAllocator());
+      swap(*storage_.GetAllocPtr(), *other.storage_.GetAllocPtr());
 
       return;
     }
@@ -1173,7 +1152,7 @@
                  a->storage_.GetInlinedData() + a_size);
 
       storage_.SwapSizeAndIsAllocated(std::addressof(other.storage_));
-      swap(storage_.GetAllocator(), other.storage_.GetAllocator());
+      swap(*storage_.GetAllocPtr(), *other.storage_.GetAllocPtr());
 
       assert(b->size() == a_size);
       assert(a->size() == b_size);
@@ -1215,8 +1194,8 @@
     a->storage_.SetAllocatedData(b_data);
     a->storage_.SetAllocatedCapacity(b_capacity);
 
-    if (a->storage_.GetAllocator() != b->storage_.GetAllocator()) {
-      swap(a->storage_.GetAllocator(), b->storage_.GetAllocator());
+    if (*a->storage_.GetAllocPtr() != *b->storage_.GetAllocPtr()) {
+      swap(*a->storage_.GetAllocPtr(), *b->storage_.GetAllocPtr());
     }
 
     assert(b->size() == a_size);
diff --git a/absl/container/inlined_vector_benchmark.cc b/absl/container/inlined_vector_benchmark.cc
index 7bb3271..d906997 100644
--- a/absl/container/inlined_vector_benchmark.cc
+++ b/absl/container/inlined_vector_benchmark.cc
@@ -405,12 +405,6 @@
 
 using NontrivialVec = absl::InlinedVector<NontrivialType, kInlineElements>;
 
-#define BENCHMARK_OPERATION(BM_Function)                      \
-  BENCHMARK_TEMPLATE(BM_Function, TrivialVec, kSmallSize);    \
-  BENCHMARK_TEMPLATE(BM_Function, TrivialVec, kLargeSize);    \
-  BENCHMARK_TEMPLATE(BM_Function, NontrivialVec, kSmallSize); \
-  BENCHMARK_TEMPLATE(BM_Function, NontrivialVec, kLargeSize)
-
 template <typename VecT, typename PrepareVec, typename TestVec>
 void BatchedBenchmark(benchmark::State& state, PrepareVec prepare_vec,
                       TestVec test_vec) {
@@ -432,13 +426,18 @@
   }
 }
 
-template <typename VecT, size_t Size>
+template <typename VecT, size_t FromSize>
 void BM_Clear(benchmark::State& state) {
   BatchedBenchmark<VecT>(
       state,
-      /* prepare_vec = */ [](VecT* vec) { vec->resize(Size); },
+      /* prepare_vec = */ [](VecT* vec) { vec->resize(FromSize); },
       /* test_vec = */ [](VecT* vec) { vec->clear(); });
 }
-BENCHMARK_OPERATION(BM_Clear);
+
+BENCHMARK_TEMPLATE(BM_Clear, TrivialVec, kSmallSize);
+BENCHMARK_TEMPLATE(BM_Clear, TrivialVec, kLargeSize);
+
+BENCHMARK_TEMPLATE(BM_Clear, NontrivialVec, kSmallSize);
+BENCHMARK_TEMPLATE(BM_Clear, NontrivialVec, kLargeSize);
 
 }  // namespace
diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h
index 4589ce0..a2b3d24 100644
--- a/absl/container/internal/inlined_vector.h
+++ b/absl/container/internal/inlined_vector.h
@@ -33,7 +33,7 @@
     std::forward_iterator_tag>;
 
 template <typename AllocatorType, typename ValueType, typename SizeType>
-void DestroyElements(AllocatorType alloc, ValueType* destroy_first,
+void DestroyElements(AllocatorType* alloc_ptr, ValueType* destroy_first,
                      SizeType destroy_size) {
   using AllocatorTraits = std::allocator_traits<AllocatorType>;
 
@@ -45,7 +45,7 @@
   // NOTE: We assume destructors do not throw and thus make no attempt to roll
   // back.
   for (SizeType i = 0; i < destroy_size; ++i) {
-    AllocatorTraits::destroy(alloc, destroy_first + i);
+    AllocatorTraits::destroy(*alloc_ptr, destroy_first + i);
   }
 
 #ifndef NDEBUG
@@ -104,10 +104,12 @@
     return data_.allocated.allocated_capacity;
   }
 
-  allocator_type& GetAllocator() { return metadata_.template get<0>(); }
+  allocator_type* GetAllocPtr() {
+    return std::addressof(metadata_.template get<0>());
+  }
 
-  const allocator_type& GetAllocator() const {
-    return metadata_.template get<0>();
+  const allocator_type* GetAllocPtr() const {
+    return std::addressof(metadata_.template get<0>());
   }
 
   void SetAllocatedSize(size_type size) {
diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc
index 263d9d6..5e53ccd 100644
--- a/absl/flags/parse.cc
+++ b/absl/flags/parse.cc
@@ -190,7 +190,7 @@
   char buf[1024];
   auto get_res = GetEnvironmentVariableA(var_name, buf, sizeof(buf));
   if (get_res >= sizeof(buf)) {
-    return "";
+    return false;
   }
 
   if (get_res == 0) {
diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc
index 92c64ad..449e77b 100644
--- a/absl/hash/hash_test.cc
+++ b/absl/hash/hash_test.cc
@@ -470,7 +470,7 @@
 struct NoOp {
   template <typename HashCode>
   friend HashCode AbslHashValue(HashCode h, NoOp n) {
-    return std::move(h);
+    return h;
   }
 };
 
diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h
index 4d48af0..5cb3a14 100644
--- a/absl/strings/internal/str_format/arg.h
+++ b/absl/strings/internal/str_format/arg.h
@@ -7,6 +7,7 @@
 #include <cstdio>
 #include <iomanip>
 #include <limits>
+#include <memory>
 #include <sstream>
 #include <string>
 #include <type_traits>
@@ -292,7 +293,7 @@
   struct Manager<T, ByPointer> {
     static Data SetValue(const T& value) {
       Data data;
-      data.ptr = &value;
+      data.ptr = std::addressof(value);
       return data;
     }
 
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc
index 3b4d4b0..814ccf4 100644
--- a/absl/strings/internal/str_format/convert_test.cc
+++ b/absl/strings/internal/str_format/convert_test.cc
@@ -367,6 +367,17 @@
 INSTANTIATE_TYPED_TEST_CASE_P(TypedFormatConvertTestWithAllIntTypes,
                               TypedFormatConvertTest, AllIntTypes);
 
+TEST_F(FormatConvertTest, VectorBool) {
+  // Make sure vector<bool>'s values behave as bools.
+  std::vector<bool> v = {true, false};
+  const std::vector<bool> cv = {true, false};
+  EXPECT_EQ("1,0,1,0",
+            FormatPack(UntypedFormatSpecImpl("%d,%d,%d,%d"),
+                       absl::Span<const FormatArgImpl>(
+                           {FormatArgImpl(v[0]), FormatArgImpl(v[1]),
+                            FormatArgImpl(cv[0]), FormatArgImpl(cv[1])})));
+}
+
 TEST_F(FormatConvertTest, Uint128) {
   absl::uint128 v = static_cast<absl::uint128>(0x1234567890abcdef) * 1979;
   absl::uint128 max = absl::Uint128Max();
diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc
index 2667976..ffe99db 100644
--- a/absl/strings/str_cat.cc
+++ b/absl/strings/str_cat.cc
@@ -89,7 +89,9 @@
   // memcpy is allowed to overwrite arbitrary memory, so doing this after the
   // call would force an extra fetch of x.size().
   char* after = out + x.size();
-  memcpy(out, x.data(), x.size());
+  if (x.size() != 0) {
+    memcpy(out, x.data(), x.size());
+  }
   return after;
 }
 
@@ -146,8 +148,10 @@
   char* out = begin;
   for (const absl::string_view piece : pieces) {
     const size_t this_size = piece.size();
-    memcpy(out, piece.data(), this_size);
-    out += this_size;
+    if (this_size != 0) {
+      memcpy(out, piece.data(), this_size);
+      out += this_size;
+    }
   }
   assert(out == begin + result.size());
   return result;
@@ -176,8 +180,10 @@
   char* out = begin + old_size;
   for (const absl::string_view piece : pieces) {
     const size_t this_size = piece.size();
-    memcpy(out, piece.data(), this_size);
-    out += this_size;
+    if (this_size != 0) {
+      memcpy(out, piece.data(), this_size);
+      out += this_size;
+    }
   }
   assert(out == begin + dest->size());
 }
diff --git a/absl/strings/str_cat_test.cc b/absl/strings/str_cat_test.cc
index 1f1051d..29db9c0 100644
--- a/absl/strings/str_cat_test.cc
+++ b/absl/strings/str_cat_test.cc
@@ -408,6 +408,20 @@
   EXPECT_EQ(result, "1010");
 }
 
+// Passing nullptr to memcpy is undefined behavior and this test
+// provides coverage of codepaths that handle empty strings with nullptrs.
+TEST(StrCat, AvoidsMemcpyWithNullptr) {
+  EXPECT_EQ(absl::StrCat(42, absl::string_view{}), "42");
+
+  // Cover CatPieces code.
+  EXPECT_EQ(absl::StrCat(1, 2, 3, 4, 5, absl::string_view{}), "12345");
+
+  // Cover AppendPieces.
+  std::string result;
+  absl::StrAppend(&result, 1, 2, 3, 4, 5, absl::string_view{});
+  EXPECT_EQ(result, "12345");
+}
+
 #ifdef GTEST_HAS_DEATH_TEST
 TEST(StrAppend, Death) {
   std::string s = "self";
diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h
index 507bc4f..32dec30 100644
--- a/absl/strings/substitute.h
+++ b/absl/strings/substitute.h
@@ -69,6 +69,8 @@
 
 #include <cstring>
 #include <string>
+#include <type_traits>
+#include <vector>
 
 #include "absl/base/macros.h"
 #include "absl/base/port.h"
@@ -151,6 +153,17 @@
   Arg(Hex hex);  // NOLINT(runtime/explicit)
   Arg(Dec dec);  // NOLINT(runtime/explicit)
 
+  // vector<bool>::reference and const_reference require special help to
+  // convert to `AlphaNum` because it requires two user defined conversions.
+  template <typename T,
+            absl::enable_if_t<
+                std::is_class<T>::value &&
+                (std::is_same<T, std::vector<bool>::reference>::value ||
+                 std::is_same<T, std::vector<bool>::const_reference>::value)>* =
+                nullptr>
+  Arg(T value)  // NOLINT(google-explicit-constructor)
+      : Arg(static_cast<bool>(value)) {}
+
   // `void*` values, with the exception of `char*`, are printed as
   // "0x<hex value>". However, in the case of `nullptr`, "NULL" is printed.
   Arg(const void* value);  // NOLINT(runtime/explicit)
diff --git a/absl/strings/substitute_test.cc b/absl/strings/substitute_test.cc
index f656890..e27abb1 100644
--- a/absl/strings/substitute_test.cc
+++ b/absl/strings/substitute_test.cc
@@ -15,6 +15,7 @@
 #include "absl/strings/substitute.h"
 
 #include <cstdint>
+#include <vector>
 
 #include "gtest/gtest.h"
 #include "absl/strings/str_cat.h"
@@ -172,6 +173,17 @@
   EXPECT_EQ("a b c d e f g h i j", str);
 }
 
+TEST(SubstituteTest, VectorBoolRef) {
+  std::vector<bool> v = {true, false};
+  const auto& cv = v;
+  EXPECT_EQ("true false true false",
+            absl::Substitute("$0 $1 $2 $3", v[0], v[1], cv[0], cv[1]));
+
+  std::string str = "Logic be like: ";
+  absl::SubstituteAndAppend(&str, "$0 $1 $2 $3", v[0], v[1], cv[0], cv[1]);
+  EXPECT_EQ("Logic be like: true false true false", str);
+}
+
 #ifdef GTEST_HAS_DEATH_TEST
 
 TEST(SubstituteDeathTest, SubstituteDeath) {
diff --git a/absl/types/optional.h b/absl/types/optional.h
index 1670022..142dc83 100644
--- a/absl/types/optional.h
+++ b/absl/types/optional.h
@@ -421,7 +421,9 @@
   //
   // Accesses the underlying `T` value of an `optional`. If the `optional` is
   // empty, behavior is undefined.
-  constexpr const T& operator*() const & { return reference(); }
+  constexpr const T& operator*() const& {
+    return ABSL_ASSERT(this->engaged_), reference();
+  }
   T& operator*() & {
     assert(this->engaged_);
     return reference();