https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111708
--- Comment #4 from Kirill Frolov <k.frolov at samsung dot com> --- With updated source ICC still gives an error. MSVC works from my point of view correcly, same as Clang. Lets see to a C-standard (https://files.lhmouse.com/standards/ISO%20C%20N2176.pdf), section 6.2.2 states that: | 4) For an identifier declared with the storage-class specifier extern | in a scope in which a prior declaration of that identifier is visible [31] | if the prior declaration specifies internal or external linkage, | the linkage of the identifier at the later declaration is the same as | the linkage specified at the prior declaration. If no prior declaration | _is_ _visible_, or if the prior declaration specifies no linkage, then the | identifier has external linkage. | [31] As specified in 6.2.1, the later declaration might hide the | prior declaration. Lets see section 6.2.1: | 4) ... Within the inner scope, the identifier designates the entity | declared in the inner scope; the entity declared in the outer scope | is hidden (and _not_ _visible_) within the inner scope. As a result, I must conclude that GCC generates code right, but Clang, MSVC and ICC works incorrectly. But this happens with "-Os" options. With "-O0" option GCC generates _wrong_ _code_, as it avoids calling of _external_ function (https://godbolt.org/z/6GbPdc9vT): main: push rbp mov rbp, rsp sub rsp, 16 mov DWORD PTR [rbp-4], edi mov QWORD PTR [rbp-16], rsi mov eax, DWORD PTR [rbp-4] mov edi, eax call f leave ret f: push rbp mov rbp, rsp sub rsp, 32 mov DWORD PTR [rbp-20], edi mov eax, DWORD PTR [rbp-20] mov DWORD PTR [rbp-4], eax cmp DWORD PTR [rbp-4], 0 jg .L4 mov eax, 0 jmp .L5 .L4: mov eax, DWORD PTR [rbp-4] sub eax, 1 mov edi, eax call f .L5: leave ret In any case, GCC generated different code with -O0 and -Os, and such behaviour is definitely a bug.