As a result in
Type 'T' is not yet completely defined.
But T is completely defined, just in another block, just like the constant "b".
The problem is that it added the current T type definition into the parser's tables and, because of that when searching for the definition of T (as the type of array element), it finds the incomplete definition instead of the previously defined T. IOW, it added the current type definition too early, that caused the masking of the previous full definition of T. In the case of the constant "b", the fact that it finds the previous definition indicates that the current definition was _not_ added to the parser's table until the definition was complete. That prevented the previous definition of "b" from being masked away by the new one.
All that said, re-using names in the same definition (such as "b" and "T") is a very poor practice so, maybe it's better that FPC does it that way even though, strictly speaking, it is "questionable".
I see your point about the class definitions, you're right, for classes it does need to add the type early in the parser's table. That's probably why it initially marks it "incomplete" and it accepts a reference to the class because unlike in a "normal" type definition, a reference to a class is just a pointer and that's all it really needs to know at that point.
This seems not a bug to me.
Strictly speaking, it is incorrect. Pascal's scope rules allow the definition of T as I posted it. OTOH, losing the ability of creating such questionable definitions is more a blessing than anything else. That said, if it allows it for constants then it should allow it for types too. Either allow it or don't allow it but, not "allow sometimes" and "don't allow other times".