Re: const-improved function macros

2025-02-10 Thread Bruno Haible via Gnulib discussion list
>   * lib/string.in.h (mbsstr, mbspcasecmp, mbscasestr): Define as macros
>   that cast the result to 'const char *' when the first argument is a
>   'const char *'.

One more tweak is needed, for library namespacing. That is, for when a library
does
   #define mbsstr libfoo_mbsstr
in its , we get a link error (because mbsstr.c defines the symbol
'libfoo_mbsstr' whereas the users of this function reference 'mbsstr').
This patch fixes it.


2025-02-10  Bruno Haible  

mbsstr, unistr, unigbrk: Support library namespacing.
* lib/string.in.h (mbsstr, mbspcasecmp, mbscasestr): Don't define
const-improved macro if the function is already declared as a macro.
* lib/unistr.in.h (u*_check, u*_next, u*_prev, u*_chr, u*_strchr,
u*_strrchr, u*_strpbrk, u*_strstr): Likewise.
* lib/unigbrk.in.h (u*_grapheme_next, u*_grapheme_prev): Likewise.

diff --git a/lib/string.in.h b/lib/string.in.h
index ac6b459de9..d2bf296146 100644
--- a/lib/string.in.h
+++ b/lib/string.in.h
@@ -1192,8 +1192,9 @@ template <>
   inline const char * mbsstr_template (const char *haystack, const char 
*needle)
   { return mbsstr (haystack, needle); }
 }
+#   undef mbsstr
 #   define mbsstr mbsstr_template
-#  else
+#  elif !defined mbsstr
 #   if ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
 || defined __ICC  || defined __TINYC__ \
 || (__STDC_VERSION__ >= 201112L && !(defined __GNUC__ || defined 
__clang__)))
@@ -1259,8 +1260,9 @@ template <>
   inline const char * mbspcasecmp_template (const char *string, const char 
*prefix)
   { return mbspcasecmp (string, prefix); }
 }
+#   undef mbspcasecmp
 #   define mbspcasecmp mbspcasecmp_template
-#  else
+#  elif !defined mbspcasecmp
 #   if ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
 || defined __ICC  || defined __TINYC__ \
 || (__STDC_VERSION__ >= 201112L && !(defined __GNUC__ || defined 
__clang__)))
@@ -1296,8 +1298,9 @@ template <>
   inline const char * mbscasestr_template (const char *haystack, const char 
*needle)
   { return mbscasestr (haystack, needle); }
 }
+#   undef mbscasestr
 #   define mbscasestr mbscasestr_template
-#  else
+#  elif !defined mbscasestr
 #   if ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
 || defined __ICC  || defined __TINYC__ \
 || (__STDC_VERSION__ >= 201112L && !(defined __GNUC__ || defined 
__clang__)))
diff --git a/lib/unigbrk.in.h b/lib/unigbrk.in.h
index c09749a146..0c474632b3 100644
--- a/lib/unigbrk.in.h
+++ b/lib/unigbrk.in.h
@@ -122,8 +122,9 @@ template <>
 template <>
   inline const uint8_t * u8_grapheme_next_template (const uint8_t *s, const 
uint8_t *end)
   { return u8_grapheme_next (s, end); }
+#  undef u8_grapheme_next
 #  define u8_grapheme_next u8_grapheme_next_template
-# else
+# elif !defined u8_grapheme_next
 #  if ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
|| defined __ICC  || defined __TINYC__ \
|| (__STDC_VERSION__ >= 201112L && !(defined __GNUC__ || defined 
__clang__)))
@@ -142,8 +143,9 @@ template <>
 template <>
   inline const uint16_t * u16_grapheme_next_template (const uint16_t *s, const 
uint16_t *end)
   { return u16_grapheme_next (s, end); }
+#  undef u16_grapheme_next
 #  define u16_grapheme_next u16_grapheme_next_template
-# else
+# elif !defined u16_grapheme_next
 #  if ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
|| defined __ICC  || defined __TINYC__ \
|| (__STDC_VERSION__ >= 201112L && !(defined __GNUC__ || defined 
__clang__)))
@@ -162,8 +164,9 @@ template <>
 template <>
   inline const uint32_t * u32_grapheme_next_template (const uint32_t *s, const 
uint32_t *end)
   { return u32_grapheme_next (s, end); }
+#  undef u32_grapheme_next
 #  define u32_grapheme_next u32_grapheme_next_template
-# else
+# elif !defined u32_grapheme_next
 #  if ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
|| defined __ICC  || defined __TINYC__ \
|| (__STDC_VERSION__ >= 201112L && !(defined __GNUC__ || defined 
__clang__)))
@@ -200,8 +203,9 @@ template <>
 template <>
   inline const uint8_t * u8_grapheme_prev_template (const uint8_t *s, const 
uint8_t *start)
   { return u8_grapheme_prev (s, start); }
+#  undef u8_grapheme_prev
 #  define u8_grapheme_prev u8_grapheme_prev_template
-# else
+# elif !defined u8_grapheme_prev
 #  if ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
|| defined __ICC  || defined __TINYC__ \
|| (__STDC_VERSION__ >= 201112L && !(defined __GNUC__ || defined 
__clang__)))
@@ -220,8 +224,9 @@ template <>
 template <>
   inline const uint16_t * u16_grapheme_prev_template (const uint16_t *s, const 
uint16_t *start)
   { return u16_grapheme_prev (s, start); }
+#  undef u16_grapheme_prev
 #  define u16_grapheme_prev u16_grapheme_prev_template
-# else
+# elif !defined u16_grapheme_prev
 #  if ((__GNUC__ + 

Re: const-improved function macros

2025-02-10 Thread Bruno Haible via Gnulib discussion list
>   mbsstr, mbscasestr, mbspcasecmp: Use const-improved C++ templates.
>   * lib/string.in.h (mbsstr, mbspcasecmp, mbscasestr): In C++, define
>   through a template that supports both 'char *' and 'const char *'.

On AIX 7.1 with xlc I get these compilation errors:

xlC -q64 -qthreaded -qtls -DHAVE_CONFIG_H -DEXEEXT=\"\" -DEXEEXT=\"\" -I. 
-I../../gltests -I..  -DGNULIB_STRICT_CHECKING=1 -DIN_GNULIB_TESTS=1 -I. 
-I../../gltests -I.. -I../../gltests/.. -I../gllib -I../../gltests/../gllib 
-I/home/haible/prefix64/include -D_THREAD_SAFE  -g -c -o test-strings-h-c++.o 
../../gltests/test-strings-h-c++.cc
"../gllib/string.h", line 1723.7: 1540-0121 (S) A template cannot have "C" 
linkage.
"../gllib/string.h", line 1725.17: 1540-0603 (S) The template declaration 
"mbsstr_template" cannot be found. An extra "template <>" may be specified on 
this declaration.
"../gllib/string.h", line 1728.23: 1540-0603 (S) The template declaration 
"mbsstr_template" cannot be found. An extra "template <>" may be specified on 
this declaration.
"../gllib/string.h", line 1787.7: 1540-0121 (S) A template cannot have "C" 
linkage.
"../gllib/string.h", line 1789.17: 1540-0603 (S) The template declaration 
"mbspcasecmp_template" cannot be found. An extra "template <>" may be specified 
on this declaration.
"../gllib/string.h", line 1792.23: 1540-0603 (S) The template declaration 
"mbspcasecmp_template" cannot be found. An extra "template <>" may be specified 
on this declaration.
"../gllib/string.h", line 1821.7: 1540-0121 (S) A template cannot have "C" 
linkage.
"../gllib/string.h", line 1823.17: 1540-0603 (S) The template declaration 
"mbscasestr_template" cannot be found. An extra "template <>" may be specified 
on this declaration.
"../gllib/string.h", line 1826.23: 1540-0603 (S) The template declaration 
"mbscasestr_template" cannot be found. An extra "template <>" may be specified 
on this declaration.
gmake[4]: *** [Makefile:26704: test-strings-h-c++.o] Error 1

The cause is that some header files in /usr/include do things like

  extern "C" {
  #include <...>
  }

and one of these system include files ends up doing '#include ',
which includes Gnulib's string.h.

This patch fixes it.


2025-02-10  Bruno Haible  

mbsstr, etc.: Fix compilation in C++ mode on AIX with xlc.
* lib/string.in.h (mbsstr, mbspcasecmp, mbscasestr): Wrap template
declarations and definitions in 'extern "C++" { ... }'.

diff --git a/lib/string.in.h b/lib/string.in.h
index 0b7f8cebc6..ac6b459de9 100644
--- a/lib/string.in.h
+++ b/lib/string.in.h
@@ -1182,6 +1182,7 @@ _GL_EXTERN_C char * mbsstr (const char *haystack, const 
char *needle)
 /* Don't silently convert a 'const char *' to a 'char *'.  Programmers want
compiler warnings for 'const' related mistakes.  */
 #  ifdef __cplusplus
+extern "C++" { /* needed for AIX */
 template 
   T * mbsstr_template (T* haystack, const char *needle);
 template <>
@@ -1190,6 +1191,7 @@ template <>
 template <>
   inline const char * mbsstr_template (const char *haystack, const char 
*needle)
   { return mbsstr (haystack, needle); }
+}
 #   define mbsstr mbsstr_template
 #  else
 #   if ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
@@ -1247,6 +1249,7 @@ _GL_EXTERN_C char * mbspcasecmp (const char *string, 
const char *prefix)
 /* Don't silently convert a 'const char *' to a 'char *'.  Programmers want
compiler warnings for 'const' related mistakes.  */
 #  ifdef __cplusplus
+extern "C++" { /* needed for AIX */
 template 
   T * mbspcasecmp_template (T* string, const char *prefix);
 template <>
@@ -1255,6 +1258,7 @@ template <>
 template <>
   inline const char * mbspcasecmp_template (const char *string, const char 
*prefix)
   { return mbspcasecmp (string, prefix); }
+}
 #   define mbspcasecmp mbspcasecmp_template
 #  else
 #   if ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
@@ -1282,6 +1286,7 @@ _GL_EXTERN_C char * mbscasestr (const char *haystack, 
const char *needle)
 /* Don't silently convert a 'const char *' to a 'char *'.  Programmers want
compiler warnings for 'const' related mistakes.  */
 #  ifdef __cplusplus
+extern "C++" { /* needed for AIX */
 template 
   T * mbscasestr_template (T* haystack, const char *needle);
 template <>
@@ -1290,6 +1295,7 @@ template <>
 template <>
   inline const char * mbscasestr_template (const char *haystack, const char 
*needle)
   { return mbscasestr (haystack, needle); }
+}
 #   define mbscasestr mbscasestr_template
 #  else
 #   if ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \






Re: const-improved function macros

2025-02-09 Thread Bruno Haible via Gnulib discussion list
I wrote:
> @@ -1192,10 +1192,8 @@ template <>
>{ return mbsstr (haystack, needle); }
>  #   define mbsstr mbsstr_template
>  #  else
> -#   if __STDC_VERSION__ >= 202311
> -#define mbsstr(h,n) (typeof ((h) + 0)) mbsstr ((h), (n))
> -#   elif ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
> -  || defined __ICC  || defined __TINYC__)
> +#   if (__STDC_VERSION__ >= 201112L || (__GNUC__ + (__GNUC_MINOR__ >= 9) > 
> 4) \
> +|| (__clang_major__ >= 3) || defined __ICC  || defined __TINYC__)
>  #define mbsstr(h,n) \
> _Generic ((h), \
>   char const *: (char const *) mbsstr ((h), (n)), \

The assumption that (__STDC_VERSION__ >= 201112L) implies that '_Generic' is
supported is wrong: gcc 4.8.5 with '-std=gnu11' has
  #define __STDC_VERSION__ 201112L
but does not support '_Generic'. Found by the multi-platform CI on CentOS 7.

This patch fixes it.


2025-02-10  Bruno Haible  

mbsstr, unistr, unigbrk: Fix compilation with "gcc-4.8.5 -std=gnu11".
* lib/string.in.h (mbsstr, mbspcasecmp, mbscasestr): Don't assume that
GCC and clang support '_Generic' with '-std=c11' or 'std=gnu11' option.
* lib/unistr.in.h (u*_check, u*_next, u*_prev, u*_chr, u*_strchr,
u*_strrchr, u*_strpbrk, u*_strstr): Likewise.
* lib/unigbrk.in.h (u*_grapheme_next, u*_grapheme_prev): Likewise.

diff --git a/lib/string.in.h b/lib/string.in.h
index 5dbfadb3e0..0b7f8cebc6 100644
--- a/lib/string.in.h
+++ b/lib/string.in.h
@@ -1192,8 +1192,9 @@ template <>
   { return mbsstr (haystack, needle); }
 #   define mbsstr mbsstr_template
 #  else
-#   if (__STDC_VERSION__ >= 201112L || (__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) \
-|| (__clang_major__ >= 3) || defined __ICC  || defined __TINYC__)
+#   if ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
+|| defined __ICC  || defined __TINYC__ \
+|| (__STDC_VERSION__ >= 201112L && !(defined __GNUC__ || defined 
__clang__)))
 #define mbsstr(h,n) \
_Generic ((h), \
  char const *: (char const *) mbsstr ((h), (n)), \
@@ -1256,8 +1257,9 @@ template <>
   { return mbspcasecmp (string, prefix); }
 #   define mbspcasecmp mbspcasecmp_template
 #  else
-#   if (__STDC_VERSION__ >= 201112L || (__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) \
-|| (__clang_major__ >= 3) || defined __ICC  || defined __TINYC__)
+#   if ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
+|| defined __ICC  || defined __TINYC__ \
+|| (__STDC_VERSION__ >= 201112L && !(defined __GNUC__ || defined 
__clang__)))
 #define mbspcasecmp(s,p) \
_Generic ((s), \
  char const *: (char const *) mbspcasecmp ((s), (p)), \
@@ -1290,8 +1292,9 @@ template <>
   { return mbscasestr (haystack, needle); }
 #   define mbscasestr mbscasestr_template
 #  else
-#   if (__STDC_VERSION__ >= 201112L || (__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) \
-|| (__clang_major__ >= 3) || defined __ICC  || defined __TINYC__)
+#   if ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
+|| defined __ICC  || defined __TINYC__ \
+|| (__STDC_VERSION__ >= 201112L && !(defined __GNUC__ || defined 
__clang__)))
 #define mbscasestr(h,n) \
_Generic ((h), \
  char const *: (char const *) mbscasestr ((h), (n)), \
diff --git a/lib/unigbrk.in.h b/lib/unigbrk.in.h
index f5a8bcf700..c09749a146 100644
--- a/lib/unigbrk.in.h
+++ b/lib/unigbrk.in.h
@@ -124,8 +124,9 @@ template <>
   { return u8_grapheme_next (s, end); }
 #  define u8_grapheme_next u8_grapheme_next_template
 # else
-#  if (__STDC_VERSION__ >= 201112L || (__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) \
-   || (__clang_major__ >= 3) || defined __ICC  || defined __TINYC__)
+#  if ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
+   || defined __ICC  || defined __TINYC__ \
+   || (__STDC_VERSION__ >= 201112L && !(defined __GNUC__ || defined 
__clang__)))
 #   define u8_grapheme_next(s,end) \
   _Generic ((s), \
 uint8_t *: (uint8_t *) u8_grapheme_next ((s), (end)), \
@@ -143,8 +144,9 @@ template <>
   { return u16_grapheme_next (s, end); }
 #  define u16_grapheme_next u16_grapheme_next_template
 # else
-#  if (__STDC_VERSION__ >= 201112L || (__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) \
-   || (__clang_major__ >= 3) || defined __ICC  || defined __TINYC__)
+#  if ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
+   || defined __ICC  || defined __TINYC__ \
+   || (__STDC_VERSION__ >= 201112L && !(defined __GNUC__ || defined 
__clang__)))
 #   define u16_grapheme_next(s,end) \
   _Generic ((s), \
 uint16_t *: (uint16_t *) u16_grapheme_next ((s), (end)), \
@@ -162,8 +164,9 @@ template <>
   { return u32_grapheme_next (s, end); }
 #  define u32_grapheme_next u32_grapheme_next_template
 # else
-#  if (__STDC_VERSION__ >= 201112L || (__GNUC__ + (__GNUC_MI

Re: const-improved function macros

2025-02-09 Thread Paul Eggert

On 2025-02-09 12:53, Bruno Haible wrote:

I thought that typeof_unqual removed the 'const'. Maybe it does so only
at the top-level, i.e. mapping  'const char *const' -> 'const char *' ?


Yes, that's my understanding. See C23 §6.2.5 ¶31.



Re: const-improved function macros

2025-02-09 Thread Bruno Haible via Gnulib discussion list
Paul Eggert wrote:
> On 2025-02-08 23:33, Bruno Haible via Gnulib discussion list wrote:
> > # define strchr(s,c) (typeof(s)) strchr ((s), (c))
> 
> This evaluates S twice if S's type is variably modified

Indeed, that's a pitfall better to be avoided.

> Also, why use typeof rather than typeof_unqual?

I thought that typeof_unqual removed the 'const'. Maybe it does so only
at the top-level, i.e. mapping  'const char *const' -> 'const char *' ?
Then typeof_unqual would be indeed just as good as typeof.

> It might be better to just use the _Generic implementation, as that 
> avoids the double-evaluation problem

Thanks for the suggestion. Done:


2025-02-09  Bruno Haible  

mbsstr, mbscasestr, mbspcasecmp, unistr, unigbrk: Simplify.
Suggested by Paul Eggert.
* lib/string.in.h (mbsstr, mbspcasecmp, mbscasestr): On ISO C compliant
compilers, use the _Generic based macro instead of the 'typeof' based
macro.
* lib/unistr.in.h (u*_check, u*_next, u*_prev, u*_chr, u*_strchr,
u*_strrchr, u*_strpbrk, u*_strstr): Likewise.
* lib/unigbrk.in.h (u*_grapheme_next, u*_grapheme_prev): Likewise.

diff --git a/lib/string.in.h b/lib/string.in.h
index d4c7df6258..5dbfadb3e0 100644
--- a/lib/string.in.h
+++ b/lib/string.in.h
@@ -1192,10 +1192,8 @@ template <>
   { return mbsstr (haystack, needle); }
 #   define mbsstr mbsstr_template
 #  else
-#   if __STDC_VERSION__ >= 202311
-#define mbsstr(h,n) (typeof ((h) + 0)) mbsstr ((h), (n))
-#   elif ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
-  || defined __ICC  || defined __TINYC__)
+#   if (__STDC_VERSION__ >= 201112L || (__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) \
+|| (__clang_major__ >= 3) || defined __ICC  || defined __TINYC__)
 #define mbsstr(h,n) \
_Generic ((h), \
  char const *: (char const *) mbsstr ((h), (n)), \
@@ -1258,10 +1256,8 @@ template <>
   { return mbspcasecmp (string, prefix); }
 #   define mbspcasecmp mbspcasecmp_template
 #  else
-#   if __STDC_VERSION__ >= 202311
-#define mbspcasecmp(s,p) (typeof ((s) + 0)) mbspcasecmp ((s), (p))
-#   elif ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
-  || defined __ICC  || defined __TINYC__)
+#   if (__STDC_VERSION__ >= 201112L || (__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) \
+|| (__clang_major__ >= 3) || defined __ICC  || defined __TINYC__)
 #define mbspcasecmp(s,p) \
_Generic ((s), \
  char const *: (char const *) mbspcasecmp ((s), (p)), \
@@ -1294,10 +1290,8 @@ template <>
   { return mbscasestr (haystack, needle); }
 #   define mbscasestr mbscasestr_template
 #  else
-#   if __STDC_VERSION__ >= 202311
-#define mbscasestr(h,n) (typeof ((h) + 0)) mbscasestr ((h), (n))
-#   elif ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
-  || defined __ICC  || defined __TINYC__)
+#   if (__STDC_VERSION__ >= 201112L || (__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) \
+|| (__clang_major__ >= 3) || defined __ICC  || defined __TINYC__)
 #define mbscasestr(h,n) \
_Generic ((h), \
  char const *: (char const *) mbscasestr ((h), (n)), \
diff --git a/lib/unigbrk.in.h b/lib/unigbrk.in.h
index 19c3e0771b..f5a8bcf700 100644
--- a/lib/unigbrk.in.h
+++ b/lib/unigbrk.in.h
@@ -124,10 +124,8 @@ template <>
   { return u8_grapheme_next (s, end); }
 #  define u8_grapheme_next u8_grapheme_next_template
 # else
-#  if __STDC_VERSION__ >= 202311
-#   define u8_grapheme_next(s,end) (typeof ((s) + 0)) u8_grapheme_next ((s), 
(end))
-#  elif ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
- || defined __ICC  || defined __TINYC__)
+#  if (__STDC_VERSION__ >= 201112L || (__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) \
+   || (__clang_major__ >= 3) || defined __ICC  || defined __TINYC__)
 #   define u8_grapheme_next(s,end) \
   _Generic ((s), \
 uint8_t *: (uint8_t *) u8_grapheme_next ((s), (end)), \
@@ -145,10 +143,8 @@ template <>
   { return u16_grapheme_next (s, end); }
 #  define u16_grapheme_next u16_grapheme_next_template
 # else
-#  if __STDC_VERSION__ >= 202311
-#   define u16_grapheme_next(s,end) (typeof ((s) + 0)) u16_grapheme_next ((s), 
(end))
-#  elif ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
- || defined __ICC  || defined __TINYC__)
+#  if (__STDC_VERSION__ >= 201112L || (__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) \
+   || (__clang_major__ >= 3) || defined __ICC  || defined __TINYC__)
 #   define u16_grapheme_next(s,end) \
   _Generic ((s), \
 uint16_t *: (uint16_t *) u16_grapheme_next ((s), (end)), \
@@ -166,10 +162,8 @@ template <>
   { return u32_grapheme_next (s, end); }
 #  define u32_grapheme_next u32_grapheme_next_template
 # else
-#  if __STDC_VERSION__ >= 202311
-#   define u32_grapheme_next(s,end) (typeof ((s) + 0)) u32_grapheme_next ((s), 
(end))
-#  elif ((__GNUC__ + (__GNUC_MINOR__ 

Re: const-improved function macros

2025-02-09 Thread Paul Eggert

On 2025-02-08 23:33, Bruno Haible via Gnulib discussion list wrote:

# define strchr(s,c) (typeof(s)) strchr ((s), (c))


This evaluates S twice if S's type is variably modified, which violates 
the C standard. Also, why use typeof rather than typeof_unqual?


It might be better to just use the _Generic implementation, as that 
avoids the double-evaluation problem and it should be easier to test one 
implementation (the one supported by more compilers) as opposed to 
testing two.




Re: const-improved function macros

2025-02-09 Thread Bruno Haible via Gnulib discussion list
> +#   define mbsstr(h,n) (typeof(h)) mbsstr ((h), (n))

Oops, this does not work when the argument is an array:
  error: cast specifies array type

We need to convert the array argument to a pointer first.


2025-02-09  Bruno Haible  

mbsstr, mbscasestr, mbspcasecmp: Fix use of 'typeof'.
* lib/string.in.h (mbsstr, mbspcasecmp, mbscasestr): Perform array to
pointer conversion in argument of 'typeof'.

diff --git a/lib/string.in.h b/lib/string.in.h
index bfe949cf84..d4c7df6258 100644
--- a/lib/string.in.h
+++ b/lib/string.in.h
@@ -1193,7 +1193,7 @@ template <>
 #   define mbsstr mbsstr_template
 #  else
 #   if __STDC_VERSION__ >= 202311
-#define mbsstr(h,n) (typeof(h)) mbsstr ((h), (n))
+#define mbsstr(h,n) (typeof ((h) + 0)) mbsstr ((h), (n))
 #   elif ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
   || defined __ICC  || defined __TINYC__)
 #define mbsstr(h,n) \
@@ -1259,7 +1259,7 @@ template <>
 #   define mbspcasecmp mbspcasecmp_template
 #  else
 #   if __STDC_VERSION__ >= 202311
-#define mbspcasecmp(s,p) (typeof(s)) mbspcasecmp ((s), (p))
+#define mbspcasecmp(s,p) (typeof ((s) + 0)) mbspcasecmp ((s), (p))
 #   elif ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
   || defined __ICC  || defined __TINYC__)
 #define mbspcasecmp(s,p) \
@@ -1295,7 +1295,7 @@ template <>
 #   define mbscasestr mbscasestr_template
 #  else
 #   if __STDC_VERSION__ >= 202311
-#define mbscasestr(h,n) (typeof(h)) mbscasestr ((h), (n))
+#define mbscasestr(h,n) (typeof ((h) + 0)) mbscasestr ((h), (n))
 #   elif ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
   || defined __ICC  || defined __TINYC__)
 #define mbscasestr(h,n) \






Re: const-improved function macros

2025-02-09 Thread Bruno Haible via Gnulib discussion list
I wrote:
> So, for C++, the solution should be something with templates.
> If someone has spare time available for this, please go ahead.

The solution for C++ is easier than I thought.


2025-02-09  Bruno Haible  

mbsstr, mbscasestr, mbspcasecmp: Use const-improved C++ templates.
* lib/string.in.h (mbsstr, mbspcasecmp, mbscasestr): In C++, define
through a template that supports both 'char *' and 'const char *'.

diff --git a/lib/string.in.h b/lib/string.in.h
index 6705967c59..bfe949cf84 100644
--- a/lib/string.in.h
+++ b/lib/string.in.h
@@ -1178,17 +1178,29 @@ _GL_CXXALIASWARN (mbsrchr);
 _GL_EXTERN_C char * mbsstr (const char *haystack, const char *needle)
  _GL_ATTRIBUTE_PURE
  _GL_ARG_NONNULL ((1, 2));
+# ifndef _GL_NO_CONST_GENERICS
 /* Don't silently convert a 'const char *' to a 'char *'.  Programmers want
compiler warnings for 'const' related mistakes.  */
-# if !(defined _GL_NO_CONST_GENERICS || defined __cplusplus)
-#  if __STDC_VERSION__ >= 202311
-#   define mbsstr(h,n) (typeof(h)) mbsstr ((h), (n))
-#  elif ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
- || defined __ICC  || defined __TINYC__)
-#   define mbsstr(h,n) \
-  _Generic ((h), \
-char const *: (char const *) mbsstr ((h), (n)), \
-default :mbsstr ((h), (n)))
+#  ifdef __cplusplus
+template 
+  T * mbsstr_template (T* haystack, const char *needle);
+template <>
+  inline char * mbsstr_template (char *haystack, const char *needle)
+  { return mbsstr (haystack, needle); }
+template <>
+  inline const char * mbsstr_template (const char *haystack, const char 
*needle)
+  { return mbsstr (haystack, needle); }
+#   define mbsstr mbsstr_template
+#  else
+#   if __STDC_VERSION__ >= 202311
+#define mbsstr(h,n) (typeof(h)) mbsstr ((h), (n))
+#   elif ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
+  || defined __ICC  || defined __TINYC__)
+#define mbsstr(h,n) \
+   _Generic ((h), \
+ char const *: (char const *) mbsstr ((h), (n)), \
+ default :mbsstr ((h), (n)))
+#   endif
 #  endif
 # endif
 #endif
@@ -1232,17 +1244,29 @@ _GL_EXTERN_C int mbsncasecmp (const char *s1, const 
char *s2, size_t n)
 _GL_EXTERN_C char * mbspcasecmp (const char *string, const char *prefix)
  _GL_ATTRIBUTE_PURE
  _GL_ARG_NONNULL ((1, 2));
+# ifndef _GL_NO_CONST_GENERICS
 /* Don't silently convert a 'const char *' to a 'char *'.  Programmers want
compiler warnings for 'const' related mistakes.  */
-# if !(defined _GL_NO_CONST_GENERICS || defined __cplusplus)
-#  if __STDC_VERSION__ >= 202311
-#   define mbspcasecmp(s,p) (typeof(s)) mbspcasecmp ((s), (p))
-#  elif ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
- || defined __ICC  || defined __TINYC__)
-#   define mbspcasecmp(s,p) \
-  _Generic ((s), \
-char const *: (char const *) mbspcasecmp ((s), (p)), \
-default :mbspcasecmp ((s), (p)))
+#  ifdef __cplusplus
+template 
+  T * mbspcasecmp_template (T* string, const char *prefix);
+template <>
+  inline char * mbspcasecmp_template (char *string, const char *prefix)
+  { return mbspcasecmp (string, prefix); }
+template <>
+  inline const char * mbspcasecmp_template (const char *string, const char 
*prefix)
+  { return mbspcasecmp (string, prefix); }
+#   define mbspcasecmp mbspcasecmp_template
+#  else
+#   if __STDC_VERSION__ >= 202311
+#define mbspcasecmp(s,p) (typeof(s)) mbspcasecmp ((s), (p))
+#   elif ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
+  || defined __ICC  || defined __TINYC__)
+#define mbspcasecmp(s,p) \
+   _Generic ((s), \
+ char const *: (char const *) mbspcasecmp ((s), (p)), \
+ default :mbspcasecmp ((s), (p)))
+#   endif
 #  endif
 # endif
 #endif
@@ -1256,17 +1280,29 @@ _GL_EXTERN_C char * mbspcasecmp (const char *string, 
const char *prefix)
 _GL_EXTERN_C char * mbscasestr (const char *haystack, const char *needle)
  _GL_ATTRIBUTE_PURE
  _GL_ARG_NONNULL ((1, 2));
+# ifndef _GL_NO_CONST_GENERICS
 /* Don't silently convert a 'const char *' to a 'char *'.  Programmers want
compiler warnings for 'const' related mistakes.  */
-# if !(defined _GL_NO_CONST_GENERICS || defined __cplusplus)
-#  if __STDC_VERSION__ >= 202311
-#   define mbscasestr(h,n) (typeof(h)) mbscasestr ((h), (n))
-#  elif ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
- || defined __ICC  || defined __TINYC__)
-#   define mbscasestr(h,n) \
-  _Generic ((h), \
-char const *: (char const *) mbscasestr ((h), (n)), \
-default :mbscasestr ((h), (n)))
+#  ifdef __cplusplus
+template 
+  T * mbscasestr_template (T* haystack, const char *needle);
+template <>
+  inline char * mbscasestr_template (