http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59626
--- Comment #13 from Richard Biener <rguenth at gcc dot gnu.org> --- (In reply to Markus Trippelsdorf from comment #12) > Created attachment 32210 [details] > Unreduced testcase > > Here's the unreduced testcase: > > markus@x4 coreutils % gcc -std=gnu99 -flto -O2 cp.i copy.i areadlinkat.i > careadlinkat.i linkat.i > /usr/include/bits/unistd.h: In function ‘careadlinkat.constprop’: > /usr/include/bits/unistd.h:173:42: error: inlining failed in call to > always_inline ‘readlinkat’: recursive inlining > __NTH (readlinkat (int __fd, const char *__restrict __path, > ^ > /usr/include/bits/unistd.h:185:3: error: called from here > return __readlinkat_alias (__fd, __path, __buf, __len); > ^ > lto-wrapper: /usr/x86_64-pc-linux-gnu/gcc-bin/4.9.0/gcc returned 1 exit > status > /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.0/../../../../x86_64-pc-linux-gnu/bin/ > ld: fatal error: lto-wrapper failed > collect2: error: ld returned 1 exit status Confirmed with that testcase. (it doesn't link though - files are missing?) cgraph merging does Replacing cgraph node __readlinkat_alias/183 by readlinkat/181 for symbol readlinkat I think it's caused by IPA-CP which does Evaluating opportunities for careadlinkat/187. - Creating a specialized node of careadlinkat/187 for all known contexts. replacing param fd with const -100 replacing param buffer with const 0B replacing param buffer_size with const 0 replacing param alloc with const 0B replacing param preadlinkat with const readlinkat Accounting size:45.00, time:231.11 on predicate:(true) Accounting size:3.00, time:2.00 on new predicate:(not inlined) the new node is careadlinkat.constprop.5/106. ipa-prop: Discovered an indirect call to a known target (careadlinkat.constprop.5/106 -> readlinkat/181), for stmt with uid 2 and then IPA inlining decides Considering readlinkat with 27 size Estimating body: readlinkat/181 Known to be false: not inlined size:24 time:19 to be inlined into careadlinkat.constprop.5 in unknown:-1 Estimated growth after inlined into all is +36 insns. Estimated badness is -2147483648, frequency 16.39. Accounting size:4.00, time:55.21 on predicate:(true) Processing frequency readlinkat Called by careadlinkat.constprop.5 that is normal or hot enqueuing call readlinkat/130 -> readlinkat/181, badness -2147483648 (!) So it is IPA inlining that follows aliases bogously. The alias target is _not_ the non-prevailing extern inline function. OTOH coreutils is walking on shaking grounds (or glibc is) as it takes the address of an always-inline function. That address-taking should probably refer to an extern decl instead (and we are wrong to identify it with the readlinkat variant with body at LTO time). Btw, the LTO symbol table looks good to me. Still somehow the inline body prevails ... :/ /* If there's not a prevailing symbol yet it's an external reference. Happens a lot during ltrans. Choose the first symbol with a cgraph or a varpool node. */ if (!prevailing) { ... /* For variables prefer the non-builtin if one is available. */ else if (TREE_CODE (prevailing->decl) == FUNCTION_DECL) { for (e = first; e; e = e->next_sharing_asm_name) if (TREE_CODE (e->decl) == FUNCTION_DECL && !DECL_BUILT_IN (e->decl) && lto_symtab_symbol_p (e)) { prevailing = e; break; } Now it is readlinkat $22 = {type = SYMTAB_FUNCTION, resolution = LDPR_RESOLVED_DYN, definition = 1, alias = 0, weakref = 0, cpp_implicit_alias = 0, analyzed = 1, externally_visible = 0, force_output = 0, forced_by_abi = 0, unique_name = 0, used_from_other_partition = 0, in_other_partition = 0, address_taken = 1, order = 777, decl = 0x7ffff6dfc300, next = 0x7ffff6e19668, previous = 0x7ffff6e19a40, next_sharing_asm_name = 0x7ffff6e19b88, previous_sharing_asm_name = 0x0, same_comdat_group = 0x0, ref_list = {references = 0x0, referring = { m_vec = 0x1ddfe00}}, alias_target = 0x0, lto_file_data = 0x7ffff7fe1000, aux = 0x0} that prevails, not the alias $23 = {type = SYMTAB_FUNCTION, resolution = LDPR_UNKNOWN, definition = 0, alias = 0, weakref = 0, cpp_implicit_alias = 0, analyzed = 0, externally_visible = 0, force_output = 0, forced_by_abi = 0, unique_name = 0, used_from_other_partition = 0, in_other_partition = 0, address_taken = 0, order = 792, decl = 0x7ffff6dfc500, next = 0x7ffff6e19a40, previous = 0x7ffff6e19cd0, next_sharing_asm_name = 0x0, previous_sharing_asm_name = 0x7ffff6e198f8, same_comdat_group = 0x0, ref_list = {references = 0x0, referring = { m_vec = 0x0}}, alias_target = 0x0, lto_file_data = 0x7ffff7fe1000, aux = 0x0} and we replace its cgraph node *readlinkat/792 (__readlinkat_alias) @0x7ffff6e19b88 Type: function Visibility: external public previous sharing asm name: 777 References: Referring: Read from file: areadlinkat.o First run: 0 Function flags: Called by: readlinkat/777 (0.68 per call) Calls: by readlinkat/777 (readlinkat) @0x7ffff6e198f8 Type: function definition analyzed Visibility: resolved_dyn external public next sharing asm name: 792 Address is taken. References: Referring: areadlinkat/786 (addr) Read from file: areadlinkat.o First run: 0 Function flags: Called by: Calls: *readlinkat/792 (0.68 per call) *__readlinkat_chk/791 (0.14 per call) *__readlinkat_chk/791 (0.18 per call) __builtin_constant_p/789 (0.86 per call) __builtin_object_size/788 (1.00 per call) Note that I think the resolved_dyn should be on the alias, not the inline body (wouldn't help here I guess, but at least we could choose the one the linker chose ...). Index: gcc/lto/lto-symtab.c =================================================================== --- gcc/lto/lto-symtab.c (revision 208114) +++ gcc/lto/lto-symtab.c (working copy) @@ -476,7 +476,8 @@ lto_symtab_merge_decls_1 (symtab_node *f for (e = first; e; e = e->next_sharing_asm_name) if (TREE_CODE (e->decl) == FUNCTION_DECL && !DECL_BUILT_IN (e->decl) - && lto_symtab_symbol_p (e)) + && lto_symtab_symbol_p (e) + && !e->analyzed) { prevailing = e; break; fixes it in an awkward way (don't prevail a function with body that wasn't chosen by the linker). Not sure if we have to add a fallback then. (I'd rather chose the symbol with LDPR_RESOLVED_DYN but that's the wrong one ...?).