From: Bruno Haible Date: Mon, 11 May 2026 19:15:44 +0000 (+0200) Subject: gettext-h: Ensure no warnings with --disable-nls and -Wformat=2. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d900c802d9be920747dee37eef323d435a186e80;p=thirdparty%2Fgnulib.git gettext-h: Ensure no warnings with --disable-nls and -Wformat=2. * lib/gettext.h (gettext, dgettext, dcgettext): Define differently for clang. (ngettext, dngettext, dcngettext): Define differently for gcc and clang. With gcc in C mode, silence -Wuseless-cast warnings. --- diff --git a/ChangeLog b/ChangeLog index 8cbef68690..5e31f790bf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2026-05-11 Bruno Haible + + gettext-h: Ensure no warnings with --disable-nls and -Wformat=2. + * lib/gettext.h (gettext, dgettext, dcgettext): Define differently for + clang. + (ngettext, dngettext, dcngettext): Define differently for gcc and clang. + With gcc in C mode, silence -Wuseless-cast warnings. + 2026-05-11 Paul Eggert careadlinkat: pacify GCC 12+ -Wreturn-local-addr more simply diff --git a/lib/gettext.h b/lib/gettext.h index 1ea5c9be78..07f2dfed53 100644 --- a/lib/gettext.h +++ b/lib/gettext.h @@ -60,10 +60,39 @@ # endif /* Disabled NLS. */ +/* When gcc is used with option -Wformat=2, we need to silence + "warning: format not a string literal, argument types not checked [-Wformat-nonliteral]" + warnings that would occur at every invocation of a *ngettext function + in a *printf format string position. + Do this with inline functions when possible. + It is not ideal to ignore the possible side effects done in the + Domainname and Category arguments, but it's better than to have a + warning at every invocation in a format string position. */ +/* When clang is used with option -Wformat=2, we need to silence + "warning: format string is not a string literal [-Wformat-nonliteral]" + warnings that would occur at every invocation of a *gettext function + in a *printf format string position. + It is not ideal to ignore the possible side effects done in the + Domainname and Category arguments, but it's better than to have a + warning at every invocation in a format string position. */ +/* These warnings would not occur with enabled NLS. */ +/* A test case: + ================================ foo.c ================================ + #include + #include "gettext.h" + void foo (int n) + { + printf (gettext ("foo %d"), n); + printf (dgettext ("toto", "foo %d"), n); + printf (dcgettext ("toto", "foo %d", LC_MESSAGES), n); + printf (ngettext ("foo %d", "bar %d", n), n); + printf (dngettext ("toto", "foo %d", "bar %d", n), n); + printf (dcngettext ("toto", "foo %d", "bar %d", n, LC_MESSAGES), n); + } + ======================================================================= + $CC -Wformat=2 -S foo.c + */ # if defined __GNUC__ && !defined __clang__ && !defined __cplusplus -/* Use inline functions, to avoid warnings - warning: format not a string literal and no format arguments - that don't occur with enabled NLS. */ /* The return type 'const char *' serves the purpose of producing warnings for invalid uses of the value returned from these functions. */ # if __GNUC__ >= 9 @@ -92,7 +121,7 @@ __attribute__ ((__always_inline__)) extern inline # if !defined(__sun) const -# endif +# endif char * dgettext (const char *domain, const char *msgid) { @@ -118,11 +147,21 @@ dcgettext (const char *domain, const char *msgid, int category) # if __GNUC__ >= 9 # pragma GCC diagnostic pop # endif +# elif defined __clang__ +# undef gettext +# define gettext(Msgid) ((const char *) (Msgid)) +# undef dgettext +# define dgettext(Domainname, Msgid) gettext (Msgid) +# undef dcgettext +# define dcgettext(Domainname, Msgid, Category) dgettext (Domainname, Msgid) # else -/* The 'const char *' compound literals produce warnings - for invalid uses of the value returned from these functions. */ +/* The conversions to 'const char *' via compound literals serve the purpose + of producing warnings for invalid uses of the value returned from these + functions and for invalid-typed Msgid arguments. */ # undef gettext # define gettext(Msgid) ((const char *) {(Msgid)}) +/* The conversions via compound literals serve the purpose of producing warnings + for invalid-typed arguments. */ # undef dgettext # define dgettext(Domainname, Msgid) \ ((void) (const char *) {(Domainname)}, gettext (Msgid)) @@ -130,17 +169,50 @@ dcgettext (const char *domain, const char *msgid, int category) # define dcgettext(Domainname, Msgid, Category) \ ((void) (int) {(Category)}, dgettext (Domainname, Msgid)) # endif -# undef ngettext -# define ngettext(Msgid1, Msgid2, N) \ - ((N) == 1 \ - ? ((void) (Msgid2), (const char *) {(Msgid1)}) \ - : ((void) (Msgid1), (const char *) {(Msgid2)})) -# undef dngettext -# define dngettext(Domainname, Msgid1, Msgid2, N) \ - ((void) (const char *) {(Domainname)}, ngettext (Msgid1, Msgid2, N)) -# undef dcngettext -# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ - ((void) (int) {(Category)}, dngettext (Domainname, Msgid1, Msgid2, N)) + +# if (defined __GNUC__ && defined __cplusplus) || defined __clang__ +# undef ngettext +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# undef dngettext +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ngettext (Msgid1, Msgid2, N) +# undef dcngettext +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + dngettext (Domainname, Msgid1, Msgid2, N) +# elif defined __GNUC__ && !defined __cplusplus +/* Silence -Wuseless-cast warnings. */ +# if __GNUC__ >= 14 +# pragma GCC diagnostic ignored "-Wuseless-cast" +# endif +# undef ngettext +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# undef dngettext +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((void) (const char *) (Domainname), ngettext (Msgid1, Msgid2, N)) +# undef dcngettext +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((void) (int) (Category), dngettext (Domainname, Msgid1, Msgid2, N)) +# else +/* The conversions to 'const char *' via compound literals serve the purpose + of producing warnings for invalid uses of the value returned from these + functions and for invalid-typed Msgid1 and Msgid2 arguments. */ +# undef ngettext +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 \ + ? ((void) (Msgid2), (const char *) {(Msgid1)}) \ + : ((void) (Msgid1), (const char *) {(Msgid2)})) +/* The conversions via compound literals serve the purpose of producing warnings + for invalid-typed arguments. */ +# undef dngettext +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((void) (const char *) {(Domainname)}, ngettext (Msgid1, Msgid2, N)) +# undef dcngettext +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((void) (int) {(Category)}, dngettext (Domainname, Msgid1, Msgid2, N)) +# endif + # undef textdomain # define textdomain(Domainname) ((const char *) {(Domainname)}) # undef bindtextdomain