llvm-project/clang/test/SemaCXX/ms_struct-bitfield-padding.cpp
Oliver Hunt 8a05c20c96
Add an off-by-default warning to complain about MSVC bitfield padding (#117428)
This just adds a warning for bitfields placed next to other bitfields
where the underlying type has different storage. Under the MS struct
bitfield packing ABI such bitfields are not packed.
2025-05-13 14:00:20 -07:00

197 lines
5.3 KiB
C++

// RUN: %clang_cc1 -fsyntax-only -Wms-bitfield-padding -verify -triple armv8 -std=c++23 %s
// RUN: %clang_cc1 -fsyntax-only -DMS_BITFIELDS -mms-bitfields -verify=msbitfields -triple armv8-apple-macos10.15 -std=c++23 %s
// msbitfields-no-diagnostics
enum Enum1 { Enum1_A, Enum1_B };
enum Enum2 { Enum2_A, Enum2_B };
enum class EnumU32_1 : unsigned { A, B };
enum class EnumU32_2 : unsigned { A, B };
enum class EnumU64 : unsigned long long { A, B };
enum class EnumI32 : int { A, B };
enum class EnumU8 : unsigned char { A, B };
enum class EnumI8 : char { A, B };
enum class EnumU16 : unsigned short { A, B };
enum class EnumI16 : short { A, B };
struct A {
unsigned int a : 15;
unsigned int b : 15;
};
static_assert(sizeof(A) == 4);
struct B {
unsigned int a : 15;
int b : 15;
};
static_assert(sizeof(B) == 4);
struct C {
unsigned int a : 15;
int b : 15;
};
static_assert(sizeof(C) == 4);
struct D {
Enum1 a : 15;
Enum1 b : 15;
};
static_assert(sizeof(D) == 4);
struct E {
Enum1 a : 15;
Enum2 b : 15;
};
static_assert(sizeof(E) == 4);
struct F {
EnumU32_1 a : 15;
EnumU32_2 b : 15;
};
static_assert(sizeof(F) == 4);
struct G {
EnumU32_1 a : 15;
EnumU64 b : 15;
// expected-warning@-1 {{bit-field 'b' of type 'EnumU64' has a different storage size than the preceding bit-field (8 vs 4 bytes) and will not be packed under the Microsoft ABI}}
// expected-note@-3 {{preceding bit-field 'a' declared here with type 'EnumU32_1'}}
};
#ifdef MS_BITFIELDS
static_assert(sizeof(G) == 16);
#else
static_assert(sizeof(G) == 8);
#endif
struct H {
EnumU32_1 a : 10;
EnumI32 b : 10;
EnumU32_1 c : 10;
};
static_assert(sizeof(H) == 4);
struct I {
EnumU8 a : 3;
EnumI8 b : 5;
EnumU32_1 c : 10;
// expected-warning@-1 {{bit-field 'c' of type 'EnumU32_1' has a different storage size than the preceding bit-field (4 vs 1 bytes) and will not be packed under the Microsoft ABI}}
// expected-note@-3 {{preceding bit-field 'b' declared here with type 'EnumI8'}}
};
#ifdef MS_BITFIELDS
static_assert(sizeof(I) == 8);
#else
static_assert(sizeof(I) == 4);
#endif
struct J {
EnumU8 : 0;
EnumU8 b : 4;
};
static_assert(sizeof(J) == 1);
struct K {
EnumU8 a : 4;
EnumU8 : 0;
};
static_assert(sizeof(K) == 1);
struct L {
EnumU32_1 a : 10;
EnumU32_2 b : 10;
EnumU32_1 c : 10;
};
static_assert(sizeof(L) == 4);
struct M {
EnumU32_1 a : 10;
EnumI32 b : 10;
EnumU32_1 c : 10;
};
static_assert(sizeof(M) == 4);
struct N {
EnumU32_1 a : 10;
EnumU64 b : 10;
// expected-warning@-1 {{bit-field 'b' of type 'EnumU64' has a different storage size than the preceding bit-field (8 vs 4 bytes) and will not be packed under the Microsoft ABI}}
// expected-note@-3 {{preceding bit-field 'a' declared here with type 'EnumU32_1'}}
EnumU32_1 c : 10;
// expected-warning@-1 {{bit-field 'c' of type 'EnumU32_1' has a different storage size than the preceding bit-field (4 vs 8 bytes) and will not be packed under the Microsoft ABI}}
// expected-note@-5 {{preceding bit-field 'b' declared here with type 'EnumU64'}}
};
#ifdef MS_BITFIELDS
static_assert(sizeof(N) == 24);
#else
static_assert(sizeof(N) == 8);
#endif
struct O {
EnumU16 a : 10;
EnumU32_1 b : 10;
// expected-warning@-1 {{bit-field 'b' of type 'EnumU32_1' has a different storage size than the preceding bit-field (4 vs 2 bytes) and will not be packed under the Microsoft ABI}}
// expected-note@-3 {{preceding bit-field 'a' declared here with type 'EnumU16'}}
};
#ifdef MS_BITFIELDS
static_assert(sizeof(O) == 8);
#else
static_assert(sizeof(O) == 4);
#endif
struct P {
EnumU32_1 a : 10;
EnumU16 b : 10;
// expected-warning@-1 {{bit-field 'b' of type 'EnumU16' has a different storage size than the preceding bit-field (2 vs 4 bytes) and will not be packed under the Microsoft ABI}}
// expected-note@-3 {{preceding bit-field 'a' declared here with type 'EnumU32_1'}}
};
#ifdef MS_BITFIELDS
static_assert(sizeof(P) == 8);
#else
static_assert(sizeof(P) == 4);
#endif
struct Q {
EnumU8 a : 6;
EnumU16 b : 6;
// expected-warning@-1 {{bit-field 'b' of type 'EnumU16' has a different storage size than the preceding bit-field (2 vs 1 bytes) and will not be packed under the Microsoft ABI}}
// expected-note@-3 {{preceding bit-field 'a' declared here with type 'EnumU8'}}
};
#ifdef MS_BITFIELDS
static_assert(sizeof(Q) == 4);
#else
static_assert(sizeof(Q) == 2);
#endif
struct R {
EnumU16 a : 9;
EnumU16 b : 9;
EnumU8 c : 6;
// expected-warning@-1 {{bit-field 'c' of type 'EnumU8' has a different storage size than the preceding bit-field (1 vs 2 bytes) and will not be packed under the Microsoft ABI}}
// expected-note@-3 {{preceding bit-field 'b' declared here with type 'EnumU16'}}
};
#ifdef MS_BITFIELDS
static_assert(sizeof(R) == 6);
#else
static_assert(sizeof(R) == 4);
#endif
struct S {
char a : 4;
char b : 4;
char c : 4;
char d : 4;
short x : 7;
// expected-warning@-1 {{bit-field 'x' of type 'short' has a different storage size than the preceding bit-field (2 vs 1 bytes) and will not be packed under the Microsoft ABI}}
// expected-note@-3 {{preceding bit-field 'd' declared here with type 'char'}}
// This is a false positive. Reporting this correctly requires duplicating the record layout process
// in target and MS layout modes, and it's also unclear if that's the correct choice for users of
// this diagnostic.
short y : 9;
};
static_assert(sizeof(S) == 4);