[fpc-devel] [Suggestion] Enumeration range-check intrinsic

Martin Frb lazarus at mfriebe.de
Sat Jul 13 13:28:38 CEST 2019


On 11/07/2019 15:46, J. Gareth Moreton wrote:
>
> For my personal point of view, I would like these operators to be the 
> exception to the rule of the compiler assuming an enum always contains 
> a valid value,

As much as I would like to agree with you (and yes I think such a check, 
if possible, would be desirable - even if it meant to ignore certain 
language design principles), it is indeed not possible.
Maybe it would be today (as in today's fpc implementation), maybe not. I 
do not know.

But it would not be future safe.

Lets say "fpc breaks the rule for "is/as" and only for those".

   FooEnum := SomeApi();
   if not (FooEnum is TFooEnum) then FooEnum := low(TFooEnum);

Now we do *not* know what the optimizer does in the first line. And that 
is the problem.
On some platform (that we have no clue of today), the compiler may store 
the value bitpacked into a temp var/register. The storage is shared with 
other values.
If the result of "SomeApi()" is out of bounds, it might overwrite one of 
the other values stored in that var/register.
The "is" can only check the part of the storage actually meant to be 
used by the enum. The change to the other value goes unnoticed.

So in such a future case, the is may do what you expect. A later "case 
FooEnum" will be ok, as FooEnum is "forced" to be valid.
But your program still crashes, due to the other var being modified 
unexpectedly.

Yes that may sound far fetched. But maybe some embedded system, with 
scarce resources requires such behaviour?

----------------
Maybe a possible solution would be based on:

On 13/07/2019 12:48, Jonas Maebe wrote:
> In Delphi's type system (and in C, C++, and C#), the valid values for 
> an enum are always all values that fit within its storage size, and 
> that storage size is fixed.

Create such an enum type in fpc too (as a new type / assignment 
compatible with the current enum)

   {modeswitch StorageSizeValidEnum}
   type TFullFooEnum = (a,b,c);

would treat all values of the (unpacked) storage as valid.
As a consequence:
  - it can not be packed / it would keep its full size
  - many optimizations can not be applied

But for such a type, that has explicitly been defined as having all the 
other values, you could use "is".
Of course not straight forward. Because now  255 is a valid value for 
that enum, so "is" would return true. But with:

   {modeswitch StorageSizeValidEnum on}
   type TFullFooEnum = (a,b,c);
   {modeswitch StorageSizeValidEnum off}
   type TFooEnum = (a,b,c);

this would work:
   if  FullFooEnum is TFooEnum then

Since this is only/mainly used for "external" data, the extra type def 
would not be to much overhead.

Of course, it is merely syntactical sugar, since it is identical too
   type TFullFooEnum = integer; //or whatever represents the storage size
   type TFooEnum = (a,b,c);

It only allows to have named values for that "integer"


More information about the fpc-devel mailing list