Skip to content

Commit 60ddbaf

Browse files
theomagellanThéo De Magalhaes
authored andcommitted
fix(clang-cl): added -Wpadded and -Wpadded-bitfield warning
1 parent 09572af commit 60ddbaf

File tree

1 file changed

+84
-2
lines changed

1 file changed

+84
-2
lines changed

clang/lib/AST/RecordLayoutBuilder.cpp

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

31933256
void 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

Comments
 (0)