New user self-registration is disabled due to spam. For an account please email bugs-admin@lists.llvm.org with your e-mail address and full name.

Bug 6277 - Conversion between different language linkages not diagnosed.
Summary: Conversion between different language linkages not diagnosed.
Status: NEW
Alias: None
Product: clang
Classification: Unclassified
Component: C++ (show other bugs)
Version: trunk
Hardware: All All
: P normal
Assignee: Unassigned Clang Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-02-10 23:02 PST by Sean Hunt
Modified: 2013-07-18 08:01 PDT (History)
6 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Sean Hunt 2010-02-10 23:02:29 PST
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; }
Comment 1 Douglas Gregor 2010-02-13 00:18:59 PST
(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.
Comment 2 Seth 2012-08-09 11:54:39 PDT
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.
Comment 3 Richard Smith 2013-07-08 12:58:20 PDT
(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.
Comment 4 Marc Glisse 2013-07-18 08:01:42 PDT
(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).