From d3e18ccb5eef80f35ccaab8f8551cdbc7acd9f7d Mon Sep 17 00:00:00 2001 From: svenbarth Date: Fri, 18 Sep 2020 15:00:10 +0000 Subject: [PATCH] * fix for Mantis #37221: apply adjusted patch by Ondrej Pokorny to allow the use of Copy() on open array parameters (the result will be a dynamic array) + added test git-svn-id: trunk@46890 - --- .gitattributes | 1 + compiler/ninl.pas | 63 ++++++++++++++++++++++----- rtl/inc/compproc.inc | 7 +++ rtl/inc/dynarr.inc | 66 +++++++++++++++++----------- tests/test/tarray22.pp | 99 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 199 insertions(+), 37 deletions(-) create mode 100644 tests/test/tarray22.pp diff --git a/.gitattributes b/.gitattributes index 8fb6ced190..328f11ddb0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -14389,6 +14389,7 @@ tests/test/tarray19.pp svneol=native#text/pascal tests/test/tarray2.pp svneol=native#text/plain tests/test/tarray20.pp svneol=native#text/pascal tests/test/tarray21.pp svneol=native#text/pascal +tests/test/tarray22.pp svneol=native#text/pascal tests/test/tarray3.pp svneol=native#text/plain tests/test/tarray4.pp svneol=native#text/plain tests/test/tarray5.pp svneol=native#text/plain diff --git a/compiler/ninl.pas b/compiler/ninl.pas index 5c70bed2c2..fbd53328f0 100644 --- a/compiler/ninl.pas +++ b/compiler/ninl.pas @@ -1914,7 +1914,16 @@ implementation begin minargs:=1; resultdef:=paradef; - func:='fpc_dynarray_copy'; + func:='fpc_array_to_dynarray_copy'; + end + else + if is_open_array(paradef) then + begin + minargs:=1; + resultdef:=carraydef.create(0,-1,tarraydef(paradef).rangedef); + tarraydef(resultdef).arrayoptions:=tarraydef(resultdef).arrayoptions+[ado_IsDynamicArray]; + tarraydef(resultdef).elementdef:=tarraydef(paradef).elementdef; + func:='fpc_array_to_dynarray_copy'; end else if counter in [2..3] then begin @@ -4697,7 +4706,12 @@ implementation function tinlinenode.first_copy: tnode; var lowppn, - highppn, + countppn, + elesizeppn, + eletypeppn, + maxcountppn, + arrayppn, + rttippn, npara, paras : tnode; ppn : tcallparanode; @@ -4737,30 +4751,57 @@ implementation else if is_dynamic_array(resultdef) then begin { create statements with call } + elesizeppn:=cordconstnode.create(tarraydef(paradef).elesize,sinttype,false); + if is_managed_type(tarraydef(paradef).elementdef) then + eletypeppn:=caddrnode.create_internal( + crttinode.create(tstoreddef(tarraydef(paradef).elementdef),fullrtti,rdt_normal)) + else + eletypeppn:=cordconstnode.create(0,voidpointertype,false); + maxcountppn:=geninlinenode(in_length_x,false,ppn.left.getcopy); case counter of 1: begin { copy the whole array using [0..high(sizeint)] range } - highppn:=cordconstnode.create(torddef(sinttype).high,sinttype,false); + countppn:=cordconstnode.create(torddef(sinttype).high,sinttype,false); lowppn:=cordconstnode.create(0,sinttype,false); end; + 2: + begin + { copy the array using [low..high(sizeint)] range } + countppn:=cordconstnode.create(torddef(sinttype).high,sinttype,false); + lowppn:=tcallparanode(paras).left.getcopy; + end; 3: begin - highppn:=tcallparanode(paras).left.getcopy; + countppn:=tcallparanode(paras).left.getcopy; lowppn:=tcallparanode(tcallparanode(paras).right).left.getcopy; end; else internalerror(2012100701); end; - { create call to fpc_dynarray_copy } - npara:=ccallparanode.create(highppn, + if is_open_array(paradef) then + begin + arrayppn:=caddrnode.create_internal(ppn.left); + end + else if is_dynamic_array(paradef) then + begin + arrayppn:=ctypeconvnode.create_internal(ppn.left,voidpointertype); + end + else + internalerror(2012100702); + + rttippn:=caddrnode.create_internal(crttinode.create(tstoreddef(resultdef),initrtti,rdt_normal)); + + { create call to fpc_array_to_dynarray_copy } + npara:=ccallparanode.create(eletypeppn, + ccallparanode.create(elesizeppn, + ccallparanode.create(maxcountppn, + ccallparanode.create(countppn, ccallparanode.create(lowppn, - ccallparanode.create(caddrnode.create_internal - (crttinode.create(tstoreddef(paradef),initrtti,rdt_normal)), - ccallparanode.create - (ctypeconvnode.create_internal(ppn.left,voidpointertype),nil)))); - result:=ccallnode.createinternres('fpc_dynarray_copy',npara,paradef); + ccallparanode.create(rttippn, + ccallparanode.create(arrayppn,nil))))))); + result:=ccallnode.createinternres('fpc_array_to_dynarray_copy',npara,resultdef); ppn.left:=nil; paras.free; diff --git a/rtl/inc/compproc.inc b/rtl/inc/compproc.inc index 02e521c5e9..158d14f931 100644 --- a/rtl/inc/compproc.inc +++ b/rtl/inc/compproc.inc @@ -67,8 +67,15 @@ Procedure fpc_shortstr_insert_char(source:Char;var s:shortstring;index:SizeInt); {$endif VER3_0} {$ifdef FPC_HAS_FEATURE_DYNARRAYS} +{$ifdef VER3_2} function fpc_dynarray_copy(psrc : pointer;ti : pointer; lowidx,count:tdynarrayindex) : fpc_stub_dynarray;compilerproc; +{$endif VER3_2} +function fpc_array_to_dynarray_copy(psrc : pointer;ti : pointer; + lowidx,count,maxcount:tdynarrayindex; + elesize : sizeint; + eletype : pointer + ) : fpc_stub_dynarray;compilerproc; function fpc_dynarray_length(p : pointer) : tdynarrayindex; compilerproc; function fpc_dynarray_high(p : pointer) : tdynarrayindex; compilerproc; procedure fpc_dynarray_clear(var p : pointer;ti : pointer); compilerproc; diff --git a/rtl/inc/dynarr.inc b/rtl/inc/dynarr.inc index 0fbb020f54..436295c9d0 100644 --- a/rtl/inc/dynarr.inc +++ b/rtl/inc/dynarr.inc @@ -315,21 +315,54 @@ procedure fpc_dynarray_setlength(var p : pointer;pti : pointer; end; -{ provide local access to dynarr_copy } -function int_dynarray_copy(psrc : pointer;ti : pointer; - lowidx,count:tdynarrayindex) : fpc_stub_dynarray;[external name 'FPC_DYNARR_COPY']; +{ provide local access to array_to_dynarray_copy } +function int_array_to_dynarray_copy(psrc : pointer;ti : pointer; + lowidx,count,maxcount:tdynarrayindex; + elesize : sizeint; + eletype : pointer + ) : fpc_stub_dynarray;[external name 'FPC_ARR_TO_DYNARR_COPY']; + +{$ifdef VER3_2} function fpc_dynarray_copy(psrc : pointer;ti : pointer; lowidx,count:tdynarrayindex) : fpc_stub_dynarray;[Public,Alias:'FPC_DYNARR_COPY'];compilerproc; var realpsrc : pdynarray; - i,size : sizeint; + eletype,tti : pointer; elesize : sizeint; - eletype : pointer; begin fpc_dynarray_clear(pointer(result),ti); if psrc=nil then exit; + + realpsrc:=pdynarray(psrc-sizeof(tdynarray)); + + tti:=aligntoqword(ti+2+PByte(ti)[1]); + + elesize:=pdynarraytypedata(tti)^.elSize; + { only set if type needs finalization } + if assigned(pdynarraytypedata(tti)^.elType) then + eletype:=pdynarraytypedata(tti)^.elType^ + else + eletype:=nil; + + fpc_array_to_dynarray_copy(psrc,ti,lowidx,count,realpsrc^.high+1,elesize,eletype); + end; +{$endif VER3_2} + +{ copy a custom array (open/dynamic/static) to dynamic array } +function fpc_array_to_dynarray_copy(psrc : pointer;ti : pointer; + lowidx,count,maxcount:tdynarrayindex; + elesize : sizeint; + eletype : pointer + ) : fpc_stub_dynarray;[Public,Alias:'FPC_ARR_TO_DYNARR_COPY'];compilerproc; + var + i,size : sizeint; + begin + fpc_dynarray_clear(pointer(result),ti); + if psrc=nil then + exit; + {$ifndef FPC_DYNARRAYCOPY_FIXED} if (lowidx=-1) and (count=-1) then begin @@ -337,7 +370,6 @@ function fpc_dynarray_copy(psrc : pointer;ti : pointer; count:=high(tdynarrayindex); end; {$endif FPC_DYNARRAYCOPY_FIXED} - realpsrc:=pdynarray(psrc-sizeof(tdynarray)); if (lowidx<0) then begin { Decrease count if index is negative, this is different from how copy() @@ -347,29 +379,11 @@ function fpc_dynarray_copy(psrc : pointer;ti : pointer; count:=count+lowidx; lowidx:=0; end; - if (count>realpsrc^.high-lowidx+1) then - count:=realpsrc^.high-lowidx+1; + if (count>maxcount-lowidx) then + count:=maxcount-lowidx; if count<=0 then exit; - { skip kind and name } -{$ifdef VER3_0} - ti:=aligntoptr(ti+2+PByte(ti)[1]); -{$else VER3_0} - ti:=aligntoqword(ti+2+PByte(ti)[1]); -{$endif VER3_0} - - elesize:=pdynarraytypedata(ti)^.elSize; - { only set if type needs finalization } - {$ifdef VER3_0} - eletype:=pdynarraytypedata(ti)^.elType; - {$else} - if assigned(pdynarraytypedata(ti)^.elType) then - eletype:=pdynarraytypedata(ti)^.elType^ - else - eletype:=nil; - {$endif} - { create new array } size:=elesize*count; getmem(pointer(result),size+sizeof(tdynarray)); diff --git a/tests/test/tarray22.pp b/tests/test/tarray22.pp new file mode 100644 index 0000000000..6466e9e6ef --- /dev/null +++ b/tests/test/tarray22.pp @@ -0,0 +1,99 @@ +{ %OPT = -gh } + +program tarray22; + +{$mode objfpc}{$h+} + +type + TIntegerArray = array of Integer; + TStringArray = array of String; + +generic procedure CheckArray(const Actual, Expected: array of T; Code: LongInt); +var + i: SizeInt; +begin + if Length(Actual) <> Length(Expected) then + Halt(Code); + for i := 0 to High(Actual) do + if Actual[i] <> Expected[i] then + Halt(Code); +end; + +procedure TestOpen(const A: array of Integer; Exp: array of Integer; Code: LongInt); +var + B: array of Integer; +begin + B := Copy(A); + specialize CheckArray(B, Exp, Code); +end; + +procedure TestOpen2(const A: array of Integer; Exp: array of Integer; Code: LongInt); +var + B: array of Integer; +begin + B := Copy(A, 1, 2); + specialize CheckArray(B, Exp, Code); +end; + +procedure TestDyn(const A: TIntegerArray; Exp: array of Integer; Code: LongInt); +var + B: array of Integer; +begin + B := Copy(A); + specialize CheckArray(B, Exp, Code); +end; + +procedure TestDyn2(const A: TIntegerArray; Exp: array of Integer; Code: LongInt); +var + B: array of Integer; +begin + B := Copy(A, 1, 2); + specialize CheckArray(B, Exp, Code); +end; + +procedure TestOpen(const A: array of String; Exp: array of String; Code: LongInt); +var + B: array of String; +begin + B := Copy(A); + specialize CheckArray(B, Exp, Code); +end; + +procedure TestOpen2(const A: array of String; Exp: array of String; Code: LongInt); +var + B: array of String; +begin + B := Copy(A, 1, 2); + specialize CheckArray(B, Exp, Code); +end; + +procedure TestDyn(const A: TStringArray; Exp: array of String; Code: LongInt); +var + B: array of String; +begin + B := Copy(A); + specialize CheckArray(B, Exp, Code); +end; + +procedure TestDyn2(const A: TStringArray; Exp: array of String; Code: LongInt); +var + B: array of String; +begin + B := Copy(A, 1, 2); + specialize CheckArray(B, Exp, Code); +end; + +begin + HaltOnNotReleased := True; + + TestOpen([0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], 1); + TestOpen2([0, 1, 2, 3, 4, 5], [1, 2], 2); + TestDyn([0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], 3); + TestDyn2([0, 1, 2, 3, 4, 5], [1, 2], 4); + + TestOpen(['Alpha', 'Beta', 'Gamma', 'Delta'], ['Alpha', 'Beta', 'Gamma', 'Delta'], 5); + TestOpen2(['Alpha', 'Beta', 'Gamma', 'Delta'], ['Beta', 'Gamma'], 6); + TestDyn(['Alpha', 'Beta', 'Gamma', 'Delta'], ['Alpha', 'Beta', 'Gamma', 'Delta'], 7); + TestDyn2(['Alpha', 'Beta', 'Gamma', 'Delta'], ['Beta', 'Gamma'], 8); +end. +