Skip to content

Commit 41892fc

Browse files
authored
[CLANG-CL] ignores Wpadded (#134426)
[clang] add support for -Wpadded on Windows Implements the -Wpadded warning for --target=x86_64-windows-msvc etc. Fixes #61702 .
1 parent 5216633 commit 41892fc

File tree

4 files changed

+153
-12
lines changed

4 files changed

+153
-12
lines changed

clang/docs/ReleaseNotes.rst

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

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

220+
- `-Wpadded` option implemented for the `x86_64-windows-msvc` target. Fixes #61702
221+
220222
Removed Compiler Flags
221223
-------------------------
222224

clang/lib/AST/RecordLayoutBuilder.cpp

Lines changed: 62 additions & 12 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,
@@ -2555,7 +2563,8 @@ struct MicrosoftRecordLayoutBuilder {
25552563
typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
25562564
MicrosoftRecordLayoutBuilder(const ASTContext &Context,
25572565
EmptySubobjectMap *EmptySubobjects)
2558-
: Context(Context), EmptySubobjects(EmptySubobjects) {}
2566+
: Context(Context), EmptySubobjects(EmptySubobjects),
2567+
RemainingBitsInField(0) {}
25592568

25602569
private:
25612570
MicrosoftRecordLayoutBuilder(const MicrosoftRecordLayoutBuilder &) = delete;
@@ -2642,8 +2651,6 @@ struct MicrosoftRecordLayoutBuilder {
26422651
/// virtual base classes and their offsets in the record.
26432652
ASTRecordLayout::VBaseOffsetsMapTy VBases;
26442653
/// The number of remaining bits in our last bitfield allocation.
2645-
/// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield is
2646-
/// true.
26472654
unsigned RemainingBitsInField;
26482655
bool IsUnion : 1;
26492656
/// True if the last field laid out was a bitfield and was not 0
@@ -3004,6 +3011,15 @@ void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) {
30043011
} else {
30053012
FieldOffset = Size.alignTo(Info.Alignment);
30063013
}
3014+
3015+
uint64_t UnpaddedFielddOffsetInBits =
3016+
Context.toBits(DataSize) - RemainingBitsInField;
3017+
3018+
::CheckFieldPadding(Context, IsUnion, Context.toBits(FieldOffset),
3019+
UnpaddedFielddOffsetInBits, FD);
3020+
3021+
RemainingBitsInField = 0;
3022+
30073023
placeFieldAtOffset(FieldOffset);
30083024

30093025
if (!IsOverlappingEmptyField)
@@ -3049,10 +3065,14 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) {
30493065
} else {
30503066
// Allocate a new block of memory and place the bitfield in it.
30513067
CharUnits FieldOffset = Size.alignTo(Info.Alignment);
3068+
uint64_t UnpaddedFieldOffsetInBits =
3069+
Context.toBits(DataSize) - RemainingBitsInField;
30523070
placeFieldAtOffset(FieldOffset);
30533071
Size = FieldOffset + Info.Size;
30543072
Alignment = std::max(Alignment, Info.Alignment);
30553073
RemainingBitsInField = Context.toBits(Info.Size) - Width;
3074+
::CheckFieldPadding(Context, IsUnion, Context.toBits(FieldOffset),
3075+
UnpaddedFieldOffsetInBits, FD);
30563076
}
30573077
DataSize = Size;
30583078
}
@@ -3076,9 +3096,14 @@ MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(const FieldDecl *FD) {
30763096
} else {
30773097
// Round up the current record size to the field's alignment boundary.
30783098
CharUnits FieldOffset = Size.alignTo(Info.Alignment);
3099+
uint64_t UnpaddedFieldOffsetInBits =
3100+
Context.toBits(DataSize) - RemainingBitsInField;
30793101
placeFieldAtOffset(FieldOffset);
3102+
RemainingBitsInField = 0;
30803103
Size = FieldOffset;
30813104
Alignment = std::max(Alignment, Info.Alignment);
3105+
::CheckFieldPadding(Context, IsUnion, Context.toBits(FieldOffset),
3106+
UnpaddedFieldOffsetInBits, FD);
30823107
}
30833108
DataSize = Size;
30843109
}
@@ -3203,6 +3228,14 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {
32033228
}
32043229

32053230
void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) {
3231+
uint64_t UnpaddedSizeInBits = Context.toBits(DataSize);
3232+
UnpaddedSizeInBits -= RemainingBitsInField;
3233+
3234+
// MS ABI allocates 1 byte for empty class
3235+
// (not padding)
3236+
if (Size.isZero())
3237+
UnpaddedSizeInBits += 8;
3238+
32063239
// Respect required alignment. Note that in 32-bit mode Required alignment
32073240
// may be 0 and cause size not to be updated.
32083241
DataSize = Size;
@@ -3231,6 +3264,23 @@ void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) {
32313264
Size = Context.toCharUnitsFromBits(External.Size);
32323265
if (External.Align)
32333266
Alignment = Context.toCharUnitsFromBits(External.Align);
3267+
return;
3268+
}
3269+
unsigned CharBitNum = Context.getTargetInfo().getCharWidth();
3270+
uint64_t SizeInBits = Context.toBits(Size);
3271+
3272+
if (SizeInBits > UnpaddedSizeInBits) {
3273+
unsigned int PadSize = SizeInBits - UnpaddedSizeInBits;
3274+
bool InBits = true;
3275+
if (PadSize % CharBitNum == 0) {
3276+
PadSize = PadSize / CharBitNum;
3277+
InBits = false;
3278+
}
3279+
3280+
Context.getDiagnostics().Report(RD->getLocation(),
3281+
diag::warn_padded_struct_size)
3282+
<< Context.getTypeDeclType(RD) << PadSize
3283+
<< (InBits ? 1 : 0); // (byte|bit)
32343284
}
32353285
}
32363286

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: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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+
struct __attribute__((ms_struct)) EmptyStruct {};
36+
37+
struct __attribute__((ms_struct)) AlignedMemberStruct { // expected-warning {{padding size of 'AlignedMemberStruct' with 28 bytes to alignment boundary}}
38+
alignas(32) int x;
39+
};
40+
41+
struct alignas(32) __attribute__((ms_struct)) AlignedNonEmptyStruct { // expected-warning {{padding size of 'AlignedNonEmptyStruct' with 28 bytes to alignment boundary}}
42+
int x;
43+
};
44+
45+
46+
struct alignas(16) __attribute__((ms_struct)) AlignedEmptyStruct {}; // expected-warning {{padding size of 'AlignedEmptyStruct' with 15 bytes to alignment boundary}}
47+
48+
int main() {
49+
Foo f;
50+
AlignedStruct a;
51+
Derived d;
52+
StructWithUnion swu;
53+
EmptyStruct e;
54+
AlignedNonEmptyStruct anes;
55+
AlignedMemberStruct ams;
56+
AlignedEmptyStruct aes;
57+
}

0 commit comments

Comments
 (0)