Paul Eggert wrote:
> > Maybe by defining
> > error and error_at_line as inline functions
> 
> They're defined by glibc, no? The definitions might collide.

Yes, they are defined in glibc. Overriding functions without causing
collisions is our core expertise here :)

> Also, I suppose the compiler might not inline them

Indeed, when I attempt to define
  void inline_error (int status, int errnum, const char *fmt, ...) { ... }
gcc does not inline the function, because it never inlines varargs functions.

An alternative would be to define
  void inline_error (int status, int errnum, const char *message) { ... }
and pass xasprintf (fmt, ...) as message argument. But the out-of-memory
handling or the LGPLv2+ / GPL license difference causes problems.

Fortunately, we don't need an inline function: Jim's die() implementation
shows that it can be done with just a macro definition.

> The basic problem is that the old 'error' API doesn't mix well with 
> [[noreturn]] and the like. We could write a new function, "eexit" say, 
> that behaves like "error" except it never returns. (I chose the name 
> "eexit" so as to not mess up the indenting of existing code.)
> 
> Or we could just live with "die", as it works.

While this is definitely working, it has the problem that it pulls
developers away from the glibc API. Things are easier for developers
if they can use the symbols from POSIX or glibc rather than gnulib-
invented symbols. And that is possible here.

Also, the name 'die' has the problem that it may invoke traumatic
memories in some people (like the verb 'kill', but we can't get rid
of this one since it's standardized).


2023-05-27  Bruno Haible  <br...@clisp.org>

        error: Support the compiler's control flow analysis better.
        * lib/error.in.h: Remove @PRAGMA_SYSTEM_HEADER@. Include <stdlib.h>.
        (error): Define as a macro that explicitly invokes exit().
        (error_at_line): Likewise.
        * lib/error.c (_GL_NO_INLINE_ERROR): Define before including error.h.
        * modules/error-h (configure.ac): Don't invoke gl_CONDITIONAL_HEADER.
        (Makefile.am): Generate error.h always. Don't substitute
        PRAGMA_SYSTEM_HEADER.
        * m4/error_h.m4 (gl_ERROR_H): Set COMPILE_ERROR_C instead of
        GL_GENERATE_ERROR_H.
        * modules/error (configure.ac, Depends-on): Test COMPILE_ERROR_C instead
        of GL_GENERATE_ERROR_H.
        * lib/copy-file.c: Revert the last change.

diff --git a/lib/copy-file.c b/lib/copy-file.c
index bd98b35e7e..78da3996bb 100644
--- a/lib/copy-file.c
+++ b/lib/copy-file.c
@@ -180,13 +180,6 @@ qcopy_file_preserving (const char *src_filename, const 
char *dest_filename)
   return err;
 }
 
-/* Silence gcc warnings "this statement may fall through".
-   gcc cannot know that error(), when invoked with a non-zero status argument,
-   will not return.  */
-#if __GNUC__ >= 7
-#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
-#endif
-
 void
 copy_file_preserving (const char *src_filename, const char *dest_filename)
 {
diff --git a/lib/error.c b/lib/error.c
index ef4372875f..9e26391e98 100644
--- a/lib/error.c
+++ b/lib/error.c
@@ -19,6 +19,7 @@
 
 #if !_LIBC
 # include <config.h>
+# define _GL_NO_INLINE_ERROR
 #endif
 
 #include "error.h"
diff --git a/lib/error.in.h b/lib/error.in.h
index 9a520f1ee3..4bf191e102 100644
--- a/lib/error.in.h
+++ b/lib/error.in.h
@@ -18,9 +18,9 @@
 
 #ifndef _@GUARD_PREFIX@_ERROR_H
 
-#if __GNUC__ >= 3
-@PRAGMA_SYSTEM_HEADER@
-#endif
+/* No @PRAGMA_SYSTEM_HEADER@ here, because it would prevent
+   -Wimplicit-fallthrough warnings for missing FALLTHROUGH after error(...)
+   or error_at_line(...) invocations.  */
 
 /* The include_next requires a split double-inclusion guard.  */
 #if @HAVE_ERROR_H@
@@ -38,6 +38,9 @@
 /* Get _GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, _GL_ATTRIBUTE_SPEC_PRINTF_SYSTEM.  
*/
 #include <stdio.h>
 
+/* Get exit().  */
+#include <stdlib.h>
+
 /* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */
 
 #if GNULIB_VFPRINTF_POSIX
@@ -63,6 +66,11 @@ _GL_FUNCDECL_RPL (error, void,
                   _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 3, 
4)));
 _GL_CXXALIAS_RPL (error, void,
                   (int __status, int __errnum, const char *__format, ...));
+# ifndef _GL_NO_INLINE_ERROR
+#  undef error
+#  define error(status, ...) \
+     ((rpl_error)(0, __VA_ARGS__), (status) ? exit (status) : (void)0)
+# endif
 #else
 # if ! @HAVE_ERROR@
 _GL_FUNCDECL_SYS (error, void,
@@ -71,6 +79,10 @@ _GL_FUNCDECL_SYS (error, void,
 # endif
 _GL_CXXALIAS_SYS (error, void,
                   (int __status, int __errnum, const char *__format, ...));
+# ifndef _GL_NO_INLINE_ERROR
+#  define error(status, ...) \
+     ((error)(0, __VA_ARGS__), (status) ? exit (status) : (void)0)
+# endif
 #endif
 #if __GLIBC__ >= 2
 _GL_CXXALIASWARN (error);
@@ -90,6 +102,11 @@ _GL_FUNCDECL_RPL (error_at_line, void,
 _GL_CXXALIAS_RPL (error_at_line, void,
                   (int __status, int __errnum, const char *__filename,
                    unsigned int __lineno, const char *__format, ...));
+# ifndef _GL_NO_INLINE_ERROR
+#  undef error_at_line
+#  define error_at_line(status, ...) \
+     ((rpl_error_at_line)(0, __VA_ARGS__), (status) ? exit (status) : (void)0)
+# endif
 #else
 # if ! @HAVE_ERROR_AT_LINE@
 _GL_FUNCDECL_SYS (error_at_line, void,
@@ -100,6 +117,10 @@ _GL_FUNCDECL_SYS (error_at_line, void,
 _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, ...) \
+     ((error_at_line)(0, __VA_ARGS__), (status) ? exit (status) : (void)0)
+# endif
 #endif
 _GL_CXXALIASWARN (error_at_line);
 
diff --git a/m4/error_h.m4 b/m4/error_h.m4
index f38e4ead13..e8a58f6fbd 100644
--- a/m4/error_h.m4
+++ b/m4/error_h.m4
@@ -1,4 +1,4 @@
-# error_h.m4 serial 3
+# error_h.m4 serial 4
 dnl Copyright (C) 1996-2023 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -112,10 +112,9 @@ AC_DEFUN_ONCE([gl_ERROR_H]
 
   if test $HAVE_ERROR = 0 || test $REPLACE_ERROR = 1 \
      || test $HAVE_ERROR_AT_LINE = 0 || test $REPLACE_ERROR_AT_LINE = 1; then
-    dnl Provide a substitute <error.h> file.
-    GL_GENERATE_ERROR_H=true
+    COMPILE_ERROR_C=1
   else
-    GL_GENERATE_ERROR_H=false
+    COMPILE_ERROR_C=0
   fi
 
   AC_SUBST([HAVE_ERROR])
diff --git a/modules/error b/modules/error
index 5f716865a9..63317f1821 100644
--- a/modules/error
+++ b/modules/error
@@ -9,14 +9,14 @@ Depends-on:
 error-h
 stdio
 getprogname
-strerror        [test $GL_GENERATE_ERROR_H = true]
-unistd          [test $GL_GENERATE_ERROR_H = true]
-msvc-nothrow    [test $GL_GENERATE_ERROR_H = true]
+strerror        [test $COMPILE_ERROR_C = 1]
+unistd          [test $COMPILE_ERROR_C = 1]
+msvc-nothrow    [test $COMPILE_ERROR_C = 1]
 
 configure.ac:
 AC_REQUIRE([gl_ERROR_H])
 gl_ERROR
-gl_CONDITIONAL([GL_COND_OBJ_ERROR], [test $GL_GENERATE_ERROR_H = true])
+gl_CONDITIONAL([GL_COND_OBJ_ERROR], [test $COMPILE_ERROR_C = 1])
 AM_COND_IF([GL_COND_OBJ_ERROR], [
   gl_PREREQ_ERROR
 ])
diff --git a/modules/error-h b/modules/error-h
index a84d8e2705..b6618d3c76 100644
--- a/modules/error-h
+++ b/modules/error-h
@@ -11,22 +11,18 @@ snippet/c++defs
 
 configure.ac:
 gl_ERROR_H
-gl_CONDITIONAL_HEADER([error.h])
 AC_PROG_MKDIR_P
 
 Makefile.am:
-BUILT_SOURCES += $(ERROR_H)
+BUILT_SOURCES += error.h
 
-# We need the following in order to create <error.h> when the system
-# doesn't have one that works.
-if GL_GENERATE_ERROR_H
+# We need the following in order to override <error.h>.
 error.h: error.in.h $(top_builddir)/config.status $(CXXDEFS_H)
 @NMD@  $(AM_V_GEN)$(MKDIR_P) '%reldir%'
        $(gl_V_at)$(SED_HEADER_STDOUT) \
              -e 's|@''GUARD_PREFIX''@|${gl_include_guard_prefix}|g' \
              -e 's|@''HAVE_ERROR_H''@|$(HAVE_ERROR_H)|g' \
              -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
-             -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
              -e 's|@''NEXT_ERROR_H''@|$(NEXT_ERROR_H)|g' \
              -e 's|@''HAVE_ERROR''@|$(HAVE_ERROR)|g' \
              -e 's|@''HAVE_ERROR_AT_LINE''@|$(HAVE_ERROR_AT_LINE)|g' \
@@ -35,10 +31,6 @@ error.h: error.in.h $(top_builddir)/config.status 
$(CXXDEFS_H)
              -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
              $(srcdir)/error.in.h > $@-t
        $(AM_V_at)mv $@-t $@
-else
-error.h: $(top_builddir)/config.status
-       rm -f $@
-endif
 MOSTLYCLEANFILES += error.h error.h-t
 
 Include:




Reply via email to