diff options
author | Evan Brown <ezb@google.com> | 2022-07-27 13:45:19 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2022-07-27 13:46:14 -0700 |
commit | c7e60ccfcd708a73008ed2df040162c66697bc18 (patch) | |
tree | 904eb83861d0174d48ee11b5637c8919be623d40 /absl/base | |
parent | 51f6d868c8463ac13492d504cbc034e91b43a461 (diff) |
Add ABSL_IS_TRIVIALLY_RELOCATABLE and ABSL_ATTRIBUTE_TRIVIAL_ABI macros for use with clang's __is_trivially_relocatable and [[clang::trivial_abi]].
PiperOrigin-RevId: 463668740
Change-Id: I2d2d2f53d8184a7e4f7c848c2a5f5140c2481d72
Diffstat (limited to 'absl/base')
-rw-r--r-- | absl/base/attributes.h | 37 | ||||
-rw-r--r-- | absl/base/optimization.h | 24 | ||||
-rw-r--r-- | absl/base/optimization_test.cc | 19 |
3 files changed, 80 insertions, 0 deletions
diff --git a/absl/base/attributes.h b/absl/base/attributes.h index e4e7a3d8..e11a064a 100644 --- a/absl/base/attributes.h +++ b/absl/base/attributes.h @@ -759,4 +759,41 @@ #define ABSL_ATTRIBUTE_LIFETIME_BOUND #endif +// ABSL_ATTRIBUTE_TRIVIAL_ABI +// Indicates that a type is "trivially relocatable" -- meaning it can be +// relocated without invoking the constructor/destructor, using a form of move +// elision. +// +// From a memory safety point of view, putting aside destructor ordering, it's +// safe to apply ABSL_ATTRIBUTE_TRIVIAL_ABI if an object's location +// can change over the course of its lifetime: if a constructor can be run one +// place, and then the object magically teleports to another place where some +// methods are run, and then the object teleports to yet another place where it +// is destroyed. This is notably not true for self-referential types, where the +// move-constructor must keep the self-reference up to date. If the type changed +// location without invoking the move constructor, it would have a dangling +// self-reference. +// +// The use of this teleporting machinery means that the number of paired +// move/destroy operations can change, and so it is a bad idea to apply this to +// a type meant to count the number of moves. +// +// Warning: applying this can, rarely, break callers. Objects passed by value +// will be destroyed at the end of the call, instead of the end of the +// full-expression containing the call. In addition, it changes the ABI +// of functions accepting this type by value (e.g. to pass in registers). +// +// See also the upstream documentation: +// https://clang.llvm.org/docs/AttributeReference.html#trivial-abi +// +#if ABSL_HAVE_CPP_ATTRIBUTE(clang::trivial_abi) +#define ABSL_ATTRIBUTE_TRIVIAL_ABI [[clang::trivial_abi]] +#define ABSL_HAVE_ATTRIBUTE_TRIVIAL_ABI 1 +#elif ABSL_HAVE_ATTRIBUTE(trivial_abi) +#define ABSL_ATTRIBUTE_TRIVIAL_ABI __attribute__((trivial_abi)) +#define ABSL_HAVE_ATTRIBUTE_TRIVIAL_ABI 1 +#else +#define ABSL_ATTRIBUTE_TRIVIAL_ABI +#endif + #endif // ABSL_BASE_ATTRIBUTES_H_ diff --git a/absl/base/optimization.h b/absl/base/optimization.h index db5cc097..57999a18 100644 --- a/absl/base/optimization.h +++ b/absl/base/optimization.h @@ -249,4 +249,28 @@ #define ABSL_INTERNAL_UNIQUE_SMALL_NAME() #endif +// ABSL_IS_TRIVIALLY_RELOCATABLE(type) +// Detects whether a type is "trivially relocatable" -- meaning it can be +// relocated without invoking the constructor/destructor, using a form of move +// elision. +// +// Example: +// +// if constexpr (ABSL_IS_TRIVIALLY_RELOCATABLE(T)) { +// memcpy(new_location, old_location, sizeof(T)); +// } else { +// new(new_location) T(std::move(*old_location)); +// old_location->~T(); +// } +// +// Upstream documentation: +// +// https://clang.llvm.org/docs/LanguageExtensions.html#:~:text=__is_trivially_relocatable +// +#if ABSL_HAVE_BUILTIN(__is_trivially_relocatable) +#define ABSL_IS_TRIVIALLY_RELOCATABLE(type) __is_trivially_relocatable(type) +#else +#define ABSL_IS_TRIVIALLY_RELOCATABLE(type) false +#endif + #endif // ABSL_BASE_OPTIMIZATION_H_ diff --git a/absl/base/optimization_test.cc b/absl/base/optimization_test.cc index e83369f3..5f7a8f4c 100644 --- a/absl/base/optimization_test.cc +++ b/absl/base/optimization_test.cc @@ -15,6 +15,7 @@ #include "absl/base/optimization.h" #include "gtest/gtest.h" +#include "absl/base/attributes.h" #include "absl/types/optional.h" namespace { @@ -126,4 +127,22 @@ TEST(PredictTest, ExplicitBoolConversion) { if (ABSL_PREDICT_FALSE(is_false)) ADD_FAILURE(); } +TEST(TrivallyRelocatable, Sanity) { +#if !defined(ABSL_HAVE_ATTRIBUTE_TRIVIAL_ABI) || \ + !ABSL_HAVE_BUILTIN(__is_trivially_relocatable) + GTEST_SKIP() << "No trivial ABI support."; +#endif + + struct Trivial {}; + struct NonTrivial { + NonTrivial(const NonTrivial&) {} + }; + struct ABSL_ATTRIBUTE_TRIVIAL_ABI TrivialAbi { + TrivialAbi(const TrivialAbi&) {} + }; + EXPECT_TRUE(ABSL_IS_TRIVIALLY_RELOCATABLE(Trivial)); + EXPECT_FALSE(ABSL_IS_TRIVIALLY_RELOCATABLE(NonTrivial)); + EXPECT_TRUE(ABSL_IS_TRIVIALLY_RELOCATABLE(TrivialAbi)); +} + } // namespace |