* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
@ 2025-01-31 9:39 Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-31 11:05 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-31 11:50 ` Eli Zaretskii
0 siblings, 2 replies; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-01-31 9:39 UTC (permalink / raw)
To: 75964
I'm proposing to enable -Wswitch-enum as a warning option when compiling
Emacs C sources in src/, and to modify those source files to make good
use of it.
GCC's -Wswitch-enum will warn about a switch statement of the form
enum ABC { A, B, C };
enum ABC x = ...;
switch (x)
{
case A:
case B:
return 1;
default:
return 0;
}
The reason is that the "default" branch covers both case C and the case
that the value of x isn't A, B, or, C. C allows this latter case and
requires compilers to support it, and some Emacs code relies on
non-enumerated values to be valid.
Instead, with -Wswitch-enum, one should write:
enum ABC { A, B, C };
enum ABC x = ...;
switch (x)
{
case A:
case B:
return 1;
case C:
return 0;
default: eassume (false);
}
assuming x is known never to have a non-enumerated value (this is almost
always the case in Emacs).
The limitations of other approaches have become quite apparent in
previous threads discussing this. Let's try this one.
While I think we can and should argue about the best way to write a
switch statement over an enum, I want to state one personal opinion:
replacing switch statements by if constructs, array lookups, or even
array lookups of function pointers is the wrong approach here.
Some preliminary patches to follow once this has a bug number.
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-01-31 9:39 bug#75964: Switching the Emacs build to -Wswitch-enum in src/ Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-01-31 11:05 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-31 18:30 ` Paul Eggert
2025-01-31 21:46 ` Paul Eggert
2025-01-31 11:50 ` Eli Zaretskii
1 sibling, 2 replies; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-01-31 11:05 UTC (permalink / raw)
To: 75964, Paul Eggert, Stefan Kangas
Pip Cet <pipcet@protonmail.com> writes:
> Some preliminary patches to follow once this has a bug number.
Here's a first small patch series. Some initial remarks
1. I built a fresh GCC from scratch, so I'd be able to get the latest
warnings. Unfortunately, GCC now thinks:
static const char hexchar[16] = "0123456789ABCDEF";
is unsafe and the [16] should be [17] or omitted. So while I changed
that in my build, I'm not including that in the patches.
This GCC version is also patched to "infer" a switch type: if you do
int x:n
switch (x)
{
case PVEC_NORMAL:
return;
default:
emacs_abort ();
}
this GCC version will warn about the other PVEC types, which should
appear explicitly in the enum, because PVEC_NORMAL is part of an
enumeration, even though x is an integer.
Onwards to the patches:
First. it enables -Wswitch-enum if the
compiler supports it:
From 474b0b2aa3deb1a674dd7b112bcdbbe596475ad1 Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@protonmail.com>
Subject: [PATCH 1/5] Enable -Wswitch-enum (bug#75964)
* configure.ac: Enable warning -Wswitch-enum if available.
---
configure.ac | 1 +
1 file changed, 1 insertion(+)
diff --git a/configure.ac b/configure.ac
index ba39074c83a..caa12347738 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1855,6 +1855,7 @@ AC_DEFUN
[nw="$nw -Wsuggest-attribute=noreturn"])
gl_MANYWARN_ALL_GCC([ws])
+ ws="$ws -Wswitch-enum"
gl_MANYWARN_COMPLEMENT([ws], [$ws], [$nw])
for w in $ws; do
gl_WARN_ADD([$w])
--
2.48.1
Then, it adds a PACIFYING_CFLAGS variable set on a per-file basis to
src/Makefile.in, so we can list those files which we don't want to
compile with this new warning flag yet:
From bb884c228ee27c97682007119a21ec202c3799ee Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@protonmail.com>
Subject: [PATCH] Disable -Wswitch-enum in lib-src (bug#75964)
* lib-src/Makefile.in (PACIFYING_CFLAGS, unfixed_Wswitch_obj): New
variables. Use it.
---
lib-src/Makefile.in | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/lib-src/Makefile.in b/lib-src/Makefile.in
index 439d9a1a52d..b2b596cfac4 100644
--- a/lib-src/Makefile.in
+++ b/lib-src/Makefile.in
@@ -274,12 +274,27 @@ BASE_CFLAGS =
-I. -I../src -I../lib \
-I${srcdir} -I${srcdir}/../src -I${srcdir}/../lib
-ALL_CFLAGS = ${BASE_CFLAGS} ${PROFILING_CFLAGS} ${LDFLAGS} ${CPPFLAGS} ${CFLAGS}
+ALL_CFLAGS = ${BASE_CFLAGS} ${PROFILING_CFLAGS} ${LDFLAGS} ${CPPFLAGS} ${CFLAGS} ${PACIFYING_CFLAGS}
CPP_CFLAGS = ${BASE_CFLAGS} ${PROFILING_CFLAGS} ${CPPFLAGS} ${CFLAGS}
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}
+unfixed_Wswitch_obj += ebrowse${EXEEXT}
+unfixed_Wswitch_obj += ctags${EXEEXT}
+unfixed_Wswitch_obj += asset-directory-tool${EXEEXT}
+unfixed_Wswitch_obj += ebrowse${EXEEXT}
+unfixed_Wswitch_obj += make-docfile${EXEEXT}
+unfixed_Wswitch_obj += make-fingerprint${EXEEXT}
+unfixed_Wswitch_obj += movemail${EXEEXT}
+unfixed_Wswitch_obj += emacsclient${EXEEXT}
+unfixed_Wswitch_obj += emacsclientw${EXEEXT}
+unfixed_Wswitch_obj += hexl${EXEEXT}
+unfixed_Wswitch_obj += update-game-score${EXEEXT}
+
+$(unfixed_Wswitch_obj): PACIFYING_CFLAGS += -Wno-switch-enum -Wno-switch
# Configuration files for .o files to depend on.
config_h = ../src/config.h $(srcdir)/../src/conf_post.h
--
2.48.1
From ccf6b7f0690bcc11d0cba55997cd427fd7d18804 Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@protonmail.com>
Subject: [PATCH 3/5] Per-file flags to disable -Wswitch-enum in src
(bug#75964)
* src/Makefile.in (unfixed_wenum_obj): New variable. Make it include
all known objects. (.c.o): Use it.
---
src/Makefile.in | 177 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 176 insertions(+), 1 deletion(-)
diff --git a/src/Makefile.in b/src/Makefile.in
index d987124d29d..cb75ffc8482 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -455,7 +455,7 @@ ALL_CXX_CFLAGS =
.SUFFIXES: .c .m .cc
.c.o:
- $(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $(PROFILING_CFLAGS) $<
+ $(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $(PROFILING_CFLAGS) $(PACIFYING_CFLAGS) $<
.m.o:
$(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_OBJC_CFLAGS) $(PROFILING_CFLAGS) $<
.cc.o:
@@ -484,6 +484,181 @@ base_obj =
$(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \
$(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) \
$(HAIKU_OBJ) $(PGTK_OBJ) $(ANDROID_OBJ)
+
+unfixed_Wswitch_obj += alloc.o
+unfixed_Wswitch_obj += android-emacs.o
+unfixed_Wswitch_obj += android.o
+unfixed_Wswitch_obj += androidfns.o
+unfixed_Wswitch_obj += androidfont.o
+unfixed_Wswitch_obj += androidmenu.o
+unfixed_Wswitch_obj += androidselect.o
+unfixed_Wswitch_obj += androidterm.o
+unfixed_Wswitch_obj += androidvfs.o
+unfixed_Wswitch_obj += atimer.o
+unfixed_Wswitch_obj += bidi.o
+unfixed_Wswitch_obj += bignum.o
+unfixed_Wswitch_obj += buffer.o
+unfixed_Wswitch_obj += bytecode.o
+unfixed_Wswitch_obj += callint.o
+unfixed_Wswitch_obj += callproc.o
+unfixed_Wswitch_obj += casefiddle.o
+unfixed_Wswitch_obj += casetab.o
+unfixed_Wswitch_obj += category.o
+unfixed_Wswitch_obj += ccl.o
+unfixed_Wswitch_obj += character.o
+unfixed_Wswitch_obj += charset.o
+unfixed_Wswitch_obj += chartab.o
+unfixed_Wswitch_obj += cm.o
+unfixed_Wswitch_obj += cmds.o
+unfixed_Wswitch_obj += coding.o
+unfixed_Wswitch_obj += comp.o
+unfixed_Wswitch_obj += composite.o
+unfixed_Wswitch_obj += cygw32.o
+unfixed_Wswitch_obj += data.o
+unfixed_Wswitch_obj += dbusbind.o
+unfixed_Wswitch_obj += decompress.o
+unfixed_Wswitch_obj += dired.o
+unfixed_Wswitch_obj += dispnew.o
+unfixed_Wswitch_obj += doc.o
+unfixed_Wswitch_obj += doprnt.o
+unfixed_Wswitch_obj += dosfns.o
+unfixed_Wswitch_obj += dynlib.o
+unfixed_Wswitch_obj += editfns.o
+unfixed_Wswitch_obj += emacs-module.o
+unfixed_Wswitch_obj += emacs.o
+unfixed_Wswitch_obj += emacsgtkfixed.o
+unfixed_Wswitch_obj += eval.o
+unfixed_Wswitch_obj += fileio.o
+unfixed_Wswitch_obj += filelock.o
+unfixed_Wswitch_obj += firstfile.o
+unfixed_Wswitch_obj += floatfns.o
+unfixed_Wswitch_obj += fns.o
+unfixed_Wswitch_obj += font.o
+unfixed_Wswitch_obj += fontset.o
+unfixed_Wswitch_obj += frame.o
+unfixed_Wswitch_obj += fringe.o
+unfixed_Wswitch_obj += ftcrfont.o
+unfixed_Wswitch_obj += ftfont.o
+unfixed_Wswitch_obj += gfilenotify.o
+unfixed_Wswitch_obj += gmalloc.o
+unfixed_Wswitch_obj += gnutls.o
+unfixed_Wswitch_obj += gtkutil.o
+unfixed_Wswitch_obj += haiku.o
+unfixed_Wswitch_obj += haiku_io.o
+unfixed_Wswitch_obj += haikufns.o
+unfixed_Wswitch_obj += haikufont.o
+unfixed_Wswitch_obj += haikuimage.o
+unfixed_Wswitch_obj += haikumenu.o
+unfixed_Wswitch_obj += haikuselect.o
+unfixed_Wswitch_obj += haikuterm.o
+unfixed_Wswitch_obj += hbfont.o
+unfixed_Wswitch_obj += image.o
+unfixed_Wswitch_obj += indent.o
+unfixed_Wswitch_obj += inotify.o
+unfixed_Wswitch_obj += insdel.o
+unfixed_Wswitch_obj += intervals.o
+unfixed_Wswitch_obj += itree.o
+unfixed_Wswitch_obj += json.o
+unfixed_Wswitch_obj += keyboard.o
+unfixed_Wswitch_obj += keymap.o
+unfixed_Wswitch_obj += kqueue.o
+unfixed_Wswitch_obj += lastfile.o
+unfixed_Wswitch_obj += lcms.o
+unfixed_Wswitch_obj += lread.o
+unfixed_Wswitch_obj += macfont.o
+unfixed_Wswitch_obj += macros.o
+unfixed_Wswitch_obj += marker.o
+unfixed_Wswitch_obj += menu.o
+unfixed_Wswitch_obj += minibuf.o
+unfixed_Wswitch_obj += msdos.o
+unfixed_Wswitch_obj += nsfns.o
+unfixed_Wswitch_obj += nsfont.o
+unfixed_Wswitch_obj += nsimage.o
+unfixed_Wswitch_obj += nsmenu.o
+unfixed_Wswitch_obj += nsselect.o
+unfixed_Wswitch_obj += nsterm.o
+unfixed_Wswitch_obj += nsxwidget.o
+unfixed_Wswitch_obj += pdumper.o
+unfixed_Wswitch_obj += pgtkfns.o
+unfixed_Wswitch_obj += pgtkim.o
+unfixed_Wswitch_obj += pgtkmenu.o
+unfixed_Wswitch_obj += pgtkselect.o
+unfixed_Wswitch_obj += pgtkterm.o
+unfixed_Wswitch_obj += print.o
+unfixed_Wswitch_obj += process.o
+unfixed_Wswitch_obj += profiler.o
+unfixed_Wswitch_obj += ralloc.o
+unfixed_Wswitch_obj += regex-emacs.o
+unfixed_Wswitch_obj += region-cache.o
+unfixed_Wswitch_obj += scroll.o
+unfixed_Wswitch_obj += search.o
+unfixed_Wswitch_obj += sfnt.o
+unfixed_Wswitch_obj += sfntfont-android.o
+unfixed_Wswitch_obj += sfntfont.o
+unfixed_Wswitch_obj += sheap.o
+unfixed_Wswitch_obj += sort.o
+unfixed_Wswitch_obj += sound.o
+unfixed_Wswitch_obj += sqlite.o
+unfixed_Wswitch_obj += syntax.o
+unfixed_Wswitch_obj += sysdep.o
+unfixed_Wswitch_obj += systhread.o
+unfixed_Wswitch_obj += term.o
+unfixed_Wswitch_obj += termcap.o
+unfixed_Wswitch_obj += terminal.o
+unfixed_Wswitch_obj += terminfo.o
+unfixed_Wswitch_obj += textconv.o
+unfixed_Wswitch_obj += textprop.o
+unfixed_Wswitch_obj += thread.o
+unfixed_Wswitch_obj += timefns.o
+unfixed_Wswitch_obj += tparam.o
+unfixed_Wswitch_obj += treesit.o
+unfixed_Wswitch_obj += undo.o
+unfixed_Wswitch_obj += unexaix.o
+unfixed_Wswitch_obj += unexcoff.o
+unfixed_Wswitch_obj += unexcw.o
+unfixed_Wswitch_obj += unexelf.o
+unfixed_Wswitch_obj += unexhp9k800.o
+unfixed_Wswitch_obj += unexmacosx.o
+unfixed_Wswitch_obj += unexsol.o
+unfixed_Wswitch_obj += unexw32.o
+unfixed_Wswitch_obj += vm-limit.o
+unfixed_Wswitch_obj += w16select.o
+unfixed_Wswitch_obj += w32.o
+unfixed_Wswitch_obj += w32console.o
+unfixed_Wswitch_obj += w32cygwinx.o
+unfixed_Wswitch_obj += w32dwrite.o
+unfixed_Wswitch_obj += w32fns.o
+unfixed_Wswitch_obj += w32font.o
+unfixed_Wswitch_obj += w32heap.o
+unfixed_Wswitch_obj += w32image.o
+unfixed_Wswitch_obj += w32inevt.o
+unfixed_Wswitch_obj += w32menu.o
+unfixed_Wswitch_obj += w32notify.o
+unfixed_Wswitch_obj += w32proc.o
+unfixed_Wswitch_obj += w32reg.o
+unfixed_Wswitch_obj += w32select.o
+unfixed_Wswitch_obj += w32term.o
+unfixed_Wswitch_obj += w32uniscribe.o
+unfixed_Wswitch_obj += w32xfns.o
+unfixed_Wswitch_obj += widget.o
+unfixed_Wswitch_obj += window.o
+unfixed_Wswitch_obj += xdisp.o
+unfixed_Wswitch_obj += xfaces.o
+unfixed_Wswitch_obj += xfns.o
+unfixed_Wswitch_obj += xfont.o
+unfixed_Wswitch_obj += xftfont.o
+unfixed_Wswitch_obj += xgselect.o
+unfixed_Wswitch_obj += xmenu.o
+unfixed_Wswitch_obj += xml.o
+unfixed_Wswitch_obj += xrdb.o
+unfixed_Wswitch_obj += xselect.o
+unfixed_Wswitch_obj += xsettings.o
+unfixed_Wswitch_obj += xsmfns.o
+unfixed_Wswitch_obj += xterm.o
+unfixed_Wswitch_obj += xwidget.o
+
+$(unfixed_Wswitch_obj): PACIFYING_CFLAGS += -Wno-switch-enum -Wno-switch
+
doc_obj = $(base_obj) $(NS_OBJC_OBJ)
obj = $(doc_obj) $(HAIKU_CXX_OBJ)
--
2.48.1
Since that listed *all* files, let's remove those which do not actually
contain any switch statements:
From 8ed603be95fdfe911cd567b88a7a1992695f4dc7 Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@protonmail.com>
Subject: [PATCH 4/5] C files without switch statements are safe for
-Wswitch-enum (bug#75964)
* src/Makefile.in (unfixed_Wswitch_obj): Remove files which do not
contain any switches.
---
src/Makefile.in | 61 -------------------------------------------------
1 file changed, 61 deletions(-)
diff --git a/src/Makefile.in b/src/Makefile.in
index cb75ffc8482..8f54006e276 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -486,88 +486,57 @@ base_obj =
$(HAIKU_OBJ) $(PGTK_OBJ) $(ANDROID_OBJ)
unfixed_Wswitch_obj += alloc.o
-unfixed_Wswitch_obj += android-emacs.o
unfixed_Wswitch_obj += android.o
unfixed_Wswitch_obj += androidfns.o
-unfixed_Wswitch_obj += androidfont.o
-unfixed_Wswitch_obj += androidmenu.o
-unfixed_Wswitch_obj += androidselect.o
unfixed_Wswitch_obj += androidterm.o
unfixed_Wswitch_obj += androidvfs.o
unfixed_Wswitch_obj += atimer.o
unfixed_Wswitch_obj += bidi.o
-unfixed_Wswitch_obj += bignum.o
unfixed_Wswitch_obj += buffer.o
unfixed_Wswitch_obj += bytecode.o
unfixed_Wswitch_obj += callint.o
-unfixed_Wswitch_obj += callproc.o
-unfixed_Wswitch_obj += casefiddle.o
-unfixed_Wswitch_obj += casetab.o
-unfixed_Wswitch_obj += category.o
unfixed_Wswitch_obj += ccl.o
-unfixed_Wswitch_obj += character.o
-unfixed_Wswitch_obj += charset.o
-unfixed_Wswitch_obj += chartab.o
unfixed_Wswitch_obj += cm.o
-unfixed_Wswitch_obj += cmds.o
unfixed_Wswitch_obj += coding.o
unfixed_Wswitch_obj += comp.o
-unfixed_Wswitch_obj += composite.o
-unfixed_Wswitch_obj += cygw32.o
unfixed_Wswitch_obj += data.o
unfixed_Wswitch_obj += dbusbind.o
-unfixed_Wswitch_obj += decompress.o
unfixed_Wswitch_obj += dired.o
unfixed_Wswitch_obj += dispnew.o
-unfixed_Wswitch_obj += doc.o
unfixed_Wswitch_obj += doprnt.o
unfixed_Wswitch_obj += dosfns.o
-unfixed_Wswitch_obj += dynlib.o
unfixed_Wswitch_obj += editfns.o
unfixed_Wswitch_obj += emacs-module.o
unfixed_Wswitch_obj += emacs.o
-unfixed_Wswitch_obj += emacsgtkfixed.o
unfixed_Wswitch_obj += eval.o
unfixed_Wswitch_obj += fileio.o
unfixed_Wswitch_obj += filelock.o
-unfixed_Wswitch_obj += firstfile.o
-unfixed_Wswitch_obj += floatfns.o
unfixed_Wswitch_obj += fns.o
unfixed_Wswitch_obj += font.o
unfixed_Wswitch_obj += fontset.o
unfixed_Wswitch_obj += frame.o
unfixed_Wswitch_obj += fringe.o
-unfixed_Wswitch_obj += ftcrfont.o
unfixed_Wswitch_obj += ftfont.o
unfixed_Wswitch_obj += gfilenotify.o
unfixed_Wswitch_obj += gmalloc.o
unfixed_Wswitch_obj += gnutls.o
unfixed_Wswitch_obj += gtkutil.o
-unfixed_Wswitch_obj += haiku.o
unfixed_Wswitch_obj += haiku_io.o
unfixed_Wswitch_obj += haikufns.o
unfixed_Wswitch_obj += haikufont.o
-unfixed_Wswitch_obj += haikuimage.o
-unfixed_Wswitch_obj += haikumenu.o
unfixed_Wswitch_obj += haikuselect.o
unfixed_Wswitch_obj += haikuterm.o
unfixed_Wswitch_obj += hbfont.o
unfixed_Wswitch_obj += image.o
unfixed_Wswitch_obj += indent.o
-unfixed_Wswitch_obj += inotify.o
unfixed_Wswitch_obj += insdel.o
-unfixed_Wswitch_obj += intervals.o
unfixed_Wswitch_obj += itree.o
unfixed_Wswitch_obj += json.o
unfixed_Wswitch_obj += keyboard.o
unfixed_Wswitch_obj += keymap.o
-unfixed_Wswitch_obj += kqueue.o
-unfixed_Wswitch_obj += lastfile.o
-unfixed_Wswitch_obj += lcms.o
unfixed_Wswitch_obj += lread.o
unfixed_Wswitch_obj += macfont.o
unfixed_Wswitch_obj += macros.o
-unfixed_Wswitch_obj += marker.o
unfixed_Wswitch_obj += menu.o
unfixed_Wswitch_obj += minibuf.o
unfixed_Wswitch_obj += msdos.o
@@ -580,80 +549,50 @@ unfixed_Wswitch_obj +=
unfixed_Wswitch_obj += nsxwidget.o
unfixed_Wswitch_obj += pdumper.o
unfixed_Wswitch_obj += pgtkfns.o
-unfixed_Wswitch_obj += pgtkim.o
-unfixed_Wswitch_obj += pgtkmenu.o
-unfixed_Wswitch_obj += pgtkselect.o
unfixed_Wswitch_obj += pgtkterm.o
unfixed_Wswitch_obj += print.o
unfixed_Wswitch_obj += process.o
unfixed_Wswitch_obj += profiler.o
-unfixed_Wswitch_obj += ralloc.o
unfixed_Wswitch_obj += regex-emacs.o
-unfixed_Wswitch_obj += region-cache.o
-unfixed_Wswitch_obj += scroll.o
unfixed_Wswitch_obj += search.o
unfixed_Wswitch_obj += sfnt.o
-unfixed_Wswitch_obj += sfntfont-android.o
unfixed_Wswitch_obj += sfntfont.o
-unfixed_Wswitch_obj += sheap.o
-unfixed_Wswitch_obj += sort.o
unfixed_Wswitch_obj += sound.o
unfixed_Wswitch_obj += sqlite.o
unfixed_Wswitch_obj += syntax.o
unfixed_Wswitch_obj += sysdep.o
-unfixed_Wswitch_obj += systhread.o
unfixed_Wswitch_obj += term.o
-unfixed_Wswitch_obj += termcap.o
unfixed_Wswitch_obj += terminal.o
-unfixed_Wswitch_obj += terminfo.o
unfixed_Wswitch_obj += textconv.o
unfixed_Wswitch_obj += textprop.o
unfixed_Wswitch_obj += thread.o
unfixed_Wswitch_obj += timefns.o
unfixed_Wswitch_obj += tparam.o
unfixed_Wswitch_obj += treesit.o
-unfixed_Wswitch_obj += undo.o
unfixed_Wswitch_obj += unexaix.o
-unfixed_Wswitch_obj += unexcoff.o
-unfixed_Wswitch_obj += unexcw.o
unfixed_Wswitch_obj += unexelf.o
-unfixed_Wswitch_obj += unexhp9k800.o
unfixed_Wswitch_obj += unexmacosx.o
-unfixed_Wswitch_obj += unexsol.o
-unfixed_Wswitch_obj += unexw32.o
-unfixed_Wswitch_obj += vm-limit.o
unfixed_Wswitch_obj += w16select.o
unfixed_Wswitch_obj += w32.o
-unfixed_Wswitch_obj += w32console.o
-unfixed_Wswitch_obj += w32cygwinx.o
-unfixed_Wswitch_obj += w32dwrite.o
unfixed_Wswitch_obj += w32fns.o
unfixed_Wswitch_obj += w32font.o
unfixed_Wswitch_obj += w32heap.o
unfixed_Wswitch_obj += w32image.o
unfixed_Wswitch_obj += w32inevt.o
unfixed_Wswitch_obj += w32menu.o
-unfixed_Wswitch_obj += w32notify.o
unfixed_Wswitch_obj += w32proc.o
-unfixed_Wswitch_obj += w32reg.o
unfixed_Wswitch_obj += w32select.o
unfixed_Wswitch_obj += w32term.o
-unfixed_Wswitch_obj += w32uniscribe.o
unfixed_Wswitch_obj += w32xfns.o
-unfixed_Wswitch_obj += widget.o
unfixed_Wswitch_obj += window.o
unfixed_Wswitch_obj += xdisp.o
unfixed_Wswitch_obj += xfaces.o
unfixed_Wswitch_obj += xfns.o
-unfixed_Wswitch_obj += xfont.o
-unfixed_Wswitch_obj += xftfont.o
unfixed_Wswitch_obj += xgselect.o
unfixed_Wswitch_obj += xmenu.o
-unfixed_Wswitch_obj += xml.o
unfixed_Wswitch_obj += xrdb.o
unfixed_Wswitch_obj += xselect.o
unfixed_Wswitch_obj += xsettings.o
-unfixed_Wswitch_obj += xsmfns.o
unfixed_Wswitch_obj += xterm.o
unfixed_Wswitch_obj += xwidget.o
--
2.48.1
Finally, convert the first file (alloc.c) to use exhaustive switches in
a way that makes it safe for -Wswitch-enum:
From 0de72741ed4bb5ef1b299390e4a031135b042f65 Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@protonmail.com>
Subject: [PATCH 5/5] Make alloc.c safe for -Wswitch-enum (#75996)
---
src/Makefile.in | 1 -
src/alloc.c | 51 +++++++++++++++++++++++++++++++++++--------------
2 files changed, 37 insertions(+), 15 deletions(-)
diff --git a/src/Makefile.in b/src/Makefile.in
index 8f54006e276..7388284fef2 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -485,7 +485,6 @@ base_obj =
$(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) \
$(HAIKU_OBJ) $(PGTK_OBJ) $(ANDROID_OBJ)
-unfixed_Wswitch_obj += alloc.o
unfixed_Wswitch_obj += android.o
unfixed_Wswitch_obj += androidfns.o
unfixed_Wswitch_obj += androidterm.o
diff --git a/src/alloc.c b/src/alloc.c
index b13c3e49224..e44e7223f90 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -3405,7 +3405,6 @@ cleanup_vector (struct Lisp_Vector *vector)
break;
/* Keep the switch exhaustive. */
case PVEC_NORMAL_VECTOR:
- case PVEC_FREE:
case PVEC_SYMBOL_WITH_POS:
case PVEC_MISC_PTR:
case PVEC_PROCESS:
@@ -3425,6 +3424,8 @@ cleanup_vector (struct Lisp_Vector *vector)
case PVEC_SUB_CHAR_TABLE:
case PVEC_RECORD:
break;
+ case PVEC_FREE: eassume (0);
+ default: eassume (0);
}
}
@@ -5192,8 +5193,7 @@ mark_maybe_pointer (void *p, bool symbol_only)
}
break;
- default:
- emacs_abort ();
+ default: eassume (0);
}
mark_object (obj);
@@ -5573,8 +5573,7 @@ valid_lisp_object_p (Lisp_Object obj)
case MEM_TYPE_VECTOR_BLOCK:
return live_small_vector_p (m, p);
- default:
- break;
+ default: eassume (0);
}
return 0;
@@ -7274,10 +7273,31 @@ #define CHECK_ALLOCATED_AND_LIVE_SYMBOL() ((void) 0)
#endif
break;
- case PVEC_FREE:
- emacs_abort ();
-
- default:
+ case PVEC_NORMAL_VECTOR:
+ case PVEC_BIGNUM:
+ case PVEC_MARKER:
+ case PVEC_FINALIZER:
+ case PVEC_SYMBOL_WITH_POS:
+ case PVEC_MISC_PTR:
+ case PVEC_USER_PTR:
+ case PVEC_PROCESS:
+ case PVEC_TERMINAL:
+ case PVEC_WINDOW_CONFIGURATION:
+ case PVEC_OTHER:
+ case PVEC_XWIDGET:
+ case PVEC_XWIDGET_VIEW:
+ case PVEC_THREAD:
+ case PVEC_MUTEX:
+ case PVEC_CONDVAR:
+ case PVEC_MODULE_FUNCTION:
+ case PVEC_NATIVE_COMP_UNIT:
+ case PVEC_TS_PARSER:
+ case PVEC_TS_NODE:
+ case PVEC_TS_COMPILED_QUERY:
+ case PVEC_SQLITE:
+ case PVEC_CLOSURE:
+ case PVEC_RECORD:
+ case PVEC_FONT:
{
/* A regular vector or pseudovector needing no special
treatment. */
@@ -7288,6 +7308,9 @@ #define CHECK_ALLOCATED_AND_LIVE_SYMBOL() ((void) 0)
mark_stack_push_values (ptr->contents, size);
}
break;
+
+ case PVEC_FREE: eassume (0);
+ default: eassume (0);
}
}
break;
@@ -7337,7 +7360,7 @@ #define CHECK_ALLOCATED_AND_LIVE_SYMBOL() ((void) 0)
reachable from font_style_table which is also
staticpro'd. */
break;
- default: emacs_abort ();
+ default: eassume (0);
}
if (!PURE_P (XSTRING (ptr->u.s.name)))
set_string_marked (XSTRING (ptr->u.s.name));
@@ -7391,8 +7414,8 @@ #define CHECK_ALLOCATED_AND_LIVE_SYMBOL() ((void) 0)
case Lisp_Int1:
break;
- default:
- emacs_abort ();
+ case Lisp_Type_Unused0: eassume (0);
+ default: eassume (0);
}
}
@@ -7471,8 +7494,8 @@ survives_gc_p (Lisp_Object obj)
pdumper_object_p (XFLOAT (obj));
break;
- default:
- emacs_abort ();
+ case Lisp_Type_Unused0: eassume (0);
+ default: eassume (0);
}
return survives_p || PURE_P (XPNTR (obj));
--
2.48.1
I think this is a good place to stop for comments. I've converted many
more files in my local tree, but let's agree on what we want to change
before having to do that work over and over again.
Note that 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.
Note that some additional work will be required to ensure we don't pass
-Wno-switch-enum or -Wno-switch to clang, assuming at least some version
of clang don't support these options.
I'll do pdumper.c next.
Thanks!
Pip
^ permalink raw reply related [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-01-31 9:39 bug#75964: Switching the Emacs build to -Wswitch-enum in src/ Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-31 11:05 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-01-31 11:50 ` Eli Zaretskii
2025-01-31 12:15 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
1 sibling, 1 reply; 74+ messages in thread
From: Eli Zaretskii @ 2025-01-31 11:50 UTC (permalink / raw)
To: Pip Cet; +Cc: 75964
> Date: Fri, 31 Jan 2025 09:39:45 +0000
> From: Pip Cet via "Bug reports for GNU Emacs,
> the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
>
> I'm proposing to enable -Wswitch-enum as a warning option when compiling
> Emacs C sources in src/, and to modify those source files to make good
> use of it.
>
> GCC's -Wswitch-enum will warn about a switch statement of the form
>
> enum ABC { A, B, C };
>
> enum ABC x = ...;
>
> switch (x)
> {
> case A:
> case B:
> return 1;
> default:
> return 0;
> }
>
> The reason is that the "default" branch covers both case C and the case
> that the value of x isn't A, B, or, C. C allows this latter case and
> requires compilers to support it, and some Emacs code relies on
> non-enumerated values to be valid.
>
> Instead, with -Wswitch-enum, one should write:
>
> enum ABC { A, B, C };
>
> enum ABC x = ...;
>
> switch (x)
> {
> case A:
> case B:
> return 1;
> case C:
> return 0;
> default: eassume (false);
> }
>
> assuming x is known never to have a non-enumerated value (this is almost
> always the case in Emacs).
What should one do if the enumeration is large and the code wants to
treat all but the few values the same? This is a legitimate use case,
isn't it? Having to spell out all of the values is quite tedious, and
eassume will not do what we want in this case.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-01-31 11:50 ` Eli Zaretskii
@ 2025-01-31 12:15 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-31 12:24 ` Eli Zaretskii
0 siblings, 1 reply; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-01-31 12:15 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: 75964
"Eli Zaretskii" <eliz@gnu.org> writes:
>> Date: Fri, 31 Jan 2025 09:39:45 +0000
>> From: Pip Cet via "Bug reports for GNU Emacs,
>> the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
>>
>> I'm proposing to enable -Wswitch-enum as a warning option when compiling
>> Emacs C sources in src/, and to modify those source files to make good
>> use of it.
>>
>> GCC's -Wswitch-enum will warn about a switch statement of the form
>>
>> enum ABC { A, B, C };
>>
>> enum ABC x = ...;
>>
>> switch (x)
>> {
>> case A:
>> case B:
>> return 1;
>> default:
>> return 0;
>> }
>>
>> The reason is that the "default" branch covers both case C and the case
>> that the value of x isn't A, B, or, C. C allows this latter case and
>> requires compilers to support it, and some Emacs code relies on
>> non-enumerated values to be valid.
>>
>> Instead, with -Wswitch-enum, one should write:
>>
>> enum ABC { A, B, C };
>>
>> enum ABC x = ...;
>>
>> switch (x)
>> {
>> case A:
>> case B:
>> return 1;
>> case C:
>> return 0;
>> default: eassume (false);
>> }
>>
>> assuming x is known never to have a non-enumerated value (this is almost
>> always the case in Emacs).
>
> What should one do if the enumeration is large and the code wants to
> treat all but the few values the same? This is a legitimate use case,
We have several options:
0. do nothing, keeping bidi.o on the list of unfixed Wswitch objects,
explaining that too many large switches are in use for the result of (1)
to be readable
1. bite the bullet and apply a 184-line diff to bidi.c.
2. add #pragma statements in bidi.c around the five large switch
statements, giving us the benefit of warnings for the other switch
statements in bidi.c
3. turn bidi_type_t into a real integer type to avoid the warning
4. cast bidi_type_t to a real integer type in the switch statement.
-1. use if() instead
-2. use arrays instead
-3. use arrays of function pointers instead
The negative options are bad and I'd very much advise against them. (0)
is easiest, and allows us to deal with that problem if we want to change
our approach. I've done (1), but then I'm having a hard time reading
bidi.c with or without that patch.
(2) is bad because if we ever want to make sure the pragmas disabling
warnings are still appropriate, we've got to find them all.
(3) and (4) avoids the problem with standard GCC, but if my patch is
ever accepted, GCC will start warning about this in some fashion
> isn't it? Having to spell out all of the values is quite tedious, and
I don't think the (slight) pain of having to add the case labels is the
problem. I'm willing to do that. The real harm is to readability, and
that's really important.
> eassume will not do what we want in this case.
Why not? While "default: eassume (0);" is a weird way of putting it,
the semantics with -Werror=switch-enum are "I've handled all enumerated
cases explicitly; if the enumeration holds an anonymous value different
from all named values, abort in debug builds and don't generate code for
this in optimized builds".
That applies the same no matter how large the enum is. What am I
missing here?
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-01-31 12:15 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-01-31 12:24 ` Eli Zaretskii
2025-01-31 12:48 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 1 reply; 74+ messages in thread
From: Eli Zaretskii @ 2025-01-31 12:24 UTC (permalink / raw)
To: Pip Cet; +Cc: 75964
> Date: Fri, 31 Jan 2025 12:15:04 +0000
> From: Pip Cet <pipcet@protonmail.com>
> Cc: 75964@debbugs.gnu.org
>
> "Eli Zaretskii" <eliz@gnu.org> writes:
>
> > What should one do if the enumeration is large and the code wants to
> > treat all but the few values the same? This is a legitimate use case,
>
> We have several options:
>
> 0. do nothing, keeping bidi.o on the list of unfixed Wswitch objects,
> explaining that too many large switches are in use for the result of (1)
> to be readable
> 1. bite the bullet and apply a 184-line diff to bidi.c.
> 2. add #pragma statements in bidi.c around the five large switch
> statements, giving us the benefit of warnings for the other switch
> statements in bidi.c
> 3. turn bidi_type_t into a real integer type to avoid the warning
> 4. cast bidi_type_t to a real integer type in the switch statement.
> -1. use if() instead
> -2. use arrays instead
> -3. use arrays of function pointers instead
That might be fine when the enumeration is ours, but if it comes from
a system header file, the only practical option is 0, with 1 being a
very distant second (having a switch with many dozens of values is
hardly a good thing).
> > isn't it? Having to spell out all of the values is quite tedious, and
>
> I don't think the (slight) pain of having to add the case labels is the
> problem. I'm willing to do that.
We'll then need to update that each time the library headers add more
values, so this is not something anyone of us can volunteer to do,
forever.
> The real harm is to readability, and that's really important.
Right.
> > eassume will not do what we want in this case.
>
> Why not?
Because I'm describing the case where we actually _want_ the default
handling of an enumerated value to be something valid, whereas eassume
is for when it's invalid.
> While "default: eassume (0);" is a weird way of putting it,
> the semantics with -Werror=switch-enum are "I've handled all enumerated
> cases explicitly; if the enumeration holds an anonymous value different
> from all named values, abort in debug builds and don't generate code for
> this in optimized builds".
>
> That applies the same no matter how large the enum is. What am I
> missing here?
AFAIU, you are talking about the case where all the enum values were
spelled out in the switch, in which case eassume is indeed TRT. But I
was talking about a different case.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-01-31 12:24 ` Eli Zaretskii
@ 2025-01-31 12:48 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-31 13:42 ` Eli Zaretskii
2025-01-31 13:58 ` Robert Pluim
0 siblings, 2 replies; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-01-31 12:48 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: 75964
"Eli Zaretskii" <eliz@gnu.org> writes:
>> Date: Fri, 31 Jan 2025 12:15:04 +0000
>> From: Pip Cet <pipcet@protonmail.com>
>> Cc: 75964@debbugs.gnu.org
>>
>> "Eli Zaretskii" <eliz@gnu.org> writes:
>>
>> > What should one do if the enumeration is large and the code wants to
>> > treat all but the few values the same? This is a legitimate use case,
>>
>> We have several options:
>>
>> 0. do nothing, keeping bidi.o on the list of unfixed Wswitch objects,
>> explaining that too many large switches are in use for the result of (1)
>> to be readable
>> 1. bite the bullet and apply a 184-line diff to bidi.c.
>> 2. add #pragma statements in bidi.c around the five large switch
>> statements, giving us the benefit of warnings for the other switch
>> statements in bidi.c
>> 3. turn bidi_type_t into a real integer type to avoid the warning
>> 4. cast bidi_type_t to a real integer type in the switch statement.
>> -1. use if() instead
>> -2. use arrays instead
>> -3. use arrays of function pointers instead
>
> That might be fine when the enumeration is ours, but if it comes from
> a system header file, the only practical option is 0, with 1 being a
> very distant second (having a switch with many dozens of values is
> hardly a good thing).
You're talking about a different problem then. If an
externally-controlled enum is expected to grow, we want a compiler
warning to let us know when this happens, but we also need a default:
handler that deals with this case. So the right option is that we don't
need any of the extra options, the default behaviour will be just fine.
>> > isn't it? Having to spell out all of the values is quite tedious, and
>>
>> I don't think the (slight) pain of having to add the case labels is the
>> problem. I'm willing to do that.
>
> We'll then need to update that each time the library headers add more
> values, so this is not something anyone of us can volunteer to do,
> forever.
It's a compiler warning caused by external code. Those get added all
the time, and someone usually gets around to fixing or silencing them
eventually.
The last time this happened, our code just silently did the wrong thing
for the new value in an expanded enum. Having to ignore a warning
letting you know that will happen seems better, IMHO.
>> > eassume will not do what we want in this case.
>>
>> Why not?
>
> Because I'm describing the case where we actually _want_ the default
> handling of an enumerated value to be something valid, whereas eassume
> is for when it's invalid.
Note that in several cases where I've done the conversion, it turns out
that the comment after default: indicated that cases X and Y could be
handled that way, but there's also a case Z that got caught by the
default label and shouldn't have been. If nothing else, this hints
there are documentation bugs we can catch that way.
>> While "default: eassume (0);" is a weird way of putting it,
>> the semantics with -Werror=switch-enum are "I've handled all enumerated
>> cases explicitly; if the enumeration holds an anonymous value different
>> from all named values, abort in debug builds and don't generate code for
>> this in optimized builds".
>>
>> That applies the same no matter how large the enum is. What am I
>> missing here?
>
> AFAIU, you are talking about the case where all the enum values were
> spelled out in the switch, in which case eassume is indeed TRT. But I
> was talking about a different case.
I understand now. It'd be nice if we could disable -Wswitch-enum for a
specific switch or a specific enum, without using #pragmas, but I don't
think GCC has an option for that yet. You can use a cast to turn off
the warning with standard GCC.
I think it would be good to tag the bidi_type_t enum so it doesn't
produce such warnings, for example, but only the two switches deep in
bidi_resolve_brackets and bidi_resolve_neutral really seem problematic
at a first glance, to me, and is that worth hacking GCC for?
I'd be perfectly happy making bidi.o a permanent exception (0). Add a
comment explaining that decision, keep it in the obj list, done.
(I picked bidi.c as an example because it seems to me to be the most
difficult case: the bidi_type_t is large add somewhat tricky, and while
it's defined in the Emacs source code it's ultimately controlled by
Unicode. If you have a better example, feel free to discuss that instead).
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-01-31 12:48 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-01-31 13:42 ` Eli Zaretskii
2025-01-31 14:25 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-31 13:58 ` Robert Pluim
1 sibling, 1 reply; 74+ messages in thread
From: Eli Zaretskii @ 2025-01-31 13:42 UTC (permalink / raw)
To: Pip Cet; +Cc: 75964
> Date: Fri, 31 Jan 2025 12:48:02 +0000
> From: Pip Cet <pipcet@protonmail.com>
> Cc: 75964@debbugs.gnu.org
>
> "Eli Zaretskii" <eliz@gnu.org> writes:
>
> >> 0. do nothing, keeping bidi.o on the list of unfixed Wswitch objects,
> >> explaining that too many large switches are in use for the result of (1)
> >> to be readable
> >> 1. bite the bullet and apply a 184-line diff to bidi.c.
> >> 2. add #pragma statements in bidi.c around the five large switch
> >> statements, giving us the benefit of warnings for the other switch
> >> statements in bidi.c
> >> 3. turn bidi_type_t into a real integer type to avoid the warning
> >> 4. cast bidi_type_t to a real integer type in the switch statement.
> >> -1. use if() instead
> >> -2. use arrays instead
> >> -3. use arrays of function pointers instead
> >
> > That might be fine when the enumeration is ours, but if it comes from
> > a system header file, the only practical option is 0, with 1 being a
> > very distant second (having a switch with many dozens of values is
> > hardly a good thing).
>
> You're talking about a different problem then. If an
> externally-controlled enum is expected to grow, we want a compiler
> warning to let us know when this happens, but we also need a default:
> handler that deals with this case. So the right option is that we don't
> need any of the extra options, the default behaviour will be just fine.
Maybe. I'm not yet sure.
I also think we should maybe take a step back and summarize the
problems the use of -Wswitch-enum everywhere is supposed to help us
solve. You mentioned other approaches that have limitations, but what
are the specific problems in our sources that this and the other
approaches aim to solve?
I think we need to have the problems we want to solve in mind when
considering the solutions, because the solutions are not without
costs. And if we end up leaving many source files in the "unfixed"
class, then maybe we should turn this around and only use this switch
for those few files where it doesn't cause us problems for which
solutions we don't want to pay those costs.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-01-31 12:48 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-31 13:42 ` Eli Zaretskii
@ 2025-01-31 13:58 ` Robert Pluim
2025-01-31 14:11 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
1 sibling, 1 reply; 74+ messages in thread
From: Robert Pluim @ 2025-01-31 13:58 UTC (permalink / raw)
To: 75964; +Cc: eliz, pipcet
>>>>> On Fri, 31 Jan 2025 12:48:02 +0000, Pip Cet via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org> said:
>>
>> That might be fine when the enumeration is ours, but if it comes from
>> a system header file, the only practical option is 0, with 1 being a
>> very distant second (having a switch with many dozens of values is
>> hardly a good thing).
Pip> You're talking about a different problem then. If an
Pip> externally-controlled enum is expected to grow, we want a compiler
Pip> warning to let us know when this happens, but we also need a default:
Pip> handler that deals with this case. So the right option is that we don't
Pip> need any of the extra options, the default behaviour will be just fine.
Both gcc and clang support case ranges these days, so handling large
enums should not be a problem.
Robert
--
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-01-31 13:58 ` Robert Pluim
@ 2025-01-31 14:11 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 0 replies; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-01-31 14:11 UTC (permalink / raw)
To: Robert Pluim; +Cc: 75964, eliz
"Robert Pluim" <rpluim@gmail.com> writes:
>>>>>> On Fri, 31 Jan 2025 12:48:02 +0000, Pip Cet via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org> said:
> >>
> >> That might be fine when the enumeration is ours, but if it comes from
> >> a system header file, the only practical option is 0, with 1 being a
> >> very distant second (having a switch with many dozens of values is
> >> hardly a good thing).
>
> Pip> You're talking about a different problem then. If an
> Pip> externally-controlled enum is expected to grow, we want a compiler
> Pip> warning to let us know when this happens, but we also need a default:
> Pip> handler that deals with this case. So the right option is that we don't
> Pip> need any of the extra options, the default behaviour will be just fine.
>
> Both gcc and clang support case ranges these days, so handling large
> enums should not be a problem.
Thanks! Indeed, in many cases enums are ordered logically so we can use
case ranges. Here's pdumper.c, which illustrates this:
(first three patches revert recent attempts to get more or fewer
warnings):
From 2fd1752051e7b7b1a3a51a659277bdc0e37aca8f Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@protonmail.com>
Subject: [PATCH 1/4] Revert "; * src/pdumper.c (dump_do_fixup): Pacify GCC."
This reverts commit a99ba59aa02ef8cfd314737950b6cd8d97015925.
---
src/pdumper.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pdumper.c b/src/pdumper.c
index bfa790b963a..9f0447eb5aa 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -3990,7 +3990,7 @@ dump_do_fixup (struct dump_context *ctx,
Lisp_Object arg = dump_pop (&fixup);
eassert (NILP (fixup));
dump_seek (ctx, dump_fixup_offset);
- intptr_t dump_value UNINIT;
+ intptr_t dump_value;
bool do_write = true;
switch (type)
{
--
2.48.1
From a56416559996359570ff70c8749a5972fb9e14d4 Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@protonmail.com>
Subject: [PATCH 2/4] Revert "Pacify -Wanalyzer-use-of-uninitialized-value"
This reverts commit 1ed769a3cb753a86badba8a2878fa788a6fdc1f8.
---
src/pdumper.c | 91 +++++++++++++++++++++++++++++++++++----------------
1 file changed, 62 insertions(+), 29 deletions(-)
diff --git a/src/pdumper.c b/src/pdumper.c
index 9f0447eb5aa..45a44db0243 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -2292,12 +2292,11 @@ dump_float (struct dump_context *ctx, const struct Lisp_Float *lfloat)
}
static dump_off
-dump_fwd_int (struct dump_context *ctx, void const *fwdptr)
+dump_fwd_int (struct dump_context *ctx, const struct Lisp_Intfwd *intfwd)
{
#if CHECK_STRUCTS && !defined HASH_Lisp_Intfwd_4D887A7387
# error "Lisp_Intfwd changed. See CHECK_STRUCTS comment in config.h."
#endif
- struct Lisp_Intfwd const *intfwd = fwdptr;
dump_emacs_reloc_immediate_intmax_t (ctx, intfwd->intvar, *intfwd->intvar);
struct Lisp_Intfwd out;
dump_object_start (ctx, &out, sizeof (out));
@@ -2307,12 +2306,11 @@ dump_fwd_int (struct dump_context *ctx, void const *fwdptr)
}
static dump_off
-dump_fwd_bool (struct dump_context *ctx, void const *fwdptr)
+dump_fwd_bool (struct dump_context *ctx, const struct Lisp_Boolfwd *boolfwd)
{
#if CHECK_STRUCTS && !defined (HASH_Lisp_Boolfwd_0EA1C7ADCC)
# error "Lisp_Boolfwd changed. See CHECK_STRUCTS comment in config.h."
#endif
- struct Lisp_Boolfwd const *boolfwd = fwdptr;
dump_emacs_reloc_immediate_bool (ctx, boolfwd->boolvar, *boolfwd->boolvar);
struct Lisp_Boolfwd out;
dump_object_start (ctx, &out, sizeof (out));
@@ -2322,12 +2320,11 @@ dump_fwd_bool (struct dump_context *ctx, void const *fwdptr)
}
static dump_off
-dump_fwd_obj (struct dump_context *ctx, void const *fwdptr)
+dump_fwd_obj (struct dump_context *ctx, const struct Lisp_Objfwd *objfwd)
{
#if CHECK_STRUCTS && !defined (HASH_Lisp_Objfwd_45D3E513DC)
# error "Lisp_Objfwd changed. See CHECK_STRUCTS comment in config.h."
#endif
- struct Lisp_Objfwd const *objfwd = fwdptr;
if (NILP (Fgethash (dump_off_to_lisp (emacs_offset (objfwd->objvar)),
ctx->staticpro_table,
Qnil)))
@@ -2340,12 +2337,12 @@ dump_fwd_obj (struct dump_context *ctx, void const *fwdptr)
}
static dump_off
-dump_fwd_buffer_obj (struct dump_context *ctx, void const *fwdptr)
+dump_fwd_buffer_obj (struct dump_context *ctx,
+ const struct Lisp_Buffer_Objfwd *buffer_objfwd)
{
#if CHECK_STRUCTS && !defined (HASH_Lisp_Buffer_Objfwd_611EBD13FF)
# error "Lisp_Buffer_Objfwd changed. See CHECK_STRUCTS comment in config.h."
#endif
- struct Lisp_Buffer_Objfwd const *buffer_objfwd = fwdptr;
struct Lisp_Buffer_Objfwd out;
dump_object_start (ctx, &out, sizeof (out));
DUMP_FIELD_COPY (&out, buffer_objfwd, type);
@@ -2356,12 +2353,12 @@ dump_fwd_buffer_obj (struct dump_context *ctx, void const *fwdptr)
}
static dump_off
-dump_fwd_kboard_obj (struct dump_context *ctx, void const *fwdptr)
+dump_fwd_kboard_obj (struct dump_context *ctx,
+ const struct Lisp_Kboard_Objfwd *kboard_objfwd)
{
#if CHECK_STRUCTS && !defined (HASH_Lisp_Kboard_Objfwd_CAA7E71069)
# error "Lisp_Intfwd changed. See CHECK_STRUCTS comment in config.h."
#endif
- struct Lisp_Kboard_Objfwd const *kboard_objfwd = fwdptr;
struct Lisp_Kboard_Objfwd out;
dump_object_start (ctx, &out, sizeof (out));
DUMP_FIELD_COPY (&out, kboard_objfwd, type);
@@ -2375,16 +2372,29 @@ dump_fwd (struct dump_context *ctx, lispfwd fwd)
#if CHECK_STRUCTS && !defined (HASH_Lisp_Fwd_Type_9CBA6EE55E)
# error "Lisp_Fwd_Type changed. See CHECK_STRUCTS comment in config.h."
#endif
- typedef dump_off (*dump_fwd_fnptr) (struct dump_context *, void const *);
- static dump_fwd_fnptr const dump_fwd_table[] = {
- [Lisp_Fwd_Int] = dump_fwd_int,
- [Lisp_Fwd_Bool] = dump_fwd_bool,
- [Lisp_Fwd_Obj] = dump_fwd_obj,
- [Lisp_Fwd_Buffer_Obj] = dump_fwd_buffer_obj,
- [Lisp_Fwd_Kboard_Obj] = dump_fwd_kboard_obj,
- };
+ void const *p = fwd.fwdptr;
+ dump_off offset;
- return dump_fwd_table[XFWDTYPE (fwd)] (ctx, fwd.fwdptr);
+ switch (XFWDTYPE (fwd))
+ {
+ case Lisp_Fwd_Int:
+ offset = dump_fwd_int (ctx, p);
+ break;
+ case Lisp_Fwd_Bool:
+ offset = dump_fwd_bool (ctx, p);
+ break;
+ case Lisp_Fwd_Obj:
+ offset = dump_fwd_obj (ctx, p);
+ break;
+ case Lisp_Fwd_Buffer_Obj:
+ offset = dump_fwd_buffer_obj (ctx, p);
+ break;
+ case Lisp_Fwd_Kboard_Obj:
+ offset = dump_fwd_kboard_obj (ctx, p);
+ break;
+ }
+
+ return offset;
}
static dump_off
@@ -4534,19 +4544,26 @@ dump_anonymous_allocate_w32 (void *base,
# define MAP_ANONYMOUS MAP_ANON
# endif
-static int const mem_prot_posix_table[] = {
- [DUMP_MEMORY_ACCESS_NONE] = PROT_NONE,
- [DUMP_MEMORY_ACCESS_READ] = PROT_READ,
- [DUMP_MEMORY_ACCESS_READWRITE] = PROT_READ | PROT_WRITE,
-};
-
static void *
dump_anonymous_allocate_posix (void *base,
size_t size,
enum dump_memory_protection protection)
{
void *ret;
- int mem_prot = mem_prot_posix_table[protection];
+ int mem_prot;
+
+ switch (protection)
+ {
+ case DUMP_MEMORY_ACCESS_NONE:
+ mem_prot = PROT_NONE;
+ break;
+ case DUMP_MEMORY_ACCESS_READ:
+ mem_prot = PROT_READ;
+ break;
+ case DUMP_MEMORY_ACCESS_READWRITE:
+ mem_prot = PROT_READ | PROT_WRITE;
+ break;
+ }
int mem_flags = MAP_PRIVATE | MAP_ANONYMOUS;
if (mem_prot != PROT_NONE)
@@ -4690,9 +4707,25 @@ dump_map_file_posix (void *base, int fd, off_t offset, size_t size,
enum dump_memory_protection protection)
{
void *ret;
- int mem_prot = mem_prot_posix_table[protection];
- int mem_flags = (protection == DUMP_MEMORY_ACCESS_READWRITE
- ? MAP_PRIVATE : MAP_SHARED);
+ int mem_prot;
+ int mem_flags;
+
+ switch (protection)
+ {
+ case DUMP_MEMORY_ACCESS_NONE:
+ mem_prot = PROT_NONE;
+ mem_flags = MAP_SHARED;
+ break;
+ case DUMP_MEMORY_ACCESS_READ:
+ mem_prot = PROT_READ;
+ mem_flags = MAP_SHARED;
+ break;
+ case DUMP_MEMORY_ACCESS_READWRITE:
+ mem_prot = PROT_READ | PROT_WRITE;
+ mem_flags = MAP_PRIVATE;
+ break;
+ }
+
if (base)
mem_flags |= MAP_FIXED;
--
2.48.1
From ae7fdb7348b25e35ea6778220105a536458bfdae Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@protonmail.com>
Subject: [PATCH 3/4] Revert "Prefer static switch-case checking in pdumper"
This reverts commit 6e2e7265a04f63f482db7fbdfd8e2519d8bfe03e.
---
src/pdumper.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/src/pdumper.c b/src/pdumper.c
index 45a44db0243..71d82629b56 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -2392,6 +2392,8 @@ dump_fwd (struct dump_context *ctx, lispfwd fwd)
case Lisp_Fwd_Kboard_Obj:
offset = dump_fwd_kboard_obj (ctx, p);
break;
+ default:
+ emacs_abort ();
}
return offset;
@@ -2523,6 +2525,8 @@ dump_symbol (struct dump_context *ctx,
case SYMBOL_FORWARDED:
dump_field_fixup_later (ctx, &out, symbol, &symbol->u.s.val.fwd);
break;
+ default:
+ emacs_abort ();
}
dump_field_lv (ctx, &out, symbol, &symbol->u.s.function, WEIGHT_NORMAL);
dump_field_lv (ctx, &out, symbol, &symbol->u.s.plist, WEIGHT_NORMAL);
@@ -3603,6 +3607,8 @@ dump_drain_cold_data (struct dump_context *ctx)
dump_cold_native_subr (ctx, data);
break;
#endif
+ default:
+ emacs_abort ();
}
}
@@ -4067,6 +4073,8 @@ dump_do_fixup (struct dump_context *ctx,
do_write = false;
break;
}
+ default:
+ emacs_abort ();
}
if (do_write)
dump_write (ctx, &dump_value, sizeof (dump_value));
@@ -4525,6 +4533,8 @@ dump_anonymous_allocate_w32 (void *base,
mem_type = MEM_COMMIT;
mem_prot = PAGE_READWRITE;
break;
+ default:
+ emacs_abort ();
}
ret = VirtualAlloc (base, size, mem_type, mem_prot);
@@ -4563,6 +4573,8 @@ dump_anonymous_allocate_posix (void *base,
case DUMP_MEMORY_ACCESS_READWRITE:
mem_prot = PROT_READ | PROT_WRITE;
break;
+ default:
+ emacs_abort ();
}
int mem_flags = MAP_PRIVATE | MAP_ANONYMOUS;
@@ -4655,6 +4667,7 @@ dump_map_file_w32 (void *base, int fd, off_t offset, size_t size,
case DUMP_MEMORY_ACCESS_READWRITE:
protect = PAGE_WRITECOPY; /* for Windows 9X */
break;
+ default:
case DUMP_MEMORY_ACCESS_NONE:
case DUMP_MEMORY_ACCESS_READ:
protect = PAGE_READONLY;
@@ -4682,6 +4695,8 @@ dump_map_file_w32 (void *base, int fd, off_t offset, size_t size,
case DUMP_MEMORY_ACCESS_READWRITE:
map_access = FILE_MAP_COPY;
break;
+ default:
+ emacs_abort ();
}
ret = MapViewOfFileEx (section,
@@ -4724,6 +4739,8 @@ dump_map_file_posix (void *base, int fd, off_t offset, size_t size,
mem_prot = PROT_READ | PROT_WRITE;
mem_flags = MAP_PRIVATE;
break;
+ default:
+ emacs_abort ();
}
if (base)
@@ -5590,6 +5607,8 @@ dump_do_emacs_relocation (const uintptr_t dump_base,
memcpy (emacs_ptr_at (reloc.emacs_offset), &lv, sizeof (lv));
break;
}
+ default:
+ fatal ("unrecognied relocation type %d", (int) reloc.type);
}
}
--
2.48.1
From 9aff2f5644f4933747d7af5412f2cffc8b2c98b2 Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@protonmail.com>
Subject: [PATCH 4/4] Enable -Wswitch-enum in pdumper.c (bug#75964)
* src/Makefile.in (unfixed_Wswitch_obj): Remove 'pdumper.o'.
* src/pdumper.c (enum dump_reloc_type): Only include nativecomp cases
if HAVE_NATIVE_COMP. Add additional cases to cover ranges.
(dump_reloc_dump_to_emacs_lv):
(dump_field_lv_or_rawptr):
(dump_fwd):
(dump_pre_dump_symbol):
(dump_symbol):
(dump_vectorlike):
(dump_drain_cold_data):
(read_ptr_raw_and_lv):
(decode_emacs_reloc):
(dump_do_fixup):
(dump_anonymous_allocate_w32):
(dump_anonymous_allocate_posix):
(dump_map_file_w32):
(dump_map_file_posix):
(dump_do_emacs_relocation): Expand 'default' labels. Always
eassume (0) for 'default' labels.
(dump_object): Also use 'emacs_abort ()' rather than 'abort'.
(dump_do_dump_relocation): Also Handle case ranges explicitly.
---
src/Makefile.in | 1 -
src/pdumper.c | 94 ++++++++++++++++++++++++++++++++-----------------
2 files changed, 61 insertions(+), 34 deletions(-)
diff --git a/src/Makefile.in b/src/Makefile.in
index 7388284fef2..79a88af3584 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -546,7 +546,6 @@ unfixed_Wswitch_obj +=
unfixed_Wswitch_obj += nsselect.o
unfixed_Wswitch_obj += nsterm.o
unfixed_Wswitch_obj += nsxwidget.o
-unfixed_Wswitch_obj += pdumper.o
unfixed_Wswitch_obj += pgtkfns.o
unfixed_Wswitch_obj += pgtkterm.o
unfixed_Wswitch_obj += print.o
diff --git a/src/pdumper.c b/src/pdumper.c
index 71d82629b56..93119fd09c2 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -178,19 +178,35 @@ #define dump_offsetof(type, member) \
/* dump_ptr = dump_ptr + dump_base */
RELOC_DUMP_TO_DUMP_PTR_RAW,
/* dump_mpz = [rebuild bignum] */
+#ifdef HAVE_NATIVE_COMP
RELOC_NATIVE_COMP_UNIT,
RELOC_NATIVE_SUBR,
+#endif
RELOC_BIGNUM,
/* dump_lv = make_lisp_ptr (dump_lv + dump_base,
type - RELOC_DUMP_TO_DUMP_LV)
(Special case for symbols: make_lisp_symbol)
Must be second-last. */
RELOC_DUMP_TO_DUMP_LV,
+ RELOC_DUMP_TO_DUMP_LV1,
+ RELOC_DUMP_TO_DUMP_LV2,
+ RELOC_DUMP_TO_DUMP_LV3,
+ RELOC_DUMP_TO_DUMP_LV4,
+ RELOC_DUMP_TO_DUMP_LV5,
+ RELOC_DUMP_TO_DUMP_LV6,
+ RELOC_DUMP_TO_DUMP_LV7,
/* dump_lv = make_lisp_ptr (dump_lv + emacs_basis(),
type - RELOC_DUMP_TO_DUMP_LV)
(Special case for symbols: make_lisp_symbol.)
Must be last. */
RELOC_DUMP_TO_EMACS_LV = RELOC_DUMP_TO_DUMP_LV + 8,
+ RELOC_DUMP_TO_EMACS_LV1,
+ RELOC_DUMP_TO_EMACS_LV2,
+ RELOC_DUMP_TO_EMACS_LV3,
+ RELOC_DUMP_TO_EMACS_LV4,
+ RELOC_DUMP_TO_EMACS_LV5,
+ RELOC_DUMP_TO_EMACS_LV6,
+ RELOC_DUMP_TO_EMACS_LV7,
};
enum emacs_reloc_type
@@ -1445,8 +1461,11 @@ dump_reloc_dump_to_dump_lv (struct dump_context *ctx,
case Lisp_Float:
reloc_type = RELOC_DUMP_TO_DUMP_LV + type;
break;
- default:
+ case Lisp_Int0:
+ case Lisp_Int1:
emacs_abort ();
+ case Lisp_Type_Unused0: eassume (0);
+ default: eassume (0);
}
dump_push (&ctx->dump_relocs[EARLY_RELOCS],
@@ -1494,8 +1513,12 @@ dump_reloc_dump_to_emacs_lv (struct dump_context *ctx,
case Lisp_Float:
reloc_type = RELOC_DUMP_TO_EMACS_LV + type;
break;
- default:
+ case Lisp_Symbol:
+ case Lisp_Int0:
+ case Lisp_Int1:
emacs_abort ();
+ case Lisp_Type_Unused0: eassume (0);
+ default: eassume (0);
}
dump_push (&ctx->dump_relocs[EARLY_RELOCS],
@@ -1817,8 +1840,12 @@ dump_field_lv_or_rawptr (struct dump_context *ctx,
case Lisp_Float:
value = make_lisp_ptr (ptrval, *ptr_raw_type);
break;
- default:
- emacs_abort ();
+ case Lisp_Int0:
+ case Lisp_Int1:
+ emacs_abort ();
+
+ case Lisp_Type_Unused0: eassume (0);
+ default: eassume (0);
}
}
@@ -2392,8 +2419,7 @@ dump_fwd (struct dump_context *ctx, lispfwd fwd)
case Lisp_Fwd_Kboard_Obj:
offset = dump_fwd_kboard_obj (ctx, p);
break;
- default:
- emacs_abort ();
+ default: eassume (0);
}
return offset;
@@ -2458,8 +2484,10 @@ dump_pre_dump_symbol (struct dump_context *ctx, struct Lisp_Symbol *symbol)
dump_remember_symbol_aux (ctx, symbol_lv,
dump_fwd (ctx, symbol->u.s.val.fwd));
break;
- default:
+ case SYMBOL_PLAINVAL:
+ case SYMBOL_VARALIAS:
break;
+ default: eassume (0);
}
dump_clear_referrer (ctx);
}
@@ -2525,8 +2553,7 @@ dump_symbol (struct dump_context *ctx,
case SYMBOL_FORWARDED:
dump_field_fixup_later (ctx, &out, symbol, &symbol->u.s.val.fwd);
break;
- default:
- emacs_abort ();
+ default: eassume (0);
}
dump_field_lv (ctx, &out, symbol, &symbol->u.s.function, WEIGHT_NORMAL);
dump_field_lv (ctx, &out, symbol, &symbol->u.s.plist, WEIGHT_NORMAL);
@@ -2556,8 +2583,10 @@ dump_symbol (struct dump_context *ctx,
? aux_offset
: dump_fwd (ctx, symbol->u.s.val.fwd)));
break;
- default:
+ case SYMBOL_PLAINVAL:
+ case SYMBOL_VARALIAS:
break;
+ default: eassume (0);
}
return offset;
}
@@ -3144,10 +3173,11 @@ dump_vectorlike (struct dump_context *ctx,
case PVEC_SQLITE:
case PVEC_MODULE_FUNCTION:
case PVEC_SYMBOL_WITH_POS:
- case PVEC_FREE:
case PVEC_TS_PARSER:
case PVEC_TS_NODE:
break;
+ case PVEC_FREE: eassume (0);
+ default: eassume (0);
}
int iptype = ptype;
static char const fmt[] = "pseudovector type %d";
@@ -3249,9 +3279,9 @@ dump_object (struct dump_context *ctx, Lisp_Object object)
case Lisp_Int0:
case Lisp_Int1:
eassert ("should not be dumping int: is self-representing" && 0);
- abort ();
- default:
emacs_abort ();
+ case Lisp_Type_Unused0: eassume (0);
+ default: eassume (0);
}
dump_clear_referrer (ctx);
@@ -3607,8 +3637,7 @@ dump_drain_cold_data (struct dump_context *ctx)
dump_cold_native_subr (ctx, data);
break;
#endif
- default:
- emacs_abort ();
+ default: eassume (0);
}
}
@@ -3635,8 +3664,11 @@ read_ptr_raw_and_lv (const void *mem,
case Lisp_Float:
*out_lv = make_lisp_ptr (*out_ptr, type);
break;
- default:
- emacs_abort ();
+ case Lisp_Int0:
+ case Lisp_Int1:
+ case Lisp_Type_Unused0:
+ eassume (0);
+ default: eassume (0);
}
}
}
@@ -3888,8 +3920,7 @@ decode_emacs_reloc (struct dump_context *ctx, Lisp_Object lreloc)
}
}
break;
- default:
- eassume (!"not reached");
+ default: eassume (0);
}
/* We should have consumed the whole relocation descriptor. */
@@ -4073,8 +4104,7 @@ dump_do_fixup (struct dump_context *ctx,
do_write = false;
break;
}
- default:
- emacs_abort ();
+ default: eassume (0);
}
if (do_write)
dump_write (ctx, &dump_value, sizeof (dump_value));
@@ -4533,8 +4563,7 @@ dump_anonymous_allocate_w32 (void *base,
mem_type = MEM_COMMIT;
mem_prot = PAGE_READWRITE;
break;
- default:
- emacs_abort ();
+ default: eassume (0);
}
ret = VirtualAlloc (base, size, mem_type, mem_prot);
@@ -4573,8 +4602,7 @@ dump_anonymous_allocate_posix (void *base,
case DUMP_MEMORY_ACCESS_READWRITE:
mem_prot = PROT_READ | PROT_WRITE;
break;
- default:
- emacs_abort ();
+ default: eassume (0);
}
int mem_flags = MAP_PRIVATE | MAP_ANONYMOUS;
@@ -4667,11 +4695,11 @@ dump_map_file_w32 (void *base, int fd, off_t offset, size_t size,
case DUMP_MEMORY_ACCESS_READWRITE:
protect = PAGE_WRITECOPY; /* for Windows 9X */
break;
- default:
case DUMP_MEMORY_ACCESS_NONE:
case DUMP_MEMORY_ACCESS_READ:
protect = PAGE_READONLY;
break;
+ default: eassume (0);
}
section = CreateFileMapping (file,
@@ -4695,8 +4723,7 @@ dump_map_file_w32 (void *base, int fd, off_t offset, size_t size,
case DUMP_MEMORY_ACCESS_READWRITE:
map_access = FILE_MAP_COPY;
break;
- default:
- emacs_abort ();
+ default: eassume (0);
}
ret = MapViewOfFileEx (section,
@@ -4739,8 +4766,7 @@ dump_map_file_posix (void *base, int fd, off_t offset, size_t size,
mem_prot = PROT_READ | PROT_WRITE;
mem_flags = MAP_PRIVATE;
break;
- default:
- emacs_abort ();
+ default: eassume (0);
}
if (base)
@@ -5541,13 +5567,16 @@ dump_do_dump_relocation (const uintptr_t dump_base,
mpz_roinit_n (bignum->value, limbs, reload_info.nlimbs);
break;
}
- default: /* Lisp_Object in the dump; precise type in reloc.type */
+ case RELOC_DUMP_TO_DUMP_LV ... RELOC_DUMP_TO_DUMP_LV + 7:
+ case RELOC_DUMP_TO_EMACS_LV ... RELOC_DUMP_TO_EMACS_LV + 7:
+ /* Lisp_Object in the dump; precise type in reloc.type */
{
Lisp_Object lv = dump_make_lv_from_reloc (dump_base, reloc);
eassert (dump_reloc_size (reloc) == sizeof (lv));
dump_write_lv_to_dump (dump_base, reloc_offset, lv);
break;
}
+ default: eassume (0);
}
}
@@ -5607,8 +5636,7 @@ dump_do_emacs_relocation (const uintptr_t dump_base,
memcpy (emacs_ptr_at (reloc.emacs_offset), &lv, sizeof (lv));
break;
}
- default:
- fatal ("unrecognied relocation type %d", (int) reloc.type);
+ default: eassume (0);
}
}
--
2.48.1
>
> Robert
^ permalink raw reply related [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-01-31 13:42 ` Eli Zaretskii
@ 2025-01-31 14:25 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-31 15:00 ` Eli Zaretskii
0 siblings, 1 reply; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-01-31 14:25 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: 75964
"Eli Zaretskii" <eliz@gnu.org> writes:
>> Date: Fri, 31 Jan 2025 12:48:02 +0000
>> From: Pip Cet <pipcet@protonmail.com>
>> Cc: 75964@debbugs.gnu.org
>>
>> "Eli Zaretskii" <eliz@gnu.org> writes:
>>
>> >> 0. do nothing, keeping bidi.o on the list of unfixed Wswitch objects,
>> >> explaining that too many large switches are in use for the result of (1)
>> >> to be readable
>> >> 1. bite the bullet and apply a 184-line diff to bidi.c.
>> >> 2. add #pragma statements in bidi.c around the five large switch
>> >> statements, giving us the benefit of warnings for the other switch
>> >> statements in bidi.c
>> >> 3. turn bidi_type_t into a real integer type to avoid the warning
>> >> 4. cast bidi_type_t to a real integer type in the switch statement.
>> >> -1. use if() instead
>> >> -2. use arrays instead
>> >> -3. use arrays of function pointers instead
>> >
>> > That might be fine when the enumeration is ours, but if it comes from
>> > a system header file, the only practical option is 0, with 1 being a
>> > very distant second (having a switch with many dozens of values is
>> > hardly a good thing).
>>
>> You're talking about a different problem then. If an
>> externally-controlled enum is expected to grow, we want a compiler
>> warning to let us know when this happens, but we also need a default:
>> handler that deals with this case. So the right option is that we don't
>> need any of the extra options, the default behaviour will be just fine.
>
> Maybe. I'm not yet sure.
>
> I also think we should maybe take a step back and summarize the
> problems the use of -Wswitch-enum everywhere is supposed to help us
> solve. You mentioned other approaches that have limitations, but what
> are the specific problems in our sources that this and the other
> approaches aim to solve?
I'd like to say "look at these bugs we've fixed", but so far the list is
quite short: rsvg misbehaved for a newly-added unit, and treesitter
produced a suboptimal error message.
> I think we need to have the problems we want to solve in mind when
> considering the solutions, because the solutions are not without
> costs.
Agreed. I'm still looking for a smoking gun: a case label which we
forgot and which caused the default case label to do the wrong thing.
The only reason I see to hurry here is that various people are
pushing changes to master which follow this or that solution, and
usually it's not the right one (in my very personal view). If we could
agree to stop doing that and leave switch statements alone for now, I'd
be very happy (i.e. apply the three reverts to pdumper.c but not the
fourth patch in the last series).
> And if we end up leaving many source files in the "unfixed"
> class, then maybe we should turn this around and only use this switch
> for those few files where it doesn't cause us problems for which
> solutions we don't want to pay those costs.
Thanks! That's a great idea! I also shouldn't have used "unfixed" as a
name: there's nothing wrong with disabling warnings per file, and
different files have different requirements, and all that's perfectly
okay and not anyone's refusal to fix anything.
Thanks for the feedback!
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-01-31 14:25 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-01-31 15:00 ` Eli Zaretskii
2025-02-02 15:21 ` Stefan Kangas
0 siblings, 1 reply; 74+ messages in thread
From: Eli Zaretskii @ 2025-01-31 15:00 UTC (permalink / raw)
To: Pip Cet, Stefan Kangas; +Cc: 75964
> Date: Fri, 31 Jan 2025 14:25:21 +0000
> From: Pip Cet <pipcet@protonmail.com>
> Cc: 75964@debbugs.gnu.org
>
> "Eli Zaretskii" <eliz@gnu.org> writes:
>
> > I think we need to have the problems we want to solve in mind when
> > considering the solutions, because the solutions are not without
> > costs.
>
> Agreed. I'm still looking for a smoking gun: a case label which we
> forgot and which caused the default case label to do the wrong thing.
>
> The only reason I see to hurry here is that various people are
> pushing changes to master which follow this or that solution, and
> usually it's not the right one (in my very personal view). If we could
> agree to stop doing that and leave switch statements alone for now, I'd
> be very happy (i.e. apply the three reverts to pdumper.c but not the
> fourth patch in the last series).
It would indeed be wise to stop pushing changes in this area as long
as we are not sure what would be the best solution.
Stefan, do you agree?
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-01-31 11:05 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-01-31 18:30 ` Paul Eggert
2025-01-31 18:41 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-31 21:46 ` Paul Eggert
1 sibling, 1 reply; 74+ messages in thread
From: Paul Eggert @ 2025-01-31 18:30 UTC (permalink / raw)
To: Pip Cet; +Cc: 75964, Stefan Kangas
On 2025-01-31 03:05, Pip Cet wrote:
> Unfortunately, GCC now thinks:
>
> static const char hexchar[16] = "0123456789ABCDEF";
>
> is unsafe and the [16] should be [17] or omitted.
This is GCC bug 117178
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117178>, which also bites
in several places in the Linux kernel. In the meantime I wouldn't worry
about it, other than perhaps suppressing the false positive with current
GCC.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-01-31 18:30 ` Paul Eggert
@ 2025-01-31 18:41 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 0 replies; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-01-31 18:41 UTC (permalink / raw)
To: Paul Eggert; +Cc: 75964, Stefan Kangas
"Paul Eggert" <eggert@cs.ucla.edu> writes:
> On 2025-01-31 03:05, Pip Cet wrote:
>> Unfortunately, GCC now thinks:
>>
>> static const char hexchar[16] = "0123456789ABCDEF";
>>
>> is unsafe and the [16] should be [17] or omitted.
>
> This is GCC bug 117178
> <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117178>, which also bites
> in several places in the Linux kernel. In the meantime I wouldn't worry
> about it, other than perhaps suppressing the false positive with current
> GCC.
Thanks! Easy enough to work around that for now, and there are many
other new warnings, it seems :-)
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-01-31 11:05 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-31 18:30 ` Paul Eggert
@ 2025-01-31 21:46 ` Paul Eggert
2025-02-01 9:02 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
1 sibling, 1 reply; 74+ messages in thread
From: Paul Eggert @ 2025-01-31 21:46 UTC (permalink / raw)
To: Pip Cet, 75964, Stefan Kangas
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:"?
Suppose one case has an enum type and another case has some other type:
is that an error?
> + 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?
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.
> 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?
> + 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. 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.
> +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.
Alternatively, perhaps it'd be better to use a pragma in the (I hope)
rare places we need to pacify GCC. E.g., how we currently treat
-Wanalyzer-null-dereference in four .c files.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-01-31 21:46 ` Paul Eggert
@ 2025-02-01 9:02 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-01 18:18 ` Paul Eggert
0 siblings, 1 reply; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-01 9:02 UTC (permalink / raw)
To: Paul Eggert; +Cc: 75964, Stefan Kangas
"Paul Eggert" <eggert@cs.ucla.edu> 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
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-01 9:02 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-01 18:18 ` Paul Eggert
2025-02-01 18:54 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 1 reply; 74+ messages in thread
From: Paul Eggert @ 2025-02-01 18:18 UTC (permalink / raw)
To: Pip Cet; +Cc: 75964, Stefan Kangas
On 2025-02-01 01:02, Pip Cet wrote:
> "Paul Eggert" <eggert@cs.ucla.edu> writes:
>> 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 :-)
It'd be helpful to document this workaround in any proposed GCC patch
(which I assume would include a doc patch).
>> 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.
Either name would work of course. I mildly prefer just the "e" prefix.
>> 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.
As long as there's an Autoconfy way to tell whether the new GCC behavior
is present we should be OK. This could be via a test program compiled
with the relev antGCC options. If that approach works, it might be
better to fold the new behavior into -Wswitch-enum. As you say, this
requires some thought.
>>> +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.
It's the usual tradeoff between keeping each patch small and simple, vs
minimizing the total size of all the patches. Here it might be better to
opt for the latter, as changes like the above are a turnoff.
> 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.
I also dislike the pragmas, which is why I like to adorn them with
comments containing the relevant GCC bug numbers. The intent is that the
pragmas are "temporary" and should go away once the GCC bugs are fixed.
> 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.
Sounds good.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-01 18:18 ` Paul Eggert
@ 2025-02-01 18:54 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 7:46 ` Paul Eggert
0 siblings, 1 reply; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-01 18:54 UTC (permalink / raw)
To: Paul Eggert; +Cc: 75964, Stefan Kangas
"Paul Eggert" <eggert@cs.ucla.edu> writes:
> On 2025-02-01 01:02, Pip Cet wrote:
>> "Paul Eggert" <eggert@cs.ucla.edu> writes:
>>> 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 :-)
>
> It'd be helpful to document this workaround in any proposed GCC patch
> (which I assume would include a doc patch).
Thanks for the subtle hint to actually document this. Will do :-)
>>> 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.
> Either name would work of course. I mildly prefer just the "e" prefix.
Not so much about the name as about what it does by default. We've
disagreed before on the merits of having eassume and eassert: I still
think we should have just one, and GCC can figure out itself whether the
information is useful for optimization (treat it as eassume) or not
(treat it as eassert)!
I don't know which builds eunreachable () would actually be treated as
unreachable in. All optimized builds? Only builds that also omit
emacs_abort ()? What about machines where there's a single byte
"abort" instruction?
>>> 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.
>
> As long as there's an Autoconfy way to tell whether the new GCC behavior
> is present we should be OK. This could be via a test program compiled
> with the relev antGCC options. If that approach works, it might be
> better to fold the new behavior into -Wswitch-enum.
I don't think people will be very happy if we don't even try
understanding chained enums. They're quite common. And while detecting
enums with at least two distinct values forming a range is easy to do in
theory, it might use significant CPU resources on some builds.
> As you say, this requires some thought.
I'll work on the "infer type from case label" thing first. That's
small, manageable, useful, and if I can't even get that in what's the
point writing long code to determine whether an enum is switchable?
>>>> +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.
>
> It's the usual tradeoff between keeping each patch small and simple, vs
> minimizing the total size of all the patches. Here it might be better to
> opt for the latter, as changes like the above are a turnoff.
I'm not sure whether you're suggesting to list only the remaining
"unfixed" (yes, yes, better name) files somewhere, or something else
that I don't understand :-)
>> 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.
>
> I also dislike the pragmas, which is why I like to adorn them with
> comments containing the relevant GCC bug numbers. The intent is that the
> pragmas are "temporary" and should go away once the GCC bugs are fixed.
Thank you so much for the bug numbers! I'd go further and put the
pragmas into single-purpose include files, where we absolutely need
them.
_Pragma, well.
>> 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.
>
> Sounds good.
Of course it'd be even nicer if it were to remind us to turn "unsigned bf
: 3" into an ENUM_BF, but I have no idea, er, leave it as an exercise
for the reader.
I'll continue working on this.
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-01 18:54 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-02 7:46 ` Paul Eggert
2025-02-02 8:21 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 1 reply; 74+ messages in thread
From: Paul Eggert @ 2025-02-02 7:46 UTC (permalink / raw)
To: Pip Cet; +Cc: 75964, Stefan Kangas
On 2025-02-01 10:54, Pip Cet wrote:
> I don't know which builds eunreachable () would actually be treated as
> unreachable in. All optimized builds? Only builds that also omit
> emacs_abort ()? What about machines where there's a single byte
> "abort" instruction?
I thought eunreachable () would be equivalent to eassume (false), for
the same reason unreachable () is equivalent to assume (false). If we
change the meaning of eassume (false), eunreachable () would change to
match.
Currently, if !ENABLE_CHECKING, eassume (false) is equivalent to
unreachable (). And ENABLE_CHECKING, eassume (false) is equivalent to
(suppress_checking ? unreachable () : die (...)). I was thinking that
eunreachable () would do the same. That is, if we change the die (...)
to __builtin_abort () or emacs_abort () or whatever, that would affect
both eassume and eunreachable.
>> As long as there's an Autoconfy way to tell whether the new GCC behavior
>> is present we should be OK. This could be via a test program compiled
>> with the relevant GCC options. If that approach works, it might be
>> better to fold the new behavior into -Wswitch-enum.
>
> I don't think people will be very happy if we don't even try
> understanding chained enums. They're quite common.
Not sure we're talking on the same wavelength. I was worried about a
lesser problem: how 'configure' should detect whether GCC behaves as
now, or behaves as you're proposing. I suspect such a configure-time
test would be needed if we head in this direction.
> I'm not sure whether you're suggesting to list only the remaining
> "unfixed" (yes, yes, better name) files somewhere, or something else
> that I don't understand :-)
Oh, I was hoping that we'd just fix the files, so there would be no
unfixed files and no need for makefilery to deal with unfixed files.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 7:46 ` Paul Eggert
@ 2025-02-02 8:21 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 8:31 ` Paul Eggert
0 siblings, 1 reply; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-02 8:21 UTC (permalink / raw)
To: Paul Eggert; +Cc: 75964, Stefan Kangas
"Paul Eggert" <eggert@cs.ucla.edu> writes:
> On 2025-02-01 10:54, Pip Cet wrote:
>
>> I don't know which builds eunreachable () would actually be treated as
>> unreachable in. All optimized builds? Only builds that also omit
>> emacs_abort ()? What about machines where there's a single byte
>> "abort" instruction?
>
> I thought eunreachable () would be equivalent to eassume (false), for
> the same reason unreachable () is equivalent to assume (false). If we
> change the meaning of eassume (false), eunreachable () would change to
> match.
But emacs_abort () isn't equivalent to eassert (false), and that's
always been confusing to me. Perhaps it needs to be that way, though.
>>> As long as there's an Autoconfy way to tell whether the new GCC behavior
>>> is present we should be OK. This could be via a test program compiled
>>> with the relevant GCC options. If that approach works, it might be
>>> better to fold the new behavior into -Wswitch-enum.
>>
>> I don't think people will be very happy if we don't even try
>> understanding chained enums. They're quite common.
>
> Not sure we're talking on the same wavelength. I was worried about a
> lesser problem: how 'configure' should detect whether GCC behaves as
> now, or behaves as you're proposing. I suspect such a configure-time
> test would be needed if we head in this direction.
I must have misread. I was trying to say that rolling the enum-checking
behavior into -Wswitch-enum would be a bad idea because of chained
enums, in use by some people who don't know much about autoconf (such
as, erm, myself).
Is autoconf the best way to establish whether this warning exists and is
useful? Do we need to know that, even, or can't we just enable
-Wswitch-enum and people live with what they get? I honestly don't know
that, and if it increases the chances this code will be merged I'm happy
to change things!
>> I'm not sure whether you're suggesting to list only the remaining
>> "unfixed" (yes, yes, better name) files somewhere, or something else
>> that I don't understand :-)
>
> Oh, I was hoping that we'd just fix the files, so there would be no
> unfixed files and no need for makefilery to deal with unfixed files.
My preference, too, but I thought the per-file approach would seem less
aggressive to files like bidi.c: We've got to choose what to do there,
and artificially taking the "don't touch bidi.c, tell make not to pass
the switch there" option off the table seemed unwise to me.
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 8:21 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-02 8:31 ` Paul Eggert
2025-02-02 8:39 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 1 reply; 74+ messages in thread
From: Paul Eggert @ 2025-02-02 8:31 UTC (permalink / raw)
To: Pip Cet; +Cc: 75964, Stefan Kangas
On 2025-02-02 00:21, Pip Cet wrote:
> emacs_abort () isn't equivalent to eassert (false), and that's
> always been confusing to me.
The inspiration is emacs_abort : abort :: eassert : assert. If we made
emacs_abort () equivalent to eassert (false) we'd break that, as in C
abort () is not equivalent to assert (false).
> can't we just enable
> -Wswitch-enum and people live with what they get?
Yes, if the new -Wswitch-enum behavior is in stable GCC and if Emacs
compiles cleanly with the new GCC. Come to think of it, that'd be better
than autoconfery.
In other words, I'm thinking that the change to Emacs can wait until GCC
is fixed, and once that happens we can change Emacs. We shouldn't need
to fiddle with configure.ac or with Makefiles or whatever, other than to
add -Wswitch-enum.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 8:31 ` Paul Eggert
@ 2025-02-02 8:39 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 8:49 ` Eli Zaretskii
0 siblings, 1 reply; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-02 8:39 UTC (permalink / raw)
To: Paul Eggert; +Cc: 75964, Stefan Kangas
"Paul Eggert" <eggert@cs.ucla.edu> writes:
> On 2025-02-02 00:21, Pip Cet wrote:
>
>> emacs_abort () isn't equivalent to eassert (false), and that's
>> always been confusing to me.
>
> The inspiration is emacs_abort : abort :: eassert : assert. If we made
> emacs_abort () equivalent to eassert (false) we'd break that, as in C
> abort () is not equivalent to assert (false).
You're correct there. I was confused because some software does turn
abort() into __builtin_unreachable(), but that's not what POSIX says.
>> can't we just enable
>> -Wswitch-enum and people live with what they get?
>
> Yes, if the new -Wswitch-enum behavior is in stable GCC and if Emacs
> compiles cleanly with the new GCC. Come to think of it, that'd be better
> than autoconfery.
>
> In other words, I'm thinking that the change to Emacs can wait until GCC
> is fixed, and once that happens we can change Emacs. We shouldn't need
> to fiddle with configure.ac or with Makefiles or whatever, other than to
> add -Wswitch-enum.
I think we should enable -Wswitch-enum now, and expect it to generate
more warnings in the future. Not sure whether that's what you were
saying. The current mixed collection of switches doesn't help
readability, IMHO.
Anyway, I'd like to convert a few more files first, then I'll have
another patch.
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 8:39 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-02 8:49 ` Eli Zaretskii
2025-02-02 9:26 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 1 reply; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-02 8:49 UTC (permalink / raw)
To: Pip Cet; +Cc: eggert, 75964, stefankangas
> Cc: 75964@debbugs.gnu.org, Stefan Kangas <stefankangas@gmail.com>
> Date: Sun, 02 Feb 2025 08:39:11 +0000
> From: Pip Cet via "Bug reports for GNU Emacs,
> the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
>
> I think we should enable -Wswitch-enum now, and expect it to generate
> more warnings in the future.
I'm not sure I understand what "in the future" means here, but please
don't add warning options that will generate warnings while compiling
the current sources; if they do, either the source code should be
fixed to avoid the warnings before the warning option is turned on by
default, or the warning option should not be turned on by default. We
strive to have the current sources compile cleanly with the default
warning options, so that any warning draws attention and is fixed
ASAP; thus, having compilation warnings routinely emitted that cannot
be easily fixed is not a good idea because that causes people to
ignore warnings.
Apologies if the above is not relevant to what you were discussing
regarding adding warning options.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 8:49 ` Eli Zaretskii
@ 2025-02-02 9:26 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 10:34 ` Eli Zaretskii
0 siblings, 1 reply; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-02 9:26 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: eggert, 75964, stefankangas
"Eli Zaretskii" <eliz@gnu.org> writes:
>> Cc: 75964@debbugs.gnu.org, Stefan Kangas <stefankangas@gmail.com>
>> Date: Sun, 02 Feb 2025 08:39:11 +0000
>> From: Pip Cet via "Bug reports for GNU Emacs,
>> the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
>>
>> I think we should enable -Wswitch-enum now, and expect it to generate
>> more warnings in the future.
>
> I'm not sure I understand what "in the future" means here, but please
Future GCC versions may and will add warnings about cases that they
currently fail to warn about, for the same switch. I don't think we can
change that.
> don't add warning options that will generate warnings while compiling
> the current sources; if they do, either the source code should be
> fixed to avoid the warnings before the warning option is turned on by
> default, or the warning option should not be turned on by default. We
I agree. Making GCC emit more warnings by changing its configuration
and then telling others to fix them isn't right.
> strive to have the current sources compile cleanly with the default
> warning options, so that any warning draws attention and is fixed
> ASAP; thus, having compilation warnings routinely emitted that cannot
> be easily fixed is not a good idea because that causes people to
> ignore warnings.
Agreed, as far as changing Emacs goes. GCC, of course, can change
independently.
(In this case, it's unlikely I'll submit a GCC patch that produces
fixable warning in Emacs, but other projects may not be so lucky).
> Apologies if the above is not relevant to what you were discussing
> regarding adding warning options.
I think it's highly relevant: I proposed several ways of adding the
warning options: one file at a time, #pragma'd out, or enabled globally
and only merged once we can fix, at least, the common build systems.
Simply enabling them globally and waiting for someone else to fix the
warnings only leads to other warnings being missed.
Is that an accurate summary? If you have another option, or a
preference between the three options I mentioned, would you mind sharing
it?
Thanks!
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 9:26 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-02 10:34 ` Eli Zaretskii
2025-02-02 11:48 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 1 reply; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-02 10:34 UTC (permalink / raw)
To: Pip Cet; +Cc: eggert, 75964, stefankangas
> Date: Sun, 02 Feb 2025 09:26:48 +0000
> From: Pip Cet <pipcet@protonmail.com>
> Cc: eggert@cs.ucla.edu, 75964@debbugs.gnu.org, stefankangas@gmail.com
>
> "Eli Zaretskii" <eliz@gnu.org> writes:
>
> >> Cc: 75964@debbugs.gnu.org, Stefan Kangas <stefankangas@gmail.com>
> >> Date: Sun, 02 Feb 2025 08:39:11 +0000
> >> From: Pip Cet via "Bug reports for GNU Emacs,
> >> the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
> >>
> >> I think we should enable -Wswitch-enum now, and expect it to generate
> >> more warnings in the future.
> >
> > I'm not sure I understand what "in the future" means here, but please
>
> Future GCC versions may and will add warnings about cases that they
> currently fail to warn about, for the same switch. I don't think we can
> change that.
If future GCC versions add warnings, we will handle them when that
happens and the warnings are reported or seen. We don't need (and
really cannot) worry about that at this time.
> > Apologies if the above is not relevant to what you were discussing
> > regarding adding warning options.
>
> I think it's highly relevant: I proposed several ways of adding the
> warning options: one file at a time, #pragma'd out, or enabled globally
> and only merged once we can fix, at least, the common build systems.
SGTM, thanks.
> Simply enabling them globally and waiting for someone else to fix the
> warnings only leads to other warnings being missed.
Right.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 10:34 ` Eli Zaretskii
@ 2025-02-02 11:48 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 12:13 ` Eli Zaretskii
2025-02-02 18:27 ` Paul Eggert
0 siblings, 2 replies; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-02 11:48 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: eggert, 75964, stefankangas
"Eli Zaretskii" <eliz@gnu.org> writes:
>> Date: Sun, 02 Feb 2025 09:26:48 +0000
>> From: Pip Cet <pipcet@protonmail.com>
>> Cc: eggert@cs.ucla.edu, 75964@debbugs.gnu.org, stefankangas@gmail.com
>>
>> "Eli Zaretskii" <eliz@gnu.org> writes:
>>
>> >> Cc: 75964@debbugs.gnu.org, Stefan Kangas <stefankangas@gmail.com>
>> >> Date: Sun, 02 Feb 2025 08:39:11 +0000
>> >> From: Pip Cet via "Bug reports for GNU Emacs,
>> >> the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
>> >>
>> >> I think we should enable -Wswitch-enum now, and expect it to generate
>> >> more warnings in the future.
>> >
>> > I'm not sure I understand what "in the future" means here, but please
>>
>> Future GCC versions may and will add warnings about cases that they
>> currently fail to warn about, for the same switch. I don't think we can
>> change that.
>
> If future GCC versions add warnings, we will handle them when that
> happens and the warnings are reported or seen. We don't need (and
> really cannot) worry about that at this time.
Agreed.
>> > Apologies if the above is not relevant to what you were discussing
>> > regarding adding warning options.
>>
>> I think it's highly relevant: I proposed several ways of adding the
>> warning options: one file at a time, #pragma'd out, or enabled globally
>> and only merged once we can fix, at least, the common build systems.
>
> SGTM, thanks.
So while I'd like us to keep those options in mind, I've removed them
from the following diff. The idea is this would give an overview over
which code segments would become hard to read as a result of such a
change, and whether it's bad enough that we need to look at
alternatives.
I think this concerns bidi.c and keyboard.c in particular.
I've marked some places where I'm not sure the old behavior was okay,
but I haven't checked them in detail. I haven't found any "there was a
bug here and we only caught it because of this new warning" smoking
guns.
I've also stayed away from lib-src for now.
>> Simply enabling them globally and waiting for someone else to fix the
>> warnings only leads to other warnings being missed.
>
> Right.
diff --git a/configure.ac b/configure.ac
index 9db1f07d7fc..1fd86b9bac9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1828,6 +1828,8 @@ AC_DEFUN
[nw="$nw -Wsuggest-attribute=noreturn"])
gl_MANYWARN_ALL_GCC([ws])
+ ws="$ws -Wswitch-enum"
+# ws="$ws -Wswitch-enum-consistency" .... one day
gl_MANYWARN_COMPLEMENT([ws], [$ws], [$nw])
for w in $ws; do
gl_WARN_ADD([$w])
diff --git a/lib-src/ebrowse.c b/lib-src/ebrowse.c
index 61a45622933..2dfc42389dc 100644
--- a/lib-src/ebrowse.c
+++ b/lib-src/ebrowse.c
@@ -657,6 +657,8 @@ find_member (struct sym *cls, char *name, int var, int sc, unsigned int hash)
list = var ? &cls->static_vars : &cls->static_fns;
break;
+ case SC_UNKNOWN:
+ case SC_MEMBER:
default:
list = var ? &cls->vars : &cls->fns;
break;
@@ -902,6 +904,8 @@ add_member (struct sym *cls, char *name, int var, int sc, unsigned int hash)
list = var ? &cls->static_vars : &cls->static_fns;
break;
+ case SC_UNKNOWN:
+ case SC_MEMBER:
default:
list = var ? &cls->vars : &cls->fns;
break;
diff --git a/lib-src/make-docfile.c b/lib-src/make-docfile.c
index 6243f666955..f55057ee2ea 100644
--- a/lib-src/make-docfile.c
+++ b/lib-src/make-docfile.c
@@ -718,6 +718,7 @@ write_globals (void)
seen_defun = true;
}
break;
+ case INVALID:
default:
fatal ("not a recognized DEFVAR_");
}
diff --git a/src/alloc.c b/src/alloc.c
index 7fa05e54202..6eeffb3e4e9 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -3341,7 +3341,6 @@ cleanup_vector (struct Lisp_Vector *vector)
break;
/* Keep the switch exhaustive. */
case PVEC_NORMAL_VECTOR:
- case PVEC_FREE:
case PVEC_SYMBOL_WITH_POS:
case PVEC_MISC_PTR:
case PVEC_PROCESS:
@@ -3361,6 +3360,8 @@ cleanup_vector (struct Lisp_Vector *vector)
case PVEC_SUB_CHAR_TABLE:
case PVEC_RECORD:
break;
+ case PVEC_FREE: eassume (0);
+ default: eassume (0);
}
}
@@ -5113,8 +5114,7 @@ mark_maybe_pointer (void *p, bool symbol_only)
}
break;
- default:
- emacs_abort ();
+ default: eassume (0);
}
mark_object (obj);
@@ -5492,8 +5492,7 @@ valid_lisp_object_p (Lisp_Object obj)
case MEM_TYPE_VECTOR_BLOCK:
return live_small_vector_p (m, p);
- default:
- break;
+ default: eassume (0);
}
return 0;
@@ -6727,10 +6726,31 @@ #define CHECK_ALLOCATED_AND_LIVE_SYMBOL() ((void) 0)
#endif
break;
- case PVEC_FREE:
- emacs_abort ();
-
- default:
+ case PVEC_NORMAL_VECTOR:
+ case PVEC_BIGNUM:
+ case PVEC_MARKER:
+ case PVEC_FINALIZER:
+ case PVEC_SYMBOL_WITH_POS:
+ case PVEC_MISC_PTR:
+ case PVEC_USER_PTR:
+ case PVEC_PROCESS:
+ case PVEC_TERMINAL:
+ case PVEC_WINDOW_CONFIGURATION:
+ case PVEC_OTHER:
+ case PVEC_XWIDGET:
+ case PVEC_XWIDGET_VIEW:
+ case PVEC_THREAD:
+ case PVEC_MUTEX:
+ case PVEC_CONDVAR:
+ case PVEC_MODULE_FUNCTION:
+ case PVEC_NATIVE_COMP_UNIT:
+ case PVEC_TS_PARSER:
+ case PVEC_TS_NODE:
+ case PVEC_TS_COMPILED_QUERY:
+ case PVEC_SQLITE:
+ case PVEC_CLOSURE:
+ case PVEC_RECORD:
+ case PVEC_FONT:
{
/* A regular vector or pseudovector needing no special
treatment. */
@@ -6741,6 +6761,8 @@ #define CHECK_ALLOCATED_AND_LIVE_SYMBOL() ((void) 0)
mark_stack_push_values (ptr->contents, size);
}
break;
+ case PVEC_FREE: eassume (0);
+ default: eassume (0);
}
}
break;
@@ -6790,7 +6812,7 @@ #define CHECK_ALLOCATED_AND_LIVE_SYMBOL() ((void) 0)
reachable from font_style_table which is also
staticpro'd. */
break;
- default: emacs_abort ();
+ default: eassume (0);
}
set_string_marked (XSTRING (ptr->u.s.name));
mark_interval_tree (string_intervals (ptr->u.s.name));
@@ -6846,8 +6868,9 @@ #define CHECK_ALLOCATED_AND_LIVE_SYMBOL() ((void) 0)
case Lisp_Int1:
break;
- default:
- emacs_abort ();
+ case Lisp_Type_Unused0:
+ eassume (0);
+ default: eassume (0);
}
}
@@ -6926,8 +6949,8 @@ survives_gc_p (Lisp_Object obj)
pdumper_object_p (XFLOAT (obj));
break;
- default:
- emacs_abort ();
+ case Lisp_Type_Unused0: eassume (0);
+ default: eassume (0);
}
return survives_p;
diff --git a/src/android.c b/src/android.c
index f8d2df8fcf5..bd3a6028c85 100644
--- a/src/android.c
+++ b/src/android.c
@@ -745,8 +745,7 @@ android_write_event (union android_event *event)
kill (getpid (), SIGIO);
break;
- default:
- break;
+ default: eassume (0);
}
}
@@ -3815,8 +3814,7 @@ android_create_pixmap_from_bitmap_data (char *data, unsigned int width,
break;
- default:
- emacs_abort ();
+ default: eassume (0);
}
/* Unlock the bitmap itself. */
@@ -4346,8 +4344,7 @@ android_copy_area (android_drawable src, android_drawable dest,
/* do_blit = android_blit_invert; */
/* A GC with its operation set to ANDROID_GC_INVERT is never given
to CopyArea. */
- default:
- emacs_abort ();
+ default: eassume (0);
}
/* Load the bounds of the destination rectangle. */
@@ -4799,8 +4796,7 @@ android_get_image (android_drawable handle,
break;
/* Other formats are currently not supported. */
- default:
- emacs_abort ();
+ default: eassume (0);
}
image->format = format;
diff --git a/src/bidi.c b/src/bidi.c
index d8754e2db73..9fd33a049c5 100644
--- a/src/bidi.c
+++ b/src/bidi.c
@@ -303,8 +303,20 @@ bidi_get_type (int ch, bidi_dir_t override)
case FSI:
case PDI:
return default_type;
- default:
- if (override == L2R)
+ case UNKNOWN_BT:
+ case STRONG_L:
+ case STRONG_R:
+ case WEAK_EN:
+ case WEAK_AN:
+ case STRONG_AL:
+ case WEAK_ES:
+ case WEAK_ET:
+ case WEAK_CS:
+ case WEAK_NSM:
+ case NEUTRAL_S:
+ case NEUTRAL_WS:
+ case NEUTRAL_ON:
+ default: if (override == L2R)
return STRONG_L;
else if (override == R2L)
return STRONG_R;
@@ -354,8 +366,7 @@ bidi_get_category (bidi_type_t type)
case FSI:
case PDI:
return EXPLICIT_FORMATTING;
- default:
- emacs_abort ();
+ default: emacs_abort ();
}
}
@@ -2047,8 +2058,28 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
new_level = bidi_pop_embedding_level (bidi_it);
}
break;
- default:
- eassert (prev_type != FSI);
+ case UNKNOWN_BT:
+ case STRONG_L:
+ case STRONG_R:
+ case WEAK_EN:
+ case WEAK_AN:
+ case WEAK_BN:
+ case NEUTRAL_B:
+ case STRONG_AL:
+ case LRE:
+ case LRO:
+ case RLE:
+ case RLO:
+ case FSI:
+ case PDI:
+ case WEAK_ES:
+ case WEAK_ET:
+ case WEAK_CS:
+ case WEAK_NSM:
+ case NEUTRAL_S:
+ case NEUTRAL_WS:
+ case NEUTRAL_ON:
+ default: eassert (prev_type != FSI);
/* Nothing. */
break;
}
@@ -2197,8 +2228,22 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
bidi_check_type (bidi_it->type_after_wn);
type = WEAK_BN; /* X9/Retaining */
break;
- default:
- /* Nothing. */
+ case UNKNOWN_BT:
+ case STRONG_L:
+ case STRONG_R:
+ case WEAK_EN:
+ case WEAK_AN:
+ case WEAK_BN:
+ case NEUTRAL_B:
+ case STRONG_AL:
+ case WEAK_ES:
+ case WEAK_ET:
+ case WEAK_CS:
+ case WEAK_NSM:
+ case NEUTRAL_S:
+ case NEUTRAL_WS:
+ case NEUTRAL_ON:
+ default: /* Nothing. */
break;
}
@@ -2723,8 +2768,27 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it)
: FLAG_OPPOSITE_INSIDE);
r2l_seen = true;
break;
- default:
- break;
+ case UNKNOWN_BT:
+ case WEAK_BN:
+ case NEUTRAL_B:
+ case STRONG_AL:
+ case LRE:
+ case LRO:
+ case RLE:
+ case RLO:
+ case PDF:
+ case LRI:
+ case RLI:
+ case FSI:
+ case PDI:
+ case WEAK_ES:
+ case WEAK_ET:
+ case WEAK_CS:
+ case WEAK_NSM:
+ case NEUTRAL_S:
+ case NEUTRAL_WS:
+ case NEUTRAL_ON:
+ default: break;
}
if (flag)
{
@@ -2995,8 +3059,27 @@ bidi_resolve_brackets (struct bidi_it *bidi_it)
? STRONG_L /* N0c1 */
: embedding_type; /* N0c2 */
break;
- default:
- /* N0d: Do not set the type for that bracket pair. */
+ case UNKNOWN_BT:
+ case WEAK_BN:
+ case NEUTRAL_B:
+ case STRONG_AL:
+ case LRE:
+ case LRO:
+ case RLE:
+ case RLO:
+ case PDF:
+ case LRI:
+ case RLI:
+ case FSI:
+ case PDI:
+ case WEAK_ES:
+ case WEAK_ET:
+ case WEAK_CS:
+ case WEAK_NSM:
+ case NEUTRAL_S:
+ case NEUTRAL_WS:
+ case NEUTRAL_ON:
+ default: /* N0d: Do not set the type for that bracket pair. */
break;
}
}
@@ -3191,8 +3274,26 @@ bidi_resolve_neutral (struct bidi_it *bidi_it)
were R in terms of their influence on NIs." */
next_type = STRONG_R;
break;
- default:
- emacs_abort ();
+ case UNKNOWN_BT:
+ case WEAK_BN:
+ case NEUTRAL_B:
+ case LRE:
+ case LRO:
+ case RLE:
+ case RLO:
+ case PDF:
+ case LRI:
+ case RLI:
+ case FSI:
+ case PDI:
+ case WEAK_ES:
+ case WEAK_ET:
+ case WEAK_CS:
+ case WEAK_NSM:
+ case NEUTRAL_S:
+ case NEUTRAL_WS:
+ case NEUTRAL_ON:
+ default: emacs_abort ();
break;
}
}
diff --git a/src/buffer.c b/src/buffer.c
index 40f7ec83d6b..4e8f12727c1 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1389,7 +1389,7 @@ buffer_local_value (Lisp_Object variable, Lisp_Object buffer)
result = Fdefault_value (variable);
break;
}
- default: emacs_abort ();
+ default: eassume (0);
}
return result;
diff --git a/src/data.c b/src/data.c
index 5fcdda1b6e8..aac95f4329e 100644
--- a/src/data.c
+++ b/src/data.c
@@ -286,16 +286,18 @@ DEFUN ("cl-type-of", Fcl_type_of, Scl_type_of, 1, 1, 0,
return Qsub_char_table;
/* "Impossible" cases. */
case PVEC_MISC_PTR:
- case PVEC_OTHER:
- case PVEC_FREE: ;
+ case PVEC_OTHER: break;
+ case PVEC_FREE: eassume (0);
}
emacs_abort ();
case Lisp_Float:
return Qfloat;
- default:
- emacs_abort ();
+ default: eassume (0);
+
+ case Lisp_Type_Unused0:
+ eassume (0);
}
}
@@ -737,7 +739,7 @@ DEFUN ("boundp", Fboundp, Sboundp, 1, 1, 0,
/* In set_internal, we un-forward vars when their value is
set to Qunbound. */
return Qt;
- default: emacs_abort ();
+ default: eassume (0);
}
return (BASE_EQ (valcontents, Qunbound) ? Qnil : Qt);
@@ -1335,7 +1337,7 @@ do_symval_forwarding (lispfwd valcontents)
case Lisp_Fwd_Kboard_Obj:
return *(Lisp_Object *) (XKBOARD_OBJFWD (valcontents)->offset
+ (char *) kboard_for_bindings ());
- default: emacs_abort ();
+ default: eassume (0);
}
}
@@ -1592,7 +1594,7 @@ find_symbol_value (Lisp_Object symbol)
}
case SYMBOL_FORWARDED:
return do_symval_forwarding (SYMBOL_FWD (sym));
- default: emacs_abort ();
+ default: eassume (0);
}
}
@@ -1664,7 +1666,7 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where,
case SYMBOL_UNTRAPPED_WRITE:
break;
- default: emacs_abort ();
+ default: eassume (0);
}
start:
@@ -1777,7 +1779,7 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where,
store_symval_forwarding (/* sym, */ innercontents, newval, buf);
break;
}
- default: emacs_abort ();
+ default: eassume (0);
}
return;
}
@@ -1951,7 +1953,7 @@ default_value (Lisp_Object symbol)
/* For other variables, get the current value. */
return do_symval_forwarding (valcontents);
}
- default: emacs_abort ();
+ default: eassume (0);
}
}
@@ -2009,7 +2011,7 @@ set_default_internal (Lisp_Object symbol, Lisp_Object value,
case SYMBOL_UNTRAPPED_WRITE:
break;
- default: emacs_abort ();
+ default: eassume (0);
}
start:
@@ -2075,7 +2077,7 @@ set_default_internal (Lisp_Object symbol, Lisp_Object value,
set_internal (symbol, value, Qnil, bindflag);
return;
}
- default: emacs_abort ();
+ default: eassume (0);
}
}
@@ -2177,7 +2179,7 @@ DEFUN ("make-variable-buffer-local", Fmake_variable_buffer_local,
else if (BUFFER_OBJFWDP (valcontents.fwd))
return variable;
break;
- default: emacs_abort ();
+ default: eassume (0);
}
if (SYMBOL_CONSTANT_P (variable))
@@ -2240,7 +2242,7 @@ DEFUN ("make-local-variable", Fmake_local_variable, Smake_local_variable,
error ("Symbol %s may not be buffer-local",
SDATA (SYMBOL_NAME (variable)));
break;
- default: emacs_abort ();
+ default: eassume (0);
}
if (sym->u.s.trapped_write == SYMBOL_NOWRITE)
@@ -2337,7 +2339,7 @@ DEFUN ("kill-local-variable", Fkill_local_variable, Skill_local_variable,
case SYMBOL_LOCALIZED:
blv = SYMBOL_BLV (sym);
break;
- default: emacs_abort ();
+ default: eassume (0);
}
if (sym->u.s.trapped_write == SYMBOL_TRAPPED_WRITE)
@@ -2410,7 +2412,7 @@ DEFUN ("local-variable-p", Flocal_variable_p, Slocal_variable_p,
}
return Qnil;
}
- default: emacs_abort ();
+ default: eassume (0);
}
}
@@ -2445,7 +2447,7 @@ DEFUN ("local-variable-if-set-p", Flocal_variable_if_set_p, Slocal_variable_if_s
case SYMBOL_FORWARDED:
/* All BUFFER_OBJFWD slots become local if they are set. */
return (BUFFER_OBJFWDP (SYMBOL_FWD (sym)) ? Qt : Qnil);
- default: emacs_abort ();
+ default: eassume (0);
}
}
@@ -2488,7 +2490,7 @@ DEFUN ("variable-binding-locus", Fvariable_binding_locus, Svariable_binding_locu
return SYMBOL_BLV (sym)->where;
else
return Qnil;
- default: emacs_abort ();
+ default: eassume (0);
}
}
@@ -3133,7 +3135,10 @@ floatop_arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args,
xsignal0 (Qarith_error);
accum /= next;
break;
- default: eassume (false);
+ case Alogior:
+ case Alogxor:
+ case Alogand:
+ default: eassume (0);
}
next_arg:
@@ -3193,8 +3198,7 @@ bignum_arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args,
xsignal0 (Qarith_error);
mpz_tdiv_q (mpz[0], *accum, *next);
break;
- default:
- eassume (false);
+ default: eassume (0);
}
accum = &mpz[0];
@@ -3258,7 +3262,7 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args,
case Alogand: accum &= next; continue;
case Alogior: accum |= next; continue;
case Alogxor: accum ^= next; continue;
- default: eassume (false);
+ default: eassume (0);
}
if (overflow)
break;
@@ -3772,8 +3776,8 @@ bool_vector_binop_driver (Lisp_Object a,
destdata[i] = adata[i] &~ bdata[i];
break;
- default:
- eassume (0);
+ case bool_vector_subsetp:
+ default: eassume (0);
}
return dest;
diff --git a/src/dbusbind.c b/src/dbusbind.c
index 5f89122eaf7..e22347a7e1e 100644
--- a/src/dbusbind.c
+++ b/src/dbusbind.c
@@ -557,8 +557,7 @@ xd_signature (char *signature, int dtype, int parent_type, Lisp_Object object)
xd_signature_cat (signature, DBUS_DICT_ENTRY_END_CHAR_AS_STRING);
break;
- default:
- wrong_type_argument (QD_Bus, object);
+ default: wrong_type_argument (QD_Bus, object);
}
XD_DEBUG_MESSAGE ("%s", signature);
@@ -985,8 +984,7 @@ xd_retrieve_arg (int dtype, DBusMessageIter *iter)
return Fcons (xd_dbus_type_to_symbol (dtype), Fnreverse (result));
}
- default:
- XD_DEBUG_MESSAGE ("DBusType '%c' not supported", dtype);
+ default: XD_DEBUG_MESSAGE ("DBusType '%c' not supported", dtype);
return Qnil;
}
}
diff --git a/src/dired.c b/src/dired.c
index 915a2097042..95108fb7b14 100644
--- a/src/dired.c
+++ b/src/dired.c
@@ -612,8 +612,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag,
directoryp = file_name_completion_dirp (fd, dp, len);
break;
- default:
- directoryp = false;
+ default: directoryp = false;
break;
}
diff --git a/src/dispextern.h b/src/dispextern.h
index 1b383164752..85b2e57402b 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -2337,9 +2337,11 @@ #define MAX_FRINGE_BITMAPS (1<<FRINGE_ID_BITS)
GET_FROM_IMAGE,
GET_FROM_STRETCH,
GET_FROM_XWIDGET,
- NUM_IT_METHODS
+ MAX_IT_METHOD = GET_FROM_XWIDGET
};
+#define NUM_IT_METHODS (MAX_IT_METHOD + 1)
+
/* FIXME: What is this? Why 5? */
#define IT_STACK_SIZE 5
diff --git a/src/dispnew.c b/src/dispnew.c
index 5f5575d484b..cd1f2255c93 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -3608,6 +3608,8 @@ produce_box_glyphs (enum box box, struct glyph_row *row, int x, int n,
case BOX_DOUBLE_UP_RIGHT:
case BOX_DOUBLE_UP_LEFT:
emacs_abort ();
+ default:
+ eassume (0);
}
/* FIXME/tty: some face for the border. */
diff --git a/src/emacs.c b/src/emacs.c
index f0281044c9e..72a2e42b193 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -846,6 +846,7 @@ dump_error_to_string (int result)
return "dump file is result of failed dump attempt";
case PDUMPER_LOAD_VERSION_MISMATCH:
return "not built for this Emacs executable";
+ case PDUMPER_LOAD_ERROR:
default:
return (result <= PDUMPER_LOAD_ERROR
? "generic error"
diff --git a/src/eval.c b/src/eval.c
index 70f533842b9..372b84d4d48 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -729,6 +729,19 @@ default_toplevel_binding (Lisp_Object symbol)
{
switch ((--pdl)->kind)
{
+ case SPECPDL_UNWIND:
+ case SPECPDL_UNWIND_ARRAY:
+ case SPECPDL_UNWIND_PTR:
+ case SPECPDL_UNWIND_INT:
+ case SPECPDL_UNWIND_INTMAX:
+ case SPECPDL_UNWIND_EXCURSION:
+ case SPECPDL_UNWIND_VOID:
+ case SPECPDL_BACKTRACE:
+ case SPECPDL_NOP:
+ case SPECPDL_MODULE_RUNTIME:
+ case SPECPDL_MODULE_ENVIRONMENT:
+ case SPECPDL_LET_LOCAL:
+ break;
case SPECPDL_LET_DEFAULT:
case SPECPDL_LET:
if (EQ (specpdl_symbol (pdl), symbol))
@@ -762,6 +775,18 @@ lexbound_p (Lisp_Object symbol)
}
break;
+ case SPECPDL_UNWIND:
+ case SPECPDL_UNWIND_ARRAY:
+ case SPECPDL_UNWIND_PTR:
+ case SPECPDL_UNWIND_INT:
+ case SPECPDL_UNWIND_INTMAX:
+ case SPECPDL_UNWIND_EXCURSION:
+ case SPECPDL_UNWIND_VOID:
+ case SPECPDL_BACKTRACE:
+ case SPECPDL_NOP:
+ case SPECPDL_MODULE_RUNTIME:
+ case SPECPDL_MODULE_ENVIRONMENT:
+ case SPECPDL_LET_LOCAL:
default: break;
}
}
@@ -3489,6 +3514,7 @@ do_specbind (struct Lisp_Symbol *sym, union specbinding *bind,
set_internal (specpdl_symbol (bind), value, Qnil, bindflag);
break;
+ case SYMBOL_VARALIAS:
default:
emacs_abort ();
}
@@ -4081,6 +4107,15 @@ specpdl_unrewind (union specbinding *pdl, int distance, bool vars_only)
}
break;
+ case SPECPDL_UNWIND_ARRAY:
+ case SPECPDL_UNWIND_PTR:
+ case SPECPDL_UNWIND_INT:
+ case SPECPDL_UNWIND_INTMAX:
+ case SPECPDL_UNWIND_VOID:
+ case SPECPDL_BACKTRACE:
+ case SPECPDL_NOP:
+ case SPECPDL_MODULE_RUNTIME:
+ case SPECPDL_MODULE_ENVIRONMENT:
default: break;
}
}
@@ -4149,6 +4184,18 @@ DEFUN ("backtrace--locals", Fbacktrace__locals, Sbacktrace__locals, 1, 2, NULL,
{
switch (tmp->kind)
{
+ case SPECPDL_UNWIND:
+ case SPECPDL_UNWIND_ARRAY:
+ case SPECPDL_UNWIND_PTR:
+ case SPECPDL_UNWIND_INT:
+ case SPECPDL_UNWIND_INTMAX:
+ case SPECPDL_UNWIND_EXCURSION:
+ case SPECPDL_UNWIND_VOID:
+ case SPECPDL_BACKTRACE:
+ case SPECPDL_NOP:
+ case SPECPDL_MODULE_RUNTIME:
+ case SPECPDL_MODULE_ENVIRONMENT
+ break;
case SPECPDL_LET:
case SPECPDL_LET_DEFAULT:
case SPECPDL_LET_LOCAL:
diff --git a/src/filelock.c b/src/filelock.c
index e61c6776e3e..3105e8044d3 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -373,7 +373,9 @@ integer_prefixed (char const *s)
ANOTHER_OWNS_IT = NEGATIVE_ERRNO ? 1 : -1,
/* This Emacs process owns it. */
- I_OWN_IT = 2 * ANOTHER_OWNS_IT
+ I_OWN_IT = 2 * ANOTHER_OWNS_IT,
+
+ NOBODY_OWNS_IT = 0,
};
/* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete,
@@ -800,7 +802,7 @@ DEFUN ("file-locked-p", Ffile_locked_p, Sfile_locked_p, 1, 1, 0,
case ANOTHER_OWNS_IT:
ret = make_string (locker.user, locker.at - locker.user);
break;
- case 0: ret = Qnil; break;
+ case NOBODY_OWNS_IT: ret = Qnil; break;
default: report_file_errno ("Testing file lock", filename, owner);
}
diff --git a/src/fns.c b/src/fns.c
index ec1a39fada7..1d3ec32a637 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -2860,6 +2860,12 @@ internal_equal_1 (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind,
else
hash_put (h, o1, Fcons (o2, Qnil), hash);
}
+ case Lisp_Symbol:
+ case Lisp_Type_Unused0:
+ case Lisp_Int0:
+ case Lisp_Int1:
+ case Lisp_String:
+ case Lisp_Float:
default: ;
}
}
@@ -2986,8 +2992,12 @@ internal_equal_1 (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind,
&& (equal_kind != EQUAL_INCLUDING_PROPERTIES
|| compare_string_intervals (o1, o2)));
- default:
- break;
+ case Lisp_Type_Unused0:
+ eassume (0);
+ case Lisp_Symbol:
+ case Lisp_Int0:
+ case Lisp_Int1:
+ default: break;
}
return false;
@@ -3195,8 +3205,35 @@ value_cmp (Lisp_Object a, Lisp_Object b, int maxdepth)
b = XSYMBOL_WITH_POS_SYM (b);
goto tail_recurse;
- default:
- /* Treat other types as unordered. */
+ case PVEC_FREE: eassume (0);
+ case PVEC_OVERLAY:
+ case PVEC_FINALIZER:
+ case PVEC_MISC_PTR:
+ case PVEC_USER_PTR:
+ case PVEC_FRAME:
+ case PVEC_WINDOW:
+ case PVEC_HASH_TABLE:
+ case PVEC_OBARRAY:
+ case PVEC_TERMINAL:
+ case PVEC_WINDOW_CONFIGURATION:
+ case PVEC_SUBR:
+ case PVEC_OTHER:
+ case PVEC_XWIDGET:
+ case PVEC_XWIDGET_VIEW:
+ case PVEC_THREAD:
+ case PVEC_MUTEX:
+ case PVEC_CONDVAR:
+ case PVEC_MODULE_FUNCTION:
+ case PVEC_NATIVE_COMP_UNIT:
+ case PVEC_TS_PARSER:
+ case PVEC_TS_NODE:
+ case PVEC_TS_COMPILED_QUERY:
+ case PVEC_SQLITE:
+ case PVEC_CLOSURE:
+ case PVEC_CHAR_TABLE:
+ case PVEC_SUB_CHAR_TABLE:
+ case PVEC_FONT:
+ default: /* Treat other types as unordered. */
return 0;
}
}
@@ -3226,8 +3263,8 @@ value_cmp (Lisp_Object a, Lisp_Object b, int maxdepth)
}
goto type_mismatch;
- default:
- eassume (0);
+ case Lisp_Type_Unused0:
+ default: eassume (0);
}
type_mismatch:
xsignal2 (Qtype_mismatch, a, b);
@@ -5572,8 +5609,9 @@ sxhash_obj (Lisp_Object obj, int depth)
case Lisp_Float:
return sxhash_float (XFLOAT_DATA (obj));
- default:
- emacs_abort ();
+ case Lisp_Type_Unused0:
+ eassume (0);
+ default: emacs_abort ();
}
}
diff --git a/src/font.c b/src/font.c
index dfe479f9355..1bbb27b07fc 100644
--- a/src/font.c
+++ b/src/font.c
@@ -432,8 +432,22 @@ font_style_to_value (enum font_property_index prop, Lisp_Object val,
case FONT_WIDTH_INDEX:
Vfont_width_table = new_table;
break;
- default:
- break;
+ case FONT_TYPE_INDEX:
+ case FONT_FOUNDRY_INDEX:
+ case FONT_FAMILY_INDEX:
+ case FONT_ADSTYLE_INDEX:
+ case FONT_REGISTRY_INDEX:
+ case FONT_SIZE_INDEX:
+ case FONT_DPI_INDEX:
+ case FONT_SPACING_INDEX:
+ case FONT_AVGWIDTH_INDEX:
+ case FONT_EXTRA_INDEX:
+ case FONT_OBJLIST_INDEX:
+ case FONT_NAME_INDEX:
+ case FONT_FULLNAME_INDEX:
+ case FONT_FILE_INDEX:
+ case FONT_OBJECT_MAX:
+ default: eassume (0);
}
ASET (font_style_table, prop - FONT_WEIGHT_INDEX, new_table);
return (100 << 8) | (i << 4);
diff --git a/src/fringe.c b/src/fringe.c
index 5cd6ff5fc8d..301ea0aba3d 100644
--- a/src/fringe.c
+++ b/src/fringe.c
@@ -861,8 +861,8 @@ draw_fringe_bitmap (struct window *w, struct glyph_row *row, int left_p)
cursor = Qhbar;
break;
case NO_CURSOR:
- default:
- w->phys_cursor_on_p = 0;
+ case DEFAULT_CURSOR:
+ default: w->phys_cursor_on_p = 0;
row->cursor_in_fringe_p = 0;
break;
}
diff --git a/src/keyboard.c b/src/keyboard.c
index 2d8c45c05ee..2b6a27c0604 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -4278,8 +4278,27 @@ kbd_buffer_get_event (KBOARD **kbp,
kbd_fetch_ptr = next_kbd_event (event);
}
break;
- default:
- {
+
+ case MULTIBYTE_CHAR_KEYSTROKE_EVENT:
+ case ASCII_KEYSTROKE_EVENT:
+ case NON_ASCII_KEYSTROKE_EVENT:
+ case TIMER_EVENT:
+ case MOUSE_CLICK_EVENT:
+ case WHEEL_EVENT:
+ case HORIZ_WHEEL_EVENT:
+ case SCROLL_BAR_CLICK_EVENT:
+ case HORIZONTAL_SCROLL_BAR_CLICK_EVENT:
+ case MENU_BAR_EVENT:
+ case DRAG_N_DROP_EVENT:
+ case USER_SIGNAL_EVENT:
+ case TAB_BAR_EVENT:
+ case TOOL_BAR_EVENT:
+ case TOUCH_END_EVENT:
+ case TOUCHSCREEN_UPDATE_EVENT:
+ case TOUCHSCREEN_BEGIN_EVENT:
+ case TOUCHSCREEN_END_EVENT:
+ case PINCH_EVENT:
+ default: {
/* If this event is on a different frame, return a
switch-frame this time, and leave the event in the queue
for next time. */
@@ -7117,9 +7136,15 @@ make_lispy_event (struct input_event *event)
case PREEDIT_TEXT_EVENT:
return list2 (Qpreedit_text, event->arg);
- /* The 'kind' field of the event is something we don't recognize. */
- default:
+ case SELECTION_REQUEST_EVENT:
+ case MENU_BAR_ACTIVATE_EVENT:
+ case SELECTION_CLEAR_EVENT:
+ case MONITORS_CHANGED_EVENT:
+ case TIMER_EVENT:
emacs_abort ();
+
+ /* The 'kind' field of the event is something we don't recognize. */
+ default: emacs_abort ();
}
}
@@ -12826,6 +12851,36 @@ is_ignored_event (union buffered_input_event *event)
#ifdef HAVE_DBUS
case DBUS_EVENT: ignore_event = Qdbus_event; break;
#endif
+ case ASCII_KEYSTROKE_EVENT:
+ case MULTIBYTE_CHAR_KEYSTROKE_EVENT:
+ case NON_ASCII_KEYSTROKE_EVENT:
+ case TIMER_EVENT:
+ case MOUSE_CLICK_EVENT:
+ case WHEEL_EVENT:
+ case HORIZ_WHEEL_EVENT:
+ case SCROLL_BAR_CLICK_EVENT:
+ case HORIZONTAL_SCROLL_BAR_CLICK_EVENT:
+ case SELECTION_CLEAR_EVENT:
+ case DELETE_WINDOW_EVENT:
+ case MENU_BAR_EVENT:
+ case MENU_BAR_ACTIVATE_EVENT:
+ case DRAG_N_DROP_EVENT:
+ case USER_SIGNAL_EVENT:
+ case TAB_BAR_EVENT:
+ case TOOL_BAR_EVENT:
+ case MOVE_FRAME_EVENT:
+ case SELECT_WINDOW_EVENT:
+ case SAVE_SESSION_EVENT:
+ case THREAD_EVENT:
+ case CONFIG_CHANGED_EVENT:
+ case PREEDIT_TEXT_EVENT:
+ case TOUCH_END_EVENT:
+ case TOUCHSCREEN_UPDATE_EVENT:
+ case TOUCHSCREEN_BEGIN_EVENT:
+ case TOUCHSCREEN_END_EVENT:
+ case PINCH_EVENT:
+ case MONITORS_CHANGED_EVENT:
+ case NO_EVENT:
default: ignore_event = Qnil; break;
}
diff --git a/src/lread.c b/src/lread.c
index 6af95873bb8..5e2389b3a64 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -3994,8 +3994,14 @@ read0 (Lisp_Object readcharfun, bool locate_syms)
obj = string_props_from_rev_list (read_stack_pop () ->u.vector.elems,
readcharfun);
break;
- default:
- invalid_syntax (")", readcharfun);
+ case RE_list_dot: /* ( a . ) */
+ case RE_vector: /* [ a ) */
+ case RE_char_table:
+ case RE_sub_char_table:
+ case RE_byte_code:
+ case RE_special:
+ case RE_numbered:
+ default: invalid_syntax (")", readcharfun);
}
break;
@@ -4032,8 +4038,14 @@ read0 (Lisp_Object readcharfun, bool locate_syms)
obj = sub_char_table_from_rev_list (read_stack_pop ()->u.vector.elems,
readcharfun);
break;
- default:
- invalid_syntax ("]", readcharfun);
+ case RE_list_start:
+ case RE_list:
+ case RE_list_dot:
+ case RE_record:
+ case RE_string_props:
+ case RE_special:
+ case RE_numbered:
+ default: invalid_syntax ("]", readcharfun);
break;
}
break;
@@ -4695,8 +4707,14 @@ substitute_object_recurse (struct subst *subst, Lisp_Object subtree)
}
/* Other types don't recurse any further. */
- default:
+ case Lisp_Int0:
+ case Lisp_Int1:
+ case Lisp_Float:
+ case Lisp_Symbol:
return subtree;
+
+ case Lisp_Type_Unused0:
+ default: eassume (0);
}
}
diff --git a/src/pdumper.c b/src/pdumper.c
index dee13fb9a81..9918a690e58 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -178,19 +178,35 @@ #define dump_offsetof(type, member) \
/* dump_ptr = dump_ptr + dump_base */
RELOC_DUMP_TO_DUMP_PTR_RAW,
/* dump_mpz = [rebuild bignum] */
+#ifdef HAVE_NATIVE_COMP
RELOC_NATIVE_COMP_UNIT,
RELOC_NATIVE_SUBR,
+#endif
RELOC_BIGNUM,
/* dump_lv = make_lisp_ptr (dump_lv + dump_base,
type - RELOC_DUMP_TO_DUMP_LV)
(Special case for symbols: make_lisp_symbol)
Must be second-last. */
RELOC_DUMP_TO_DUMP_LV,
+ RELOC_DUMP_TO_DUMP_LV1,
+ RELOC_DUMP_TO_DUMP_LV2,
+ RELOC_DUMP_TO_DUMP_LV3,
+ RELOC_DUMP_TO_DUMP_LV4,
+ RELOC_DUMP_TO_DUMP_LV5,
+ RELOC_DUMP_TO_DUMP_LV6,
+ RELOC_DUMP_TO_DUMP_LV7,
/* dump_lv = make_lisp_ptr (dump_lv + emacs_basis(),
type - RELOC_DUMP_TO_DUMP_LV)
(Special case for symbols: make_lisp_symbol.)
Must be last. */
RELOC_DUMP_TO_EMACS_LV = RELOC_DUMP_TO_DUMP_LV + 8,
+ RELOC_DUMP_TO_EMACS_LV1,
+ RELOC_DUMP_TO_EMACS_LV2,
+ RELOC_DUMP_TO_EMACS_LV3,
+ RELOC_DUMP_TO_EMACS_LV4,
+ RELOC_DUMP_TO_EMACS_LV5,
+ RELOC_DUMP_TO_EMACS_LV6,
+ RELOC_DUMP_TO_EMACS_LV7,
};
enum emacs_reloc_type
@@ -1445,6 +1461,9 @@ dump_reloc_dump_to_dump_lv (struct dump_context *ctx,
case Lisp_Float:
reloc_type = RELOC_DUMP_TO_DUMP_LV + type;
break;
+ case Lisp_Type_Unused0: eassume (0);
+ case Lisp_Int0:
+ case Lisp_Int1:
default:
emacs_abort ();
}
@@ -1494,8 +1513,12 @@ dump_reloc_dump_to_emacs_lv (struct dump_context *ctx,
case Lisp_Float:
reloc_type = RELOC_DUMP_TO_EMACS_LV + type;
break;
+ case Lisp_Symbol:
+ case Lisp_Int0:
+ case Lisp_Int1:
default:
emacs_abort ();
+ case Lisp_Type_Unused0: eassume (0);
}
dump_push (&ctx->dump_relocs[EARLY_RELOCS],
@@ -1817,8 +1840,12 @@ dump_field_lv_or_rawptr (struct dump_context *ctx,
case Lisp_Float:
value = make_lisp_ptr (ptrval, *ptr_raw_type);
break;
- default:
- emacs_abort ();
+ case Lisp_Int0:
+ case Lisp_Int1:
+ emacs_abort ();
+
+ case Lisp_Type_Unused0: eassume (0);
+ default: eassume (0);
}
}
@@ -2392,8 +2419,7 @@ dump_fwd (struct dump_context *ctx, lispfwd fwd)
case Lisp_Fwd_Kboard_Obj:
offset = dump_fwd_kboard_obj (ctx, p);
break;
- default:
- emacs_abort ();
+ default: eassume (0);
}
return offset;
@@ -2458,8 +2484,10 @@ dump_pre_dump_symbol (struct dump_context *ctx, struct Lisp_Symbol *symbol)
dump_remember_symbol_aux (ctx, symbol_lv,
dump_fwd (ctx, symbol->u.s.val.fwd));
break;
- default:
+ case SYMBOL_PLAINVAL:
+ case SYMBOL_VARALIAS:
break;
+ default: eassume (0);
}
dump_clear_referrer (ctx);
}
@@ -2524,8 +2552,7 @@ dump_symbol (struct dump_context *ctx,
case SYMBOL_FORWARDED:
dump_field_fixup_later (ctx, &out, symbol, &symbol->u.s.val.fwd);
break;
- default:
- emacs_abort ();
+ default: eassume (0);
}
dump_field_lv (ctx, &out, symbol, &symbol->u.s.function, WEIGHT_NORMAL);
dump_field_lv (ctx, &out, symbol, &symbol->u.s.plist, WEIGHT_NORMAL);
@@ -2555,8 +2582,10 @@ dump_symbol (struct dump_context *ctx,
? aux_offset
: dump_fwd (ctx, symbol->u.s.val.fwd)));
break;
- default:
+ case SYMBOL_PLAINVAL:
+ case SYMBOL_VARALIAS:
break;
+ default: eassume (0);
}
return offset;
}
@@ -3142,10 +3171,11 @@ dump_vectorlike (struct dump_context *ctx,
case PVEC_SQLITE:
case PVEC_MODULE_FUNCTION:
case PVEC_SYMBOL_WITH_POS:
- case PVEC_FREE:
case PVEC_TS_PARSER:
case PVEC_TS_NODE:
break;
+ case PVEC_FREE: eassume (0);
+ default: eassume (0);
}
int iptype = ptype;
static char const fmt[] = "pseudovector type %d";
@@ -3248,8 +3278,9 @@ dump_object (struct dump_context *ctx, Lisp_Object object)
case Lisp_Int1:
eassert ("should not be dumping int: is self-representing" && 0);
abort ();
- default:
- emacs_abort ();
+ case Lisp_Type_Unused0:
+ eassume (0);
+ default: eassume (0);
}
dump_clear_referrer (ctx);
@@ -3605,8 +3636,7 @@ dump_drain_cold_data (struct dump_context *ctx)
dump_cold_native_subr (ctx, data);
break;
#endif
- default:
- emacs_abo
rt ();
+ default: eassume (0);
}
}
@@ -3633,8 +3663,12 @@ read_ptr_raw_and_lv (const void *mem,
case Lisp_Float:
*out_lv = make_lisp_ptr (*out_ptr, type);
break;
- default:
- emacs_abort ();
+ case Lisp_Int0:
+ case Lisp_Int1:
+ emacs_abort ();
+ case Lisp_Type_Unused0:
+ eassume (0);
+ default: eassume (0);
}
}
}
@@ -3886,8 +3920,7 @@ decode_emacs_reloc (struct dump_context *ctx, Lisp_Object lreloc)
}
}
break;
- default:
- eassume (!"not reached");
+ default: eassume (0);
}
/* We should have consumed the whole relocation descriptor. */
@@ -4071,8 +4104,7 @@ dump_do_fixup (struct dump_context *ctx,
do_write = false;
break;
}
- default:
- emacs_abort ();
+ default: eassume (0);
}
if (do_write)
dump_write (ctx, &dump_value, sizeof (dump_value));
@@ -4523,8 +4555,7 @@ dump_anonymous_allocate_w32 (void *base,
mem_type = MEM_COMMIT;
mem_prot = PAGE_READWRITE;
break;
- default:
- emacs_abort ();
+ default: eassume (0);
}
ret = VirtualAlloc (base, size, mem_type, mem_prot);
@@ -4563,8 +4594,7 @@ dump_anonymous_allocate_posix (void *base,
case DUMP_MEMORY_ACCESS_READWRITE:
mem_prot = PROT_READ | PROT_WRITE;
break;
- default:
- emacs_abort ();
+ default: eassume (0);
}
int mem_flags = MAP_PRIVATE | MAP_ANONYMOUS;
@@ -4657,11 +4687,11 @@ dump_map_file_w32 (void *base, int fd, off_t offset, size_t size,
case DUMP_MEMORY_ACCESS_READWRITE:
protect = PAGE_WRITECOPY; /* for Windows 9X */
break;
- default:
case DUMP_MEMORY_ACCESS_NONE:
case DUMP_MEMORY_ACCESS_READ:
protect = PAGE_READONLY;
break;
+ default: eassume (0);
}
section = CreateFileMapping (file,
@@ -4685,8 +4715,7 @@ dump_map_file_w32 (void *base, int fd, off_t offset, size_t size,
case DUMP_MEMORY_ACCESS_READWRITE:
map_access = FILE_MAP_COPY;
break;
- default:
- emacs_abort ();
+ default: eassume (0);
}
ret = MapViewOfFileEx (section,
@@ -4729,8 +4758,7 @@ dump_map_file_posix (void *base, int fd, off_t offset, size_t size,
mem_prot = PROT_READ | PROT_WRITE;
mem_flags = MAP_PRIVATE;
break;
- default:
- emacs_abort ();
+ default: eassume (0);
}
if (base)
@@ -5531,13 +5559,16 @@ dump_do_dump_relocation (const uintptr_t dump_base,
mpz_roinit_n (bignum->value, limbs, reload_info.nlimbs);
break;
}
- default: /* Lisp_Object in the dump; precise type in reloc.type */
+ case RELOC_DUMP_TO_DUMP_LV ... RELOC_DUMP_TO_DUMP_LV + 7:
+ case RELOC_DUMP_TO_EMACS_LV ... RELOC_DUMP_TO_EMACS_LV + 7:
+ /* Lisp_Object in the dump; precise type in reloc.type */
{
Lisp_Object lv = dump_make_lv_from_reloc (dump_base, reloc);
eassert (dump_reloc_size (reloc) == sizeof (lv));
dump_write_lv_to_dump (dump_base, reloc_offset, lv);
break;
}
+ default: eassume (0);
}
}
@@ -5597,8 +5628,7 @@ dump_do_emacs_relocation (const uintptr_t dump_base,
memcpy (emacs_ptr_at (reloc.emacs_offset), &lv, sizeof (lv));
break;
}
- default:
- fatal ("unrecognied relocation type %d", (int) reloc.type);
+ default: eassume (0);
}
}
diff --git a/src/print.c b/src/print.c
index c7cba5bface..a2537fcf759 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1461,8 +1461,12 @@ print_preprocess (Lisp_Object obj)
break;
}
- default:
- break;
+ case Lisp_Symbol:
+ case Lisp_Type_Unused0:
+ case Lisp_Int0:
+ case Lisp_Int1:
+ case Lisp_Float:
+ default: break;
}
}
}
@@ -2103,9 +2107,9 @@ print_vectorlike_unreadable (Lisp_Object obj, Lisp_Object printcharfun,
case PVEC_BIGNUM:
case PVEC_BOOL_VECTOR:
/* Impossible cases. */
- case PVEC_FREE:
case PVEC_OTHER:
break;
+ case PVEC_FREE: eassume (0);
}
emacs_abort ();
}
@@ -2640,14 +2644,44 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
print_bool_vector (obj, printcharfun);
break;
- default:
- print_vectorlike_unreadable (obj, printcharfun, escapeflag, buf);
+ case PVEC_MARKER:
+ case PVEC_OVERLAY:
+ case PVEC_FINALIZER:
+ case PVEC_SYMBOL_WITH_POS:
+ case PVEC_MISC_PTR:
+ case PVEC_USER_PTR:
+ case PVEC_PROCESS:
+ case PVEC_FRAME:
+ case PVEC_WINDOW:
+ case PVEC_BUFFER:
+ case PVEC_OBARRAY:
+ case PVEC_TERMINAL:
+ case PVEC_WINDOW_CONFIGURATION:
+ case PVEC_SUBR:
+ case PVEC_OTHER:
+ case PVEC_XWIDGET:
+ case PVEC_XWIDGET_VIEW:
+ case PVEC_THREAD:
+ case PVEC_MUTEX:
+ case PVEC_CONDVAR:
+ case PVEC_MODULE_FUNCTION:
+ case PVEC_NATIVE_COMP_UNIT:
+ case PVEC_TS_PARSER:
+ case PVEC_TS_NODE:
+ case PVEC_TS_COMPILED_QUERY:
+ case PVEC_SQLITE:
+ case PVEC_FONT:
+ default: print_vectorlike_unreadable (obj, printcharfun, escapeflag, buf);
break;
+
+ case PVEC_FREE: eassume (0);
}
break;
- default:
- emacs_abort ();
+ case Lisp_Type_Unused0:
+ eassume (0);
+
+ default: emacs_abort ();
}
print_depth--;
diff --git a/src/process.c b/src/process.c
index 807f06f990b..00944710128 100644
--- a/src/process.c
+++ b/src/process.c
@@ -2949,8 +2949,8 @@ set_socket_option (int s, Lisp_Object opt, Lisp_Object val)
}
#endif
- default:
- return 0;
+ case SOPT_UNKNOWN:
+ default: return 0;
}
if (ret < 0)
diff --git a/src/regex-emacs.c b/src/regex-emacs.c
index d3017f46751..e568b4638f4 100644
--- a/src/regex-emacs.c
+++ b/src/regex-emacs.c
@@ -2907,9 +2907,36 @@ forall_firstchar_1 (re_char *p, re_char *pend,
case succeed_n:
newp2 = extract_address (newp1 + 1);
goto do_twoway_jump;
- default:
+ case no_op:
newp2 = loop_end; /* "Safe" choice. */
goto do_jump;
+ case succeed:
+ case exactn:
+ case anychar:
+ case charset:
+ case charset_not:
+ case start_memory:
+ case stop_memory:
+ case duplicate:
+ case begline:
+ case endline:
+ case begbuf:
+ case endbuf:
+ case jump:
+ case jump_n:
+ case set_number_at:
+ case wordbeg:
+ case wordend:
+ case wordbound:
+ case notwordbound:
+ case symbeg:
+ case symend:
+ case syntaxspec:
+ case notsyntaxspec:
+ case at_dot:
+ case categoryspec:
+ case notcategoryspec:
+ default: eassume (0);
}
case on_failure_jump:
@@ -3221,7 +3248,18 @@ analyze_first_fastmap (const re_char *p, void *arg)
case symend:
/* This false doesn't mean failure but rather "not succeeded yet". */
return false;
-
+ case no_op:
+ case start_memory:
+ case stop_memory:
+ case jump:
+ case on_failure_jump:
+ case on_failure_keep_string_jump:
+ case on_failure_jump_loop:
+ case on_failure_jump_nastyloop:
+ case on_failure_jump_smart:
+ case succeed_n:
+ case jump_n:
+ case set_number_at:
default:
#if ENABLE_CHECKING
abort (); /* We have listed all the cases. */
@@ -3270,6 +3308,18 @@ analyze_first_null (const re_char *p, void *arg)
/* This false doesn't mean failure but rather "not succeeded yet". */
return false;
+ case no_op:
+ case start_memory:
+ case stop_memory:
+ case jump:
+ case on_failure_jump:
+ case on_failure_keep_string_jump:
+ case on_failure_jump_loop:
+ case on_failure_jump_nastyloop:
+ case on_failure_jump_smart:
+ case succeed_n:
+ case jump_n:
+ case set_number_at:
default:
#if ENABLE_CHECKING
abort (); /* We have listed all the cases. */
@@ -3739,8 +3789,32 @@ skip_one_char (re_char *p)
p++;
break;
- default:
- p = NULL;
+ case no_op:
+ case succeed:
+ case start_memory:
+ case stop_memory:
+ case duplicate:
+ case begline:
+ case endline:
+ case begbuf:
+ case endbuf:
+ case jump:
+ case on_failure_jump:
+ case on_failure_keep_string_jump:
+ case on_failure_jump_loop:
+ case on_failure_jump_nastyloop:
+ case on_failure_jump_smart:
+ case succeed_n:
+ case jump_n:
+ case set_number_at:
+ case wordbeg:
+ case wordend:
+ case wordbound:
+ case notwordbound:
+ case symbeg:
+ case symend:
+ case at_dot:
+ default: p = NULL;
}
return p;
}
@@ -3974,6 +4048,37 @@ #define RETURN_CONSTRAIN(v) \
chars should cover all possible chars, which, as a matter of
fact, is virtually impossible in multibyte buffers. */
return false;
+ case no_op:
+ case succeed:
+ case anychar:
+ case start_memory:
+ case stop_memory:
+ case duplicate:
+ case begline:
+ case endline:
+ case begbuf:
+ case endbuf:
+ case jump:
+ case on_failure_jump:
+ case on_failure_keep_string_jump:
+ case on_failure_jump_loop:
+ case on_failure_jump_nastyloop:
+ case on_failure_jump_smart:
+ case succeed_n:
+ case jump_n:
+ case set_number_at:
+ case wordbeg:
+ case wordend:
+ case wordbound:
+ case notwordbound:
+ case symbeg:
+ case symend:
+ case syntaxspec:
+ case notsyntaxspec:
+ case at_dot:
+ case categoryspec:
+ case notcategoryspec:
+ break;
}
return false;
case anychar:
@@ -4011,6 +4116,18 @@ #define RETURN_CONSTRAIN(v) \
/* At this point, we know nothing about what this can match, sadly. */
return false;
+ case no_op:
+ case start_memory:
+ case stop_memory:
+ case jump:
+ case on_failure_jump:
+ case on_failure_keep_string_jump:
+ case on_failure_jump_loop:
+ case on_failure_jump_nastyloop:
+ case on_failure_jump_smart:
+ case succeed_n:
+ case jump_n:
+ case set_number_at:
default:
#if ENABLE_CHECKING
abort (); /* We have listed all the cases. */
@@ -5225,8 +5342,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
}
break;
- default:
- abort ();
+ default: abort ();
}
continue; /* Successfully executed one pattern command; keep going. */
@@ -5262,8 +5378,34 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
/* A special frame used for nastyloops. */
goto fail;
- default:
- abort ();
+ case succeed:
+ case exactn:
+ case anychar:
+ case charset:
+ case charset_not:
+ case start_memory:
+ case stop_memory:
+ case duplicate:
+ case begline:
+ case endline:
+ case begbuf:
+ case endbuf:
+ case jump:
+ case on_failure_jump_smart:
+ case jump_n:
+ case set_number_at:
+ case wordbeg:
+ case wordend:
+ case wordbound:
+ case notwordbound:
+ case symbeg:
+ case symend:
+ case syntaxspec:
+ case notsyntaxspec:
+ case at_dot:
+ case categoryspec:
+ case notcategoryspec:
+ default: abort ();
}
eassert (p >= bufp->buffer && p <= pend);
diff --git a/src/syntax.c b/src/syntax.c
index 91dbe6a5f83..56db5c484fb 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -882,8 +882,18 @@ back_comment (ptrdiff_t from, ptrdiff_t from_byte, ptrdiff_t stop,
}
break;
- default:
+ case Swhitespace:
+ case Spunct:
+ case Sword:
+ case Ssymbol:
+ case Sclose:
+ case Squote:
+ case Smath:
+ case Sescape:
+ case Scharquote:
+ case Sinherit:
break;
+ default: eassume (0);
}
}
@@ -1399,9 +1409,7 @@ DEFUN ("internal-describe-syntax-value", Finternal_describe_syntax_value,
insert_string ("comment fence"); break;
case Sstring_fence:
insert_string ("string fence"); break;
- default:
- insert_string ("invalid");
- return syntax;
+ default: eassume (0);
}
if (!NILP (match_lisp))
@@ -2738,8 +2746,19 @@ scan_lists (EMACS_INT from0, EMACS_INT count, EMACS_INT depth, bool sexpflag)
case Ssymbol:
case Squote:
break;
- default:
+ case Swhitespace:
+ case Spunct:
+ case Sopen:
+ case Sclose:
+ case Sstring:
+ case Smath:
+ case Scomment:
+ case Sendcomment:
+ case Sinherit:
+ case Scomment_fence:
+ case Sstring_fence:
goto done;
+ default: eassume (0);
}
inc_both (&from, &from_byte);
rarely_quit (++quit_count);
@@ -2819,9 +2838,14 @@ scan_lists (EMACS_INT from0, EMACS_INT count, EMACS_INT depth, bool sexpflag)
inc_both (&from, &from_byte);
if (!depth && sexpflag) goto done;
break;
- default:
+ case Swhitespace:
+ case Spunct:
+ case Squote:
+ case Sendcomment:
+ case Sinherit:
/* Ignore whitespace, punctuation, quote, endcomment. */
break;
+ default: eassume (0);
}
}
@@ -2909,7 +2933,21 @@ scan_lists (EMACS_INT from0, EMACS_INT count, EMACS_INT depth, bool sexpflag)
switch (syntax_multibyte (c1, multibyte_symbol_p))
{
case Sword: case Ssymbol: case Squote: break;
- default: goto done2;
+ case Spunct:
+ case Sopen:
+ case Sclose:
+ case Sstring:
+ case Smath:
+ case Sescape:
+ case Scharquote:
+ case Scomment:
+ case Sendcomment:
+ case Sinherit:
+ case Scomment_fence:
+ case Sstring_fence:
+ case Swhitespace:
+ goto done2;
+ default: eassume (0);
}
dec_both (&from, &from_byte);
rarely_quit (++quit_count);
@@ -3000,9 +3038,14 @@ scan_lists (EMACS_INT from0, EMACS_INT count, EMACS_INT depth, bool sexpflag)
}
if (!depth && sexpflag) goto done2;
break;
- default:
+ case Spunct:
+ case Squote:
+ case Scomment:
+ case Sinherit:
+ case Swhitespace:
/* Ignore whitespace, punctuation, quote, endcomment. */
break;
+ default: eassume (0);
}
}
@@ -3304,8 +3347,19 @@ #define INC_FROM \
case Ssymbol:
case Squote:
break;
- default:
+ case Spunct:
+ case Sopen:
+ case Sclose:
+ case Sstring:
+ case Smath:
+ case Scomment:
+ case Sendcomment:
+ case Sinherit:
+ case Scomment_fence:
+ case Sstring_fence:
+ case Swhitespace:
goto symdone;
+ default: eassume (0);
}
INC_FROM;
rarely_quit (++quit_count);
@@ -3422,8 +3476,21 @@ #define INC_FROM \
if (from >= end) goto endquoted;
break;
- default:
+ case Spunct:
+ case Sword:
+ case Ssymbol:
+ case Sopen:
+ case Sclose:
+ case Squote:
+ case Sstring:
+ case Smath:
+ case Scomment:
+ case Sendcomment:
+ case Sinherit:
+ case Scomment_fence:
+ case Swhitespace:
break;
+ default: eassume (0);
}
INC_FROM;
rarely_quit (++quit_count);
@@ -3439,9 +3506,14 @@ #define INC_FROM \
case Smath:
/* FIXME: We should do something with it. */
break;
- default:
+ case Spunct:
+ case Squote:
+ case Sendcomment:
+ case Sinherit:
+ case Swhitespace:
/* Ignore whitespace, punctuation, quote, endcomment. */
break;
+ default: eassume (0);
}
}
goto done;
diff --git a/src/syntax.h b/src/syntax.h
index 354b116bfd1..c2c14d686b4 100644
--- a/src/syntax.h
+++ b/src/syntax.h
@@ -59,9 +59,10 @@ #define Vstandard_syntax_table BVAR (&buffer_defaults, syntax_table)
other side by any char with the same syntaxcode. */
Sstring_fence, /* Starts/ends string which is delimited on the
other side by any char with the same syntaxcode. */
- Smax /* Upper bound on codes that are meaningful. */
+ Smaxm1 = Sstring_fence /* Upper bound on codes that are meaningful. */
};
+#define Smax (Smaxm1 + 1)
struct gl_state_s
{
diff --git a/src/sysdep.c b/src/sysdep.c
index a161b4af100..a3051c4978b 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -2520,7 +2520,7 @@ emacs_fopen (char const *file, char const *mode)
case 'r': omode = O_RDONLY; oflags = 0; break;
case 'w': omode = O_WRONLY; oflags = O_CREAT | O_TRUNC; break;
case 'a': omode = O_WRONLY; oflags = O_CREAT | O_APPEND; break;
- default: emacs_abort ();
+ default: eassume (0);
}
while (*m)
diff --git a/src/term.c b/src/term.c
index f307d709316..5cb545d8632 100644
--- a/src/term.c
+++ b/src/term.c
@@ -3476,6 +3476,8 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
first_item--;
leave = 0;
break;
+ case MI_CONTINUE:
+ case MI_ITEM_SELECTED:
default:
/* MI_ITEM_SELECTED is handled below, so nothing to do. */
break;
diff --git a/src/textconv.c b/src/textconv.c
index 105a8077072..fe269aee8d7 100644
--- a/src/textconv.c
+++ b/src/textconv.c
@@ -267,9 +267,15 @@ textconv_query (struct frame *f, struct textconv_callback_struct *query,
pos = end;
break;
- default:
+ case TEXTCONV_BACKWARD_CHAR:
+ case TEXTCONV_BACKWARD_WORD:
+ case TEXTCONV_CARET_UP:
+ case TEXTCONV_PREVIOUS_LINE:
+ case TEXTCONV_LINE_END:
+ case TEXTCONV_ABSOLUTE_POSITION:
pos = max (BEGV, start - 1);
break;
+ default: eassume (0);
}
}
}
@@ -433,8 +439,8 @@ textconv_query (struct frame *f, struct textconv_callback_struct *query,
return 1;
}
- default:
- break;
+ case TEXTCONV_RETRIEVAL:
+ default: break;
}
/* Undo any changes to the excursion. */
diff --git a/src/timefns.c b/src/timefns.c
index aab4dbb9206..db5eaa7a25c 100644
--- a/src/timefns.c
+++ b/src/timefns.c
@@ -577,8 +577,9 @@ decode_ticks_hz (Lisp_Object ticks, Lisp_Object hz, enum cform cform)
case CFORM_TICKS_HZ:
return (union c_time) { .th = { .ticks = ticks, .hz = hz } };
- default:
- return (union c_time) { .ts = ticks_hz_to_timespec (ticks, hz) };
+ case CFORM_TIMESPEC:
+ case CFORM_SECS_ONLY:
+ default: return (union c_time) { .ts = ticks_hz_to_timespec (ticks, hz) };
}
}
diff --git a/src/treesit.c b/src/treesit.c
index 62606d99749..8bf18f9defb 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -1457,8 +1457,9 @@ treesit_query_error_to_string (TSQueryError error)
return "Capture error at";
case TSQueryErrorStructure:
return "Structure error at";
- default:
- return "Unknown error";
+ case TSQueryErrorLanguage:
+ return "Language error at";
+ default: return "Unknown error";
}
}
diff --git a/src/xdisp.c b/src/xdisp.c
index 36e82f873ab..9a167ff453f 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -2961,6 +2961,8 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
height = WINDOW_BOTTOM_DIVIDER_WIDTH (w);
goto add_edge;
+ case ON_NOTHING:
+ case ON_HORIZONTAL_SCROLL_BAR: /* FIXME: is this right? */
default:
;
virtual_glyph:
@@ -11028,8 +11030,9 @@ move_it_to (struct it *it, ptrdiff_t to_charpos, int to_x, int to_y, int to_vpos
it->continuation_lines_width += it->current_x;
break;
- default:
- emacs_abort ();
+ case MOVE_UNDEFINED:
+ case MOVE_X_REACHED:
+ default: emacs_abort ();
}
/* Reset/increment for the next run. */
@@ -20528,8 +20531,9 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
case CURSOR_MOVEMENT_MUST_SCROLL:
goto try_to_scroll;
- default:
- emacs_abort ();
+ case CURSOR_MOVEMENT_CANNOT_BE_USED:
+ case CURSOR_MOVEMENT_NEED_LARGER_MATRICES:
+ default: emacs_abort ();
}
}
/* If current starting point was originally the beginning of a line
@@ -26362,6 +26366,7 @@ DEFUN ("current-bidi-paragraph-direction", Fcurrent_bidi_paragraph_direction,
case R2L:
return Qright_to_left;
break;
+ case NEUTRAL_DIR: /* Is this right? */
default:
emacs_abort ();
}
@@ -28155,8 +28160,14 @@ display_mode_element (struct it *it, int depth, int field_width, int precision,
}
break;
- default:
- invalid:
+ case Lisp_Type_Unused0:
+ eassume (0);
+
+ case Lisp_Int0:
+ case Lisp_Int1:
+ case Lisp_Vectorlike:
+ case Lisp_Float:
+ default: invalid:
elt = build_string ("*invalid*");
goto tail_recurse;
}
diff --git a/src/xfaces.c b/src/xfaces.c
index fbbaffb8889..6a701f89cd3 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -1334,8 +1334,21 @@ load_color2 (struct frame *f, struct face *face, Lisp_Object name,
color->pixel = FRAME_FOREGROUND_PIXEL (f);
break;
- default:
- emacs_abort ();
+ case LFACE_FAMILY_INDEX:
+ case LFACE_FOUNDRY_INDEX:
+ case LFACE_SWIDTH_INDEX:
+ case LFACE_HEIGHT_INDEX:
+ case LFACE_WEIGHT_INDEX:
+ case LFACE_SLANT_INDEX:
+ case LFACE_INVERSE_INDEX:
+ case LFACE_STIPPLE_INDEX:
+ case LFACE_FONT_INDEX:
+ case LFACE_INHERIT_INDEX:
+ case LFACE_FONTSET_INDEX:
+ case LFACE_DISTANT_FOREGROUND_INDEX:
+ case LFACE_EXTEND_INDEX:
+ case LFACE_VECTOR_SIZE:
+ default: emacs_abort ();
}
}
#ifdef GLYPH_DEBUG
@@ -1615,8 +1628,19 @@ DEFUN ("x-family-fonts", Fx_family_fonts, Sx_family_fonts, 0, 2, 0,
font_props_for_sorting[i] = FONT_SIZE_INDEX; break;
case XLFD_WEIGHT:
font_props_for_sorting[i] = FONT_WEIGHT_INDEX; break;
- default:
- font_props_for_sorting[i] = FONT_SLANT_INDEX; break;
+ case XLFD_FOUNDRY:
+ case XLFD_FAMILY:
+ case XLFD_SLANT:
+ case XLFD_ADSTYLE:
+ case XLFD_PIXEL_SIZE:
+ case XLFD_RESX:
+ case XLFD_RESY:
+ case XLFD_SPACING:
+ case XLFD_AVGWIDTH:
+ case XLFD_REGISTRY:
+ case XLFD_ENCODING:
+ case XLFD_LAST:
+ default: font_props_for_sorting[i] = FONT_SLANT_INDEX; break;
}
font_props_for_sorting[i++] = FONT_FAMILY_INDEX;
font_props_for_sorting[i++] = FONT_FOUNDRY_INDEX;
@@ -4430,8 +4454,12 @@ face_attr_equal_p (Lisp_Object v1, Lisp_Object v2)
case Lisp_Symbol:
return false;
- default:
- return !NILP (Fequal (v1, v2));
+ case Lisp_Type_Unused0:
+ eassume (0);
+ case Lisp_Vectorlike:
+ case Lisp_Cons:
+ case Lisp_Float:
+ default: return !NILP (Fequal (v1, v2));
}
}
@@ -5138,8 +5166,8 @@ lookup_basic_face (struct window *w, struct frame *f, int face_id)
case INTERNAL_BORDER_FACE_ID: name = Qinternal_border; break;
case CHILD_FRAME_BORDER_FACE_ID: name = Qchild_frame_border; break;
- default:
- emacs_abort (); /* the caller is supposed to pass us a basic face id */
+ case BASIC_FACE_ID_SENTINEL:
+ default: emacs_abort (); /* the caller is supposed to pass us a basic face id */
}
/* Do a quick scan through Vface_remapping_alist, and return immediately
@@ -6611,8 +6639,24 @@ map_tty_color (struct frame *f, struct face *face, Lisp_Object color,
face->underline_color = pixel;
break;
case LFACE_BACKGROUND_INDEX:
- default:
- face->background = pixel;
+ case LFACE_FAMILY_INDEX:
+ case LFACE_FOUNDRY_INDEX:
+ case LFACE_SWIDTH_INDEX:
+ case LFACE_HEIGHT_INDEX:
+ case LFACE_WEIGHT_INDEX:
+ case LFACE_SLANT_INDEX:
+ case LFACE_INVERSE_INDEX:
+ case LFACE_STIPPLE_INDEX:
+ case LFACE_OVERLINE_INDEX:
+ case LFACE_STRIKE_THROUGH_INDEX:
+ case LFACE_BOX_INDEX:
+ case LFACE_FONT_INDEX:
+ case LFACE_INHERIT_INDEX:
+ case LFACE_FONTSET_INDEX:
+ case LFACE_DISTANT_FOREGROUND_INDEX:
+ case LFACE_EXTEND_INDEX:
+ case LFACE_VECTOR_SIZE:
+ default: face->background = pixel;
break;
}
}
diff --git a/src/xfns.c b/src/xfns.c
index ec7d54180e4..2cfcba6f29a 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -3379,8 +3379,14 @@ xic_preedit_caret_callback (XIC xic, XPointer client_data,
case XIMBackwardWord:
call_data->position = max (0, output->preedit_caret--);
break;
- default:
- call_data->position = output->preedit_caret;
+ case XIMCaretUp:
+ case XIMCaretDown:
+ case XIMNextLine:
+ case XIMPreviousLine:
+ case XIMLineStart:
+ case XIMLineEnd:
+ case XIMDontChange:
+ default: call_data->position = output->preedit_caret;
}
if (output->preedit_chars)
@@ -3874,8 +3880,8 @@ xic_string_conversion_callback (XIC ic, XPointer client_data,
request.direction = TEXTCONV_ABSOLUTE_POSITION;
break;
- default:
- goto failure;
+ case XIMDontChange:
+ default: goto failure;
}
/* factor is signed in call_data but is actually a CARD16. */
diff --git a/src/xterm.c b/src/xterm.c
index 0a877e9edf9..02c5f03830b 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -5652,10 +5652,10 @@ xi_populate_device_from_info (struct x_display_info *dpyinfo,
xi_device->direct_p = true;
else
xi_device->direct_p = false;
+ break;
}
#endif /* HAVE_XINPUT2_2 */
- default:
- break;
+ default: eassume (0);
}
}
@@ -6150,8 +6150,30 @@ x_try_cr_xlib_drawable (struct frame *f, GC gc)
case CAIRO_SURFACE_TYPE_IMAGE:
break;
- default:
- return false;
+ case CAIRO_SURFACE_TYPE_PDF:
+ case CAIRO_SURFACE_TYPE_PS:
+ case CAIRO_SURFACE_TYPE_XCB:
+ case CAIRO_SURFACE_TYPE_GLITZ:
+ case CAIRO_SURFACE_TYPE_QUARTZ:
+ case CAIRO_SURFACE_TYPE_WIN32:
+ case CAIRO_SURFACE_TYPE_BEOS:
+ case CAIRO_SURFACE_TYPE_DIRECTFB:
+ case CAIRO_SURFACE_TYPE_SVG:
+ case CAIRO_SURFACE_TYPE_OS2:
+ case CAIRO_SURFACE_TYPE_WIN32_PRINTING:
+ case CAIRO_SURFACE_TYPE_QUARTZ_IMAGE:
+ case CAIRO_SURFACE_TYPE_SCRIPT:
+ case CAIRO_SURFACE_TYPE_QT:
+ case CAIRO_SURFACE_TYPE_RECORDING:
+ case CAIRO_SURFACE_TYPE_VG:
+ case CAIRO_SURFACE_TYPE_GL:
+ case CAIRO_SURFACE_TYPE_DRM:
+ case CAIRO_SURFACE_TYPE_TEE:
+ case CAIRO_SURFACE_TYPE_XML:
+ case CAIRO_SURFACE_TYPE_SKIA:
+ case CAIRO_SURFACE_TYPE_SUBSURFACE:
+ case CAIRO_SURFACE_TYPE_COGL:
+ default: return false;
}
/* FRAME_CR_CONTEXT (f) is an image surface we can not draw into
@@ -10928,8 +10950,7 @@ x_fill_underline (struct frame *f, struct glyph_string *s,
case FACE_NO_UNDERLINE:
case FACE_UNDERLINE_WAVE:
- default:
- emacs_abort ();
+ default: eassume (0);
}
}
@@ -15862,8 +15883,18 @@ xg_scroll_callback (GtkRange *range, GtkScrollType scroll,
? scroll_bar_after_handle : scroll_bar_below_handle);
bar->dragging = -1;
break;
- default:
- break;
+case GTK_SCROLL_NONE:
+case GTK_SCROLL_STEP_UP:
+case GTK_SCROLL_STEP_DOWN:
+case GTK_SCROLL_PAGE_UP:
+case GTK_SCROLL_PAGE_DOWN:
+case GTK_SCROLL_STEP_LEFT:
+case GTK_SCROLL_STEP_RIGHT:
+case GTK_SCROLL_PAGE_LEFT:
+case GTK_SCROLL_PAGE_RIGHT:
+case GTK_SCROLL_START:
+case GTK_SCROLL_END:
+ default: break;
}
if (part != scroll_bar_nowhere)
@@ -18030,6 +18061,10 @@ x_net_wm_state (struct frame *f, Window window)
case FULLSCREEN_MAXIMIZED:
lval = Qmaximized;
break;
+ case FULLSCREEN_NONE:
+ lval = Qnil;
+ break;
+ default: eassume (0);
}
store_frame_param (f, Qfullscreen, lval);
@@ -19139,6 +19174,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_dnd_action_symbol = QXdndActionCopy;
break;
+ case XM_DRAG_NOOP:
+ case XM_DRAG_LINK:
+ case XM_DRAG_LINK_REC:
/* This means XM_DRAG_OPERATION_IS_LINK (operation). */
default:
x_dnd_action_symbol = QXdndActionLink;
@@ -26086,8 +26124,9 @@ x_draw_window_cursor (struct window *w, struct glyph_row *glyph_row, int x,
w->phys_cursor_width = 0;
break;
- default:
+ case DEFAULT_CURSOR:
emacs_abort ();
+ default: emacs_abort ();
}
}
@@ -28259,6 +28298,10 @@ x_handle_net_wm_state (struct frame *f, const XPropertyEvent *event)
case FULLSCREEN_MAXIMIZED:
lval = Qmaximized;
break;
+ case FULLSCREEN_NONE:
+ lval = Qnil;
+ break;
+ default: eassume (0);
}
store_frame_param (f, Qfullscreen, lval);
@@ -28312,8 +28355,8 @@ x_check_fullscreen (struct frame *f)
lval = Qfullheight;
height = x_display_pixel_height (dpyinfo);
break;
- default:
- emacs_abort ();
+ case FULLSCREEN_NONE:
+ default: emacs_abort ();
}
x_wm_set_size_hint (f, 0, false);
@@ -29919,8 +29962,7 @@ x_get_atom_name (struct x_display_info *dpyinfo, Atom atom,
case XA_FONT:
return xstrdup ("FONT");
- default:
- if (dpyinfo->motif_drag_atom
+ default: if (dpyinfo->motif_drag_atom
&& atom == dpyinfo->motif_drag_atom)
return xstrdup (dpyinfo->motif_drag_atom_name);
diff --git a/src/xwidget.c b/src/xwidget.c
index 4f5b46c692a..c2a29048ea2 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -196,8 +196,7 @@ xw_forward_event_translate (GdkEvent *event, struct xwidget_view *xv,
return 1;
}
return 0;
- default:
- return 0;
+ default: eassume (0);
}
}
@@ -1548,8 +1547,7 @@ xi_translate_notify_detail (int detail)
return GDK_NOTIFY_NONLINEAR;
case XINotifyNonlinearVirtual:
return GDK_NOTIFY_NONLINEAR_VIRTUAL;
- default:
- emacs_abort ();
+ default: eassume (0);
}
}
#endif
@@ -2398,8 +2396,8 @@ webkit_create_cb (WebKitWebView *webview,
case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED:
case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED:
case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED:
- default:
return NULL;
+ default: eassume (0);
}
}
@@ -2618,8 +2616,7 @@ webkit_decide_policy_cb (WebKitWebView *webView,
return FALSE;
break;
}
- default:
- return FALSE;
+ default: eassume (0);
}
}
^ permalink raw reply related [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 11:48 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-02 12:13 ` Eli Zaretskii
2025-02-02 12:50 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 18:27 ` Paul Eggert
1 sibling, 1 reply; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-02 12:13 UTC (permalink / raw)
To: Pip Cet; +Cc: Andrea Corallo, eggert, 75964, stefankangas, Stefan Monnier
> Date: Sun, 02 Feb 2025 11:48:45 +0000
> From: Pip Cet <pipcet@protonmail.com>
> Cc: eggert@cs.ucla.edu, 75964@debbugs.gnu.org, stefankangas@gmail.com
>
> So while I'd like us to keep those options in mind, I've removed them
> from the following diff. The idea is this would give an overview over
> which code segments would become hard to read as a result of such a
> change, and whether it's bad enough that we need to look at
> alternatives.
>
> I think this concerns bidi.c and keyboard.c in particular.
>
> I've marked some places where I'm not sure the old behavior was okay,
> but I haven't checked them in detail. I haven't found any "there was a
> bug here and we only caught it because of this new warning" smoking
> guns.
Hmm... like I envisioned, where the list of enum values hiding behind
'default' is longer than half a dozen or so, the result looks really
problematic: a long and hard-to-read list of values without any
promise that it's exhaustive. (I realize that the compiler will flag
any missing values, but when I read code, I prefer not to compile it,
and besides, it could not be in a compilable shape at that point).
Humans are not good when they need to deal with long lists, which is
why when the list gets long, it is easier to list values not in the
list.
So I wonder if we could find a better way, or perhaps decide that
where we need such long lists, we could do it the old way.
Btw, does eassume compile to emacs_abort in a production build (i.e. a
build without --enable-checking)? If not, then perhaps this
replacement is not always a good idea? We (should) use emacs_abort
when the code has no way of dealing with some situation, so letting
the execution continue past that point will sometimes crash or corrupt
data in ways that are much harder to debug than an abort.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 12:13 ` Eli Zaretskii
@ 2025-02-02 12:50 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 13:21 ` Eli Zaretskii
` (2 more replies)
0 siblings, 3 replies; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-02 12:50 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Andrea Corallo, eggert, 75964, stefankangas, Stefan Monnier
"Eli Zaretskii" <eliz@gnu.org> writes:
>> Date: Sun, 02 Feb 2025 11:48:45 +0000
>> From: Pip Cet <pipcet@protonmail.com>
>> Cc: eggert@cs.ucla.edu, 75964@debbugs.gnu.org, stefankangas@gmail.com
>>
>> So while I'd like us to keep those options in mind, I've removed them
>> from the following diff. The idea is this would give an overview over
>> which code segments would become hard to read as a result of such a
>> change, and whether it's bad enough that we need to look at
>> alternatives.
>>
>> I think this concerns bidi.c and keyboard.c in particular.
>>
>> I've marked some places where I'm not sure the old behavior was okay,
>> but I haven't checked them in detail. I haven't found any "there was a
>> bug here and we only caught it because of this new warning" smoking
>> guns.
>
> Hmm... like I envisioned, where the list of enum values hiding behind
> 'default' is longer than half a dozen or so, the result looks really
> problematic: a long and hard-to-read list of values without any
> promise that it's exhaustive. (I realize that the compiler will flag
> any missing values, but when I read code, I prefer not to compile it,
> and besides, it could not be in a compilable shape at that point).
>
> Humans are not good when they need to deal with long lists, which is
> why when the list gets long, it is easier to list values not in the
> list.
>
> So I wonder if we could find a better way,
I haven't found one that's easy to do.
> or perhaps decide that
> where we need such long lists, we could do it the old way.
Absolutely. There are plenty of ways to do that, but the easiest is,
for now, to decide which files this applies to and either put them in a
list in Makefile.in or add a #pragma.
Looking at bidi.c, I find bidi_get_type, which is essentially a single
switch statement, much easier to read than the new long switch statement
in in bidi_find_bracket_pairs:
switch (bidi_it->type)
{
case STRONG_L:
flag = ((embedding_level & 1) == 0
? FLAG_EMBEDDING_INSIDE
: FLAG_OPPOSITE_INSIDE);
l2r_seen = true;
break;
case STRONG_R:
case WEAK_EN:
case WEAK_AN:
flag = ((embedding_level & 1) == 1
? FLAG_EMBEDDING_INSIDE
: FLAG_OPPOSITE_INSIDE);
r2l_seen = true;
break;
case UNKNOWN_BT:
case WEAK_BN:
case NEUTRAL_B:
case STRONG_AL:
case LRE:
case LRO:
case RLE:
case RLO:
case PDF:
case LRI:
case RLI:
case FSI:
case PDI:
case WEAK_ES:
case WEAK_ET:
case WEAK_CS:
case WEAK_NSM:
case NEUTRAL_S:
case NEUTRAL_WS:
case NEUTRAL_ON:
default: break;
}
I think that could be rewritten to be more readable in a number of ways,
including, of course, putting a #pragma in.
(I'm focusing on bidi.c because it uses a very large
externally-mandated enum. Splitting up the specpdl cases is something
we can do, but touching the unicode classification tables is clearly not
a good idea.)
I'd probably try to avoid switches in deeply-nested contexts, but that's
an aesthetic preference.
And, of course, code like
switch (prev_type)
{
<...>
case LRO:
case RLE:
case RLO:
case FSI:
case PDI:
case WEAK_ES:
case WEAK_ET:
case WEAK_CS:
case WEAK_NSM:
case NEUTRAL_S:
case NEUTRAL_WS:
case NEUTRAL_ON:
default: eassert (prev_type != FSI);
/* Nothing. */
break;
}
simply isn't readable, and that one's my fault.
My current impression is this will eventually help us find rare bugs,
and produce better C code, but where it hurts readability we should use
#pragma and leave the code as it is. When we really want to, we can
rewrite predicates such as the first example to be inline functions, and
then bidi_find_brackt_pairs could be at least a bit shorter and perhaps
more readable; but, again, that's an aesthetic choice.
Stefan Kangas, are there files where we currently use switch statements
that you'd like to clean up most? I think it's most important for
pdumper.c (subtle code) and where external library unions are in use
(GTK, RSVG, tree sitter).
I'm not sure whether there's a good way to invert the switch without
hiding things in Makefile.in where no one ever looks. Maybe just add
#include "exhaustive.h"
in the relevant C files, which does whatever pragma magic we need?
But I'm open to other suggestions.
> Btw, does eassume compile to emacs_abort in a production build (i.e. a
> build without --enable-checking)?
It does not, no. This is sometimes necessary for speed, but most of
that effect can be achieved by using emacs_abort: it's a cold function
and GCC will penalize code paths that lead to this function call and
optimize those which don't.
That's what I liked about the eunreachable proposal: in some, very rare
cases, a full eassume () is what we want, but usually we're okay with
"crash if this happens, but optimize the non-crashing case statically".
If someone wants to define eunreachable to eassume (0) they can, but on
x86 I'd prefer a single-insn trap.
> If not, then perhaps this replacement is not always a good idea?
Sorry to point to someone else's code as an example, but Paul's changes
meant that if the mmap protection flag enum in pdumper.c was out of
bounds, we'd read something from outside the array and pass it to mmap
as its protection argument. I think finding such a bug, even if it
happens just with production builds, is hard enough to justify a bounds
check or a ud2.
> We (should) use emacs_abort when the code has no way of dealing with
> some situation, so letting the execution continue past that point will
> sometimes crash or corrupt data in ways that are much harder to debug
> than an abort.
We often use eassert for that, and I don't know how many people realize
this subtle difference between emacs_abort () and eassert (0). I think
there should be an even subtler difference between eunreachable () and
eassume (0): initially, they'd do the same both in production builds and
development builds, but we reserve the right to weaken eunreachable to
an abort if we think it helps us find bugs, and eassume is only to be
used where the performance gains are significantly larger than an enum
check would be.
I still think eassume and eassert shouldn't evaluate expressions with
side effects. I'd like to enforce that in GCC but no one liked my
patch.
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 12:50 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-02 13:21 ` Eli Zaretskii
2025-02-02 16:51 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 13:40 ` Eli Zaretskii
2025-02-03 3:01 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2 siblings, 1 reply; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-02 13:21 UTC (permalink / raw)
To: Pip Cet; +Cc: acorallo, eggert, 75964, stefankangas, monnier
> Date: Sun, 02 Feb 2025 12:50:15 +0000
> From: Pip Cet <pipcet@protonmail.com>
> Cc: eggert@cs.ucla.edu, 75964@debbugs.gnu.org, stefankangas@gmail.com, Andrea Corallo <acorallo@gnu.org>, Stefan Monnier <monnier@iro.umontreal.ca>
>
> "Eli Zaretskii" <eliz@gnu.org> writes:
>
> > We (should) use emacs_abort when the code has no way of dealing with
> > some situation, so letting the execution continue past that point will
> > sometimes crash or corrupt data in ways that are much harder to debug
> > than an abort.
>
> We often use eassert for that, and I don't know how many people realize
> this subtle difference between emacs_abort () and eassert (0).
Well, I do: eassert compiles to nothing in a production build, so it
is only okay if the code can do something with the situation, albeit
something that will cause weird effects. eassert is also appropriate
to convey the assumptions made by the code, even if no trouble will be
caused by violating those assumptions.
> I still think eassume and eassert shouldn't evaluate expressions with
> side effects.
I agree. Do we have code which does that in Emacs?
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 12:50 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 13:21 ` Eli Zaretskii
@ 2025-02-02 13:40 ` Eli Zaretskii
2025-02-02 16:54 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 17:02 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-03 3:01 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2 siblings, 2 replies; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-02 13:40 UTC (permalink / raw)
To: Pip Cet; +Cc: acorallo, eggert, 75964, stefankangas, monnier
> Date: Sun, 02 Feb 2025 12:50:15 +0000
> From: Pip Cet <pipcet@protonmail.com>
> Cc: eggert@cs.ucla.edu, 75964@debbugs.gnu.org, stefankangas@gmail.com, Andrea Corallo <acorallo@gnu.org>, Stefan Monnier <monnier@iro.umontreal.ca>
>
> Looking at bidi.c, I find bidi_get_type, which is essentially a single
> switch statement, much easier to read than the new long switch statement
> in in bidi_find_bracket_pairs:
>
> switch (bidi_it->type)
> {
> case STRONG_L:
> flag = ((embedding_level & 1) == 0
> ? FLAG_EMBEDDING_INSIDE
> : FLAG_OPPOSITE_INSIDE);
> l2r_seen = true;
> break;
> case STRONG_R:
> case WEAK_EN:
> case WEAK_AN:
> flag = ((embedding_level & 1) == 1
> ? FLAG_EMBEDDING_INSIDE
> : FLAG_OPPOSITE_INSIDE);
> r2l_seen = true;
> break;
> case UNKNOWN_BT:
> case WEAK_BN:
> case NEUTRAL_B:
> case STRONG_AL:
> case LRE:
> case LRO:
> case RLE:
> case RLO:
> case PDF:
> case LRI:
> case RLI:
> case FSI:
> case PDI:
> case WEAK_ES:
> case WEAK_ET:
> case WEAK_CS:
> case WEAK_NSM:
> case NEUTRAL_S:
> case NEUTRAL_WS:
> case NEUTRAL_ON:
> default: break;
> }
This is an example of code where some value of an enumeration need
special handling, and the rest don't need any handling at all. IMO,
we should ask ourselves what are we trying to accomplish by spelling
out all of the "other" values instead of just 'default'? If we only
care for a handful of values, what kind of errors could slip us if we
use 'default'?
> I think that could be rewritten to be more readable in a number of ways,
> including, of course, putting a #pragma in.
IMO, the way it should be rewritten (or not) depends on the answer to
the above question.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-01-31 15:00 ` Eli Zaretskii
@ 2025-02-02 15:21 ` Stefan Kangas
2025-02-02 17:27 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 1 reply; 74+ messages in thread
From: Stefan Kangas @ 2025-02-02 15:21 UTC (permalink / raw)
To: Eli Zaretskii, Pip Cet; +Cc: 75964
Eli Zaretskii <eliz@gnu.org> writes:
> It would indeed be wise to stop pushing changes in this area as long
> as we are not sure what would be the best solution.
>
> Stefan, do you agree?
Yes. Let's decide what's the best way forward here before making any
further changes.
The recent reverts by Pip Cet seems like a good step.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 13:21 ` Eli Zaretskii
@ 2025-02-02 16:51 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 17:21 ` Eli Zaretskii
0 siblings, 1 reply; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-02 16:51 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: acorallo, eggert, 75964, stefankangas, monnier
"Eli Zaretskii" <eliz@gnu.org> writes:
>> Date: Sun, 02 Feb 2025 12:50:15 +0000
>> From: Pip Cet <pipcet@protonmail.com>
>> Cc: eggert@cs.ucla.edu, 75964@debbugs.gnu.org, stefankangas@gmail.com, Andrea Corallo <acorallo@gnu.org>, Stefan Monnier <monnier@iro.umontreal.ca>
>>
>> "Eli Zaretskii" <eliz@gnu.org> writes:
>>
>> > We (should) use emacs_abort when the code has no way of dealing with
>> > some situation, so letting the execution continue past that point will
>> > sometimes crash or corrupt data in ways that are much harder to debug
>> > than an abort.
>>
>> We often use eassert for that, and I don't know how many people realize
>> this subtle difference between emacs_abort () and eassert (0).
>
> Well, I do: eassert compiles to nothing in a production build, so it
> is only okay if the code can do something with the situation, albeit
> something that will cause weird effects. eassert is also appropriate
> to convey the assumptions made by the code, even if no trouble will be
> caused by violating those assumptions.
Interesting. I often use eassert where the only thing we can do in a
production build is almost certainly a crash. Can you say more about
cases in which it's used to avoid crashes?
>> I still think eassume and eassert shouldn't evaluate expressions with
>> side effects.
>
> I agree. Do we have code which does that in Emacs?
I'm aware of
eassert (check_comp_unit_relocs (comp_u));
in comp.c, which does call an extra function, which might in theory have
side effects because dynlib_sym or Flength or, God forbid, Fgethash may
develop some. But, really, this is a special case and a very minor
issue.
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 13:40 ` Eli Zaretskii
@ 2025-02-02 16:54 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 17:02 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
1 sibling, 0 replies; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-02 16:54 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: acorallo, eggert, 75964, stefankangas, monnier
"Eli Zaretskii" <eliz@gnu.org> writes:
>> Date: Sun, 02 Feb 2025 12:50:15 +0000
>> From: Pip Cet <pipcet@protonmail.com>
>> Cc: eggert@cs.ucla.edu, 75964@debbugs.gnu.org, stefankangas@gmail.com, Andrea Corallo <acorallo@gnu.org>, Stefan Monnier <monnier@iro.umontreal.ca>
>>
>> Looking at bidi.c, I find bidi_get_type, which is essentially a single
>> switch statement, much easier to read than the new long switch statement
>> in in bidi_find_bracket_pairs:
>>
>> switch (bidi_it->type)
>> {
>> case STRONG_L:
>> flag = ((embedding_level & 1) == 0
>> ? FLAG_EMBEDDING_INSIDE
>> : FLAG_OPPOSITE_INSIDE);
>> l2r_seen = true;
>> break;
>> case STRONG_R:
>> case WEAK_EN:
>> case WEAK_AN:
>> flag = ((embedding_level & 1) == 1
>> ? FLAG_EMBEDDING_INSIDE
>> : FLAG_OPPOSITE_INSIDE);
>> r2l_seen = true;
>> break;
>> case UNKNOWN_BT:
>> case WEAK_BN:
>> case NEUTRAL_B:
>> case STRONG_AL:
>> case LRE:
>> case LRO:
>> case RLE:
>> case RLO:
>> case PDF:
>> case LRI:
>> case RLI:
>> case FSI:
>> case PDI:
>> case WEAK_ES:
>> case WEAK_ET:
>> case WEAK_CS:
>> case WEAK_NSM:
>> case NEUTRAL_S:
>> case NEUTRAL_WS:
>> case NEUTRAL_ON:
>> default: break;
>> }
>
> This is an example of code where some value of an enumeration need
> special handling, and the rest don't need any handling at all. IMO,
> we should ask ourselves what are we trying to accomplish by spelling
> out all of the "other" values instead of just 'default'? If we only
> care for a handful of values, what kind of errors could slip us if we
> use 'default'?
If I were to write that code, I would put the switch statement into a
separate function, returning (say) R2L, L2R, and NEUTRAL: Only STRONG_L
characters count as l2r_seen, only STRONG_R and two other c
>
>> I think that could be rewritten to be more readable in a number of ways,
>> including, of course, putting a #pragma in.
>
> IMO, the way it should be rewritten (or not) depends on the answer to
> the above question.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 13:40 ` Eli Zaretskii
2025-02-02 16:54 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-02 17:02 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 17:35 ` Eli Zaretskii
1 sibling, 1 reply; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-02 17:02 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: acorallo, eggert, 75964, stefankangas, monnier
"Eli Zaretskii" <eliz@gnu.org> writes:
>> Date: Sun, 02 Feb 2025 12:50:15 +0000
>> From: Pip Cet <pipcet@protonmail.com>
>> Cc: eggert@cs.ucla.edu, 75964@debbugs.gnu.org, stefankangas@gmail.com, Andrea Corallo <acorallo@gnu.org>, Stefan Monnier <monnier@iro.umontreal.ca>
>>
>> Looking at bidi.c, I find bidi_get_type, which is essentially a single
>> switch statement, much easier to read than the new long switch statement
>> in in bidi_find_bracket_pairs:
>>
>> switch (bidi_it->type)
>> {
>> case STRONG_L:
>> flag = ((embedding_level & 1) == 0
>> ? FLAG_EMBEDDING_INSIDE
>> : FLAG_OPPOSITE_INSIDE);
>> l2r_seen = true;
>> break;
>> case STRONG_R:
>> case WEAK_EN:
>> case WEAK_AN:
>> flag = ((embedding_level & 1) == 1
>> ? FLAG_EMBEDDING_INSIDE
>> : FLAG_OPPOSITE_INSIDE);
>> r2l_seen = true;
>> break;
>> case UNKNOWN_BT:
>> case WEAK_BN:
>> case NEUTRAL_B:
>> case STRONG_AL:
>> case LRE:
>> case LRO:
>> case RLE:
>> case RLO:
>> case PDF:
>> case LRI:
>> case RLI:
>> case FSI:
>> case PDI:
>> case WEAK_ES:
>> case WEAK_ET:
>> case WEAK_CS:
>> case WEAK_NSM:
>> case NEUTRAL_S:
>> case NEUTRAL_WS:
>> case NEUTRAL_ON:
>> default: break;
>> }
>
> This is an example of code where some value of an enumeration need
> special handling, and the rest don't need any handling at all. IMO,
> we should ask ourselves what are we trying to accomplish by spelling
> out all of the "other" values instead of just 'default'? If we only
> care for a handful of values, what kind of errors could slip us if we
> use 'default'?
As someone who's not very familiar with the bidi code, I would feel most
comfortable if this switch, with all cases, were in an inline function
which decides whether we set l2r_seen, r2l_seen, or neither, in this
context. Ideally, in my case, with further comments, though trying to
understand this code without studying the Unicode Bidirectional
Algorithm will always be foolish...
However, I think bidi.c is the file I most strongly feel would not
benefit from -Wswitch-enum.
>> I think that could be rewritten to be more readable in a number of ways,
>> including, of course, putting a #pragma in.
>
> IMO, the way it should be rewritten (or not) depends on the answer to
> the above question.
Agreed.
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 16:51 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-02 17:21 ` Eli Zaretskii
2025-02-02 17:30 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 1 reply; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-02 17:21 UTC (permalink / raw)
To: Pip Cet; +Cc: acorallo, eggert, 75964, stefankangas, monnier
> Date: Sun, 02 Feb 2025 16:51:30 +0000
> From: Pip Cet <pipcet@protonmail.com>
> Cc: eggert@cs.ucla.edu, 75964@debbugs.gnu.org, stefankangas@gmail.com, acorallo@gnu.org, monnier@iro.umontreal.ca
>
> "Eli Zaretskii" <eliz@gnu.org> writes:
>
> >> We often use eassert for that, and I don't know how many people realize
> >> this subtle difference between emacs_abort () and eassert (0).
> >
> > Well, I do: eassert compiles to nothing in a production build, so it
> > is only okay if the code can do something with the situation, albeit
> > something that will cause weird effects. eassert is also appropriate
> > to convey the assumptions made by the code, even if no trouble will be
> > caused by violating those assumptions.
>
> Interesting. I often use eassert where the only thing we can do in a
> production build is almost certainly a crash. Can you say more about
> cases in which it's used to avoid crashes?
No, eassert should _never_ be used to avoid crashes. It should be
used to flag problems (by forcing a crash) before the mistaken code
causes too much harm, with the purpose of helping us find problems
before they become very hard to analyze.
A crash can only be avoided if we have a fallback code that can do
something reasonable with an impossible situation, like signaling an
error or silently skipping some action.
> >> I still think eassume and eassert shouldn't evaluate expressions with
> >> side effects.
> >
> > I agree. Do we have code which does that in Emacs?
>
> I'm aware of
>
> eassert (check_comp_unit_relocs (comp_u));
>
> in comp.c, which does call an extra function, which might in theory have
> side effects because dynlib_sym or Flength or, God forbid, Fgethash may
> develop some. But, really, this is a special case and a very minor
> issue.
I'm quite sure there was no intention for the above to cause any side
effects.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 15:21 ` Stefan Kangas
@ 2025-02-02 17:27 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 0 replies; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-02 17:27 UTC (permalink / raw)
To: Stefan Kangas; +Cc: Eli Zaretskii, 75964
"Stefan Kangas" <stefankangas@gmail.com> writes:
> Eli Zaretskii <eliz@gnu.org> writes:
>
>> It would indeed be wise to stop pushing changes in this area as long
>> as we are not sure what would be the best solution.
>>
>> Stefan, do you agree?
>
> Yes. Let's decide what's the best way forward here before making any
> further changes.
Agreed. I thought there might be a one-time benefit, but I haven't had
time to look at the places where I was confused about a case not being
handled... Anyway, I have the GCC option in my tree now and no one can
take it away from me :-)
> The recent reverts by Pip Cet seems like a good step.
Just for the record, I proposed but did not push those. I don't think
that changes anything, though.
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 17:21 ` Eli Zaretskii
@ 2025-02-02 17:30 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 0 replies; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-02 17:30 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: acorallo, eggert, 75964, stefankangas, monnier
"Eli Zaretskii" <eliz@gnu.org> writes:
>> Date: Sun, 02 Feb 2025 16:51:30 +0000
>> From: Pip Cet <pipcet@protonmail.com>
>> Cc: eggert@cs.ucla.edu, 75964@debbugs.gnu.org, stefankangas@gmail.com, acorallo@gnu.org, monnier@iro.umontreal.ca
>>
>> "Eli Zaretskii" <eliz@gnu.org> writes:
>>
>> >> We often use eassert for that, and I don't know how many people realize
>> >> this subtle difference between emacs_abort () and eassert (0).
>> >
>> > Well, I do: eassert compiles to nothing in a production build, so it
>> > is only okay if the code can do something with the situation, albeit
>> > something that will cause weird effects. eassert is also appropriate
>> > to convey the assumptions made by the code, even if no trouble will be
>> > caused by violating those assumptions.
>>
>> Interesting. I often use eassert where the only thing we can do in a
>> production build is almost certainly a crash. Can you say more about
>> cases in which it's used to avoid crashes?
>
> No, eassert should _never_ be used to avoid crashes. It should be
> used to flag problems (by forcing a crash) before the mistaken code
> causes too much harm, with the purpose of helping us find problems
> before they become very hard to analyze.
Sorry, I misunderstood. I agree completely with this statement, and was
confused by "the code can do something with the situation".
> A crash can only be avoided if we have a fallback code that can do
> something reasonable with an impossible situation, like signaling an
> error or silently skipping some action.
Agreed. eassert is definitely not good for that.
>
>> >> I still think eassume and eassert shouldn't evaluate expressions with
>> >> side effects.
>> >
>> > I agree. Do we have code which does that in Emacs?
>>
>> I'm aware of
>>
>> eassert (check_comp_unit_relocs (comp_u));
>>
>> in comp.c, which does call an extra function, which might in theory have
>> side effects because dynlib_sym or Flength or, God forbid, Fgethash may
>> develop some. But, really, this is a special case and a very minor
>> issue.
>
> I'm quite sure there was no intention for the above to cause any side
> effects.
Yes, which is why it's only technically an example. If I see
eassert (i++ < len)
I'll let you know :-)
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 17:02 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-02 17:35 ` Eli Zaretskii
0 siblings, 0 replies; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-02 17:35 UTC (permalink / raw)
To: Pip Cet; +Cc: acorallo, eggert, 75964, stefankangas, monnier
> Date: Sun, 02 Feb 2025 17:02:04 +0000
> From: Pip Cet <pipcet@protonmail.com>
> Cc: eggert@cs.ucla.edu, 75964@debbugs.gnu.org, stefankangas@gmail.com, acorallo@gnu.org, monnier@iro.umontreal.ca
>
> "Eli Zaretskii" <eliz@gnu.org> writes:
>
> > This is an example of code where some value of an enumeration need
> > special handling, and the rest don't need any handling at all. IMO,
> > we should ask ourselves what are we trying to accomplish by spelling
> > out all of the "other" values instead of just 'default'? If we only
> > care for a handful of values, what kind of errors could slip us if we
> > use 'default'?
>
> As someone who's not very familiar with the bidi code, I would feel most
> comfortable if this switch, with all cases, were in an inline function
> which decides whether we set l2r_seen, r2l_seen, or neither, in this
> context. Ideally, in my case, with further comments, though trying to
> understand this code without studying the Unicode Bidirectional
> Algorithm will always be foolish...
The bidi.c code is in many places in the shape it is because it tries
to closely follow the description in the UBA, so as to make the
understanding of what the code does easier without drowning it in
comments.
If the goal here is to make sure we never miss a type is to invent a
new category, which includes only the 4 types mentioned in the switch,
and then do the switch only for that category.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 11:48 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 12:13 ` Eli Zaretskii
@ 2025-02-02 18:27 ` Paul Eggert
2025-02-02 18:47 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 19:27 ` Eli Zaretskii
1 sibling, 2 replies; 74+ messages in thread
From: Paul Eggert @ 2025-02-02 18:27 UTC (permalink / raw)
To: Pip Cet; +Cc: Eli Zaretskii, 75964, stefankangas
[-- Attachment #1: Type: text/plain, Size: 1940 bytes --]
On 2025-02-02 03:48, Pip Cet wrote:
> I've also stayed away from lib-src for now.
Although you did look at lib-src (I see some changes there) you
understandably did not tackle lib-src/etags.c which has many enum
switches and gimmicks to pacify GCC. So I took a crack at etags.c and
came up with an alternative proposal consisting of two suggestions to
support the following goals:
* Cleanly compile with -Wswitch-enum to catch potential errors.
* A style that is easy to explain and understand.
* No changes to GCC needed for now.
* No new C macros in the Emacs source code.
* Source code that is shorter and easier to maintain.
Here's the proposal:
Suggestion 1: Don't treat all enum switch statements the same. Some enum
switch statements merely want to treat a couple of enum values
specially, with all other enum values being default. For these, it's
unlikely that forcing the programmer to list a case for every enum value
will catch many bugs; it's even possible that this would cause more
problems than it'll cure, and it's certainly an annoyance.
For these switch statements, use "switch (+E)" instead of "switch (E)".
This pacifies GCC and clearly signals to the reader that the switch's
cases are not intended to exhaust the enum. A "switch (E)" must list all
the enum values; a "switch (+E)" need not do so. A reasonable guideline
is that if a switch statement has more than three "case X: break;"s then
it may be a good idea to use "switch (+E)" instead of "switch (E)".
Suggestion 2: Omit "default: break;"s present only to tell GCC and/or
the reader that the switch is otherwise not exhaustive. "switch (+expr)"
already does this more concisely and more usefully.
Combine these two suggestions, and I made etags.c shorter (by 23 lines)
and easier to read once you know the style. See attached patch, which
compiles cleanly with -Wswitch-enum.
I assume similar results would apply elsewhere in Emacs.
[-- Attachment #2: 0001-Pacify-gcc-Wswitch-enum-in-etags.c.patch --]
[-- Type: text/x-patch, Size: 9584 bytes --]
From 8cbd3ce89a30e0968831bcb7b56edff031adbfd8 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Sun, 2 Feb 2025 10:01:46 -0800
Subject: [PATCH] Pacify gcc -Wswitch-enum in etags.c
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* lib-src/etags.c (main, consider_token, C_entries)
(TeX_commands): For every switch (E) with an enum expression E,
either enumerate all the enum values as cases, or if that’s too
verbose use ‘switch (E+)’ to indicate that it’s intended that
we not enumerate all the enum values. Remove ‘default: break;’
cases that are not now needed to pacify GCC.
---
lib-src/etags.c | 85 ++++++++++++++++++-------------------------------
1 file changed, 31 insertions(+), 54 deletions(-)
diff --git a/lib-src/etags.c b/lib-src/etags.c
index b59b70c9ec7..619d0765867 100644
--- a/lib-src/etags.c
+++ b/lib-src/etags.c
@@ -1397,6 +1397,7 @@ main (int argc, char **argv)
this_file = argbuffer[i].what;
process_file (stdin, this_file, lang);
break;
+ case at_end:
default:
error ("internal error: arg_type");
}
@@ -1444,11 +1445,11 @@ main (int argc, char **argv)
{
case at_filename:
case at_stdin:
+ cleanup_tags_file (tagfile, argbuffer[i].what);
+ break;
+ case at_end: case at_language: case at_regexp:
break;
- default:
- continue; /* the for loop */
}
- cleanup_tags_file (tagfile, argbuffer[i].what);
}
append_to_tagfile = true;
}
@@ -3147,7 +3148,7 @@ consider_token (char *str, /* IN: token pointer */
}
break;
case tkeyseen:
- switch (toktype)
+ switch (+toktype)
{
case st_none:
case st_C_class:
@@ -3155,8 +3156,6 @@ consider_token (char *str, /* IN: token pointer */
case st_C_enum:
typdef = ttypeseen;
break;
- default:
- break;
}
break;
case ttypeseen:
@@ -3167,7 +3166,7 @@ consider_token (char *str, /* IN: token pointer */
}
break;
case tend:
- switch (toktype)
+ switch (+toktype)
{
case st_C_class:
case st_C_struct:
@@ -3176,11 +3175,11 @@ consider_token (char *str, /* IN: token pointer */
default:
return true;
}
- default:
+ case tinbody: case tignore:
break;
}
- switch (toktype)
+ switch (+toktype)
{
case st_C_javastruct:
if (structdef == stagseen)
@@ -3210,8 +3209,6 @@ consider_token (char *str, /* IN: token pointer */
fvdef = fvnone;
}
return false;
- default:
- break;
}
if (structdef == skeyseen)
@@ -3227,7 +3224,7 @@ consider_token (char *str, /* IN: token pointer */
switch (objdef)
{
case onone:
- switch (toktype)
+ switch (+toktype)
{
case st_C_objprot:
objdef = oprotocol;
@@ -3235,8 +3232,6 @@ consider_token (char *str, /* IN: token pointer */
case st_C_objimpl:
objdef = oimplementation;
return false;
- default:
- break;
}
break;
case oimplementation:
@@ -3296,16 +3291,16 @@ consider_token (char *str, /* IN: token pointer */
objdef = onone;
}
return false;
- default:
+ case ocatseen: case omethodtag: case otagseen:
break;
}
/* A function, variable or enum constant? */
- switch (toktype)
+ switch (+toktype)
{
case st_C_extern:
fvextern = true;
- switch (fvdef)
+ switch (+fvdef)
{
case finlist:
case flistseen:
@@ -3332,7 +3327,7 @@ consider_token (char *str, /* IN: token pointer */
constants. */
&& fvdef != vignore)
return true; /* enum constant */
- switch (fvdef)
+ switch (+fvdef)
{
case fdefunkey:
if (bracelev > 0)
@@ -3341,7 +3336,7 @@ consider_token (char *str, /* IN: token pointer */
*is_func_or_var = true;
return true;
case fvnone:
- switch (typdef)
+ switch (+typdef)
{
case ttypeseen:
return false;
@@ -3353,8 +3348,6 @@ consider_token (char *str, /* IN: token pointer */
return false;
}
break;
- default:
- break;
}
FALLTHROUGH;
case fvnameseen:
@@ -3371,12 +3364,8 @@ consider_token (char *str, /* IN: token pointer */
fvdef = fvnameseen; /* function or variable */
*is_func_or_var = true;
return true;
- default:
- break;
}
break;
- default:
- break;
}
return false;
@@ -3581,7 +3570,7 @@ C_entries (int c_ext, /* extension of C */
continue;
if (inattribute)
break;
- switch (fvdef)
+ switch (+fvdef)
{
case fdefunkey:
case fstartlist:
@@ -3883,7 +3872,7 @@ C_entries (int c_ext, /* extension of C */
switch (definedef)
{
case dnone:
- switch (fvdef)
+ switch (+fvdef)
{
case fstartlist:
/* This prevents tagging fb in
@@ -3898,8 +3887,6 @@ C_entries (int c_ext, /* extension of C */
fvdef = fignore;
}
break;
- default:
- break;
}
if (structdef == stagseen && !cjava)
{
@@ -3910,7 +3897,7 @@ C_entries (int c_ext, /* extension of C */
case dsharpseen:
savetoken = token;
break;
- default:
+ case ddefineseen: case dignorerest:
break;
}
if (!yacc_rules || lp == newlb.buffer + 1)
@@ -3938,7 +3925,7 @@ C_entries (int c_ext, /* extension of C */
}
if (definedef != dnone)
break;
- switch (objdef)
+ switch (+objdef)
{
case otagseen:
objdef = oignore;
@@ -3954,8 +3941,6 @@ C_entries (int c_ext, /* extension of C */
strcpy (token_name.buffer + toklen, ":");
}
break;
- default:
- break;
}
if (structdef == stagseen)
{
@@ -3984,7 +3969,7 @@ C_entries (int c_ext, /* extension of C */
case tnone:
case tinbody:
case tignore:
- switch (fvdef)
+ switch (+fvdef)
{
case fignore:
if (typdef == tignore || cplpl)
@@ -4016,6 +4001,7 @@ C_entries (int c_ext, /* extension of C */
token.valid = false;
} /* switch (fvdef) */
FALLTHROUGH;
+ case tkeyseen:
default:
if (!instruct)
typdef = tnone;
@@ -4026,15 +4012,13 @@ C_entries (int c_ext, /* extension of C */
case ',':
if (definedef != dnone || inattribute)
break;
- switch (objdef)
+ switch (+objdef)
{
case omethodtag:
case omethodparm:
make_C_tag (true); /* an Objective C method */
objdef = oinbody;
break;
- default:
- break;
}
switch (fvdef)
{
@@ -4071,6 +4055,7 @@ C_entries (int c_ext, /* extension of C */
fvdef = fvnone;
token.valid = false;
break;
+ case fvnone:
default:
fvdef = fvnone;
}
@@ -4093,7 +4078,7 @@ C_entries (int c_ext, /* extension of C */
break;
case tnone:
case tinbody:
- switch (fvdef)
+ switch (+fvdef)
{
case foperator:
case finlist:
@@ -4110,7 +4095,7 @@ C_entries (int c_ext, /* extension of C */
fvdef = fvnone;
}
break;
- default:
+ case tignore: case tkeyseen:
break;
}
break;
@@ -4124,7 +4109,7 @@ C_entries (int c_ext, /* extension of C */
break;
if (objdef == otagseen && parlev == 0)
objdef = oparenseen;
- switch (fvdef)
+ switch (+fvdef)
{
case fvnameseen:
if (typdef == ttypeseen
@@ -4145,8 +4130,6 @@ C_entries (int c_ext, /* extension of C */
case flistseen:
fvdef = finlist;
break;
- default:
- break;
}
parlev++;
break;
@@ -4172,14 +4155,12 @@ C_entries (int c_ext, /* extension of C */
}
if (--parlev == 0)
{
- switch (fvdef)
+ switch (+fvdef)
{
case fstartlist:
case finlist:
fvdef = flistseen;
break;
- default:
- break;
}
if (!instruct
&& (typdef == tend
@@ -4202,7 +4183,7 @@ C_entries (int c_ext, /* extension of C */
typdef = tinbody;
typdefbracelev = bracelev;
}
- switch (fvdef)
+ switch (+fvdef)
{
case flistseen:
if (cplpl && !class_qualify)
@@ -4233,7 +4214,7 @@ C_entries (int c_ext, /* extension of C */
fvdef = fvnone;
break;
case fvnone:
- switch (objdef)
+ switch (+objdef)
{
case otagseen:
make_C_tag (true); /* an Objective C class */
@@ -4251,8 +4232,6 @@ C_entries (int c_ext, /* extension of C */
bracelev = -1;
}
break;
- default:
- break;
}
switch (structdef)
{
@@ -4266,7 +4245,7 @@ C_entries (int c_ext, /* extension of C */
structdef = snone;
make_C_tag (false); /* a struct or enum */
break;
- default:
+ case snone:
break;
}
bracelev += 1;
@@ -4316,7 +4295,7 @@ C_entries (int c_ext, /* extension of C */
case '=':
if (definedef != dnone)
break;
- switch (fvdef)
+ switch (+fvdef)
{
case foperator:
case finlist:
@@ -4361,7 +4340,7 @@ C_entries (int c_ext, /* extension of C */
if (definedef != dnone)
break;
/* These surely cannot follow a function tag in C. */
- switch (fvdef)
+ switch (+fvdef)
{
case foperator:
case finlist:
@@ -6006,8 +5985,6 @@ TeX_commands (FILE *inf)
goto tex_next_line;
}
break;
- default:
- break;
}
}
namelen = p - cp;
--
2.45.2
^ permalink raw reply related [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 18:27 ` Paul Eggert
@ 2025-02-02 18:47 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 19:27 ` Eli Zaretskii
1 sibling, 0 replies; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-02 18:47 UTC (permalink / raw)
To: Paul Eggert; +Cc: Eli Zaretskii, 75964, stefankangas
"Paul Eggert" <eggert@cs.ucla.edu> writes:
> On 2025-02-02 03:48, Pip Cet wrote:
>> I've also stayed away from lib-src for now.
^^^^^^
I meant to say "run" :-)
> Although you did look at lib-src (I see some changes there) you
Just because I changed code doesn't mean I looked at it!
> understandably did not tackle lib-src/etags.c which has many enum
> switches and gimmicks to pacify GCC. So I took a crack at etags.c and
> came up with an alternative proposal consisting of two suggestions to
> support the following goals:
>
> * Cleanly compile with -Wswitch-enum to catch potential errors.
> * A style that is easy to explain and understand.
> * No changes to GCC needed for now.
> * No new C macros in the Emacs source code.
> * Source code that is shorter and easier to maintain.
>
> Here's the proposal:
>
> Suggestion 1: Don't treat all enum switch statements the same. Some enum
> switch statements merely want to treat a couple of enum values
> specially, with all other enum values being default. For these, it's
> unlikely that forcing the programmer to list a case for every enum value
> will catch many bugs; it's even possible that this would cause more
> problems than it'll cure, and it's certainly an annoyance.
I agree. Using "if" should not be made an even more tempting option
than it already is.
> For these switch statements, use "switch (+E)" instead of "switch (E)".
> This pacifies GCC and clearly signals to the reader that the switch's
> cases are not intended to exhaust the enum. A "switch (E)" must list all
> the enum values; a "switch (+E)" need not do so. A reasonable guideline
> is that if a switch statement has more than three "case X: break;"s then
> it may be a good idea to use "switch (+E)" instead of "switch (E)".
TBH, the syntax seems a bit hacky to me; when the fallthrough statement
attribute was added, we should have gained the ability to add attributes
to labels to indicate that *this* default label is actually useful, or
isn't, or that we do or do not want warnings about it.
However, maybe I got that all wrong: GCC has statement attributes, too,
and maybe we should add an attribute to the switch statement, not the
label. If that can be done.
However, switch (+E) seems easier, if we only distinguish two cases.
Also easier to wrap in a macro if you must.
> Suggestion 2: Omit "default: break;"s present only to tell GCC and/or
> the reader that the switch is otherwise not exhaustive. "switch (+expr)"
> already does this more concisely and more usefully.
Total agreement there.
> I assume similar results would apply elsewhere in Emacs.
I think it's a bit of a special case, but I'm not stopping you :-) Very
interesting idea, in any case!
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 18:27 ` Paul Eggert
2025-02-02 18:47 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-02 19:27 ` Eli Zaretskii
2025-02-02 21:43 ` Paul Eggert
1 sibling, 1 reply; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-02 19:27 UTC (permalink / raw)
To: Paul Eggert; +Cc: pipcet, 75964, stefankangas
> Date: Sun, 2 Feb 2025 10:27:02 -0800
> Cc: 75964@debbugs.gnu.org, stefankangas@gmail.com,
> Eli Zaretskii <eliz@gnu.org>
> From: Paul Eggert <eggert@cs.ucla.edu>
>
> * Cleanly compile with -Wswitch-enum to catch potential errors.
> * A style that is easy to explain and understand.
> * No changes to GCC needed for now.
> * No new C macros in the Emacs source code.
> * Source code that is shorter and easier to maintain.
What are the problems in etags.c this tries to solve? just that its
source is 23 lines too long?
> Here's the proposal:
>
> Suggestion 1: Don't treat all enum switch statements the same. Some enum
> switch statements merely want to treat a couple of enum values
> specially, with all other enum values being default. For these, it's
> unlikely that forcing the programmer to list a case for every enum value
> will catch many bugs; it's even possible that this would cause more
> problems than it'll cure, and it's certainly an annoyance.
>
> For these switch statements, use "switch (+E)" instead of "switch (E)".
> This pacifies GCC and clearly signals to the reader that the switch's
> cases are not intended to exhaust the enum. A "switch (E)" must list all
> the enum values; a "switch (+E)" need not do so. A reasonable guideline
> is that if a switch statement has more than three "case X: break;"s then
> it may be a good idea to use "switch (+E)" instead of "switch (E)".
>
> Suggestion 2: Omit "default: break;"s present only to tell GCC and/or
> the reader that the switch is otherwise not exhaustive. "switch (+expr)"
> already does this more concisely and more usefully.
"switch (+expr)" has the disadvantage that it is not widely known.
E.g., I couldn't find its description in the two GNU manuals of the C
language I have. Why would we want to use a construct that people
might not be familiar with?
> Combine these two suggestions, and I made etags.c shorter (by 23 lines)
> and easier to read once you know the style. See attached patch, which
> compiles cleanly with -Wswitch-enum.
I'm not sure shortening etags.c by 23 lines justifies this.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 19:27 ` Eli Zaretskii
@ 2025-02-02 21:43 ` Paul Eggert
2025-02-03 12:08 ` Eli Zaretskii
0 siblings, 1 reply; 74+ messages in thread
From: Paul Eggert @ 2025-02-02 21:43 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: pipcet, 75964, stefankangas
[-- Attachment #1: Type: text/plain, Size: 2177 bytes --]
On 2025-02-02 11:27, Eli Zaretskii wrote:
> What are the problems in etags.c this tries to solve?
The main point is to catch more potential inadvertent omissions of "case
X:" in a "switch (E)" where E's type is an enum containing X. etags.c,
like the rest of Emacs, currently uses one style to do this; the
proposed style would be better at catching these mistakes.
Although the proposed style is shorter than what Emacs currently uses,
brevity is not the main goal here.
> "switch (+expr)" has the disadvantage that it is not widely known.
It is a simple combination of two widely-known constructs, "switch (E)"
and "+E". It is not a GNU extension: support for this has always been
required by the C standard and it works everywhere.
If we use this style consistently it will be obvious, and gcc
-Wswitch-enum will report inadvertent deviations from it which will be
better than what we have now (no static checking). Also, developers who
don't like the style won't be obliged to use it: they can use other
techniques (already discussed) to pacify -Wswitch-enum if they prefer.
> Why would we want to use a construct that people
> might not be familiar with?
Because when we add -Wswitch-enum, GCC will be more likely to catch
trivial mistakes that it doesn't currently catch.
> I'm not sure shortening etags.c by 23 lines justifies this.
The main goal here is reliability via better static checking, not
brevity. Pip Cet's proposal to improve reliability makes the code more
verbose, which is a minus. This proposal does not have that minus - on
the contrary, it makes code shorter and simpler.
To test this again, I applied the style to the file that Pip Cet said
was a troublesome case: src/bidi.c. Here the style made the code only a
little bit shorter, but that was because I took the liberty of also
improving the already-existing dynamic checking, as I modified
bidi_get_type to also abort if default_value is not listed in the
bidi_type_t enum. So this patch improves dynamic checking (without
significant runtime cost), improves static checking, and makes the code
a bit shorter and easier to read.
All in all it's a success story.
[-- Attachment #2: 0001-Pacify-gcc-Wswitch-enum-in-bidi.c.patch --]
[-- Type: text/x-patch, Size: 4264 bytes --]
From 400f3d8eb6d171f3a5692554ce2df59ebd3e1c5a Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Sun, 2 Feb 2025 13:36:35 -0800
Subject: [PATCH] Pacify gcc -Wswitch-enum in bidi.c
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* src/bidi.c (bidi_get_type): Abort if the default type has a
value not listed in the enum, instead of silently treating
it like NEUTRAL_ON etc. List all enum values in a switch.
(bidi_resolve_explicit, bidi_find_bracket_pairs)
(bidi_resolve_neutral): Use ‘switch (+E)’ to indicate that it’s
intended that we not enumerate all the enum values. Remove
‘default: break;’ cases that are not now needed to pacify GCC.
---
src/bidi.c | 34 ++++++++++++++++------------------
1 file changed, 16 insertions(+), 18 deletions(-)
diff --git a/src/bidi.c b/src/bidi.c
index d8754e2db73..5656b7a9cf9 100644
--- a/src/bidi.c
+++ b/src/bidi.c
@@ -282,12 +282,6 @@ bidi_get_type (int ch, bidi_dir_t override)
emacs_abort ();
default_type = (bidi_type_t) XFIXNUM (CHAR_TABLE_REF (bidi_type_table, ch));
- /* Every valid character code, even those that are unassigned by the
- UCD, have some bidi-class property, according to
- DerivedBidiClass.txt file. Therefore, if we ever get UNKNOWN_BT
- (= zero) code from CHAR_TABLE_REF, that's a bug. */
- if (default_type == UNKNOWN_BT)
- emacs_abort ();
switch (default_type)
{
@@ -303,7 +297,18 @@ bidi_get_type (int ch, bidi_dir_t override)
case FSI:
case PDI:
return default_type;
+
+ case UNKNOWN_BT:
default:
+ /* Every valid character code, even those that are unassigned by the
+ UCD, have some bidi-class property, according to
+ DerivedBidiClass.txt file. Therefore, if we ever get UNKNOWN_BT
+ (= zero) or some unknown code from CHAR_TABLE_REF, that's a bug. */
+ emacs_abort ();
+
+ case NEUTRAL_ON: case NEUTRAL_S: case NEUTRAL_WS:
+ case STRONG_AL: case STRONG_L: case STRONG_R:
+ case WEAK_AN: case WEAK_CS: case WEAK_EN: case WEAK_ES: case WEAK_ET: case WEAK_NSM:
if (override == L2R)
return STRONG_L;
else if (override == R2L)
@@ -2010,7 +2015,7 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
embedding level of the _following_ characters, so we must
first look at the type of the previous character to support
that. */
- switch (prev_type)
+ switch (+prev_type)
{
case RLI: /* X5a */
if (current_level < BIDI_MAXDEPTH
@@ -2074,7 +2079,7 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
bidi_it->type_after_wn = UNKNOWN_BT;
- switch (type)
+ switch (+type)
{
case RLE: /* X2 */
case RLO: /* X4 */
@@ -2197,9 +2202,6 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
bidi_check_type (bidi_it->type_after_wn);
type = WEAK_BN; /* X9/Retaining */
break;
- default:
- /* Nothing. */
- break;
}
bidi_it->type = type;
@@ -2707,7 +2709,7 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it)
/* Whenever we see a strong type, update the flags of
all the slots on the stack. */
- switch (bidi_it->type)
+ switch (+bidi_it->type)
{
case STRONG_L:
flag = ((embedding_level & 1) == 0
@@ -2723,8 +2725,6 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it)
: FLAG_OPPOSITE_INSIDE);
r2l_seen = true;
break;
- default:
- break;
}
if (flag)
{
@@ -2979,7 +2979,7 @@ bidi_resolve_brackets (struct bidi_it *bidi_it)
if (prev_type_for_neutral == UNKNOWN_BT)
prev_type_for_neutral = embedding_type;
- switch (prev_type_for_neutral)
+ switch (+prev_type_for_neutral)
{
case STRONG_R:
case WEAK_EN:
@@ -2995,9 +2995,7 @@ bidi_resolve_brackets (struct bidi_it *bidi_it)
? STRONG_L /* N0c1 */
: embedding_type; /* N0c2 */
break;
- default:
/* N0d: Do not set the type for that bracket pair. */
- break;
}
}
eassert (type == STRONG_L || type == STRONG_R || type == NEUTRAL_ON);
@@ -3175,7 +3173,7 @@ bidi_resolve_neutral (struct bidi_it *bidi_it)
}
else
{
- switch (type)
+ switch (+type)
{
case STRONG_L:
case STRONG_R:
--
2.45.2
^ permalink raw reply related [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 12:50 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 13:21 ` Eli Zaretskii
2025-02-02 13:40 ` Eli Zaretskii
@ 2025-02-03 3:01 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-03 3:52 ` Paul Eggert
` (2 more replies)
2 siblings, 3 replies; 74+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-03 3:01 UTC (permalink / raw)
To: Pip Cet; +Cc: Andrea Corallo, Eli Zaretskii, eggert, 75964, stefankangas
> switch (bidi_it->type)
> {
> case STRONG_L:
> flag = ((embedding_level & 1) == 0
> ? FLAG_EMBEDDING_INSIDE
> : FLAG_OPPOSITE_INSIDE);
> l2r_seen = true;
> break;
> case STRONG_R:
> case WEAK_EN:
> case WEAK_AN:
> flag = ((embedding_level & 1) == 1
> ? FLAG_EMBEDDING_INSIDE
> : FLAG_OPPOSITE_INSIDE);
> r2l_seen = true;
> break;
> case UNKNOWN_BT:
> case WEAK_BN:
> case NEUTRAL_B:
> case STRONG_AL:
> case LRE:
> case LRO:
> case RLE:
> case RLO:
> case PDF:
> case LRI:
> case RLI:
> case FSI:
> case PDI:
> case WEAK_ES:
> case WEAK_ET:
> case WEAK_CS:
> case WEAK_NSM:
> case NEUTRAL_S:
> case NEUTRAL_WS:
> case NEUTRAL_ON:
> default: break;
> }
>
> I think that could be rewritten to be more readable in a number of ways,
The most obvious one is to remove all the `case ..:` just before `default:`.
That would be my vote as well (tho only because I don't know that
code. There might be a very good reason to keep it as above, of course).
> including, of course, putting a #pragma in.
I hate `#pragma`.
Stefan
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-03 3:01 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-03 3:52 ` Paul Eggert
2025-02-03 12:31 ` Eli Zaretskii
2025-02-03 9:01 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-03 12:18 ` Eli Zaretskii
2 siblings, 1 reply; 74+ messages in thread
From: Paul Eggert @ 2025-02-03 3:52 UTC (permalink / raw)
To: Stefan Monnier
Cc: Pip Cet, Eli Zaretskii, Andrea Corallo, 75964, stefankangas
On 2025-02-02 19:01, Stefan Monnier wrote:
> I hate `#pragma`.
I'm not a fan either. Luckily my suggestion[1][2] doesn't use #pragma.
[1]: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=75964#122
[2]: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=75964#131
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-03 3:01 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-03 3:52 ` Paul Eggert
@ 2025-02-03 9:01 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-03 11:08 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-03 12:18 ` Eli Zaretskii
2 siblings, 1 reply; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-03 9:01 UTC (permalink / raw)
To: Stefan Monnier; +Cc: Andrea Corallo, Eli Zaretskii, eggert, 75964, stefankangas
"Stefan Monnier" <monnier@iro.umontreal.ca> writes:
>> switch (bidi_it->type)
>> {
>> case STRONG_L:
>> flag = ((embedding_level & 1) == 0
>> ? FLAG_EMBEDDING_INSIDE
>> : FLAG_OPPOSITE_INSIDE);
>> l2r_seen = true;
>> break;
>> case STRONG_R:
>> case WEAK_EN:
>> case WEAK_AN:
>> flag = ((embedding_level & 1) == 1
>> ? FLAG_EMBEDDING_INSIDE
>> : FLAG_OPPOSITE_INSIDE);
>> r2l_seen = true;
>> break;
>> case UNKNOWN_BT:
>> case WEAK_BN:
>> case NEUTRAL_B:
>> case STRONG_AL:
>> case LRE:
>> case LRO:
>> case RLE:
>> case RLO:
>> case PDF:
>> case LRI:
>> case RLI:
>> case FSI:
>> case PDI:
>> case WEAK_ES:
>> case WEAK_ET:
>> case WEAK_CS:
>> case WEAK_NSM:
>> case NEUTRAL_S:
>> case NEUTRAL_WS:
>> case NEUTRAL_ON:
>> default: break;
>> }
>>
>> I think that could be rewritten to be more readable in a number of ways,
>
> The most obvious one is to remove all the `case ..:` just before `default:`.
> That would be my vote as well (tho only because I don't know that
> code. There might be a very good reason to keep it as above, of course).
The reason was to add -Wswitch-enum, which would warn about incomplete
case enumerations involving an enum type. My hope was to make some
existing bugs more obvious that way, because applying a patch like:
@@ -26086,8 +26124,9 @@ x_draw_window_cursor (struct window *w, struct glyph_row *glyph_row, int x,
w->phys_cursor_width = 0;
break;
- default:
+ case DEFAULT_CURSOR:
emacs_abort ();
+ default: emacs_abort ();
}
}
does make you wonder what's so special about the DEFAULT_CURSOR case
that aborting when we're asked to draw one is the right thing to do.
(There's probably a good reason in this case).
There are more cases like this in the patch I sent. I guess the
consensus now is not to add -Wswitch-enum to regular builds at all, so
we'll just have to live with those bugs.
>> including, of course, putting a #pragma in.
>
> I hate `#pragma`.
Consider it a failed last-ditch attempt to enable these warnings on a
per-file basis, by using #include "exhaustive.h" or a similar construct.
We still have the option of doing so in Makefile.in, but who reads
Makeile.in?
So I guess we'll just do nothing.
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-03 9:01 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-03 11:08 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-03 11:31 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 1 reply; 74+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-03 11:08 UTC (permalink / raw)
To: Pip Cet; +Cc: Andrea Corallo, Eli Zaretskii, eggert, 75964, stefankangas
>> The most obvious one is to remove all the `case ..:` just before `default:`.
>> That would be my vote as well (tho only because I don't know that
>> code. There might be a very good reason to keep it as above, of course).
>
> The reason was to add -Wswitch-enum, which would warn about incomplete
> case enumerations involving an enum type.
In which sense is a "`switch` with a `default` clause" incomplete?
Stefan
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-03 11:08 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-03 11:31 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-03 20:47 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 1 reply; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-03 11:31 UTC (permalink / raw)
To: Stefan Monnier; +Cc: Andrea Corallo, Eli Zaretskii, eggert, 75964, stefankangas
"Stefan Monnier" <monnier@iro.umontreal.ca> writes:
>>> The most obvious one is to remove all the `case ..:` just before `default:`.
>>> That would be my vote as well (tho only because I don't know that
>>> code. There might be a very good reason to keep it as above, of course).
>>
>> The reason was to add -Wswitch-enum, which would warn about incomplete
>> case enumerations involving an enum type.
>
> In which sense is a "`switch` with a `default` clause" incomplete?
Only in the sense that it's sometimes useful to warn about such
statements! They're not invalid C.
GCC offers an option to do that. Disabling that option, as we had
previously done, had led to some (very minor) bugs and some potential
bugs that I have yet to look at (such as the "crash on DEFAULT_CURSOR"
thing upthread).
But it seems there is a consensus we'd rather live with such bugs, so
nothing about switch statements is about to change. It'll be perfectly
okay to continue writing code such as:
enum ABC { A, B, C };
enum ABC abc;
switch (abc) {
case A:
/* handle case A */
break;
default:
/* we know this must be case C */
/* handle case C */
break;
}
(The major problem, of course, is that case B might have to be handled
differently. The minor, much rarer problem is that abc might not be any
of A, B, or C, but a different value altogether: C + 3, for example. C
makes this legal, and Emacs relies on such behavior.)
Paul's suggestion for switching off the warning behavior is very clever,
and if he could come up with a way of switching ON the warning behavior
where we might want it, maybe that would be an option, but at this point
we need to look at the potential bugs this warning has found, then close
the bug. If it had discovered massive numbers of actual bugs I'd argue
differently, but it hasn't, so unless Paul wants to take over and argue
for this change, it lacks a champion.
We might want to disable -Wswitch, too, as it only results in a false
sense of security and useless default: clauses being added to pacify
warnings.
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-02 21:43 ` Paul Eggert
@ 2025-02-03 12:08 ` Eli Zaretskii
2025-02-03 12:24 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-04 21:23 ` Paul Eggert
0 siblings, 2 replies; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-03 12:08 UTC (permalink / raw)
To: Paul Eggert; +Cc: pipcet, 75964, stefankangas
> Date: Sun, 2 Feb 2025 13:43:40 -0800
> Cc: pipcet@protonmail.com, 75964@debbugs.gnu.org, stefankangas@gmail.com
> From: Paul Eggert <eggert@cs.ucla.edu>
>
> > What are the problems in etags.c this tries to solve?
>
> The main point is to catch more potential inadvertent omissions of "case
> X:" in a "switch (E)" where E's type is an enum containing X. etags.c,
> like the rest of Emacs, currently uses one style to do this; the
> proposed style would be better at catching these mistakes.
And how do the proposed changes achieve that goal?
> > "switch (+expr)" has the disadvantage that it is not widely known.
>
> It is a simple combination of two widely-known constructs, "switch (E)"
> and "+E". It is not a GNU extension: support for this has always been
> required by the C standard and it works everywhere.
I am asking about the "+E" part. You said in an earlier message:
> For these switch statements, use "switch (+E)" instead of "switch (E)".
> This pacifies GCC and clearly signals to the reader that the switch's
> cases are not intended to exhaust the enum. A "switch (E)" must list all
> the enum values; a "switch (+E)" need not do so. A reasonable guideline
The above seems to say that "+E" is different from "E" in ways that
the compiler knows about. So I'm asking where is this special meaning
documented, to make sure I completely understand its semantics and its
treatment by the compiler.
> > Why would we want to use a construct that people
> > might not be familiar with?
>
> Because when we add -Wswitch-enum, GCC will be more likely to catch
> trivial mistakes that it doesn't currently catch.
If the special meaning of "+E" is not well understood, using it might
cause people make more mistakes.
> > I'm not sure shortening etags.c by 23 lines justifies this.
>
> The main goal here is reliability via better static checking, not
> brevity. Pip Cet's proposal to improve reliability makes the code more
> verbose, which is a minus. This proposal does not have that minus - on
> the contrary, it makes code shorter and simpler.
I'm not comparing this with what Pip Cet proposed, I compare it with
what we have now.
> To test this again, I applied the style to the file that Pip Cet said
> was a troublesome case: src/bidi.c. Here the style made the code only a
> little bit shorter, but that was because I took the liberty of also
> improving the already-existing dynamic checking, as I modified
> bidi_get_type to also abort if default_value is not listed in the
> bidi_type_t enum. So this patch improves dynamic checking (without
> significant runtime cost), improves static checking, and makes the code
> a bit shorter and easier to read.
I don't think I see how these changes improve checking and make the
code easier to read. For me, the "+E" thing is an obstacle to
negotiate; I'm sure others will also stumble on that. And apart of
that change, the code basically remained the same.
> + case NEUTRAL_ON: case NEUTRAL_S: case NEUTRAL_WS:
> + case STRONG_AL: case STRONG_L: case STRONG_R:
> + case WEAK_AN: case WEAK_CS: case WEAK_EN: case WEAK_ES: case WEAK_ET: case WEAK_NSM:
> if (override == L2R)
> return STRONG_L;
> else if (override == R2L)
If you really consider this long list of values more readable than the
original code, then I guess we disagree on what is and isn't readable.
As I mentioned up-thread, such a long list doesn't convince me that
all the values were mentioned. So for me this is a net loss, because
the original code left no doubt that all the types get the
directionality-override handling.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-03 3:01 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-03 3:52 ` Paul Eggert
2025-02-03 9:01 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-03 12:18 ` Eli Zaretskii
2 siblings, 0 replies; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-03 12:18 UTC (permalink / raw)
To: Stefan Monnier; +Cc: acorallo, pipcet, eggert, 75964, stefankangas
> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Eli Zaretskii <eliz@gnu.org>, eggert@cs.ucla.edu,
> 75964@debbugs.gnu.org, stefankangas@gmail.com, Andrea Corallo
> <acorallo@gnu.org>
> Date: Sun, 02 Feb 2025 22:01:23 -0500
>
> > switch (bidi_it->type)
> > {
> > case STRONG_L:
> > flag = ((embedding_level & 1) == 0
> > ? FLAG_EMBEDDING_INSIDE
> > : FLAG_OPPOSITE_INSIDE);
> > l2r_seen = true;
> > break;
> > case STRONG_R:
> > case WEAK_EN:
> > case WEAK_AN:
> > flag = ((embedding_level & 1) == 1
> > ? FLAG_EMBEDDING_INSIDE
> > : FLAG_OPPOSITE_INSIDE);
> > r2l_seen = true;
> > break;
> > case UNKNOWN_BT:
> > case WEAK_BN:
> > case NEUTRAL_B:
> > case STRONG_AL:
> > case LRE:
> > case LRO:
> > case RLE:
> > case RLO:
> > case PDF:
> > case LRI:
> > case RLI:
> > case FSI:
> > case PDI:
> > case WEAK_ES:
> > case WEAK_ET:
> > case WEAK_CS:
> > case WEAK_NSM:
> > case NEUTRAL_S:
> > case NEUTRAL_WS:
> > case NEUTRAL_ON:
> > default: break;
> > }
> >
> > I think that could be rewritten to be more readable in a number of ways,
>
> The most obvious one is to remove all the `case ..:` just before `default:`.
That's what the current code does:
switch (bidi_it->type)
{
case STRONG_L:
flag = ((embedding_level & 1) == 0
? FLAG_EMBEDDING_INSIDE
: FLAG_OPPOSITE_INSIDE);
l2r_seen = true;
break;
case STRONG_R:
case WEAK_EN:
case WEAK_AN:
flag = ((embedding_level & 1) == 1
? FLAG_EMBEDDING_INSIDE
: FLAG_OPPOSITE_INSIDE);
r2l_seen = true;
break;
default:
break;
}
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-03 12:08 ` Eli Zaretskii
@ 2025-02-03 12:24 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-03 13:13 ` Eli Zaretskii
2025-02-04 21:23 ` Paul Eggert
1 sibling, 1 reply; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-03 12:24 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Paul Eggert, 75964, stefankangas
"Eli Zaretskii" <eliz@gnu.org> writes:
>> + case NEUTRAL_ON: case NEUTRAL_S: case NEUTRAL_WS:
>> + case STRONG_AL: case STRONG_L: case STRONG_R:
>> + case WEAK_AN: case WEAK_CS: case WEAK_EN: case WEAK_ES: case WEAK_ET: case WEAK_NSM:
>> if (override == L2R)
>> return STRONG_L;
>> else if (override == R2L)
>
> If you really consider this long list of values more readable than the
> original code, then I guess we disagree on what is and isn't readable.
> As I mentioned up-thread, such a long list doesn't convince me that
> all the values were mentioned.
The compiler, with -Wswitch-enum, would have warned about that. The
point is you would not have to convince yourself that the "default"
doesn't catch a case you should have explicitly handled otherwise.
But, again, bidi.c is the exception where -Wswitch-enum adds *nothing*
but verbosity, and would require us to rewrite the code around it rather
than writing the code we want.
At the very least, we'd have to add comments, and those comments would
have to explain or reference the Unicode consortium's decisions, and I
don't think anyone is volunteering to do that.
As an example: why is a European Number, which is always written L2R
even in R2L context, treated the same as a strongly R2L character in the
specific context of bidi_find_bracket_pairs? That's confusing, because
I don't understand the reason, and I should look at the Unicode
algorithm to answer that question. Adding more case labels doesn't help
the confusion at all; in fact, it distracts from this important
exception by hiding it in a long list of no-op cases.
> So for me this is a net loss, because the original code left no doubt
> that all the types get the directionality-override handling.
I'm very tempted to suggest rewriting this code to make the exceptional
handling of WEAK_EN more obvious, but I'm not going to, so all I can do
is agree with Eli here: -Wswitch-enum doesn't work in this case, or in
any of the switch statements in bidi.c.
Let's look at the potential bugs this uncovered in detail, improve
comments where we can (because most likely, they're not bugs), and close
this bug.
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-03 3:52 ` Paul Eggert
@ 2025-02-03 12:31 ` Eli Zaretskii
0 siblings, 0 replies; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-03 12:31 UTC (permalink / raw)
To: Paul Eggert; +Cc: pipcet, acorallo, 75964, monnier, stefankangas
> Date: Sun, 2 Feb 2025 19:52:04 -0800
> Cc: Eli Zaretskii <eliz@gnu.org>, 75964@debbugs.gnu.org,
> stefankangas@gmail.com, Andrea Corallo <acorallo@gnu.org>,
> Pip Cet <pipcet@protonmail.com>
> From: Paul Eggert <eggert@cs.ucla.edu>
>
> On 2025-02-02 19:01, Stefan Monnier wrote:
> > I hate `#pragma`.
>
> I'm not a fan either. Luckily my suggestion[1][2] doesn't use #pragma.
We use #pragma only as the last resort, and I think we should keep
doing that.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-03 12:24 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-03 13:13 ` Eli Zaretskii
0 siblings, 0 replies; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-03 13:13 UTC (permalink / raw)
To: Pip Cet; +Cc: eggert, 75964, stefankangas
> Date: Mon, 03 Feb 2025 12:24:18 +0000
> From: Pip Cet <pipcet@protonmail.com>
> Cc: Paul Eggert <eggert@cs.ucla.edu>, 75964@debbugs.gnu.org, stefankangas@gmail.com
>
> "Eli Zaretskii" <eliz@gnu.org> writes:
>
> >> + case NEUTRAL_ON: case NEUTRAL_S: case NEUTRAL_WS:
> >> + case STRONG_AL: case STRONG_L: case STRONG_R:
> >> + case WEAK_AN: case WEAK_CS: case WEAK_EN: case WEAK_ES: case WEAK_ET: case WEAK_NSM:
> >> if (override == L2R)
> >> return STRONG_L;
> >> else if (override == R2L)
> >
> > If you really consider this long list of values more readable than the
> > original code, then I guess we disagree on what is and isn't readable.
> > As I mentioned up-thread, such a long list doesn't convince me that
> > all the values were mentioned.
>
> The compiler, with -Wswitch-enum, would have warned about that.
Yes, but when I read code, I don't want to run the compiler, I want to
be able to understand the code and reason about it by myself.
> The
> point is you would not have to convince yourself that the "default"
> doesn't catch a case you should have explicitly handled otherwise.
I don't need to convince myself: the code says so. If the algorithm
is in error, that's a different issue.
> As an example: why is a European Number, which is always written L2R
> even in R2L context, treated the same as a strongly R2L character in the
> specific context of bidi_find_bracket_pairs? That's confusing, because
> I don't understand the reason, and I should look at the Unicode
> algorithm to answer that question. Adding more case labels doesn't help
> the confusion at all; in fact, it distracts from this important
> exception by hiding it in a long list of no-op cases.
Like I said: bidi.c must be read with the UBA at hand. I've
explicitly added pointers to specific parts of the UBA description for
that very reason. I've also made the code resemble the UBA text as
much as reasonably possible.
> > So for me this is a net loss, because the original code left no doubt
> > that all the types get the directionality-override handling.
>
> I'm very tempted to suggest rewriting this code to make the exceptional
> handling of WEAK_EN more obvious
Why does it have to be more obvious?
First, it isn't just WEAK_EN, it's also WEAK_AN.
Here's what the UBA says about that:
For each bracket-pair element in the list of pairs of text positions
a. Inspect the bidirectional types of the characters enclosed
within the bracket pair.
b. If any strong type (either L or R) matching the embedding
direction is found, set the type for both brackets in the pair
to match the embedding direction.
Note that EN and AN should be treated as a strong R type
when searching within the brackets.
Note that the isolating run sequence may not be
contiguous. Implementations should take care to ignore
characters not contained in the isolating run sequence when
processing neutral or weak characters.
o [ e ] o → o e e e o
o [ o e ] → o e o e e
o [ NI e ] → o e NI e e
c. Otherwise, if there is a strong type it must be opposite the
embedding direction. Therefore, test for an established context
with a preceding strong type by checking backwards before the
opening paired bracket until the first strong type (L or R) is
found, using the value of sos if there is none.
Note that EN and AN should be treated as a strong R type
when searching for established context.
1. If the preceding strong type is also opposite the
embedding direction, context is established, so set the
type for both brackets in the pair to that direction.
o [ o ] e → o o o o e
o [ o NI ] o → o o o NI o o
2. Otherwise set the type for both brackets in the pair to the
embedding direction.
e [ o ] o → e e o e o
e [ o ] e → e e o e e
Note that taken together the two steps in item 2 are
guaranteed to set the type for both brackets to the
preceding strong type, as there are only two possible
values (L and R).
d. Otherwise, there are no strong types within the bracket
pair. Therefore, do not set the type for that bracket pair.
e ( NI ) o → e ( NI ) o
Note that if the enclosed text contains no strong types the
bracket pairs will both resolve to the same level when resolved
individually using rules N1 and N2.
As you see, the UBA description explicitly mentions EN and AN, so
having that in the code makes it easier (at least IMO) to read and
validate the code.
> Let's look at the potential bugs this uncovered in detail, improve
> comments where we can (because most likely, they're not bugs), and close
> this bug.
Agreed.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-03 11:31 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-03 20:47 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-03 21:15 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 1 reply; 74+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-03 20:47 UTC (permalink / raw)
To: Pip Cet; +Cc: Andrea Corallo, Eli Zaretskii, eggert, 75964, stefankangas
> enum ABC abc;
> switch (abc) {
> case A:
> /* handle case A */
> break;
> default:
> /* we know this must be case C */
> /* handle case C */
> break;
> }
I think this just suggests we should refrain from using `default:`
except in those cases where we really think it's the better tradeoff.
I don't think there can be a silver bullet.
Stefan
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-03 20:47 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-03 21:15 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-04 12:24 ` Eli Zaretskii
2025-02-04 13:58 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 2 replies; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-03 21:15 UTC (permalink / raw)
To: Stefan Monnier; +Cc: Andrea Corallo, Eli Zaretskii, eggert, 75964, stefankangas
"Stefan Monnier" <monnier@iro.umontreal.ca> writes:
>> enum ABC abc;
>> switch (abc) {
>> case A:
>> /* handle case A */
>> break;
>> default:
>> /* we know this must be case C */
>> /* handle case C */
>> break;
>> }
>
> I think this just suggests we should refrain from using `default:`
Switching over an enum without a default: label will generate
fall-through code, for those cases in which the enum variable has a
value that's not in the enumeration.
Yes, C allows this, and requires it, and Emacs relies on this "feature"
(in at least two places, which I won't mention to protect the guilty).
That means extra code will be generated, and GCC will warn about
uninitialized data or whatever other state of things falling through the
switch statement will leave us with.
This is all very silly and hopefully C3X will introduce actual enums,
but until then, we need the default branch.
> I don't think there can be a silver bullet.
Maybe not.
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-03 21:15 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-04 12:24 ` Eli Zaretskii
2025-02-04 13:52 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-04 13:58 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
1 sibling, 1 reply; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-04 12:24 UTC (permalink / raw)
To: Pip Cet; +Cc: acorallo, eggert, 75964, monnier, stefankangas
> Date: Mon, 03 Feb 2025 21:15:38 +0000
> From: Pip Cet <pipcet@protonmail.com>
> Cc: Eli Zaretskii <eliz@gnu.org>, eggert@cs.ucla.edu, 75964@debbugs.gnu.org, stefankangas@gmail.com, Andrea Corallo <acorallo@gnu.org>
>
> "Stefan Monnier" <monnier@iro.umontreal.ca> writes:
>
> >> enum ABC abc;
> >> switch (abc) {
> >> case A:
> >> /* handle case A */
> >> break;
> >> default:
> >> /* we know this must be case C */
> >> /* handle case C */
> >> break;
> >> }
> >
> > I think this just suggests we should refrain from using `default:`
>
> Switching over an enum without a default: label will generate
> fall-through code, for those cases in which the enum variable has a
> value that's not in the enumeration.
What is "fall-through code" in this context, and why is it bad that
the compiler will generate such code?
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-04 12:24 ` Eli Zaretskii
@ 2025-02-04 13:52 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-04 14:57 ` Eli Zaretskii
0 siblings, 1 reply; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-04 13:52 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: acorallo, eggert, 75964, monnier, stefankangas
"Eli Zaretskii" <eliz@gnu.org> writes:
>> Date: Mon, 03 Feb 2025 21:15:38 +0000
>> From: Pip Cet <pipcet@protonmail.com>
>> Cc: Eli Zaretskii <eliz@gnu.org>, eggert@cs.ucla.edu, 75964@debbugs.gnu.org, stefankangas@gmail.com, Andrea Corallo <acorallo@gnu.org>
>>
>> "Stefan Monnier" <monnier@iro.umontreal.ca> writes:
>>
>> >> enum ABC abc;
>> >> switch (abc) {
>> >> case A:
>> >> /* handle case A */
>> >> break;
>> >> default:
>> >> /* we know this must be case C */
>> >> /* handle case C */
>> >> break;
>> >> }
>> >
>> > I think this just suggests we should refrain from using `default:`
>>
>> Switching over an enum without a default: label will generate
>> fall-through code, for those cases in which the enum variable has a
>> value that's not in the enumeration.
>
> What is "fall-through code" in this context,
A switch statement which doesn't execute any branches, so it becomes a
nop.
so
enum ABC abc;
int x; /* uninitialized */
switch (abc)
{
case A:
x = 1;
break;
case B:
x = 2;
break;
case C:
x = 3;
break;
}
printf ("x = %d\n", x);
will (and should!) generate a warning that x may be used uninitialized,
because it's possible abc == C + 1, and then none of the three
statements initializing x is executed.
> and why is it bad that the compiler will generate such code?
1. it's slightly less efficient. Not really an issue, but others
disagree about how important performance is here.
2. the compiler will generate warnings because the code cannot be assumed
to have initialized x at all. This is annoying, since we wanted better
warnings, and we just got more noise.
3. The analyzer will waste its scarce resources analyzing code paths
that are of no interest to us, making its output less useful and more
noisy.
Just to be clear: We should not blindly go adding default: labels to
every switch statement because of (1) or (3). If (2) happens, adding a
default: label may be one option, but this shouldn't be automatic.
However, *removing* a default: label is something that should not be
done either.
Let's leave our switch statements as they are now, and remember to be
careful that we won't get warnings about missed enumeration cases?
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-03 21:15 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-04 12:24 ` Eli Zaretskii
@ 2025-02-04 13:58 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-04 14:57 ` Eli Zaretskii
1 sibling, 1 reply; 74+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-04 13:58 UTC (permalink / raw)
To: Pip Cet; +Cc: Andrea Corallo, Eli Zaretskii, eggert, 75964, stefankangas
> Switching over an enum without a default: label will generate
> fall-through code, for those cases in which the enum variable has a
> value that's not in the enumeration.
Ah, thanks, now I understand the problem.
Yes, this part of C sucks and I had forgotten about it.
I wish it offered a special label (call it `invalid:`, `notenum:`,
`bogus:`, `outofrange:`, ...) for "what to do when the value is not
a member of the enum".
Stefan
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-04 13:52 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-04 14:57 ` Eli Zaretskii
0 siblings, 0 replies; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-04 14:57 UTC (permalink / raw)
To: Pip Cet; +Cc: acorallo, eggert, 75964, monnier, stefankangas
> Date: Tue, 04 Feb 2025 13:52:33 +0000
> From: Pip Cet <pipcet@protonmail.com>
> Cc: monnier@iro.umontreal.ca, eggert@cs.ucla.edu, 75964@debbugs.gnu.org, stefankangas@gmail.com, acorallo@gnu.org
>
> "Eli Zaretskii" <eliz@gnu.org> writes:
>
> >> Switching over an enum without a default: label will generate
> >> fall-through code, for those cases in which the enum variable has a
> >> value that's not in the enumeration.
> >
> > What is "fall-through code" in this context,
>
> A switch statement which doesn't execute any branches, so it becomes a
> nop.
>
> so
>
> enum ABC abc;
> int x; /* uninitialized */
> switch (abc)
> {
> case A:
> x = 1;
> break;
> case B:
> x = 2;
> break;
> case C:
> x = 3;
> break;
> }
> printf ("x = %d\n", x);
>
> will (and should!) generate a warning that x may be used uninitialized,
> because it's possible abc == C + 1, and then none of the three
> statements initializing x is executed.
Right, but the same will (or should!) happen if I just add a default
case:
enum ABC abc;
int x; /* uninitialized */
switch (abc)
{
case A:
x = 1;
break;
case B:
x = 2;
break;
case C:
x = 3;
break;
default:
break;
}
printf ("x = %d\n", x);
Right? So abc = C + 1 is still possible, and thus just adding the
default case doesn't miraculously fix my code, where I forgot to
initialize x. Or does it?
> 1. it's slightly less efficient. Not really an issue, but others
> disagree about how important performance is here.
> 2. the compiler will generate warnings because the code cannot be assumed
> to have initialized x at all. This is annoying, since we wanted better
> warnings, and we just got more noise.
> 3. The analyzer will waste its scarce resources analyzing code paths
> that are of no interest to us, making its output less useful and more
> noisy.
>
> Just to be clear: We should not blindly go adding default: labels to
> every switch statement because of (1) or (3). If (2) happens, adding a
> default: label may be one option, but this shouldn't be automatic.
I think adding the default here is actually a bad thing: it shuts up
the warning without fixing the code.
And anyway, the above is only a problem if the switch fails to
initialize something. In many cases, some values of an enum really
don't need any handling, in which case there's no need for default.
> Let's leave our switch statements as they are now, and remember to be
> careful that we won't get warnings about missed enumeration cases?
Sure.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-04 13:58 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-04 14:57 ` Eli Zaretskii
2025-02-04 16:55 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 1 reply; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-04 14:57 UTC (permalink / raw)
To: Stefan Monnier; +Cc: acorallo, pipcet, eggert, 75964, stefankangas
> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Eli Zaretskii <eliz@gnu.org>, eggert@cs.ucla.edu,
> 75964@debbugs.gnu.org, stefankangas@gmail.com, Andrea Corallo
> <acorallo@gnu.org>
> Date: Tue, 04 Feb 2025 08:58:21 -0500
>
> > Switching over an enum without a default: label will generate
> > fall-through code, for those cases in which the enum variable has a
> > value that's not in the enumeration.
>
> Ah, thanks, now I understand the problem.
>
> Yes, this part of C sucks and I had forgotten about it.
What sucks and why?
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-04 14:57 ` Eli Zaretskii
@ 2025-02-04 16:55 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-04 17:30 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-04 19:36 ` Eli Zaretskii
0 siblings, 2 replies; 74+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-04 16:55 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: acorallo, pipcet, eggert, 75964, stefankangas
>> Yes, this part of C sucks and I had forgotten about it.
> What sucks and why?
That
switch ((enum Lisp_Type) 53) {
case Lisp_Symbol:
case Lisp_Type_Unused0:
case Lisp_Int0:
case Lisp_Int1:
case Lisp_String:
case Lisp_Vectorlike:
case Lisp_Cons:
case Lisp_Float:
return 1;
}
return 2;
should return 2, because I'd prefer that it aborts and/or that the
programmer have a way to say explicitly what should happen. `default:`
works for that in the case where you have listed *all* the enum's
values, but then you get stiffed in the case where you add an enum value
because the compiler won't tell you that you forgot to update this
`switch` accordingly.
Stefan
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-04 16:55 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-04 17:30 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-04 18:17 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-04 19:36 ` Eli Zaretskii
1 sibling, 1 reply; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-04 17:30 UTC (permalink / raw)
To: Stefan Monnier; +Cc: acorallo, Eli Zaretskii, eggert, 75964, stefankangas
"Stefan Monnier" <monnier@iro.umontreal.ca> writes:
>>> Yes, this part of C sucks and I had forgotten about it.
>> What sucks and why?
>
> That
>
> switch ((enum Lisp_Type) 53) {
> case Lisp_Symbol:
> case Lisp_Type_Unused0:
> case Lisp_Int0:
> case Lisp_Int1:
> case Lisp_String:
> case Lisp_Vectorlike:
> case Lisp_Cons:
> case Lisp_Float:
> return 1;
> }
> return 2;
>
> should return 2, because I'd prefer that it aborts and/or that the
> programmer have a way to say explicitly what should happen. `default:`
> works for that in the case where you have listed *all* the enum's
> values, but then you get stiffed in the case where you add an enum value
> because the compiler won't tell you that you forgot to update this
> `switch` accordingly.
But... that's precisely what -Wswitch-enum does! It warns about a
fargotten case even though there is also a default label!
So, yes, the compiler will warn you about that forgotten enumeration,
but it's not easy to turn this on and off on a per-switch basis.
(Also GCC misses a few cases where the enumeration type isn't the type
of the switch expression but is the type of the labels. That one's
easiest to fix).
Paul's proposal to use switch (+x) when you mean "don't warn me about
new cases" and switch (x) when you mean "do warn me about new cases"
seems easy enough to add as a special case, but it is new and
non-obvious syntax.
And while it would be nice to
#define exhaustive_switch(x) switch (x) { default: eassume (false); ELIDE_TOKEN("{")
I don't know how to write ELIDE_TOKEN in CPP, because someone decided
token streams form a free monoid rather than a free group...
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-04 17:30 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-04 18:17 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-04 18:28 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 1 reply; 74+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-04 18:17 UTC (permalink / raw)
To: Pip Cet; +Cc: acorallo, Eli Zaretskii, eggert, 75964, stefankangas
>> should return 2, because I'd prefer that it aborts and/or that the
>> programmer have a way to say explicitly what should happen. `default:`
>> works for that in the case where you have listed *all* the enum's
>> values, but then you get stiffed in the case where you add an enum value
>> because the compiler won't tell you that you forgot to update this
>> `switch` accordingly.
>
> But... that's precisely what -Wswitch-enum does! It warns about a
> forgotten case even though there is also a default label!
But IIUC that breaks the other case, where you do want to use `default:`
to mean "any other (valid) enum value".
Stefan
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-04 18:17 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-04 18:28 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 0 replies; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-04 18:28 UTC (permalink / raw)
To: Stefan Monnier; +Cc: acorallo, Eli Zaretskii, eggert, 75964, stefankangas
"Stefan Monnier" <monnier@iro.umontreal.ca> writes:
>>> should return 2, because I'd prefer that it aborts and/or that the
>>> programmer have a way to say explicitly what should happen. `default:`
>>> works for that in the case where you have listed *all* the enum's
>>> values, but then you get stiffed in the case where you add an enum value
>>> because the compiler won't tell you that you forgot to update this
>>> `switch` accordingly.
>>
>> But... that's precisely what -Wswitch-enum does! It warns about a
>> forgotten case even though there is also a default label!
>
> But IIUC that breaks the other case, where you do want to use `default:`
> to mean "any other (valid) enum value".
That's what I meant by "not easy to turn on and off on a per-switch
basis", yes (unless you really want to learn about _Pragma). Slightly
easier to do so on a per-enum basis, though (it has a type, types have
attributes, there's already one for bitfield enums), but that means you
need to control the enums rather than some other header file doing so.
And while statement/label atttributes are possible, they turn into
horrible macro constructions.
So while I still think -Wswitch-enum would be the best solution, it's by
a slight margin and Eli's describing the effect on bidi.c as so drastic
that we'd have to disable it for that file, and per-file CFLAGS are a
nightmare, so all we can do is wait for GCC to learn new tricks (which
I'm not smart enough to think of).
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-04 16:55 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-04 17:30 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-04 19:36 ` Eli Zaretskii
2025-02-04 20:45 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
1 sibling, 1 reply; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-04 19:36 UTC (permalink / raw)
To: Stefan Monnier; +Cc: acorallo, pipcet, eggert, 75964, stefankangas
> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: pipcet@protonmail.com, eggert@cs.ucla.edu, 75964@debbugs.gnu.org,
> stefankangas@gmail.com, acorallo@gnu.org
> Date: Tue, 04 Feb 2025 11:55:12 -0500
>
> >> Yes, this part of C sucks and I had forgotten about it.
> > What sucks and why?
>
> That
>
> switch ((enum Lisp_Type) 53) {
> case Lisp_Symbol:
> case Lisp_Type_Unused0:
> case Lisp_Int0:
> case Lisp_Int1:
> case Lisp_String:
> case Lisp_Vectorlike:
> case Lisp_Cons:
> case Lisp_Float:
> return 1;
> }
> return 2;
>
> should return 2, because I'd prefer that it aborts and/or that the
> programmer have a way to say explicitly what should happen. `default:`
> works for that in the case where you have listed *all* the enum's
> values, but then you get stiffed in the case where you add an enum value
> because the compiler won't tell you that you forgot to update this
> `switch` accordingly.
So you want a device that would abort for unexpected values? Then why
use switch at all? You want eassert or even a simple if:
if ((enum foo) foo > max_enum_value)
emacs_abort ();
Or what am I missing?
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-04 19:36 ` Eli Zaretskii
@ 2025-02-04 20:45 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-05 12:15 ` Eli Zaretskii
0 siblings, 1 reply; 74+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-04 20:45 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: acorallo, pipcet, eggert, 75964, stefankangas
> So you want a device that would abort for unexpected values?
I want the compiler to consider this case as an error, rather than
a defined "this is an empty statement".
> Then why use switch at all?
Because you want to perform various operations depending on the value of
the enum (admittedly, in my example I performed the same op on all
values, but that's because I typed it by hand and got lazy).
Stefan
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-03 12:08 ` Eli Zaretskii
2025-02-03 12:24 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-04 21:23 ` Paul Eggert
2025-02-05 13:05 ` Eli Zaretskii
2025-02-05 18:10 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
1 sibling, 2 replies; 74+ messages in thread
From: Paul Eggert @ 2025-02-04 21:23 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: pipcet, 75964, stefankangas
[-- Attachment #1: Type: text/plain, Size: 4511 bytes --]
On 2/3/25 04:08, Eli Zaretskii wrote:
>> From: Paul Eggert <eggert@cs.ucla.edu>
>> The main point is to catch more potential inadvertent omissions of "case
>> X:" in a "switch (E)" where E's type is an enum containing X. etags.c,
>> like the rest of Emacs, currently uses one style to do this; the
>> proposed style would be better at catching these mistakes.
>
> And how do the proposed changes achieve that goal?
With an enum expression E and code like this:
switch (E) { case A: ...; case B: ...; }
there is currently no compile-time diagnostic for mismatches between the
type and the code when the enum type also has a value C, either because
the programmer forgot to handle case C when the switch was written, or
because the enum type was changed and the programmer forgot to check all
uses of the enum.
There *is* a compile-time diagnostic for similar mismatches between type
and code, e.g., if the enum type lacks a B (perhaps because B was
formerly present but has since been removed). But there is no
compile-time diagnostic for the mismatch in question.
Mismatches like these are all too common and can lead to user-visible
bugs. It's a win to detect these mismatches statically.
>> For these switch statements, use "switch (+E)" instead of "switch (E)".
>> This pacifies GCC and clearly signals to the reader that the switch's
>> cases are not intended to exhaust the enum. A "switch (E)" must list all
>> the enum values; a "switch (+E)" need not do so. A reasonable guideline
>
> The above seems to say that "+E" is different from "E" in ways that
> the compiler knows about. So I'm asking where is this special meaning
> documented
It is more than merely documented; it's been common practice for years.
For example, given enum W {X,Y,Z} the type of an expression like X+1 has
been int (not enum W) ever since enums were standardized in the C89
standard.
For documentation chapter and verse, please see C23 §6.5.4.3 ¶2, which
says that the type of +E is like that of -E: the type is E's type after
integer promotions. Also please see C23 §6.3.1.1 ¶1–2, which says that
int is the type of these Emacs enums after integer promotion. So, when E
is one of these enums, the type of +E (and of -E) is int.
> If the special meaning of "+E" is not well understood
I hope the above suffices to explain why it is well understood.
> I don't think I see how these changes improve checking and make the
> code easier to read. For me, the "+E" thing is an obstacle to
> negotiate; I'm sure others will also stumble on that.
If necessary we can package "+E" inside an inline identity function.
That might help prevent stumbling by people who don't know the C
language well, and it would not have any runtime cost in the usual -O2
case. I'd rather not use such a function (as +E is clear once you get
used to it) but using one would be better than doing nothing, as it
would improve static checking.
> apart of that change, the code basically remained the same.
Yes, and that's a plus for +E: you don't have to change the code much.
In that sense it's better than Pip Cet's earlier proposal.
>> + case NEUTRAL_ON: case NEUTRAL_S: case NEUTRAL_WS:
>> + case STRONG_AL: case STRONG_L: case STRONG_R:
>> + case WEAK_AN: case WEAK_CS: case WEAK_EN: case WEAK_ES: case WEAK_ET: case WEAK_NSM:
>> if (override == L2R)
>> return STRONG_L;
>> else if (override == R2L)
>
> If you really consider this long list of values more readable than the
> original code, then I guess we disagree on what is and isn't readable.
Oh, that long list was in some sense a misfire, as the patch did two
things where I suppose it should have done one. First, the patch
improved the runtime checkcing for invalid values, something that can
and should be done independently of what we do about -Wswitch-enum.
Second, the patch pacified -Wswitch-enum.
I fixed this misfire by splitting the patch into two parts, which I'm
attaching. The first attached patch improves the runtime checking
without changing the -Wswitch-enum style, and I installed that on
master. The second attached patch, which I have not installed, is the
-Wswitch-enum change proper.
In this example, pacifying -Wswitch-enum helped find code where Emacs's
internal runtime checking was missing some invalid values. So this is an
example of why this style change is helpful in practice.
[-- Attachment #2: 0001-Improve-bidi_get_time-runtime-checking.patch --]
[-- Type: text/x-patch, Size: 1876 bytes --]
From 782ec71053d8535511522f27f28c11682ca0f40b Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Tue, 4 Feb 2025 11:43:58 -0800
Subject: [PATCH 1/2] Improve bidi_get_time runtime checking
* src/bidi.c (bidi_get_type): Improve runtime checking, by also
aborting if the bidi_type_table entry is not a bidi_type_t value.
---
src/bidi.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/src/bidi.c b/src/bidi.c
index d8754e2db73..fd0bebb85e0 100644
--- a/src/bidi.c
+++ b/src/bidi.c
@@ -282,12 +282,6 @@ bidi_get_type (int ch, bidi_dir_t override)
emacs_abort ();
default_type = (bidi_type_t) XFIXNUM (CHAR_TABLE_REF (bidi_type_table, ch));
- /* Every valid character code, even those that are unassigned by the
- UCD, have some bidi-class property, according to
- DerivedBidiClass.txt file. Therefore, if we ever get UNKNOWN_BT
- (= zero) code from CHAR_TABLE_REF, that's a bug. */
- if (default_type == UNKNOWN_BT)
- emacs_abort ();
switch (default_type)
{
@@ -303,13 +297,26 @@ bidi_get_type (int ch, bidi_dir_t override)
case FSI:
case PDI:
return default_type;
- default:
+
+ case STRONG_L: case STRONG_R:
+ case WEAK_EN: case WEAK_AN:
+ case STRONG_AL:
+ case WEAK_ES: case WEAK_ET: case WEAK_CS: case WEAK_NSM:
+ case NEUTRAL_S: case NEUTRAL_WS: case NEUTRAL_ON:
if (override == L2R)
return STRONG_L;
else if (override == R2L)
return STRONG_R;
else
return default_type;
+
+ case UNKNOWN_BT:
+ default:
+ /* Every valid character code, even those unassigned by the UCD,
+ have some bidi-class property, according to DerivedBidiClass.txt.
+ Therefore, if we ever get UNKNOWN_BT (= zero) or some unknown
+ code from CHAR_TABLE_REF, that's a bug. */
+ emacs_abort ();
}
}
--
2.48.1
[-- Attachment #3: 0002-Pacify-gcc-Wswitch-enum-in-bidi.c.patch --]
[-- Type: text/x-patch, Size: 2852 bytes --]
From e75ff04e92d16394dcd7b24a87adf1e2fc5bae91 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Tue, 4 Feb 2025 13:02:18 -0800
Subject: [PATCH 2/2] Pacify gcc -Wswitch-enum in bidi.c
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* src/bidi.c (characters, bidi_find_bracket_pairs)
(bidi_resolve_brackets, bidi_resolve_neutral):
Use ‘switch (+E)’ to indicate that it’s intended that we not
enumerate all the enum values.
Remove ‘default: break;’ cases that are not now needed to pacify GCC.
---
src/bidi.c | 17 +++++------------
1 file changed, 5 insertions(+), 12 deletions(-)
diff --git a/src/bidi.c b/src/bidi.c
index fd0bebb85e0..fae5f04d03d 100644
--- a/src/bidi.c
+++ b/src/bidi.c
@@ -2017,7 +2017,7 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
embedding level of the _following_ characters, so we must
first look at the type of the previous character to support
that. */
- switch (prev_type)
+ switch (+prev_type)
{
case RLI: /* X5a */
if (current_level < BIDI_MAXDEPTH
@@ -2081,7 +2081,7 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
bidi_it->type_after_wn = UNKNOWN_BT;
- switch (type)
+ switch (+type)
{
case RLE: /* X2 */
case RLO: /* X4 */
@@ -2204,9 +2204,6 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
bidi_check_type (bidi_it->type_after_wn);
type = WEAK_BN; /* X9/Retaining */
break;
- default:
- /* Nothing. */
- break;
}
bidi_it->type = type;
@@ -2714,7 +2711,7 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it)
/* Whenever we see a strong type, update the flags of
all the slots on the stack. */
- switch (bidi_it->type)
+ switch (+bidi_it->type)
{
case STRONG_L:
flag = ((embedding_level & 1) == 0
@@ -2730,8 +2727,6 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it)
: FLAG_OPPOSITE_INSIDE);
r2l_seen = true;
break;
- default:
- break;
}
if (flag)
{
@@ -2986,7 +2981,7 @@ bidi_resolve_brackets (struct bidi_it *bidi_it)
if (prev_type_for_neutral == UNKNOWN_BT)
prev_type_for_neutral = embedding_type;
- switch (prev_type_for_neutral)
+ switch (+prev_type_for_neutral)
{
case STRONG_R:
case WEAK_EN:
@@ -3002,9 +2997,7 @@ bidi_resolve_brackets (struct bidi_it *bidi_it)
? STRONG_L /* N0c1 */
: embedding_type; /* N0c2 */
break;
- default:
/* N0d: Do not set the type for that bracket pair. */
- break;
}
}
eassert (type == STRONG_L || type == STRONG_R || type == NEUTRAL_ON);
@@ -3182,7 +3175,7 @@ bidi_resolve_neutral (struct bidi_it *bidi_it)
}
else
{
- switch (type)
+ switch (+type)
{
case STRONG_L:
case STRONG_R:
--
2.48.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-04 20:45 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-05 12:15 ` Eli Zaretskii
0 siblings, 0 replies; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-05 12:15 UTC (permalink / raw)
To: Stefan Monnier; +Cc: acorallo, pipcet, eggert, 75964, stefankangas
> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: pipcet@protonmail.com, eggert@cs.ucla.edu, 75964@debbugs.gnu.org,
> stefankangas@gmail.com, acorallo@gnu.org
> Date: Tue, 04 Feb 2025 15:45:36 -0500
>
> > So you want a device that would abort for unexpected values?
>
> I want the compiler to consider this case as an error, rather than
> a defined "this is an empty statement".
Which part of your code is the error you want the compiler to flag?
the cast to enum of a value that is outside of the enum, or the fact
that not all the valid values of the enum are mentioned explicitly in
the switch, so some will fall through?
> > Then why use switch at all?
>
> Because you want to perform various operations depending on the value of
> the enum (admittedly, in my example I performed the same op on all
> values, but that's because I typed it by hand and got lazy).
An assertion followed by a switch should fit the bill, no?
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-04 21:23 ` Paul Eggert
@ 2025-02-05 13:05 ` Eli Zaretskii
2025-02-05 19:20 ` Paul Eggert
2025-02-05 18:10 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
1 sibling, 1 reply; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-05 13:05 UTC (permalink / raw)
To: Paul Eggert; +Cc: pipcet, 75964, stefankangas
> Date: Tue, 4 Feb 2025 13:23:25 -0800
> From: Paul Eggert <eggert@cs.ucla.edu>
> Cc: pipcet@protonmail.com, 75964@debbugs.gnu.org, stefankangas@gmail.com
>
> On 2/3/25 04:08, Eli Zaretskii wrote:
> >> From: Paul Eggert <eggert@cs.ucla.edu>
> >> The main point is to catch more potential inadvertent omissions of "case
> >> X:" in a "switch (E)" where E's type is an enum containing X. etags.c,
> >> like the rest of Emacs, currently uses one style to do this; the
> >> proposed style would be better at catching these mistakes.
> >
> > And how do the proposed changes achieve that goal?
>
> With an enum expression E and code like this:
>
> switch (E) { case A: ...; case B: ...; }
>
> there is currently no compile-time diagnostic for mismatches between the
> type and the code when the enum type also has a value C, either because
> the programmer forgot to handle case C when the switch was written, or
> because the enum type was changed and the programmer forgot to check all
> uses of the enum.
>
> There *is* a compile-time diagnostic for similar mismatches between type
> and code, e.g., if the enum type lacks a B (perhaps because B was
> formerly present but has since been removed). But there is no
> compile-time diagnostic for the mismatch in question.
>
> Mismatches like these are all too common and can lead to user-visible
> bugs. It's a win to detect these mismatches statically.
There's no way to know, just by looking at the code, whether the
omission is a mistake or deliberate and required. Enlisting the
compiler to flag these cases is as likely to yield false positives as
it is likely to point out a real mistake. Ideally, the code authors
should have either explicitly written all the values, or added
assertions or comments to explain the intent if they don't. But in
practice, this seldom if ever happens, and when someone else reads the
code they didn't write, they cannot always know which is which, and
neither can the compiler.
So I very much doubt these techniques will make our situation
significantly better, if at all.
> >> For these switch statements, use "switch (+E)" instead of "switch (E)".
> >> This pacifies GCC and clearly signals to the reader that the switch's
> >> cases are not intended to exhaust the enum. A "switch (E)" must list all
> >> the enum values; a "switch (+E)" need not do so. A reasonable guideline
> >
> > The above seems to say that "+E" is different from "E" in ways that
> > the compiler knows about. So I'm asking where is this special meaning
> > documented
>
> It is more than merely documented; it's been common practice for years.
> For example, given enum W {X,Y,Z} the type of an expression like X+1 has
> been int (not enum W) ever since enums were standardized in the C89
> standard.
So basically the plus sign converts the enum to an int, and thus shuts
up the compiler warnings? If so, why not use an explicit cast -- it
should at least be more clear to more people.
> For documentation chapter and verse, please see C23 §6.5.4.3 ¶2, which
> says that the type of +E is like that of -E: the type is E's type after
> integer promotions.
And which doesn't mention "enum" even once.
> Also please see C23 §6.3.1.1 ¶1–2, which says that
> int is the type of these Emacs enums after integer promotion.
Which also don't mention "enum".
> So, when E is one of these enums, the type of +E (and of -E) is int.
How many people you envision to be aware of the meaning of this
trickery? When I see a unary plus sign in code I consider it strange
formatting at best, a mistake at worst. I wouldn't want our code to
use this if it can be avoided, definitely not without comments.
> > I don't think I see how these changes improve checking and make the
> > code easier to read. For me, the "+E" thing is an obstacle to
> > negotiate; I'm sure others will also stumble on that.
>
> If necessary we can package "+E" inside an inline identity function.
Wouldn't a cast (preferably followed by a comment) do the job? If so,
I prefer to use an explicit cast.
> > If you really consider this long list of values more readable than the
> > original code, then I guess we disagree on what is and isn't readable.
>
> Oh, that long list was in some sense a misfire, as the patch did two
> things where I suppose it should have done one. First, the patch
> improved the runtime checkcing for invalid values, something that can
> and should be done independently of what we do about -Wswitch-enum.
> Second, the patch pacified -Wswitch-enum.
There are no invalid values in that place, by definition. The code
checks for invalid bidi types elsewhere, where it needs that, by using
bidi_check_type.
> I fixed this misfire by splitting the patch into two parts, which I'm
> attaching. The first attached patch improves the runtime checking
> without changing the -Wswitch-enum style, and I installed that on
> master. The second attached patch, which I have not installed, is the
> -Wswitch-enum change proper.
>
> In this example, pacifying -Wswitch-enum helped find code where Emacs's
> internal runtime checking was missing some invalid values.
Which code was that?
> diff --git a/src/bidi.c b/src/bidi.c
> index d8754e2db73..fd0bebb85e0 100644
> --- a/src/bidi.c
> +++ b/src/bidi.c
> @@ -282,12 +282,6 @@ bidi_get_type (int ch, bidi_dir_t override)
> emacs_abort ();
>
> default_type = (bidi_type_t) XFIXNUM (CHAR_TABLE_REF (bidi_type_table, ch));
> - /* Every valid character code, even those that are unassigned by the
> - UCD, have some bidi-class property, according to
> - DerivedBidiClass.txt file. Therefore, if we ever get UNKNOWN_BT
> - (= zero) code from CHAR_TABLE_REF, that's a bug. */
> - if (default_type == UNKNOWN_BT)
> - emacs_abort ();
>
> switch (default_type)
> {
> @@ -303,13 +297,26 @@ bidi_get_type (int ch, bidi_dir_t override)
> case FSI:
> case PDI:
> return default_type;
> - default:
> +
> + case STRONG_L: case STRONG_R:
> + case WEAK_EN: case WEAK_AN:
> + case STRONG_AL:
> + case WEAK_ES: case WEAK_ET: case WEAK_CS: case WEAK_NSM:
> + case NEUTRAL_S: case NEUTRAL_WS: case NEUTRAL_ON:
> if (override == L2R)
> return STRONG_L;
> else if (override == R2L)
> return STRONG_R;
> else
> return default_type;
> +
> + case UNKNOWN_BT:
> + default:
> + /* Every valid character code, even those unassigned by the UCD,
> + have some bidi-class property, according to DerivedBidiClass.txt.
> + Therefore, if we ever get UNKNOWN_BT (= zero) or some unknown
> + code from CHAR_TABLE_REF, that's a bug. */
> + emacs_abort ();
> }
> }
This change is for the worse, sorry. The test for values outside of
bidi_type_t is done elsewhere, as I explained, and the explicit list
of types whose directionality is overridden makes the code less
future-proof.
So I've reverted that commit.
> * src/bidi.c (characters, bidi_find_bracket_pairs)
> (bidi_resolve_brackets, bidi_resolve_neutral):
> Use ‘switch (+E)’ to indicate that it’s intended that we not
> enumerate all the enum values.
I don't understand why we need to potentially obfuscate our code just
to indicate that not all the enum values are explicitly mentioned.
Would a comment to that effect do the same? In fact, there are
already comments there, like this one:
> - switch (prev_type)
> + switch (+prev_type)
> {
> case RLI: /* X5a */
"X5a" is a reference to a section in the UBA description, where the
interested reader can find the details which will explain why only
some values are mentioned. Why is that worse than the sign trick?
> Remove ‘default: break;’ cases that are not now needed to pacify GCC.
They were there not for pacifying GCC, they were an important part of
the code. For example, this:
> @@ -2204,9 +2204,6 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
> bidi_check_type (bidi_it->type_after_wn);
> type = WEAK_BN; /* X9/Retaining */
> break;
> - default:
> - /* Nothing. */
> - break;
is there because no other characters neither start nor stop explicit
embeddings (see the UBA sections to which the comments refer). I
didn't write the "Nothing" comment there because I didn't trust the
reader to know what "default: break;" means. Why would you assume
that this default case could be removed without any adverse effects?
So all in all, I think these changes in the particular case of bidi.c
don't improve our code. I realize that it is easier for you (as it is
for every one of us) to read the code you yourself wrote than to read
the code of someone else, but that doesn't mean changing the code to
match your preferences is necessarily a change for the better. E.g.,
it is the opposite for me.
I'm not saying that there are no places in Emacs where similar changes
could help, but a general rule of using the cryptic "+E" everywhere
where not all the enum values are mentioned is not something I agree
to.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-04 21:23 ` Paul Eggert
2025-02-05 13:05 ` Eli Zaretskii
@ 2025-02-05 18:10 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-05 19:42 ` Paul Eggert
1 sibling, 1 reply; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-05 18:10 UTC (permalink / raw)
To: Paul Eggert; +Cc: Eli Zaretskii, 75964, stefankangas
"Paul Eggert" <eggert@cs.ucla.edu> writes:
> On 2/3/25 04:08, Eli Zaretskii wrote:
>>> From: Paul Eggert <eggert@cs.ucla.edu>
>>> The main point is to catch more potential inadvertent omissions of "case
>>> X:" in a "switch (E)" where E's type is an enum containing X. etags.c,
>>> like the rest of Emacs, currently uses one style to do this; the
>>> proposed style would be better at catching these mistakes.
>>
>> And how do the proposed changes achieve that goal?
>
> With an enum expression E and code like this:
>
> switch (E) { case A: ...; case B: ...; }
>
> there is currently no compile-time diagnostic for mismatches between the
> type and the code when the enum type also has a value C, either because
> the programmer forgot to handle case C when the switch was written, or
> because the enum type was changed and the programmer forgot to check all
> uses of the enum.
Sorry this got long. I think it's worth it to do this, but I don't
think a redundant + operator is a good way to avoid the warning, sorry.
I'm very confused here. If you mean code like this:
enum ABC { A, B, C, };
int sw(enum ABC abc)
{
switch (abc)
{
case A: return 1;
case B: return 2;
}
}
gcc -Wswitch will warn about it.
If you mean code like this:
enum ABC { A, B, C, };
int sw(enum ABC abc)
{
switch (abc)
{
case A: return 1;
case B: return 2;
default: return -1;
}
}
gcc -Wswitch-enum will warn about it, but gcc -Wswitch won't.
> Mismatches like these are all too common and can lead to user-visible
> bugs. It's a win to detect these mismatches statically.
The problem is that we lose the ability to abbreviate switch statements
where we know "default" covers both enumerated cases and non-enumerated
ones. I thought this was rare enough to avoid warning about those
switches using a #pragma, but it's more common than that.
The current GCC behavior of treating a switch statement as
non-enumerated if the control expression isn't of enum type leads to
false negatives, and I'd like to change it. Relying on it as a way to
disable warnings using the switch (+x) idiom seems unwise to me for that
reason, because we will then permanently lose those important warnings.
For example, there are currently two instances of switch (XFIXNUM (...))
in my Emacs tree, and I'm responsible for only one of them.
>>> For these switch statements, use "switch (+E)" instead of "switch (E)".
>>> This pacifies GCC and clearly signals to the reader that the switch's
>>> cases are not intended to exhaust the enum. A "switch (E)" must list all
>>> the enum values; a "switch (+E)" need not do so. A reasonable guideline
I'm not sure whether you're using "+e" (lower-case, because it's a
variable, right?) as an idiom to be recognized by the compiler here or
because the compiler will assign it to a different type from e. While
the compiler must generate the same code for switch ((int)e) and switch
(+e) (and switch (e) except in the most unlikely of cases), there is no
requirement for it to generate the same warnings.
So we shouldn't let C type coercion rules guide us here.
> Yes, and that's a plus for +E: you don't have to change the code much.
> In that sense it's better than Pip Cet's earlier proposal.
I agree that adding a back-door to get back to abbreviated switch
statements where "default" covers enumerated cases is a good thing.
(Well, I don't, see below; I just think resistance to -Wswitch-enum in
the absence of a readable and useful back-door is too great to be worth
it).
But switch (+e) is not a good one, not least because it appears at the
very beginning of the switch statement, rather than near the default
label where it's useful to the human reader.
The situation is analogous to the now-required fall-through labelling of
switch statements? That also happens near the label, and an initial hack
could just treat a fall-through default: statement as covering more enum
cases, while one without a fall-through is limited to the non-enum
cases...
In fact, given that we almost always want to have a default case which
is eassume(0), it may make more sense to explicitly enable -Wswitch-enum
warnings by marking the default label as applying only to the
"paradoxical" case that the enum variable's value isn't in the enum.
switch (e)
{
case A:
case B:
return 1;
default __attribute__((impossible)):
eassume (0);
}
would warn, while
switch (e)
{
case A:
case B:
return 1;
default:
return 2;
}
wouldn't.
This clearly needs more thought, particularly since the support for
label attributes in GCC isn't as nice as it could be. I don't know the
GCC source code well enough to come up with a quick hack here.
But since macros are also considered bad form (how else are we supposed
to use GCC attributes?), I don't know how to do it at all.
Of course if all we care about is the occasional forgotten case, the
easy solution is to have a threshold heuristic: count the explicit cases
C and the possible cases N, and warn if C > N - 4 && C > 3 && C < N :-)
>>> + case NEUTRAL_ON: case NEUTRAL_S: case NEUTRAL_WS:
>>> + case STRONG_AL: case STRONG_L: case STRONG_R:
>>> + case WEAK_AN: case WEAK_CS: case WEAK_EN: case WEAK_ES: case WEAK_ET: case WEAK_NSM:
>>> if (override == L2R)
>>> return STRONG_L;
>>> else if (override == R2L)
As a very tangential remark, one of the great problems with simply
enabling -Wswitch-enum is that someone might list extra case labels in
random order, or even several unrelated ones on one line. That appears
to have happened here.
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-05 13:05 ` Eli Zaretskii
@ 2025-02-05 19:20 ` Paul Eggert
2025-02-05 22:20 ` Stefan Kangas
2025-02-06 7:41 ` Eli Zaretskii
0 siblings, 2 replies; 74+ messages in thread
From: Paul Eggert @ 2025-02-05 19:20 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: pipcet, 75964, stefankangas
[-- Attachment #1: Type: text/plain, Size: 5386 bytes --]
On 2025-02-05 05:05, Eli Zaretskii wrote:
> There's no way to know, just by looking at the code, whether the
> omission is a mistake or deliberate and required.
Which is exactly why these sorts of patches, if done right, are a good
idea. They make it clear to the compiler and the reader whether these
omission are deliberate.
> I very much doubt these techniques will make our situation
> significantly better, if at all.
Admittedly Emacs has more serious bugs than enum mismatches. However,
checking these mismatches can help find mistakes or help clarify code.
> So basically the plus sign converts the enum to an int, and thus shuts
> up the compiler warnings? If so, why not use an explicit cast
A cast like ((int) E) is too powerful in C. For example, it works even
if E is a pointer, or is floating point. That would introduce more
possibilities for mistakes than +E does. When possible (as is the case
here) we should avoid using casts.
>> For documentation chapter and verse, please see C23 §6.5.4.3 ¶2, which
>> says that the type of +E is like that of -E: the type is E's type after
>> integer promotions.
>
> And which doesn't mention "enum" even once.
It says that the integer promotions are performed. The Emacs enums
promote to int, as shown below.
>> Also please see C23 §6.3.1.1 ¶1–2, which says that
>> int is the type of these Emacs enums after integer promotion.
>
> Which also don't mention "enum".
No, it says "The rank of any enumerated type shall equal the rank of the
compatible integer type". For Emacs's enums, that type is 'int'.
>> So, when E is one of these enums, the type of +E (and of -E) is int.
>
> How many people you envision to be aware of the meaning of this
> trickery?
It's not trickery and everybody who counts will know it. You now know
it, I know it, and Emacs already uses it elsewhere.
If you prefer, we can package it inside a macro and put a comment on the
macro, to document it more explicitly. Something like this, perhaps:
/* The value of E, after the usual integer promotions.
This is safer than a cast or inline function,
as it does only integer promotions.
"switch (promote (E))" pacifies gcc -Wswitch-enum
when some enum values are deliberately omitted from the cases.
*/
#define promote(E) (+ (E))
> Wouldn't a cast (preferably followed by a comment) do the job?
Not as well, for reasons discussed above.
> There are no invalid values in that place, by definition.
Oh, I thought the code was worrying about something like uni-bidi.el
being corrupted and containing invalid data. If that sort of thing is
impossible then you're right, there should be no need for an extra
runtime test.
But in that case, why does bidi_get_type have a runtime test for
UNKNOWN_BT? Shouldn't that also be impossible?
It would help the reader to explain why UNKNOWN_BT needs to be checked
for, but non-enum values need not be. That could be put into the comment.
> The code
> checks for invalid bidi types elsewhere, where it needs that, by using
> bidi_check_type.
This patch was to bidi_check_type itself, not to its callers.
Do you mean that bidi_check_type's callers all check for invalid bidi
types (i.e., types not listed under bidi_type_t)? Can you give an
example of that? I'm not following the logic here.
>> In this example, pacifying -Wswitch-enum helped find code where Emacs's
>> internal runtime checking was missing some invalid values.
>
> Which code was that?
Currently the code does this:
default_type = (bidi_type_t) XFIXNUM (CHAR_TABLE_REF
(bidi_type_table, ch));
Suppose 'default_type' at this point has the value 100, because
uni-bidi.el was corrupted or something like that. Then the next statement:
if (default_type == UNKNOWN_BT)
emacs_abort ();
does not abort because UNKNOWN_BT is 0, not 100. And the following
'switch (default_type)' statement merely causes bidi_get_type to return
100, a value that is not in the bidi_type_t enum that bidi_get_type is
declared to return. Surely that is problematic.
>> - switch (prev_type)
>> + switch (+prev_type)
>> {
>> case RLI: /* X5a */
>
> "X5a" is a reference to a section in the UBA description, where the
> interested reader can find the details which will explain why only
> some values are mentioned. Why is that worse...?
It's not worse. "X5a" is a useful comment and should be left in, which
is what the patch did. There's no implication in the patch that "X5a" is
worse.
>> Remove ‘default: break;’ cases that are not now needed to pacify GCC.
>
> They were there not for pacifying GCC, they were an important part of
> the code.
I must confess that the comment in:
default:
/* Nothing. */
break;
conveyed no useful information to me because "default: break;" obviously
does nothing and is equivalent to omitting the default case entirely. So
to me, the comment read like the comment in "i++; /* Add one to I. */".
But if these "default: break;"s are important for style let's leave them
in. Proposed patch to master attached. This pacifies -Wswitch-enum
without attempting to deal with UNKNOWN_BT issue, and without removing
any "default: break;"s.
[-- Attachment #2: 0001-Pacify-gcc-Wswitch-enum-in-bidi.c.patch --]
[-- Type: text/x-patch, Size: 2231 bytes --]
From 6e4f1f628689aa1e38ca112adc7eeb0400ce3e78 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Wed, 5 Feb 2025 11:06:40 -0800
Subject: [PATCH] Pacify gcc -Wswitch-enum in bidi.c
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* src/bidi.c (bidi_get_type, bidi_resolve_explicit)
(bidi_find_bracket_pairs, bidi_resolve_brackets)
(bidi_resolve_neutral): Use ‘switch (+E)’ to indicate that it’s
intended that we not enumerate all the enum values.
---
src/bidi.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/bidi.c b/src/bidi.c
index d8754e2db73..2c0a09d6210 100644
--- a/src/bidi.c
+++ b/src/bidi.c
@@ -289,7 +289,7 @@ bidi_get_type (int ch, bidi_dir_t override)
if (default_type == UNKNOWN_BT)
emacs_abort ();
- switch (default_type)
+ switch (+default_type)
{
case WEAK_BN:
case NEUTRAL_B:
@@ -2010,7 +2010,7 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
embedding level of the _following_ characters, so we must
first look at the type of the previous character to support
that. */
- switch (prev_type)
+ switch (+prev_type)
{
case RLI: /* X5a */
if (current_level < BIDI_MAXDEPTH
@@ -2074,7 +2074,7 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
bidi_it->type_after_wn = UNKNOWN_BT;
- switch (type)
+ switch (+type)
{
case RLE: /* X2 */
case RLO: /* X4 */
@@ -2707,7 +2707,7 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it)
/* Whenever we see a strong type, update the flags of
all the slots on the stack. */
- switch (bidi_it->type)
+ switch (+bidi_it->type)
{
case STRONG_L:
flag = ((embedding_level & 1) == 0
@@ -2979,7 +2979,7 @@ bidi_resolve_brackets (struct bidi_it *bidi_it)
if (prev_type_for_neutral == UNKNOWN_BT)
prev_type_for_neutral = embedding_type;
- switch (prev_type_for_neutral)
+ switch (+prev_type_for_neutral)
{
case STRONG_R:
case WEAK_EN:
@@ -3175,7 +3175,7 @@ bidi_resolve_neutral (struct bidi_it *bidi_it)
}
else
{
- switch (type)
+ switch (+type)
{
case STRONG_L:
case STRONG_R:
--
2.45.2
^ permalink raw reply related [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-05 18:10 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-02-05 19:42 ` Paul Eggert
2025-02-05 20:02 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 1 reply; 74+ messages in thread
From: Paul Eggert @ 2025-02-05 19:42 UTC (permalink / raw)
To: Pip Cet; +Cc: Eli Zaretskii, 75964, stefankangas
On 2025-02-05 10:10, Pip Cet wrote:
> "Paul Eggert" <eggert@cs.ucla.edu> writes:
>> With an enum expression E and code like this:
>>
>> switch (E) { case A: ...; case B: ...; }
>>
>> there is currently no compile-time diagnostic for mismatches between the
>> type and the code when the enum type also has a value C
> gcc -Wswitch-enum will warn about it, but gcc -Wswitch won't.
Oh yes, my outline should have said "switch (E) { case A: ...; case B:
...; default; }".
> The current GCC behavior of treating a switch statement as
> non-enumerated if the control expression isn't of enum type leads to
> false negatives, and I'd like to change it. Relying on it as a way to
> disable warnings using the switch (+x) idiom seems unwise to me for that
> reason, because we will then permanently lose those important warnings.
My little proposal (and it is a little one) works better with GCC as it
is now. If GCC is improved, we can change the code to deal with the
improved version. It wouldn't be the first time this sort of thing has
happened.
> I'm not sure whether you're using "+e" (lower-case, because it's a
> variable, right?)
It's an arbitrary expression E. The "+E" is abstract syntax meaning "use
the unary + operator on E". Parenthesize E if necessary.
> While
> the compiler must generate the same code for switch ((int)e) and switch
> (+e) (and switch (e) except in the most unlikely of cases), there is no
> requirement for it to generate the same warnings.
Yes, there is no requirement for a compiler to generate these warnings
and in theory the next version of GCC could stop generating all such
warnings. That's not the issue, though. The general rule of thumb for
--enable-gcc-warnings diagnostics is: what does the latest stable
version of GCC do? We typically don't have time to worry even about
older GCC versions, much less arbitrary hypothetical future ones.
> switch (+e) is not a good one, not least because it appears at the
> very beginning of the switch statement, rather than near the default
> label where it's useful to the human reader.
If we want something better, we'll have to change GCC. What I've
proposed works now, and is an improvement over what Emacs does now. I
cheerfully admit it's not as good as what an improved GCC could do. One
thing at a time.
>>>> + case NEUTRAL_ON: case NEUTRAL_S: case NEUTRAL_WS:
>>>> + case STRONG_AL: case STRONG_L: case STRONG_R:
>>>> + case WEAK_AN: case WEAK_CS: case WEAK_EN: case WEAK_ES: case WEAK_ET: case WEAK_NSM:
>>>> if (override == L2R)
>>>> return STRONG_L;
>>>> else if (override == R2L)
>
> As a very tangential remark, one of the great problems with simply
> enabling -Wswitch-enum is that someone might list extra case labels in
> random order, or even several unrelated ones on one line. That appears
> to have happened here.
I listed them in the same order that the enum declaration does. If you'd
prefer alphabetic order we could do that. It's no big deal.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-05 19:42 ` Paul Eggert
@ 2025-02-05 20:02 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 0 replies; 74+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-02-05 20:02 UTC (permalink / raw)
To: Paul Eggert; +Cc: Eli Zaretskii, 75964, stefankangas
"Paul Eggert" <eggert@cs.ucla.edu> writes:
> On 2025-02-05 10:10, Pip Cet wrote:
>> "Paul Eggert" <eggert@cs.ucla.edu> writes:
>>> With an enum expression E and code like this:
>>>
>>> switch (E) { case A: ...; case B: ...; }
>>>
>>> there is currently no compile-time diagnostic for mismatches between the
>>> type and the code when the enum type also has a value C
>
>> gcc -Wswitch-enum will warn about it, but gcc -Wswitch won't.
>
> Oh yes, my outline should have said "switch (E) { case A: ...; case B:
> ...; default; }".
Well, as it turns out, that wasn't the only thing I was confused about :-)
>> The current GCC behavior of treating a switch statement as
>> non-enumerated if the control expression isn't of enum type leads to
>> false negatives, and I'd like to change it. Relying on it as a way to
>> disable warnings using the switch (+x) idiom seems unwise to me for that
>> reason, because we will then permanently lose those important warnings.
>
> My little proposal (and it is a little one) works better with GCC as it
> is now. If GCC is improved, we can change the code to deal with the
Sorry. I totally missed that point!
I think if we want to do something with GCC now, your proposal seems
best, then.
Thanks!
Pip
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-05 19:20 ` Paul Eggert
@ 2025-02-05 22:20 ` Stefan Kangas
2025-02-06 8:17 ` Eli Zaretskii
2025-02-06 7:41 ` Eli Zaretskii
1 sibling, 1 reply; 74+ messages in thread
From: Stefan Kangas @ 2025-02-05 22:20 UTC (permalink / raw)
To: Paul Eggert, Eli Zaretskii; +Cc: pipcet, 75964
Paul Eggert <eggert@cs.ucla.edu> writes:
>> I very much doubt these techniques will make our situation
>> significantly better, if at all.
>
> Admittedly Emacs has more serious bugs than enum mismatches. However,
> checking these mismatches can help find mistakes or help clarify code.
We had Bug#75712, for example, which I believe Pip Cet found by enabling
-Wswitch-enum. It would be nice to catch such bugs statically.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-05 19:20 ` Paul Eggert
2025-02-05 22:20 ` Stefan Kangas
@ 2025-02-06 7:41 ` Eli Zaretskii
1 sibling, 0 replies; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-06 7:41 UTC (permalink / raw)
To: Paul Eggert; +Cc: pipcet, 75964, stefankangas
> Date: Wed, 5 Feb 2025 11:20:47 -0800
> Cc: pipcet@protonmail.com, 75964@debbugs.gnu.org, stefankangas@gmail.com
> From: Paul Eggert <eggert@cs.ucla.edu>
>
> > There's no way to know, just by looking at the code, whether the
> > omission is a mistake or deliberate and required.
>
> Which is exactly why these sorts of patches, if done right, are a good
> idea. They make it clear to the compiler and the reader whether these
> omission are deliberate.
My point is that it is not easy, to say the least, "to do it right"
when the code was written by someone else, especially if it is complex
(etags.c is a good case in point). This is what we are discussing, or
at least this is a part of our discussion; if you are talking about
guidelines for future code writers, I will probably agree, but will
point out that there's a non-vanishing probability that quite a few
contributors will not follow such guidelines, or maybe are even unable
to.
> > I very much doubt these techniques will make our situation
> > significantly better, if at all.
>
> Admittedly Emacs has more serious bugs than enum mismatches. However,
> checking these mismatches can help find mistakes or help clarify code.
Where it's easy, and the code's intent is clear and relatively simple,
I agree. But we should avoid blindly rewriting each and every switch
and enum along these lines, especially where the code is NOT simple
and clear, because there the risk of introducing problems and making
the code harder to read and understand outweighs the small gains from
these changes.
> > So basically the plus sign converts the enum to an int, and thus shuts
> > up the compiler warnings? If so, why not use an explicit cast
>
> A cast like ((int) E) is too powerful in C. For example, it works even
> if E is a pointer, or is floating point.
Yes, but such casts are easy to detect when reviewing code, and we
should reject such type-casts in our code, except in rare places where
they are a must (imposed by restrictions of external APIs and data
types).
> That would introduce more possibilities for mistakes than +E does.
I doubt that. The advantage is that the code is much less surprising.
> When possible (as is the case here) we should avoid using casts.
I agree, but I think this is one of the cases where we could use it.
I would even agree to using
switch (E + 0)
although I suspect that some GCC warning will flag it, and if it
doesn't today, it will probably do so in some non-t-distant future.
But even that is easier on the code reader that +E.
> >> For documentation chapter and verse, please see C23 §6.5.4.3 ¶2, which
> >> says that the type of +E is like that of -E: the type is E's type after
> >> integer promotions.
> >
> > And which doesn't mention "enum" even once.
>
> It says that the integer promotions are performed. The Emacs enums
> promote to int, as shown below.
My point is that this coding trick, or anything close to it, is never
mentioned explicitly, neither in the C Standard, nor in several other
documents on C that I looked in. E.g., in all of Gnulib it is used
exactly 3 times. So it should be quite clear that this technique is
not widely used, and thus is relatively unknown to people. And it
looks strange enough to raise brows. Which, from where I stand, is a
disadvantage.
> >> Also please see C23 §6.3.1.1 ¶1–2, which says that
> >> int is the type of these Emacs enums after integer promotion.
> >
> > Which also don't mention "enum".
>
> No, it says "The rank of any enumerated type shall equal the rank of the
> compatible integer type". For Emacs's enums, that type is 'int'.
I'm not saying that the C Standard doesn't cover this, or that it's
invalid C. I'm saying that a naïve reading of that text will never
explain the semantics of +E, let alone how it's related to the issue
of switch statements on enums.
> >> So, when E is one of these enums, the type of +E (and of -E) is int.
> >
> > How many people you envision to be aware of the meaning of this
> > trickery?
>
> It's not trickery and everybody who counts will know it. You now know
> it, I know it, and Emacs already uses it elsewhere.
Yes, I now know it, after asking many questions. We do not want to
use in our code techniques that require prolonged discussions to
understand them, at least not use them widely.
> If you prefer, we can package it inside a macro and put a comment on the
> macro, to document it more explicitly. Something like this, perhaps:
>
> /* The value of E, after the usual integer promotions.
> This is safer than a cast or inline function,
> as it does only integer promotions.
> "switch (promote (E))" pacifies gcc -Wswitch-enum
> when some enum values are deliberately omitted from the cases.
> */
> #define promote(E) (+ (E))
"Promote" is too general, IMO, and will still be a riddle. Something
like 'to_int' (with the commentary you propose) could be better,
because it says more clearly what is the intent here. People should
have at least mild chances to understand the code without consulting
the definition of every macro it uses, so the names of the macros
should express what they do well enough to allow such code reading.
> > There are no invalid values in that place, by definition.
>
> Oh, I thought the code was worrying about something like uni-bidi.el
> being corrupted and containing invalid data.
If we want to take into account the possibility of corrupted code,
then all bets are off, and this discussion is not useful. E.g., why
assume that uni-bidi is corrupted, but the code which checks validity
of bidi_type_t is not? uni-bidi is preloaded (via charprop.el) and is
either in the pdumper file or (if the build is with native
compilation) in a shared library loaded at startup, so it is basically
part of the Emacs binary. As long as we don't have protection from
corrupted Emacs binary, why should we seriously consider corruption in
preloaded Lisp files that are essential for basic Emacs operation?
> If that sort of thing is
> impossible then you're right, there should be no need for an extra
> runtime test.
>
> But in that case, why does bidi_get_type have a runtime test for
> UNKNOWN_BT? Shouldn't that also be impossible?
The comment there tries to explain that, but it is possible that it is
not detailed enough for someone who is not as "immersed" in this as I
am.
Each Unicode character has some bidi-class property, whose value is
never UNKNOWN_BT. The file DerivedBidiClass.txt in the Unicode
Character Database (UCD) says:
# Bidi Class (listing UnicodeData.txt, field 4: see UAX #44: https://www.unicode.org/reports/tr44/)
# Unlike other properties, unassigned code points in blocks
# reserved for right-to-left scripts are given either values R or AL,
# and unassigned code points in the Currency Symbols block are given the value ET.
# For details see the @missing lines below.
#
# The unassigned code points that default to BN have one of the following properties:
# Default_Ignorable_Code_Point
# Noncharacter_Code_Point
#
# For all other cases:
# All code points not explicitly listed for Bidi_Class
# have the value Left_To_Right (L).
Thus, the bidi-class code we get from bidi_type_table for any
character can never be UNKNOWN_BT (which is not a bidi type, just an
indication of "no bidi-class information"; the valid bidi types start
with STRONG_L). So getting UNKNOWN_BT there could mean one of the
following:
. the UnicodeData.txt file used for building Emacs was corrupted or
incorrectly interpreted by our scripts
. admin/unidata-gen.el has a bug or was incorrectly adjusted to
changes in Unicode
. there's a bug in chartab.c code that deals with uniprop char-tables
Moreover, all of the code in bidi.c is written under an implicit
assumption that each character has a bidi_type_t value that is _not_
UNKNOWN_BT; if that assumption breaks, I don't know what will happen,
but it's quite possible that Emacs will display garbage or crash or
cause the end of the world as we know it.
> It would help the reader to explain why UNKNOWN_BT needs to be checked
> for, but non-enum values need not be. That could be put into the comment.
OK, I will try to expand the comment. Is the explanation above
sufficient?
> > The code
> > checks for invalid bidi types elsewhere, where it needs that, by using
> > bidi_check_type.
>
> This patch was to bidi_check_type itself, not to its callers.
No, it was to bidi_get_type.
> Do you mean that bidi_check_type's callers all check for invalid bidi
> types (i.e., types not listed under bidi_type_t)? Can you give an
> example of that? I'm not following the logic here.
Just search bidi.c for the calls to bidi_check_type. You will see
that bidi_check_type is called in many places where some function can
return a bidi_type_t value, including after calling bidi_get_type, to
make sure we don't get values outside of the enumeration.
> >> In this example, pacifying -Wswitch-enum helped find code where Emacs's
> >> internal runtime checking was missing some invalid values.
> >
> > Which code was that?
>
> Currently the code does this:
>
> default_type = (bidi_type_t) XFIXNUM (CHAR_TABLE_REF
> (bidi_type_table, ch));
>
> Suppose 'default_type' at this point has the value 100, because
> uni-bidi.el was corrupted or something like that. Then the next statement:
>
> if (default_type == UNKNOWN_BT)
> emacs_abort ();
>
> does not abort because UNKNOWN_BT is 0, not 100. And the following
> 'switch (default_type)' statement merely causes bidi_get_type to return
> 100, a value that is not in the bidi_type_t enum that bidi_get_type is
> declared to return. Surely that is problematic.
I don't think it is useful to consider the case of corrupted uni-bidi,
see above. But if we want to call bidi_check_type (or something
similar) right after CHAR_TABLE_REF, I won't mind (but then we'd need
to abort, not eassert, and several calls to bidi_check_type elsewhere
in the file will become redundant).
> >> - switch (prev_type)
> >> + switch (+prev_type)
> >> {
> >> case RLI: /* X5a */
> >
> > "X5a" is a reference to a section in the UBA description, where the
> > interested reader can find the details which will explain why only
> > some values are mentioned. Why is that worse...?
>
> It's not worse. "X5a" is a useful comment and should be left in, which
> is what the patch did. There's no implication in the patch that "X5a" is
> worse.
Then why make the code harder to read by adding those unary plus signs
where the code and the references to the UBA should clearly explain
the intent? What does the unary plus sign gain us?
> But if these "default: break;"s are important for style let's leave them
> in. Proposed patch to master attached. This pacifies -Wswitch-enum
> without attempting to deal with UNKNOWN_BT issue, and without removing
> any "default: break;"s.
I don't mind installing it, subject to the above considerations of
making a macro with a mnemonic name for that purpose, but I would like
first to understand, in each case, what does adding that gain us in
terms of better code readability and future extensions.
Thanks.
^ permalink raw reply [flat|nested] 74+ messages in thread
* bug#75964: Switching the Emacs build to -Wswitch-enum in src/
2025-02-05 22:20 ` Stefan Kangas
@ 2025-02-06 8:17 ` Eli Zaretskii
0 siblings, 0 replies; 74+ messages in thread
From: Eli Zaretskii @ 2025-02-06 8:17 UTC (permalink / raw)
To: Stefan Kangas; +Cc: pipcet, eggert, 75964
> From: Stefan Kangas <stefankangas@gmail.com>
> Date: Wed, 5 Feb 2025 14:20:12 -0800
> Cc: pipcet@protonmail.com, 75964@debbugs.gnu.org
>
> Paul Eggert <eggert@cs.ucla.edu> writes:
>
> >> I very much doubt these techniques will make our situation
> >> significantly better, if at all.
> >
> > Admittedly Emacs has more serious bugs than enum mismatches. However,
> > checking these mismatches can help find mistakes or help clarify code.
>
> We had Bug#75712, for example, which I believe Pip Cet found by enabling
> -Wswitch-enum. It would be nice to catch such bugs statically.
It IMO is okay to use special GCC switches for hunting hidden bugs,
but that doesn't mean we need to use those switches by default,
especially if that requires us to make problematic changes to our
code. Please don't forget that many people who track the development
branches are not themselves Emacs developers.
We could have a special non-default configure option for adding
"noisy" warning options; many projects do that.
^ permalink raw reply [flat|nested] 74+ messages in thread
end of thread, other threads:[~2025-02-06 8:17 UTC | newest]
Thread overview: 74+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-31 9:39 bug#75964: Switching the Emacs build to -Wswitch-enum in src/ Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-31 11:05 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-31 18:30 ` Paul Eggert
2025-01-31 18:41 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-31 21:46 ` Paul Eggert
2025-02-01 9:02 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-01 18:18 ` Paul Eggert
2025-02-01 18:54 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 7:46 ` Paul Eggert
2025-02-02 8:21 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 8:31 ` Paul Eggert
2025-02-02 8:39 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 8:49 ` Eli Zaretskii
2025-02-02 9:26 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 10:34 ` Eli Zaretskii
2025-02-02 11:48 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 12:13 ` Eli Zaretskii
2025-02-02 12:50 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 13:21 ` Eli Zaretskii
2025-02-02 16:51 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 17:21 ` Eli Zaretskii
2025-02-02 17:30 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 13:40 ` Eli Zaretskii
2025-02-02 16:54 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 17:02 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 17:35 ` Eli Zaretskii
2025-02-03 3:01 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-03 3:52 ` Paul Eggert
2025-02-03 12:31 ` Eli Zaretskii
2025-02-03 9:01 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-03 11:08 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-03 11:31 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-03 20:47 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-03 21:15 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-04 12:24 ` Eli Zaretskii
2025-02-04 13:52 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-04 14:57 ` Eli Zaretskii
2025-02-04 13:58 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-04 14:57 ` Eli Zaretskii
2025-02-04 16:55 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-04 17:30 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-04 18:17 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-04 18:28 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-04 19:36 ` Eli Zaretskii
2025-02-04 20:45 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-05 12:15 ` Eli Zaretskii
2025-02-03 12:18 ` Eli Zaretskii
2025-02-02 18:27 ` Paul Eggert
2025-02-02 18:47 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-02 19:27 ` Eli Zaretskii
2025-02-02 21:43 ` Paul Eggert
2025-02-03 12:08 ` Eli Zaretskii
2025-02-03 12:24 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-03 13:13 ` Eli Zaretskii
2025-02-04 21:23 ` Paul Eggert
2025-02-05 13:05 ` Eli Zaretskii
2025-02-05 19:20 ` Paul Eggert
2025-02-05 22:20 ` Stefan Kangas
2025-02-06 8:17 ` Eli Zaretskii
2025-02-06 7:41 ` Eli Zaretskii
2025-02-05 18:10 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-02-05 19:42 ` Paul Eggert
2025-02-05 20:02 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-31 11:50 ` Eli Zaretskii
2025-01-31 12:15 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-31 12:24 ` Eli Zaretskii
2025-01-31 12:48 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-31 13:42 ` Eli Zaretskii
2025-01-31 14:25 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-31 15:00 ` Eli Zaretskii
2025-02-02 15:21 ` Stefan Kangas
2025-02-02 17:27 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-31 13:58 ` Robert Pluim
2025-01-31 14:11 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.