Function types with different language linkages are distinct types ([dcl.link]/1). There is no conversion between them, so we should at warn and/or error when such a conversion is attempted: void foo(); extern "C++" { void (*bar) () = &foo; }
(In reply to comment #0) > Function types with different language linkages are distinct types > ([dcl.link]/1). There is no conversion between them, so we should at warn > and/or error when such a conversion is attempted: > > void foo(); > extern "C++" { void (*bar) () = &foo; } I assume that you meant: void foo(); extern "C" { void (*bar) () = &foo; } so that the function pointer and function have different language linkage. I totally agree that you are correct. However, I'm terrified of actually enforcing this rule, because doing it properly means making language linkage part of the canonical type, which is going to break a ton of code. For example, stdlib.h on most platforms defined malloc as: extern "C" { void *malloc(size_t); } and then brought into namespace std with: namespace std { using std::malloc; } alas, it still has C linkage, so good luck taking the address of it and putting it into a function pointer with C++ linkage. We'd have to try it to see how badly things break, but GCC doesn't distinguish language linkage and EDG doesn't do it when in GCC mode. I see two possible options: - Do the right thing w.r.t. language linkage for function types (by adding it into the canonical type system), but only when we're in some pedantic mode. - Introduce language linkage into the non-canonical function types the same way we cope with exception specifications, so that we diagnose collisions without making them part of the canonical type system. Both are about the same amount of work, and of course we could introduce a flag to let the user decide which way to go.
There are a whole bunch of errors with linkage that aren't diagnosed. For example: void bar(); extern "C" void bar(); // error redeclaration with different linkage --- void foo(void (*)()) {} extern "C" void bar(); int main() { foo(bar); // error, calling function with argument of wrong type } --- extern "C" int i; // not a definition [dcl.link] 7.5p7 int main() { i = 1; // error, no definition } And here's some legal code that is treated as an error: extern "C" typedef void (*func)(); void foo(func) {} void foo(void (*)()) {} // okay, different type GCC correctly diagnoses the redeclaration with different linkage and sees extern "C" int i; as a declaration only (I used ideone.com), so some improvement is possible without breaking too much.
(In reply to comment #1) > We'd have to try it to see how badly things break, but GCC doesn't > distinguish language linkage and EDG doesn't do it when in GCC mode. I see > two possible options: > > - Do the right thing w.r.t. language linkage for function types (by adding > it into the canonical type system), but only when we're in some pedantic > mode. > - Introduce language linkage into the non-canonical function types the > same way we cope with exception specifications, so that we diagnose > collisions without making them part of the canonical type system. Third option: we follow the direction of core issue 1555, make the language linkage part of the canonical type, and support implicit conversions between C and C++ language linkage function pointers/references as a qualification conversion on platforms where the calling convention is the same (that is, all platforms we support). It would be good to test out a patch for this and find if this approach is workable, so we can provide feedback to EWG on core issue 1555.
(In reply to comment #3) > Third option: we follow the direction of core issue 1555, make the language > linkage part of the canonical type, and support implicit conversions between > C and C++ language linkage function pointers/references as a qualification > conversion on platforms where the calling convention is the same (that is, > all platforms we support). > > It would be good to test out a patch for this and find if this approach is > workable, so we can provide feedback to EWG on core issue 1555. That sounds extremely similar to what the Sun/Oracle compiler does, so that's a strong indication that it should be workable. In gcc, I had a rough patch ( http://gcc.gnu.org/bugzilla/show_bug.cgi?id=2316 ) that also made linkage part of the canonical type and supported some conversions in a more ad-hoc way, which also allowed conversion between extern"C"** and extern"C++"** (as opposed to what happens with "const" or what Sun's compiler does) so that the resulting compiler could compile the whole gcc, but gave them the lowest priority, to remain closer to the current standard. One non-obvious case is the deduction of F(T...) from an extern "C" function. However, I gave up on this when I saw how much weight people put on binary compatibility, which this can hardly avoid breaking :-( (I sometimes wondered if allowing casts between functions with different linkage without allowing to silently use one for the other (the double pointer thing, for instance) was so that the compiler could in theory generate wrappers, but probably not) Note that functions with different calling conventions (fastcall, thiscall, etc on windows) could use the same mechanism (without allowing conversions, I guess).