Skip to content

Commit 76fa953

Browse files
authored
[clang] add support for -Wpadded on Windows (#130182)
Implements the -Wpadded warning for --target=x86_64-windows-msvc etc. Fixes #61702 .
1 parent 380defd commit 76fa953

File tree

4 files changed

+128
-11
lines changed

4 files changed

+128
-11
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ Modified Compiler Flags
190190

191191
- The compiler flag `-fbracket-depth` default value is increased from 256 to 2048. (#GH94728)
192192

193+
- `-Wpadded` option implemented for the `x86_64-windows-msvc` target. Fixes #61702
194+
193195
Removed Compiler Flags
194196
-------------------------
195197

clang/lib/AST/RecordLayoutBuilder.cpp

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2274,9 +2274,9 @@ static unsigned getPaddingDiagFromTagKind(TagTypeKind Tag) {
22742274
}
22752275
}
22762276

2277-
void ItaniumRecordLayoutBuilder::CheckFieldPadding(
2278-
uint64_t Offset, uint64_t UnpaddedOffset, uint64_t UnpackedOffset,
2279-
unsigned UnpackedAlign, bool isPacked, const FieldDecl *D) {
2277+
static void CheckFieldPadding(const ASTContext &Context, bool IsUnion,
2278+
uint64_t Offset, uint64_t UnpaddedOffset,
2279+
const FieldDecl *D) {
22802280
// We let objc ivars without warning, objc interfaces generally are not used
22812281
// for padding tricks.
22822282
if (isa<ObjCIvarDecl>(D))
@@ -2300,23 +2300,31 @@ void ItaniumRecordLayoutBuilder::CheckFieldPadding(
23002300
if (D->getIdentifier()) {
23012301
auto Diagnostic = D->isBitField() ? diag::warn_padded_struct_bitfield
23022302
: diag::warn_padded_struct_field;
2303-
Diag(D->getLocation(), Diagnostic)
2303+
Context.getDiagnostics().Report(D->getLocation(),
2304+
Diagnostic)
23042305
<< getPaddingDiagFromTagKind(D->getParent()->getTagKind())
23052306
<< Context.getTypeDeclType(D->getParent()) << PadSize
23062307
<< (InBits ? 1 : 0) // (byte|bit)
23072308
<< D->getIdentifier();
23082309
} else {
23092310
auto Diagnostic = D->isBitField() ? diag::warn_padded_struct_anon_bitfield
23102311
: diag::warn_padded_struct_anon_field;
2311-
Diag(D->getLocation(), Diagnostic)
2312+
Context.getDiagnostics().Report(D->getLocation(),
2313+
Diagnostic)
23122314
<< getPaddingDiagFromTagKind(D->getParent()->getTagKind())
23132315
<< Context.getTypeDeclType(D->getParent()) << PadSize
23142316
<< (InBits ? 1 : 0); // (byte|bit)
23152317
}
2316-
}
2317-
if (isPacked && Offset != UnpackedOffset) {
2318-
HasPackedField = true;
2319-
}
2318+
}
2319+
}
2320+
2321+
void ItaniumRecordLayoutBuilder::CheckFieldPadding(
2322+
uint64_t Offset, uint64_t UnpaddedOffset, uint64_t UnpackedOffset,
2323+
unsigned UnpackedAlign, bool isPacked, const FieldDecl *D) {
2324+
::CheckFieldPadding(Context, IsUnion, Offset, UnpaddedOffset, D);
2325+
if (isPacked && Offset != UnpackedOffset) {
2326+
HasPackedField = true;
2327+
}
23202328
}
23212329

23222330
static const CXXMethodDecl *computeKeyFunction(ASTContext &Context,
@@ -2642,8 +2650,6 @@ struct MicrosoftRecordLayoutBuilder {
26422650
/// virtual base classes and their offsets in the record.
26432651
ASTRecordLayout::VBaseOffsetsMapTy VBases;
26442652
/// The number of remaining bits in our last bitfield allocation.
2645-
/// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield is
2646-
/// true.
26472653
unsigned RemainingBitsInField;
26482654
bool IsUnion : 1;
26492655
/// True if the last field laid out was a bitfield and was not 0
@@ -3004,6 +3010,15 @@ void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) {
30043010
} else {
30053011
FieldOffset = Size.alignTo(Info.Alignment);
30063012
}
3013+
3014+
uint64_t UnpaddedFielddOffsetInBits =
3015+
Context.toBits(DataSize) - RemainingBitsInField;
3016+
3017+
::CheckFieldPadding(Context, IsUnion, Context.toBits(FieldOffset),
3018+
UnpaddedFielddOffsetInBits, FD);
3019+
3020+
RemainingBitsInField = 0;
3021+
30073022
placeFieldAtOffset(FieldOffset);
30083023

30093024
if (!IsOverlappingEmptyField)
@@ -3049,10 +3064,14 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) {
30493064
} else {
30503065
// Allocate a new block of memory and place the bitfield in it.
30513066
CharUnits FieldOffset = Size.alignTo(Info.Alignment);
3067+
uint64_t UnpaddedFieldOffsetInBits =
3068+
Context.toBits(DataSize) - RemainingBitsInField;
30523069
placeFieldAtOffset(FieldOffset);
30533070
Size = FieldOffset + Info.Size;
30543071
Alignment = std::max(Alignment, Info.Alignment);
30553072
RemainingBitsInField = Context.toBits(Info.Size) - Width;
3073+
::CheckFieldPadding(Context, IsUnion, Context.toBits(FieldOffset),
3074+
UnpaddedFieldOffsetInBits, FD);
30563075
}
30573076
DataSize = Size;
30583077
}
@@ -3076,9 +3095,14 @@ MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(const FieldDecl *FD) {
30763095
} else {
30773096
// Round up the current record size to the field's alignment boundary.
30783097
CharUnits FieldOffset = Size.alignTo(Info.Alignment);
3098+
uint64_t UnpaddedFieldOffsetInBits =
3099+
Context.toBits(DataSize) - RemainingBitsInField;
30793100
placeFieldAtOffset(FieldOffset);
3101+
RemainingBitsInField = 0;
30803102
Size = FieldOffset;
30813103
Alignment = std::max(Alignment, Info.Alignment);
3104+
::CheckFieldPadding(Context, IsUnion, Context.toBits(FieldOffset),
3105+
UnpaddedFieldOffsetInBits, FD);
30823106
}
30833107
DataSize = Size;
30843108
}
@@ -3203,6 +3227,9 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {
32033227
}
32043228

32053229
void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) {
3230+
uint64_t UnpaddedSizeInBits = Context.toBits(DataSize);
3231+
UnpaddedSizeInBits -= RemainingBitsInField;
3232+
32063233
// Respect required alignment. Note that in 32-bit mode Required alignment
32073234
// may be 0 and cause size not to be updated.
32083235
DataSize = Size;
@@ -3231,6 +3258,22 @@ void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) {
32313258
Size = Context.toCharUnitsFromBits(External.Size);
32323259
if (External.Align)
32333260
Alignment = Context.toCharUnitsFromBits(External.Align);
3261+
return;
3262+
}
3263+
unsigned CharBitNum = Context.getTargetInfo().getCharWidth();
3264+
uint64_t SizeInBits = Context.toBits(Size);
3265+
if (SizeInBits > UnpaddedSizeInBits) {
3266+
unsigned int PadSize = SizeInBits - UnpaddedSizeInBits;
3267+
bool InBits = true;
3268+
if (PadSize % CharBitNum == 0) {
3269+
PadSize = PadSize / CharBitNum;
3270+
InBits = false;
3271+
}
3272+
3273+
Context.getDiagnostics().Report(RD->getLocation(),
3274+
diag::warn_padded_struct_size)
3275+
<< Context.getTypeDeclType(RD) << PadSize
3276+
<< (InBits ? 1 : 0); // (byte|bit)
32343277
}
32353278
}
32363279

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %clang_cc1 -triple x86_64-windows-msvc -fsyntax-only -verify -Wpadded %s
2+
3+
struct __attribute__((ms_struct)) BitfieldStruct { // expected-warning {{padding size of 'BitfieldStruct' with 3 bytes to alignment boundary}}
4+
char c : 1;
5+
int : 0; // expected-warning {{padding struct 'BitfieldStruct' with 31 bits to align anonymous bit-field}}
6+
char i;
7+
};
8+
9+
struct __attribute__((ms_struct)) SevenBitfieldStruct { // expected-warning {{padding size of 'SevenBitfieldStruct' with 3 bytes to alignment boundary}}
10+
char c : 7;
11+
int : 0; // expected-warning {{padding struct 'SevenBitfieldStruct' with 25 bits to align anonymous bit-field}}
12+
char i;
13+
};
14+
15+
struct __attribute__((ms_struct)) SameUnitSizeBitfield {
16+
char c : 7;
17+
char : 1; // Same unit size attributes fall in the same unit + they fill the unit -> no padding
18+
char i;
19+
};
20+
21+
struct __attribute__((ms_struct)) DifferentUnitSizeBitfield { // expected-warning {{padding size of 'DifferentUnitSizeBitfield' with 3 bytes to alignment boundary}}
22+
char c : 7;
23+
int : 1; // expected-warning {{padding struct 'DifferentUnitSizeBitfield' with 25 bits to align anonymous bit-field}}
24+
char i; // expected-warning {{padding struct 'DifferentUnitSizeBitfield' with 31 bits to align 'i'}}
25+
};
26+
27+
int main() {
28+
BitfieldStruct b;
29+
SevenBitfieldStruct s;
30+
SameUnitSizeBitfield su;
31+
DifferentUnitSizeBitfield du;
32+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %clang_cc1 -triple x86_64-windows-msvc -fsyntax-only -verify -Wpadded %s
2+
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -verify -Wpadded %s
3+
4+
struct __attribute__((ms_struct)) Foo { // expected-warning {{padding size of 'Foo' with 3 bytes to alignment boundary}}
5+
int b : 1;
6+
char a; // expected-warning {{padding struct 'Foo' with 31 bits to align 'a'}}
7+
};
8+
9+
struct __attribute__((ms_struct)) AlignedStruct { // expected-warning {{padding size of 'AlignedStruct' with 4 bytes to alignment boundary}}
10+
char c;
11+
alignas(8) int i; // expected-warning {{padding struct 'AlignedStruct' with 7 bytes to align 'i'}}
12+
};
13+
14+
15+
struct Base {
16+
int b;
17+
};
18+
19+
struct Derived : public Base { // expected-warning {{padding size of 'Derived' with 3 bytes to alignment boundary}}
20+
char c;
21+
};
22+
23+
union __attribute__((ms_struct)) Union {
24+
char c;
25+
long long u;
26+
};
27+
28+
struct __attribute__((ms_struct)) StructWithUnion { // expected-warning {{padding size of 'StructWithUnion' with 6 bytes to alignment boundary}}
29+
char c;
30+
int : 0;
31+
Union t; // expected-warning {{padding struct 'StructWithUnion' with 7 bytes to align 't'}}
32+
short i;
33+
};
34+
35+
int main() {
36+
Foo f;
37+
AlignedStruct a;
38+
Derived d;
39+
StructWithUnion swu;
40+
}

0 commit comments

Comments
 (0)