about summary refs log tree commit diff
path: root/absl
diff options
context:
space:
mode:
Diffstat (limited to 'absl')
-rw-r--r--absl/algorithm/container.h78
-rw-r--r--absl/base/call_once.h8
-rw-r--r--absl/base/config.h24
-rw-r--r--absl/container/BUILD.bazel4
-rw-r--r--absl/container/flat_hash_map.h12
-rw-r--r--absl/container/flat_hash_set.h12
-rw-r--r--absl/container/inlined_vector.h41
-rw-r--r--absl/container/internal/hash_generator_testing.cc8
-rw-r--r--absl/container/internal/hash_generator_testing.h8
-rw-r--r--absl/container/node_hash_map.h14
-rw-r--r--absl/container/node_hash_set.h11
-rw-r--r--absl/numeric/int128.h11
-rw-r--r--absl/synchronization/lifetime_test.cc15
-rw-r--r--absl/synchronization/notification.cc1
-rw-r--r--absl/time/duration_test.cc11
-rw-r--r--absl/time/internal/cctz/src/time_zone_libc.cc200
-rw-r--r--absl/time/internal/cctz/src/time_zone_lookup_test.cc100
-rw-r--r--absl/time/time.h18
-rw-r--r--absl/types/BUILD.bazel1
-rw-r--r--absl/types/variant_exception_safety_test.cc6
-rw-r--r--absl/types/variant_test.cc9
21 files changed, 488 insertions, 104 deletions
diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h
index 53ab15686c6e..6d5f6630f718 100644
--- a/absl/algorithm/container.h
+++ b/absl/algorithm/container.h
@@ -46,6 +46,8 @@
 #include <iterator>
 #include <numeric>
 #include <type_traits>
+#include <unordered_map>
+#include <unordered_set>
 #include <utility>
 #include <vector>
 
@@ -54,7 +56,6 @@
 #include "absl/meta/type_traits.h"
 
 namespace absl {
-
 namespace container_algorithm_internal {
 
 // NOTE: it is important to defer to ADL lookup for building with C++ modules,
@@ -101,6 +102,17 @@ ContainerIter<C> c_begin(C& c) { return begin(c); }
 template <typename C>
 ContainerIter<C> c_end(C& c) { return end(c); }
 
+template <typename T>
+struct IsUnorderedContainer : std::false_type {};
+
+template <class Key, class T, class Hash, class KeyEqual, class Allocator>
+struct IsUnorderedContainer<
+    std::unordered_map<Key, T, Hash, KeyEqual, Allocator>> : std::true_type {};
+
+template <class Key, class Hash, class KeyEqual, class Allocator>
+struct IsUnorderedContainer<std::unordered_set<Key, Hash, KeyEqual, Allocator>>
+    : std::true_type {};
+
 }  // namespace container_algorithm_internal
 
 // PUBLIC API
@@ -1154,7 +1166,13 @@ bool c_includes(const C1& c1, const C2& c2, Compare&& comp) {
 // Container-based version of the <algorithm> `std::set_union()` function
 // to return an iterator containing the union of two containers; duplicate
 // values are not copied into the output.
-template <typename C1, typename C2, typename OutputIterator>
+template <typename C1, typename C2, typename OutputIterator,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+              void>::type,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+              void>::type>
 OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output) {
   return std::set_union(container_algorithm_internal::c_begin(c1),
                         container_algorithm_internal::c_end(c1),
@@ -1164,7 +1182,13 @@ OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output) {
 
 // Overload of c_set_union() for performing a merge using a `comp` other than
 // `operator<`.
-template <typename C1, typename C2, typename OutputIterator, typename Compare>
+template <typename C1, typename C2, typename OutputIterator, typename Compare,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+              void>::type,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+              void>::type>
 OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output,
                            Compare&& comp) {
   return std::set_union(container_algorithm_internal::c_begin(c1),
@@ -1178,7 +1202,13 @@ OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output,
 //
 // Container-based version of the <algorithm> `std::set_intersection()` function
 // to return an iterator containing the intersection of two containers.
-template <typename C1, typename C2, typename OutputIterator>
+template <typename C1, typename C2, typename OutputIterator,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+              void>::type,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+              void>::type>
 OutputIterator c_set_intersection(const C1& c1, const C2& c2,
                                   OutputIterator output) {
   return std::set_intersection(container_algorithm_internal::c_begin(c1),
@@ -1189,7 +1219,13 @@ OutputIterator c_set_intersection(const C1& c1, const C2& c2,
 
 // Overload of c_set_intersection() for performing a merge using a `comp` other
 // than `operator<`.
-template <typename C1, typename C2, typename OutputIterator, typename Compare>
+template <typename C1, typename C2, typename OutputIterator, typename Compare,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+              void>::type,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+              void>::type>
 OutputIterator c_set_intersection(const C1& c1, const C2& c2,
                                   OutputIterator output, Compare&& comp) {
   return std::set_intersection(container_algorithm_internal::c_begin(c1),
@@ -1204,7 +1240,13 @@ OutputIterator c_set_intersection(const C1& c1, const C2& c2,
 // Container-based version of the <algorithm> `std::set_difference()` function
 // to return an iterator containing elements present in the first container but
 // not in the second.
-template <typename C1, typename C2, typename OutputIterator>
+template <typename C1, typename C2, typename OutputIterator,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+              void>::type,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+              void>::type>
 OutputIterator c_set_difference(const C1& c1, const C2& c2,
                                 OutputIterator output) {
   return std::set_difference(container_algorithm_internal::c_begin(c1),
@@ -1215,7 +1257,13 @@ OutputIterator c_set_difference(const C1& c1, const C2& c2,
 
 // Overload of c_set_difference() for performing a merge using a `comp` other
 // than `operator<`.
-template <typename C1, typename C2, typename OutputIterator, typename Compare>
+template <typename C1, typename C2, typename OutputIterator, typename Compare,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+              void>::type,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+              void>::type>
 OutputIterator c_set_difference(const C1& c1, const C2& c2,
                                 OutputIterator output, Compare&& comp) {
   return std::set_difference(container_algorithm_internal::c_begin(c1),
@@ -1230,7 +1278,13 @@ OutputIterator c_set_difference(const C1& c1, const C2& c2,
 // Container-based version of the <algorithm> `std::set_symmetric_difference()`
 // function to return an iterator containing elements present in either one
 // container or the other, but not both.
-template <typename C1, typename C2, typename OutputIterator>
+template <typename C1, typename C2, typename OutputIterator,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+              void>::type,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+              void>::type>
 OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
                                           OutputIterator output) {
   return std::set_symmetric_difference(
@@ -1242,7 +1296,13 @@ OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
 
 // Overload of c_set_symmetric_difference() for performing a merge using a
 // `comp` other than `operator<`.
-template <typename C1, typename C2, typename OutputIterator, typename Compare>
+template <typename C1, typename C2, typename OutputIterator, typename Compare,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+              void>::type,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+              void>::type>
 OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
                                           OutputIterator output,
                                           Compare&& comp) {
diff --git a/absl/base/call_once.h b/absl/base/call_once.h
index 532ee2e38bb5..f6c8ebb2f791 100644
--- a/absl/base/call_once.h
+++ b/absl/base/call_once.h
@@ -150,12 +150,8 @@ void CallOnceImpl(std::atomic<uint32_t>* control,
         old_control != kOnceRunning &&
         old_control != kOnceWaiter &&
         old_control != kOnceDone) {
-      ABSL_RAW_LOG(
-          FATAL,
-          "Unexpected value for control word: %lx. Either the control word "
-          "has non-static storage duration (where GoogleOnceDynamic might "
-          "be appropriate), or there's been a memory corruption.",
-          static_cast<unsigned long>(old_control)); // NOLINT
+      ABSL_RAW_LOG(FATAL, "Unexpected value for control word: 0x%lx",
+                   static_cast<unsigned long>(old_control));  // NOLINT
     }
   }
 #endif  // NDEBUG
diff --git a/absl/base/config.h b/absl/base/config.h
index d4eb7d0cbd76..e3edb2bf0cb6 100644
--- a/absl/base/config.h
+++ b/absl/base/config.h
@@ -139,12 +139,18 @@
 #ifdef ABSL_HAVE_THREAD_LOCAL
 #error ABSL_HAVE_THREAD_LOCAL cannot be directly set
 #elif defined(__APPLE__)
-// Notes: Xcode's clang did not support `thread_local` until version
-// 8, and even then not for all iOS < 9.0. Also, Xcode 9.3 started disallowing
-// `thread_local` for 32-bit iOS simulator targeting iOS 9.x.
-// `__has_feature` is only supported by Clang so it has be inside
+// Notes:
+// * Xcode's clang did not support `thread_local` until version 8, and
+//   even then not for all iOS < 9.0.
+// * Xcode 9.3 started disallowing `thread_local` for 32-bit iOS simulator
+//   targeting iOS 9.x.
+// * Xcode 10 moves the deployment target check for iOS < 9.0 to link time
+//   making __has_feature unreliable there.
+//
+// Otherwise, `__has_feature` is only supported by Clang so it has be inside
 // `defined(__APPLE__)` check.
-#if __has_feature(cxx_thread_local)
+#if __has_feature(cxx_thread_local) && \
+    !(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
 #define ABSL_HAVE_THREAD_LOCAL 1
 #endif
 #else  // !defined(__APPLE__)
@@ -423,4 +429,12 @@
 #define ABSL_HAVE_STD_STRING_VIEW 1
 #endif
 
+// In debug mode, MSVC 2017's std::variant throws a EXCEPTION_ACCESS_VIOLATION
+// SEH exception from emplace for variant<SomeStruct> when constructing the
+// struct can throw. This defeats some of variant_test and
+// variant_exception_safety_test.
+#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_DEBUG)
+#define ABSL_INTERNAL_MSVC_2017_DBG_MODE
+#endif
+
 #endif  // ABSL_BASE_CONFIG_H_
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
index d75f8916317a..afc869f45aac 100644
--- a/absl/container/BUILD.bazel
+++ b/absl/container/BUILD.bazel
@@ -212,6 +212,7 @@ cc_library(
         ":container_memory",
         ":hash_function_defaults",
         ":raw_hash_map",
+        "//absl/algorithm:container",
         "//absl/memory",
     ],
 )
@@ -240,6 +241,7 @@ cc_library(
         ":container_memory",
         ":hash_function_defaults",
         ":raw_hash_set",
+        "//absl/algorithm:container",
         "//absl/base:core_headers",
         "//absl/memory",
     ],
@@ -271,6 +273,7 @@ cc_library(
         ":hash_function_defaults",
         ":node_hash_policy",
         ":raw_hash_map",
+        "//absl/algorithm:container",
         "//absl/memory",
     ],
 )
@@ -299,6 +302,7 @@ cc_library(
         ":hash_function_defaults",
         ":node_hash_policy",
         ":raw_hash_set",
+        "//absl/algorithm:container",
         "//absl/memory",
     ],
 )
diff --git a/absl/container/flat_hash_map.h b/absl/container/flat_hash_map.h
index de632be2cf21..7bc213802476 100644
--- a/absl/container/flat_hash_map.h
+++ b/absl/container/flat_hash_map.h
@@ -35,6 +35,7 @@
 #include <type_traits>
 #include <utility>
 
+#include "absl/algorithm/container.h"
 #include "absl/container/internal/container_memory.h"
 #include "absl/container/internal/hash_function_defaults.h"  // IWYU pragma: export
 #include "absl/container/internal/raw_hash_map.h"  // IWYU pragma: export
@@ -564,5 +565,16 @@ struct FlatHashMapPolicy {
 };
 
 }  // namespace container_internal
+
+namespace container_algorithm_internal {
+
+// Specialization of trait in absl/algorithm/container.h
+template <class Key, class T, class Hash, class KeyEqual, class Allocator>
+struct IsUnorderedContainer<
+    absl::flat_hash_map<Key, T, Hash, KeyEqual, Allocator>> : std::true_type {};
+
+}  // namespace container_algorithm_internal
+
 }  // namespace absl
+
 #endif  // ABSL_CONTAINER_FLAT_HASH_MAP_H_
diff --git a/absl/container/flat_hash_set.h b/absl/container/flat_hash_set.h
index a2584d66f8e6..f7c1acaaa7b8 100644
--- a/absl/container/flat_hash_set.h
+++ b/absl/container/flat_hash_set.h
@@ -32,6 +32,7 @@
 #include <type_traits>
 #include <utility>
 
+#include "absl/algorithm/container.h"
 #include "absl/base/macros.h"
 #include "absl/container/internal/container_memory.h"
 #include "absl/container/internal/hash_function_defaults.h"  // IWYU pragma: export
@@ -475,5 +476,16 @@ struct FlatHashSetPolicy {
   static size_t space_used(const T*) { return 0; }
 };
 }  // namespace container_internal
+
+namespace container_algorithm_internal {
+
+// Specialization of trait in absl/algorithm/container.h
+template <class Key, class Hash, class KeyEqual, class Allocator>
+struct IsUnorderedContainer<absl::flat_hash_set<Key, Hash, KeyEqual, Allocator>>
+    : std::true_type {};
+
+}  // namespace container_algorithm_internal
+
 }  // namespace absl
+
 #endif  // ABSL_CONTAINER_FLAT_HASH_SET_H_
diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h
index ea8cb02baa61..642dae6cb907 100644
--- a/absl/container/inlined_vector.h
+++ b/absl/container/inlined_vector.h
@@ -20,17 +20,17 @@
 // vector" which behaves in an equivalent fashion to a `std::vector`, except
 // that storage for small sequences of the vector are provided inline without
 // requiring any heap allocation.
-
-// An `absl::InlinedVector<T,N>` specifies the size N at which to inline as one
-// of its template parameters. Vectors of length <= N are provided inline.
-// Typically N is very small (e.g., 4) so that sequences that are expected to be
-// short do not require allocations.
-
-// An `absl::InlinedVector` does not usually require a specific allocator; if
+//
+// An `absl::InlinedVector<T, N>` specifies the default capacity `N` as one of
+// its template parameters. Instances where `size() <= N` hold contained
+// elements in inline space. Typically `N` is very small so that sequences that
+// are expected to be short do not require allocations.
+//
+// An `absl::InlinedVector` does not usually require a specific allocator. If
 // the inlined vector grows beyond its initial constraints, it will need to
-// allocate (as any normal `std::vector` would) and it will generally use the
-// default allocator in that case; optionally, a custom allocator may be
-// specified using an `absl::InlinedVector<T,N,A>` construction.
+// allocate (as any normal `std::vector` would). This is usually performed with
+// the default allocator (defined as `std::allocator<T>`). Optionally, a custom
+// allocator type may be specified as `A` in `absl::InlinedVector<T, N, A>`.
 
 #ifndef ABSL_CONTAINER_INLINED_VECTOR_H_
 #define ABSL_CONTAINER_INLINED_VECTOR_H_
@@ -61,8 +61,8 @@ namespace absl {
 // An `absl::InlinedVector` is designed to be a drop-in replacement for
 // `std::vector` for use cases where the vector's size is sufficiently small
 // that it can be inlined. If the inlined vector does grow beyond its estimated
-// size, it will trigger an initial allocation on the heap, and will behave as a
-// `std:vector`. The API of the `absl::InlinedVector` within this file is
+// capacity, it will trigger an initial allocation on the heap, and will behave
+// as a `std:vector`. The API of the `absl::InlinedVector` within this file is
 // designed to cover the same API footprint as covered by `std::vector`.
 template <typename T, size_t N, typename A = std::allocator<T>>
 class InlinedVector {
@@ -101,7 +101,6 @@ class InlinedVector {
   using reverse_iterator = std::reverse_iterator<iterator>;
   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
 
-
   // ---------------------------------------------------------------------------
   // InlinedVector Constructors and Destructor
   // ---------------------------------------------------------------------------
@@ -135,11 +134,12 @@ class InlinedVector {
     AppendRange(init_list.begin(), init_list.end());
   }
 
-  // Creates and initialize with the elements [`first`, `last`).
+  // Creates an inlined vector with elements constructed from the provided
+  // Iterator range [`first`, `last`).
   //
   // NOTE: The `enable_if` prevents ambiguous interpretation between a call to
-  // this constructor with two integral arguments and a call to the preceding
-  // `InlinedVector(n, v)` constructor.
+  // this constructor with two integral arguments and a call to the above
+  // `InlinedVector(size_type, const_reference)` constructor.
   template <typename InputIterator, DisableIfIntegral<InputIterator>* = nullptr>
   InlinedVector(InputIterator first, InputIterator last,
                 const allocator_type& alloc = allocator_type())
@@ -153,11 +153,11 @@ class InlinedVector {
   // Creates a copy of `other` but with a specified allocator.
   InlinedVector(const InlinedVector& other, const allocator_type& alloc);
 
-  // Creates an inlined vector with the contents of `other`.
+  // Creates an inlined vector by moving in the contents of `other`.
   //
   // NOTE: This move constructor does not allocate and only moves the underlying
   // objects, so its `noexcept` specification depends on whether moving the
-  // underlying objects can throw or not. We assume
+  // underlying objects can throw or not. We assume:
   //  a) move constructors should only throw due to allocation failure and
   //  b) if `value_type`'s move constructor allocates, it uses the same
   //     allocation function as the `InlinedVector`'s allocator, so the move
@@ -167,9 +167,9 @@ class InlinedVector {
       absl::allocator_is_nothrow<allocator_type>::value ||
       std::is_nothrow_move_constructible<value_type>::value);
 
-  // Creates an inlined vector with the contents of `other`.
+  // Creates an inlined vector by moving in the contents of `other`.
   //
-  // NOTE: This move constructor allocates and also moves the underlying
+  // NOTE: This move constructor allocates and subsequently moves the underlying
   // objects, so its `noexcept` specification depends on whether the allocation
   // can throw and whether moving the underlying objects can throw. Based on the
   // same assumptions as above, the `noexcept` specification is dominated by
@@ -180,7 +180,6 @@ class InlinedVector {
 
   ~InlinedVector() { clear(); }
 
-
   // ---------------------------------------------------------------------------
   // InlinedVector Member Accessors
   // ---------------------------------------------------------------------------
diff --git a/absl/container/internal/hash_generator_testing.cc b/absl/container/internal/hash_generator_testing.cc
index 0d6a9df16f8a..e0fefbffdfa1 100644
--- a/absl/container/internal/hash_generator_testing.cc
+++ b/absl/container/internal/hash_generator_testing.cc
@@ -39,9 +39,9 @@ class RandomDeviceSeedSeq {
 
 }  // namespace
 
-std::mt19937_64* GetThreadLocalRng() {
+std::mt19937_64* GetSharedRng() {
   RandomDeviceSeedSeq seed_seq;
-  thread_local auto* rng = new std::mt19937_64(seed_seq);
+  static auto* rng = new std::mt19937_64(seed_seq);
   return rng;
 }
 
@@ -51,7 +51,7 @@ std::string Generator<std::string>::operator()() const {
   std::string res;
   res.resize(32);
   std::generate(res.begin(), res.end(),
-                [&]() { return chars(*GetThreadLocalRng()); });
+                [&]() { return chars(*GetSharedRng()); });
   return res;
 }
 
@@ -63,7 +63,7 @@ absl::string_view Generator<absl::string_view>::operator()() const {
   auto& res = arena->back();
   res.resize(32);
   std::generate(res.begin(), res.end(),
-                [&]() { return chars(*GetThreadLocalRng()); });
+                [&]() { return chars(*GetSharedRng()); });
   return res;
 }
 
diff --git a/absl/container/internal/hash_generator_testing.h b/absl/container/internal/hash_generator_testing.h
index 50d771026c7b..6521efe87337 100644
--- a/absl/container/internal/hash_generator_testing.h
+++ b/absl/container/internal/hash_generator_testing.h
@@ -43,7 +43,7 @@ struct IsMap<Map, absl::void_t<typename Map::mapped_type>> : std::true_type {};
 
 }  // namespace generator_internal
 
-std::mt19937_64* GetThreadLocalRng();
+std::mt19937_64* GetSharedRng();
 
 enum Enum {
   kEnumEmpty,
@@ -66,7 +66,7 @@ template <class T>
 struct Generator<T, typename std::enable_if<std::is_integral<T>::value>::type> {
   T operator()() const {
     std::uniform_int_distribution<T> dist;
-    return dist(*GetThreadLocalRng());
+    return dist(*GetSharedRng());
   }
 };
 
@@ -76,7 +76,7 @@ struct Generator<Enum> {
     std::uniform_int_distribution<typename std::underlying_type<Enum>::type>
         dist;
     while (true) {
-      auto variate = dist(*GetThreadLocalRng());
+      auto variate = dist(*GetSharedRng());
       if (variate != kEnumEmpty && variate != kEnumDeleted)
         return static_cast<Enum>(variate);
     }
@@ -90,7 +90,7 @@ struct Generator<EnumClass> {
         typename std::underlying_type<EnumClass>::type>
         dist;
     while (true) {
-      EnumClass variate = static_cast<EnumClass>(dist(*GetThreadLocalRng()));
+      EnumClass variate = static_cast<EnumClass>(dist(*GetSharedRng()));
       if (variate != EnumClass::kEmpty && variate != EnumClass::kDeleted)
         return static_cast<EnumClass>(variate);
     }
diff --git a/absl/container/node_hash_map.h b/absl/container/node_hash_map.h
index 00710e52c577..18d3f28f2202 100644
--- a/absl/container/node_hash_map.h
+++ b/absl/container/node_hash_map.h
@@ -40,6 +40,7 @@
 #include <type_traits>
 #include <utility>
 
+#include "absl/algorithm/container.h"
 #include "absl/container/internal/container_memory.h"
 #include "absl/container/internal/hash_function_defaults.h"  // IWYU pragma: export
 #include "absl/container/internal/node_hash_policy.h"
@@ -91,7 +92,7 @@ class NodeHashMapPolicy;
 //  std::string search_key = "b";
 //  auto result = ducks.find(search_key);
 //  if (result != ducks.end()) {
-//    std::cout << "Result: " << search_key->second << std::endl;
+//    std::cout << "Result: " << result->second << std::endl;
 //  }
 template <class Key, class Value,
           class Hash = absl::container_internal::hash_default_hash<Key>,
@@ -566,5 +567,16 @@ class NodeHashMapPolicy
   static const Value& value(const value_type* elem) { return elem->second; }
 };
 }  // namespace container_internal
+
+namespace container_algorithm_internal {
+
+// Specialization of trait in absl/algorithm/container.h
+template <class Key, class T, class Hash, class KeyEqual, class Allocator>
+struct IsUnorderedContainer<
+    absl::node_hash_map<Key, T, Hash, KeyEqual, Allocator>> : std::true_type {};
+
+}  // namespace container_algorithm_internal
+
 }  // namespace absl
+
 #endif  // ABSL_CONTAINER_NODE_HASH_MAP_H_
diff --git a/absl/container/node_hash_set.h b/absl/container/node_hash_set.h
index 813fdeffce0e..e0897c99afff 100644
--- a/absl/container/node_hash_set.h
+++ b/absl/container/node_hash_set.h
@@ -37,6 +37,7 @@
 
 #include <type_traits>
 
+#include "absl/algorithm/container.h"
 #include "absl/container/internal/hash_function_defaults.h"  // IWYU pragma: export
 #include "absl/container/internal/node_hash_policy.h"
 #include "absl/container/internal/raw_hash_set.h"  // IWYU pragma: export
@@ -475,5 +476,15 @@ struct NodeHashSetPolicy
   static size_t element_space_used(const T*) { return sizeof(T); }
 };
 }  // namespace container_internal
+
+namespace container_algorithm_internal {
+
+// Specialization of trait in absl/algorithm/container.h
+template <class Key, class Hash, class KeyEqual, class Allocator>
+struct IsUnorderedContainer<absl::node_hash_set<Key, Hash, KeyEqual, Allocator>>
+    : std::true_type {};
+
+}  // namespace container_algorithm_internal
 }  // namespace absl
+
 #endif  // ABSL_CONTAINER_NODE_HASH_SET_H_
diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h
index 5d14a4a8962a..9c2e00f6d4a1 100644
--- a/absl/numeric/int128.h
+++ b/absl/numeric/int128.h
@@ -37,6 +37,11 @@
 #include "absl/base/macros.h"
 #include "absl/base/port.h"
 
+#if defined(_MSC_VER) && defined(_WIN64)
+#include <intrin.h>
+#pragma intrinsic(_umul128)
+#endif  // defined(_MSC_VER) && defined(_WIN64)
+
 namespace absl {
 
 
@@ -661,6 +666,12 @@ inline uint128 operator*(uint128 lhs, uint128 rhs) {
   // can be used for uint128 storage.
   return static_cast<unsigned __int128>(lhs) *
          static_cast<unsigned __int128>(rhs);
+#elif defined(_MSC_VER) && defined(_WIN64)
+  uint64_t carry;
+  uint64_t low = _umul128(Uint128Low64(lhs), Uint128Low64(rhs), &carry);
+  return MakeUint128(Uint128Low64(lhs) * Uint128High64(rhs) +
+                         Uint128High64(lhs) * Uint128Low64(rhs) + carry,
+                     low);
 #else   // ABSL_HAVE_INTRINSIC128
   uint64_t a32 = Uint128Low64(lhs) >> 32;
   uint64_t a00 = Uint128Low64(lhs) & 0xffffffff;
diff --git a/absl/synchronization/lifetime_test.cc b/absl/synchronization/lifetime_test.cc
index 90c9009b18fa..b7360c29016b 100644
--- a/absl/synchronization/lifetime_test.cc
+++ b/absl/synchronization/lifetime_test.cc
@@ -72,23 +72,19 @@ void ThreadTwo(absl::Mutex* mutex, absl::CondVar* condvar,
 // Launch thread 1 and thread 2, and block on their completion.
 // If any of 'mutex', 'condvar', or 'notification' is nullptr, use a locally
 // constructed instance instead.
-void RunTests(absl::Mutex* mutex, absl::CondVar* condvar,
-              absl::Notification* notification) {
+void RunTests(absl::Mutex* mutex, absl::CondVar* condvar) {
   absl::Mutex default_mutex;
   absl::CondVar default_condvar;
-  absl::Notification default_notification;
+  absl::Notification notification;
   if (!mutex) {
     mutex = &default_mutex;
   }
   if (!condvar) {
     condvar = &default_condvar;
   }
-  if (!notification) {
-    notification = &default_notification;
-  }
   bool state = false;
-  std::thread thread_one(ThreadOne, mutex, condvar, notification, &state);
-  std::thread thread_two(ThreadTwo, mutex, condvar, notification, &state);
+  std::thread thread_one(ThreadOne, mutex, condvar, &notification, &state);
+  std::thread thread_two(ThreadTwo, mutex, condvar, &notification, &state);
   thread_one.join();
   thread_two.join();
 }
@@ -96,8 +92,7 @@ void RunTests(absl::Mutex* mutex, absl::CondVar* condvar,
 void TestLocals() {
   absl::Mutex mutex;
   absl::CondVar condvar;
-  absl::Notification notification;
-  RunTests(&mutex, &condvar, &notification);
+  RunTests(&mutex, &condvar);
 }
 
 // Global variables during start and termination
diff --git a/absl/synchronization/notification.cc b/absl/synchronization/notification.cc
index ed8cc9067740..cdcbc134fa65 100644
--- a/absl/synchronization/notification.cc
+++ b/absl/synchronization/notification.cc
@@ -22,6 +22,7 @@
 #include "absl/time/time.h"
 
 namespace absl {
+
 void Notification::Notify() {
   MutexLock l(&this->mutex_);
 
diff --git a/absl/time/duration_test.cc b/absl/time/duration_test.cc
index 7ae25dc68f9a..775da91e6929 100644
--- a/absl/time/duration_test.cc
+++ b/absl/time/duration_test.cc
@@ -56,6 +56,17 @@ MATCHER_P(TimevalMatcher, tv, "") {
   return false;
 }
 
+TEST(Duration, ConstExpr) {
+  constexpr absl::Duration d0 = absl::ZeroDuration();
+  static_assert(d0 == absl::ZeroDuration(), "ZeroDuration()");
+  constexpr absl::Duration d1 = absl::Seconds(1);
+  static_assert(d1 == absl::Seconds(1), "Seconds(1)");
+  static_assert(d1 != absl::ZeroDuration(), "Seconds(1)");
+  constexpr absl::Duration d2 = absl::InfiniteDuration();
+  static_assert(d2 == absl::InfiniteDuration(), "InfiniteDuration()");
+  static_assert(d2 != absl::ZeroDuration(), "InfiniteDuration()");
+}
+
 TEST(Duration, ValueSemantics) {
   // If this compiles, the test passes.
   constexpr absl::Duration a;      // Default construction
diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc
index e35fa18b7733..6db519e165cf 100644
--- a/absl/time/internal/cctz/src/time_zone_libc.cc
+++ b/absl/time/internal/cctz/src/time_zone_libc.cc
@@ -20,6 +20,7 @@
 
 #include <chrono>
 #include <ctime>
+#include <limits>
 #include <tuple>
 #include <utility>
 
@@ -85,6 +86,76 @@ OffsetAbbr get_offset_abbr(const T& tm, decltype(&T::__tm_gmtoff) = nullptr,
 #endif  // !defined(__tm_gmtoff) && !defined(__tm_zone)
 #endif
 
+inline std::tm* gm_time(const std::time_t *timep, std::tm *result) {
+#if defined(_WIN32) || defined(_WIN64)
+    return gmtime_s(result, timep) ? nullptr : result;
+#else
+    return gmtime_r(timep, result);
+#endif
+}
+
+inline std::tm* local_time(const std::time_t *timep, std::tm *result) {
+#if defined(_WIN32) || defined(_WIN64)
+    return localtime_s(result, timep) ? nullptr : result;
+#else
+    return localtime_r(timep, result);
+#endif
+}
+
+// Converts a civil second and "dst" flag into a time_t and UTC offset.
+// Returns false if time_t cannot represent the requested civil second.
+// Caller must have already checked that cs.year() will fit into a tm_year.
+bool make_time(const civil_second& cs, int is_dst, std::time_t* t, int* off) {
+  std::tm tm;
+  tm.tm_year = static_cast<int>(cs.year() - year_t{1900});
+  tm.tm_mon = cs.month() - 1;
+  tm.tm_mday = cs.day();
+  tm.tm_hour = cs.hour();
+  tm.tm_min = cs.minute();
+  tm.tm_sec = cs.second();
+  tm.tm_isdst = is_dst;
+  *t = std::mktime(&tm);
+  if (*t == std::time_t{-1}) {
+    std::tm tm2;
+    const std::tm* tmp = local_time(t, &tm2);
+    if (tmp == nullptr || tmp->tm_year != tm.tm_year ||
+        tmp->tm_mon != tm.tm_mon || tmp->tm_mday != tm.tm_mday ||
+        tmp->tm_hour != tm.tm_hour || tmp->tm_min != tm.tm_min ||
+        tmp->tm_sec != tm.tm_sec) {
+      // A true error (not just one second before the epoch).
+      return false;
+    }
+  }
+  *off = get_offset_abbr(tm).first;
+  return true;
+}
+
+// Find the least time_t in [lo:hi] where local time matches offset, given:
+// (1) lo doesn't match, (2) hi does, and (3) there is only one transition.
+std::time_t find_trans(std::time_t lo, std::time_t hi, int offset) {
+  std::tm tm;
+  while (lo + 1 != hi) {
+    const std::time_t mid = lo + (hi - lo) / 2;
+    if (std::tm* tmp = local_time(&mid, &tm)) {
+      if (get_offset_abbr(*tmp).first == offset) {
+        hi = mid;
+      } else {
+        lo = mid;
+      }
+    } else {
+      // If std::tm cannot hold some result we resort to a linear search,
+      // ignoring all failed conversions.  Slow, but never really happens.
+      while (++lo != hi) {
+        if (std::tm* tmp = local_time(&lo, &tm)) {
+          if (get_offset_abbr(*tmp).first == offset) break;
+        }
+      }
+      return lo;
+    }
+  }
+  return hi;
+}
+
 }  // namespace
 
 TimeZoneLibC::TimeZoneLibC(const std::string& name)
@@ -93,50 +164,107 @@ TimeZoneLibC::TimeZoneLibC(const std::string& name)
 time_zone::absolute_lookup TimeZoneLibC::BreakTime(
     const time_point<seconds>& tp) const {
   time_zone::absolute_lookup al;
-  std::time_t t = ToUnixSeconds(tp);
+  al.offset = 0;
+  al.is_dst = false;
+  al.abbr = "-00";
+
+  const std::int_fast64_t s = ToUnixSeconds(tp);
+
+  // If std::time_t cannot hold the input we saturate the output.
+  if (s < std::numeric_limits<std::time_t>::min()) {
+    al.cs = civil_second::min();
+    return al;
+  }
+  if (s > std::numeric_limits<std::time_t>::max()) {
+    al.cs = civil_second::max();
+    return al;
+  }
+
+  const std::time_t t = static_cast<std::time_t>(s);
   std::tm tm;
-  if (local_) {
-#if defined(_WIN32) || defined(_WIN64)
-    localtime_s(&tm, &t);
-#else
-    localtime_r(&t, &tm);
-#endif
-    std::tie(al.offset, al.abbr) = get_offset_abbr(tm);
-  } else {
-#if defined(_WIN32) || defined(_WIN64)
-    gmtime_s(&tm, &t);
-#else
-    gmtime_r(&t, &tm);
-#endif
-    al.offset = 0;
-    al.abbr = "UTC";
+  std::tm* tmp = local_ ? local_time(&t, &tm) : gm_time(&t, &tm);
+
+  // If std::tm cannot hold the result we saturate the output.
+  if (tmp == nullptr) {
+    al.cs = (s < 0) ? civil_second::min() : civil_second::max();
+    return al;
   }
-  al.cs = civil_second(tm.tm_year + year_t{1900}, tm.tm_mon + 1, tm.tm_mday,
-                       tm.tm_hour, tm.tm_min, tm.tm_sec);
-  al.is_dst = tm.tm_isdst > 0;
+
+  const year_t year = tmp->tm_year + year_t{1900};
+  al.cs = civil_second(year, tmp->tm_mon + 1, tmp->tm_mday,
+                       tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+  std::tie(al.offset, al.abbr) = get_offset_abbr(*tmp);
+  if (!local_) al.abbr = "UTC";  // as expected by cctz
+  al.is_dst = tmp->tm_isdst > 0;
   return al;
 }
 
 time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const {
-  time_zone::civil_lookup cl;
-  std::time_t t;
-  if (local_) {
-    // Does not handle SKIPPED/AMBIGUOUS or huge years.
-    std::tm tm;
-    tm.tm_year = static_cast<int>(cs.year() - 1900);
-    tm.tm_mon = cs.month() - 1;
-    tm.tm_mday = cs.day();
-    tm.tm_hour = cs.hour();
-    tm.tm_min = cs.minute();
-    tm.tm_sec = cs.second();
-    tm.tm_isdst = -1;
-    t = std::mktime(&tm);
+  if (!local_) {
+    // If time_point<seconds> cannot hold the result we saturate.
+    static const civil_second min_tp_cs =
+        civil_second() + ToUnixSeconds(time_point<seconds>::min());
+    static const civil_second max_tp_cs =
+        civil_second() + ToUnixSeconds(time_point<seconds>::max());
+    const time_point<seconds> tp =
+        (cs < min_tp_cs)
+            ? time_point<seconds>::min()
+            : (cs > max_tp_cs) ? time_point<seconds>::max()
+                               : FromUnixSeconds(cs - civil_second());
+    return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
+  }
+
+  // If tm_year cannot hold the requested year we saturate the result.
+  if (cs.year() < 0) {
+    if (cs.year() < std::numeric_limits<int>::min() + year_t{1900}) {
+      const time_point<seconds> tp = time_point<seconds>::min();
+      return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
+    }
   } else {
-    t = cs - civil_second();
+    if (cs.year() - year_t{1900} > std::numeric_limits<int>::max()) {
+      const time_point<seconds> tp = time_point<seconds>::max();
+      return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
+    }
+  }
+
+  // We probe with "is_dst" values of 0 and 1 to try to distinguish unique
+  // civil seconds from skipped or repeated ones.  This is not always possible
+  // however, as the "dst" flag does not change over some offset transitions.
+  // We are also subject to the vagaries of mktime() implementations.
+  std::time_t t0, t1;
+  int offset0, offset1;
+  if (make_time(cs, 0, &t0, &offset0) && make_time(cs, 1, &t1, &offset1)) {
+    if (t0 == t1) {
+      // The civil time was singular (pre == trans == post).
+      const time_point<seconds> tp = FromUnixSeconds(t0);
+      return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
+    }
+
+    if (t0 > t1) {
+      std::swap(t0, t1);
+      std::swap(offset0, offset1);
+    }
+    const std::time_t tt = find_trans(t0, t1, offset1);
+    const time_point<seconds> trans = FromUnixSeconds(tt);
+
+    if (offset0 < offset1) {
+      // The civil time did not exist (pre >= trans > post).
+      const time_point<seconds> pre = FromUnixSeconds(t1);
+      const time_point<seconds> post = FromUnixSeconds(t0);
+      return {time_zone::civil_lookup::SKIPPED, pre, trans, post};
+    }
+
+    // The civil time was ambiguous (pre < trans <= post).
+    const time_point<seconds> pre = FromUnixSeconds(t0);
+    const time_point<seconds> post = FromUnixSeconds(t1);
+    return {time_zone::civil_lookup::REPEATED, pre, trans, post};
   }
-  cl.kind = time_zone::civil_lookup::UNIQUE;
-  cl.pre = cl.trans = cl.post = FromUnixSeconds(t);
-  return cl;
+
+  // make_time() failed somehow so we saturate the result.
+  const time_point<seconds> tp = (cs < civil_second())
+                                     ? time_point<seconds>::min()
+                                     : time_point<seconds>::max();
+  return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
 }
 
 bool TimeZoneLibC::NextTransition(const time_point<seconds>& tp,
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 f28e7f853b69..e84b9469aa08 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -16,7 +16,9 @@
 
 #include <chrono>
 #include <cstddef>
+#include <cstdlib>
 #include <future>
+#include <limits>
 #include <string>
 #include <thread>
 #include <vector>
@@ -925,7 +927,7 @@ TEST(MakeTime, Normalization) {
   EXPECT_EQ(tp, convert(civil_second(2009, 2, 13, 18, 30, 90), tz));   // second
 }
 
-// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
+// NOTE: Run this with -ftrapv to detect overflow problems.
 TEST(MakeTime, SysSecondsLimits) {
   const char RFC3339[] =  "%Y-%m-%dT%H:%M:%S%Ez";
   const time_zone utc = utc_time_zone();
@@ -991,19 +993,107 @@ TEST(MakeTime, SysSecondsLimits) {
   tp = convert(civil_second::min(), west);
   EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp);
 
+  // Some similar checks for the "libc" time-zone implementation.
   if (sizeof(std::time_t) >= 8) {
     // Checks that "tm_year + 1900", as used by the "libc" implementation,
     // can produce year values beyond the range on an int without overflow.
 #if defined(_WIN32) || defined(_WIN64)
-    // localtime_s() and gmtime_s() don't believe in years past 3000.
+    // localtime_s() and gmtime_s() don't believe in years outside [1970:3000].
 #else
-    const time_zone libc_utc = LoadZone("libc:UTC");
-    tp = convert(civil_year(year_t{2147483648}), libc_utc);
-    EXPECT_EQ("2147483648-01-01T00:00:00+00:00", format(RFC3339, tp, libc_utc));
+    const time_zone utc = LoadZone("libc:UTC");
+    const year_t max_tm_year = year_t{std::numeric_limits<int>::max()} + 1900;
+    tp = convert(civil_second(max_tm_year, 12, 31, 23, 59, 59), utc);
+    EXPECT_EQ("2147485547-12-31T23:59:59+00:00", format(RFC3339, tp, utc));
+    const year_t min_tm_year = year_t{std::numeric_limits<int>::min()} + 1900;
+    tp = convert(civil_second(min_tm_year, 1, 1, 0, 0, 0), utc);
+    EXPECT_EQ("-2147481748-01-01T00:00:00+00:00", format(RFC3339, tp, utc));
 #endif
   }
 }
 
+TEST(MakeTime, LocalTimeLibC) {
+  // Checks that cctz and libc agree on transition points in [1970:2037].
+  //
+  // We limit this test case to environments where:
+  //  1) we know how to change the time zone used by localtime()/mktime(),
+  //  2) cctz and localtime()/mktime() will use similar-enough tzdata, and
+  //  3) we have some idea about how mktime() behaves during transitions.
+#if defined(__linux__)
+  const char* const ep = getenv("TZ");
+  std::string tz_name = (ep != nullptr) ? ep : "";
+  for (const char* const* np = kTimeZoneNames; *np != nullptr; ++np) {
+    ASSERT_EQ(0, setenv("TZ", *np, 1));  // change what "localtime" means
+    const auto zi = local_time_zone();
+    const auto lc = LoadZone("libc:localtime");
+    time_zone::civil_transition trans;
+    for (auto tp = zi.lookup(civil_second()).trans;
+         zi.next_transition(tp, &trans);
+         tp = zi.lookup(trans.to).trans) {
+      const auto fcl = zi.lookup(trans.from);
+      const auto tcl = zi.lookup(trans.to);
+      civil_second cs;  // compare cs in zi and lc
+      if (fcl.kind == time_zone::civil_lookup::UNIQUE) {
+        if (tcl.kind == time_zone::civil_lookup::UNIQUE) {
+          // Both unique; must be an is_dst or abbr change.
+          ASSERT_EQ(trans.from, trans.to);
+          const auto trans = fcl.trans;
+          const auto tal = zi.lookup(trans);
+          const auto tprev = trans - absl::time_internal::cctz::seconds(1);
+          const auto pal = zi.lookup(tprev);
+          if (pal.is_dst == tal.is_dst) {
+            ASSERT_STRNE(pal.abbr, tal.abbr);
+          }
+          continue;
+        }
+        ASSERT_EQ(time_zone::civil_lookup::REPEATED, tcl.kind);
+        cs = trans.to;
+      } else {
+        ASSERT_EQ(time_zone::civil_lookup::UNIQUE, tcl.kind);
+        ASSERT_EQ(time_zone::civil_lookup::SKIPPED, fcl.kind);
+        cs = trans.from;
+      }
+      if (cs.year() > 2037) break;  // limit test time (and to 32-bit time_t)
+      const auto cl_zi = zi.lookup(cs);
+      if (zi.lookup(cl_zi.pre).is_dst == zi.lookup(cl_zi.post).is_dst) {
+        // The "libc" implementation cannot correctly classify transitions
+        // that don't change the "tm_isdst" flag.  In Europe/Volgograd, for
+        // example, there is a SKIPPED transition from +03 to +04 with dst=F
+        // on both sides ...
+        //   1540681199 = 2018-10-28 01:59:59 +03:00:00 [dst=F off=10800]
+        //   1540681200 = 2018-10-28 03:00:00 +04:00:00 [dst=F off=14400]
+        // but std::mktime(2018-10-28 02:00:00, tm_isdst=0) fails, unlike,
+        // say, the similar Europe/Chisinau transition from +02 to +03 ...
+        //   1521935999 = 2018-03-25 01:59:59 +02:00:00 [dst=F off=7200]
+        //   1521936000 = 2018-03-25 03:00:00 +03:00:00 [dst=T off=10800]
+        // where std::mktime(2018-03-25 02:00:00, tm_isdst=0) succeeds and
+        // returns 1521936000.
+        continue;
+      }
+      if (cs == civil_second(2037, 10, 4, 2, 0, 0)) {
+        const std::string tzname = *np;
+        if (tzname == "Africa/Casablanca" || tzname == "Africa/El_Aaiun") {
+          // The "libc" implementation gets this transition wrong (at least
+          // until 2018g when it was removed), returning an offset of 3600
+          // instead of 0.  TODO: Revert this when 2018g is ubiquitous.
+          continue;
+        }
+      }
+      const auto cl_lc = lc.lookup(cs);
+      SCOPED_TRACE(testing::Message() << "For " << cs << " in " << *np);
+      EXPECT_EQ(cl_zi.kind, cl_lc.kind);
+      EXPECT_EQ(cl_zi.pre, cl_lc.pre);
+      EXPECT_EQ(cl_zi.trans, cl_lc.trans);
+      EXPECT_EQ(cl_zi.post, cl_lc.post);
+    }
+  }
+  if (ep == nullptr) {
+    ASSERT_EQ(0, unsetenv("TZ"));
+  } else {
+    ASSERT_EQ(0, setenv("TZ", tz_name.c_str(), 1));
+  }
+#endif
+}
+
 TEST(NextTransition, UTC) {
   const auto tz = utc_time_zone();
   time_zone::civil_transition trans;
diff --git a/absl/time/time.h b/absl/time/time.h
index e9e989cb0561..de12e5608b29 100644
--- a/absl/time/time.h
+++ b/absl/time/time.h
@@ -153,6 +153,16 @@ class Duration {
   // Value semantics.
   constexpr Duration() : rep_hi_(0), rep_lo_(0) {}  // zero-length duration
 
+  // Copyable.
+#if !defined(__clang__) && defined(_MSC_VER) && _MSC_VER < 1910
+  // Explicitly defining the constexpr copy constructor avoids an MSVC bug.
+  constexpr Duration(const Duration& d)
+      : rep_hi_(d.rep_hi_), rep_lo_(d.rep_lo_) {}
+#else
+  constexpr Duration(const Duration& d) = default;
+#endif
+  Duration& operator=(const Duration& d) = default;
+
   // Compound assignment operators.
   Duration& operator+=(Duration d);
   Duration& operator-=(Duration d);
@@ -584,7 +594,11 @@ class Time {
   //   absl::Time t = absl::Now();
   //   absl::Time t = absl::TimeFromTimeval(tv);
   //   absl::Time t = absl::InfinitePast();
-  constexpr Time() {}
+  constexpr Time() = default;
+
+  // Copyable.
+  constexpr Time(const Time& t) = default;
+  Time& operator=(const Time& t) = default;
 
   // Assignment operators.
   Time& operator+=(Duration d) {
@@ -826,6 +840,8 @@ class TimeZone {
  public:
   explicit TimeZone(time_internal::cctz::time_zone tz) : cz_(tz) {}
   TimeZone() = default;  // UTC, but prefer UTCTimeZone() to be explicit.
+
+  // Copyable.
   TimeZone(const TimeZone&) = default;
   TimeZone& operator=(const TimeZone&) = default;
 
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel
index 43899ca7ccf7..d56fea6e90db 100644
--- a/absl/types/BUILD.bazel
+++ b/absl/types/BUILD.bazel
@@ -287,6 +287,7 @@ cc_test(
     linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
     deps = [
         ":variant",
+        "//absl/base:config",
         "//absl/base:exception_safety_testing",
         "//absl/memory",
         "@com_google_googletest//:gtest_main",
diff --git a/absl/types/variant_exception_safety_test.cc b/absl/types/variant_exception_safety_test.cc
index 58436f07b843..82425dbd1904 100644
--- a/absl/types/variant_exception_safety_test.cc
+++ b/absl/types/variant_exception_safety_test.cc
@@ -11,6 +11,7 @@
 // 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>
@@ -20,8 +21,11 @@
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/base/config.h"
 #include "absl/base/internal/exception_safety_testing.h"
 #include "absl/memory/memory.h"
+// See comment in absl/base/config.h
+#if !defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE)
 
 namespace absl {
 namespace {
@@ -506,3 +510,5 @@ TEST(VariantExceptionSafetyTest, Swap) {
 
 }  // namespace
 }  // namespace absl
+
+#endif  // !defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE)
diff --git a/absl/types/variant_test.cc b/absl/types/variant_test.cc
index 626d5e617eae..f47f3a728dc6 100644
--- a/absl/types/variant_test.cc
+++ b/absl/types/variant_test.cc
@@ -559,9 +559,14 @@ TEST(VariantTest, TestDtor) {
 }
 
 #ifdef ABSL_HAVE_EXCEPTIONS
-
+// See comment in absl/base/config.h
+#if defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE)
+TEST(VariantTest, DISABLED_TestDtorValuelessByException)
+#else
 // Test destruction when in the valueless_by_exception state.
-TEST(VariantTest, TestDtorValuelessByException) {
+TEST(VariantTest, TestDtorValuelessByException)
+#endif
+{
   int counter = 0;
   IncrementInDtor counter_adjuster(&counter);