My reading of the C++11-and-beyond Standard is that the name of a function with extern "C" language linkage declared in an unnamed namespace should have internal linkage: Per [basic.link], it has the same linkage as the enclosing unnamed namespace (i.e., internal). And [dcl.link]'s "A declaration directly contained in a linkage-specification is treated as if it contains the extern specifier..." is irrelevant, as even a function declared with the "extern" storage specifier in an unnamed namespace has internal linkage. (See also <https://groups.google.com/a/isocpp.org/forum/#!topic/std-discussion/oyLCkCUKpfU> "Linkage of: namespace { extern "C" { void f() {} } }".) That is, with test.cc being void external01() {} extern void external02() {} static void internal03() {} extern "C" void external04() {} extern "C" { void external05() {} } extern "C" { extern void external06() {} } extern "C" { static void internal07() {} } namespace { void internal08() {} } namespace { extern void internal09() {} } namespace { static void internal10() {} } namespace { extern "C" void internal11() {} } namespace { extern "C" { void internal12() {} } } namespace { extern "C" { extern void internal13() {} } } namespace { extern "C" { static void internal14() {} } } all external* should have external linkage and all internal* should have internal linkage when compiled as C++11 or later. But (at least on Linux with recent GCC trunk) > $ gcc/trunk/inst/bin/g++ --version > g++ (GCC) 6.0.0 20160331 (experimental) > Copyright (C) 2016 Free Software Foundation, Inc. > This is free software; see the source for copying conditions. There is NO > warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. > > $ gcc/trunk/inst/bin/g++ -std=c++11 -c test.cc && nm test.o | grep -w T > 0000000000000015 T external04 > 000000000000001c T external05 > 0000000000000023 T external06 > 0000000000000046 T internal11 > 000000000000004d T internal12 > 0000000000000054 T internal13 > 0000000000000000 T _Z10external01v > 0000000000000007 T _Z10external02v shows that internal11--13 erroneously get external linkage.
I haven't checked for other relevant rules in the standard, but Clang and EDG give the same result as G++.
And this means the functions I thought were local to src/c++11/thread.cc are not ... drat.
GCC, clang, ICC, and MSVC all agree they have external linkage.
[dcl.link] p8: "A declaration directly contained in a linkage-specification is treated as if it contains the extern specifier (9.2.2) for the purpose of determining the linkage of the declared name and whether it is a definition. Such a declaration shall not specify a storage class."
Since language linkage of an entity without linkage makes no sense, it wouldn't make sense to even allow specifying language linkage in an unnamed namespace if it did nothing.
Actually I suppose that's not true, since in theory C language linkage gives the function a different type, orthogonal from internal/external/no linkage, but nobody implements that.
This is not very helpful: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2230 A discussion in 2017 concluded that Stephan is correct, but that never made it to the issues list. So confirming as a bug.
Having functions with "C" language linkage (calling convention, etc) but internal linkage is useful for writing callbacks provided to C functions. It's not an significant issue, however, as one can get the same effect by declaring the callback function "static" inside an "extern C" block.
Does these two functions the same name then? ``` namespace a { extern "C" void f(void); } namespace { extern "C" void f(void) {} } void g(void) { f(); a::f(); } ``` It seems counter intuitive that a::f and the ::f map to different functions.
I see no implementation (MSVC, GCC, clang) implements this at all. Here is an example where GCC produces an assembly failure: ``` namespace a { extern "C" void f(void){} } namespace { extern "C" void f(void) {} } int main(void) { f(); a::f(); } ``` It might be handle to implement this even correctly too.
(In reply to Andrew Pinski from comment #9) > Does these two functions the same name then? > ``` > namespace a { > extern "C" void f(void); > } > > namespace { > extern "C" void f(void) {} > } > > void g(void) > { > f(); > a::f(); > } > > ``` > It seems counter intuitive that a::f and the ::f map to different functions. According to [dcl.link] "Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function", so it would seem that both refer to the same function indeed. > Here is an example where GCC produces an assembly failure: > > namespace a { > extern "C" void f(void){} > } > > namespace { > extern "C" void f(void) {} > } If they are the same function then this shouldn't work (it would be a re-definition).
It seems that the current specification is still broken for extern "C" functions with internal linkage.(In reply to Maciej S. Szmigiero from comment #8) > Having functions with "C" language linkage (calling convention, etc) but > internal linkage is useful for writing callbacks provided to C functions. > > It's not an significant issue, however, as one can get the same effect by > declaring the callback function "static" inside an "extern C" block. This is not so useful in practice because most compilers don't make extern "C" and extern "C++" differentiate function types (implying calling conventions etc.). There's a long battle story, and the divergence between the standard and implementations is not resolved yet. See https://cplusplus.github.io/CWG/issues/1555.html https://lists.isocpp.org/sg12/2020/04/0900.php
(In reply to Maciej S. Szmigiero from comment #11) > (In reply to Andrew Pinski from comment #9) > > Does these two functions the same name then? > > ``` > > namespace a { > > extern "C" void f(void); > > } > > > > namespace { > > extern "C" void f(void) {} > > } > > > > void g(void) > > { > > f(); > > a::f(); > > } > > > > ``` > > It seems counter intuitive that a::f and the ::f map to different functions. > > According to [dcl.link] "Two declarations for a function with C language > linkage with the same function name (ignoring the namespace names that > qualify it) that > appear in different namespace scopes refer to the same function", so it > would seem that both refer to the same function indeed. > > > Here is an example where GCC produces an assembly failure: > > > > namespace a { > > extern "C" void f(void){} > > } > > > > namespace { > > extern "C" void f(void) {} > > } > > If they are the same function then this shouldn't work (it would be a > re-definition). Oh, I think they shouldn't be the same function. [dcl.link]/1 says: > All functions and variables whose names have external linkage and all > function types have a language linkage. which implies that a function with internal linkage doesn't have a language linkage, and thus [dcl.link]/7 doesn't apply to it.
> This is not so useful in practice because most compilers don't make extern "C" and extern "C++" differentiate function types (implying calling conventions etc.). The standard allows different calling conventions for "C" and "C++" language linkage and that's what matters when writing standard-compliant code - one shouldn't write to a particular implementation (or implementations). > > All functions and variables whose names have external linkage and all > > function types have a language linkage. > > which implies that a function with internal linkage doesn't have a language > linkage, and thus [dcl.link]/7 doesn't apply to it. Nothing in the above quote says that *only* these specified have a language linkage, just that these explicitly enumerated sure do.
(In reply to Maciej S. Szmigiero from comment #14) > > This is not so useful in practice because most compilers don't make extern "C" and extern "C++" differentiate function types (implying calling conventions etc.). > > The standard allows different calling conventions for "C" and "C++" language > linkage and that's what matters when writing standard-compliant code - one > shouldn't write to a particular implementation (or implementations). > The problem in pratice is that most implementations are not standard-compliant here. If you rely on the standard guarantee that extern "C" and extern "C++" make function types different, you probably get compilation errors. > > > All functions and variables whose names have external linkage and all > > > function types have a language linkage. > > > > which implies that a function with internal linkage doesn't have a language > linkage, and thus [dcl.link]/7 doesn't apply to it. > > Nothing in the above quote says that *only* these specified have a language > linkage, just that these explicitly enumerated sure do. I think the italic style is "the thing", which should mean that the term "language linkage" is introduced and restricted here.
> If you rely on the standard guarantee that extern "C" and extern "C++" make function types different, you probably get compilation errors. It's the other way around - functions in standard-compliant code should have proper language linkage markings (including implicit markings). They are needed in case some compiler or platform decides that, for example, "C" and "C++" language linkages need to have different calling conventions. Which is something that the standard allows. However, this bug is about having internal linkage for all anonymous namespace functions (including the ones declared with "C" language linkage) - whether "C" and "C++" language linkages should be allowed to have different calling conventions is a different matter.