From 2901ec32a919311384d6ad4194e2d927c06831f7 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 7 Feb 2019 14:13:06 -0800 Subject: Export of internal Abseil changes. -- 5da9755667df37e38ccaf6938c9f408e294110bb by Shaindel Schwartz : Import of CCTZ from GitHub. PiperOrigin-RevId: 232942734 -- b6fb275769c66fdd2bd92b119198c59e9a7dd737 by Samuel Benzaquen : Fix integral underflow when from-arg width is INT_MIN. PiperOrigin-RevId: 232888037 -- 4135dbba4a26c4642277fc2a7e2a833d593daa1c by Abseil Team : Add the insert_return_type alias to raw_hash_set. PiperOrigin-RevId: 232683892 -- 0b120b7d3693800bbb886f6fc607ae54a9338cb1 by Abseil Team : Macros to detect and disabled SafeStack https://clang.llvm.org/docs/SafeStack.html PiperOrigin-RevId: 232680114 -- a77b3fb533a9e37966d1d6ef5ccd09c73fff2ca1 by Abseil Team : Avoid potential red zone clobber Pushing on the stack on x86-64 may clobber local variables held below %rsp in the red zone. Avoid this by using lea on x86-64. PiperOrigin-RevId: 232592478 -- bf326a0eefa92f4e704287563df0c5a5b1873b6d by Eric Fiselier : Add additional tests for AbslHashValue. PiperOrigin-RevId: 232344325 -- 816e4f98fd7632c944c779db87b7dac4e138afcf by Eric Fiselier : Avoid upcoming GCC 9.0 warnings about base class init. Currently, in trunk, GCC has a new warning under -Wextra that diagnoses when a derived class fails to explicitly initialize the base class in a constructor initializer list. This patch avoids this warning. PiperOrigin-RevId: 232327626 -- 779c0f44b3c2b7a04d4bdf978641eb8180515bf6 by Eric Fiselier : Guard against C++2a char8_t change. PiperOrigin-RevId: 232326178 -- 41e5395b85bbbfb5bf418cc21b04ad4ccb15a284 by Eric Fiselier : Avoid Clang Warning PiperOrigin-RevId: 232138866 GitOrigin-RevId: 5da9755667df37e38ccaf6938c9f408e294110bb Change-Id: I49ee4f58db177b81b039d7d949f671c97c5a7933 --- absl/base/attributes.h | 11 ++ absl/container/BUILD.bazel | 2 +- absl/container/fixed_array_test.cc | 17 +++ absl/container/inlined_vector_test.cc | 19 ++++ absl/container/internal/common.h | 136 +++++++++++++++++++++++- absl/container/internal/hashtablez_sampler.cc | 2 +- absl/container/internal/hashtablez_sampler.h | 12 +-- absl/container/internal/raw_hash_set.h | 136 ++---------------------- absl/container/internal/raw_hash_set_test.cc | 2 +- absl/debugging/symbolize_test.cc | 12 ++- absl/numeric/int128_test.cc | 25 +++++ absl/strings/internal/str_format/bind.cc | 3 +- absl/strings/internal/str_format/bind_test.cc | 15 +++ absl/strings/internal/utf8_test.cc | 9 ++ absl/strings/str_split_test.cc | 9 ++ absl/time/internal/cctz/src/zone_info_source.cc | 2 +- absl/types/optional.h | 5 +- absl/types/span_test.cc | 15 +++ 18 files changed, 287 insertions(+), 145 deletions(-) diff --git a/absl/base/attributes.h b/absl/base/attributes.h index 291ad89..fa44012 100644 --- a/absl/base/attributes.h +++ b/absl/base/attributes.h @@ -287,6 +287,17 @@ #define ABSL_ATTRIBUTE_NO_SANITIZE_CFI #endif +// ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK +// +// Tells the SafeStack to not instrument a given function. +// See https://clang.llvm.org/docs/SafeStack.html for details. +#if defined(__GNUC__) && defined(SAFESTACK_SANITIZER) +#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK \ + __attribute__((no_sanitize("safe-stack"))) +#else +#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK +#endif + // ABSL_ATTRIBUTE_RETURNS_NONNULL // // Tells the compiler that a particular function never returns a null pointer. diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel index acdbc47..f3b3a2c 100644 --- a/absl/container/BUILD.bazel +++ b/absl/container/BUILD.bazel @@ -542,6 +542,7 @@ cc_library( copts = ABSL_DEFAULT_COPTS, deps = [ "//absl/meta:type_traits", + "//absl/types:optional", ], ) @@ -565,7 +566,6 @@ cc_library( "//absl/base:endian", "//absl/memory", "//absl/meta:type_traits", - "//absl/types:optional", "//absl/utility", ], ) diff --git a/absl/container/fixed_array_test.cc b/absl/container/fixed_array_test.cc index 205ff41..1679ba4 100644 --- a/absl/container/fixed_array_test.cc +++ b/absl/container/fixed_array_test.cc @@ -869,4 +869,21 @@ TEST(FixedArrayTest, AddressSanitizerAnnotations4) { } #endif // ADDRESS_SANITIZER +TEST(FixedArrayTest, AbslHashValueWorks) { + using V = absl::FixedArray; + std::vector cases; + + // Generate a variety of vectors some of these are small enough for the inline + // space but are stored out of line. + for (int i = 0; i < 10; ++i) { + V v(i); + for (int j = 0; j < i; ++j) { + v[j] = j; + } + cases.push_back(v); + } + + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(cases)); +} + } // namespace diff --git a/absl/container/inlined_vector_test.cc b/absl/container/inlined_vector_test.cc index 9408ee9..5b1527e 100644 --- a/absl/container/inlined_vector_test.cc +++ b/absl/container/inlined_vector_test.cc @@ -1762,4 +1762,23 @@ TEST(AllocatorSupportTest, SizeAllocConstructor) { } } +TEST(InlinedVectorTest, AbslHashValueWorks) { + using V = absl::InlinedVector; + std::vector cases; + + // Generate a variety of vectors some of these are small enough for the inline + // space but are stored out of line. + for (int i = 0; i < 10; ++i) { + V v; + for (int j = 0; j < i; ++j) { + v.push_back(j); + } + cases.push_back(v); + v.resize(i % 4); + cases.push_back(v); + } + + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(cases)); +} + } // anonymous namespace diff --git a/absl/container/internal/common.h b/absl/container/internal/common.h index a6dc910..c781656 100644 --- a/absl/container/internal/common.h +++ b/absl/container/internal/common.h @@ -18,6 +18,7 @@ #include #include "absl/meta/type_traits.h" +#include "absl/types/optional.h" namespace absl { namespace container_internal { @@ -42,7 +43,140 @@ struct KeyArg { using type = key_type; }; +// The node_handle concept from C++17. +// We specialize node_handle for sets and maps. node_handle_base holds the +// common API of both. +template +class node_handle_base { + protected: + using slot_type = typename PolicyTraits::slot_type; + + public: + using allocator_type = Alloc; + + constexpr node_handle_base() {} + node_handle_base(node_handle_base&& other) noexcept { + *this = std::move(other); + } + ~node_handle_base() { destroy(); } + node_handle_base& operator=(node_handle_base&& other) noexcept { + destroy(); + if (!other.empty()) { + alloc_ = other.alloc_; + PolicyTraits::transfer(alloc(), slot(), other.slot()); + other.reset(); + } + return *this; + } + + bool empty() const noexcept { return !alloc_; } + explicit operator bool() const noexcept { return !empty(); } + allocator_type get_allocator() const { return *alloc_; } + + protected: + friend struct CommonAccess; + + node_handle_base(const allocator_type& a, slot_type* s) : alloc_(a) { + PolicyTraits::transfer(alloc(), slot(), s); + } + + void destroy() { + if (!empty()) { + PolicyTraits::destroy(alloc(), slot()); + reset(); + } + } + + void reset() { + assert(alloc_.has_value()); + alloc_ = absl::nullopt; + } + + slot_type* slot() const { + assert(!empty()); + return reinterpret_cast(std::addressof(slot_space_)); + } + allocator_type* alloc() { return std::addressof(*alloc_); } + + private: + absl::optional alloc_; + mutable absl::aligned_storage_t + slot_space_; +}; + +// For sets. +template +class node_handle : public node_handle_base { + using Base = typename node_handle::node_handle_base; + + public: + using value_type = typename PolicyTraits::value_type; + + constexpr node_handle() {} + + value_type& value() const { return PolicyTraits::element(this->slot()); } + + private: + friend struct CommonAccess; + + node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {} +}; + +// For maps. +template +class node_handle> + : public node_handle_base { + using Base = typename node_handle::node_handle_base; + + public: + using key_type = typename Policy::key_type; + using mapped_type = typename Policy::mapped_type; + + constexpr node_handle() {} + + auto key() const -> decltype(PolicyTraits::key(this->slot())) { + return PolicyTraits::key(this->slot()); + } + + mapped_type& mapped() const { + return PolicyTraits::value(&PolicyTraits::element(this->slot())); + } + + private: + friend struct CommonAccess; + + node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {} +}; + +// Provide access to non-public node-handle functions. +struct CommonAccess { + template + static auto GetSlot(const Node& node) -> decltype(node.slot()) { + return node.slot(); + } + + template + static void Reset(Node* node) { + node->reset(); + } + + template + static T Make(Args&&... args) { + return T(std::forward(args)...); + } +}; + +// Implement the insert_return_type<> concept of C++17. +template +struct InsertReturnType { + Iterator position; + bool inserted; + NodeType node; +}; + } // namespace container_internal -} // namespace absl +} // namespace absl #endif // ABSL_CONTAINER_INTERNAL_CONTAINER_H_ diff --git a/absl/container/internal/hashtablez_sampler.cc b/absl/container/internal/hashtablez_sampler.cc index 99cd834..dc66924 100644 --- a/absl/container/internal/hashtablez_sampler.cc +++ b/absl/container/internal/hashtablez_sampler.cc @@ -254,7 +254,7 @@ HashtablezInfo* SampleSlow(int64_t* next_sample) { } #if ABSL_PER_THREAD_TLS == 1 -ABSL_PER_THREAD_TLS_KEYWORD int64_t next_sample = 0; +ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample = 0; #endif // ABSL_PER_THREAD_TLS == 1 void UnsampleSlow(HashtablezInfo* info) { diff --git a/absl/container/internal/hashtablez_sampler.h b/absl/container/internal/hashtablez_sampler.h index 126a0ad..8b81653 100644 --- a/absl/container/internal/hashtablez_sampler.h +++ b/absl/container/internal/hashtablez_sampler.h @@ -146,23 +146,23 @@ class HashtablezInfoHandle { HashtablezInfo* info_; }; -// Returns an RAII sampling handle that manages registration and unregistation -// with the global sampler. #if ABSL_PER_THREAD_TLS == 1 -extern ABSL_PER_THREAD_TLS_KEYWORD int64_t next_sample; +extern ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample; #endif // ABSL_PER_THREAD_TLS +// Returns an RAII sampling handle that manages registration and unregistation +// with the global sampler. inline HashtablezInfoHandle Sample() { #if ABSL_PER_THREAD_TLS == 0 static auto* mu = new absl::Mutex; - static int64_t next_sample = 0; + static int64_t global_next_sample = 0; absl::MutexLock l(mu); #endif // !ABSL_HAVE_THREAD_LOCAL - if (ABSL_PREDICT_TRUE(--next_sample > 0)) { + if (ABSL_PREDICT_TRUE(--global_next_sample > 0)) { return HashtablezInfoHandle(nullptr); } - return HashtablezInfoHandle(SampleSlow(&next_sample)); + return HashtablezInfoHandle(SampleSlow(&global_next_sample)); } // Holds samples and their associated stack traces with a soft limit of diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 8e3fa02..a5d0cae 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -115,7 +115,6 @@ #include "absl/container/internal/layout.h" #include "absl/memory/memory.h" #include "absl/meta/type_traits.h" -#include "absl/types/optional.h" #include "absl/utility/utility.h" namespace absl { @@ -502,126 +501,6 @@ inline size_t GrowthToLowerboundCapacity(size_t growth) { return growth + static_cast((static_cast(growth) - 1) / 7); } -// The node_handle concept from C++17. -// We specialize node_handle for sets and maps. node_handle_base holds the -// common API of both. -template -class node_handle_base { - protected: - using PolicyTraits = hash_policy_traits; - using slot_type = typename PolicyTraits::slot_type; - - public: - using allocator_type = Alloc; - - constexpr node_handle_base() {} - node_handle_base(node_handle_base&& other) noexcept { - *this = std::move(other); - } - ~node_handle_base() { destroy(); } - node_handle_base& operator=(node_handle_base&& other) { - destroy(); - if (!other.empty()) { - alloc_ = other.alloc_; - PolicyTraits::transfer(alloc(), slot(), other.slot()); - other.reset(); - } - return *this; - } - - bool empty() const noexcept { return !alloc_; } - explicit operator bool() const noexcept { return !empty(); } - allocator_type get_allocator() const { return *alloc_; } - - protected: - template - friend class raw_hash_set; - - node_handle_base(const allocator_type& a, slot_type* s) : alloc_(a) { - PolicyTraits::transfer(alloc(), slot(), s); - } - - void destroy() { - if (!empty()) { - PolicyTraits::destroy(alloc(), slot()); - reset(); - } - } - - void reset() { - assert(alloc_.has_value()); - alloc_ = absl::nullopt; - } - - slot_type* slot() const { - assert(!empty()); - return reinterpret_cast(std::addressof(slot_space_)); - } - allocator_type* alloc() { return std::addressof(*alloc_); } - - private: - absl::optional alloc_; - mutable absl::aligned_storage_t - slot_space_; -}; - -// For sets. -template -class node_handle : public node_handle_base { - using Base = typename node_handle::node_handle_base; - - public: - using value_type = typename Base::PolicyTraits::value_type; - - constexpr node_handle() {} - - value_type& value() const { - return Base::PolicyTraits::element(this->slot()); - } - - private: - template - friend class raw_hash_set; - - node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {} -}; - -// For maps. -template -class node_handle> - : public node_handle_base { - using Base = typename node_handle::node_handle_base; - - public: - using key_type = typename Policy::key_type; - using mapped_type = typename Policy::mapped_type; - - constexpr node_handle() {} - - auto key() const -> decltype(Base::PolicyTraits::key(this->slot())) { - return Base::PolicyTraits::key(this->slot()); - } - - mapped_type& mapped() const { - return Base::PolicyTraits::value( - &Base::PolicyTraits::element(this->slot())); - } - - private: - template - friend class raw_hash_set; - - node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {} -}; - -// Implement the insert_return_type<> concept of C++17. -template -struct insert_return_type { - Iterator position; - bool inserted; - NodeType node; -}; - // Policy: a policy defines how to perform different operations on // the slots of the hashtable (see hash_policy_traits.h for the full interface // of policy). @@ -828,7 +707,8 @@ class raw_hash_set { iterator inner_; }; - using node_type = container_internal::node_handle; + using node_type = node_handle, Alloc>; + using insert_return_type = InsertReturnType; raw_hash_set() noexcept( std::is_nothrow_default_constructible::value&& @@ -1136,13 +1016,14 @@ class raw_hash_set { insert(ilist.begin(), ilist.end()); } - insert_return_type insert(node_type&& node) { + insert_return_type insert(node_type&& node) { if (!node) return {end(), false, node_type()}; - const auto& elem = PolicyTraits::element(node.slot()); + const auto& elem = PolicyTraits::element(CommonAccess::GetSlot(node)); auto res = PolicyTraits::apply( - InsertSlot{*this, std::move(*node.slot())}, elem); + InsertSlot{*this, std::move(*CommonAccess::GetSlot(node))}, + elem); if (res.second) { - node.reset(); + CommonAccess::Reset(&node); return {res.first, true, node_type()}; } else { return {res.first, false, std::move(node)}; @@ -1306,7 +1187,8 @@ class raw_hash_set { } node_type extract(const_iterator position) { - node_type node(alloc_ref(), position.inner_.slot_); + auto node = + CommonAccess::Make(alloc_ref(), position.inner_.slot_); erase_meta_only(position); return node; } diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc index d9f1826..7adcc96 100644 --- a/absl/container/internal/raw_hash_set_test.cc +++ b/absl/container/internal/raw_hash_set_test.cc @@ -1706,7 +1706,7 @@ TEST(Nodes, ExtractInsert) { EXPECT_FALSE(node.empty()); StringTable t2; - auto res = t2.insert(std::move(node)); + StringTable::insert_return_type res = t2.insert(std::move(node)); EXPECT_TRUE(res.inserted); EXPECT_THAT(*res.position, Pair(k0, "")); EXPECT_FALSE(res.node); diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc index 8029fbe..dcb5269 100644 --- a/absl/debugging/symbolize_test.cc +++ b/absl/debugging/symbolize_test.cc @@ -392,16 +392,20 @@ TEST(Symbolize, ForEachSection) { extern "C" { inline void *ABSL_ATTRIBUTE_ALWAYS_INLINE inline_func() { void *pc = nullptr; -#if defined(__i386__) || defined(__x86_64__) - __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc)); +#if defined(__i386__) + __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [ PC ] "=r"(pc)); +#elif defined(__x86_64__) + __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [ PC ] "=r"(pc)); #endif return pc; } void *ABSL_ATTRIBUTE_NOINLINE non_inline_func() { void *pc = nullptr; -#if defined(__i386__) || defined(__x86_64__) - __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc)); +#if defined(__i386__) + __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [ PC ] "=r"(pc)); +#elif defined(__x86_64__) + __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [ PC ] "=r"(pc)); #endif return pc; } diff --git a/absl/numeric/int128_test.cc b/absl/numeric/int128_test.cc index 81c868d..4a6eb45 100644 --- a/absl/numeric/int128_test.cc +++ b/absl/numeric/int128_test.cc @@ -440,4 +440,29 @@ TEST(Uint128, NumericLimitsTest) { EXPECT_EQ(absl::Uint128Max(), std::numeric_limits::max()); } +TEST(Uint128, Hash) { + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({ + // Some simple values + absl::uint128{0}, + absl::uint128{1}, + ~absl::uint128{}, + // 64 bit limits + absl::uint128{std::numeric_limits::max()}, + absl::uint128{std::numeric_limits::max()} + 0, + absl::uint128{std::numeric_limits::max()} + 1, + absl::uint128{std::numeric_limits::max()} + 2, + // Keeping high same + absl::uint128{1} << 62, + absl::uint128{1} << 63, + // Keeping low same + absl::uint128{1} << 64, + absl::uint128{1} << 65, + // 128 bit limits + std::numeric_limits::max(), + std::numeric_limits::max() - 1, + std::numeric_limits::min() + 1, + std::numeric_limits::min(), + })); +} + } // namespace diff --git a/absl/strings/internal/str_format/bind.cc b/absl/strings/internal/str_format/bind.cc index 758adb7..a89295d 100644 --- a/absl/strings/internal/str_format/bind.cc +++ b/absl/strings/internal/str_format/bind.cc @@ -53,7 +53,8 @@ inline bool ArgContext::Bind(const UnboundConversion* unbound, // "A negative field width is taken as a '-' flag followed by a // positive field width." force_left = true; - width = -width; + // Make sure we don't overflow the width when negating it. + width = -std::max(width, -std::numeric_limits::max()); } } diff --git a/absl/strings/internal/str_format/bind_test.cc b/absl/strings/internal/str_format/bind_test.cc index 4757573..ba6470e 100644 --- a/absl/strings/internal/str_format/bind_test.cc +++ b/absl/strings/internal/str_format/bind_test.cc @@ -1,6 +1,7 @@ #include "absl/strings/internal/str_format/bind.h" #include +#include #include "gtest/gtest.h" @@ -91,6 +92,20 @@ TEST_F(FormatBindTest, BindSingle) { } } +TEST_F(FormatBindTest, WidthUnderflowRegression) { + UnboundConversion props; + BoundConversion bound; + int next = 0; + const int args_i[] = {std::numeric_limits::min(), 17}; + const FormatArgImpl args[] = {FormatArgImpl(args_i[0]), + FormatArgImpl(args_i[1])}; + ASSERT_TRUE(Extract("*d", &props, &next)); + ASSERT_TRUE(BindWithPack(&props, args, &bound)); + + EXPECT_EQ(bound.width(), std::numeric_limits::max()); + EXPECT_EQ(bound.arg(), args + 1); +} + TEST_F(FormatBindTest, FormatPack) { struct Expectation { int line; diff --git a/absl/strings/internal/utf8_test.cc b/absl/strings/internal/utf8_test.cc index 64cec70..07a000c 100644 --- a/absl/strings/internal/utf8_test.cc +++ b/absl/strings/internal/utf8_test.cc @@ -22,6 +22,11 @@ namespace { +#if !defined(__cpp_char8_t) +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++2a-compat" +#endif TEST(EncodeUTF8Char, BasicFunction) { std::pair tests[] = {{0x0030, u8"\u0030"}, {0x00A3, u8"\u00A3"}, @@ -53,5 +58,9 @@ TEST(EncodeUTF8Char, BasicFunction) { EXPECT_LE(absl::strings_internal::EncodeUTF8Char(buf2, -1), absl::strings_internal::kMaxEncodedUTF8Size); } +#if defined(__clang__) +#pragma clang diagnostic pop +#endif +#endif // !defined(__cpp_char8_t) } // namespace diff --git a/absl/strings/str_split_test.cc b/absl/strings/str_split_test.cc index caa8827..a008558 100644 --- a/absl/strings/str_split_test.cc +++ b/absl/strings/str_split_test.cc @@ -647,6 +647,11 @@ TEST(Split, StringDelimiter) { } } +#if !defined(__cpp_char8_t) +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++2a-compat" +#endif TEST(Split, UTF8) { // Tests splitting utf8 strings and utf8 delimiters. std::string utf8_string = u8"\u03BA\u1F79\u03C3\u03BC\u03B5"; @@ -673,6 +678,10 @@ TEST(Split, UTF8) { EXPECT_THAT(v, ElementsAre("Foo", u8"h\u00E4llo", u8"th\u4E1Ere")); } } +#if defined(__clang__) +#pragma clang diagnostic pop +#endif +#endif // !defined(__cpp_char8_t) TEST(Split, EmptyStringDelimiter) { { diff --git a/absl/time/internal/cctz/src/zone_info_source.cc b/absl/time/internal/cctz/src/zone_info_source.cc index bf2d2d2..1bc16ae 100644 --- a/absl/time/internal/cctz/src/zone_info_source.cc +++ b/absl/time/internal/cctz/src/zone_info_source.cc @@ -54,7 +54,7 @@ ZoneInfoSourceFactory default_factory = DefaultFactory; #pragma comment( \ linker, \ "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZA=?default_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZA") -#elif defined(_M_IA_64) || defined(_M_AMD64) +#elif defined(_M_IA_64) || defined(_M_AMD64) || defined(_M_ARM64) #pragma comment( \ linker, \ "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA=?default_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA") diff --git a/absl/types/optional.h b/absl/types/optional.h index fd185f3..d800ca6 100644 --- a/absl/types/optional.h +++ b/absl/types/optional.h @@ -295,7 +295,7 @@ class optional_data : public optional_data_base { optional_data() = default; - optional_data(const optional_data& rhs) { + optional_data(const optional_data& rhs) : optional_data_base() { if (rhs.engaged_) { this->construct(rhs.data_); } @@ -303,7 +303,8 @@ class optional_data : public optional_data_base { optional_data(optional_data&& rhs) noexcept( absl::default_allocator_is_nothrow::value || - std::is_nothrow_move_constructible::value) { + std::is_nothrow_move_constructible::value) + : optional_data_base() { if (rhs.engaged_) { this->construct(std::move(rhs.data_)); } diff --git a/absl/types/span_test.cc b/absl/types/span_test.cc index bd739ff..f4203b5 100644 --- a/absl/types/span_test.cc +++ b/absl/types/span_test.cc @@ -779,4 +779,19 @@ TEST(Span, SpanSize) { EXPECT_LE(sizeof(absl::Span), 2 * sizeof(void*)); } +TEST(Span, Hash) { + int array[] = {1, 2, 3, 4}; + int array2[] = {1, 2, 3}; + using T = absl::Span; + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( + {// Empties + T(), T(nullptr, 0), T(array, 0), T(array2, 0), + // Different array with same value + T(array, 3), T(array2), T({1, 2, 3}), + // Same array, but different length + T(array, 1), T(array, 2), + // Same length, but different array + T(array + 1, 2), T(array + 2, 2)})); +} + } // namespace -- cgit v1.2.3