summaryrefslogtreecommitdiff
path: root/absl/meta
diff options
context:
space:
mode:
Diffstat (limited to 'absl/meta')
-rw-r--r--absl/meta/BUILD.bazel17
-rw-r--r--absl/meta/type_traits.h65
-rw-r--r--absl/meta/type_traits_test.cc43
3 files changed, 93 insertions, 32 deletions
diff --git a/absl/meta/BUILD.bazel b/absl/meta/BUILD.bazel
index e004b509..c06d2d97 100644
--- a/absl/meta/BUILD.bazel
+++ b/absl/meta/BUILD.bazel
@@ -1,3 +1,20 @@
+#
+# Copyright 2019 The Abseil Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load(
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h
index ae7130dd..ba87d2f0 100644
--- a/absl/meta/type_traits.h
+++ b/absl/meta/type_traits.h
@@ -41,8 +41,18 @@
#include "absl/base/config.h"
+// MSVC constructibility traits do not detect destructor properties and so our
+// implementations should not use them as a source-of-truth.
+#if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__)
+#define ABSL_META_INTERNAL_STD_CONSTRUCTION_TRAITS_DONT_CHECK_DESTRUCTION 1
+#endif
+
namespace absl {
-inline namespace lts_2019_08_08 {
+ABSL_NAMESPACE_BEGIN
+
+// Defined and documented later on in this file.
+template <typename T>
+struct is_trivially_destructible;
// Defined and documented later on in this file.
template <typename T>
@@ -67,6 +77,20 @@ union SingleMemberUnion {
#endif // defined(_MSC_VER) && !defined(__GNUC__)
template <class T>
+struct IsTriviallyMoveConstructibleObject
+ : std::integral_constant<
+ bool, std::is_move_constructible<
+ type_traits_internal::SingleMemberUnion<T>>::value &&
+ absl::is_trivially_destructible<T>::value> {};
+
+template <class T>
+struct IsTriviallyCopyConstructibleObject
+ : std::integral_constant<
+ bool, std::is_copy_constructible<
+ type_traits_internal::SingleMemberUnion<T>>::value &&
+ absl::is_trivially_destructible<T>::value> {};
+
+template <class T>
struct IsTriviallyMoveAssignableReference : std::false_type {};
template <class T>
@@ -146,6 +170,18 @@ using IsMoveAssignableImpl = decltype(std::declval<T&>() = std::declval<T&&>());
} // namespace type_traits_internal
+// MSVC 19.20 has a regression that causes our workarounds to fail, but their
+// std forms now appear to be compliant.
+#if defined(_MSC_VER) && !defined(__clang__) && (_MSC_VER >= 1920)
+
+template <typename T>
+using is_copy_assignable = std::is_copy_assignable<T>;
+
+template <typename T>
+using is_move_assignable = std::is_move_assignable<T>;
+
+#else
+
template <typename T>
struct is_copy_assignable : type_traits_internal::is_detected<
type_traits_internal::IsCopyAssignableImpl, T> {
@@ -156,6 +192,8 @@ struct is_move_assignable : type_traits_internal::is_detected<
type_traits_internal::IsMoveAssignableImpl, T> {
};
+#endif
+
// void_t()
//
// Ignores the type of any its arguments and returns `void`. In general, this
@@ -244,7 +282,7 @@ struct is_function
// is_trivially_destructible()
//
-// Determines whether the passed type `T` is trivially destructable.
+// Determines whether the passed type `T` is trivially destructible.
//
// This metafunction is designed to be a drop-in replacement for the C++11
// `std::is_trivially_destructible()` metafunction for platforms that have
@@ -310,7 +348,9 @@ struct is_trivially_default_constructible
: std::integral_constant<bool, __has_trivial_constructor(T) &&
std::is_default_constructible<T>::value &&
is_trivially_destructible<T>::value> {
-#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE) && \
+ !defined( \
+ ABSL_META_INTERNAL_STD_CONSTRUCTION_TRAITS_DONT_CHECK_DESTRUCTION)
private:
static constexpr bool compliant =
std::is_trivially_default_constructible<T>::value ==
@@ -341,10 +381,11 @@ template <typename T>
struct is_trivially_move_constructible
: std::conditional<
std::is_object<T>::value && !std::is_array<T>::value,
- std::is_move_constructible<
- type_traits_internal::SingleMemberUnion<T>>,
+ type_traits_internal::IsTriviallyMoveConstructibleObject<T>,
std::is_reference<T>>::type::type {
-#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE) && \
+ !defined( \
+ ABSL_META_INTERNAL_STD_CONSTRUCTION_TRAITS_DONT_CHECK_DESTRUCTION)
private:
static constexpr bool compliant =
std::is_trivially_move_constructible<T>::value ==
@@ -375,10 +416,11 @@ template <typename T>
struct is_trivially_copy_constructible
: std::conditional<
std::is_object<T>::value && !std::is_array<T>::value,
- std::is_copy_constructible<
- type_traits_internal::SingleMemberUnion<T>>,
+ type_traits_internal::IsTriviallyCopyConstructibleObject<T>,
std::is_lvalue_reference<T>>::type::type {
-#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE) && \
+ !defined( \
+ ABSL_META_INTERNAL_STD_CONSTRUCTION_TRAITS_DONT_CHECK_DESTRUCTION)
private:
static constexpr bool compliant =
std::is_trivially_copy_constructible<T>::value ==
@@ -410,7 +452,8 @@ struct is_trivially_copy_constructible
template <typename T>
struct is_trivially_move_assignable
: std::conditional<
- std::is_object<T>::value && !std::is_array<T>::value,
+ std::is_object<T>::value && !std::is_array<T>::value &&
+ std::is_move_assignable<T>::value,
std::is_move_assignable<type_traits_internal::SingleMemberUnion<T>>,
type_traits_internal::IsTriviallyMoveAssignableReference<T>>::type::
type {
@@ -710,7 +753,7 @@ using swap_internal::Swap;
using swap_internal::StdSwapIsUnconstrained;
} // namespace type_traits_internal
-} // inline namespace lts_2019_08_08
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_META_TYPE_TRAITS_H_
diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc
index a7a9c5c9..1aafd0d4 100644
--- a/absl/meta/type_traits_test.cc
+++ b/absl/meta/type_traits_test.cc
@@ -347,21 +347,6 @@ class Base {
virtual ~Base() {}
};
-// In GCC/Clang, std::is_trivially_constructible requires that the destructor is
-// trivial. However, MSVC doesn't require that. This results in different
-// behavior when checking is_trivially_constructible on any type with
-// nontrivial destructor. Since absl::is_trivially_default_constructible and
-// absl::is_trivially_copy_constructible both follows Clang/GCC's interpretation
-// and check is_trivially_destructible, it results in inconsistency with
-// std::is_trivially_xxx_constructible on MSVC. This macro is used to work
-// around this issue in test. In practice, a trivially constructible type
-// should also be trivially destructible.
-// GCC bug 51452: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452
-// LWG issue 2116: http://cplusplus.github.io/LWG/lwg-active.html#2116
-#ifndef _MSC_VER
-#define ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE 1
-#endif
-
// Old versions of libc++, around Clang 3.5 to 3.6, consider deleted destructors
// as also being trivial. With the resolution of CWG 1928 and CWG 1734, this
// is no longer considered true and has thus been amended.
@@ -499,11 +484,9 @@ TEST(TypeTraitsTest, TestTrivialDefaultCtor) {
EXPECT_FALSE(
absl::is_trivially_default_constructible<DeletedDefaultCtor>::value);
-#ifdef ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE
// types with nontrivial destructor are nontrivial
EXPECT_FALSE(
absl::is_trivially_default_constructible<NontrivialDestructor>::value);
-#endif
// types with vtables
EXPECT_FALSE(absl::is_trivially_default_constructible<Base>::value);
@@ -546,6 +529,28 @@ TEST(TypeTraitsTest, TestTrivialDefaultCtor) {
#endif
}
+// GCC prior to 7.4 had a bug in its trivially-constructible traits
+// (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80654).
+// This test makes sure that we do not depend on the trait in these cases when
+// implementing absl triviality traits.
+
+template <class T>
+struct BadConstructors {
+ BadConstructors() { static_assert(T::value, ""); }
+
+ BadConstructors(BadConstructors&&) { static_assert(T::value, ""); }
+
+ BadConstructors(const BadConstructors&) { static_assert(T::value, ""); }
+};
+
+TEST(TypeTraitsTest, TestTrivialityBadConstructors) {
+ using BadType = BadConstructors<int>;
+
+ EXPECT_FALSE(absl::is_trivially_default_constructible<BadType>::value);
+ EXPECT_FALSE(absl::is_trivially_move_constructible<BadType>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_constructible<BadType>::value);
+}
+
TEST(TypeTraitsTest, TestTrivialMoveCtor) {
// Verify that arithmetic types and pointers have trivial move
// constructors.
@@ -585,11 +590,9 @@ TEST(TypeTraitsTest, TestTrivialMoveCtor) {
EXPECT_FALSE(
absl::is_trivially_move_constructible<NonCopyableOrMovable>::value);
-#ifdef ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE
// type with nontrivial destructor are nontrivial move construbtible
EXPECT_FALSE(
absl::is_trivially_move_constructible<NontrivialDestructor>::value);
-#endif
// types with vtables
EXPECT_FALSE(absl::is_trivially_move_constructible<Base>::value);
@@ -660,11 +663,9 @@ TEST(TypeTraitsTest, TestTrivialCopyCtor) {
EXPECT_FALSE(
absl::is_trivially_copy_constructible<NonCopyableOrMovable>::value);
-#ifdef ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE
// type with nontrivial destructor are nontrivial copy construbtible
EXPECT_FALSE(
absl::is_trivially_copy_constructible<NontrivialDestructor>::value);
-#endif
// types with vtables
EXPECT_FALSE(absl::is_trivially_copy_constructible<Base>::value);