digitalmars.D - [SPEC/DMD] Bug (?): extern( C ) function pointers (D1 and D2)
- David Nadlinger (33/33) Dec 30 2010 As easily verified e.g. by compiling
- Andrej Mitrovic (18/51) Dec 30 2010 Try this:
- David Nadlinger (6/7) Dec 30 2010 Thanks for your answer, but as I mentioned in my original post, I don't
- Andrej Mitrovic (5/13) Dec 30 2010 Yes, I agree. This will not work either but I'd like it to:
- David Nadlinger (15/16) Dec 30 2010 I don't quite see how this would be a feature request – »I'd like to ...
- Andrej Mitrovic (45/104) Dec 30 2010 I'm pretty sure this will work as well, because I have this defined in
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
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 functionTry 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
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