bug#81554: gcc useless cast warning in X11 files

Paul Eggert <[email protected]> Wed, 5 Aug 2026 23:54:05 -0500
Newsgroups gmane.emacs.bugs
Message-ID <[email protected]>
On 8/5/26 07:18, Eli Zaretskii wrote:
> Paul, WDYT about this?  Should we perhaps turn off this warning
> option?

For this case, probably better to pacify GCC than to disable the 
warning, as that makes it clearer when we really want strings to be 
writeable. I installed the attached patch onto Emacs master on savannah. 
Jonathan, please give it a try.
0001-Pacify-Wuseless-cast-with-Lucid-toolkit.patch (text/x-patch, 14.3 KB)
From 39f42a8248e1c6642907e4917a4ab547c00be930 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email protected]>
Date: Wed, 5 Aug 2026 23:44:57 -0500
Subject: [PATCH] Pacify -Wuseless-cast with Lucid toolkit
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Problem reported by Jonathan Mitchell (bug#81554).
Also, clean up the const situation elsewhere, e.g.,
with Motif toolkit, and with no X toolkit.
* configure.ac (_CONST_X_STRING): New macro, when using X11.
This causes most X11 include files to use ‘const char *’ for
readonly strings, rather than the ‘char *’ that was needed for K&R C.
* lwlib/lwlib-Xaw.c (xaw_generic_callback):
* lwlib/lwlib.c (lw_get_widget_value_for_widget)
(lw_internal_update_other_instances):
* lwlib/xlwmenu.c (openXftFont):
* src/xdisp.c (update_redisplay_ticks):
Use char const *, not char *, for readonly strings.
* lwlib/lwlib-Xm.c (update_one_menu_entry):
A cast is needed now that XtName returns char const *,
in a context where Motif wants char *, not String.
* lwlib/xlwmenu.c (openXftFont): Put newly allocated string
into its own local variable, so that main local can be char const *.
* src/emacs.c (android_emacs_init):
* src/xterm.c (x_term_init):
Pacify both -Wuseless-cast and -Wdiscarded-qualifiers.
* src/widget.c (resources, emacsFrameClassRec):
* src/xdisp.c (update_redisplay_ticks):
* src/xfns.c (x_window):
* src/xmenu.c (create_and_show_popup_menu):
* src/xterm.c (emacs_options) [USE_X_TOOLKIT]:
Omit now-useless casts.
* src/xfns.c (Fx_file_dialog):
Use char *, not String, for a mutable string.
---
 configure.ac      |  2 ++
 lwlib/lwlib-Xaw.c |  2 +-
 lwlib/lwlib-Xm.c  |  3 ++-
 lwlib/lwlib.c     |  4 ++--
 lwlib/xlwmenu.c   |  9 +++++----
 src/emacs.c       |  9 ++++++---
 src/widget.c      | 28 ++++++++++++++--------------
 src/xdisp.c       |  4 ++--
 src/xfns.c        | 10 +++++-----
 src/xmenu.c       |  2 +-
 src/xterm.c       | 32 +++++++++++++++++---------------
 11 files changed, 57 insertions(+), 48 deletions(-)

diff --git a/configure.ac b/configure.ac
index 897cc7870a1..5db3c1cc6a5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7277,6 +7277,8 @@ AC_DEFUN
 if test "${HAVE_X11}" = "yes" ; then
   AC_DEFINE([HAVE_X11], [1],
 	    [Define to 1 if you want to use version 11 of X windows.])
+  AC_DEFINE([_CONST_X_STRING], [1],
+    [Define to 1 for X11 headers to use the 'const' keyword of C89 or later.])
   LIBX_OTHER="\$(LIBXT) \$(LIBX_EXTRA)"
 else
   LIBX_OTHER=
diff --git a/lwlib/lwlib-Xaw.c b/lwlib/lwlib-Xaw.c
index 72e7b23c654..53aa8789dc9 100644
--- a/lwlib/lwlib-Xaw.c
+++ b/lwlib/lwlib-Xaw.c
@@ -762,7 +762,7 @@ xaw_generic_callback (Widget widget, XtPointer closure, XtPointer call_data)
      all instances of a button have the same call data. */
   {
     widget_value *val = instance->info->val->contents;
-    char *name = XtName (widget);
+    char const *name = XtName (widget);
     while (val)
       {
 	if (val->name && !strcmp (val->name, name))
diff --git a/lwlib/lwlib-Xm.c b/lwlib/lwlib-Xm.c
index 0eedaac3d12..1c70b5eeaee 100644
--- a/lwlib/lwlib-Xm.c
+++ b/lwlib/lwlib-Xm.c
@@ -685,7 +685,8 @@ update_one_menu_entry (widget_instance* instance,
 	    emacs_abort ();
 	  if (XmIsCascadeButton (widget_list[i]))
 	    {
-	      menu = XmCreatePulldownMenu (parent, XtName(widget), NULL, 0);
+	      menu = XmCreatePulldownMenu (parent, (char *) XtName(widget),
+					   NULL, 0);
 	      make_menu_in_widget (instance, menu, contents, 0);
 	      ac = 0;
 	      XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
diff --git a/lwlib/lwlib.c b/lwlib/lwlib.c
index 5fb6b5f7f49..76ab5c7259b 100644
--- a/lwlib/lwlib.c
+++ b/lwlib/lwlib.c
@@ -1048,7 +1048,7 @@ lw_get_all_values (LWLIB_ID id)
 widget_value*
 lw_get_widget_value_for_widget (widget_instance *instance, Widget w)
 {
-  char* name = XtName (w);
+  char const *name = XtName (w);
   widget_value* cur;
   for (cur = instance->info->val; cur; cur = cur->next)
     if (!strcmp (cur->name, name))
@@ -1070,7 +1070,7 @@ lw_internal_update_other_instances (Widget widget,
                                     XtPointer call_data)
 {
   widget_instance* instance = (widget_instance*)closure;
-  char* name = XtName (widget);
+  char const *name = XtName (widget);
   widget_info* info;
   widget_instance* cur;
   widget_value* val;
diff --git a/lwlib/xlwmenu.c b/lwlib/xlwmenu.c
index 9dc27929517..483dd6104f8 100644
--- a/lwlib/xlwmenu.c
+++ b/lwlib/xlwmenu.c
@@ -2033,7 +2033,8 @@ getDefaultXftFont (XlwMenuWidget mw)
 static int
 openXftFont (XlwMenuWidget mw)
 {
-  char *fname = mw->menu.fontName;
+  char const *fname = mw->menu.fontName;
+  char *fname_minus = NULL;
 
   mw->menu.xft_font = 0;
   mw->menu.default_face = fname && strcmp (fname, DEFAULT_FONTNAME) == 0;
@@ -2047,8 +2048,8 @@ openXftFont (XlwMenuWidget mw)
         --i;
       if (fname[i] == ' ')
         {
-          fname = xstrdup (mw->menu.fontName);
-          fname[i] = '-';
+	  fname = fname_minus = xstrdup (mw->menu.fontName);
+	  fname_minus[i] = '-';
         }
 
       mw->menu.xft_font = XftFontOpenName (XtDisplay (mw), screen, fname);
@@ -2056,7 +2057,7 @@ openXftFont (XlwMenuWidget mw)
 	mw->menu.xft_font = getDefaultXftFont (mw);
     }
 
-  if (fname != mw->menu.fontName) xfree (fname);
+  xfree (fname_minus);
 
   return mw->menu.xft_font != 0;
 }
diff --git a/src/emacs.c b/src/emacs.c
index 703ceec1045..95e0c170435 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -1707,7 +1707,8 @@ android_emacs_init (int argc, char **argv, char *dump_file)
       /* Convert --script to -scriptload, un-skip it, and sort again
 	 so that it will be handled in proper sequence.  */
       /* FIXME broken for --script=FILE - is that supposed to work?  */
-      argv[skip_args - 1] = (char *) "-scriptload";
+      static char const scriptload_option[] = "-scriptload";
+      argv[skip_args - 1] = (char *) scriptload_option;
       skip_args -= 2;
       sort_args (argc, argv);
     }
@@ -2112,7 +2113,8 @@ android_emacs_init (int argc, char **argv, char *dump_file)
 	    argv[count_before + 2] = displayname;
 	    argc++;
 	  }
-	argv[count_before + 1] = (char *) "-d";
+	static char const d_option[] = "-d";
+	argv[count_before + 1] = (char *) d_option;
       }
 #endif	/* HAVE_X_WINDOWS */
 
@@ -2130,7 +2132,8 @@ android_emacs_init (int argc, char **argv, char *dump_file)
 	noninteractive = 1;
 	no_site_lisp = 1;
 	/* This is picked up in startup.el.  */
-	argv[skip_args - 1] = (char *) "-scripteval";
+	static char const scripteval_option[] = "-scripteval";
+	argv[skip_args - 1] = (char *) scripteval_option;;
 	skip_args -= 1;
 	sort_args (argc, argv);
       }
diff --git a/src/widget.c b/src/widget.c
index 8aa67885047..b6fe0dca137 100644
--- a/src/widget.c
+++ b/src/widget.c
@@ -54,34 +54,34 @@
 #define offset(field) offsetof (EmacsFrameRec, emacs_frame.field)
 
 static XtResource resources[] = {
-  {(char *) XtNgeometry, (char *) XtCGeometry, XtRString, sizeof (String),
+  {XtNgeometry, XtCGeometry, XtRString, sizeof (String),
      offset (geometry), XtRString, (XtPointer) 0},
   {XtNiconic, XtCIconic, XtRBoolean, sizeof (Boolean),
      offset (iconic), XtRImmediate, (XtPointer) False},
 
-  {(char *) XtNemacsFrame, (char *) XtCEmacsFrame,
+  {XtNemacsFrame, XtCEmacsFrame,
      XtRPointer, sizeof (XtPointer),
      offset (frame), XtRImmediate, 0},
 
-  {(char *) XtNminibuffer, (char *) XtCMinibuffer, XtRInt, sizeof (int),
+  {XtNminibuffer, XtCMinibuffer, XtRInt, sizeof (int),
      offset (minibuffer), XtRImmediate, (XtPointer)0},
-  {(char *) XtNunsplittable, (char *) XtCUnsplittable,
+  {XtNunsplittable, XtCUnsplittable,
      XtRBoolean, sizeof (Boolean),
      offset (unsplittable), XtRImmediate, (XtPointer)0},
-  {(char *) XtNinternalBorderWidth, (char *) XtCInternalBorderWidth,
+  {XtNinternalBorderWidth, XtCInternalBorderWidth,
      XtRInt, sizeof (int),
      offset (internal_border_width), XtRImmediate, (XtPointer)4},
-  {(char *) XtNinterline, (char *) XtCInterline, XtRInt, sizeof (int),
+  {XtNinterline, XtCInterline, XtRInt, sizeof (int),
      offset (interline), XtRImmediate, (XtPointer)0},
-  {(char *) XtNforeground, (char *) XtCForeground, XtRPixel, sizeof (Pixel),
-     offset (foreground_pixel), XtRString, (char *) "XtDefaultForeground"},
-  {(char *) XtNcursorColor, (char *) XtCForeground, XtRPixel, sizeof (Pixel),
-     offset (cursor_color), XtRString, (char *) "XtDefaultForeground"},
-  {(char *) XtNbarCursor, (char *) XtCBarCursor, XtRBoolean, sizeof (Boolean),
+  {XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
+     offset (foreground_pixel), XtRString, "XtDefaultForeground"},
+  {XtNcursorColor, XtCForeground, XtRPixel, sizeof (Pixel),
+     offset (cursor_color), XtRString, "XtDefaultForeground"},
+  {XtNbarCursor, XtCBarCursor, XtRBoolean, sizeof (Boolean),
      offset (bar_cursor), XtRImmediate, (XtPointer)0},
-  {(char *) XtNvisualBell, (char *) XtCVisualBell, XtRBoolean, sizeof (Boolean),
+  {XtNvisualBell, XtCVisualBell, XtRBoolean, sizeof (Boolean),
      offset (visual_bell), XtRImmediate, (XtPointer)0},
-  {(char *) XtNbellVolume, (char *) XtCBellVolume, XtRInt, sizeof (int),
+  {XtNbellVolume, XtCBellVolume, XtRInt, sizeof (int),
      offset (bell_volume), XtRImmediate, (XtPointer)0},
 };
 
@@ -106,7 +106,7 @@ #define offset(field) offsetof (EmacsFrameRec, emacs_frame.field)
 static EmacsFrameClassRec emacsFrameClassRec = {
     { /* core fields */
     /* superclass		*/	0, /* filled in by emacsFrameClass */
-    /* class_name		*/	(char *) "EmacsFrame",
+    /* class_name		*/	"EmacsFrame",
     /* widget_size		*/	sizeof (EmacsFrameRec),
     /* class_initialize		*/	0,
     /* class_part_initialize	*/	0,
diff --git a/src/xdisp.c b/src/xdisp.c
index caea8e77a9d..6f44461f170 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -18571,12 +18571,12 @@ update_redisplay_ticks (int ticks, struct window *w)
 	 windows, not expected here) or nil (for pseudo-windows like
 	 the one used for the native tool bar).  */
       Lisp_Object contents = w ? w->contents : Qnil;
-      char *bufname =
+      char const *bufname =
 	NILP (contents)
 	? SSDATA (BVAR (current_buffer, name))
 	: (BUFFERP (contents)
 	   ? SSDATA (BVAR (XBUFFER (contents), name))
-	   : (char *) "<unknown>");
+	   : "<unknown>");
 
       windows_or_buffers_changed = 177;
       /* scrolling_window depends too much on the glyph matrices being
diff --git a/src/xfns.c b/src/xfns.c
index 0750a444e81..fdb8eaf7f84 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -4226,10 +4226,10 @@ x_window (struct frame *f, long window_prompting)
 
   ac = 0;
   XtSetArg (al[ac], XtNmappedWhenManaged, 0); ac++;
-  XtSetArg (al[ac], (char *) XtNshowGrip, 0); ac++;
-  XtSetArg (al[ac], (char *) XtNallowResize, 1); ac++;
-  XtSetArg (al[ac], (char *) XtNresizeToPreferred, 1); ac++;
-  XtSetArg (al[ac], (char *) XtNemacsFrame, f); ac++;
+  XtSetArg (al[ac], XtNshowGrip, 0); ac++;
+  XtSetArg (al[ac], XtNallowResize, 1); ac++;
+  XtSetArg (al[ac], XtNresizeToPreferred, 1); ac++;
+  XtSetArg (al[ac], XtNemacsFrame, f); ac++;
   XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
   XtSetArg (al[ac], XtNdepth, FRAME_DISPLAY_INFO (f)->n_planes); ac++;
   XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
@@ -9632,7 +9632,7 @@ DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0,
   if (result == XmCR_OK)
     {
       XmString text_string;
-      String data;
+      char *data;
 
       XtVaGetValues (dialog, XmNtextString, &text_string, NULL);
       XmStringGetLtoR (text_string, XmFONTLIST_DEFAULT_TAG, &data);
diff --git a/src/xmenu.c b/src/xmenu.c
index 35473f2db0e..467846cf62f 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -1795,7 +1795,7 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
       event->button = i;
 
   /* Don't allow any geometry request from the user.  */
-  XtSetArg (av[ac], (char *) XtNgeometry, 0); ac++;
+  XtSetArg (av[ac], XtNgeometry, 0); ac++;
   XtSetValues (menu, av, ac);
 
 #ifdef HAVE_XINPUT2
diff --git a/src/xterm.c b/src/xterm.c
index 549b5007f26..c9e7121692b 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -30455,21 +30455,21 @@ x_free_pixmap (struct frame *f, Emacs_Pixmap pixmap)
 
 #ifdef USE_X_TOOLKIT
 static XrmOptionDescRec emacs_options[] = {
-  {(char *) "-geometry", (char *) ".geometry", XrmoptionSepArg, NULL},
-  {(char *) "-iconic", (char *) ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
+  {"-geometry", ".geometry", XrmoptionSepArg, NULL},
+  {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
 
-  {(char *) "-internal-border-width",
-   (char *) "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
-  {(char *) "-ib", (char *) "*EmacsScreen.internalBorderWidth",
+  {"-internal-border-width",
+   "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
+  {"-ib", "*EmacsScreen.internalBorderWidth",
    XrmoptionSepArg, NULL},
-  {(char *) "-T", (char *) "*EmacsShell.title", XrmoptionSepArg, NULL},
-  {(char *) "-wn", (char *) "*EmacsShell.title", XrmoptionSepArg, NULL},
-  {(char *) "-title", (char *) "*EmacsShell.title", XrmoptionSepArg, NULL},
-  {(char *) "-iconname", (char *) "*EmacsShell.iconName",
+  {"-T", "*EmacsShell.title", XrmoptionSepArg, NULL},
+  {"-wn", "*EmacsShell.title", XrmoptionSepArg, NULL},
+  {"-title", "*EmacsShell.title", XrmoptionSepArg, NULL},
+  {"-iconname", "*EmacsShell.iconName",
    XrmoptionSepArg, NULL},
-  {(char *) "-in", (char *) "*EmacsShell.iconName", XrmoptionSepArg, NULL},
-  {(char *) "-mc", (char *) "*pointerColor", XrmoptionSepArg, NULL},
-  {(char *) "-cr", (char *) "*cursorColor", XrmoptionSepArg, NULL}
+  {"-in", "*EmacsShell.iconName", XrmoptionSepArg, NULL},
+  {"-mc", "*pointerColor", XrmoptionSepArg, NULL},
+  {"-cr", "*cursorColor", XrmoptionSepArg, NULL}
 };
 
 /* Whether atimer for Xt timeouts is activated or not.  */
@@ -30797,11 +30797,13 @@ #define NUM_ARGV 10
     int argc = 0;
     char *argv[3];
 
-    argv[0] = (char *) "";
+    static char const mt[] = "";
+    argv[0] = (char *) mt;
     argc = 1;
     if (xrm_option)
       {
-	argv[argc++] = (char *) "-xrm";
+	static char const xrmopt[] = "-xrm";
+	argv[argc++] = (char *) xrmopt;
 	argv[argc++] = xrm_option;
       }
     turn_on_atimers (false);
@@ -31612,7 +31614,7 @@ #define NUM_ARGV 10
     dpy = dpyinfo->display;
     d.addr = (XPointer) &dpy;
     d.size = sizeof (Display *);
-    fr.addr = (char *) XtDefaultFont;
+    fr.addr = XtDefaultFont;
     fr.size = sizeof (XtDefaultFont);
     to.size = sizeof (Font *);
     to.addr = (XPointer) &font;
-- 
2.55.0