Skip to content

Reland [Clang] Deprecate __is_trivially_relocatable #139061

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1859,12 +1859,18 @@ The following type trait primitives are supported by Clang. Those traits marked
* ``__is_trivially_constructible`` (C++, GNU, Microsoft)
* ``__is_trivially_copyable`` (C++, GNU, Microsoft)
* ``__is_trivially_destructible`` (C++, MSVC 2013)
* ``__is_trivially_relocatable`` (Clang): Returns true if moving an object
* ``__is_trivially_relocatable`` (Clang) (Deprecated,
use ``__builtin_is_cpp_trivially_relocatable`` instead).
Returns true if moving an object
of the given type, and then destroying the source object, is known to be
functionally equivalent to copying the underlying bytes and then dropping the
source object on the floor. This is true of trivial types,
C++26 relocatable types, and types which
were made trivially relocatable via the ``clang::trivial_abi`` attribute.
This trait is deprecated and should be replaced by
``__builtin_is_cpp_trivially_relocatable``. Note however that it is generally
unsafe to relocate a C++-relocatable type with ``memcpy`` or ``memmove``;
use ``__builtin_trivially_relocate``.
* ``__builtin_is_cpp_trivially_relocatable`` (C++): Returns true if an object
is trivially relocatable, as defined by the C++26 standard [meta.unary.prop].
Note that when relocating the caller code should ensure that if the object is polymorphic,
Expand Down
9 changes: 9 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,15 @@ Bug Fixes to Compiler Builtins
- ``__has_unique_object_representations(Incomplete[])`` is no longer accepted, per
`LWG4113 <https://cplusplus.github.io/LWG/issue4113>`_.

- ``__builtin_is_cpp_trivially_relocatable``, ``__builtin_is_replaceable`` and
``__builtin_trivially_relocate`` have been added to support standard C++26 relocation.

- ``__is_trivially_relocatable`` has been deprecated, and uses should be replaced by
``__builtin_is_cpp_trivially_relocatable``.
Note that, it is generally unsafe to ``memcpy`` non-trivially copyable types that
are ``__builtin_is_cpp_trivially_relocatable``. It is recommanded to use
``__builtin_trivially_relocate`` instead.

Bug Fixes to Attribute Support
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed crash when a parameter to the ``clang::annotate`` attribute evaluates to ``void``. See #GH119125
Expand Down
6 changes: 4 additions & 2 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,6 @@ TYPE_TRAIT_2(__is_pointer_interconvertible_base_of, IsPointerInterconvertibleBas
#include "clang/Basic/TransformTypeTraits.def"

// Clang-only C++ Type Traits
TYPE_TRAIT_1(__is_trivially_relocatable, IsTriviallyRelocatable, KEYCXX)
TYPE_TRAIT_1(__is_trivially_equality_comparable, IsTriviallyEqualityComparable, KEYCXX)
TYPE_TRAIT_1(__is_bounded_array, IsBoundedArray, KEYCXX)
TYPE_TRAIT_1(__is_unbounded_array, IsUnboundedArray, KEYCXX)
Expand All @@ -556,8 +555,11 @@ TYPE_TRAIT_2(__reference_converts_from_temporary, ReferenceConvertsFromTemporary
// IsDeducible is only used internally by clang for CTAD implementation and
// is not exposed to users.
TYPE_TRAIT_2(/*EmptySpellingName*/, IsDeducible, KEYCXX)
TYPE_TRAIT_1(__is_bitwise_cloneable, IsBitwiseCloneable, KEYALL)

// __is_trivially_relocatable is deprecated
TYPE_TRAIT_1(__builtin_is_cpp_trivially_relocatable, IsCppTriviallyRelocatable, KEYCXX)
TYPE_TRAIT_1(__is_trivially_relocatable, IsTriviallyRelocatable, KEYCXX)
TYPE_TRAIT_1(__is_bitwise_cloneable, IsBitwiseCloneable, KEYALL)
TYPE_TRAIT_1(__builtin_is_replaceable, IsReplaceable, KEYCXX)
TYPE_TRAIT_1(__builtin_structured_binding_size, StructuredBindingSize, KEYCXX)

Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6449,6 +6449,9 @@ void DiagnoseBuiltinDeprecation(Sema& S, TypeTrait Kind,
case UTT_HasTrivialDestructor:
Replacement = UTT_IsTriviallyDestructible;
break;
case UTT_IsTriviallyRelocatable:
Replacement = clang::UTT_IsCppTriviallyRelocatable;
break;
default:
return;
}
Expand Down
116 changes: 84 additions & 32 deletions clang/test/SemaCXX/attr-trivial-abi.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-windows-msvc -std=c++11
// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-scei-ps4 -std=c++11


void __attribute__((trivial_abi)) foo(); // expected-warning {{'trivial_abi' attribute only applies to classes}}

Expand All @@ -10,30 +13,38 @@ class __attribute__((trivial_abi)) a { a(a &&); };
// (And it is only trivially relocatable, currently, if it is trivial for calls.)
// In this case, it is suppressed by an explicitly defined move constructor.
// Similar concerns apply to later tests that have #if defined(_WIN64) && !defined(__MINGW32__)
static_assert(!__is_trivially_relocatable(a<int>), "");
static_assert(!__is_trivially_relocatable(a<int>), ""); // expected-warning{{deprecated}}
static_assert(!__builtin_is_cpp_trivially_relocatable(a<int>), "");
#else
static_assert(__is_trivially_relocatable(a<int>), "");
static_assert(__is_trivially_relocatable(a<int>), ""); // expected-warning{{deprecated}}
static_assert(!__builtin_is_cpp_trivially_relocatable(a<int>), "");
#endif

struct [[clang::trivial_abi]] S0 {
int a;
};
static_assert(__is_trivially_relocatable(S0), "");
static_assert(__is_trivially_relocatable(S0), ""); // expected-warning{{deprecated}}
static_assert(__builtin_is_cpp_trivially_relocatable(S0), "");

struct __attribute__((trivial_abi)) S1 {
int a;
};
static_assert(__is_trivially_relocatable(S1), "");
static_assert(__is_trivially_relocatable(S1), ""); // expected-warning{{deprecated}}
static_assert(__builtin_is_cpp_trivially_relocatable(S1), "");


struct __attribute__((trivial_abi)) S3 { // expected-warning {{'trivial_abi' cannot be applied to 'S3'}} expected-note {{is polymorphic}}
virtual void m();
};
static_assert(!__is_trivially_relocatable(S3), "");
static_assert(!__is_trivially_relocatable(S3), ""); // expected-warning{{deprecated}}
static_assert(__builtin_is_cpp_trivially_relocatable(S3), "");


struct S3_2 {
virtual void m();
} __attribute__((trivial_abi)); // expected-warning {{'trivial_abi' cannot be applied to 'S3_2'}} expected-note {{is polymorphic}}
static_assert(!__is_trivially_relocatable(S3_2), "");
static_assert(!__is_trivially_relocatable(S3_2), ""); // expected-warning{{deprecated}}
static_assert(__builtin_is_cpp_trivially_relocatable(S3_2), "");

struct __attribute__((trivial_abi)) S3_3 { // expected-warning {{'trivial_abi' cannot be applied to 'S3_3'}} expected-note {{has a field of a non-trivial class type}}
S3_3(S3_3 &&);
Expand All @@ -43,9 +54,13 @@ struct __attribute__((trivial_abi)) S3_3 { // expected-warning {{'trivial_abi' c
// The ClangABI4OrPS4 calling convention kind passes classes in registers if the
// copy constructor is trivial for calls *or deleted*, while other platforms do
// not accept deleted constructors.
static_assert(__is_trivially_relocatable(S3_3), "");
static_assert(__is_trivially_relocatable(S3_3), ""); // expected-warning{{deprecated}}
static_assert(!__builtin_is_cpp_trivially_relocatable(S3_3), "");

#else
static_assert(!__is_trivially_relocatable(S3_3), "");
static_assert(!__is_trivially_relocatable(S3_3), ""); // expected-warning{{deprecated}}
static_assert(!__builtin_is_cpp_trivially_relocatable(S3_3), "");

#endif

// Diagnose invalid trivial_abi even when the type is templated because it has a non-trivial field.
Expand All @@ -54,20 +69,28 @@ struct __attribute__((trivial_abi)) S3_4 { // expected-warning {{'trivial_abi' c
S3_4(S3_4 &&);
S3_2 s32;
};
static_assert(!__is_trivially_relocatable(S3_4<int>), "");
static_assert(!__is_trivially_relocatable(S3_4<int>), ""); // expected-warning{{deprecated}}
static_assert(!__builtin_is_cpp_trivially_relocatable(S3_4<int>), "");


struct S4 {
int a;
};
static_assert(__is_trivially_relocatable(S4), "");
static_assert(__is_trivially_relocatable(S4), ""); // expected-warning{{deprecated}}
static_assert(__builtin_is_cpp_trivially_relocatable(S4), "");


struct __attribute__((trivial_abi)) S5 : public virtual S4 { // expected-warning {{'trivial_abi' cannot be applied to 'S5'}} expected-note {{has a virtual base}}
};
static_assert(!__is_trivially_relocatable(S5), "");
static_assert(!__is_trivially_relocatable(S5), ""); // expected-warning{{deprecated}}
static_assert(!__builtin_is_cpp_trivially_relocatable(S5), "");


struct __attribute__((trivial_abi)) S9 : public S4 {
};
static_assert(__is_trivially_relocatable(S9), "");
static_assert(__is_trivially_relocatable(S9), ""); // expected-warning{{deprecated}}
static_assert(__builtin_is_cpp_trivially_relocatable(S9), "");


struct __attribute__((trivial_abi(1))) S8 { // expected-error {{'trivial_abi' attribute takes no arguments}}
int a;
Expand All @@ -80,8 +103,12 @@ struct __attribute__((trivial_abi)) S10 {
};

S10<int *> p1;
static_assert(__is_trivially_relocatable(S10<int>), "");
static_assert(__is_trivially_relocatable(S10<S3>), "");
static_assert(__is_trivially_relocatable(S10<int>), ""); // expected-warning{{deprecated}}
static_assert(__builtin_is_cpp_trivially_relocatable(S10<int>), "");

static_assert(__is_trivially_relocatable(S10<S3>), ""); // expected-warning{{deprecated}}
static_assert(__builtin_is_cpp_trivially_relocatable(S10<S3>), "");


template <class T>
struct S14 {
Expand All @@ -93,15 +120,21 @@ struct __attribute__((trivial_abi)) S15 : S14<T> {
};

S15<int> s15;
static_assert(__is_trivially_relocatable(S15<int>), "");
static_assert(__is_trivially_relocatable(S15<S3>), "");
static_assert(__is_trivially_relocatable(S15<int>), ""); // expected-warning{{deprecated}}
static_assert(__builtin_is_cpp_trivially_relocatable(S15<int>), "");

static_assert(__is_trivially_relocatable(S15<S3>), ""); // expected-warning{{deprecated}}
static_assert(__builtin_is_cpp_trivially_relocatable(S15<S3>), "");

template <class T>
struct __attribute__((trivial_abi)) S16 {
S14<T> a;
};
static_assert(__is_trivially_relocatable(S16<int>), "");
static_assert(__is_trivially_relocatable(S16<S3>), "");
static_assert(__is_trivially_relocatable(S16<int>), ""); // expected-warning{{deprecated}}
static_assert(__builtin_is_cpp_trivially_relocatable(S16<int>), "");

static_assert(__is_trivially_relocatable(S16<S3>), ""); // expected-warning{{deprecated}}
static_assert(__builtin_is_cpp_trivially_relocatable(S16<S3>), "");

S16<int> s16;

Expand All @@ -110,62 +143,81 @@ struct __attribute__((trivial_abi)) S17 {
};

S17<int> s17;
static_assert(__is_trivially_relocatable(S17<int>), "");
static_assert(__is_trivially_relocatable(S17<S3>), "");
static_assert(__is_trivially_relocatable(S17<int>), ""); // expected-warning{{deprecated}}
static_assert(__builtin_is_cpp_trivially_relocatable(S17<int>), "");

static_assert(__is_trivially_relocatable(S17<S3>), ""); // expected-warning{{deprecated}}
static_assert(__builtin_is_cpp_trivially_relocatable(S17<S3>), "");


namespace deletedCopyMoveConstructor {
struct __attribute__((trivial_abi)) CopyMoveDeleted { // expected-warning {{'trivial_abi' cannot be applied to 'CopyMoveDeleted'}} expected-note {{copy constructors and move constructors are all deleted}}
CopyMoveDeleted(const CopyMoveDeleted &) = delete;
CopyMoveDeleted(CopyMoveDeleted &&) = delete;
};
#ifdef __ORBIS__
static_assert(__is_trivially_relocatable(CopyMoveDeleted), "");
static_assert(__is_trivially_relocatable(CopyMoveDeleted), ""); // expected-warning{{deprecated}}
static_assert(!__builtin_is_cpp_trivially_relocatable(CopyMoveDeleted), "");

#else
static_assert(!__is_trivially_relocatable(CopyMoveDeleted), "");
static_assert(!__is_trivially_relocatable(CopyMoveDeleted), ""); // expected-warning{{deprecated}}
static_assert(!__builtin_is_cpp_trivially_relocatable(CopyMoveDeleted), "");

#endif

struct __attribute__((trivial_abi)) S18 { // expected-warning {{'trivial_abi' cannot be applied to 'S18'}} expected-note {{copy constructors and move constructors are all deleted}}
CopyMoveDeleted a;
};
#ifdef __ORBIS__
static_assert(__is_trivially_relocatable(S18), "");
static_assert(__is_trivially_relocatable(S18), ""); // expected-warning{{deprecated}}
static_assert(!__builtin_is_cpp_trivially_relocatable(S18), "");
#else
static_assert(!__is_trivially_relocatable(S18), "");
static_assert(!__is_trivially_relocatable(S18), ""); // expected-warning{{deprecated}}
static_assert(!__builtin_is_cpp_trivially_relocatable(S18), "");
#endif

struct __attribute__((trivial_abi)) CopyDeleted {
CopyDeleted(const CopyDeleted &) = delete;
CopyDeleted(CopyDeleted &&) = default;
};
#if defined(_WIN64) && !defined(__MINGW32__)
static_assert(!__is_trivially_relocatable(CopyDeleted), "");
static_assert(!__is_trivially_relocatable(CopyDeleted), ""); // expected-warning{{deprecated}}
static_assert(!__builtin_is_cpp_trivially_relocatable(CopyDeleted), "");

#else
static_assert(__is_trivially_relocatable(CopyDeleted), "");
static_assert(__is_trivially_relocatable(CopyDeleted), ""); // expected-warning{{deprecated}}
static_assert(!__builtin_is_cpp_trivially_relocatable(CopyDeleted), "");
#endif

struct __attribute__((trivial_abi)) MoveDeleted {
MoveDeleted(const MoveDeleted &) = default;
MoveDeleted(MoveDeleted &&) = delete;
};
static_assert(__is_trivially_relocatable(MoveDeleted), "");

static_assert(__is_trivially_relocatable(MoveDeleted), ""); // expected-warning{{deprecated}}
static_assert(!__builtin_is_cpp_trivially_relocatable(MoveDeleted), "");
struct __attribute__((trivial_abi)) S19 { // expected-warning {{'trivial_abi' cannot be applied to 'S19'}} expected-note {{copy constructors and move constructors are all deleted}}
CopyDeleted a;
MoveDeleted b;
};
#ifdef __ORBIS__
static_assert(__is_trivially_relocatable(S19), "");
static_assert(__is_trivially_relocatable(S19), ""); // expected-warning{{deprecated}}
static_assert(!__builtin_is_cpp_trivially_relocatable(S19), "");
#else
static_assert(!__is_trivially_relocatable(S19), "");
static_assert(!__is_trivially_relocatable(S19), ""); // expected-warning{{deprecated}}
static_assert(!__builtin_is_cpp_trivially_relocatable(S19), "");
#endif

// This is fine since the move constructor isn't deleted.
struct __attribute__((trivial_abi)) S20 {
int &&a; // a member of rvalue reference type deletes the copy constructor.
};
#if defined(_WIN64) && !defined(__MINGW32__)
static_assert(!__is_trivially_relocatable(S20), "");
static_assert(!__is_trivially_relocatable(S20), ""); // expected-warning{{deprecated}}
static_assert(!__builtin_is_cpp_trivially_relocatable(S20), "");

#else
static_assert(__is_trivially_relocatable(S20), "");
static_assert(__is_trivially_relocatable(S20), ""); // expected-warning{{deprecated}}
static_assert(!__builtin_is_cpp_trivially_relocatable(S20), "");

#endif
} // namespace deletedCopyMoveConstructor
Loading
Loading