@@ -2545,7 +2545,10 @@ struct MicrosoftRecordLayoutBuilder {
2545
2545
CharUnits Alignment;
2546
2546
};
2547
2547
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
+
2549
2552
private:
2550
2553
MicrosoftRecordLayoutBuilder (const MicrosoftRecordLayoutBuilder &) = delete ;
2551
2554
void operator =(const MicrosoftRecordLayoutBuilder &) = delete ;
@@ -2595,6 +2598,8 @@ struct MicrosoftRecordLayoutBuilder {
2595
2598
llvm::SmallPtrSetImpl<const CXXRecordDecl *> &HasVtorDispSet,
2596
2599
const CXXRecordDecl *RD) const ;
2597
2600
const ASTContext &Context;
2601
+ EmptySubobjectMap *EmptySubobjects;
2602
+
2598
2603
// / The size of the record being laid out.
2599
2604
CharUnits Size ;
2600
2605
// / The non-virtual size of the record layout.
@@ -2908,8 +2913,7 @@ static bool recordUsesEBO(const RecordDecl *RD) {
2908
2913
}
2909
2914
2910
2915
void MicrosoftRecordLayoutBuilder::layoutNonVirtualBase (
2911
- const CXXRecordDecl *RD,
2912
- const CXXRecordDecl *BaseDecl,
2916
+ const CXXRecordDecl *RD, const CXXRecordDecl *BaseDecl,
2913
2917
const ASTRecordLayout &BaseLayout,
2914
2918
const ASTRecordLayout *&PreviousBaseLayout) {
2915
2919
// Insert padding between two bases if the left first one is zero sized or
@@ -2942,6 +2946,7 @@ void MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(
2942
2946
}
2943
2947
Bases.insert (std::make_pair (BaseDecl, BaseOffset));
2944
2948
Size += BaseLayout.getNonVirtualSize ();
2949
+ DataSize = Size ;
2945
2950
PreviousBaseLayout = &BaseLayout;
2946
2951
}
2947
2952
@@ -2959,15 +2964,43 @@ void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) {
2959
2964
LastFieldIsNonZeroWidthBitfield = false ;
2960
2965
ElementInfo Info = getAdjustedElementInfo (FD);
2961
2966
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) {
2964
2975
FieldOffset =
2965
2976
Context.toCharUnitsFromBits (External.getExternalFieldOffset (FD));
2966
- else if (IsUnion)
2977
+ } else if (IsUnion) {
2967
2978
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 {
2969
2997
FieldOffset = Size .alignTo (Info.Alignment );
2998
+ }
2970
2999
placeFieldAtOffset (FieldOffset);
3000
+
3001
+ if (!IsOverlappingEmptyField)
3002
+ DataSize = std::max (DataSize, FieldOffset + Info.Size );
3003
+
2971
3004
Size = std::max (Size , FieldOffset + Info.Size );
2972
3005
}
2973
3006
@@ -3013,6 +3046,7 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) {
3013
3046
Alignment = std::max (Alignment, Info.Alignment );
3014
3047
RemainingBitsInField = Context.toBits (Info.Size ) - Width;
3015
3048
}
3049
+ DataSize = Size ;
3016
3050
}
3017
3051
3018
3052
void
@@ -3038,6 +3072,7 @@ MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(const FieldDecl *FD) {
3038
3072
Size = FieldOffset;
3039
3073
Alignment = std::max (Alignment, Info.Alignment );
3040
3074
}
3075
+ DataSize = Size ;
3041
3076
}
3042
3077
3043
3078
void MicrosoftRecordLayoutBuilder::injectVBPtr (const CXXRecordDecl *RD) {
@@ -3304,8 +3339,9 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
3304
3339
const ASTRecordLayout *NewEntry = nullptr ;
3305
3340
3306
3341
if (isMsLayout (*this )) {
3307
- MicrosoftRecordLayoutBuilder Builder (*this );
3308
3342
if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
3343
+ EmptySubobjectMap EmptySubobjects (*this , RD);
3344
+ MicrosoftRecordLayoutBuilder Builder (*this , &EmptySubobjects);
3309
3345
Builder.cxxLayout (RD);
3310
3346
NewEntry = new (*this ) ASTRecordLayout (
3311
3347
*this , Builder.Size , Builder.Alignment , Builder.Alignment ,
@@ -3317,6 +3353,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
3317
3353
Builder.EndsWithZeroSizedObject , Builder.LeadsWithZeroSizedBase ,
3318
3354
Builder.Bases , Builder.VBases );
3319
3355
} else {
3356
+ MicrosoftRecordLayoutBuilder Builder (*this , /* EmptySubobjects=*/ nullptr );
3320
3357
Builder.layout (D);
3321
3358
NewEntry = new (*this ) ASTRecordLayout (
3322
3359
*this , Builder.Size , Builder.Alignment , Builder.Alignment ,
0 commit comments