Skip to content

Commit f64fe43

Browse files
committed
Address review comments.
1 parent 10d4b9e commit f64fe43

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
@@ -3958,6 +3958,50 @@ Note that the `size` argument must be a compile time constant.
39583958
39593959
Note that this intrinsic cannot yet be called in a ``constexpr`` context.
39603960
3961+
``__is_bitwise_cloneable``
3962+
-------------------------
3963+
3964+
A type trait is used to check whether a type can be safely copied by memcpy.
3965+
3966+
**Syntax**:
3967+
3968+
.. code-block:: c++
3969+
3970+
bool __is_bitwise_cloneable(Type)
3971+
3972+
** Example of Use**:
3973+
3974+
.. code-block:: c++
3975+
3976+
// Return a cloned object of the given default instance.
3977+
Foo* Clone(const Foo* default_instance, char* buffer, unsigned size) {
3978+
if constexpr __is_bitwise_cloneable(decltype(*default_instance)) {
3979+
// Fast path via memcopy, without calling class constructor.
3980+
memcpy(buffer, default_instance, size);
3981+
// Explicitly start the lifetime of the cloned object.
3982+
return __builtin_start_object_lifetime(reinterpret_cast<Foo*>(buffer));
3983+
}
3984+
// Fallback the operator new, which invoke the class constructor.
3985+
return new(buffer) Foo(*default_instance);
3986+
}
3987+
3988+
**Description**:
3989+
3990+
It is common for library owners to perform memcpy/memmove on types that aren't
3991+
trivally copyable for performance reason. However, according to the C++ standard,
3992+
it is undefined bheavior to mempcy non-trivially-copyable types, even though
3993+
it may work in pratice. This builtin is designed to bridge that gap.
3994+
3995+
Objects of bitwise cloneable types can be bitwise copied by memcpy/memmove. The
3996+
Clang compiler warrants that this behavior is well defined, and won't be
3997+
broken by compiler optimizations.
3998+
3999+
After the copy, the lifetime of the new object isn't started yet (unless the
4000+
type is trivially copyable). Users must explicitly start its lifetime by the
4001+
`__builtin_start_object_lifetime` mechanism to avoid undefined behavior.
4002+
4003+
This builtin can be used in constant expressions.
4004+
39614005
Atomic Min/Max builtins with memory ordering
39624006
--------------------------------------------
39634007

clang/include/clang/AST/Type.h

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -918,17 +918,13 @@ class QualType {
918918
/// Return true if this is a trivially copyable type (C++0x [basic.types]p9)
919919
bool isTriviallyCopyableType(const ASTContext &Context) const;
920920

921-
/// Return true if this is a bitwise copyable type.
921+
/// Return true if the type is safe to bitwise copy by memcpy.
922922
///
923-
/// This is an extension in clang: bitwise copyable types act as trivially
924-
/// copyable types, underlying bytes of bitwise copyable type can be safely
925-
/// copied by memcpy or memmove. Clang guarantees that both source and
926-
/// destination objects have the same **object** representations after the
927-
/// copy, and the lifetime of the destination object implicitly starts.
928-
///
929-
/// bitwise copyable types cover a wider range of types, e.g. classes with
930-
/// virtual methods.
931-
bool isBitwiseCopyableType(const ASTContext &Context) const;
923+
/// This is an extension in clang: bitwise clonable types act as trivially
924+
/// copyable types, their underlying bytes can be safely copied by memcpy or
925+
/// memmove. Clang guarantees that the destination has the same **object**
926+
/// representations after the copy.
927+
bool isBitwiseCloneableType(const ASTContext &Context) const;
932928

933929
/// Return true if this is a trivially copyable type
934930
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)
@@ -539,6 +538,8 @@ TYPE_TRAIT_1(__can_pass_in_regs, CanPassInRegs, KEYCXX)
539538
TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX)
540539
TYPE_TRAIT_2(__reference_constructs_from_temporary, ReferenceConstructsFromTemporary, KEYCXX)
541540

541+
TYPE_TRAIT_1(__is_bitwise_cloneable, IsBitwiseCloneable, KEYALL)
542+
542543
// Embarcadero Expression Traits
543544
EXPRESSION_TRAIT(__is_lvalue_expr, IsLValueExpr, KEYCXX)
544545
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
@@ -2718,22 +2718,29 @@ bool QualType::isTriviallyCopyableType(const ASTContext &Context) const {
27182718
/*IsCopyConstructible=*/false);
27192719
}
27202720

2721-
bool QualType::isBitwiseCopyableType(const ASTContext & Context) const {
2721+
bool QualType::isBitwiseCloneableType(const ASTContext & Context) const {
27222722
QualType CanonicalType = getCanonicalType();
27232723
if (CanonicalType->isIncompleteType() || CanonicalType->isDependentType())
27242724
return false;
2725-
// Trivially copyable types are bitwise copyable, e.g. scalar types.
2725+
// Trivially copyable types are bitwise clonable, e.g. scalar types.
27262726
if (CanonicalType.isTriviallyCopyableType(Context))
27272727
return true;
27282728

27292729
if (CanonicalType->isArrayType())
27302730
return Context.getBaseElementType(CanonicalType)
2731-
.isBitwiseCopyableType(Context);
2731+
.isBitwiseCloneableType(Context);
27322732

27332733
if (const auto *RD = CanonicalType->getAsCXXRecordDecl()) {
2734+
for (auto Base : RD->bases())
2735+
if (!Base.getType().isBitwiseCloneableType(Context))
2736+
return false;
2737+
for (auto VBase : RD->vbases())
2738+
if (!VBase.getType().isBitwiseCloneableType(Context))
2739+
return false;
2740+
27342741
for (auto *const Field : RD->fields()) {
27352742
QualType T = Context.getBaseElementType(Field->getType());
2736-
if (!T.isBitwiseCopyableType(Context))
2743+
if (!T.isBitwiseCloneableType(Context))
27372744
return false;
27382745
}
27392746
return true;

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5109,8 +5109,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
51095109
case UTT_IsStandardLayout:
51105110
case UTT_IsPOD:
51115111
case UTT_IsLiteral:
5112-
// Clang extension:
5113-
case UTT_IsBitwiseCopyable:
5112+
case UTT_IsBitwiseCloneable:
51145113
// By analogy, is_trivially_relocatable and is_trivially_equality_comparable
51155114
// impose the same constraints.
51165115
case UTT_IsTriviallyRelocatable:
@@ -5596,8 +5595,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
55965595
return C.hasUniqueObjectRepresentations(T);
55975596
case UTT_IsTriviallyRelocatable:
55985597
return T.isTriviallyRelocatableType(C);
5599-
case UTT_IsBitwiseCopyable:
5600-
return T.isBitwiseCopyableType(C);
5598+
case UTT_IsBitwiseCloneable:
5599+
return T.isBitwiseCloneableType(C);
56015600
case UTT_IsReferenceable:
56025601
return T.isReferenceable();
56035602
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)