http://www.ecma-international.org/publications/standards/Ecma-335.htm
Page 334
"1.1.5.2 Managed pointers (type &)
1.2 Managed pointers (&) can point to a local variable, a method argument, an object field, a value field type, an array element, a static field, or the address in which the element will be just beyond the end of the array (for pointers to pointers to managed arrays). Managed pointers cannot be null. (They must be reported to the garbage collector, even if they do not indicate managed memory) "
Page 149
7.1.2 pinned
Signature encoding for pinning should appear only in signatures describing local variables (Β§15.4.1.3). When using a method with a fixed local variable, VES should not move the object to which the local belongs. That is, if the CLI implementation uses a garbage collector that moves objects, the collector should not move objects referenced by the active bound local variable. [Justification. If unmanaged pointers are used to dereference managed objects, these objects must be pinned. This happens, for example, when a managed object is passed to a method designed to work with unmanaged data. final rationale]
I agree with Hans regarding the rational choice of msil language design.
These two things are different:
int[] arry = new int[5]; fixed (int* ptr = arry) { ... }
against.
int* ptr = stackalloc int[5];
If you look at the IL created for the second, you will see this (which, I think, you expect):
.locals init ([0] int32* ptr)
In the first version (your version), you point to an instance of System.Array (a managed type). In my version (using stackalloc) you indicate that, I think, you expect to point to ... a memory block large enough for 5 ints.