aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--absl/meta/type_traits.h50
-rw-r--r--absl/meta/type_traits_test.cc59
2 files changed, 70 insertions, 39 deletions
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 <typename... Ts>
struct disjunction : std::false_type {};
template <typename T, typename... Ts>
-struct disjunction<T, Ts...> :
- std::conditional<T::value, T, disjunction<Ts...>>::type {};
+struct disjunction<T, Ts...>
+ : std::conditional<T::value, T, disjunction<Ts...>>::type {};
template <typename T>
struct disjunction<T> : T {};
@@ -315,22 +315,23 @@ using common_type_t = typename std::common_type<T...>::type;
template <typename T>
using underlying_type_t = typename std::underlying_type<T>::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<typename> struct result_of;
-template<typename F, typename... Args>
+template <typename>
+struct result_of;
+template <typename F, typename... Args>
struct result_of<F(Args...)> : std::invoke_result<F, Args...> {};
#else
-template<typename F> using result_of = std::result_of<F>;
+template <typename F>
+using result_of = std::result_of<F>;
#endif
} // namespace type_traits_internal
-template<typename F>
+template <typename F>
using result_of_t = typename type_traits_internal::result_of<F>::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<T>
//
// 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<int> is trivially relocatable on every known STL
+// implementation, but absl::is_trivially_relocatable<std::vector<int>> 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 <class T>
struct is_trivially_relocatable
: std::integral_constant<bool, __is_trivially_relocatable(T)> {};
#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 <class T>
-struct is_trivially_relocatable
- : absl::conjunction<absl::is_trivially_move_constructible<T>,
- absl::is_trivially_destructible<T>> {};
+struct is_trivially_relocatable : std::is_trivially_copyable<T> {};
#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<void() noexcept>::value);
EXPECT_TRUE(absl::is_function<void(...) noexcept>::value);
- EXPECT_FALSE(absl::is_function<void(*)()>::value);
- EXPECT_FALSE(absl::is_function<void(&)()>::value);
+ EXPECT_FALSE(absl::is_function<void (*)()>::value);
+ EXPECT_FALSE(absl::is_function<void (&)()>::value);
EXPECT_FALSE(absl::is_function<int>::value);
EXPECT_FALSE(absl::is_function<Callable>::value);
}
@@ -382,8 +382,8 @@ TEST(TypeTraitsTest, TestRemoveCVRef) {
// Does not remove const in this case.
EXPECT_TRUE((std::is_same<typename absl::remove_cvref<const int*>::type,
const int*>::value));
- EXPECT_TRUE((std::is_same<typename absl::remove_cvref<int[2]>::type,
- int[2]>::value));
+ EXPECT_TRUE(
+ (std::is_same<typename absl::remove_cvref<int[2]>::type, int[2]>::value));
EXPECT_TRUE((std::is_same<typename absl::remove_cvref<int(&)[2]>::type,
int[2]>::value));
EXPECT_TRUE((std::is_same<typename absl::remove_cvref<int(&&)[2]>::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<S>::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<S>::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<S>::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<S>::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