I spent some time looking into this one. I'm using FPC 3.2.0, which is a little old, so maybe someone else can test. I first thought generic methods ignore the calling convention, but after checking the RTTI data, I found the calling conventions for generic methods are stored correctly. I think I found the crux of the issue.
First here is a simplified version of the test class:
type
generic TGenericTest<T> = class
procedure StdCalling(A: T); stdcall;
procedure RegCalling(A: T); cdecl;
end;
procedure TGenericTest.StdCalling(A: T); stdcall;
begin
end;
procedure TGenericTest.RegCalling(A: T); cdecl;
begin
end;
This code compiles as expected:
procedure ThisWorks;
var
A: procedure(A: integer) of object; stdcall;
B: procedure(A: integer) of object; cdecl;
begin
with specialize TGenericTest<integer>.Create do begin
try
A := @StdCalling;
B := @RegCalling;
finally
Free;
end;
end;
end;
But, if you also want to define the vars A and B using generic "procedure of object"'s, the compiler fails. eg:
type
generic TCallProcStdCall<T> = procedure(A: T) of object; stdcall;
generic TCallProcCDecl<T> = procedure(A: T) of object; cdecl;
procedure ThisDoesNotWork;
var
A: specialize TCallProcStdCall<integer>;
B: specialize TCallProcCDecl<integer>;
begin
with specialize TGenericTest<integer>.Create do begin
try
A := @StdCalling;
B := @RegCalling; // <<< This fails to compile
// Error: Incompatible types:
// got "<procedure variable type of procedure(LongInt) of object;CDecl>"
// expected "<procedure variable type of procedure(LongInt) of object;StdCall>"
finally
Free;
end;
end;
end;
As far as I can tell, there should be no difference between the two.
To simplify the problem even more, the following code uses basic functions. Assignment to procedure pointers with defined calling definitions, works.
procedure Test1(A: integer); stdcall;
begin
end;
procedure Test2(A: integer); cdecl;
begin
end;
procedure ThisWorks;
var
A: procedure(A: integer); stdcall;
B: procedure(A: integer); cdecl;
begin
A := @Test1;
B := @Test2;
end;
While, pointers to procedures created via a specialized generic definition, does not:
type
generic TProcedureStdCall<T> = procedure(A: T); stdcall;
generic TProcedureCDecl<T> = procedure(A: T); cdecl;
procedure ThisDoesNotWork;
var
A: specialize TProcedureStdCall<integer>;
B: specialize TProcedureCDecl<integer>;
begin
A := @Test1;
B := @Test2; // << This fails to compile
// Error: Incompatible types:
// got "<address of procedure(LongInt);CDecl>"
// expected "<procedure variable type of procedure(LongInt);StdCall>"
end;
This might be a bug which has been fixed. Maybe someone can check.