Subject: bug#75964: Switching the Emacs build to -Wswitch-enum in src/

From: Pip Cet <[email-masked]>
Date: Sat, 01 Feb 2025 09:02:57 +0000

"Paul Eggert" <[email-masked]> writes:

> On 2025-01-31 03:05, Pip Cet wrote:
>> This GCC version is also patched to "infer" a switch type
>
> Suppose the inference is wrong: how does one easily pacify the modified
> GCC? Is it something like "case +PVEC_NORMAL:"?

I haven't submitted a patch yet, because I wasn't sure of such details.
In this case, yes, case +PVEC_NORMAL would work, but I had to test this :-)

> Suppose one case has an enum type and another case has some other type:
> is that an error?

I have code to make mixing several enums and mixing enums and integer
types an error, but the second is in use in Emacs, so that switch would
be a bit useless, and extending enums by starting a second enum starting
with the last value of the first one is also quite common.

>
>> +    case PVEC_FREE: eassume (0);
>> +    default: eassume (0);
>
> Must this be written that way? Suppose I do this:
>
>     case PVEC_FREE:
>     default:
>       eassume (false);

> Does that also pacify the modified GCC? Also, does emacs_abort () also
> pacify the modified GCC?

Absolutely.  You can also handle the default case, of course, it just
has to be there in addition to one case per enumerated value.

> Perhaps we should define a new macro eunreachable () that expands to
> eassume (false). eunreachable : unreachable :: eassert : assert. This
> might be a good idea regardless of anything else we do.

I was thinking the same thing!

I was going to propose emacs_unreachable (), but using the

emacs_abort : emacs_unreachable :: eassert : eassume

diagram.

>> alloc.c was a simple case because the enums are all internal
>> to Emacs and unlikely to change drastically without people touching the
>> code anyway.  image.c is very different in that regard.
>
> How does that sort of thing pan out?

Not sure I understand the question.  Right now, image people extend
their enums, we don't handle the new cases, the bug goes unnoticed until
it bites the user.

>> +  ws="$ws -Wswitch-enum"
>
> This won't work with the latest stable GCC, as it will cause false
> positives. We need a way to have Emacs use -Wswitch-enum only with the
> proposed patch installed.

While modifying GCC seems (to me) important, the behavior of unmodified
GCC is to produce some of the warnings we want, and I'm testing my patch
with both versions.

The difference is that modified GCC warns about some additional cases.
Most importantly, many enum values are stored in plain integer bitfields
rather than ENUM_BF ones, and the modified GCC warns about those.
(struct glyph::type is an example).  While that should be fixed by
turning them into ENUM_BF, we get warnings in the meantime.

> Perhaps the new GCC behavior should be enabled
> by a new GCC option (not -Wswitch-enum), so that it's easy to test
> whether the proposed GCC behavior is available.

I believe that applies to the "mismatched enum" code (two different
enums/enums and ints), but simply inferring that a switch is an enum
switch because all of its case labels are seems safe to me.  But I'll
think about it some more.

>> +ALL_CFLAGS = ${BASE_CFLAGS} ${PROFILING_CFLAGS} ${LDFLAGS} ${CPPFLAGS} ${CFLAGS} ${PACIFYING_CFLAGS}
>>  CPP_CFLAGS = ${BASE_CFLAGS} ${PROFILING_CFLAGS} ${CPPFLAGS} ${CFLAGS}
>>  o
>>  ALL_CXXFLAGS = $(filter-out ${NON_CXX_CFLAGS},${BASE_CFLAGS}) \
>>    ${PROFILING_CFLAGS} ${LDFLAGS} ${CPPFLAGS} ${CFLAGS} ${CXXFLAGS} ${HAIKU_CFLAGS}
>>
>> +unfixed_Wswitch_obj += ctags${EXEEXT}
>> +unfixed_Wswitch_obj += etags${EXEEXT}
>
> This sort of thing can be confusing. Do we need it at all? That is, once
> the fixes are in the C source files we shouldn't need to change the
> Makefile.

That was my initial reason for making it so unfixed_Wswitch_obj would
eventually be empty.

> Alternatively, perhaps it'd be better to use a pragma in the (I hope)
> rare places we need to pacify GCC.

I did propose that as an alternative, yes.

> E.g., how we currently treat
> -Wanalyzer-null-dereference in four .c files.

I've been bitten by "old" #pragmas disabling "bogus" warnings which
turned out not to be bogus before, and I think the #pragma syntax is
horrible, so I'd prefer the case +A: approach.

But the important thing is we start doing this to some files, not how we
fix what are likely to be two or three problematic files.  I'm totally
open to suggestions there.

The modified GCC is in no way necessary to switch to switch-enum; it
does catch some more cases, but those cases caught by plain old GCC are
those we should fix first.

The only effect of the modified GCC is that if we try working around the
current GCC's behavior by casting the switch value, that won't work with
the modified GCC.

Thank you so much for those comments!  Please do let me know if there's
anything else I can help with!

Pip