Bug 46596 - misbehavior when mixing always_inline and alias attributes in the same compilation unit
Summary: misbehavior when mixing always_inline and alias attributes in the same compil...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: ipa (show other bugs)
Version: 4.5.3
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 59197 (view as bug list)
Depends on:
Blocks:
 
Reported: 2010-11-22 03:48 UTC by Mike Frysinger
Modified: 2024-03-01 23:11 UTC (History)
6 users (show)

See Also:
Host: x86_64-linux-gnu
Target: x86_64-linux-gnu
Build:
Known to work:
Known to fail: 4.0.4, 4.1.2, 4.2.4, 4.3.5, 4.4.4, 4.5.1
Last reconfirmed: 2010-11-22 11:08:59


Attachments
example file (167 bytes, text/plain)
2010-11-22 03:49 UTC, Mike Frysinger
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Mike Frysinger 2010-11-22 03:48:20 UTC
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).
Comment 1 Mike Frysinger 2010-11-22 03:49:52 UTC
Created attachment 22479 [details]
example file
Comment 2 Richard Biener 2010-11-22 11:08:59 UTC
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).
Comment 3 Mike Frysinger 2010-11-22 18:51:09 UTC
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.
Comment 4 Jeffrey Yasskin 2012-02-29 09:41:05 UTC
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.
Comment 5 Jan Hubicka 2012-02-29 15:07:18 UTC
> 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
Comment 6 Mike Frysinger 2012-02-29 16:13:44 UTC
(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.
Comment 7 Andrew Pinski 2024-03-01 23:09:45 UTC
*** Bug 59197 has been marked as a duplicate of this bug. ***