The sparse static C language checker contains a type attribute extension: __attribute__((bitwise)) The bitwise attribute modifies an arithmetic type so that the only arithmetic options permitted are the ones that are strictly bitwise. This is primarily used for data items with a specific endianness, such as the "network" side of the htonX() and ntohX() functions. The sparse documentation describes this as: Warn about unsupported operations or type mismatches with restricted integer types. Sparse supports an extended attribute, __attribute__((bitwise)), which creates a new restricted integer type from a base integer type, distinct from the base integer type and from any other restricted integer type not declared in the same declaration or typedef. For example, this allows programs to create typedefs for integer types with specific endianness. With -Wbitwise, Sparse will warn on any use of a restricted type in arithmetic operations other than bitwise operations, and on any conversion of one restricted type into another, except via a cast that includes __attribute__((force)). __bitwise ends up being a "stronger integer separation". That one doesn't allow you to mix with non-bitwise integers, so now it's much harder to lose the type by mistake. __bitwise is for *unique types* that cannot be mixed with other types, and that you'd never want to just use as a random integer (the integer 0 is special, though, and gets silently accepted iirc - it's kind of like "NULL" for pointers). So "gfp_t" or the "safe endianness" types would be __bitwise: you can only operate on them by doing specific operations that know about *that* particular type. Generally, you want bitwise if you are looking for type safety. Sparse does not issue these warnings by default.
Note in particular the bit about typedefs. Two identical declarations both using __attribute__((bitwise)) create two variables with different types, but two declarations both usin the same typedef declared with __attribute__((bitwise)) create two variables with the same type. In code: __attribute__((bitwise)) unsigned a, b; __attribute__((bitwise)) unsigned c, d; typedef __attribute__((bitwise)) unsigned foo_t; foo_t e, f; foo_t g, h; a and b have the same type. c and d have the same type. e, f, g, and h have the same type.
Suppose 'x' is of bitwise type. Is "x == x" an allowable operation? On the one hand, it isn't obvious whether "==" is "strictly bitwise". On the other hand, this seems well-defined, at least in cases where no promotion is needed. This applies to "!=" as well.
a == b and a != b are permitted. ~a is permitted iff sizeof(a) >= sizeof(int). !a and other booleanizing operations are permitted but produces integer (non-bitwise) results.
Also note that arithmetic operations between a bitwise and a known-zero value do not warn. The warning on ~ of a value smaller than int only occurs if the value is not subsequently stuffed back into the same bitwise type. For instance, this does not warn: typedef unsigned short __attribute__((bitwise)) le16; le16 i, j; le16 k = ~i | j;
(In reply to Josh Triplett from comment #4) > Also note that arithmetic operations between a bitwise and a known-zero > value do not warn. I'm curious about this too. If it means that the warnings should be deferred until after optimization, then it seems like maybe a difficult problem. On the other extreme, if this just refers to constant expressions, making this a purely front-end feature, then it seems more tractable.
(In reply to Tom Tromey from comment #5) > (In reply to Josh Triplett from comment #4) > > Also note that arithmetic operations between a bitwise and a known-zero > > value do not warn. > > I'm curious about this too. > If it means that the warnings should be deferred until after > optimization, then it seems like maybe a difficult problem. > On the other extreme, if this just refers to constant expressions, > making this a purely front-end feature, then it seems more tractable. Sparse does it for constant expressions only, as far as I can tell.
(In reply to Josh Triplett from comment #4) > Also note that arithmetic operations between a bitwise and a known-zero > value do not warn. > > The warning on ~ of a value smaller than int only occurs if the value is not > subsequently stuffed back into the same bitwise type. For instance, this > does not warn: > > typedef unsigned short __attribute__((bitwise)) le16; > > le16 i, j; > > le16 k = ~i | j; To elaborate on this with some implementation details of Sparse: applying ~ to a bitwise type smaller than an int produces a value of a corresponding bitwise type with the added attribute "fouled". Bitwise operations propagate the fouled bit if either operand has it, without warning. == and != will warn about fouled types. Assignments or conversions to the original unfouled bitwise type will work without warning, discarding the fouled bit. And any arithmetic operation that would warn about a bitwise type will warn about a fouled type, complaining that the type degraded to "int".
(In reply to Josh Triplett from comment #7) > (In reply to Josh Triplett from comment #4) > > Also note that arithmetic operations between a bitwise and a known-zero > > value do not warn. > > > > The warning on ~ of a value smaller than int only occurs if the value is not > > subsequently stuffed back into the same bitwise type. For instance, this > > does not warn: > > > > typedef unsigned short __attribute__((bitwise)) le16; > > > > le16 i, j; > > > > le16 k = ~i | j; > > To elaborate on this with some implementation details of Sparse: applying ~ > to a bitwise type smaller than an int produces a value of a corresponding > bitwise type with the added attribute "fouled". Bitwise operations > propagate the fouled bit if either operand has it, without warning. == and > != will warn about fouled types. Assignments or conversions to the original > unfouled bitwise type will work without warning, discarding the fouled bit. > And any arithmetic operation that would warn about a bitwise type will warn > about a fouled type, complaining that the type degraded to "int". One more detail: bitwise '&' of two fouled bitwise types will work and produce the same fouled type; but bitwise '&' of a bitwise type and the corresponding fouled bitwise type will produce the unfouled bitwise type. For details, see commit d24967cb847b7a04920698a9053ea8195046a831 in Sparse by Al Viro: Basically, we delay reporting an error on ~<short bitwise> for as long as possible in hope that taint will be cleansed later. Exact rules follow: * ~short_bitwise => corresponding fouled * any arithmetics that would be banned for bitwise => same warning as if we would have bitwise * if t1 is bitwise type and t2 - its fouled analog, then t1 & t2 => t1, t1 | t2 => t2, t1 ^ t2 => t2. * conversion of t2 to t1 is silent (be it passing as argument or assignment). Other conversions are banned. * x ? t1 : t2 => t2 * ~t2 => t2 (_not_ t1; something like ~(x ? y : ~y) is still fouled) * x ? t2 : t2 => t2, t2 {&,|,^} t2 => t2 (yes, even ^ - same as before). * x ? t2 : constant_valid_for_t1 => t2 * !t2 => warning, ditto for comparisons involving t2 in any way. * wrt casts t2 acts exactly as t1 would. * for sizeof, typeof and alignof t2 acts as promoted t1. Note that fouled can never be an lvalue or have types derived from it - can't happen.