@@ -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 ;
@@ -2562,7 +2565,11 @@ struct MicrosoftRecordLayoutBuilder {
2562
2565
void layoutNonVirtualBase (const CXXRecordDecl *RD,
2563
2566
const CXXRecordDecl *BaseDecl,
2564
2567
const ASTRecordLayout &BaseLayout,
2565
- const ASTRecordLayout *&PreviousBaseLayout);
2568
+ const ASTRecordLayout *&PreviousBaseLayout,
2569
+ BaseSubobjectInfo *Base);
2570
+ BaseSubobjectInfo *computeBaseSubobjectInfo (const CXXRecordDecl *RD,
2571
+ bool IsVirtual,
2572
+ BaseSubobjectInfo *Derived);
2566
2573
void injectVFPtr (const CXXRecordDecl *RD);
2567
2574
void injectVBPtr (const CXXRecordDecl *RD);
2568
2575
// / Lays out the fields of the record. Also rounds size up to
@@ -2595,6 +2602,12 @@ struct MicrosoftRecordLayoutBuilder {
2595
2602
llvm::SmallPtrSetImpl<const CXXRecordDecl *> &HasVtorDispSet,
2596
2603
const CXXRecordDecl *RD) const ;
2597
2604
const ASTContext &Context;
2605
+ EmptySubobjectMap *EmptySubobjects;
2606
+ llvm::SpecificBumpPtrAllocator<BaseSubobjectInfo> BaseSubobjectInfoAllocator;
2607
+ typedef llvm::DenseMap<const CXXRecordDecl *, BaseSubobjectInfo *>
2608
+ BaseSubobjectInfoMapTy;
2609
+ BaseSubobjectInfoMapTy VirtualBaseInfo;
2610
+
2598
2611
// / The size of the record being laid out.
2599
2612
CharUnits Size ;
2600
2613
// / The non-virtual size of the record layout.
@@ -2818,6 +2831,8 @@ MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) {
2818
2831
// Iterate through the bases and lay out the non-virtual ones.
2819
2832
for (const CXXBaseSpecifier &Base : RD->bases ()) {
2820
2833
const CXXRecordDecl *BaseDecl = Base.getType ()->getAsCXXRecordDecl ();
2834
+ BaseSubobjectInfo *BaseInfo =
2835
+ computeBaseSubobjectInfo (BaseDecl, Base.isVirtual (), nullptr );
2821
2836
HasPolymorphicBaseClass |= BaseDecl->isPolymorphic ();
2822
2837
const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout (BaseDecl);
2823
2838
// Mark and skip virtual bases.
@@ -2839,7 +2854,8 @@ MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) {
2839
2854
LeadsWithZeroSizedBase = BaseLayout.leadsWithZeroSizedBase ();
2840
2855
}
2841
2856
// Lay out the base.
2842
- layoutNonVirtualBase (RD, BaseDecl, BaseLayout, PreviousBaseLayout);
2857
+ layoutNonVirtualBase (RD, BaseDecl, BaseLayout, PreviousBaseLayout,
2858
+ BaseInfo);
2843
2859
}
2844
2860
// Figure out if we need a fresh VFPtr for this class.
2845
2861
if (RD->isPolymorphic ()) {
@@ -2864,10 +2880,21 @@ MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) {
2864
2880
bool CheckLeadingLayout = !PrimaryBase;
2865
2881
// Iterate through the bases and lay out the non-virtual ones.
2866
2882
for (const CXXBaseSpecifier &Base : RD->bases ()) {
2867
- if (Base.isVirtual ())
2868
- continue ;
2869
2883
const CXXRecordDecl *BaseDecl = Base.getType ()->getAsCXXRecordDecl ();
2870
2884
const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout (BaseDecl);
2885
+ BaseSubobjectInfo *BaseInfo =
2886
+ computeBaseSubobjectInfo (BaseDecl, Base.isVirtual (), nullptr );
2887
+
2888
+ if (Base.isVirtual ()) {
2889
+ // Mark offset for virtual base.
2890
+ CharUnits Offset = CharUnits::Zero ();
2891
+ while (!EmptySubobjects->CanPlaceBaseAtOffset (BaseInfo, Offset)) {
2892
+ ElementInfo Info = getAdjustedElementInfo (BaseLayout);
2893
+ Offset += Info.Alignment ;
2894
+ }
2895
+ continue ;
2896
+ }
2897
+
2871
2898
// Only lay out bases without extendable VFPtrs on the second pass.
2872
2899
if (BaseLayout.hasExtendableVFPtr ()) {
2873
2900
VBPtrOffset = Bases[BaseDecl] + BaseLayout.getNonVirtualSize ();
@@ -2880,7 +2907,8 @@ MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) {
2880
2907
LeadsWithZeroSizedBase = BaseLayout.leadsWithZeroSizedBase ();
2881
2908
}
2882
2909
// Lay out the base.
2883
- layoutNonVirtualBase (RD, BaseDecl, BaseLayout, PreviousBaseLayout);
2910
+ layoutNonVirtualBase (RD, BaseDecl, BaseLayout, PreviousBaseLayout,
2911
+ BaseInfo);
2884
2912
VBPtrOffset = Bases[BaseDecl] + BaseLayout.getNonVirtualSize ();
2885
2913
}
2886
2914
// Set our VBPtroffset if we know it at this point.
@@ -2908,10 +2936,9 @@ static bool recordUsesEBO(const RecordDecl *RD) {
2908
2936
}
2909
2937
2910
2938
void MicrosoftRecordLayoutBuilder::layoutNonVirtualBase (
2911
- const CXXRecordDecl *RD,
2912
- const CXXRecordDecl *BaseDecl,
2939
+ const CXXRecordDecl *RD, const CXXRecordDecl *BaseDecl,
2913
2940
const ASTRecordLayout &BaseLayout,
2914
- const ASTRecordLayout *&PreviousBaseLayout) {
2941
+ const ASTRecordLayout *&PreviousBaseLayout, BaseSubobjectInfo *Base ) {
2915
2942
// Insert padding between two bases if the left first one is zero sized or
2916
2943
// contains a zero sized subobject and the right is zero sized or one leads
2917
2944
// with a zero sized base.
@@ -2927,7 +2954,7 @@ void MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(
2927
2954
if (UseExternalLayout) {
2928
2955
FoundBase = External.getExternalNVBaseOffset (BaseDecl, BaseOffset);
2929
2956
if (BaseOffset > Size ) {
2930
- Size = BaseOffset;
2957
+ DataSize = Size = BaseOffset;
2931
2958
}
2932
2959
}
2933
2960
@@ -2937,14 +2964,97 @@ void MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(
2937
2964
BaseOffset = CharUnits::Zero ();
2938
2965
} else {
2939
2966
// Otherwise, lay the base out at the end of the MDC.
2940
- BaseOffset = Size = Size .alignTo (Info.Alignment );
2967
+ BaseOffset = DataSize = Size = Size .alignTo (Info.Alignment );
2941
2968
}
2969
+
2970
+ // Place in EmptySubobjects map but don't check the position? MSVC seems to
2971
+ // not allow fields to overlap at the end of a virtual base, but they can
2972
+ // overlap with other bass.
2973
+ EmptySubobjects->CanPlaceBaseAtOffset (Base, BaseOffset);
2942
2974
}
2975
+
2943
2976
Bases.insert (std::make_pair (BaseDecl, BaseOffset));
2944
2977
Size += BaseLayout.getNonVirtualSize ();
2978
+ DataSize = Size ;
2945
2979
PreviousBaseLayout = &BaseLayout;
2946
2980
}
2947
2981
2982
+ BaseSubobjectInfo *MicrosoftRecordLayoutBuilder::computeBaseSubobjectInfo (
2983
+ const CXXRecordDecl *RD, bool IsVirtual, BaseSubobjectInfo *Derived) {
2984
+ // This is copied directly from ItaniumRecordLayoutBuilder::ComputeBaseSubobjectInfo.
2985
+ BaseSubobjectInfo *Info;
2986
+
2987
+ if (IsVirtual) {
2988
+ // Check if we already have info about this virtual base.
2989
+ BaseSubobjectInfo *&InfoSlot = VirtualBaseInfo[RD];
2990
+ if (InfoSlot) {
2991
+ assert (InfoSlot->Class == RD && " Wrong class for virtual base info!" );
2992
+ return InfoSlot;
2993
+ }
2994
+
2995
+ // We don't, create it.
2996
+ InfoSlot = new (BaseSubobjectInfoAllocator.Allocate ()) BaseSubobjectInfo;
2997
+ Info = InfoSlot;
2998
+ } else {
2999
+ Info = new (BaseSubobjectInfoAllocator.Allocate ()) BaseSubobjectInfo;
3000
+ }
3001
+
3002
+ Info->Class = RD;
3003
+ Info->IsVirtual = IsVirtual;
3004
+ Info->Derived = nullptr ;
3005
+ Info->PrimaryVirtualBaseInfo = nullptr ;
3006
+
3007
+ const CXXRecordDecl *PrimaryVirtualBase = nullptr ;
3008
+ BaseSubobjectInfo *PrimaryVirtualBaseInfo = nullptr ;
3009
+
3010
+ // Check if this base has a primary virtual base.
3011
+ if (RD->getNumVBases ()) {
3012
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout (RD);
3013
+ if (Layout.isPrimaryBaseVirtual ()) {
3014
+ // This base does have a primary virtual base.
3015
+ PrimaryVirtualBase = Layout.getPrimaryBase ();
3016
+ assert (PrimaryVirtualBase && " Didn't have a primary virtual base!" );
3017
+
3018
+ // Now check if we have base subobject info about this primary base.
3019
+ PrimaryVirtualBaseInfo = VirtualBaseInfo.lookup (PrimaryVirtualBase);
3020
+
3021
+ if (PrimaryVirtualBaseInfo) {
3022
+ if (PrimaryVirtualBaseInfo->Derived ) {
3023
+ // We did have info about this primary base, and it turns out that it
3024
+ // has already been claimed as a primary virtual base for another
3025
+ // base.
3026
+ PrimaryVirtualBase = nullptr ;
3027
+ } else {
3028
+ // We can claim this base as our primary base.
3029
+ Info->PrimaryVirtualBaseInfo = PrimaryVirtualBaseInfo;
3030
+ PrimaryVirtualBaseInfo->Derived = Info;
3031
+ }
3032
+ }
3033
+ }
3034
+ }
3035
+
3036
+ // Now go through all direct bases.
3037
+ for (const auto &I : RD->bases ()) {
3038
+ bool IsVirtual = I.isVirtual ();
3039
+
3040
+ const CXXRecordDecl *BaseDecl = I.getType ()->getAsCXXRecordDecl ();
3041
+
3042
+ Info->Bases .push_back (computeBaseSubobjectInfo (BaseDecl, IsVirtual, Info));
3043
+ }
3044
+
3045
+ if (PrimaryVirtualBase && !PrimaryVirtualBaseInfo) {
3046
+ // Traversing the bases must have created the base info for our primary
3047
+ // virtual base.
3048
+ PrimaryVirtualBaseInfo = VirtualBaseInfo.lookup (PrimaryVirtualBase);
3049
+ assert (PrimaryVirtualBaseInfo && " Did not create a primary virtual base!" );
3050
+
3051
+ // Claim the primary virtual base as our primary virtual base.
3052
+ Info->PrimaryVirtualBaseInfo = PrimaryVirtualBaseInfo;
3053
+ PrimaryVirtualBaseInfo->Derived = Info;
3054
+ }
3055
+ return Info;
3056
+ }
3057
+
2948
3058
void MicrosoftRecordLayoutBuilder::layoutFields (const RecordDecl *RD) {
2949
3059
LastFieldIsNonZeroWidthBitfield = false ;
2950
3060
for (const FieldDecl *Field : RD->fields ())
@@ -2956,18 +3066,48 @@ void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) {
2956
3066
layoutBitField (FD);
2957
3067
return ;
2958
3068
}
3069
+
2959
3070
LastFieldIsNonZeroWidthBitfield = false ;
2960
3071
ElementInfo Info = getAdjustedElementInfo (FD);
2961
3072
Alignment = std::max (Alignment, Info.Alignment );
2962
- CharUnits FieldOffset;
2963
- if (UseExternalLayout)
3073
+
3074
+ const CXXRecordDecl *FieldClass = FD->getType ()->getAsCXXRecordDecl ();
3075
+ bool IsOverlappingEmptyField = FD->isPotentiallyOverlapping () &&
3076
+ FieldClass->isEmpty () &&
3077
+ FieldClass->fields ().empty ();
3078
+ const CXXRecordDecl *ParentClass = cast<CXXRecordDecl>(FD->getParent ());
3079
+ bool HasBases =
3080
+ !ParentClass->bases ().empty () || !ParentClass->vbases ().empty ();
3081
+
3082
+ CharUnits FieldOffset = CharUnits::Zero ();
3083
+
3084
+ if (UseExternalLayout) {
2964
3085
FieldOffset =
2965
3086
Context.toCharUnitsFromBits (External.getExternalFieldOffset (FD));
2966
- else if (IsUnion)
3087
+ } else if (IsUnion) {
2967
3088
FieldOffset = CharUnits::Zero ();
2968
- else
3089
+ } else if (EmptySubobjects) {
3090
+ if (!IsOverlappingEmptyField)
3091
+ FieldOffset = DataSize.alignTo (Info.Alignment );
3092
+
3093
+ while (!EmptySubobjects->CanPlaceFieldAtOffset (FD, FieldOffset)) {
3094
+ if (FieldOffset == CharUnits::Zero () && DataSize != CharUnits::Zero () &&
3095
+ HasBases) {
3096
+ // MSVC appears to only do this when there are base classes;
3097
+ // otherwise it overlaps no_unique_address fields in non-zero offsets.
3098
+ FieldOffset = DataSize.alignTo (Info.Alignment );
3099
+ } else {
3100
+ FieldOffset += Info.Alignment ;
3101
+ }
3102
+ }
3103
+ } else {
2969
3104
FieldOffset = Size .alignTo (Info.Alignment );
3105
+ }
2970
3106
placeFieldAtOffset (FieldOffset);
3107
+
3108
+ if (!IsOverlappingEmptyField)
3109
+ DataSize = std::max (DataSize, FieldOffset + Info.Size );
3110
+
2971
3111
Size = std::max (Size , FieldOffset + Info.Size );
2972
3112
}
2973
3113
@@ -2999,17 +3139,17 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) {
2999
3139
auto NewSize = Context.toCharUnitsFromBits (
3000
3140
llvm::alignDown (FieldBitOffset, Context.toBits (Info.Alignment )) +
3001
3141
Context.toBits (Info.Size ));
3002
- Size = std::max (Size , NewSize);
3142
+ DataSize = Size = std::max (Size , NewSize);
3003
3143
Alignment = std::max (Alignment, Info.Alignment );
3004
3144
} else if (IsUnion) {
3005
3145
placeFieldAtOffset (CharUnits::Zero ());
3006
- Size = std::max (Size , Info.Size );
3146
+ DataSize = Size = std::max (Size , Info.Size );
3007
3147
// TODO: Add a Sema warning that MS ignores bitfield alignment in unions.
3008
3148
} else {
3009
3149
// Allocate a new block of memory and place the bitfield in it.
3010
3150
CharUnits FieldOffset = Size .alignTo (Info.Alignment );
3011
3151
placeFieldAtOffset (FieldOffset);
3012
- Size = FieldOffset + Info.Size ;
3152
+ DataSize = Size = FieldOffset + Info.Size ;
3013
3153
Alignment = std::max (Alignment, Info.Alignment );
3014
3154
RemainingBitsInField = Context.toBits (Info.Size ) - Width;
3015
3155
}
@@ -3029,13 +3169,13 @@ MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(const FieldDecl *FD) {
3029
3169
ElementInfo Info = getAdjustedElementInfo (FD);
3030
3170
if (IsUnion) {
3031
3171
placeFieldAtOffset (CharUnits::Zero ());
3032
- Size = std::max (Size , Info.Size );
3172
+ DataSize = Size = std::max (Size , Info.Size );
3033
3173
// TODO: Add a Sema warning that MS ignores bitfield alignment in unions.
3034
3174
} else {
3035
3175
// Round up the current record size to the field's alignment boundary.
3036
3176
CharUnits FieldOffset = Size .alignTo (Info.Alignment );
3037
3177
placeFieldAtOffset (FieldOffset);
3038
- Size = FieldOffset;
3178
+ DataSize = Size = FieldOffset;
3039
3179
Alignment = std::max (Alignment, Info.Alignment );
3040
3180
}
3041
3181
}
@@ -3055,7 +3195,7 @@ void MicrosoftRecordLayoutBuilder::injectVBPtr(const CXXRecordDecl *RD) {
3055
3195
// It is possible that there were no fields or bases located after vbptr,
3056
3196
// so the size was not adjusted before.
3057
3197
if (Size < FieldStart)
3058
- Size = FieldStart;
3198
+ DataSize = Size = FieldStart;
3059
3199
return ;
3060
3200
}
3061
3201
// Make sure that the amount we push the fields back by is a multiple of the
@@ -3103,6 +3243,7 @@ void MicrosoftRecordLayoutBuilder::injectVFPtr(const CXXRecordDecl *RD) {
3103
3243
void MicrosoftRecordLayoutBuilder::layoutVirtualBases (const CXXRecordDecl *RD) {
3104
3244
if (!HasVBPtr)
3105
3245
return ;
3246
+
3106
3247
// Vtordisps are always 4 bytes (even in 64-bit mode)
3107
3248
CharUnits VtorDispSize = CharUnits::fromQuantity (4 );
3108
3249
CharUnits VtorDispAlignment = VtorDispSize;
@@ -3136,7 +3277,7 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {
3136
3277
if ((PreviousBaseLayout && PreviousBaseLayout->endsWithZeroSizedObject () &&
3137
3278
BaseLayout.leadsWithZeroSizedBase () && !recordUsesEBO (RD)) ||
3138
3279
HasVtordisp) {
3139
- Size = Size .alignTo (VtorDispAlignment) + VtorDispSize;
3280
+ DataSize = Size = Size .alignTo (VtorDispAlignment) + VtorDispSize;
3140
3281
Alignment = std::max (VtorDispAlignment, Alignment);
3141
3282
}
3142
3283
// Insert the virtual base.
@@ -3154,7 +3295,7 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {
3154
3295
3155
3296
VBases.insert (std::make_pair (BaseDecl,
3156
3297
ASTRecordLayout::VBaseInfo (BaseOffset, HasVtordisp)));
3157
- Size = BaseOffset + BaseLayout.getNonVirtualSize ();
3298
+ DataSize = Size = BaseOffset + BaseLayout.getNonVirtualSize ();
3158
3299
PreviousBaseLayout = &BaseLayout;
3159
3300
}
3160
3301
}
@@ -3304,8 +3445,9 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
3304
3445
const ASTRecordLayout *NewEntry = nullptr ;
3305
3446
3306
3447
if (isMsLayout (*this )) {
3307
- MicrosoftRecordLayoutBuilder Builder (*this );
3308
3448
if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
3449
+ EmptySubobjectMap EmptySubobjects (*this , RD);
3450
+ MicrosoftRecordLayoutBuilder Builder (*this , &EmptySubobjects);
3309
3451
Builder.cxxLayout (RD);
3310
3452
NewEntry = new (*this ) ASTRecordLayout (
3311
3453
*this , Builder.Size , Builder.Alignment , Builder.Alignment ,
@@ -3317,6 +3459,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
3317
3459
Builder.EndsWithZeroSizedObject , Builder.LeadsWithZeroSizedBase ,
3318
3460
Builder.Bases , Builder.VBases );
3319
3461
} else {
3462
+ MicrosoftRecordLayoutBuilder Builder (*this , /* EmptySubobjects*/ nullptr );
3320
3463
Builder.layout (D);
3321
3464
NewEntry = new (*this ) ASTRecordLayout (
3322
3465
*this , Builder.Size , Builder.Alignment , Builder.Alignment ,
0 commit comments