diff options
author | John McCall <rjmccall@apple.com> | 2011-01-20 07:57:12 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-01-20 07:57:12 +0000 |
commit | ba4f5d5754c8291690d01ca9581926673d69b24c (patch) | |
tree | ba5c8463382801f9f2f55641e03278da8c565d69 /lib/AST/ASTContext.cpp | |
parent | 9eefa229dfb71400a6bbee326420a7f0e2e91f1f (diff) |
Fix the computation of alignment for fields of packed+aligned structs.
Part of the fix for PR8413.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123904 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/ASTContext.cpp')
-rw-r--r-- | lib/AST/ASTContext.cpp | 34 |
1 files changed, 28 insertions, 6 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index d1ac00871a..043d56a98d 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -590,8 +590,11 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { } } + // If we're using the align attribute only, just ignore everything + // else about the declaration and its type. if (UseAlignAttrOnly) { - // ignore type of value + // do nothing + } else if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) { QualType T = VD->getType(); if (const ReferenceType* RT = T->getAs<ReferenceType>()) { @@ -617,11 +620,30 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { } Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr())); } - if (const FieldDecl *FD = dyn_cast<FieldDecl>(VD)) { - // In the case of a field in a packed struct, we want the minimum - // of the alignment of the field and the alignment of the struct. - Align = std::min(Align, - getPreferredTypeAlign(FD->getParent()->getTypeForDecl())); + + // Fields can be subject to extra alignment constraints, like if + // the field is packed, the struct is packed, or the struct has a + // a max-field-alignment constraint (#pragma pack). So calculate + // the actual alignment of the field within the struct, and then + // (as we're expected to) constrain that by the alignment of the type. + if (const FieldDecl *field = dyn_cast<FieldDecl>(VD)) { + // So calculate the alignment of the field. + const ASTRecordLayout &layout = getASTRecordLayout(field->getParent()); + + // Start with the record's overall alignment. + unsigned fieldAlign = layout.getAlignment(); + + // Use the GCD of that and the offset within the record. + uint64_t offset = layout.getFieldOffset(field->getFieldIndex()); + if (offset > 0) { + // Alignment is always a power of 2, so the GCD will be a power of 2, + // which means we get to do this crazy thing instead of Euclid's. + uint64_t lowBitOfOffset = offset & (~offset + 1); + if (lowBitOfOffset < fieldAlign) + fieldAlign = static_cast<unsigned>(lowBitOfOffset); + } + + Align = std::min(Align, fieldAlign); } } |