aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp23
-rw-r--r--lib/AST/RecordLayoutBuilder.h4
-rw-r--r--test/SemaCXX/empty-class-layout.cpp7
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);