未验证 提交 71e6a3be 编写于 作者: C Charles Stoner 提交者: GitHub

Emit conversions between native integers and pointers directly (#47708)

上级 4ae6eb35
...@@ -1917,16 +1917,20 @@ private static bool HasSpecialIntPtrConversion(TypeSymbol source, TypeSymbol tar ...@@ -1917,16 +1917,20 @@ private static bool HasSpecialIntPtrConversion(TypeSymbol source, TypeSymbol tar
var s0 = source.StrippedType(); var s0 = source.StrippedType();
var t0 = target.StrippedType(); var t0 = target.StrippedType();
if (s0.SpecialType != SpecialType.System_UIntPtr && TypeSymbol otherType;
s0.SpecialType != SpecialType.System_IntPtr && if (isIntPtrOrUIntPtr(s0))
t0.SpecialType != SpecialType.System_UIntPtr && {
t0.SpecialType != SpecialType.System_IntPtr) otherType = t0;
}
else if (isIntPtrOrUIntPtr(t0))
{
otherType = s0;
}
else
{ {
return false; return false;
} }
TypeSymbol otherType = (s0.SpecialType == SpecialType.System_UIntPtr || s0.SpecialType == SpecialType.System_IntPtr) ? t0 : s0;
if (otherType.IsPointerOrFunctionPointer()) if (otherType.IsPointerOrFunctionPointer())
{ {
return true; return true;
...@@ -1955,6 +1959,9 @@ private static bool HasSpecialIntPtrConversion(TypeSymbol source, TypeSymbol tar ...@@ -1955,6 +1959,9 @@ private static bool HasSpecialIntPtrConversion(TypeSymbol source, TypeSymbol tar
} }
return false; 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) private static bool HasExplicitEnumerationConversion(TypeSymbol source, TypeSymbol destination)
...@@ -3494,20 +3501,7 @@ private static bool HasPointerToIntegerConversion(TypeSymbol source, TypeSymbol ...@@ -3494,20 +3501,7 @@ private static bool HasPointerToIntegerConversion(TypeSymbol source, TypeSymbol
// The spec should state that any pointer type is convertible to // The spec should state that any pointer type is convertible to
// sbyte, byte, ... etc, or any corresponding nullable type. // sbyte, byte, ... etc, or any corresponding nullable type.
switch (destination.StrippedType().SpecialType) return IsIntegerTypeSupportingPointerConversions(destination.StrippedType());
{
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;
} }
private static bool HasIntegerToPointerConversion(TypeSymbol source, TypeSymbol destination) private static bool HasIntegerToPointerConversion(TypeSymbol source, TypeSymbol destination)
...@@ -3521,8 +3515,12 @@ private static bool HasIntegerToPointerConversion(TypeSymbol source, TypeSymbol ...@@ -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*. // 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_SByte:
case SpecialType.System_Byte: case SpecialType.System_Byte:
...@@ -3533,6 +3531,9 @@ private static bool HasIntegerToPointerConversion(TypeSymbol source, TypeSymbol ...@@ -3533,6 +3531,9 @@ private static bool HasIntegerToPointerConversion(TypeSymbol source, TypeSymbol
case SpecialType.System_Int64: case SpecialType.System_Int64:
case SpecialType.System_UInt64: case SpecialType.System_UInt64:
return true; return true;
case SpecialType.System_IntPtr:
case SpecialType.System_UIntPtr:
return type.IsNativeIntegerType;
} }
return false; return false;
......
...@@ -143,8 +143,8 @@ private void EmitConversion(BoundConversion conversion) ...@@ -143,8 +143,8 @@ private void EmitConversion(BoundConversion conversion)
#if DEBUG #if DEBUG
switch (fromPredefTypeKind) switch (fromPredefTypeKind)
{ {
case Microsoft.Cci.PrimitiveTypeCode.IntPtr: case Microsoft.Cci.PrimitiveTypeCode.IntPtr when !fromType.IsNativeIntegerType:
case Microsoft.Cci.PrimitiveTypeCode.UIntPtr: case Microsoft.Cci.PrimitiveTypeCode.UIntPtr when !fromType.IsNativeIntegerType:
case Microsoft.Cci.PrimitiveTypeCode.Pointer: case Microsoft.Cci.PrimitiveTypeCode.Pointer:
case Microsoft.Cci.PrimitiveTypeCode.FunctionPointer: case Microsoft.Cci.PrimitiveTypeCode.FunctionPointer:
Debug.Assert(IsNumeric(toType)); Debug.Assert(IsNumeric(toType));
...@@ -152,8 +152,7 @@ private void EmitConversion(BoundConversion conversion) ...@@ -152,8 +152,7 @@ private void EmitConversion(BoundConversion conversion)
default: default:
Debug.Assert(IsNumeric(fromType)); Debug.Assert(IsNumeric(fromType));
Debug.Assert( Debug.Assert(
toPredefTypeKind == Microsoft.Cci.PrimitiveTypeCode.IntPtr || (toPredefTypeKind == Microsoft.Cci.PrimitiveTypeCode.IntPtr || toPredefTypeKind == Microsoft.Cci.PrimitiveTypeCode.UIntPtr) && !toType.IsNativeIntegerType ||
toPredefTypeKind == Microsoft.Cci.PrimitiveTypeCode.UIntPtr ||
toPredefTypeKind == Microsoft.Cci.PrimitiveTypeCode.Pointer || toPredefTypeKind == Microsoft.Cci.PrimitiveTypeCode.Pointer ||
toPredefTypeKind == Microsoft.Cci.PrimitiveTypeCode.FunctionPointer); toPredefTypeKind == Microsoft.Cci.PrimitiveTypeCode.FunctionPointer);
break; break;
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System; using System;
using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols;
...@@ -6963,16 +6962,8 @@ .maxstack 1 ...@@ -6963,16 +6962,8 @@ .maxstack 1
IL_0006: ret IL_0006: ret
}"); }");
conversions(sourceType: "string", destType: "nint", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "string", destType: "nint", expectedImplicitIL: null, expectedExplicitIL: null);
conversions(sourceType: "void*", destType: "nint", expectedImplicitIL: null, conversions(sourceType: "void*", destType: "nint", expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.i.un"));
// https://github.com/dotnet/roslyn/issues/42457: Investigate whether this conversion (and other conversions(sourceType: "delegate*<void>", destType: "nint", expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.i.un"));
// 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: "bool", destType: "nint", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "bool", destType: "nint", expectedImplicitIL: null, expectedExplicitIL: null);
conversions(sourceType: "char", destType: "nint", expectedImplicitIL: conv("conv.u"), expectedExplicitIL: conv("conv.u")); 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")); conversions(sourceType: "sbyte", destType: "nint", expectedImplicitIL: conv("conv.i"), expectedExplicitIL: conv("conv.i"));
...@@ -7066,12 +7057,35 @@ .maxstack 1 ...@@ -7066,12 +7057,35 @@ .maxstack 1
conversions(sourceType: "string", destType: "nint?", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "string", destType: "nint?", expectedImplicitIL: null, expectedExplicitIL: null);
conversions(sourceType: "void*", destType: "nint?", expectedImplicitIL: null, conversions(sourceType: "void*", destType: "nint?", expectedImplicitIL: null,
@"{ @"{
// Code size 12 (0xc) // Code size 7 (0x7)
.maxstack 1 .maxstack 1
IL_0000: ldarg.0 IL_0000: ldarg.0
IL_0001: call ""System.IntPtr System.IntPtr.op_Explicit(void*)"" IL_0001: newobj ""nint?..ctor(nint)""
IL_0006: newobj ""nint?..ctor(nint)"" IL_0006: ret
IL_000b: 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*<void>", 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: "bool", destType: "nint?", expectedImplicitIL: null, expectedExplicitIL: null);
conversions(sourceType: "char", destType: "nint?", expectedImplicitIL: convToNullableT("conv.u", "nint"), expectedExplicitIL: convToNullableT("conv.u", "nint")); conversions(sourceType: "char", destType: "nint?", expectedImplicitIL: convToNullableT("conv.u", "nint"), expectedExplicitIL: convToNullableT("conv.u", "nint"));
...@@ -7211,14 +7225,8 @@ .maxstack 1 ...@@ -7211,14 +7225,8 @@ .maxstack 1
IL_0006: ret IL_0006: ret
}"); }");
conversions(sourceType: "nint", destType: "string", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "nint", destType: "string", expectedImplicitIL: null, expectedExplicitIL: null);
conversions(sourceType: "nint", destType: "void*", expectedImplicitIL: null, conversions(sourceType: "nint", destType: "void*", expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.u"));
@"{ conversions(sourceType: "nint", destType: "delegate*<void>", expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.u"));
// 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: "bool", expectedImplicitIL: null, expectedExplicitIL: null); 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: "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")); conversions(sourceType: "nint", destType: "sbyte", expectedImplicitIL: null, expectedExplicitIL: conv("conv.i1"), expectedCheckedIL: conv("conv.ovf.i1"));
...@@ -7315,15 +7323,8 @@ .maxstack 1 ...@@ -7315,15 +7323,8 @@ .maxstack 1
IL_0006: ret IL_0006: ret
}"); }");
conversions(sourceType: "nint?", destType: "string", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "nint?", destType: "string", expectedImplicitIL: null, expectedExplicitIL: null);
conversions(sourceType: "nint?", destType: "void*", expectedImplicitIL: null, conversions(sourceType: "nint?", destType: "void*", expectedImplicitIL: null, expectedExplicitIL: null);
@"{ conversions(sourceType: "nint?", destType: "delegate*<void>", expectedImplicitIL: null, expectedExplicitIL: 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: "bool", 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: "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")); conversions(sourceType: "nint?", destType: "sbyte", expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.i1", "nint"), expectedCheckedIL: convFromNullableT("conv.ovf.i1", "nint"));
...@@ -7421,14 +7422,8 @@ .maxstack 1 ...@@ -7421,14 +7422,8 @@ .maxstack 1
IL_0006: ret IL_0006: ret
}"); }");
conversions(sourceType: "string", destType: "nuint", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "string", destType: "nuint", expectedImplicitIL: null, expectedExplicitIL: null);
conversions(sourceType: "void*", destType: "nuint", expectedImplicitIL: null, conversions(sourceType: "void*", destType: "nuint", expectedImplicitIL: null, expectedExplicitIL: convNone);
@"{ conversions(sourceType: "delegate*<void>", destType: "nuint", expectedImplicitIL: null, expectedExplicitIL: convNone);
// 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: "bool", destType: "nuint", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "bool", destType: "nuint", expectedImplicitIL: null, expectedExplicitIL: null);
conversions(sourceType: "char", destType: "nuint", expectedImplicitIL: conv("conv.u"), expectedExplicitIL: conv("conv.u")); 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")); conversions(sourceType: "sbyte", destType: "nuint", expectedImplicitIL: conv("conv.i"), expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.u"));
...@@ -7522,12 +7517,19 @@ .maxstack 1 ...@@ -7522,12 +7517,19 @@ .maxstack 1
conversions(sourceType: "string", destType: "nuint?", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "string", destType: "nuint?", expectedImplicitIL: null, expectedExplicitIL: null);
conversions(sourceType: "void*", destType: "nuint?", expectedImplicitIL: null, conversions(sourceType: "void*", destType: "nuint?", expectedImplicitIL: null,
@"{ @"{
// Code size 12 (0xc) // Code size 7 (0x7)
.maxstack 1 .maxstack 1
IL_0000: ldarg.0 IL_0000: ldarg.0
IL_0001: call ""System.UIntPtr System.UIntPtr.op_Explicit(void*)"" IL_0001: newobj ""nuint?..ctor(nuint)""
IL_0006: newobj ""nuint?..ctor(nuint)"" IL_0006: ret
IL_000b: ret }");
conversions(sourceType: "delegate*<void>", 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: "bool", destType: "nuint?", expectedImplicitIL: null, expectedExplicitIL: null);
conversions(sourceType: "char", destType: "nuint?", expectedImplicitIL: convToNullableT("conv.u", "nuint"), expectedExplicitIL: convToNullableT("conv.u", "nuint")); conversions(sourceType: "char", destType: "nuint?", expectedImplicitIL: convToNullableT("conv.u", "nuint"), expectedExplicitIL: convToNullableT("conv.u", "nuint"));
...@@ -7667,14 +7669,8 @@ .maxstack 1 ...@@ -7667,14 +7669,8 @@ .maxstack 1
IL_0006: ret IL_0006: ret
}"); }");
conversions(sourceType: "nuint", destType: "string", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "nuint", destType: "string", expectedImplicitIL: null, expectedExplicitIL: null);
conversions(sourceType: "nuint", destType: "void*", expectedImplicitIL: null, conversions(sourceType: "nuint", destType: "void*", expectedImplicitIL: null, expectedExplicitIL: convNone);
@"{ conversions(sourceType: "nuint", destType: "delegate*<void>", expectedImplicitIL: null, expectedExplicitIL: convNone);
// 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: "bool", expectedImplicitIL: null, expectedExplicitIL: null); 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: "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")); conversions(sourceType: "nuint", destType: "sbyte", expectedImplicitIL: null, expectedExplicitIL: conv("conv.i1"), expectedCheckedIL: conv("conv.ovf.i1.un"));
...@@ -7769,15 +7765,8 @@ .maxstack 1 ...@@ -7769,15 +7765,8 @@ .maxstack 1
IL_0006: ret IL_0006: ret
}"); }");
conversions(sourceType: "nuint?", destType: "string", expectedImplicitIL: null, expectedExplicitIL: null); conversions(sourceType: "nuint?", destType: "string", expectedImplicitIL: null, expectedExplicitIL: null);
conversions(sourceType: "nuint?", destType: "void*", expectedImplicitIL: null, conversions(sourceType: "nuint?", destType: "void*", expectedImplicitIL: null, expectedExplicitIL: null);
@"{ conversions(sourceType: "nuint?", destType: "delegate*<void>", expectedImplicitIL: null, expectedExplicitIL: 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: "bool", 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: "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")); 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 ...@@ -7883,6 +7872,7 @@ .maxstack 1
}"); }");
conversions(sourceType: "System.IntPtr", destType: "string", expectedImplicitIL: null, expectedExplicitIL: null); 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: "void*", expectedImplicitIL: null, expectedExplicitIL: convAndExplicit("void* System.IntPtr.op_Explicit(System.IntPtr)"));
conversions(sourceType: "System.IntPtr", destType: "delegate*<void>", 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: "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: "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")); 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 ...@@ -8020,6 +8010,7 @@ .maxstack 1
}"); }");
conversions(sourceType: "string", destType: "System.IntPtr", expectedImplicitIL: null, expectedExplicitIL: null); 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: "void*", destType: "System.IntPtr", expectedImplicitIL: null, expectedExplicitIL: explicitAndConv("System.IntPtr System.IntPtr.op_Explicit(void*)"));
conversions(sourceType: "delegate*<void>", 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: "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: "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)")); conversions(sourceType: "sbyte", destType: "System.IntPtr", expectedImplicitIL: null, expectedExplicitIL: explicitAndConv("System.IntPtr System.IntPtr.op_Explicit(int)"));
...@@ -8135,6 +8126,7 @@ .maxstack 1 ...@@ -8135,6 +8126,7 @@ .maxstack 1
}"); }");
conversions(sourceType: "System.UIntPtr", destType: "string", expectedImplicitIL: null, expectedExplicitIL: null); 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: "void*", expectedImplicitIL: null, expectedExplicitIL: convAndExplicit("void* System.UIntPtr.op_Explicit(System.UIntPtr)"));
conversions(sourceType: "System.UIntPtr", destType: "delegate*<void>", 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: "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: "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")); 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 ...@@ -8330,6 +8322,7 @@ .maxstack 1
}"); }");
conversions(sourceType: "string", destType: "System.UIntPtr", expectedImplicitIL: null, expectedExplicitIL: null); 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: "void*", destType: "System.UIntPtr", expectedImplicitIL: null, expectedExplicitIL: explicitAndConv("System.UIntPtr System.UIntPtr.op_Explicit(void*)"));
conversions(sourceType: "delegate*<void>", 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: "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: "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")); 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 ...@@ -8481,7 +8474,7 @@ .maxstack 1
verifier.VerifyIL("Program.Convert", expectedIL); verifier.VerifyIL("Program.Convert", expectedIL);
} }
static bool useUnsafe(string type) => type == "void*"; static bool useUnsafe(string type) => type == "void*" || type == "delegate*<void>";
} }
} }
...@@ -12243,5 +12236,142 @@ static object Execute(Func<object> f) ...@@ -12243,5 +12236,142 @@ static object Execute(Func<object> f)
0 0
{(IntPtr.Size == 4 ? "System.OverflowException" : "0")}"); {(IntPtr.Size == 4 ? "System.OverflowException" : "0")}");
} }
[WorkItem(44810, "https://github.com/dotnet/roslyn/issues/44810")]
[Theory]
[InlineData("void*")]
[InlineData("byte*")]
[InlineData("delegate*<void>")]
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<object> 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
}");
}
} }
} }
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Reflection.Metadata; using System.Reflection.Metadata;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities; using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CodeGen namespace Microsoft.CodeAnalysis.CodeGen
...@@ -151,6 +150,11 @@ public void EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode fromPredefType ...@@ -151,6 +150,11 @@ public void EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode fromPredefType
// Don't want to sign extend if this is a widening conversion. // Don't want to sign extend if this is a widening conversion.
this.EmitOpCode(ILOpCode.Conv_u); // potentially widening, so not NOP this.EmitOpCode(ILOpCode.Conv_u); // potentially widening, so not NOP
break; break;
case Microsoft.Cci.PrimitiveTypeCode.Pointer:
case Microsoft.Cci.PrimitiveTypeCode.FunctionPointer:
if (@checked)
goto default;
break; // NOP
default: default:
if (@checked) if (@checked)
this.EmitOpCode(fromUnsigned ? ILOpCode.Conv_ovf_i_un : ILOpCode.Conv_ovf_i); this.EmitOpCode(fromUnsigned ? ILOpCode.Conv_ovf_i_un : ILOpCode.Conv_ovf_i);
...@@ -164,6 +168,8 @@ public void EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode fromPredefType ...@@ -164,6 +168,8 @@ public void EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode fromPredefType
switch (fromPredefTypeKind) switch (fromPredefTypeKind)
{ {
case Microsoft.Cci.PrimitiveTypeCode.UIntPtr: case Microsoft.Cci.PrimitiveTypeCode.UIntPtr:
case Microsoft.Cci.PrimitiveTypeCode.Pointer:
case Microsoft.Cci.PrimitiveTypeCode.FunctionPointer:
break; // NOP break; // NOP
case Microsoft.Cci.PrimitiveTypeCode.UInt8: case Microsoft.Cci.PrimitiveTypeCode.UInt8:
case Microsoft.Cci.PrimitiveTypeCode.UInt16: case Microsoft.Cci.PrimitiveTypeCode.UInt16:
...@@ -306,6 +312,11 @@ public void EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode fromPredefType ...@@ -306,6 +312,11 @@ public void EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode fromPredefType
case Microsoft.Cci.PrimitiveTypeCode.Int64: case Microsoft.Cci.PrimitiveTypeCode.Int64:
this.EmitOpCode(ILOpCode.Conv_ovf_u); this.EmitOpCode(ILOpCode.Conv_ovf_u);
break; break;
case Microsoft.Cci.PrimitiveTypeCode.IntPtr:
this.EmitOpCode(ILOpCode.Conv_ovf_u);
break;
case Microsoft.Cci.PrimitiveTypeCode.UIntPtr:
break; // NOP
default: default:
throw ExceptionUtilities.UnexpectedValue(fromPredefTypeKind); throw ExceptionUtilities.UnexpectedValue(fromPredefTypeKind);
} }
...@@ -328,6 +339,9 @@ public void EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode fromPredefType ...@@ -328,6 +339,9 @@ public void EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode fromPredefType
// rather than conv_u, to sign-extend the value. // rather than conv_u, to sign-extend the value.
this.EmitOpCode(ILOpCode.Conv_i); this.EmitOpCode(ILOpCode.Conv_i);
break; break;
case Microsoft.Cci.PrimitiveTypeCode.IntPtr:
case Microsoft.Cci.PrimitiveTypeCode.UIntPtr:
break; // NOP
default: default:
throw ExceptionUtilities.UnexpectedValue(fromPredefTypeKind); throw ExceptionUtilities.UnexpectedValue(fromPredefTypeKind);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册