diff options
author | Aleksandr Urakov <aleksandr.urakov@jetbrains.com> | 2019-03-13 13:38:12 +0000 |
---|---|---|
committer | Aleksandr Urakov <aleksandr.urakov@jetbrains.com> | 2019-03-13 13:38:12 +0000 |
commit | 867c2a7d369c6a067cadead7cd94ad5b391f14b4 (patch) | |
tree | f89c44f8aeecdfca51685cda3d31190d3d8c1c83 /clang/lib/AST/RecordLayoutBuilder.cpp | |
parent | 0c1e5aacd35f42fdce2fdacb0e278d7879caf529 (diff) | |
download | bcm5719-llvm-867c2a7d369c6a067cadead7cd94ad5b391f14b4.tar.gz bcm5719-llvm-867c2a7d369c6a067cadead7cd94ad5b391f14b4.zip |
[AST] Improve support of external layouts in `MicrosoftRecordLayoutBuilder`
Summary:
This patch fixes several small problems with external layouts support in
`MicrosoftRecordLayoutBuilder`:
- aligns properly the size of a struct that ends with a bit field. It was
aligned on byte before, not on the size of the field, so the struct size was
smaller than it should be;
- adjusts the struct size when injecting a vbptr in the case when there were no
bases or fields allocated after the vbptr. Similarly, without the adjustment
the struct was smaller than it should be;
- the same fix as above for the vfptr.
All these fixes affect the non-virtual size of a struct, so they are tested
through non-virtual inheritance.
Reviewers: rnk, zturner, rsmith
Reviewed By: rnk
Subscribers: jdoerfert, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D58544
llvm-svn: 356047
Diffstat (limited to 'clang/lib/AST/RecordLayoutBuilder.cpp')
-rw-r--r-- | clang/lib/AST/RecordLayoutBuilder.cpp | 22 |
1 files changed, 17 insertions, 5 deletions
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 99b7cbd0224..2d112c45222 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2692,7 +2692,8 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) { auto FieldBitOffset = External.getExternalFieldOffset(FD); placeFieldAtBitOffset(FieldBitOffset); auto NewSize = Context.toCharUnitsFromBits( - llvm::alignTo(FieldBitOffset + Width, Context.getCharWidth())); + llvm::alignDown(FieldBitOffset, Context.toBits(Info.Alignment)) + + Context.toBits(Info.Size)); Size = std::max(Size, NewSize); Alignment = std::max(Alignment, Info.Alignment); } else if (IsUnion) { @@ -2741,12 +2742,17 @@ void MicrosoftRecordLayoutBuilder::injectVBPtr(const CXXRecordDecl *RD) { CharUnits InjectionSite = VBPtrOffset; // But before we do, make sure it's properly aligned. VBPtrOffset = VBPtrOffset.alignTo(PointerInfo.Alignment); + // Determine where the first field should be laid out after the vbptr. + CharUnits FieldStart = VBPtrOffset + PointerInfo.Size; // Shift everything after the vbptr down, unless we're using an external // layout. - if (UseExternalLayout) + if (UseExternalLayout) { + // It is possible that there were no fields or bases located after vbptr, + // so the size was not adjusted before. + if (Size < FieldStart) + Size = FieldStart; return; - // Determine where the first field should be laid out after the vbptr. - CharUnits FieldStart = VBPtrOffset + PointerInfo.Size; + } // Make sure that the amount we push the fields back by is a multiple of the // alignment. CharUnits Offset = (FieldStart - InjectionSite) @@ -2771,8 +2777,14 @@ void MicrosoftRecordLayoutBuilder::injectVFPtr(const CXXRecordDecl *RD) { if (HasVBPtr) VBPtrOffset += Offset; - if (UseExternalLayout) + if (UseExternalLayout) { + // The class may have no bases or fields, but still have a vfptr + // (e.g. it's an interface class). The size was not correctly set before + // in this case. + if (FieldOffsets.empty() && Bases.empty()) + Size += Offset; return; + } Size += Offset; |