]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
tools: gnulib: fix build with latest glibc C23 changes
authorMichael Pratt <mcpratt@pm.me>
Sat, 18 Jul 2026 12:14:19 +0000 (08:14 -0400)
committerRobert Marko <robimarko@gmail.com>
Thu, 30 Jul 2026 17:40:44 +0000 (19:40 +0200)
Backport a patch that covers a build problem with latest glibc
being used as the host standard C library during tools build.

The C23 standard changes some functions that used to drop qualifiers
like "const" or "volatile" and are now forced to preserve them
in the return type based on the input type at all times.
Developers of glibc have responded by making these functions
into macros after they are declared with prototypes.
This is not compatible with the way gnulib is written,
so when the functions are redeclared in gnulib,
the preprocessor expands the _function name_ itself
as if it is a macro name, but not fully,
which results in unusual looking build errors,
e.g. the failed processing of keywords that were never written
and have no business being in a prototype, or,
as a keyword that is expected to be there and nearly guarenteed
to work but mysteriously is not working, displayed as:
"error: expected identifier or '(' before _____".

The backport patch introduces and implements a new macro
in order to prevent function names from being interpreted as macros,
by wrapping it in parentheses for C, or simply placing it back for C++
in the first stage of macro expansion which satisfies the goal
of no further expansion taking place during preprocessing.

Add an additional patch for the functions declared
in the fts header, as this bug also applies to them,
however, this was overlooked by upstream gnulib,
likely because the bug is not presenting as an error.

Yet another patch corrects the order between
specifiers and attributes in GCC syntax for header
lib/fts.in.h which can be blamed on an upstream commit.

Specifically, the throw() or noexcept() keywords
must be before attributes at the end of a declaration.
There are two headers, lib/cdefs.h and lib/getopt-ext.h
that already demonstrate the correct order which is very
strictly necessary in the latest version of GCC
when compiling C++ code, and acceptable for C code,
as the "__THROW" macro is simply another attribute in that case.

Added backport patch:
 - 400-c23-qualifier-generic.patch

Added pending patch:
 - 410-unmacro-fts-functions.patch
 - 450-attribute-specifier-order.patch

Ref: 80e5de158316 ("fts: Improve GCC 11 allocation-deallocation checking.") # gnulib.git
Reported-by: Aditya Nugraha <vortexilation@gmail.com>
Signed-off-by: Michael Pratt <mcpratt@pm.me>
Link: https://github.com/openwrt/openwrt/pull/24247
Signed-off-by: Robert Marko <robimarko@gmail.com>
tools/gnulib/patches/400-c23-qualifier-generic.patch [new file with mode: 0644]
tools/gnulib/patches/410-unmacro-fts-functions.patch [new file with mode: 0644]
tools/gnulib/patches/450-attribute-specifier-order.patch [new file with mode: 0644]

diff --git a/tools/gnulib/patches/400-c23-qualifier-generic.patch b/tools/gnulib/patches/400-c23-qualifier-generic.patch
new file mode 100644 (file)
index 0000000..d1f8b3f
--- /dev/null
@@ -0,0 +1,266 @@
+From df17f4f37ed3ca373d23ad42eae51122bdb96626 Mon Sep 17 00:00:00 2001
+From: Paul Eggert <eggert@cs.ucla.edu>
+Date: Sun, 23 Nov 2025 00:50:40 -0800
+Subject: [PATCH] Port to C23 qualifier-generic fns like strchr
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+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
+_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.
+---
+ ChangeLog            | 40 ++++++++++++++++++++++++++++++++++++++++
+ lib/argp-help.c      |  2 +-
+ lib/c++defs.h        | 12 +++++++++++-
+ lib/c-strstr.c       |  2 +-
+ lib/dfa.c            |  2 +-
+ lib/mbschr.c         |  2 +-
+ lib/mbspbrk.c        |  2 +-
+ lib/mbsrchr.c        |  2 +-
+ lib/memchr2.c        |  2 +-
+ lib/stdlib.in.h      |  6 +++---
+ lib/string-desc.c    |  4 ++--
+ lib/string.in.h      |  4 ----
+ lib/wchar.in.h       |  2 +-
+ tests/test-bsearch.c |  2 +-
+ tests/test-memchr.c  |  2 +-
+ tests/test-wmemchr.c |  2 +-
+ 16 files changed, 67 insertions(+), 21 deletions(-)
+
+--- a/lib/argp-help.c
++++ b/lib/argp-help.c
+@@ -1601,7 +1601,7 @@ argp_doc (const struct argp *argp, const
+   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;
+     }
+--- 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
+--- a/lib/c-strstr.c
++++ b/lib/c-strstr.c
+@@ -28,5 +28,5 @@ c_strstr (const char *haystack, const ch
+ {
+   /* 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);
+ }
+--- a/lib/dfa.c
++++ b/lib/dfa.c
+@@ -4069,7 +4069,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;
+--- 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);
+ }
+--- a/lib/mbspbrk.c
++++ b/lib/mbspbrk.c
+@@ -90,5 +90,5 @@ mbspbrk (const char *string, const char
+       return NULL;
+     }
+   else
+-    return strpbrk (string, accept);
++    return (char *) strpbrk (string, accept);
+ }
+--- 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);
+ }
+--- a/lib/memchr2.c
++++ b/lib/memchr2.c
+@@ -55,7 +55,7 @@ memchr2 (void const *s, int c1_in, int c
+   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.  */
+--- a/lib/stdlib.in.h
++++ b/lib/stdlib.in.h
+@@ -238,9 +238,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 *))
+--- a/lib/string-desc.c
++++ b/lib/string-desc.c
+@@ -113,9 +113,9 @@ _sd_index (idx_t s_nbytes, const char *s
+ {
+   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;
+ }
+--- a/lib/string.in.h
++++ b/lib/string.in.h
+@@ -403,7 +403,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_CXX (memchr,
+                      const void *, void *, (void const *, int, size_t),
+@@ -655,7 +654,6 @@ _GL_WARN_ON_USE (stpncpy, "stpncpy is un
+ #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),
+@@ -976,7 +974,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 "
+@@ -1006,7 +1003,6 @@ _GL_WARN_ON_USE (strspn, "strspn cannot
+ #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),
+--- a/lib/wchar.in.h
++++ b/lib/wchar.in.h
+@@ -316,7 +316,7 @@ _GL_EXTERN_C int wcsncmp (const wchar_t
+   _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)
+--- 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,
+--- a/tests/test-memchr.c
++++ b/tests/test-memchr.c
+@@ -31,7 +31,7 @@ SIGNATURE_CHECK (memchr, void *, (void c
+ 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;
+--- 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;
diff --git a/tools/gnulib/patches/410-unmacro-fts-functions.patch b/tools/gnulib/patches/410-unmacro-fts-functions.patch
new file mode 100644 (file)
index 0000000..01a6285
--- /dev/null
@@ -0,0 +1,28 @@
+--- a/lib/fts.in.h
++++ b/lib/fts.in.h
+@@ -291,20 +291,20 @@ typedef struct _ftsent {
+ __BEGIN_DECLS
+  _GL_ATTRIBUTE_NODISCARD
+-FTSENT  *fts_children (FTS *, int) __THROW;
++FTSENT  *_GL_FUNCDECL_SYS_NAME (fts_children) (FTS *, int) __THROW;
+ _GL_ATTRIBUTE_NODISCARD
+-int      fts_close (FTS *) __THROW;
++int      _GL_FUNCDECL_SYS_NAME (fts_close) (FTS *) __THROW;
+ _GL_ATTRIBUTE_NODISCARD
+-FTS     *fts_open (char * const *, int,
++FTS     *_GL_FUNCDECL_SYS_NAME (fts_open) (char * const *, int,
+                    int (*)(const FTSENT **, const FTSENT **))
+   _GL_ATTRIBUTE_DEALLOC (fts_close, 1) __THROW;
+ _GL_ATTRIBUTE_NODISCARD
+-FTSENT  *fts_read (FTS *) __THROW;
++FTSENT  *_GL_FUNCDECL_SYS_NAME (fts_read) (FTS *) __THROW;
+-int      fts_set (FTS *, FTSENT *, int) __THROW;
++int      _GL_FUNCDECL_SYS_NAME (fts_set) (FTS *, FTSENT *, int) __THROW;
+ #if GNULIB_FTS_DEBUG
+ extern bool fts_debug;
diff --git a/tools/gnulib/patches/450-attribute-specifier-order.patch b/tools/gnulib/patches/450-attribute-specifier-order.patch
new file mode 100644 (file)
index 0000000..3a5caac
--- /dev/null
@@ -0,0 +1,12 @@
+--- a/lib/fts.in.h
++++ b/lib/fts.in.h
+@@ -299,7 +299,8 @@ int      _GL_FUNCDECL_SYS_NAME (fts_clos
+ _GL_ATTRIBUTE_NODISCARD
+ FTS     *_GL_FUNCDECL_SYS_NAME (fts_open) (char * const *, int,
+                    int (*)(const FTSENT **, const FTSENT **))
+-  _GL_ATTRIBUTE_DEALLOC (fts_close, 1) __THROW;
++  __THROW
++  _GL_ATTRIBUTE_DEALLOC (fts_close, 1);
+ _GL_ATTRIBUTE_NODISCARD
+ FTSENT  *_GL_FUNCDECL_SYS_NAME (fts_read) (FTS *) __THROW;