It only is unexpected if you ignore the type.
On the contrary. A boolean is supposed to have only two possible values (0 and 1), therefore the compiler should not claim that a boolean with a value that is neither zero (0) nor one (1) is true or false, it is something (a donald trump !?) but, neither true nor false.
It is the same as TWeekDay(999).
What is supposed to happen with TWeekDay(999)?
There was a huge discussion, about that when certain "case of" optimization came into play. (a case "else" does not catch 999, if all defined values are already explicitly mentioned)
A "longbool" has 4million possible values. And 2 defined meanings for them.
A boolean as you said has only 2 possible values. (and 2 meanings for them).
How to bring your 2 statements together?
- There are only 2 possible value for boolean (true and false)
- 1, 3, 5 or whatever are all boolean values
That is a direct contradiction.
You clearly expect the behaviour of longbool. So use that.
Pascal offers you both worlds.
- boolean with only 0 or 1 and all else undefined
- longbool with true = not zero
What is the problem with that?
Maybe you would prefer, if Pascal did not allow type-casts (as they are not type safe)
Boolean is enum(False,True).
yes, it is and, it would nice if the compiler knew that too. 
Where and when does it not?
Isn't your complain about the compiler behaving exactly to that knowledge when it compares the 2 values?
It does indeed ignore that, when you typecast boolean(n). (n outside range).
Again: typecasts are not typecast. So indeed, typecasts mean that the compiler ignores the knowledge it has about the data type.
I do not know if/were the documentation for that is, but it has been pointed out plenty of times: typecasts can break the type system.
Typecasts allow to produce invalid data, and invalid data has no defined behaviour.
5 is not a boolean value (its an integer). Typecasting it, does not necessarily result in valid boolean data.
Run your code again, but use "longbool" (for the var, and the typecast).
And it will say that they are "equal". (I did test that)
It does exactly what you ask it to do.
But, longbool is a different data type with different semantics than boolean. A longbool is true for any nolean.
But isn't that exactly what you were asking for?
That is the result you expect in your final compare.
Just to show how undefined the behaviour is
{$APPTYPE CONSOLE}
program TestBooleanExpression;
var
x: bitpacked record
b : boolean;
c : boolean;
c1 : boolean;
c2 : boolean;
c3 : boolean;
c4 : boolean;
end ;
begin
x.c := boolean(5);
x.b := boolean(7); // <<< changed this
writeln;
writeln('x.b = ', ord(x.b));
writeln('x.b = ', x.b);
writeln('x.c = ', ord(x.c));
writeln('x.c = ', x.c);
writeln;
write('x.b = x.c ? : ');
// it doesn't do a logical comparison (likely because Delphi doesn't either)
if x.b = x.c then writeln('equal') else writeln('not equal (logic in wonderland)');
end.
with bitpacked
x.b = 1
x.b = True
x.c = 1
x.c = TRUE
x.b = x.c ? : equal
without bitpacked
x.b = 7
x.b = TRUE
x.c = 5
x.c = TRUE
x.b = x.c ? : not equal (logic in wonderland)
As you can see the behaviour changes, for the same code. With the same type "boolean". Only because bitpacked changed the underlying storage.
And further more, there is no guarantee, that future fpc version will produce the same result. The result may be different (even without changing the storage), depending on fpc version, optimization, target system, ..... => undefined behaviour.