Skip to content

Commit 2e1bea3

Browse files
author
git apple-llvm automerger
committed
Merge commit '8a05c20c963d' from llvm.org/main into next
2 parents 8b7bbe9 + 8a05c20 commit 2e1bea3

File tree

10 files changed

+323
-10
lines changed

10 files changed

+323
-10
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,10 @@ Improvements to Clang's diagnostics
524524
- An error is now emitted when OpenMP ``collapse`` and ``ordered`` clauses have an
525525
argument larger than what can fit within a 64-bit integer.
526526

527+
- A new off-by-default warning ``-Wms-bitfield-padding`` has been added to alert to cases where bit-field
528+
packing may differ under the MS struct ABI (#GH117428).
529+
530+
527531
Improvements to Clang's time-trace
528532
----------------------------------
529533

clang/include/clang/Basic/AttrDocs.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8740,6 +8740,7 @@ its underlying representation to be a WebAssembly ``funcref``.
87408740

87418741
def PreferredTypeDocumentation : Documentation {
87428742
let Category = DocCatField;
8743+
let Label = "langext-preferred_type_documentation";
87438744
let Content = [{
87448745
This attribute allows adjusting the type of a bit-field in debug information.
87458746
This can be helpful when a bit-field is intended to store an enumeration value,

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,52 @@ def Packed : DiagGroup<"packed", [PackedNonPod]>;
691691
def PaddedBitField : DiagGroup<"padded-bitfield">;
692692
def Padded : DiagGroup<"padded", [PaddedBitField]>;
693693
def UnalignedAccess : DiagGroup<"unaligned-access">;
694+
def MSBitfieldCompatibility : DiagGroup<"ms-bitfield-padding"> {
695+
code Documentation = [{
696+
Under the Microsoft ABI, adjacent bit-fields are not packed if the
697+
underlying type has a different storage size. This warning indicates that a
698+
pair of adjacent bit-fields may not pack in the same way due to this behavioural
699+
difference.
700+
701+
This can occur when mixing different types explicitly:
702+
703+
.. code-block:: c++
704+
705+
struct S {
706+
uint16_t field1 : 1;
707+
uint32_t field2 : 1;
708+
};
709+
710+
or more subtly through enums
711+
712+
.. code-block:: c++
713+
714+
enum Enum1 { /* ... */ };
715+
enum class Enum2 : unsigned char { /* ... */ };
716+
struct S {
717+
Enum1 field1 : 1;
718+
Enum2 field2 : 1;
719+
};
720+
721+
In each of these cases under the Microsoft ABI the second bit-field
722+
will not be packed with the preceding bit-field, and instead will be aligned
723+
as if the fields were each separately defined integer fields of their respective
724+
storage size. For binary compatibility this is obviously and observably
725+
incompatible, however where bit-fields are being used solely for memory use
726+
reduction this incomplete packing may silently increase the size of objects vs
727+
what is expected.
728+
729+
This issue can be addressed by ensuring the storage type of each bit-field is
730+
the same, either by explicitly using the same integer type, or in the case of
731+
enum types declaring the enum types with the same storage size. For enum types
732+
where you cannot specify the underlying type, the options are to either switch
733+
to int sized storage for all specifiers or to resort to declaring the
734+
bit-fields with explicit integer storage types and cast in and out of the field.
735+
If such a solution is required the
736+
:ref:`preferred_type <langext-preferred_type_documentation>` attribute can be
737+
used to convey the actual field type to debuggers and other tooling.
738+
}];
739+
}
694740

695741
def PessimizingMove : DiagGroup<"pessimizing-move">;
696742
def ReturnStdMove : DiagGroup<"return-std-move">;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6606,6 +6606,13 @@ def note_change_bitfield_sign : Note<
66066606
"consider making the bit-field type %select{unsigned|signed}0">;
66076607
def note_bitfield_preferred_type
66086608
: Note<"preferred type for bit-field %0 specified here">;
6609+
def warn_ms_bitfield_mismatched_storage_packing : Warning<
6610+
"bit-field %0 of type %1 has a different storage size than the "
6611+
"preceding bit-field (%2 vs %3 bytes) and will not be packed under "
6612+
"the Microsoft ABI">,
6613+
InGroup<MSBitfieldCompatibility>, DefaultIgnore;
6614+
def note_ms_bitfield_mismatched_storage_size_previous : Note<
6615+
"preceding bit-field %0 declared here with type %1">;
66096616

66106617
def warn_missing_braces : Warning<
66116618
"suggest braces around initialization of subobject">,

clang/lib/Sema/SemaDecl.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20502,9 +20502,9 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
2050220502

2050320503
// Verify that all the fields are okay.
2050420504
SmallVector<FieldDecl*, 32> RecFields;
20505-
20505+
const FieldDecl *PreviousField = nullptr;
2050620506
for (ArrayRef<Decl *>::iterator i = Fields.begin(), end = Fields.end();
20507-
i != end; ++i) {
20507+
i != end; PreviousField = cast<FieldDecl>(*i), ++i) {
2050820508
FieldDecl *FD = cast<FieldDecl>(*i);
2050920509

2051020510
// Get the type for the field.
@@ -20720,6 +20720,29 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
2072020720

2072120721
if (Record && FD->getType().isVolatileQualified())
2072220722
Record->setHasVolatileMember(true);
20723+
bool ReportMSBitfieldStoragePacking =
20724+
Record && PreviousField &&
20725+
!Diags.isIgnored(diag::warn_ms_bitfield_mismatched_storage_packing,
20726+
Record->getLocation());
20727+
auto IsNonDependentBitField = [](const FieldDecl *FD) {
20728+
return FD->isBitField() && !FD->getType()->isDependentType();
20729+
};
20730+
20731+
if (ReportMSBitfieldStoragePacking && IsNonDependentBitField(FD) &&
20732+
IsNonDependentBitField(PreviousField)) {
20733+
CharUnits FDStorageSize = Context.getTypeSizeInChars(FD->getType());
20734+
CharUnits PreviousFieldStorageSize =
20735+
Context.getTypeSizeInChars(PreviousField->getType());
20736+
if (FDStorageSize != PreviousFieldStorageSize) {
20737+
Diag(FD->getLocation(),
20738+
diag::warn_ms_bitfield_mismatched_storage_packing)
20739+
<< FD << FD->getType() << FDStorageSize.getQuantity()
20740+
<< PreviousFieldStorageSize.getQuantity();
20741+
Diag(PreviousField->getLocation(),
20742+
diag::note_ms_bitfield_mismatched_storage_size_previous)
20743+
<< PreviousField << PreviousField->getType();
20744+
}
20745+
}
2072320746
// Keep track of the number of named members.
2072420747
if (FD->getIdentifier())
2072520748
++NumNamedMembers;

clang/test/Sema/bitfield-layout.c

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=aarch64-linux-gnu
44
// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=x86_64-pc-linux-gnu
55
// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=x86_64-scei-ps4
6+
// RUN: %clang_cc1 %s -fsyntax-only -verify=checkms -triple=i686-apple-darwin9 -Wms-bitfield-padding
7+
68
// expected-no-diagnostics
79
#include <stddef.h>
810

@@ -24,12 +26,27 @@ CHECK_ALIGN(struct, a, 1)
2426
#endif
2527

2628
// Zero-width bit-fields with packed
27-
struct __attribute__((packed)) a2 { short x : 9; char : 0; int y : 17; };
29+
struct __attribute__((packed)) a2 {
30+
short x : 9; // #a2x
31+
char : 0; // #a2anon
32+
// checkms-warning@-1 {{bit-field '' of type 'char' has a different storage size than the preceding bit-field (1 vs 2 bytes) and will not be packed under the Microsoft ABI}}
33+
// checkms-note@#a2x {{preceding bit-field 'x' declared here with type 'short'}}
34+
int y : 17;
35+
// checkms-warning@-1 {{bit-field 'y' of type 'int' has a different storage size than the preceding bit-field (4 vs 1 bytes) and will not be packed under the Microsoft ABI}}
36+
// checkms-note@#a2anon {{preceding bit-field '' declared here with type 'char'}}
37+
};
38+
2839
CHECK_SIZE(struct, a2, 5)
2940
CHECK_ALIGN(struct, a2, 1)
3041

3142
// Zero-width bit-fields at the end of packed struct
32-
struct __attribute__((packed)) a3 { short x : 9; int : 0; };
43+
struct __attribute__((packed)) a3 {
44+
short x : 9; // #a3x
45+
int : 0;
46+
// checkms-warning@-1 {{bit-field '' of type 'int' has a different storage size than the preceding bit-field (4 vs 2 bytes) and will not be packed under the Microsoft ABI}}
47+
// checkms-note@#a3x {{preceding bit-field 'x' declared here with type 'short'}}
48+
};
49+
3350
#if defined(__arm__) || defined(__aarch64__)
3451
CHECK_SIZE(struct, a3, 4)
3552
CHECK_ALIGN(struct, a3, 4)
@@ -39,7 +56,12 @@ CHECK_ALIGN(struct, a3, 1)
3956
#endif
4057

4158
// For comparison, non-zero-width bit-fields at the end of packed struct
42-
struct __attribute__((packed)) a4 { short x : 9; int : 1; };
59+
struct __attribute__((packed)) a4 {
60+
short x : 9; // #a4x
61+
int : 1;
62+
// checkms-warning@-1 {{bit-field '' of type 'int' has a different storage size than the preceding bit-field (4 vs 2 bytes) and will not be packed under the Microsoft ABI}}
63+
// checkms-note@#a4x {{preceding bit-field 'x' declared here with type 'short'}}
64+
};
4365
CHECK_SIZE(struct, a4, 2)
4466
CHECK_ALIGN(struct, a4, 1)
4567

@@ -165,22 +187,28 @@ CHECK_OFFSET(struct, g4, c, 3);
165187
#endif
166188

167189
struct g5 {
168-
char : 1;
190+
char : 1; // #g5
169191
__attribute__((aligned(1))) int n : 24;
192+
// checkms-warning@-1 {{bit-field 'n' of type 'int' has a different storage size than the preceding bit-field (4 vs 1 bytes) and will not be packed under the Microsoft ABI}}
193+
// checkms-note@#g5 {{preceding bit-field '' declared here with type 'char'}}
170194
};
171195
CHECK_SIZE(struct, g5, 4);
172196
CHECK_ALIGN(struct, g5, 4);
173197

174198
struct __attribute__((packed)) g6 {
175-
char : 1;
199+
char : 1; // #g6
176200
__attribute__((aligned(1))) int n : 24;
201+
// checkms-warning@-1 {{bit-field 'n' of type 'int' has a different storage size than the preceding bit-field (4 vs 1 bytes) and will not be packed under the Microsoft ABI}}
202+
// checkms-note@#g6 {{preceding bit-field '' declared here with type 'char'}}
177203
};
178204
CHECK_SIZE(struct, g6, 4);
179205
CHECK_ALIGN(struct, g6, 1);
180206

181207
struct g7 {
182-
char : 1;
208+
char : 1; // #g7
183209
__attribute__((aligned(1))) int n : 25;
210+
// checkms-warning@-1 {{bit-field 'n' of type 'int' has a different storage size than the preceding bit-field (4 vs 1 bytes) and will not be packed under the Microsoft ABI}}
211+
// checkms-note@#g7 {{preceding bit-field '' declared here with type 'char'}}
184212
};
185213
#if defined(__ORBIS__)
186214
CHECK_SIZE(struct, g7, 4);
@@ -190,8 +218,10 @@ CHECK_SIZE(struct, g7, 8);
190218
CHECK_ALIGN(struct, g7, 4);
191219

192220
struct __attribute__((packed)) g8 {
193-
char : 1;
221+
char : 1; // #g8
194222
__attribute__((aligned(1))) int n : 25;
223+
// checkms-warning@-1 {{bit-field 'n' of type 'int' has a different storage size than the preceding bit-field (4 vs 1 bytes) and will not be packed under the Microsoft ABI}}
224+
// checkms-note@#g8 {{preceding bit-field '' declared here with type 'char'}}
195225
};
196226
#if defined(__ORBIS__)
197227
CHECK_SIZE(struct, g8, 4);

clang/test/Sema/bitfield-layout_1.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=arm-linux-gnueabihf
33
// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=aarch64-linux-gnu
44
// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=x86_64-pc-linux-gnu
5+
// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=i686-apple-darwin9 -Wms-bitfield-padding
56
// expected-no-diagnostics
67

78
#define CHECK_SIZE(name, size) \

clang/test/Sema/mms-bitfields.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
// RUN: %clang_cc1 -mms-bitfields -fsyntax-only -verify -triple x86_64-apple-darwin9 %s
2+
// RUN: %clang_cc1 -mms-bitfields -fsyntax-only -Wms-bitfield-padding -verify=checkms -triple x86_64-apple-darwin9 %s
3+
24
// expected-no-diagnostics
35

46
// The -mms-bitfields commandline parameter should behave the same
57
// as the ms_struct attribute.
68
struct
79
{
8-
int a : 1;
10+
int a : 1; // #a
911
short b : 1;
12+
// checkms-warning@-1 {{bit-field 'b' of type 'short' has a different storage size than the preceding bit-field (2 vs 4 bytes) and will not be packed under the Microsoft ABI}}
13+
// checkms-note@#a {{preceding bit-field 'a' declared here with type 'int'}}
1014
} t;
1115

1216
// MS pads out bitfields between different types.

clang/test/SemaCXX/bitfield.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %clang_cc1 %s -verify
2+
// RUN: %clang_cc1 %s -verify -Wms-bitfield-padding
23

34
// expected-no-diagnostics
45

0 commit comments

Comments
 (0)