http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33763
--- Comment #31 from Richard Guenther <rguenth at gcc dot gnu.org> 2012-01-13 09:26:45 UTC --- Ok, so the following patch makes extern __inline __attribute__ ((__always_inline__)) void open () { } void bar () { open (); } void open () { open (); } "work" as in the extern inline variant is used for the callin bar() and the call in open () is recursive and all following calls would refer to it. That means, we end up with two cgraph nodes (but do not magically use one for inlining and one for the offline copy - that would need to be fixed in the C frontend by _not_ changing name-lookup to lookup the 2nd version, but I'm not sure that is desired). At least you can say the behavior makes sense and it avoids the ICEs, too. I'm going to test this. Index: gcc/c-decl.c =================================================================== --- gcc/c-decl.c (revision 183121) +++ gcc/c-decl.c (working copy) @@ -2513,6 +2513,24 @@ duplicate_decls (tree newdecl, tree oldd return false; } + /* If we have a redeclared extern inline function simply drop olddecl + on the floor instead of merging it with newdecl. */ + if (TREE_CODE (newdecl) == FUNCTION_DECL + && DECL_INITIAL (newdecl) + && DECL_INITIAL (olddecl) + && !(!(DECL_DECLARED_INLINE_P (olddecl) + && DECL_EXTERNAL (olddecl)) + || (DECL_DECLARED_INLINE_P (newdecl) + && DECL_EXTERNAL (newdecl)) + || (!flag_gnu89_inline + && (!DECL_DECLARED_INLINE_P (olddecl) + || !lookup_attribute ("gnu_inline", + DECL_ATTRIBUTES (olddecl))) + && (!DECL_DECLARED_INLINE_P (newdecl) + || !lookup_attribute ("gnu_inline", + DECL_ATTRIBUTES (newdecl)))))) + return false; + merge_decls (newdecl, olddecl, newtype, oldtype); return true; }