[fpc-devel] [Suggestion] Enumeration range-check intrinsic
Martok
listbox at martoks-place.de
Sun Jul 14 19:40:31 CEST 2019
> If you want to nitpick, the compiler will perform 1/2/4 byte writes for
> enums of those sizes, so the full reserved data is in fact
> used/initialised. Again: the only relevant part in this discussion is
> the valid values. The reserved/used/accessed/written/... storage size is
> unrelated to that to the extent explained in my previous message.
That was exactly my point!
The storage size is unrelated to the "used"/"valid" size, therefore there is
little point in being able to set it.
I can tell the compiler "this type is 4 bytes wide", but it will still only ever
consider the lowest byte if that's how many elements there are.
> This inconsistency would mean that we at least need two versions of
> defutils.getrange() in the compiler: one for (some) range checks (using
> the named range), and one for other reasoning (which must use the
> basedef range). There may be other such places that need modifications.
Interestingly, that's not the case, I checked.
There are like 2 major places that need adjustment, everything else already
correctly uses getrange for the type range and min/max for label range. It
almost looks as if most of the compiler was written assuming these two are not
the same.
The JVM class generator is the only real challenge. These days, one could
probably take a look at .Net Core to see how a managed language does this.
>> Arrays of such a type should not be allowed (as for enums with jumps right now)
>> (* although they could be without surprises, Array[tmyenum] would simply be
>> Array[Byte] *).
>
> The whole point of a directive/modifier would be to get
> Delphi-compatible enums, not to add a third variant.
Where do you see a third variant? If you think this is anything but a
"Hejlsberg-Enum", I seriously failed to explain it.
The proposed syntax would be a shorthand for what Delphi does when you write
{$Zn} tenum = (ea,eb,ec,ed);
With n:=sizeof(basetype).
Nothing else, nothing more.
> I meant that Delphi's range checking for enums/subranges doesn't make
> any sense due to the inconsistency between the "valid" and "declared" range.
The thing about $R and Delphi: a) it is purely ancillary and not part of the
type system. A *lot* of stuff is not rangechecked there at all. This has not a
lot to do with the nesting of type ranges.
b) only pred/succ, literal assignment without hard cast and assignment from
larger to smaller type are guaranteed to check if a subrange type is exceeded by
an action. Nothing else does - anything(!!) that fits in the same storage is a
valid value.
Both of that is documented behaviour, and has been for decades.
> E.g., take this Delphi program (tested with Kylix 3; YMMV with modern
> Delphi versions, to which I don't have access)
> [snip]
> This is both 100% inconsistent and 100% logical.
> On the other hand, you have this whole inconsistency where 255 is both a
> valid and an invalid value. So when a range check happens to be
> inserted, you get a range check error, and when it isn't, you don't.
One might argue that it is 100% consistent as well. Compile in {$R-} (remember,
in TP and Delphi it's a debugging aid, not a
thing-you-have-to-do-to-get-somehwat-safe-results like in FPC), and only the out
of bounds array accesses remain. And those are 100% equivalent to our old
friend, the unchecked jumptable access.
> As described in that post, the issue is that the default FPC units
> declare various enumeration types without any specific modifiers. Even
> if all default FPC units would be changed to Delphi-compatible enums,
> then you would still get issues when mixing and matching units declared
> with differently declared enumeration types, since there is no obvious
> way to know how a particular enumeration type has been declared.
Except, you know, looking at the source?
That's like arguing that there is no way to know if a record is packed or not.
Of course there is, it's a keyword right in the declaration.
Or, actually, more like asking what the calling convention of a function could
be. Usually you don't need to know, but when you do, it's either a keyword at
declaration site, or a {$CALLING} setting is in effect. No ambiguity at all.
That's why I say the decision must be clear at declaration point, not for every
access (as was previously suggested).
Best,
Sebastian
More information about the fpc-devel
mailing list