Improve support of PDB as an external layout source

Summary:
This patch improves support of PDB as an external layout source
in the next cases:

- Multiple non-virtual inheritance from packed base classes. When using
  external layout, there's no need to align `NonVirtualSize` of a base class.
  It may cause an overlapping when the next base classes will be layouted
  (but there is a slightly different case in the test because I can't find
  a way to specify a base offset);
- Support of nameless structs and unions. There is no info about nameless child
  structs and unions in Microsoft cl-emitted PDBs. Instead all its fields
  are just treated as outer structure's (union's) fields. This also causes
  a fields overlapping, and makes it possible for unions to have fields located
  at a non-zero offset.

Reviewers: rsmith, zturner, rnk, mstorsjo, majnemer

Reviewed By: rnk

Subscribers: cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D49871

llvm-svn: 338353
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index dd58b10..6f71d5b 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -2452,7 +2452,9 @@
   auto RoundingAlignment = Alignment;
   if (!MaxFieldAlignment.isZero())
     RoundingAlignment = std::min(RoundingAlignment, MaxFieldAlignment);
-  NonVirtualSize = Size = Size.alignTo(RoundingAlignment);
+  if (!UseExternalLayout)
+    Size = Size.alignTo(RoundingAlignment);
+  NonVirtualSize = Size;
   RequiredAlignment = std::max(
       RequiredAlignment, Context.toCharUnitsFromBits(RD->getMaxAlignment()));
   layoutVirtualBases(RD);
@@ -2653,21 +2655,16 @@
   LastFieldIsNonZeroWidthBitfield = false;
   ElementInfo Info = getAdjustedElementInfo(FD);
   Alignment = std::max(Alignment, Info.Alignment);
-  if (IsUnion) {
-    placeFieldAtOffset(CharUnits::Zero());
-    Size = std::max(Size, Info.Size);
-  } else {
-    CharUnits FieldOffset;
-    if (UseExternalLayout) {
-      FieldOffset =
-          Context.toCharUnitsFromBits(External.getExternalFieldOffset(FD));
-      assert(FieldOffset >= Size && "field offset already allocated");
-    } else {
-      FieldOffset = Size.alignTo(Info.Alignment);
-    }
-    placeFieldAtOffset(FieldOffset);
-    Size = FieldOffset + Info.Size;
-  }
+  CharUnits FieldOffset;
+  if (UseExternalLayout)
+    FieldOffset =
+        Context.toCharUnitsFromBits(External.getExternalFieldOffset(FD));
+  else if (IsUnion)
+    FieldOffset = CharUnits::Zero();
+  else
+    FieldOffset = Size.alignTo(Info.Alignment);
+  placeFieldAtOffset(FieldOffset);
+  Size = std::max(Size, FieldOffset + Info.Size);
 }
 
 void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) {
@@ -2692,18 +2689,17 @@
   }
   LastFieldIsNonZeroWidthBitfield = true;
   CurrentBitfieldSize = Info.Size;
-  if (IsUnion) {
-    placeFieldAtOffset(CharUnits::Zero());
-    Size = std::max(Size, Info.Size);
-    // TODO: Add a Sema warning that MS ignores bitfield alignment in unions.
-  } else if (UseExternalLayout) {
+  if (UseExternalLayout) {
     auto FieldBitOffset = External.getExternalFieldOffset(FD);
     placeFieldAtBitOffset(FieldBitOffset);
     auto NewSize = Context.toCharUnitsFromBits(
         llvm::alignTo(FieldBitOffset + Width, Context.getCharWidth()));
-    assert(NewSize >= Size && "bit field offset already allocated");
-    Size = NewSize;
+    Size = std::max(Size, NewSize);
     Alignment = std::max(Alignment, Info.Alignment);
+  } else if (IsUnion) {
+    placeFieldAtOffset(CharUnits::Zero());
+    Size = std::max(Size, Info.Size);
+    // TODO: Add a Sema warning that MS ignores bitfield alignment in unions.
   } else {
     // Allocate a new block of memory and place the bitfield in it.
     CharUnits FieldOffset = Size.alignTo(Info.Alignment);