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)

Most upvoted comments

Here’s another related issue. flags - other computes a different result than flags -= other

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 ! call from_bits_truncate, because it makes the flags & !other idiom silently clear unrecognized bits.

In other use cases, I can see how it’s desirable to have complement call from_bits_truncate. If some code defines its own bitflags and never deals with bits from the outside world, having those extra bits get set by complement could make things like is_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”?