aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaChecking.cpp
diff options
context:
space:
mode:
authorVlad Serebrennikov <serebrennikov.vladislav@gmail.com>2024-03-08 11:31:00 +0400
committerGitHub <noreply@github.com>2024-03-08 11:31:00 +0400
commitb6a340023d383d1e77cb8d91d92c096f791fa8c0 (patch)
tree144a04723ed79b61d2a1a4d1a77a06062120f3f3 /clang/lib/Sema/SemaChecking.cpp
parentf6b825f51ec8a67c4ace43aaacc27bfd4a78f706 (diff)
downloadllvm-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.cpp23
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);