mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-15 13:59:29 +02:00
1421 lines
57 KiB
ObjectPascal
1421 lines
57 KiB
ObjectPascal
{
|
|
$Id$
|
|
Copyright (c) 1998-2002 by Florian Klaempfl
|
|
|
|
Compare definitions and parameter lists
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
****************************************************************************
|
|
}
|
|
unit defcmp;
|
|
|
|
{$i fpcdefs.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
cclasses,
|
|
cpuinfo,
|
|
globtype,globals,tokens,
|
|
node,
|
|
symconst,symbase,symtype,symdef;
|
|
|
|
type
|
|
{ if acp is cp_all the var const or nothing are considered equal }
|
|
tcompare_paras_type = ( cp_none, cp_value_equal_const, cp_all,cp_procvar);
|
|
tcompare_paras_option = (cpo_allowdefaults,cpo_ignorehidden,cpo_allowconvert,cpo_comparedefaultvalue);
|
|
tcompare_paras_options = set of tcompare_paras_option;
|
|
|
|
tconverttype = (
|
|
tc_equal,
|
|
tc_not_possible,
|
|
tc_string_2_string,
|
|
tc_char_2_string,
|
|
tc_char_2_chararray,
|
|
tc_pchar_2_string,
|
|
tc_cchar_2_pchar,
|
|
tc_cstring_2_pchar,
|
|
tc_ansistring_2_pchar,
|
|
tc_string_2_chararray,
|
|
tc_chararray_2_string,
|
|
tc_array_2_pointer,
|
|
tc_pointer_2_array,
|
|
tc_int_2_int,
|
|
tc_int_2_bool,
|
|
tc_bool_2_bool,
|
|
tc_bool_2_int,
|
|
tc_real_2_real,
|
|
tc_int_2_real,
|
|
tc_real_2_currency,
|
|
tc_proc_2_procvar,
|
|
tc_arrayconstructor_2_set,
|
|
tc_load_smallset,
|
|
tc_cord_2_pointer,
|
|
tc_intf_2_string,
|
|
tc_intf_2_guid,
|
|
tc_class_2_intf,
|
|
tc_char_2_char,
|
|
tc_normal_2_smallset,
|
|
tc_dynarray_2_openarray,
|
|
tc_pwchar_2_string,
|
|
tc_variant_2_dynarray,
|
|
tc_dynarray_2_variant,
|
|
tc_variant_2_enum,
|
|
tc_enum_2_variant
|
|
);
|
|
|
|
function compare_defs_ext(def_from,def_to : tdef;
|
|
fromtreetype : tnodetype;
|
|
explicit : boolean;
|
|
check_operator : boolean;
|
|
var doconv : tconverttype;
|
|
var operatorpd : tprocdef):tequaltype;
|
|
|
|
{ Returns if the type def_from can be converted to def_to or if both types are equal }
|
|
function compare_defs(def_from,def_to:tdef;fromtreetype:tnodetype):tequaltype;
|
|
|
|
{ Returns true, if def1 and def2 are semantically the same }
|
|
function equal_defs(def_from,def_to:tdef):boolean;
|
|
|
|
{ Checks for type compatibility (subgroups of type)
|
|
used for case statements... probably missing stuff
|
|
to use on other types }
|
|
function is_subequal(def1, def2: tdef): boolean;
|
|
|
|
function assignment_overloaded(from_def,to_def : tdef) : tprocdef;
|
|
|
|
{# true, if two parameter lists are equal
|
|
if acp is cp_none, all have to match exactly
|
|
if acp is cp_value_equal_const call by value
|
|
and call by const parameter are assumed as
|
|
equal
|
|
allowdefaults indicates if default value parameters
|
|
are allowed (in this case, the search order will first
|
|
search for a routine with default parameters, before
|
|
searching for the same definition with no parameters)
|
|
}
|
|
function compare_paras(paralist1,paralist2 : TLinkedList; acp : tcompare_paras_type; cpoptions: tcompare_paras_options):tequaltype;
|
|
|
|
{ True if a function can be assigned to a procvar }
|
|
{ changed first argument type to pabstractprocdef so that it can also be }
|
|
{ used to test compatibility between two pprocvardefs (JM) }
|
|
function proc_to_procvar_equal(def1:tabstractprocdef;def2:tprocvardef;methoderr:boolean):tequaltype;
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
verbose,systems,
|
|
symtable,symsym,
|
|
defutil,symutil;
|
|
|
|
|
|
function assignment_overloaded(from_def,to_def:tdef):tprocdef;
|
|
begin
|
|
if assigned(overloaded_operators[_ASSIGNMENT]) then
|
|
assignment_overloaded:=overloaded_operators[_ASSIGNMENT].search_procdef_assignment_operator(from_def,to_def)
|
|
else
|
|
assignment_overloaded:=nil;
|
|
end;
|
|
|
|
|
|
function compare_defs_ext(def_from,def_to : tdef;
|
|
fromtreetype : tnodetype;
|
|
explicit : boolean;
|
|
check_operator : boolean;
|
|
var doconv : tconverttype;
|
|
var operatorpd : tprocdef):tequaltype;
|
|
|
|
{ Tbasetype:
|
|
uvoid,
|
|
u8bit,u16bit,u32bit,u64bit,
|
|
s8bit,s16bit,s32bit,s64bit,
|
|
bool8bit,bool16bit,bool32bit,
|
|
uchar,uwidechar }
|
|
|
|
type
|
|
tbasedef=(bvoid,bchar,bint,bbool);
|
|
const
|
|
basedeftbl:array[tbasetype] of tbasedef =
|
|
(bvoid,
|
|
bint,bint,bint,bint,
|
|
bint,bint,bint,bint,
|
|
bbool,bbool,bbool,
|
|
bchar,bchar,bint);
|
|
|
|
basedefconvertsimplicit : array[tbasedef,tbasedef] of tconverttype =
|
|
{ void, char, int, bool }
|
|
((tc_not_possible,tc_not_possible,tc_not_possible,tc_not_possible),
|
|
(tc_not_possible,tc_char_2_char,tc_not_possible,tc_not_possible),
|
|
(tc_not_possible,tc_not_possible,tc_int_2_int,tc_not_possible),
|
|
(tc_not_possible,tc_not_possible,tc_not_possible,tc_bool_2_bool));
|
|
basedefconvertsexplicit : array[tbasedef,tbasedef] of tconverttype =
|
|
{ void, char, int, bool }
|
|
((tc_not_possible,tc_not_possible,tc_not_possible,tc_not_possible),
|
|
(tc_not_possible,tc_char_2_char,tc_int_2_int,tc_int_2_bool),
|
|
(tc_not_possible,tc_int_2_int,tc_int_2_int,tc_int_2_bool),
|
|
(tc_not_possible,tc_bool_2_int,tc_bool_2_int,tc_bool_2_bool));
|
|
|
|
var
|
|
subeq,eq : tequaltype;
|
|
hd1,hd2 : tdef;
|
|
hct : tconverttype;
|
|
hd3 : tobjectdef;
|
|
hpd : tprocdef;
|
|
begin
|
|
{ safety check }
|
|
if not(assigned(def_from) and assigned(def_to)) then
|
|
begin
|
|
compare_defs_ext:=te_incompatible;
|
|
exit;
|
|
end;
|
|
|
|
{ same def? then we've an exact match }
|
|
if def_from=def_to then
|
|
begin
|
|
compare_defs_ext:=te_exact;
|
|
exit;
|
|
end;
|
|
|
|
{ we walk the wanted (def_to) types and check then the def_from
|
|
types if there is a conversion possible }
|
|
eq:=te_incompatible;
|
|
doconv:=tc_not_possible;
|
|
case def_to.deftype of
|
|
orddef :
|
|
begin
|
|
case def_from.deftype of
|
|
orddef :
|
|
begin
|
|
if (torddef(def_from).typ=torddef(def_to).typ) then
|
|
begin
|
|
case torddef(def_from).typ of
|
|
uchar,uwidechar,
|
|
u8bit,u16bit,u32bit,u64bit,
|
|
s8bit,s16bit,s32bit,s64bit:
|
|
begin
|
|
if (torddef(def_from).low=torddef(def_to).low) and
|
|
(torddef(def_from).high=torddef(def_to).high) then
|
|
eq:=te_equal
|
|
else
|
|
begin
|
|
doconv:=tc_int_2_int;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
uvoid,
|
|
bool8bit,bool16bit,bool32bit:
|
|
eq:=te_equal;
|
|
else
|
|
internalerror(200210061);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if explicit then
|
|
doconv:=basedefconvertsexplicit[basedeftbl[torddef(def_from).typ],basedeftbl[torddef(def_to).typ]]
|
|
else
|
|
doconv:=basedefconvertsimplicit[basedeftbl[torddef(def_from).typ],basedeftbl[torddef(def_to).typ]];
|
|
if (doconv=tc_not_possible) then
|
|
eq:=te_incompatible
|
|
else
|
|
{ "punish" bad type conversions :) (JM) }
|
|
if (not is_in_limit(def_from,def_to)) and
|
|
(def_from.size > def_to.size) then
|
|
eq:=te_convert_l3
|
|
else
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
enumdef :
|
|
begin
|
|
{ needed for char(enum) }
|
|
if explicit then
|
|
begin
|
|
doconv:=tc_int_2_int;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
floatdef :
|
|
begin
|
|
if is_currency(def_to) then
|
|
begin
|
|
doconv:=tc_real_2_currency;
|
|
eq:=te_convert_l2;
|
|
end;
|
|
end;
|
|
classrefdef,
|
|
procvardef,
|
|
pointerdef :
|
|
begin
|
|
if explicit then
|
|
begin
|
|
eq:=te_convert_l1;
|
|
if (fromtreetype=niln) then
|
|
begin
|
|
{ will be handled by the constant folding }
|
|
doconv:=tc_equal;
|
|
end
|
|
else
|
|
doconv:=tc_int_2_int;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
stringdef :
|
|
begin
|
|
case def_from.deftype of
|
|
stringdef :
|
|
begin
|
|
{ Constant string }
|
|
if (fromtreetype=stringconstn) then
|
|
begin
|
|
if (tstringdef(def_from).string_typ=tstringdef(def_to).string_typ) then
|
|
eq:=te_equal
|
|
else
|
|
begin
|
|
doconv:=tc_string_2_string;
|
|
{ Don't prefer conversions from widestring to a
|
|
normal string as we can loose information }
|
|
if tstringdef(def_from).string_typ=st_widestring then
|
|
eq:=te_convert_l1
|
|
else
|
|
begin
|
|
if tstringdef(def_to).string_typ=st_widestring then
|
|
eq:=te_convert_l1
|
|
else
|
|
eq:=te_equal; { we can change the stringconst node }
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
{ Same string type, for shortstrings also the length must match }
|
|
if (tstringdef(def_from).string_typ=tstringdef(def_to).string_typ) and
|
|
((tstringdef(def_from).string_typ<>st_shortstring) or
|
|
(tstringdef(def_from).len=tstringdef(def_to).len)) then
|
|
eq:=te_equal
|
|
else
|
|
begin
|
|
doconv:=tc_string_2_string;
|
|
{ Prefer conversions to shortstring over other
|
|
conversions. This is compatible with Delphi (PFV) }
|
|
if tstringdef(def_to).string_typ=st_shortstring then
|
|
eq:=te_convert_l2
|
|
else
|
|
eq:=te_convert_l3;
|
|
end;
|
|
end;
|
|
orddef :
|
|
begin
|
|
{ char to string}
|
|
if is_char(def_from) or
|
|
is_widechar(def_from) then
|
|
begin
|
|
doconv:=tc_char_2_string;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
arraydef :
|
|
begin
|
|
{ array of char to string, the length check is done by the firstpass of this node }
|
|
if is_chararray(def_from) or
|
|
(is_char(tarraydef(def_from).elementtype.def) and
|
|
is_open_array(def_from)) then
|
|
begin
|
|
doconv:=tc_chararray_2_string;
|
|
if is_open_array(def_from) or
|
|
(is_shortstring(def_to) and
|
|
(def_from.size <= 255)) or
|
|
(is_ansistring(def_to) and
|
|
(def_from.size > 255)) then
|
|
eq:=te_convert_l1
|
|
else
|
|
eq:=te_convert_l2;
|
|
end;
|
|
end;
|
|
pointerdef :
|
|
begin
|
|
{ pchar can be assigned to short/ansistrings,
|
|
but not in tp7 compatible mode }
|
|
if not(m_tp7 in aktmodeswitches) then
|
|
begin
|
|
if is_pchar(def_from) then
|
|
begin
|
|
doconv:=tc_pchar_2_string;
|
|
{ prefer ansistrings because pchars can overflow shortstrings, }
|
|
{ but only if ansistrings are the default (JM) }
|
|
if (is_shortstring(def_to) and
|
|
not(cs_ansistrings in aktlocalswitches)) or
|
|
(is_ansistring(def_to) and
|
|
(cs_ansistrings in aktlocalswitches)) then
|
|
eq:=te_convert_l1
|
|
else
|
|
eq:=te_convert_l2;
|
|
end
|
|
else if is_pwidechar(def_from) then
|
|
begin
|
|
doconv:=tc_pwchar_2_string;
|
|
{ prefer ansistrings because pchars can overflow shortstrings, }
|
|
{ but only if ansistrings are the default (JM) }
|
|
if is_widestring(def_to) then
|
|
eq:=te_convert_l1
|
|
else
|
|
eq:=te_convert_l3;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
floatdef :
|
|
begin
|
|
case def_from.deftype of
|
|
orddef :
|
|
begin { ordinal to real }
|
|
if is_integer(def_from) or
|
|
(is_currency(def_from) and
|
|
(s64currencytype.def.deftype = floatdef)) then
|
|
begin
|
|
doconv:=tc_int_2_real;
|
|
eq:=te_convert_l1;
|
|
end
|
|
else if is_currency(def_from)
|
|
{ and (s64currencytype.def.deftype = orddef)) } then
|
|
begin
|
|
{ prefer conversion to orddef in this case, unless }
|
|
{ the orddef < currency (then it will get convert l3, }
|
|
{ and conversion to float is favoured) }
|
|
doconv:=tc_int_2_real;
|
|
eq:=te_convert_l2;
|
|
end;
|
|
end;
|
|
floatdef :
|
|
begin
|
|
if tfloatdef(def_from).typ=tfloatdef(def_to).typ then
|
|
eq:=te_equal
|
|
else
|
|
begin
|
|
if not(explicit) or
|
|
not(m_delphi in aktmodeswitches) then
|
|
begin
|
|
doconv:=tc_real_2_real;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
enumdef :
|
|
begin
|
|
case def_from.deftype of
|
|
enumdef :
|
|
begin
|
|
if explicit then
|
|
begin
|
|
eq:=te_convert_l1;
|
|
doconv:=tc_int_2_int;
|
|
end
|
|
else
|
|
begin
|
|
hd1:=def_from;
|
|
while assigned(tenumdef(hd1).basedef) do
|
|
hd1:=tenumdef(hd1).basedef;
|
|
hd2:=def_to;
|
|
while assigned(tenumdef(hd2).basedef) do
|
|
hd2:=tenumdef(hd2).basedef;
|
|
if (hd1=hd2) then
|
|
begin
|
|
eq:=te_convert_l1;
|
|
{ because of packenum they can have different sizes! (JM) }
|
|
doconv:=tc_int_2_int;
|
|
end;
|
|
end;
|
|
end;
|
|
orddef :
|
|
begin
|
|
if explicit then
|
|
begin
|
|
eq:=te_convert_l1;
|
|
doconv:=tc_int_2_int;
|
|
end;
|
|
end;
|
|
variantdef :
|
|
begin
|
|
eq:=te_convert_l1;
|
|
doconv:=tc_variant_2_enum;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
arraydef :
|
|
begin
|
|
{ open array is also compatible with a single element of its base type }
|
|
if is_open_array(def_to) and
|
|
equal_defs(def_from,tarraydef(def_to).elementtype.def) then
|
|
begin
|
|
doconv:=tc_equal;
|
|
eq:=te_convert_l1;
|
|
end
|
|
else
|
|
begin
|
|
case def_from.deftype of
|
|
arraydef :
|
|
begin
|
|
{ to dynamic array }
|
|
if is_dynamic_array(def_to) then
|
|
begin
|
|
{ dynamic array -> dynamic array }
|
|
if is_dynamic_array(def_from) and
|
|
equal_defs(tarraydef(def_from).elementtype.def,tarraydef(def_to).elementtype.def) then
|
|
eq:=te_equal;
|
|
end
|
|
else
|
|
{ to open array }
|
|
if is_open_array(def_to) then
|
|
begin
|
|
{ array constructor -> open array }
|
|
if is_array_constructor(def_from) then
|
|
begin
|
|
if is_void(tarraydef(def_from).elementtype.def) then
|
|
begin
|
|
doconv:=tc_equal;
|
|
eq:=te_convert_l1;
|
|
end
|
|
else
|
|
begin
|
|
subeq:=compare_defs_ext(tarraydef(def_from).elementtype.def,
|
|
tarraydef(def_to).elementtype.def,
|
|
arrayconstructorn,false,true,hct,hpd);
|
|
if (subeq>=te_equal) then
|
|
begin
|
|
doconv:=tc_equal;
|
|
eq:=te_convert_l1;
|
|
end
|
|
else
|
|
if (subeq>te_incompatible) then
|
|
begin
|
|
doconv:=hct;
|
|
eq:=te_convert_l2;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
{ dynamic array -> open array }
|
|
if is_dynamic_array(def_from) and
|
|
equal_defs(tarraydef(def_from).elementtype.def,tarraydef(def_to).elementtype.def) then
|
|
begin
|
|
doconv:=tc_dynarray_2_openarray;
|
|
eq:=te_convert_l2;
|
|
end
|
|
else
|
|
{ array -> open array }
|
|
if equal_defs(tarraydef(def_from).elementtype.def,tarraydef(def_to).elementtype.def) then
|
|
eq:=te_equal;
|
|
end
|
|
else
|
|
{ to array of const }
|
|
if is_array_of_const(def_to) then
|
|
begin
|
|
if is_array_of_const(def_from) or
|
|
is_array_constructor(def_from) then
|
|
begin
|
|
eq:=te_equal;
|
|
end
|
|
else
|
|
{ array of tvarrec -> array of const }
|
|
if equal_defs(tarraydef(def_to).elementtype.def,tarraydef(def_from).elementtype.def) then
|
|
begin
|
|
doconv:=tc_equal;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end
|
|
else
|
|
{ other arrays }
|
|
begin
|
|
{ open array -> array }
|
|
if is_open_array(def_from) and
|
|
equal_defs(tarraydef(def_from).elementtype.def,tarraydef(def_to).elementtype.def) then
|
|
begin
|
|
eq:=te_equal
|
|
end
|
|
else
|
|
{ array -> array }
|
|
if not(m_tp7 in aktmodeswitches) and
|
|
not(m_delphi in aktmodeswitches) and
|
|
(tarraydef(def_from).lowrange=tarraydef(def_to).lowrange) and
|
|
(tarraydef(def_from).highrange=tarraydef(def_to).highrange) and
|
|
equal_defs(tarraydef(def_from).elementtype.def,tarraydef(def_to).elementtype.def) and
|
|
equal_defs(tarraydef(def_from).rangetype.def,tarraydef(def_to).rangetype.def) then
|
|
begin
|
|
eq:=te_equal
|
|
end;
|
|
end;
|
|
end;
|
|
pointerdef :
|
|
begin
|
|
{ nil is compatible with dyn. arrays }
|
|
if is_dynamic_array(def_to) and
|
|
(fromtreetype=niln) then
|
|
begin
|
|
doconv:=tc_equal;
|
|
eq:=te_convert_l1;
|
|
end
|
|
else
|
|
if is_zero_based_array(def_to) and
|
|
equal_defs(tpointerdef(def_from).pointertype.def,tarraydef(def_to).elementtype.def) then
|
|
begin
|
|
doconv:=tc_pointer_2_array;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
stringdef :
|
|
begin
|
|
{ string to char array }
|
|
if (not is_special_array(def_to)) and
|
|
is_char(tarraydef(def_to).elementtype.def) then
|
|
begin
|
|
doconv:=tc_string_2_chararray;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
orddef:
|
|
begin
|
|
if is_chararray(def_to) and
|
|
is_char(def_from) then
|
|
begin
|
|
doconv:=tc_char_2_chararray;
|
|
eq:=te_convert_l2;
|
|
end;
|
|
end;
|
|
recorddef :
|
|
begin
|
|
{ tvarrec -> array of const }
|
|
if is_array_of_const(def_to) and
|
|
equal_defs(def_from,tarraydef(def_to).elementtype.def) then
|
|
begin
|
|
doconv:=tc_equal;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
variantdef :
|
|
begin
|
|
if is_dynamic_array(def_to) then
|
|
begin
|
|
doconv:=tc_variant_2_dynarray;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
variantdef :
|
|
begin
|
|
case def_from.deftype of
|
|
enumdef :
|
|
begin
|
|
doconv:=tc_enum_2_variant;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
arraydef :
|
|
begin
|
|
if is_dynamic_array(def_from) then
|
|
begin
|
|
doconv:=tc_dynarray_2_variant;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
pointerdef :
|
|
begin
|
|
case def_from.deftype of
|
|
stringdef :
|
|
begin
|
|
{ string constant (which can be part of array constructor)
|
|
to zero terminated string constant }
|
|
if (fromtreetype in [arrayconstructorn,stringconstn]) and
|
|
(is_pchar(def_to) or is_pwidechar(def_to)) then
|
|
begin
|
|
doconv:=tc_cstring_2_pchar;
|
|
eq:=te_convert_l1;
|
|
end
|
|
else
|
|
if explicit then
|
|
begin
|
|
{ pchar(ansistring) }
|
|
if is_pchar(def_to) and
|
|
is_ansistring(def_from) then
|
|
begin
|
|
doconv:=tc_ansistring_2_pchar;
|
|
eq:=te_convert_l1;
|
|
end
|
|
else
|
|
{ pwidechar(ansistring) }
|
|
if is_pwidechar(def_to) and
|
|
is_widestring(def_from) then
|
|
begin
|
|
doconv:=tc_ansistring_2_pchar;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
end;
|
|
orddef :
|
|
begin
|
|
{ char constant to zero terminated string constant }
|
|
if (fromtreetype=ordconstn) then
|
|
begin
|
|
if is_char(def_from) and
|
|
is_pchar(def_to) then
|
|
begin
|
|
doconv:=tc_cchar_2_pchar;
|
|
eq:=te_convert_l1;
|
|
end
|
|
else
|
|
if (m_delphi in aktmodeswitches) and is_integer(def_from) then
|
|
begin
|
|
doconv:=tc_cord_2_pointer;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
if (eq=te_incompatible) and explicit then
|
|
begin
|
|
doconv:=tc_int_2_int;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
arraydef :
|
|
begin
|
|
{ chararray to pointer }
|
|
if is_zero_based_array(def_from) and
|
|
equal_defs(tarraydef(def_from).elementtype.def,tpointerdef(def_to).pointertype.def) then
|
|
begin
|
|
doconv:=tc_array_2_pointer;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
pointerdef :
|
|
begin
|
|
{ check for far pointers }
|
|
if (tpointerdef(def_from).is_far<>tpointerdef(def_to).is_far) then
|
|
begin
|
|
eq:=te_incompatible;
|
|
end
|
|
else
|
|
{ the types can be forward type, handle before normal type check !! }
|
|
if assigned(def_to.typesym) and
|
|
(tpointerdef(def_to).pointertype.def.deftype=forwarddef) then
|
|
begin
|
|
if (def_from.typesym=def_to.typesym) then
|
|
eq:=te_equal
|
|
end
|
|
else
|
|
{ same types }
|
|
if (tpointerdef(def_from).pointertype.def=tpointerdef(def_to).pointertype.def) then
|
|
begin
|
|
eq:=te_equal
|
|
end
|
|
else
|
|
{ child class pointer can be assigned to anchestor pointers }
|
|
if (
|
|
(tpointerdef(def_from).pointertype.def.deftype=objectdef) and
|
|
(tpointerdef(def_to).pointertype.def.deftype=objectdef) and
|
|
tobjectdef(tpointerdef(def_from).pointertype.def).is_related(
|
|
tobjectdef(tpointerdef(def_to).pointertype.def))
|
|
) or
|
|
{ all pointers can be assigned to/from void-pointer }
|
|
is_void(tpointerdef(def_to).pointertype.def) or
|
|
is_void(tpointerdef(def_from).pointertype.def) then
|
|
begin
|
|
doconv:=tc_equal;
|
|
{ give pwidechar a penalty }
|
|
if is_pwidechar(def_to) then
|
|
eq:=te_convert_l2
|
|
else
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
procvardef :
|
|
begin
|
|
{ procedure variable can be assigned to an void pointer }
|
|
{ Not anymore. Use the @ operator now.}
|
|
if not(m_tp_procvar in aktmodeswitches) and
|
|
{ method pointers can't be assigned to void pointers
|
|
not(tprocvardef(def_from).is_methodpointer) and }
|
|
(tpointerdef(def_to).pointertype.def.deftype=orddef) and
|
|
(torddef(tpointerdef(def_to).pointertype.def).typ=uvoid) then
|
|
begin
|
|
doconv:=tc_equal;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
classrefdef,
|
|
objectdef :
|
|
begin
|
|
{ class types and class reference type
|
|
can be assigned to void pointers }
|
|
if (
|
|
is_class_or_interface(def_from) or
|
|
(def_from.deftype=classrefdef)
|
|
) and
|
|
(tpointerdef(def_to).pointertype.def.deftype=orddef) and
|
|
(torddef(tpointerdef(def_to).pointertype.def).typ=uvoid) then
|
|
begin
|
|
doconv:=tc_equal;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
setdef :
|
|
begin
|
|
case def_from.deftype of
|
|
setdef :
|
|
begin
|
|
if assigned(tsetdef(def_from).elementtype.def) and
|
|
assigned(tsetdef(def_to).elementtype.def) then
|
|
begin
|
|
{ sets with the same element base type are equal }
|
|
if is_subequal(tsetdef(def_from).elementtype.def,tsetdef(def_to).elementtype.def) then
|
|
eq:=te_equal;
|
|
end
|
|
else
|
|
{ empty set is compatible with everything }
|
|
eq:=te_equal;
|
|
end;
|
|
arraydef :
|
|
begin
|
|
{ automatic arrayconstructor -> set conversion }
|
|
if is_array_constructor(def_from) then
|
|
begin
|
|
doconv:=tc_arrayconstructor_2_set;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procvardef :
|
|
begin
|
|
case def_from.deftype of
|
|
procdef :
|
|
begin
|
|
{ proc -> procvar }
|
|
if (m_tp_procvar in aktmodeswitches) then
|
|
begin
|
|
subeq:=proc_to_procvar_equal(tprocdef(def_from),tprocvardef(def_to),true);
|
|
if subeq>te_incompatible then
|
|
begin
|
|
doconv:=tc_proc_2_procvar;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
end;
|
|
procvardef :
|
|
begin
|
|
{ procvar -> procvar }
|
|
eq:=proc_to_procvar_equal(tprocvardef(def_from),tprocvardef(def_to),false);
|
|
end;
|
|
pointerdef :
|
|
begin
|
|
{ nil is compatible with procvars }
|
|
if (fromtreetype=niln) then
|
|
begin
|
|
doconv:=tc_equal;
|
|
eq:=te_convert_l1;
|
|
end
|
|
else
|
|
{ for example delphi allows the assignement from pointers }
|
|
{ to procedure variables }
|
|
if (m_pointer_2_procedure in aktmodeswitches) and
|
|
(tpointerdef(def_from).pointertype.def.deftype=orddef) and
|
|
(torddef(tpointerdef(def_from).pointertype.def).typ=uvoid) then
|
|
begin
|
|
doconv:=tc_equal;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
objectdef :
|
|
begin
|
|
{ object pascal objects }
|
|
if (def_from.deftype=objectdef) and
|
|
(tobjectdef(def_from).is_related(tobjectdef(def_to))) then
|
|
begin
|
|
doconv:=tc_equal;
|
|
eq:=te_convert_l1;
|
|
end
|
|
else
|
|
{ Class/interface specific }
|
|
if is_class_or_interface(def_to) then
|
|
begin
|
|
{ void pointer also for delphi mode }
|
|
if (m_delphi in aktmodeswitches) and
|
|
is_voidpointer(def_from) then
|
|
begin
|
|
doconv:=tc_equal;
|
|
{ prefer pointer-pointer assignments }
|
|
eq:=te_convert_l2;
|
|
end
|
|
else
|
|
{ nil is compatible with class instances and interfaces }
|
|
if (fromtreetype=niln) then
|
|
begin
|
|
doconv:=tc_equal;
|
|
eq:=te_convert_l1;
|
|
end
|
|
{ classes can be assigned to interfaces }
|
|
else if is_interface(def_to) and
|
|
is_class(def_from) and
|
|
assigned(tobjectdef(def_from).implementedinterfaces) then
|
|
begin
|
|
{ we've to search in parent classes as well }
|
|
hd3:=tobjectdef(def_from);
|
|
while assigned(hd3) do
|
|
begin
|
|
if hd3.implementedinterfaces.searchintf(def_to)<>-1 then
|
|
begin
|
|
doconv:=tc_class_2_intf;
|
|
eq:=te_convert_l1;
|
|
break;
|
|
end;
|
|
hd3:=hd3.childof;
|
|
end;
|
|
end
|
|
{ Interface 2 GUID handling }
|
|
else if (def_to=tdef(rec_tguid)) and
|
|
(fromtreetype=typen) and
|
|
is_interface(def_from) and
|
|
assigned(tobjectdef(def_from).iidguid) then
|
|
begin
|
|
eq:=te_convert_l1;
|
|
doconv:=tc_equal;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
classrefdef :
|
|
begin
|
|
{ similar to pointerdef wrt forwards }
|
|
if assigned(def_to.typesym) and
|
|
(tclassrefdef(def_to).pointertype.def.deftype=forwarddef) then
|
|
begin
|
|
if (def_from.typesym=def_to.typesym) then
|
|
eq:=te_equal;
|
|
end
|
|
else
|
|
{ class reference types }
|
|
if (def_from.deftype=classrefdef) then
|
|
begin
|
|
if equal_defs(tclassrefdef(def_from).pointertype.def,tclassrefdef(def_to).pointertype.def) then
|
|
begin
|
|
eq:=te_equal;
|
|
end
|
|
else
|
|
begin
|
|
doconv:=tc_equal;
|
|
if explicit or
|
|
tobjectdef(tclassrefdef(def_from).pointertype.def).is_related(
|
|
tobjectdef(tclassrefdef(def_to).pointertype.def)) then
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end
|
|
else
|
|
{ nil is compatible with class references }
|
|
if (fromtreetype=niln) then
|
|
begin
|
|
doconv:=tc_equal;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
|
|
filedef :
|
|
begin
|
|
{ typed files are all equal to the abstract file type
|
|
name TYPEDFILE in system.pp in is_equal in types.pas
|
|
the problem is that it sholud be also compatible to FILE
|
|
but this would leed to a problem for ASSIGN RESET and REWRITE
|
|
when trying to find the good overloaded function !!
|
|
so all file function are doubled in system.pp
|
|
this is not very beautiful !!}
|
|
if (def_from.deftype=filedef) then
|
|
begin
|
|
if (tfiledef(def_from).filetyp=tfiledef(def_to).filetyp) then
|
|
begin
|
|
if
|
|
(
|
|
(tfiledef(def_from).typedfiletype.def=nil) and
|
|
(tfiledef(def_to).typedfiletype.def=nil)
|
|
) or
|
|
(
|
|
(tfiledef(def_from).typedfiletype.def<>nil) and
|
|
(tfiledef(def_to).typedfiletype.def<>nil) and
|
|
equal_defs(tfiledef(def_from).typedfiletype.def,tfiledef(def_to).typedfiletype.def)
|
|
) or
|
|
(
|
|
(tfiledef(def_from).filetyp = ft_typed) and
|
|
(tfiledef(def_to).filetyp = ft_typed) and
|
|
(
|
|
(tfiledef(def_from).typedfiletype.def = tdef(voidtype.def)) or
|
|
(tfiledef(def_to).typedfiletype.def = tdef(voidtype.def))
|
|
)
|
|
) then
|
|
begin
|
|
eq:=te_equal;
|
|
end;
|
|
end
|
|
else
|
|
if ((tfiledef(def_from).filetyp = ft_untyped) and
|
|
(tfiledef(def_to).filetyp = ft_typed)) or
|
|
((tfiledef(def_from).filetyp = ft_typed) and
|
|
(tfiledef(def_to).filetyp = ft_untyped)) then
|
|
begin
|
|
doconv:=tc_equal;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
recorddef :
|
|
begin
|
|
{ interface -> guid }
|
|
if is_interface(def_from) and
|
|
(def_to=rec_tguid) then
|
|
begin
|
|
doconv:=tc_intf_2_guid;
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
|
|
formaldef :
|
|
begin
|
|
doconv:=tc_equal;
|
|
if (def_from.deftype=formaldef) then
|
|
eq:=te_equal
|
|
else
|
|
{ Just about everything can be converted to a formaldef...}
|
|
if not (def_from.deftype in [abstractdef,errordef]) then
|
|
eq:=te_convert_l1;
|
|
end;
|
|
end;
|
|
|
|
{ if we didn't find an appropriate type conversion yet
|
|
then we search also the := operator }
|
|
if (eq=te_incompatible) and
|
|
check_operator and
|
|
((def_from.deftype in [objectdef,recorddef,arraydef,stringdef,variantdef]) or
|
|
(def_to.deftype in [objectdef,recorddef,arraydef,stringdef,variantdef])) then
|
|
begin
|
|
operatorpd:=assignment_overloaded(def_from,def_to);
|
|
if assigned(operatorpd) then
|
|
eq:=te_convert_operator;
|
|
end;
|
|
|
|
{ update convtype for te_equal when it is not yet set }
|
|
if (eq=te_equal) and
|
|
(doconv=tc_not_possible) then
|
|
doconv:=tc_equal;
|
|
|
|
compare_defs_ext:=eq;
|
|
end;
|
|
|
|
|
|
function equal_defs(def_from,def_to:tdef):boolean;
|
|
var
|
|
convtyp : tconverttype;
|
|
pd : tprocdef;
|
|
begin
|
|
{ Compare defs with nothingn and no explicit typecasts and
|
|
searching for overloaded operators is not needed }
|
|
equal_defs:=(compare_defs_ext(def_from,def_to,nothingn,false,false,convtyp,pd)>=te_equal);
|
|
end;
|
|
|
|
|
|
function compare_defs(def_from,def_to:tdef;fromtreetype:tnodetype):tequaltype;
|
|
var
|
|
doconv : tconverttype;
|
|
pd : tprocdef;
|
|
begin
|
|
compare_defs:=compare_defs_ext(def_from,def_to,fromtreetype,false,true,doconv,pd);
|
|
end;
|
|
|
|
|
|
function is_subequal(def1, def2: tdef): boolean;
|
|
var
|
|
basedef1,basedef2 : tenumdef;
|
|
|
|
Begin
|
|
is_subequal := false;
|
|
if assigned(def1) and assigned(def2) then
|
|
Begin
|
|
if (def1.deftype = orddef) and (def2.deftype = orddef) then
|
|
Begin
|
|
{ see p.47 of Turbo Pascal 7.01 manual for the separation of types }
|
|
{ range checking for case statements is done with testrange }
|
|
case torddef(def1).typ of
|
|
u8bit,u16bit,u32bit,u64bit,
|
|
s8bit,s16bit,s32bit,s64bit :
|
|
is_subequal:=(torddef(def2).typ in [s64bit,u64bit,s32bit,u32bit,u8bit,s8bit,s16bit,u16bit]);
|
|
bool8bit,bool16bit,bool32bit :
|
|
is_subequal:=(torddef(def2).typ in [bool8bit,bool16bit,bool32bit]);
|
|
uchar :
|
|
is_subequal:=(torddef(def2).typ=uchar);
|
|
uwidechar :
|
|
is_subequal:=(torddef(def2).typ=uwidechar);
|
|
end;
|
|
end
|
|
else
|
|
Begin
|
|
{ Check if both basedefs are equal }
|
|
if (def1.deftype=enumdef) and (def2.deftype=enumdef) then
|
|
Begin
|
|
{ get both basedefs }
|
|
basedef1:=tenumdef(def1);
|
|
while assigned(basedef1.basedef) do
|
|
basedef1:=basedef1.basedef;
|
|
basedef2:=tenumdef(def2);
|
|
while assigned(basedef2.basedef) do
|
|
basedef2:=basedef2.basedef;
|
|
is_subequal:=(basedef1=basedef2);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function compare_paras(paralist1,paralist2 : TLinkedList; acp : tcompare_paras_type; cpoptions: tcompare_paras_options):tequaltype;
|
|
var
|
|
currpara1,
|
|
currpara2 : TParaItem;
|
|
eq,lowesteq : tequaltype;
|
|
hpd : tprocdef;
|
|
convtype : tconverttype;
|
|
begin
|
|
compare_paras:=te_incompatible;
|
|
{ we need to parse the list from left-right so the
|
|
not-default parameters are checked first }
|
|
lowesteq:=high(tequaltype);
|
|
currpara1:=TParaItem(paralist1.first);
|
|
currpara2:=TParaItem(paralist2.first);
|
|
if cpo_ignorehidden in cpoptions then
|
|
begin
|
|
while assigned(currpara1) and currpara1.is_hidden do
|
|
currpara1:=tparaitem(currpara1.next);
|
|
while assigned(currpara2) and currpara2.is_hidden do
|
|
currpara2:=tparaitem(currpara2.next);
|
|
end;
|
|
while (assigned(currpara1)) and (assigned(currpara2)) do
|
|
begin
|
|
eq:=te_incompatible;
|
|
|
|
{ Unique types must match exact }
|
|
if ((df_unique in currpara1.paratype.def.defoptions) or (df_unique in currpara2.paratype.def.defoptions)) and
|
|
(currpara1.paratype.def<>currpara2.paratype.def) then
|
|
exit;
|
|
|
|
{ Handle hidden parameters separately, because self is
|
|
defined as voidpointer for methodpointers }
|
|
if (currpara1.is_hidden or
|
|
currpara2.is_hidden) then
|
|
begin
|
|
{ both must be hidden }
|
|
if currpara1.is_hidden<>currpara2.is_hidden then
|
|
exit;
|
|
eq:=te_equal;
|
|
if not(vo_is_self in tvarsym(currpara1.parasym).varoptions) and
|
|
not(vo_is_self in tvarsym(currpara2.parasym).varoptions) then
|
|
begin
|
|
if (currpara1.paratyp<>currpara2.paratyp) then
|
|
exit;
|
|
eq:=compare_defs(currpara1.paratype.def,currpara2.paratype.def,nothingn);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
case acp of
|
|
cp_value_equal_const :
|
|
begin
|
|
if (
|
|
(currpara1.paratyp<>currpara2.paratyp) and
|
|
((currpara1.paratyp in [vs_var,vs_out]) or
|
|
(currpara2.paratyp in [vs_var,vs_out]))
|
|
) then
|
|
exit;
|
|
eq:=compare_defs(currpara1.paratype.def,currpara2.paratype.def,nothingn);
|
|
end;
|
|
cp_all :
|
|
begin
|
|
if (currpara1.paratyp<>currpara2.paratyp) then
|
|
exit;
|
|
eq:=compare_defs(currpara1.paratype.def,currpara2.paratype.def,nothingn);
|
|
end;
|
|
cp_procvar :
|
|
begin
|
|
if (currpara1.paratyp<>currpara2.paratyp) then
|
|
exit;
|
|
eq:=compare_defs_ext(currpara1.paratype.def,currpara2.paratype.def,nothingn,
|
|
false,true,convtype,hpd);
|
|
if (eq>te_incompatible) and
|
|
(eq<te_equal) and
|
|
not(
|
|
(convtype in [tc_equal,tc_int_2_int]) and
|
|
(currpara1.paratype.def.size=currpara2.paratype.def.size)
|
|
) then
|
|
begin
|
|
eq:=te_incompatible;
|
|
end;
|
|
end;
|
|
else
|
|
eq:=compare_defs(currpara1.paratype.def,currpara2.paratype.def,nothingn);
|
|
end;
|
|
end;
|
|
{ check type }
|
|
if eq=te_incompatible then
|
|
exit;
|
|
if eq<lowesteq then
|
|
lowesteq:=eq;
|
|
{ also check default value if both have it declared }
|
|
if (cpo_comparedefaultvalue in cpoptions) and
|
|
assigned(currpara1.defaultvalue) and
|
|
assigned(currpara2.defaultvalue) then
|
|
begin
|
|
if not equal_constsym(tconstsym(currpara1.defaultvalue),tconstsym(currpara2.defaultvalue)) then
|
|
exit;
|
|
end;
|
|
currpara1:=TParaItem(currpara1.next);
|
|
currpara2:=TParaItem(currpara2.next);
|
|
if cpo_ignorehidden in cpoptions then
|
|
begin
|
|
while assigned(currpara1) and currpara1.is_hidden do
|
|
currpara1:=tparaitem(currpara1.next);
|
|
while assigned(currpara2) and currpara2.is_hidden do
|
|
currpara2:=tparaitem(currpara2.next);
|
|
end;
|
|
end;
|
|
{ when both lists are empty then the parameters are equal. Also
|
|
when one list is empty and the other has a parameter with default
|
|
value assigned then the parameters are also equal }
|
|
if ((currpara1=nil) and (currpara2=nil)) or
|
|
((cpo_allowdefaults in cpoptions) and
|
|
((assigned(currpara1) and assigned(currpara1.defaultvalue)) or
|
|
(assigned(currpara2) and assigned(currpara2.defaultvalue)))) then
|
|
compare_paras:=lowesteq;
|
|
end;
|
|
|
|
|
|
function proc_to_procvar_equal(def1:tabstractprocdef;def2:tprocvardef;methoderr:boolean):tequaltype;
|
|
var
|
|
eq : tequaltype;
|
|
po_comp : tprocoptions;
|
|
begin
|
|
proc_to_procvar_equal:=te_incompatible;
|
|
if not(assigned(def1)) or not(assigned(def2)) then
|
|
exit;
|
|
{ check for method pointer }
|
|
if (def1.is_methodpointer xor def2.is_methodpointer) or
|
|
(def1.is_addressonly xor def2.is_addressonly) then
|
|
begin
|
|
if methoderr then
|
|
Message(type_e_no_method_and_procedure_not_compatible);
|
|
exit;
|
|
end;
|
|
{ check return value and options, methodpointer is already checked }
|
|
po_comp:=[po_staticmethod,po_interrupt,
|
|
po_iocheck,po_varargs];
|
|
if (m_delphi in aktmodeswitches) then
|
|
exclude(po_comp,po_varargs);
|
|
if ((po_comp * def1.procoptions)= (po_comp * def2.procoptions)) and
|
|
equal_defs(def1.rettype.def,def2.rettype.def) then
|
|
begin
|
|
{ return equal type based on the parameters, but a proc->procvar
|
|
is never exact, so map an exact match of the parameters to
|
|
te_equal }
|
|
eq:=compare_paras(def1.para,def2.para,cp_procvar,[]);
|
|
if eq=te_exact then
|
|
eq:=te_equal;
|
|
proc_to_procvar_equal:=eq;
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
{
|
|
$Log$
|
|
Revision 1.41 2004-01-06 02:17:44 florian
|
|
* fixed webbug 2878
|
|
|
|
Revision 1.40 2004/01/02 17:19:04 jonas
|
|
* if currency = int64, FPC_CURRENCY_IS_INT64 is defined
|
|
+ round and trunc for currency and comp if FPC_CURRENCY_IS_INT64 is
|
|
defined
|
|
* if currency = orddef, prefer currency -> int64/qword conversion over
|
|
currency -> float conversions
|
|
* optimized currency/currency if currency = orddef
|
|
* TODO: write FPC_DIV_CURRENCY and FPC_MUL_CURRENCY routines to prevent
|
|
precision loss if currency=int64 and bestreal = double
|
|
|
|
Revision 1.39 2003/12/16 09:41:44 daniel
|
|
* Automatic conversion from integer constants to pointer constants is no
|
|
longer done except in Delphi mode
|
|
|
|
Revision 1.38 2003/11/26 15:11:42 michael
|
|
+ Patch to prefer getpropinfo(ptypeinfo,name) over getpropinfo(tobject,name) when called with getpropinfo(aclass.classinfo) from Peter
|
|
|
|
Revision 1.37 2003/11/10 19:09:29 peter
|
|
* procvar default value support
|
|
|
|
Revision 1.36 2003/11/04 22:30:15 florian
|
|
+ type cast variant<->enum
|
|
* cnv. node second pass uses now as well helper wrappers
|
|
|
|
Revision 1.35 2003/10/30 16:23:13 peter
|
|
* don't search for overloads in parents for constructors
|
|
|
|
Revision 1.34 2003/10/26 14:11:35 florian
|
|
* fixed web bug 2129: explicit float casts in Delphi mode must be handled by the default code
|
|
|
|
Revision 1.33 2003/10/14 12:23:06 florian
|
|
* fixed 2729: overloading problem with methodvars and procvars
|
|
|
|
Revision 1.32 2003/10/10 17:48:13 peter
|
|
* old trgobj moved to x86/rgcpu and renamed to trgx86fpu
|
|
* tregisteralloctor renamed to trgobj
|
|
* removed rgobj from a lot of units
|
|
* moved location_* and reference_* to cgobj
|
|
* first things for mmx register allocation
|
|
|
|
Revision 1.31 2003/10/07 21:14:32 peter
|
|
* compare_paras() has a parameter to ignore hidden parameters
|
|
* cross unit overload searching ignores hidden parameters when
|
|
comparing parameter lists. Now function(string):string is
|
|
not overriden with procedure(string) which has the same visible
|
|
parameter list
|
|
|
|
Revision 1.30 2003/10/05 13:05:05 peter
|
|
* when comparing hidden parameters both must be hidden
|
|
|
|
Revision 1.29 2003/10/05 12:57:11 peter
|
|
* set correct conversion for subranges
|
|
|
|
Revision 1.28 2003/09/09 21:03:17 peter
|
|
* basics for x86 register calling
|
|
|
|
Revision 1.27 2003/06/03 21:02:08 peter
|
|
* allow pointer(int64) in all modes
|
|
|
|
Revision 1.26 2003/05/26 21:17:17 peter
|
|
* procinlinenode removed
|
|
* aktexit2label removed, fast exit removed
|
|
+ tcallnode.inlined_pass_2 added
|
|
|
|
Revision 1.25 2003/05/15 18:58:53 peter
|
|
* removed selfpointer_offset, vmtpointer_offset
|
|
* tvarsym.adjusted_address
|
|
* address in localsymtable is now in the real direction
|
|
* removed some obsolete globals
|
|
|
|
Revision 1.24 2003/05/09 17:47:02 peter
|
|
* self moved to hidden parameter
|
|
* removed hdisposen,hnewn,selfn
|
|
|
|
Revision 1.23 2003/04/23 20:16:04 peter
|
|
+ added currency support based on int64
|
|
+ is_64bit for use in cg units instead of is_64bitint
|
|
* removed cgmessage from n386add, replace with internalerrors
|
|
|
|
Revision 1.22 2003/04/23 11:37:33 peter
|
|
* po_comp for proc to procvar fixed
|
|
|
|
Revision 1.21 2003/04/10 17:57:52 peter
|
|
* vs_hidden released
|
|
|
|
Revision 1.20 2003/03/20 17:52:18 peter
|
|
* fix compare for unique types, they are allowed when they match
|
|
exact
|
|
|
|
Revision 1.19 2003/01/16 22:13:51 peter
|
|
* convert_l3 convertlevel added. This level is used for conversions
|
|
where information can be lost like converting widestring->ansistring
|
|
or dword->byte
|
|
|
|
Revision 1.18 2003/01/15 01:44:32 peter
|
|
* merged methodpointer fixes from 1.0.x
|
|
|
|
Revision 1.17 2003/01/09 21:43:39 peter
|
|
* constant string conversion fixed, it's now equal to both
|
|
shortstring, ansistring and the typeconvnode will return
|
|
te_equal but still return convtype to change the constnode
|
|
|
|
Revision 1.16 2003/01/05 22:42:13 peter
|
|
* use int_to_int conversion for pointer/procvar/classref to int
|
|
|
|
Revision 1.15 2003/01/05 15:54:15 florian
|
|
+ added proper support of type = type <type>; for simple types
|
|
|
|
Revision 1.14 2003/01/03 17:16:04 peter
|
|
* fixed assignment operator checking for typecast
|
|
|
|
Revision 1.13 2002/12/29 18:15:19 peter
|
|
* varargs is not checked in proc->procvar for delphi
|
|
|
|
Revision 1.12 2002/12/29 14:57:50 peter
|
|
* unit loading changed to first register units and load them
|
|
afterwards. This is needed to support uses xxx in yyy correctly
|
|
* unit dependency check fixed
|
|
|
|
Revision 1.11 2002/12/27 15:26:12 peter
|
|
* procvar compare with 2 ints did not check the integer size
|
|
|
|
Revision 1.10 2002/12/23 22:22:16 peter
|
|
* don't allow implicit bool->int conversion
|
|
|
|
Revision 1.9 2002/12/18 21:37:36 peter
|
|
* allow classref-classref always when explicit
|
|
|
|
Revision 1.8 2002/12/15 22:37:53 peter
|
|
* give conversions from pointer to pwidechar a penalty (=prefer pchar)
|
|
|
|
Revision 1.7 2002/12/11 22:40:12 peter
|
|
* proc->procvar is never an exact match, convert exact parameters
|
|
to equal for the whole proc to procvar conversion level
|
|
|
|
Revision 1.6 2002/12/06 17:49:44 peter
|
|
* prefer string-shortstring over other string-string conversions
|
|
|
|
Revision 1.5 2002/12/05 14:27:26 florian
|
|
* some variant <-> dyn. array stuff
|
|
|
|
Revision 1.4 2002/12/01 22:07:41 carl
|
|
* warning of portabilitiy problems with parasize / localsize
|
|
+ some added documentation
|
|
|
|
Revision 1.3 2002/11/27 15:33:46 peter
|
|
* the never ending story of tp procvar hacks
|
|
|
|
Revision 1.2 2002/11/27 02:32:14 peter
|
|
* fix cp_procvar compare
|
|
|
|
Revision 1.1 2002/11/25 17:43:16 peter
|
|
* splitted defbase in defutil,symutil,defcmp
|
|
* merged isconvertable and is_equal into compare_defs(_ext)
|
|
* made operator search faster by walking the list only once
|
|
|
|
}
|