@@ -2545,7 +2545,10 @@ struct MicrosoftRecordLayoutBuilder {
25452545 CharUnits Alignment;
25462546 };
25472547 typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
2548- MicrosoftRecordLayoutBuilder (const ASTContext &Context) : Context(Context) {}
2548+ MicrosoftRecordLayoutBuilder (const ASTContext &Context,
2549+ EmptySubobjectMap *EmptySubobjects)
2550+ : Context(Context), EmptySubobjects(EmptySubobjects) {}
2551+
25492552private:
25502553 MicrosoftRecordLayoutBuilder (const MicrosoftRecordLayoutBuilder &) = delete ;
25512554 void operator =(const MicrosoftRecordLayoutBuilder &) = delete ;
@@ -2595,6 +2598,8 @@ struct MicrosoftRecordLayoutBuilder {
25952598 llvm::SmallPtrSetImpl<const CXXRecordDecl *> &HasVtorDispSet,
25962599 const CXXRecordDecl *RD) const ;
25972600 const ASTContext &Context;
2601+ EmptySubobjectMap *EmptySubobjects;
2602+
25982603 // / The size of the record being laid out.
25992604 CharUnits Size;
26002605 // / The non-virtual size of the record layout.
@@ -2908,8 +2913,7 @@ static bool recordUsesEBO(const RecordDecl *RD) {
29082913}
29092914
29102915void MicrosoftRecordLayoutBuilder::layoutNonVirtualBase (
2911- const CXXRecordDecl *RD,
2912- const CXXRecordDecl *BaseDecl,
2916+ const CXXRecordDecl *RD, const CXXRecordDecl *BaseDecl,
29132917 const ASTRecordLayout &BaseLayout,
29142918 const ASTRecordLayout *&PreviousBaseLayout) {
29152919 // Insert padding between two bases if the left first one is zero sized or
@@ -2942,6 +2946,7 @@ void MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(
29422946 }
29432947 Bases.insert (std::make_pair (BaseDecl, BaseOffset));
29442948 Size += BaseLayout.getNonVirtualSize ();
2949+ DataSize = Size;
29452950 PreviousBaseLayout = &BaseLayout;
29462951}
29472952
@@ -2959,15 +2964,43 @@ void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) {
29592964 LastFieldIsNonZeroWidthBitfield = false ;
29602965 ElementInfo Info = getAdjustedElementInfo (FD);
29612966 Alignment = std::max (Alignment, Info.Alignment );
2962- CharUnits FieldOffset;
2963- if (UseExternalLayout)
2967+
2968+ const CXXRecordDecl *FieldClass = FD->getType ()->getAsCXXRecordDecl ();
2969+ bool IsOverlappingEmptyField = FD->isPotentiallyOverlapping () &&
2970+ FieldClass->isEmpty () &&
2971+ FieldClass->fields ().empty ();
2972+ CharUnits FieldOffset = CharUnits::Zero ();
2973+
2974+ if (UseExternalLayout) {
29642975 FieldOffset =
29652976 Context.toCharUnitsFromBits (External.getExternalFieldOffset (FD));
2966- else if (IsUnion)
2977+ } else if (IsUnion) {
29672978 FieldOffset = CharUnits::Zero ();
2968- else
2979+ } else if (EmptySubobjects) {
2980+ if (!IsOverlappingEmptyField)
2981+ FieldOffset = DataSize.alignTo (Info.Alignment );
2982+
2983+ while (!EmptySubobjects->CanPlaceFieldAtOffset (FD, FieldOffset)) {
2984+ const CXXRecordDecl *ParentClass = cast<CXXRecordDecl>(FD->getParent ());
2985+ bool HasBases = ParentClass && (!ParentClass->bases ().empty () ||
2986+ !ParentClass->vbases ().empty ());
2987+ if (FieldOffset == CharUnits::Zero () && DataSize != CharUnits::Zero () &&
2988+ HasBases) {
2989+ // MSVC appears to only do this when there are base classes;
2990+ // otherwise it overlaps no_unique_address fields in non-zero offsets.
2991+ FieldOffset = DataSize.alignTo (Info.Alignment );
2992+ } else {
2993+ FieldOffset += Info.Alignment ;
2994+ }
2995+ }
2996+ } else {
29692997 FieldOffset = Size.alignTo (Info.Alignment );
2998+ }
29702999 placeFieldAtOffset (FieldOffset);
3000+
3001+ if (!IsOverlappingEmptyField)
3002+ DataSize = std::max (DataSize, FieldOffset + Info.Size );
3003+
29713004 Size = std::max (Size, FieldOffset + Info.Size );
29723005}
29733006
@@ -3013,6 +3046,7 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) {
30133046 Alignment = std::max (Alignment, Info.Alignment );
30143047 RemainingBitsInField = Context.toBits (Info.Size ) - Width;
30153048 }
3049+ DataSize = Size;
30163050}
30173051
30183052void
@@ -3038,6 +3072,7 @@ MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(const FieldDecl *FD) {
30383072 Size = FieldOffset;
30393073 Alignment = std::max (Alignment, Info.Alignment );
30403074 }
3075+ DataSize = Size;
30413076}
30423077
30433078void MicrosoftRecordLayoutBuilder::injectVBPtr (const CXXRecordDecl *RD) {
@@ -3304,8 +3339,9 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
33043339 const ASTRecordLayout *NewEntry = nullptr ;
33053340
33063341 if (isMsLayout (*this )) {
3307- MicrosoftRecordLayoutBuilder Builder (*this );
33083342 if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
3343+ EmptySubobjectMap EmptySubobjects (*this , RD);
3344+ MicrosoftRecordLayoutBuilder Builder (*this , &EmptySubobjects);
33093345 Builder.cxxLayout (RD);
33103346 NewEntry = new (*this ) ASTRecordLayout (
33113347 *this , Builder.Size , Builder.Alignment , Builder.Alignment ,
@@ -3317,6 +3353,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
33173353 Builder.EndsWithZeroSizedObject , Builder.LeadsWithZeroSizedBase ,
33183354 Builder.Bases , Builder.VBases );
33193355 } else {
3356+ MicrosoftRecordLayoutBuilder Builder (*this , /* EmptySubobjects=*/ nullptr );
33203357 Builder.layout (D);
33213358 NewEntry = new (*this ) ASTRecordLayout (
33223359 *this , Builder.Size , Builder.Alignment , Builder.Alignment ,
0 commit comments