extern(C) and mangling type names

Mike Parker via Digitalmars-d digitalmars-d at puremagic.com
Tue Feb 14 19:40:32 PST 2017


```
module mang;
extern(C):
     struct Foo;
     void bar();
     int x;

pragma(msg, Foo.mangleof);
pragma(msg, bar.mangleof);
pragma(msg, x.mangleof);
```

Obviously, x and bar are seen by the linker and mangling is 
turned off for them. I've always believed it was the same for 
type declarations as well. Alas, that is not the case.

The use case I'm looking at here is forward references (opaque 
types). Works fine when binding to C libraries. Or even with 
other D modules when written like this:


```
module ec1;
extern(C):
     struct Foo;
     Foo* newFoo(int x);
     void printFoo(Foo* f);

module ec2;
extern(C):
     struct Foo { int x; }
     Foo* newFoo(int x) { return new Foo(x); }
     void printFoo(Foo* f) { import std.stdio; writeln(f.x); }

module ec3;
void main() {
     import ec1;
     Foo* f = newFoo(30);
     printFoo(f);
}
```

This compiles and runs. Now change ec1 and ec3 like so:

```
module ec1;
extern(C) struct Foo;

module ec3;
void main() {
     import ec1, ec2;
     Foo* f = newFoo(30);
     printFoo(f);
}
```

This produces the following errors:

ec3.d(4): Error: ec1.Foo at ec1.d(2) conflicts with ec2.Foo at 
ec2.d(3)
ec3.d(4): Error: cannot implicitly convert expression 
(newFoo(30)) of type Foo* to Foo*
ec3.d(5): Error: function ec2.printFoo (Foo* f) is not callable 
using argument types (Foo*)

IMO, extern(C) should turn off mangling for Foo. It would make 
forward references useful outside of the specific case of C 
bindings.

Consider the situation where you want to call a user-defined 
function (not a function pointer or a delegate). It's easy to do 
by providing an extern(C) prototype and requiring the user to use 
extern(C) in the implementation. The same thing should be 
possible for types.

My specific use case is a binding to a C library that makes use 
of specific types from X11, Wayland and elsewhere. I don't want 
to force a specific binding upon the user, so I need to declare 
the relevant types in a way that is binding-neutral. One option, 
of course, is to use void*, which has a lack of type safety and 
requires casting all over the place. Another is to wrap the 
declarations up in mixin templates and have the user mix them 
where they've imported the specific binding. Less onerous than 
void*, but still not ideal.

So, should extern(C) turn off mangling for types?


More information about the Digitalmars-d mailing list