Skip to content

Commit 3ac1aa4

Browse files
authored
[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.
1 parent 842e591 commit 3ac1aa4

File tree

5 files changed

+468
-7
lines changed

5 files changed

+468
-7
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,14 @@ Improvements to Clang's diagnostics
395395
constructors to initialize their non-modifiable members. The diagnostic is
396396
not new; being controlled via a warning group is what's new. Fixes #GH41104
397397

398+
- Improved bit-field diagnostics to consider the type specified by the
399+
``preferred_type`` attribute. These diagnostics are controlled by the flags
400+
``-Wpreferred-type-bitfield-enum-conversion`` and
401+
``-Wpreferred-type-bitfield-width``. These warnings are on by default as they
402+
they're only triggered if the authors are already making the choice to use
403+
``preferred_type`` attribute.
404+
405+
398406
Improvements to Clang's time-trace
399407
----------------------------------
400408

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ def SingleBitBitFieldConstantConversion :
4949
DiagGroup<"single-bit-bitfield-constant-conversion">;
5050
def BitFieldConstantConversion : DiagGroup<"bitfield-constant-conversion",
5151
[SingleBitBitFieldConstantConversion]>;
52+
def PreferredTypeBitFieldEnumConversion
53+
: DiagGroup<"preferred-type-bitfield-enum-conversion">;
54+
def PreferredTypeBitFieldWidth : DiagGroup<"preferred-type-bitfield-width">;
5255
def BitFieldEnumConversion : DiagGroup<"bitfield-enum-conversion">;
5356
def BitFieldWidth : DiagGroup<"bitfield-width">;
5457
def CompoundTokenSplitByMacro : DiagGroup<"compound-token-split-by-macro">;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6492,8 +6492,25 @@ def warn_signed_bitfield_enum_conversion : Warning<
64926492
"signed bit-field %0 needs an extra bit to represent the largest positive "
64936493
"enumerators of %1">,
64946494
InGroup<BitFieldEnumConversion>, DefaultIgnore;
6495+
def warn_preferred_type_bitfield_too_small_for_enum
6496+
: Warning<"bit-field %0 is not wide enough to store all enumerators of "
6497+
"preferred type %1">,
6498+
InGroup<PreferredTypeBitFieldEnumConversion>;
6499+
def warn_preferred_type_unsigned_bitfield_assigned_signed_enum
6500+
: Warning<"assigning value of preferred signed enum type %1 to unsigned "
6501+
"bit-field %0; "
6502+
"negative enumerators of enum %1 will be converted to positive "
6503+
"values">,
6504+
InGroup<PreferredTypeBitFieldEnumConversion>;
6505+
def warn_preferred_type_signed_bitfield_enum_conversion
6506+
: Warning<"signed bit-field %0 needs an extra bit to represent the largest "
6507+
"positive "
6508+
"enumerators of preferred type %1">,
6509+
InGroup<PreferredTypeBitFieldEnumConversion>;
64956510
def note_change_bitfield_sign : Note<
64966511
"consider making the bit-field type %select{unsigned|signed}0">;
6512+
def note_bitfield_preferred_type
6513+
: Note<"preferred type for bit-field %0 specified here">;
64976514

64986515
def warn_missing_braces : Warning<
64996516
"suggest braces around initialization of subobject">,

clang/lib/Sema/SemaChecking.cpp

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11293,9 +11293,16 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
1129311293
// The RHS is not constant. If the RHS has an enum type, make sure the
1129411294
// bitfield is wide enough to hold all the values of the enum without
1129511295
// truncation.
11296-
if (const auto *EnumTy = OriginalInit->getType()->getAs<EnumType>()) {
11296+
const auto *EnumTy = OriginalInit->getType()->getAs<EnumType>();
11297+
const PreferredTypeAttr *PTAttr = nullptr;
11298+
if (!EnumTy) {
11299+
PTAttr = Bitfield->getAttr<PreferredTypeAttr>();
11300+
if (PTAttr)
11301+
EnumTy = PTAttr->getType()->getAs<EnumType>();
11302+
}
11303+
if (EnumTy) {
1129711304
EnumDecl *ED = EnumTy->getDecl();
11298-
bool SignedBitfield = BitfieldType->isSignedIntegerType();
11305+
bool SignedBitfield = BitfieldType->isSignedIntegerOrEnumerationType();
1129911306

1130011307
// Enum types are implicitly signed on Windows, so check if there are any
1130111308
// negative enumerators to see if the enum was intended to be signed or
@@ -11309,19 +11316,28 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
1130911316
// on Windows where unfixed enums always use an underlying type of 'int'.
1131011317
unsigned DiagID = 0;
1131111318
if (SignedEnum && !SignedBitfield) {
11312-
DiagID = diag::warn_unsigned_bitfield_assigned_signed_enum;
11319+
DiagID =
11320+
PTAttr == nullptr
11321+
? diag::warn_unsigned_bitfield_assigned_signed_enum
11322+
: diag::
11323+
warn_preferred_type_unsigned_bitfield_assigned_signed_enum;
1131311324
} else if (SignedBitfield && !SignedEnum &&
1131411325
ED->getNumPositiveBits() == FieldWidth) {
11315-
DiagID = diag::warn_signed_bitfield_enum_conversion;
11326+
DiagID =
11327+
PTAttr == nullptr
11328+
? diag::warn_signed_bitfield_enum_conversion
11329+
: diag::warn_preferred_type_signed_bitfield_enum_conversion;
1131611330
}
11317-
1131811331
if (DiagID) {
1131911332
S.Diag(InitLoc, DiagID) << Bitfield << ED;
1132011333
TypeSourceInfo *TSI = Bitfield->getTypeSourceInfo();
1132111334
SourceRange TypeRange =
1132211335
TSI ? TSI->getTypeLoc().getSourceRange() : SourceRange();
1132311336
S.Diag(Bitfield->getTypeSpecStartLoc(), diag::note_change_bitfield_sign)
1132411337
<< SignedEnum << TypeRange;
11338+
if (PTAttr)
11339+
S.Diag(PTAttr->getLocation(), diag::note_bitfield_preferred_type)
11340+
<< ED;
1132511341
}
1132611342

1132711343
// 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,
1133411350
// Check the bitwidth.
1133511351
if (BitsNeeded > FieldWidth) {
1133611352
Expr *WidthExpr = Bitfield->getBitWidth();
11337-
S.Diag(InitLoc, diag::warn_bitfield_too_small_for_enum)
11338-
<< Bitfield << ED;
11353+
auto DiagID =
11354+
PTAttr == nullptr
11355+
? diag::warn_bitfield_too_small_for_enum
11356+
: diag::warn_preferred_type_bitfield_too_small_for_enum;
11357+
S.Diag(InitLoc, DiagID) << Bitfield << ED;
1133911358
S.Diag(WidthExpr->getExprLoc(), diag::note_widen_bitfield)
1134011359
<< BitsNeeded << ED << WidthExpr->getSourceRange();
11360+
if (PTAttr)
11361+
S.Diag(PTAttr->getLocation(), diag::note_bitfield_preferred_type)
11362+
<< ED;
1134111363
}
1134211364
}
1134311365

0 commit comments

Comments
 (0)