i have a function "foo". its header sets up an always_inline function that does sanity checks when constants are involved. otherwise it delays the non-constant checking to another function. here is the portion from the header: extern void foo(int i); extern void __in(int i); extern inline __attribute__((always_inline)) void foo(int i) { __in(i); } where i actually define "foo", there is an alias used to setup multiple symbols. also in that file is another function which calls the inline checking function. together, gcc barfs. here is the portion of the file: void bar(int i) { foo(i + 1234); } void __foo(int i) {} extern typeof(__foo) foo __attribute__((alias("__foo"))); combine them into one and compile like so (this is 4.5.1): gcc -O2 -c test.c -std=gnu99 -fgnu89-inline -Winline this produces the error: test.c: In function ‘bar’: test.c:18:22: sorry, unimplemented: inlining failed in call to ‘foo’: function body not available test.c:14:5: sorry, unimplemented: called from here that doesnt seem right since the function body *is* available. if i split the __foo/foo definitions into their own dedicated file, then everything compiles just fine as i'd expect. what's even more odd though is that -Winline affects code generation. if you compile without that flag, you dont get any errors, but the generated code is wrong: gcc -O2 -c test.c -std=gnu99 -fgnu89-inline objdump -dr test.o ... 0000000000000000 <bar>: 0: 81 c7 d2 04 00 00 add $0x4d2,%edi 6: e9 00 00 00 00 jmpq b <bar+0xb> 7: R_X86_64_PC32 foo-0x4 b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) ... clearly it's just jumping straight to the definition of foo rather than going through the inline function. doesnt seem to be a regression ... every gcc version ive tested fails in the same way: 4.0.4, 4.1.2, 4.2.4, 4.3.5, 4.4.4, 4.5.1. versions before 4.2.x had the -fgnu89-inline flag dropped since that was the default behavior and so was unnecessary (and unrecognized).
Created attachment 22479 [details] example file
Confirmed. That -Winline changes behavior is definitely a bug. I'm not so sure about the rest, what probably happens is that the later extern declaration overrides the former (but inherits the always-inline attribute), removing the body. What you seem to want is always inline foo(), but still have an out-of-line copy that dispatches to __foo. That seems - backward, no? Complete testcase: extern void __in(int i); extern inline __attribute__((always_inline,gnu_inline)) void foo(int i) { __in(i); } void bar(int i) { foo(i + 1234); } void __foo(int i) { } extern void foo(int i) __attribute__((alias("__foo"))); > ./cc1 -quiet /tmp/t.c -O -Winline /tmp/t.c: In function 'bar': /tmp/t.c:6:13: sorry, unimplemented: inlining failed in call to 'foo': function body not available /tmp/t.c:4:22: sorry, unimplemented: called from here expected: bar calls __in (i + 1234).
i want to provide two symbols -- one that may be overridden and one that always exists. that's the point of having "__foo" be the normal symbol and "foo" being the alias. for people calling foo(), i want them to always use the inline one to get the extra (but not required) checking.
glibc runs into the "sorry, unimplemented" part of the issue, with delta-reduced code like: $ cat test.i typedef __builtin_va_list __gnuc_va_list; extern __inline __attribute__ ((__always_inline__)) __attribute__ ((__artificial__)) void syslog (int __pri, const char *__fmt, ...) { }; typedef __gnuc_va_list va_list; void __syslog(int pri, const char *fmt, ...) { } extern __typeof (__syslog) syslog __attribute__ ((alias ("__syslog"))); void __vsyslog_chk(int pri, int flag, const char *fmt, va_list ap) { if (pri & ~(0x07|0x03f8)) { syslog(3|0x02|0x20|0x01, "syslog: unknown facility/priority: %x", pri); } } $ gcc -c -O2 -Winline test.i test.i: In function ‘__vsyslog_chk’: test.i:7:28: sorry, unimplemented: inlining failed in call to ‘syslog’: function body not available test.i:10:11: sorry, unimplemented: called from here $ gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6.1/lto-wrapper Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.1-9ubuntu3' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++,go --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-plugin --enable-objc-gc --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix gcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3) I haven't yet built a gcc from head to make sure the behavior is there without Ubuntu's patches. The glibc problem was described at http://plash.beasts.org/wiki/GlibcBuildIssues#head-b9149fbab065967691cf1bade23d84325c05e9b0 and reported at http://sourceware.org/bugzilla/show_bug.cgi?id=10375, but it looks like a gcc problem to me.
> glibc runs into the "sorry, unimplemented" part of the issue, with > delta-reduced code like: > > $ cat test.i > typedef __builtin_va_list __gnuc_va_list; > extern __inline __attribute__ ((__always_inline__)) __attribute__ > ((__artificial__)) void syslog (int __pri, const char *__fmt, ...) { > }; > typedef __gnuc_va_list va_list; > void __syslog(int pri, const char *fmt, ...) { > } > extern __typeof (__syslog) syslog __attribute__ ((alias ("__syslog"))); The problem here seems to be that typeof copies always inline attribute. GCC before version 4.7 do not see through aliases and thus it has always inline function that is alias but it can not see the body. So the message is correct. GCC 4.7 newly understands alaises, but this was major change of the internal representation and can not be backported. For older GCC, i think only workaround is to call __syslog instead of syslog or drop the idea of using always iline here. Extern inlines will be inlined anyway. Honza
(In reply to comment #4) yes, the source of this bug was the glibc code which i reduced even further into the testcase posted originally (In reply to comment #5) if gcc-4.7 works fine with the proposed code, then i'm fine with that. we already have workarounds in place for those.
*** Bug 59197 has been marked as a duplicate of this bug. ***