diff options
author | Vlad Serebrennikov <serebrennikov.vladislav@gmail.com> | 2024-03-08 11:31:00 +0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-08 11:31:00 +0400 |
commit | b6a340023d383d1e77cb8d91d92c096f791fa8c0 (patch) | |
tree | 144a04723ed79b61d2a1a4d1a77a06062120f3f3 /clang/lib/Sema/SemaChecking.cpp | |
parent | f6b825f51ec8a67c4ace43aaacc27bfd4a78f706 (diff) | |
download | llvm-b6a340023d383d1e77cb8d91d92c096f791fa8c0.zip llvm-b6a340023d383d1e77cb8d91d92c096f791fa8c0.tar.gz llvm-b6a340023d383d1e77cb8d91d92c096f791fa8c0.tar.bz2 |
[clang] Respect field alignment in layout compatibility of structs (#84313)
This patch implements
[CWG2586](https://cplusplus.github.io/CWG/issues/2583.html) "Common
initial sequence should consider over-alignment". Note that alignment of
union members doesn't have to match, as layout compatibility of unions
is not defined in terms of common initial sequence
(http://eel.is/c++draft/class.mem.general#25).
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 23 |
1 files changed, 21 insertions, 2 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 3597f93..b34b8df 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -19184,8 +19184,22 @@ static bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) { } /// Check if two fields are layout-compatible. +/// Can be used on union members, which are exempt from alignment requirement +/// of common initial sequence. static bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, - FieldDecl *Field2) { + FieldDecl *Field2, + bool AreUnionMembers = false) { + const Type *Field1Parent = Field1->getParent()->getTypeForDecl(); + const Type *Field2Parent = Field2->getParent()->getTypeForDecl(); + assert(((Field1Parent->isStructureOrClassType() && + Field2Parent->isStructureOrClassType()) || + (Field1Parent->isUnionType() && Field2Parent->isUnionType())) && + "Can't evaluate layout compatibility between a struct field and a " + "union field."); + assert(((!AreUnionMembers && Field1Parent->isStructureOrClassType()) || + (AreUnionMembers && Field1Parent->isUnionType())) && + "AreUnionMembers should be 'true' for union fields (only)."); + if (!isLayoutCompatible(C, Field1->getType(), Field2->getType())) return false; @@ -19204,6 +19218,11 @@ static bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, if (Field1->hasAttr<clang::NoUniqueAddressAttr>() || Field2->hasAttr<clang::NoUniqueAddressAttr>()) return false; + + if (!AreUnionMembers && + Field1->getMaxAlignment() != Field2->getMaxAlignment()) + return false; + return true; } @@ -19265,7 +19284,7 @@ static bool isLayoutCompatibleUnion(ASTContext &C, RecordDecl *RD1, E = UnmatchedFields.end(); for ( ; I != E; ++I) { - if (isLayoutCompatible(C, Field1, *I)) { + if (isLayoutCompatible(C, Field1, *I, /*IsUnionMember=*/true)) { bool Result = UnmatchedFields.erase(*I); (void) Result; assert(Result); |