I did: > (error): Define as a macro that explicitly invokes exit(). > (error_at_line): Likewise.
Oops. That patch broke the library namespacing via config.h. Namely, when a package uses a config.h definition such as #define error libgettextpo_error the intent is that the Gnulib module defines a function named 'libgettextpo_error', not 'error'. With the error.in.h change, I now get redefinition warnings and compilation errors (on platforms other than glibc and cygwin) such as ./error.h:458:11: warning: 'error' macro redefined [-Wmacro-redefined] # define error(status, ...) \ ^ ./config.h:51:9: note: previous definition is here #define error libgettextpo_error ^ ... ../../../gettext-tools/libgettextpo/gettext-po.c:1326:5: error: use of undeclared identifier 'error' error (EXIT_FAILURE, 0, _("memory exhausted")); ^ ./error.h:459:23: note: expanded from macro 'error' __gl_error_call (error, status, __VA_ARGS__) ^ The fix is: 1) Capture the name of the error function through an static function. 2) Since this static function is a varargs function and needs to call a varargs function, it needs to invoke __builtin_va_arg_pack(). (The alternative would be to add a dependency from 'error' to the 'verror' module. Which is not really better...) 3) Since __builtin_va_arg_pack is only allowed in always-inline function, we need to mark it as _GL_ATTRIBUTE_ALWAYS_INLINE. 4) The compiler then warns that the inlining may fail. To silence this warning, we need a '#pragma GCC diagnostic ignored "-Wattributes"'. That's more involved than what I had expected. 2023-06-04 Bruno Haible <br...@clisp.org> error: Fix support for library namespacing (regression 2023-05-27). * lib/error.in.h (error): If error is defined as a macro, define a static inline function _gl_inline_error that invokes it, and let the new error macro invoke that function. (error_at_line): If error_at_line is defined as a macro, define a static inline function _gl_inline_error_at_line that invokes it, and let the new error_at_line macro invoke that function. diff --git a/lib/error.in.h b/lib/error.in.h index ef4b3c3815..94477fde08 100644 --- a/lib/error.in.h +++ b/lib/error.in.h @@ -30,7 +30,8 @@ #ifndef _@GUARD_PREFIX@_ERROR_H #define _@GUARD_PREFIX@_ERROR_H -/* This file uses _GL_ATTRIBUTE_FORMAT. */ +/* This file uses _GL_ATTRIBUTE_ALWAYS_INLINE, _GL_ATTRIBUTE_FORMAT, + _GL_ATTRIBUTE_MAYBE_UNUSED. */ #if !_GL_CONFIG_H_INCLUDED #error "Please include config.h first." #endif @@ -108,8 +109,28 @@ _GL_FUNCDECL_SYS (error, void, _GL_CXXALIAS_SYS (error, void, (int __status, int __errnum, const char *__format, ...)); # ifndef _GL_NO_INLINE_ERROR -# define error(status, ...) \ - __gl_error_call (error, status, __VA_ARGS__) +# ifdef error +/* Only gcc ≥ 4.7 has __builtin_va_arg_pack. */ +# if _GL_GNUC_PREREQ (4, 7) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wattributes" +_GL_ATTRIBUTE_MAYBE_UNUSED +static void +_GL_ATTRIBUTE_ALWAYS_INLINE +_GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 3, 4)) +_gl_inline_error (int __status, int __errnum, const char *__format, ...) +{ + return error (__status, __errnum, __format, __builtin_va_arg_pack ()); +} +# pragma GCC diagnostic pop +# undef error +# define error(status, ...) \ + __gl_error_call (_gl_inline_error, status, __VA_ARGS__) +# endif +# else +# define error(status, ...) \ + __gl_error_call (error, status, __VA_ARGS__) +# endif # endif #endif #if __GLIBC__ >= 2 @@ -146,8 +167,30 @@ _GL_CXXALIAS_SYS (error_at_line, void, (int __status, int __errnum, const char *__filename, unsigned int __lineno, const char *__format, ...)); # ifndef _GL_NO_INLINE_ERROR -# define error_at_line(status, ...) \ - __gl_error_call (error_at_line, status, __VA_ARGS__) +# ifdef error_at_line +/* Only gcc ≥ 4.7 has __builtin_va_arg_pack. */ +# if _GL_GNUC_PREREQ (4, 7) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wattributes" +_GL_ATTRIBUTE_MAYBE_UNUSED +static void +_GL_ATTRIBUTE_ALWAYS_INLINE +_GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 5, 6)) +_gl_inline_error_at_line (int __status, int __errnum, const char *__filename, + unsigned int __lineno, const char *__format, ...) +{ + return error_at_line (__status, __errnum, __filename, __lineno, __format, + __builtin_va_arg_pack ()); +} +# pragma GCC diagnostic pop +# undef error_at_line +# define error_at_line(status, ...) \ + __gl_error_call (_gl_inline_error_at_line, status, __VA_ARGS__) +# endif +# else +# define error_at_line(status, ...) \ + __gl_error_call (error_at_line, status, __VA_ARGS__) +# endif # endif #endif _GL_CXXALIASWARN (error_at_line);