CBFalconer wrote:
You can test yourself easily. While writing such a test, I ran into an internal compiler error.
program zero; type int64 = integer( 64); var r: double; l: int64; begin l:= 0; int64( r):=l; writeln( 'r = ', r); r:= -1; double( l):= r; writeln( 'l = ', l) end.
[G4:~/gnu/testgpc/adriaan] adriaan% gpc -o zero zero.pas zero.pas: In main program: zero.pas:1: Internal compiler error in convert_move, at expr.c:507 Please submit a full bug report, with preprocessed source if appropriate. See URL:http://www.gnu-pascal.de/todo.html for instructions.
Thanks for the report (adriaan1.pas).
BTW, the test is questionable itself. It assumes 64 bit doubles which is true for IEEE, but not guaranteed at all for other formats. So better use `SizeOf' etc.
Besides, shouldn't that be:
begin l := 0; r := double(l); writeln('r = ', r); r := -1; l := int64(r); writeln('l = ', l) end.
i.e. the transform is applied to the right hand side. I would expect an error such as 'taking the address of an expression' with the original.
Actually, assigning is not the same as taking the address (you can assign to register variables, but not take their address). But that's beside the point.
The type-cast model GPC follows (or rather, aims to) is the one of BP (the only one I know) which is as follows:
- Expressions can be cast between ordinal and pointer types. In this case, the result of the type-cast is no "lvalue" (can't be assigned to etc.), and the ordinal value (extended to pointers) is preserved.
- "Lvalues" (the BP manual speaks of variable type casts here, but in fact it allows it also for things like `foo^', i.e. any lvalue) can be cast to a type whose size matches. (Of course, this is a portability issue, which BP doesn't care about, so it's up to the user to make sure that the size matches, e.g. casting something of type `Foo' to `array [1 .. SizeOf (Foo)] of Byte', or in the example above using `BitSizeOf (Double)' instead of 64.) In this case, the bit pattern is preserved, and the result is also an lvalue, i.e. can be used on both sides of an assignment etc.
There are cases where both kinds of type-casts are applicable, e.g.:
var a: ^Foo; [...] WriteLn (PtrInt (a)) { `LongInt' in BP }
"Fortunately", in these cases both are equivalent, since the same ordinal values correspond to the same bit patterns in all ordinal types and pointers in BP (and also GPC).
Now, GPC doesn't quite follow this model so far, but I think that's bugs which should be fixed. E.g.:
- It crashes on some type casts, which the original mail was about.
- It allows value type casts from ordinal to real types. At first sight, this might seem useful in case you want to use an integer in a place where a real is expected and no automatic conversion is performed (rather few cases).
However, there's a conflict:
var a: Integer; [...] WriteLn (ShortReal (a))
If `Integer' and `ShortReal' have the same size (as on IA32), this could be either a value or a variable type casts, but the results are different.
So BP's restriction to only ordinal and pointer types seems quite reasonably, and I'd like to forbid the other case in GPC as well (no objections I hope ;-). In the few cases where such a conversion is needed, there are alternatives such as adding `0.0' or assigning to a temporary variable of real type.
- It allows some more dubious casts which I'll also forbid.
Frank