mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-22 01:52:48 +02:00
* differentiate between typecasts on the assignment side or not, because we
cannot insert typecasting checks on the assignment side, only on the values that are being assigned o since valid_for_assignment() is called in tassignmentnode.typecheckpass() after typecheckpassing left and right, moved the conversion of the typecheck nodes into JVM-specific constructs from typecheckpass to pass_1, so that they can use the information whether they are on the assignment side or not * forbid casting a child type to a parent type on the assignment side on managed platforms, because that circumvents the type checking git-svn-id: branches/jvmbackend@18515 -
This commit is contained in:
parent
77707a447e
commit
10a7532968
@ -1231,12 +1231,21 @@ implementation
|
|||||||
- typecast from pointer to array }
|
- typecast from pointer to array }
|
||||||
fromdef:=ttypeconvnode(hp).left.resultdef;
|
fromdef:=ttypeconvnode(hp).left.resultdef;
|
||||||
todef:=hp.resultdef;
|
todef:=hp.resultdef;
|
||||||
|
{ typeconversions on the assignment side must keep
|
||||||
|
left.location the same }
|
||||||
|
if not(gotderef or
|
||||||
|
((target_info.system=system_jvm_java32) and
|
||||||
|
(gotsubscript or gotvec))) then
|
||||||
|
ttypeconvnode(hp).assignment_side:=true;
|
||||||
{ in managed VMs, you cannot typecast formaldef when assigning
|
{ in managed VMs, you cannot typecast formaldef when assigning
|
||||||
to it, see http://hallvards.blogspot.com/2007/10/dn4dp24-net-vs-win32-untyped-parameters.html }
|
to it, see http://hallvards.blogspot.com/2007/10/dn4dp24-net-vs-win32-untyped-parameters.html }
|
||||||
if (target_info.system in systems_managed_vm) and
|
if (target_info.system in systems_managed_vm) and
|
||||||
(fromdef.typ=formaldef) then
|
(fromdef.typ=formaldef) then
|
||||||
CGMessagePos(hp.fileinfo,type_e_no_managed_formal_assign_typecast)
|
CGMessagePos(hp.fileinfo,type_e_no_managed_formal_assign_typecast)
|
||||||
else if not((nf_absolute in ttypeconvnode(hp).flags) or
|
else if not((nf_absolute in ttypeconvnode(hp).flags) or
|
||||||
|
ttypeconvnode(hp).target_specific_general_typeconv or
|
||||||
|
((nf_explicit in hp.flags) and
|
||||||
|
ttypeconvnode(hp).target_specific_explicit_typeconv) or
|
||||||
(fromdef.typ=formaldef) or
|
(fromdef.typ=formaldef) or
|
||||||
is_void(fromdef) or
|
is_void(fromdef) or
|
||||||
is_open_array(fromdef) or
|
is_open_array(fromdef) or
|
||||||
|
@ -32,6 +32,7 @@ interface
|
|||||||
tjvmtypeconvnode = class(tcgtypeconvnode)
|
tjvmtypeconvnode = class(tcgtypeconvnode)
|
||||||
function typecheck_dynarray_to_openarray: tnode; override;
|
function typecheck_dynarray_to_openarray: tnode; override;
|
||||||
function typecheck_string_to_chararray: tnode; override;
|
function typecheck_string_to_chararray: tnode; override;
|
||||||
|
function pass_1: tnode; override;
|
||||||
|
|
||||||
procedure second_int_to_int;override;
|
procedure second_int_to_int;override;
|
||||||
{ procedure second_string_to_string;override; }
|
{ procedure second_string_to_string;override; }
|
||||||
@ -53,9 +54,10 @@ interface
|
|||||||
{ procedure second_pchar_to_string;override; }
|
{ procedure second_pchar_to_string;override; }
|
||||||
{ procedure second_class_to_intf;override; }
|
{ procedure second_class_to_intf;override; }
|
||||||
{ procedure second_char_to_char;override; }
|
{ procedure second_char_to_char;override; }
|
||||||
|
function target_specific_explicit_typeconv: boolean; override;
|
||||||
|
function target_specific_general_typeconv: boolean; override;
|
||||||
protected
|
protected
|
||||||
function target_specific_explicit_typeconv: tnode; override;
|
function do_target_specific_explicit_typeconv(check_only: boolean; out resnode: tnode): boolean;
|
||||||
function target_specific_general_typeconv(var res: tnode): boolean; override;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
tjvmasnode = class(tcgasnode)
|
tjvmasnode = class(tcgasnode)
|
||||||
@ -146,6 +148,18 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function tjvmtypeconvnode.pass_1: tnode;
|
||||||
|
begin
|
||||||
|
if (nf_explicit in flags) then
|
||||||
|
begin
|
||||||
|
do_target_specific_explicit_typeconv(false,result);
|
||||||
|
if assigned(result) then
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
result:=inherited pass_1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{*****************************************************************************
|
{*****************************************************************************
|
||||||
SecondTypeConv
|
SecondTypeConv
|
||||||
*****************************************************************************}
|
*****************************************************************************}
|
||||||
@ -404,7 +418,7 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
function tjvmtypeconvnode.target_specific_explicit_typeconv: tnode;
|
function tjvmtypeconvnode.do_target_specific_explicit_typeconv(check_only: boolean; out resnode: tnode): boolean;
|
||||||
|
|
||||||
{ handle explicit typecast from int to to real or vice versa }
|
{ handle explicit typecast from int to to real or vice versa }
|
||||||
function int_real_explicit_typecast(fdef: tfloatdef; const singlemethod, doublemethod: string): tnode;
|
function int_real_explicit_typecast(fdef: tfloatdef; const singlemethod, doublemethod: string): tnode;
|
||||||
@ -441,11 +455,12 @@ implementation
|
|||||||
fromclasscompatible,
|
fromclasscompatible,
|
||||||
toclasscompatible: boolean;
|
toclasscompatible: boolean;
|
||||||
fromdef,
|
fromdef,
|
||||||
todef: tdef;
|
todef,
|
||||||
|
jlclass: tdef;
|
||||||
fromarrtype,
|
fromarrtype,
|
||||||
toarrtype: char;
|
toarrtype: char;
|
||||||
begin
|
begin
|
||||||
result:=nil;
|
resnode:=nil;
|
||||||
{ This routine is only called for explicit typeconversions of same-sized
|
{ This routine is only called for explicit typeconversions of same-sized
|
||||||
entities that aren't handled by normal type conversions -> bit pattern
|
entities that aren't handled by normal type conversions -> bit pattern
|
||||||
reinterpretations. In the JVM, many of these also need special
|
reinterpretations. In the JVM, many of these also need special
|
||||||
@ -486,12 +501,22 @@ implementation
|
|||||||
((fromarrtype in ['A','R']) or
|
((fromarrtype in ['A','R']) or
|
||||||
(fromarrtype<>toarrtype)) then
|
(fromarrtype<>toarrtype)) then
|
||||||
begin
|
begin
|
||||||
result:=ctypenode.create(resultdef);
|
if not check_only and
|
||||||
|
not assignment_side then
|
||||||
|
begin
|
||||||
|
resnode:=ctypenode.create(resultdef);
|
||||||
if resultdef.typ=objectdef then
|
if resultdef.typ=objectdef then
|
||||||
result:=cloadvmtaddrnode.create(result);
|
resnode:=cloadvmtaddrnode.create(resnode);
|
||||||
result:=casnode.create(left,result);
|
resnode:=casnode.create(left,resnode);
|
||||||
left:=nil;
|
left:=nil;
|
||||||
end;
|
end
|
||||||
|
end
|
||||||
|
{ typecasting from a child to a parent type on the assignment side
|
||||||
|
will (rightly) mess up the type safety verification of the JVM }
|
||||||
|
else if assignment_side and
|
||||||
|
(compare_defs(fromdef,todef,nothingn)<te_equal) then
|
||||||
|
CGMessage(type_e_no_managed_assign_generic_typecast);
|
||||||
|
result:=true;
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -503,7 +528,9 @@ implementation
|
|||||||
(is_integer(resultdef) or
|
(is_integer(resultdef) or
|
||||||
(resultdef.typ=enumdef)) then
|
(resultdef.typ=enumdef)) then
|
||||||
begin
|
begin
|
||||||
result:=int_real_explicit_typecast(tfloatdef(left.resultdef),'FLOATTORAWINTBITS','DOUBLETORAWLONGBITS');
|
if not check_only then
|
||||||
|
resnode:=int_real_explicit_typecast(tfloatdef(left.resultdef),'FLOATTORAWINTBITS','DOUBLETORAWLONGBITS');
|
||||||
|
result:=true;
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
{ int to float explicit type conversion: also use the bits }
|
{ int to float explicit type conversion: also use the bits }
|
||||||
@ -511,12 +538,23 @@ implementation
|
|||||||
(left.resultdef.typ=enumdef)) and
|
(left.resultdef.typ=enumdef)) and
|
||||||
(resultdef.typ=floatdef) then
|
(resultdef.typ=floatdef) then
|
||||||
begin
|
begin
|
||||||
result:=int_real_explicit_typecast(tfloatdef(resultdef),'INTBITSTOFLOAT','LONGBITSTODOUBLE');
|
if not check_only then
|
||||||
|
resnode:=int_real_explicit_typecast(tfloatdef(resultdef),'INTBITSTOFLOAT','LONGBITSTODOUBLE');
|
||||||
|
result:=true;
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
{ nothing special required when going between ordinals and enums }
|
{ nothing special required when going between ordinals and enums }
|
||||||
if (left.resultdef.typ in [orddef,enumdef])=(resultdef.typ in [orddef,enumdef]) then
|
if (left.resultdef.typ in [orddef,enumdef]) and
|
||||||
|
(resultdef.typ in [orddef,enumdef]) then
|
||||||
|
begin
|
||||||
|
result:=false;
|
||||||
exit;
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ifndef nounsupported}
|
||||||
|
result:=false;
|
||||||
|
exit;
|
||||||
|
{endif}
|
||||||
|
|
||||||
{ Todo:
|
{ Todo:
|
||||||
* int to set and vice versa
|
* int to set and vice versa
|
||||||
@ -532,7 +570,16 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
function tjvmtypeconvnode.target_specific_general_typeconv(var res: tnode): boolean;
|
function tjvmtypeconvnode.target_specific_explicit_typeconv: boolean;
|
||||||
|
var
|
||||||
|
dummyres: tnode;
|
||||||
|
begin
|
||||||
|
result:=do_target_specific_explicit_typeconv(true,dummyres);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function tjvmtypeconvnode.target_specific_general_typeconv: boolean;
|
||||||
begin
|
begin
|
||||||
result:=false;
|
result:=false;
|
||||||
{ deal with explicit typecasts between records and classes (for
|
{ deal with explicit typecasts between records and classes (for
|
||||||
@ -546,7 +593,6 @@ implementation
|
|||||||
(nf_explicit in flags) then
|
(nf_explicit in flags) then
|
||||||
begin
|
begin
|
||||||
convtype:=tc_equal;
|
convtype:=tc_equal;
|
||||||
res:=target_specific_explicit_typeconv;
|
|
||||||
result:=true;
|
result:=true;
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
@ -1423,7 +1423,7 @@ parser_d_internal_parser_string=03318_D_Parsing internally generated code: $1
|
|||||||
% \end{description}
|
% \end{description}
|
||||||
# Type Checking
|
# Type Checking
|
||||||
#
|
#
|
||||||
# 04105 is the last used one
|
# 04106 is the last used one
|
||||||
#
|
#
|
||||||
% \section{Type checking errors}
|
% \section{Type checking errors}
|
||||||
% This section lists all errors that can occur when type checking is
|
% This section lists all errors that can occur when type checking is
|
||||||
@ -1795,6 +1795,11 @@ type_e_no_managed_formal_assign_typecast=04105_E_It is not possible to typecast
|
|||||||
% values to them (either class-based or primitive ones). On the caller side,
|
% values to them (either class-based or primitive ones). On the caller side,
|
||||||
% they will be extracted and if their type does not match the original variable's,
|
% they will be extracted and if their type does not match the original variable's,
|
||||||
% an exception will be raised.
|
% an exception will be raised.
|
||||||
|
type_e_no_managed_assign_generic_typecast=04106_E_The assignment side of an expression cannot be typecasted to a supertype on managed platforms
|
||||||
|
% Managed platforms guarantee type safety at the bytecode level. This means that the virtual machine must be able
|
||||||
|
% to statically determine that no type-unsafe assignments or operations occur. By assigning a parent class type to a
|
||||||
|
% variable of a child type by typecasting the assignment side to the parent class type, the type safety would no
|
||||||
|
% longer be guaranteed and the generated code would fail verification at run time time.
|
||||||
%
|
%
|
||||||
%
|
%
|
||||||
% \end{description}
|
% \end{description}
|
||||||
|
@ -506,6 +506,7 @@ const
|
|||||||
type_e_java_class_method_not_static=04103;
|
type_e_java_class_method_not_static=04103;
|
||||||
type_e_invalid_final_assignment=04104;
|
type_e_invalid_final_assignment=04104;
|
||||||
type_e_no_managed_formal_assign_typecast=04105;
|
type_e_no_managed_formal_assign_typecast=04105;
|
||||||
|
type_e_no_managed_assign_generic_typecast=04106;
|
||||||
sym_e_id_not_found=05000;
|
sym_e_id_not_found=05000;
|
||||||
sym_f_internal_error_in_symtablestack=05001;
|
sym_f_internal_error_in_symtablestack=05001;
|
||||||
sym_e_duplicate_id=05002;
|
sym_e_duplicate_id=05002;
|
||||||
@ -910,9 +911,9 @@ const
|
|||||||
option_info=11024;
|
option_info=11024;
|
||||||
option_help_pages=11025;
|
option_help_pages=11025;
|
||||||
|
|
||||||
MsgTxtSize = 61848;
|
MsgTxtSize = 61950;
|
||||||
|
|
||||||
MsgIdxMax : array[1..20] of longint=(
|
MsgIdxMax : array[1..20] of longint=(
|
||||||
26,89,319,106,87,54,111,23,202,63,
|
26,89,319,107,87,54,111,23,202,63,
|
||||||
49,20,1,1,1,1,1,1,1,1
|
49,20,1,1,1,1,1,1,1,1
|
||||||
);
|
);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -37,7 +37,8 @@ interface
|
|||||||
totypedef : tdef;
|
totypedef : tdef;
|
||||||
totypedefderef : tderef;
|
totypedefderef : tderef;
|
||||||
convtype : tconverttype;
|
convtype : tconverttype;
|
||||||
warn_pointer_to_signed: boolean;
|
warn_pointer_to_signed,
|
||||||
|
assignment_side: boolean;
|
||||||
constructor create(node : tnode;def:tdef);virtual;
|
constructor create(node : tnode;def:tdef);virtual;
|
||||||
constructor create_explicit(node : tnode;def:tdef);
|
constructor create_explicit(node : tnode;def:tdef);
|
||||||
constructor create_internal(node : tnode;def:tdef);
|
constructor create_internal(node : tnode;def:tdef);
|
||||||
@ -57,6 +58,14 @@ interface
|
|||||||
function retains_value_location:boolean;
|
function retains_value_location:boolean;
|
||||||
function assign_allowed:boolean;
|
function assign_allowed:boolean;
|
||||||
procedure second_call_helper(c : tconverttype);
|
procedure second_call_helper(c : tconverttype);
|
||||||
|
{ always called before any other type conversion checks. If it
|
||||||
|
returns true, the type conversion is ok and no further checks/
|
||||||
|
handling are required. }
|
||||||
|
function target_specific_general_typeconv: boolean;virtual;
|
||||||
|
{ called in case of a valid explicit type conversion. Can be used to
|
||||||
|
replace this explicit type conversion with a different node, or to
|
||||||
|
reject it after all }
|
||||||
|
function target_specific_explicit_typeconv: boolean;virtual;
|
||||||
protected
|
protected
|
||||||
function typecheck_int_to_int : tnode; virtual;
|
function typecheck_int_to_int : tnode; virtual;
|
||||||
function typecheck_cord_to_pointer : tnode; virtual;
|
function typecheck_cord_to_pointer : tnode; virtual;
|
||||||
@ -116,15 +125,6 @@ interface
|
|||||||
function _typecheck_interface_to_variant : tnode;
|
function _typecheck_interface_to_variant : tnode;
|
||||||
function _typecheck_array_2_dynarray : tnode;
|
function _typecheck_array_2_dynarray : tnode;
|
||||||
protected
|
protected
|
||||||
{ always called before any other type conversion checks. If it
|
|
||||||
returns true, the type conversion is ok and no further checks/
|
|
||||||
handling are required. "res" can be set to a node that should
|
|
||||||
replace the type conversion node, but this is not required }
|
|
||||||
function target_specific_general_typeconv(var res: tnode): boolean;virtual;
|
|
||||||
{ called in case of a valid explicit type conversion. Can be used to
|
|
||||||
replace this explicit type conversion with a different node, or to
|
|
||||||
reject it after all }
|
|
||||||
function target_specific_explicit_typeconv: tnode;virtual;
|
|
||||||
function first_int_to_int : tnode;virtual;
|
function first_int_to_int : tnode;virtual;
|
||||||
function first_cstring_to_pchar : tnode;virtual;
|
function first_cstring_to_pchar : tnode;virtual;
|
||||||
function first_cstring_to_int : tnode;virtual;
|
function first_cstring_to_int : tnode;virtual;
|
||||||
@ -858,6 +858,7 @@ implementation
|
|||||||
n:=ttypeconvnode(inherited dogetcopy);
|
n:=ttypeconvnode(inherited dogetcopy);
|
||||||
n.convtype:=convtype;
|
n.convtype:=convtype;
|
||||||
n.totypedef:=totypedef;
|
n.totypedef:=totypedef;
|
||||||
|
n.assignment_side:=assignment_side;
|
||||||
dogetcopy:=n;
|
dogetcopy:=n;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1786,15 +1787,15 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
function ttypeconvnode.target_specific_general_typeconv(var res: tnode): boolean;
|
function ttypeconvnode.target_specific_general_typeconv: boolean;
|
||||||
begin
|
begin
|
||||||
result:=false;
|
result:=false;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
function ttypeconvnode.target_specific_explicit_typeconv: tnode;
|
function ttypeconvnode.target_specific_explicit_typeconv: boolean;
|
||||||
begin
|
begin
|
||||||
result:=nil;
|
result:=false;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -1975,7 +1976,7 @@ implementation
|
|||||||
typecheckpass(left);
|
typecheckpass(left);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if target_specific_general_typeconv(result) then
|
if target_specific_general_typeconv then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
if convtype=tc_none then
|
if convtype=tc_none then
|
||||||
@ -2220,8 +2221,7 @@ implementation
|
|||||||
begin
|
begin
|
||||||
{ perform target-specific explicit typecast
|
{ perform target-specific explicit typecast
|
||||||
checks }
|
checks }
|
||||||
result:=target_specific_explicit_typeconv;
|
if target_specific_explicit_typeconv then
|
||||||
if assigned(result) then
|
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
Loading…
Reference in New Issue
Block a user