csharpstandard
csharpstandard copied to clipboard
§8.8: Is IntPtr as an unmanaged type an extension?
Describe the bug
C# 7.x draft §8.8 (Unmanaged types) is not clear on whether System.IntPtr and System.UIntPtr can be unmanaged types.
It first says:
An unmanaged_type is any type that isn’t a reference_type, a type_parameter, or a constructed type, and contains no fields whose type is not an unmanaged_type.
Based on that definition, System.IntPtr and System.UIntPtr could be unmanaged types, as the specification does not require them to contain any "fields whose type is not an unmanaged_type."
The text continues:
In other words, an unmanaged_type is one of the following:
sbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,float
,double
,decimal
, orbool
.- Any enum_type.
- Any user-defined struct_type that is not a constructed type and contains fields of unmanaged_types only.
System.IntPtr and System.UIntPtr do not match this second definition, as they are struct types but not user-defined; they are required by §C.2 (Standard Library Types defined in ISO/IEC 23271).
Example
If an implementation allows the following, is that an extension (that would have to be documented)?
unsafe class C {
System.IntPtr* p;
}
Expected behavior
Allow System.IntPtr and System.UIntPtr to be unmanaged types even though they are not user-defined.
Additional context
C# 11 https://github.com/dotnet/csharplang/issues/6065 will require IntPtr and UIntPtr to be unmanaged types.
On .NET Framework, pre-Roslyn "Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.9149" /langversion:ISO-1
treats IntPtr as an unmanaged type.
Found while perusing https://github.com/dotnet/csharpstandard/pull/888.
@KalleOlaviNiemitalo – One could ask the same question regarding System.Int128
, and the answer in both cases is they are unmanaged types.
The issue is really the term “user-defined” which, while not formally defined in the Standard, happens to mean not formally defined in the Standard! Or alternatively ”not language-defined”.
So types such a System.IntPtr
or System.Int128
which are in the system library (the latter maybe of only some implementations) are “user-defined”.
So IntPtr
and UIntPtr
do match the second definition, but that may not be obvious as your raising this attests.
In your particular example just removing “user-defined” works fine:
- Any struct_type that is not a constructed type and contains fields of unmanaged_types only.
And we could do that, but that leaves the other ~134 uses of “user-defined” to check for similar issues… So maybe defining “user-defined” would be better… Or just leaving it as is, it has survived some two decades after all.
I'll slap a milestone and meeting discuss label on your issue to prompt input from others; if you wish to make a PR to drop the phrase in this case I expect it will get accepted.
@Nigel-Ecma: Is there anything specifically C#-7-related in this? If we can get it resolved before we ship C# 7, that's great - but I'm not sure it should be a blocking issue for C# 7.
@Nigel-Ecma @jskeet
I'd like to defer this. Once we get to C# 9, the addition of the nint
and nuint
keywords make this almost moot. Once C# 10 comes around, I think it's completely moot.
Moved to C# 9 - we can always tackle it before then if we want to do it earlier.
@Nigel-Ecma, AFAICT the only things C# 7.x specifies about IntPtr are that it is a readonly struct
type and can be used as the type of a volatile
field. So a conforming implementation could give IntPtr an instance field whose type is not an unmanaged_type, making IntPtr itself not an unmanaged_type.