mirror of
https://github.com/abseil/abseil-cpp.git
synced 2026-06-04 12:07:05 +08:00
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
This commit is contained in:
committed by
Copybara-Service
parent
51f6d868c8
commit
c7e60ccfcd
@@ -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_
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user