* 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:
Jonas Maebe 2011-08-20 08:06:20 +00:00
parent 77707a447e
commit 10a7532968
6 changed files with 431 additions and 367 deletions

View File

@ -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

View File

@ -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;

View File

@ -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}

View File

@ -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

View File

@ -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;