Skip to content

Commit 10d06e7

Browse files
committed
[clang] Implement a bitwise_copyable builtin type trait.
This patch implements a `__is_bitwise_copyable` builtin in clang. The bitwise copyable types act as the trivially copyable types, but they support a wider range of types (e.g. classes with virtual methods) -- their underlying types can be safely copied by `memcopy` or `memmove`, the clang compiler guarantees that both source and destination objects have the same *object* representations after the copy operation, and the lifetime of the destination object implicitly starts. A particular use case of this builtin is to clone an object via memcopy (without running the constructor): ``` Message* clone(const Message* src, char* buffer, int size) { if constexpr __is_bitwise_copyable(Message) { // bitwise copy to buffer, and implicitly create objects at the buffer __builtin_memcpy(buffer, src, size); return std::launder(reinterpret_cast<Message*>(buffer)); } // Fallback the operator new, which calls the constructor to start the lifetime. return new(buffer) Message(src); } ``` Note that the definition of bitwise copyable is not tied to the Rule Of Five, so users of this builtin must guarantee that program semantic constraints are satisfied, e.g. no double resource deallocations. Context: https://discourse.llvm.org/t/extension-for-creating-objects-via-memcpy
1 parent 6479e3c commit 10d06e7

File tree

5 files changed

+66
-0
lines changed

5 files changed

+66
-0
lines changed

clang/include/clang/AST/Type.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,6 +1120,18 @@ class QualType {
11201120
/// Return true if this is a trivially copyable type (C++0x [basic.types]p9)
11211121
bool isTriviallyCopyableType(const ASTContext &Context) const;
11221122

1123+
/// Return true if this is a bitwise copyable type.
1124+
///
1125+
/// This is an extension in clang: bitwise copyable types act as trivially
1126+
/// copyable types, underlying bytes of bitwise copyable type can be safely
1127+
/// copied by memcpy or memmove. Clang guarantees that both source and
1128+
/// destination objects have the same **object** representations after the
1129+
/// copy, and the lifetime of the destination object implicitly starts.
1130+
///
1131+
/// bitwise copyable types cover a wider range of types, e.g. classes with
1132+
/// virtual methods.
1133+
bool isBitwiseCopyableType(const ASTContext &Context) const;
1134+
11231135
/// Return true if this is a trivially copyable type
11241136
bool isTriviallyCopyConstructibleType(const ASTContext &Context) const;
11251137

clang/include/clang/Basic/TokenKinds.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,7 @@ TYPE_TRAIT_2(__is_pointer_interconvertible_base_of, IsPointerInterconvertibleBas
527527
#include "clang/Basic/TransformTypeTraits.def"
528528

529529
// Clang-only C++ Type Traits
530+
TYPE_TRAIT_1(__is_bitwise_copyable, IsBitwiseCopyable, KEYCXX)
530531
TYPE_TRAIT_1(__is_trivially_relocatable, IsTriviallyRelocatable, KEYCXX)
531532
TYPE_TRAIT_1(__is_trivially_equality_comparable, IsTriviallyEqualityComparable, KEYCXX)
532533
TYPE_TRAIT_1(__is_bounded_array, IsBoundedArray, KEYCXX)

clang/lib/AST/Type.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2731,6 +2731,29 @@ bool QualType::isTriviallyCopyableType(const ASTContext &Context) const {
27312731
/*IsCopyConstructible=*/false);
27322732
}
27332733

2734+
bool QualType::isBitwiseCopyableType(const ASTContext & Context) const {
2735+
QualType CanonicalType = getCanonicalType();
2736+
if (CanonicalType->isIncompleteType() || CanonicalType->isDependentType())
2737+
return false;
2738+
// Trivially copyable types are bitwise copyable, e.g. scalar types.
2739+
if (CanonicalType.isTriviallyCopyableType(Context))
2740+
return true;
2741+
2742+
if (CanonicalType->isArrayType())
2743+
return Context.getBaseElementType(CanonicalType)
2744+
.isBitwiseCopyableType(Context);
2745+
2746+
if (const auto *RD = CanonicalType->getAsCXXRecordDecl()) {
2747+
for (auto *const Field : RD->fields()) {
2748+
QualType T = Context.getBaseElementType(Field->getType());
2749+
if (!T.isBitwiseCopyableType(Context))
2750+
return false;
2751+
}
2752+
return true;
2753+
}
2754+
return false;
2755+
}
2756+
27342757
bool QualType::isTriviallyCopyConstructibleType(
27352758
const ASTContext &Context) const {
27362759
return isTriviallyCopyableTypeImpl(*this, Context,

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5128,6 +5128,8 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
51285128
case UTT_IsStandardLayout:
51295129
case UTT_IsPOD:
51305130
case UTT_IsLiteral:
5131+
// Clang extension:
5132+
case UTT_IsBitwiseCopyable:
51315133
// By analogy, is_trivially_relocatable and is_trivially_equality_comparable
51325134
// impose the same constraints.
51335135
case UTT_IsTriviallyRelocatable:
@@ -5613,6 +5615,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
56135615
return C.hasUniqueObjectRepresentations(T);
56145616
case UTT_IsTriviallyRelocatable:
56155617
return T.isTriviallyRelocatableType(C);
5618+
case UTT_IsBitwiseCopyable:
5619+
return T.isBitwiseCopyableType(C);
56165620
case UTT_IsReferenceable:
56175621
return T.isReferenceable();
56185622
case UTT_CanPassInRegs:
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
2+
3+
// Scalar types are bitwise copyable.
4+
static_assert(__is_bitwise_copyable(int));
5+
static_assert(__is_bitwise_copyable(int*));
6+
// array
7+
static_assert(__is_bitwise_copyable(int[10]));
8+
9+
10+
struct Forward; // expected-note 2{{forward declaration of 'Forward'}}
11+
static_assert(!__is_bitwise_copyable(Forward)); // expected-error {{incomplete type 'Forward' used in type trait expression}}
12+
13+
struct Foo { int a; };
14+
static_assert(__is_bitwise_copyable(Foo));
15+
16+
struct DynamicClass { virtual int Foo(); };
17+
static_assert(__is_bitwise_copyable(DynamicClass));
18+
19+
template <typename T>
20+
void TemplateFunction() {
21+
static_assert(__is_bitwise_copyable(T)); // expected-error {{incomplete type 'Forward' used in type trait expression}}
22+
}
23+
void CallTemplateFunc() {
24+
TemplateFunction<Forward>(); // expected-note {{in instantiation of function template specialization}}
25+
TemplateFunction<Foo>();
26+
}

0 commit comments

Comments
 (0)