From 71e6a3be24bf1cc24a8c0d4d0935c1ae603f0ca7 Mon Sep 17 00:00:00 2001 From: Charles Stoner Date: Wed, 16 Sep 2020 14:28:27 -0700 Subject: [PATCH] Emit conversions between native integers and pointers directly (#47708) --- .../Semantics/Conversions/ConversionsBase.cs | 43 +-- .../CSharp/Portable/CodeGen/EmitConversion.cs | 7 +- .../Semantic/Semantics/NativeIntegerTests.cs | 254 +++++++++++++----- .../Portable/CodeGen/ILBuilderConversions.cs | 16 +- 4 files changed, 232 insertions(+), 88 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs index 24f6176c9a8..c5e52a1e94d 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs @@ -1917,16 +1917,20 @@ private static bool HasSpecialIntPtrConversion(TypeSymbol source, TypeSymbol tar var s0 = source.StrippedType(); var t0 = target.StrippedType(); - if (s0.SpecialType != SpecialType.System_UIntPtr && - s0.SpecialType != SpecialType.System_IntPtr && - t0.SpecialType != SpecialType.System_UIntPtr && - t0.SpecialType != SpecialType.System_IntPtr) + TypeSymbol otherType; + if (isIntPtrOrUIntPtr(s0)) + { + otherType = t0; + } + else if (isIntPtrOrUIntPtr(t0)) + { + otherType = s0; + } + else { return false; } - TypeSymbol otherType = (s0.SpecialType == SpecialType.System_UIntPtr || s0.SpecialType == SpecialType.System_IntPtr) ? t0 : s0; - if (otherType.IsPointerOrFunctionPointer()) { return true; @@ -1955,6 +1959,9 @@ private static bool HasSpecialIntPtrConversion(TypeSymbol source, TypeSymbol tar } return false; + + static bool isIntPtrOrUIntPtr(TypeSymbol type) => + (type.SpecialType == SpecialType.System_IntPtr || type.SpecialType == SpecialType.System_UIntPtr) && !type.IsNativeIntegerType; } private static bool HasExplicitEnumerationConversion(TypeSymbol source, TypeSymbol destination) @@ -3494,20 +3501,7 @@ private static bool HasPointerToIntegerConversion(TypeSymbol source, TypeSymbol // The spec should state that any pointer type is convertible to // sbyte, byte, ... etc, or any corresponding nullable type. - switch (destination.StrippedType().SpecialType) - { - case SpecialType.System_SByte: - case SpecialType.System_Byte: - case SpecialType.System_Int16: - case SpecialType.System_UInt16: - case SpecialType.System_Int32: - case SpecialType.System_UInt32: - case SpecialType.System_Int64: - case SpecialType.System_UInt64: - return true; - } - - return false; + return IsIntegerTypeSupportingPointerConversions(destination.StrippedType()); } private static bool HasIntegerToPointerConversion(TypeSymbol source, TypeSymbol destination) @@ -3521,8 +3515,12 @@ private static bool HasIntegerToPointerConversion(TypeSymbol source, TypeSymbol } // Note that void* is convertible to int?, but int? is not convertible to void*. + return IsIntegerTypeSupportingPointerConversions(source); + } - switch (source.SpecialType) + private static bool IsIntegerTypeSupportingPointerConversions(TypeSymbol type) + { + switch (type.SpecialType) { case SpecialType.System_SByte: case SpecialType.System_Byte: @@ -3533,6 +3531,9 @@ private static bool HasIntegerToPointerConversion(TypeSymbol source, TypeSymbol case SpecialType.System_Int64: case SpecialType.System_UInt64: return true; + case SpecialType.System_IntPtr: + case SpecialType.System_UIntPtr: + return type.IsNativeIntegerType; } return false; diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitConversion.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitConversion.cs index 2ad47f644a2..c05018faf86 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitConversion.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitConversion.cs @@ -143,8 +143,8 @@ private void EmitConversion(BoundConversion conversion) #if DEBUG switch (fromPredefTypeKind) { - case Microsoft.Cci.PrimitiveTypeCode.IntPtr: - case Microsoft.Cci.PrimitiveTypeCode.UIntPtr: + case Microsoft.Cci.PrimitiveTypeCode.IntPtr when !fromType.IsNativeIntegerType: + case Microsoft.Cci.PrimitiveTypeCode.UIntPtr when !fromType.IsNativeIntegerType: case Microsoft.Cci.PrimitiveTypeCode.Pointer: case Microsoft.Cci.PrimitiveTypeCode.FunctionPointer: Debug.Assert(IsNumeric(toType)); @@ -152,8 +152,7 @@ private void EmitConversion(BoundConversion conversion) default: Debug.Assert(IsNumeric(fromType)); Debug.Assert( - toPredefTypeKind == Microsoft.Cci.PrimitiveTypeCode.IntPtr || - toPredefTypeKind == Microsoft.Cci.PrimitiveTypeCode.UIntPtr || + (toPredefTypeKind == Microsoft.Cci.PrimitiveTypeCode.IntPtr || toPredefTypeKind == Microsoft.Cci.PrimitiveTypeCode.UIntPtr) && !toType.IsNativeIntegerType || toPredefTypeKind == Microsoft.Cci.PrimitiveTypeCode.Pointer || toPredefTypeKind == Microsoft.Cci.PrimitiveTypeCode.FunctionPointer); break; diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs index 51d88f042db..e3a629035ca 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; @@ -6963,16 +6962,8 @@ .maxstack 1 IL_0006: ret }"); conversions(sourceType: "string", destType: "nint", expectedImplicitIL: null, expectedExplicitIL: null); - conversions(sourceType: "void*", destType: "nint", expectedImplicitIL: null, -// https://github.com/dotnet/roslyn/issues/42457: Investigate whether this conversion (and other -// conversions to/from void*) can use conv.i or conv.u instead of explicit operators on System.[U]IntPtr. -@"{ - // Code size 7 (0x7) - .maxstack 1 - IL_0000: ldarg.0 - IL_0001: call ""System.IntPtr System.IntPtr.op_Explicit(void*)"" - IL_0006: ret -}"); + conversions(sourceType: "void*", destType: "nint", expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.i.un")); + conversions(sourceType: "delegate*", destType: "nint", expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.i.un")); conversions(sourceType: "bool", destType: "nint", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "char", destType: "nint", expectedImplicitIL: conv("conv.u"), expectedExplicitIL: conv("conv.u")); conversions(sourceType: "sbyte", destType: "nint", expectedImplicitIL: conv("conv.i"), expectedExplicitIL: conv("conv.i")); @@ -7066,12 +7057,35 @@ .maxstack 1 conversions(sourceType: "string", destType: "nint?", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "void*", destType: "nint?", expectedImplicitIL: null, @"{ - // Code size 12 (0xc) + // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 - IL_0001: call ""System.IntPtr System.IntPtr.op_Explicit(void*)"" - IL_0006: newobj ""nint?..ctor(nint)"" - IL_000b: ret + IL_0001: newobj ""nint?..ctor(nint)"" + IL_0006: ret +}", +@"{ + // Code size 8 (0x8) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: conv.ovf.i.un + IL_0002: newobj ""nint?..ctor(nint)"" + IL_0007: ret +}"); + conversions(sourceType: "delegate*", destType: "nint?", expectedImplicitIL: null, +@"{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: newobj ""nint?..ctor(nint)"" + IL_0006: ret +}", +@"{ + // Code size 8 (0x8) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: conv.ovf.i.un + IL_0002: newobj ""nint?..ctor(nint)"" + IL_0007: ret }"); conversions(sourceType: "bool", destType: "nint?", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "char", destType: "nint?", expectedImplicitIL: convToNullableT("conv.u", "nint"), expectedExplicitIL: convToNullableT("conv.u", "nint")); @@ -7211,14 +7225,8 @@ .maxstack 1 IL_0006: ret }"); conversions(sourceType: "nint", destType: "string", expectedImplicitIL: null, expectedExplicitIL: null); - conversions(sourceType: "nint", destType: "void*", expectedImplicitIL: null, -@"{ - // Code size 7 (0x7) - .maxstack 1 - IL_0000: ldarg.0 - IL_0001: call ""void* System.IntPtr.op_Explicit(System.IntPtr)"" - IL_0006: ret -}"); + conversions(sourceType: "nint", destType: "void*", expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.u")); + conversions(sourceType: "nint", destType: "delegate*", expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.u")); conversions(sourceType: "nint", destType: "bool", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "nint", destType: "char", expectedImplicitIL: null, expectedExplicitIL: conv("conv.u2"), expectedCheckedIL: conv("conv.ovf.u2")); conversions(sourceType: "nint", destType: "sbyte", expectedImplicitIL: null, expectedExplicitIL: conv("conv.i1"), expectedCheckedIL: conv("conv.ovf.i1")); @@ -7315,15 +7323,8 @@ .maxstack 1 IL_0006: ret }"); conversions(sourceType: "nint?", destType: "string", expectedImplicitIL: null, expectedExplicitIL: null); - conversions(sourceType: "nint?", destType: "void*", expectedImplicitIL: null, -@"{ - // Code size 13 (0xd) - .maxstack 1 - IL_0000: ldarga.s V_0 - IL_0002: call ""nint nint?.Value.get"" - IL_0007: call ""void* System.IntPtr.op_Explicit(System.IntPtr)"" - IL_000c: ret -}"); + conversions(sourceType: "nint?", destType: "void*", expectedImplicitIL: null, expectedExplicitIL: null); + conversions(sourceType: "nint?", destType: "delegate*", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "nint?", destType: "bool", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "nint?", destType: "char", expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.u2", "nint"), expectedCheckedIL: convFromNullableT("conv.ovf.u2", "nint")); conversions(sourceType: "nint?", destType: "sbyte", expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.i1", "nint"), expectedCheckedIL: convFromNullableT("conv.ovf.i1", "nint")); @@ -7421,14 +7422,8 @@ .maxstack 1 IL_0006: ret }"); conversions(sourceType: "string", destType: "nuint", expectedImplicitIL: null, expectedExplicitIL: null); - conversions(sourceType: "void*", destType: "nuint", expectedImplicitIL: null, -@"{ - // Code size 7 (0x7) - .maxstack 1 - IL_0000: ldarg.0 - IL_0001: call ""System.UIntPtr System.UIntPtr.op_Explicit(void*)"" - IL_0006: ret -}"); + conversions(sourceType: "void*", destType: "nuint", expectedImplicitIL: null, expectedExplicitIL: convNone); + conversions(sourceType: "delegate*", destType: "nuint", expectedImplicitIL: null, expectedExplicitIL: convNone); conversions(sourceType: "bool", destType: "nuint", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "char", destType: "nuint", expectedImplicitIL: conv("conv.u"), expectedExplicitIL: conv("conv.u")); conversions(sourceType: "sbyte", destType: "nuint", expectedImplicitIL: conv("conv.i"), expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.u")); @@ -7522,12 +7517,19 @@ .maxstack 1 conversions(sourceType: "string", destType: "nuint?", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "void*", destType: "nuint?", expectedImplicitIL: null, @"{ - // Code size 12 (0xc) + // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 - IL_0001: call ""System.UIntPtr System.UIntPtr.op_Explicit(void*)"" - IL_0006: newobj ""nuint?..ctor(nuint)"" - IL_000b: ret + IL_0001: newobj ""nuint?..ctor(nuint)"" + IL_0006: ret +}"); + conversions(sourceType: "delegate*", destType: "nuint?", expectedImplicitIL: null, +@"{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: newobj ""nuint?..ctor(nuint)"" + IL_0006: ret }"); conversions(sourceType: "bool", destType: "nuint?", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "char", destType: "nuint?", expectedImplicitIL: convToNullableT("conv.u", "nuint"), expectedExplicitIL: convToNullableT("conv.u", "nuint")); @@ -7667,14 +7669,8 @@ .maxstack 1 IL_0006: ret }"); conversions(sourceType: "nuint", destType: "string", expectedImplicitIL: null, expectedExplicitIL: null); - conversions(sourceType: "nuint", destType: "void*", expectedImplicitIL: null, -@"{ - // Code size 7 (0x7) - .maxstack 1 - IL_0000: ldarg.0 - IL_0001: call ""void* System.UIntPtr.op_Explicit(System.UIntPtr)"" - IL_0006: ret -}"); + conversions(sourceType: "nuint", destType: "void*", expectedImplicitIL: null, expectedExplicitIL: convNone); + conversions(sourceType: "nuint", destType: "delegate*", expectedImplicitIL: null, expectedExplicitIL: convNone); conversions(sourceType: "nuint", destType: "bool", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "nuint", destType: "char", expectedImplicitIL: null, expectedExplicitIL: conv("conv.u2"), expectedCheckedIL: conv("conv.ovf.u2.un")); conversions(sourceType: "nuint", destType: "sbyte", expectedImplicitIL: null, expectedExplicitIL: conv("conv.i1"), expectedCheckedIL: conv("conv.ovf.i1.un")); @@ -7769,15 +7765,8 @@ .maxstack 1 IL_0006: ret }"); conversions(sourceType: "nuint?", destType: "string", expectedImplicitIL: null, expectedExplicitIL: null); - conversions(sourceType: "nuint?", destType: "void*", expectedImplicitIL: null, -@"{ - // Code size 13 (0xd) - .maxstack 1 - IL_0000: ldarga.s V_0 - IL_0002: call ""nuint nuint?.Value.get"" - IL_0007: call ""void* System.UIntPtr.op_Explicit(System.UIntPtr)"" - IL_000c: ret -}"); + conversions(sourceType: "nuint?", destType: "void*", expectedImplicitIL: null, expectedExplicitIL: null); + conversions(sourceType: "nuint?", destType: "delegate*", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "nuint?", destType: "bool", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "nuint?", destType: "char", expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.u2", "nuint"), expectedCheckedIL: convFromNullableT("conv.ovf.u2.un", "nuint")); conversions(sourceType: "nuint?", destType: "sbyte", expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.i1", "nuint"), expectedCheckedIL: convFromNullableT("conv.ovf.i1.un", "nuint")); @@ -7883,6 +7872,7 @@ .maxstack 1 }"); conversions(sourceType: "System.IntPtr", destType: "string", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "System.IntPtr", destType: "void*", expectedImplicitIL: null, expectedExplicitIL: convAndExplicit("void* System.IntPtr.op_Explicit(System.IntPtr)")); + conversions(sourceType: "System.IntPtr", destType: "delegate*", expectedImplicitIL: null, expectedExplicitIL: convAndExplicit("void* System.IntPtr.op_Explicit(System.IntPtr)")); conversions(sourceType: "System.IntPtr", destType: "bool", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "System.IntPtr", destType: "char", expectedImplicitIL: null, expectedExplicitIL: convAndExplicit("int System.IntPtr.op_Explicit(System.IntPtr)", "conv.u2"), expectedCheckedIL: convAndExplicit("int System.IntPtr.op_Explicit(System.IntPtr)", "conv.ovf.u2")); conversions(sourceType: "System.IntPtr", destType: "sbyte", expectedImplicitIL: null, expectedExplicitIL: convAndExplicit("int System.IntPtr.op_Explicit(System.IntPtr)", "conv.i1"), expectedCheckedIL: convAndExplicit("int System.IntPtr.op_Explicit(System.IntPtr)", "conv.ovf.i1")); @@ -8020,6 +8010,7 @@ .maxstack 1 }"); conversions(sourceType: "string", destType: "System.IntPtr", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "void*", destType: "System.IntPtr", expectedImplicitIL: null, expectedExplicitIL: explicitAndConv("System.IntPtr System.IntPtr.op_Explicit(void*)")); + conversions(sourceType: "delegate*", destType: "System.IntPtr", expectedImplicitIL: null, expectedExplicitIL: explicitAndConv("System.IntPtr System.IntPtr.op_Explicit(void*)")); conversions(sourceType: "bool", destType: "System.IntPtr", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "char", destType: "System.IntPtr", expectedImplicitIL: null, expectedExplicitIL: explicitAndConv("System.IntPtr System.IntPtr.op_Explicit(int)")); conversions(sourceType: "sbyte", destType: "System.IntPtr", expectedImplicitIL: null, expectedExplicitIL: explicitAndConv("System.IntPtr System.IntPtr.op_Explicit(int)")); @@ -8135,6 +8126,7 @@ .maxstack 1 }"); conversions(sourceType: "System.UIntPtr", destType: "string", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "System.UIntPtr", destType: "void*", expectedImplicitIL: null, expectedExplicitIL: convAndExplicit("void* System.UIntPtr.op_Explicit(System.UIntPtr)")); + conversions(sourceType: "System.UIntPtr", destType: "delegate*", expectedImplicitIL: null, expectedExplicitIL: convAndExplicit("void* System.UIntPtr.op_Explicit(System.UIntPtr)")); conversions(sourceType: "System.UIntPtr", destType: "bool", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "System.UIntPtr", destType: "char", expectedImplicitIL: null, expectedExplicitIL: convAndExplicit("uint System.UIntPtr.op_Explicit(System.UIntPtr)", "conv.u2"), expectedCheckedIL: convAndExplicit("uint System.UIntPtr.op_Explicit(System.UIntPtr)", "conv.ovf.u2.un")); conversions(sourceType: "System.UIntPtr", destType: "sbyte", expectedImplicitIL: null, expectedExplicitIL: convAndExplicit("uint System.UIntPtr.op_Explicit(System.UIntPtr)", "conv.i1"), expectedCheckedIL: convAndExplicit("uint System.UIntPtr.op_Explicit(System.UIntPtr)", "conv.ovf.i1.un")); @@ -8330,6 +8322,7 @@ .maxstack 1 }"); conversions(sourceType: "string", destType: "System.UIntPtr", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "void*", destType: "System.UIntPtr", expectedImplicitIL: null, expectedExplicitIL: explicitAndConv("System.UIntPtr System.UIntPtr.op_Explicit(void*)")); + conversions(sourceType: "delegate*", destType: "System.UIntPtr", expectedImplicitIL: null, expectedExplicitIL: explicitAndConv("System.UIntPtr System.UIntPtr.op_Explicit(void*)")); conversions(sourceType: "bool", destType: "System.UIntPtr", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "char", destType: "System.UIntPtr", expectedImplicitIL: null, expectedExplicitIL: explicitAndConv("System.UIntPtr System.UIntPtr.op_Explicit(uint)")); conversions(sourceType: "sbyte", destType: "System.UIntPtr", expectedImplicitIL: null, expectedExplicitIL: explicitAndConv("System.UIntPtr System.UIntPtr.op_Explicit(ulong)", "conv.i8"), expectedCheckedIL: explicitAndConv("System.UIntPtr System.UIntPtr.op_Explicit(ulong)", "conv.ovf.u8")); @@ -8481,7 +8474,7 @@ .maxstack 1 verifier.VerifyIL("Program.Convert", expectedIL); } - static bool useUnsafe(string type) => type == "void*"; + static bool useUnsafe(string type) => type == "void*" || type == "delegate*"; } } @@ -12243,5 +12236,142 @@ static object Execute(Func f) 0 {(IntPtr.Size == 4 ? "System.OverflowException" : "0")}"); } + + [WorkItem(44810, "https://github.com/dotnet/roslyn/issues/44810")] + [Theory] + [InlineData("void*")] + [InlineData("byte*")] + [InlineData("delegate*")] + public void PointerConversions(string pointerType) + { + string source = +$@"using System; +unsafe class Program +{{ + static {pointerType} ToPointer1(nint i) => ({pointerType})i; + static {pointerType} ToPointer2(nuint u) => ({pointerType})u; + static {pointerType} ToPointer3(nint i) => checked(({pointerType})i); + static {pointerType} ToPointer4(nuint u) => checked(({pointerType})u); + static nint FromPointer1({pointerType} p) => (nint)p; + static nuint FromPointer2({pointerType} p) => (nuint)p; + static nint FromPointer3({pointerType} p) => checked((nint)p); + static nuint FromPointer4({pointerType} p) => checked((nuint)p); + static object Execute(Func f) + {{ + try + {{ + return f(); + }} + catch (Exception e) + {{ + return e.GetType().FullName; + }} + }} + static void Execute({pointerType} p) + {{ + Console.WriteLine((int)p); + Console.WriteLine(Execute(() => FromPointer1(p))); + Console.WriteLine(Execute(() => FromPointer2(p))); + Console.WriteLine(Execute(() => FromPointer3(p))); + Console.WriteLine(Execute(() => FromPointer4(p))); + }} + static void Main() + {{ + Execute(ToPointer1(-42)); + Execute(ToPointer2(42)); + Execute(ToPointer1(int.MinValue)); + Execute(ToPointer2(uint.MaxValue)); + Console.WriteLine(Execute(() => (ulong)ToPointer3(-42))); + Console.WriteLine(Execute(() => (ulong)ToPointer4(42))); + Console.WriteLine(Execute(() => (ulong)ToPointer3(int.MinValue))); + Console.WriteLine(Execute(() => (ulong)ToPointer4(uint.MaxValue))); + }} +}}"; + var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseExe, parseOptions: TestOptions.Regular9); + string expectedOutput = +$@"-42 +-42 +{(IntPtr.Size == 4 ? "4294967254" : "18446744073709551574")} +System.OverflowException +{(IntPtr.Size == 4 ? "4294967254" : "18446744073709551574")} +42 +42 +42 +42 +42 +-2147483648 +-2147483648 +{(IntPtr.Size == 4 ? "2147483648" : "18446744071562067968")} +System.OverflowException +{(IntPtr.Size == 4 ? "2147483648" : "18446744071562067968")} +-1 +{(IntPtr.Size == 4 ? "-1" : "4294967295")} +4294967295 +{(IntPtr.Size == 4 ? "System.OverflowException" : "4294967295")} +4294967295 +System.OverflowException +42 +System.OverflowException +4294967295"; + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: expectedOutput); + verifier.VerifyIL("Program.ToPointer1", +@"{ + // Code size 2 (0x2) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ret +}"); + verifier.VerifyIL("Program.ToPointer2", +@"{ + // Code size 2 (0x2) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ret +}"); + verifier.VerifyIL("Program.ToPointer3", +@"{ + // Code size 3 (0x3) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: conv.ovf.u + IL_0002: ret +}"); + verifier.VerifyIL("Program.ToPointer4", +@"{ + // Code size 2 (0x2) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ret +}"); + verifier.VerifyIL("Program.FromPointer1", +@"{ + // Code size 2 (0x2) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ret +}"); + verifier.VerifyIL("Program.FromPointer2", +@"{ + // Code size 2 (0x2) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ret +}"); + verifier.VerifyIL("Program.FromPointer3", +@"{ + // Code size 3 (0x3) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: conv.ovf.i.un + IL_0002: ret +}"); + verifier.VerifyIL("Program.FromPointer4", +@"{ + // Code size 2 (0x2) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ret +}"); + } } } diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilderConversions.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilderConversions.cs index be80aefa2c7..932d935abb3 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilderConversions.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilderConversions.cs @@ -7,7 +7,6 @@ using System; using System.Diagnostics; using System.Reflection.Metadata; -using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeGen @@ -151,6 +150,11 @@ public void EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode fromPredefType // Don't want to sign extend if this is a widening conversion. this.EmitOpCode(ILOpCode.Conv_u); // potentially widening, so not NOP break; + case Microsoft.Cci.PrimitiveTypeCode.Pointer: + case Microsoft.Cci.PrimitiveTypeCode.FunctionPointer: + if (@checked) + goto default; + break; // NOP default: if (@checked) this.EmitOpCode(fromUnsigned ? ILOpCode.Conv_ovf_i_un : ILOpCode.Conv_ovf_i); @@ -164,6 +168,8 @@ public void EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode fromPredefType switch (fromPredefTypeKind) { case Microsoft.Cci.PrimitiveTypeCode.UIntPtr: + case Microsoft.Cci.PrimitiveTypeCode.Pointer: + case Microsoft.Cci.PrimitiveTypeCode.FunctionPointer: break; // NOP case Microsoft.Cci.PrimitiveTypeCode.UInt8: case Microsoft.Cci.PrimitiveTypeCode.UInt16: @@ -306,6 +312,11 @@ public void EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode fromPredefType case Microsoft.Cci.PrimitiveTypeCode.Int64: this.EmitOpCode(ILOpCode.Conv_ovf_u); break; + case Microsoft.Cci.PrimitiveTypeCode.IntPtr: + this.EmitOpCode(ILOpCode.Conv_ovf_u); + break; + case Microsoft.Cci.PrimitiveTypeCode.UIntPtr: + break; // NOP default: throw ExceptionUtilities.UnexpectedValue(fromPredefTypeKind); } @@ -328,6 +339,9 @@ public void EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode fromPredefType // rather than conv_u, to sign-extend the value. this.EmitOpCode(ILOpCode.Conv_i); break; + case Microsoft.Cci.PrimitiveTypeCode.IntPtr: + case Microsoft.Cci.PrimitiveTypeCode.UIntPtr: + break; // NOP default: throw ExceptionUtilities.UnexpectedValue(fromPredefTypeKind); } -- GitLab