about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--absl/algorithm/BUILD.bazel4
-rw-r--r--absl/base/internal/endian_test.cc6
-rw-r--r--absl/base/optimization.h34
-rw-r--r--absl/container/internal/raw_hash_set.h24
-rw-r--r--absl/flags/BUILD.bazel2
-rw-r--r--absl/flags/CMakeLists.txt1
-rw-r--r--absl/flags/flag.h6
-rw-r--r--absl/flags/flag_test.cc173
-rw-r--r--absl/flags/internal/flag.cc73
-rw-r--r--absl/flags/internal/flag.h103
-rw-r--r--absl/random/internal/iostream_state_saver.h4
-rw-r--r--absl/random/internal/nanobenchmark_test.cc2
-rw-r--r--absl/random/internal/wide_multiply.h10
-rw-r--r--absl/time/duration.cc6
-rwxr-xr-xci/cmake_install_test.sh2
-rwxr-xr-xci/linux_clang-latest_libcxx_asan_bazel.sh12
-rwxr-xr-xci/linux_clang-latest_libcxx_bazel.sh12
-rwxr-xr-xci/linux_clang-latest_libcxx_tsan_bazel.sh12
-rwxr-xr-xci/linux_clang-latest_libstdcxx_bazel.sh12
-rwxr-xr-xci/linux_gcc-4.9_libstdcxx_bazel.sh12
-rwxr-xr-xci/linux_gcc-latest_libstdcxx_bazel.sh14
-rwxr-xr-xci/linux_gcc-latest_libstdcxx_cmake.sh6
-rwxr-xr-xci/linux_gcc_alpine_cmake.sh6
-rwxr-xr-xci/macos_xcode_bazel.sh6
-rwxr-xr-xci/macos_xcode_cmake.sh4
25 files changed, 362 insertions, 184 deletions
diff --git a/absl/algorithm/BUILD.bazel b/absl/algorithm/BUILD.bazel
index 6a96420b96..229cd713a2 100644
--- a/absl/algorithm/BUILD.bazel
+++ b/absl/algorithm/BUILD.bazel
@@ -31,7 +31,9 @@ cc_library(
     hdrs = ["algorithm.h"],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
-    deps = ["//absl/base:config"],
+    deps = [
+        "//absl/base:config",
+    ],
 )
 
 cc_test(
diff --git a/absl/base/internal/endian_test.cc b/absl/base/internal/endian_test.cc
index aa6b849690..678a0bf78b 100644
--- a/absl/base/internal/endian_test.cc
+++ b/absl/base/internal/endian_test.cc
@@ -57,6 +57,7 @@ const uint16_t k16ValueBE{0x2301};
 template<typename T>
 std::vector<T> GenerateAllValuesForType() {
   std::vector<T> result;
+  result.reserve(size_t{1} << (sizeof(T) * 8));
   T next = std::numeric_limits<T>::min();
   while (true) {
     result.push_back(next);
@@ -68,10 +69,11 @@ std::vector<T> GenerateAllValuesForType() {
 }
 
 template<typename T>
-std::vector<T> GenerateRandomIntegers(size_t numValuesToTest) {
+std::vector<T> GenerateRandomIntegers(size_t num_values_to_test) {
   std::vector<T> result;
+  result.reserve(num_values_to_test);
   std::mt19937_64 rng(kRandomSeed);
-  for (size_t i = 0; i < numValuesToTest; ++i) {
+  for (size_t i = 0; i < num_values_to_test; ++i) {
     result.push_back(rng());
   }
   return result;
diff --git a/absl/base/optimization.h b/absl/base/optimization.h
index 646523b346..1541d7a8dc 100644
--- a/absl/base/optimization.h
+++ b/absl/base/optimization.h
@@ -178,4 +178,38 @@
 #define ABSL_PREDICT_TRUE(x) (x)
 #endif
 
+// ABSL_INTERNAL_ASSUME(cond)
+// Informs the compiler than a condition is always true and that it can assume
+// it to be true for optimization purposes. The call has undefined behavior if
+// the condition is false.
+// In !NDEBUG mode, the condition is checked with an assert().
+// NOTE: The expression must not have side effects, as it will only be evaluated
+// in some compilation modes and not others.
+//
+// Example:
+//
+//   int x = ...;
+//   ABSL_INTERNAL_ASSUME(x >= 0);
+//   // The compiler can optimize the division to a simple right shift using the
+//   // assumption specified above.
+//   int y = x / 16;
+//
+#if !defined(NDEBUG)
+#define ABSL_INTERNAL_ASSUME(cond) assert(cond)
+#elif ABSL_HAVE_BUILTIN(__builtin_assume)
+#define ABSL_INTERNAL_ASSUME(cond) __builtin_assume(cond)
+#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
+#define ABSL_INTERNAL_ASSUME(cond)        \
+  do {                                    \
+    if (!(cond)) __builtin_unreachable(); \
+  } while (0)
+#elif defined(_MSC_VER)
+#define ABSL_INTERNAL_ASSUME(cond) __assume(cond)
+#else
+#define ABSL_INTERNAL_ASSUME(cond)      \
+  do {                                  \
+    static_cast<void>(false && (cond)); \
+  } while (0)
+#endif
+
 #endif  // ABSL_BASE_OPTIMIZATION_H_
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index e47e1fedf7..df0f2b2b54 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -104,7 +104,7 @@
 
 #include "absl/base/internal/bits.h"
 #include "absl/base/internal/endian.h"
-#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
 #include "absl/base/port.h"
 #include "absl/container/internal/common.h"
 #include "absl/container/internal/compressed_tuple.h"
@@ -649,24 +649,26 @@ class raw_hash_set {
     }
 
    private:
-    iterator(ctrl_t* ctrl) : ctrl_(ctrl) {}  // for end()
-    iterator(ctrl_t* ctrl, slot_type* slot) : ctrl_(ctrl), slot_(slot) {}
+    iterator(ctrl_t* ctrl, slot_type* slot) : ctrl_(ctrl), slot_(slot) {
+      // This assumption helps the compiler know that any non-end iterator is
+      // not equal to any end iterator.
+      ABSL_INTERNAL_ASSUME(ctrl != nullptr);
+    }
 
-    void assert_is_full() const { ABSL_HARDENING_ASSERT(IsFull(*ctrl_)); }
+    void assert_is_full() const {
+      ABSL_HARDENING_ASSERT(ctrl_ != nullptr && IsFull(*ctrl_));
+    }
     void assert_is_valid() const {
-      ABSL_HARDENING_ASSERT(!ctrl_ || IsFull(*ctrl_) || *ctrl_ == kSentinel);
+      ABSL_HARDENING_ASSERT(ctrl_ == nullptr || IsFull(*ctrl_));
     }
 
     void skip_empty_or_deleted() {
       while (IsEmptyOrDeleted(*ctrl_)) {
-        // ctrl is not necessarily aligned to Group::kWidth. It is also likely
-        // to read past the space for ctrl bytes and into slots. This is ok
-        // because ctrl has sizeof() == 1 and slot has sizeof() >= 1 so there
-        // is no way to read outside the combined slot array.
         uint32_t shift = Group{ctrl_}.CountLeadingEmptyOrDeleted();
         ctrl_ += shift;
         slot_ += shift;
       }
+      if (ABSL_PREDICT_FALSE(*ctrl_ == kSentinel)) ctrl_ = nullptr;
     }
 
     ctrl_t* ctrl_ = nullptr;
@@ -908,12 +910,12 @@ class raw_hash_set {
     it.skip_empty_or_deleted();
     return it;
   }
-  iterator end() { return {ctrl_ + capacity_}; }
+  iterator end() { return {}; }
 
   const_iterator begin() const {
     return const_cast<raw_hash_set*>(this)->begin();
   }
-  const_iterator end() const { return const_cast<raw_hash_set*>(this)->end(); }
+  const_iterator end() const { return {}; }
   const_iterator cbegin() const { return begin(); }
   const_iterator cend() const { return end(); }
 
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel
index 4b51d9d452..685e395419 100644
--- a/absl/flags/BUILD.bazel
+++ b/absl/flags/BUILD.bazel
@@ -326,7 +326,9 @@ cc_test(
         ":handle",
         ":registry",
         "//absl/base:core_headers",
+        "//absl/base:malloc_internal",
         "//absl/strings",
+        "//absl/time",
         "@com_google_googletest//:gtest_main",
     ],
 )
diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt
index 2204b0ff2d..ec82ee1e36 100644
--- a/absl/flags/CMakeLists.txt
+++ b/absl/flags/CMakeLists.txt
@@ -304,6 +304,7 @@ absl_cc_test(
     absl::flags_internal
     absl::flags_registry
     absl::strings
+    absl::time
     gtest_main
 )
 
diff --git a/absl/flags/flag.h b/absl/flags/flag.h
index 4cc8ae3732..150615929b 100644
--- a/absl/flags/flag.h
+++ b/absl/flags/flag.h
@@ -314,9 +314,9 @@ ABSL_NAMESPACE_END
     static std::string NonConst() { return ABSL_FLAG_IMPL_FLAGHELP(txt); } \
   }
 
-#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value)   \
-  static void* AbslFlagsInitFlag##name() {                                  \
-    return absl::flags_internal::MakeFromDefaultValue<Type>(default_value); \
+#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \
+  static void AbslFlagsInitFlag##name(void* dst) {                        \
+    absl::flags_internal::MakeFromDefaultValue<Type>(dst, default_value); \
   }
 
 // ABSL_FLAG_IMPL
diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc
index 377e3b2b89..dbe94a2c3b 100644
--- a/absl/flags/flag_test.cc
+++ b/absl/flags/flag_test.cc
@@ -19,6 +19,7 @@
 
 #include <cmath>
 #include <string>
+#include <thread>  // NOLINT
 #include <vector>
 
 #include "gtest/gtest.h"
@@ -34,6 +35,7 @@
 #include "absl/strings/str_cat.h"
 #include "absl/strings/str_split.h"
 #include "absl/strings/string_view.h"
+#include "absl/time/time.h"
 
 ABSL_DECLARE_FLAG(int64_t, mistyped_int_flag);
 ABSL_DECLARE_FLAG(std::vector<std::string>, mistyped_string_flag);
@@ -44,8 +46,8 @@ namespace flags = absl::flags_internal;
 
 std::string TestHelpMsg() { return "dynamic help"; }
 template <typename T>
-void* TestMakeDflt() {
-  return new T{};
+void TestMakeDflt(void* dst) {
+  new (dst) T{};
 }
 void TestCallback() {}
 
@@ -74,6 +76,7 @@ class FlagTest : public testing::Test {
 #endif
     return std::string(fname);
   }
+  flags::FlagSaver flag_saver_;
 };
 
 struct S1 {
@@ -107,15 +110,15 @@ TEST_F(FlagTest, Traits) {
             flags::FlagValueStorageKind::kTwoWordsAtomic);
 #else
   EXPECT_EQ(flags::StorageKind<S1>(),
-            flags::FlagValueStorageKind::kHeapAllocated);
+            flags::FlagValueStorageKind::kAlignedBuffer);
   EXPECT_EQ(flags::StorageKind<S2>(),
-            flags::FlagValueStorageKind::kHeapAllocated);
+            flags::FlagValueStorageKind::kAlignedBuffer);
 #endif
 
   EXPECT_EQ(flags::StorageKind<std::string>(),
-            flags::FlagValueStorageKind::kHeapAllocated);
+            flags::FlagValueStorageKind::kAlignedBuffer);
   EXPECT_EQ(flags::StorageKind<std::vector<std::string>>(),
-            flags::FlagValueStorageKind::kHeapAllocated);
+            flags::FlagValueStorageKind::kAlignedBuffer);
 }
 
 // --------------------------------------------------------------------
@@ -190,6 +193,7 @@ ABSL_DECLARE_FLAG(uint64_t, test_flag_08);
 ABSL_DECLARE_FLAG(double, test_flag_09);
 ABSL_DECLARE_FLAG(float, test_flag_10);
 ABSL_DECLARE_FLAG(std::string, test_flag_11);
+ABSL_DECLARE_FLAG(absl::Duration, test_flag_12);
 
 namespace {
 
@@ -208,6 +212,7 @@ TEST_F(FlagTest, TestFlagDeclaration) {
   EXPECT_EQ(FLAGS_test_flag_09.Name(), "test_flag_09");
   EXPECT_EQ(FLAGS_test_flag_10.Name(), "test_flag_10");
   EXPECT_EQ(FLAGS_test_flag_11.Name(), "test_flag_11");
+  EXPECT_EQ(FLAGS_test_flag_12.Name(), "test_flag_12");
 }
 #endif  // !ABSL_FLAGS_STRIP_NAMES
 
@@ -226,6 +231,7 @@ ABSL_FLAG(uint64_t, test_flag_08, 9876543, "test flag 08");
 ABSL_FLAG(double, test_flag_09, -9.876e-50, "test flag 09");
 ABSL_FLAG(float, test_flag_10, 1.234e12f, "test flag 10");
 ABSL_FLAG(std::string, test_flag_11, "", "test flag 11");
+ABSL_FLAG(absl::Duration, test_flag_12, absl::Minutes(10), "test flag 12");
 
 namespace {
 
@@ -287,6 +293,11 @@ TEST_F(FlagTest, TestFlagDefinition) {
   EXPECT_EQ(FLAGS_test_flag_11.Help(), "test flag 11");
   EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_11.Filename(), expected_file_name))
       << FLAGS_test_flag_11.Filename();
+
+  EXPECT_EQ(FLAGS_test_flag_12.Name(), "test_flag_12");
+  EXPECT_EQ(FLAGS_test_flag_12.Help(), "test flag 12");
+  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_12.Filename(), expected_file_name))
+      << FLAGS_test_flag_12.Filename();
 }
 #endif  // !ABSL_FLAGS_STRIP_NAMES
 
@@ -304,6 +315,20 @@ TEST_F(FlagTest, TestDefault) {
   EXPECT_EQ(FLAGS_test_flag_09.DefaultValue(), "-9.876e-50");
   EXPECT_EQ(FLAGS_test_flag_10.DefaultValue(), "1.234e+12");
   EXPECT_EQ(FLAGS_test_flag_11.DefaultValue(), "");
+  EXPECT_EQ(FLAGS_test_flag_12.DefaultValue(), "10m");
+
+  EXPECT_EQ(FLAGS_test_flag_01.CurrentValue(), "true");
+  EXPECT_EQ(FLAGS_test_flag_02.CurrentValue(), "1234");
+  EXPECT_EQ(FLAGS_test_flag_03.CurrentValue(), "-34");
+  EXPECT_EQ(FLAGS_test_flag_04.CurrentValue(), "189");
+  EXPECT_EQ(FLAGS_test_flag_05.CurrentValue(), "10765");
+  EXPECT_EQ(FLAGS_test_flag_06.CurrentValue(), "40000");
+  EXPECT_EQ(FLAGS_test_flag_07.CurrentValue(), "-1234567");
+  EXPECT_EQ(FLAGS_test_flag_08.CurrentValue(), "9876543");
+  EXPECT_EQ(FLAGS_test_flag_09.CurrentValue(), "-9.876e-50");
+  EXPECT_EQ(FLAGS_test_flag_10.CurrentValue(), "1.234e+12");
+  EXPECT_EQ(FLAGS_test_flag_11.CurrentValue(), "");
+  EXPECT_EQ(FLAGS_test_flag_12.CurrentValue(), "10m");
 
   EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true);
   EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234);
@@ -316,6 +341,7 @@ TEST_F(FlagTest, TestDefault) {
   EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), -9.876e-50, 1e-55);
   EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f);
   EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "");
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Minutes(10));
 }
 
 // --------------------------------------------------------------------
@@ -408,6 +434,38 @@ TEST_F(FlagTest, TestGetSet) {
 
   absl::SetFlag(&FLAGS_test_flag_11, "asdf");
   EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "asdf");
+
+  absl::SetFlag(&FLAGS_test_flag_12, absl::Seconds(110));
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Seconds(110));
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(FlagTest, TestGetViaReflection) {
+  auto* handle = flags::FindCommandLineFlag("test_flag_01");
+  EXPECT_EQ(*handle->Get<bool>(), true);
+  handle = flags::FindCommandLineFlag("test_flag_02");
+  EXPECT_EQ(*handle->Get<int>(), 1234);
+  handle = flags::FindCommandLineFlag("test_flag_03");
+  EXPECT_EQ(*handle->Get<int16_t>(), -34);
+  handle = flags::FindCommandLineFlag("test_flag_04");
+  EXPECT_EQ(*handle->Get<uint16_t>(), 189);
+  handle = flags::FindCommandLineFlag("test_flag_05");
+  EXPECT_EQ(*handle->Get<int32_t>(), 10765);
+  handle = flags::FindCommandLineFlag("test_flag_06");
+  EXPECT_EQ(*handle->Get<uint32_t>(), 40000);
+  handle = flags::FindCommandLineFlag("test_flag_07");
+  EXPECT_EQ(*handle->Get<int64_t>(), -1234567);
+  handle = flags::FindCommandLineFlag("test_flag_08");
+  EXPECT_EQ(*handle->Get<uint64_t>(), 9876543);
+  handle = flags::FindCommandLineFlag("test_flag_09");
+  EXPECT_NEAR(*handle->Get<double>(), -9.876e-50, 1e-55);
+  handle = flags::FindCommandLineFlag("test_flag_10");
+  EXPECT_NEAR(*handle->Get<float>(), 1.234e12f, 1e5f);
+  handle = flags::FindCommandLineFlag("test_flag_11");
+  EXPECT_EQ(*handle->Get<std::string>(), "");
+  handle = flags::FindCommandLineFlag("test_flag_12");
+  EXPECT_EQ(*handle->Get<absl::Duration>(), absl::Minutes(10));
 }
 
 // --------------------------------------------------------------------
@@ -416,28 +474,32 @@ int GetDflt1() { return 1; }
 
 }  // namespace
 
-ABSL_FLAG(int, test_flag_12, GetDflt1(), "test flag 12");
-ABSL_FLAG(std::string, test_flag_13, absl::StrCat("AAA", "BBB"),
-          "test flag 13");
+ABSL_FLAG(int, test_int_flag_with_non_const_default, GetDflt1(),
+          "test int flag non const default");
+ABSL_FLAG(std::string, test_string_flag_with_non_const_default,
+          absl::StrCat("AAA", "BBB"), "test string flag non const default");
 
 namespace {
 
 TEST_F(FlagTest, TestNonConstexprDefault) {
-  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), 1);
-  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), "AAABBB");
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_int_flag_with_non_const_default), 1);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_string_flag_with_non_const_default),
+            "AAABBB");
 }
 
 // --------------------------------------------------------------------
 
 }  // namespace
 
-ABSL_FLAG(bool, test_flag_14, true, absl::StrCat("test ", "flag ", "14"));
+ABSL_FLAG(bool, test_flag_with_non_const_help, true,
+          absl::StrCat("test ", "flag ", "non const help"));
 
 namespace {
 
 #if !ABSL_FLAGS_STRIP_HELP
 TEST_F(FlagTest, TestNonConstexprHelp) {
-  EXPECT_EQ(FLAGS_test_flag_14.Help(), "test flag 14");
+  EXPECT_EQ(FLAGS_test_flag_with_non_const_help.Help(),
+            "test flag non const help");
 }
 #endif  //! ABSL_FLAGS_STRIP_HELP
 
@@ -503,14 +565,14 @@ std::string AbslUnparseFlag(const CustomUDT& f) {
 
 }  // namespace
 
-ABSL_FLAG(CustomUDT, test_flag_15, CustomUDT(), "test flag 15");
+ABSL_FLAG(CustomUDT, test_flag_custom_udt, CustomUDT(), "test flag custom UDT");
 
 namespace {
 
 TEST_F(FlagTest, TestCustomUDT) {
-  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_15), CustomUDT(1, 1));
-  absl::SetFlag(&FLAGS_test_flag_15, CustomUDT(2, 3));
-  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_15), CustomUDT(2, 3));
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_custom_udt), CustomUDT(1, 1));
+  absl::SetFlag(&FLAGS_test_flag_custom_udt, CustomUDT(2, 3));
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_custom_udt), CustomUDT(2, 3));
 }
 
 // MSVC produces link error on the type mismatch.
@@ -570,16 +632,17 @@ std::string AbslUnparseFlag(const ConversionTestVal& val) {
 
 // Flag default values can be specified with a value that converts to the flag
 // value type implicitly.
-ABSL_FLAG(ConversionTestVal, test_flag_16,
-          ConversionTestVal::ViaImplicitConv::kTen, "test flag 16");
+ABSL_FLAG(ConversionTestVal, test_flag_implicit_conv,
+          ConversionTestVal::ViaImplicitConv::kTen,
+          "test flag init via implicit conversion");
 
 namespace {
 
 TEST_F(FlagTest, CanSetViaImplicitConversion) {
-  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_16).a, 10);
-  absl::SetFlag(&FLAGS_test_flag_16,
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_implicit_conv).a, 10);
+  absl::SetFlag(&FLAGS_test_flag_implicit_conv,
                 ConversionTestVal::ViaImplicitConv::kEleven);
-  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_16).a, 11);
+  EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_implicit_conv).a, 11);
 }
 
 // --------------------------------------------------------------------
@@ -646,3 +709,69 @@ TEST_F(FlagTest, TestRetiredFlagRegistration) {
 }
 
 }  // namespace
+
+// --------------------------------------------------------------------
+
+namespace {
+
+// User-defined type with small alignment, but size exceeding 16.
+struct SmallAlignUDT {
+  SmallAlignUDT() : c('A'), s(12) {}
+  char c;
+  int16_t s;
+  char bytes[14];
+};
+
+bool AbslParseFlag(absl::string_view, SmallAlignUDT*, std::string*) {
+  return true;
+}
+std::string AbslUnparseFlag(const SmallAlignUDT&) { return ""; }
+
+// User-defined type with small size, but not trivially copyable.
+struct NonTriviallyCopyableUDT {
+  NonTriviallyCopyableUDT() : c('A') {}
+  NonTriviallyCopyableUDT(const NonTriviallyCopyableUDT& rhs) : c(rhs.c) {}
+  NonTriviallyCopyableUDT& operator=(const NonTriviallyCopyableUDT& rhs) {
+    c = rhs.c;
+    return *this;
+  }
+
+  char c;
+};
+
+bool AbslParseFlag(absl::string_view, NonTriviallyCopyableUDT*, std::string*) {
+  return true;
+}
+std::string AbslUnparseFlag(const NonTriviallyCopyableUDT&) { return ""; }
+
+}  // namespace
+
+ABSL_FLAG(SmallAlignUDT, test_flag_sa_udt, {}, "help");
+ABSL_FLAG(NonTriviallyCopyableUDT, test_flag_ntc_udt, {}, "help");
+
+namespace {
+
+TEST_F(FlagTest, TestSmallAlignUDT) {
+  SmallAlignUDT value = absl::GetFlag(FLAGS_test_flag_sa_udt);
+  EXPECT_EQ(value.c, 'A');
+  EXPECT_EQ(value.s, 12);
+
+  value.c = 'B';
+  value.s = 45;
+  absl::SetFlag(&FLAGS_test_flag_sa_udt, value);
+  value = absl::GetFlag(FLAGS_test_flag_sa_udt);
+  EXPECT_EQ(value.c, 'B');
+  EXPECT_EQ(value.s, 45);
+}
+
+TEST_F(FlagTest, TestNonTriviallyCopyableUDT) {
+  NonTriviallyCopyableUDT value = absl::GetFlag(FLAGS_test_flag_ntc_udt);
+  EXPECT_EQ(value.c, 'A');
+
+  value.c = 'B';
+  absl::SetFlag(&FLAGS_test_flag_ntc_udt, value);
+  value = absl::GetFlag(FLAGS_test_flag_ntc_udt);
+  EXPECT_EQ(value.c, 'B');
+}
+
+}  // namespace
diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc
index f3c424ad83..089567f7ae 100644
--- a/absl/flags/internal/flag.cc
+++ b/absl/flags/internal/flag.cc
@@ -92,9 +92,9 @@ class FlagState : public flags_internal::FlagStateInterface {
         counter_(counter) {}
 
   ~FlagState() override {
-    if (flag_impl_->ValueStorageKind() != FlagValueStorageKind::kHeapAllocated)
+    if (flag_impl_->ValueStorageKind() != FlagValueStorageKind::kAlignedBuffer)
       return;
-    flags_internal::Delete(flag_impl_->op_, value_.dynamic);
+    flags_internal::Delete(flag_impl_->op_, value_.heap_allocated);
   }
 
  private:
@@ -112,11 +112,11 @@ class FlagState : public flags_internal::FlagStateInterface {
   // Flag and saved flag data.
   FlagImpl* flag_impl_;
   union SavedValue {
-    explicit SavedValue(void* v) : dynamic(v) {}
+    explicit SavedValue(void* v) : heap_allocated(v) {}
     explicit SavedValue(int64_t v) : one_word(v) {}
     explicit SavedValue(flags_internal::AlignedTwoWords v) : two_words(v) {}
 
-    void* dynamic;
+    void* heap_allocated;
     int64_t one_word;
     flags_internal::AlignedTwoWords two_words;
   } value_;
@@ -128,25 +128,33 @@ class FlagState : public flags_internal::FlagStateInterface {
 ///////////////////////////////////////////////////////////////////////////////
 // Flag implementation, which does not depend on flag value type.
 
+DynValueDeleter::DynValueDeleter(FlagOpFn op_arg) : op(op_arg) {}
+
+void DynValueDeleter::operator()(void* ptr) const {
+  if (op == nullptr) return;
+
+  Delete(op, ptr);
+}
+
 void FlagImpl::Init() {
   new (&data_guard_) absl::Mutex;
 
   // At this point the default_value_ always points to gen_func.
-  std::unique_ptr<void, DynValueDeleter> init_value(
-      (*default_value_.gen_func)(), DynValueDeleter{op_});
   switch (ValueStorageKind()) {
-    case FlagValueStorageKind::kHeapAllocated:
-      HeapAllocatedValue() = init_value.release();
+    case FlagValueStorageKind::kAlignedBuffer:
+      (*default_value_.gen_func)(AlignedBufferValue());
       break;
     case FlagValueStorageKind::kOneWordAtomic: {
-      int64_t atomic_value;
-      std::memcpy(&atomic_value, init_value.get(), Sizeof(op_));
-      OneWordValue().store(atomic_value, std::memory_order_release);
+      alignas(int64_t) std::array<char, sizeof(int64_t)> buf{};
+      (*default_value_.gen_func)(buf.data());
+      auto value = absl::bit_cast<int64_t>(buf);
+      OneWordValue().store(value, std::memory_order_release);
       break;
     }
     case FlagValueStorageKind::kTwoWordsAtomic: {
-      AlignedTwoWords atomic_value{0, 0};
-      std::memcpy(&atomic_value, init_value.get(), Sizeof(op_));
+      alignas(AlignedTwoWords) std::array<char, sizeof(AlignedTwoWords)> buf{};
+      (*default_value_.gen_func)(buf.data());
+      auto atomic_value = absl::bit_cast<AlignedTwoWords>(buf);
       TwoWordsValue().store(atomic_value, std::memory_order_release);
       break;
     }
@@ -191,15 +199,16 @@ std::unique_ptr<void, DynValueDeleter> FlagImpl::MakeInitValue() const {
   if (DefaultKind() == FlagDefaultKind::kDynamicValue) {
     res = flags_internal::Clone(op_, default_value_.dynamic_value);
   } else {
-    res = (*default_value_.gen_func)();
+    res = flags_internal::Alloc(op_);
+    (*default_value_.gen_func)(res);
   }
   return {res, DynValueDeleter{op_}};
 }
 
 void FlagImpl::StoreValue(const void* src) {
   switch (ValueStorageKind()) {
-    case FlagValueStorageKind::kHeapAllocated:
-      Copy(op_, src, HeapAllocatedValue());
+    case FlagValueStorageKind::kAlignedBuffer:
+      Copy(op_, src, AlignedBufferValue());
       break;
     case FlagValueStorageKind::kOneWordAtomic: {
       int64_t one_word_val = 0;
@@ -257,9 +266,9 @@ std::string FlagImpl::DefaultValue() const {
 std::string FlagImpl::CurrentValue() const {
   auto* guard = DataGuard();  // Make sure flag initialized
   switch (ValueStorageKind()) {
-    case FlagValueStorageKind::kHeapAllocated: {
+    case FlagValueStorageKind::kAlignedBuffer: {
       absl::MutexLock l(guard);
-      return flags_internal::Unparse(op_, HeapAllocatedValue());
+      return flags_internal::Unparse(op_, AlignedBufferValue());
     }
     case FlagValueStorageKind::kOneWordAtomic: {
       const auto one_word_val =
@@ -318,9 +327,9 @@ std::unique_ptr<FlagStateInterface> FlagImpl::SaveState() {
   bool modified = modified_;
   bool on_command_line = on_command_line_;
   switch (ValueStorageKind()) {
-    case FlagValueStorageKind::kHeapAllocated: {
+    case FlagValueStorageKind::kAlignedBuffer: {
       return absl::make_unique<FlagState>(
-          this, flags_internal::Clone(op_, HeapAllocatedValue()), modified,
+          this, flags_internal::Clone(op_, AlignedBufferValue()), modified,
           on_command_line, counter_);
     }
     case FlagValueStorageKind::kOneWordAtomic: {
@@ -345,8 +354,8 @@ bool FlagImpl::RestoreState(const FlagState& flag_state) {
   }
 
   switch (ValueStorageKind()) {
-    case FlagValueStorageKind::kHeapAllocated:
-      StoreValue(flag_state.value_.dynamic);
+    case FlagValueStorageKind::kAlignedBuffer:
+      StoreValue(flag_state.value_.heap_allocated);
       break;
     case FlagValueStorageKind::kOneWordAtomic:
       StoreValue(&flag_state.value_.one_word);
@@ -363,25 +372,27 @@ bool FlagImpl::RestoreState(const FlagState& flag_state) {
 }
 
 template <typename StorageT>
-typename StorageT::value_type& FlagImpl::OffsetValue() const {
+StorageT* FlagImpl::OffsetValue() const {
   char* p = reinterpret_cast<char*>(const_cast<FlagImpl*>(this));
   // The offset is deduced via Flag value type specific op_.
   size_t offset = flags_internal::ValueOffset(op_);
 
-  return reinterpret_cast<StorageT*>(p + offset)->value;
+  return reinterpret_cast<StorageT*>(p + offset);
 }
 
-void*& FlagImpl::HeapAllocatedValue() const {
-  assert(ValueStorageKind() == FlagValueStorageKind::kHeapAllocated);
-  return OffsetValue<FlagHeapAllocatedValue>();
+void* FlagImpl::AlignedBufferValue() const {
+  assert(ValueStorageKind() == FlagValueStorageKind::kAlignedBuffer);
+  return OffsetValue<void>();
 }
+
 std::atomic<int64_t>& FlagImpl::OneWordValue() const {
   assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic);
-  return OffsetValue<FlagOneWordValue>();
+  return OffsetValue<FlagOneWordValue>()->value;
 }
+
 std::atomic<AlignedTwoWords>& FlagImpl::TwoWordsValue() const {
   assert(ValueStorageKind() == FlagValueStorageKind::kTwoWordsAtomic);
-  return OffsetValue<FlagTwoWordsValue>();
+  return OffsetValue<FlagTwoWordsValue>()->value;
 }
 
 // Attempts to parse supplied `value` string using parsing routine in the `flag`
@@ -406,9 +417,9 @@ std::unique_ptr<void, DynValueDeleter> FlagImpl::TryParse(
 void FlagImpl::Read(void* dst) const {
   auto* guard = DataGuard();  // Make sure flag initialized
   switch (ValueStorageKind()) {
-    case FlagValueStorageKind::kHeapAllocated: {
+    case FlagValueStorageKind::kAlignedBuffer: {
       absl::MutexLock l(guard);
-      flags_internal::CopyConstruct(op_, HeapAllocatedValue(), dst);
+      flags_internal::CopyConstruct(op_, AlignedBufferValue(), dst);
       break;
     }
     case FlagValueStorageKind::kOneWordAtomic: {
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index ae42dedcd6..2ae3dce3d1 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -46,8 +46,8 @@ namespace flags_internal {
 // by function specific to that type with a signature matching FlagOpFn.
 
 enum class FlagOp {
+  kAlloc,
   kDelete,
-  kClone,
   kCopy,
   kCopyConstruct,
   kSizeof,
@@ -63,13 +63,13 @@ using FlagOpFn = void* (*)(FlagOp, const void*, void*, void*);
 template <typename T>
 void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3);
 
-// Deletes memory interpreting obj as flag value type pointer.
-inline void Delete(FlagOpFn op, const void* obj) {
-  op(FlagOp::kDelete, obj, nullptr, nullptr);
+// Allocate aligned memory for a flag value.
+inline void* Alloc(FlagOpFn op) {
+  return op(FlagOp::kAlloc, nullptr, nullptr, nullptr);
 }
-// Makes a copy of flag value pointed by obj.
-inline void* Clone(FlagOpFn op, const void* obj) {
-  return op(FlagOp::kClone, obj, nullptr, nullptr);
+// Deletes memory interpreting obj as flag value type pointer.
+inline void Delete(FlagOpFn op, void* obj) {
+  op(FlagOp::kDelete, nullptr, obj, nullptr);
 }
 // Copies src to dst interpreting as flag value type pointers.
 inline void Copy(FlagOpFn op, const void* src, void* dst) {
@@ -80,6 +80,12 @@ inline void Copy(FlagOpFn op, const void* src, void* dst) {
 inline void CopyConstruct(FlagOpFn op, const void* src, void* dst) {
   op(FlagOp::kCopyConstruct, src, dst, nullptr);
 }
+// Makes a copy of flag value pointed by obj.
+inline void* Clone(FlagOpFn op, const void* obj) {
+  void* res = flags_internal::Alloc(op);
+  flags_internal::CopyConstruct(op, obj, res);
+  return res;
+}
 // Returns true if parsing of input text is successfull.
 inline bool Parse(FlagOpFn op, absl::string_view text, void* dst,
                   std::string* error) {
@@ -195,7 +201,7 @@ constexpr FlagHelpArg HelpArg(char) {
 
 // Signature for the function generating the initial flag value (usually
 // based on default value supplied in flag's definition)
-using FlagDfltGenFunc = void* (*)();
+using FlagDfltGenFunc = void (*)(void*);
 
 union FlagDefaultSrc {
   constexpr explicit FlagDefaultSrc(FlagDfltGenFunc gen_func_arg)
@@ -253,46 +259,36 @@ using FlagUseTwoWordsStorage =
 #endif
 
 template <typename T>
-using FlagUseHeapStorage =
+using FlagUseBufferStorage =
     std::integral_constant<bool, !FlagUseOneWordStorage<T>::value &&
                                      !FlagUseTwoWordsStorage<T>::value>;
 
 enum class FlagValueStorageKind : uint8_t {
-  kHeapAllocated = 0,
+  kAlignedBuffer = 0,
   kOneWordAtomic = 1,
   kTwoWordsAtomic = 2
 };
 
 template <typename T>
 static constexpr FlagValueStorageKind StorageKind() {
-  return FlagUseHeapStorage<T>::value
-             ? FlagValueStorageKind::kHeapAllocated
+  return FlagUseBufferStorage<T>::value
+             ? FlagValueStorageKind::kAlignedBuffer
              : FlagUseOneWordStorage<T>::value
                    ? FlagValueStorageKind::kOneWordAtomic
-                   : FlagUseTwoWordsStorage<T>::value
-                         ? FlagValueStorageKind::kTwoWordsAtomic
-                         : FlagValueStorageKind::kHeapAllocated;
+                   : FlagValueStorageKind::kTwoWordsAtomic;
 }
 
-struct FlagHeapAllocatedValue {
-  using value_type = void*;
-
-  value_type value;
-};
-
 struct FlagOneWordValue {
-  using value_type = std::atomic<int64_t>;
   constexpr FlagOneWordValue() : value(UninitializedFlagValue()) {}
 
-  value_type value;
+  std::atomic<int64_t> value;
 };
 
 struct FlagTwoWordsValue {
-  using value_type = std::atomic<AlignedTwoWords>;
   constexpr FlagTwoWordsValue()
       : value(AlignedTwoWords{UninitializedFlagValue(), 0}) {}
 
-  value_type value;
+  std::atomic<AlignedTwoWords> value;
 };
 
 template <typename T,
@@ -300,9 +296,10 @@ template <typename T,
 struct FlagValue;
 
 template <typename T>
-struct FlagValue<T, FlagValueStorageKind::kHeapAllocated>
-    : FlagHeapAllocatedValue {
+struct FlagValue<T, FlagValueStorageKind::kAlignedBuffer> {
   bool Get(T*) const { return false; }
+
+  alignas(T) char value[sizeof(T)];
 };
 
 template <typename T>
@@ -347,10 +344,8 @@ struct FlagCallback {
 // The class encapsulates the Flag's data and access to it.
 
 struct DynValueDeleter {
-  explicit DynValueDeleter(FlagOpFn op_arg = nullptr) : op(op_arg) {}
-  void operator()(void* ptr) const {
-    if (op != nullptr) flags_internal::Delete(op, ptr);
-  }
+  explicit DynValueDeleter(FlagOpFn op_arg = nullptr);
+  void operator()(void* ptr) const;
 
   FlagOpFn op;
 };
@@ -416,10 +411,10 @@ class FlagImpl final : public flags_internal::CommandLineFlag {
   // it is only used inside the three routines below, which are defined in
   // flag.cc, we can define it in that file as well.
   template <typename StorageT>
-  typename StorageT::value_type& OffsetValue() const;
-  // This is an accessor for a value stored in heap allocated storage.
-  // Returns a mutable reference to a pointer to allow vlaue mutation.
-  void*& HeapAllocatedValue() const;
+  StorageT* OffsetValue() const;
+  // This is an accessor for a value stored in an aligned buffer storage.
+  // Returns a mutable pointer to the start of a buffer.
+  void* AlignedBufferValue() const;
   // This is an accessor for a value stored as one word atomic. Returns a
   // mutable reference to an atomic value.
   std::atomic<int64_t>& OneWordValue() const;
@@ -492,17 +487,8 @@ class FlagImpl final : public flags_internal::CommandLineFlag {
   // Kind of storage this flag is using for the flag's value.
   const uint8_t value_storage_kind_ : 2;
 
-  // ------------------------------------------------------------------------
-  // The bytes containing the const bitfields must not be shared with bytes
-  // containing the mutable bitfields.
-  // ------------------------------------------------------------------------
-
-  // Unique tag for absl::call_once call to initialize this flag.
-  //
-  // The placement of this variable between the immutable and mutable bitfields
-  // is important as prevents them from occupying the same byte. If you remove
-  // this variable, make sure to maintain this property.
-  absl::once_flag init_control_;
+  uint8_t : 0;  // The bytes containing the const bitfields must not be
+                // shared with bytes containing the mutable bitfields.
 
   // Mutable flag's state (guarded by `data_guard_`).
 
@@ -514,6 +500,9 @@ class FlagImpl final : public flags_internal::CommandLineFlag {
   // Has this flag been specified on command line.
   bool on_command_line_ : 1 ABSL_GUARDED_BY(*DataGuard());
 
+  // Unique tag for absl::call_once call to initialize this flag.
+  absl::once_flag init_control_;
+
   // Mutation counter
   int64_t counter_ ABSL_GUARDED_BY(*DataGuard());
   // Optional flag's callback and absl::Mutex to guard the invocations.
@@ -600,11 +589,17 @@ class Flag {
 template <typename T>
 void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3) {
   switch (op) {
-    case FlagOp::kDelete:
-      delete static_cast<const T*>(v1);
+    case FlagOp::kAlloc: {
+      std::allocator<T> alloc;
+      return std::allocator_traits<std::allocator<T>>::allocate(alloc, 1);
+    }
+    case FlagOp::kDelete: {
+      T* p = static_cast<T*>(v2);
+      p->~T();
+      std::allocator<T> alloc;
+      std::allocator_traits<std::allocator<T>>::deallocate(alloc, p, 1);
       return nullptr;
-    case FlagOp::kClone:
-      return new T(*static_cast<const T*>(v1));
+    }
     case FlagOp::kCopy:
       *static_cast<T*>(v2) = *static_cast<const T*>(v1);
       return nullptr;
@@ -675,13 +670,13 @@ class FlagRegistrar {
 struct EmptyBraces {};
 
 template <typename T>
-T* MakeFromDefaultValue(T t) {
-  return new T(std::move(t));
+void MakeFromDefaultValue(void* dst, T t) {
+  new (dst) T(std::move(t));
 }
 
 template <typename T>
-T* MakeFromDefaultValue(EmptyBraces) {
-  return new T{};
+void MakeFromDefaultValue(void* dst, EmptyBraces) {
+  new (dst) T{};
 }
 
 }  // namespace flags_internal
diff --git a/absl/random/internal/iostream_state_saver.h b/absl/random/internal/iostream_state_saver.h
index 7378829a42..e6e242ee1e 100644
--- a/absl/random/internal/iostream_state_saver.h
+++ b/absl/random/internal/iostream_state_saver.h
@@ -192,8 +192,8 @@ struct stream_u128_helper<absl::uint128> {
 
   template <typename OStream>
   inline void write(absl::uint128 val, OStream& out) {
-    uint64_t h = Uint128High64(val);
-    uint64_t l = Uint128Low64(val);
+    uint64_t h = absl::Uint128High64(val);
+    uint64_t l = absl::Uint128Low64(val);
     out << h << out.fill() << l;
   }
 };
diff --git a/absl/random/internal/nanobenchmark_test.cc b/absl/random/internal/nanobenchmark_test.cc
index ab824ef55f..f1571e269f 100644
--- a/absl/random/internal/nanobenchmark_test.cc
+++ b/absl/random/internal/nanobenchmark_test.cc
@@ -53,7 +53,7 @@ void RunAll(const int argc, char* argv[]) {
   // Avoid migrating between cores - important on multi-socket systems.
   int cpu = -1;
   if (argc == 2) {
-    if (!SimpleAtoi(argv[1], &cpu)) {
+    if (!absl::SimpleAtoi(argv[1], &cpu)) {
       ABSL_RAW_LOG(FATAL, "The optional argument must be a CPU number >= 0.\n");
     }
   }
diff --git a/absl/random/internal/wide_multiply.h b/absl/random/internal/wide_multiply.h
index 6e4cf1be0a..0afcbe08e2 100644
--- a/absl/random/internal/wide_multiply.h
+++ b/absl/random/internal/wide_multiply.h
@@ -38,9 +38,9 @@ namespace random_internal {
 // MultiplyU64ToU128 multiplies two 64-bit values to a 128-bit value.
 // If an intrinsic is available, it is used, otherwise use native 32-bit
 // multiplies to construct the result.
-inline uint128 MultiplyU64ToU128(uint64_t a, uint64_t b) {
+inline absl::uint128 MultiplyU64ToU128(uint64_t a, uint64_t b) {
 #if defined(ABSL_HAVE_INTRINSIC_INT128)
-  return uint128(static_cast<__uint128_t>(a) * b);
+  return absl::uint128(static_cast<__uint128_t>(a) * b);
 #elif defined(ABSL_INTERNAL_USE_UMUL128)
   // uint64_t * uint64_t => uint128 multiply using imul intrinsic on MSVC.
   uint64_t high = 0;
@@ -93,14 +93,14 @@ struct wide_multiply {
 template <>
 struct wide_multiply<uint64_t> {
   using input_type = uint64_t;
-  using result_type = uint128;
+  using result_type = absl::uint128;
 
   static result_type multiply(uint64_t a, uint64_t b) {
     return MultiplyU64ToU128(a, b);
   }
 
-  static uint64_t hi(result_type r) { return Uint128High64(r); }
-  static uint64_t lo(result_type r) { return Uint128Low64(r); }
+  static uint64_t hi(result_type r) { return absl::Uint128High64(r); }
+  static uint64_t lo(result_type r) { return absl::Uint128Low64(r); }
 };
 #endif
 
diff --git a/absl/time/duration.cc b/absl/time/duration.cc
index 1353fa0aec..f01825599d 100644
--- a/absl/time/duration.cc
+++ b/absl/time/duration.cc
@@ -732,9 +732,9 @@ void AppendNumberUnit(std::string* out, int64_t n, DisplayUnit unit) {
 // Note: unit.prec is limited to double's digits10 value (typically 15) so it
 // always fits in buf[].
 void AppendNumberUnit(std::string* out, double n, DisplayUnit unit) {
-  const int buf_size = std::numeric_limits<double>::digits10;
-  const int prec = std::min(buf_size, unit.prec);
-  char buf[buf_size];  // also large enough to hold integer part
+  constexpr int kBufferSize = std::numeric_limits<double>::digits10;
+  const int prec = std::min(kBufferSize, unit.prec);
+  char buf[kBufferSize];  // also large enough to hold integer part
   char* ep = buf + sizeof(buf);
   double d = 0;
   int64_t frac_part = Round(std::modf(n, &d) * unit.pow10);
diff --git a/ci/cmake_install_test.sh b/ci/cmake_install_test.sh
index 4c748eb9df..b31e4b8cdb 100755
--- a/ci/cmake_install_test.sh
+++ b/ci/cmake_install_test.sh
@@ -16,7 +16,7 @@
 
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
diff --git a/ci/linux_clang-latest_libcxx_asan_bazel.sh b/ci/linux_clang-latest_libcxx_asan_bazel.sh
index 03463e2eae..88d2a97dfe 100755
--- a/ci/linux_clang-latest_libcxx_asan_bazel.sh
+++ b/ci/linux_clang-latest_libcxx_asan_bazel.sh
@@ -20,19 +20,19 @@
 
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
-if [ -z ${STD:-} ]; then
+if [[ -z ${STD:-} ]]; then
   STD="c++11 c++14 c++17"
 fi
 
-if [ -z ${COMPILATION_MODE:-} ]; then
+if [[ -z ${COMPILATION_MODE:-} ]]; then
   COMPILATION_MODE="fastbuild opt"
 fi
 
-if [ -z ${EXCEPTIONS_MODE:-} ]; then
+if [[ -z ${EXCEPTIONS_MODE:-} ]]; then
   EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
 fi
 
@@ -41,7 +41,7 @@ readonly DOCKER_CONTAINER=${LINUX_CLANG_LATEST_CONTAINER}
 
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
-if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
+if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
   DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
   # Bazel doesn't track changes to tools outside of the workspace
   # (e.g. /usr/bin/gcc), so by appending the docker container to the
@@ -54,7 +54,7 @@ fi
 # Avoid depending on external sites like GitHub by checking --distdir for
 # external dependencies first.
 # https://docs.bazel.build/versions/master/guide.html#distdir
-if [ -z ${KOKORO_GFILE_DIR:-} && -d "${KOKORO_GFILE_DIR}/distdir" ]; then
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
   DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
   BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
 fi
diff --git a/ci/linux_clang-latest_libcxx_bazel.sh b/ci/linux_clang-latest_libcxx_bazel.sh
index 050a98c93b..f344a588ae 100755
--- a/ci/linux_clang-latest_libcxx_bazel.sh
+++ b/ci/linux_clang-latest_libcxx_bazel.sh
@@ -20,19 +20,19 @@
 
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
-if [ -z ${STD:-} ]; then
+if [[ -z ${STD:-} ]]; then
   STD="c++11 c++14 c++17"
 fi
 
-if [ -z ${COMPILATION_MODE:-} ]; then
+if [[ -z ${COMPILATION_MODE:-} ]]; then
   COMPILATION_MODE="fastbuild opt"
 fi
 
-if [ -z ${EXCEPTIONS_MODE:-} ]; then
+if [[ -z ${EXCEPTIONS_MODE:-} ]]; then
   EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
 fi
 
@@ -41,7 +41,7 @@ readonly DOCKER_CONTAINER=${LINUX_CLANG_LATEST_CONTAINER}
 
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
-if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
+if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
   DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
   # Bazel doesn't track changes to tools outside of the workspace
   # (e.g. /usr/bin/gcc), so by appending the docker container to the
@@ -54,7 +54,7 @@ fi
 # Avoid depending on external sites like GitHub by checking --distdir for
 # external dependencies first.
 # https://docs.bazel.build/versions/master/guide.html#distdir
-if [ -z ${KOKORO_GFILE_DIR:-} && -d "${KOKORO_GFILE_DIR}/distdir" ]; then
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
   DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
   BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
 fi
diff --git a/ci/linux_clang-latest_libcxx_tsan_bazel.sh b/ci/linux_clang-latest_libcxx_tsan_bazel.sh
index 2f5fb12d2e..f7238457ee 100755
--- a/ci/linux_clang-latest_libcxx_tsan_bazel.sh
+++ b/ci/linux_clang-latest_libcxx_tsan_bazel.sh
@@ -20,19 +20,19 @@
 
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
-if [ -z ${STD:-} ]; then
+if [[ -z ${STD:-} ]]; then
   STD="c++11 c++14 c++17"
 fi
 
-if [ -z ${COMPILATION_MODE:-} ]; then
+if [[ -z ${COMPILATION_MODE:-} ]]; then
   COMPILATION_MODE="fastbuild opt"
 fi
 
-if [ -z ${EXCEPTIONS_MODE:-} ]; then
+if [[ -z ${EXCEPTIONS_MODE:-} ]]; then
   EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
 fi
 
@@ -41,7 +41,7 @@ readonly DOCKER_CONTAINER=${LINUX_CLANG_LATEST_CONTAINER}
 
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
-if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
+if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
   DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
   # Bazel doesn't track changes to tools outside of the workspace
   # (e.g. /usr/bin/gcc), so by appending the docker container to the
@@ -54,7 +54,7 @@ fi
 # Avoid depending on external sites like GitHub by checking --distdir for
 # external dependencies first.
 # https://docs.bazel.build/versions/master/guide.html#distdir
-if [ -z ${KOKORO_GFILE_DIR:-} && -d "${KOKORO_GFILE_DIR}/distdir" ]; then
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
   DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
   BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
 fi
diff --git a/ci/linux_clang-latest_libstdcxx_bazel.sh b/ci/linux_clang-latest_libstdcxx_bazel.sh
index 087f59ba45..62696293c8 100755
--- a/ci/linux_clang-latest_libstdcxx_bazel.sh
+++ b/ci/linux_clang-latest_libstdcxx_bazel.sh
@@ -20,19 +20,19 @@
 
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
-if [ -z ${STD:-} ]; then
+if [[ -z ${STD:-} ]]; then
   STD="c++11 c++14 c++17"
 fi
 
-if [ -z ${COMPILATION_MODE:-} ]; then
+if [[ -z ${COMPILATION_MODE:-} ]]; then
   COMPILATION_MODE="fastbuild opt"
 fi
 
-if [ -z ${EXCEPTIONS_MODE:-} ]; then
+if [[ -z ${EXCEPTIONS_MODE:-} ]]; then
   EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
 fi
 
@@ -41,7 +41,7 @@ readonly DOCKER_CONTAINER=${LINUX_CLANG_LATEST_CONTAINER}
 
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
-if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
+if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
   DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
   # Bazel doesn't track changes to tools outside of the workspace
   # (e.g. /usr/bin/gcc), so by appending the docker container to the
@@ -54,7 +54,7 @@ fi
 # Avoid depending on external sites like GitHub by checking --distdir for
 # external dependencies first.
 # https://docs.bazel.build/versions/master/guide.html#distdir
-if [ -z ${KOKORO_GFILE_DIR:-} && -d "${KOKORO_GFILE_DIR}/distdir" ]; then
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
   DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
   BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
 fi
diff --git a/ci/linux_gcc-4.9_libstdcxx_bazel.sh b/ci/linux_gcc-4.9_libstdcxx_bazel.sh
index 622ea84bc2..8e6540cf02 100755
--- a/ci/linux_gcc-4.9_libstdcxx_bazel.sh
+++ b/ci/linux_gcc-4.9_libstdcxx_bazel.sh
@@ -20,19 +20,19 @@
 
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
-if [ -z ${STD:-} ]; then
+if [[ -z ${STD:-} ]]; then
   STD="c++11 c++14"
 fi
 
-if [ -z ${COMPILATION_MODE:-} ]; then
+if [[ -z ${COMPILATION_MODE:-} ]]; then
   COMPILATION_MODE="fastbuild opt"
 fi
 
-if [ -z ${EXCEPTIONS_MODE:-} ]; then
+if [[ -z ${EXCEPTIONS_MODE:-} ]]; then
   EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
 fi
 
@@ -41,7 +41,7 @@ readonly DOCKER_CONTAINER=${LINUX_GCC_49_CONTAINER}
 
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
-if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
+if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
   DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
   # Bazel doesn't track changes to tools outside of the workspace
   # (e.g. /usr/bin/gcc), so by appending the docker container to the
@@ -54,7 +54,7 @@ fi
 # Avoid depending on external sites like GitHub by checking --distdir for
 # external dependencies first.
 # https://docs.bazel.build/versions/master/guide.html#distdir
-if [ -z ${KOKORO_GFILE_DIR:-} && -d "${KOKORO_GFILE_DIR}/distdir" ]; then
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
   DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
   BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
 fi
diff --git a/ci/linux_gcc-latest_libstdcxx_bazel.sh b/ci/linux_gcc-latest_libstdcxx_bazel.sh
index f7dbd199de..337285b092 100755
--- a/ci/linux_gcc-latest_libstdcxx_bazel.sh
+++ b/ci/linux_gcc-latest_libstdcxx_bazel.sh
@@ -20,19 +20,19 @@
 
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
-if [ -z ${STD:-} ]; then
+if [[ -z ${STD:-} ]]; then
   STD="c++11 c++14 c++17"
 fi
 
-if [ -z ${COMPILATION_MODE:-} ]; then
+if [[ -z ${COMPILATION_MODE:-} ]]; then
   COMPILATION_MODE="fastbuild opt"
 fi
 
-if [ -z ${EXCEPTIONS_MODE:-} ]; then
+if [[ -z ${EXCEPTIONS_MODE:-} ]]; then
   EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
 fi
 
@@ -41,7 +41,7 @@ readonly DOCKER_CONTAINER=${LINUX_GCC_LATEST_CONTAINER}
 
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
-if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
+if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
   DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
   # Bazel doesn't track changes to tools outside of the workspace
   # (e.g. /usr/bin/gcc), so by appending the docker container to the
@@ -54,7 +54,7 @@ fi
 # Avoid depending on external sites like GitHub by checking --distdir for
 # external dependencies first.
 # https://docs.bazel.build/versions/master/guide.html#distdir
-if [ -z ${KOKORO_GFILE_DIR:-} && -d "${KOKORO_GFILE_DIR}/distdir" ]; then
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
   DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
   BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
 fi
@@ -75,7 +75,7 @@ for std in ${STD}; do
         ${DOCKER_CONTAINER} \
         /bin/sh -c "
           cp -r /abseil-cpp-ro/* /abseil-cpp/
-          if [ -n \"${ALTERNATE_OPTIONS:-}\" ]; then
+          if [[ -n \"${ALTERNATE_OPTIONS:-}\" ]]; then
             cp ${ALTERNATE_OPTIONS:-} absl/base/options.h || exit 1
           fi
           /usr/local/bin/bazel test ... \
diff --git a/ci/linux_gcc-latest_libstdcxx_cmake.sh b/ci/linux_gcc-latest_libstdcxx_cmake.sh
index b501544945..db5f69181e 100755
--- a/ci/linux_gcc-latest_libstdcxx_cmake.sh
+++ b/ci/linux_gcc-latest_libstdcxx_cmake.sh
@@ -22,15 +22,15 @@
 
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
-if [ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]; then
+if [[ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]]; then
   ABSL_CMAKE_CXX_STANDARDS="11 14 17"
 fi
 
-if [ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]; then
+if [[ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]]; then
   ABSL_CMAKE_BUILD_TYPES="Debug Release"
 fi
 
diff --git a/ci/linux_gcc_alpine_cmake.sh b/ci/linux_gcc_alpine_cmake.sh
index 4496f8d476..f57ab12b1f 100755
--- a/ci/linux_gcc_alpine_cmake.sh
+++ b/ci/linux_gcc_alpine_cmake.sh
@@ -22,15 +22,15 @@
 
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
-if [ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]; then
+if [[ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]]; then
   ABSL_CMAKE_CXX_STANDARDS="11 14 17"
 fi
 
-if [ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]; then
+if [[ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]]; then
   ABSL_CMAKE_BUILD_TYPES="Debug Release"
 fi
 
diff --git a/ci/macos_xcode_bazel.sh b/ci/macos_xcode_bazel.sh
index f5f2d759cf..738adf9476 100755
--- a/ci/macos_xcode_bazel.sh
+++ b/ci/macos_xcode_bazel.sh
@@ -19,13 +19,13 @@
 
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
 # If we are running on Kokoro, check for a versioned Bazel binary.
 KOKORO_GFILE_BAZEL_BIN="bazel-2.0.0-darwin-x86_64"
-if [ ${KOKORO_GFILE_DIR:-} ] && [ -f ${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN} ]; then
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f ${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN} ]]; then
   BAZEL_BIN="${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN}"
   chmod +x ${BAZEL_BIN}
 else
@@ -41,7 +41,7 @@ echo "---------------"
 
 cd ${ABSEIL_ROOT}
 
-if [ -n "${ALTERNATE_OPTIONS:-}" ]; then
+if [[ -n "${ALTERNATE_OPTIONS:-}" ]]; then
   cp ${ALTERNATE_OPTIONS:-} absl/base/options.h || exit 1
 fi
 
diff --git a/ci/macos_xcode_cmake.sh b/ci/macos_xcode_cmake.sh
index a1f4a857be..cf78e207e3 100755
--- a/ci/macos_xcode_cmake.sh
+++ b/ci/macos_xcode_cmake.sh
@@ -19,12 +19,12 @@
 
 set -euox pipefail
 
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(dirname ${0})/.."
 fi
 ABSEIL_ROOT=$(realpath ${ABSEIL_ROOT})
 
-if [ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]; then
+if [[ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]]; then
   ABSL_CMAKE_BUILD_TYPES="Debug"
 fi