bitflags: Treatment of unknown bits in operators is inconsistent
The complement
function’s documentation says “the returned set contains all the flags which are not set in self
, but which are allowed for this type”. So primarily here, the phrase “allowed for this type” is ambiguous; the word “allowed” doesn’t appear to be used anywhere else in the documentation, and bitflags in general seems to “allow” bits that aren’t defined, with the new from_bits_retain
function.
Looking at the code, it appears complement
does a from_bits_truncate
. Secondarily, I just converted some existing code to bitflags 2.0 and found this behavior surprising. Bitflags allows users to create values with from_bits_retain
, and I assumed that applying !
would act like a plain bitwise complement, and had a debugging adventure trying to figure why code that looked like it was setting a flag wasn’t actually setting it.
About this issue
- Original URL
- State: closed
- Created a year ago
- Comments: 18 (10 by maintainers)
That’s absolutely a bug and needs to be fixed. It seems like things are basically broken enough to justify fixing them all up together so that unknown bits are always respected. The other niche case we have to consider are multi-bit flags, where they’re treated as only representing a single flag when all related bits are set, not just when any are.
It may be that there are different use cases that want different things. In my use case, the bits are defined by an external API, and new flags can be defined that my code doesn’t know about yet, and I want my code to default to preserving such flags. In this use case, it’s undesirable to have
!
callfrom_bits_truncate
, because it makes theflags & !other
idiom silently clear unrecognized bits.In other use cases, I can see how it’s desirable to have
complement
callfrom_bits_truncate
. If some code defines its own bitflags and never deals with bits from the outside world, having those extra bits get set bycomplement
could make things likeis_empty()
unexpectedly return false.Would it make sense to add some new syntax to the
bitflags
macro to allow users to specify when they have the external-API use case, and that all bits should be treated as “known”?