dmd
dmd copied to clipboard
Fix 5309 - Support `extern(D)` symbol refs
Currently, `extern(D)` is quite incomplete: An `extern(D)` symbol is mangled
as if it was in the module it is declared in, while users usually want to
declare a function or type that lives in another module.
Borrowing from the syntax that was adopted for `extern(C++, name.space)`, we introduce `extern(D, pkg.mod)`.
Note that, unlike `extern(C++)`, no string alternative is needed:
the motivation for the string variant was that C++ namespaces could be D keywords,
hence some namespaces could not be bound with the identifier variant,
a problem which obviously does not apply to `extern(D)` symbols.
The need for this functionality is easily demonstrated by druntime's `externDFunc`.
`core.internal.traits : externDFunc` is a template that defines an `extern(D)` symbol in another module.
This is currently done by using `pragma(mangle)` along with `core.demangle : mangleFunc`.
And as it turns out, the only reason for `core.demangle : mangleFunc` to exists is for `externDFunc`.
Hence, implementing this functionality will greatly simplify a core piece of druntime:
`core.demangle : mangle` (and its derivatives, including `mangleFunc` and `externDFunc`) can be removed
and replaced by `XXX.mangleof`, relying on the compiler instead of a library function which have to be
kept in sync with the compiler implementation.
TL;DR: While we should do things in libraries as much as possible, replicating in a library complex compiler logic (in this case, symbol mangling) is bad. With this in mind, I was puzzled as to why core.demangle : mangle existed in the first place (also consider that the module is called demangle but holds a mangle function, so it was clearly an afterthought). Issue 5309 held the answer, and hopefully after this is merged we can greatly simply core.demangle ("fun" fact: the demangling code is re-used for the mangler, with added boolean logic here and there).
Thanks for your pull request, @Geod24!
Bugzilla references
| Auto-close | Bugzilla | Severity | Description |
|---|---|---|---|
| ✓ | 5309 | enhancement | Add language support for external D symbols refs |
Testing this PR locally
If you don't have a local development environment setup, you can use Digger to test this PR:
dub run digger -- build "master + dmd#12839"
Yeah, externDFunc must die.
This is common practice in C. But D tries to get away from that. I fear this sort of thing will have a tendency to break the sanctity(!) of the module system in D. It could be used to insert symbols into modules that aren't in those modules at all.
I've found a need to do this when translating C code to D, as C does that all over the place. But the way I get it to work is by declaring those functions extern(C). While it does take advantage of C mangling being rootless (i.e. not a member of a module), it is clearly ugly, and I use it as a temporary measure while converting existing code to D.
Having this work with extern(D) declarations, however, is blessing a code smell.
I recommend instead one of:
- making such functions
extern(C)orextern(C++). - using .di imports. That's exactly what they're for.
externDfunc is probably an abomination. Should seriously look into just why it is being used.
This is common practice in C. But D tries to get away from that. I fear this sort of thing will have a tendency to break the sanctity(!) of the module system in D.
It does indeed, and it's not really something we should advertise.
It could be used to insert symbols into modules that aren't in those modules at all.
This part I'm not sure I follow how that'd be possible ?
Having this work with
extern(D)declarations, however, is blessing a code smell.
When looking at the issue, I was wondering what was the best way to fix this. I think that we are faced with two solutions:
- Deprecate
extern(D)extern functions in a module (not.di), because they are completely useless; - Make
extern(D)declarations work: This PR;
I went with the later because:
- The DLL use case seemed legit;
- It makes it consistent with other
externdeclaration; - Deprecating
extern(D)in modules would make the language less consistent, while solution 2 makes it more consistent;
@Geod24 I agree with @WalterBright in that I really don't want this complexity in the language if we can avoid it. Do you still want to add this feature?