Skip to content

Commit 3f74c49

Browse files
committed
Address review comments.
1 parent 10d06e7 commit 3f74c49

File tree

7 files changed

+107
-45
lines changed

7 files changed

+107
-45
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4016,6 +4016,50 @@ Note that the `size` argument must be a compile time constant.
40164016
40174017
Note that this intrinsic cannot yet be called in a ``constexpr`` context.
40184018
4019+
``__is_bitwise_cloneable``
4020+
-------------------------
4021+
4022+
A type trait is used to check whether a type can be safely copied by memcpy.
4023+
4024+
**Syntax**:
4025+
4026+
.. code-block:: c++
4027+
4028+
bool __is_bitwise_cloneable(Type)
4029+
4030+
** Example of Use**:
4031+
4032+
.. code-block:: c++
4033+
4034+
// Return a cloned object of the given default instance.
4035+
Foo* Clone(const Foo* default_instance, char* buffer, unsigned size) {
4036+
if constexpr __is_bitwise_cloneable(decltype(*default_instance)) {
4037+
// Fast path via memcopy, without calling class constructor.
4038+
memcpy(buffer, default_instance, size);
4039+
// Explicitly start the lifetime of the cloned object.
4040+
return __builtin_start_object_lifetime(reinterpret_cast<Foo*>(buffer));
4041+
}
4042+
// Fallback the operator new, which invoke the class constructor.
4043+
return new(buffer) Foo(*default_instance);
4044+
}
4045+
4046+
**Description**:
4047+
4048+
It is common for library owners to perform memcpy/memmove on types that aren't
4049+
trivally copyable for performance reason. However, according to the C++ standard,
4050+
it is undefined bheavior to mempcy non-trivially-copyable types, even though
4051+
it may work in pratice. This builtin is designed to bridge that gap.
4052+
4053+
Objects of bitwise cloneable types can be bitwise copied by memcpy/memmove. The
4054+
Clang compiler warrants that this behavior is well defined, and won't be
4055+
broken by compiler optimizations.
4056+
4057+
After the copy, the lifetime of the new object isn't started yet (unless the
4058+
type is trivially copyable). Users must explicitly start its lifetime by the
4059+
`__builtin_start_object_lifetime` mechanism to avoid undefined behavior.
4060+
4061+
This builtin can be used in constant expressions.
4062+
40194063
Atomic Min/Max builtins with memory ordering
40204064
--------------------------------------------
40214065

clang/include/clang/AST/Type.h

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,17 +1120,13 @@ 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.
1123+
/// Return true if the type is safe to bitwise copy by memcpy.
11241124
///
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;
1125+
/// This is an extension in clang: bitwise clonable types act as trivially
1126+
/// copyable types, their underlying bytes can be safely copied by memcpy or
1127+
/// memmove. Clang guarantees that the destination has the same **object**
1128+
/// representations after the copy.
1129+
bool isBitwiseCloneableType(const ASTContext &Context) const;
11341130

11351131
/// Return true if this is a trivially copyable type
11361132
bool isTriviallyCopyConstructibleType(const ASTContext &Context) const;

clang/include/clang/Basic/TokenKinds.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,6 @@ 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)
531530
TYPE_TRAIT_1(__is_trivially_relocatable, IsTriviallyRelocatable, KEYCXX)
532531
TYPE_TRAIT_1(__is_trivially_equality_comparable, IsTriviallyEqualityComparable, KEYCXX)
533532
TYPE_TRAIT_1(__is_bounded_array, IsBoundedArray, KEYCXX)
@@ -540,6 +539,8 @@ TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX)
540539
TYPE_TRAIT_2(__reference_constructs_from_temporary, ReferenceConstructsFromTemporary, KEYCXX)
541540
TYPE_TRAIT_2(__reference_converts_from_temporary, ReferenceConvertsFromTemporary, KEYCXX)
542541

542+
TYPE_TRAIT_1(__is_bitwise_cloneable, IsBitwiseCloneable, KEYALL)
543+
543544
// Embarcadero Expression Traits
544545
EXPRESSION_TRAIT(__is_lvalue_expr, IsLValueExpr, KEYCXX)
545546
EXPRESSION_TRAIT(__is_rvalue_expr, IsRValueExpr, KEYCXX)

clang/lib/AST/Type.cpp

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

2734-
bool QualType::isBitwiseCopyableType(const ASTContext & Context) const {
2734+
bool QualType::isBitwiseCloneableType(const ASTContext & Context) const {
27352735
QualType CanonicalType = getCanonicalType();
27362736
if (CanonicalType->isIncompleteType() || CanonicalType->isDependentType())
27372737
return false;
2738-
// Trivially copyable types are bitwise copyable, e.g. scalar types.
2738+
// Trivially copyable types are bitwise clonable, e.g. scalar types.
27392739
if (CanonicalType.isTriviallyCopyableType(Context))
27402740
return true;
27412741

27422742
if (CanonicalType->isArrayType())
27432743
return Context.getBaseElementType(CanonicalType)
2744-
.isBitwiseCopyableType(Context);
2744+
.isBitwiseCloneableType(Context);
27452745

27462746
if (const auto *RD = CanonicalType->getAsCXXRecordDecl()) {
2747+
for (auto Base : RD->bases())
2748+
if (!Base.getType().isBitwiseCloneableType(Context))
2749+
return false;
2750+
for (auto VBase : RD->vbases())
2751+
if (!VBase.getType().isBitwiseCloneableType(Context))
2752+
return false;
2753+
27472754
for (auto *const Field : RD->fields()) {
27482755
QualType T = Context.getBaseElementType(Field->getType());
2749-
if (!T.isBitwiseCopyableType(Context))
2756+
if (!T.isBitwiseCloneableType(Context))
27502757
return false;
27512758
}
27522759
return true;

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5128,8 +5128,7 @@ 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:
5131+
case UTT_IsBitwiseCloneable:
51335132
// By analogy, is_trivially_relocatable and is_trivially_equality_comparable
51345133
// impose the same constraints.
51355134
case UTT_IsTriviallyRelocatable:
@@ -5615,8 +5614,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
56155614
return C.hasUniqueObjectRepresentations(T);
56165615
case UTT_IsTriviallyRelocatable:
56175616
return T.isTriviallyRelocatableType(C);
5618-
case UTT_IsBitwiseCopyable:
5619-
return T.isBitwiseCopyableType(C);
5617+
case UTT_IsBitwiseCloneable:
5618+
return T.isBitwiseCloneableType(C);
56205619
case UTT_IsReferenceable:
56215620
return T.isReferenceable();
56225621
case UTT_CanPassInRegs:
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
2+
3+
// Scalar types are bitwise clonable.
4+
static_assert(__is_bitwise_cloneable(int));
5+
static_assert(__is_bitwise_cloneable(int*));
6+
// array
7+
static_assert(__is_bitwise_cloneable(int[10]));
8+
9+
// non-scalar types.
10+
static_assert(!__is_bitwise_cloneable(int&));
11+
12+
13+
struct Forward; // expected-note 2{{forward declaration of 'Forward'}}
14+
static_assert(!__is_bitwise_cloneable(Forward)); // expected-error {{incomplete type 'Forward' used in type trait expression}}
15+
16+
struct Foo { int a; };
17+
static_assert(__is_bitwise_cloneable(Foo));
18+
19+
struct DynamicClass { virtual int Foo(); };
20+
static_assert(__is_bitwise_cloneable(DynamicClass));
21+
22+
struct Bar { int& b; }; // trivially copyable
23+
static_assert(__is_trivially_copyable(Bar));
24+
static_assert(__is_bitwise_cloneable(Bar));
25+
26+
struct Bar2 { Bar2(const Bar2&); int& b; }; // non-trivially copyable
27+
static_assert(!__is_trivially_copyable(Bar2));
28+
static_assert(!__is_bitwise_cloneable(Bar2)); // int& non-scalar member.
29+
30+
struct DerivedBar2 : public Bar2 {};
31+
static_assert(!__is_bitwise_cloneable(DerivedBar2)); // base Bar2 is non-bitwise-cloneable.
32+
33+
34+
template <typename T>
35+
void TemplateFunction() {
36+
static_assert(__is_bitwise_cloneable(T)); // expected-error {{incomplete type 'Forward' used in type trait expression}}
37+
}
38+
void CallTemplateFunc() {
39+
TemplateFunction<Forward>(); // expected-note {{in instantiation of function template specialization}}
40+
TemplateFunction<Foo>();
41+
}

clang/test/SemaCXX/builtin-is-bitwise-copyable.cpp

Lines changed: 0 additions & 26 deletions
This file was deleted.

0 commit comments

Comments
 (0)