mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-07 16:28:22 +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 }
|
||||
fromdef:=ttypeconvnode(hp).left.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
|
||||
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
|
||||
(fromdef.typ=formaldef) then
|
||||
CGMessagePos(hp.fileinfo,type_e_no_managed_formal_assign_typecast)
|
||||
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
|
||||
is_void(fromdef) or
|
||||
is_open_array(fromdef) or
|
||||
|
@ -32,6 +32,7 @@ interface
|
||||
tjvmtypeconvnode = class(tcgtypeconvnode)
|
||||
function typecheck_dynarray_to_openarray: tnode; override;
|
||||
function typecheck_string_to_chararray: tnode; override;
|
||||
function pass_1: tnode; override;
|
||||
|
||||
procedure second_int_to_int;override;
|
||||
{ procedure second_string_to_string;override; }
|
||||
@ -53,9 +54,10 @@ interface
|
||||
{ procedure second_pchar_to_string;override; }
|
||||
{ procedure second_class_to_intf;override; }
|
||||
{ procedure second_char_to_char;override; }
|
||||
function target_specific_explicit_typeconv: boolean; override;
|
||||
function target_specific_general_typeconv: boolean; override;
|
||||
protected
|
||||
function target_specific_explicit_typeconv: tnode; override;
|
||||
function target_specific_general_typeconv(var res: tnode): boolean; override;
|
||||
function do_target_specific_explicit_typeconv(check_only: boolean; out resnode: tnode): boolean;
|
||||
end;
|
||||
|
||||
tjvmasnode = class(tcgasnode)
|
||||
@ -146,6 +148,18 @@ implementation
|
||||
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
|
||||
*****************************************************************************}
|
||||
@ -404,7 +418,7 @@ implementation
|
||||
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 }
|
||||
function int_real_explicit_typecast(fdef: tfloatdef; const singlemethod, doublemethod: string): tnode;
|
||||
@ -441,11 +455,12 @@ implementation
|
||||
fromclasscompatible,
|
||||
toclasscompatible: boolean;
|
||||
fromdef,
|
||||
todef: tdef;
|
||||
todef,
|
||||
jlclass: tdef;
|
||||
fromarrtype,
|
||||
toarrtype: char;
|
||||
begin
|
||||
result:=nil;
|
||||
resnode:=nil;
|
||||
{ This routine is only called for explicit typeconversions of same-sized
|
||||
entities that aren't handled by normal type conversions -> bit pattern
|
||||
reinterpretations. In the JVM, many of these also need special
|
||||
@ -486,12 +501,22 @@ implementation
|
||||
((fromarrtype in ['A','R']) or
|
||||
(fromarrtype<>toarrtype)) then
|
||||
begin
|
||||
result:=ctypenode.create(resultdef);
|
||||
if resultdef.typ=objectdef then
|
||||
result:=cloadvmtaddrnode.create(result);
|
||||
result:=casnode.create(left,result);
|
||||
left:=nil;
|
||||
end;
|
||||
if not check_only and
|
||||
not assignment_side then
|
||||
begin
|
||||
resnode:=ctypenode.create(resultdef);
|
||||
if resultdef.typ=objectdef then
|
||||
resnode:=cloadvmtaddrnode.create(resnode);
|
||||
resnode:=casnode.create(left,resnode);
|
||||
left:=nil;
|
||||
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;
|
||||
end;
|
||||
|
||||
@ -503,7 +528,9 @@ implementation
|
||||
(is_integer(resultdef) or
|
||||
(resultdef.typ=enumdef)) then
|
||||
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;
|
||||
end;
|
||||
{ int to float explicit type conversion: also use the bits }
|
||||
@ -511,12 +538,23 @@ implementation
|
||||
(left.resultdef.typ=enumdef)) and
|
||||
(resultdef.typ=floatdef) then
|
||||
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;
|
||||
end;
|
||||
{ nothing special required when going between ordinals and enums }
|
||||
if (left.resultdef.typ in [orddef,enumdef])=(resultdef.typ in [orddef,enumdef]) then
|
||||
exit;
|
||||
if (left.resultdef.typ in [orddef,enumdef]) and
|
||||
(resultdef.typ in [orddef,enumdef]) then
|
||||
begin
|
||||
result:=false;
|
||||
exit;
|
||||
end;
|
||||
|
||||
{ifndef nounsupported}
|
||||
result:=false;
|
||||
exit;
|
||||
{endif}
|
||||
|
||||
{ Todo:
|
||||
* int to set and vice versa
|
||||
@ -532,7 +570,16 @@ implementation
|
||||
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
|
||||
result:=false;
|
||||
{ deal with explicit typecasts between records and classes (for
|
||||
@ -546,7 +593,6 @@ implementation
|
||||
(nf_explicit in flags) then
|
||||
begin
|
||||
convtype:=tc_equal;
|
||||
res:=target_specific_explicit_typeconv;
|
||||
result:=true;
|
||||
exit;
|
||||
end;
|
||||
|
@ -1423,7 +1423,7 @@ parser_d_internal_parser_string=03318_D_Parsing internally generated code: $1
|
||||
% \end{description}
|
||||
# Type Checking
|
||||
#
|
||||
# 04105 is the last used one
|
||||
# 04106 is the last used one
|
||||
#
|
||||
% \section{Type checking errors}
|
||||
% 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,
|
||||
% they will be extracted and if their type does not match the original variable's,
|
||||
% 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}
|
||||
|
@ -506,6 +506,7 @@ const
|
||||
type_e_java_class_method_not_static=04103;
|
||||
type_e_invalid_final_assignment=04104;
|
||||
type_e_no_managed_formal_assign_typecast=04105;
|
||||
type_e_no_managed_assign_generic_typecast=04106;
|
||||
sym_e_id_not_found=05000;
|
||||
sym_f_internal_error_in_symtablestack=05001;
|
||||
sym_e_duplicate_id=05002;
|
||||
@ -910,9 +911,9 @@ const
|
||||
option_info=11024;
|
||||
option_help_pages=11025;
|
||||
|
||||
MsgTxtSize = 61848;
|
||||
MsgTxtSize = 61950;
|
||||
|
||||
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
|
||||
);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -37,7 +37,8 @@ interface
|
||||
totypedef : tdef;
|
||||
totypedefderef : tderef;
|
||||
convtype : tconverttype;
|
||||
warn_pointer_to_signed: boolean;
|
||||
warn_pointer_to_signed,
|
||||
assignment_side: boolean;
|
||||
constructor create(node : tnode;def:tdef);virtual;
|
||||
constructor create_explicit(node : tnode;def:tdef);
|
||||
constructor create_internal(node : tnode;def:tdef);
|
||||
@ -57,6 +58,14 @@ interface
|
||||
function retains_value_location:boolean;
|
||||
function assign_allowed:boolean;
|
||||
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
|
||||
function typecheck_int_to_int : tnode; virtual;
|
||||
function typecheck_cord_to_pointer : tnode; virtual;
|
||||
@ -116,15 +125,6 @@ interface
|
||||
function _typecheck_interface_to_variant : tnode;
|
||||
function _typecheck_array_2_dynarray : tnode;
|
||||
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_cstring_to_pchar : tnode;virtual;
|
||||
function first_cstring_to_int : tnode;virtual;
|
||||
@ -858,6 +858,7 @@ implementation
|
||||
n:=ttypeconvnode(inherited dogetcopy);
|
||||
n.convtype:=convtype;
|
||||
n.totypedef:=totypedef;
|
||||
n.assignment_side:=assignment_side;
|
||||
dogetcopy:=n;
|
||||
end;
|
||||
|
||||
@ -1786,15 +1787,15 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
function ttypeconvnode.target_specific_general_typeconv(var res: tnode): boolean;
|
||||
function ttypeconvnode.target_specific_general_typeconv: boolean;
|
||||
begin
|
||||
result:=false;
|
||||
end;
|
||||
|
||||
|
||||
function ttypeconvnode.target_specific_explicit_typeconv: tnode;
|
||||
function ttypeconvnode.target_specific_explicit_typeconv: boolean;
|
||||
begin
|
||||
result:=nil;
|
||||
result:=false;
|
||||
end;
|
||||
|
||||
|
||||
@ -1975,7 +1976,7 @@ implementation
|
||||
typecheckpass(left);
|
||||
end;
|
||||
|
||||
if target_specific_general_typeconv(result) then
|
||||
if target_specific_general_typeconv then
|
||||
exit;
|
||||
|
||||
if convtype=tc_none then
|
||||
@ -2220,8 +2221,7 @@ implementation
|
||||
begin
|
||||
{ perform target-specific explicit typecast
|
||||
checks }
|
||||
result:=target_specific_explicit_typeconv;
|
||||
if assigned(result) then
|
||||
if target_specific_explicit_typeconv then
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
|
Loading…
Reference in New Issue
Block a user