Description
Summary
Provide a way to take the address of a generic struct provided it does not contain any "managed" (GC-tracked) types.
For example, the following generic type is "unmanaged":
public struct MyStruct<T> where T : unmanaged
{
public T field;
}
Motivation
Today, users have the ability to declare structs and take the address of it (in an unsafe context) provided that it is not considered a "managed" type.
- The compiler currently reports generic structs as "managed" types, even though they are not GC-tracked
However, there is nothing in the runtime preventing a user from taking the address of a generic struct and, in certain scenarios, it may be desirable to allow this.
One such example is the System.Runtime.Intrinsics.Vector128<T>
type, which contains no GC tracked objects. The type is designed to be used in high-performance and generally unsafe scenarios, but there are certain operations (such as stackalloc
, pinning
, etc) which cannot be done in C# today.
Design
The C# 6 spec states that an unmanaged_type
is:
isn't a reference_type or constructed type, and doesn't contain reference_type or constructed type fields at any level of nesting. In other words, an unmanaged_type is one of the following:
- sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool.
- Any enum_type.
- Any pointer_type.
- Any user-defined struct_type that is not a constructed type and contains fields of unmanaged_types only.
This change would remove the restriction that unmanaged_type
cannot be a constructed type. Instead, constructed types would be unmanaged if they meet the requirements of general user-defined struct types.
Drawbacks
The compiler may need to do additional validation in order to validate that a user-defined generic struct is "ok" to use.
Notes
The user will still not be able to take the address of any type, which is possible to do in IL code today.