strpbrk stops expand.c from compiling on Ubuntu 26-04

Andrew C Aitchison via Exim-dev <[email protected]> Sat, 2 May 2026 21:50:18 +0100 (BST)
Newsgroups gmane.mail.exim.devel
Message-ID <[email protected]>
Do we have an Ubuntu 26-04 (Resolute Raccoon) build animal ?

Both gcc 15.2 and clang 23 object to the use of strpbrk at
expand.c line 4638:

# gcc -Werror -Wno-dangling-else -Wno-format -Wno-format-extra-args \
   -Wno-misleading-indentation -Wno-missing-field-initializers \
   -Wno-parentheses -Wno-sign-compare -Wno-unused-but-set-variable \
   -Wno-unused-function -Wno-unused-parameter -Wno-unused-variable \
   -Wno-empty-body expand.c
expand.c: In function ‘expand_listnamed’:
expand.c:4638:23: error: assignment discards ‘const’ qualifier from 
pointer target type [-Werror=discarded-qualifiers]
  4638 |     for(char * cp; cp = strpbrk(CCS item, tok); item = US cp)
       |                       ^
cc1: all warnings being treated as errors

# /usr/bin/clang-23 -Werror -Wall -Wextra -Wno-constant-logical-operand \
   -Wno-dangling-else -Wno-format -Wno-format-extra-args       \
   -Wno-format-insufficient-args -Wno-format-invalid-specifier \
   -Wno-misleading-indentation -Wno-missing-field-initializers \
   -Wno-parentheses -Wno-self-assign -Wno-sign-compare         \
   -Wno-unused-but-set-variable -Wno-unused-function -Wno-unused-parameter \
   -Wno-unused-variable -Wno-empty-body expand.c
expand.c:4638:23: error: assigning to 'char *' from 'const char *' 
discards qualifiers 
[-Werror,-Wincompatible-pointer-types-discards-qualifiers]
  4638 |     for(char * cp; cp = strpbrk(CCS item, tok); item = US cp)
       |                       ^ ~~~~~~~~~~~~~~~~~~~~~~
1 error generated.

There have been no recent changes to this area of expand.c.
strpbrk is defined in /usr/include/string.h which *has* changed in this 
Ubuntu.

clang -E expand.c turns line 4638 into
     for(char * cp; cp = _Generic (0 ? ((const char *) item) : (void *) 1, const void *: (const char *) (strpbrk ((const char *) item, tok)), default: strpbrk ((const char *) item, tok)); item = (unsigned char *) cp)


The full definition of strpbrk in /usr/include/string.h
(which *has* changed in this Ubuntu) now conditionally has
separate declarations for const and non-const:

grep -3 strpbrk /usr/include/string.h | sed -e 's/^/  /'
   #ifdef __CORRECT_ISO_CPP_STRING_H_PROTO
   extern "C++"
   {
   extern char *strpbrk (char *__s, const char *__accept)
        __THROW __asm ("strpbrk") __attribute_pure__ __nonnull ((1, 2));
   extern const char *strpbrk (const char *__s, const char *__accept)
        __THROW __asm ("strpbrk") __attribute_pure__ __nonnull ((1, 2));

   # ifdef __OPTIMIZE__
   __extern_always_inline char *
   strpbrk (char *__s, const char *__accept) __THROW
   {
     return __builtin_strpbrk (__s, __accept);
   }

   __extern_always_inline const char *
   strpbrk (const char *__s, const char *__accept) __THROW
   {
     return __builtin_strpbrk (__s, __accept);
   }
   # endif
   }
   #else
   extern char *strpbrk (const char *__s, const char *__accept)
        __THROW __attribute_pure__ __nonnull ((1, 2));
   # if __GLIBC_USE (ISOC23) && defined __glibc_const_generic && !defined _LIBC
   #  define strpbrk(S, ACCEPT)                                  \
     __glibc_const_generic (S, const char *, strpbrk (S, ACCEPT))
   # endif
   #endif
   /* Find the first occurrence of NEEDLE in HAYSTACK.  */

Does this look different from other platforms, in a way that might cause
the compiler to object ?

Thanks,

-- 
Andrew C. Aitchison                      Kendal, UK
                    [email protected]

-- 
## subscription configuration (requires account):
##   https://lists.exim.org/mailman3/postorius/lists/exim-dev.lists.exim.org/
## unsubscribe (doesn't require an account):
##   [email protected]
## Exim details at https://www.exim.org/
## Please use the Wiki with this list - https://code.exim.org/exim/wiki/wiki