@@ -2592,6 +2592,8 @@ struct MicrosoftRecordLayoutBuilder {
25922592 void computeVtorDispSet (
25932593 llvm::SmallPtrSetImpl<const CXXRecordDecl *> &HasVtorDispSet,
25942594 const CXXRecordDecl *RD) const ;
2595+ void CheckFieldPadding (uint64_t Offset, uint64_t UnpaddedOffset,
2596+ const FieldDecl *D);
25952597 const ASTContext &Context;
25962598 EmptySubobjectMap *EmptySubobjects;
25972599
@@ -2629,8 +2631,6 @@ struct MicrosoftRecordLayoutBuilder {
26292631 // / virtual base classes and their offsets in the record.
26302632 ASTRecordLayout::VBaseOffsetsMapTy VBases;
26312633 // / The number of remaining bits in our last bitfield allocation.
2632- // / This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield is
2633- // / true.
26342634 unsigned RemainingBitsInField;
26352635 bool IsUnion : 1 ;
26362636 // / True if the last field laid out was a bitfield and was not 0
@@ -2992,6 +2992,15 @@ void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) {
29922992 } else {
29932993 FieldOffset = Size.alignTo (Info.Alignment );
29942994 }
2995+
2996+ uint64_t UnpaddedFielddOffsetInBits =
2997+ Context.toBits (DataSize) - RemainingBitsInField;
2998+
2999+ CheckFieldPadding (Context.toBits (FieldOffset), UnpaddedFielddOffsetInBits,
3000+ FD);
3001+
3002+ RemainingBitsInField = 0 ;
3003+
29953004 placeFieldAtOffset (FieldOffset);
29963005
29973006 if (!IsOverlappingEmptyField)
@@ -3037,10 +3046,14 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) {
30373046 } else {
30383047 // Allocate a new block of memory and place the bitfield in it.
30393048 CharUnits FieldOffset = Size.alignTo (Info.Alignment );
3049+ uint64_t UnpaddedFieldOffsetInBits =
3050+ Context.toBits (DataSize) - RemainingBitsInField;
30403051 placeFieldAtOffset (FieldOffset);
30413052 Size = FieldOffset + Info.Size ;
30423053 Alignment = std::max (Alignment, Info.Alignment );
30433054 RemainingBitsInField = Context.toBits (Info.Size ) - Width;
3055+ CheckFieldPadding (Context.toBits (FieldOffset), UnpaddedFieldOffsetInBits,
3056+ FD);
30443057 }
30453058 DataSize = Size;
30463059}
@@ -3064,9 +3077,14 @@ void MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(
30643077 } else {
30653078 // Round up the current record size to the field's alignment boundary.
30663079 CharUnits FieldOffset = Size.alignTo (Info.Alignment );
3080+ uint64_t UnpaddedFieldOffsetInBits =
3081+ Context.toBits (DataSize) - RemainingBitsInField;
30673082 placeFieldAtOffset (FieldOffset);
3083+ RemainingBitsInField = 0 ;
30683084 Size = FieldOffset;
30693085 Alignment = std::max (Alignment, Info.Alignment );
3086+ CheckFieldPadding (Context.toBits (FieldOffset), UnpaddedFieldOffsetInBits,
3087+ FD);
30703088 }
30713089 DataSize = Size;
30723090}
@@ -3189,8 +3207,56 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {
31893207 PreviousBaseLayout = &BaseLayout;
31903208 }
31913209}
3210+ // Function based on ItaniumRecordLayoutBuilder::CheckFieldPadding.
3211+ void MicrosoftRecordLayoutBuilder::CheckFieldPadding (uint64_t Offset,
3212+ uint64_t UnpaddedOffset,
3213+ const FieldDecl *D) {
3214+
3215+ // We let objc ivars without warning, objc interfaces generally are not used
3216+ // for padding tricks.
3217+ if (isa<ObjCIvarDecl>(D))
3218+ return ;
3219+
3220+ // Don't warn about structs created without a SourceLocation. This can
3221+ // be done by clients of the AST, such as codegen.
3222+ if (D->getLocation ().isInvalid ())
3223+ return ;
3224+
3225+ unsigned CharBitNum = Context.getTargetInfo ().getCharWidth ();
3226+
3227+ // Warn if padding was introduced to the struct/class.
3228+ if (!IsUnion && Offset > UnpaddedOffset) {
3229+ unsigned PadSize = Offset - UnpaddedOffset;
3230+ bool InBits = true ;
3231+ if (PadSize % CharBitNum == 0 ) {
3232+ PadSize = PadSize / CharBitNum;
3233+ InBits = false ;
3234+ }
3235+ if (D->getIdentifier ()) {
3236+ auto Diagnostic = D->isBitField () ? diag::warn_padded_struct_bitfield
3237+ : diag::warn_padded_struct_field;
3238+ Context.getDiagnostics ().Report (D->getLocation (),
3239+ Diagnostic)
3240+ << getPaddingDiagFromTagKind (D->getParent ()->getTagKind ())
3241+ << Context.getTypeDeclType (D->getParent ()) << PadSize
3242+ << (InBits ? 1 : 0 ) // (byte|bit)
3243+ << D->getIdentifier ();
3244+ } else {
3245+ auto Diagnostic = D->isBitField () ? diag::warn_padded_struct_anon_bitfield
3246+ : diag::warn_padded_struct_anon_field;
3247+ Context.getDiagnostics ().Report (D->getLocation (),
3248+ Diagnostic)
3249+ << getPaddingDiagFromTagKind (D->getParent ()->getTagKind ())
3250+ << Context.getTypeDeclType (D->getParent ()) << PadSize
3251+ << (InBits ? 1 : 0 ); // (byte|bit)
3252+ }
3253+ }
3254+ }
31923255
31933256void MicrosoftRecordLayoutBuilder::finalizeLayout (const RecordDecl *RD) {
3257+ uint64_t UnpaddedSizeInBits = Context.toBits (DataSize);
3258+ UnpaddedSizeInBits -= RemainingBitsInField;
3259+
31943260 // Respect required alignment. Note that in 32-bit mode Required alignment
31953261 // may be 0 and cause size not to be updated.
31963262 DataSize = Size;
@@ -3219,6 +3285,22 @@ void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) {
32193285 Size = Context.toCharUnitsFromBits (External.Size );
32203286 if (External.Align )
32213287 Alignment = Context.toCharUnitsFromBits (External.Align );
3288+ return ;
3289+ }
3290+ unsigned CharBitNum = Context.getTargetInfo ().getCharWidth ();
3291+ uint64_t SizeInBits = Context.toBits (Size);
3292+ if (SizeInBits > UnpaddedSizeInBits) {
3293+ unsigned int PadSize = SizeInBits - UnpaddedSizeInBits;
3294+ bool InBits = true ;
3295+ if (PadSize % CharBitNum == 0 ) {
3296+ PadSize = PadSize / CharBitNum;
3297+ InBits = false ;
3298+ }
3299+
3300+ Context.getDiagnostics ().Report (RD->getLocation (),
3301+ diag::warn_padded_struct_size)
3302+ << Context.getTypeDeclType (RD) << PadSize
3303+ << (InBits ? 1 : 0 ); // (byte|bit)
32223304 }
32233305}
32243306
0 commit comments