www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - Can't declare extern(C) fp in function body

reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
DMD 0.109, Linux

The following program fails on line 7 with the error:
	found 'extern' instead of statement

 import std.stdio;
  
 extern(C) void foo(int i,char c) { writef("%d, %s\n", i,c); }
 extern(C) void function(int,char) global_fp = &foo;
  
 void main() {
   extern(C) void function(int,char) local_fp = &foo;
  
   global_fp(1,'a');
   local_fp(2,'b');
 }

Dec 14 2004
next sibling parent reply John Reimer <brk_6502 yahoo.com> writes:
Russ Lewis wrote:
 DMD 0.109, Linux
 
 The following program fails on line 7 with the error:
     found 'extern' instead of statement
 
 import std.stdio;
  
 extern(C) void foo(int i,char c) { writef("%d, %s\n", i,c); }
 extern(C) void function(int,char) global_fp = &foo;
  
 void main() {
   extern(C) void function(int,char) local_fp = &foo;
  
   global_fp(1,'a');
   local_fp(2,'b');
 }


Yeah, I was going to mention that. I tried to do that too and it didn't work... I think the problem is that it doesn't make sense to declare a function extern(C) inside another function, thus it seems D refuses to permit any type of extern(C) reference there. But this keeps the programmer from being able to declare a function variable extern(C), which appears to be a severe limitation. So what to do? It works in a class, so should it also work in a function? I'm not sure what the answer to that is. But I did find a bit of a cheat that works around the problem. Try: # import std.stdio; # # extern (C) void foo(int i, char c) # { # writefln("%d, %s", i,c); # } # # extern (C) typedef void function(int, char) functype; # # void main() # { # functype func; # # func = &foo; # # func(2, 'c'); # } Alias will work too. Kind of strange, but perhaps it a safer way of achieving the same goal, anyway. Gotta love typedef and alias! :-) -John
Dec 14 2004
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
John Reimer wrote:
 I think the problem is that it doesn't make sense to declare a function 
 extern(C) inside another function, thus it seems D refuses to permit any 
 type of extern(C) reference there.  But this keeps the programmer from 
 being able to declare a function variable extern(C), which appears to be 
 a severe limitation.

I could imagine a scenario where you pass a pointer to a nested function (or even an anonymous function!) to a C library. I'm pretty sure that extern(C) says things about the calling convention (not just the mangling) and so you'd need extern(C) in that case. We probably want to be able to do:
 extern(C) void RegisterCallback(extern(C) int function() foo);
 void main() {
   RegisterCallback(extern(C) function int() { return 0; });
 }

But right now that code breaks terribly.
Dec 14 2004
next sibling parent John Reimer <brk_6502 yahoo.com> writes:
Russ Lewis wrote:
 John Reimer wrote:
 
 I think the problem is that it doesn't make sense to declare a 
 function extern(C) inside another function, thus it seems D refuses to 
 permit any type of extern(C) reference there.  But this keeps the 
 programmer from being able to declare a function variable extern(C), 
 which appears to be a severe limitation.

I could imagine a scenario where you pass a pointer to a nested function (or even an anonymous function!) to a C library. I'm pretty sure that extern(C) says things about the calling convention (not just the mangling) and so you'd need extern(C) in that case. We probably want to be able to do:

Yes, I belive calling convention is different for extern(C), ie order the arguments are pushed/pulled off the stack.
 extern(C) void RegisterCallback(extern(C) int function() foo);
 void main() {
   RegisterCallback(extern(C) function int() { return 0; });
 }

But right now that code breaks terribly.

Okay, that sounds reasonable. You also want extern(C) to be available for function literals as well. Referring to my example, doesn't the function type declaration with extern(C) fix this problem then? The use of alias or typedef cleans up the lenghthy declarations as a bonus. Later, John
Dec 14 2004
prev sibling next sibling parent John Reimer <brk_6502 yahoo.com> writes:
Russ Lewis wrote:
 John Reimer wrote:
 
 I think the problem is that it doesn't make sense to declare a 
 function extern(C) inside another function, thus it seems D refuses to 
 permit any type of extern(C) reference there.  But this keeps the 
 programmer from being able to declare a function variable extern(C), 
 which appears to be a severe limitation.

I could imagine a scenario where you pass a pointer to a nested function (or even an anonymous function!) to a C library. I'm pretty sure that extern(C) says things about the calling convention (not just the mangling) and so you'd need extern(C) in that case. We probably want to be able to do:
 extern(C) void RegisterCallback(extern(C) int function() foo);
 void main() {
   RegisterCallback(extern(C) function int() { return 0; });
 }

But right now that code breaks terribly.

From further testing, I see now that even with typdef or aliasing, one can't do an extern(C) function literal. Interesting. While that's a limitation, I don't think it's a very significant one since it just means that you have to declare a separate local function. Later, John
Dec 14 2004
prev sibling parent reply John Reimer <brk_6502 yahoo.com> writes:
Russ Lewis wrote:
 John Reimer wrote:
 
 I think the problem is that it doesn't make sense to declare a 
 function extern(C) inside another function, thus it seems D refuses to 
 permit any type of extern(C) reference there.  But this keeps the 
 programmer from being able to declare a function variable extern(C), 
 which appears to be a severe limitation.

I could imagine a scenario where you pass a pointer to a nested function (or even an anonymous function!) to a C library. I'm pretty sure that extern(C) says things about the calling convention (not just the mangling) and so you'd need extern(C) in that case. We probably want to be able to do:
 extern(C) void RegisterCallback(extern(C) int function() foo);
 void main() {
   RegisterCallback(extern(C) function int() { return 0; });
 }

But right now that code breaks terribly.

You won't believe this (or maybe you will), but the above is possible with some manipulation. D seems to be full of surprises. I tried the following and it worked: # import std.stdio; # # extern (C) alias int function() functype; # # extern (C) void RegisterCallback ( functype fo ) # { # int i=fo(); # writefln("%d",i); # } # # void main() # { # RegisterCallback( cast(functype) function int() { return 100;} ); # } Output: 100 Later, John
Dec 14 2004
next sibling parent John Reimer <brk_6502 yahoo.com> writes:
John Reimer wrote:
 Russ Lewis wrote:
 
 John Reimer wrote:

 I think the problem is that it doesn't make sense to declare a 
 function extern(C) inside another function, thus it seems D refuses 
 to permit any type of extern(C) reference there.  But this keeps the 
 programmer from being able to declare a function variable extern(C), 
 which appears to be a severe limitation.

I could imagine a scenario where you pass a pointer to a nested function (or even an anonymous function!) to a C library. I'm pretty sure that extern(C) says things about the calling convention (not just the mangling) and so you'd need extern(C) in that case. We probably want to be able to do:
 extern(C) void RegisterCallback(extern(C) int function() foo);
 void main() {
   RegisterCallback(extern(C) function int() { return 0; });
 }

But right now that code breaks terribly.

You won't believe this (or maybe you will), but the above is possible with some manipulation. D seems to be full of surprises. I tried the following and it worked: # import std.stdio; # # extern (C) alias int function() functype; # # extern (C) void RegisterCallback ( functype fo ) # { # int i=fo(); # writefln("%d",i); # } # # void main() # { # RegisterCallback( cast(functype) function int() { return 100;} ); # } Output: 100 Later, John

Now that I think about this a little more, access to function literals like this is indeed useful and important. This was one problem that I had been trying to solve awhile ago in one of my projects. It had more to do with extern(C) local functions than function literals, but the idea was the same. The fact that an extern(C) function can be passed like so is a great asset! Later, John
Dec 14 2004
prev sibling parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
I'm pretty sure that the code you wrote below exposes another bug in the 
compiler.  That cast would certainly be broken in any architecture where 
the C and D calling conventions were different.

John Reimer wrote:
 Russ Lewis wrote:
 
 John Reimer wrote:

 I think the problem is that it doesn't make sense to declare a 
 function extern(C) inside another function, thus it seems D refuses 
 to permit any type of extern(C) reference there.  But this keeps the 
 programmer from being able to declare a function variable extern(C), 
 which appears to be a severe limitation.

I could imagine a scenario where you pass a pointer to a nested function (or even an anonymous function!) to a C library. I'm pretty sure that extern(C) says things about the calling convention (not just the mangling) and so you'd need extern(C) in that case. We probably want to be able to do:
 extern(C) void RegisterCallback(extern(C) int function() foo);
 void main() {
   RegisterCallback(extern(C) function int() { return 0; });
 }

But right now that code breaks terribly.

You won't believe this (or maybe you will), but the above is possible with some manipulation. D seems to be full of surprises. I tried the following and it worked: # import std.stdio; # # extern (C) alias int function() functype; # # extern (C) void RegisterCallback ( functype fo ) # { # int i=fo(); # writefln("%d",i); # } # # void main() # { # RegisterCallback( cast(functype) function int() { return 100;} ); # } Output: 100 Later, John

Dec 14 2004
next sibling parent John Reimer <brk_6502 yahoo.com> writes:
Russ Lewis wrote:
 I'm pretty sure that the code you wrote below exposes another bug in the 
 compiler.  That cast would certainly be broken in any architecture where 
 the C and D calling conventions were different.
 

But, I believe they are different on the pc platform. Doesn't the cast just force the calling convention expected by the argument? I realize that you are referring to the function literal's status as an extern(D) type function as declared. Is it not possible for that to be changed by casting? I don't know enough about the low level details to comment further. Perhaps Walter will clarify? Later, John
Dec 14 2004
prev sibling next sibling parent John Reimer <brk_6502 yahoo.com> writes:
Russ Lewis wrote:
 I'm pretty sure that the code you wrote below exposes another bug in the 
 compiler.  That cast would certainly be broken in any architecture where 
 the C and D calling conventions were different.
 

Okay, I'm doing a few more tests. The bug probably doesn't show because the function doesn't take any arguments. Calling convention issues probably surface once arguments are included. I'll give it a go. Later, John
Dec 14 2004
prev sibling next sibling parent John Reimer <brk_6502 yahoo.com> writes:
Russ Lewis wrote:
 I'm pretty sure that the code you wrote below exposes another bug in the 
 compiler.  That cast would certainly be broken in any architecture where 
 the C and D calling conventions were different.
 

Ah yes, you are correct to question this one... Obviously I was getting excited about the possibilities without thinking the problem through clearly... just being hopeful. Example: # import std.stdio; # # extern (C) alias int function( int, int, int) functype; # # int func(int a, int b, int c) # { # writefln("Test: %d, %d, %d", a, b, c); # return a+b+c; # } # # void main() # { # functype f = cast(functype) &func; # # writefln("Return value: %d", f(2,4,8)); # } Output: Test: 4, 2, 4202512 Return Value: 4202518 Error: Access Violation In this case "func" is an extern(D) type and "f" is extern(C). Now the question is: is this example equivalent to casting a function literal? I'm not sure yet. I was hoping that the function literal could be coerced in its definition by the cast to a different calling convention. - John
Dec 14 2004
prev sibling parent John Reimer <brk_6502 yahoo.com> writes:
Russ Lewis wrote:
 I'm pretty sure that the code you wrote below exposes another bug in the 
 compiler.  That cast would certainly be broken in any architecture where 
 the C and D calling conventions were different.
 

And finally a proper example that demonstrates why what Russ said here is true: # import std.stdio; # # extern (C) alias int function( int, int, int) functype; # # void main() # { # functype f = cast(functype) function int(int a, int b, int c) { # writefln("Test function literal: %d, %d, %d", a, b, c); # return a+b+c; # }; # # writefln("Return value: %d", f(2,4,8)); # } Output: Test Function literal: 4, 2, 4202564 Return value: 4202570 Error: Access Violation "Can't declare extern(C) fp in function body" is a valid complaint. Fixing this in D should improve interfacing with external C code. - John
Dec 14 2004
prev sibling parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
This was mentioned in passing in this thread, but I thought I would mark 
it explicitly: at least in the context of a cast, I can't declare the type
	extern(C) int function()

The following module won't compile, but I'm pretty sure that it should. 
  (Can we add this to DStress?):

 extern(C) void *wglGetProcAddress(char*);
 extern(C) int function() glFunctionFoo;
  
 static this() {
   glFunctionFoo = cast(extern(C) int function())
                       wglGetProcAddress("glFunctionFoo");
 }

Second, here's an example which (correctly) fails because I don't add the extern(C) modifier. This would be good to add to DStress as expfail:
 extern(C) void *wglGetProcAddress(char*);
 extern(C) int function() glFunctionFoo;
  
 static this() {
   glFunctionFoo = cast(int function())
                       wglGetProcAddress("glFunctionFoo");
 }

Dec 14 2004
parent Thomas Kuehne <thomas-dloop kuehne.thisisspam.cn> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Added to DStress as
http://svn.kuehne.cn/dstress/nocompile/extern_06.d
http://svn.kuehne.cn/dstress/compile/extern_07.d

Thomas

Russ Lewis schrieb am Tue, 14 Dec 2004 20:23:47 -0700:
 This was mentioned in passing in this thread, but I thought I would mark 
 it explicitly: at least in the context of a cast, I can't declare the type
 	extern(C) int function()

 The following module won't compile, but I'm pretty sure that it should. 
   (Can we add this to DStress?):

 extern(C) void *wglGetProcAddress(char*);
 extern(C) int function() glFunctionFoo;
  
 static this() {
   glFunctionFoo = cast(extern(C) int function())
                       wglGetProcAddress("glFunctionFoo");
 }

Second, here's an example which (correctly) fails because I don't add the extern(C) modifier. This would be good to add to DStress as expfail:
 extern(C) void *wglGetProcAddress(char*);
 extern(C) int function() glFunctionFoo;
  
 static this() {
   glFunctionFoo = cast(int function())
                       wglGetProcAddress("glFunctionFoo");
 }


-----BEGIN PGP SIGNATURE----- iD8DBQFBwHe03w+/yD4P9tIRAk0OAJ0e+R9x8FJRZ5SJofA4yEXtdoDMYgCgvJQR TaV+pFaIj1jAWhHStB1lQMA= =6K9A -----END PGP SIGNATURE-----
Dec 15 2004