[Clang] Consider preferred_type in bitfield warnings (#116760) (#116785)

Very simply extends the bitfield sema checks for assignment to fields
with a preferred type specified to consider the preferred type if the
decl storage type is not explicitly an enum type.

This does mean that if the preferred and explicit types have different
storage requirements we may not warn in all possible cases, but that's a
scenario for which the warnings are much more complex and confusing.
This commit is contained in:
Oliver Hunt 2025-04-20 14:16:51 -07:00 committed by GitHub
parent 842e591577
commit 3ac1aa4c88
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 468 additions and 7 deletions

View File

@ -395,6 +395,14 @@ Improvements to Clang's diagnostics
constructors to initialize their non-modifiable members. The diagnostic is
not new; being controlled via a warning group is what's new. Fixes #GH41104
- Improved bit-field diagnostics to consider the type specified by the
``preferred_type`` attribute. These diagnostics are controlled by the flags
``-Wpreferred-type-bitfield-enum-conversion`` and
``-Wpreferred-type-bitfield-width``. These warnings are on by default as they
they're only triggered if the authors are already making the choice to use
``preferred_type`` attribute.
Improvements to Clang's time-trace
----------------------------------

View File

@ -49,6 +49,9 @@ def SingleBitBitFieldConstantConversion :
DiagGroup<"single-bit-bitfield-constant-conversion">;
def BitFieldConstantConversion : DiagGroup<"bitfield-constant-conversion",
[SingleBitBitFieldConstantConversion]>;
def PreferredTypeBitFieldEnumConversion
: DiagGroup<"preferred-type-bitfield-enum-conversion">;
def PreferredTypeBitFieldWidth : DiagGroup<"preferred-type-bitfield-width">;
def BitFieldEnumConversion : DiagGroup<"bitfield-enum-conversion">;
def BitFieldWidth : DiagGroup<"bitfield-width">;
def CompoundTokenSplitByMacro : DiagGroup<"compound-token-split-by-macro">;

View File

@ -6492,8 +6492,25 @@ def warn_signed_bitfield_enum_conversion : Warning<
"signed bit-field %0 needs an extra bit to represent the largest positive "
"enumerators of %1">,
InGroup<BitFieldEnumConversion>, DefaultIgnore;
def warn_preferred_type_bitfield_too_small_for_enum
: Warning<"bit-field %0 is not wide enough to store all enumerators of "
"preferred type %1">,
InGroup<PreferredTypeBitFieldEnumConversion>;
def warn_preferred_type_unsigned_bitfield_assigned_signed_enum
: Warning<"assigning value of preferred signed enum type %1 to unsigned "
"bit-field %0; "
"negative enumerators of enum %1 will be converted to positive "
"values">,
InGroup<PreferredTypeBitFieldEnumConversion>;
def warn_preferred_type_signed_bitfield_enum_conversion
: Warning<"signed bit-field %0 needs an extra bit to represent the largest "
"positive "
"enumerators of preferred type %1">,
InGroup<PreferredTypeBitFieldEnumConversion>;
def note_change_bitfield_sign : Note<
"consider making the bit-field type %select{unsigned|signed}0">;
def note_bitfield_preferred_type
: Note<"preferred type for bit-field %0 specified here">;
def warn_missing_braces : Warning<
"suggest braces around initialization of subobject">,

View File

@ -11293,9 +11293,16 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
// The RHS is not constant. If the RHS has an enum type, make sure the
// bitfield is wide enough to hold all the values of the enum without
// truncation.
if (const auto *EnumTy = OriginalInit->getType()->getAs<EnumType>()) {
const auto *EnumTy = OriginalInit->getType()->getAs<EnumType>();
const PreferredTypeAttr *PTAttr = nullptr;
if (!EnumTy) {
PTAttr = Bitfield->getAttr<PreferredTypeAttr>();
if (PTAttr)
EnumTy = PTAttr->getType()->getAs<EnumType>();
}
if (EnumTy) {
EnumDecl *ED = EnumTy->getDecl();
bool SignedBitfield = BitfieldType->isSignedIntegerType();
bool SignedBitfield = BitfieldType->isSignedIntegerOrEnumerationType();
// Enum types are implicitly signed on Windows, so check if there are any
// negative enumerators to see if the enum was intended to be signed or
@ -11309,12 +11316,18 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
// on Windows where unfixed enums always use an underlying type of 'int'.
unsigned DiagID = 0;
if (SignedEnum && !SignedBitfield) {
DiagID = diag::warn_unsigned_bitfield_assigned_signed_enum;
DiagID =
PTAttr == nullptr
? diag::warn_unsigned_bitfield_assigned_signed_enum
: diag::
warn_preferred_type_unsigned_bitfield_assigned_signed_enum;
} else if (SignedBitfield && !SignedEnum &&
ED->getNumPositiveBits() == FieldWidth) {
DiagID = diag::warn_signed_bitfield_enum_conversion;
DiagID =
PTAttr == nullptr
? diag::warn_signed_bitfield_enum_conversion
: diag::warn_preferred_type_signed_bitfield_enum_conversion;
}
if (DiagID) {
S.Diag(InitLoc, DiagID) << Bitfield << ED;
TypeSourceInfo *TSI = Bitfield->getTypeSourceInfo();
@ -11322,6 +11335,9 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
TSI ? TSI->getTypeLoc().getSourceRange() : SourceRange();
S.Diag(Bitfield->getTypeSpecStartLoc(), diag::note_change_bitfield_sign)
<< SignedEnum << TypeRange;
if (PTAttr)
S.Diag(PTAttr->getLocation(), diag::note_bitfield_preferred_type)
<< ED;
}
// Compute the required bitwidth. If the enum has negative values, we need
@ -11334,10 +11350,16 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
// Check the bitwidth.
if (BitsNeeded > FieldWidth) {
Expr *WidthExpr = Bitfield->getBitWidth();
S.Diag(InitLoc, diag::warn_bitfield_too_small_for_enum)
<< Bitfield << ED;
auto DiagID =
PTAttr == nullptr
? diag::warn_bitfield_too_small_for_enum
: diag::warn_preferred_type_bitfield_too_small_for_enum;
S.Diag(InitLoc, DiagID) << Bitfield << ED;
S.Diag(WidthExpr->getExprLoc(), diag::note_widen_bitfield)
<< BitsNeeded << ED << WidthExpr->getSourceRange();
if (PTAttr)
S.Diag(PTAttr->getLocation(), diag::note_bitfield_preferred_type)
<< ED;
}
}

View File

@ -0,0 +1,411 @@
// RUN: %clang_cc1 %s -std=c++23 -triple=x86_64-apple-darwin10 -fsyntax-only -verify=expected,bitfieldwarnings,cpp -Wno-unused-value -Wno-unused-but-set-variable -Wbitfield-width -Wbitfield-enum-conversion
// RUN: %clang_cc1 %s -std=c++23 -triple=x86_64-apple-darwin10 -fsyntax-only -verify=expected,cpp -Wno-unused-value -Wno-unused-but-set-variable
// RUN: %clang_cc1 %s -x c -std=c23 -triple=x86_64-apple-darwin10 -fsyntax-only -verify=expected,c -Wno-unused-value -Wno-unused-but-set-variable
// RUN: %clang_cc1 %s -x c -std=c23 -triple=x86_64-apple-darwin10 -fsyntax-only -verify=expected,bitfieldwarnings,c -Wno-unused-value -Wno-unused-but-set-variable -Wbitfield-width -Wbitfield-enum-conversion
typedef enum A {
A_a,
A_b,
A_c,
A_d
} A;
#ifdef __cplusplus
#define DEFINE_ENUM(_Name, _Type, ...) enum class _Name : _Type { __VA_ARGS__ } ;
#define ENUM_CLASS_REF(_Name, _Enum) _Name::_Enum
#else
#define DEFINE_ENUM(_Name, _Type, ...) typedef enum _Name : _Type { __VA_ARGS__ } _Name;
#define ENUM_CLASS_REF(_Name, _Enum) _Enum
#endif
DEFINE_ENUM(B, int, B_a, B_b, B_c, B_d );
DEFINE_ENUM(C, unsigned, C_a, C_b, C_c, C_d );
DEFINE_ENUM(D, unsigned, D_a, D_b);
// Not using templates here so we can more easily distinguish the responsible
// party for each warning
typedef struct S_A {
A field1 : 1; // #S_A_field1
A field2 : 2; // #S_A_field2
A field3 : 8; // #S_A_field3
__attribute__((preferred_type(A))) // #preferred_S_A_field4
unsigned field4 : 1; // #S_A_field4
__attribute__((preferred_type(A)))
unsigned field5 : 2; // #S_A_field5
__attribute__((preferred_type(A)))
unsigned field6 : 8; // #S_A_field6
__attribute__((preferred_type(A))) // #preferred_S_A_field7
int field7 : 1; // #S_A_field7
__attribute__((preferred_type(A))) // #preferred_S_A_field8
int field8 : 2; // #S_A_field8
__attribute__((preferred_type(A)))
int field9 : 8; // #S_A_field9
__attribute__((preferred_type(A)))
D field10 : 1; // #S_A_field10
__attribute__((preferred_type(A))) // #preferred_S_A_field11
D field11 : 2; // #S_A_field11
__attribute__((preferred_type(A)))
D field12 : 8; // #S_A_field12
} S_A;
typedef struct S_B {
B field1 : 1; // #S_B_field1
B field2 : 2; // #S_B_field2
B field3 : 8; // #S_B_field3
__attribute__((preferred_type(B))) // #preferred_S_B_field4
unsigned field4 : 1; // #S_B_field4
__attribute__((preferred_type(B)))
unsigned field5 : 2; // #S_B_field5
__attribute__((preferred_type(B)))
unsigned field6 : 8; // #S_B_field6
__attribute__((preferred_type(B))) // #preferred_S_B_field7
int field7 : 1; // #S_B_field7
__attribute__((preferred_type(B))) // #preferred_S_B_field8
int field8 : 2; // #S_B_field8
__attribute__((preferred_type(B)))
int field9 : 8; // #S_B_field9
__attribute__((preferred_type(B)))
D field10 : 1; // #S_B_field10
__attribute__((preferred_type(B))) // #preferred_S_B_field11
D field11 : 2; // #S_B_field11
__attribute__((preferred_type(B)))
D field12 : 8; // #S_B_field12
} S_B;
typedef struct S_C {
C field1 : 1; // #S_C_field1
C field2 : 2; // #S_C_field2
C field3 : 8; // #S_C_field3
__attribute__((preferred_type(C))) // #preferred_S_C_field4
unsigned field4 : 1; // #S_C_field4
__attribute__((preferred_type(C)))
unsigned field5 : 2; // #S_C_field5
__attribute__((preferred_type(C)))
unsigned field6 : 8; // #S_C_field6
__attribute__((preferred_type(C))) // #preferred_S_C_field7
int field7 : 1; // #S_C_field7
__attribute__((preferred_type(C))) // #preferred_S_C_field8
int field8 : 2; // #S_C_field8
__attribute__((preferred_type(C)))
int field9 : 8; // #S_C_field9
__attribute__((preferred_type(C)))
D field10 : 1; // #S_C_field10
__attribute__((preferred_type(C))) // #preferred_S_C_field11
D field11 : 2; // #S_C_field11
__attribute__((preferred_type(C)))
D field12 : 8; // #S_C_field12
} S_C;
void read_enumA(S_A *s) {
A x;
x = s->field1;
x = s->field2;
x = s->field3;
x = (A)s->field4;
x = (A)s->field5;
x = (A)s->field6;
x = (A)s->field7;
x = (A)s->field8;
x = (A)s->field9;
x = (A)s->field10;
x = (A)s->field11;
x = (A)s->field12;
}
void read_enumB(S_B *s) {
B x;
x = s->field1;
x = s->field2;
x = s->field3;
x = (B)s->field4;
x = (B)s->field5;
x = (B)s->field6;
x = (B)s->field7;
x = (B)s->field8;
x = (B)s->field9;
x = (B)s->field10;
x = (B)s->field11;
x = (B)s->field12;
}
void read_enumC(S_C *s) {
C x;
x = s->field1;
x = s->field2;
x = s->field3;
x = (C)s->field4;
x = (C)s->field5;
x = (C)s->field6;
x = (C)s->field7;
x = (C)s->field8;
x = (C)s->field9;
x = (C)s->field10;
x = (C)s->field11;
x = (C)s->field12;
}
void write_enumA(S_A *s, A x) {
s->field1 = x;
// bitfieldwarnings-warning@-1 {{bit-field 'field1' is not wide enough to store all enumerators of 'A'}}
// bitfieldwarnings-note@#S_A_field1 {{widen this field to 2 bits to store all values of 'A'}}
s->field2 = x;
s->field3 = x;
s->field4 = x;
// bitfieldwarnings-warning@-1 {{bit-field 'field4' is not wide enough to store all enumerators of 'A'}}
// bitfieldwarnings-note@#S_A_field4 {{widen this field to 2 bits to store all values of 'A'}}
s->field5 = x;
s->field6 = x;
s->field7 = x;
// bitfieldwarnings-warning@-1 {{bit-field 'field7' is not wide enough to store all enumerators of 'A'}}
// bitfieldwarnings-note@#S_A_field7 {{widen this field to 2 bits to store all values of 'A'}}
s->field8 = x;
// bitfieldwarnings-warning@-1 {{signed bit-field 'field8' needs an extra bit to represent the largest positive enumerators of 'A'}}
// bitfieldwarnings-note@#S_A_field8 {{consider making the bit-field type unsigned}}
s->field9 = x;
s->field10 = (D)x;
s->field11 = (D)x;
s->field12 = (D)x;
}
void write_enumB(S_B *s, B x) {
s->field1 = x;
// bitfieldwarnings-warning@-1 {{bit-field 'field1' is not wide enough to store all enumerators of 'B'}}
// bitfieldwarnings-note@#S_B_field1 {{widen this field to 2 bits to store all values of 'B'}}
s->field2 = x;
// bitfieldwarnings-warning@-1 {{signed bit-field 'field2' needs an extra bit to represent the largest positive enumerators of 'B'}}
// bitfieldwarnings-note@#S_B_field2 {{consider making the bit-field type unsigned}}
s->field3 = x;
s->field4 = (unsigned)x;
// expected-warning@-1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'B'}}
// expected-note@#S_B_field4 {{widen this field to 2 bits to store all values of 'B'}}
// expected-note@#preferred_S_B_field4 {{preferred type for bit-field 'B' specified here}}
s->field5 = (unsigned)x;
s->field6 = (unsigned)x;
s->field7 = (int)x;
// expected-warning@-1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'B'}}
// expected-note@#S_B_field7 {{widen this field to 2 bits to store all values of 'B'}}
// expected-note@#preferred_S_B_field7 {{preferred type for bit-field 'B' specified here}}
s->field8 = (int)x;
// expected-warning@-1 {{signed bit-field 'field8' needs an extra bit to represent the largest positive enumerators of preferred type 'B'}}
// expected-note@#S_B_field8 {{consider making the bit-field type unsigned}}
// expected-note@#preferred_S_B_field8 {{preferred type for bit-field 'B' specified here}}
s->field9 = (int)x;
s->field10 = (D)x;
s->field11 = (D)x;
s->field12 = (D)x;
}
void write_enumC(S_C *s, C x) {
s->field1 = x;
// bitfieldwarnings-warning@-1 {{bit-field 'field1' is not wide enough to store all enumerators of 'C'}}
// bitfieldwarnings-note@#S_C_field1 {{widen this field to 2 bits to store all values of 'C'}}
s->field2 = x;
s->field3 = x;
s->field4 = (unsigned)x;
// expected-warning@-1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'C'}}
// expected-note@#S_C_field4 {{widen this field to 2 bits to store all values of 'C'}}
// expected-note@#preferred_S_C_field4 {{preferred type for bit-field 'C' specified here}}
s->field5 = (unsigned)x;
s->field6 = (unsigned)x;
s->field7 = (int)x;
// expected-warning@-1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'C'}}
// expected-note@#S_C_field7 {{widen this field to 2 bits to store all values of 'C'}}
// expected-note@#preferred_S_C_field7 {{preferred type for bit-field 'C' specified here}}
s->field8 = (int)x;
// expected-warning@-1 {{signed bit-field 'field8' needs an extra bit to represent the largest positive enumerators of preferred type 'C'}}
// expected-note@#S_C_field8 {{consider making the bit-field type unsigned}}
// expected-note@#preferred_S_C_field8 {{preferred type for bit-field 'C' specified here}}
s->field9 = (int)x;
s->field10 = (D)x;
s->field11 = (D)x;
s->field12 = (D)x;
}
void write_enum_intA(struct S_A *s, int x) {
s->field1 = (A)x;
// bitfieldwarnings-warning@-1 {{bit-field 'field1' is not wide enough to store all enumerators of 'A'}}
// bitfieldwarnings-note@#S_A_field1 {{widen this field to 2 bits to store all values of 'A'}}
s->field2 = (A)x;
s->field3 = (A)x;
s->field4 = x;
// expected-warning@-1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'A'}}
// expected-note@#S_A_field4 {{widen this field to 2 bits to store all values of 'A'}}
// expected-note@#preferred_S_A_field4 {{preferred type for bit-field 'A' specified here}}
s->field5 = x;
s->field6 = x;
s->field7 = x;
// expected-warning@-1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'A'}}
// expected-note@#S_A_field7 {{widen this field to 2 bits to store all values of 'A'}}
// expected-note@#preferred_S_A_field7 {{preferred type for bit-field 'A' specified here}}
s->field8 = x;
// expected-warning@-1 {{signed bit-field 'field8' needs an extra bit to represent the largest positive enumerators of preferred type 'A'}}
// expected-note@#S_A_field8 {{consider making the bit-field type unsigned}}
// expected-note@#preferred_S_A_field8 {{preferred type for bit-field 'A' specified here}}
s->field9 = x;
s->field10 = (D)x;
s->field11 = (D)x;
s->field12 = (D)x;
}
void write_enum_intB(struct S_B *s, int x) {
s->field1 = (B)x;
// bitfieldwarnings-warning@-1 {{bit-field 'field1' is not wide enough to store all enumerators of 'B'}}
// bitfieldwarnings-note@#S_B_field1 {{widen this field to 2 bits to store all values of 'B'}}
s->field2 = (B)x;
// bitfieldwarnings-warning@-1 {{signed bit-field 'field2' needs an extra bit to represent the largest positive enumerators of 'B'}}
// bitfieldwarnings-note@#S_B_field2 {{consider making the bit-field type unsigned}}
s->field3 = (B)x;
s->field4 = x;
// expected-warning@-1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'B'}}
// expected-note@#S_B_field4 {{widen this field to 2 bits to store all values of 'B'}}
// expected-note@#preferred_S_B_field4 {{preferred type for bit-field 'B' specified here}}
s->field5 = x;
s->field6 = x;
s->field7 = x;
// expected-warning@-1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'B'}}
// expected-note@#S_B_field7 {{widen this field to 2 bits to store all values of 'B'}}
// expected-note@#preferred_S_B_field7 {{preferred type for bit-field 'B' specified here}}
s->field8 = x;
// expected-warning@-1 {{signed bit-field 'field8' needs an extra bit to represent the largest positive enumerators of preferred type 'B'}}
// expected-note@#S_B_field8 {{consider making the bit-field type unsigned}}
// expected-note@#preferred_S_B_field8 {{preferred type for bit-field 'B' specified here}}
s->field9 = x;
s->field10 = (D)x;
s->field11 = (D)x;
s->field12 = (D)x;
}
void write_enum_intC(struct S_C *s, int x) {
s->field1 = (C)x;
// bitfieldwarnings-warning@-1 {{bit-field 'field1' is not wide enough to store all enumerators of 'C'}}
// bitfieldwarnings-note@#S_C_field1 {{widen this field to 2 bits to store all values of 'C'}}
s->field2 = (C)x;
s->field3 = (C)x;
s->field4 = x;
// expected-warning@-1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'C'}}
// expected-note@#S_C_field4 {{widen this field to 2 bits to store all values of 'C'}}
// expected-note@#preferred_S_C_field4 {{preferred type for bit-field 'C' specified here}}
s->field5 = x;
s->field6 = x;
s->field7 = x;
// expected-warning@-1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'C'}}
// expected-note@#S_C_field7 {{widen this field to 2 bits to store all values of 'C'}}
// expected-note@#preferred_S_C_field7 {{preferred type for bit-field 'C' specified here}}
s->field8 = x;
// expected-warning@-1 {{signed bit-field 'field8' needs an extra bit to represent the largest positive enumerators of preferred type 'C'}}
// expected-note@#S_C_field8 {{consider making the bit-field type unsigned}}
// expected-note@#preferred_S_C_field8 {{preferred type for bit-field 'C' specified here}}
s->field9 = x;
s->field10 = (D)x;
s->field11 = (D)x;
s->field12 = (D)x;
}
void write_low_constantA(S_A *s) {
s->field1 = A_a;
s->field2 = A_a;
s->field3 = A_a;
s->field4 = A_a;
s->field5 = A_a;
s->field6 = A_a;
s->field7 = A_a;
s->field8 = A_a;
s->field9 = A_a;
s->field10 = (D)A_a;
s->field11 = (D)A_a;
s->field12 = (D)A_a;
};
void write_low_constantB(S_B *s) {
s->field1 = ENUM_CLASS_REF(B, B_a);
s->field2 = ENUM_CLASS_REF(B, B_a);
s->field3 = ENUM_CLASS_REF(B, B_a);
s->field4 = (unsigned)ENUM_CLASS_REF(B, B_a);
s->field5 = (unsigned)ENUM_CLASS_REF(B, B_a);
s->field6 = (unsigned)ENUM_CLASS_REF(B, B_a);
s->field7 = (int)ENUM_CLASS_REF(B, B_a);
s->field8 = (int)ENUM_CLASS_REF(B, B_a);
s->field9 = (int)ENUM_CLASS_REF(B, B_a);
s->field10 = (D)ENUM_CLASS_REF(B, B_a);
s->field11 = (D)ENUM_CLASS_REF(B, B_a);
s->field12 = (D)ENUM_CLASS_REF(B, B_a);
};
void write_low_constantC(S_C *s) {
s->field1 = ENUM_CLASS_REF(C, C_a);
s->field2 = ENUM_CLASS_REF(C, C_a);
s->field3 = ENUM_CLASS_REF(C, C_a);
s->field4 = (unsigned)ENUM_CLASS_REF(C, C_a);
s->field5 = (unsigned)ENUM_CLASS_REF(C, C_a);
s->field6 = (unsigned)ENUM_CLASS_REF(C, C_a);
s->field7 = (int)ENUM_CLASS_REF(C, C_a);
s->field8 = (int)ENUM_CLASS_REF(C, C_a);
s->field9 = (int)ENUM_CLASS_REF(C, C_a);
s->field10 = (D)ENUM_CLASS_REF(C, C_a);
s->field11 = (D)ENUM_CLASS_REF(C, C_a);
s->field12 = (D)ENUM_CLASS_REF(C, C_a);
};
void write_high_constantA(S_A *s) {
s->field1 = A_d;
// cpp-warning@-1 {{implicit truncation from 'A' to bit-field changes value from 3 to 1}}
// c-warning@-2 {{implicit truncation from 'int' to bit-field changes value from 3 to 1}}
s->field2 = A_d;
s->field3 = A_d;
s->field4 = A_d;
// cpp-warning@-1 {{implicit truncation from 'A' to bit-field changes value from 3 to 1}}
// c-warning@-2 {{implicit truncation from 'int' to bit-field changes value from 3 to 1}}
s->field5 = A_d;
s->field6 = A_d;
s->field7 = A_d;
// cpp-warning@-1 {{implicit truncation from 'A' to bit-field changes value from 3 to -1}}
// c-warning@-2 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
s->field8 = A_d;
// cpp-warning@-1 {{implicit truncation from 'A' to bit-field changes value from 3 to -1}}
// c-warning@-2 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
s->field9 = A_d;
s->field10 = (D)A_d;
// cpp-warning@-1 {{implicit truncation from 'D' to bit-field changes value from 3 to 1}}
// c-warning@-2 {{implicit truncation from 'D' (aka 'enum D') to bit-field changes value from 3 to 1}}
s->field11 = (D)A_d;
s->field12 = (D)A_d;
};
void write_high_constantB(S_B *s) {
s->field1 = ENUM_CLASS_REF(B, B_d);
// cpp-warning@-1 {{implicit truncation from 'B' to bit-field changes value from 3 to 1}}
// c-warning@-2 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
s->field2 = ENUM_CLASS_REF(B, B_d);
// c-warning@-1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
s->field3 = ENUM_CLASS_REF(B, B_d);
s->field4 = (unsigned)ENUM_CLASS_REF(B, B_d);
// expected-warning@-1 {{implicit truncation from 'unsigned int' to bit-field changes value from 3 to 1}}
s->field5 = (unsigned)ENUM_CLASS_REF(B, B_d);
s->field6 = (unsigned)ENUM_CLASS_REF(B, B_d);
s->field7 = (int)ENUM_CLASS_REF(B, B_d);
// expected-warning@-1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
s->field8 = (int)ENUM_CLASS_REF(B, B_d);
// expected-warning@-1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
s->field9 = (int)ENUM_CLASS_REF(B, B_d);
};
void write_high_constantC(S_C *s) {
s->field1 = ENUM_CLASS_REF(C, C_d);
// cpp-warning@-1 {{implicit truncation from 'C' to bit-field changes value from 3 to 1}}
// c-warning@-2 {{implicit truncation from 'unsigned int' to bit-field changes value from 3 to 1}}
s->field2 = ENUM_CLASS_REF(C, C_d);
s->field3 = ENUM_CLASS_REF(C, C_d);
s->field4 = (unsigned)ENUM_CLASS_REF(C, C_d);
// expected-warning@-1 {{implicit truncation from 'unsigned int' to bit-field changes value from 3 to 1}}
s->field5 = (unsigned)ENUM_CLASS_REF(C, C_d);
s->field6 = (unsigned)ENUM_CLASS_REF(C, C_d);
s->field7 = (int)ENUM_CLASS_REF(C, C_d);
// expected-warning@-1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
s->field8 = (int)ENUM_CLASS_REF(C, C_d);
// expected-warning@-1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
s->field9 = (int)ENUM_CLASS_REF(C, C_d);
};