diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 3b89d5a8720785..bce27dc8c4a996 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -251,6 +251,9 @@ Bug Fixes in This Version for logical operators in C23. Fixes (#GH64356). +- ``__is_trivially_relocatable`` no longer returns ``false`` for volatile-qualified types. + Fixes (#GH77091). + - Clang no longer produces a false-positive `-Wunused-variable` warning for variables created through copy initialization having side-effects in C++17 and later. Fixes (#GH64356) (#GH79518). diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 78dcd3f4007a5a..22666184c56ccf 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -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()) { case PCK_Trivial: diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index f50f51cc70982e..14ec17989ec7c7 100644 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -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() @@ -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)); @@ -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}} @@ -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&) {} @@ -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 @@ -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