mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-12 00:26:16 +02:00
* fix #39742: when assigning a function to a function reference it's not the function itself that needs to be checked to be captureable, but instead what it captures (this applies for both the non-generic and the generic case)
+ added tests
This commit is contained in:
parent
0874521a78
commit
a27bc236a0
@ -860,14 +860,6 @@ implementation
|
||||
|
||||
result:=funcref_intf_for_proc(tabstractprocdef(n.resultdef),fileinfo_to_suffix(sym.fileinfo));
|
||||
|
||||
if df_generic in owner.procdef.defoptions then
|
||||
begin
|
||||
{ only check whether we can capture the symbol }
|
||||
if not can_be_captured(sym) then
|
||||
MessagePos1(n.fileinfo,sym_e_symbol_no_capture,sym.realname);
|
||||
exit;
|
||||
end;
|
||||
|
||||
if (sym.typ=procsym) and (sym.owner.symtabletype=localsymtable) then
|
||||
begin
|
||||
{ this is assigning a nested function, so retrieve the correct procdef
|
||||
@ -882,17 +874,29 @@ implementation
|
||||
if not assigned(pd) then
|
||||
internalerror(2022041802);
|
||||
end;
|
||||
pinested:=find_nested_procinfo(pd);
|
||||
if not assigned(pinested) then
|
||||
internalerror(2022041803);
|
||||
if pinested.parent<>owner then
|
||||
{ check whether all captured symbols can indeed be captured }
|
||||
capturesyms:=pd.capturedsyms;
|
||||
if assigned(capturesyms) then
|
||||
for i:=0 to capturesyms.count-1 do
|
||||
begin
|
||||
captured:=pcapturedsyminfo(capturesyms[i]);
|
||||
if not can_be_captured(captured^.sym) then
|
||||
MessagePos1(captured^.fileinfo,sym_e_symbol_no_capture,captured^.sym.realname);
|
||||
end;
|
||||
if not (df_generic in owner.procdef.defoptions) then
|
||||
begin
|
||||
{ we need to capture this into the owner of the nested function
|
||||
instead }
|
||||
owner:=pinested;
|
||||
capturer:=get_or_create_capturer(pinested.procdef);
|
||||
if not assigned(capturer) then
|
||||
internalerror(2022041804);
|
||||
pinested:=find_nested_procinfo(pd);
|
||||
if not assigned(pinested) then
|
||||
internalerror(2022041803);
|
||||
if pinested.parent<>owner then
|
||||
begin
|
||||
{ we need to capture this into the owner of the nested function
|
||||
instead }
|
||||
owner:=pinested;
|
||||
capturer:=get_or_create_capturer(pinested.procdef);
|
||||
if not assigned(capturer) then
|
||||
internalerror(2022041804);
|
||||
end;
|
||||
end;
|
||||
end
|
||||
else if (n.resultdef.typ=procvardef) and
|
||||
@ -904,6 +908,9 @@ implementation
|
||||
else
|
||||
pinested:=nil;
|
||||
|
||||
if df_generic in owner.procdef.defoptions then
|
||||
exit;
|
||||
|
||||
if not assigned(capturer) then
|
||||
capturer:=get_or_create_capturer(owner.procdef);
|
||||
|
||||
|
24
tests/test/tfuncref37.pp
Normal file
24
tests/test/tfuncref37.pp
Normal file
@ -0,0 +1,24 @@
|
||||
{ %FAIL }
|
||||
|
||||
program tfuncref37;
|
||||
|
||||
{$mode objfpc}
|
||||
{$ModeSwitch functionreferences}
|
||||
|
||||
type
|
||||
TFuncRef = reference to function: LongInt;
|
||||
|
||||
function Test(var aArg: LongInt): TFuncRef;
|
||||
|
||||
function TestSub: LongInt;
|
||||
begin
|
||||
Result := aArg;
|
||||
end;
|
||||
|
||||
begin
|
||||
Result := @TestSub;
|
||||
end;
|
||||
|
||||
begin
|
||||
end.
|
||||
|
24
tests/test/tfuncref38.pp
Normal file
24
tests/test/tfuncref38.pp
Normal file
@ -0,0 +1,24 @@
|
||||
{ %FAIL }
|
||||
|
||||
program tfuncref38;
|
||||
|
||||
{$mode objfpc}
|
||||
{$ModeSwitch functionreferences}
|
||||
|
||||
type
|
||||
TFuncRef = reference to function: LongInt;
|
||||
|
||||
function Test(aArg: array of LongInt): TFuncRef;
|
||||
|
||||
function TestSub: LongInt;
|
||||
begin
|
||||
Result := aArg[2];
|
||||
end;
|
||||
|
||||
begin
|
||||
Result := @TestSub;
|
||||
end;
|
||||
|
||||
begin
|
||||
end.
|
||||
|
26
tests/test/tfuncref39.pp
Normal file
26
tests/test/tfuncref39.pp
Normal file
@ -0,0 +1,26 @@
|
||||
{ %FAIL }
|
||||
|
||||
program tfuncref39;
|
||||
|
||||
{$mode objfpc}
|
||||
{$ModeSwitch functionreferences}
|
||||
|
||||
type
|
||||
TProcRef = reference to procedure;
|
||||
|
||||
function Test: LongInt;
|
||||
|
||||
procedure TestSub;
|
||||
begin
|
||||
Writeln(Result);
|
||||
end;
|
||||
|
||||
var
|
||||
tmp: TProcRef;
|
||||
begin
|
||||
tmp := @TestSub;
|
||||
end;
|
||||
|
||||
begin
|
||||
end.
|
||||
|
24
tests/test/tfuncref40.pp
Normal file
24
tests/test/tfuncref40.pp
Normal file
@ -0,0 +1,24 @@
|
||||
{ %FAIL }
|
||||
|
||||
program tfuncref40;
|
||||
|
||||
{$mode objfpc}
|
||||
{$ModeSwitch functionreferences}
|
||||
|
||||
type
|
||||
TFuncRef = reference to function: LongInt;
|
||||
|
||||
generic function Test<T>(var aArg: LongInt): TFuncRef;
|
||||
|
||||
function TestSub: LongInt;
|
||||
begin
|
||||
Result := aArg;
|
||||
end;
|
||||
|
||||
begin
|
||||
Result := @TestSub;
|
||||
end;
|
||||
|
||||
begin
|
||||
end.
|
||||
|
24
tests/test/tfuncref41.pp
Normal file
24
tests/test/tfuncref41.pp
Normal file
@ -0,0 +1,24 @@
|
||||
{ %FAIL }
|
||||
|
||||
program tfuncref41;
|
||||
|
||||
{$mode objfpc}
|
||||
{$ModeSwitch functionreferences}
|
||||
|
||||
type
|
||||
TFuncRef = reference to function: LongInt;
|
||||
|
||||
generic function Test<T>(aArg: array of LongInt): TFuncRef;
|
||||
|
||||
function TestSub: LongInt;
|
||||
begin
|
||||
Result := aArg[2];
|
||||
end;
|
||||
|
||||
begin
|
||||
Result := @TestSub;
|
||||
end;
|
||||
|
||||
begin
|
||||
end.
|
||||
|
26
tests/test/tfuncref42.pp
Normal file
26
tests/test/tfuncref42.pp
Normal file
@ -0,0 +1,26 @@
|
||||
{ %FAIL }
|
||||
|
||||
program tfuncref39;
|
||||
|
||||
{$mode objfpc}
|
||||
{$ModeSwitch functionreferences}
|
||||
|
||||
type
|
||||
TProcRef = reference to procedure;
|
||||
|
||||
generic function Test<T>: LongInt;
|
||||
|
||||
procedure TestSub;
|
||||
begin
|
||||
Writeln(Result);
|
||||
end;
|
||||
|
||||
var
|
||||
tmp: TProcRef;
|
||||
begin
|
||||
tmp := @TestSub;
|
||||
end;
|
||||
|
||||
begin
|
||||
end.
|
||||
|
34
tests/webtbs/tw39742.pp
Normal file
34
tests/webtbs/tw39742.pp
Normal file
@ -0,0 +1,34 @@
|
||||
{ %NORUN }
|
||||
|
||||
program tw39742;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
{$ModeSwitch nestedprocvars}
|
||||
{$ModeSwitch functionreferences}
|
||||
|
||||
type
|
||||
TIntFunction = reference to function: Integer;
|
||||
|
||||
// Works
|
||||
function FourtyTwo(const AParam: Integer): TIntFunction;
|
||||
function Helper: Integer;
|
||||
begin
|
||||
Result := 42;
|
||||
end;
|
||||
begin
|
||||
Result := @Helper
|
||||
end;
|
||||
|
||||
// Error
|
||||
generic function GenericFourtyTwo<T>: TIntFunction;
|
||||
function Helper: Integer;
|
||||
begin
|
||||
Result := 42;
|
||||
end;
|
||||
begin
|
||||
Result := @Helper
|
||||
end;
|
||||
|
||||
begin
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user