diff options
-rw-r--r-- | lib/AST/RecordLayoutBuilder.cpp | 23 | ||||
-rw-r--r-- | lib/AST/RecordLayoutBuilder.h | 4 | ||||
-rw-r--r-- | test/SemaCXX/empty-class-layout.cpp | 7 |
3 files changed, 34 insertions, 0 deletions
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index dec6402d36..38c3e37352 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -252,6 +252,18 @@ bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, return true; } +bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD, + uint64_t Offset) const { + if (const RecordType *RT = dyn_cast<RecordType>(FD->getType())) { + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) + return canPlaceRecordAtOffset(RD, Offset); + } + + // FIXME: Arrays. + + return true; +} + void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD, uint64_t Offset) { if (RD->isEmpty()) @@ -485,6 +497,17 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { // Round up the current record size to the field's alignment boundary. FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign); + + if (!IsUnion) { + while (true) { + // Check if we can place the field at this offset. + if (canPlaceFieldAtOffset(D, FieldOffset)) + break; + + // We can't try again. + FieldOffset += FieldAlign; + } + } } // Place this field at the current location. diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h index 43563c6729..0f83661cd9 100644 --- a/lib/AST/RecordLayoutBuilder.h +++ b/lib/AST/RecordLayoutBuilder.h @@ -103,6 +103,10 @@ class ASTRecordLayoutBuilder { /// (direct or indirect) of the same type having the same offset. bool canPlaceRecordAtOffset(const CXXRecordDecl *RD, uint64_t Offset) const; + /// canPlaceFieldAtOffset - Return whether a field can be placed at the given + /// offset. + bool canPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) const; + /// UpdateEmptyClassOffsets - Called after a record (either a base class /// or a field) has been placed at the given offset. Will update the /// EmptyClassOffsets map if the class is empty or has any empty bases or diff --git a/test/SemaCXX/empty-class-layout.cpp b/test/SemaCXX/empty-class-layout.cpp index ebbeb38fc9..625e3ee903 100644 --- a/test/SemaCXX/empty-class-layout.cpp +++ b/test/SemaCXX/empty-class-layout.cpp @@ -17,3 +17,10 @@ struct F : E { }; struct G : E, F { }; SA(3, sizeof(G) == 2); + +struct H { H(); }; + +struct I : H { + H h; +}; +SA(4, sizeof(I) == 2); |