Re: const-improved function macros
> * 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
> 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
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
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
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
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
> +# 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
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 (
