digitalmars.D - [SPEC/DMD] Bug (?): extern( C ) function pointers (D1 and D2)
- David Nadlinger <see klickverbot.at> Dec 30 2010
- Andrej Mitrovic <andrej.mitrovich gmail.com> Dec 30 2010
- David Nadlinger <see klickverbot.at> Dec 30 2010
- David Nadlinger <see klickverbot.at> Dec 30 2010
- Andrej Mitrovic <andrej.mitrovich gmail.com> Dec 30 2010
- Andrej Mitrovic <andrej.mitrovich gmail.com> Dec 30 2010
As easily verified e.g. by compiling
---
extern(C) void foo() {}
pragma( msg, typeof( &foo ) );
---,
function pointers types include the linkage type (the code above prints
»void C function()«).
However, there is no way to specify the linkage type e.g. in the
signature of a function accepting a delegate, i.e.:
---
extern(C) void foo() {}
void bar( void function() func ) {} // How to correctly specify the full
parameter type here?
void main() {
bar( &foo );
}
---
This problem is currently somewhat hidden by the fact that DMD simply
ignores the linkage when doing type checking. But e.g. LDC does strict
type checking (probably because it needs to reflect the pointer types in
the LLVM IR, but that's just guessing) today, and it will hopefully be
added to DMD at some point.
Note: Simply adding »extern( C )« to the type specification does not
work, but: At the first glance, I couldn't even find any section in the
language spec for both D1 and D2 mentioning linkage annotations for
function pointers. Has this part simply not been spec'd yet?
In any case, this currently breaks passing of function pointers to C
functions resp. their SWIG-generated wrappers with LDC, as I could find
no easy way to work around it – creating an alias for the function
pointer type before might work, as extern( C ) seems to be accepted
there, but this is a major annoyance if you are automatically generating
code.
David
Dec 30 2010
Try this:
extern(C) void foo() {}
extern(C)
{
alias void function() FooFunc;
// alias typeof(foo) FooFunc; // or try this one if it works
}
void bar(FooFunc func) { }
void main() {
bar( &foo );
}
I've had a nasty bug where I forgot to put extern(C) on a function
type like that. I spend the entire day trying to debug the damn thing,
because for some reason calling C code worked, but C code trying to
call a delegate which I've passed failed with arbitrary types.
Basically, it was a communication mismatch with the calling
convention.
On 12/30/10, David Nadlinger <see klickverbot.at> wrote:
As easily verified e.g. by compiling
---
extern(C) void foo() {}
pragma( msg, typeof( &foo ) );
---,
function pointers types include the linkage type (the code above prints
=BBvoid C function()=AB).
However, there is no way to specify the linkage type e.g. in the
signature of a function accepting a delegate, i.e.:
---
extern(C) void foo() {}
void bar( void function() func ) {} // How to correctly specify the full
parameter type here?
void main() {
bar( &foo );
}
---
This problem is currently somewhat hidden by the fact that DMD simply
ignores the linkage when doing type checking. But e.g. LDC does strict
type checking (probably because it needs to reflect the pointer types in
the LLVM IR, but that's just guessing) today, and it will hopefully be
added to DMD at some point.
Note: Simply adding =BBextern( C )=AB to the type specification does not
work, but: At the first glance, I couldn't even find any section in the
language spec for both D1 and D2 mentioning linkage annotations for
function pointers. Has this part simply not been spec'd yet?
In any case, this currently breaks passing of function pointers to C
functions resp. their SWIG-generated wrappers with LDC, as I could find
no easy way to work around it =96 creating an alias for the function
pointer type before might work, as extern( C ) seems to be accepted
there, but this is a major annoyance if you are automatically generating
code.
David
Dec 30 2010
On 12/30/10 10:44 PM, Andrej Mitrovic wrote:Try this: [snip]
Thanks for your answer, but as I mentioned in my original post, I don't see why creating an alias for the function pointer type should be necessary – it is quite annoying when you are automatically creating code, you'd need a special case for function pointers then. David
Dec 30 2010
On 12/30/10 11:29 PM, Andrej Mitrovic wrote:Try filing a feature request on bugzilla.
I don't quite see how this would be a feature request – »I'd like to be able to actually express the implicitly used types in D code«? The reason I brought this here instead of directly filing a specification bug to Bugzilla is that 1) I am not sure if I had missed a related part of the specification and 2) since resolving this issue will probably require a change/addition to the language specification, I think it deserves some extended discussion. So, to restate the question: Currently, the spec for both D1 and D2 apparently does not allow specifying the calling convention of function pointer types directly. This issue probably hasn't popped up so far just becasue DMD currently does not take the calling convention into account when type-checking function pointers, but this might not be the case for other compilers or future versions of DMD. How should we resolve this issue? David
Dec 30 2010
I'm pretty sure this will work as well, because I have this defined in
a module where I'm passing a function pointer to C:
alias extern(C) size_t function(/*params*/) CallbackType;
Here's a snippet of how I used the OS to get a pointer to a C
function, which I've used to pass my own callback, and get a struct
back (or a pointer to one anyway):
alias extern(C) size_t function(AEffect* effect, int opcode, int
index, size_t value, void* ptr, float opt) audioMasterCallback;
extern(C) size_t HostCallback(AEffect* effect, int opcode, int index,
size_t value, void* ptr, float opt)
{
// code..
}
extern(C)
{
alias AEffect* function(audioMasterCallback) EntryProc;
}
EntryProc getMainEntry()
{
auto MainEntry =3D cast(EntryProc)GetProcAddress(VSTModule,
"VSTPluginMain");
// Older VSTs use "main" entry point
if (!MainEntry)
MainEntry =3D cast(EntryProc)GetProcAddress(VSTModule, "main");
if (MainEntry is null)
throw new Exception("Entry function 'VSTPluginMain' or 'main'
not found.");
return MainEntry;
}
AEffect* getEffect()
{
EntryProc VSTMain =3D getMainEntry();
auto effect =3D VSTMain(&HostCallback); // Passing the function addres=
s to C,
// and getting back a struct
if (effect is null)
throw new Exception("VST failed to return the effect struct.");
return effect;
}
It was code to load DLLs with a defined standard, all DLLs that
conform to the spec need to have an entry point function with a
specific name, and then I can pass a callback and in turn I get back
this nice structure where I can figure things out the functionality of
that "VST" plugin.
On 12/30/10, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:
Try this:
extern(C) void foo() {}
extern(C)
{
alias void function() FooFunc;
// alias typeof(foo) FooFunc; // or try this one if it works
}
void bar(FooFunc func) { }
void main() {
bar( &foo );
}
I've had a nasty bug where I forgot to put extern(C) on a function
type like that. I spend the entire day trying to debug the damn thing,
because for some reason calling C code worked, but C code trying to
call a delegate which I've passed failed with arbitrary types.
Basically, it was a communication mismatch with the calling
convention.
On 12/30/10, David Nadlinger <see klickverbot.at> wrote:
As easily verified e.g. by compiling
---
extern(C) void foo() {}
pragma( msg, typeof( &foo ) );
---,
function pointers types include the linkage type (the code above prints
=BBvoid C function()=AB).
However, there is no way to specify the linkage type e.g. in the
signature of a function accepting a delegate, i.e.:
---
extern(C) void foo() {}
void bar( void function() func ) {} // How to correctly specify the full
parameter type here?
void main() {
bar( &foo );
}
---
This problem is currently somewhat hidden by the fact that DMD simply
ignores the linkage when doing type checking. But e.g. LDC does strict
type checking (probably because it needs to reflect the pointer types in
the LLVM IR, but that's just guessing) today, and it will hopefully be
added to DMD at some point.
Note: Simply adding =BBextern( C )=AB to the type specification does not
work, but: At the first glance, I couldn't even find any section in the
language spec for both D1 and D2 mentioning linkage annotations for
function pointers. Has this part simply not been spec'd yet?
In any case, this currently breaks passing of function pointers to C
functions resp. their SWIG-generated wrappers with LDC, as I could find
no easy way to work around it =96 creating an alias for the function
pointer type before might work, as extern( C ) seems to be accepted
there, but this is a major annoyance if you are automatically generating
code.
David
Dec 30 2010
Yes, I agree. This will not work either but I'd like it to:
extern(C) void foo() { }
void bar(typeof(foo) func) { }
Error: variable main.bar.func cannot be declared to be a function
Try filing a feature request on bugzilla.
On 12/30/10, David Nadlinger <see klickverbot.at> wrote:
On 12/30/10 10:44 PM, Andrej Mitrovic wrote:
Try this: [snip]
Thanks for your answer, but as I mentioned in my original post, I don't
see why creating an alias for the function pointer type should be
necessary =96 it is quite annoying when you are automatically creating
code, you'd need a special case for function pointers then.
David
Dec 30 2010









David Nadlinger <see klickverbot.at> 