about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAbseil Team <absl-team@google.com>2018-05-04T16·58-0700
committervslashg <gfalcon@google.com>2018-05-04T17·30-0400
commit26b789f9a53d086c8b8c9c2668efb251e37861cd (patch)
tree9fdcdfa6f42993dd9abce0498d18810911765211
parent9613678332c976568272c8f4a78631a29159271d (diff)
- 07191b0f52301e1e4a790e236f7b7c2fd90561ae Disambiguates computed return type of absl::optional logi... by Abseil Team <absl-team@google.com>
  - acd95f8ec4e6ec1587cb198c7f40af3c81094d92 Release container benchmarks. by Alex Strelnikov <strel@google.com>
  - 80f596b6b7c5e06453e778c16527d5a0e85f8413 Allow absl::base_internal::AtomicHook to have a default v... by Derek Mauro <dmauro@google.com>
  - 8402631546af8bcbd4acdf897d0cdfb805ad544a Release thread_identity benchmark. by Alex Strelnikov <strel@google.com>
  - 6dcb1e90fefb8556ce4654983d3a73c7585b4b99 Fix spelling error in variant.h by Abseil Team <absl-team@google.com>
  - faa8a81e1442018c0d400b09a595a5be55074715 Run tests from CMake.  The CI is currently Linux only, fo... by Jon Cohen <cohenjon@google.com>
  - 745ed6db574f931f2ec3a88e964fb03a5f22f816 Internal change. by Derek Mauro <dmauro@google.com>
  - 23facd7d1c5f43ac8181b016ee4acc5955f048c1 absl::variant exception safety test. by Xiaoyi Zhang <zhangxy@google.com>
  - c18e21e7cf8f6e83ae9d90e536e886409dd6cf68 Reinstate the syntax check on time-zone abbreviations now... by Abseil Team <absl-team@google.com>
  - da469f4314f0c820665a2b5b9477af9462b23e42 Import CCTZ changes to internal copy. by Shaindel Schwartz <shaindel@google.com>
  - 44ea35843517be03ab256b69449ccfea64352621 Import CCTZ changes to internal copy. by Abseil Team <absl-team@google.com>
  - 55d1105312687c6093950fac831c7540f49045b5 Import CCTZ changes to internal copy. by Greg Falcon <gfalcon@google.com>
  - 58d7965ad274406410b6d833213eca04d41c6867 Add zoneinfo as a data dependency to the //absl/time tests. by Shaindel Schwartz <shaindel@google.com>
  - 6acc50146f9ff29015bfaaa5bf9900691f839da5 Change benchmark target type from cc_test to cc_binary. by Alex Strelnikov <strel@google.com>
  - db3fbdae8f9f285a466f7a070326b1ce43b6a0dd Update WORKSPACE for C++ microbenchmarks and release algo... by Alex Strelnikov <strel@google.com>
  - 0869ae168255242af651853ed01719166d8cebf6 Update to Bazel version 0.13.0. by Abseil Team <absl-team@google.com>
  - e507dd53ab788964207fdf27d31b72a33c296fab Add missing include of cstdio by Abseil Team <absl-team@google.com>

GitOrigin-RevId: 07191b0f52301e1e4a790e236f7b7c2fd90561ae
Change-Id: I90994cf2b438fbec894724dcd9b90882281eef56
-rw-r--r--CMake/AbseilHelpers.cmake2
-rw-r--r--CMake/CMakeLists.txt.in15
-rw-r--r--CMake/DownloadGTest.cmake32
-rw-r--r--CMake/README.md32
-rw-r--r--CMakeLists.txt22
-rw-r--r--WORKSPACE15
-rw-r--r--absl/algorithm/BUILD.bazel12
-rw-r--r--absl/algorithm/equal_benchmark.cc128
-rw-r--r--absl/base/BUILD.bazel25
-rw-r--r--absl/base/CMakeLists.txt33
-rw-r--r--absl/base/exception_safety_testing_test.cc21
-rw-r--r--absl/base/internal/atomic_hook.h59
-rw-r--r--absl/base/internal/atomic_hook_test.cc70
-rw-r--r--absl/base/internal/exception_safety_testing.h16
-rw-r--r--absl/base/internal/thread_identity_benchmark.cc40
-rw-r--r--absl/container/BUILD.bazel24
-rw-r--r--absl/container/fixed_array_benchmark.cc68
-rw-r--r--absl/container/inlined_vector_benchmark.cc376
-rw-r--r--absl/debugging/CMakeLists.txt41
-rw-r--r--absl/debugging/failure_signal_handler.cc1
-rw-r--r--absl/meta/CMakeLists.txt5
-rw-r--r--absl/strings/str_join_test.cc1
-rw-r--r--absl/time/internal/cctz/BUILD.bazel7
-rw-r--r--absl/time/internal/cctz/include/cctz/civil_time_detail.h4
-rw-r--r--absl/time/internal/cctz/src/civil_time_test.cc4
-rw-r--r--absl/time/internal/cctz/src/time_zone_fixed.cc34
-rw-r--r--absl/time/internal/cctz/src/time_zone_lookup.cc3
-rw-r--r--absl/time/internal/cctz/src/time_zone_lookup_test.cc12
-rw-r--r--absl/time/internal/test_util.cc3
-rw-r--r--absl/types/BUILD.bazel15
-rw-r--r--absl/types/CMakeLists.txt14
-rw-r--r--absl/types/optional.h38
-rw-r--r--absl/types/variant.h2
-rw-r--r--absl/types/variant_exception_safety_test.cc519
-rw-r--r--absl/utility/CMakeLists.txt9
35 files changed, 1583 insertions, 119 deletions
diff --git a/CMake/AbseilHelpers.cmake b/CMake/AbseilHelpers.cmake
index 0520fba3f0..7b6f0879d6 100644
--- a/CMake/AbseilHelpers.cmake
+++ b/CMake/AbseilHelpers.cmake
@@ -139,7 +139,7 @@ function(absl_test)
       PRIVATE ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS}
     )
 
-    add_test(${_NAME}_test ${_NAME}_bin)
+    add_test(${_NAME} ${_NAME}_bin)
   endif(BUILD_TESTING)
 
 endfunction()
diff --git a/CMake/CMakeLists.txt.in b/CMake/CMakeLists.txt.in
new file mode 100644
index 0000000000..d60a33e9ac
--- /dev/null
+++ b/CMake/CMakeLists.txt.in
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 2.8.2)
+
+project(googletest-download NONE)
+
+include(ExternalProject)
+ExternalProject_Add(googletest
+  GIT_REPOSITORY    https://github.com/google/googletest.git
+  GIT_TAG           master
+  SOURCE_DIR        "${CMAKE_BINARY_DIR}/googletest-src"
+  BINARY_DIR        "${CMAKE_BINARY_DIR}/googletest-build"
+  CONFIGURE_COMMAND ""
+  BUILD_COMMAND     ""
+  INSTALL_COMMAND   ""
+  TEST_COMMAND      ""
+)
\ No newline at end of file
diff --git a/CMake/DownloadGTest.cmake b/CMake/DownloadGTest.cmake
new file mode 100644
index 0000000000..9d4132158b
--- /dev/null
+++ b/CMake/DownloadGTest.cmake
@@ -0,0 +1,32 @@
+# Downloads and unpacks googletest at configure time.  Based on the instructions
+# at https://github.com/google/googletest/tree/master/googletest#incorporating-into-an-existing-cmake-project
+
+# Download the latest googletest from Github master
+configure_file(
+  ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt.in
+  googletest-download/CMakeLists.txt
+)
+
+# Configure and build the downloaded googletest source
+execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
+  RESULT_VARIABLE result
+  WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
+if(result)
+  message(FATAL_ERROR "CMake step for googletest failed: ${result}")
+endif()
+
+execute_process(COMMAND ${CMAKE_COMMAND} --build .
+  RESULT_VARIABLE result
+  WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
+if(result)
+  message(FATAL_ERROR "Build step for googletest failed: ${result}")
+endif()
+
+# Prevent overriding the parent project's compiler/linker settings on Windows
+set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
+
+# Add googletest directly to our build. This defines the gtest and gtest_main
+# targets.
+add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
+                 ${CMAKE_BINARY_DIR}/googletest-build
+                 EXCLUDE_FROM_ALL)
diff --git a/CMake/README.md b/CMake/README.md
index e99340cc6b..79bbe24d5a 100644
--- a/CMake/README.md
+++ b/CMake/README.md
@@ -52,14 +52,42 @@ if(MSVC)
   add_definitions(/DNOMINMAX /DWIN32_LEAN_AND_MEAN=1 /D_CRT_SECURE_NO_WARNINGS)
 endif()
 
-add_subdirectory(googletest)
-add_subdirectory(cctz)
 add_subdirectory(abseil-cpp)
 
 add_executable(my_exe source.cpp)
 target_link_libraries(my_exe absl::base absl::synchronization absl::strings)
 ```
 
+### Running Abseil Tests with CMake
+
+Use the `-DABSL_RUN_TESTS=ON` flag to run Abseil tests.  Note that if the `-DBUILD_TESTING=OFF` flag is passed then Abseil tests will not be run.
+
+You will need to provide Abseil with a Googletest dependency.  There are two
+options for how to do this:
+
+* Use `-DABSL_USE_GOOGLETEST_HEAD`.  This will automatically download the latest
+Googletest source into the build directory at configure time.  Googletest will
+then be compiled directly alongside Abseil's tests.
+* Manually integrate Googletest with your build.  See
+https://github.com/google/googletest/blob/master/googletest/README.md#using-cmake
+for more information on using Googletest in a CMake project.
+
+For example, to run just the Abseil tests, you could use this script:
+
+```
+cd path/to/abseil-cpp
+mkdir build
+cd build
+cmake -DABSL_USE_GOOGLETEST_HEAD=ON -DABSL_RUN_TESTS=ON ..
+make -j
+ctest
+```
+
+Currently, we only run our tests with CMake in a Linux environment, but we are
+working on the rest of our supported platforms. See
+https://github.com/abseil/abseil-cpp/projects/1 and
+https://github.com/abseil/abseil-cpp/issues/109 for more information.
+
 ### Available Abseil CMake Public Targets
 
 Here's a non-exhaustive list of Abseil CMake public targets:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e46bdf455e..1a8f86222f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,9 +16,6 @@
 cmake_minimum_required(VERSION 2.8.12)
 project(absl)
 
-# enable ctest
-include(CTest)
-
 list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake)
 
 include(GNUInstallDirs)
@@ -65,12 +62,25 @@ set(ABSL_EXCEPTIONS_FLAG "${CMAKE_CXX_EXCEPTIONS}")
 ## pthread
 find_package(Threads REQUIRED)
 
-# commented: used only for standalone test
-# Don't remove these or else CMake CI will break
-#add_subdirectory(googletest)
+option(ABSL_USE_GOOGLETEST_HEAD
+  "If ON, abseil will download HEAD from googletest at config time." OFF)
+
+option(ABSL_RUN_TESTS "If ON, Abseil tests will be run." OFF)
+
+if(${ABSL_RUN_TESTS})
+  # enable CTest.  This will set BUILD_TESTING to ON unless otherwise specified
+  # on the command line
+  include(CTest)
+  enable_testing()
+endif()
 
 ## check targets
 if(BUILD_TESTING)
+
+  if(${ABSL_USE_GOOGLETEST_HEAD})
+    include(CMake/DownloadGTest.cmake)
+  endif()
+
   check_target(gtest)
   check_target(gtest_main)
   check_target(gmock)
diff --git a/WORKSPACE b/WORKSPACE
index 0546573f32..064459306d 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -3,11 +3,11 @@ workspace(name = "com_google_absl")
 http_archive(
     name = "bazel_toolchains",
     urls = [
-        "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/r324073.tar.gz",
-        "https://github.com/bazelbuild/bazel-toolchains/archive/r324073.tar.gz",
+        "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/f8847f64e6950e8ab9fde1c0aba768550b0d9ab2.tar.gz",
+        "https://github.com/bazelbuild/bazel-toolchains/archive/f8847f64e6950e8ab9fde1c0aba768550b0d9ab2.tar.gz",
     ],
-    strip_prefix = "bazel-toolchains-r324073",
-    sha256 = "71548c0d6cd53eddebbde4fa9962f5395e82645fb9992719e0890505b177f245",
+    strip_prefix = "bazel-toolchains-f8847f64e6950e8ab9fde1c0aba768550b0d9ab2",
+    sha256 = "794366f51fea224b3656a0b0f8f1518e739748646523a572fcd3d68614a0e670",
 )
 
 # GoogleTest/GoogleMock framework. Used by most unit-tests.
@@ -17,6 +17,13 @@ http_archive(
      strip_prefix = "googletest-master",
 )
 
+# Google benchmark.
+http_archive(
+    name = "com_github_google_benchmark",
+    urls = ["https://github.com/google/benchmark/archive/master.zip"],
+    strip_prefix = "benchmark-master",
+)
+
 # RE2 regular-expression framework. Used by some unit-tests.
 http_archive(
     name = "com_googlesource_code_re2",
diff --git a/absl/algorithm/BUILD.bazel b/absl/algorithm/BUILD.bazel
index 255b986e9a..5cd5496027 100644
--- a/absl/algorithm/BUILD.bazel
+++ b/absl/algorithm/BUILD.bazel
@@ -41,6 +41,18 @@ cc_test(
     ],
 )
 
+cc_binary(
+    name = "algorithm_benchmark",
+    testonly = 1,
+    srcs = ["equal_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":algorithm",
+        "//absl/base:core_headers",
+        "@com_github_google_benchmark//:benchmark",
+    ],
+)
+
 cc_library(
     name = "container",
     hdrs = [
diff --git a/absl/algorithm/equal_benchmark.cc b/absl/algorithm/equal_benchmark.cc
new file mode 100644
index 0000000000..fea6d13766
--- /dev/null
+++ b/absl/algorithm/equal_benchmark.cc
@@ -0,0 +1,128 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <cstdint>
+#include <cstring>
+
+#include "absl/algorithm/algorithm.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+// The range of sequence sizes to benchmark.
+constexpr int kMinBenchmarkSize = 1024;
+constexpr int kMaxBenchmarkSize = 8 * 1024 * 1024;
+
+// A user-defined type for use in equality benchmarks. Note that we expect
+// std::memcmp to win for this type: libstdc++'s std::equal only defers to
+// memcmp for integral types. This is because it is not straightforward to
+// guarantee that std::memcmp would produce a result "as-if" compared by
+// operator== for other types (example gotchas: NaN floats, structs with
+// padding).
+struct EightBits {
+  explicit EightBits(int /* unused */) : data(0) {}
+  bool operator==(const EightBits& rhs) const { return data == rhs.data; }
+  uint8_t data;
+};
+
+template <typename T>
+void BM_absl_equal_benchmark(benchmark::State& state) {
+  std::vector<T> xs(state.range(0), T(0));
+  std::vector<T> ys = xs;
+  while (state.KeepRunning()) {
+    const bool same = absl::equal(xs.begin(), xs.end(), ys.begin(), ys.end());
+    benchmark::DoNotOptimize(same);
+  }
+}
+
+template <typename T>
+void BM_std_equal_benchmark(benchmark::State& state) {
+  std::vector<T> xs(state.range(0), T(0));
+  std::vector<T> ys = xs;
+  while (state.KeepRunning()) {
+    const bool same = std::equal(xs.begin(), xs.end(), ys.begin());
+    benchmark::DoNotOptimize(same);
+  }
+}
+
+template <typename T>
+void BM_memcmp_benchmark(benchmark::State& state) {
+  std::vector<T> xs(state.range(0), T(0));
+  std::vector<T> ys = xs;
+  while (state.KeepRunning()) {
+    const bool same =
+        std::memcmp(xs.data(), ys.data(), xs.size() * sizeof(T)) == 0;
+    benchmark::DoNotOptimize(same);
+  }
+}
+
+// The expectation is that the compiler should be able to elide the equality
+// comparison altogether for sufficiently simple types.
+template <typename T>
+void BM_absl_equal_self_benchmark(benchmark::State& state) {
+  std::vector<T> xs(state.range(0), T(0));
+  while (state.KeepRunning()) {
+    const bool same = absl::equal(xs.begin(), xs.end(), xs.begin(), xs.end());
+    benchmark::DoNotOptimize(same);
+  }
+}
+
+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint8_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint8_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint8_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint8_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+
+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint16_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint16_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint16_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint16_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+
+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint32_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint32_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint32_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint32_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+
+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint64_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint64_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint64_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint64_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+
+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, EightBits)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, EightBits)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, EightBits)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, EightBits)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+
+}  // namespace
+
+BENCHMARK_MAIN();
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index f9aac5a5aa..bb7a598177 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -148,6 +148,18 @@ cc_library(
 )
 
 cc_test(
+    name = "atomic_hook_test",
+    size = "small",
+    srcs = ["internal/atomic_hook_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":base",
+        ":core_headers",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
     name = "bit_cast_test",
     size = "small",
     srcs = [
@@ -393,3 +405,16 @@ cc_test(
         "@com_google_googletest//:gtest_main",
     ],
 )
+
+cc_binary(
+    name = "thread_identity_benchmark",
+    testonly = 1,
+    srcs = ["internal/thread_identity_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":base",
+        "//absl/synchronization",
+        "@com_github_google_benchmark//:benchmark",
+    ],
+)
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index 329a3d0555..4564056278 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -99,14 +99,18 @@ absl_library(
 
 if(BUILD_TESTING)
   # exception-safety testing library
-  set(EXCEPTION_SAFETY_TESTING_SRC "internal/exception_safety_testing.cc")
+  set(EXCEPTION_SAFETY_TESTING_SRC
+    "internal/exception_safety_testing.h"
+    "internal/exception_safety_testing.cc"
+  )
   set(EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES
     ${ABSL_TEST_COMMON_LIBRARIES}
     absl::base
     absl::memory
     absl::meta
     absl::strings
-    absl::types
+    absl::optional
+    gtest
   )
 
 absl_library(
@@ -116,6 +120,8 @@ absl_library(
     ${EXCEPTION_SAFETY_TESTING_SRC}
   PUBLIC_LIBRARIES
     ${EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES}
+  PRIVATE_COMPILE_FLAGS
+    ${ABSL_EXCEPTIONS_FLAG}
 )
 endif()
 
@@ -163,6 +169,20 @@ absl_library(
 #
 
 # call once test
+set(ATOMIC_HOOK_TEST_SRC "internal/atomic_hook_test.cc")
+set(ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES absl::base)
+
+absl_test(
+  TARGET
+    atomic_hook_test
+  SOURCES
+    ${ATOMIC_HOOK_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# call once test
 set(CALL_ONCE_TEST_SRC "call_once_test.cc")
 set(CALL_ONCE_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
 
@@ -344,7 +364,14 @@ absl_test(
 
 #test exceptions_safety_testing_test
 set(EXCEPTION_SAFETY_TESTING_TEST_SRC "exception_safety_testing_test.cc")
-set(EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES absl::base absl::memory absl::meta absl::strings absl::optional)
+set(EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES
+  absl::base
+  absl_base_internal_exception_safety_testing
+  absl::memory
+  absl::meta
+  absl::strings
+  absl::optional
+)
 
 absl_test(
   TARGET
diff --git a/absl/base/exception_safety_testing_test.cc b/absl/base/exception_safety_testing_test.cc
index 9bd8b9dbd0..4507b94658 100644
--- a/absl/base/exception_safety_testing_test.cc
+++ b/absl/base/exception_safety_testing_test.cc
@@ -83,6 +83,27 @@ TEST(ThrowingValueTest, ThrowingAssignment) {
 
   TestOp([&]() { bomb = bomb1; });
   TestOp([&]() { bomb = std::move(bomb1); });
+
+  // Test that when assignment throws, the assignment should fail (lhs != rhs)
+  // and strong guarantee fails (lhs != lhs_copy).
+  {
+    ThrowingValue<> lhs(39), rhs(42);
+    ThrowingValue<> lhs_copy(lhs);
+    SetCountdown();
+    EXPECT_THROW(lhs = rhs, TestException);
+    UnsetCountdown();
+    EXPECT_NE(lhs, rhs);
+    EXPECT_NE(lhs_copy, lhs);
+  }
+  {
+    ThrowingValue<> lhs(39), rhs(42);
+    ThrowingValue<> lhs_copy(lhs), rhs_copy(rhs);
+    SetCountdown();
+    EXPECT_THROW(lhs = std::move(rhs), TestException);
+    UnsetCountdown();
+    EXPECT_NE(lhs, rhs_copy);
+    EXPECT_NE(lhs_copy, lhs);
+  }
 }
 
 TEST(ThrowingValueTest, ThrowingComparisons) {
diff --git a/absl/base/internal/atomic_hook.h b/absl/base/internal/atomic_hook.h
index 47d4013928..b458511b0c 100644
--- a/absl/base/internal/atomic_hook.h
+++ b/absl/base/internal/atomic_hook.h
@@ -21,6 +21,12 @@
 #include <cstdint>
 #include <utility>
 
+#ifdef _MSC_FULL_VER
+#define ABSL_HAVE_WORKING_ATOMIC_POINTER 0
+#else
+#define ABSL_HAVE_WORKING_ATOMIC_POINTER 1
+#endif
+
 namespace absl {
 namespace base_internal {
 
@@ -29,9 +35,15 @@ class AtomicHook;
 
 // AtomicHook is a helper class, templatized on a raw function pointer type, for
 // implementing Abseil customization hooks.  It is a callable object that
-// dispatches to the registered hook, or performs a no-op (and returns a default
+// dispatches to the registered hook.
+//
+// A default constructed object performs a no-op (and returns a default
 // constructed object) if no hook has been registered.
 //
+// Hooks can be pre-registered via constant initialization, for example,
+// ABSL_CONST_INIT static AtomicHook<void(*)()> my_hook(DefaultAction);
+// and then changed at runtime via a call to Store().
+//
 // Reads and writes guarantee memory_order_acquire/memory_order_release
 // semantics.
 template <typename ReturnType, typename... Args>
@@ -39,7 +51,19 @@ class AtomicHook<ReturnType (*)(Args...)> {
  public:
   using FnPtr = ReturnType (*)(Args...);
 
-  constexpr AtomicHook() : hook_(kInitialValue) {}
+  // Constructs an object that by default performs a no-op (and
+  // returns a default constructed object) when no hook as been registered.
+  constexpr AtomicHook() : AtomicHook(DummyFunction) {}
+
+  // Constructs an object that by default dispatches to/returns the
+  // pre-registered default_fn when no hook has been registered at runtime.
+#if ABSL_HAVE_WORKING_ATOMIC_POINTER
+  explicit constexpr AtomicHook(FnPtr default_fn)
+      : hook_(default_fn), default_fn_(default_fn) {}
+#else
+  explicit constexpr AtomicHook(FnPtr default_fn)
+      : hook_(kUninitialized), default_fn_(default_fn) {}
+#endif
 
   // Stores the provided function pointer as the value for this hook.
   //
@@ -86,16 +110,7 @@ class AtomicHook<ReturnType (*)(Args...)> {
   //
   // This causes an issue when building with LLVM under Windows.  To avoid this,
   // we use a less-efficient, intptr_t-based implementation on Windows.
-
-#ifdef _MSC_FULL_VER
-#define ABSL_HAVE_WORKING_ATOMIC_POINTER 0
-#else
-#define ABSL_HAVE_WORKING_ATOMIC_POINTER 1
-#endif
-
 #if ABSL_HAVE_WORKING_ATOMIC_POINTER
-  static constexpr FnPtr kInitialValue = &DummyFunction;
-
   // Return the stored value, or DummyFunction if no value has been stored.
   FnPtr DoLoad() const { return hook_.load(std::memory_order_acquire); }
 
@@ -103,10 +118,9 @@ class AtomicHook<ReturnType (*)(Args...)> {
   // stored to this object.
   bool DoStore(FnPtr fn) {
     assert(fn);
-    FnPtr expected = DummyFunction;
-    hook_.compare_exchange_strong(expected, fn, std::memory_order_acq_rel,
-                                  std::memory_order_acquire);
-    const bool store_succeeded = (expected == DummyFunction);
+    FnPtr expected = default_fn_;
+    const bool store_succeeded = hook_.compare_exchange_strong(
+        expected, fn, std::memory_order_acq_rel, std::memory_order_acquire);
     const bool same_value_already_stored = (expected == fn);
     return store_succeeded || same_value_already_stored;
   }
@@ -114,15 +128,15 @@ class AtomicHook<ReturnType (*)(Args...)> {
   std::atomic<FnPtr> hook_;
 #else  // !ABSL_HAVE_WORKING_ATOMIC_POINTER
   // Use a sentinel value unlikely to be the address of an actual function.
-  static constexpr intptr_t kInitialValue = 0;
+  static constexpr intptr_t kUninitialized = 0;
 
   static_assert(sizeof(intptr_t) >= sizeof(FnPtr),
                 "intptr_t can't contain a function pointer");
 
   FnPtr DoLoad() const {
     const intptr_t value = hook_.load(std::memory_order_acquire);
-    if (value == 0) {
-      return DummyFunction;
+    if (value == kUninitialized) {
+      return default_fn_;
     }
     return reinterpret_cast<FnPtr>(value);
   }
@@ -130,16 +144,17 @@ class AtomicHook<ReturnType (*)(Args...)> {
   bool DoStore(FnPtr fn) {
     assert(fn);
     const auto value = reinterpret_cast<intptr_t>(fn);
-    intptr_t expected = 0;
-    hook_.compare_exchange_strong(expected, value, std::memory_order_acq_rel,
-                                  std::memory_order_acquire);
-    const bool store_succeeded = (expected == 0);
+    intptr_t expected = kUninitialized;
+    const bool store_succeeded = hook_.compare_exchange_strong(
+        expected, value, std::memory_order_acq_rel, std::memory_order_acquire);
     const bool same_value_already_stored = (expected == value);
     return store_succeeded || same_value_already_stored;
   }
 
   std::atomic<intptr_t> hook_;
 #endif
+
+  const FnPtr default_fn_;
 };
 
 #undef ABSL_HAVE_WORKING_ATOMIC_POINTER
diff --git a/absl/base/internal/atomic_hook_test.cc b/absl/base/internal/atomic_hook_test.cc
new file mode 100644
index 0000000000..cf7407573a
--- /dev/null
+++ b/absl/base/internal/atomic_hook_test.cc
@@ -0,0 +1,70 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/atomic_hook.h"
+
+#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+
+namespace {
+
+int value = 0;
+void TestHook(int x) { value = x; }
+
+TEST(AtomicHookTest, NoDefaultFunction) {
+  ABSL_CONST_INIT static absl::base_internal::AtomicHook<void(*)(int)> hook;
+  value = 0;
+
+  // Test the default DummyFunction.
+  EXPECT_TRUE(hook.Load() == nullptr);
+  EXPECT_EQ(value, 0);
+  hook(1);
+  EXPECT_EQ(value, 0);
+
+  // Test a stored hook.
+  hook.Store(TestHook);
+  EXPECT_TRUE(hook.Load() == TestHook);
+  EXPECT_EQ(value, 0);
+  hook(1);
+  EXPECT_EQ(value, 1);
+
+  // Calling Store() with the same hook should not crash.
+  hook.Store(TestHook);
+  EXPECT_TRUE(hook.Load() == TestHook);
+  EXPECT_EQ(value, 1);
+  hook(2);
+  EXPECT_EQ(value, 2);
+}
+
+TEST(AtomicHookTest, WithDefaultFunction) {
+  // Set the default value to TestHook at compile-time.
+  ABSL_CONST_INIT static absl::base_internal::AtomicHook<void (*)(int)> hook(
+      TestHook);
+  value = 0;
+
+  // Test the default value is TestHook.
+  EXPECT_TRUE(hook.Load() == TestHook);
+  EXPECT_EQ(value, 0);
+  hook(1);
+  EXPECT_EQ(value, 1);
+
+  // Calling Store() with the same hook should not crash.
+  hook.Store(TestHook);
+  EXPECT_TRUE(hook.Load() == TestHook);
+  EXPECT_EQ(value, 1);
+  hook(2);
+  EXPECT_EQ(value, 2);
+}
+
+}  // namespace
diff --git a/absl/base/internal/exception_safety_testing.h b/absl/base/internal/exception_safety_testing.h
index 32450465a3..bec3ab3046 100644
--- a/absl/base/internal/exception_safety_testing.h
+++ b/absl/base/internal/exception_safety_testing.h
@@ -164,7 +164,7 @@ class ConstructorTracker {
 
 template <typename Factory, typename Operation, typename Invariant>
 absl::optional<testing::AssertionResult> TestSingleInvariantAtCountdownImpl(
-    const Factory& factory, const Operation& operation, int count,
+    const Factory& factory, Operation operation, int count,
     const Invariant& invariant) {
   auto t_ptr = factory();
   absl::optional<testing::AssertionResult> current_res;
@@ -277,10 +277,12 @@ enum class TypeSpec {
  */
 template <TypeSpec Spec = TypeSpec::kEverythingThrows>
 class ThrowingValue : private exceptions_internal::TrackedObject {
-  constexpr static bool IsSpecified(TypeSpec spec) {
+  static constexpr bool IsSpecified(TypeSpec spec) {
     return static_cast<bool>(Spec & spec);
   }
 
+  static constexpr int kBadValue = 938550620;
+
  public:
   ThrowingValue() : TrackedObject(ABSL_PRETTY_FUNCTION) {
     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
@@ -318,6 +320,7 @@ class ThrowingValue : private exceptions_internal::TrackedObject {
 
   ThrowingValue& operator=(const ThrowingValue& other) noexcept(
       IsSpecified(TypeSpec::kNoThrowCopy)) {
+    dummy_ = kBadValue;
     if (!IsSpecified(TypeSpec::kNoThrowCopy)) {
       exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
     }
@@ -327,6 +330,7 @@ class ThrowingValue : private exceptions_internal::TrackedObject {
 
   ThrowingValue& operator=(ThrowingValue&& other) noexcept(
       IsSpecified(TypeSpec::kNoThrowMove)) {
+    dummy_ = kBadValue;
     if (!IsSpecified(TypeSpec::kNoThrowMove)) {
       exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
     }
@@ -630,7 +634,7 @@ enum class AllocSpec {
  */
 template <typename T, AllocSpec Spec = AllocSpec::kEverythingThrows>
 class ThrowingAllocator : private exceptions_internal::TrackedObject {
-  constexpr static bool IsSpecified(AllocSpec spec) {
+  static constexpr bool IsSpecified(AllocSpec spec) {
     return static_cast<bool>(Spec & spec);
   }
 
@@ -1030,6 +1034,12 @@ MakeExceptionSafetyTester() {
   return {};
 }
 
+// Always return false, intended to be used as a checker with
+// TestExceptionSafety() to check that no exception is thrown.
+inline bool nothrow_guarantee(const void*) {
+  return ::testing::AssertionFailure() << "Violating NoThrowGuarantee";
+}
+
 }  // namespace testing
 
 #endif  // ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
diff --git a/absl/base/internal/thread_identity_benchmark.cc b/absl/base/internal/thread_identity_benchmark.cc
new file mode 100644
index 0000000000..3ae57317ea
--- /dev/null
+++ b/absl/base/internal/thread_identity_benchmark.cc
@@ -0,0 +1,40 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/create_thread_identity.h"
+#include "absl/synchronization/internal/per_thread_sem.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+void BM_SafeCurrentThreadIdentity(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::synchronization_internal::GetOrCreateCurrentThreadIdentity());
+  }
+}
+BENCHMARK(BM_SafeCurrentThreadIdentity);
+
+void BM_UnsafeCurrentThreadIdentity(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::base_internal::CurrentThreadIdentityIfPresent());
+  }
+}
+BENCHMARK(BM_UnsafeCurrentThreadIdentity);
+
+}  // namespace
+
+BENCHMARK_MAIN();
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
index 8bdf63122a..69cd5195dc 100644
--- a/absl/container/BUILD.bazel
+++ b/absl/container/BUILD.bazel
@@ -62,6 +62,17 @@ cc_test(
     ],
 )
 
+cc_binary(
+    name = "fixed_array_benchmark",
+    testonly = 1,
+    srcs = ["fixed_array_benchmark.cc"],
+    copts = ABSL_TEST_COPTS + ["$(STACK_FRAME_UNLIMITED)"],
+    deps = [
+        ":fixed_array",
+        "@com_github_google_benchmark//:benchmark",
+    ],
+)
+
 cc_library(
     name = "inlined_vector",
     hdrs = ["inlined_vector.h"],
@@ -106,6 +117,19 @@ cc_test(
     ],
 )
 
+cc_binary(
+    name = "inlined_vector_benchmark",
+    testonly = 1,
+    srcs = ["inlined_vector_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":inlined_vector",
+        "//absl/base",
+        "//absl/strings",
+        "@com_github_google_benchmark//:benchmark",
+    ],
+)
+
 cc_library(
     name = "test_instance_tracker",
     testonly = 1,
diff --git a/absl/container/fixed_array_benchmark.cc b/absl/container/fixed_array_benchmark.cc
new file mode 100644
index 0000000000..2d39898d8a
--- /dev/null
+++ b/absl/container/fixed_array_benchmark.cc
@@ -0,0 +1,68 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/container/fixed_array.h"
+
+#include <stddef.h>
+#include <string>
+
+#include "benchmark/benchmark.h"
+
+namespace {
+
+// For benchmarking -- simple class with constructor and destructor that
+// set an int to a constant..
+class SimpleClass {
+ public:
+  SimpleClass() : i(3) { }
+  ~SimpleClass() { i = 0; }
+ private:
+  int i;
+};
+
+template <typename C, size_t stack_size>
+void BM_FixedArray(benchmark::State& state) {
+  const int size = state.range(0);
+  for (auto _ : state) {
+    absl::FixedArray<C, stack_size> fa(size);
+    benchmark::DoNotOptimize(fa.data());
+  }
+}
+BENCHMARK_TEMPLATE(BM_FixedArray, char, absl::kFixedArrayUseDefault)
+    ->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, char, 0)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, char, 1)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, char, 16)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, char, 256)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, char, 65536)->Range(0, 1 << 16);
+
+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, absl::kFixedArrayUseDefault)
+    ->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 0)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 1)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 16)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 256)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 65536)->Range(0, 1 << 16);
+
+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, absl::kFixedArrayUseDefault)
+    ->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 0)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 1)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 16)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 256)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 65536)->Range(0, 1 << 16);
+
+}  // namespace
+
+BENCHMARK_MAIN();
diff --git a/absl/container/inlined_vector_benchmark.cc b/absl/container/inlined_vector_benchmark.cc
new file mode 100644
index 0000000000..a2035e35ca
--- /dev/null
+++ b/absl/container/inlined_vector_benchmark.cc
@@ -0,0 +1,376 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/container/inlined_vector.h"
+
+#include <string>
+#include <vector>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/str_cat.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+using IntVec = absl::InlinedVector<int, 8>;
+
+void BM_InlinedVectorFill(benchmark::State& state) {
+  const int len = state.range(0);
+  for (auto _ : state) {
+    IntVec v;
+    for (int i = 0; i < len; i++) {
+      v.push_back(i);
+    }
+  }
+  state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
+}
+BENCHMARK(BM_InlinedVectorFill)->Range(0, 1024);
+
+void BM_InlinedVectorFillRange(benchmark::State& state) {
+  const int len = state.range(0);
+  std::unique_ptr<int[]> ia(new int[len]);
+  for (int i = 0; i < len; i++) {
+    ia[i] = i;
+  }
+  for (auto _ : state) {
+    IntVec v(ia.get(), ia.get() + len);
+    benchmark::DoNotOptimize(v);
+  }
+  state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
+}
+BENCHMARK(BM_InlinedVectorFillRange)->Range(0, 1024);
+
+void BM_StdVectorFill(benchmark::State& state) {
+  const int len = state.range(0);
+  for (auto _ : state) {
+    std::vector<int> v;
+    for (int i = 0; i < len; i++) {
+      v.push_back(i);
+    }
+  }
+  state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
+}
+BENCHMARK(BM_StdVectorFill)->Range(0, 1024);
+
+bool StringRepresentedInline(std::string s) {
+  const char* chars = s.data();
+  std::string s1 = std::move(s);
+  return s1.data() != chars;
+}
+
+void BM_InlinedVectorFillString(benchmark::State& state) {
+  const int len = state.range(0);
+  std::string strings[4] = {"a quite long string",
+                       "another long string",
+                       "012345678901234567",
+                       "to cause allocation"};
+  for (auto _ : state) {
+    absl::InlinedVector<std::string, 8> v;
+    for (int i = 0; i < len; i++) {
+      v.push_back(strings[i & 3]);
+    }
+  }
+  state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
+}
+BENCHMARK(BM_InlinedVectorFillString)->Range(0, 1024);
+
+void BM_StdVectorFillString(benchmark::State& state) {
+  const int len = state.range(0);
+  std::string strings[4] = {"a quite long string",
+                       "another long string",
+                       "012345678901234567",
+                       "to cause allocation"};
+  for (auto _ : state) {
+    std::vector<std::string> v;
+    for (int i = 0; i < len; i++) {
+      v.push_back(strings[i & 3]);
+    }
+  }
+  state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
+  // The purpose of the benchmark is to verify that inlined vector is
+  // efficient when moving is more efficent than copying. To do so, we
+  // use strings that are larger than the small std::string optimization.
+  ABSL_RAW_CHECK(!StringRepresentedInline(strings[0]),
+                 "benchmarked with strings that are too small");
+}
+BENCHMARK(BM_StdVectorFillString)->Range(0, 1024);
+
+struct Buffer {  // some arbitrary structure for benchmarking.
+  char* base;
+  int length;
+  int capacity;
+  void* user_data;
+};
+
+void BM_InlinedVectorTenAssignments(benchmark::State& state) {
+  const int len = state.range(0);
+  using BufferVec = absl::InlinedVector<Buffer, 2>;
+
+  BufferVec src;
+  src.resize(len);
+
+  BufferVec dst;
+  for (auto _ : state) {
+    for (int i = 0; i < 10; ++i) {
+      dst = src;
+    }
+  }
+}
+BENCHMARK(BM_InlinedVectorTenAssignments)
+    ->Arg(0)->Arg(1)->Arg(2)->Arg(3)->Arg(4)->Arg(20);
+
+void BM_CreateFromContainer(benchmark::State& state) {
+  for (auto _ : state) {
+    absl::InlinedVector<int, 4> x(absl::InlinedVector<int, 4>{1, 2, 3});
+    benchmark::DoNotOptimize(x);
+  }
+}
+BENCHMARK(BM_CreateFromContainer);
+
+struct LargeCopyableOnly {
+  LargeCopyableOnly() : d(1024, 17) {}
+  LargeCopyableOnly(const LargeCopyableOnly& o) = default;
+  LargeCopyableOnly& operator=(const LargeCopyableOnly& o) = default;
+
+  std::vector<int> d;
+};
+
+struct LargeCopyableSwappable {
+  LargeCopyableSwappable() : d(1024, 17) {}
+  LargeCopyableSwappable(const LargeCopyableSwappable& o) = default;
+  LargeCopyableSwappable(LargeCopyableSwappable&& o) = delete;
+
+  LargeCopyableSwappable& operator=(LargeCopyableSwappable o) {
+    using std::swap;
+    swap(*this, o);
+    return *this;
+  }
+  LargeCopyableSwappable& operator=(LargeCopyableSwappable&& o) = delete;
+
+  friend void swap(LargeCopyableSwappable& a, LargeCopyableSwappable& b) {
+    using std::swap;
+    swap(a.d, b.d);
+  }
+
+  std::vector<int> d;
+};
+
+struct LargeCopyableMovable {
+  LargeCopyableMovable() : d(1024, 17) {}
+  // Use implicitly defined copy and move.
+
+  std::vector<int> d;
+};
+
+struct LargeCopyableMovableSwappable {
+  LargeCopyableMovableSwappable() : d(1024, 17) {}
+  LargeCopyableMovableSwappable(const LargeCopyableMovableSwappable& o) =
+      default;
+  LargeCopyableMovableSwappable(LargeCopyableMovableSwappable&& o) = default;
+
+  LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable o) {
+    using std::swap;
+    swap(*this, o);
+    return *this;
+  }
+  LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable&& o) =
+      default;
+
+  friend void swap(LargeCopyableMovableSwappable& a,
+                   LargeCopyableMovableSwappable& b) {
+    using std::swap;
+    swap(a.d, b.d);
+  }
+
+  std::vector<int> d;
+};
+
+template <typename ElementType>
+void BM_SwapElements(benchmark::State& state) {
+  const int len = state.range(0);
+  using Vec = absl::InlinedVector<ElementType, 32>;
+  Vec a(len);
+  Vec b;
+  for (auto _ : state) {
+    using std::swap;
+    swap(a, b);
+  }
+}
+BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableOnly)->Range(0, 1024);
+BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableSwappable)->Range(0, 1024);
+BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovable)->Range(0, 1024);
+BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovableSwappable)
+    ->Range(0, 1024);
+
+// The following benchmark is meant to track the efficiency of the vector size
+// as a function of stored type via the benchmark label. It is not meant to
+// output useful sizeof operator performance. The loop is a dummy operation
+// to fulfill the requirement of running the benchmark.
+template <typename VecType>
+void BM_Sizeof(benchmark::State& state) {
+  int size = 0;
+  for (auto _ : state) {
+    VecType vec;
+    size = sizeof(vec);
+  }
+  state.SetLabel(absl::StrCat("sz=", size));
+}
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 1>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 4>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 7>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 8>);
+
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 1>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 4>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 7>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 8>);
+
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 1>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 4>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 7>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 8>);
+
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 1>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 4>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 7>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 8>);
+
+void BM_InlinedVectorIndexInlined(benchmark::State& state) {
+  absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
+  for (auto _ : state) {
+    for (int i = 0; i < 1000; ++i) {
+      benchmark::DoNotOptimize(v);
+      benchmark::DoNotOptimize(v[4]);
+    }
+  }
+  state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorIndexInlined);
+
+void BM_InlinedVectorIndexExternal(benchmark::State& state) {
+  absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  for (auto _ : state) {
+    for (int i = 0; i < 1000; ++i) {
+      benchmark::DoNotOptimize(v);
+      benchmark::DoNotOptimize(v[4]);
+    }
+  }
+  state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorIndexExternal);
+
+void BM_StdVectorIndex(benchmark::State& state) {
+  std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  for (auto _ : state) {
+    for (int i = 0; i < 1000; ++i) {
+      benchmark::DoNotOptimize(v);
+      benchmark::DoNotOptimize(v[4]);
+    }
+  }
+  state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_StdVectorIndex);
+
+#define UNROLL_2(x)            \
+  benchmark::DoNotOptimize(x); \
+  benchmark::DoNotOptimize(x);
+
+#define UNROLL_4(x) UNROLL_2(x) UNROLL_2(x)
+#define UNROLL_8(x) UNROLL_4(x) UNROLL_4(x)
+#define UNROLL_16(x) UNROLL_8(x) UNROLL_8(x);
+
+void BM_InlinedVectorDataInlined(benchmark::State& state) {
+  absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
+  for (auto _ : state) {
+    UNROLL_16(v.data());
+  }
+  state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorDataInlined);
+
+void BM_InlinedVectorDataExternal(benchmark::State& state) {
+  absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  for (auto _ : state) {
+    UNROLL_16(v.data());
+  }
+  state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorDataExternal);
+
+void BM_StdVectorData(benchmark::State& state) {
+  std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  for (auto _ : state) {
+    UNROLL_16(v.data());
+  }
+  state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_StdVectorData);
+
+void BM_InlinedVectorSizeInlined(benchmark::State& state) {
+  absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
+  for (auto _ : state) {
+    UNROLL_16(v.size());
+  }
+  state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorSizeInlined);
+
+void BM_InlinedVectorSizeExternal(benchmark::State& state) {
+  absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  for (auto _ : state) {
+    UNROLL_16(v.size());
+  }
+  state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorSizeExternal);
+
+void BM_StdVectorSize(benchmark::State& state) {
+  std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  for (auto _ : state) {
+    UNROLL_16(v.size());
+  }
+  state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_StdVectorSize);
+
+void BM_InlinedVectorEmptyInlined(benchmark::State& state) {
+  absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
+  for (auto _ : state) {
+    UNROLL_16(v.empty());
+  }
+  state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorEmptyInlined);
+
+void BM_InlinedVectorEmptyExternal(benchmark::State& state) {
+  absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  for (auto _ : state) {
+    UNROLL_16(v.empty());
+  }
+  state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorEmptyExternal);
+
+void BM_StdVectorEmpty(benchmark::State& state) {
+  std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  for (auto _ : state) {
+    UNROLL_16(v.empty());
+  }
+  state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_StdVectorEmpty);
+
+}  // namespace
+
+BENCHMARK_MAIN();
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt
index 03a0a617e2..4af2ec8a41 100644
--- a/absl/debugging/CMakeLists.txt
+++ b/absl/debugging/CMakeLists.txt
@@ -21,7 +21,8 @@ list(APPEND DEBUGGING_PUBLIC_HEADERS
   "symbolize.h"
 )
 
-
+# TODO(cohenjon) The below is all kinds of wrong.  Make this match what we do in
+# Bazel
 list(APPEND DEBUGGING_INTERNAL_HEADERS
   "internal/address_is_readable.h"
   "internal/demangle.h"
@@ -32,12 +33,16 @@ list(APPEND DEBUGGING_INTERNAL_HEADERS
   "internal/vdso_support.h"
 )
 
-
-list(APPEND STACKTRACE_SRC
-  "stacktrace.cc"
+list(APPEND DEBUGGING_INTERNAL_SRC
   "internal/address_is_readable.cc"
   "internal/elf_mem_image.cc"
   "internal/vdso_support.cc"
+)
+
+
+list(APPEND STACKTRACE_SRC
+  "stacktrace.cc"
+  ${DEBUGGING_INTERNAL_SRC}
   ${DEBUGGING_PUBLIC_HEADERS}
   ${DEBUGGING_INTERNAL_HEADERS}
 )
@@ -50,6 +55,7 @@ list(APPEND SYMBOLIZE_SRC
   "internal/demangle.cc"
   ${DEBUGGING_PUBLIC_HEADERS}
   ${DEBUGGING_INTERNAL_HEADERS}
+  ${DEBUGGING_INTERNAL_SRC}
 )
 
 list(APPEND FAILURE_SIGNAL_HANDLER_SRC
@@ -77,6 +83,9 @@ absl_library(
     absl_symbolize
   SOURCES
     ${SYMBOLIZE_SRC}
+  PUBLIC_LIBRARIES
+    absl::base
+    absl_malloc_internal
   EXPORT_NAME
     symbolize
 )
@@ -87,7 +96,7 @@ absl_library(
   SOURCES
     ${FAILURE_SIGNAL_HANDLER_SRC}
   PUBLIC_LIBRARIES
-    absl_base absl_synchronization
+    absl_base absl::examine_stack absl::stacktrace absl_synchronization
   EXPORT_NAME
     failure_signal_handler
 )
@@ -135,13 +144,9 @@ absl_header_library(
 ## TESTS
 #
 
-list(APPEND DEBUGGING_INTERNAL_TEST_HEADERS
-  "internal/stack_consumption.h"
-)
-
 list(APPEND STACK_CONSUMPTION_SRC
   "internal/stack_consumption.cc"
-  ${DEBUGGING_INTERNAL_TEST_HEADERS}
+  "internal/stack_consumption.h"
 )
 
 absl_library(
@@ -155,10 +160,13 @@ absl_test(
   TARGET
     absl_stack_consumption_test
   SOURCES
-    ${STACK_CONSUMPTION_SRC}
+    "internal/stack_consumption_test.cc"
+  PUBLIC_LIBRARIES
+    absl_stack_consumption
+    absl::base
 )
 
-list(APPEND DEMANGLE_TEST_SRC "demangle_test.cc")
+list(APPEND DEMANGLE_TEST_SRC "internal/demangle_test.cc")
 
 absl_test(
   TARGET
@@ -177,7 +185,7 @@ absl_test(
   SOURCES
     ${SYMBOLIZE_TEST_SRC}
   PUBLIC_LIBRARIES
-    absl_symbolize absl_stack_consumption
+    absl::base absl::memory absl_symbolize absl_stack_consumption
 )
 
 list(APPEND FAILURE_SIGNAL_HANDLER_TEST_SRC "failure_signal_handler_test.cc")
@@ -188,7 +196,12 @@ absl_test(
   SOURCES
     ${FAILURE_SIGNAL_HANDLER_TEST_SRC}
   PUBLIC_LIBRARIES
-    absl_examine_stack absl_stacktrace absl_symbolize
+    absl_examine_stack
+    absl_failure_signal_handler
+    absl_stacktrace
+    absl_symbolize
+    absl::base
+    absl::strings
 )
 
 # test leak_check_test
diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc
index 597ad1445b..3de45f0bb2 100644
--- a/absl/debugging/failure_signal_handler.cc
+++ b/absl/debugging/failure_signal_handler.cc
@@ -32,6 +32,7 @@
 #include <atomic>
 #include <cerrno>
 #include <csignal>
+#include <cstdio>
 #include <cstring>
 #include <ctime>
 
diff --git a/absl/meta/CMakeLists.txt b/absl/meta/CMakeLists.txt
index d56fced8aa..adb0ceb754 100644
--- a/absl/meta/CMakeLists.txt
+++ b/absl/meta/CMakeLists.txt
@@ -32,6 +32,8 @@ list(APPEND TYPE_TRAITS_TEST_SRC
 absl_header_library(
   TARGET
     absl_meta
+  PUBLIC_LIBRARIES
+    absl::base
   EXPORT_NAME
     meta
  )
@@ -42,7 +44,8 @@ absl_test(
   SOURCES
     ${TYPE_TRAITS_TEST_SRC}
   PUBLIC_LIBRARIES
-    ${TYPE_TRAITS_TEST_PUBLIC_LIBRARIES} absl::meta
+    absl::base
+    absl::meta
 )
 
 
diff --git a/absl/strings/str_join_test.cc b/absl/strings/str_join_test.cc
index 03b60f03c8..c941f9c80d 100644
--- a/absl/strings/str_join_test.cc
+++ b/absl/strings/str_join_test.cc
@@ -24,7 +24,6 @@
 #include <map>
 #include <memory>
 #include <ostream>
-#include <set>
 #include <tuple>
 #include <type_traits>
 #include <vector>
diff --git a/absl/time/internal/cctz/BUILD.bazel b/absl/time/internal/cctz/BUILD.bazel
index fe17b3e31b..468470b4fb 100644
--- a/absl/time/internal/cctz/BUILD.bazel
+++ b/absl/time/internal/cctz/BUILD.bazel
@@ -80,6 +80,7 @@ cc_test(
     name = "time_zone_format_test",
     size = "small",
     srcs = ["src/time_zone_format_test.cc"],
+    data = [":zoneinfo"],
     deps = [
         ":civil_time",
         ":time_zone",
@@ -91,6 +92,7 @@ cc_test(
     name = "time_zone_lookup_test",
     size = "small",
     srcs = ["src/time_zone_lookup_test.cc"],
+    data = [":zoneinfo"],
     deps = [
         ":civil_time",
         ":time_zone",
@@ -103,3 +105,8 @@ cc_test(
 ### examples
 
 ### binaries
+
+filegroup(
+    name = "zoneinfo",
+    srcs = glob(["testdata/zoneinfo/**"]),
+)
diff --git a/absl/time/internal/cctz/include/cctz/civil_time_detail.h b/absl/time/internal/cctz/include/cctz/civil_time_detail.h
index 4c39c7d120..d52eddcdba 100644
--- a/absl/time/internal/cctz/include/cctz/civil_time_detail.h
+++ b/absl/time/internal/cctz/include/cctz/civil_time_detail.h
@@ -20,8 +20,8 @@
 #include <ostream>
 #include <type_traits>
 
-// Disable constexpr support unless we are using clang in C++14 mode.
-#if __clang__ && __cpp_constexpr >= 201304
+// Disable constexpr support unless we are in C++14 mode.
+#if __cpp_constexpr >= 201304 || _MSC_VER >= 1910
 #define CONSTEXPR_D constexpr  // data
 #define CONSTEXPR_F constexpr  // function
 #define CONSTEXPR_M constexpr  // member
diff --git a/absl/time/internal/cctz/src/civil_time_test.cc b/absl/time/internal/cctz/src/civil_time_test.cc
index 6df0395bad..f6648c8f1f 100644
--- a/absl/time/internal/cctz/src/civil_time_test.cc
+++ b/absl/time/internal/cctz/src/civil_time_test.cc
@@ -37,7 +37,7 @@ std::string Format(const T& t) {
 
 }  // namespace
 
-#if __clang__ && __cpp_constexpr >= 201304
+#if __cpp_constexpr >= 201304 || _MSC_VER >= 1910
 // Construction constexpr tests
 
 TEST(CivilTime, Normal) {
@@ -319,7 +319,7 @@ TEST(CivilTime, YearDay) {
   constexpr int yd = get_yearday(cd);
   static_assert(yd == 28, "YearDay");
 }
-#endif  // __clang__ && __cpp_constexpr >= 201304
+#endif  // __cpp_constexpr >= 201304 || _MSC_VER >= 1910
 
 // The remaining tests do not use constexpr.
 
diff --git a/absl/time/internal/cctz/src/time_zone_fixed.cc b/absl/time/internal/cctz/src/time_zone_fixed.cc
index 8d3b144252..65eba3569d 100644
--- a/absl/time/internal/cctz/src/time_zone_fixed.cc
+++ b/absl/time/internal/cctz/src/time_zone_fixed.cc
@@ -27,7 +27,7 @@ namespace cctz {
 namespace {
 
 // The prefix used for the internal names of fixed-offset zones.
-const char kFixedOffsetPrefix[] = "Fixed/";
+const char kFixedOffsetPrefix[] = "Fixed/UTC";
 
 int Parse02d(const char* p) {
   static const char kDigits[] = "0123456789";
@@ -50,13 +50,11 @@ bool FixedOffsetFromName(const std::string& name, sys_seconds* offset) {
 
   const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
   const char* const ep = kFixedOffsetPrefix + prefix_len;
-  if (name.size() != prefix_len + 12)  // "<prefix>UTC+99:99:99"
+  if (name.size() != prefix_len + 9)  // <prefix>+99:99:99
     return false;
   if (!std::equal(kFixedOffsetPrefix, ep, name.begin()))
     return false;
   const char* np = name.data() + prefix_len;
-  if (*np++ != 'U' || *np++ != 'T' || *np++ != 'C')
-    return false;
   if (np[0] != '+' && np[0] != '-')
     return false;
   if (np[3] != ':' || np[6] != ':')  // see note below about large offsets
@@ -97,8 +95,8 @@ std::string FixedOffsetToName(const sys_seconds& offset) {
   }
   int hours = minutes / 60;
   minutes %= 60;
-  char buf[sizeof(kFixedOffsetPrefix) + sizeof("UTC-24:00:00")];
-  snprintf(buf, sizeof(buf), "%sUTC%c%02d:%02d:%02d",
+  char buf[sizeof(kFixedOffsetPrefix) + sizeof("-24:00:00")];
+  snprintf(buf, sizeof(buf), "%s%c%02d:%02d:%02d",
            kFixedOffsetPrefix, sign, hours, minutes, seconds);
   return buf;
 }
@@ -106,22 +104,14 @@ std::string FixedOffsetToName(const sys_seconds& offset) {
 std::string FixedOffsetToAbbr(const sys_seconds& offset) {
   std::string abbr = FixedOffsetToName(offset);
   const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
-  const char* const ep = kFixedOffsetPrefix + prefix_len;
-  if (abbr.size() >= prefix_len) {
-    if (std::equal(kFixedOffsetPrefix, ep, abbr.begin())) {
-      abbr.erase(0, prefix_len);
-      if (abbr.size() == 12) {                     // UTC+99:99:99
-        abbr.erase(9, 1);                          // UTC+99:9999
-        abbr.erase(6, 1);                          // UTC+999999
-        if (abbr[8] == '0' && abbr[9] == '0') {    // UTC+999900
-          abbr.erase(8, 2);                        // UTC+9999
-          if (abbr[6] == '0' && abbr[7] == '0') {  // UTC+9900
-            abbr.erase(6, 2);                      // UTC+99
-            if (abbr[4] == '0') {                  // UTC+09
-              abbr.erase(4, 1);                    // UTC+9
-            }
-          }
-        }
+  if (abbr.size() == prefix_len + 9) {         // <prefix>+99:99:99
+    abbr.erase(0, prefix_len);                 // +99:99:99
+    abbr.erase(6, 1);                          // +99:9999
+    abbr.erase(3, 1);                          // +999999
+    if (abbr[5] == '0' && abbr[6] == '0') {    // +999900
+      abbr.erase(5, 2);                        // +9999
+      if (abbr[3] == '0' && abbr[4] == '0') {  // +9900
+        abbr.erase(3, 2);                      // +99
       }
     }
   }
diff --git a/absl/time/internal/cctz/src/time_zone_lookup.cc b/absl/time/internal/cctz/src/time_zone_lookup.cc
index fbd86e16b4..d549d862a7 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup.cc
@@ -134,6 +134,9 @@ time_zone local_time_zone() {
 
   time_zone tz;
   load_time_zone(name, &tz);  // Falls back to UTC.
+  // TODO: Follow the RFC3339 "Unknown Local Offset Convention" and
+  // arrange for %z to generate "-0000" when we don't know the local
+  // offset because the load_time_zone() failed and we're using UTC.
   return tz;
 }
 
diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
index a5d73d5492..2dfe53b267 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -1119,18 +1119,6 @@ TEST(TimeZoneEdgeCase, AfricaMonrovia) {
   auto tp = convert(civil_second(1972, 1, 6, 23, 59, 59), tz);
   ExpectTime(tp, tz, 1972, 1, 6, 23, 59, 59, -44.5 * 60, false, "MMT");
   tp += seconds(1);
-#ifndef TZDATA_2017B_IS_UBIQUITOUS
-  // The 2017b tzdata release moved the shift from -004430 to +00
-  // from 1972-05-01 to 1972-01-07, so we temporarily accept both
-  // outcomes until 2017b is ubiquitous.
-  if (tz.lookup(tp).offset == -44.5 * 60) {
-    tp = convert(civil_second(1972, 4, 30, 23, 59, 59), tz);
-    ExpectTime(tp, tz, 1972, 4, 30, 23, 59, 59, -44.5 * 60, false, "LRT");
-    tp += seconds(1);
-    ExpectTime(tp, tz, 1972, 5, 1, 0, 44, 30, 0 * 60, false, "GMT");
-    return;
-  }
-#endif
   ExpectTime(tp, tz, 1972, 1, 7, 0, 44, 30, 0 * 60, false, "GMT");
 }
 
diff --git a/absl/time/internal/test_util.cc b/absl/time/internal/test_util.cc
index 419d859d2d..bbbef7da70 100644
--- a/absl/time/internal/test_util.cc
+++ b/absl/time/internal/test_util.cc
@@ -26,8 +26,7 @@ namespace cctz = absl::time_internal::cctz;
 namespace absl {
 namespace time_internal {
 
-// TODO(bww): Reinstate when the FixedTimeZone() abbreviations are updated.
-#if 1 || GTEST_USES_SIMPLE_RE
+#if GTEST_USES_SIMPLE_RE
 extern const char kZoneAbbrRE[] = ".*";  // just punt
 #else
 extern const char kZoneAbbrRE[] = "[A-Za-z]{3,4}|[-+][0-9]{2}([0-9]{2})?";
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel
index 0bdb2f78ae..f8d53c263b 100644
--- a/absl/types/BUILD.bazel
+++ b/absl/types/BUILD.bazel
@@ -223,3 +223,18 @@ cc_test(
         "@com_google_googletest//:gtest_main",
     ],
 )
+
+cc_test(
+    name = "variant_exception_safety_test",
+    size = "small",
+    srcs = [
+        "variant_exception_safety_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+    deps = [
+        ":variant",
+        "//absl/base:exception_safety_testing",
+        "//absl/memory",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt
index f51d126f81..fbd8374031 100644
--- a/absl/types/CMakeLists.txt
+++ b/absl/types/CMakeLists.txt
@@ -29,6 +29,9 @@ absl_header_library(
   TARGET
     absl_any
   PUBLIC_LIBRARIES
+    absl::bad_any_cast
+    absl::base
+    absl::meta
     absl::utility
   PRIVATE_COMPILE_FLAGS
     ${ABSL_EXCEPTIONS_FLAG}
@@ -59,7 +62,6 @@ absl_library(
   SOURCES
     ${BAD_ANY_CAST_SRC}
   PUBLIC_LIBRARIES
-    absl::base absl::any
   EXPORT_NAME
     bad_any_cast
 )
@@ -76,7 +78,11 @@ absl_library(
   SOURCES
     ${OPTIONAL_SRC}
   PUBLIC_LIBRARIES
+    absl::bad_optional_access
     absl::base
+    absl::memory
+    absl::meta
+    absl::utility
   EXPORT_NAME
     optional
 )
@@ -143,7 +149,11 @@ absl_test(
 
 # test any_exception_safety_test
 set(ANY_EXCEPTION_SAFETY_TEST_SRC "any_exception_safety_test.cc")
-set(ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES absl::any absl::base absl::base_internal_exception_safety_testing)
+set(ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES
+  absl::any
+  absl::base
+  absl_base_internal_exception_safety_testing
+)
 
 absl_test(
   TARGET
diff --git a/absl/types/optional.h b/absl/types/optional.h
index 98b29e591d..4dcf479615 100644
--- a/absl/types/optional.h
+++ b/absl/types/optional.h
@@ -958,7 +958,8 @@ constexpr auto operator==(const optional<T>& x, const optional<U>& y)
     -> decltype(optional_internal::convertible_to_bool(*x == *y)) {
   return static_cast<bool>(x) != static_cast<bool>(y)
              ? false
-             : static_cast<bool>(x) == false ? true : *x == *y;
+             : static_cast<bool>(x) == false ? true
+                                             : static_cast<bool>(*x == *y);
 }
 
 // Returns: If bool(x) != bool(y), true; otherwise, if bool(x) == false, false;
@@ -968,31 +969,32 @@ constexpr auto operator!=(const optional<T>& x, const optional<U>& y)
     -> decltype(optional_internal::convertible_to_bool(*x != *y)) {
   return static_cast<bool>(x) != static_cast<bool>(y)
              ? true
-             : static_cast<bool>(x) == false ? false : *x != *y;
+             : static_cast<bool>(x) == false ? false
+                                             : static_cast<bool>(*x != *y);
 }
 // Returns: If !y, false; otherwise, if !x, true; otherwise *x < *y.
 template <typename T, typename U>
 constexpr auto operator<(const optional<T>& x, const optional<U>& y)
     -> decltype(optional_internal::convertible_to_bool(*x < *y)) {
-  return !y ? false : !x ? true : *x < *y;
+  return !y ? false : !x ? true : static_cast<bool>(*x < *y);
 }
 // Returns: If !x, false; otherwise, if !y, true; otherwise *x > *y.
 template <typename T, typename U>
 constexpr auto operator>(const optional<T>& x, const optional<U>& y)
     -> decltype(optional_internal::convertible_to_bool(*x > *y)) {
-  return !x ? false : !y ? true : *x > *y;
+  return !x ? false : !y ? true : static_cast<bool>(*x > *y);
 }
 // Returns: If !x, true; otherwise, if !y, false; otherwise *x <= *y.
 template <typename T, typename U>
 constexpr auto operator<=(const optional<T>& x, const optional<U>& y)
     -> decltype(optional_internal::convertible_to_bool(*x <= *y)) {
-  return !x ? true : !y ? false : *x <= *y;
+  return !x ? true : !y ? false : static_cast<bool>(*x <= *y);
 }
 // Returns: If !y, true; otherwise, if !x, false; otherwise *x >= *y.
 template <typename T, typename U>
 constexpr auto operator>=(const optional<T>& x, const optional<U>& y)
     -> decltype(optional_internal::convertible_to_bool(*x >= *y)) {
-  return !y ? true : !x ? false : *x >= *y;
+  return !y ? true : !x ? false : static_cast<bool>(*x >= *y);
 }
 
 // Comparison with nullopt [optional.nullops]
@@ -1054,62 +1056,62 @@ constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept {
 template <typename T, typename U>
 constexpr auto operator==(const optional<T>& x, const U& v)
     -> decltype(optional_internal::convertible_to_bool(*x == v)) {
-  return static_cast<bool>(x) ? *x == v : false;
+  return static_cast<bool>(x) ? static_cast<bool>(*x == v) : false;
 }
 template <typename T, typename U>
 constexpr auto operator==(const U& v, const optional<T>& x)
     -> decltype(optional_internal::convertible_to_bool(v == *x)) {
-  return static_cast<bool>(x) ? v == *x : false;
+  return static_cast<bool>(x) ? static_cast<bool>(v == *x) : false;
 }
 template <typename T, typename U>
 constexpr auto operator!=(const optional<T>& x, const U& v)
     -> decltype(optional_internal::convertible_to_bool(*x != v)) {
-  return static_cast<bool>(x) ? *x != v : true;
+  return static_cast<bool>(x) ? static_cast<bool>(*x != v) : true;
 }
 template <typename T, typename U>
 constexpr auto operator!=(const U& v, const optional<T>& x)
     -> decltype(optional_internal::convertible_to_bool(v != *x)) {
-  return static_cast<bool>(x) ? v != *x : true;
+  return static_cast<bool>(x) ? static_cast<bool>(v != *x) : true;
 }
 template <typename T, typename U>
 constexpr auto operator<(const optional<T>& x, const U& v)
     -> decltype(optional_internal::convertible_to_bool(*x < v)) {
-  return static_cast<bool>(x) ? *x < v : true;
+  return static_cast<bool>(x) ? static_cast<bool>(*x < v) : true;
 }
 template <typename T, typename U>
 constexpr auto operator<(const U& v, const optional<T>& x)
     -> decltype(optional_internal::convertible_to_bool(v < *x)) {
-  return static_cast<bool>(x) ? v < *x : false;
+  return static_cast<bool>(x) ? static_cast<bool>(v < *x) : false;
 }
 template <typename T, typename U>
 constexpr auto operator<=(const optional<T>& x, const U& v)
     -> decltype(optional_internal::convertible_to_bool(*x <= v)) {
-  return static_cast<bool>(x) ? *x <= v : true;
+  return static_cast<bool>(x) ? static_cast<bool>(*x <= v) : true;
 }
 template <typename T, typename U>
 constexpr auto operator<=(const U& v, const optional<T>& x)
     -> decltype(optional_internal::convertible_to_bool(v <= *x)) {
-  return static_cast<bool>(x) ? v <= *x : false;
+  return static_cast<bool>(x) ? static_cast<bool>(v <= *x) : false;
 }
 template <typename T, typename U>
 constexpr auto operator>(const optional<T>& x, const U& v)
     -> decltype(optional_internal::convertible_to_bool(*x > v)) {
-  return static_cast<bool>(x) ? *x > v : false;
+  return static_cast<bool>(x) ? static_cast<bool>(*x > v) : false;
 }
 template <typename T, typename U>
 constexpr auto operator>(const U& v, const optional<T>& x)
     -> decltype(optional_internal::convertible_to_bool(v > *x)) {
-  return static_cast<bool>(x) ? v > *x : true;
+  return static_cast<bool>(x) ? static_cast<bool>(v > *x) : true;
 }
 template <typename T, typename U>
 constexpr auto operator>=(const optional<T>& x, const U& v)
     -> decltype(optional_internal::convertible_to_bool(*x >= v)) {
-  return static_cast<bool>(x) ? *x >= v : false;
+  return static_cast<bool>(x) ? static_cast<bool>(*x >= v) : false;
 }
 template <typename T, typename U>
 constexpr auto operator>=(const U& v, const optional<T>& x)
     -> decltype(optional_internal::convertible_to_bool(v >= *x)) {
-  return static_cast<bool>(x) ? v >= *x : true;
+  return static_cast<bool>(x) ? static_cast<bool>(v >= *x) : true;
 }
 
 }  // namespace absl
diff --git a/absl/types/variant.h b/absl/types/variant.h
index 52a311e37d..7ae65abe0e 100644
--- a/absl/types/variant.h
+++ b/absl/types/variant.h
@@ -350,7 +350,7 @@ constexpr const variant_alternative_t<I, variant<Types...>>&& get(
 // get_if()
 //
 // Returns a pointer to the value currently stored within a given variant, if
-// present, using either a unique alternative type amonst the variant's set of
+// present, using either a unique alternative type amongst the variant's set of
 // alternative types, or the variant's index value. If such a value does not
 // exist, returns `nullptr`.
 //
diff --git a/absl/types/variant_exception_safety_test.cc b/absl/types/variant_exception_safety_test.cc
new file mode 100644
index 0000000000..377e4afac5
--- /dev/null
+++ b/absl/types/variant_exception_safety_test.cc
@@ -0,0 +1,519 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "absl/types/variant.h"
+
+#include <iostream>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/exception_safety_testing.h"
+#include "absl/memory/memory.h"
+
+namespace absl {
+namespace {
+
+using ::testing::MakeExceptionSafetyTester;
+using ::testing::nothrow_guarantee;
+using ::testing::strong_guarantee;
+using ::testing::TestThrowingCtor;
+
+using Thrower = testing::ThrowingValue<>;
+using CopyNothrow = testing::ThrowingValue<testing::TypeSpec::kNoThrowCopy>;
+using MoveNothrow = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
+using ThrowingAlloc = testing::ThrowingAllocator<Thrower>;
+using ThrowerVec = std::vector<Thrower, ThrowingAlloc>;
+using ThrowingVariant =
+    absl::variant<Thrower, CopyNothrow, MoveNothrow, ThrowerVec>;
+
+struct ConversionException {};
+
+template <class T>
+struct ExceptionOnConversion {
+  operator T() const {  // NOLINT
+    throw ConversionException();
+  }
+};
+
+// Forces a variant into the valueless by exception state.
+void ToValuelessByException(ThrowingVariant& v) {  // NOLINT
+  try {
+    v.emplace<Thrower>();
+    v.emplace<Thrower>(ExceptionOnConversion<Thrower>());
+  } catch (ConversionException& /*e*/) {
+    // This space intentionally left blank.
+  }
+}
+
+// Check that variant is still in a usable state after an exception is thrown.
+testing::AssertionResult CheckInvariants(ThrowingVariant* v) {
+  using testing::AssertionFailure;
+  using testing::AssertionSuccess;
+
+  // Try using the active alternative
+  if (absl::holds_alternative<Thrower>(*v)) {
+    auto& t = absl::get<Thrower>(*v);
+    t = Thrower{-100};
+    if (t.Get() != -100) {
+      return AssertionFailure() << "Thrower should be assigned -100";
+    }
+  } else if (absl::holds_alternative<ThrowerVec>(*v)) {
+    auto& tv = absl::get<ThrowerVec>(*v);
+    tv.clear();
+    tv.emplace_back(-100);
+    if (tv.size() != 1 || tv[0].Get() != -100) {
+      return AssertionFailure() << "ThrowerVec should be {Thrower{-100}}";
+    }
+  } else if (absl::holds_alternative<CopyNothrow>(*v)) {
+    auto& t = absl::get<CopyNothrow>(*v);
+    t = CopyNothrow{-100};
+    if (t.Get() != -100) {
+      return AssertionFailure() << "CopyNothrow should be assigned -100";
+    }
+  } else if (absl::holds_alternative<MoveNothrow>(*v)) {
+    auto& t = absl::get<MoveNothrow>(*v);
+    t = MoveNothrow{-100};
+    if (t.Get() != -100) {
+      return AssertionFailure() << "MoveNothrow should be assigned -100";
+    }
+  }
+
+  // Try making variant valueless_by_exception
+  if (!v->valueless_by_exception()) ToValuelessByException(*v);
+  if (!v->valueless_by_exception()) {
+    return AssertionFailure() << "Variant should be valueless_by_exception";
+  }
+  try {
+    auto unused = absl::get<Thrower>(*v);
+    static_cast<void>(unused);
+    return AssertionFailure() << "Variant should not contain Thrower";
+  } catch (absl::bad_variant_access) {
+  } catch (...) {
+    return AssertionFailure() << "Unexpected exception throw from absl::get";
+  }
+
+  // Try using the variant
+  v->emplace<Thrower>(100);
+  if (!absl::holds_alternative<Thrower>(*v) ||
+      absl::get<Thrower>(*v) != Thrower(100)) {
+    return AssertionFailure() << "Variant should contain Thrower(100)";
+  }
+  v->emplace<ThrowerVec>({Thrower(100)});
+  if (!absl::holds_alternative<ThrowerVec>(*v) ||
+      absl::get<ThrowerVec>(*v)[0] != Thrower(100)) {
+    return AssertionFailure()
+           << "Variant should contain ThrowerVec{Thrower(100)}";
+  }
+  return AssertionSuccess();
+}
+
+Thrower ExpectedThrower() { return Thrower(42); }
+ThrowerVec ExpectedThrowerVec() { return {Thrower(100), Thrower(200)}; }
+ThrowingVariant ValuelessByException() {
+  ThrowingVariant v;
+  ToValuelessByException(v);
+  return v;
+}
+ThrowingVariant WithThrower() { return Thrower(39); }
+ThrowingVariant WithThrowerVec() {
+  return ThrowerVec{Thrower(1), Thrower(2), Thrower(3)};
+}
+ThrowingVariant WithCopyNoThrow() { return CopyNothrow(39); }
+ThrowingVariant WithMoveNoThrow() { return MoveNothrow(39); }
+
+TEST(VariantExceptionSafetyTest, DefaultConstructor) {
+  TestThrowingCtor<ThrowingVariant>();
+}
+
+TEST(VariantExceptionSafetyTest, CopyConstructor) {
+  {
+    ThrowingVariant v(ExpectedThrower());
+    TestThrowingCtor<ThrowingVariant>(v);
+  }
+  {
+    ThrowingVariant v(ExpectedThrowerVec());
+    TestThrowingCtor<ThrowingVariant>(v);
+  }
+  {
+    ThrowingVariant v(ValuelessByException());
+    TestThrowingCtor<ThrowingVariant>(v);
+  }
+}
+
+TEST(VariantExceptionSafetyTest, MoveConstructor) {
+  {
+    ThrowingVariant v(ExpectedThrower());
+    TestThrowingCtor<ThrowingVariant>(std::move(v));
+  }
+  {
+    ThrowingVariant v(ExpectedThrowerVec());
+    TestThrowingCtor<ThrowingVariant>(std::move(v));
+  }
+  {
+    ThrowingVariant v(ValuelessByException());
+    TestThrowingCtor<ThrowingVariant>(std::move(v));
+  }
+}
+
+TEST(VariantExceptionSafetyTest, ValueConstructor) {
+  TestThrowingCtor<ThrowingVariant>(ExpectedThrower());
+  TestThrowingCtor<ThrowingVariant>(ExpectedThrowerVec());
+}
+
+TEST(VariantExceptionSafetyTest, InPlaceTypeConstructor) {
+  TestThrowingCtor<ThrowingVariant>(absl::in_place_type_t<Thrower>{},
+                                    ExpectedThrower());
+  TestThrowingCtor<ThrowingVariant>(absl::in_place_type_t<ThrowerVec>{},
+                                    ExpectedThrowerVec());
+}
+
+TEST(VariantExceptionSafetyTest, InPlaceIndexConstructor) {
+  TestThrowingCtor<ThrowingVariant>(absl::in_place_index_t<0>{},
+                                    ExpectedThrower());
+  TestThrowingCtor<ThrowingVariant>(absl::in_place_index_t<3>{},
+                                    ExpectedThrowerVec());
+}
+
+TEST(VariantExceptionSafetyTest, CopyAssign) {
+  // variant& operator=(const variant& rhs);
+  // Let j be rhs.index()
+  {
+    // - neither *this nor rhs holds a value
+    const ThrowingVariant rhs = ValuelessByException();
+    EXPECT_TRUE(MakeExceptionSafetyTester()
+                    .WithInitialValue(ValuelessByException())
+                    .WithInvariants(nothrow_guarantee)
+                    .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
+  }
+  {
+    // - *this holds a value but rhs does not
+    const ThrowingVariant rhs = ValuelessByException();
+    EXPECT_TRUE(MakeExceptionSafetyTester()
+                    .WithInitialValue(WithThrower())
+                    .WithInvariants(nothrow_guarantee)
+                    .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
+  }
+  // - index() == j
+  {
+    const ThrowingVariant rhs(ExpectedThrower());
+    auto tester =
+        MakeExceptionSafetyTester()
+            .WithInitialValue(WithThrower())
+            .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
+    EXPECT_TRUE(tester.WithInvariants(CheckInvariants).Test());
+    EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
+  }
+  {
+    const ThrowingVariant rhs(ExpectedThrowerVec());
+    auto tester =
+        MakeExceptionSafetyTester()
+            .WithInitialValue(WithThrowerVec())
+            .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
+    EXPECT_TRUE(tester.WithInvariants(CheckInvariants).Test());
+    EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
+  }
+  // libstdc++ std::variant has bugs on copy assignment regarding exception
+  // safety.
+#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+  // index() != j
+  // if is_nothrow_copy_constructible_v<Tj> or
+  // !is_nothrow_move_constructible<Tj> is true, equivalent to
+  // emplace<j>(get<j>(rhs))
+  {
+    // is_nothrow_copy_constructible_v<Tj> == true
+    // should not throw because emplace() invokes Tj's copy ctor
+    // which should not throw.
+    const ThrowingVariant rhs(CopyNothrow{});
+    EXPECT_TRUE(MakeExceptionSafetyTester()
+                    .WithInitialValue(WithThrower())
+                    .WithInvariants(nothrow_guarantee)
+                    .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
+  }
+  {
+    // is_nothrow_copy_constructible<Tj> == false &&
+    // is_nothrow_move_constructible<Tj> == false
+    // should provide basic guarantee because emplace() invokes Tj's copy ctor
+    // which may throw.
+    const ThrowingVariant rhs(ExpectedThrower());
+    auto tester =
+        MakeExceptionSafetyTester()
+            .WithInitialValue(WithCopyNoThrow())
+            .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
+    EXPECT_TRUE(tester
+                    .WithInvariants(CheckInvariants,
+                                    [](ThrowingVariant* lhs) {
+                                      return lhs->valueless_by_exception();
+                                    })
+                    .Test());
+    EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
+  }
+#endif  // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+  {
+    // is_nothrow_copy_constructible_v<Tj> == false &&
+    // is_nothrow_move_constructible_v<Tj> == true
+    // should provide strong guarantee because it is equivalent to
+    // operator=(variant(rhs)) which creates a temporary then invoke the move
+    // ctor which shouldn't throw.
+    const ThrowingVariant rhs(MoveNothrow{});
+    EXPECT_TRUE(MakeExceptionSafetyTester()
+                    .WithInitialValue(WithThrower())
+                    .WithInvariants(CheckInvariants, strong_guarantee)
+                    .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
+  }
+}
+
+TEST(VariantExceptionSafetyTest, MoveAssign) {
+  // variant& operator=(variant&& rhs);
+  // Let j be rhs.index()
+  {
+    // - neither *this nor rhs holds a value
+    ThrowingVariant rhs = ValuelessByException();
+
+    EXPECT_TRUE(MakeExceptionSafetyTester()
+                    .WithInitialValue(ValuelessByException())
+                    .WithInvariants(nothrow_guarantee)
+                    .Test([rhs](ThrowingVariant* lhs) mutable {
+                      *lhs = std::move(rhs);
+                    }));
+  }
+  {
+    // - *this holds a value but rhs does not
+    ThrowingVariant rhs = ValuelessByException();
+    EXPECT_TRUE(MakeExceptionSafetyTester()
+                    .WithInitialValue(WithThrower())
+                    .WithInvariants(nothrow_guarantee)
+                    .Test([rhs](ThrowingVariant* lhs) mutable {
+                      *lhs = std::move(rhs);
+                    }));
+  }
+  {
+    // - index() == j
+    // assign get<j>(std::move(rhs)) to the value contained in *this.
+    // If an exception is thrown during call to Tj's move assignment, the state
+    // of the contained value is as defined by the exception safety guarantee of
+    // Tj's move assignment; index() will be j.
+    ThrowingVariant rhs(ExpectedThrower());
+    size_t j = rhs.index();
+    // Since Thrower's move assignment has basic guarantee, so should variant's.
+    auto tester = MakeExceptionSafetyTester()
+                      .WithInitialValue(WithThrower())
+                      .WithOperation([rhs](ThrowingVariant* lhs) mutable {
+                        *lhs = std::move(rhs);
+                      });
+    EXPECT_TRUE(tester
+                    .WithInvariants(
+                        CheckInvariants,
+                        [j](ThrowingVariant* lhs) { return lhs->index() == j; })
+                    .Test());
+    EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
+  }
+  {
+    // - otherwise (index() != j), equivalent to
+    // emplace<j>(get<j>(std::move(rhs)))
+    // - If an exception is thrown during the call to Tj's move construction
+    // (with j being rhs.index()), the variant will hold no value.
+    ThrowingVariant rhs(CopyNothrow{});
+    EXPECT_TRUE(MakeExceptionSafetyTester()
+                    .WithInitialValue(WithThrower())
+                    .WithInvariants(CheckInvariants,
+                                    [](ThrowingVariant* lhs) {
+                                      return lhs->valueless_by_exception();
+                                    })
+                    .Test([rhs](ThrowingVariant* lhs) mutable {
+                      *lhs = std::move(rhs);
+                    }));
+  }
+}
+
+TEST(VariantExceptionSafetyTest, ValueAssign) {
+  // template<class T> variant& operator=(T&& t);
+  // Let Tj be the type that is selected by overload resolution to be assigned.
+  {
+    // If *this holds a Tj, assigns std::forward<T>(t) to the value contained in
+    // *this. If  an exception is thrown during the assignment of
+    // std::forward<T>(t) to the value contained in *this, the state of the
+    // contained value and t are as defined by the exception safety guarantee of
+    // the assignment expression; valueless_by_exception() will be false.
+    // Since Thrower's copy/move assignment has basic guarantee, so should
+    // variant's.
+    Thrower rhs = ExpectedThrower();
+    // copy assign
+    auto copy_tester =
+        MakeExceptionSafetyTester()
+            .WithInitialValue(WithThrower())
+            .WithOperation([rhs](ThrowingVariant* lhs) { *lhs = rhs; });
+    EXPECT_TRUE(copy_tester
+                    .WithInvariants(CheckInvariants,
+                                    [](ThrowingVariant* lhs) {
+                                      return !lhs->valueless_by_exception();
+                                    })
+                    .Test());
+    EXPECT_FALSE(copy_tester.WithInvariants(strong_guarantee).Test());
+    // move assign
+    auto move_tester = MakeExceptionSafetyTester()
+                           .WithInitialValue(WithThrower())
+                           .WithOperation([rhs](ThrowingVariant* lhs) mutable {
+                             *lhs = std::move(rhs);
+                           });
+    EXPECT_TRUE(move_tester
+                    .WithInvariants(CheckInvariants,
+                                    [](ThrowingVariant* lhs) {
+                                      return !lhs->valueless_by_exception();
+                                    })
+                    .Test());
+
+    EXPECT_FALSE(move_tester.WithInvariants(strong_guarantee).Test());
+  }
+  // Otherwise (*this holds something else), if is_nothrow_constructible_v<Tj,
+  // T> || !is_nothrow_move_constructible_v<Tj> is true, equivalent to
+  // emplace<j>(std::forward<T>(t)).
+  // We simplify the test by letting T = `const Tj&`  or `Tj&&`, so we can reuse
+  // the CopyNothrow and MoveNothrow types.
+
+  // if is_nothrow_constructible_v<Tj, T>
+  // (i.e. is_nothrow_copy/move_constructible_v<Tj>) is true, emplace() just
+  // invokes the copy/move constructor and it should not throw.
+  {
+    const CopyNothrow rhs;
+    EXPECT_TRUE(MakeExceptionSafetyTester()
+                    .WithInitialValue(WithThrower())
+                    .WithInvariants(nothrow_guarantee)
+                    .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
+  }
+  {
+    MoveNothrow rhs;
+    EXPECT_TRUE(MakeExceptionSafetyTester()
+                    .WithInitialValue(WithThrower())
+                    .WithInvariants(nothrow_guarantee)
+                    .Test([rhs](ThrowingVariant* lhs) mutable {
+                      *lhs = std::move(rhs);
+                    }));
+  }
+  // if is_nothrow_constructible_v<Tj, T> == false &&
+  // is_nothrow_move_constructible<Tj> == false
+  // emplace() invokes the copy/move constructor which may throw so it should
+  // provide basic guarantee and variant object might not hold a value.
+  {
+    Thrower rhs = ExpectedThrower();
+    // copy
+    auto copy_tester =
+        MakeExceptionSafetyTester()
+            .WithInitialValue(WithCopyNoThrow())
+            .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
+    EXPECT_TRUE(copy_tester
+                    .WithInvariants(CheckInvariants,
+                                    [](ThrowingVariant* lhs) {
+                                      return lhs->valueless_by_exception();
+                                    })
+                    .Test());
+    EXPECT_FALSE(copy_tester.WithInvariants(strong_guarantee).Test());
+    // move
+    auto move_tester = MakeExceptionSafetyTester()
+                           .WithInitialValue(WithCopyNoThrow())
+                           .WithOperation([rhs](ThrowingVariant* lhs) mutable {
+                             *lhs = std::move(rhs);
+                           });
+    EXPECT_TRUE(move_tester
+                    .WithInvariants(CheckInvariants,
+                                    [](ThrowingVariant* lhs) {
+                                      return lhs->valueless_by_exception();
+                                    })
+                    .Test());
+    EXPECT_FALSE(move_tester.WithInvariants(strong_guarantee).Test());
+  }
+  // Otherwise (if is_nothrow_constructible_v<Tj, T> == false &&
+  // is_nothrow_move_constructible<Tj> == true),
+  // equivalent to operator=(variant(std::forward<T>(t)))
+  // This should have strong guarantee because it creates a temporary variant
+  // and operator=(variant&&) invokes Tj's move ctor which doesn't throw.
+  // libstdc++ std::variant has bugs on conversion assignment regarding
+  // exception safety.
+#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+  {
+    MoveNothrow rhs;
+    EXPECT_TRUE(MakeExceptionSafetyTester()
+                    .WithInitialValue(WithThrower())
+                    .WithInvariants(CheckInvariants, strong_guarantee)
+                    .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
+  }
+#endif  // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+}
+
+TEST(VariantExceptionSafetyTest, Emplace) {
+  // If an exception during the initialization of the contained value, the
+  // variant might not hold a value. The standard requires emplace() to provide
+  // only basic guarantee.
+  {
+    Thrower args = ExpectedThrower();
+    auto tester = MakeExceptionSafetyTester()
+                      .WithInitialValue(WithThrower())
+                      .WithOperation([&args](ThrowingVariant* v) {
+                        v->emplace<Thrower>(args);
+                      });
+    EXPECT_TRUE(tester
+                    .WithInvariants(CheckInvariants,
+                                    [](ThrowingVariant* v) {
+                                      return v->valueless_by_exception();
+                                    })
+                    .Test());
+    EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
+  }
+}
+
+TEST(VariantExceptionSafetyTest, Swap) {
+  // if both are valueless_by_exception(), no effect
+  {
+    ThrowingVariant rhs = ValuelessByException();
+    EXPECT_TRUE(
+        MakeExceptionSafetyTester()
+            .WithInitialValue(ValuelessByException())
+            .WithInvariants(nothrow_guarantee)
+            .Test([rhs](ThrowingVariant* lhs) mutable { lhs->swap(rhs); }));
+  }
+  // if index() == rhs.index(), calls swap(get<i>(*this), get<i>(rhs))
+  // where i is index().
+  {
+    ThrowingVariant rhs = ExpectedThrower();
+    EXPECT_TRUE(
+        MakeExceptionSafetyTester()
+            .WithInitialValue(WithThrower())
+            .WithInvariants(CheckInvariants)
+            .Test([rhs](ThrowingVariant* lhs) mutable { lhs->swap(rhs); }));
+  }
+  // Otherwise, exchanges the value of rhs and *this. The exception safety
+  // involves variant in moved-from state which is not specified in the
+  // standard, and since swap is 3-step it's impossible for it to provide a
+  // overall strong guarantee. So, we are only checking basic guarantee here.
+  {
+    ThrowingVariant rhs = ExpectedThrower();
+    EXPECT_TRUE(
+        MakeExceptionSafetyTester()
+            .WithInitialValue(WithCopyNoThrow())
+            .WithInvariants(CheckInvariants)
+            .Test([rhs](ThrowingVariant* lhs) mutable { lhs->swap(rhs); }));
+  }
+  {
+    ThrowingVariant rhs = ExpectedThrower();
+    EXPECT_TRUE(
+        MakeExceptionSafetyTester()
+            .WithInitialValue(WithCopyNoThrow())
+            .WithInvariants(CheckInvariants)
+            .Test([rhs](ThrowingVariant* lhs) mutable { rhs.swap(*lhs); }));
+  }
+}
+
+}  // namespace
+}  // namespace absl
diff --git a/absl/utility/CMakeLists.txt b/absl/utility/CMakeLists.txt
index df21b85b34..dc3a631905 100644
--- a/absl/utility/CMakeLists.txt
+++ b/absl/utility/CMakeLists.txt
@@ -22,6 +22,8 @@ list(APPEND UTILITY_PUBLIC_HEADERS
 absl_header_library(
   TARGET
     absl_utility
+  PUBLIC_LIBRARIES
+    absl::base
   EXPORT_NAME
     utility
 )
@@ -33,7 +35,12 @@ absl_header_library(
 
 # test utility_test
 set(UTILITY_TEST_SRC "utility_test.cc")
-set(UTILITY_TEST_PUBLIC_LIBRARIES absl::utility)
+set(UTILITY_TEST_PUBLIC_LIBRARIES
+  absl::base
+  absl::memory
+  absl::strings
+  absl::utility
+)
 
 absl_test(
   TARGET