Santiago Vila <[email protected]> writes:
> I received the report below from the Debian bug system.
>
> I see a recent commit from Paul Eggert regarding glibc 2.43,
> so I guess this is already known. Should I try to cherry-pick
> fixes from the git repo (and if so, which ones?) or maybe I can
> expect a new release of m4 soon?
There was some discussion on bug-gnulib about how to work around this
[1]. Paul said that Eric will make a new release soon for it [2], but
I've attatched the relevant Gnulib patch if you need it more urgently.
Or you can generate it in Gnulib using:
$ git diff df17f4f37ed3ca373d23ad42eae51122bdb96626^!
Collin
[1] https://lists.gnu.org/archive/html/bug-gnulib/2026-01/msg00211.html
[2] https://lists.gnu.org/archive/html/bug-gnulib/2026-01/msg00216.html
diff --git a/ChangeLog b/ChangeLog
index 4eadd88f12..1cfaf9e528 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,43 @@
+2025-11-23 Paul Eggert <[email protected]>
+
+ Port to C23 qualifier-generic fns like strchr
+ This ports Gnulib to strict C23 platforms that reject code
+ like ‘char *q = strchr (P, 'x');’ when P is a pointer to const,
+ because in C23 strchr is a qualifier-generic function so
+ strchr (P, 'x') returns char const *.
+ This patch does not attempt to do the following two things,
+ which might be useful in the future:
+ 1. When compiling on non-C23 platforms, check user code for
+ portability to platforms that define qualifier-generic functions.
+ 2. Port Gnulib to platforms that have qualifier-generic functions
+ not listed in the C23 standard, e.g., strchrnul. I don’t know
+ of any such platforms.
+ * lib/argp-help.c (argp_doc):
+ * lib/c-strstr.c (c_strstr):
+ * lib/dfa.c (comsubs):
+ * lib/mbschr.c (mbschr):
+ * lib/mbspbrk.c (mbspbrk):
+ * lib/mbsrchr.c (mbsrchr):
+ * lib/memchr2.c (memchr2):
+ * lib/string-desc.c (_sd_index):
+ * tests/test-bsearch.c (lib_bsearch):
+ * tests/test-memchr.c (lib_memchr):
+ * tests/test-wmemchr.c (lib_wmemchr):
+ Port to C23, where functions like strchr are qualifier-generic.
+ * lib/c++defs.h (_GL_FUNCDECL_SYS_NAME): New macro.
+ * lib/c++defs.h (_GL_FUNCDECL_SYS):
+ * lib/stdlib.in.h (bsearch):
+ Use it, to prevent C23 names like strchr from acting like macros.
+ * lib/string.in.h (memchr, strchr, strpbrk, strrchr):
+ Do not #undef when GNULIB_POSIXCHECK is defined, as this could
+ cause conforming C23 code to fail to conform. It’s not clear why
+ #undef is needed before others uses of _GL_WARN_ON_USE and
+ _GL_WARN_ON_USE_CXX; perhaps it was needed but isn’t any more?
+ But for now, limit the removal of #undef to these four functions
+ where #undeffing is clearly undesirable in C23.
+ * lib/wchar.in.h (wmemchr): Parenthesize function name in decl,
+ to prevent it from acting like a macro.
+
2025-11-20 Bruno Haible <[email protected]>
strnlen: Fix compilation error (regression 2025-11-18).
diff --git a/lib/argp-help.c b/lib/argp-help.c
index f742e1870f..5bf4d3aacf 100644
--- a/lib/argp-help.c
+++ b/lib/argp-help.c
@@ -1601,7 +1601,7 @@ argp_doc (const struct argp *argp, const struct argp_state *state,
if (doc)
{
- char *vt = strchr (doc, '\v');
+ char const *vt = strchr (doc, '\v');
inp_text = post ? (vt ? vt + 1 : NULL) : doc;
inp_text_limit = (!post && vt) ? (vt - doc) : 0;
}
diff --git a/lib/c++defs.h b/lib/c++defs.h
index b77979a325..7384457432 100644
--- a/lib/c++defs.h
+++ b/lib/c++defs.h
@@ -127,6 +127,16 @@
#define _GL_FUNCDECL_RPL_1(rpl_func,rettype,parameters,...) \
_GL_EXTERN_C_FUNC __VA_ARGS__ rettype rpl_func parameters
+/* _GL_FUNCDECL_SYS_NAME (func) expands to plain func if C++, and to
+ parenthsized func otherwise. Parenthesization is needed in C23 if
+ the function is like strchr and so is a qualifier-generic macro
+ that expands to something more complicated. */
+#ifdef __cplusplus
+# define _GL_FUNCDECL_SYS_NAME(func) func
+#else
+# define _GL_FUNCDECL_SYS_NAME(func) (func)
+#endif
+
/* _GL_FUNCDECL_SYS (func, rettype, parameters, [attributes]);
declares the system function, named func, with the given prototype,
consisting of return type, parameters, and attributes.
@@ -139,7 +149,7 @@
_GL_FUNCDECL_SYS (posix_openpt, int, (int flags), _GL_ATTRIBUTE_NODISCARD);
*/
#define _GL_FUNCDECL_SYS(func,rettype,parameters,...) \
- _GL_EXTERN_C_FUNC __VA_ARGS__ rettype func parameters
+ _GL_EXTERN_C_FUNC __VA_ARGS__ rettype _GL_FUNCDECL_SYS_NAME (func) parameters
/* _GL_CXXALIAS_RPL (func, rettype, parameters);
declares a C++ alias called GNULIB_NAMESPACE::func
diff --git a/lib/c-strstr.c b/lib/c-strstr.c
index 36ee9d29ca..660da96acd 100644
--- a/lib/c-strstr.c
+++ b/lib/c-strstr.c
@@ -28,5 +28,5 @@ c_strstr (const char *haystack, const char *needle)
{
/* POSIX says that strstr() interprets the strings as byte sequences, not
as character sequences in the current locale. */
- return strstr (haystack, needle);
+ return (char *) strstr (haystack, needle);
}
diff --git a/lib/dfa.c b/lib/dfa.c
index 34b7f8bf2d..11309ab36b 100644
--- a/lib/dfa.c
+++ b/lib/dfa.c
@@ -4050,7 +4050,7 @@ comsubs (char *left, char const *right)
for (char *lcp = left; *lcp != '\0'; lcp++)
{
idx_t len = 0;
- char *rcp = strchr (right, *lcp);
+ char const *rcp = strchr (right, *lcp);
while (rcp != NULL)
{
idx_t i;
diff --git a/lib/mbschr.c b/lib/mbschr.c
index c9e14b5baa..65821340df 100644
--- a/lib/mbschr.c
+++ b/lib/mbschr.c
@@ -65,5 +65,5 @@ mbschr (const char *string, int c)
return NULL;
}
else
- return strchr (string, c);
+ return (char *) strchr (string, c);
}
diff --git a/lib/mbspbrk.c b/lib/mbspbrk.c
index 3331d70e5c..974efe3a29 100644
--- a/lib/mbspbrk.c
+++ b/lib/mbspbrk.c
@@ -90,5 +90,5 @@ mbspbrk (const char *string, const char *accept)
return NULL;
}
else
- return strpbrk (string, accept);
+ return (char *) strpbrk (string, accept);
}
diff --git a/lib/mbsrchr.c b/lib/mbsrchr.c
index f1cd8dccaf..3defe676dd 100644
--- a/lib/mbsrchr.c
+++ b/lib/mbsrchr.c
@@ -64,5 +64,5 @@ mbsrchr (const char *string, int c)
return (char *) result;
}
else
- return strrchr (string, c);
+ return (char *) strrchr (string, c);
}
diff --git a/lib/memchr2.c b/lib/memchr2.c
index c6e7f4e9dc..8ad96500bd 100644
--- a/lib/memchr2.c
+++ b/lib/memchr2.c
@@ -55,7 +55,7 @@ memchr2 (void const *s, int c1_in, int c2_in, size_t n)
c2 = (unsigned char) c2_in;
if (c1 == c2)
- return memchr (s, c1, n);
+ return (void *) memchr (s, c1, n);
/* Handle the first few bytes by reading one byte at a time.
Do this until VOID_PTR is aligned on a longword boundary. */
diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h
index bef0aaaf92..fd0e1e0d29 100644
--- a/lib/stdlib.in.h
+++ b/lib/stdlib.in.h
@@ -224,9 +224,9 @@ _GL_INLINE_HEADER_BEGIN
/* Declarations for ISO C N3322. */
#if defined __GNUC__ && __GNUC__ >= 15 && !defined __clang__
-_GL_EXTERN_C void *bsearch (const void *__key,
- const void *__base, size_t __nmemb, size_t __size,
- int (*__compare) (const void *, const void *))
+_GL_EXTERN_C void *_GL_FUNCDECL_SYS_NAME (bsearch)
+ (const void *__key, const void *__base, size_t __nmemb, size_t __size,
+ int (*__compare) (const void *, const void *))
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3) _GL_ARG_NONNULL ((5));
_GL_EXTERN_C void qsort (void *__base, size_t __nmemb, size_t __size,
int (*__compare) (const void *, const void *))
diff --git a/lib/string-desc.c b/lib/string-desc.c
index 2d13a866b9..4113aba865 100644
--- a/lib/string-desc.c
+++ b/lib/string-desc.c
@@ -110,9 +110,9 @@ _sd_index (idx_t s_nbytes, const char *s_data, char c)
{
if (s_nbytes > 0)
{
- void *found = memchr (s_data, (unsigned char) c, s_nbytes);
+ char const *found = memchr (s_data, (unsigned char) c, s_nbytes);
if (found != NULL)
- return (char *) found - s_data;
+ return found - s_data;
}
return -1;
}
diff --git a/lib/string.in.h b/lib/string.in.h
index fdcdd21bed..8b56acfb51 100644
--- a/lib/string.in.h
+++ b/lib/string.in.h
@@ -409,7 +409,6 @@ _GL_CXXALIASWARN1 (memchr, void const *,
_GL_CXXALIASWARN (memchr);
# endif
#elif defined GNULIB_POSIXCHECK
-# undef memchr
/* Assume memchr is always declared. */
_GL_WARN_ON_USE (memchr, "memchr has platform-specific bugs - "
"use gnulib module memchr for portability" );
@@ -674,7 +673,6 @@ _GL_WARN_ON_USE (stpncpy, "stpncpy is unportable - "
#if defined GNULIB_POSIXCHECK
/* strchr() does not work with multibyte strings if the locale encoding is
GB18030 and the character to be searched is a digit. */
-# undef strchr
/* Assume strchr is always declared. */
_GL_WARN_ON_USE_CXX (strchr,
const char *, char *, (const char *, int),
@@ -981,7 +979,6 @@ _GL_CXXALIASWARN (strpbrk);
Even in this simple case, it does not work with multibyte strings if the
locale encoding is GB18030 and one of the characters to be searched is a
digit. */
-# undef strpbrk
_GL_WARN_ON_USE_CXX (strpbrk,
const char *, char *, (const char *, const char *),
"strpbrk cannot work correctly on character strings "
@@ -1011,7 +1008,6 @@ _GL_WARN_ON_USE (strspn, "strspn cannot work correctly on character strings "
#if defined GNULIB_POSIXCHECK
/* strrchr() does not work with multibyte strings if the locale encoding is
GB18030 and the character to be searched is a digit. */
-# undef strrchr
/* Assume strrchr is always declared. */
_GL_WARN_ON_USE_CXX (strrchr,
const char *, char *, (const char *, int),
diff --git a/lib/wchar.in.h b/lib/wchar.in.h
index ab602a2811..6be45155f3 100644
--- a/lib/wchar.in.h
+++ b/lib/wchar.in.h
@@ -301,7 +301,7 @@ _GL_EXTERN_C int wcsncmp (const wchar_t *__s1, const wchar_t *__s2, size_t __n)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
# ifndef __cplusplus
-_GL_EXTERN_C wchar_t *wmemchr (const wchar_t *__s, wchar_t __wc, size_t __n)
+_GL_EXTERN_C wchar_t *(wmemchr) (const wchar_t *__s, wchar_t __wc, size_t __n)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3);
# endif
_GL_EXTERN_C wchar_t *wmemset (wchar_t *__s, wchar_t __wc, size_t __n)
diff --git a/tests/test-bsearch.c b/tests/test-bsearch.c
index aad3a22807..2e9575cc41 100644
--- a/tests/test-bsearch.c
+++ b/tests/test-bsearch.c
@@ -26,7 +26,7 @@ static void *
lib_bsearch (void const *key, void const *base, size_t nel, size_t width,
int (*compar) (void const *, void const *))
{
- return bsearch (key, base, nel, width, compar);
+ return (void *) bsearch (key, base, nel, width, compar);
}
static void *(*volatile volatile_bsearch) (void const *, void const *, size_t,
size_t,
diff --git a/tests/test-memchr.c b/tests/test-memchr.c
index 02b882a975..ef04790f90 100644
--- a/tests/test-memchr.c
+++ b/tests/test-memchr.c
@@ -31,7 +31,7 @@ SIGNATURE_CHECK (memchr, void *, (void const *, int, size_t));
static void *
lib_memchr (void const *s, int c, size_t n)
{
- return memchr (s, c, n);
+ return (void *) memchr (s, c, n);
}
static void *(*volatile volatile_memchr) (void const *, int, size_t)
= lib_memchr;
diff --git a/tests/test-wmemchr.c b/tests/test-wmemchr.c
index c5e8ce541c..457ed76a9b 100644
--- a/tests/test-wmemchr.c
+++ b/tests/test-wmemchr.c
@@ -27,7 +27,7 @@
static wchar_t *
lib_wmemchr (wchar_t const *s, wchar_t wc, size_t n)
{
- return wmemchr (s, wc, n);
+ return (wchar_t *) wmemchr (s, wc, n);
}
static wchar_t *(*volatile volatile_wmemchr) (wchar_t const *, wchar_t, size_t)
= lib_wmemchr;