]> git.ipfire.org Git - thirdparty/gnulib.git/commitdiff
gettext-h: Ensure no warnings with --disable-nls and -Wformat=2.
authorBruno Haible <bruno@clisp.org>
Mon, 11 May 2026 19:15:44 +0000 (21:15 +0200)
committerBruno Haible <bruno@clisp.org>
Mon, 11 May 2026 19:24:12 +0000 (21:24 +0200)
* 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.

ChangeLog
lib/gettext.h

index 8cbef68690b3f1885ab2ffc1b8c807faf5339c47..5e31f790bf906dc6ce306a6cf4556583823a693b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2026-05-11  Bruno Haible  <bruno@clisp.org>
+
+       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  <eggert@cs.ucla.edu>
 
        careadlinkat: pacify GCC 12+ -Wreturn-local-addr more simply
index 1ea5c9be78eef8e22e3227277c5a2d5ff971c576..07f2dfed535f9fbfb4dec71f9bc1a67d9823a6ca 100644 (file)
 # 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 <stdio.h>
+   #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