http://gcc.gnu.org/bugzilla/show_bug.cgi?id=2316
--- Comment #53 from Harald van Dijk <harald at gigawatt dot nl> --- (In reply to Marc Glisse from comment #52) > (In reply to Harald van Dijk from comment #51) > > extern "C" { void f(); } > > typedef void t(); > > t f, *g = f; // valid redeclaration of f, invalid initialisation of g > > Fun! What's fun is that in getting this working, I found not only had I accidentally introduced a bug (already fixed -- the typedef got changed, instead of only the function's type), but that exact same bug also affects in Sun C++. > > extern "C" t f; // invalid redeclaration of f > > I am not 100% sure about that one. It redeclares f as void(), where the previous declaration gave it type void() extern "C", and the special exception in [dcl.link] to inherit a previous declaration's linkage (both of the name and of the type) doesn't apply when the linkage is explicitly specified, right? > > Linkage conflicts with built-in declarations of functions are also a bit of > > a problem: > > Yes, as I said in comment #38 and comment #39, giving builtin functions the > right linkage is a big missing part of the patch. I've got this part working, and found it much easier to reverse the logic: all code using build_function_type gets a C function type. It required just a few more changes of build_function_type to build_function_type2 in the C++ frontend. > > implementing this as described makes GCC fail to compile, > > At least in the version of the patch that is attached to the PR, gcc tries > to accept almost anything except in some pedantic mode. The goal is to avoid > breaking every code on earth, or the patch has no chance of ever being > accepted. I've given it a try on a large number of packages (including Firefox, Chromium, Qt+KDE), and I'm down to five categories of hard errors, four of which IMO should be warnings, but comments on that would be welcome. 1: extern "C" typedef void (*fpt1)() __attribute__((noreturn)); void f1(); fpt1 fp1 = f1; // error: invalid conversion from ‘void (*)()’ to ‘fpt1 {aka void (*)()__attribute__((noreturn)) extern "C"}’ [-fpermissive] This should work, with a warning. The logic to allow an implicit conversion to the corresponding function type with different linkage doesn't work when the attributes differ. 2: extern "C" typedef void (*fpt2)(); template <typename> void f2(); fpt2 fp2 = f2<int>; // error: no matches converting function ‘f2’ to type ‘fpt2 {aka void (*)() extern "C"}’ This should work, with a warning. This possibly has the same underlying cause as what I reported as PR60531, namely that f2<int> is considered an overloaded function even though it isn't. 3: extern "C" void f3(); template <void()> struct S3 { }; template struct S3<f3>; This should work, with a warning. I was worried this might cause a conflict between a C function template argument and a C++ function template argument with the same name, but that cannot ever happen, the only possible way that they could get the same mangled name is if the code is already invalid for other reasons. 4: extern "C" void f4(); struct S4 { S4(void()); private: S4(const S4 &); }; S4 s4(f4); This should work, with a warning, but only after all standard means of constructing S4 have failed. In particular, if another constructor is added that can accept f4's type (say S4(...), or S4(bool)), the other constructor needs to be picked. 5: extern "C" void f5(void()); void f5(void()); void g5() { long p = (long)f5; } This should be considered acceptable breakage. The function f5 in question is actually atexit, which in current glibc is not an overloaded function, but would become an overloaded function, as specified in the standard. Taking its address without any context doesn't give enough information to determine which overload's address should be taken (even though they both have the same address). P.S.: the patch here contains a comment questioning the validity of extern "C" template aliases. I think that a _lot_ more is valid than is currently accepted: 7.5p1: All function types, function names with external linkage, and variable names with external linkage have a language linkage. 14p4: A template name has linkage (3.5). A non-member function template can have internal linkage; any other template name shall have external linkage. [...] A template, a template explicit specialization (14.7.3), and a class template partial specialization shall not have C linkage. A static template function has internal linkage, so doesn't have external linkage, so doesn't have language linkage, so never has C linkage, even if it appears in an extern "C" block. Template classes and template aliases aren't function types, so also never have language linkage, so never have C linkage. The restriction on class template partial specializations suggests that this isn't what the standard intends (they never have C linkage, so why specify that they cannot have C linkage?), but it's useful, and I don't see any other interpretation based on the actual wording, so that is what I've implemented. This avoids the need for some of the uses of template aliases in libstdc++. If desired, the useful templates that were previously rejected could get a pedwarn rather than a hard error.