csharpstandard icon indicating copy to clipboard operation
csharpstandard copied to clipboard

§8.8: Is IntPtr as an unmanaged type an extension?

Open KalleOlaviNiemitalo opened this issue 1 year ago • 5 comments

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, or bool.
  • 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 avatar Aug 15 '23 07:08 KalleOlaviNiemitalo

@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 avatar Aug 15 '23 23:08 Nigel-Ecma

@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.

jskeet avatar Aug 16 '23 10:08 jskeet

@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.

BillWagner avatar Aug 16 '23 14:08 BillWagner

Moved to C# 9 - we can always tackle it before then if we want to do it earlier.

jskeet avatar Aug 16 '23 14:08 jskeet

@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.

KalleOlaviNiemitalo avatar Aug 21 '23 07:08 KalleOlaviNiemitalo