HomePhabricator

[clang-tidy] Ignore narrowing conversions in case of bitfields

Authored by steakhal on Nov 29 2021, 12:56 AM.

Description

[clang-tidy] Ignore narrowing conversions in case of bitfields

Bitfields are special. Due to integral promotion [conv.prom/5] bitfield
member access expressions are frequently wrapped by an implicit cast to
int if that type can represent all the values of the bitfield.

Consider these examples:

struct SmallBitfield { unsigned int id : 4; };
x.id & 1;             (case-1)
x.id & 1u;            (case-2)
x.id << 1u;           (case-3)
(unsigned)x.id << 1;  (case-4)

Due to the promotion rules, we would get a warning for case-1. It's
debatable how useful this is, but the user at least has a convenient way
of fixing it by adding the u unsigned-suffix to the literal as
demonstrated by case-2. However, this won't work for shift operators like
the one in case-3. In case of a normal binary operator, both operands
contribute to the result type. However, the type of the shift expression is
the promoted type of the left operand. One could still suppress this
superfluous warning by explicitly casting the bitfield member access as
case-4 demonstrates, but why? The compiler already knew that the value from
the member access should safely fit into an int, why do we have this
warning in the first place? So, hereby we suppress this specific scenario,
when a bitfield's value is implicitly cast to int (likely due to integral
promotion).

Note that the bitshift operation might invoke unspecified/undefined
behavior, but that's another topic, this checker is about detecting
conversion-related defects.

Example AST for x.id << 1:

BinaryOperator 'int' '<<'
|-ImplicitCastExpr 'int' <IntegralCast>
| `-ImplicitCastExpr 'unsigned int' <LValueToRValue>
|   `-MemberExpr 'unsigned int' lvalue bitfield .id
|     `-DeclRefExpr 'SmallBitfield' lvalue ParmVar 'x' 'SmallBitfield'
`-IntegerLiteral 'int' 1

Reviewed By: courbet

Differential Revision: https://reviews.llvm.org/D114105