Merged revision(s) 44172, 44188, 45457 - 45458, 45645, 46218, 46953 from trunk:

r46953
* fix for Mantis #37806: allow undefineddefs for Include() and Exclude() + added tests
---------------------
r46218
* fix for Mantis #37187: inside generics the constant code in pexpr does not handle all cases and thus current_procinfo needs to be checked as well + added test
---------------------
r45645
* correctly set the generic related defoptions for an outlined procdef
---------------------
r45458
  * make more use of is_typeparam
---------------------
r45457
  * constrained type parameters are not undefined defs, resolves #37107
---------------------
r44188
* keep track of the fileposinfo for generic constraints
---------------------
r44172
* only resolve a dummy symbol if it is a type symbol (thus truly a dummy symbol) + added tests
---------------------

git-svn-id: branches/fixes_3_2@47802 -
This commit is contained in:
svenbarth 2020-12-17 21:31:16 +00:00
parent b9fe6b9612
commit e6ad8a0dfa
13 changed files with 275 additions and 115 deletions

6
.gitattributes vendored
View File

@ -12930,8 +12930,11 @@ tests/tbs/tb0659g.pp svneol=native#text/pascal
tests/tbs/tb0665.pp svneol=native#text/pascal tests/tbs/tb0665.pp svneol=native#text/pascal
tests/tbs/tb0666a.pp svneol=native#text/pascal tests/tbs/tb0666a.pp svneol=native#text/pascal
tests/tbs/tb0666b.pp svneol=native#text/pascal tests/tbs/tb0666b.pp svneol=native#text/pascal
tests/tbs/tb0668a.pp svneol=native#text/pascal
tests/tbs/tb0668b.pp svneol=native#text/pascal
tests/tbs/tb0669.pp svneol=native#text/pascal tests/tbs/tb0669.pp svneol=native#text/pascal
tests/tbs/tb0676.pp svneol=native#text/pascal tests/tbs/tb0676.pp svneol=native#text/pascal
tests/tbs/tb0677.pp svneol=native#text/pascal
tests/tbs/tb0678.pp svneol=native#text/pascal tests/tbs/tb0678.pp svneol=native#text/pascal
tests/tbs/tb205.pp svneol=native#text/plain tests/tbs/tb205.pp svneol=native#text/plain
tests/tbs/tb610.pp svneol=native#text/pascal tests/tbs/tb610.pp svneol=native#text/pascal
@ -17770,7 +17773,9 @@ tests/webtbs/tw3708.pp svneol=native#text/plain
tests/webtbs/tw37085.pp svneol=native#text/pascal tests/webtbs/tw37085.pp svneol=native#text/pascal
tests/webtbs/tw37095.pp svneol=native#text/plain tests/webtbs/tw37095.pp svneol=native#text/plain
tests/webtbs/tw37095d/uw37095.pp svneol=native#text/plain tests/webtbs/tw37095d/uw37095.pp svneol=native#text/plain
tests/webtbs/tw37107.pp svneol=native#text/pascal
tests/webtbs/tw37154.pp svneol=native#text/pascal tests/webtbs/tw37154.pp svneol=native#text/pascal
tests/webtbs/tw37187.pp svneol=native#text/pascal
tests/webtbs/tw3719.pp svneol=native#text/plain tests/webtbs/tw3719.pp svneol=native#text/plain
tests/webtbs/tw3721.pp svneol=native#text/plain tests/webtbs/tw3721.pp svneol=native#text/plain
tests/webtbs/tw37218.pp svneol=native#text/pascal tests/webtbs/tw37218.pp svneol=native#text/pascal
@ -17792,6 +17797,7 @@ tests/webtbs/tw3774.pp svneol=native#text/plain
tests/webtbs/tw3777.pp svneol=native#text/plain tests/webtbs/tw3777.pp svneol=native#text/plain
tests/webtbs/tw3778.pp svneol=native#text/plain tests/webtbs/tw3778.pp svneol=native#text/plain
tests/webtbs/tw3780.pp svneol=native#text/plain tests/webtbs/tw3780.pp svneol=native#text/plain
tests/webtbs/tw37806.pp svneol=native#text/pascal
tests/webtbs/tw3782.pp svneol=native#text/plain tests/webtbs/tw3782.pp svneol=native#text/plain
tests/webtbs/tw37949.pp svneol=native#text/pascal tests/webtbs/tw37949.pp svneol=native#text/pascal
tests/webtbs/tw3796.pp svneol=native#text/plain tests/webtbs/tw3796.pp svneol=native#text/plain

View File

@ -1687,7 +1687,7 @@ implementation
function is_typeparam(def : tdef) : boolean;{$ifdef USEINLINE}inline;{$endif} function is_typeparam(def : tdef) : boolean;{$ifdef USEINLINE}inline;{$endif}
begin begin
result:=(def.typ=undefineddef); result:=(def.typ=undefineddef) or (df_genconstraint in def.defoptions);
end; end;

View File

@ -725,7 +725,7 @@ implementation
readfunctype:=nil; readfunctype:=nil;
{ can't read/write types } { can't read/write types }
if (para.left.nodetype=typen) and not(ttypenode(para.left).typedef.typ=undefineddef) then if (para.left.nodetype=typen) and not(is_typeparam(ttypenode(para.left).typedef)) then
begin begin
CGMessagePos(para.fileinfo,type_e_cant_read_write_type); CGMessagePos(para.fileinfo,type_e_cant_read_write_type);
error_para := true; error_para := true;
@ -742,126 +742,124 @@ implementation
if inlinenumber in [in_write_x,in_writeln_x] then if inlinenumber in [in_write_x,in_writeln_x] then
{ prefer strings to chararrays } { prefer strings to chararrays }
maybe_convert_to_string(para.left); maybe_convert_to_string(para.left);
if is_typeparam(para.left.resultdef) then
case para.left.resultdef.typ of error_para:=true
stringdef : else
name:=procprefixes[do_read]+tstringdef(para.left.resultdef).stringtypname; case para.left.resultdef.typ of
pointerdef : stringdef :
begin name:=procprefixes[do_read]+tstringdef(para.left.resultdef).stringtypname;
if (not is_pchar(para.left.resultdef)) or do_read then pointerdef :
begin begin
CGMessagePos(para.fileinfo,type_e_cant_read_write_type); if (not is_pchar(para.left.resultdef)) or do_read then
error_para := true;
end
else
name:=procprefixes[do_read]+'pchar_as_pointer';
end;
floatdef :
begin
is_real:=true;
if Tfloatdef(para.left.resultdef).floattype=s64currency then
name := procprefixes[do_read]+'currency'
else
begin
name := procprefixes[do_read]+'float';
readfunctype:=pbestrealtype^;
end;
{ iso pascal needs a different handler }
if (m_isolike_io in current_settings.modeswitches) and do_read then
name:=name+'_iso';
end;
enumdef:
begin
name:=procprefixes[do_read]+'enum';
readfunctype:=s32inttype;
end;
orddef :
begin
case Torddef(para.left.resultdef).ordtype of
s8bit,
s16bit,
s32bit,
s64bit,
u8bit,
u16bit,
u32bit,
u64bit:
begin begin
get_read_write_int_func(para.left.resultdef,func_suffix,readfunctype); CGMessagePos(para.fileinfo,type_e_cant_read_write_type);
name := procprefixes[do_read]+func_suffix; error_para := true;
if (m_isolike_io in current_settings.modeswitches) and do_read then end
name:=name+'_iso'; else
end; name:=procprefixes[do_read]+'pchar_as_pointer';
uchar : end;
floatdef :
begin
is_real:=true;
if Tfloatdef(para.left.resultdef).floattype=s64currency then
name := procprefixes[do_read]+'currency'
else
begin begin
name := procprefixes[do_read]+'char'; name := procprefixes[do_read]+'float';
{ iso pascal needs a different handler } readfunctype:=pbestrealtype^;
if (m_isolike_io in current_settings.modeswitches) and do_read then
name:=name+'_iso';
readfunctype:=cansichartype;
end; end;
uwidechar : { iso pascal needs a different handler }
begin if (m_isolike_io in current_settings.modeswitches) and do_read then
name := procprefixes[do_read]+'widechar'; name:=name+'_iso';
readfunctype:=cwidechartype; end;
end; enumdef:
scurrency: begin
begin name:=procprefixes[do_read]+'enum';
name := procprefixes[do_read]+'currency'; readfunctype:=s32inttype;
{ iso pascal needs a different handler } end;
if (m_isolike_io in current_settings.modeswitches) and do_read then orddef :
name:=name+'_iso'; begin
readfunctype:=s64currencytype; case Torddef(para.left.resultdef).ordtype of
is_real:=true; s8bit,
end; s16bit,
pasbool1, s32bit,
pasbool8, s64bit,
pasbool16, u8bit,
pasbool32, u16bit,
pasbool64, u32bit,
bool8bit, u64bit:
bool16bit, begin
bool32bit, get_read_write_int_func(para.left.resultdef,func_suffix,readfunctype);
bool64bit: name := procprefixes[do_read]+func_suffix;
if do_read then if (m_isolike_io in current_settings.modeswitches) and do_read then
name:=name+'_iso';
end;
uchar :
begin
name := procprefixes[do_read]+'char';
{ iso pascal needs a different handler }
if (m_isolike_io in current_settings.modeswitches) and do_read then
name:=name+'_iso';
readfunctype:=cansichartype;
end;
uwidechar :
begin
name := procprefixes[do_read]+'widechar';
readfunctype:=cwidechartype;
end;
scurrency:
begin
name := procprefixes[do_read]+'currency';
{ iso pascal needs a different handler }
if (m_isolike_io in current_settings.modeswitches) and do_read then
name:=name+'_iso';
readfunctype:=s64currencytype;
is_real:=true;
end;
pasbool1,
pasbool8,
pasbool16,
pasbool32,
pasbool64,
bool8bit,
bool16bit,
bool32bit,
bool64bit:
if do_read then
begin
CGMessagePos(para.fileinfo,type_e_cant_read_write_type);
error_para := true;
end
else
begin
name := procprefixes[do_read]+'boolean';
readfunctype:=pasbool1type;
end
else
begin begin
CGMessagePos(para.fileinfo,type_e_cant_read_write_type); CGMessagePos(para.fileinfo,type_e_cant_read_write_type);
error_para := true; error_para := true;
end end;
else end;
begin end;
name := procprefixes[do_read]+'boolean'; variantdef :
readfunctype:=pasbool1type; name:=procprefixes[do_read]+'variant';
end arraydef :
begin
if is_chararray(para.left.resultdef) then
name := procprefixes[do_read]+'pchar_as_array'
else else
begin begin
CGMessagePos(para.fileinfo,type_e_cant_read_write_type); CGMessagePos(para.fileinfo,type_e_cant_read_write_type);
error_para := true; error_para := true;
end; end
end; end;
end; else
variantdef : begin
name:=procprefixes[do_read]+'variant'; CGMessagePos(para.fileinfo,type_e_cant_read_write_type);
arraydef : error_para := true;
begin end;
if is_chararray(para.left.resultdef) then end;
name := procprefixes[do_read]+'pchar_as_array'
else
begin
CGMessagePos(para.fileinfo,type_e_cant_read_write_type);
error_para := true;
end
end;
{ generic parameter }
undefineddef:
{ don't try to generate any code for a writeln on a generic parameter }
error_para:=true;
else
begin
CGMessagePos(para.fileinfo,type_e_cant_read_write_type);
error_para := true;
end;
end;
{ iso pascal needs a different handler } { iso pascal needs a different handler }
if (m_isolike_io in current_settings.modeswitches) and not(do_read) then if (m_isolike_io in current_settings.modeswitches) and not(do_read) then
@ -2919,9 +2917,11 @@ implementation
in_sizeof_x: in_sizeof_x:
begin begin
{ the constant evaluation of in_sizeof_x happens in pexpr where possible } { the constant evaluation of in_sizeof_x happens in pexpr where possible,
though for generics it can reach here as well }
set_varstate(left,vs_read,[]); set_varstate(left,vs_read,[]);
if (left.resultdef.typ<>undefineddef) and if (left.resultdef.typ<>undefineddef) and
assigned(current_procinfo) and
paramanager.push_high_param(vs_value,left.resultdef,current_procinfo.procdef.proccalloption) then paramanager.push_high_param(vs_value,left.resultdef,current_procinfo.procdef.proccalloption) then
begin begin
{ this should be an open array or array of const, both of { this should be an open array or array of const, both of
@ -3401,7 +3401,7 @@ implementation
inserttypeconv(tcallparanode(tcallparanode(left).right).left, inserttypeconv(tcallparanode(tcallparanode(left).right).left,
tsetdef(left.resultdef).elementdef); tsetdef(left.resultdef).elementdef);
end end
else else if left.resultdef.typ<>undefineddef then
CGMessage(type_e_mismatch); CGMessage(type_e_mismatch);
end; end;
in_pack_x_y_z, in_pack_x_y_z,

View File

@ -440,7 +440,7 @@ implementation
is_open_string(p1.resultdef) is_open_string(p1.resultdef)
)) or )) or
{ keep the function call if it is a type parameter to avoid arithmetic errors due to constant folding } { keep the function call if it is a type parameter to avoid arithmetic errors due to constant folding }
(p1.resultdef.typ=undefineddef) then is_typeparam(p1.resultdef) then
begin begin
statement_syssym:=geninlinenode(in_sizeof_x,false,p1); statement_syssym:=geninlinenode(in_sizeof_x,false,p1);
{ no packed bit support for these things } { no packed bit support for these things }
@ -2959,11 +2959,11 @@ implementation
wasgenericdummy:=false; wasgenericdummy:=false;
if assigned(srsym) and if assigned(srsym) and
(sp_generic_dummy in srsym.symoptions) and (sp_generic_dummy in srsym.symoptions) and
(srsym.typ=typesym) and
( (
( (
(m_delphi in current_settings.modeswitches) and (m_delphi in current_settings.modeswitches) and
not (token in [_LT, _LSHARPBRACKET]) and not (token in [_LT, _LSHARPBRACKET]) and
(srsym.typ=typesym) and
(ttypesym(srsym).typedef.typ=undefineddef) (ttypesym(srsym).typedef.typ=undefineddef)
) )
or or

View File

@ -1259,6 +1259,7 @@ uses
doconsume : boolean; doconsume : boolean;
constraintdata : tgenericconstraintdata; constraintdata : tgenericconstraintdata;
old_block_type : tblock_type; old_block_type : tblock_type;
fileinfo : tfileposinfo;
begin begin
result:=tfphashobjectlist.create(false); result:=tfphashobjectlist.create(false);
firstidx:=0; firstidx:=0;
@ -1274,6 +1275,7 @@ uses
result.add(orgpattern,generictype); result.add(orgpattern,generictype);
end; end;
consume(_ID); consume(_ID);
fileinfo:=current_tokenpos;
if try_to_consume(_COLON) then if try_to_consume(_COLON) then
begin begin
if not allowconstraints then if not allowconstraints then
@ -1281,6 +1283,7 @@ uses
Message(parser_e_illegal_expression{ parser_e_generic_constraints_not_allowed_here}); Message(parser_e_illegal_expression{ parser_e_generic_constraints_not_allowed_here});
{ construct a name which can be used for a type specification } { construct a name which can be used for a type specification }
constraintdata:=tgenericconstraintdata.create; constraintdata:=tgenericconstraintdata.create;
constraintdata.fileinfo:=fileinfo;
defname:=''; defname:='';
str(current_module.deflist.count,defname); str(current_module.deflist.count,defname);
defname:='$gendef'+defname; defname:='$gendef'+defname;
@ -1395,6 +1398,7 @@ uses
genconstraintdata:=tgenericconstraintdata.create; genconstraintdata:=tgenericconstraintdata.create;
genconstraintdata.flags:=constraintdata.flags; genconstraintdata.flags:=constraintdata.flags;
genconstraintdata.interfaces.assign(constraintdata.interfaces); genconstraintdata.interfaces.assign(constraintdata.interfaces);
genconstraintdata.fileinfo:=constraintdata.fileinfo;
include(defoptions,df_genconstraint); include(defoptions,df_genconstraint);
end; end;

View File

@ -65,6 +65,10 @@ implementation
symtablestack:=nil; symtablestack:=nil;
result:=cprocdef.create(max(normal_function_level,st.symtablelevel)+1,true); result:=cprocdef.create(max(normal_function_level,st.symtablelevel)+1,true);
result.returndef:=resultdef; result.returndef:=resultdef;
{ if the parent is a generic or a specialization, the new function is one
as well }
if st.symtabletype=localsymtable then
result.defoptions:=result.defoptions+(tstoreddef(st.defowner).defoptions*[df_generic,df_specialization]);
symtablestack:=oldsymtablestack; symtablestack:=oldsymtablestack;
st.insertdef(result); st.insertdef(result);
result.struct:=astruct; result.struct:=astruct;

View File

@ -50,6 +50,8 @@ interface
interfaces : tfpobjectlist; interfaces : tfpobjectlist;
interfacesderef : tfplist; interfacesderef : tfplist;
flags : tgenericconstraintflags; flags : tgenericconstraintflags;
{ only required while parsing }
fileinfo : tfileposinfo;
constructor create; constructor create;
destructor destroy;override; destructor destroy;override;
procedure ppuload(ppufile:tcompilerppufile); procedure ppuload(ppufile:tcompilerppufile);

20
tests/tbs/tb0668a.pp Normal file
View File

@ -0,0 +1,20 @@
{ %NORUN }
program tb0668a;
{$mode objfpc}
procedure FreeAndNil(var Obj);
begin
end;
generic procedure FreeAndNil<T: class>(var Obj: T);
begin
end;
var
t: TObject;
begin
FreeAndNil(t);
specialize FreeAndNil<TObject>(t);
end.

20
tests/tbs/tb0668b.pp Normal file
View File

@ -0,0 +1,20 @@
{ %NORUN }
program tb0668b;
{$mode objfpc}
generic procedure FreeAndNil<T: class>(var Obj: T);
begin
end;
procedure FreeAndNil(var Obj);
begin
end;
var
t: TObject;
begin
FreeAndNil(t);
specialize FreeAndNil<TObject>(t);
end.

40
tests/tbs/tb0677.pp Normal file
View File

@ -0,0 +1,40 @@
{ %NORUN }
program tb0677;
{$mode objfpc}
type
TEnum = (eOne, eTwo, eThree, eFour);
TSet = set of TEnum;
generic TTest<SetType, EnumType> = class
procedure Test;
end;
procedure TTest.Test;
var
s1: TSet;
s2: SetType;
e1: TEnum;
e2: EnumType;
begin
Include(s1, e1);
Exclude(s1, e1);
Include(s2, e1);
Exclude(s2, e1);
Include(s2, e2);
Exclude(s2, e2);
Include(s2, e1);
Exclude(s2, e2);
end;
type
TTestTypes = specialize TTest<TSet, TEnum>;
begin
end.

19
tests/webtbs/tw37107.pp Normal file
View File

@ -0,0 +1,19 @@
program genTest;
{$IFDEF FPC}{$mode Delphi}{$ENDIF}
type
TTest<T: Record> = class(TObject)
procedure testit();
end;
procedure TTest<T>.testit();
begin
WriteLn('=== ', 1 div SizeOf(T));
if SizeOf(T) > 0 then
WriteLn('I''m reachable!')
end;
begin
TTest<Char>.Create().TestIt();
end.

19
tests/webtbs/tw37187.pp Normal file
View File

@ -0,0 +1,19 @@
{ %NORUN }
program tw37187;
{$mode objfpc}
type
generic TTest<T: class> = class
arr: array[0..SizeOf(T)] of Byte;
end;
generic TTest2<T: class> = class
public type
TTestT = specialize TTest<T>;
end;
begin
end.

26
tests/webtbs/tw37806.pp Normal file
View File

@ -0,0 +1,26 @@
program tw37806;
{$mode delphi}
procedure TurnSetElem<TSet, TElem>(var aSet: TSet; aElem: TElem; aOn: Boolean);
begin
if aOn then
Include(aSet, aElem)
else
Exclude(aSet, aElem);
end;
type
TElem = (One, Two, Three, Four, Five);
TSet = set of TElem;
var
s: TSet = [];
begin
TurnSetElem<TSet, TElem>(s, Two, True);
TurnSetElem<TSet, TElem>(s, Five, True);
if not((Two in s) and (Five in s)) then
Halt(1);
//WriteLn('does not work');
end.