|
@@ -289,15 +289,25 @@ interface
|
|
{ true, if def is a signed int type, equal in size to the processor's native int size }
|
|
{ true, if def is a signed int type, equal in size to the processor's native int size }
|
|
function is_nativesint(def : tdef) : boolean;
|
|
function is_nativesint(def : tdef) : boolean;
|
|
|
|
|
|
|
|
+ type
|
|
|
|
+ tperformrangecheck = (
|
|
|
|
+ rc_internal, { never at all, internal conversion }
|
|
|
|
+ rc_explicit, { no, but this is a user conversion and hence can still give warnings in some cases }
|
|
|
|
+ rc_default, { only if range checking is enabled }
|
|
|
|
+ rc_always { always }
|
|
|
|
+ );
|
|
{# If @var(l) isn't in the range of todef a range check error (if not explicit) is generated and
|
|
{# If @var(l) isn't in the range of todef a range check error (if not explicit) is generated and
|
|
the value is placed within the range
|
|
the value is placed within the range
|
|
}
|
|
}
|
|
- procedure testrange(todef : tdef;var l : tconstexprint;explicit,forcerangecheck:boolean);
|
|
|
|
|
|
+ procedure adaptrange(todef : tdef;var l : tconstexprint; rangecheck: tperformrangecheck);
|
|
|
|
+ { for when used with nf_explicit/nf_internal nodeflags }
|
|
|
|
+ procedure adaptrange(todef : tdef;var l : tconstexprint; internal, explicit: boolean);
|
|
|
|
|
|
{# Returns the range of def, where @var(l) is the low-range and @var(h) is
|
|
{# Returns the range of def, where @var(l) is the low-range and @var(h) is
|
|
the high-range.
|
|
the high-range.
|
|
}
|
|
}
|
|
procedure getrange(def : tdef;out l, h : TConstExprInt);
|
|
procedure getrange(def : tdef;out l, h : TConstExprInt);
|
|
|
|
+ procedure getrangedefmasksize(def: tdef; out rangedef: tdef; out mask: TConstExprInt; out size: longint);
|
|
|
|
|
|
{ Returns the range type of an ordinal type in the sense of ISO-10206 }
|
|
{ Returns the range type of an ordinal type in the sense of ISO-10206 }
|
|
function get_iso_range_type(def: tdef): tdef;
|
|
function get_iso_range_type(def: tdef): tdef;
|
|
@@ -1086,51 +1096,86 @@ implementation
|
|
|
|
|
|
{ if l isn't in the range of todef a range check error (if not explicit) is generated and
|
|
{ if l isn't in the range of todef a range check error (if not explicit) is generated and
|
|
the value is placed within the range }
|
|
the value is placed within the range }
|
|
- procedure testrange(todef : tdef;var l : tconstexprint;explicit,forcerangecheck:boolean);
|
|
|
|
|
|
+ procedure adaptrange(todef : tdef;var l : tconstexprint; rangecheck: tperformrangecheck);
|
|
var
|
|
var
|
|
- lv,hv: TConstExprInt;
|
|
|
|
|
|
+ lv,hv,oldval,sextval,mask: TConstExprInt;
|
|
|
|
+ rangedef: tdef;
|
|
|
|
+ rangedefsize: longint;
|
|
|
|
+ warned: boolean;
|
|
begin
|
|
begin
|
|
- { for 64 bit types we need only to check if it is less than }
|
|
|
|
- { zero, if def is a qword node }
|
|
|
|
getrange(todef,lv,hv);
|
|
getrange(todef,lv,hv);
|
|
if (l<lv) or (l>hv) then
|
|
if (l<lv) or (l>hv) then
|
|
begin
|
|
begin
|
|
- if not explicit then
|
|
|
|
|
|
+ warned:=false;
|
|
|
|
+ if rangecheck in [rc_default,rc_always] then
|
|
begin
|
|
begin
|
|
- if (cs_check_range in current_settings.localswitches) or
|
|
|
|
- forcerangecheck or
|
|
|
|
- (not is_pasbool(todef) and
|
|
|
|
- not spans_entire_range(todef)) then
|
|
|
|
|
|
+ if (rangecheck=rc_always) or
|
|
|
|
+ (todef.typ=enumdef) or
|
|
|
|
+ (cs_check_range in current_settings.localswitches) then
|
|
Message3(type_e_range_check_error_bounds,tostr(l),tostr(lv),tostr(hv))
|
|
Message3(type_e_range_check_error_bounds,tostr(l),tostr(lv),tostr(hv))
|
|
else
|
|
else
|
|
Message3(type_w_range_check_error_bounds,tostr(l),tostr(lv),tostr(hv));
|
|
Message3(type_w_range_check_error_bounds,tostr(l),tostr(lv),tostr(hv));
|
|
|
|
+ warned:=true;
|
|
|
|
+ end
|
|
|
|
+ { give warnings about range errors with explicit typeconversions if the target
|
|
|
|
+ type does not span the entire range that can be represented by its bits
|
|
|
|
+ (subrange type or enum), because then the result is undefined }
|
|
|
|
+ else if (rangecheck<>rc_internal) and
|
|
|
|
+ (not is_pasbool(todef) and
|
|
|
|
+ not spans_entire_range(todef)) then
|
|
|
|
+ begin
|
|
|
|
+ Message3(type_w_range_check_error_bounds,tostr(l),tostr(lv),tostr(hv));
|
|
|
|
+ warned:=true;
|
|
end;
|
|
end;
|
|
|
|
+
|
|
{ Fix the value to fit in the allocated space for this type of variable }
|
|
{ Fix the value to fit in the allocated space for this type of variable }
|
|
- case longint(todef.size) of
|
|
|
|
- 1: l := l and $ff;
|
|
|
|
- 2: l := l and $ffff;
|
|
|
|
- 4: l := l and $ffffffff;
|
|
|
|
- else
|
|
|
|
- ;
|
|
|
|
- end;
|
|
|
|
|
|
+ oldval:=l;
|
|
|
|
+ getrangedefmasksize(todef,rangedef,mask,rangedefsize);
|
|
|
|
+ l:=l and mask;
|
|
{reset sign, i.e. converting -1 to qword changes the value to high(qword)}
|
|
{reset sign, i.e. converting -1 to qword changes the value to high(qword)}
|
|
l.signed:=false;
|
|
l.signed:=false;
|
|
|
|
+ sextval:=0;
|
|
{ do sign extension if necessary (JM) }
|
|
{ do sign extension if necessary (JM) }
|
|
- if is_signed(todef) then
|
|
|
|
- begin
|
|
|
|
- case longint(todef.size) of
|
|
|
|
- 1: l.svalue := shortint(l.svalue);
|
|
|
|
- 2: l.svalue := smallint(l.svalue);
|
|
|
|
- 4: l.svalue := longint(l.svalue);
|
|
|
|
- else
|
|
|
|
- ;
|
|
|
|
- end;
|
|
|
|
- l.signed:=true;
|
|
|
|
|
|
+ case rangedefsize of
|
|
|
|
+ 1: sextval.svalue:=shortint(l.svalue);
|
|
|
|
+ 2: sextval.svalue:=smallint(l.svalue);
|
|
|
|
+ 4: sextval.svalue:=longint(l.svalue);
|
|
|
|
+ 8: sextval.svalue:=l.svalue;
|
|
|
|
+ else
|
|
|
|
+ internalerror(201906230);
|
|
end;
|
|
end;
|
|
|
|
+ sextval.signed:=true;
|
|
|
|
+ { Detect if the type spans the entire range, but more bits were specified than
|
|
|
|
+ the type can contain, e.g. shortint($fff).
|
|
|
|
+ However, none of the following should result in a warning:
|
|
|
|
+ 1) shortint($ff) (-> $ff -> $ff -> $ffff ffff ffff ffff)
|
|
|
|
+ 2) shortint(longint(-1)) ($ffff ffff ffff ffff ffff -> $ff -> $ffff ffff ffff ffff
|
|
|
|
+ 3) cardinal(-1) (-> $ffff ffff ffff ffff -> $ffff ffff)
|
|
|
|
+ }
|
|
|
|
+ if not warned and
|
|
|
|
+ (rangecheck<>rc_internal) and
|
|
|
|
+ (oldval.uvalue<>l.uvalue) and
|
|
|
|
+ (oldval.uvalue<>sextval.uvalue) then
|
|
|
|
+ begin
|
|
|
|
+ Message3(type_w_range_check_error_bounds,tostr(oldval),tostr(lv),tostr(hv));
|
|
|
|
+ end;
|
|
|
|
+ if is_signed(rangedef) then
|
|
|
|
+ l:=sextval;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
+ procedure adaptrange(todef: tdef; var l: tconstexprint; internal, explicit: boolean);
|
|
|
|
+ begin
|
|
|
|
+ if internal then
|
|
|
|
+ adaptrange(todef, l, rc_internal)
|
|
|
|
+ else if explicit then
|
|
|
|
+ adaptrange(todef, l, rc_explicit)
|
|
|
|
+ else
|
|
|
|
+ adaptrange(todef, l, rc_default)
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+
|
|
{ return the range from def in l and h }
|
|
{ return the range from def in l and h }
|
|
procedure getrange(def : tdef;out l, h : TConstExprInt);
|
|
procedure getrange(def : tdef;out l, h : TConstExprInt);
|
|
begin
|
|
begin
|
|
@@ -1161,6 +1206,39 @@ implementation
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
+ procedure getrangedefmasksize(def: tdef; out rangedef: tdef; out mask: TConstExprInt; out size: longint);
|
|
|
|
+ begin
|
|
|
|
+ case def.typ of
|
|
|
|
+ orddef, enumdef:
|
|
|
|
+ begin
|
|
|
|
+ rangedef:=def;
|
|
|
|
+ size:=def.size;
|
|
|
|
+ case size of
|
|
|
|
+ 1: mask:=$ff;
|
|
|
|
+ 2: mask:=$ffff;
|
|
|
|
+ 4: mask:=$ffffffff;
|
|
|
|
+ 8: mask:=$ffffffffffffffff;
|
|
|
|
+ else
|
|
|
|
+ internalerror(2019062305);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ arraydef:
|
|
|
|
+ begin
|
|
|
|
+ rangedef:=tarraydef(def).rangedef;
|
|
|
|
+ getrangedefmasksize(rangedef,rangedef,mask,size);
|
|
|
|
+ end;
|
|
|
|
+ undefineddef:
|
|
|
|
+ begin
|
|
|
|
+ rangedef:=sizesinttype;
|
|
|
|
+ size:=rangedef.size;
|
|
|
|
+ mask:=-1;
|
|
|
|
+ end;
|
|
|
|
+ else
|
|
|
|
+ internalerror(2019062306);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+
|
|
function mmx_type(p : tdef) : tmmxtype;
|
|
function mmx_type(p : tdef) : tmmxtype;
|
|
begin
|
|
begin
|
|
mmx_type:=mmxno;
|
|
mmx_type:=mmxno;
|