Background: =========== In the Linux kernel one often sees the following idiom:
static void foo_func(void) { } static struct foo_type foo_struct = { .foo_call = foo_func, }; some_init_func(...) { register_foo(&foo_struct); } some_exit_func(...) { unregister_foo(&foo_struct); } The point is that {un}register_foo() may be a configuration-dependent functions that may either be externally-implemented-in-another-module or, if that configuration item is turned off, resolve to empty stubs defined in a header itself. [ The empty stubs may be do-nothing macros, or often static inline functions with empty bodies. ] The expectation is that, when defined as empty stubs, because there is effectively no reference left to the static foo_struct and, transitively, to the static foo_func, the optimizer must just optimize them away completely. Problem: ======== The expectation holds true, when the empty stubs are defined as empty do {} while (0); macros, but not if defined as empty "static inline int ... {return 0;}" functions. Testcase: ========= I think the below (with given commentary) is self-explanatory: /* gcc -Wall -Os -S */ struct abc { void (*abc_call)(void); }; /* * Use only any one of the three definitions below at a time: * * 1. nothing optimized away. Good. * 2. call_func() _not_ optimized away, but struct xyz is. gcc disappoints. * 3. both call_func() and struct xyz optimized away. Nice. */ /* 1 */ /*extern int do_register(struct abc *xyz);*/ /* 2 */ static inline int do_register(struct abc *xyz) { return 0; } /* 3 */ /*#define do_register(xyz) do { (void)(xyz); } while (0)*/ static void call_func(void) { } static struct abc xyz = { .abc_call = call_func, }; void func(void) { do_register(&xyz); } Assembler for problematic case: =============================== .file "xyz.c" .text .type call_func, @function call_func: pushl %ebp movl %esp, %ebp popl %ebp ret .size call_func, .-call_func .globl func .type func, @function func: pushl %ebp movl %esp, %ebp popl %ebp ret .size func, .-func .ident "GCC: (GNU) 4.1.1 20070105 (Red Hat 4.1.1-51)" .section .note.GNU-stack,"",@progbits As you can see, there is nobody referencing the static call_func() in this object file, and being static, there can be none in others either. Why did we fail to just elid it away completely? [ Interestingly, the equally-unreferenced static struct xyz _did_ get elided away. But not so the static function. ] -- Summary: Optimizer fails to elid away unreferenced static function Product: gcc Version: 4.1.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: rtl-optimization AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: satyam at infradead dot org GCC host triplet: i386-redhat-linux GCC target triplet: i386-redhat-linux http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33172