Re: enabling -Werror=assign-enum for kernel

John Baldwin <[email protected]>
Newsgroups gmane.os.freebsd.current
Message-ID <0e34f0c6-b41a-49d3-9c41-3ec84ea2e0be__24202.2624284559$1787764579$gmane$org@FreeBSD.org>
On 8/26/26 13:02, Gleb Smirnoff wrote:
>    John,
> 
> On Wed, Aug 26, 2026 at 09:17:36AM -0400, John Baldwin wrote:
> J> > modern clang has a nice feature: it allows to catch enum misuse.  For example:
> J> >
> J> > enum foo { A = 1, B } var;
> J> > var = 1;	/* success */
> J> > var = A;	/* success */
> J> > var = B;	/* success */
> J> > var = 3;	/* fail */
> J> >
> J> > What about enums that are used as flags? For that it has
> J> > __attribute__((flag_enum)).  This will allow using combination of values and
> J> > clearing them:
> J> >
> J> > var = A | B;	/* success */
> J> > var &= ~A;	/* success */
> J> > var = 3;	/* fail */
> J>
> J> Note that C++ doesn't allow this at the language level.  When I converted ctld to
> J> C++ I had to adjust some enums to be simple #define's instead in the ctl headers.
> 
> Noted.  I can't make a judgement if it is a smart restriction by C++ or not.
> In our case using enums as flags is common and handy and Werror=assign-enum in
> combination with __attribute__((flag_enum)) will make this use fortified
> against mistakes.

Mostly my point is that over time we may be forced to convert away from enums to
plain constants if more of the base system starts using C++ anyway.  At least for
enums exposed to userspace.

> Question: what is our policy of adding attributes into code?  The convetion is
> that compilers warn and don't fail on unknown attributes, so adding them as
> bare words definitely works.  I personally prefer to avoid use of preprocessor
> when it is possible, so I'm for adding the __attribute__((flag_enum)) as is.
> However, few people who compile with gcc may be unhappy about lots of warnings.
> The best practice to shut these warning is:
> 
> #ifndef __flag_enum
> #ifdef __clang__
> #define	__flag_enum	__attribute__((flag_enum))
> #else
> #define	__flag_enum
> #endif
> #endif
> 
> This would require us use FreeBSD-specific keyword in the code.  Which one is
> the preferred way to move forward?

Normally we define a new wrapper in <sys/cdefs.h> so that the only #ifdef's are in
that header, and the rest of the code uses the wrapper macro unconditionally.

> J> > This seems like a nice enforcement of a good code.  I already found a few
> J> > hamrless bugs with it and one in e1000 that could be a real bug.  It also
> J> > highlights some sketchy code that better be refactored.
> J> >
> J> > I have a branch where LINT is compilable with -Werror=assign-enum:
> J> >
> J> > https://github.com/freebsd/freebsd-src/compare/main...glebius:FreeBSD:Werror%3Dassign-enum
> J> >
> J> > There are basically three parts that require work:
> J> >
> J> > 1) The most common violators are SYSINIT(9)s that use (SI_SUB_FOO + 1) as
> J> > argument.  I have posted a pack of reviews to cover that.
> J>
> J> So I think this is probably sensible for SI_SUB_* to define new values.  I
> J> worry about SI_ORDER_*.  Possibly we should use plain #define's for SI_ORDER_*
> J> instead of an enum if we aren't already.  I wonder if you ran into any cases
> J> where we use an SI_ORDER_* value that is an expression?
> 
> Nope.  Everything in SYSINIT(9) that was violating Werror=assign-enum is
> already in main, except ipfw.  One bit left is ipfw's sysinits, which I left
> for later, since I wanted more changes to it.
> 
> I don't agree we should use plain #define for SI_ORDER_*.  The current code
> combined with Werror=assign-enum will enforce intentionality and thoughtfulness
> when adding new sysinits.  Would prevent quick adhoc additions in the "works
> for me" style.

At some point 'SI_ORDER_<ENGLISH ORDINAL TERM>' isn't really more readable than
just using an integer.  In particular for offsets relative to SI_ORDER_FIRST.
Today we probably don't have more than SI_ORDER_THIRD, but something like
SI_ORDER_FOUR_HUNDRED_FIFTY_SEVENTH would be a mouthful compared to
'SI_ORDER_FIRST + 456'.  For SI_SUB_* the names are generally descriptive of
some subsystem, but SI_ORDER are inherently a range of explicitly numbered values
along with a few special cases such as SI_ORDER_ANY/LAST.  The special cases
make sense as names.  The numeric range makes less sense as names.  However, if
we all fit fine today with just SI_ORDER_THIRD then it's probably ok.  I worried
we might have a broader range than just FIRST/SECOND/THIRD.

> J> > 2) hwpmc has enum pmc_event that is generated by preprocessor and its use is
> J> > sketchy,    thus files that utilize HWPMC_HOOKS are temporarily excluded from
> J> > the enforcements.
> J> >
> J> > 3) I was too tired to look at OFED, thus just disabled it in ${OFED_C} in
> J> > kern.mk
> J>
> J> Also, we should avoid gratuitous diffs to OFED since it is really contrib code,
> J> so your approach here is fine.  OTOH, note that other Linuxy bits like the wifi
> J> drivers and drm drivers might also need to opt out of this via CFLAGS.
> 
> I touched ZFS though.  It appeared to be 100% clean and pretty.  Just adding
> __attribute__((flag_enum)) to all enums that are used as flags was enough.
> Zero other corrections, zero failures.  I will look into upstreaming the ZFS
> part when we got overall agreement that we enable Werror=assign-enum for the
> kernel.

Yes but I wouldn't want to require getting Linux as a whole to adopt this as a
prerequisite for us to adopt it, and local diffs we have to OFED make future
merges a headache so should be avoided when possible.  Some day I'd like to do
true vendor imports into sys/contrib/rdma or the like, but OFED wasn't maintained
that way in the past and is a giant rats nest of partially merged bits and missing
bug fixes, etc.  It's a bit of work to get to a more maintainble thing, and needless
local diffs only make that work even harder.

-- 
John Baldwin
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.