https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114262
--- Comment #4 from LIU Hao <lh_mouse at 126 dot com> --- (In reply to Andrew Pinski from comment #3) > It looks like it has been this way since r0-37737-g4838c5ee553f06 (2001) (or > rather that is when it was used by the tree inline; I don't want to dig > further back to understand the RTL inliner). So looks like this is just > missing documentation ... It's not just about `gnu_inline`. If we switch to C++ inline we get the same result: (https://gcc.godbolt.org/z/ehbjqj5xh) ``` struct impl; struct impl* get_impl(int key); int get_value(struct impl* p); extern inline int get_value_by_key(int key) { struct impl* p = get_impl(key); if(!p) return -1; return get_value(p); } int real_get_value_by_key(int key) { return get_value_by_key(key); } ``` GCC outputs: ``` real_get_value_by_key(int): push rsi call get_impl(int) test rax, rax je .L2 mov rdi, rax pop rcx jmp get_value(impl*) .L2: or eax, -1 pop rdx ret ``` If we switched to C99 `extern inline` then it would produce desired result: ``` get_value_by_key: push rsi call get_impl test rax, rax je .L2 mov rdi, rax pop rcx jmp get_value .L2: or eax, -1 pop rdx ret real_get_value_by_key: jmp get_value_by_key `` The only difference between the C99 `extern inline` and C++ `extern inline` is that the C++ external definition is COMDAT.