From df2c771ec596b385448117f237ee70be35efe4ce Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 9 Feb 2024 14:08:46 -0800 Subject: On Apple, implement absl::is_trivially_relocatable with the fallback. The Apple implementation gives false positives starting with Xcode 15. PiperOrigin-RevId: 605726702 Change-Id: I2e5e574eca08071d24e97304f005cf9c78230913 --- absl/meta/type_traits.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'absl/meta/type_traits.h') diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h index cf71164b..a456ae4f 100644 --- a/absl/meta/type_traits.h +++ b/absl/meta/type_traits.h @@ -501,11 +501,19 @@ using swap_internal::StdSwapIsUnconstrained; // // TODO(b/275003464): remove the opt-out once the bug is fixed. // +// Starting with Xcode 15, the Apple compiler will falsely say a type +// with a user-provided move constructor is trivially relocatable +// (b/324278148). We will opt out without a version check, due to +// the fluidity of Apple versions. +// +// TODO(b/324278148): If all versions we use have the bug fixed, then +// remove the condition. +// // According to https://github.com/abseil/abseil-cpp/issues/1479, this does not // work with NVCC either. #if ABSL_HAVE_BUILTIN(__is_trivially_relocatable) && \ !(defined(__clang__) && (defined(_WIN32) || defined(_WIN64))) && \ - !defined(__NVCC__) + !(defined(__APPLE__)) && !defined(__NVCC__) template struct is_trivially_relocatable : std::integral_constant {}; -- cgit v1.2.3 From 14b8a4eac3e5a7b97ba4cc7b7dadf2a85aae8215 Mon Sep 17 00:00:00 2001 From: Arthur O'Dwyer Date: Sat, 17 Feb 2024 09:32:01 -0800 Subject: PR #1625: absl::is_trivially_relocatable now respects assignment operators Imported from GitHub PR https://github.com/abseil/abseil-cpp/pull/1625 Trivial relocatability also requires that the type not do anything weird with its assignment operator; update the type-trait to reflect this. (This is the definition used by BSL, Folly, HPX, Thrust, Parlay, Amadeus, and P1144.) This is important if we want to use `absl::is_trivially_relocatable` as a gate for memcpy optimizations in `inlined_vector::erase` and/or `inlined_vector::swap`, because in those cases relocation is used to replace part of a sequence involving assignment; the optimization requires an assignment operator that behaves value-semantically. Clang's builtin currently fails to check the assignment operator, so we stop using it entirely for now. We already refused to use it on Win32, Win64, and Apple, for various unrelated reasons. I'm working on giving Clang's builtin the behavior that would let us re-enable it here. Assume that any compiler providing both `__cpp_impl_trivially_relocatable` and a builtin `__is_trivially_relocatable(T)` will use the appropriate (P1144) definition for its builtin. Right now there's only one such compiler (the P1144 reference implementation, which forks Clang), so this is largely a moot point, but I'm being optimistic. Merge d943abdbabc1b7080aa5f0a2fff3e724135164dc into 34604d5b1f6ae14c65b3992478b59f7108051979 Merging this change closes #1625 COPYBARA_INTEGRATE_REVIEW=https://github.com/abseil/abseil-cpp/pull/1625 from Quuxplusone:trivially-relocatable d943abdbabc1b7080aa5f0a2fff3e724135164dc PiperOrigin-RevId: 607977323 Change-Id: I6436a60326c6d1064bdd71ec2e15b86b7a29efd4 --- absl/meta/type_traits.h | 50 +++++++++++++++++++++--------------- absl/meta/type_traits_test.cc | 59 ++++++++++++++++++++++++++++++------------- 2 files changed, 70 insertions(+), 39 deletions(-) (limited to 'absl/meta/type_traits.h') diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h index a456ae4f..ed5e6080 100644 --- a/absl/meta/type_traits.h +++ b/absl/meta/type_traits.h @@ -152,8 +152,8 @@ template struct disjunction : std::false_type {}; template -struct disjunction : - std::conditional>::type {}; +struct disjunction + : std::conditional>::type {}; template struct disjunction : T {}; @@ -315,22 +315,23 @@ using common_type_t = typename std::common_type::type; template using underlying_type_t = typename std::underlying_type::type; - namespace type_traits_internal { #if (defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703L) || \ (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) // std::result_of is deprecated (C++17) or removed (C++20) -template struct result_of; -template +template +struct result_of; +template struct result_of : std::invoke_result {}; #else -template using result_of = std::result_of; +template +using result_of = std::result_of; #endif } // namespace type_traits_internal -template +template using result_of_t = typename type_traits_internal::result_of::type; namespace type_traits_internal { @@ -463,20 +464,23 @@ namespace type_traits_internal { // Make the swap-related traits/function accessible from this namespace. using swap_internal::IsNothrowSwappable; using swap_internal::IsSwappable; -using swap_internal::Swap; using swap_internal::StdSwapIsUnconstrained; +using swap_internal::Swap; } // namespace type_traits_internal // absl::is_trivially_relocatable // // Detects whether a type is known to be "trivially relocatable" -- meaning it -// can be relocated without invoking the constructor/destructor, using a form of -// move elision. +// can be relocated from one place to another as if by memcpy/memmove. +// This implies that its object representation doesn't depend on its address, +// and also none of its special member functions do anything strange. // -// This trait is conservative, for backwards compatibility. If it's true then -// the type is definitely trivially relocatable, but if it's false then the type -// may or may not be. +// This trait is conservative. If it's true then the type is definitely +// trivially relocatable, but if it's false then the type may or may not be. For +// example, std::vector is trivially relocatable on every known STL +// implementation, but absl::is_trivially_relocatable> remains +// false. // // Example: // @@ -509,22 +513,26 @@ using swap_internal::StdSwapIsUnconstrained; // TODO(b/324278148): If all versions we use have the bug fixed, then // remove the condition. // +// Clang on all platforms fails to detect that a type with a user-provided +// move-assignment operator is not trivially relocatable. So in fact we +// opt out of Clang altogether, for now. +// +// TODO(b/325479096): Remove the opt-out once Clang's behavior is fixed. +// // According to https://github.com/abseil/abseil-cpp/issues/1479, this does not // work with NVCC either. -#if ABSL_HAVE_BUILTIN(__is_trivially_relocatable) && \ - !(defined(__clang__) && (defined(_WIN32) || defined(_WIN64))) && \ - !(defined(__APPLE__)) && !defined(__NVCC__) +#if ABSL_HAVE_BUILTIN(__is_trivially_relocatable) && \ + (defined(__cpp_impl_trivially_relocatable) || \ + (!defined(__clang__) && !defined(__APPLE__) && !defined(__NVCC__))) template struct is_trivially_relocatable : std::integral_constant {}; #else // Otherwise we use a fallback that detects only those types we can feasibly -// detect. Any time that has trivial move-construction and destruction -// operations is by definition trivially relocatable. +// detect. Any type that is trivially copyable is by definition trivially +// relocatable. template -struct is_trivially_relocatable - : absl::conjunction, - absl::is_trivially_destructible> {}; +struct is_trivially_relocatable : std::is_trivially_copyable {}; #endif // absl::is_constant_evaluated() diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc index 8f926901..25f5abbc 100644 --- a/absl/meta/type_traits_test.cc +++ b/absl/meta/type_traits_test.cc @@ -362,8 +362,8 @@ TEST(TypeTraitsTest, TestIsFunction) { EXPECT_TRUE(absl::is_function::value); EXPECT_TRUE(absl::is_function::value); - EXPECT_FALSE(absl::is_function::value); - EXPECT_FALSE(absl::is_function::value); + EXPECT_FALSE(absl::is_function::value); + EXPECT_FALSE(absl::is_function::value); EXPECT_FALSE(absl::is_function::value); EXPECT_FALSE(absl::is_function::value); } @@ -382,8 +382,8 @@ TEST(TypeTraitsTest, TestRemoveCVRef) { // Does not remove const in this case. EXPECT_TRUE((std::is_same::type, const int*>::value)); - EXPECT_TRUE((std::is_same::type, - int[2]>::value)); + EXPECT_TRUE( + (std::is_same::type, int[2]>::value)); EXPECT_TRUE((std::is_same::type, int[2]>::value)); EXPECT_TRUE((std::is_same::type, @@ -580,7 +580,7 @@ TEST(TypeTraitsTest, TestDecay) { ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int[][1]); ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int()); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int(float)); // NOLINT + ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int(float)); // NOLINT ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int(char, ...)); // NOLINT } @@ -664,8 +664,7 @@ TEST(TypeTraitsTest, TestResultOf) { namespace adl_namespace { -struct DeletedSwap { -}; +struct DeletedSwap {}; void swap(DeletedSwap&, DeletedSwap&) = delete; @@ -751,7 +750,7 @@ TEST(TriviallyRelocatable, PrimitiveTypes) { // User-defined types can be trivially relocatable as long as they don't have a // user-provided move constructor or destructor. -TEST(TriviallyRelocatable, UserDefinedTriviallyReconstructible) { +TEST(TriviallyRelocatable, UserDefinedTriviallyRelocatable) { struct S { int x; int y; @@ -780,6 +779,30 @@ TEST(TriviallyRelocatable, UserProvidedCopyConstructor) { static_assert(!absl::is_trivially_relocatable::value, ""); } +// A user-provided copy assignment operator disqualifies a type from +// being trivially relocatable. +TEST(TriviallyRelocatable, UserProvidedCopyAssignment) { + struct S { + S(const S&) = default; + S& operator=(const S&) { // NOLINT(modernize-use-equals-default) + return *this; + } + }; + + static_assert(!absl::is_trivially_relocatable::value, ""); +} + +// A user-provided move assignment operator disqualifies a type from +// being trivially relocatable. +TEST(TriviallyRelocatable, UserProvidedMoveAssignment) { + struct S { + S(S&&) = default; + S& operator=(S&&) { return *this; } // NOLINT(modernize-use-equals-default) + }; + + static_assert(!absl::is_trivially_relocatable::value, ""); +} + // A user-provided destructor disqualifies a type from being trivially // relocatable. TEST(TriviallyRelocatable, UserProvidedDestructor) { @@ -794,18 +817,19 @@ TEST(TriviallyRelocatable, UserProvidedDestructor) { // __is_trivially_relocatable is used there again. // TODO(b/324278148): remove the opt-out for Apple once // __is_trivially_relocatable is fixed there. -#if defined(ABSL_HAVE_ATTRIBUTE_TRIVIAL_ABI) && \ - ABSL_HAVE_BUILTIN(__is_trivially_relocatable) && \ - !(defined(__clang__) && (defined(_WIN32) || defined(_WIN64))) && \ - !defined(__APPLE__) +#if defined(ABSL_HAVE_ATTRIBUTE_TRIVIAL_ABI) && \ + ABSL_HAVE_BUILTIN(__is_trivially_relocatable) && \ + (defined(__cpp_impl_trivially_relocatable) || \ + (!defined(__clang__) && !defined(__APPLE__) && !defined(__NVCC__))) // A type marked with the "trivial ABI" attribute is trivially relocatable even -// if it has user-provided move/copy constructors and a user-provided -// destructor. -TEST(TrivallyRelocatable, TrivialAbi) { +// if it has user-provided special members. +TEST(TriviallyRelocatable, TrivialAbi) { struct ABSL_ATTRIBUTE_TRIVIAL_ABI S { S(S&&) {} // NOLINT(modernize-use-equals-default) S(const S&) {} // NOLINT(modernize-use-equals-default) - ~S() {} // NOLINT(modernize-use-equals-default) + void operator=(S&&) {} + void operator=(const S&) {} + ~S() {} // NOLINT(modernize-use-equals-default) }; static_assert(absl::is_trivially_relocatable::value, ""); @@ -824,7 +848,7 @@ constexpr int64_t NegateIfConstantEvaluated(int64_t i) { #endif // ABSL_HAVE_CONSTANT_EVALUATED -TEST(TrivallyRelocatable, is_constant_evaluated) { +TEST(IsConstantEvaluated, is_constant_evaluated) { #ifdef ABSL_HAVE_CONSTANT_EVALUATED constexpr int64_t constant = NegateIfConstantEvaluated(42); EXPECT_EQ(constant, -42); @@ -840,5 +864,4 @@ TEST(TrivallyRelocatable, is_constant_evaluated) { #endif // ABSL_HAVE_CONSTANT_EVALUATED } - } // namespace -- cgit v1.2.3 From 42133464db0ae5383fef723067835ef768b849f8 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Tue, 19 Mar 2024 19:22:00 -0700 Subject: Remove absl::aligned_storage_t Consistent with std::aligned_storage_t, it is deprecated in C++23. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1413r3.pdf has a suggested replacement PiperOrigin-RevId: 617367005 Change-Id: I009533c5609c8ffd77e406e1fc88e51a3ce99f9f --- absl/meta/type_traits.h | 21 ------------- absl/meta/type_traits_test.cc | 70 ------------------------------------------- 2 files changed, 91 deletions(-) (limited to 'absl/meta/type_traits.h') diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h index ed5e6080..a15059de 100644 --- a/absl/meta/type_traits.h +++ b/absl/meta/type_traits.h @@ -279,27 +279,6 @@ using remove_extent_t = typename std::remove_extent::type; template using remove_all_extents_t = typename std::remove_all_extents::type; -ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING -namespace type_traits_internal { -// This trick to retrieve a default alignment is necessary for our -// implementation of aligned_storage_t to be consistent with any -// implementation of std::aligned_storage. -template > -struct default_alignment_of_aligned_storage; - -template -struct default_alignment_of_aligned_storage< - Len, std::aligned_storage> { - static constexpr size_t value = Align; -}; -} // namespace type_traits_internal - -// TODO(b/260219225): std::aligned_storage(_t) is deprecated in C++23. -template ::value> -using aligned_storage_t = typename std::aligned_storage::type; -ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING - template using decay_t = typename std::decay::type; diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc index 25f5abbc..6080beef 100644 --- a/absl/meta/type_traits_test.cc +++ b/absl/meta/type_traits_test.cc @@ -489,76 +489,6 @@ TEST(TypeTraitsTest, TestExtentAliases) { ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[][1]); } -TEST(TypeTraitsTest, TestAlignedStorageAlias) { - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 1); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 2); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 3); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 4); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 5); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 6); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 7); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 8); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 9); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 10); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 11); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 12); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 13); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 14); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 15); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 16); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 17); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 18); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 19); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 20); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 21); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 22); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 23); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 24); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 25); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 26); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 27); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 28); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 29); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 30); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 31); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 32); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 33); - - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 1, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 2, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 3, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 4, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 5, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 6, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 7, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 8, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 9, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 10, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 11, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 12, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 13, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 14, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 15, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 16, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 17, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 18, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 19, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 20, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 21, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 22, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 23, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 24, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 25, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 26, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 27, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 28, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 29, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 30, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 31, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 32, 128); - ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 33, 128); -} - TEST(TypeTraitsTest, TestDecay) { ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int); ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const int); -- cgit v1.2.3 From 8a31d4a8dd3d9e81eedae2d3be679423a84f33c9 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 1 Apr 2024 09:27:16 -0700 Subject: Add internal traits for lifetimebound detection This will helps compilers that understand `ABSL_ATTRIBUTE_LIFETIME_BOUND` flag constructs such as `absl::StatusOr str = std::string(...)` as error-prone. For standard types, this is done via specializing the type traits. For all other types, this is done by detecting the presence of a Boolean member trait such as: `using absl_internal_is_view = std::true_type;` in the type. This is purely intended as a safety feature, and the values of these traits (even if wrong!) must NOT be depended on for correct behavior. Furthermore, only high-value types (such as `absl::StatusOr`) are the intended users here. Do not declare or use these traits on arbitrary types that are unlikely to be misused. Do not depend on any of these to be stable, as they not (yet) public APIs. Moreover, the trait declarations and mechanisms are all subject to change. (For example, if `[[clang::lifetimebound]]` becomes possible to detect directly, the traits may need to be altered to utilize that, and distinguish between assignments and constructions.) Should these or similar APIs be made public at a later point, the detection mechanisms may be altered quickly, and may (either loudly or silently) break existing code depending on these internal APIs without notice. PiperOrigin-RevId: 620868493 Change-Id: I4a528a1dcf0df6ffbc3641d09537bc4c674aee4e --- absl/meta/type_traits.h | 101 ++++++++++++++++++++++++++++++++++++++++++ absl/meta/type_traits_test.cc | 22 +++++++++ 2 files changed, 123 insertions(+) (limited to 'absl/meta/type_traits.h') diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h index a15059de..ded55820 100644 --- a/absl/meta/type_traits.h +++ b/absl/meta/type_traits.h @@ -37,11 +37,21 @@ #include #include +#include #include +#include #include "absl/base/attributes.h" #include "absl/base/config.h" +#ifdef __cpp_lib_span +#include // NOLINT(build/c++20) +#endif + +#ifdef ABSL_HAVE_STD_STRING_VIEW +#include +#endif + // Defines the default alignment. `__STDCPP_DEFAULT_NEW_ALIGNMENT__` is a C++17 // feature. #if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) @@ -553,6 +563,97 @@ constexpr bool is_constant_evaluated() noexcept { #endif } #endif // ABSL_HAVE_CONSTANT_EVALUATED + +namespace type_traits_internal { + +// Detects if a class's definition has declared itself to be an owner by +// declaring +// using absl_internal_is_view = std::true_type; +// as a member. +// Types that don't want either must either omit this declaration entirely, or +// (if e.g. inheriting from a base class) define the member to something that +// isn't a Boolean trait class, such as `void`. +// Do not specialize or use this directly. It's an implementation detail. +template +struct IsOwnerImpl : std::false_type { + static_assert(std::is_same>::value, + "type must lack qualifiers"); +}; + +template +struct IsOwnerImpl< + T, + std::enable_if_t::value>> + : absl::negation {}; + +// A trait to determine whether a type is an owner. +// Do *not* depend on the correctness of this trait for correct code behavior. +// It is only a safety feature and its value may change in the future. +// Do not specialize this; instead, define the member trait inside your type so +// that it can be auto-detected, and to prevent ODR violations. +// If it ever becomes possible to detect [[gsl::Owner]], we should leverage it: +// https://wg21.link/p1179 +template +struct IsOwner : IsOwnerImpl {}; + +template +struct IsOwner> : std::true_type {}; + +template +struct IsOwner> : std::true_type {}; + +// Detects if a class's definition has declared itself to be a view by declaring +// using absl_internal_is_view = std::true_type; +// as a member. +// Do not specialize or use this directly. +template +struct IsViewImpl : std::false_type { + static_assert(std::is_same>::value, + "type must lack qualifiers"); +}; + +template +struct IsViewImpl< + T, + std::enable_if_t::value>> + : T::absl_internal_is_view {}; + +// A trait to determine whether a type is a view. +// Do *not* depend on the correctness of this trait for correct code behavior. +// It is only a safety feature, and its value may change in the future. +// Do not specialize this trait. Instead, define the member +// using absl_internal_is_view = std::true_type; +// in your class to allow its detection while preventing ODR violations. +// If it ever becomes possible to detect [[gsl::Pointer]], we should leverage +// it: https://wg21.link/p1179 +template +struct IsView : std::integral_constant::value || + IsViewImpl::value> {}; + +#ifdef ABSL_HAVE_STD_STRING_VIEW +template +struct IsView> : std::true_type {}; +#endif + +#ifdef __cpp_lib_span +template +struct IsView> : std::true_type {}; +#endif + +// Determines whether the assignment of the given types is lifetime-bound. +// Do *not* depend on the correctness of this trait for correct code behavior. +// It is only a safety feature and its value may change in the future. +// If it ever becomes possible to detect [[clang::lifetimebound]] directly, +// we should change the implementation to leverage that. +// Until then, we consider an assignment from an "owner" (such as std::string) +// to a "view" (such as std::string_view) to be a lifetime-bound assignment. +template +using IsLifetimeBoundAssignment = + std::integral_constant>::value && + IsOwner>::value>; + +} // namespace type_traits_internal + ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc index 6080beef..1e056bb2 100644 --- a/absl/meta/type_traits_test.cc +++ b/absl/meta/type_traits_test.cc @@ -26,10 +26,32 @@ #include "absl/time/clock.h" #include "absl/time/time.h" +#ifdef ABSL_HAVE_STD_STRING_VIEW +#include +#endif + namespace { using ::testing::StaticAssertTypeEq; +template +using IsOwnerAndNotView = + absl::conjunction, + absl::negation>>; + +static_assert(IsOwnerAndNotView>::value, + "vector is an owner, not a view"); +static_assert(IsOwnerAndNotView::value, + "string is an owner, not a view"); +static_assert(IsOwnerAndNotView::value, + "wstring is an owner, not a view"); +#ifdef ABSL_HAVE_STD_STRING_VIEW +static_assert(!IsOwnerAndNotView::value, + "string_view is a view, not an owner"); +static_assert(!IsOwnerAndNotView::value, + "wstring_view is a view, not an owner"); +#endif + template struct simple_pair { T first; -- cgit v1.2.3 From d5e426097680beafbf72d6c88f50a680736ec770 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 2 Apr 2024 23:41:16 -0700 Subject: Temporarily revert dangling std::string_view detection until dependent is fixed PiperOrigin-RevId: 621413395 Change-Id: I20e9fac94e81e59c0d723f115670c8cf68e9b44a --- absl/meta/type_traits.h | 5 ----- absl/meta/type_traits_test.cc | 6 ------ absl/strings/string_view.h | 1 - absl/strings/string_view_test.cc | 8 -------- 4 files changed, 20 deletions(-) (limited to 'absl/meta/type_traits.h') diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h index ded55820..a1be47f1 100644 --- a/absl/meta/type_traits.h +++ b/absl/meta/type_traits.h @@ -630,11 +630,6 @@ template struct IsView : std::integral_constant::value || IsViewImpl::value> {}; -#ifdef ABSL_HAVE_STD_STRING_VIEW -template -struct IsView> : std::true_type {}; -#endif - #ifdef __cpp_lib_span template struct IsView> : std::true_type {}; diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc index 1e056bb2..e4107e53 100644 --- a/absl/meta/type_traits_test.cc +++ b/absl/meta/type_traits_test.cc @@ -45,12 +45,6 @@ static_assert(IsOwnerAndNotView::value, "string is an owner, not a view"); static_assert(IsOwnerAndNotView::value, "wstring is an owner, not a view"); -#ifdef ABSL_HAVE_STD_STRING_VIEW -static_assert(!IsOwnerAndNotView::value, - "string_view is a view, not an owner"); -static_assert(!IsOwnerAndNotView::value, - "wstring_view is a view, not an owner"); -#endif template struct simple_pair { diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h index b1fb7a10..b393c6fc 100644 --- a/absl/strings/string_view.h +++ b/absl/strings/string_view.h @@ -173,7 +173,6 @@ class string_view { using reverse_iterator = const_reverse_iterator; using size_type = size_t; using difference_type = std::ptrdiff_t; - using absl_internal_is_view = std::true_type; static constexpr size_type npos = static_cast(-1); diff --git a/absl/strings/string_view_test.cc b/absl/strings/string_view_test.cc index e978fc3f..1c73943e 100644 --- a/absl/strings/string_view_test.cc +++ b/absl/strings/string_view_test.cc @@ -47,14 +47,6 @@ namespace { -static_assert(!absl::type_traits_internal::IsOwner::value && - absl::type_traits_internal::IsView::value, - "string_view is a view, not an owner"); - -static_assert(absl::type_traits_internal::IsLifetimeBoundAssignment< - absl::string_view, std::string>::value, - "lifetimebound assignment not detected"); - // A minimal allocator that uses malloc(). template struct Mallocator { -- cgit v1.2.3 From 8f9e5f0203c8a708c71f4498bf59355d1d7bbf87 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 9 Apr 2024 09:42:18 -0700 Subject: Restore string_view detection check PiperOrigin-RevId: 623195368 Change-Id: Iadb9bdedee4d9b5ced4fff9e6316ee63f9a89ea5 --- absl/meta/type_traits.h | 5 +++++ absl/meta/type_traits_test.cc | 6 ++++++ absl/strings/string_view.h | 1 + absl/strings/string_view_test.cc | 8 ++++++++ 4 files changed, 20 insertions(+) (limited to 'absl/meta/type_traits.h') diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h index a1be47f1..ded55820 100644 --- a/absl/meta/type_traits.h +++ b/absl/meta/type_traits.h @@ -630,6 +630,11 @@ template struct IsView : std::integral_constant::value || IsViewImpl::value> {}; +#ifdef ABSL_HAVE_STD_STRING_VIEW +template +struct IsView> : std::true_type {}; +#endif + #ifdef __cpp_lib_span template struct IsView> : std::true_type {}; diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc index e4107e53..1e056bb2 100644 --- a/absl/meta/type_traits_test.cc +++ b/absl/meta/type_traits_test.cc @@ -45,6 +45,12 @@ static_assert(IsOwnerAndNotView::value, "string is an owner, not a view"); static_assert(IsOwnerAndNotView::value, "wstring is an owner, not a view"); +#ifdef ABSL_HAVE_STD_STRING_VIEW +static_assert(!IsOwnerAndNotView::value, + "string_view is a view, not an owner"); +static_assert(!IsOwnerAndNotView::value, + "wstring_view is a view, not an owner"); +#endif template struct simple_pair { diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h index b393c6fc..b1fb7a10 100644 --- a/absl/strings/string_view.h +++ b/absl/strings/string_view.h @@ -173,6 +173,7 @@ class string_view { using reverse_iterator = const_reverse_iterator; using size_type = size_t; using difference_type = std::ptrdiff_t; + using absl_internal_is_view = std::true_type; static constexpr size_type npos = static_cast(-1); diff --git a/absl/strings/string_view_test.cc b/absl/strings/string_view_test.cc index 1c73943e..e978fc3f 100644 --- a/absl/strings/string_view_test.cc +++ b/absl/strings/string_view_test.cc @@ -47,6 +47,14 @@ namespace { +static_assert(!absl::type_traits_internal::IsOwner::value && + absl::type_traits_internal::IsView::value, + "string_view is a view, not an owner"); + +static_assert(absl::type_traits_internal::IsLifetimeBoundAssignment< + absl::string_view, std::string>::value, + "lifetimebound assignment not detected"); + // A minimal allocator that uses malloc(). template struct Mallocator { -- cgit v1.2.3