Skip to content
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

[clang] Fix behavior of __is_trivially_relocatable(volatile int) #77092

Merged
Merged
Show file tree
Hide file tree
Changes from 4 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
6 changes: 6 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,12 @@ Bug Fixes in This Version

- Clang now doesn't produce false-positive warning `-Wconstant-logical-operand`
for logical operators in C23.
Fixes (`#64356 <https://github.com/llvm/llvm-project/issues/64356>`_).
- ``__is_trivially_relocatable`` no longer returns ``true`` for non-object types
such as references and functions, and no longer returns ``false`` for volatile-qualified types.
Fixes (`#67498 <https://github.com/llvm/llvm-project/issues/67498>`_) and
(`#77091 <https://github.com/llvm/llvm-project/issues/77091>`_)

Copy link
Contributor

@cor3ntin cor3ntin Mar 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That should be moved after the next line (and you can use the same #GHXXXX syntax )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right! I've fixed it.

Fixes (#GH64356).

- Clang no longer produces a false-positive `-Wunused-variable` warning
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2682,6 +2682,8 @@ bool QualType::isTriviallyRelocatableType(const ASTContext &Context) const {
return false;
} else if (const auto *RD = BaseElementType->getAsRecordDecl()) {
return RD->canPassInRegisters();
} else if (BaseElementType.isTriviallyCopyableType(Context)) {
return true;
} else {
switch (isNonTrivialToPrimitiveDestructiveMove()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why these are different functions, other than maybe having different preconditions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean why is isNonTrivialToPrimitiveDestructiveMove different from isTriviallyRelocatable? I don't know, but I think it has to do with Objective-C, so I left it alone.

case PCK_Trivial:
Expand Down
181 changes: 106 additions & 75 deletions clang/test/SemaCXX/type-traits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1722,91 +1722,91 @@ struct StructWithAnonUnion3 {

void is_layout_compatible(int n)
{
static_assert(__is_layout_compatible(void, void), "");
static_assert(!__is_layout_compatible(void, int), "");
static_assert(__is_layout_compatible(void, const void), "");
static_assert(__is_layout_compatible(void, volatile void), "");
static_assert(__is_layout_compatible(const int, volatile int), "");
static_assert(__is_layout_compatible(int, int), "");
static_assert(__is_layout_compatible(int, const int), "");
static_assert(__is_layout_compatible(int, volatile int), "");
static_assert(__is_layout_compatible(const int, volatile int), "");
static_assert(__is_layout_compatible(int *, int * __restrict), "");
static_assert(__is_layout_compatible(void, void));
static_assert(!__is_layout_compatible(void, int));
static_assert(__is_layout_compatible(void, const void));
static_assert(__is_layout_compatible(void, volatile void));
static_assert(__is_layout_compatible(const int, volatile int));
static_assert(__is_layout_compatible(int, int));
static_assert(__is_layout_compatible(int, const int));
static_assert(__is_layout_compatible(int, volatile int));
static_assert(__is_layout_compatible(const int, volatile int));
static_assert(__is_layout_compatible(int *, int * __restrict));
// Note: atomic qualification matters for layout compatibility.
static_assert(!__is_layout_compatible(int, _Atomic int), "");
static_assert(__is_layout_compatible(_Atomic(int), _Atomic int), "");
static_assert(!__is_layout_compatible(int, unsigned int), "");
static_assert(!__is_layout_compatible(char, unsigned char), "");
static_assert(!__is_layout_compatible(char, signed char), "");
static_assert(!__is_layout_compatible(unsigned char, signed char), "");
static_assert(__is_layout_compatible(int[], int[]), "");
static_assert(__is_layout_compatible(int[2], int[2]), "");
static_assert(!__is_layout_compatible(int[n], int[2]), ""); // FIXME: VLAs should be rejected
static_assert(!__is_layout_compatible(int[n], int[n]), ""); // FIXME: VLAs should be rejected
static_assert(__is_layout_compatible(int&, int&), "");
static_assert(!__is_layout_compatible(int&, char&), "");
static_assert(__is_layout_compatible(void(int), void(int)), "");
static_assert(!__is_layout_compatible(void(int), void(char)), "");
static_assert(__is_layout_compatible(void(&)(int), void(&)(int)), "");
static_assert(!__is_layout_compatible(void(&)(int), void(&)(char)), "");
static_assert(__is_layout_compatible(void(*)(int), void(*)(int)), "");
static_assert(!__is_layout_compatible(void(*)(int), void(*)(char)), "");
static_assert(!__is_layout_compatible(int, _Atomic int));
static_assert(__is_layout_compatible(_Atomic(int), _Atomic int));
static_assert(!__is_layout_compatible(int, unsigned int));
static_assert(!__is_layout_compatible(char, unsigned char));
static_assert(!__is_layout_compatible(char, signed char));
static_assert(!__is_layout_compatible(unsigned char, signed char));
static_assert(__is_layout_compatible(int[], int[]));
static_assert(__is_layout_compatible(int[2], int[2]));
static_assert(!__is_layout_compatible(int[n], int[2])); // FIXME: VLAs should be rejected
static_assert(!__is_layout_compatible(int[n], int[n])); // FIXME: VLAs should be rejected
static_assert(__is_layout_compatible(int&, int&));
static_assert(!__is_layout_compatible(int&, char&));
static_assert(__is_layout_compatible(void(int), void(int)));
static_assert(!__is_layout_compatible(void(int), void(char)));
static_assert(__is_layout_compatible(void(&)(int), void(&)(int)));
static_assert(!__is_layout_compatible(void(&)(int), void(&)(char)));
static_assert(__is_layout_compatible(void(*)(int), void(*)(int)));
static_assert(!__is_layout_compatible(void(*)(int), void(*)(char)));
using function_type = void();
using function_type2 = void(char);
static_assert(__is_layout_compatible(const function_type, const function_type), "");
static_assert(__is_layout_compatible(const function_type, const function_type));
// expected-warning@-1 {{'const' qualifier on function type 'function_type' (aka 'void ()') has no effect}}
// expected-warning@-2 {{'const' qualifier on function type 'function_type' (aka 'void ()') has no effect}}
static_assert(__is_layout_compatible(function_type, const function_type), "");
static_assert(__is_layout_compatible(function_type, const function_type));
// expected-warning@-1 {{'const' qualifier on function type 'function_type' (aka 'void ()') has no effect}}
static_assert(!__is_layout_compatible(const function_type, const function_type2), "");
static_assert(!__is_layout_compatible(const function_type, const function_type2));
// expected-warning@-1 {{'const' qualifier on function type 'function_type' (aka 'void ()') has no effect}}
// expected-warning@-2 {{'const' qualifier on function type 'function_type2' (aka 'void (char)') has no effect}}
static_assert(__is_layout_compatible(CStruct, CStruct2), "");
static_assert(__is_layout_compatible(CStruct, const CStruct2), "");
static_assert(__is_layout_compatible(CStruct, volatile CStruct2), "");
static_assert(__is_layout_compatible(const CStruct, volatile CStruct2), "");
static_assert(__is_layout_compatible(CEmptyStruct, CEmptyStruct2), "");
static_assert(__is_layout_compatible(CppEmptyStruct, CppEmptyStruct2), "");
static_assert(__is_layout_compatible(CppStructStandard, CppStructStandard2), "");
static_assert(!__is_layout_compatible(CppStructNonStandardByBase, CppStructNonStandardByBase2), "");
static_assert(!__is_layout_compatible(CppStructNonStandardByVirt, CppStructNonStandardByVirt2), "");
static_assert(!__is_layout_compatible(CppStructNonStandardByMemb, CppStructNonStandardByMemb2), "");
static_assert(!__is_layout_compatible(CppStructNonStandardByProt, CppStructNonStandardByProt2), "");
static_assert(!__is_layout_compatible(CppStructNonStandardByVirtBase, CppStructNonStandardByVirtBase2), "");
static_assert(!__is_layout_compatible(CppStructNonStandardBySameBase, CppStructNonStandardBySameBase2), "");
static_assert(!__is_layout_compatible(CppStructNonStandardBy2ndVirtBase, CppStructNonStandardBy2ndVirtBase2), "");
static_assert(__is_layout_compatible(CStruct, CStructWithQualifiers), "");
static_assert(__is_layout_compatible(CStruct, CStructNoUniqueAddress) != bool(__has_cpp_attribute(no_unique_address)), "");
static_assert(__is_layout_compatible(CStructNoUniqueAddress, CStructNoUniqueAddress2) != bool(__has_cpp_attribute(no_unique_address)), "");
static_assert(__is_layout_compatible(CStruct, CStructAlignment), "");
static_assert(!__is_layout_compatible(CStruct, CStructAlignedMembers), "");
static_assert(__is_layout_compatible(UnionNoOveralignedMembers, UnionWithOveralignedMembers), "");
static_assert(__is_layout_compatible(CStructWithBitfelds, CStructWithBitfelds), "");
static_assert(__is_layout_compatible(CStructWithBitfelds, CStructWithBitfelds2), "");
static_assert(!__is_layout_compatible(CStructWithBitfelds, CStructWithBitfelds3), "");
static_assert(!__is_layout_compatible(CStructWithBitfelds, CStructWithBitfelds4), "");
static_assert(__is_layout_compatible(int CStruct2::*, int CStruct2::*), "");
static_assert(!__is_layout_compatible(int CStruct2::*, char CStruct2::*), "");
static_assert(__is_layout_compatible(void(CStruct2::*)(int), void(CStruct2::*)(int)), "");
static_assert(!__is_layout_compatible(void(CStruct2::*)(int), void(CStruct2::*)(char)), "");
static_assert(__is_layout_compatible(CStructNested, CStructNested2), "");
static_assert(__is_layout_compatible(UnionLayout, UnionLayout), "");
static_assert(!__is_layout_compatible(UnionLayout, UnionLayout2), "");
static_assert(!__is_layout_compatible(UnionLayout, UnionLayout3), "");
static_assert(!__is_layout_compatible(StructWithAnonUnion, StructWithAnonUnion2), "");
static_assert(!__is_layout_compatible(StructWithAnonUnion, StructWithAnonUnion3), "");
static_assert(__is_layout_compatible(EnumLayout, EnumClassLayout), "");
static_assert(__is_layout_compatible(EnumForward, EnumForward), "");
static_assert(__is_layout_compatible(EnumForward, EnumClassForward), "");
static_assert(__is_layout_compatible(CStruct, CStruct2));
static_assert(__is_layout_compatible(CStruct, const CStruct2));
static_assert(__is_layout_compatible(CStruct, volatile CStruct2));
static_assert(__is_layout_compatible(const CStruct, volatile CStruct2));
static_assert(__is_layout_compatible(CEmptyStruct, CEmptyStruct2));
static_assert(__is_layout_compatible(CppEmptyStruct, CppEmptyStruct2));
static_assert(__is_layout_compatible(CppStructStandard, CppStructStandard2));
static_assert(!__is_layout_compatible(CppStructNonStandardByBase, CppStructNonStandardByBase2));
static_assert(!__is_layout_compatible(CppStructNonStandardByVirt, CppStructNonStandardByVirt2));
static_assert(!__is_layout_compatible(CppStructNonStandardByMemb, CppStructNonStandardByMemb2));
static_assert(!__is_layout_compatible(CppStructNonStandardByProt, CppStructNonStandardByProt2));
static_assert(!__is_layout_compatible(CppStructNonStandardByVirtBase, CppStructNonStandardByVirtBase2));
static_assert(!__is_layout_compatible(CppStructNonStandardBySameBase, CppStructNonStandardBySameBase2));
static_assert(!__is_layout_compatible(CppStructNonStandardBy2ndVirtBase, CppStructNonStandardBy2ndVirtBase2));
static_assert(__is_layout_compatible(CStruct, CStructWithQualifiers));
static_assert(__is_layout_compatible(CStruct, CStructNoUniqueAddress) != bool(__has_cpp_attribute(no_unique_address)));
static_assert(__is_layout_compatible(CStructNoUniqueAddress, CStructNoUniqueAddress2) != bool(__has_cpp_attribute(no_unique_address)));
static_assert(__is_layout_compatible(CStruct, CStructAlignment));
static_assert(!__is_layout_compatible(CStruct, CStructAlignedMembers));
static_assert(__is_layout_compatible(UnionNoOveralignedMembers, UnionWithOveralignedMembers));
static_assert(__is_layout_compatible(CStructWithBitfelds, CStructWithBitfelds));
static_assert(__is_layout_compatible(CStructWithBitfelds, CStructWithBitfelds2));
static_assert(!__is_layout_compatible(CStructWithBitfelds, CStructWithBitfelds3));
static_assert(!__is_layout_compatible(CStructWithBitfelds, CStructWithBitfelds4));
static_assert(__is_layout_compatible(int CStruct2::*, int CStruct2::*));
static_assert(!__is_layout_compatible(int CStruct2::*, char CStruct2::*));
static_assert(__is_layout_compatible(void(CStruct2::*)(int), void(CStruct2::*)(int)));
static_assert(!__is_layout_compatible(void(CStruct2::*)(int), void(CStruct2::*)(char)));
static_assert(__is_layout_compatible(CStructNested, CStructNested2));
static_assert(__is_layout_compatible(UnionLayout, UnionLayout));
static_assert(!__is_layout_compatible(UnionLayout, UnionLayout2));
static_assert(!__is_layout_compatible(UnionLayout, UnionLayout3));
static_assert(!__is_layout_compatible(StructWithAnonUnion, StructWithAnonUnion2));
static_assert(!__is_layout_compatible(StructWithAnonUnion, StructWithAnonUnion3));
static_assert(__is_layout_compatible(EnumLayout, EnumClassLayout));
static_assert(__is_layout_compatible(EnumForward, EnumForward));
static_assert(__is_layout_compatible(EnumForward, EnumClassForward));
// Layout compatibility for enums might be relaxed in the future. See https://github.com/cplusplus/CWG/issues/39#issuecomment-1184791364
static_assert(!__is_layout_compatible(EnumLayout, int), "");
static_assert(!__is_layout_compatible(EnumClassLayout, int), "");
static_assert(!__is_layout_compatible(EnumForward, int), "");
static_assert(!__is_layout_compatible(EnumClassForward, int), "");
static_assert(!__is_layout_compatible(EnumLayout, int));
static_assert(!__is_layout_compatible(EnumClassLayout, int));
static_assert(!__is_layout_compatible(EnumForward, int));
static_assert(!__is_layout_compatible(EnumClassForward, int));
// FIXME: the following should be rejected (array of unknown bound and void are the only allowed incomplete types)
static_assert(__is_layout_compatible(CStructIncomplete, CStructIncomplete), "");
static_assert(!__is_layout_compatible(CStruct, CStructIncomplete), "");
static_assert(__is_layout_compatible(CStructIncomplete[2], CStructIncomplete[2]), "");
static_assert(__is_layout_compatible(CStructIncomplete, CStructIncomplete));
static_assert(!__is_layout_compatible(CStruct, CStructIncomplete));
static_assert(__is_layout_compatible(CStructIncomplete[2], CStructIncomplete[2]));
}

void is_signed()
Expand Down Expand Up @@ -3340,6 +3340,8 @@ namespace is_trivially_relocatable {
static_assert(!__is_trivially_relocatable(void));
static_assert(__is_trivially_relocatable(int));
static_assert(__is_trivially_relocatable(int[]));
static_assert(__is_trivially_relocatable(const int));
static_assert(__is_trivially_relocatable(volatile int));

enum Enum {};
static_assert(__is_trivially_relocatable(Enum));
Expand All @@ -3351,7 +3353,28 @@ static_assert(__is_trivially_relocatable(Union[]));

struct Trivial {};
static_assert(__is_trivially_relocatable(Trivial));
static_assert(__is_trivially_relocatable(const Trivial));
static_assert(__is_trivially_relocatable(volatile Trivial));

static_assert(__is_trivially_relocatable(Trivial[]));
static_assert(__is_trivially_relocatable(const Trivial[]));
static_assert(__is_trivially_relocatable(volatile Trivial[]));

static_assert(__is_trivially_relocatable(int[10]));
static_assert(__is_trivially_relocatable(const int[10]));
static_assert(__is_trivially_relocatable(volatile int[10]));

static_assert(__is_trivially_relocatable(int[10][10]));
static_assert(__is_trivially_relocatable(const int[10][10]));
static_assert(__is_trivially_relocatable(volatile int[10][10]));

static_assert(__is_trivially_relocatable(int[]));
static_assert(__is_trivially_relocatable(const int[]));
static_assert(__is_trivially_relocatable(volatile int[]));

static_assert(__is_trivially_relocatable(int[][10]));
static_assert(__is_trivially_relocatable(const int[][10]));
static_assert(__is_trivially_relocatable(volatile int[][10]));

struct Incomplete; // expected-note {{forward declaration of 'is_trivially_relocatable::Incomplete'}}
bool unused = __is_trivially_relocatable(Incomplete); // expected-error {{incomplete type}}
Expand All @@ -3361,6 +3384,8 @@ struct NontrivialDtor {
};
static_assert(!__is_trivially_relocatable(NontrivialDtor));
static_assert(!__is_trivially_relocatable(NontrivialDtor[]));
static_assert(!__is_trivially_relocatable(const NontrivialDtor));
static_assert(!__is_trivially_relocatable(volatile NontrivialDtor));

struct NontrivialCopyCtor {
NontrivialCopyCtor(const NontrivialCopyCtor&) {}
Expand All @@ -3379,12 +3404,16 @@ struct [[clang::trivial_abi]] TrivialAbiNontrivialDtor {
};
static_assert(__is_trivially_relocatable(TrivialAbiNontrivialDtor));
static_assert(__is_trivially_relocatable(TrivialAbiNontrivialDtor[]));
static_assert(__is_trivially_relocatable(const TrivialAbiNontrivialDtor));
static_assert(__is_trivially_relocatable(volatile TrivialAbiNontrivialDtor));

struct [[clang::trivial_abi]] TrivialAbiNontrivialCopyCtor {
TrivialAbiNontrivialCopyCtor(const TrivialAbiNontrivialCopyCtor&) {}
};
static_assert(__is_trivially_relocatable(TrivialAbiNontrivialCopyCtor));
static_assert(__is_trivially_relocatable(TrivialAbiNontrivialCopyCtor[]));
static_assert(__is_trivially_relocatable(const TrivialAbiNontrivialCopyCtor));
static_assert(__is_trivially_relocatable(volatile TrivialAbiNontrivialCopyCtor));

// A more complete set of tests for the behavior of trivial_abi can be found in
// clang/test/SemaCXX/attr-trivial-abi.cpp
Expand All @@ -3393,6 +3422,8 @@ struct [[clang::trivial_abi]] TrivialAbiNontrivialMoveCtor {
};
static_assert(__is_trivially_relocatable(TrivialAbiNontrivialMoveCtor));
static_assert(__is_trivially_relocatable(TrivialAbiNontrivialMoveCtor[]));
static_assert(__is_trivially_relocatable(const TrivialAbiNontrivialMoveCtor));
static_assert(__is_trivially_relocatable(volatile TrivialAbiNontrivialMoveCtor));

} // namespace is_trivially_relocatable

Expand Down
Loading