make error()'s constant return value more visible
When git is compiled with "gcc -Wuninitialized -O3", some
inlined calls provide an additional opportunity for the
compiler to do static analysis on variable initialization.
For example, with two functions like this:
  int get_foo(int *foo)
  {
	if (something_that_might_fail() < 0)
		return error("unable to get foo");
	*foo = 0;
	return 0;
  }
  void some_fun(void)
  {
	  int foo;
	  if (get_foo(&foo) < 0)
		  return -1;
	  printf("foo is %d\n", foo);
  }
If get_foo() is not inlined, then when compiling some_fun,
gcc sees only that a pointer to the local variable is
passed, and must assume that it is an out parameter that
is initialized after get_foo returns.
However, when get_foo() is inlined, the compiler may look at
all of the code together and see that some code paths in
get_foo() do not initialize the variable. As a result, it
prints a warning. But what the compiler can't see is that
error() always returns -1, and therefore we know that either
we return early from some_fun, or foo ends up initialized,
and the code is safe.  The warning is a false positive.
If we can make the compiler aware that error() will always
return -1, it can do a better job of analysis. The simplest
method would be to inline the error() function. However,
this doesn't work, because gcc will not inline a variadc
function. We can work around this by defining a macro. This
relies on two gcc extensions:
  1. Variadic macros (these are present in C99, but we do
     not rely on that).
  2. Gcc treats the "##" paste operator specially between a
     comma and __VA_ARGS__, which lets our variadic macro
     work even if no format parameters are passed to
     error().
Since we are using these extra features, we hide the macro
behind an #ifdef. This is OK, though, because our goal was
just to help gcc.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
			
			
				maint
			
			
		
							parent
							
								
									bfae342c97
								
							
						
					
					
						commit
						e208f9cc75
					
				|  | @ -288,6 +288,17 @@ extern NORETURN void die_errno(const char *err, ...) __attribute__((format (prin | |||
| extern int error(const char *err, ...) __attribute__((format (printf, 1, 2))); | ||||
| extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2))); | ||||
|  | ||||
| /* | ||||
|  * Let callers be aware of the constant return value; this can help | ||||
|  * gcc with -Wuninitialized analysis. We have to restrict this trick to | ||||
|  * gcc, though, because of the variadic macro and the magic ## comma pasting | ||||
|  * behavior. But since we're only trying to help gcc, anyway, it's OK; other | ||||
|  * compilers will fall back to using the function as usual. | ||||
|  */ | ||||
| #ifdef __GNUC__ | ||||
| #define error(fmt, ...) (error((fmt), ##__VA_ARGS__), -1) | ||||
| #endif | ||||
|  | ||||
| extern void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params)); | ||||
| extern void set_error_routine(void (*routine)(const char *err, va_list params)); | ||||
|  | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Jeff King
						Jeff King