File: CodeGen\UnsafeTests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Emit\Microsoft.CodeAnalysis.CSharp.Emit.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Emit.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#nullable disable
 
using System;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen
{
    public class UnsafeTests : EmitMetadataTestBase
    {
        #region AddressOf tests
 
        [Fact]
        public void AddressOfLocal_Unused()
        {
            var text = @"
unsafe class C
{
    void M()
    {
        int x;
        int* p = &x;
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Passes);
            compVerifier.VerifyIL("C.M", @"
{
  // Code size        4 (0x4)
  .maxstack  1
  .locals init (int V_0) //x
  IL_0000:  ldloca.s   V_0
  IL_0002:  pop
  IL_0003:  ret
}
");
        }
 
        [Fact]
        public void AddressOfLocal_Used()
        {
            var text = @"
unsafe class C
{
    void M(int* param)
    {
        int x;
        int* p = &x;
        M(p);
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails);
            compVerifier.VerifyIL("C.M", @"
{
  // Code size       12 (0xc)
  .maxstack  2
  .locals init (int V_0, //x
  int* V_1) //p
  IL_0000:  ldloca.s   V_0
  IL_0002:  conv.u
  IL_0003:  stloc.1
  IL_0004:  ldarg.0
  IL_0005:  ldloc.1
  IL_0006:  call       ""void C.M(int*)""
  IL_000b:  ret
}
");
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67330")]
        public void Invocation_Pointer()
        {
            var text = @"
class C
{
    void M(int* param)
    {
        M(param);
    }
}
";
            var comp = CreateCompilation(text, options: TestOptions.UnsafeDebugDll);
            comp.VerifyDiagnostics(
                // (4,12): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //     void M(int* param)
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(4, 12),
                // (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         M(param);
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "M(param)").WithLocation(6, 9),
                // (6,11): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         M(param);
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "param").WithLocation(6, 11)
                );
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67330")]
        public void Invocation_PointerArray()
        {
            var text = @"
class C
{
    void M(int*[] param)
    {
        M(param);
    }
}
";
            var comp = CreateCompilation(text, options: TestOptions.UnsafeDebugDll);
            comp.VerifyDiagnostics(
                // (4,12): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //     void M(int*[] param)
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(4, 12),
                // (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         M(param);
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "M(param)").WithLocation(6, 9),
                // (6,11): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         M(param);
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "param").WithLocation(6, 11)
                );
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67330")]
        public void Invocation_PointerArray_Nested()
        {
            var text = @"
class C<T>
{
    void M(C<int*[]>[] param)
    {
        M(param);
    }
}
";
            var comp = CreateCompilation(text, options: TestOptions.UnsafeDebugDll);
            comp.VerifyDiagnostics(
                // (4,14): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //     void M(C<int*[]>[] param)
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(4, 14),
                // (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         M(param);
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "M(param)").WithLocation(6, 9),
                // (6,11): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         M(param);
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "param").WithLocation(6, 11)
                );
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67330")]
        public void ClassCreation_Pointer()
        {
            var text = @"
class C
{
    C(int* param)
    {
        new C(param);
    }
}
";
            var comp = CreateCompilation(text, options: TestOptions.UnsafeDebugDll);
            comp.VerifyDiagnostics(
                // (4,7): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //     C(int* param)
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(4, 7),
                // (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         new C(param);
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "new C(param)").WithLocation(6, 9),
                // (6,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         new C(param);
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "param").WithLocation(6, 15)
                );
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67330")]
        public void ClassCreation_PointerArray()
        {
            var text = @"
class C
{
    C(int*[] param)
    {
        new C(param);
    }
}
";
            var comp = CreateCompilation(text, options: TestOptions.UnsafeDebugDll);
            comp.VerifyDiagnostics(
                // (4,7): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //     C(int*[] param)
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(4, 7),
                // (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         new C(param);
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "new C(param)").WithLocation(6, 9),
                // (6,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         new C(param);
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "param").WithLocation(6, 15)
                );
        }
 
        [Fact]
        public void AddressOfParameter_Unused()
        {
            var text = @"
unsafe class C
{
    void M(int x)
    {
        int* p = &x;
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Passes);
            compVerifier.VerifyIL("C.M", @"
{
  // Code size        4 (0x4)
  .maxstack  1
  IL_0000:  ldarga.s   V_1
  IL_0002:  pop
  IL_0003:  ret
}
");
        }
 
        [Fact]
        public void AddressOfParameter_Used()
        {
            var text = @"
unsafe class C
{
    void M(int x, int* param)
    {
        int* p = &x;
        M(x, p);
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails);
            compVerifier.VerifyIL("C.M", @"
{
  // Code size       13 (0xd)
  .maxstack  3
  .locals init (int* V_0) //p
  IL_0000:  ldarga.s   V_1
  IL_0002:  conv.u
  IL_0003:  stloc.0
  IL_0004:  ldarg.0
  IL_0005:  ldarg.1
  IL_0006:  ldloc.0
  IL_0007:  call       ""void C.M(int, int*)""
  IL_000c:  ret
}
");
        }
 
        [Fact]
        public void AddressOfStructField()
        {
            var text = @"
unsafe class C
{
    void M()
    {
        S1 s;
        S1* p1 = &s;
        S2* p2 = &s.s;
        int* p3 = &s.s.x;
 
        Goo(s, p1, p2, p3);
    }
 
    void Goo(S1 s, S1* p1, S2* p2, int* p3) { }
}
 
struct S1
{
    public S2 s;
}
 
struct S2
{
    public int x;
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails);
            compVerifier.VerifyIL("C.M", @"
{
  // Code size       38 (0x26)
  .maxstack  5
  .locals init (S1 V_0, //s
  S1* V_1, //p1
  S2* V_2, //p2
  int* V_3) //p3
  IL_0000:  ldloca.s   V_0
  IL_0002:  conv.u
  IL_0003:  stloc.1
  IL_0004:  ldloca.s   V_0
  IL_0006:  ldflda     ""S2 S1.s""
  IL_000b:  conv.u
  IL_000c:  stloc.2
  IL_000d:  ldloca.s   V_0
  IL_000f:  ldflda     ""S2 S1.s""
  IL_0014:  ldflda     ""int S2.x""
  IL_0019:  conv.u
  IL_001a:  stloc.3
  IL_001b:  ldarg.0
  IL_001c:  ldloc.0
  IL_001d:  ldloc.1
  IL_001e:  ldloc.2
  IL_001f:  ldloc.3
  IL_0020:  call       ""void C.Goo(S1, S1*, S2*, int*)""
  IL_0025:  ret
}
");
        }
 
        [Fact]
        public void AddressOfSuppressOptimization()
        {
            var text = @"
unsafe class C
{
    static void M()
    {
        int x = 123;
        Goo(&x); // should not optimize into 'Goo(&123)'
    }
 
    static void Goo(int* p) { }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails);
            compVerifier.VerifyIL("C.M", @"
{
  // Code size       12 (0xc)
  .maxstack  1
  .locals init (int V_0) //x
  IL_0000:  ldc.i4.s   123
  IL_0002:  stloc.0
  IL_0003:  ldloca.s   V_0
  IL_0005:  conv.u
  IL_0006:  call       ""void C.Goo(int*)""
  IL_000b:  ret
}
");
        }
 
        #endregion AddressOf tests
 
        #region Dereference tests
 
        [Fact]
        public void DereferenceLocal()
        {
            var text = @"
unsafe class C
{
    static void Main()
    {
        int x = 123;
        int* p = &x;
        System.Console.WriteLine(*p);
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "123", verify: Verification.Fails);
 
            // NOTE: p is optimized away, but & and * aren't.
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       13 (0xd)
  .maxstack  1
  .locals init (int V_0) //x
  IL_0000:  ldc.i4.s   123
  IL_0002:  stloc.0
  IL_0003:  ldloca.s   V_0
  IL_0005:  conv.u
  IL_0006:  ldind.i4
  IL_0007:  call       ""void System.Console.WriteLine(int)""
  IL_000c:  ret
}
");
        }
 
        [Fact]
        public void DereferenceParameter()
        {
            var text = @"
unsafe class C
{
    static void Main()
    {
        long x = 456;
        System.Console.WriteLine(Dereference(&x));
    }
 
    static long Dereference(long* p)
    {
        return *p;
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "456", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Dereference", @"
{
  // Code size        3 (0x3)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  ldind.i8
  IL_0002:  ret
}
");
        }
 
        [Fact]
        public void DereferenceWrite()
        {
            var text = @"
unsafe class C
{
    static void Main()
    {
        int x = 1;
        int* p = &x;
        *p = 2;
        System.Console.WriteLine(x);
    }
}
";
            var compVerifierOptimized = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "2", verify: Verification.Fails);
 
            // NOTE: p is optimized away, but & and * aren't.
            compVerifierOptimized.VerifyIL("C.Main", @"
{
  // Code size       14 (0xe)
  .maxstack  2
  .locals init (int V_0) //x
  IL_0000:  ldc.i4.1
  IL_0001:  stloc.0
  IL_0002:  ldloca.s   V_0
  IL_0004:  conv.u
  IL_0005:  ldc.i4.2
  IL_0006:  stind.i4
  IL_0007:  ldloc.0
  IL_0008:  call       ""void System.Console.WriteLine(int)""
  IL_000d:  ret
}
");
            var compVerifierUnoptimized = CompileAndVerify(text, options: TestOptions.UnsafeDebugExe, expectedOutput: "2", verify: Verification.Fails);
 
            compVerifierUnoptimized.VerifyIL("C.Main", @"
{
  // Code size       18 (0x12)
  .maxstack  2
  .locals init (int V_0, //x
  int* V_1) //p
  IL_0000:  nop
  IL_0001:  ldc.i4.1
  IL_0002:  stloc.0
  IL_0003:  ldloca.s   V_0
  IL_0005:  conv.u
  IL_0006:  stloc.1
  IL_0007:  ldloc.1
  IL_0008:  ldc.i4.2
  IL_0009:  stind.i4
  IL_000a:  ldloc.0
  IL_000b:  call       ""void System.Console.WriteLine(int)""
  IL_0010:  nop
  IL_0011:  ret
}
");
        }
 
        [Fact]
        public void DereferenceStruct()
        {
            var text = @"
unsafe struct S
{
    S* p;
    byte x;
 
    static void Main()
    {
        S s;
        S* sp = &s;
        (*sp).p = sp;
        (*sp).x = 1;
        System.Console.WriteLine((*(s.p)).x);
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "1", verify: Verification.Fails);
 
            compVerifier.VerifyIL("S.Main", @"
{
  // Code size       35 (0x23)
  .maxstack  2
  .locals init (S V_0, //s
  S* V_1) //sp
  IL_0000:  ldloca.s   V_0
  IL_0002:  conv.u
  IL_0003:  stloc.1
  IL_0004:  ldloc.1
  IL_0005:  ldloc.1
  IL_0006:  stfld      ""S* S.p""
  IL_000b:  ldloc.1
  IL_000c:  ldc.i4.1
  IL_000d:  stfld      ""byte S.x""
  IL_0012:  ldloc.0
  IL_0013:  ldfld      ""S* S.p""
  IL_0018:  ldfld      ""byte S.x""
  IL_001d:  call       ""void System.Console.WriteLine(int)""
  IL_0022:  ret
}
");
        }
 
        [Fact]
        public void DereferenceSwap()
        {
            var text = @"
using System;
 
unsafe class C
{
    static void Main()
    {
        byte b1 = 2;
        byte b2 = 7;
 
        Console.WriteLine(""Before: {0} {1}"", b1, b2);
        Swap(&b1, &b2);
        Console.WriteLine(""After: {0} {1}"", b1, b2);
    }
 
    static void Swap(byte* p1, byte* p2)
    {
        byte tmp = *p1;
        *p1 = *p2;
        *p2 = tmp;
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"Before: 2 7
After: 7 2", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Swap", @"
{
  // Code size       11 (0xb)
  .maxstack  2
  .locals init (byte V_0) //tmp
  IL_0000:  ldarg.0
  IL_0001:  ldind.u1
  IL_0002:  stloc.0
  IL_0003:  ldarg.0
  IL_0004:  ldarg.1
  IL_0005:  ldind.u1
  IL_0006:  stind.i1
  IL_0007:  ldarg.1
  IL_0008:  ldloc.0
  IL_0009:  stind.i1
  IL_000a:  ret
}
");
        }
 
        [Fact]
        public void DereferenceIsLValue1()
        {
            var text = @"
using System;
 
unsafe class C
{
    static void Main()
    {
        char c = 'a';
        char* p = &c;
 
        Console.Write(c);
        Incr(ref *p);
        Console.Write(c);
    }
 
    static void Incr(ref char c)
    {
        c++;
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"ab", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       24 (0x18)
  .maxstack  2
  .locals init (char V_0) //c
  IL_0000:  ldc.i4.s   97
  IL_0002:  stloc.0
  IL_0003:  ldloca.s   V_0
  IL_0005:  conv.u
  IL_0006:  ldloc.0
  IL_0007:  call       ""void System.Console.Write(char)""
  IL_000c:  call       ""void C.Incr(ref char)""
  IL_0011:  ldloc.0
  IL_0012:  call       ""void System.Console.Write(char)""
  IL_0017:  ret
}
");
        }
 
        [Fact]
        public void DereferenceIsLValue2()
        {
            var text = @"
using System;
 
unsafe struct S
{
 
    int x;
 
    static void Main()
    {
        S s;
        s.x = 1;
        S* p = &s;
        Console.Write(s.x);
        (*p).Mutate();
        Console.Write(s.x);
    }
 
    void Mutate()
    {
        x++;
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"12", verify: Verification.Fails);
 
            compVerifier.VerifyIL("S.Main", @"
{
  // Code size       39 (0x27)
  .maxstack  2
  .locals init (S V_0) //s
  IL_0000:  ldloca.s   V_0
  IL_0002:  ldc.i4.1
  IL_0003:  stfld      ""int S.x""
  IL_0008:  ldloca.s   V_0
  IL_000a:  conv.u
  IL_000b:  ldloc.0
  IL_000c:  ldfld      ""int S.x""
  IL_0011:  call       ""void System.Console.Write(int)""
  IL_0016:  call       ""void S.Mutate()""
  IL_001b:  ldloc.0
  IL_001c:  ldfld      ""int S.x""
  IL_0021:  call       ""void System.Console.Write(int)""
  IL_0026:  ret
}
");
        }
 
        #endregion Dereference tests
 
        #region Pointer member access tests
 
        [Fact]
        public void PointerMemberAccessRead()
        {
            var text = @"
using System;
 
unsafe struct S
{
    int x;
    
    static void Main()
    {
        S s;
        s.x = 3;
        S* p = &s;
        Console.Write(p->x);
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"3", verify: Verification.Fails);
 
            compVerifier.VerifyIL("S.Main", @"
{
  // Code size       22 (0x16)
  .maxstack  2
  .locals init (S V_0) //s
  IL_0000:  ldloca.s   V_0
  IL_0002:  ldc.i4.3
  IL_0003:  stfld      ""int S.x""
  IL_0008:  ldloca.s   V_0
  IL_000a:  conv.u
  IL_000b:  ldfld      ""int S.x""
  IL_0010:  call       ""void System.Console.Write(int)""
  IL_0015:  ret
}
");
 
            compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"3", verify: Verification.Fails);
 
            compVerifier.VerifyIL("S.Main", @"
{
  // Code size       22 (0x16)
  .maxstack  2
  .locals init (S V_0) //s
  IL_0000:  ldloca.s   V_0
  IL_0002:  ldc.i4.3
  IL_0003:  stfld      ""int S.x""
  IL_0008:  ldloca.s   V_0
  IL_000a:  conv.u
  IL_000b:  ldfld      ""int S.x""
  IL_0010:  call       ""void System.Console.Write(int)""
  IL_0015:  ret
}
");
        }
 
        [Fact]
        public void PointerMemberAccessWrite()
        {
            var text = @"
using System;
 
unsafe struct S
{
    int x;
    
    static void Main()
    {
        S s;
        s.x = 3;
        S* p = &s;
        Console.Write(s.x);
        p->x = 4;
        Console.Write(s.x);
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"34", verify: Verification.Fails);
 
            compVerifier.VerifyIL("S.Main", @"
{
  // Code size       40 (0x28)
  .maxstack  2
  .locals init (S V_0) //s
  IL_0000:  ldloca.s   V_0
  IL_0002:  ldc.i4.3
  IL_0003:  stfld      ""int S.x""
  IL_0008:  ldloca.s   V_0
  IL_000a:  conv.u
  IL_000b:  ldloc.0
  IL_000c:  ldfld      ""int S.x""
  IL_0011:  call       ""void System.Console.Write(int)""
  IL_0016:  ldc.i4.4
  IL_0017:  stfld      ""int S.x""
  IL_001c:  ldloc.0
  IL_001d:  ldfld      ""int S.x""
  IL_0022:  call       ""void System.Console.Write(int)""
  IL_0027:  ret
}
");
 
            compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"34", verify: Verification.Fails);
 
            compVerifier.VerifyIL("S.Main", @"
{
  // Code size       40 (0x28)
  .maxstack  2
  .locals init (S V_0) //s
  IL_0000:  ldloca.s   V_0
  IL_0002:  ldc.i4.3
  IL_0003:  stfld      ""int S.x""
  IL_0008:  ldloca.s   V_0
  IL_000a:  conv.u
  IL_000b:  ldloc.0
  IL_000c:  ldfld      ""int S.x""
  IL_0011:  call       ""void System.Console.Write(int)""
  IL_0016:  ldc.i4.4
  IL_0017:  stfld      ""int S.x""
  IL_001c:  ldloc.0
  IL_001d:  ldfld      ""int S.x""
  IL_0022:  call       ""void System.Console.Write(int)""
  IL_0027:  ret
}
");
        }
 
        [Fact]
        public void PointerMemberAccessInvoke()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        S s;
        S* p = &s;
        p->M();
        p->M(1);
        p->M(1, 2);
    }
 
    void M() { Console.Write(1); }
    void M(int x) { Console.Write(2); }
}
 
static class Extensions
{
    public static void M(this S s, int x, int y) { Console.Write(3); }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"123", verify: Verification.Fails);
 
            compVerifier.VerifyIL("S.Main", @"
{
  // Code size       29 (0x1d)
  .maxstack  3
  .locals init (S V_0) //s
  IL_0000:  ldloca.s   V_0
  IL_0002:  conv.u
  IL_0003:  dup
  IL_0004:  call       ""void S.M()""
  IL_0009:  dup
  IL_000a:  ldc.i4.1
  IL_000b:  call       ""void S.M(int)""
  IL_0010:  ldobj      ""S""
  IL_0015:  ldc.i4.1
  IL_0016:  ldc.i4.2
  IL_0017:  call       ""void Extensions.M(S, int, int)""
  IL_001c:  ret
}
");
 
            compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"123", verify: Verification.Fails);
 
            compVerifier.VerifyIL("S.Main", @"
{
  // Code size       29 (0x1d)
  .maxstack  3
  .locals init (S V_0) //s
  IL_0000:  ldloca.s   V_0
  IL_0002:  conv.u
  IL_0003:  dup
  IL_0004:  call       ""void S.M()""
  IL_0009:  dup
  IL_000a:  ldc.i4.1
  IL_000b:  call       ""void S.M(int)""
  IL_0010:  ldobj      ""S""
  IL_0015:  ldc.i4.1
  IL_0016:  ldc.i4.2
  IL_0017:  call       ""void Extensions.M(S, int, int)""
  IL_001c:  ret
}
");
        }
 
        [Fact]
        public void PointerMemberAccessInvoke001()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        S s;
        S* p = &s;
        Test(ref p);
    }
 
    static void Test(ref S* p)
    {
        p->M();
        p->M(1);
        p->M(1, 2);
    }
 
    void M() { Console.Write(1); }
    void M(int x) { Console.Write(2); }
}
 
static class Extensions
{
    public static void M(this S s, int x, int y) { Console.Write(3); }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"123", verify: Verification.Fails);
 
            compVerifier.VerifyIL("S.Test(ref S*)", @"
{
  // Code size       30 (0x1e)
  .maxstack  3
  IL_0000:  ldarg.0
  IL_0001:  ldind.i
  IL_0002:  call       ""void S.M()""
  IL_0007:  ldarg.0
  IL_0008:  ldind.i
  IL_0009:  ldc.i4.1
  IL_000a:  call       ""void S.M(int)""
  IL_000f:  ldarg.0
  IL_0010:  ldind.i
  IL_0011:  ldobj      ""S""
  IL_0016:  ldc.i4.1
  IL_0017:  ldc.i4.2
  IL_0018:  call       ""void Extensions.M(S, int, int)""
  IL_001d:  ret
}
");
 
            compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"123", verify: Verification.Fails);
 
            compVerifier.VerifyIL("S.Test(ref S*)", @"
{
  // Code size       30 (0x1e)
  .maxstack  3
  IL_0000:  ldarg.0
  IL_0001:  ldind.i
  IL_0002:  call       ""void S.M()""
  IL_0007:  ldarg.0
  IL_0008:  ldind.i
  IL_0009:  ldc.i4.1
  IL_000a:  call       ""void S.M(int)""
  IL_000f:  ldarg.0
  IL_0010:  ldind.i
  IL_0011:  ldobj      ""S""
  IL_0016:  ldc.i4.1
  IL_0017:  ldc.i4.2
  IL_0018:  call       ""void Extensions.M(S, int, int)""
  IL_001d:  ret
}
");
        }
 
        [Fact]
        public void PointerMemberAccessMutate()
        {
            var text = @"
using System;
 
unsafe struct S
{
    int x;
    
    static void Main()
    {
        S s;
        s.x = 3;
        S* p = &s;
        Console.Write((p->x)++);
        Console.Write((p->x)++);
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"34", verify: Verification.Fails);
 
            compVerifier.VerifyIL("S.Main", @"
{
  // Code size       49 (0x31)
  .maxstack  4
  .locals init (S V_0, //s
                int V_1)
  IL_0000:  ldloca.s   V_0
  IL_0002:  ldc.i4.3
  IL_0003:  stfld      ""int S.x""
  IL_0008:  ldloca.s   V_0
  IL_000a:  conv.u
  IL_000b:  dup
  IL_000c:  ldflda     ""int S.x""
  IL_0011:  dup
  IL_0012:  ldind.i4
  IL_0013:  stloc.1
  IL_0014:  ldloc.1
  IL_0015:  ldc.i4.1
  IL_0016:  add
  IL_0017:  stind.i4
  IL_0018:  ldloc.1
  IL_0019:  call       ""void System.Console.Write(int)""
  IL_001e:  ldflda     ""int S.x""
  IL_0023:  dup
  IL_0024:  ldind.i4
  IL_0025:  stloc.1
  IL_0026:  ldloc.1
  IL_0027:  ldc.i4.1
  IL_0028:  add
  IL_0029:  stind.i4
  IL_002a:  ldloc.1
  IL_002b:  call       ""void System.Console.Write(int)""
  IL_0030:  ret
}
");
 
            compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"34", verify: Verification.Fails);
 
            compVerifier.VerifyIL("S.Main", @"
{
  // Code size       49 (0x31)
  .maxstack  4
  .locals init (S V_0, //s
  int V_1)
  IL_0000:  ldloca.s   V_0
  IL_0002:  ldc.i4.3
  IL_0003:  stfld      ""int S.x""
  IL_0008:  ldloca.s   V_0
  IL_000a:  conv.u
  IL_000b:  dup
  IL_000c:  ldflda     ""int S.x""
  IL_0011:  dup
  IL_0012:  ldind.i4
  IL_0013:  stloc.1
  IL_0014:  ldloc.1
  IL_0015:  ldc.i4.1
  IL_0016:  add
  IL_0017:  stind.i4
  IL_0018:  ldloc.1
  IL_0019:  call       ""void System.Console.Write(int)""
  IL_001e:  ldflda     ""int S.x""
  IL_0023:  dup
  IL_0024:  ldind.i4
  IL_0025:  stloc.1
  IL_0026:  ldloc.1
  IL_0027:  ldc.i4.1
  IL_0028:  add
  IL_0029:  stind.i4
  IL_002a:  ldloc.1
  IL_002b:  call       ""void System.Console.Write(int)""
  IL_0030:  ret
}
");
        }
 
        #endregion Pointer member access tests
 
        #region Pointer element access tests
 
        [Fact]
        public void PointerElementAccessCheckedAndUnchecked()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        S s = new S();
        S* p = &s;
        int i = (int)p;
        uint ui = (uint)p;
        long l = (long)p;
        ulong ul = (ulong)p;
        checked
        {
            s = p[i];
            s = p[ui];
            s = p[l];
            s = p[ul];
        }
        unchecked
        {
            s = p[i];
            s = p[ui];
            s = p[l];
            s = p[ul];
        }
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails);
 
            // The conversions differ from dev10 in the same way as for numeric addition.
            // Note that, unlike for numeric addition, the add operation is never checked.
            compVerifier.VerifyIL("S.Main", @"
{
  // Code size      170 (0xaa)
  .maxstack  4
  .locals init (S V_0, //s
                int V_1, //i
                uint V_2, //ui
                long V_3, //l
                ulong V_4) //ul
  IL_0000:  ldloca.s   V_0
  IL_0002:  initobj    ""S""
  IL_0008:  ldloca.s   V_0
  IL_000a:  conv.u
  IL_000b:  dup
  IL_000c:  conv.i4
  IL_000d:  stloc.1
  IL_000e:  dup
  IL_000f:  conv.u4
  IL_0010:  stloc.2
  IL_0011:  dup
  IL_0012:  conv.u8
  IL_0013:  stloc.3
  IL_0014:  dup
  IL_0015:  conv.u8
  IL_0016:  stloc.s    V_4
  IL_0018:  dup
  IL_0019:  ldloc.1
  IL_001a:  conv.i
  IL_001b:  sizeof     ""S""
  IL_0021:  mul.ovf
  IL_0022:  add
  IL_0023:  ldobj      ""S""
  IL_0028:  stloc.0
  IL_0029:  dup
  IL_002a:  ldloc.2
  IL_002b:  conv.u8
  IL_002c:  sizeof     ""S""
  IL_0032:  conv.i8
  IL_0033:  mul.ovf
  IL_0034:  conv.i
  IL_0035:  add
  IL_0036:  ldobj      ""S""
  IL_003b:  stloc.0
  IL_003c:  dup
  IL_003d:  ldloc.3
  IL_003e:  sizeof     ""S""
  IL_0044:  conv.i8
  IL_0045:  mul.ovf
  IL_0046:  conv.i
  IL_0047:  add
  IL_0048:  ldobj      ""S""
  IL_004d:  stloc.0
  IL_004e:  dup
  IL_004f:  ldloc.s    V_4
  IL_0051:  sizeof     ""S""
  IL_0057:  conv.ovf.u8
  IL_0058:  mul.ovf.un
  IL_0059:  conv.u
  IL_005a:  add
  IL_005b:  ldobj      ""S""
  IL_0060:  stloc.0
  IL_0061:  dup
  IL_0062:  ldloc.1
  IL_0063:  conv.i
  IL_0064:  sizeof     ""S""
  IL_006a:  mul
  IL_006b:  add
  IL_006c:  ldobj      ""S""
  IL_0071:  stloc.0
  IL_0072:  dup
  IL_0073:  ldloc.2
  IL_0074:  conv.u8
  IL_0075:  sizeof     ""S""
  IL_007b:  conv.i8
  IL_007c:  mul
  IL_007d:  conv.i
  IL_007e:  add
  IL_007f:  ldobj      ""S""
  IL_0084:  stloc.0
  IL_0085:  dup
  IL_0086:  ldloc.3
  IL_0087:  sizeof     ""S""
  IL_008d:  conv.i8
  IL_008e:  mul
  IL_008f:  conv.i
  IL_0090:  add
  IL_0091:  ldobj      ""S""
  IL_0096:  stloc.0
  IL_0097:  ldloc.s    V_4
  IL_0099:  sizeof     ""S""
  IL_009f:  conv.i8
  IL_00a0:  mul
  IL_00a1:  conv.u
  IL_00a2:  add
  IL_00a3:  ldobj      ""S""
  IL_00a8:  stloc.0
  IL_00a9:  ret
}
");
        }
 
        [Fact]
        public void PointerElementAccessWrite()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        int* p = null;
        p[1] = 2;
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails);
 
            compVerifier.VerifyIL("S.Main", @"
{
  // Code size        9 (0x9)
  .maxstack  2
  .locals init (int* V_0) //p
  IL_0000:  ldc.i4.0
  IL_0001:  conv.u
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  ldc.i4.4
  IL_0005:  add
  IL_0006:  ldc.i4.2
  IL_0007:  stind.i4
  IL_0008:  ret
}
");
        }
 
        [Fact]
        public void PointerElementAccessMutate()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        int[] array = new int[3];
        fixed (int* p = array)
        {
            p[1] += ++p[0];
            p[2] -= p[1]--;
        }
 
        foreach (int element in array)
        {
            Console.WriteLine(element);
        }
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"
1
0
-1", verify: Verification.Fails);
        }
 
        [Fact]
        public void PointerElementAccessNested()
        {
            var text = @"
using System;
 
unsafe class C
{
    static void Main()
    {
        fixed (int* q = new int[3])
        {
            q[0] = 2;
            q[1] = 0;
            q[2] = 1;
 
            Console.Write(q[q[q[q[q[q[*q]]]]]]);
            Console.Write(q[q[q[q[q[q[q[*q]]]]]]]);
            Console.Write(q[q[q[q[q[q[q[q[*q]]]]]]]]);
        }
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "210", verify: Verification.Fails);
        }
 
        [Fact]
        public void PointerElementAccessZero()
        {
            var text = @"
using System;
 
unsafe class C
{
    static void Main()
    {
        int x = 1;
        int* p = &x;
        Console.WriteLine(p[0]);
    }
}
";
            // NOTE: no pointer arithmetic - just dereference p.
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "1", verify: Verification.Fails).VerifyIL("C.Main", @"
{
  // Code size       12 (0xc)
  .maxstack  1
  .locals init (int V_0) //x
  IL_0000:  ldc.i4.1
  IL_0001:  stloc.0
  IL_0002:  ldloca.s   V_0
  IL_0004:  conv.u
  IL_0005:  ldind.i4
  IL_0006:  call       ""void System.Console.WriteLine(int)""
  IL_000b:  ret
}
");
        }
 
        #endregion Pointer element access tests
 
        #region Fixed statement tests
 
        [Fact]
        public void FixedStatementField()
        {
            var text = @"
using System;
 
unsafe class C
{
    int x;
    
    static void Main()
    {
        C c = new C();
        fixed (int* p = &c.x)
        {
            *p = 1;
        }
        Console.WriteLine(c.x);
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"1", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       30 (0x1e)
  .maxstack  3
  .locals init (pinned int& V_0)
  IL_0000:  newobj     ""C..ctor()""
  IL_0005:  dup
  IL_0006:  ldflda     ""int C.x""
  IL_000b:  stloc.0
  IL_000c:  ldloc.0
  IL_000d:  conv.u
  IL_000e:  ldc.i4.1
  IL_000f:  stind.i4
  IL_0010:  ldc.i4.0
  IL_0011:  conv.u
  IL_0012:  stloc.0
  IL_0013:  ldfld      ""int C.x""
  IL_0018:  call       ""void System.Console.WriteLine(int)""
  IL_001d:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementThis()
        {
            var text = @"
public class Program
{
    public static void Main()
    {
        S1 s = default;
        s.Test();
    }
 
    unsafe readonly struct S1
    {
        readonly int x;
 
        public void Test()
        {
            fixed(void* p = &this)
            {
                *(int*)p = 123;
            }
 
            ref readonly S1 r = ref this;
 
            fixed (S1* p = &r)
            {
                System.Console.WriteLine(p->x);
            }
        }
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"123", verify: Verification.Fails);
 
            compVerifier.VerifyIL("Program.S1.Test()", @"
{
  // Code size       30 (0x1e)
  .maxstack  2
  .locals init (void* V_0, //p
                pinned Program.S1& V_1)
  IL_0000:  ldarg.0
  IL_0001:  stloc.1
  IL_0002:  ldloc.1
  IL_0003:  conv.u
  IL_0004:  stloc.0
  IL_0005:  ldloc.0
  IL_0006:  ldc.i4.s   123
  IL_0008:  stind.i4
  IL_0009:  ldc.i4.0
  IL_000a:  conv.u
  IL_000b:  stloc.1
  IL_000c:  ldarg.0
  IL_000d:  stloc.1
  IL_000e:  ldloc.1
  IL_000f:  conv.u
  IL_0010:  ldfld      ""int Program.S1.x""
  IL_0015:  call       ""void System.Console.WriteLine(int)""
  IL_001a:  ldc.i4.0
  IL_001b:  conv.u
  IL_001c:  stloc.1
  IL_001d:  ret
}
");
        }
 
        [WorkItem(22306, "https://github.com/dotnet/roslyn/issues/22306")]
        [Fact]
        public void FixedStatementMultipleFields()
        {
            var text = @"
using System;
 
unsafe class C
{
    int x;
    readonly int y;
    
    static void Main()
    {
        C c = new C();
        fixed (int* p = &c.x, q = &c.y)
        {
            *p = 1;
            *q = 2;
        }
        Console.Write(c.x);
        Console.Write(c.y);
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"12", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       57 (0x39)
  .maxstack  4
  .locals init (int* V_0, //p
                pinned int& V_1,
                pinned int& V_2)
  IL_0000:  newobj     ""C..ctor()""
  IL_0005:  dup
  IL_0006:  ldflda     ""int C.x""
  IL_000b:  stloc.1
  IL_000c:  ldloc.1
  IL_000d:  conv.u
  IL_000e:  stloc.0
  IL_000f:  dup
  IL_0010:  ldflda     ""int C.y""
  IL_0015:  stloc.2
  IL_0016:  ldloc.2
  IL_0017:  conv.u
  IL_0018:  ldloc.0
  IL_0019:  ldc.i4.1
  IL_001a:  stind.i4
  IL_001b:  ldc.i4.2
  IL_001c:  stind.i4
  IL_001d:  ldc.i4.0
  IL_001e:  conv.u
  IL_001f:  stloc.1
  IL_0020:  ldc.i4.0
  IL_0021:  conv.u
  IL_0022:  stloc.2
  IL_0023:  dup
  IL_0024:  ldfld      ""int C.x""
  IL_0029:  call       ""void System.Console.Write(int)""
  IL_002e:  ldfld      ""int C.y""
  IL_0033:  call       ""void System.Console.Write(int)""
  IL_0038:  ret
}
");
        }
 
        [WorkItem(22306, "https://github.com/dotnet/roslyn/issues/22306")]
        [Fact]
        public void FixedStatementMultipleMethods()
        {
            var text = @"
using System;
 
unsafe class C
{
    int x;
    readonly int y;
    
    ref int X()=>ref x;
    ref readonly int this[int i]=>ref y;
 
    static void Main()
    {
        C c = new C();
        fixed (int* p = &c.X(), q = &c[3])
        {
            *p = 1;
            *q = 2;
        }
        Console.Write(c.x);
        Console.Write(c.y);
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"12", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       58 (0x3a)
  .maxstack  4
  .locals init (int* V_0, //p
                pinned int& V_1,
                pinned int& V_2)
  IL_0000:  newobj     ""C..ctor()""
  IL_0005:  dup
  IL_0006:  callvirt   ""ref int C.X()""
  IL_000b:  stloc.1
  IL_000c:  ldloc.1
  IL_000d:  conv.u
  IL_000e:  stloc.0
  IL_000f:  dup
  IL_0010:  ldc.i4.3
  IL_0011:  callvirt   ""ref readonly int C.this[int].get""
  IL_0016:  stloc.2
  IL_0017:  ldloc.2
  IL_0018:  conv.u
  IL_0019:  ldloc.0
  IL_001a:  ldc.i4.1
  IL_001b:  stind.i4
  IL_001c:  ldc.i4.2
  IL_001d:  stind.i4
  IL_001e:  ldc.i4.0
  IL_001f:  conv.u
  IL_0020:  stloc.1
  IL_0021:  ldc.i4.0
  IL_0022:  conv.u
  IL_0023:  stloc.2
  IL_0024:  dup
  IL_0025:  ldfld      ""int C.x""
  IL_002a:  call       ""void System.Console.Write(int)""
  IL_002f:  ldfld      ""int C.y""
  IL_0034:  call       ""void System.Console.Write(int)""
  IL_0039:  ret
}
");
        }
 
        [WorkItem(546866, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546866")]
        [Fact]
        public void FixedStatementProperty()
        {
            var text =
@"class C
{
    string P { get { return null; } }
    char[] Q { get { return null; } }
    unsafe static void M(C c)
    {
        fixed (char* o = c.P)
        {
        }
        fixed (char* o = c.Q)
        {
        }
    }
}";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails);
            compVerifier.VerifyIL("C.M(C)",
@"
{
  // Code size       55 (0x37)
  .maxstack  2
  .locals init (char* V_0, //o
                pinned string V_1,
                char* V_2, //o
                pinned char[] V_3)
  IL_0000:  ldarg.0
  IL_0001:  callvirt   ""string C.P.get""
  IL_0006:  stloc.1
  IL_0007:  ldloc.1
  IL_0008:  conv.u
  IL_0009:  stloc.0
  IL_000a:  ldloc.0
  IL_000b:  brfalse.s  IL_0015
  IL_000d:  ldloc.0
  IL_000e:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0013:  add
  IL_0014:  stloc.0
  IL_0015:  ldnull
  IL_0016:  stloc.1
  IL_0017:  ldarg.0
  IL_0018:  callvirt   ""char[] C.Q.get""
  IL_001d:  dup
  IL_001e:  stloc.3
  IL_001f:  brfalse.s  IL_0026
  IL_0021:  ldloc.3
  IL_0022:  ldlen
  IL_0023:  conv.i4
  IL_0024:  brtrue.s   IL_002b
  IL_0026:  ldc.i4.0
  IL_0027:  conv.u
  IL_0028:  stloc.2
  IL_0029:  br.s       IL_0034
  IL_002b:  ldloc.3
  IL_002c:  ldc.i4.0
  IL_002d:  ldelema    ""char""
  IL_0032:  conv.u
  IL_0033:  stloc.2
  IL_0034:  ldnull
  IL_0035:  stloc.3
  IL_0036:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementMultipleOptimized()
        {
            var text = @"
using System;
 
unsafe class C
{
    int x;
    int y;
    
    static void Main()
    {
        C c = new C();
        fixed (int* p = &c.x, q = &c.y)
        {
            *p = 1;
            *q = 2;
        }
        Console.Write(c.x);
        Console.Write(c.y);
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"12", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       57 (0x39)
  .maxstack  4
  .locals init (int* V_0, //p
                pinned int& V_1,
                pinned int& V_2)
  IL_0000:  newobj     ""C..ctor()""
  IL_0005:  dup
  IL_0006:  ldflda     ""int C.x""
  IL_000b:  stloc.1
  IL_000c:  ldloc.1
  IL_000d:  conv.u
  IL_000e:  stloc.0
  IL_000f:  dup
  IL_0010:  ldflda     ""int C.y""
  IL_0015:  stloc.2
  IL_0016:  ldloc.2
  IL_0017:  conv.u
  IL_0018:  ldloc.0
  IL_0019:  ldc.i4.1
  IL_001a:  stind.i4
  IL_001b:  ldc.i4.2
  IL_001c:  stind.i4
  IL_001d:  ldc.i4.0
  IL_001e:  conv.u
  IL_001f:  stloc.1
  IL_0020:  ldc.i4.0
  IL_0021:  conv.u
  IL_0022:  stloc.2
  IL_0023:  dup
  IL_0024:  ldfld      ""int C.x""
  IL_0029:  call       ""void System.Console.Write(int)""
  IL_002e:  ldfld      ""int C.y""
  IL_0033:  call       ""void System.Console.Write(int)""
  IL_0038:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementReferenceParameter()
        {
            var text = @"
using System;
 
class C
{
    static void Main()
    {
        char ch;
        M(out ch);
        Console.WriteLine(ch);
    }
 
    unsafe static void M(out char ch)
    {
        fixed (char* p = &ch)
        {
            *p = 'a';
        }
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"a", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.M", @"
{
  // Code size       11 (0xb)
  .maxstack  2
  .locals init (pinned char& V_0)
  IL_0000:  ldarg.0
  IL_0001:  stloc.0
  IL_0002:  ldloc.0
  IL_0003:  conv.u
  IL_0004:  ldc.i4.s   97
  IL_0006:  stind.i2
  IL_0007:  ldc.i4.0
  IL_0008:  conv.u
  IL_0009:  stloc.0
  IL_000a:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementReferenceParameterDebug()
        {
            var text = @"
using System;
 
class C
{
    static void Main()
    {
        char ch;
        M(out ch);
        Console.WriteLine(ch);
    }
 
    unsafe static void M(out char ch)
    {
        fixed (char* p = &ch)
        {
            *p = 'a';
        }
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeDebugExe, expectedOutput: @"a", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.M", @"
{
  // Code size       16 (0x10)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned char& V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  stloc.1
  IL_0003:  ldloc.1
  IL_0004:  conv.u
  IL_0005:  stloc.0
  IL_0006:  nop
  IL_0007:  ldloc.0
  IL_0008:  ldc.i4.s   97
  IL_000a:  stind.i2
  IL_000b:  nop
  IL_000c:  ldc.i4.0
  IL_000d:  conv.u
  IL_000e:  stloc.1
  IL_000f:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementStringLiteral()
        {
            var text = @"
using System;
 
unsafe class C
{
    static void Main()
    {
        fixed (char* p = ""hello"")
        {
            Console.WriteLine(*p);
        }
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeDebugExe, expectedOutput: @"h", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       34 (0x22)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
 -IL_0000:  nop
  IL_0001:  ldstr      ""hello""
  IL_0006:  stloc.1
 -IL_0007:  ldloc.1
  IL_0008:  conv.u
  IL_0009:  stloc.0
  IL_000a:  ldloc.0
  IL_000b:  brfalse.s  IL_0015
  IL_000d:  ldloc.0
  IL_000e:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0013:  add
  IL_0014:  stloc.0
 -IL_0015:  nop
 -IL_0016:  ldloc.0
  IL_0017:  ldind.u2
  IL_0018:  call       ""void System.Console.WriteLine(char)""
  IL_001d:  nop
 -IL_001e:  nop
 ~IL_001f:  ldnull
  IL_0020:  stloc.1
 -IL_0021:  ret
}
", sequencePoints: "C.Main");
        }
 
        [Fact]
        public void FixedStatementStringVariable()
        {
            var text = @"
using System;
 
unsafe class C
{
    static void Main()
    {
        string s = ""hello"";
        fixed (char* p = s)
        {
            Console.Write(*p);
        }
 
        s = null;
        fixed (char* p = s)
        {
            Console.Write(p == null);
        }
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeDebugExe, expectedOutput: @"hTrue", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       72 (0x48)
  .maxstack  2
  .locals init (string V_0, //s
                char* V_1, //p
                pinned string V_2,
                char* V_3, //p
                pinned string V_4)
 -IL_0000:  nop
 -IL_0001:  ldstr      ""hello""
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  stloc.2
 -IL_0009:  ldloc.2
  IL_000a:  conv.u
  IL_000b:  stloc.1
  IL_000c:  ldloc.1
  IL_000d:  brfalse.s  IL_0017
  IL_000f:  ldloc.1
  IL_0010:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0015:  add
  IL_0016:  stloc.1
 -IL_0017:  nop
 -IL_0018:  ldloc.1
  IL_0019:  ldind.u2
  IL_001a:  call       ""void System.Console.Write(char)""
  IL_001f:  nop
 -IL_0020:  nop
 ~IL_0021:  ldnull
  IL_0022:  stloc.2
 -IL_0023:  ldnull
  IL_0024:  stloc.0
  IL_0025:  ldloc.0
  IL_0026:  stloc.s    V_4
 -IL_0028:  ldloc.s    V_4
  IL_002a:  conv.u
  IL_002b:  stloc.3
  IL_002c:  ldloc.3
  IL_002d:  brfalse.s  IL_0037
  IL_002f:  ldloc.3
  IL_0030:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0035:  add
  IL_0036:  stloc.3
 -IL_0037:  nop
 -IL_0038:  ldloc.3
  IL_0039:  ldc.i4.0
  IL_003a:  conv.u
  IL_003b:  ceq
  IL_003d:  call       ""void System.Console.Write(bool)""
  IL_0042:  nop
 -IL_0043:  nop
 ~IL_0044:  ldnull
  IL_0045:  stloc.s    V_4
 -IL_0047:  ret
}
", sequencePoints: "C.Main");
        }
 
        [Fact]
        public void FixedStatementStringVariableOptimized()
        {
            var text = @"
using System;
 
unsafe class C
{
    static void Main()
    {
        string s = ""hello"";
        fixed (char* p = s)
        {
            Console.Write(*p);
        }
 
        s = null;
        fixed (char* p = s)
        {
            Console.Write(p == null);
        }
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"hTrue", verify: Verification.Fails);
 
            // Null checks and branches are much simpler, but string temps are NOT optimized away.
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       58 (0x3a)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1,
                char* V_2) //p
  IL_0000:  ldstr      ""hello""
  IL_0005:  stloc.1
  IL_0006:  ldloc.1
  IL_0007:  conv.u
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  brfalse.s  IL_0014
  IL_000c:  ldloc.0
  IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0012:  add
  IL_0013:  stloc.0
  IL_0014:  ldloc.0
  IL_0015:  ldind.u2
  IL_0016:  call       ""void System.Console.Write(char)""
  IL_001b:  ldnull
  IL_001c:  stloc.1
  IL_001d:  ldnull
  IL_001e:  stloc.1
  IL_001f:  ldloc.1
  IL_0020:  conv.u
  IL_0021:  stloc.2
  IL_0022:  ldloc.2
  IL_0023:  brfalse.s  IL_002d
  IL_0025:  ldloc.2
  IL_0026:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_002b:  add
  IL_002c:  stloc.2
  IL_002d:  ldloc.2
  IL_002e:  ldc.i4.0
  IL_002f:  conv.u
  IL_0030:  ceq
  IL_0032:  call       ""void System.Console.Write(bool)""
  IL_0037:  ldnull
  IL_0038:  stloc.1
  IL_0039:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementOneDimensionalArray()
        {
            var text = @"
using System;
 
unsafe class C
{
    int[] a = new int[1];
 
    static void Main()
    {
        C c = new C();
        Console.Write(c.a[0]);
        fixed (int* p = c.a)
        {
            *p = 1;
        }
        Console.Write(c.a[0]);
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"01", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       65 (0x41)
  .maxstack  3
  .locals init (int* V_0, //p
                pinned int[] V_1)
  IL_0000:  newobj     ""C..ctor()""
  IL_0005:  dup
  IL_0006:  ldfld      ""int[] C.a""
  IL_000b:  ldc.i4.0
  IL_000c:  ldelem.i4
  IL_000d:  call       ""void System.Console.Write(int)""
  IL_0012:  dup
  IL_0013:  ldfld      ""int[] C.a""
  IL_0018:  dup
  IL_0019:  stloc.1
  IL_001a:  brfalse.s  IL_0021
  IL_001c:  ldloc.1
  IL_001d:  ldlen
  IL_001e:  conv.i4
  IL_001f:  brtrue.s   IL_0026
  IL_0021:  ldc.i4.0
  IL_0022:  conv.u
  IL_0023:  stloc.0
  IL_0024:  br.s       IL_002f
  IL_0026:  ldloc.1
  IL_0027:  ldc.i4.0
  IL_0028:  ldelema    ""int""
  IL_002d:  conv.u
  IL_002e:  stloc.0
  IL_002f:  ldloc.0
  IL_0030:  ldc.i4.1
  IL_0031:  stind.i4
  IL_0032:  ldnull
  IL_0033:  stloc.1
  IL_0034:  ldfld      ""int[] C.a""
  IL_0039:  ldc.i4.0
  IL_003a:  ldelem.i4
  IL_003b:  call       ""void System.Console.Write(int)""
  IL_0040:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementOneDimensionalArrayOptimized()
        {
            var text = @"
using System;
 
unsafe class C
{
    int[] a = new int[1];
 
    static void Main()
    {
        C c = new C();
        Console.Write(c.a[0]);
        fixed (int* p = c.a)
        {
            *p = 1;
        }
        Console.Write(c.a[0]);
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"01", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       65 (0x41)
  .maxstack  3
  .locals init (int* V_0, //p
                pinned int[] V_1)
  IL_0000:  newobj     ""C..ctor()""
  IL_0005:  dup
  IL_0006:  ldfld      ""int[] C.a""
  IL_000b:  ldc.i4.0
  IL_000c:  ldelem.i4
  IL_000d:  call       ""void System.Console.Write(int)""
  IL_0012:  dup
  IL_0013:  ldfld      ""int[] C.a""
  IL_0018:  dup
  IL_0019:  stloc.1
  IL_001a:  brfalse.s  IL_0021
  IL_001c:  ldloc.1
  IL_001d:  ldlen
  IL_001e:  conv.i4
  IL_001f:  brtrue.s   IL_0026
  IL_0021:  ldc.i4.0
  IL_0022:  conv.u
  IL_0023:  stloc.0
  IL_0024:  br.s       IL_002f
  IL_0026:  ldloc.1
  IL_0027:  ldc.i4.0
  IL_0028:  ldelema    ""int""
  IL_002d:  conv.u
  IL_002e:  stloc.0
  IL_002f:  ldloc.0
  IL_0030:  ldc.i4.1
  IL_0031:  stind.i4
  IL_0032:  ldnull
  IL_0033:  stloc.1
  IL_0034:  ldfld      ""int[] C.a""
  IL_0039:  ldc.i4.0
  IL_003a:  ldelem.i4
  IL_003b:  call       ""void System.Console.Write(int)""
  IL_0040:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementMultiDimensionalArrayOptimized()
        {
            var text = @"
using System;
 
unsafe class C
{
    int[,] a = new int[1,1];
 
    static void Main()
    {
        C c = new C();
        Console.Write(c.a[0, 0]);
        fixed (int* p = c.a)
        {
            *p = 1;
        }
        Console.Write(c.a[0, 0]);
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"01", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       79 (0x4f)
  .maxstack  4
  .locals init (int* V_0, //p
                pinned int[,] V_1)
  IL_0000:  newobj     ""C..ctor()""
  IL_0005:  dup
  IL_0006:  ldfld      ""int[,] C.a""
  IL_000b:  ldc.i4.0
  IL_000c:  ldc.i4.0
  IL_000d:  call       ""int[*,*].Get""
  IL_0012:  call       ""void System.Console.Write(int)""
  IL_0017:  dup
  IL_0018:  ldfld      ""int[,] C.a""
  IL_001d:  dup
  IL_001e:  stloc.1
  IL_001f:  brfalse.s  IL_0029
  IL_0021:  ldloc.1
  IL_0022:  callvirt   ""int System.Array.Length.get""
  IL_0027:  brtrue.s   IL_002e
  IL_0029:  ldc.i4.0
  IL_002a:  conv.u
  IL_002b:  stloc.0
  IL_002c:  br.s       IL_0038
  IL_002e:  ldloc.1
  IL_002f:  ldc.i4.0
  IL_0030:  ldc.i4.0
  IL_0031:  call       ""int[*,*].Address""
  IL_0036:  conv.u
  IL_0037:  stloc.0
  IL_0038:  ldloc.0
  IL_0039:  ldc.i4.1
  IL_003a:  stind.i4
  IL_003b:  ldnull
  IL_003c:  stloc.1
  IL_003d:  ldfld      ""int[,] C.a""
  IL_0042:  ldc.i4.0
  IL_0043:  ldc.i4.0
  IL_0044:  call       ""int[*,*].Get""
  IL_0049:  call       ""void System.Console.Write(int)""
  IL_004e:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementMixed()
        {
            var text = @"
using System;
 
unsafe class C
{
    char c = 'a';
    char[] a = new char[1];
 
    static void Main()
    {
        C c = new C();
        fixed (char* p = &c.c, q = c.a, r = ""hello"")
        {
            Console.Write((int)*p);
            Console.Write((int)*q);
            Console.Write((int)*r);
        }
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"970104", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       99 (0x63)
  .maxstack  2
  .locals init (char* V_0, //p
                char* V_1, //q
                char* V_2, //r
                pinned char& V_3,
                pinned char[] V_4,
                pinned string V_5)
  IL_0000:  newobj     ""C..ctor()""
  IL_0005:  dup
  IL_0006:  ldflda     ""char C.c""
  IL_000b:  stloc.3
  IL_000c:  ldloc.3
  IL_000d:  conv.u
  IL_000e:  stloc.0
  IL_000f:  ldfld      ""char[] C.a""
  IL_0014:  dup
  IL_0015:  stloc.s    V_4
  IL_0017:  brfalse.s  IL_001f
  IL_0019:  ldloc.s    V_4
  IL_001b:  ldlen
  IL_001c:  conv.i4
  IL_001d:  brtrue.s   IL_0024
  IL_001f:  ldc.i4.0
  IL_0020:  conv.u
  IL_0021:  stloc.1
  IL_0022:  br.s       IL_002e
  IL_0024:  ldloc.s    V_4
  IL_0026:  ldc.i4.0
  IL_0027:  ldelema    ""char""
  IL_002c:  conv.u
  IL_002d:  stloc.1
  IL_002e:  ldstr      ""hello""
  IL_0033:  stloc.s    V_5
  IL_0035:  ldloc.s    V_5
  IL_0037:  conv.u
  IL_0038:  stloc.2
  IL_0039:  ldloc.2
  IL_003a:  brfalse.s  IL_0044
  IL_003c:  ldloc.2
  IL_003d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0042:  add
  IL_0043:  stloc.2
  IL_0044:  ldloc.0
  IL_0045:  ldind.u2
  IL_0046:  call       ""void System.Console.Write(int)""
  IL_004b:  ldloc.1
  IL_004c:  ldind.u2
  IL_004d:  call       ""void System.Console.Write(int)""
  IL_0052:  ldloc.2
  IL_0053:  ldind.u2
  IL_0054:  call       ""void System.Console.Write(int)""
  IL_0059:  ldc.i4.0
  IL_005a:  conv.u
  IL_005b:  stloc.3
  IL_005c:  ldnull
  IL_005d:  stloc.s    V_4
  IL_005f:  ldnull
  IL_0060:  stloc.s    V_5
  IL_0062:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementInTryOfTryFinally()
        {
            var text = @"
unsafe class C
{
    static void nop() { }
    void Test()
    {
        try
        {
            fixed (char* p = ""hello"")
            {
            }
        }
        finally
        {
            nop();
        }
    }
}
";
            // Cleanup in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       32 (0x20)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  .try
  {
    .try
    {
      IL_0000:  ldstr      ""hello""
      IL_0005:  stloc.1
      IL_0006:  ldloc.1
      IL_0007:  conv.u
      IL_0008:  stloc.0
      IL_0009:  ldloc.0
      IL_000a:  brfalse.s  IL_0014
      IL_000c:  ldloc.0
      IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
      IL_0012:  add
      IL_0013:  stloc.0
      IL_0014:  leave.s    IL_001f
    }
    finally
    {
      IL_0016:  ldnull
      IL_0017:  stloc.1
      IL_0018:  endfinally
    }
  }
  finally
  {
    IL_0019:  call       ""void C.nop()""
    IL_001e:  endfinally
  }
  IL_001f:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementInTryOfTryCatch()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        try
        {
            fixed (char* p = ""hello"")
            {
            }
        }
        catch
        {
        }
    }
}
";
            // Cleanup in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       31 (0x1f)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  .try
  {
    .try
    {
      IL_0000:  ldstr      ""hello""
      IL_0005:  stloc.1
      IL_0006:  ldloc.1
      IL_0007:  conv.u
      IL_0008:  stloc.0
      IL_0009:  ldloc.0
      IL_000a:  brfalse.s  IL_0014
      IL_000c:  ldloc.0
      IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
      IL_0012:  add
      IL_0013:  stloc.0
      IL_0014:  leave.s    IL_0019
    }
    finally
    {
      IL_0016:  ldnull
      IL_0017:  stloc.1
      IL_0018:  endfinally
    }
    IL_0019:  leave.s    IL_001e
  }
  catch object
  {
    IL_001b:  pop
    IL_001c:  leave.s    IL_001e
  }
  IL_001e:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementInFinally()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        try
        {
        }
        finally
        {
            fixed (char* p = ""hello"")
            {
            }
        }
    }
}
";
            // Cleanup not in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       26 (0x1a)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  .try
  {
    IL_0000:  leave.s    IL_0019
  }
  finally
  {
    IL_0002:  ldstr      ""hello""
    IL_0007:  stloc.1
    IL_0008:  ldloc.1
    IL_0009:  conv.u
    IL_000a:  stloc.0
    IL_000b:  ldloc.0
    IL_000c:  brfalse.s  IL_0016
    IL_000e:  ldloc.0
    IL_000f:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
    IL_0014:  add
    IL_0015:  stloc.0
    IL_0016:  ldnull
    IL_0017:  stloc.1
    IL_0018:  endfinally
  }
  IL_0019:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementInCatchOfTryCatch()
        {
            var text = @"
unsafe class C
{
    void nop() { }
    void Test()
    {
        try
        {
            nop();
        }
        catch
        {
            fixed (char* p = ""hello"")
            {
            }
        }
    }
}
";
            // Cleanup not in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test",
@"{
  // Code size       34 (0x22)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  .try
  {
    IL_0000:  ldarg.0
    IL_0001:  call       ""void C.nop()""
    IL_0006:  leave.s    IL_0021
  }
  catch object
  {
    IL_0008:  pop
    IL_0009:  ldstr      ""hello""
    IL_000e:  stloc.1
    IL_000f:  ldloc.1
    IL_0010:  conv.u
    IL_0011:  stloc.0
    IL_0012:  ldloc.0
    IL_0013:  brfalse.s  IL_001d
    IL_0015:  ldloc.0
    IL_0016:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
    IL_001b:  add
    IL_001c:  stloc.0
    IL_001d:  ldnull
    IL_001e:  stloc.1
    IL_001f:  leave.s    IL_0021
  }
  IL_0021:  ret
}");
        }
 
        [Fact]
        public void FixedStatementInCatchOfTryCatchFinally()
        {
            var text = @"
unsafe class C
{
    static void nop() { }
    void Test()
    {
        try
        {
            nop();
        }
        catch
        {
            fixed (char* p = ""hello"")
            {
            }
        }
        finally
        {
        }
    }
}
";
            // Cleanup in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       36 (0x24)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  .try
  {
    IL_0000:  call       ""void C.nop()""
    IL_0005:  leave.s    IL_0023
  }
  catch object
  {
    IL_0007:  pop
    .try
    {
      IL_0008:  ldstr      ""hello""
      IL_000d:  stloc.1
      IL_000e:  ldloc.1
      IL_000f:  conv.u
      IL_0010:  stloc.0
      IL_0011:  ldloc.0
      IL_0012:  brfalse.s  IL_001c
      IL_0014:  ldloc.0
      IL_0015:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
      IL_001a:  add
      IL_001b:  stloc.0
      IL_001c:  leave.s    IL_0021
    }
    finally
    {
      IL_001e:  ldnull
      IL_001f:  stloc.1
      IL_0020:  endfinally
    }
    IL_0021:  leave.s    IL_0023
  }
  IL_0023:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementInFixed_NoBranch()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        fixed (char* q = ""goodbye"")
        {
            fixed (char* p = ""hello"")
            {
            }
        }
    }
}
";
            // Neither inner nor outer has finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       45 (0x2d)
  .maxstack  2
  .locals init (char* V_0, //q
                pinned string V_1,
                char* V_2, //p
                pinned string V_3)
  IL_0000:  ldstr      ""goodbye""
  IL_0005:  stloc.1
  IL_0006:  ldloc.1
  IL_0007:  conv.u
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  brfalse.s  IL_0014
  IL_000c:  ldloc.0
  IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0012:  add
  IL_0013:  stloc.0
  IL_0014:  ldstr      ""hello""
  IL_0019:  stloc.3
  IL_001a:  ldloc.3
  IL_001b:  conv.u
  IL_001c:  stloc.2
  IL_001d:  ldloc.2
  IL_001e:  brfalse.s  IL_0028
  IL_0020:  ldloc.2
  IL_0021:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0026:  add
  IL_0027:  stloc.2
  IL_0028:  ldnull
  IL_0029:  stloc.3
  IL_002a:  ldnull
  IL_002b:  stloc.1
  IL_002c:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementInFixed_InnerBranch()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        fixed (char* q = ""goodbye"")
        {
            fixed (char* p = ""hello"")
            {
                goto label;
            }
        }
      label: ;
    }
}
";
            // Inner and outer both have finally blocks.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       50 (0x32)
  .maxstack  2
  .locals init (char* V_0, //q
                pinned string V_1,
                char* V_2, //p
                pinned string V_3)
  .try
  {
    IL_0000:  ldstr      ""goodbye""
    IL_0005:  stloc.1
    IL_0006:  ldloc.1
    IL_0007:  conv.u
    IL_0008:  stloc.0
    IL_0009:  ldloc.0
    IL_000a:  brfalse.s  IL_0014
    IL_000c:  ldloc.0
    IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
    IL_0012:  add
    IL_0013:  stloc.0
    IL_0014:  nop
    .try
    {
      IL_0015:  ldstr      ""hello""
      IL_001a:  stloc.3
      IL_001b:  ldloc.3
      IL_001c:  conv.u
      IL_001d:  stloc.2
      IL_001e:  ldloc.2
      IL_001f:  brfalse.s  IL_0029
      IL_0021:  ldloc.2
      IL_0022:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
      IL_0027:  add
      IL_0028:  stloc.2
      IL_0029:  leave.s    IL_0031
    }
    finally
    {
      IL_002b:  ldnull
      IL_002c:  stloc.3
      IL_002d:  endfinally
    }
  }
  finally
  {
    IL_002e:  ldnull
    IL_002f:  stloc.1
    IL_0030:  endfinally
  }
  IL_0031:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementInFixed_OuterBranch()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        fixed (char* q = ""goodbye"")
        {
            fixed (char* p = ""hello"")
            {
            }
            goto label;
        }
      label: ;
    }
}
";
            // Outer has finally, inner does not.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       48 (0x30)
  .maxstack  2
  .locals init (char* V_0, //q
                pinned string V_1,
                char* V_2, //p
                pinned string V_3)
  .try
  {
    IL_0000:  ldstr      ""goodbye""
    IL_0005:  stloc.1
    IL_0006:  ldloc.1
    IL_0007:  conv.u
    IL_0008:  stloc.0
    IL_0009:  ldloc.0
    IL_000a:  brfalse.s  IL_0014
    IL_000c:  ldloc.0
    IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
    IL_0012:  add
    IL_0013:  stloc.0
    IL_0014:  ldstr      ""hello""
    IL_0019:  stloc.3
    IL_001a:  ldloc.3
    IL_001b:  conv.u
    IL_001c:  stloc.2
    IL_001d:  ldloc.2
    IL_001e:  brfalse.s  IL_0028
    IL_0020:  ldloc.2
    IL_0021:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
    IL_0026:  add
    IL_0027:  stloc.2
    IL_0028:  ldnull
    IL_0029:  stloc.3
    IL_002a:  leave.s    IL_002f
  }
  finally
  {
    IL_002c:  ldnull
    IL_002d:  stloc.1
    IL_002e:  endfinally
  }
  IL_002f:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementInFixed_Nesting()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        fixed (char* p1 = ""A"")
        {
            fixed (char* p2 = ""B"")
            {
                fixed (char* p3 = ""C"")
                {
                }
                fixed (char* p4 = ""D"")
                {
                }
            }
            fixed (char* p5 = ""E"")
            {
                fixed (char* p6 = ""F"")
                {
                }
                fixed (char* p7 = ""G"")
                {
                }
            }
        }
    }
}
";
            // This test checks two things:
            //   1) nothing blows up with triple-nesting, and
            //   2) none of the fixed statements has a try-finally.
            // CONSIDER: Shorter test that performs the same checks.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size      187 (0xbb)
  .maxstack  2
  .locals init (char* V_0, //p1
                pinned string V_1,
                char* V_2, //p2
                pinned string V_3,
                char* V_4, //p3
                pinned string V_5,
                char* V_6, //p4
                char* V_7, //p5
                char* V_8, //p6
                char* V_9) //p7
  IL_0000:  ldstr      ""A""
  IL_0005:  stloc.1
  IL_0006:  ldloc.1
  IL_0007:  conv.u
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  brfalse.s  IL_0014
  IL_000c:  ldloc.0
  IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0012:  add
  IL_0013:  stloc.0
  IL_0014:  ldstr      ""B""
  IL_0019:  stloc.3
  IL_001a:  ldloc.3
  IL_001b:  conv.u
  IL_001c:  stloc.2
  IL_001d:  ldloc.2
  IL_001e:  brfalse.s  IL_0028
  IL_0020:  ldloc.2
  IL_0021:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0026:  add
  IL_0027:  stloc.2
  IL_0028:  ldstr      ""C""
  IL_002d:  stloc.s    V_5
  IL_002f:  ldloc.s    V_5
  IL_0031:  conv.u
  IL_0032:  stloc.s    V_4
  IL_0034:  ldloc.s    V_4
  IL_0036:  brfalse.s  IL_0042
  IL_0038:  ldloc.s    V_4
  IL_003a:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_003f:  add
  IL_0040:  stloc.s    V_4
  IL_0042:  ldnull
  IL_0043:  stloc.s    V_5
  IL_0045:  ldstr      ""D""
  IL_004a:  stloc.s    V_5
  IL_004c:  ldloc.s    V_5
  IL_004e:  conv.u
  IL_004f:  stloc.s    V_6
  IL_0051:  ldloc.s    V_6
  IL_0053:  brfalse.s  IL_005f
  IL_0055:  ldloc.s    V_6
  IL_0057:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_005c:  add
  IL_005d:  stloc.s    V_6
  IL_005f:  ldnull
  IL_0060:  stloc.s    V_5
  IL_0062:  ldnull
  IL_0063:  stloc.3
  IL_0064:  ldstr      ""E""
  IL_0069:  stloc.3
  IL_006a:  ldloc.3
  IL_006b:  conv.u
  IL_006c:  stloc.s    V_7
  IL_006e:  ldloc.s    V_7
  IL_0070:  brfalse.s  IL_007c
  IL_0072:  ldloc.s    V_7
  IL_0074:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0079:  add
  IL_007a:  stloc.s    V_7
  IL_007c:  ldstr      ""F""
  IL_0081:  stloc.s    V_5
  IL_0083:  ldloc.s    V_5
  IL_0085:  conv.u
  IL_0086:  stloc.s    V_8
  IL_0088:  ldloc.s    V_8
  IL_008a:  brfalse.s  IL_0096
  IL_008c:  ldloc.s    V_8
  IL_008e:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0093:  add
  IL_0094:  stloc.s    V_8
  IL_0096:  ldnull
  IL_0097:  stloc.s    V_5
  IL_0099:  ldstr      ""G""
  IL_009e:  stloc.s    V_5
  IL_00a0:  ldloc.s    V_5
  IL_00a2:  conv.u
  IL_00a3:  stloc.s    V_9
  IL_00a5:  ldloc.s    V_9
  IL_00a7:  brfalse.s  IL_00b3
  IL_00a9:  ldloc.s    V_9
  IL_00ab:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_00b0:  add
  IL_00b1:  stloc.s    V_9
  IL_00b3:  ldnull
  IL_00b4:  stloc.s    V_5
  IL_00b6:  ldnull
  IL_00b7:  stloc.3
  IL_00b8:  ldnull
  IL_00b9:  stloc.1
  IL_00ba:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementInUsing()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        using (System.IDisposable d = null)
        {
            fixed (char* p = ""hello"")
            {
            }
        }
    }
}
";
            // CONSIDER: This is sort of silly since the using is optimized away.
            // Cleanup in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       26 (0x1a)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  .try
  {
    IL_0000:  ldstr      ""hello""
    IL_0005:  stloc.1
    IL_0006:  ldloc.1
    IL_0007:  conv.u
    IL_0008:  stloc.0
    IL_0009:  ldloc.0
    IL_000a:  brfalse.s  IL_0014
    IL_000c:  ldloc.0
    IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
    IL_0012:  add
    IL_0013:  stloc.0
    IL_0014:  leave.s    IL_0019
  }
  finally
  {
    IL_0016:  ldnull
    IL_0017:  stloc.1
    IL_0018:  endfinally
  }
  IL_0019:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementInLock()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        lock (this)
        {
            fixed (char* p = ""hello"")
            {
            }
        }
    }
}
";
            // Cleanup not in finally (matches dev11, but not clear why).
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       47 (0x2f)
  .maxstack  2
  .locals init (C V_0,
                bool V_1,
                char* V_2, //p
                pinned string V_3)
  IL_0000:  ldarg.0
  IL_0001:  stloc.0
  IL_0002:  ldc.i4.0
  IL_0003:  stloc.1
  .try
  {
    IL_0004:  ldloc.0
    IL_0005:  ldloca.s   V_1
    IL_0007:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
    IL_000c:  ldstr      ""hello""
    IL_0011:  stloc.3
    IL_0012:  ldloc.3
    IL_0013:  conv.u
    IL_0014:  stloc.2
    IL_0015:  ldloc.2
    IL_0016:  brfalse.s  IL_0020
    IL_0018:  ldloc.2
    IL_0019:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
    IL_001e:  add
    IL_001f:  stloc.2
    IL_0020:  ldnull
    IL_0021:  stloc.3
    IL_0022:  leave.s    IL_002e
  }
  finally
  {
    IL_0024:  ldloc.1
    IL_0025:  brfalse.s  IL_002d
    IL_0027:  ldloc.0
    IL_0028:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_002d:  endfinally
  }
  IL_002e:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementInForEach_NoDispose()
        {
            var text = @"
unsafe class C
{
    void Test(int[] array)
    {
        foreach (int i in array)
        {
            fixed (char* p = ""hello"")
            {
            }
        }
    }
}
";
            // Cleanup in finally.
            // CONSIDER: dev11 is smarter and skips the try-finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       46 (0x2e)
  .maxstack  2
  .locals init (int[] V_0,
                int V_1,
                char* V_2, //p
                pinned string V_3)
  IL_0000:  ldarg.1
  IL_0001:  stloc.0
  IL_0002:  ldc.i4.0
  IL_0003:  stloc.1
  IL_0004:  br.s       IL_0027
  IL_0006:  ldloc.0
  IL_0007:  ldloc.1
  IL_0008:  ldelem.i4
  IL_0009:  pop
  .try
  {
    IL_000a:  ldstr      ""hello""
    IL_000f:  stloc.3
    IL_0010:  ldloc.3
    IL_0011:  conv.u
    IL_0012:  stloc.2
    IL_0013:  ldloc.2
    IL_0014:  brfalse.s  IL_001e
    IL_0016:  ldloc.2
    IL_0017:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
    IL_001c:  add
    IL_001d:  stloc.2
    IL_001e:  leave.s    IL_0023
  }
  finally
  {
    IL_0020:  ldnull
    IL_0021:  stloc.3
    IL_0022:  endfinally
  }
  IL_0023:  ldloc.1
  IL_0024:  ldc.i4.1
  IL_0025:  add
  IL_0026:  stloc.1
  IL_0027:  ldloc.1
  IL_0028:  ldloc.0
  IL_0029:  ldlen
  IL_002a:  conv.i4
  IL_002b:  blt.s      IL_0006
  IL_002d:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementInForEach_Dispose()
        {
            var text = @"
unsafe class C
{
    void Test(Enumerable e)
    {
        foreach (var x in e)
        {
            fixed (char* p = ""hello"")
            {
            }
        }
    }
}
 
class Enumerable
{
    public Enumerator GetEnumerator() { return new Enumerator(); }
}
 
class Enumerator : System.IDisposable
{
    int x;
    public int Current { get { return x; } }
    public bool MoveNext() { return ++x < 4; }
    void System.IDisposable.Dispose() { }
}
";
            // Cleanup in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       62 (0x3e)
  .maxstack  2
  .locals init (Enumerator V_0,
                char* V_1, //p
                pinned string V_2)
  IL_0000:  ldarg.1
  IL_0001:  callvirt   ""Enumerator Enumerable.GetEnumerator()""
  IL_0006:  stloc.0
  .try
  {
    IL_0007:  br.s       IL_0029
    IL_0009:  ldloc.0
    IL_000a:  callvirt   ""int Enumerator.Current.get""
    IL_000f:  pop
    .try
    {
      IL_0010:  ldstr      ""hello""
      IL_0015:  stloc.2
      IL_0016:  ldloc.2
      IL_0017:  conv.u
      IL_0018:  stloc.1
      IL_0019:  ldloc.1
      IL_001a:  brfalse.s  IL_0024
      IL_001c:  ldloc.1
      IL_001d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
      IL_0022:  add
      IL_0023:  stloc.1
      IL_0024:  leave.s    IL_0029
    }
    finally
    {
      IL_0026:  ldnull
      IL_0027:  stloc.2
      IL_0028:  endfinally
    }
    IL_0029:  ldloc.0
    IL_002a:  callvirt   ""bool Enumerator.MoveNext()""
    IL_002f:  brtrue.s   IL_0009
    IL_0031:  leave.s    IL_003d
  }
  finally
  {
    IL_0033:  ldloc.0
    IL_0034:  brfalse.s  IL_003c
    IL_0036:  ldloc.0
    IL_0037:  callvirt   ""void System.IDisposable.Dispose()""
    IL_003c:  endfinally
  }
  IL_003d:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementInLambda1()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        System.Action a = () =>
        {
            try
            {
                fixed (char* p = ""hello"")
                {
                }
            }
            finally
            {
            }
        };
    }
}
";
            // Cleanup in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.<>c.<Test>b__0_0()", @"
{
  // Code size       26 (0x1a)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  .try
  {
    IL_0000:  ldstr      ""hello""
    IL_0005:  stloc.1
    IL_0006:  ldloc.1
    IL_0007:  conv.u
    IL_0008:  stloc.0
    IL_0009:  ldloc.0
    IL_000a:  brfalse.s  IL_0014
    IL_000c:  ldloc.0
    IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
    IL_0012:  add
    IL_0013:  stloc.0
    IL_0014:  leave.s    IL_0019
  }
  finally
  {
    IL_0016:  ldnull
    IL_0017:  stloc.1
    IL_0018:  endfinally
  }
  IL_0019:  ret
}");
        }
 
        [Fact]
        public void FixedStatementInLambda2()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        try
        {
            System.Action a = () =>
            {
                    fixed (char* p = ""hello"")
                    {
                    }
            };
        }
        finally
        {
        }
    }
}
";
            // Cleanup not in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.<>c.<Test>b__0_0()", @"
{
  // Code size       23 (0x17)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  IL_0000:  ldstr      ""hello""
  IL_0005:  stloc.1
  IL_0006:  ldloc.1
  IL_0007:  conv.u
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  brfalse.s  IL_0014
  IL_000c:  ldloc.0
  IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0012:  add
  IL_0013:  stloc.0
  IL_0014:  ldnull
  IL_0015:  stloc.1
  IL_0016:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementInLambda3()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        System.Action a = () =>
        {
            fixed (char* p = ""hello"")
            {
                goto label;
            }
          label: ;
        };
    }
}
";
            // Cleanup in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.<>c.<Test>b__0_0()", @"
{
  // Code size       26 (0x1a)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  .try
  {
    IL_0000:  ldstr      ""hello""
    IL_0005:  stloc.1
    IL_0006:  ldloc.1
    IL_0007:  conv.u
    IL_0008:  stloc.0
    IL_0009:  ldloc.0
    IL_000a:  brfalse.s  IL_0014
    IL_000c:  ldloc.0
    IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
    IL_0012:  add
    IL_0013:  stloc.0
    IL_0014:  leave.s    IL_0019
  }
  finally
  {
    IL_0016:  ldnull
    IL_0017:  stloc.1
    IL_0018:  endfinally
  }
  IL_0019:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementInFieldInitializer1()
        {
            var text = @"
unsafe class C
{
    System.Action a = () =>
        {
            try
            {
                fixed (char* p = ""hello"")
                {
                }
            }
            finally
            {
            }
        };
}
";
            // Cleanup in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.<>c.<.ctor>b__1_0()", @"
{
  // Code size       26 (0x1a)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  .try
  {
    IL_0000:  ldstr      ""hello""
    IL_0005:  stloc.1
    IL_0006:  ldloc.1
    IL_0007:  conv.u
    IL_0008:  stloc.0
    IL_0009:  ldloc.0
    IL_000a:  brfalse.s  IL_0014
    IL_000c:  ldloc.0
    IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
    IL_0012:  add
    IL_0013:  stloc.0
    IL_0014:  leave.s    IL_0019
  }
  finally
  {
    IL_0016:  ldnull
    IL_0017:  stloc.1
    IL_0018:  endfinally
  }
  IL_0019:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementInFieldInitializer2()
        {
            var text = @"
unsafe class C
{
    System.Action a = () =>
        {
            fixed (char* p = ""hello"")
            {
                goto label;
            }
            label: ;
        };
}
";
            // Cleanup in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.<>c.<.ctor>b__1_0()", @"
{
  // Code size       26 (0x1a)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  .try
  {
    IL_0000:  ldstr      ""hello""
    IL_0005:  stloc.1
    IL_0006:  ldloc.1
    IL_0007:  conv.u
    IL_0008:  stloc.0
    IL_0009:  ldloc.0
    IL_000a:  brfalse.s  IL_0014
    IL_000c:  ldloc.0
    IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
    IL_0012:  add
    IL_0013:  stloc.0
    IL_0014:  leave.s    IL_0019
  }
  finally
  {
    IL_0016:  ldnull
    IL_0017:  stloc.1
    IL_0018:  endfinally
  }
  IL_0019:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementWithBranchOut_LoopBreak()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        while(true)
        {
            fixed (char* p = ""hello"")
            {
                break;
            }
        }
    }
}
";
            // Cleanup in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       27 (0x1b)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  IL_0000:  nop
  .try
  {
    IL_0001:  ldstr      ""hello""
    IL_0006:  stloc.1
    IL_0007:  ldloc.1
    IL_0008:  conv.u
    IL_0009:  stloc.0
    IL_000a:  ldloc.0
    IL_000b:  brfalse.s  IL_0015
    IL_000d:  ldloc.0
    IL_000e:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
    IL_0013:  add
    IL_0014:  stloc.0
    IL_0015:  leave.s    IL_001a
  }
  finally
  {
    IL_0017:  ldnull
    IL_0018:  stloc.1
    IL_0019:  endfinally
  }
  IL_001a:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementWithBranchOut_LoopContinue()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        while(true)
        {
            fixed (char* p = ""hello"")
            {
                continue;
            }
        }
    }
}
";
            // Cleanup in finally.
            // CONSIDER: dev11 doesn't have a finally here, but that seems incorrect.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       26 (0x1a)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  IL_0000:  nop
  .try
  {
    IL_0001:  ldstr      ""hello""
    IL_0006:  stloc.1
    IL_0007:  ldloc.1
    IL_0008:  conv.u
    IL_0009:  stloc.0
    IL_000a:  ldloc.0
    IL_000b:  brfalse.s  IL_0015
    IL_000d:  ldloc.0
    IL_000e:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
    IL_0013:  add
    IL_0014:  stloc.0
    IL_0015:  leave.s    IL_0000
  }
  finally
  {
    IL_0017:  ldnull
    IL_0018:  stloc.1
    IL_0019:  endfinally
  }
}
");
        }
 
        [Fact]
        public void FixedStatementWithBranchOut_SwitchBreak()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        switch (1)
        {
            case 1:
                fixed (char* p = ""hello"")
                {
                    break;
                }
        }
    }
}
";
            // Cleanup in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       27 (0x1b)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  IL_0000:  nop
  .try
  {
    IL_0001:  ldstr      ""hello""
    IL_0006:  stloc.1
    IL_0007:  ldloc.1
    IL_0008:  conv.u
    IL_0009:  stloc.0
    IL_000a:  ldloc.0
    IL_000b:  brfalse.s  IL_0015
    IL_000d:  ldloc.0
    IL_000e:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
    IL_0013:  add
    IL_0014:  stloc.0
    IL_0015:  leave.s    IL_001a
  }
  finally
  {
    IL_0017:  ldnull
    IL_0018:  stloc.1
    IL_0019:  endfinally
  }
  IL_001a:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementWithBranchOut_SwitchGoto()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        switch (1)
        {
            case 1:
                fixed (char* p = ""hello"")
                {
                    goto case 1;
                }
        }
    }
}
";
            // Cleanup in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       26 (0x1a)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  IL_0000:  nop
  .try
  {
    IL_0001:  ldstr      ""hello""
    IL_0006:  stloc.1
    IL_0007:  ldloc.1
    IL_0008:  conv.u
    IL_0009:  stloc.0
    IL_000a:  ldloc.0
    IL_000b:  brfalse.s  IL_0015
    IL_000d:  ldloc.0
    IL_000e:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
    IL_0013:  add
    IL_0014:  stloc.0
    IL_0015:  leave.s    IL_0000
  }
  finally
  {
    IL_0017:  ldnull
    IL_0018:  stloc.1
    IL_0019:  endfinally
  }
}
");
        }
 
        [Fact]
        public void FixedStatementWithBranchOut_BackwardGoto()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
      label:
        fixed (char* p = ""hello"")
        {
            goto label;
        }
    }
}
";
            // Cleanup in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       26 (0x1a)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  IL_0000:  nop
  .try
  {
    IL_0001:  ldstr      ""hello""
    IL_0006:  stloc.1
    IL_0007:  ldloc.1
    IL_0008:  conv.u
    IL_0009:  stloc.0
    IL_000a:  ldloc.0
    IL_000b:  brfalse.s  IL_0015
    IL_000d:  ldloc.0
    IL_000e:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
    IL_0013:  add
    IL_0014:  stloc.0
    IL_0015:  leave.s    IL_0000
  }
  finally
  {
    IL_0017:  ldnull
    IL_0018:  stloc.1
    IL_0019:  endfinally
  }
}
");
        }
 
        [Fact]
        public void FixedStatementWithBranchOut_ForwardGoto()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        fixed (char* p = ""hello"")
        {
            goto label;
        }
      label: ;
    }
}
";
            // Cleanup in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       26 (0x1a)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  .try
  {
    IL_0000:  ldstr      ""hello""
    IL_0005:  stloc.1
    IL_0006:  ldloc.1
    IL_0007:  conv.u
    IL_0008:  stloc.0
    IL_0009:  ldloc.0
    IL_000a:  brfalse.s  IL_0014
    IL_000c:  ldloc.0
    IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
    IL_0012:  add
    IL_0013:  stloc.0
    IL_0014:  leave.s    IL_0019
  }
  finally
  {
    IL_0016:  ldnull
    IL_0017:  stloc.1
    IL_0018:  endfinally
  }
  IL_0019:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementWithBranchOut_Throw()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        fixed (char* p = ""hello"")
        {
            throw null;
        }
    }
}
";
            // Cleanup not in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       22 (0x16)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  IL_0000:  ldstr      ""hello""
  IL_0005:  stloc.1
  IL_0006:  ldloc.1
  IL_0007:  conv.u
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  brfalse.s  IL_0014
  IL_000c:  ldloc.0
  IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0012:  add
  IL_0013:  stloc.0
  IL_0014:  ldnull
  IL_0015:  throw
}
");
        }
 
        [Fact]
        public void FixedStatementWithBranchOut_Return()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        fixed (char* p = ""hello"")
        {
            return;
        }
    }
}
";
            // Cleanup not in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       21 (0x15)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  IL_0000:  ldstr      ""hello""
  IL_0005:  stloc.1
  IL_0006:  ldloc.1
  IL_0007:  conv.u
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  brfalse.s  IL_0014
  IL_000c:  ldloc.0
  IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0012:  add
  IL_0013:  stloc.0
  IL_0014:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementWithNoBranchOut_Loop()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        fixed (char* p = ""hello"")
        {
            for (int i = 0; i < 10; i++)
            {
            }
        }
    }
}
";
            // Cleanup not in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       36 (0x24)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1,
                int V_2) //i
  IL_0000:  ldstr      ""hello""
  IL_0005:  stloc.1
  IL_0006:  ldloc.1
  IL_0007:  conv.u
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  brfalse.s  IL_0014
  IL_000c:  ldloc.0
  IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0012:  add
  IL_0013:  stloc.0
  IL_0014:  ldc.i4.0
  IL_0015:  stloc.2
  IL_0016:  br.s       IL_001c
  IL_0018:  ldloc.2
  IL_0019:  ldc.i4.1
  IL_001a:  add
  IL_001b:  stloc.2
  IL_001c:  ldloc.2
  IL_001d:  ldc.i4.s   10
  IL_001f:  blt.s      IL_0018
  IL_0021:  ldnull
  IL_0022:  stloc.1
  IL_0023:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementWithNoBranchOut_InternalGoto()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        fixed (char* p = ""hello"")
        {
            goto label;
          label: ;
        }
    }
}
";
            // NOTE: Dev11 uses a finally here, but it's unnecessary.
            // From GotoChecker::VisitGOTO:
            //      We have an unrealized goto, so we do not know whether it
            //      branches out or not.  We should be conservative and assume that
            //      it does.
            // Cleanup not in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       23 (0x17)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  IL_0000:  ldstr      ""hello""
  IL_0005:  stloc.1
  IL_0006:  ldloc.1
  IL_0007:  conv.u
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  brfalse.s  IL_0014
  IL_000c:  ldloc.0
  IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0012:  add
  IL_0013:  stloc.0
  IL_0014:  ldnull
  IL_0015:  stloc.1
  IL_0016:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementWithNoBranchOut_Switch()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        fixed (char* p = ""hello"")
        {
            switch(*p)
            {
                case 'a':
                    Test();
                    goto case 'b';
                case 'b':
                    Test();
                    goto case 'c';
                case 'c':
                    Test();
                    goto case 'd';
                case 'd':
                    Test();
                    goto case 'e';
                case 'e':
                    Test();
                    goto case 'f';
                case 'f':
                    Test();
                    goto default;
                default:
                    Test();
                    break;
            }
        }
    }
}
";
            // Cleanup not in finally.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size      103 (0x67)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1,
                char V_2)
  IL_0000:  ldstr      ""hello""
  IL_0005:  stloc.1
  IL_0006:  ldloc.1
  IL_0007:  conv.u
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  brfalse.s  IL_0014
  IL_000c:  ldloc.0
  IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0012:  add
  IL_0013:  stloc.0
  IL_0014:  ldloc.0
  IL_0015:  ldind.u2
  IL_0016:  stloc.2
  IL_0017:  ldloc.2
  IL_0018:  ldc.i4.s   97
  IL_001a:  sub
  IL_001b:  switch    (
        IL_003a,
        IL_0040,
        IL_0046,
        IL_004c,
        IL_0052,
        IL_0058)
  IL_0038:  br.s       IL_005e
  IL_003a:  ldarg.0
  IL_003b:  call       ""void C.Test()""
  IL_0040:  ldarg.0
  IL_0041:  call       ""void C.Test()""
  IL_0046:  ldarg.0
  IL_0047:  call       ""void C.Test()""
  IL_004c:  ldarg.0
  IL_004d:  call       ""void C.Test()""
  IL_0052:  ldarg.0
  IL_0053:  call       ""void C.Test()""
  IL_0058:  ldarg.0
  IL_0059:  call       ""void C.Test()""
  IL_005e:  ldarg.0
  IL_005f:  call       ""void C.Test()""
  IL_0064:  ldnull
  IL_0065:  stloc.1
  IL_0066:  ret
}
");
        }
 
        [Fact]
        public void FixedStatementWithParenthesizedStringExpression()
        {
            var text = @"
unsafe class C
{
    void Test()
    {
        fixed (char* p = ((""hello"")))
        {
        }
    }
}";
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).
                VerifyIL("C.Test", @"
{
  // Code size       23 (0x17)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1)
  IL_0000:  ldstr      ""hello""
  IL_0005:  stloc.1
  IL_0006:  ldloc.1
  IL_0007:  conv.u
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  brfalse.s  IL_0014
  IL_000c:  ldloc.0
  IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0012:  add
  IL_0013:  stloc.0
  IL_0014:  ldnull
  IL_0015:  stloc.1
  IL_0016:  ret
}
");
        }
 
        #endregion Fixed statement tests
 
        #region Custom fixed statement tests
 
        [Fact]
        public void SimpleCaseOfCustomFixed()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (int* p = new Fixable())
        {
            System.Console.WriteLine(p[1]);
        }
    }
}
 
class Fixable
{
    public ref int GetPinnableReference()
    {
        return ref (new int[]{1,2,3})[0];
    }
}
 
static class FixableExt
{
    public static ref int GetPinnableReference(this Fixable self)
    {
        return ref (new int[]{1,2,3})[0];
    }
}
 
";
 
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"2", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       33 (0x21)
  .maxstack  2
  .locals init (pinned int& V_0)
  IL_0000:  newobj     ""Fixable..ctor()""
  IL_0005:  dup
  IL_0006:  brtrue.s   IL_000d
  IL_0008:  pop
  IL_0009:  ldc.i4.0
  IL_000a:  conv.u
  IL_000b:  br.s       IL_0015
  IL_000d:  call       ""ref int Fixable.GetPinnableReference()""
  IL_0012:  stloc.0
  IL_0013:  ldloc.0
  IL_0014:  conv.u
  IL_0015:  ldc.i4.4
  IL_0016:  add
  IL_0017:  ldind.i4
  IL_0018:  call       ""void System.Console.WriteLine(int)""
  IL_001d:  ldc.i4.0
  IL_001e:  conv.u
  IL_001f:  stloc.0
  IL_0020:  ret
}
");
        }
 
        [Fact]
        public void SimpleCaseOfCustomFixedExt()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (int* p = new Fixable())
        {
            System.Console.WriteLine(p[1]);
        }
    }
}
 
class Fixable
{
    public ref int GetPinnableReference<T>() => throw null;
}
 
static class FixableExt
{
    public static ref int GetPinnableReference<T>(this T self)
    {
        return ref (new int[]{1,2,3})[0];
    }
}
 
";
 
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"2", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       33 (0x21)
  .maxstack  2
  .locals init (pinned int& V_0)
  IL_0000:  newobj     ""Fixable..ctor()""
  IL_0005:  dup
  IL_0006:  brtrue.s   IL_000d
  IL_0008:  pop
  IL_0009:  ldc.i4.0
  IL_000a:  conv.u
  IL_000b:  br.s       IL_0015
  IL_000d:  call       ""ref int FixableExt.GetPinnableReference<Fixable>(Fixable)""
  IL_0012:  stloc.0
  IL_0013:  ldloc.0
  IL_0014:  conv.u
  IL_0015:  ldc.i4.4
  IL_0016:  add
  IL_0017:  ldind.i4
  IL_0018:  call       ""void System.Console.WriteLine(int)""
  IL_001d:  ldc.i4.0
  IL_001e:  conv.u
  IL_001f:  stloc.0
  IL_0020:  ret
}
");
        }
 
        [Fact]
        public void SimpleCaseOfCustomFixed_oldVersion()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (int* p = new Fixable())
        {
            System.Console.WriteLine(p[1]);
        }
    }
 
    class Fixable
    {
        public ref int GetPinnableReference()
        {
            return ref (new int[]{1,2,3})[0];
        }
    }
 
}
";
 
            var compVerifier = CreateCompilationWithMscorlib46(text, options: TestOptions.UnsafeReleaseExe, parseOptions: TestOptions.Regular7_2);
 
            compVerifier.VerifyDiagnostics(
                // (6,25): error CS8320: Feature 'extensible fixed statement' is not available in C# 7.2. Please use language version 7.3 or greater.
                //         fixed (int* p = new Fixable())
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "new Fixable()").WithArguments("extensible fixed statement", "7.3").WithLocation(6, 25)
                );
        }
 
        [Fact]
        public void SimpleCaseOfCustomFixedNull()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (int* p = (Fixable)null)
        {
            System.Console.WriteLine((int)p);
        }
    }
 
    class Fixable
    {
        public ref int GetPinnableReference()
        {
            return ref (new int[]{1,2,3})[0];
        }
    }
 
}";
 
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"0", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       26 (0x1a)
  .maxstack  1
  .locals init (pinned int& V_0)
  IL_0000:  ldnull
  IL_0001:  brtrue.s   IL_0007
  IL_0003:  ldc.i4.0
  IL_0004:  conv.u
  IL_0005:  br.s       IL_0010
  IL_0007:  ldnull
  IL_0008:  call       ""ref int C.Fixable.GetPinnableReference()""
  IL_000d:  stloc.0
  IL_000e:  ldloc.0
  IL_000f:  conv.u
  IL_0010:  conv.i4
  IL_0011:  call       ""void System.Console.WriteLine(int)""
  IL_0016:  ldc.i4.0
  IL_0017:  conv.u
  IL_0018:  stloc.0
  IL_0019:  ret
}
");
        }
 
        [Fact]
        public void SimpleCaseOfCustomFixedStruct()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (int* p = new Fixable())
        {
            System.Console.WriteLine(p[1]);
        }
    }
 
    struct Fixable
    {
        public ref int GetPinnableReference()
        {
            return ref (new int[]{1,2,3})[0];
        }
    }
 
}";
 
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"2", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       29 (0x1d)
  .maxstack  2
  .locals init (pinned int& V_0,
                C.Fixable V_1)
  IL_0000:  ldloca.s   V_1
  IL_0002:  dup
  IL_0003:  initobj    ""C.Fixable""
  IL_0009:  call       ""ref int C.Fixable.GetPinnableReference()""
  IL_000e:  stloc.0
  IL_000f:  ldloc.0
  IL_0010:  conv.u
  IL_0011:  ldc.i4.4
  IL_0012:  add
  IL_0013:  ldind.i4
  IL_0014:  call       ""void System.Console.WriteLine(int)""
  IL_0019:  ldc.i4.0
  IL_001a:  conv.u
  IL_001b:  stloc.0
  IL_001c:  ret
}
");
        }
 
        [Fact]
        public void CustomFixedStructNullable()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        Fixable? f = new Fixable();
 
        fixed (int* p = f)
        {
            System.Console.WriteLine(p[1]);
        }
    }
}
 
public struct Fixable
{
    public ref int GetPinnableReference()
    {
        return ref (new int[]{1,2,3})[0];
    }
}
 
public static class FixableExt
{
    public static ref int GetPinnableReference(this Fixable? f)
    {
        return ref f.Value.GetPinnableReference();
    }
}
 
";
 
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"2", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       49 (0x31)
  .maxstack  2
  .locals init (Fixable V_0,
            pinned int& V_1,
            Fixable? V_2)
  IL_0000:  ldloca.s   V_0
  IL_0002:  initobj    ""Fixable""
  IL_0008:  ldloc.0
  IL_0009:  newobj     ""Fixable?..ctor(Fixable)""
  IL_000e:  stloc.2
  IL_000f:  ldloca.s   V_2
  IL_0011:  call       ""bool Fixable?.HasValue.get""
  IL_0016:  brtrue.s   IL_001c
  IL_0018:  ldc.i4.0
  IL_0019:  conv.u
  IL_001a:  br.s       IL_0025
  IL_001c:  ldloc.2
  IL_001d:  call       ""ref int FixableExt.GetPinnableReference(Fixable?)""
  IL_0022:  stloc.1
  IL_0023:  ldloc.1
  IL_0024:  conv.u
  IL_0025:  ldc.i4.4
  IL_0026:  add
  IL_0027:  ldind.i4
  IL_0028:  call       ""void System.Console.WriteLine(int)""
  IL_002d:  ldc.i4.0
  IL_002e:  conv.u
  IL_002f:  stloc.1
  IL_0030:  ret
}
");
        }
 
        [Fact]
        public void CustomFixedStructNullableErr()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        Fixable? f = new Fixable();
 
        fixed (int* p = f)
        {
            System.Console.WriteLine(p[1]);
        }
    }
}
 
public struct Fixable
{
    public ref int GetPinnableReference()
    {
        return ref (new int[]{1,2,3})[0];
    }
}
 
";
 
            var compVerifier = CreateCompilationWithMscorlib46(text, options: TestOptions.UnsafeReleaseExe);
 
            compVerifier.VerifyDiagnostics(
                // (8,25): error CS9385: The given expression cannot be used in a fixed statement
                //         fixed (int* p = f)
                Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "f").WithLocation(8, 25)
                );
        }
 
        [Fact]
        public void CustomFixedErrAmbiguous()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (int* p = new Fixable(1))
        {
            System.Console.Write(p[1]);
        }
 
        var f = new Fixable(1);
        fixed (int* p = f)
        {
            System.Console.Write(p[2]);
        }
    }
}
 
public struct Fixable
{
    public Fixable(int arg){}
}
 
public static class FixableExt
{
    public static ref readonly int GetPinnableReference(in this Fixable f)
    {
        return ref (new int[]{1,2,3})[0];
    }
}
 
public static class FixableExt1
{
    public static ref readonly int GetPinnableReference(in this Fixable f)
    {
        return ref (new int[]{1,2,3})[0];
    }
}
";
 
            var compVerifier = CreateCompilationWithMscorlib46(text, options: TestOptions.UnsafeReleaseExe);
 
            compVerifier.VerifyDiagnostics(
                // (6,25): error CS0121: The call is ambiguous between the following methods or properties: 'FixableExt.GetPinnableReference(in Fixable)' and 'FixableExt1.GetPinnableReference(in Fixable)'
                //         fixed (int* p = new Fixable(1))
                Diagnostic(ErrorCode.ERR_AmbigCall, "new Fixable(1)").WithArguments("FixableExt.GetPinnableReference(in Fixable)", "FixableExt1.GetPinnableReference(in Fixable)").WithLocation(6, 25),
                // (6,25): error CS9385: The given expression cannot be used in a fixed statement
                //         fixed (int* p = new Fixable(1))
                Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new Fixable(1)").WithLocation(6, 25),
                // (12,25): error CS0121: The call is ambiguous between the following methods or properties: 'FixableExt.GetPinnableReference(in Fixable)' and 'FixableExt1.GetPinnableReference(in Fixable)'
                //         fixed (int* p = f)
                Diagnostic(ErrorCode.ERR_AmbigCall, "f").WithArguments("FixableExt.GetPinnableReference(in Fixable)", "FixableExt1.GetPinnableReference(in Fixable)").WithLocation(12, 25),
                // (12,25): error CS9385: The given expression cannot be used in a fixed statement
                //         fixed (int* p = f)
                Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "f").WithLocation(12, 25)
                );
        }
 
        [Fact]
        public void CustomFixedErrDynamic()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (int* p = (dynamic)(new Fixable(1)))
        {
            System.Console.Write(p[1]);
        }
    }
}
 
public struct Fixable
{
    public Fixable(int arg){}
}
 
public static class FixableExt
{
    public static ref readonly int GetPinnableReference(in this Fixable f)
    {
        return ref (new int[]{1,2,3})[0];
    }
}
";
 
            var compVerifier = CreateCompilationWithMscorlib46(text, options: TestOptions.UnsafeReleaseExe);
 
            compVerifier.VerifyDiagnostics(
                // (6,25): error CS9385: The given expression cannot be used in a fixed statement
                //         fixed (int* p = (dynamic)(new Fixable(1)))
                Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "(dynamic)(new Fixable(1))").WithLocation(6, 25)
                );
        }
 
        [Fact]
        public void CustomFixedErrBad()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (int* p = (HocusPocus)(new Fixable(1)))
        {
            System.Console.Write(p[1]);
        }
    }
}
 
public struct Fixable
{
    public Fixable(int arg){}
}
 
public static class FixableExt
{
    public static ref readonly int GetPinnableReference(in this Fixable f)
    {
        return ref (new int[]{1,2,3})[0];
    }
}
";
 
            var compVerifier = CreateCompilationWithMscorlib46(text, options: TestOptions.UnsafeReleaseExe);
 
            compVerifier.VerifyDiagnostics(
                // (6,26): error CS0246: The type or namespace name 'HocusPocus' could not be found (are you missing a using directive or an assembly reference?)
                //         fixed (int* p = (HocusPocus)(new Fixable(1)))
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "HocusPocus").WithArguments("HocusPocus").WithLocation(6, 26)
                );
        }
 
        [Fact]
        public void SimpleCaseOfCustomFixedGeneric()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        Test(42);
        Test((object)null);
    }
 
    public static void Test<T>(T arg)
    {
        fixed (int* p = arg)
        {
            System.Console.Write(p == null? 0: p[1]);
        }
    }
}
 
static class FixAllExt
{
    public static ref int GetPinnableReference<T>(this T dummy)
    {
        return ref (new int[]{1,2,3})[0];
    }
}
";
 
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"20", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Test<T>(T)", @"
{
  // Code size       49 (0x31)
  .maxstack  2
  .locals init (int* V_0, //p
                pinned int& V_1)
  IL_0000:  ldarg.0
  IL_0001:  box        ""T""
  IL_0006:  brtrue.s   IL_000c
  IL_0008:  ldc.i4.0
  IL_0009:  conv.u
  IL_000a:  br.s       IL_001b
  IL_000c:  ldarga.s   V_0
  IL_000e:  ldobj      ""T""
  IL_0013:  call       ""ref int FixAllExt.GetPinnableReference<T>(T)""
  IL_0018:  stloc.1
  IL_0019:  ldloc.1
  IL_001a:  conv.u
  IL_001b:  stloc.0
  IL_001c:  ldloc.0
  IL_001d:  ldc.i4.0
  IL_001e:  conv.u
  IL_001f:  beq.s      IL_0027
  IL_0021:  ldloc.0
  IL_0022:  ldc.i4.4
  IL_0023:  add
  IL_0024:  ldind.i4
  IL_0025:  br.s       IL_0028
  IL_0027:  ldc.i4.0
  IL_0028:  call       ""void System.Console.Write(int)""
  IL_002d:  ldc.i4.0
  IL_002e:  conv.u
  IL_002f:  stloc.1
  IL_0030:  ret
}
");
        }
 
        [Fact]
        public void CustomFixedStructSideeffects()
        {
            var text = @"
    unsafe class C
    {
        public static void Main()
        {
            var b = new FixableStruct();
            Test(ref b);
            System.Console.WriteLine(b.x);
        }
 
        public static void Test(ref FixableStruct arg)
        {
            fixed (int* p = arg)
            {
                System.Console.Write(p[1]);
            }
        }
    }
 
    struct FixableStruct
    {
        public int x;
 
        public ref int GetPinnableReference()
        {
            x = 456;
            return ref (new int[] { 4, 5, 6 })[0];
        }
    }
";
 
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails, expectedOutput: @"5456");
 
            compVerifier.VerifyIL("C.Test(ref FixableStruct)", @"
{
  // Code size       21 (0x15)
  .maxstack  2
  .locals init (pinned int& V_0)
  IL_0000:  ldarg.0
  IL_0001:  call       ""ref int FixableStruct.GetPinnableReference()""
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  conv.u
  IL_0009:  ldc.i4.4
  IL_000a:  add
  IL_000b:  ldind.i4
  IL_000c:  call       ""void System.Console.Write(int)""
  IL_0011:  ldc.i4.0
  IL_0012:  conv.u
  IL_0013:  stloc.0
  IL_0014:  ret
}
");
        }
 
        [Fact]
        public void CustomFixedClassSideeffects()
        {
            var text = @"
    using System;
    unsafe class C
    {
        public static void Main()
        {
            var b = new FixableClass();
            Test(ref b);
            System.Console.WriteLine(b.x);
        }
 
        public static void Test(ref FixableClass arg)
        {
            fixed (int* p = arg)
            {
                System.Console.Write(p[1]);
            }
        }
    }
 
    class FixableClass
    {
        public int x;
 
        [Obsolete]
        public ref int GetPinnableReference()
        {
            x = 456;
            return ref (new int[] { 4, 5, 6 })[0];
        }
    }
";
 
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails, expectedOutput: @"5456");
 
            compVerifier.VerifyDiagnostics(
                // (14,29): warning CS0612: 'FixableClass.GetPinnableReference()' is obsolete
                //             fixed (int* p = arg)
                Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "arg").WithArguments("FixableClass.GetPinnableReference()").WithLocation(14, 29)
                );
 
            // note that defensive copy is created
            compVerifier.VerifyIL("C.Test(ref FixableClass)", @"
{
  // Code size       30 (0x1e)
  .maxstack  2
  .locals init (pinned int& V_0)
  IL_0000:  ldarg.0
  IL_0001:  ldind.ref
  IL_0002:  dup
  IL_0003:  brtrue.s   IL_000a
  IL_0005:  pop
  IL_0006:  ldc.i4.0
  IL_0007:  conv.u
  IL_0008:  br.s       IL_0012
  IL_000a:  call       ""ref int FixableClass.GetPinnableReference()""
  IL_000f:  stloc.0
  IL_0010:  ldloc.0
  IL_0011:  conv.u
  IL_0012:  ldc.i4.4
  IL_0013:  add
  IL_0014:  ldind.i4
  IL_0015:  call       ""void System.Console.Write(int)""
  IL_001a:  ldc.i4.0
  IL_001b:  conv.u
  IL_001c:  stloc.0
  IL_001d:  ret
}
");
        }
 
        [Fact]
        public void CustomFixedGenericSideeffects()
        {
            var text = @"
    unsafe class C
    {
        public static void Main()
        {
            var a = new FixableClass();
            Test(ref a);
            System.Console.WriteLine(a.x);
            var b = new FixableStruct();
            Test(ref b);
            System.Console.WriteLine(b.x);
        }
 
        public static void Test<T>(ref T arg) where T: IFixable
        {
            fixed (int* p = arg)
            {
                System.Console.Write(p[1]);
            }
        }
    }
 
    interface IFixable
    {
        ref int GetPinnableReference();
    }
 
    class FixableClass : IFixable
    {
 
        public int x;
 
        public ref int GetPinnableReference()
        {
            x = 123;
            return ref (new int[] { 1, 2, 3 })[0];
        }
    }
 
    struct FixableStruct : IFixable
    {
        public int x;
 
        public ref int GetPinnableReference()
        {
            x = 456;
            return ref (new int[] { 4, 5, 6 })[0];
        }
    }
";
 
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails, expectedOutput: @"2123
5456");
 
            compVerifier.VerifyIL("C.Test<T>(ref T)", @"
{
  // Code size       64 (0x40)
  .maxstack  2
  .locals init (pinned int& V_0,
                T V_1)
  IL_0000:  ldarg.0
  IL_0001:  ldloca.s   V_1
  IL_0003:  initobj    ""T""
  IL_0009:  ldloc.1
  IL_000a:  box        ""T""
  IL_000f:  brtrue.s   IL_0026
  IL_0011:  ldobj      ""T""
  IL_0016:  stloc.1
  IL_0017:  ldloca.s   V_1
  IL_0019:  ldloc.1
  IL_001a:  box        ""T""
  IL_001f:  brtrue.s   IL_0026
  IL_0021:  pop
  IL_0022:  ldc.i4.0
  IL_0023:  conv.u
  IL_0024:  br.s       IL_0034
  IL_0026:  constrained. ""T""
  IL_002c:  callvirt   ""ref int IFixable.GetPinnableReference()""
  IL_0031:  stloc.0
  IL_0032:  ldloc.0
  IL_0033:  conv.u
  IL_0034:  ldc.i4.4
  IL_0035:  add
  IL_0036:  ldind.i4
  IL_0037:  call       ""void System.Console.Write(int)""
  IL_003c:  ldc.i4.0
  IL_003d:  conv.u
  IL_003e:  stloc.0
  IL_003f:  ret
}
");
        }
 
        [Fact]
        public void CustomFixedGenericRefExtension()
        {
            var text = @"
    unsafe class C
    {
        public static void Main()
        {
            var b = new FixableStruct();
            Test(ref b);
            System.Console.WriteLine(b.x);
        }
 
        public static void Test<T>(ref T arg) where T: struct, IFixable
        {
            fixed (int* p = arg)
            {
                System.Console.Write(p[1]);
            }
        }
    }
 
    public interface IFixable
    {
        ref int GetPinnableReferenceImpl();
    }
 
    public struct FixableStruct : IFixable
    {
        public int x;
 
        public ref int GetPinnableReferenceImpl()
        {
            x = 456;
            return ref (new int[] { 4, 5, 6 })[0];
        }
    }
 
    public static class FixableExt
    {
        public static ref int GetPinnableReference<T>(ref this T f) where T: struct, IFixable
        {
            return ref f.GetPinnableReferenceImpl();
        }
    }
";
 
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails, expectedOutput: @"5456");
 
            compVerifier.VerifyIL("C.Test<T>(ref T)", @"
{
  // Code size       21 (0x15)
  .maxstack  2
  .locals init (pinned int& V_0)
  IL_0000:  ldarg.0
  IL_0001:  call       ""ref int FixableExt.GetPinnableReference<T>(ref T)""
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  conv.u
  IL_0009:  ldc.i4.4
  IL_000a:  add
  IL_000b:  ldind.i4
  IL_000c:  call       ""void System.Console.Write(int)""
  IL_0011:  ldc.i4.0
  IL_0012:  conv.u
  IL_0013:  stloc.0
  IL_0014:  ret
}
");
        }
 
        [Fact]
        public void CustomFixedStructInExtension()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (int* p = new Fixable(1))
        {
            System.Console.Write(p[1]);
        }
 
        var f = new Fixable(1);
        fixed (int* p = f)
        {
            System.Console.Write(p[2]);
        }
    }
}
 
public struct Fixable
{
    public Fixable(int arg){}
}
 
public static class FixableExt
{
    public static ref readonly int GetPinnableReference(in this Fixable f)
    {
        return ref (new int[]{1,2,3})[0];
    }
}
 
";
 
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"23", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       61 (0x3d)
  .maxstack  3
  .locals init (Fixable V_0, //f
                pinned int& V_1,
                Fixable V_2)
  IL_0000:  ldc.i4.1
  IL_0001:  newobj     ""Fixable..ctor(int)""
  IL_0006:  stloc.2
  IL_0007:  ldloca.s   V_2
  IL_0009:  call       ""ref readonly int FixableExt.GetPinnableReference(in Fixable)""
  IL_000e:  stloc.1
  IL_000f:  ldloc.1
  IL_0010:  conv.u
  IL_0011:  ldc.i4.4
  IL_0012:  add
  IL_0013:  ldind.i4
  IL_0014:  call       ""void System.Console.Write(int)""
  IL_0019:  ldc.i4.0
  IL_001a:  conv.u
  IL_001b:  stloc.1
  IL_001c:  ldloca.s   V_0
  IL_001e:  ldc.i4.1
  IL_001f:  call       ""Fixable..ctor(int)""
  IL_0024:  ldloca.s   V_0
  IL_0026:  call       ""ref readonly int FixableExt.GetPinnableReference(in Fixable)""
  IL_002b:  stloc.1
  IL_002c:  ldloc.1
  IL_002d:  conv.u
  IL_002e:  ldc.i4.2
  IL_002f:  conv.i
  IL_0030:  ldc.i4.4
  IL_0031:  mul
  IL_0032:  add
  IL_0033:  ldind.i4
  IL_0034:  call       ""void System.Console.Write(int)""
  IL_0039:  ldc.i4.0
  IL_003a:  conv.u
  IL_003b:  stloc.1
  IL_003c:  ret
}
");
        }
 
        [Fact]
        public void CustomFixedStructRefExtension()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        var f = new Fixable(1);
        fixed (int* p = f)
        {
            System.Console.Write(p[2]);
        }
    }
}
 
public struct Fixable
{
    public Fixable(int arg){}
}
 
public static class FixableExt
{
    public static ref int GetPinnableReference(ref this Fixable f)
    {
        return ref (new int[]{1,2,3})[0];
    }
}
 
";
 
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"3", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       33 (0x21)
  .maxstack  3
  .locals init (Fixable V_0, //f
                pinned int& V_1)
  IL_0000:  ldloca.s   V_0
  IL_0002:  ldc.i4.1
  IL_0003:  call       ""Fixable..ctor(int)""
  IL_0008:  ldloca.s   V_0
  IL_000a:  call       ""ref int FixableExt.GetPinnableReference(ref Fixable)""
  IL_000f:  stloc.1
  IL_0010:  ldloc.1
  IL_0011:  conv.u
  IL_0012:  ldc.i4.2
  IL_0013:  conv.i
  IL_0014:  ldc.i4.4
  IL_0015:  mul
  IL_0016:  add
  IL_0017:  ldind.i4
  IL_0018:  call       ""void System.Console.Write(int)""
  IL_001d:  ldc.i4.0
  IL_001e:  conv.u
  IL_001f:  stloc.1
  IL_0020:  ret
}
");
        }
 
        [Fact]
        public void CustomFixedStructRefExtensionErr()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (int* p = new Fixable(1))
        {
            System.Console.Write(p[1]);
        }
    }
}
 
public struct Fixable
{
    public Fixable(int arg){}
}
 
public static class FixableExt
{
    public static ref int GetPinnableReference(ref this Fixable f)
    {
        return ref (new int[]{1,2,3})[0];
    }
}
 
";
 
            var compVerifier = CreateCompilationWithMscorlib46(text, options: TestOptions.UnsafeReleaseExe);
 
            compVerifier.VerifyDiagnostics(
                // (6,25): error CS1510: A ref or out value must be an assignable variable
                //         fixed (int* p = new Fixable(1))
                Diagnostic(ErrorCode.ERR_RefLvalueExpected, "new Fixable(1)").WithLocation(6, 25),
                // (6,25): error CS9385: The given expression cannot be used in a fixed statement
                //         fixed (int* p = new Fixable(1))
                Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new Fixable(1)").WithLocation(6, 25)
                );
        }
 
        [Fact]
        public void CustomFixedStructVariousErr01()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (int* p = new Fixable(1))
        {
            System.Console.Write(p[1]);
        }
    }
}
 
public struct Fixable
{
    public Fixable(int arg){}
}
 
public static class FixableExt
{
    private static ref int GetPinnableReference(this Fixable f)
    {
        return ref (new int[]{1,2,3})[0];
    }
}
 
";
 
            var compVerifier = CreateCompilationWithMscorlib46(text, options: TestOptions.UnsafeReleaseExe);
 
            compVerifier.VerifyDiagnostics(
                // (6,25): error CS8385: The given expression cannot be used in a fixed statement
                //         fixed (int* p = new Fixable(1))
                Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new Fixable(1)").WithLocation(6, 25)
                );
        }
 
        [Fact]
        public void CustomFixedStructVariousErr01_oldVersion()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (int* p = new Fixable(1))
        {
            System.Console.Write(p[1]);
        }
    }
}
 
public struct Fixable
{
    public Fixable(int arg){}
}
 
public static class FixableExt
{
    private static ref int GetPinnableReference(this Fixable f)
    {
        return ref (new int[]{1,2,3})[0];
    }
}
 
";
 
            var compVerifier = CreateCompilationWithMscorlib46(text, options: TestOptions.UnsafeReleaseExe, parseOptions: TestOptions.Regular7_2);
 
            compVerifier.VerifyDiagnostics(
                // (6,25): error CS9385: The given expression cannot be used in a fixed statement
                //         fixed (int* p = new Fixable(1))
                Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new Fixable(1)").WithLocation(6, 25)
                );
        }
 
        [Fact]
        public void CustomFixedStructVariousErr02()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (int* p = new Fixable(1))
        {
            System.Console.Write(p[1]);
        }
    }
}
 
public struct Fixable
{
    public Fixable(int arg){}
 
    public static ref int GetPinnableReference()
    {
        return ref (new int[]{1,2,3})[0];
    }
}
 
";
 
            var compVerifier = CreateCompilationWithMscorlib46(text, options: TestOptions.UnsafeReleaseExe);
 
            compVerifier.VerifyDiagnostics(
                // (6,25): error CS9385: The given expression cannot be used in a fixed statement
                //         fixed (int* p = new Fixable(1))
                Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new Fixable(1)").WithLocation(6, 25),
                // (6,25): error CS0176: Member 'Fixable.GetPinnableReference()' cannot be accessed with an instance reference; qualify it with a type name instead
                //         fixed (int* p = new Fixable(1))
                Diagnostic(ErrorCode.ERR_ObjectProhibited, "new Fixable(1)").WithArguments("Fixable.GetPinnableReference()").WithLocation(6, 25)
                );
        }
 
        [Fact]
        public void CustomFixedStructVariousErr03()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (int* p = new Fixable(1))
        {
            System.Console.Write(p[1]);
        }
    }
}
 
public struct Fixable
{
    public Fixable(int arg){}
 
    public ref int GetPinnableReference => ref (new int[]{1,2,3})[0];
}
 
";
 
            var compVerifier = CreateCompilationWithMscorlib46(text, options: TestOptions.UnsafeReleaseExe);
 
            compVerifier.VerifyDiagnostics(
                // (6,25): error CS1955: Non-invocable member 'Fixable.GetPinnableReference' cannot be used like a method.
                //         fixed (int* p = new Fixable(1))
                Diagnostic(ErrorCode.ERR_NonInvocableMemberCalled, "new Fixable(1)").WithArguments("Fixable.GetPinnableReference").WithLocation(6, 25),
                // (6,25): error CS9385: The given expression cannot be used in a fixed statement
                //         fixed (int* p = new Fixable(1))
                Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new Fixable(1)").WithLocation(6, 25)
                );
        }
 
        [Fact]
        public void CustomFixedStructVariousErr04()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (int* p = new Fixable(1))
        {
            System.Console.Write(p[1]);
        }
    }
}
 
public struct Fixable
{
    public Fixable(int arg){}
 
    public ref int GetPinnableReference<T>() => ref (new int[]{1,2,3})[0];
}
 
";
 
            var compVerifier = CreateCompilationWithMscorlib46(text, options: TestOptions.UnsafeReleaseExe);
 
            compVerifier.VerifyDiagnostics(
                // (6,25): error CS0411: The type arguments for method 'Fixable.GetPinnableReference<T>()' cannot be inferred from the usage. Try specifying the type arguments explicitly.
                //         fixed (int* p = new Fixable(1))
                Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "new Fixable(1)").WithArguments("Fixable.GetPinnableReference<T>()").WithLocation(6, 25),
                // (6,25): error CS9385: The given expression cannot be used in a fixed statement
                //         fixed (int* p = new Fixable(1))
                Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new Fixable(1)").WithLocation(6, 25)
                );
        }
 
        [Fact]
        public void CustomFixedStructVariousErr05_Obsolete()
        {
            var text = @"
using System;
 
unsafe class C
{
    public static void Main()
    {
        fixed (int* p = new Fixable(1))
        {
            System.Console.Write(p[1]);
        }
    }
}
 
public struct Fixable
{
    public Fixable(int arg){}
 
    [Obsolete(""hi"", true)]
    public ref int GetPinnableReference() => ref (new int[]{1,2,3})[0];
}
 
";
 
            var compVerifier = CreateCompilationWithMscorlib46(text, options: TestOptions.UnsafeReleaseExe);
 
            compVerifier.VerifyDiagnostics(
                // (8,25): error CS0619: 'Fixable.GetPinnableReference()' is obsolete: 'hi'
                //         fixed (int* p = new Fixable(1))
                Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "new Fixable(1)").WithArguments("Fixable.GetPinnableReference()", "hi").WithLocation(8, 25)
                );
        }
 
        [Fact]
        public void CustomFixedStructVariousErr06_UseSite()
        {
            var missing_cs = "public struct Missing { }";
            var missing = CreateCompilationWithMscorlib461(missing_cs, options: TestOptions.DebugDll, assemblyName: "missing");
 
            var lib_cs = @"
public struct Fixable
{
    public Fixable(int arg){}
 
    public ref Missing GetPinnableReference() => throw null;
}
";
 
            var lib = CreateCompilationWithMscorlib461(lib_cs, references: new[] { missing.EmitToImageReference() }, options: TestOptions.DebugDll);
 
            var source =
@"
unsafe class C
{
    public static void Main()
    {
        fixed (void* p = new Fixable(1))
        {
        }
    }
}
";
 
            var comp = CreateCompilationWithMscorlib461(source, references: new[] { lib.EmitToImageReference() }, options: TestOptions.UnsafeDebugDll);
            comp.VerifyDiagnostics(
                // (6,26): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
                //         fixed (void* p = new Fixable(1))
                Diagnostic(ErrorCode.ERR_NoTypeDef, "new Fixable(1)").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(6, 26),
                // (6,26): error CS9385: The given expression cannot be used in a fixed statement
                //         fixed (void* p = new Fixable(1))
                Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new Fixable(1)").WithLocation(6, 26)
                );
        }
 
        [Fact]
        public void CustomFixedStructVariousErr07_Optional()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (int* p = new Fixable(1))
        {
            System.Console.Write(p[1]);
        }
    }
}
 
public struct Fixable
{
    public Fixable(int arg){}
 
    public ref int GetPinnableReference(int x = 0) => ref (new int[]{1,2,3})[0];
}
 
";
 
            var compVerifier = CreateCompilationWithMscorlib46(text, options: TestOptions.UnsafeReleaseExe);
 
            compVerifier.VerifyDiagnostics(
                // (6,25): warning CS0280: 'Fixable' does not implement the 'fixed' pattern. 'Fixable.GetPinnableReference(int)' has the wrong signature.
                //         fixed (int* p = new Fixable(1))
                Diagnostic(ErrorCode.WRN_PatternBadSignature, "new Fixable(1)").WithArguments("Fixable", "fixed", "Fixable.GetPinnableReference(int)").WithLocation(6, 25),
                // (6,25): error CS9385: The given expression cannot be used in a fixed statement
                //         fixed (int* p = new Fixable(1))
                Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new Fixable(1)").WithLocation(6, 25)
                );
        }
 
        [Fact]
        public void FixStringMissingAllHelpers()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (char* p = string.Empty)
        {
        }
    }
}
 
";
 
            var comp = CreateCompilationWithMscorlib46(text, options: TestOptions.UnsafeReleaseExe);
            comp.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__get_OffsetToStringData);
 
            comp.VerifyEmitDiagnostics(
                // (6,26): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RuntimeHelpers.get_OffsetToStringData'
                //         fixed (char* p = string.Empty)
                Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "string.Empty").WithArguments("System.Runtime.CompilerServices.RuntimeHelpers", "get_OffsetToStringData").WithLocation(6, 26)
                );
        }
 
        [Fact]
        public void FixStringArrayExtensionHelpersIgnored()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (char* p = ""A"")
        {
            *p = default;
        }
 
        fixed (char* p = new char[1])
        {
            *p = default;
        }
    }
}
 
public static class FixableExt
{
    public static ref char GetPinnableReference(this string self) => throw null;
    public static ref char GetPinnableReference(this char[] self) => throw null;
}
";
 
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails, expectedOutput: @"");
 
            compVerifier.VerifyIL("C.Main()", @"
{
  // Code size       60 (0x3c)
  .maxstack  2
  .locals init (char* V_0, //p
                pinned string V_1,
                char* V_2, //p
                pinned char[] V_3)
  IL_0000:  ldstr      ""A""
  IL_0005:  stloc.1
  IL_0006:  ldloc.1
  IL_0007:  conv.u
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  brfalse.s  IL_0014
  IL_000c:  ldloc.0
  IL_000d:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0012:  add
  IL_0013:  stloc.0
  IL_0014:  ldloc.0
  IL_0015:  ldc.i4.0
  IL_0016:  stind.i2
  IL_0017:  ldnull
  IL_0018:  stloc.1
  IL_0019:  ldc.i4.1
  IL_001a:  newarr     ""char""
  IL_001f:  dup
  IL_0020:  stloc.3
  IL_0021:  brfalse.s  IL_0028
  IL_0023:  ldloc.3
  IL_0024:  ldlen
  IL_0025:  conv.i4
  IL_0026:  brtrue.s   IL_002d
  IL_0028:  ldc.i4.0
  IL_0029:  conv.u
  IL_002a:  stloc.2
  IL_002b:  br.s       IL_0036
  IL_002d:  ldloc.3
  IL_002e:  ldc.i4.0
  IL_002f:  ldelema    ""char""
  IL_0034:  conv.u
  IL_0035:  stloc.2
  IL_0036:  ldloc.2
  IL_0037:  ldc.i4.0
  IL_0038:  stind.i2
  IL_0039:  ldnull
  IL_003a:  stloc.3
  IL_003b:  ret
}
");
        }
 
        [Fact]
        public void CustomFixedDelegateErr()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (int* p = new Fixable())
        {
            System.Console.Write(p[1]);
        }
    }
}
 
public delegate ref int ReturnsRef();
 
public struct Fixable
{
    public Fixable(int arg){}
 
    public ReturnsRef GetPinnableReference => null;
}
 
";
 
            var compVerifier = CreateCompilationWithMscorlib46(text, options: TestOptions.UnsafeReleaseExe);
 
            compVerifier.VerifyDiagnostics(
                // (6,25): error CS9385: The given expression cannot be used in a fixed statement
                //         fixed (int* p = new Fixable())
                Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new Fixable()").WithLocation(6, 25)
                );
        }
 
        [Fact]
        [WorkItem("https://github.com/dotnet/roslyn/issues/66167")]
        public void Issue66167_01()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        Test((int?)null);
        Test2((int?)null);
    }
 
    public static void Test<T>(T arg)
    {
        fixed (int* p = arg)
        {
            System.Console.Write(p == null? 0: p[1]);
        }
    }
    public static void Test2(int? arg)
    {
        fixed (int* p = arg)
        {
            System.Console.Write(p == null? 0: p[1]);
        }
    }
}
 
static class FixAllExt
{
    public static ref int GetPinnableReference<T>(this T dummy)
    {
        return ref (new int[]{1,2,3})[0];
    }
}
";
 
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"00", verify: Verification.Fails);
 
            compVerifier.VerifyIL("C.Test<T>(T)", @"
{
  // Code size       49 (0x31)
  .maxstack  2
  .locals init (int* V_0, //p
                pinned int& V_1)
  IL_0000:  ldarg.0
  IL_0001:  box        ""T""
  IL_0006:  brtrue.s   IL_000c
  IL_0008:  ldc.i4.0
  IL_0009:  conv.u
  IL_000a:  br.s       IL_001b
  IL_000c:  ldarga.s   V_0
  IL_000e:  ldobj      ""T""
  IL_0013:  call       ""ref int FixAllExt.GetPinnableReference<T>(T)""
  IL_0018:  stloc.1
  IL_0019:  ldloc.1
  IL_001a:  conv.u
  IL_001b:  stloc.0
  IL_001c:  ldloc.0
  IL_001d:  ldc.i4.0
  IL_001e:  conv.u
  IL_001f:  beq.s      IL_0027
  IL_0021:  ldloc.0
  IL_0022:  ldc.i4.4
  IL_0023:  add
  IL_0024:  ldind.i4
  IL_0025:  br.s       IL_0028
  IL_0027:  ldc.i4.0
  IL_0028:  call       ""void System.Console.Write(int)""
  IL_002d:  ldc.i4.0
  IL_002e:  conv.u
  IL_002f:  stloc.1
  IL_0030:  ret
}
");
 
            compVerifier.VerifyIL("C.Test2(int?)", @"
{
  // Code size       46 (0x2e)
  .maxstack  2
  .locals init (int* V_0, //p
                pinned int& V_1,
                int? V_2)
  IL_0000:  ldarg.0
  IL_0001:  stloc.2
  IL_0002:  ldloca.s   V_2
  IL_0004:  call       ""bool int?.HasValue.get""
  IL_0009:  brtrue.s   IL_000f
  IL_000b:  ldc.i4.0
  IL_000c:  conv.u
  IL_000d:  br.s       IL_0018
  IL_000f:  ldloc.2
  IL_0010:  call       ""ref int FixAllExt.GetPinnableReference<int?>(int?)""
  IL_0015:  stloc.1
  IL_0016:  ldloc.1
  IL_0017:  conv.u
  IL_0018:  stloc.0
  IL_0019:  ldloc.0
  IL_001a:  ldc.i4.0
  IL_001b:  conv.u
  IL_001c:  beq.s      IL_0024
  IL_001e:  ldloc.0
  IL_001f:  ldc.i4.4
  IL_0020:  add
  IL_0021:  ldind.i4
  IL_0022:  br.s       IL_0025
  IL_0024:  ldc.i4.0
  IL_0025:  call       ""void System.Console.Write(int)""
  IL_002a:  ldc.i4.0
  IL_002b:  conv.u
  IL_002c:  stloc.1
  IL_002d:  ret
}
");
        }
 
        [Fact]
        [WorkItem("https://github.com/dotnet/roslyn/issues/66167")]
        public void Issue66167_02()
        {
            var text = @"
unsafe class C
{
    public static void Main()
    {
        fixed (int* p = new S1())
        {
        }
 
        fixed (int* p = new S1?())
        {
        }
 
        fixed (int* p = new S2())
        {
        }
 
        fixed (int* p = new S2?())
        {
        }
    }
}
 
struct S1
{
    public ref int GetPinnableReference()
    {
        return ref (new int[]{1,2,3})[0];
    }
}
 
struct S2
{
}
 
static class FixAllExt
{
    public static ref int GetPinnableReference(this S2 dummy)
    {
        return ref (new int[]{1,2,3})[0];
    }
}
";
 
            var comp = CreateCompilation(text, options: TestOptions.UnsafeReleaseExe);
 
            comp.VerifyDiagnostics(
                // (10,25): error CS1929: 'S1?' does not contain a definition for 'GetPinnableReference' and the best extension method overload 'FixAllExt.GetPinnableReference(S2)' requires a receiver of type 'S2'
                //         fixed (int* p = new S1?())
                Diagnostic(ErrorCode.ERR_BadInstanceArgType, "new S1?()").WithArguments("S1?", "GetPinnableReference", "FixAllExt.GetPinnableReference(S2)", "S2").WithLocation(10, 25),
                // (10,25): error CS8385: The given expression cannot be used in a fixed statement
                //         fixed (int* p = new S1?())
                Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new S1?()").WithLocation(10, 25),
                // (18,25): error CS1929: 'S2?' does not contain a definition for 'GetPinnableReference' and the best extension method overload 'FixAllExt.GetPinnableReference(S2)' requires a receiver of type 'S2'
                //         fixed (int* p = new S2?())
                Diagnostic(ErrorCode.ERR_BadInstanceArgType, "new S2?()").WithArguments("S2?", "GetPinnableReference", "FixAllExt.GetPinnableReference(S2)", "S2").WithLocation(18, 25),
                // (18,25): error CS8385: The given expression cannot be used in a fixed statement
                //         fixed (int* p = new S2?())
                Diagnostic(ErrorCode.ERR_ExprCannotBeFixed, "new S2?()").WithLocation(18, 25)
                );
        }
 
        #endregion Custom fixed statement tests
 
        #region Pointer conversion tests
 
        [Fact]
        public void ConvertNullToPointer()
        {
            var template = @"
using System;
 
unsafe class C
{{
    static void Main()
    {{
        {0}
        {{
            char ch = 'a';
            char* p = &ch;
            Console.WriteLine(p == null);
 
            p = null;
            Console.WriteLine(p == null);
        }}
    }}
}}
";
 
            var expectedIL = @"
{
  // Code size       31 (0x1f)
  .maxstack  2
  .locals init (char V_0, //ch
      char* V_1) //p
  IL_0000:  ldc.i4.s   97
  IL_0002:  stloc.0
  IL_0003:  ldloca.s   V_0
  IL_0005:  conv.u
  IL_0006:  stloc.1
  IL_0007:  ldloc.1
  IL_0008:  ldc.i4.0
  IL_0009:  conv.u
  IL_000a:  ceq
  IL_000c:  call       ""void System.Console.WriteLine(bool)""
  IL_0011:  ldc.i4.0
  IL_0012:  conv.u
  IL_0013:  stloc.1
  IL_0014:  ldloc.1
  IL_0015:  ldc.i4.0
  IL_0016:  conv.u
  IL_0017:  ceq
  IL_0019:  call       ""void System.Console.WriteLine(bool)""
  IL_001e:  ret
}
";
            var expectedOutput = @"False
True";
 
            CompileAndVerify(string.Format(template, "unchecked"), options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyIL("C.Main", expectedIL);
            CompileAndVerify(string.Format(template, "checked"), options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyIL("C.Main", expectedIL);
        }
 
        [Fact]
        public void ConvertPointerToPointerOrVoid()
        {
            var template = @"
using System;
 
unsafe class C
{{
    static void Main()
    {{
        {0}
        {{
            char ch = 'a';
            char* c1 = &ch;
            void* v1 = c1;
            void* v2 = (void**)v1;
            char* c2 = (char*)v2;
            Console.WriteLine(*c2);
        }}
    }}
}}
";
            var expectedIL = @"
{
  // Code size       19 (0x13)
  .maxstack  1
  .locals init (char V_0, //ch
                void* V_1, //v1
                void* V_2, //v2
                char* V_3) //c2
  IL_0000:  ldc.i4.s   97
  IL_0002:  stloc.0
  IL_0003:  ldloca.s   V_0
  IL_0005:  conv.u
  IL_0006:  stloc.1
  IL_0007:  ldloc.1
  IL_0008:  stloc.2
  IL_0009:  ldloc.2
  IL_000a:  stloc.3
  IL_000b:  ldloc.3
  IL_000c:  ldind.u2
  IL_000d:  call       ""void System.Console.WriteLine(char)""
  IL_0012:  ret
}
";
            var expectedOutput = @"a";
 
            CompileAndVerify(string.Format(template, "unchecked"), options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyIL("C.Main", expectedIL);
            CompileAndVerify(string.Format(template, "checked"), options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyIL("C.Main", expectedIL);
        }
 
        [Fact]
        public void ConvertPointerToNumericUnchecked()
        {
            var text = @"
using System;
 
unsafe class C
{
    void M(int* pi, void* pv, sbyte sb, byte b, short s, ushort us, int i, uint ui, long l, ulong ul)
    {
        unchecked
        {
            sb = (sbyte)pi;
            b = (byte)pi;
            s = (short)pi;
            us = (ushort)pi;
            i = (int)pi;
            ui = (uint)pi;
            l = (long)pi;
            ul = (ulong)pi;
 
            sb = (sbyte)pv;
            b = (byte)pv;
            s = (short)pv;
            us = (ushort)pv;
            i = (int)pv;
            ui = (uint)pv;
            l = (long)pv;
            ul = (ulong)pv;
        }
    }
}
";
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyIL("C.M", @"
{
  // Code size       65 (0x41)
  .maxstack  1
  IL_0000:  ldarg.1
  IL_0001:  conv.i1
  IL_0002:  starg.s    V_3
  IL_0004:  ldarg.1
  IL_0005:  conv.u1
  IL_0006:  starg.s    V_4
  IL_0008:  ldarg.1
  IL_0009:  conv.i2
  IL_000a:  starg.s    V_5
  IL_000c:  ldarg.1
  IL_000d:  conv.u2
  IL_000e:  starg.s    V_6
  IL_0010:  ldarg.1
  IL_0011:  conv.i4
  IL_0012:  starg.s    V_7
  IL_0014:  ldarg.1
  IL_0015:  conv.u4
  IL_0016:  starg.s    V_8
  IL_0018:  ldarg.1
  IL_0019:  conv.u8
  IL_001a:  starg.s    V_9
  IL_001c:  ldarg.1
  IL_001d:  conv.u8
  IL_001e:  starg.s    V_10
  IL_0020:  ldarg.2
  IL_0021:  conv.i1
  IL_0022:  starg.s    V_3
  IL_0024:  ldarg.2
  IL_0025:  conv.u1
  IL_0026:  starg.s    V_4
  IL_0028:  ldarg.2
  IL_0029:  conv.i2
  IL_002a:  starg.s    V_5
  IL_002c:  ldarg.2
  IL_002d:  conv.u2
  IL_002e:  starg.s    V_6
  IL_0030:  ldarg.2
  IL_0031:  conv.i4
  IL_0032:  starg.s    V_7
  IL_0034:  ldarg.2
  IL_0035:  conv.u4
  IL_0036:  starg.s    V_8
  IL_0038:  ldarg.2
  IL_0039:  conv.u8
  IL_003a:  starg.s    V_9
  IL_003c:  ldarg.2
  IL_003d:  conv.u8
  IL_003e:  starg.s    V_10
  IL_0040:  ret
}
");
        }
 
        [Fact]
        public void ConvertPointerToNumericChecked()
        {
            var text = @"
using System;
 
unsafe class C
{
    void M(int* pi, void* pv, sbyte sb, byte b, short s, ushort us, int i, uint ui, long l, ulong ul)
    {
        checked
        {
            sb = (sbyte)pi;
            b = (byte)pi;
            s = (short)pi;
            us = (ushort)pi;
            i = (int)pi;
            ui = (uint)pi;
            l = (long)pi;
            ul = (ulong)pi;
 
            sb = (sbyte)pv;
            b = (byte)pv;
            s = (short)pv;
            us = (ushort)pv;
            i = (int)pv;
            ui = (uint)pv;
            l = (long)pv;
            ul = (ulong)pv;
        }
    }
}
";
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyIL("C.M", @"
{
  // Code size       65 (0x41)
  .maxstack  1
  IL_0000:  ldarg.1
  IL_0001:  conv.ovf.i1.un
  IL_0002:  starg.s    V_3
  IL_0004:  ldarg.1
  IL_0005:  conv.ovf.u1.un
  IL_0006:  starg.s    V_4
  IL_0008:  ldarg.1
  IL_0009:  conv.ovf.i2.un
  IL_000a:  starg.s    V_5
  IL_000c:  ldarg.1
  IL_000d:  conv.ovf.u2.un
  IL_000e:  starg.s    V_6
  IL_0010:  ldarg.1
  IL_0011:  conv.ovf.i4.un
  IL_0012:  starg.s    V_7
  IL_0014:  ldarg.1
  IL_0015:  conv.ovf.u4.un
  IL_0016:  starg.s    V_8
  IL_0018:  ldarg.1
  IL_0019:  conv.ovf.i8.un
  IL_001a:  starg.s    V_9
  IL_001c:  ldarg.1
  IL_001d:  conv.u8
  IL_001e:  starg.s    V_10
  IL_0020:  ldarg.2
  IL_0021:  conv.ovf.i1.un
  IL_0022:  starg.s    V_3
  IL_0024:  ldarg.2
  IL_0025:  conv.ovf.u1.un
  IL_0026:  starg.s    V_4
  IL_0028:  ldarg.2
  IL_0029:  conv.ovf.i2.un
  IL_002a:  starg.s    V_5
  IL_002c:  ldarg.2
  IL_002d:  conv.ovf.u2.un
  IL_002e:  starg.s    V_6
  IL_0030:  ldarg.2
  IL_0031:  conv.ovf.i4.un
  IL_0032:  starg.s    V_7
  IL_0034:  ldarg.2
  IL_0035:  conv.ovf.u4.un
  IL_0036:  starg.s    V_8
  IL_0038:  ldarg.2
  IL_0039:  conv.ovf.i8.un
  IL_003a:  starg.s    V_9
  IL_003c:  ldarg.2
  IL_003d:  conv.u8
  IL_003e:  starg.s    V_10
  IL_0040:  ret
}
");
        }
 
        [Fact]
        public void ConvertNumericToPointerUnchecked()
        {
            var text = @"
using System;
 
unsafe class C
{
    void M(int* pi, void* pv, sbyte sb, byte b, short s, ushort us, int i, uint ui, long l, ulong ul)
    {
        unchecked
        {
            pi = (int*)sb;
            pi = (int*)b;
            pi = (int*)s;
            pi = (int*)us;
            pi = (int*)i;
            pi = (int*)ui;
            pi = (int*)l;
            pi = (int*)ul;
 
            pv = (void*)sb;
            pv = (void*)b;
            pv = (void*)s;
            pv = (void*)us;
            pv = (void*)i;
            pv = (void*)ui;
            pv = (void*)l;
            pv = (void*)ul;
        }
    }
}
";
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.FailsPEVerify).VerifyIL("C.M", @"
{
  // Code size       79 (0x4f)
  .maxstack  1
  IL_0000:  ldarg.3
  IL_0001:  conv.i
  IL_0002:  starg.s    V_1
  IL_0004:  ldarg.s    V_4
  IL_0006:  conv.u
  IL_0007:  starg.s    V_1
  IL_0009:  ldarg.s    V_5
  IL_000b:  conv.i
  IL_000c:  starg.s    V_1
  IL_000e:  ldarg.s    V_6
  IL_0010:  conv.u
  IL_0011:  starg.s    V_1
  IL_0013:  ldarg.s    V_7
  IL_0015:  conv.i
  IL_0016:  starg.s    V_1
  IL_0018:  ldarg.s    V_8
  IL_001a:  conv.u
  IL_001b:  starg.s    V_1
  IL_001d:  ldarg.s    V_9
  IL_001f:  conv.u
  IL_0020:  starg.s    V_1
  IL_0022:  ldarg.s    V_10
  IL_0024:  conv.u
  IL_0025:  starg.s    V_1
  IL_0027:  ldarg.3
  IL_0028:  conv.i
  IL_0029:  starg.s    V_2
  IL_002b:  ldarg.s    V_4
  IL_002d:  conv.u
  IL_002e:  starg.s    V_2
  IL_0030:  ldarg.s    V_5
  IL_0032:  conv.i
  IL_0033:  starg.s    V_2
  IL_0035:  ldarg.s    V_6
  IL_0037:  conv.u
  IL_0038:  starg.s    V_2
  IL_003a:  ldarg.s    V_7
  IL_003c:  conv.i
  IL_003d:  starg.s    V_2
  IL_003f:  ldarg.s    V_8
  IL_0041:  conv.u
  IL_0042:  starg.s    V_2
  IL_0044:  ldarg.s    V_9
  IL_0046:  conv.u
  IL_0047:  starg.s    V_2
  IL_0049:  ldarg.s    V_10
  IL_004b:  conv.u
  IL_004c:  starg.s    V_2
  IL_004e:  ret
}
");
        }
 
        [Fact]
        public void ConvertNumericToPointerChecked()
        {
            var text = @"
using System;
 
unsafe class C
{
    void M(int* pi, void* pv, sbyte sb, byte b, short s, ushort us, int i, uint ui, long l, ulong ul)
    {
        checked
        {
            pi = (int*)sb;
            pi = (int*)b;
            pi = (int*)s;
            pi = (int*)us;
            pi = (int*)i;
            pi = (int*)ui;
            pi = (int*)l;
            pi = (int*)ul;
 
            pv = (void*)sb;
            pv = (void*)b;
            pv = (void*)s;
            pv = (void*)us;
            pv = (void*)i;
            pv = (void*)ui;
            pv = (void*)l;
            pv = (void*)ul;
        }
    }
}
";
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.FailsPEVerify).VerifyIL("C.M", @"
{
  // Code size       79 (0x4f)
  .maxstack  1
  IL_0000:  ldarg.3
  IL_0001:  conv.ovf.u
  IL_0002:  starg.s    V_1
  IL_0004:  ldarg.s    V_4
  IL_0006:  conv.u
  IL_0007:  starg.s    V_1
  IL_0009:  ldarg.s    V_5
  IL_000b:  conv.ovf.u
  IL_000c:  starg.s    V_1
  IL_000e:  ldarg.s    V_6
  IL_0010:  conv.u
  IL_0011:  starg.s    V_1
  IL_0013:  ldarg.s    V_7
  IL_0015:  conv.ovf.u
  IL_0016:  starg.s    V_1
  IL_0018:  ldarg.s    V_8
  IL_001a:  conv.u
  IL_001b:  starg.s    V_1
  IL_001d:  ldarg.s    V_9
  IL_001f:  conv.ovf.u
  IL_0020:  starg.s    V_1
  IL_0022:  ldarg.s    V_10
  IL_0024:  conv.ovf.u.un
  IL_0025:  starg.s    V_1
  IL_0027:  ldarg.3
  IL_0028:  conv.ovf.u
  IL_0029:  starg.s    V_2
  IL_002b:  ldarg.s    V_4
  IL_002d:  conv.u
  IL_002e:  starg.s    V_2
  IL_0030:  ldarg.s    V_5
  IL_0032:  conv.ovf.u
  IL_0033:  starg.s    V_2
  IL_0035:  ldarg.s    V_6
  IL_0037:  conv.u
  IL_0038:  starg.s    V_2
  IL_003a:  ldarg.s    V_7
  IL_003c:  conv.ovf.u
  IL_003d:  starg.s    V_2
  IL_003f:  ldarg.s    V_8
  IL_0041:  conv.u
  IL_0042:  starg.s    V_2
  IL_0044:  ldarg.s    V_9
  IL_0046:  conv.ovf.u
  IL_0047:  starg.s    V_2
  IL_0049:  ldarg.s    V_10
  IL_004b:  conv.ovf.u.un
  IL_004c:  starg.s    V_2
  IL_004e:  ret
}
");
        }
 
        [Fact]
        public void ConvertClassToPointerUDC()
        {
            var template = @"
using System;
 
unsafe class C
{{
    void M(int* pi, void* pv, Explicit e, Implicit i)
    {{
        {0}
        {{
            e = (Explicit)pi;
            e = (Explicit)pv;
 
            i = pi;
            i = pv;
 
            pi = (int*)e;
            pv = (int*)e;
 
            pi = i;
            pv = i;
        }}
    }}
}}
 
unsafe class Explicit
{{
    public static explicit operator Explicit(void* p)
    {{
        return null;
    }}
 
    public static explicit operator int*(Explicit e)
    {{
        return null;
    }}
}}
 
unsafe class Implicit
{{
    public static implicit operator Implicit(void* p)
    {{
        return null;
    }}
 
    public static implicit operator int*(Implicit e)
    {{
        return null;
    }}
}}
";
            var expectedIL = @"
{
  // Code size       67 (0x43)
  .maxstack  1
  IL_0000:  ldarg.1
  IL_0001:  call       ""Explicit Explicit.op_Explicit(void*)""
  IL_0006:  starg.s    V_3
  IL_0008:  ldarg.2
  IL_0009:  call       ""Explicit Explicit.op_Explicit(void*)""
  IL_000e:  starg.s    V_3
  IL_0010:  ldarg.1
  IL_0011:  call       ""Implicit Implicit.op_Implicit(void*)""
  IL_0016:  starg.s    V_4
  IL_0018:  ldarg.2
  IL_0019:  call       ""Implicit Implicit.op_Implicit(void*)""
  IL_001e:  starg.s    V_4
  IL_0020:  ldarg.3
  IL_0021:  call       ""int* Explicit.op_Explicit(Explicit)""
  IL_0026:  starg.s    V_1
  IL_0028:  ldarg.3
  IL_0029:  call       ""int* Explicit.op_Explicit(Explicit)""
  IL_002e:  starg.s    V_2
  IL_0030:  ldarg.s    V_4
  IL_0032:  call       ""int* Implicit.op_Implicit(Implicit)""
  IL_0037:  starg.s    V_1
  IL_0039:  ldarg.s    V_4
  IL_003b:  call       ""int* Implicit.op_Implicit(Implicit)""
  IL_0040:  starg.s    V_2
  IL_0042:  ret
}
";
            CompileAndVerify(string.Format(template, "unchecked"), options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyIL("C.M", expectedIL);
            CompileAndVerify(string.Format(template, "checked"), options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyIL("C.M", expectedIL);
        }
 
        [Fact]
        public void ConvertIntPtrToPointer()
        {
            var template = @"
using System;
 
unsafe class C
{{
    void M(int* pi, void* pv, IntPtr i, UIntPtr u)
    {{
        {0}
        {{
            i = (IntPtr)pi;
            i = (IntPtr)pv;
 
            u = (UIntPtr)pi;
            u = (UIntPtr)pv;
 
            pi = (int*)i;
            pv = (int*)i;
 
            pi = (int*)u;
            pv = (int*)u;
        }}
    }}
}}
";
            // Nothing special here - just more UDCs.
            var expectedIL = @"
{
  // Code size       67 (0x43)
  .maxstack  1
  IL_0000:  ldarg.1
  IL_0001:  call       ""System.IntPtr System.IntPtr.op_Explicit(void*)""
  IL_0006:  starg.s    V_3
  IL_0008:  ldarg.2
  IL_0009:  call       ""System.IntPtr System.IntPtr.op_Explicit(void*)""
  IL_000e:  starg.s    V_3
  IL_0010:  ldarg.1
  IL_0011:  call       ""System.UIntPtr System.UIntPtr.op_Explicit(void*)""
  IL_0016:  starg.s    V_4
  IL_0018:  ldarg.2
  IL_0019:  call       ""System.UIntPtr System.UIntPtr.op_Explicit(void*)""
  IL_001e:  starg.s    V_4
  IL_0020:  ldarg.3
  IL_0021:  call       ""void* System.IntPtr.op_Explicit(System.IntPtr)""
  IL_0026:  starg.s    V_1
  IL_0028:  ldarg.3
  IL_0029:  call       ""void* System.IntPtr.op_Explicit(System.IntPtr)""
  IL_002e:  starg.s    V_2
  IL_0030:  ldarg.s    V_4
  IL_0032:  call       ""void* System.UIntPtr.op_Explicit(System.UIntPtr)""
  IL_0037:  starg.s    V_1
  IL_0039:  ldarg.s    V_4
  IL_003b:  call       ""void* System.UIntPtr.op_Explicit(System.UIntPtr)""
  IL_0040:  starg.s    V_2
  IL_0042:  ret
}
";
            CompileAndVerify(string.Format(template, "unchecked"), options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyIL("C.M", expectedIL);
            CompileAndVerify(string.Format(template, "checked"), options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyIL("C.M", expectedIL);
        }
 
        [Fact]
        public void FixedStatementConversion()
        {
            var template = @"
using System;
 
unsafe class C
{{
    char c = 'a';
    char[] a = new char[1];
 
    static void Main()
    {{
        {0}
        {{
            C c = new C();
            fixed (void* p = &c.c, q = c.a, r = ""hello"")
            {{
                Console.Write((int)*(char*)p);
                Console.Write((int)*(char*)q);
                Console.Write((int)*(char*)r);
            }}
        }}
    }}
}}
";
            // NB: "pinned System.IntPtr&" (which ildasm displays as "pinned native int&"), not void.
            var expectedIL = @"
{
  // Code size      112 (0x70)
  .maxstack  2
  .locals init (C V_0, //c
                void* V_1, //p
                void* V_2, //q
                void* V_3, //r
                pinned char& V_4,
                pinned char[] V_5,
                pinned string V_6)
 -IL_0000:  nop
 -IL_0001:  nop
 -IL_0002:  newobj     ""C..ctor()""
  IL_0007:  stloc.0
  IL_0008:  ldloc.0
  IL_0009:  ldflda     ""char C.c""
  IL_000e:  stloc.s    V_4
 -IL_0010:  ldloc.s    V_4
  IL_0012:  conv.u
  IL_0013:  stloc.1
 -IL_0014:  ldloc.0
  IL_0015:  ldfld      ""char[] C.a""
  IL_001a:  dup
  IL_001b:  stloc.s    V_5
  IL_001d:  brfalse.s  IL_0025
  IL_001f:  ldloc.s    V_5
  IL_0021:  ldlen
  IL_0022:  conv.i4
  IL_0023:  brtrue.s   IL_002a
  IL_0025:  ldc.i4.0
  IL_0026:  conv.u
  IL_0027:  stloc.2
  IL_0028:  br.s       IL_0034
  IL_002a:  ldloc.s    V_5
  IL_002c:  ldc.i4.0
  IL_002d:  ldelema    ""char""
  IL_0032:  conv.u
  IL_0033:  stloc.2
  IL_0034:  ldstr      ""hello""
  IL_0039:  stloc.s    V_6
 -IL_003b:  ldloc.s    V_6
  IL_003d:  conv.u
  IL_003e:  stloc.3
  IL_003f:  ldloc.3
  IL_0040:  brfalse.s  IL_004a
  IL_0042:  ldloc.3
  IL_0043:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_0048:  add
  IL_0049:  stloc.3
 -IL_004a:  nop
 -IL_004b:  ldloc.1
  IL_004c:  ldind.u2
  IL_004d:  call       ""void System.Console.Write(int)""
  IL_0052:  nop
 -IL_0053:  ldloc.2
  IL_0054:  ldind.u2
  IL_0055:  call       ""void System.Console.Write(int)""
  IL_005a:  nop
 -IL_005b:  ldloc.3
  IL_005c:  ldind.u2
  IL_005d:  call       ""void System.Console.Write(int)""
  IL_0062:  nop
 -IL_0063:  nop
 ~IL_0064:  ldc.i4.0
  IL_0065:  conv.u
  IL_0066:  stloc.s    V_4
  IL_0068:  ldnull
  IL_0069:  stloc.s    V_5
  IL_006b:  ldnull
  IL_006c:  stloc.s    V_6
 -IL_006e:  nop
 -IL_006f:  ret
}
";
            var expectedOutput = @"970104";
            CompileAndVerify(string.Format(template, "unchecked"), options: TestOptions.UnsafeDebugExe, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyIL("C.Main", expectedIL, sequencePoints: "C.Main");
            CompileAndVerify(string.Format(template, "checked  "), options: TestOptions.UnsafeDebugExe, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyIL("C.Main", expectedIL, sequencePoints: "C.Main");
        }
 
        [Fact]
        public void FixedStatementVoidPointerPointer()
        {
            var template = @"
using System;
 
unsafe class C
{{
    void* v;
 
    static void Main()
    {{
        {0}
        {{
            char ch = 'a';
            C c = new C();
            c.v = &ch;
            fixed (void** p = &c.v)
            {{
                Console.Write(*(char*)*p);
            }}
        }}
    }}
}}
";
            // NB: "pinned void*&", as in Dev10.
            var expectedIL = @"
{
  // Code size       36 (0x24)
  .maxstack  3
  .locals init (char V_0, //ch
                pinned void*& V_1)
  IL_0000:  ldc.i4.s   97
  IL_0002:  stloc.0
  IL_0003:  newobj     ""C..ctor()""
  IL_0008:  dup
  IL_0009:  ldloca.s   V_0
  IL_000b:  conv.u
  IL_000c:  stfld      ""void* C.v""
  IL_0011:  ldflda     ""void* C.v""
  IL_0016:  stloc.1
  IL_0017:  ldloc.1
  IL_0018:  conv.u
  IL_0019:  ldind.i
  IL_001a:  ldind.u2
  IL_001b:  call       ""void System.Console.Write(char)""
  IL_0020:  ldc.i4.0
  IL_0021:  conv.u
  IL_0022:  stloc.1
  IL_0023:  ret
}
";
            var expectedOutput = @"a";
            CompileAndVerify(string.Format(template, "unchecked"), options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyIL("C.Main", expectedIL);
            CompileAndVerify(string.Format(template, "checked"), options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyIL("C.Main", expectedIL);
        }
 
        [ConditionalFact(typeof(DesktopOnly))]
        public void PointerArrayConversion()
        {
            var template = @"
using System;
 
unsafe class C
{{
    void M(int*[] api, void*[] apv, Array a)
    {{
        {0}
        {{
            a = api;
            a = apv;
 
            api = (int*[])a;
            apv = (void*[])a;
        }}
    }}
}}
";
            var expectedIL = @"
{
  // Code size       23 (0x17)
  .maxstack  1
  IL_0000:  ldarg.1
  IL_0001:  starg.s    V_3
  IL_0003:  ldarg.2
  IL_0004:  starg.s    V_3
  IL_0006:  ldarg.3
  IL_0007:  castclass  ""int*[]""
  IL_000c:  starg.s    V_1
  IL_000e:  ldarg.3
  IL_000f:  castclass  ""void*[]""
  IL_0014:  starg.s    V_2
  IL_0016:  ret
}
";
            CompileAndVerify(string.Format(template, "unchecked"), options: TestOptions.UnsafeReleaseDll, verify: Verification.Passes).VerifyIL("C.M", expectedIL);
            CompileAndVerify(string.Format(template, "checked"), options: TestOptions.UnsafeReleaseDll, verify: Verification.Passes).VerifyIL("C.M", expectedIL);
        }
 
        [ConditionalFact(typeof(DesktopOnly))]
        public void PointerArrayConversionRuntimeError()
        {
            var text = @"
unsafe class C
{
    static void Main()
    {
        System.Globalization.CultureInfo saveUICulture = System.Threading.Thread.CurrentThread.CurrentUICulture;
        System.Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.InvariantCulture;
 
        try
        {
            int*[] api = new int*[1];
            System.Array a = api;
            a.GetValue(0);
        }
        finally
        {
            System.Threading.Thread.CurrentThread.CurrentUICulture = saveUICulture;
        }
    }
}
";
            CompileAndVerifyException<NotSupportedException>(text, "Type is not supported.", allowUnsafe: true, verify: Verification.Fails);
        }
 
        [ConditionalFact(typeof(DesktopOnly))]
        public void PointerArrayEnumerableConversion()
        {
            var template = @"
using System.Collections;
 
unsafe class C
{{
    void M(int*[] api, void*[] apv, IEnumerable e)
    {{
        {0}
        {{
            e = api;
            e = apv;
 
            api = (int*[])e;
            apv = (void*[])e;
        }}
    }}
}}
";
            var expectedIL = @"
{
  // Code size       23 (0x17)
  .maxstack  1
  IL_0000:  ldarg.1
  IL_0001:  starg.s    V_3
  IL_0003:  ldarg.2
  IL_0004:  starg.s    V_3
  IL_0006:  ldarg.3
  IL_0007:  castclass  ""int*[]""
  IL_000c:  starg.s    V_1
  IL_000e:  ldarg.3
  IL_000f:  castclass  ""void*[]""
  IL_0014:  starg.s    V_2
  IL_0016:  ret
}
";
            CompileAndVerify(string.Format(template, "unchecked"), options: TestOptions.UnsafeReleaseDll, verify: Verification.Passes).VerifyIL("C.M", expectedIL);
            CompileAndVerify(string.Format(template, "checked"), options: TestOptions.UnsafeReleaseDll, verify: Verification.Passes).VerifyIL("C.M", expectedIL);
        }
 
        [ConditionalFact(typeof(DesktopOnly))]
        public void PointerArrayEnumerableConversionRuntimeError()
        {
            var text = @"
unsafe class C
{
    static void Main()
    {
        System.Globalization.CultureInfo saveUICulture = System.Threading.Thread.CurrentThread.CurrentUICulture;
        System.Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.InvariantCulture;
 
        try
        {
            int*[] api = new int*[1];
            System.Collections.IEnumerable e = api;
            var enumerator = e.GetEnumerator();
            enumerator.MoveNext();
            var current = enumerator.Current;
        }
        finally
        {
            System.Threading.Thread.CurrentThread.CurrentUICulture = saveUICulture;
        }
    }
}
";
            CompileAndVerifyException<NotSupportedException>(text, "Type is not supported.", allowUnsafe: true, verify: Verification.Fails);
        }
 
        [Fact]
        public void PointerArrayForeachSingle()
        {
            var text = @"
using System;
 
unsafe class C
{
    static void Main()
    {
        int*[] array = new []
        {
            (int*)1,
            (int*)2,
        };
        foreach (var element in array)
        {
            Console.Write((int)element);
        }
    }
}
";
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "12", verify: Verification.Fails).VerifyIL("C.Main", @"
{
  // Code size       41 (0x29)
  .maxstack  4
  .locals init (int*[] V_0,
                int V_1)
  IL_0000:  ldc.i4.2
  IL_0001:  newarr     ""int*""
  IL_0006:  dup
  IL_0007:  ldc.i4.0
  IL_0008:  ldc.i4.1
  IL_0009:  conv.i
  IL_000a:  stelem.i
  IL_000b:  dup
  IL_000c:  ldc.i4.1
  IL_000d:  ldc.i4.2
  IL_000e:  conv.i
  IL_000f:  stelem.i
  IL_0010:  stloc.0
  IL_0011:  ldc.i4.0
  IL_0012:  stloc.1
  IL_0013:  br.s       IL_0022
  IL_0015:  ldloc.0
  IL_0016:  ldloc.1
  IL_0017:  ldelem.i
  IL_0018:  conv.i4
  IL_0019:  call       ""void System.Console.Write(int)""
  IL_001e:  ldloc.1
  IL_001f:  ldc.i4.1
  IL_0020:  add
  IL_0021:  stloc.1
  IL_0022:  ldloc.1
  IL_0023:  ldloc.0
  IL_0024:  ldlen
  IL_0025:  conv.i4
  IL_0026:  blt.s      IL_0015
  IL_0028:  ret
}
");
        }
 
        [Fact]
        public void PointerArrayForeachMultiple()
        {
            var text = @"
using System;
 
unsafe class C
{
    static void Main()
    {
        int*[,] array = new [,]
        {
            { (int*)1, (int*)2, },
            { (int*)3, (int*)4, },
        };
        foreach (var element in array)
        {
            Console.Write((int)element);
        }
    }
}
";
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "1234", verify: Verification.FailsPEVerify).VerifyIL("C.Main", @"
{
  // Code size      120 (0x78)
  .maxstack  5
  .locals init (int*[,] V_0,
                int V_1,
                int V_2,
                int V_3,
                int V_4)
  IL_0000:  ldc.i4.2
  IL_0001:  ldc.i4.2
  IL_0002:  newobj     ""int*[*,*]..ctor""
  IL_0007:  dup
  IL_0008:  ldc.i4.0
  IL_0009:  ldc.i4.0
  IL_000a:  ldc.i4.1
  IL_000b:  conv.i
  IL_000c:  call       ""int*[*,*].Set""
  IL_0011:  dup
  IL_0012:  ldc.i4.0
  IL_0013:  ldc.i4.1
  IL_0014:  ldc.i4.2
  IL_0015:  conv.i
  IL_0016:  call       ""int*[*,*].Set""
  IL_001b:  dup
  IL_001c:  ldc.i4.1
  IL_001d:  ldc.i4.0
  IL_001e:  ldc.i4.3
  IL_001f:  conv.i
  IL_0020:  call       ""int*[*,*].Set""
  IL_0025:  dup
  IL_0026:  ldc.i4.1
  IL_0027:  ldc.i4.1
  IL_0028:  ldc.i4.4
  IL_0029:  conv.i
  IL_002a:  call       ""int*[*,*].Set""
  IL_002f:  stloc.0
  IL_0030:  ldloc.0
  IL_0031:  ldc.i4.0
  IL_0032:  callvirt   ""int System.Array.GetUpperBound(int)""
  IL_0037:  stloc.1
  IL_0038:  ldloc.0
  IL_0039:  ldc.i4.1
  IL_003a:  callvirt   ""int System.Array.GetUpperBound(int)""
  IL_003f:  stloc.2
  IL_0040:  ldloc.0
  IL_0041:  ldc.i4.0
  IL_0042:  callvirt   ""int System.Array.GetLowerBound(int)""
  IL_0047:  stloc.3
  IL_0048:  br.s       IL_0073
  IL_004a:  ldloc.0
  IL_004b:  ldc.i4.1
  IL_004c:  callvirt   ""int System.Array.GetLowerBound(int)""
  IL_0051:  stloc.s    V_4
  IL_0053:  br.s       IL_006a
  IL_0055:  ldloc.0
  IL_0056:  ldloc.3
  IL_0057:  ldloc.s    V_4
  IL_0059:  call       ""int*[*,*].Get""
  IL_005e:  conv.i4
  IL_005f:  call       ""void System.Console.Write(int)""
  IL_0064:  ldloc.s    V_4
  IL_0066:  ldc.i4.1
  IL_0067:  add
  IL_0068:  stloc.s    V_4
  IL_006a:  ldloc.s    V_4
  IL_006c:  ldloc.2
  IL_006d:  ble.s      IL_0055
  IL_006f:  ldloc.3
  IL_0070:  ldc.i4.1
  IL_0071:  add
  IL_0072:  stloc.3
  IL_0073:  ldloc.3
  IL_0074:  ldloc.1
  IL_0075:  ble.s      IL_004a
  IL_0077:  ret
}
");
        }
 
        [ConditionalFact(typeof(DesktopOnly))]
        public void PointerArrayForeachEnumerable()
        {
            var text = @"
using System;
using System.Collections;
 
unsafe class C
{
    static void Main()
    {
        System.Globalization.CultureInfo saveUICulture = System.Threading.Thread.CurrentThread.CurrentUICulture;
        System.Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.InvariantCulture;
 
        try
        {
            int*[] array = new []
            {
                (int*)1,
                (int*)2,
            };
            foreach (var element in (IEnumerable)array)
            {
                Console.Write((int)element);
            }
        }
        finally
        {
            System.Threading.Thread.CurrentThread.CurrentUICulture = saveUICulture;
        }
    }
}
";
            CompileAndVerifyException<NotSupportedException>(text, "Type is not supported.", allowUnsafe: true, verify: Verification.Fails);
        }
 
        #endregion Pointer conversion tests
 
        #region sizeof tests
 
        [Fact]
        public void SizeOfConstant()
        {
            var text = @"
using System;
 
class C
{
    static void Main()
    {
        Console.WriteLine(sizeof(sbyte));
        Console.WriteLine(sizeof(byte));
        Console.WriteLine(sizeof(short));
        Console.WriteLine(sizeof(ushort));
        Console.WriteLine(sizeof(int));
        Console.WriteLine(sizeof(uint));
        Console.WriteLine(sizeof(long));
        Console.WriteLine(sizeof(ulong));
        Console.WriteLine(sizeof(char));
        Console.WriteLine(sizeof(float));
        Console.WriteLine(sizeof(double));
        Console.WriteLine(sizeof(bool));
        Console.WriteLine(sizeof(decimal)); //Supported by dev10, but not spec.
    }
}
";
            var expectedOutput = @"
1
1
2
2
4
4
8
8
2
4
8
1
16
".Trim();
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Passes).VerifyIL("C.Main", @"
{
  // Code size       80 (0x50)
  .maxstack  1
  IL_0000:  ldc.i4.1
  IL_0001:  call       ""void System.Console.WriteLine(int)""
  IL_0006:  ldc.i4.1
  IL_0007:  call       ""void System.Console.WriteLine(int)""
  IL_000c:  ldc.i4.2
  IL_000d:  call       ""void System.Console.WriteLine(int)""
  IL_0012:  ldc.i4.2
  IL_0013:  call       ""void System.Console.WriteLine(int)""
  IL_0018:  ldc.i4.4
  IL_0019:  call       ""void System.Console.WriteLine(int)""
  IL_001e:  ldc.i4.4
  IL_001f:  call       ""void System.Console.WriteLine(int)""
  IL_0024:  ldc.i4.8
  IL_0025:  call       ""void System.Console.WriteLine(int)""
  IL_002a:  ldc.i4.8
  IL_002b:  call       ""void System.Console.WriteLine(int)""
  IL_0030:  ldc.i4.2
  IL_0031:  call       ""void System.Console.WriteLine(int)""
  IL_0036:  ldc.i4.4
  IL_0037:  call       ""void System.Console.WriteLine(int)""
  IL_003c:  ldc.i4.8
  IL_003d:  call       ""void System.Console.WriteLine(int)""
  IL_0042:  ldc.i4.1
  IL_0043:  call       ""void System.Console.WriteLine(int)""
  IL_0048:  ldc.i4.s   16
  IL_004a:  call       ""void System.Console.WriteLine(int)""
  IL_004f:  ret
}
");
        }
 
        [Fact]
        public void SizeOfNonConstant()
        {
            var text = @"
using System;
 
unsafe class C
{
    static void Main()
    {
        Console.WriteLine(sizeof(S));
        Console.WriteLine(sizeof(Outer.Inner));
        Console.WriteLine(sizeof(int*));
        Console.WriteLine(sizeof(void*));
    }
}
 
struct S
{
    public byte b;
}
 
class Outer
{
    public struct Inner
    {
        public char c;
    }
}
";
            bool isx86 = (IntPtr.Size == 4);
            string expectedOutput;
 
            if (isx86)
            {
                expectedOutput = @"
1
2
4
4
".Trim();
            }
            else
            {
                expectedOutput = @"
1
2
8
8
".Trim();
            }
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Passes).VerifyIL("C.Main", @"
{
  // Code size       45 (0x2d)
  .maxstack  1
  IL_0000:  sizeof     ""S""
  IL_0006:  call       ""void System.Console.WriteLine(int)""
  IL_000b:  sizeof     ""Outer.Inner""
  IL_0011:  call       ""void System.Console.WriteLine(int)""
  IL_0016:  sizeof     ""int*""
  IL_001c:  call       ""void System.Console.WriteLine(int)""
  IL_0021:  sizeof     ""void*""
  IL_0027:  call       ""void System.Console.WriteLine(int)""
  IL_002c:  ret
}
");
        }
 
        [Fact]
        public void SizeOfEnum()
        {
            var text = @"
using System;
 
unsafe class C
{
    static void Main()
    {
        Console.WriteLine(sizeof(E1));
        Console.WriteLine(sizeof(E2));
        Console.WriteLine(sizeof(E3));
    }
}
 
enum E1 { A }
enum E2 : byte { A }
enum E3 : long { A }
";
            var expectedOutput = @"
4
1
8
".Trim();
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Passes).VerifyIL("C.Main", @"
{
  // Code size       19 (0x13)
  .maxstack  1
  IL_0000:  ldc.i4.4
  IL_0001:  call       ""void System.Console.WriteLine(int)""
  IL_0006:  ldc.i4.1
  IL_0007:  call       ""void System.Console.WriteLine(int)""
  IL_000c:  ldc.i4.8
  IL_000d:  call       ""void System.Console.WriteLine(int)""
  IL_0012:  ret
}
");
        }
 
        #endregion sizeof tests
 
        #region Pointer arithmetic tests
 
        [Fact]
        public void NumericAdditionChecked()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        checked
        {
            S s = new S();
            S* p = &s;
            p = p + 2;
            p = p + 3u;
            p = p + 4l;
            p = p + 5ul;
        }
    }
}
";
 
            // Dev10 has conv.u after IL_000d and conv.i8 in place of conv.u8 at IL_0017.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyIL("S.Main", @"
{
  // Code size       59 (0x3b)
  .maxstack  3
  .locals init (S V_0) //s
  IL_0000:  ldloca.s   V_0
  IL_0002:  initobj    ""S""
  IL_0008:  ldloca.s   V_0
  IL_000a:  conv.u
  IL_000b:  ldc.i4.2
  IL_000c:  conv.i
  IL_000d:  sizeof     ""S""
  IL_0013:  mul.ovf
  IL_0014:  add.ovf.un
  IL_0015:  ldc.i4.3
  IL_0016:  conv.u8
  IL_0017:  sizeof     ""S""
  IL_001d:  conv.i8
  IL_001e:  mul.ovf
  IL_001f:  conv.i
  IL_0020:  add.ovf.un
  IL_0021:  ldc.i4.4
  IL_0022:  conv.i8
  IL_0023:  sizeof     ""S""
  IL_0029:  conv.i8
  IL_002a:  mul.ovf
  IL_002b:  conv.i
  IL_002c:  add.ovf.un
  IL_002d:  ldc.i4.5
  IL_002e:  conv.i8
  IL_002f:  sizeof     ""S""
  IL_0035:  conv.ovf.u8
  IL_0036:  mul.ovf.un
  IL_0037:  conv.u
  IL_0038:  add.ovf.un
  IL_0039:  pop
  IL_003a:  ret
}
");
        }
 
        [Fact]
        public void NumericAdditionUnchecked()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        unchecked
        {
            S s = new S();
            S* p = &s;
            p = p + 2;
            p = p + 3u;
            p = p + 4l;
            p = p + 5ul;
        }
    }
}
";
 
            // Dev10 has conv.u after IL_000d and conv.i8 in place of conv.u8 at IL_0017.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyIL("S.Main", @"
{
  // Code size       59 (0x3b)
  .maxstack  3
  .locals init (S V_0) //s
  IL_0000:  ldloca.s   V_0
  IL_0002:  initobj    ""S""
  IL_0008:  ldloca.s   V_0
  IL_000a:  conv.u
  IL_000b:  ldc.i4.2
  IL_000c:  conv.i
  IL_000d:  sizeof     ""S""
  IL_0013:  mul
  IL_0014:  add
  IL_0015:  ldc.i4.3
  IL_0016:  conv.u8
  IL_0017:  sizeof     ""S""
  IL_001d:  conv.i8
  IL_001e:  mul
  IL_001f:  conv.i
  IL_0020:  add
  IL_0021:  ldc.i4.4
  IL_0022:  conv.i8
  IL_0023:  sizeof     ""S""
  IL_0029:  conv.i8
  IL_002a:  mul
  IL_002b:  conv.i
  IL_002c:  add
  IL_002d:  pop
  IL_002e:  ldc.i4.5
  IL_002f:  conv.i8
  IL_0030:  sizeof     ""S""
  IL_0036:  conv.i8
  IL_0037:  mul
  IL_0038:  conv.u
  IL_0039:  pop
  IL_003a:  ret
}
");
        }
 
        [Fact]
        public void NumericSubtractionChecked()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        checked
        {
            S s = new S();
            S* p = &s;
            p = p - 2;
            p = p - 3u;
            p = p - 4l;
            p = p - 5ul;
        }
    }
}
";
 
            // Dev10 has conv.u after IL_000d and conv.i8 in place of conv.u8 at IL_0017.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyIL("S.Main", @"
{
  // Code size       59 (0x3b)
  .maxstack  3
  .locals init (S V_0) //s
  IL_0000:  ldloca.s   V_0
  IL_0002:  initobj    ""S""
  IL_0008:  ldloca.s   V_0
  IL_000a:  conv.u
  IL_000b:  ldc.i4.2
  IL_000c:  conv.i
  IL_000d:  sizeof     ""S""
  IL_0013:  mul.ovf
  IL_0014:  sub.ovf.un
  IL_0015:  ldc.i4.3
  IL_0016:  conv.u8
  IL_0017:  sizeof     ""S""
  IL_001d:  conv.i8
  IL_001e:  mul.ovf
  IL_001f:  conv.i
  IL_0020:  sub.ovf.un
  IL_0021:  ldc.i4.4
  IL_0022:  conv.i8
  IL_0023:  sizeof     ""S""
  IL_0029:  conv.i8
  IL_002a:  mul.ovf
  IL_002b:  conv.i
  IL_002c:  sub.ovf.un
  IL_002d:  ldc.i4.5
  IL_002e:  conv.i8
  IL_002f:  sizeof     ""S""
  IL_0035:  conv.ovf.u8
  IL_0036:  mul.ovf.un
  IL_0037:  conv.u
  IL_0038:  sub.ovf.un
  IL_0039:  pop
  IL_003a:  ret
}
");
        }
 
        [Fact]
        public void NumericSubtractionUnchecked()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        unchecked
        {
            S s = new S();
            S* p = &s;
            p = p - 2;
            p = p - 3u;
            p = p - 4l;
            p = p - 5ul;
        }
    }
}
";
 
            // Dev10 has conv.u after IL_000d and conv.i8 in place of conv.u8 at IL_0017.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyIL("S.Main", @"
{
  // Code size       59 (0x3b)
  .maxstack  3
  .locals init (S V_0) //s
  IL_0000:  ldloca.s   V_0
  IL_0002:  initobj    ""S""
  IL_0008:  ldloca.s   V_0
  IL_000a:  conv.u
  IL_000b:  ldc.i4.2
  IL_000c:  conv.i
  IL_000d:  sizeof     ""S""
  IL_0013:  mul
  IL_0014:  sub
  IL_0015:  ldc.i4.3
  IL_0016:  conv.u8
  IL_0017:  sizeof     ""S""
  IL_001d:  conv.i8
  IL_001e:  mul
  IL_001f:  conv.i
  IL_0020:  sub
  IL_0021:  ldc.i4.4
  IL_0022:  conv.i8
  IL_0023:  sizeof     ""S""
  IL_0029:  conv.i8
  IL_002a:  mul
  IL_002b:  conv.i
  IL_002c:  sub
  IL_002d:  pop
  IL_002e:  ldc.i4.5
  IL_002f:  conv.i8
  IL_0030:  sizeof     ""S""
  IL_0036:  conv.i8
  IL_0037:  mul
  IL_0038:  conv.u
  IL_0039:  pop
  IL_003a:  ret
}
");
        }
 
        [WorkItem(546750, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546750")]
        [Fact]
        public void NumericAdditionUnchecked_SizeOne()
        {
            var text = @"
using System;
 
unsafe class C
{
    void Test(int i, uint u, long l, ulong ul)
    {
        unchecked
        {
            byte b = 3;
            byte* p = &b;
            p = p + 2;
            p = p + 3u;
            p = p + 4l;
            p = p + 5ul;
            p = p + i;
            p = p + u;
            p = p + l;
            p = p + ul;
        }
    }
}
";
            // NOTE: even when not optimized.
            // NOTE: additional conversions applied to constants of type int and uint.
            CompileAndVerify(text, options: TestOptions.UnsafeDebugDll, verify: Verification.Fails).VerifyIL("C.Test", @"
{
  // Code size       50 (0x32)
  .maxstack  2
  .locals init (byte V_0, //b
                byte* V_1) //p
  IL_0000:  nop
  IL_0001:  nop
  IL_0002:  ldc.i4.3
  IL_0003:  stloc.0
  IL_0004:  ldloca.s   V_0
  IL_0006:  conv.u
  IL_0007:  stloc.1
  IL_0008:  ldloc.1
  IL_0009:  ldc.i4.2
  IL_000a:  add
  IL_000b:  stloc.1
  IL_000c:  ldloc.1
  IL_000d:  ldc.i4.3
  IL_000e:  add
  IL_000f:  stloc.1
  IL_0010:  ldloc.1
  IL_0011:  ldc.i4.4
  IL_0012:  conv.i8
  IL_0013:  conv.i
  IL_0014:  add
  IL_0015:  stloc.1
  IL_0016:  ldloc.1
  IL_0017:  ldc.i4.5
  IL_0018:  conv.i8
  IL_0019:  conv.u
  IL_001a:  add
  IL_001b:  stloc.1
  IL_001c:  ldloc.1
  IL_001d:  ldarg.1
  IL_001e:  add
  IL_001f:  stloc.1
  IL_0020:  ldloc.1
  IL_0021:  ldarg.2
  IL_0022:  conv.u
  IL_0023:  add
  IL_0024:  stloc.1
  IL_0025:  ldloc.1
  IL_0026:  ldarg.3
  IL_0027:  conv.i
  IL_0028:  add
  IL_0029:  stloc.1
  IL_002a:  ldloc.1
  IL_002b:  ldarg.s    V_4
  IL_002d:  conv.u
  IL_002e:  add
  IL_002f:  stloc.1
  IL_0030:  nop
  IL_0031:  ret
}
");
        }
 
        [WorkItem(18871, "https://github.com/dotnet/roslyn/issues/18871")]
        [WorkItem(546750, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546750")]
        [Fact]
        public void NumericAdditionChecked_SizeOne()
        {
            var text = @"
using System;
 
unsafe class C
{
    void Test(int i, uint u, long l, ulong ul)
    {
        checked
        {
            byte b = 3;
            byte* p = &b;
            p = p + 2;
            p = p + 3u;
            p = p + 4l;
            p = p + 5ul;
            p = p + i;
            p = p + u;
            p = p + l;
            p = p + ul;
            p = p + (-2);
        }
    }
 
    void Test1(int i, uint u, long l, ulong ul)
    {
        checked
        {
            byte b = 3;
            byte* p = &b;
            p = p - 2;
            p = p - 3u;
            p = p - 4l;
            p = p - 5ul;
            p = p - i;
            p = p - u;
            p = p - l;
            p = p - ul;
            p = p - (-1);
        }
    }
}
";
            // NOTE: even when not optimized.
            // NOTE: additional conversions applied to constants of type int and uint.
            // NOTE: identical to unchecked except "add" becomes "add.ovf.un".
            var comp = CompileAndVerify(text, options: TestOptions.UnsafeDebugDll, verify: Verification.Fails);
 
            comp.VerifyIL("C.Test", @"
{
  // Code size       57 (0x39)
  .maxstack  2
  .locals init (byte V_0, //b
                byte* V_1) //p
  IL_0000:  nop
  IL_0001:  nop
  IL_0002:  ldc.i4.3
  IL_0003:  stloc.0
  IL_0004:  ldloca.s   V_0
  IL_0006:  conv.u
  IL_0007:  stloc.1
  IL_0008:  ldloc.1
  IL_0009:  ldc.i4.2
  IL_000a:  add.ovf.un
  IL_000b:  stloc.1
  IL_000c:  ldloc.1
  IL_000d:  ldc.i4.3
  IL_000e:  add.ovf.un
  IL_000f:  stloc.1
  IL_0010:  ldloc.1
  IL_0011:  ldc.i4.4
  IL_0012:  conv.i8
  IL_0013:  conv.i
  IL_0014:  add.ovf.un
  IL_0015:  stloc.1
  IL_0016:  ldloc.1
  IL_0017:  ldc.i4.5
  IL_0018:  conv.i8
  IL_0019:  conv.u
  IL_001a:  add.ovf.un
  IL_001b:  stloc.1
  IL_001c:  ldloc.1
  IL_001d:  ldarg.1
  IL_001e:  conv.i
  IL_001f:  add.ovf.un
  IL_0020:  stloc.1
  IL_0021:  ldloc.1
  IL_0022:  ldarg.2
  IL_0023:  conv.u
  IL_0024:  add.ovf.un
  IL_0025:  stloc.1
  IL_0026:  ldloc.1
  IL_0027:  ldarg.3
  IL_0028:  conv.i
  IL_0029:  add.ovf.un
  IL_002a:  stloc.1
  IL_002b:  ldloc.1
  IL_002c:  ldarg.s    V_4
  IL_002e:  conv.u
  IL_002f:  add.ovf.un
  IL_0030:  stloc.1
  IL_0031:  ldloc.1
  IL_0032:  ldc.i4.s   -2
  IL_0034:  conv.i
  IL_0035:  add.ovf.un
  IL_0036:  stloc.1
  IL_0037:  nop
  IL_0038:  ret
}");
 
            comp.VerifyIL("C.Test1", @"
{
  // Code size       56 (0x38)
  .maxstack  2
  .locals init (byte V_0, //b
                byte* V_1) //p
  IL_0000:  nop
  IL_0001:  nop
  IL_0002:  ldc.i4.3
  IL_0003:  stloc.0
  IL_0004:  ldloca.s   V_0
  IL_0006:  conv.u
  IL_0007:  stloc.1
  IL_0008:  ldloc.1
  IL_0009:  ldc.i4.2
  IL_000a:  sub.ovf.un
  IL_000b:  stloc.1
  IL_000c:  ldloc.1
  IL_000d:  ldc.i4.3
  IL_000e:  sub.ovf.un
  IL_000f:  stloc.1
  IL_0010:  ldloc.1
  IL_0011:  ldc.i4.4
  IL_0012:  conv.i8
  IL_0013:  conv.i
  IL_0014:  sub.ovf.un
  IL_0015:  stloc.1
  IL_0016:  ldloc.1
  IL_0017:  ldc.i4.5
  IL_0018:  conv.i8
  IL_0019:  conv.u
  IL_001a:  sub.ovf.un
  IL_001b:  stloc.1
  IL_001c:  ldloc.1
  IL_001d:  ldarg.1
  IL_001e:  conv.i
  IL_001f:  sub.ovf.un
  IL_0020:  stloc.1
  IL_0021:  ldloc.1
  IL_0022:  ldarg.2
  IL_0023:  conv.u
  IL_0024:  sub.ovf.un
  IL_0025:  stloc.1
  IL_0026:  ldloc.1
  IL_0027:  ldarg.3
  IL_0028:  conv.i
  IL_0029:  sub.ovf.un
  IL_002a:  stloc.1
  IL_002b:  ldloc.1
  IL_002c:  ldarg.s    V_4
  IL_002e:  conv.u
  IL_002f:  sub.ovf.un
  IL_0030:  stloc.1
  IL_0031:  ldloc.1
  IL_0032:  ldc.i4.m1
  IL_0033:  conv.i
  IL_0034:  sub.ovf.un
  IL_0035:  stloc.1
  IL_0036:  nop
  IL_0037:  ret
}");
        }
 
        [Fact]
        public void CheckedSignExtend()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        byte* ptr1 = default(byte*);
 
        ptr1 = (byte*)2;
        checked
        {
            // should not overflow regardless of 32/64 bit
            ptr1 = ptr1 + 2147483649;
        }
 
        Console.WriteLine((long)ptr1);
 
        byte* ptr = (byte*)2;
        try
        { 
            checked
            {
                int i = -1;
                // should overflow regardless of 32/64 bit
                ptr = ptr + i;
            }
            Console.WriteLine((long)ptr);
        }
        catch (OverflowException)
        {
            Console.WriteLine(""overflow"");
            Console.WriteLine((long)ptr);
        }
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"2147483651
overflow
2", verify: Verification.Fails).VerifyIL("S.Main", @"
{
  // Code size       67 (0x43)
  .maxstack  2
  .locals init (byte* V_0, //ptr1
                byte* V_1, //ptr
                int V_2) //i
  IL_0000:  ldloca.s   V_0
  IL_0002:  initobj    ""byte*""
  IL_0008:  ldc.i4.2
  IL_0009:  conv.i
  IL_000a:  stloc.0
  IL_000b:  ldloc.0
  IL_000c:  ldc.i4     0x80000001
  IL_0011:  conv.u
  IL_0012:  add.ovf.un
  IL_0013:  stloc.0
  IL_0014:  ldloc.0
  IL_0015:  conv.u8
  IL_0016:  call       ""void System.Console.WriteLine(long)""
  IL_001b:  ldc.i4.2
  IL_001c:  conv.i
  IL_001d:  stloc.1
  .try
  {
    IL_001e:  ldc.i4.m1
    IL_001f:  stloc.2
    IL_0020:  ldloc.1
    IL_0021:  ldloc.2
    IL_0022:  conv.i
    IL_0023:  add.ovf.un
    IL_0024:  stloc.1
    IL_0025:  ldloc.1
    IL_0026:  conv.u8
    IL_0027:  call       ""void System.Console.WriteLine(long)""
    IL_002c:  leave.s    IL_0042
  }
  catch System.OverflowException
  {
    IL_002e:  pop
    IL_002f:  ldstr      ""overflow""
    IL_0034:  call       ""void System.Console.WriteLine(string)""
    IL_0039:  ldloc.1
    IL_003a:  conv.u8
    IL_003b:  call       ""void System.Console.WriteLine(long)""
    IL_0040:  leave.s    IL_0042
  }
  IL_0042:  ret
}
");
        }
 
        [Fact]
        public void Increment()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        S* p = (S*)0;
        checked
        {
            p++;
        }
        checked
        {
            ++p;
        }
        unchecked
        {
            p++;
        }
        unchecked
        {
            ++p;
        }
        Console.WriteLine((int)p);
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "4", verify: Verification.Fails).VerifyIL("S.Main", @"
{
  // Code size       47 (0x2f)
  .maxstack  2
  .locals init (S* V_0) //p
  IL_0000:  ldc.i4.0
  IL_0001:  conv.i
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  sizeof     ""S""
  IL_000a:  add.ovf.un
  IL_000b:  stloc.0
  IL_000c:  ldloc.0
  IL_000d:  sizeof     ""S""
  IL_0013:  add.ovf.un
  IL_0014:  stloc.0
  IL_0015:  ldloc.0
  IL_0016:  sizeof     ""S""
  IL_001c:  add
  IL_001d:  stloc.0
  IL_001e:  ldloc.0
  IL_001f:  sizeof     ""S""
  IL_0025:  add
  IL_0026:  stloc.0
  IL_0027:  ldloc.0
  IL_0028:  conv.i4
  IL_0029:  call       ""void System.Console.WriteLine(int)""
  IL_002e:  ret
}
");
        }
 
        [Fact]
        public void Decrement()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        S* p = (S*)8;
        checked
        {
            p--;
        }
        checked
        {
            --p;
        }
        unchecked
        {
            p--;
        }
        unchecked
        {
            --p;
        }
        Console.WriteLine((int)p);
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "4", verify: Verification.Fails).VerifyIL("S.Main", @"
{
  // Code size       47 (0x2f)
  .maxstack  2
  .locals init (S* V_0) //p
  IL_0000:  ldc.i4.8
  IL_0001:  conv.i
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  sizeof     ""S""
  IL_000a:  sub.ovf.un
  IL_000b:  stloc.0
  IL_000c:  ldloc.0
  IL_000d:  sizeof     ""S""
  IL_0013:  sub.ovf.un
  IL_0014:  stloc.0
  IL_0015:  ldloc.0
  IL_0016:  sizeof     ""S""
  IL_001c:  sub
  IL_001d:  stloc.0
  IL_001e:  ldloc.0
  IL_001f:  sizeof     ""S""
  IL_0025:  sub
  IL_0026:  stloc.0
  IL_0027:  ldloc.0
  IL_0028:  conv.i4
  IL_0029:  call       ""void System.Console.WriteLine(int)""
  IL_002e:  ret
}
");
        }
 
        [Fact]
        public void IncrementProperty()
        {
            var text = @"
using System;
 
unsafe struct S
{
    S* P { get; set; }
    S* this[int x] { get { return P; } set { P = value; } }
 
    static void Main()
    {
        S s = new S();
        s.P++;
        --s[GetIndex()];
        Console.Write((int)s.P);
    }
 
    static int GetIndex()
    {
        Console.Write(""I"");
        return 1;
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "I0", verify: Verification.Fails).VerifyIL("S.Main", @"
{
  // Code size       74 (0x4a)
  .maxstack  3
  .locals init (S V_0, //s
                S* V_1,
                int V_2)
  IL_0000:  ldloca.s   V_0
  IL_0002:  initobj    ""S""
  IL_0008:  ldloca.s   V_0
  IL_000a:  dup
  IL_000b:  call       ""readonly S* S.P.get""
  IL_0010:  stloc.1
  IL_0011:  ldloc.1
  IL_0012:  sizeof     ""S""
  IL_0018:  add
  IL_0019:  call       ""void S.P.set""
  IL_001e:  ldloca.s   V_0
  IL_0020:  call       ""int S.GetIndex()""
  IL_0025:  stloc.2
  IL_0026:  dup
  IL_0027:  ldloc.2
  IL_0028:  call       ""S* S.this[int].get""
  IL_002d:  sizeof     ""S""
  IL_0033:  sub
  IL_0034:  stloc.1
  IL_0035:  ldloc.2
  IL_0036:  ldloc.1
  IL_0037:  call       ""void S.this[int].set""
  IL_003c:  ldloca.s   V_0
  IL_003e:  call       ""readonly S* S.P.get""
  IL_0043:  conv.i4
  IL_0044:  call       ""void System.Console.Write(int)""
  IL_0049:  ret
}
");
        }
 
        [Fact]
        public void CompoundAssignment()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        S* p = (S*)8;
        checked
        {
            p += 1;
            p += 2U;
            p -= 1L;
            p -= 2UL;
        }
        unchecked
        {
            p += 1;
            p += 2U;
            p -= 1L;
            p -= 2UL;
        }
        Console.WriteLine((int)p);
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "8", verify: Verification.Fails).VerifyIL("S.Main", @"
{
  // Code size      103 (0x67)
  .maxstack  3
  .locals init (S* V_0) //p
  IL_0000:  ldc.i4.8
  IL_0001:  conv.i
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  sizeof     ""S""
  IL_000a:  add.ovf.un
  IL_000b:  stloc.0
  IL_000c:  ldloc.0
  IL_000d:  ldc.i4.2
  IL_000e:  conv.u8
  IL_000f:  sizeof     ""S""
  IL_0015:  conv.i8
  IL_0016:  mul.ovf
  IL_0017:  conv.i
  IL_0018:  add.ovf.un
  IL_0019:  stloc.0
  IL_001a:  ldloc.0
  IL_001b:  sizeof     ""S""
  IL_0021:  sub.ovf.un
  IL_0022:  stloc.0
  IL_0023:  ldloc.0
  IL_0024:  ldc.i4.2
  IL_0025:  conv.i8
  IL_0026:  sizeof     ""S""
  IL_002c:  conv.ovf.u8
  IL_002d:  mul.ovf.un
  IL_002e:  conv.u
  IL_002f:  sub.ovf.un
  IL_0030:  stloc.0
  IL_0031:  ldloc.0
  IL_0032:  sizeof     ""S""
  IL_0038:  add
  IL_0039:  stloc.0
  IL_003a:  ldloc.0
  IL_003b:  ldc.i4.2
  IL_003c:  conv.u8
  IL_003d:  sizeof     ""S""
  IL_0043:  conv.i8
  IL_0044:  mul
  IL_0045:  conv.i
  IL_0046:  add
  IL_0047:  stloc.0
  IL_0048:  ldloc.0
  IL_0049:  sizeof     ""S""
  IL_004f:  sub
  IL_0050:  stloc.0
  IL_0051:  ldloc.0
  IL_0052:  ldc.i4.2
  IL_0053:  conv.i8
  IL_0054:  sizeof     ""S""
  IL_005a:  conv.i8
  IL_005b:  mul
  IL_005c:  conv.u
  IL_005d:  sub
  IL_005e:  stloc.0
  IL_005f:  ldloc.0
  IL_0060:  conv.i4
  IL_0061:  call       ""void System.Console.WriteLine(int)""
  IL_0066:  ret
}
");
        }
 
        [Fact]
        public void CompoundAssignProperty()
        {
            var text = @"
using System;
 
unsafe struct S
{
    S* P { get; set; }
    S* this[int x] { get { return P; } set { P = value; } }
 
    static void Main()
    {
        S s = new S();
        s.P += 3;
        s[GetIndex()] -= 2;
        Console.Write((int)s.P);
    }
 
    static int GetIndex()
    {
        Console.Write(""I"");
        return 1;
    }
}
";
 
            bool isx86 = (IntPtr.Size == 4);
            string expectedOutput;
 
            if (isx86)
            {
                expectedOutput = @"I4";
            }
            else
            {
                expectedOutput = @"I8";
            }
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyIL("S.Main", @"
{
  // Code size       78 (0x4e)
  .maxstack  5
  .locals init (S V_0, //s
                S& V_1,
                int V_2)
  IL_0000:  ldloca.s   V_0
  IL_0002:  initobj    ""S""
  IL_0008:  ldloca.s   V_0
  IL_000a:  dup
  IL_000b:  call       ""readonly S* S.P.get""
  IL_0010:  ldc.i4.3
  IL_0011:  conv.i
  IL_0012:  sizeof     ""S""
  IL_0018:  mul
  IL_0019:  add
  IL_001a:  call       ""void S.P.set""
  IL_001f:  ldloca.s   V_0
  IL_0021:  stloc.1
  IL_0022:  call       ""int S.GetIndex()""
  IL_0027:  stloc.2
  IL_0028:  ldloc.1
  IL_0029:  ldloc.2
  IL_002a:  ldloc.1
  IL_002b:  ldloc.2
  IL_002c:  call       ""S* S.this[int].get""
  IL_0031:  ldc.i4.2
  IL_0032:  conv.i
  IL_0033:  sizeof     ""S""
  IL_0039:  mul
  IL_003a:  sub
  IL_003b:  call       ""void S.this[int].set""
  IL_0040:  ldloca.s   V_0
  IL_0042:  call       ""readonly S* S.P.get""
  IL_0047:  conv.i4
  IL_0048:  call       ""void System.Console.Write(int)""
  IL_004d:  ret
}
");
        }
 
        [Fact]
        public void PointerSubtraction_EmptyStruct()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        S* p = (S*)8;
        S* q = (S*)4;
        checked
        {
            Console.Write(p - q);
        }
        unchecked
        {
            Console.Write(p - q);
        }
    }
}
";
 
            // NOTE: don't use checked subtraction or division in either case (matches dev10).
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "44", verify: Verification.Fails).VerifyIL("S.Main", @"
{
  // Code size       39 (0x27)
  .maxstack  2
  .locals init (S* V_0, //p
                S* V_1) //q
  IL_0000:  ldc.i4.8
  IL_0001:  conv.i
  IL_0002:  stloc.0
  IL_0003:  ldc.i4.4
  IL_0004:  conv.i
  IL_0005:  stloc.1
  IL_0006:  ldloc.0
  IL_0007:  ldloc.1
  IL_0008:  sub
  IL_0009:  sizeof     ""S""
  IL_000f:  div
  IL_0010:  conv.i8
  IL_0011:  call       ""void System.Console.Write(long)""
  IL_0016:  ldloc.0
  IL_0017:  ldloc.1
  IL_0018:  sub
  IL_0019:  sizeof     ""S""
  IL_001f:  div
  IL_0020:  conv.i8
  IL_0021:  call       ""void System.Console.Write(long)""
  IL_0026:  ret
}
");
        }
 
        [Fact]
        public void PointerSubtraction_NonEmptyStruct()
        {
            var text = @"
using System;
 
unsafe struct S
{
    int x; //non-empty struct
 
    static void Main()
    {
        S* p = (S*)8;
        S* q = (S*)4;
        checked
        {
            Console.Write(p - q);
        }
        unchecked
        {
            Console.Write(p - q);
        }
    }
}
";
 
            // NOTE: don't use checked subtraction or division in either case (matches dev10).
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "11", verify: Verification.Fails).VerifyIL("S.Main", @"
{
  // Code size       39 (0x27)
  .maxstack  2
  .locals init (S* V_0, //p
                S* V_1) //q
  IL_0000:  ldc.i4.8
  IL_0001:  conv.i
  IL_0002:  stloc.0
  IL_0003:  ldc.i4.4
  IL_0004:  conv.i
  IL_0005:  stloc.1
  IL_0006:  ldloc.0
  IL_0007:  ldloc.1
  IL_0008:  sub
  IL_0009:  sizeof     ""S""
  IL_000f:  div
  IL_0010:  conv.i8
  IL_0011:  call       ""void System.Console.Write(long)""
  IL_0016:  ldloc.0
  IL_0017:  ldloc.1
  IL_0018:  sub
  IL_0019:  sizeof     ""S""
  IL_001f:  div
  IL_0020:  conv.i8
  IL_0021:  call       ""void System.Console.Write(long)""
  IL_0026:  ret
}
");
        }
 
        [Fact]
        public void PointerSubtraction_ConstantSize()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        int* p = (int*)8; //size is known at compile-time
        int* q = (int*)4;
        checked
        {
            Console.Write(p - q);
        }
        unchecked
        {
            Console.Write(p - q);
        }
    }
}
";
 
            // NOTE: don't use checked subtraction or division in either case (matches dev10).
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "11", verify: Verification.Fails).VerifyIL("S.Main", @"
{
  // Code size       29 (0x1d)
  .maxstack  2
  .locals init (int* V_0, //p
                int* V_1) //q
  IL_0000:  ldc.i4.8
  IL_0001:  conv.i
  IL_0002:  stloc.0
  IL_0003:  ldc.i4.4
  IL_0004:  conv.i
  IL_0005:  stloc.1
  IL_0006:  ldloc.0
  IL_0007:  ldloc.1
  IL_0008:  sub
  IL_0009:  ldc.i4.4
  IL_000a:  div
  IL_000b:  conv.i8
  IL_000c:  call       ""void System.Console.Write(long)""
  IL_0011:  ldloc.0
  IL_0012:  ldloc.1
  IL_0013:  sub
  IL_0014:  ldc.i4.4
  IL_0015:  div
  IL_0016:  conv.i8
  IL_0017:  call       ""void System.Console.Write(long)""
  IL_001c:  ret
}
");
        }
 
        [Fact]
        public void PointerSubtraction_IntegerDivision()
        {
            var text = @"
using System;
 
unsafe struct S
{
    int x; //size = 4
 
    static void Main()
    {
        S* p1 = (S*)7; //size is known at compile-time
        S* p2 = (S*)9; //size is known at compile-time
        S* q = (S*)4;
        checked
        {
            Console.Write(p1 - q);
        }
        unchecked
        {
            Console.Write(p2 - q);
        }
    }
}
";
 
            // NOTE: don't use checked subtraction or division in either case (matches dev10).
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "01", verify: Verification.Fails).VerifyIL("S.Main", @"
{
  // Code size       43 (0x2b)
  .maxstack  2
  .locals init (S* V_0, //p1
                S* V_1, //p2
                S* V_2) //q
  IL_0000:  ldc.i4.7
  IL_0001:  conv.i
  IL_0002:  stloc.0
  IL_0003:  ldc.i4.s   9
  IL_0005:  conv.i
  IL_0006:  stloc.1
  IL_0007:  ldc.i4.4
  IL_0008:  conv.i
  IL_0009:  stloc.2
  IL_000a:  ldloc.0
  IL_000b:  ldloc.2
  IL_000c:  sub
  IL_000d:  sizeof     ""S""
  IL_0013:  div
  IL_0014:  conv.i8
  IL_0015:  call       ""void System.Console.Write(long)""
  IL_001a:  ldloc.1
  IL_001b:  ldloc.2
  IL_001c:  sub
  IL_001d:  sizeof     ""S""
  IL_0023:  div
  IL_0024:  conv.i8
  IL_0025:  call       ""void System.Console.Write(long)""
  IL_002a:  ret
}
");
        }
 
        [WorkItem(544155, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544155")]
        [Fact]
        public void SubtractPointerTypes()
        {
            var text = @"
using System;
 
class PointerArithmetic
{
    static unsafe void Main()
    {
        short ia1 = 10;
        short* ptr = &ia1;
        short* newPtr;
        newPtr = ptr - 2;        
 
        Console.WriteLine((int)(ptr - newPtr));
    }
}
";
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "2", verify: Verification.Fails);
        }
 
        #endregion Pointer arithmetic tests
 
        #region Checked pointer arithmetic overflow tests
 
        // 0 - operation name (e.g. "Add")
        // 1 - pointed at type name (e.g. "S")
        // 2 - operator (e.g. "+")
        // 3 - checked/unchecked
        private const string CheckedNumericHelperTemplate = @"
unsafe static class Helper
{{
    public static void {0}Int({1}* p, int num, string description)
    {{
        {3}
        {{
            try
            {{
                p = p {2} num;
                Console.WriteLine(""{0}Int: No exception at {{0}} (value = {{1}})"",
                    description, (ulong)p);
            }}
            catch (OverflowException)
            {{
                Console.WriteLine(""{0}Int: Exception at {{0}}"", description);
            }}
        }}
    }}
 
    public static void {0}UInt({1}* p, uint num, string description)
    {{
        {3}
        {{
            try
            {{
                p = p {2} num;
                Console.WriteLine(""{0}UInt: No exception at {{0}} (value = {{1}})"",
                    description, (ulong)p);
            }}
            catch (OverflowException)
            {{
                Console.WriteLine(""{0}UInt: Exception at {{0}}"", description);
            }}
        }}
    }}
 
    public static void {0}Long({1}* p, long num, string description)
    {{
        {3}
        {{
            try
            {{
                p = p {2} num;
                Console.WriteLine(""{0}Long: No exception at {{0}} (value = {{1}})"",
                    description, (ulong)p);
            }}
            catch (OverflowException)
            {{
                Console.WriteLine(""{0}Long: Exception at {{0}}"", description);
            }}
        }}
    }}
 
    public static void {0}ULong({1}* p, ulong num, string description)
    {{
        {3}
        {{
            try
            {{
                p = p {2} num;
                Console.WriteLine(""{0}ULong: No exception at {{0}} (value = {{1}})"",
                    description, (ulong)p);
            }}
            catch (OverflowException)
            {{
                Console.WriteLine(""{0}ULong: Exception at {{0}}"", description);
            }}
        }}
    }}
}}
";
 
        private const string SizedStructs = @"
//sizeof SXX is 2 ^ XX
struct S00 { }
struct S01 { S00 a, b; }
struct S02 { S01 a, b; }
struct S03 { S02 a, b; }
struct S04 { S03 a, b; }
struct S05 { S04 a, b; }
struct S06 { S05 a, b; }
struct S07 { S06 a, b; }
struct S08 { S07 a, b; }
struct S09 { S08 a, b; }
struct S10 { S09 a, b; }
struct S11 { S10 a, b; }
struct S12 { S11 a, b; }
struct S13 { S12 a, b; }
struct S14 { S13 a, b; }
struct S15 { S14 a, b; }
struct S16 { S15 a, b; }
struct S17 { S16 a, b; }
struct S18 { S17 a, b; }
struct S19 { S18 a, b; }
struct S20 { S19 a, b; }
struct S21 { S20 a, b; }
struct S22 { S21 a, b; }
struct S23 { S22 a, b; }
struct S24 { S23 a, b; }
struct S25 { S24 a, b; }
struct S26 { S25 a, b; }
struct S27 { S26 a, b; }
//struct S28 { S27 a, b; } //Can't load type
//struct S29 { S28 a, b; } //Can't load type
//struct S30 { S29 a, b; } //Can't load type
//struct S31 { S30 a, b; } //Can't load type
";
 
        // 0 - pointed-at type
        private const string PositiveNumericAdditionCasesTemplate = @"
            Helper.AddInt(({0}*)0, int.MaxValue, ""0 + int.MaxValue"");
            Helper.AddInt(({0}*)1, int.MaxValue, ""1 + int.MaxValue"");
            Helper.AddInt(({0}*)int.MaxValue, 0, ""int.MaxValue + 0"");
            Helper.AddInt(({0}*)int.MaxValue, 1, ""int.MaxValue + 1"");
 
            //Helper.AddInt(({0}*)0, uint.MaxValue, ""0 + uint.MaxValue"");
            //Helper.AddInt(({0}*)1, uint.MaxValue, ""1 + uint.MaxValue"");
            Helper.AddInt(({0}*)uint.MaxValue, 0, ""uint.MaxValue + 0"");
            Helper.AddInt(({0}*)uint.MaxValue, 1, ""uint.MaxValue + 1"");
 
            //Helper.AddInt(({0}*)0, long.MaxValue, ""0 + long.MaxValue"");
            //Helper.AddInt(({0}*)1, long.MaxValue, ""1 + long.MaxValue"");
            //Helper.AddInt(({0}*)long.MaxValue, 0, ""long.MaxValue + 0"");
            //Helper.AddInt(({0}*)long.MaxValue, 1, ""long.MaxValue + 1"");
 
            //Helper.AddInt(({0}*)0, ulong.MaxValue, ""0 + ulong.MaxValue"");
            //Helper.AddInt(({0}*)1, ulong.MaxValue, ""1 + ulong.MaxValue"");
            //Helper.AddInt(({0}*)ulong.MaxValue, 0, ""ulong.MaxValue + 0"");
            //Helper.AddInt(({0}*)ulong.MaxValue, 1, ""ulong.MaxValue + 1"");
 
            Console.WriteLine();
 
            Helper.AddUInt(({0}*)0, int.MaxValue, ""0 + int.MaxValue"");
            Helper.AddUInt(({0}*)1, int.MaxValue, ""1 + int.MaxValue"");
            Helper.AddUInt(({0}*)int.MaxValue, 0, ""int.MaxValue + 0"");
            Helper.AddUInt(({0}*)int.MaxValue, 1, ""int.MaxValue + 1"");
 
            Helper.AddUInt(({0}*)0, uint.MaxValue, ""0 + uint.MaxValue"");
            Helper.AddUInt(({0}*)1, uint.MaxValue, ""1 + uint.MaxValue"");
            Helper.AddUInt(({0}*)uint.MaxValue, 0, ""uint.MaxValue + 0"");
            Helper.AddUInt(({0}*)uint.MaxValue, 1, ""uint.MaxValue + 1"");
 
            //Helper.AddUInt(({0}*)0, long.MaxValue, ""0 + long.MaxValue"");
            //Helper.AddUInt(({0}*)1, long.MaxValue, ""1 + long.MaxValue"");
            //Helper.AddUInt(({0}*)long.MaxValue, 0, ""long.MaxValue + 0"");
            //Helper.AddUInt(({0}*)long.MaxValue, 1, ""long.MaxValue + 1"");
 
            //Helper.AddUInt(({0}*)0, ulong.MaxValue, ""0 + ulong.MaxValue"");
            //Helper.AddUInt(({0}*)1, ulong.MaxValue, ""1 + ulong.MaxValue"");
            //Helper.AddUInt(({0}*)ulong.MaxValue, 0, ""ulong.MaxValue + 0"");
            //Helper.AddUInt(({0}*)ulong.MaxValue, 1, ""ulong.MaxValue + 1"");
 
            Console.WriteLine();
 
            Helper.AddLong(({0}*)0, int.MaxValue, ""0 + int.MaxValue"");
            Helper.AddLong(({0}*)1, int.MaxValue, ""1 + int.MaxValue"");
            Helper.AddLong(({0}*)int.MaxValue, 0, ""int.MaxValue + 0"");
            Helper.AddLong(({0}*)int.MaxValue, 1, ""int.MaxValue + 1"");
 
            Helper.AddLong(({0}*)0, uint.MaxValue, ""0 + uint.MaxValue"");
            Helper.AddLong(({0}*)1, uint.MaxValue, ""1 + uint.MaxValue"");
            Helper.AddLong(({0}*)uint.MaxValue, 0, ""uint.MaxValue + 0"");
            Helper.AddLong(({0}*)uint.MaxValue, 1, ""uint.MaxValue + 1"");
 
            Helper.AddLong(({0}*)0, long.MaxValue, ""0 + long.MaxValue"");
            Helper.AddLong(({0}*)1, long.MaxValue, ""1 + long.MaxValue"");
            //Helper.AddLong(({0}*)long.MaxValue, 0, ""long.MaxValue + 0"");
            //Helper.AddLong(({0}*)long.MaxValue, 1, ""long.MaxValue + 1"");
 
            //Helper.AddLong(({0}*)0, ulong.MaxValue, ""0 + ulong.MaxValue"");
            //Helper.AddLong(({0}*)1, ulong.MaxValue, ""1 + ulong.MaxValue"");
            //Helper.AddLong(({0}*)ulong.MaxValue, 0, ""ulong.MaxValue + 0"");
            //Helper.AddLong(({0}*)ulong.MaxValue, 1, ""ulong.MaxValue + 1"");
 
            Console.WriteLine();
 
            Helper.AddULong(({0}*)0, int.MaxValue, ""0 + int.MaxValue"");
            Helper.AddULong(({0}*)1, int.MaxValue, ""1 + int.MaxValue"");
            Helper.AddULong(({0}*)int.MaxValue, 0, ""int.MaxValue + 0"");
            Helper.AddULong(({0}*)int.MaxValue, 1, ""int.MaxValue + 1"");
 
            Helper.AddULong(({0}*)0, uint.MaxValue, ""0 + uint.MaxValue"");
            Helper.AddULong(({0}*)1, uint.MaxValue, ""1 + uint.MaxValue"");
            Helper.AddULong(({0}*)uint.MaxValue, 0, ""uint.MaxValue + 0"");
            Helper.AddULong(({0}*)uint.MaxValue, 1, ""uint.MaxValue + 1"");
 
            Helper.AddULong(({0}*)0, long.MaxValue, ""0 + long.MaxValue"");
            Helper.AddULong(({0}*)1, long.MaxValue, ""1 + long.MaxValue"");
            //Helper.AddULong(({0}*)long.MaxValue, 0, ""long.MaxValue + 0"");
            //Helper.AddULong(({0}*)long.MaxValue, 1, ""long.MaxValue + 1"");
 
            Helper.AddULong(({0}*)0, ulong.MaxValue, ""0 + ulong.MaxValue"");
            Helper.AddULong(({0}*)1, ulong.MaxValue, ""1 + ulong.MaxValue"");
            //Helper.AddULong(({0}*)ulong.MaxValue, 0, ""ulong.MaxValue + 0"");
            //Helper.AddULong(({0}*)ulong.MaxValue, 1, ""ulong.MaxValue + 1"");
";
 
        // 0 - pointed-at type
        private const string NegativeNumericAdditionCasesTemplate = @"
            Helper.AddInt(({0}*)0, -1, ""0 + (-1)"");
            Helper.AddInt(({0}*)0, int.MinValue, ""0 + int.MinValue"");
            //Helper.AddInt(({0}*)0, long.MinValue, ""0 + long.MinValue"");
 
            Console.WriteLine();
 
            Helper.AddLong(({0}*)0, -1, ""0 + (-1)"");
            Helper.AddLong(({0}*)0, int.MinValue, ""0 + int.MinValue"");
            Helper.AddLong(({0}*)0, long.MinValue, ""0 + long.MinValue"");
";
 
        // 0 - pointed-at type
        private const string PositiveNumericSubtractionCasesTemplate = @"
            Helper.SubInt(({0}*)0, 1, ""0 - 1"");
            Helper.SubInt(({0}*)0, int.MaxValue, ""0 - int.MaxValue"");
            //Helper.SubInt(({0}*)0, uint.MaxValue, ""0 - uint.MaxValue"");
            //Helper.SubInt(({0}*)0, long.MaxValue, ""0 - long.MaxValue"");
            //Helper.SubInt(({0}*)0, ulong.MaxValue, ""0 - ulong.MaxValue"");
 
            Console.WriteLine();
 
            Helper.SubUInt(({0}*)0, 1, ""0 - 1"");
            Helper.SubUInt(({0}*)0, int.MaxValue, ""0 - int.MaxValue"");
            Helper.SubUInt(({0}*)0, uint.MaxValue, ""0 - uint.MaxValue"");
            //Helper.SubUInt(({0}*)0, long.MaxValue, ""0 - long.MaxValue"");
            //Helper.SubUInt(({0}*)0, ulong.MaxValue, ""0 - ulong.MaxValue"");
 
            Console.WriteLine();
 
            Helper.SubLong(({0}*)0, 1, ""0 - 1"");
            Helper.SubLong(({0}*)0, int.MaxValue, ""0 - int.MaxValue"");
            Helper.SubLong(({0}*)0, uint.MaxValue, ""0 - uint.MaxValue"");
            Helper.SubLong(({0}*)0, long.MaxValue, ""0 - long.MaxValue"");
            //Helper.SubLong(({0}*)0, ulong.MaxValue, ""0 - ulong.MaxValue"");
 
            Console.WriteLine();
 
            Helper.SubULong(({0}*)0, 1, ""0 - 1"");
            Helper.SubULong(({0}*)0, int.MaxValue, ""0 - int.MaxValue"");
            Helper.SubULong(({0}*)0, uint.MaxValue, ""0 - uint.MaxValue"");
            Helper.SubULong(({0}*)0, long.MaxValue, ""0 - long.MaxValue"");
            Helper.SubULong(({0}*)0, ulong.MaxValue, ""0 - ulong.MaxValue"");
";
 
        // 0 - pointed-at type
        private const string NegativeNumericSubtractionCasesTemplate = @"
            Helper.SubInt(({0}*)0, -1, ""0 - -1"");
            Helper.SubInt(({0}*)0, int.MinValue, ""0 - int.MinValue"");
            Helper.SubInt(({0}*)0, -1 * int.MaxValue, ""0 - -int.MaxValue"");
 
            Console.WriteLine();
 
            Helper.SubLong(({0}*)0, -1L, ""0 - -1"");
            Helper.SubLong(({0}*)0, int.MinValue, ""0 - int.MinValue"");
            Helper.SubLong(({0}*)0, long.MinValue, ""0 - long.MinValue"");
            Helper.SubLong(({0}*)0, -1L * int.MaxValue, ""0 - -int.MaxValue"");
            Helper.SubLong(({0}*)0, -1L * uint.MaxValue, ""0 - -uint.MaxValue"");
            Helper.SubLong(({0}*)0, -1L * long.MaxValue, ""0 - -long.MaxValue"");
            Helper.SubLong(({0}*)0, -1L * long.MaxValue, ""0 - -ulong.MaxValue"");
            Helper.SubLong(({0}*)0, -1L * int.MinValue, ""0 - -int.MinValue"");
            //Helper.SubLong(({0}*)0, -1L * long.MinValue, ""0 - -long.MinValue"");
";
 
        private static string MakeNumericOverflowTest(string casesTemplate, string pointedAtType, string operationName, string @operator, string checkedness)
        {
            const string mainClassTemplate = @"
using System;
 
unsafe class C
{{
    static void Main()
    {{
        {0}
        {{
{1}
        }}
    }}
}}
 
{2}
 
{3}
";
            return string.Format(mainClassTemplate,
                checkedness,
                string.Format(casesTemplate, pointedAtType),
                string.Format(CheckedNumericHelperTemplate, operationName, pointedAtType, @operator, checkedness),
                SizedStructs);
        }
 
        // Positive numbers, size = 1
        [Fact]
        public void CheckedNumericAdditionOverflow1()
        {
            var text = MakeNumericOverflowTest(PositiveNumericAdditionCasesTemplate, "S00", "Add", "+", "checked");
            bool isx86 = (IntPtr.Size == 4);
            string expectedOutput;
 
            if (isx86)
            {
                expectedOutput = @"
AddInt: No exception at 0 + int.MaxValue (value = 2147483647)
AddInt: No exception at 1 + int.MaxValue (value = 2147483648)
AddInt: No exception at int.MaxValue + 0 (value = 2147483647)
AddInt: No exception at int.MaxValue + 1 (value = 2147483648)
AddInt: No exception at uint.MaxValue + 0 (value = 4294967295)
AddInt: Exception at uint.MaxValue + 1
 
AddUInt: No exception at 0 + int.MaxValue (value = 2147483647)
AddUInt: No exception at 1 + int.MaxValue (value = 2147483648)
AddUInt: No exception at int.MaxValue + 0 (value = 2147483647)
AddUInt: No exception at int.MaxValue + 1 (value = 2147483648)
AddUInt: No exception at 0 + uint.MaxValue (value = 4294967295)
AddUInt: Exception at 1 + uint.MaxValue
AddUInt: No exception at uint.MaxValue + 0 (value = 4294967295)
AddUInt: Exception at uint.MaxValue + 1
 
AddLong: No exception at 0 + int.MaxValue (value = 2147483647)
AddLong: No exception at 1 + int.MaxValue (value = 2147483648)
AddLong: No exception at int.MaxValue + 0 (value = 2147483647)
AddLong: No exception at int.MaxValue + 1 (value = 2147483648)
AddLong: No exception at 0 + uint.MaxValue (value = 4294967295)
AddLong: Exception at 1 + uint.MaxValue
AddLong: No exception at uint.MaxValue + 0 (value = 4294967295)
AddLong: Exception at uint.MaxValue + 1
AddLong: No exception at 0 + long.MaxValue (value = 4294967295)
AddLong: Exception at 1 + long.MaxValue
 
AddULong: No exception at 0 + int.MaxValue (value = 2147483647)
AddULong: No exception at 1 + int.MaxValue (value = 2147483648)
AddULong: No exception at int.MaxValue + 0 (value = 2147483647)
AddULong: No exception at int.MaxValue + 1 (value = 2147483648)
AddULong: No exception at 0 + uint.MaxValue (value = 4294967295)
AddULong: Exception at 1 + uint.MaxValue
AddULong: No exception at uint.MaxValue + 0 (value = 4294967295)
AddULong: Exception at uint.MaxValue + 1
AddULong: No exception at 0 + long.MaxValue (value = 4294967295)
AddULong: Exception at 1 + long.MaxValue
AddULong: No exception at 0 + ulong.MaxValue (value = 4294967295)
AddULong: Exception at 1 + ulong.MaxValue
";
            }
            else
            {
                expectedOutput = @"
AddInt: No exception at 0 + int.MaxValue (value = 2147483647)
AddInt: No exception at 1 + int.MaxValue (value = 2147483648)
AddInt: No exception at int.MaxValue + 0 (value = 2147483647)
AddInt: No exception at int.MaxValue + 1 (value = 2147483648)
AddInt: No exception at uint.MaxValue + 0 (value = 4294967295)
AddInt: No exception at uint.MaxValue + 1 (value = 4294967296)
 
AddUInt: No exception at 0 + int.MaxValue (value = 2147483647)
AddUInt: No exception at 1 + int.MaxValue (value = 2147483648)
AddUInt: No exception at int.MaxValue + 0 (value = 2147483647)
AddUInt: No exception at int.MaxValue + 1 (value = 2147483648)
AddUInt: No exception at 0 + uint.MaxValue (value = 4294967295)
AddUInt: No exception at 1 + uint.MaxValue (value = 4294967296)
AddUInt: No exception at uint.MaxValue + 0 (value = 4294967295)
AddUInt: No exception at uint.MaxValue + 1 (value = 4294967296)
 
AddLong: No exception at 0 + int.MaxValue (value = 2147483647)
AddLong: No exception at 1 + int.MaxValue (value = 2147483648)
AddLong: No exception at int.MaxValue + 0 (value = 2147483647)
AddLong: No exception at int.MaxValue + 1 (value = 2147483648)
AddLong: No exception at 0 + uint.MaxValue (value = 4294967295)
AddLong: No exception at 1 + uint.MaxValue (value = 4294967296)
AddLong: No exception at uint.MaxValue + 0 (value = 4294967295)
AddLong: No exception at uint.MaxValue + 1 (value = 4294967296)
AddLong: No exception at 0 + long.MaxValue (value = 9223372036854775807)
AddLong: No exception at 1 + long.MaxValue (value = 9223372036854775808)
 
AddULong: No exception at 0 + int.MaxValue (value = 2147483647)
AddULong: No exception at 1 + int.MaxValue (value = 2147483648)
AddULong: No exception at int.MaxValue + 0 (value = 2147483647)
AddULong: No exception at int.MaxValue + 1 (value = 2147483648)
AddULong: No exception at 0 + uint.MaxValue (value = 4294967295)
AddULong: No exception at 1 + uint.MaxValue (value = 4294967296)
AddULong: No exception at uint.MaxValue + 0 (value = 4294967295)
AddULong: No exception at uint.MaxValue + 1 (value = 4294967296)
AddULong: No exception at 0 + long.MaxValue (value = 9223372036854775807)
AddULong: No exception at 1 + long.MaxValue (value = 9223372036854775808)
AddULong: No exception at 0 + ulong.MaxValue (value = 18446744073709551615)
AddULong: Exception at 1 + ulong.MaxValue
";
            }
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails);
        }
 
        // Positive numbers, size = 4
        [Fact]
        public void CheckedNumericAdditionOverflow2()
        {
            var text = MakeNumericOverflowTest(PositiveNumericAdditionCasesTemplate, "S02", "Add", "+", "checked");
 
            bool isx86 = (IntPtr.Size == 4);
            string expectedOutput;
 
            if (isx86)
            {
                expectedOutput = @"
AddInt: Exception at 0 + int.MaxValue
AddInt: Exception at 1 + int.MaxValue
AddInt: No exception at int.MaxValue + 0 (value = 2147483647)
AddInt: No exception at int.MaxValue + 1 (value = 2147483651)
AddInt: No exception at uint.MaxValue + 0 (value = 4294967295)
AddInt: Exception at uint.MaxValue + 1
 
AddUInt: No exception at 0 + int.MaxValue (value = 4294967292)
AddUInt: No exception at 1 + int.MaxValue (value = 4294967293)
AddUInt: No exception at int.MaxValue + 0 (value = 2147483647)
AddUInt: No exception at int.MaxValue + 1 (value = 2147483651)
AddUInt: No exception at 0 + uint.MaxValue (value = 4294967292)
AddUInt: No exception at 1 + uint.MaxValue (value = 4294967293)
AddUInt: No exception at uint.MaxValue + 0 (value = 4294967295)
AddUInt: Exception at uint.MaxValue + 1
 
AddLong: No exception at 0 + int.MaxValue (value = 4294967292)
AddLong: No exception at 1 + int.MaxValue (value = 4294967293)
AddLong: No exception at int.MaxValue + 0 (value = 2147483647)
AddLong: No exception at int.MaxValue + 1 (value = 2147483651)
AddLong: No exception at 0 + uint.MaxValue (value = 4294967292)
AddLong: No exception at 1 + uint.MaxValue (value = 4294967293)
AddLong: No exception at uint.MaxValue + 0 (value = 4294967295)
AddLong: Exception at uint.MaxValue + 1
AddLong: Exception at 0 + long.MaxValue
AddLong: Exception at 1 + long.MaxValue
 
AddULong: No exception at 0 + int.MaxValue (value = 4294967292)
AddULong: No exception at 1 + int.MaxValue (value = 4294967293)
AddULong: No exception at int.MaxValue + 0 (value = 2147483647)
AddULong: No exception at int.MaxValue + 1 (value = 2147483651)
AddULong: No exception at 0 + uint.MaxValue (value = 4294967292)
AddULong: No exception at 1 + uint.MaxValue (value = 4294967293)
AddULong: No exception at uint.MaxValue + 0 (value = 4294967295)
AddULong: Exception at uint.MaxValue + 1
AddULong: Exception at 0 + long.MaxValue
AddULong: Exception at 1 + long.MaxValue
AddULong: Exception at 0 + ulong.MaxValue
AddULong: Exception at 1 + ulong.MaxValue
";
            }
            else
            {
                expectedOutput = @"
AddInt: No exception at 0 + int.MaxValue (value = 8589934588)
AddInt: No exception at 1 + int.MaxValue (value = 8589934589)
AddInt: No exception at int.MaxValue + 0 (value = 2147483647)
AddInt: No exception at int.MaxValue + 1 (value = 2147483651)
AddInt: No exception at uint.MaxValue + 0 (value = 4294967295)
AddInt: No exception at uint.MaxValue + 1 (value = 4294967299)
 
AddUInt: No exception at 0 + int.MaxValue (value = 8589934588)
AddUInt: No exception at 1 + int.MaxValue (value = 8589934589)
AddUInt: No exception at int.MaxValue + 0 (value = 2147483647)
AddUInt: No exception at int.MaxValue + 1 (value = 2147483651)
AddUInt: No exception at 0 + uint.MaxValue (value = 17179869180)
AddUInt: No exception at 1 + uint.MaxValue (value = 17179869181)
AddUInt: No exception at uint.MaxValue + 0 (value = 4294967295)
AddUInt: No exception at uint.MaxValue + 1 (value = 4294967299)
 
AddLong: No exception at 0 + int.MaxValue (value = 8589934588)
AddLong: No exception at 1 + int.MaxValue (value = 8589934589)
AddLong: No exception at int.MaxValue + 0 (value = 2147483647)
AddLong: No exception at int.MaxValue + 1 (value = 2147483651)
AddLong: No exception at 0 + uint.MaxValue (value = 17179869180)
AddLong: No exception at 1 + uint.MaxValue (value = 17179869181)
AddLong: No exception at uint.MaxValue + 0 (value = 4294967295)
AddLong: No exception at uint.MaxValue + 1 (value = 4294967299)
AddLong: Exception at 0 + long.MaxValue
AddLong: Exception at 1 + long.MaxValue
 
AddULong: No exception at 0 + int.MaxValue (value = 8589934588)
AddULong: No exception at 1 + int.MaxValue (value = 8589934589)
AddULong: No exception at int.MaxValue + 0 (value = 2147483647)
AddULong: No exception at int.MaxValue + 1 (value = 2147483651)
AddULong: No exception at 0 + uint.MaxValue (value = 17179869180)
AddULong: No exception at 1 + uint.MaxValue (value = 17179869181)
AddULong: No exception at uint.MaxValue + 0 (value = 4294967295)
AddULong: No exception at uint.MaxValue + 1 (value = 4294967299)
AddULong: Exception at 0 + long.MaxValue
AddULong: Exception at 1 + long.MaxValue
AddULong: Exception at 0 + ulong.MaxValue
AddULong: Exception at 1 + ulong.MaxValue
";
            }
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails);
        }
 
        // Negative numbers, size = 1
        [Fact]
        public void CheckedNumericAdditionOverflow3()
        {
            var text = MakeNumericOverflowTest(NegativeNumericAdditionCasesTemplate, "S00", "Add", "+", "checked");
 
            bool isx86 = (IntPtr.Size == 4);
            string expectedOutput;
 
            if (isx86)
            {
                expectedOutput = @"
AddInt: No exception at 0 + (-1) (value = 4294967295)
AddInt: No exception at 0 + int.MinValue (value = 2147483648)
 
AddLong: No exception at 0 + (-1) (value = 4294967295)
AddLong: No exception at 0 + int.MinValue (value = 2147483648)
AddLong: No exception at 0 + long.MinValue (value = 0)
";
            }
            else
            {
                expectedOutput = @"
AddInt: No exception at 0 + (-1) (value = 18446744073709551615)
AddInt: No exception at 0 + int.MinValue (value = 18446744071562067968)
 
AddLong: No exception at 0 + (-1) (value = 18446744073709551615)
AddLong: No exception at 0 + int.MinValue (value = 18446744071562067968)
AddLong: No exception at 0 + long.MinValue (value = 9223372036854775808)
";
            }
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails, expectedOutput: expectedOutput);
        }
 
        // Negative numbers, size = 4
        [Fact]
        public void CheckedNumericAdditionOverflow4()
        {
            var text = MakeNumericOverflowTest(NegativeNumericAdditionCasesTemplate, "S02", "Add", "+", "checked");
 
            bool isx86 = (IntPtr.Size == 4);
            string expectedOutput;
 
            if (isx86)
            {
                expectedOutput = @"
AddInt: No exception at 0 + (-1) (value = 4294967292)
AddInt: Exception at 0 + int.MinValue
 
AddLong: No exception at 0 + (-1) (value = 4294967292)
AddLong: No exception at 0 + int.MinValue (value = 0)
AddLong: Exception at 0 + long.MinValue
";
            }
            else
            {
                expectedOutput = @"
AddInt: No exception at 0 + (-1) (value = 18446744073709551612)
AddInt: No exception at 0 + int.MinValue (value = 18446744065119617024)
 
AddLong: No exception at 0 + (-1) (value = 18446744073709551612)
AddLong: No exception at 0 + int.MinValue (value = 18446744065119617024)
AddLong: Exception at 0 + long.MinValue
";
            }
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails);
        }
 
        // Positive numbers, size = 1
        [Fact]
        public void CheckedNumericSubtractionOverflow1()
        {
            var text = MakeNumericOverflowTest(PositiveNumericSubtractionCasesTemplate, "S00", "Sub", "-", "checked");
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails, expectedOutput: @"
SubInt: Exception at 0 - 1
SubInt: Exception at 0 - int.MaxValue
 
SubUInt: Exception at 0 - 1
SubUInt: Exception at 0 - int.MaxValue
SubUInt: Exception at 0 - uint.MaxValue
 
SubLong: Exception at 0 - 1
SubLong: Exception at 0 - int.MaxValue
SubLong: Exception at 0 - uint.MaxValue
SubLong: Exception at 0 - long.MaxValue
 
SubULong: Exception at 0 - 1
SubULong: Exception at 0 - int.MaxValue
SubULong: Exception at 0 - uint.MaxValue
SubULong: Exception at 0 - long.MaxValue
SubULong: Exception at 0 - ulong.MaxValue
");
        }
 
        // Positive numbers, size = 4
        [Fact]
        public void CheckedNumericSubtractionOverflow2()
        {
            var text = MakeNumericOverflowTest(PositiveNumericSubtractionCasesTemplate, "S02", "Sub", "-", "checked");
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails, expectedOutput: @"
SubInt: Exception at 0 - 1
SubInt: Exception at 0 - int.MaxValue
 
SubUInt: Exception at 0 - 1
SubUInt: Exception at 0 - int.MaxValue
SubUInt: Exception at 0 - uint.MaxValue
 
SubLong: Exception at 0 - 1
SubLong: Exception at 0 - int.MaxValue
SubLong: Exception at 0 - uint.MaxValue
SubLong: Exception at 0 - long.MaxValue
 
SubULong: Exception at 0 - 1
SubULong: Exception at 0 - int.MaxValue
SubULong: Exception at 0 - uint.MaxValue
SubULong: Exception at 0 - long.MaxValue
SubULong: Exception at 0 - ulong.MaxValue
");
        }
 
        // Negative numbers, size = 1
        [Fact]
        public void CheckedNumericSubtractionOverflow3()
        {
            var text = MakeNumericOverflowTest(NegativeNumericSubtractionCasesTemplate, "S00", "Sub", "-", "checked");
            bool isx86 = (IntPtr.Size == 4);
            string expectedOutput;
 
            if (isx86)
            {
                expectedOutput = @"
SubInt: Exception at 0 - -1
SubInt: Exception at 0 - int.MinValue
SubInt: Exception at 0 - -int.MaxValue
 
SubLong: Exception at 0 - -1
SubLong: Exception at 0 - int.MinValue
SubLong: No exception at 0 - long.MinValue (value = 0)
SubLong: Exception at 0 - -int.MaxValue
SubLong: Exception at 0 - -uint.MaxValue
SubLong: Exception at 0 - -long.MaxValue
SubLong: Exception at 0 - -ulong.MaxValue
SubLong: Exception at 0 - -int.MinValue
";
            }
            else
            {
                expectedOutput = @"
SubInt: Exception at 0 - -1
SubInt: Exception at 0 - int.MinValue
SubInt: Exception at 0 - -int.MaxValue
 
SubLong: Exception at 0 - -1
SubLong: Exception at 0 - int.MinValue
SubLong: Exception at 0 - long.MinValue
SubLong: Exception at 0 - -int.MaxValue
SubLong: Exception at 0 - -uint.MaxValue
SubLong: Exception at 0 - -long.MaxValue
SubLong: Exception at 0 - -ulong.MaxValue
SubLong: Exception at 0 - -int.MinValue
";
            }
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails);
        }
 
        // Negative numbers, size = 4
        [Fact]
        public void CheckedNumericSubtractionOverflow4()
        {
            var text = MakeNumericOverflowTest(NegativeNumericSubtractionCasesTemplate, "S02", "Sub", "-", "checked");
 
            bool isx86 = (IntPtr.Size == 4);
            string expectedOutput;
 
            if (isx86)
            {
                expectedOutput = @"
SubInt: Exception at 0 - -1
SubInt: Exception at 0 - int.MinValue
SubInt: Exception at 0 - -int.MaxValue
 
SubLong: Exception at 0 - -1
SubLong: No exception at 0 - int.MinValue (value = 0)
SubLong: Exception at 0 - long.MinValue
SubLong: Exception at 0 - -int.MaxValue
SubLong: Exception at 0 - -uint.MaxValue
SubLong: Exception at 0 - -long.MaxValue
SubLong: Exception at 0 - -ulong.MaxValue
SubLong: No exception at 0 - -int.MinValue (value = 0)
";
            }
            else
            {
                expectedOutput = @"
SubInt: Exception at 0 - -1
SubInt: Exception at 0 - int.MinValue
SubInt: Exception at 0 - -int.MaxValue
 
SubLong: Exception at 0 - -1
SubLong: Exception at 0 - int.MinValue
SubLong: Exception at 0 - long.MinValue
SubLong: Exception at 0 - -int.MaxValue
SubLong: Exception at 0 - -uint.MaxValue
SubLong: Exception at 0 - -long.MaxValue
SubLong: Exception at 0 - -ulong.MaxValue
SubLong: Exception at 0 - -int.MinValue
";
            }
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails);
        }
 
        [Fact]
        public void CheckedNumericSubtractionQuirk()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        checked
        {
            S* p;
            p = (S*)0 + (-1);
            System.Console.WriteLine(""No exception from addition"");
            try
            {
                p = (S*)0 - 1;
            }
            catch (OverflowException)
            {
                System.Console.WriteLine(""Exception from subtraction"");
            }
        }
    }
}
";
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.Passes, expectedOutput: @"
No exception from addition
Exception from subtraction
");
        }
 
        [Fact]
        public void CheckedNumericAdditionQuirk()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        checked
        {
            S* p;
            p = (S*)1 + int.MaxValue;
            System.Console.WriteLine(""No exception for pointer + int"");
            try
            {
                p = int.MaxValue + (S*)1;
            }
            catch (OverflowException)
            {
                System.Console.WriteLine(""Exception for int + pointer"");
            }
        }
    }
}
";
            bool isx86 = (IntPtr.Size == 4);
            string expectedOutput;
 
            if (isx86)
            {
                expectedOutput = @"
No exception for pointer + int
Exception for int + pointer
";
            }
            else
            {
                expectedOutput = @"
No exception for pointer + int
";
            }
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Passes);
        }
 
        [Fact]
        public void CheckedPointerSubtractionQuirk()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        S* p = (S*)uint.MinValue;
        S* q = (S*)uint.MaxValue;
        checked
        {
            Console.Write(p - q);
        }
        unchecked
        {
            Console.Write(p - q);
        }
    }
}
";
            bool isx86 = (IntPtr.Size == 4);
            string expectedOutput;
 
            if (isx86)
            {
                expectedOutput = @"11";
            }
            else
            {
                expectedOutput = @"-4294967295-4294967295";
            }
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails);
        }
 
        [Fact]
        public void CheckedPointerElementAccessQuirk()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        fixed (byte* p = new byte[2])
        {
            p[0] = 12;
 
            // Take a pointer to the second element of the array.
            byte* q = p + 1;
 
            // Compute the offset that will wrap around all the way to the preceding byte of memory.
            // We do this so that we can overflow, but still end up in valid memory.
            ulong offset = sizeof(IntPtr) == sizeof(int) ? uint.MaxValue : ulong.MaxValue;
 
            checked
            {
                Console.WriteLine(q[offset]);
                System.Console.WriteLine(""No exception for element access"");
                try
                {
                    Console.WriteLine(*(q + offset));
                }
                catch (OverflowException)
                {
                    System.Console.WriteLine(""Exception for add-then-dereference"");
                }
            }
        }
    }
}
";
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails, expectedOutput: @"
12
No exception for element access
Exception for add-then-dereference
");
        }
 
        #endregion Checked pointer arithmetic overflow tests
 
        #region Unchecked pointer arithmetic overflow tests
 
        // Positive numbers, size = 1
        [Fact]
        public void UncheckedNumericAdditionOverflow1()
        {
            var text = MakeNumericOverflowTest(PositiveNumericAdditionCasesTemplate, "S00", "Add", "+", "unchecked");
 
            bool isx86 = (IntPtr.Size == 4);
            string expectedOutput;
 
            if (isx86)
            {
                expectedOutput = @"
AddInt: No exception at 0 + int.MaxValue (value = 2147483647)
AddInt: No exception at 1 + int.MaxValue (value = 2147483648)
AddInt: No exception at int.MaxValue + 0 (value = 2147483647)
AddInt: No exception at int.MaxValue + 1 (value = 2147483648)
AddInt: No exception at uint.MaxValue + 0 (value = 4294967295)
AddInt: No exception at uint.MaxValue + 1 (value = 0)
 
AddUInt: No exception at 0 + int.MaxValue (value = 2147483647)
AddUInt: No exception at 1 + int.MaxValue (value = 2147483648)
AddUInt: No exception at int.MaxValue + 0 (value = 2147483647)
AddUInt: No exception at int.MaxValue + 1 (value = 2147483648)
AddUInt: No exception at 0 + uint.MaxValue (value = 4294967295)
AddUInt: No exception at 1 + uint.MaxValue (value = 0)
AddUInt: No exception at uint.MaxValue + 0 (value = 4294967295)
AddUInt: No exception at uint.MaxValue + 1 (value = 0)
 
AddLong: No exception at 0 + int.MaxValue (value = 2147483647)
AddLong: No exception at 1 + int.MaxValue (value = 2147483648)
AddLong: No exception at int.MaxValue + 0 (value = 2147483647)
AddLong: No exception at int.MaxValue + 1 (value = 2147483648)
AddLong: No exception at 0 + uint.MaxValue (value = 4294967295)
AddLong: No exception at 1 + uint.MaxValue (value = 0)
AddLong: No exception at uint.MaxValue + 0 (value = 4294967295)
AddLong: No exception at uint.MaxValue + 1 (value = 0)
AddLong: No exception at 0 + long.MaxValue (value = 4294967295)
AddLong: No exception at 1 + long.MaxValue (value = 0)
 
AddULong: No exception at 0 + int.MaxValue (value = 2147483647)
AddULong: No exception at 1 + int.MaxValue (value = 2147483648)
AddULong: No exception at int.MaxValue + 0 (value = 2147483647)
AddULong: No exception at int.MaxValue + 1 (value = 2147483648)
AddULong: No exception at 0 + uint.MaxValue (value = 4294967295)
AddULong: No exception at 1 + uint.MaxValue (value = 0)
AddULong: No exception at uint.MaxValue + 0 (value = 4294967295)
AddULong: No exception at uint.MaxValue + 1 (value = 0)
AddULong: No exception at 0 + long.MaxValue (value = 4294967295)
AddULong: No exception at 1 + long.MaxValue (value = 0)
AddULong: No exception at 0 + ulong.MaxValue (value = 4294967295)
AddULong: No exception at 1 + ulong.MaxValue (value = 0)
";
            }
            else
            {
                expectedOutput = @"
AddInt: No exception at 0 + int.MaxValue (value = 2147483647)
AddInt: No exception at 1 + int.MaxValue (value = 2147483648)
AddInt: No exception at int.MaxValue + 0 (value = 2147483647)
AddInt: No exception at int.MaxValue + 1 (value = 2147483648)
AddInt: No exception at uint.MaxValue + 0 (value = 4294967295)
AddInt: No exception at uint.MaxValue + 1 (value = 4294967296)
 
AddUInt: No exception at 0 + int.MaxValue (value = 2147483647)
AddUInt: No exception at 1 + int.MaxValue (value = 2147483648)
AddUInt: No exception at int.MaxValue + 0 (value = 2147483647)
AddUInt: No exception at int.MaxValue + 1 (value = 2147483648)
AddUInt: No exception at 0 + uint.MaxValue (value = 4294967295)
AddUInt: No exception at 1 + uint.MaxValue (value = 4294967296)
AddUInt: No exception at uint.MaxValue + 0 (value = 4294967295)
AddUInt: No exception at uint.MaxValue + 1 (value = 4294967296)
 
AddLong: No exception at 0 + int.MaxValue (value = 2147483647)
AddLong: No exception at 1 + int.MaxValue (value = 2147483648)
AddLong: No exception at int.MaxValue + 0 (value = 2147483647)
AddLong: No exception at int.MaxValue + 1 (value = 2147483648)
AddLong: No exception at 0 + uint.MaxValue (value = 4294967295)
AddLong: No exception at 1 + uint.MaxValue (value = 4294967296)
AddLong: No exception at uint.MaxValue + 0 (value = 4294967295)
AddLong: No exception at uint.MaxValue + 1 (value = 4294967296)
AddLong: No exception at 0 + long.MaxValue (value = 9223372036854775807)
AddLong: No exception at 1 + long.MaxValue (value = 9223372036854775808)
 
AddULong: No exception at 0 + int.MaxValue (value = 2147483647)
AddULong: No exception at 1 + int.MaxValue (value = 2147483648)
AddULong: No exception at int.MaxValue + 0 (value = 2147483647)
AddULong: No exception at int.MaxValue + 1 (value = 2147483648)
AddULong: No exception at 0 + uint.MaxValue (value = 4294967295)
AddULong: No exception at 1 + uint.MaxValue (value = 4294967296)
AddULong: No exception at uint.MaxValue + 0 (value = 4294967295)
AddULong: No exception at uint.MaxValue + 1 (value = 4294967296)
AddULong: No exception at 0 + long.MaxValue (value = 9223372036854775807)
AddULong: No exception at 1 + long.MaxValue (value = 9223372036854775808)
AddULong: No exception at 0 + ulong.MaxValue (value = 18446744073709551615)
AddULong: No exception at 1 + ulong.MaxValue (value = 0)
";
            }
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails);
        }
 
        // Positive numbers, size = 4
        [Fact]
        public void UncheckedNumericAdditionOverflow2()
        {
            var text = MakeNumericOverflowTest(PositiveNumericAdditionCasesTemplate, "S02", "Add", "+", "unchecked");
 
            bool isx86 = (IntPtr.Size == 4);
            string expectedOutput;
 
            if (isx86)
            {
                expectedOutput = @"
AddInt: No exception at 0 + int.MaxValue (value = 4294967292)
AddInt: No exception at 1 + int.MaxValue (value = 4294967293)
AddInt: No exception at int.MaxValue + 0 (value = 2147483647)
AddInt: No exception at int.MaxValue + 1 (value = 2147483651)
AddInt: No exception at uint.MaxValue + 0 (value = 4294967295)
AddInt: No exception at uint.MaxValue + 1 (value = 3)
 
AddUInt: No exception at 0 + int.MaxValue (value = 4294967292)
AddUInt: No exception at 1 + int.MaxValue (value = 4294967293)
AddUInt: No exception at int.MaxValue + 0 (value = 2147483647)
AddUInt: No exception at int.MaxValue + 1 (value = 2147483651)
AddUInt: No exception at 0 + uint.MaxValue (value = 4294967292)
AddUInt: No exception at 1 + uint.MaxValue (value = 4294967293)
AddUInt: No exception at uint.MaxValue + 0 (value = 4294967295)
AddUInt: No exception at uint.MaxValue + 1 (value = 3)
 
AddLong: No exception at 0 + int.MaxValue (value = 4294967292)
AddLong: No exception at 1 + int.MaxValue (value = 4294967293)
AddLong: No exception at int.MaxValue + 0 (value = 2147483647)
AddLong: No exception at int.MaxValue + 1 (value = 2147483651)
AddLong: No exception at 0 + uint.MaxValue (value = 4294967292)
AddLong: No exception at 1 + uint.MaxValue (value = 4294967293)
AddLong: No exception at uint.MaxValue + 0 (value = 4294967295)
AddLong: No exception at uint.MaxValue + 1 (value = 3)
AddLong: No exception at 0 + long.MaxValue (value = 4294967292)
AddLong: No exception at 1 + long.MaxValue (value = 4294967293)
 
AddULong: No exception at 0 + int.MaxValue (value = 4294967292)
AddULong: No exception at 1 + int.MaxValue (value = 4294967293)
AddULong: No exception at int.MaxValue + 0 (value = 2147483647)
AddULong: No exception at int.MaxValue + 1 (value = 2147483651)
AddULong: No exception at 0 + uint.MaxValue (value = 4294967292)
AddULong: No exception at 1 + uint.MaxValue (value = 4294967293)
AddULong: No exception at uint.MaxValue + 0 (value = 4294967295)
AddULong: No exception at uint.MaxValue + 1 (value = 3)
AddULong: No exception at 0 + long.MaxValue (value = 4294967292)
AddULong: No exception at 1 + long.MaxValue (value = 4294967293)
AddULong: No exception at 0 + ulong.MaxValue (value = 4294967292)
AddULong: No exception at 1 + ulong.MaxValue (value = 4294967293)
";
            }
            else
            {
                expectedOutput = @"
AddInt: No exception at 0 + int.MaxValue (value = 8589934588)
AddInt: No exception at 1 + int.MaxValue (value = 8589934589)
AddInt: No exception at int.MaxValue + 0 (value = 2147483647)
AddInt: No exception at int.MaxValue + 1 (value = 2147483651)
AddInt: No exception at uint.MaxValue + 0 (value = 4294967295)
AddInt: No exception at uint.MaxValue + 1 (value = 4294967299)
 
AddUInt: No exception at 0 + int.MaxValue (value = 8589934588)
AddUInt: No exception at 1 + int.MaxValue (value = 8589934589)
AddUInt: No exception at int.MaxValue + 0 (value = 2147483647)
AddUInt: No exception at int.MaxValue + 1 (value = 2147483651)
AddUInt: No exception at 0 + uint.MaxValue (value = 17179869180)
AddUInt: No exception at 1 + uint.MaxValue (value = 17179869181)
AddUInt: No exception at uint.MaxValue + 0 (value = 4294967295)
AddUInt: No exception at uint.MaxValue + 1 (value = 4294967299)
 
AddLong: No exception at 0 + int.MaxValue (value = 8589934588)
AddLong: No exception at 1 + int.MaxValue (value = 8589934589)
AddLong: No exception at int.MaxValue + 0 (value = 2147483647)
AddLong: No exception at int.MaxValue + 1 (value = 2147483651)
AddLong: No exception at 0 + uint.MaxValue (value = 17179869180)
AddLong: No exception at 1 + uint.MaxValue (value = 17179869181)
AddLong: No exception at uint.MaxValue + 0 (value = 4294967295)
AddLong: No exception at uint.MaxValue + 1 (value = 4294967299)
AddLong: No exception at 0 + long.MaxValue (value = 18446744073709551612)
AddLong: No exception at 1 + long.MaxValue (value = 18446744073709551613)
 
AddULong: No exception at 0 + int.MaxValue (value = 8589934588)
AddULong: No exception at 1 + int.MaxValue (value = 8589934589)
AddULong: No exception at int.MaxValue + 0 (value = 2147483647)
AddULong: No exception at int.MaxValue + 1 (value = 2147483651)
AddULong: No exception at 0 + uint.MaxValue (value = 17179869180)
AddULong: No exception at 1 + uint.MaxValue (value = 17179869181)
AddULong: No exception at uint.MaxValue + 0 (value = 4294967295)
AddULong: No exception at uint.MaxValue + 1 (value = 4294967299)
AddULong: No exception at 0 + long.MaxValue (value = 18446744073709551612)
AddULong: No exception at 1 + long.MaxValue (value = 18446744073709551613)
AddULong: No exception at 0 + ulong.MaxValue (value = 18446744073709551612)
AddULong: No exception at 1 + ulong.MaxValue (value = 18446744073709551613)
";
            }
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails);
        }
 
        // Negative numbers, size = 1
        [Fact]
        public void UncheckedNumericAdditionOverflow3()
        {
            var text = MakeNumericOverflowTest(NegativeNumericAdditionCasesTemplate, "S00", "Add", "+", "unchecked");
 
            bool isx86 = (IntPtr.Size == 4);
            string expectedOutput;
 
            if (isx86)
            {
                expectedOutput = @"
AddInt: No exception at 0 + (-1) (value = 4294967295)
AddInt: No exception at 0 + int.MinValue (value = 2147483648)
 
AddLong: No exception at 0 + (-1) (value = 4294967295)
AddLong: No exception at 0 + int.MinValue (value = 2147483648)
AddLong: No exception at 0 + long.MinValue (value = 0)
";
            }
            else
            {
                expectedOutput = @"
AddInt: No exception at 0 + (-1) (value = 18446744073709551615)
AddInt: No exception at 0 + int.MinValue (value = 18446744071562067968)
 
AddLong: No exception at 0 + (-1) (value = 18446744073709551615)
AddLong: No exception at 0 + int.MinValue (value = 18446744071562067968)
AddLong: No exception at 0 + long.MinValue (value = 9223372036854775808)
";
            }
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails);
        }
 
        // Negative numbers, size = 4
        [Fact]
        public void UncheckedNumericAdditionOverflow4()
        {
            var text = MakeNumericOverflowTest(NegativeNumericAdditionCasesTemplate, "S02", "Add", "+", "unchecked");
 
            bool isx86 = (IntPtr.Size == 4);
            string expectedOutput;
 
            if (isx86)
            {
                expectedOutput = @"
AddInt: No exception at 0 + (-1) (value = 4294967292)
AddInt: No exception at 0 + int.MinValue (value = 0)
 
AddLong: No exception at 0 + (-1) (value = 4294967292)
AddLong: No exception at 0 + int.MinValue (value = 0)
AddLong: No exception at 0 + long.MinValue (value = 0)
";
            }
            else
            {
                expectedOutput = @"
AddInt: No exception at 0 + (-1) (value = 18446744073709551612)
AddInt: No exception at 0 + int.MinValue (value = 18446744065119617024)
 
AddLong: No exception at 0 + (-1) (value = 18446744073709551612)
AddLong: No exception at 0 + int.MinValue (value = 18446744065119617024)
AddLong: No exception at 0 + long.MinValue (value = 0)
";
            }
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails);
        }
 
        // Positive numbers, size = 1
        [Fact]
        public void UncheckedNumericSubtractionOverflow1()
        {
            var text = MakeNumericOverflowTest(PositiveNumericSubtractionCasesTemplate, "S00", "Sub", "-", "unchecked");
 
            bool isx86 = (IntPtr.Size == 4);
            string expectedOutput;
 
            if (isx86)
            {
                expectedOutput = @"
SubInt: No exception at 0 - 1 (value = 4294967295)
SubInt: No exception at 0 - int.MaxValue (value = 2147483649)
 
SubUInt: No exception at 0 - 1 (value = 4294967295)
SubUInt: No exception at 0 - int.MaxValue (value = 2147483649)
SubUInt: No exception at 0 - uint.MaxValue (value = 1)
 
SubLong: No exception at 0 - 1 (value = 4294967295)
SubLong: No exception at 0 - int.MaxValue (value = 2147483649)
SubLong: No exception at 0 - uint.MaxValue (value = 1)
SubLong: No exception at 0 - long.MaxValue (value = 1)
 
SubULong: No exception at 0 - 1 (value = 4294967295)
SubULong: No exception at 0 - int.MaxValue (value = 2147483649)
SubULong: No exception at 0 - uint.MaxValue (value = 1)
SubULong: No exception at 0 - long.MaxValue (value = 1)
SubULong: No exception at 0 - ulong.MaxValue (value = 1)
";
            }
            else
            {
                expectedOutput = @"
SubInt: No exception at 0 - 1 (value = 18446744073709551615)
SubInt: No exception at 0 - int.MaxValue (value = 18446744071562067969)
 
SubUInt: No exception at 0 - 1 (value = 18446744073709551615)
SubUInt: No exception at 0 - int.MaxValue (value = 18446744071562067969)
SubUInt: No exception at 0 - uint.MaxValue (value = 18446744069414584321)
 
SubLong: No exception at 0 - 1 (value = 18446744073709551615)
SubLong: No exception at 0 - int.MaxValue (value = 18446744071562067969)
SubLong: No exception at 0 - uint.MaxValue (value = 18446744069414584321)
SubLong: No exception at 0 - long.MaxValue (value = 9223372036854775809)
 
SubULong: No exception at 0 - 1 (value = 18446744073709551615)
SubULong: No exception at 0 - int.MaxValue (value = 18446744071562067969)
SubULong: No exception at 0 - uint.MaxValue (value = 18446744069414584321)
SubULong: No exception at 0 - long.MaxValue (value = 9223372036854775809)
SubULong: No exception at 0 - ulong.MaxValue (value = 1)
";
            }
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails);
        }
 
        // Positive numbers, size = 4
        [Fact]
        public void UncheckedNumericSubtractionOverflow2()
        {
            var text = MakeNumericOverflowTest(PositiveNumericSubtractionCasesTemplate, "S02", "Sub", "-", "unchecked");
 
            bool isx86 = (IntPtr.Size == 4);
            string expectedOutput;
 
            if (isx86)
            {
                expectedOutput = @"
SubInt: No exception at 0 - 1 (value = 4294967292)
SubInt: No exception at 0 - int.MaxValue (value = 4)
 
SubUInt: No exception at 0 - 1 (value = 4294967292)
SubUInt: No exception at 0 - int.MaxValue (value = 4)
SubUInt: No exception at 0 - uint.MaxValue (value = 4)
 
SubLong: No exception at 0 - 1 (value = 4294967292)
SubLong: No exception at 0 - int.MaxValue (value = 4)
SubLong: No exception at 0 - uint.MaxValue (value = 4)
SubLong: No exception at 0 - long.MaxValue (value = 4)
 
SubULong: No exception at 0 - 1 (value = 4294967292)
SubULong: No exception at 0 - int.MaxValue (value = 4)
SubULong: No exception at 0 - uint.MaxValue (value = 4)
SubULong: No exception at 0 - long.MaxValue (value = 4)
SubULong: No exception at 0 - ulong.MaxValue (value = 4)
";
            }
            else
            {
                expectedOutput = @"
SubInt: No exception at 0 - 1 (value = 18446744073709551612)
SubInt: No exception at 0 - int.MaxValue (value = 18446744065119617028)
 
SubUInt: No exception at 0 - 1 (value = 18446744073709551612)
SubUInt: No exception at 0 - int.MaxValue (value = 18446744065119617028)
SubUInt: No exception at 0 - uint.MaxValue (value = 18446744056529682436)
 
SubLong: No exception at 0 - 1 (value = 18446744073709551612)
SubLong: No exception at 0 - int.MaxValue (value = 18446744065119617028)
SubLong: No exception at 0 - uint.MaxValue (value = 18446744056529682436)
SubLong: No exception at 0 - long.MaxValue (value = 4)
 
SubULong: No exception at 0 - 1 (value = 18446744073709551612)
SubULong: No exception at 0 - int.MaxValue (value = 18446744065119617028)
SubULong: No exception at 0 - uint.MaxValue (value = 18446744056529682436)
SubULong: No exception at 0 - long.MaxValue (value = 4)
SubULong: No exception at 0 - ulong.MaxValue (value = 4)
";
            }
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails);
        }
 
        // Negative numbers, size = 1
        [Fact]
        public void UncheckedNumericSubtractionOverflow3()
        {
            var text = MakeNumericOverflowTest(NegativeNumericSubtractionCasesTemplate, "S00", "Sub", "-", "unchecked");
 
            bool isx86 = (IntPtr.Size == 4);
            string expectedOutput;
 
            if (isx86)
            {
                expectedOutput = @"
SubInt: No exception at 0 - -1 (value = 1)
SubInt: No exception at 0 - int.MinValue (value = 2147483648)
SubInt: No exception at 0 - -int.MaxValue (value = 2147483647)
 
SubLong: No exception at 0 - -1 (value = 1)
SubLong: No exception at 0 - int.MinValue (value = 2147483648)
SubLong: No exception at 0 - long.MinValue (value = 0)
SubLong: No exception at 0 - -int.MaxValue (value = 2147483647)
SubLong: No exception at 0 - -uint.MaxValue (value = 4294967295)
SubLong: No exception at 0 - -long.MaxValue (value = 4294967295)
SubLong: No exception at 0 - -ulong.MaxValue (value = 4294967295)
SubLong: No exception at 0 - -int.MinValue (value = 2147483648)
";
            }
            else
            {
                expectedOutput = @"
SubInt: No exception at 0 - -1 (value = 1)
SubInt: No exception at 0 - int.MinValue (value = 2147483648)
SubInt: No exception at 0 - -int.MaxValue (value = 2147483647)
 
SubLong: No exception at 0 - -1 (value = 1)
SubLong: No exception at 0 - int.MinValue (value = 2147483648)
SubLong: No exception at 0 - long.MinValue (value = 9223372036854775808)
SubLong: No exception at 0 - -int.MaxValue (value = 2147483647)
SubLong: No exception at 0 - -uint.MaxValue (value = 4294967295)
SubLong: No exception at 0 - -long.MaxValue (value = 9223372036854775807)
SubLong: No exception at 0 - -ulong.MaxValue (value = 9223372036854775807)
SubLong: No exception at 0 - -int.MinValue (value = 18446744071562067968)
";
            }
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails);
        }
 
        // Negative numbers, size = 4
        [Fact]
        public void UncheckedNumericSubtractionOverflow4()
        {
            var text = MakeNumericOverflowTest(NegativeNumericSubtractionCasesTemplate, "S02", "Sub", "-", "unchecked");
            bool isx86 = (IntPtr.Size == 4);
            string expectedOutput;
 
            if (isx86)
            {
                expectedOutput = @"
SubInt: No exception at 0 - -1 (value = 4)
SubInt: No exception at 0 - int.MinValue (value = 0)
SubInt: No exception at 0 - -int.MaxValue (value = 4294967292)
 
SubLong: No exception at 0 - -1 (value = 4)
SubLong: No exception at 0 - int.MinValue (value = 0)
SubLong: No exception at 0 - long.MinValue (value = 0)
SubLong: No exception at 0 - -int.MaxValue (value = 4294967292)
SubLong: No exception at 0 - -uint.MaxValue (value = 4294967292)
SubLong: No exception at 0 - -long.MaxValue (value = 4294967292)
SubLong: No exception at 0 - -ulong.MaxValue (value = 4294967292)
SubLong: No exception at 0 - -int.MinValue (value = 0)";
            }
            else
            {
                expectedOutput = @"
SubInt: No exception at 0 - -1 (value = 4)
SubInt: No exception at 0 - int.MinValue (value = 8589934592)
SubInt: No exception at 0 - -int.MaxValue (value = 8589934588)
 
SubLong: No exception at 0 - -1 (value = 4)
SubLong: No exception at 0 - int.MinValue (value = 8589934592)
SubLong: No exception at 0 - long.MinValue (value = 0)
SubLong: No exception at 0 - -int.MaxValue (value = 8589934588)
SubLong: No exception at 0 - -uint.MaxValue (value = 17179869180)
SubLong: No exception at 0 - -long.MaxValue (value = 18446744073709551612)
SubLong: No exception at 0 - -ulong.MaxValue (value = 18446744073709551612)
SubLong: No exception at 0 - -int.MinValue (value = 18446744065119617024)";
            }
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails);
        }
 
        #endregion Unchecked pointer arithmetic overflow tests
 
        #region Pointer comparison tests
 
        [Fact]
        public void PointerComparisonSameType()
        {
            var text = @"
using System;
 
unsafe struct S
{
    static void Main()
    {
        S* p = (S*)0;
        S* q = (S*)1;
 
        unchecked
        {
            Write(p == q);
            Write(p != q);
            Write(p <= q);
            Write(p >= q);
            Write(p < q);
            Write(p > q);
        }
 
        checked
        {
            Write(p == q);
            Write(p != q);
            Write(p <= q);
            Write(p >= q);
            Write(p < q);
            Write(p > q);
        }
    }
 
    static void Write(bool b)
    {
        Console.Write(b ? 1 : 0);
    }
}
";
            // NOTE: all comparisons unsigned.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "011010011010", verify: Verification.Fails).VerifyIL("S.Main", @"
{
  // Code size      133 (0x85)
  .maxstack  2
  .locals init (S* V_0, //p
                S* V_1) //q
  IL_0000:  ldc.i4.0
  IL_0001:  conv.i
  IL_0002:  stloc.0
  IL_0003:  ldc.i4.1
  IL_0004:  conv.i
  IL_0005:  stloc.1
  IL_0006:  ldloc.0
  IL_0007:  ldloc.1
  IL_0008:  ceq
  IL_000a:  call       ""void S.Write(bool)""
  IL_000f:  ldloc.0
  IL_0010:  ldloc.1
  IL_0011:  ceq
  IL_0013:  ldc.i4.0
  IL_0014:  ceq
  IL_0016:  call       ""void S.Write(bool)""
  IL_001b:  ldloc.0
  IL_001c:  ldloc.1
  IL_001d:  cgt.un
  IL_001f:  ldc.i4.0
  IL_0020:  ceq
  IL_0022:  call       ""void S.Write(bool)""
  IL_0027:  ldloc.0
  IL_0028:  ldloc.1
  IL_0029:  clt.un
  IL_002b:  ldc.i4.0
  IL_002c:  ceq
  IL_002e:  call       ""void S.Write(bool)""
  IL_0033:  ldloc.0
  IL_0034:  ldloc.1
  IL_0035:  clt.un
  IL_0037:  call       ""void S.Write(bool)""
  IL_003c:  ldloc.0
  IL_003d:  ldloc.1
  IL_003e:  cgt.un
  IL_0040:  call       ""void S.Write(bool)""
  IL_0045:  ldloc.0
  IL_0046:  ldloc.1
  IL_0047:  ceq
  IL_0049:  call       ""void S.Write(bool)""
  IL_004e:  ldloc.0
  IL_004f:  ldloc.1
  IL_0050:  ceq
  IL_0052:  ldc.i4.0
  IL_0053:  ceq
  IL_0055:  call       ""void S.Write(bool)""
  IL_005a:  ldloc.0
  IL_005b:  ldloc.1
  IL_005c:  cgt.un
  IL_005e:  ldc.i4.0
  IL_005f:  ceq
  IL_0061:  call       ""void S.Write(bool)""
  IL_0066:  ldloc.0
  IL_0067:  ldloc.1
  IL_0068:  clt.un
  IL_006a:  ldc.i4.0
  IL_006b:  ceq
  IL_006d:  call       ""void S.Write(bool)""
  IL_0072:  ldloc.0
  IL_0073:  ldloc.1
  IL_0074:  clt.un
  IL_0076:  call       ""void S.Write(bool)""
  IL_007b:  ldloc.0
  IL_007c:  ldloc.1
  IL_007d:  cgt.un
  IL_007f:  call       ""void S.Write(bool)""
  IL_0084:  ret
}
");
        }
 
        [Fact, WorkItem(49639, "https://github.com/dotnet/roslyn/issues/49639")]
        public void CompareToNullWithNestedUnconstrainedTypeParameter()
        {
            var verifier = CompileAndVerify(@"
using System;
unsafe
{
    test<int>(null);
    S<int> s = default;
    test<int>(&s);
 
    static void test<T>(S<T>* s)
    {
        Console.WriteLine(s == null);
        Console.WriteLine(s is null);
    }
}
 
struct S<T> {}
", options: TestOptions.UnsafeReleaseExe, expectedOutput: @"
True
True
False
False", verify: Verification.Skipped);
 
            verifier.VerifyIL("Program.<<Main>$>g__test|0_0<T>(S<T>*)", @"
{
  // Code size       21 (0x15)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  conv.u
  IL_0003:  ceq
  IL_0005:  call       ""void System.Console.WriteLine(bool)""
  IL_000a:  ldarg.0
  IL_000b:  ldc.i4.0
  IL_000c:  conv.u
  IL_000d:  ceq
  IL_000f:  call       ""void System.Console.WriteLine(bool)""
  IL_0014:  ret
}
");
        }
 
        [Fact, WorkItem(49639, "https://github.com/dotnet/roslyn/issues/49639")]
        public void CompareToNullWithPointerToUnmanagedTypeParameter()
        {
            var verifier = CompileAndVerify(@"
using System;
unsafe
{
    test<int>(null);
    int i = 0;
    test<int>(&i);
 
    static void test<T>(T* t) where T : unmanaged
    {
        Console.WriteLine(t == null);
        Console.WriteLine(t is null);
    }
}
", options: TestOptions.UnsafeReleaseExe, expectedOutput: @"
True
True
False
False", verify: Verification.Skipped);
 
            verifier.VerifyIL("Program.<<Main>$>g__test|0_0<T>(T*)", @"
{
  // Code size       21 (0x15)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  conv.u
  IL_0003:  ceq
  IL_0005:  call       ""void System.Console.WriteLine(bool)""
  IL_000a:  ldarg.0
  IL_000b:  ldc.i4.0
  IL_000c:  conv.u
  IL_000d:  ceq
  IL_000f:  call       ""void System.Console.WriteLine(bool)""
  IL_0014:  ret
}
");
        }
 
        [Theory]
        [InlineData("int*")]
        [InlineData("int*[]")]
        [InlineData("delegate*<void>")]
        [InlineData("T*")]
        [InlineData("delegate*<T>")]
        public void CompareToNullInPatternOutsideUnsafe(string pointerType)
        {
            var comp = CreateCompilation($@"
var c = default(S<int>);
_ = c.Field is null;
unsafe struct S<T> where T : unmanaged
{{
#pragma warning disable CS0649 // Field is unassigned
    public {pointerType} Field;
}}
", options: TestOptions.UnsafeReleaseExe);
 
            comp.VerifyDiagnostics(
                // (3,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                // _ = c.Field is null;
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "c.Field").WithLocation(3, 5)
            );
        }
 
        #endregion Pointer comparison tests
 
        #region stackalloc tests
 
        [Fact]
        public void SimpleStackAlloc()
        {
            var text = @"
unsafe class C
{
    void M()
    {
        int count = 1;
        checked
        {
            int* p = stackalloc int[2];
            char* q = stackalloc char[count];
 
            Use(p);
            Use(q);
        }
        unchecked
        {
            int* p = stackalloc int[2];
            char* q = stackalloc char[count];
 
            Use(p);
            Use(q);
        }
    }
 
    static void Use(int * ptr)
    {        
    }
 
    static void Use(char * ptr)
    {        
    }
}
";
            // NOTE: conversion is always unchecked, multiplication is always checked.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyIL("C.M", @"
{
  // Code size       47 (0x2f)
  .maxstack  2
  .locals init (int V_0, //count
                int* V_1, //p
                int* V_2) //p
  IL_0000:  ldc.i4.1
  IL_0001:  stloc.0
  IL_0002:  ldc.i4.8
  IL_0003:  conv.u
  IL_0004:  localloc
  IL_0006:  stloc.1
  IL_0007:  ldloc.0
  IL_0008:  conv.u
  IL_0009:  ldc.i4.2
  IL_000a:  mul.ovf.un
  IL_000b:  localloc
  IL_000d:  ldloc.1
  IL_000e:  call       ""void C.Use(int*)""
  IL_0013:  call       ""void C.Use(char*)""
  IL_0018:  ldc.i4.8
  IL_0019:  conv.u
  IL_001a:  localloc
  IL_001c:  stloc.2
  IL_001d:  ldloc.0
  IL_001e:  conv.u
  IL_001f:  ldc.i4.2
  IL_0020:  mul.ovf.un
  IL_0021:  localloc
  IL_0023:  ldloc.2
  IL_0024:  call       ""void C.Use(int*)""
  IL_0029:  call       ""void C.Use(char*)""
  IL_002e:  ret
}
");
 
        }
 
        [Fact]
        public void StackAllocConversion()
        {
            var text = @"
unsafe class C
{
    void M()
    {
        void* p = stackalloc int[2];
        C q = stackalloc int[2];
    }
 
    public static implicit operator C(int* p)
    {
        return null;
    }
}
";
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyIL("C.M", @"
{
  // Code size       16 (0x10)
  .maxstack  1
  .locals init (void* V_0) //p
  IL_0000:  ldc.i4.8
  IL_0001:  conv.u
  IL_0002:  localloc
  IL_0004:  stloc.0
  IL_0005:  ldc.i4.8
  IL_0006:  conv.u
  IL_0007:  localloc
  IL_0009:  call       ""C C.op_Implicit(int*)""
  IL_000e:  pop
  IL_000f:  ret
}
");
        }
 
        [Fact]
        public void StackAllocConversionZero()
        {
            var text = @"
unsafe class C
{
    void M()
    {
        void* p = stackalloc int[0];
        C q = stackalloc int[0];
    }
 
    public static implicit operator C(int* p)
    {
        return null;
    }
}
";
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.FailsPEVerify).VerifyIL("C.M", @"
{
  // Code size       12 (0xc)
  .maxstack  1
  .locals init (void* V_0) //p
  IL_0000:  ldc.i4.0
  IL_0001:  conv.u
  IL_0002:  stloc.0
  IL_0003:  ldc.i4.0
  IL_0004:  conv.u
  IL_0005:  call       ""C C.op_Implicit(int*)""
  IL_000a:  pop
  IL_000b:  ret
}
");
        }
 
        [Fact]
        public void StackAllocSpecExample() //Section 18.8
        {
            var text = @"
using System;
 
unsafe class C
{
    static void Main()
    {
        Console.WriteLine(IntToString(123));
        Console.WriteLine(IntToString(-456));
    }
 
	static string IntToString(int value) {
		int n = value >= 0? value: -value;
		unsafe {
			char* buffer = stackalloc char[16];
			char* p = buffer + 16;
			do {
				*--p = (char)(n % 10 + '0');
				n /= 10;
			} while (n != 0);
			if (value < 0) *--p = '-';
			return new string(p, 0, (int)(buffer + 16 - p));
		}
	}
}
";
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails, expectedOutput: @"123
-456
");
        }
 
        // See MethodToClassRewriter.VisitAssignmentOperator for an explanation.
        [Fact]
        public void StackAllocIntoHoistedLocal1()
        {
            var text = @"
using System;
 
unsafe class C
{
    static void Main()
    {
        var p = stackalloc int[2];
        var q = stackalloc int[2];
 
        Action a = () =>
        {
            var r = stackalloc int[2];
            var s = stackalloc int[2];
 
            Action b = () =>
            {
                p = null; //capture p
                r = null; //capture r
            };
            
            Use(s);
        };
 
        Use(q);
    }
 
    static void Use(int * ptr)
    {        
    }
}
";
            var verifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails);
 
            // Note that the stackalloc for p is written into a temp *before* the receiver (i.e. "this")
            // for C.<>c__DisplayClass0.p is pushed onto the stack.
            verifier.VerifyIL("C.Main", @"
{
  // Code size       28 (0x1c)
  .maxstack  2
  .locals init (C.<>c__DisplayClass0_0 V_0, //CS$<>8__locals0
                int* V_1)
  IL_0000:  newobj     ""C.<>c__DisplayClass0_0..ctor()""
  IL_0005:  stloc.0
  IL_0006:  ldc.i4.8
  IL_0007:  conv.u
  IL_0008:  localloc
  IL_000a:  stloc.1
  IL_000b:  ldloc.0
  IL_000c:  ldloc.1
  IL_000d:  stfld      ""int* C.<>c__DisplayClass0_0.p""
  IL_0012:  ldc.i4.8
  IL_0013:  conv.u
  IL_0014:  localloc
  IL_0016:  call       ""void C.Use(int*)""
  IL_001b:  ret
}
");
 
            // Check that the same thing works inside a lambda.
            verifier.VerifyIL("C.<>c__DisplayClass0_0.<Main>b__0", @"
{
  // Code size       35 (0x23)
  .maxstack  2
  .locals init (C.<>c__DisplayClass0_1 V_0, //CS$<>8__locals0
                int* V_1)
  IL_0000:  newobj     ""C.<>c__DisplayClass0_1..ctor()""
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  ldarg.0
  IL_0008:  stfld      ""C.<>c__DisplayClass0_0 C.<>c__DisplayClass0_1.CS$<>8__locals1""
  IL_000d:  ldc.i4.8
  IL_000e:  conv.u
  IL_000f:  localloc
  IL_0011:  stloc.1
  IL_0012:  ldloc.0
  IL_0013:  ldloc.1
  IL_0014:  stfld      ""int* C.<>c__DisplayClass0_1.r""
  IL_0019:  ldc.i4.8
  IL_001a:  conv.u
  IL_001b:  localloc
  IL_001d:  call       ""void C.Use(int*)""
  IL_0022:  ret
}
");
        }
 
        // See MethodToClassRewriter.VisitAssignmentOperator for an explanation.
        [Fact]
        public void StackAllocIntoHoistedLocal2()
        {
            // From native bug #59454 (in DevDiv collection)
            var text = @"
unsafe class T 
{ 
    delegate int D(); 
 
    static void Main() 
    { 
        int* v = stackalloc int[1]; 
        D d = delegate { return *v; }; 
        System.Console.WriteLine(d()); 
    } 
} 
";
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "0", verify: Verification.Fails).VerifyIL("T.Main", @"
{
  // Code size       41 (0x29)
  .maxstack  2
  .locals init (T.<>c__DisplayClass1_0 V_0, //CS$<>8__locals0
                int* V_1)
  IL_0000:  newobj     ""T.<>c__DisplayClass1_0..ctor()""
  IL_0005:  stloc.0
  IL_0006:  ldc.i4.4
  IL_0007:  conv.u
  IL_0008:  localloc
  IL_000a:  stloc.1
  IL_000b:  ldloc.0
  IL_000c:  ldloc.1
  IL_000d:  stfld      ""int* T.<>c__DisplayClass1_0.v""
  IL_0012:  ldloc.0
  IL_0013:  ldftn      ""int T.<>c__DisplayClass1_0.<Main>b__0()""
  IL_0019:  newobj     ""T.D..ctor(object, System.IntPtr)""
  IL_001e:  callvirt   ""int T.D.Invoke()""
  IL_0023:  call       ""void System.Console.WriteLine(int)""
  IL_0028:  ret
}
");
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "0", verify: Verification.Fails).VerifyIL("T.Main", @"
{
  // Code size       41 (0x29)
  .maxstack  2
  .locals init (T.<>c__DisplayClass1_0 V_0, //CS$<>8__locals0
                int* V_1)
  IL_0000:  newobj     ""T.<>c__DisplayClass1_0..ctor()""
  IL_0005:  stloc.0
  IL_0006:  ldc.i4.4
  IL_0007:  conv.u
  IL_0008:  localloc
  IL_000a:  stloc.1
  IL_000b:  ldloc.0
  IL_000c:  ldloc.1
  IL_000d:  stfld      ""int* T.<>c__DisplayClass1_0.v""
  IL_0012:  ldloc.0
  IL_0013:  ldftn      ""int T.<>c__DisplayClass1_0.<Main>b__0()""
  IL_0019:  newobj     ""T.D..ctor(object, System.IntPtr)""
  IL_001e:  callvirt   ""int T.D.Invoke()""
  IL_0023:  call       ""void System.Console.WriteLine(int)""
  IL_0028:  ret
}
");
        }
 
        [Fact]
        public void CSLegacyStackallocUse32bitChecked()
        {
            // This is from C# Legacy test where it uses Perl script to call ildasm and check 'mul.ovf' emitted
            // $Roslyn\Main\LegacyTest\CSharp\Source\csharp\Source\Conformance\unsafecode\stackalloc\regr001.cs
            var text = @"// <Title>Should checked affect stackalloc?</Title>
// <Description>
// The lower level localloc MSIL instruction takes an unsigned native int as input; however the higher level 
// stackalloc uses only 32-bits. The example shows the operation overflowing the 32-bit multiply which leads to 
// a curious edge condition.
// If compile with /checked we insert a mul.ovf instruction, and this causes a system overflow exception at runtime.
// </Description>
// <RelatedBugs>VSW:489857</RelatedBugs>
 
using System;
 
public class C
{
    private static unsafe int Main()
    {
        Int64* intArray = stackalloc Int64[0x7fffffff];
        return (int)intArray[0];
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails);
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       13 (0xd)
  .maxstack  2
  IL_0000:  ldc.i4     0x7fffffff
  IL_0005:  conv.u
  IL_0006:  ldc.i4.8
  IL_0007:  mul.ovf.un
  IL_0008:  localloc
  IL_000a:  ldind.i8
  IL_000b:  conv.i4
  IL_000c:  ret
}
");
        }
 
        #endregion stackalloc tests
 
        #region Functional tests
 
        [Fact]
        public void BubbleSort()
        {
            var text = @"
using System;
 
unsafe class C
{
    static void Main() 
    {
        BubbleSort();
        BubbleSort(1);
        BubbleSort(2, 1);
        BubbleSort(3, 1, 2);
        BubbleSort(3, 1, 4, 2);
    }
 
    static void BubbleSort(params int[] array)
    {
        if (array == null)
        {
            return;
        }
 
        fixed (int* begin = array)
        {
            BubbleSort(begin, end: begin + array.Length);
        }
 
        Console.WriteLine(string.Join("", "", array));
    }
 
    private static void BubbleSort(int* begin, int* end)
    {
        for (int* firstUnsorted = begin; firstUnsorted < end; firstUnsorted++)
        {
            for (int* current = firstUnsorted; current + 1 < end; current++)
            {
                if (current[0] > current[1])
                {
                    SwapWithNext(current);
                }
            }
        }
    }
 
    static void SwapWithNext(int* p)
    {
        int temp = *p;
        p[0] = p[1];
        p[1] = temp;
    }
}
";
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails, expectedOutput: @"
1
1, 2
1, 2, 3
1, 2, 3, 4");
        }
 
        [Fact]
        public void BigStructs()
        {
            var text = @"
unsafe class C
{
    static void Main()
    {
        void* v;
 
        CheckOverflow(""(S15*)0 + sizeof(S15)"", () => v = checked((S15*)0 + sizeof(S15)));
        CheckOverflow(""(S15*)0 + sizeof(S16)"", () => v = checked((S15*)0 + sizeof(S16)));
        CheckOverflow(""(S16*)0 + sizeof(S15)"", () => v = checked((S16*)0 + sizeof(S15)));
    }
 
    static void CheckOverflow(string description, System.Action operation)
    {
        try
        {
            operation();
            System.Console.WriteLine(""No overflow from {0}"", description);
        }
        catch (System.OverflowException)
        {
            System.Console.WriteLine(""Overflow from {0}"", description);
        }
    }
}
" + SizedStructs;
 
            bool isx86 = (IntPtr.Size == 4);
            string expectedOutput;
 
            if (isx86)
            {
                expectedOutput = @"
No overflow from (S15*)0 + sizeof(S15)
Overflow from (S15*)0 + sizeof(S16)
Overflow from (S16*)0 + sizeof(S15)";
            }
            else
            {
                expectedOutput = @"
No overflow from (S15*)0 + sizeof(S15)
No overflow from (S15*)0 + sizeof(S16)
No overflow from (S16*)0 + sizeof(S15)";
            }
            // PEVerify:
            // [ : C+<>c__DisplayClass0_0::<Main>b__0][mdToken=0x6000005][offset 0x00000012][found Native Int][expected unmanaged pointer] Unexpected type on the stack.
            // [ : C+<> c__DisplayClass0_0::< Main > b__1][mdToken= 0x6000006][offset 0x00000012][found Native Int][expected unmanaged pointer] Unexpected type on the stack.
            // [ : C +<> c__DisplayClass0_0::< Main > b__2][mdToken = 0x6000007][offset 0x00000012][found Native Int][expected unmanaged pointer] Unexpected type on the stack.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify);
        }
 
        [Fact]
        public void LambdaConversion()
        {
            var text = @"
using System;
 
class Program
{
    static void Main()
    {
        Goo(x => { });
    }
 
    static void Goo(F1 f) { Console.WriteLine(1); }
    static void Goo(F2 f) { Console.WriteLine(2); }
}
 
unsafe delegate void F1(int* x);
delegate void F2(int x);
";
 
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: @"2", verify: Verification.Passes);
        }
 
        [Fact]
        public void LambdaConversion_PointerArray()
        {
            var text = @"
using System;
 
class C<T> { }
 
class Program
{
    static void Main()
    {
        M(x => { });
    }
 
    static void M(F1 f) { throw null; }
    static void M(F2 f) { Console.WriteLine(2); }
}
 
unsafe delegate void F1(C<int*[]> x);
delegate void F2(int x);
";
 
            var comp = CreateCompilation(text, options: TestOptions.UnsafeDebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "2");
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67330")]
        public void ParameterContainsPointer()
        {
            var source = """
class C<T> { }
class D
{
    public static void M1()
    {
        var lam1 = (int* ptr) => ptr; // 1
    }
    public static void M2()
    {
        var lam2 = (int*[] a) => a; // 2
    }
    public static void M3()
    {
        var lam3 = (delegate*<void> ptr) => ptr; // 3
    }
    public static void M4()
    {
        var lam4 = (C<delegate*<void>[]> a) => a; // 4
    }
}
""";
            var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll);
            comp.VerifyDiagnostics(
                // (6,21): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         var lam1 = (int* ptr) => ptr; // 1
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 21),
                // (6,26): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         var lam1 = (int* ptr) => ptr; // 1
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "ptr").WithLocation(6, 26),
                // (6,34): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         var lam1 = (int* ptr) => ptr; // 1
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "ptr").WithLocation(6, 34),
                // (10,21): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         var lam2 = (int*[] a) => a; // 2
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(10, 21),
                // (10,28): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         var lam2 = (int*[] a) => a; // 2
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "a").WithLocation(10, 28),
                // (10,34): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         var lam2 = (int*[] a) => a; // 2
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "a").WithLocation(10, 34),
                // (14,21): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         var lam3 = (delegate*<void> ptr) => ptr; // 3
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "delegate*").WithLocation(14, 21),
                // (14,37): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         var lam3 = (delegate*<void> ptr) => ptr; // 3
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "ptr").WithLocation(14, 37),
                // (14,45): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         var lam3 = (delegate*<void> ptr) => ptr; // 3
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "ptr").WithLocation(14, 45),
                // (18,23): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         var lam4 = (C<delegate*<void>[]> a) => a; // 4
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "delegate*").WithLocation(18, 23),
                // (18,42): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         var lam4 = (C<delegate*<void>[]> a) => a; // 4
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "a").WithLocation(18, 42),
                // (18,48): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         var lam4 = (C<delegate*<void>[]> a) => a; // 4
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "a").WithLocation(18, 48)
                );
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67330")]
        public void DelegateConversionContainsPointer()
        {
            var source = """
class C<T> { }
unsafe delegate int* D1(int* ptr);
unsafe delegate int*[] D2(int*[] a);
unsafe delegate delegate*<void> D3(delegate*<void> ptr);
unsafe delegate C<delegate*<void>[]> D4(C<delegate*<void>[]> a);
 
class D
{
    public static D1 M1()
    {
        return (ptr) => ptr; // 1
    }
    public static D2 M2()
    {
        return (a) => a; // 2
    }
    public static D3 M3()
    {
        return (ptr) => ptr; // 3
    }
    public static D4 M4()
    {
        return (a) => a; // 4
    }
}
""";
            var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll);
            comp.VerifyDiagnostics(
                // (11,17): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         return (ptr) => ptr; // 1
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "ptr").WithLocation(11, 17),
                // (11,25): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         return (ptr) => ptr; // 1
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "ptr").WithLocation(11, 25),
                // (15,17): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         return (a) => a; // 2
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "a").WithLocation(15, 17),
                // (15,23): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         return (a) => a; // 2
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "a").WithLocation(15, 23),
                // (19,17): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         return (ptr) => ptr; // 3
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "ptr").WithLocation(19, 17),
                // (19,25): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         return (ptr) => ptr; // 3
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "ptr").WithLocation(19, 25),
                // (23,17): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         return (a) => a; // 4
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "a").WithLocation(23, 17),
                // (23,23): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
                //         return (a) => a; // 4
                Diagnostic(ErrorCode.ERR_UnsafeNeeded, "a").WithLocation(23, 23)
                );
        }
 
        [Fact]
        public void LocalVariableReuse()
        {
            var text = @"
unsafe class C
{
    int this[string s] { get { return 0; } set { } }
 
    void Test()
    {
        {
            this[""not pinned"".ToString()] += 2; //creates an unpinned string local (for the argument)
        }
 
        fixed (char* p = ""pinned"") //creates a pinned string local
        {
        }
 
        {
            this[""not pinned"".ToString()] += 2; //reuses the unpinned string local
        }
 
        fixed (char* p = ""pinned"") //reuses the pinned string local
        {
        }
    }
}
";
            // NOTE: one pinned string temp and one unpinned string temp.
            // That is, pinned temps are reused in by other pinned temps
            // but not by unpinned temps and vice versa.
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyIL("C.Test", @"
{
  // Code size       99 (0x63)
  .maxstack  4
  .locals init (string V_0,
                char* V_1, //p
                pinned string V_2,
                char* V_3) //p
  IL_0000:  ldstr      ""not pinned""
  IL_0005:  callvirt   ""string object.ToString()""
  IL_000a:  stloc.0
  IL_000b:  ldarg.0
  IL_000c:  ldloc.0
  IL_000d:  ldarg.0
  IL_000e:  ldloc.0
  IL_000f:  call       ""int C.this[string].get""
  IL_0014:  ldc.i4.2
  IL_0015:  add
  IL_0016:  call       ""void C.this[string].set""
  IL_001b:  ldstr      ""pinned""
  IL_0020:  stloc.2
  IL_0021:  ldloc.2
  IL_0022:  conv.u
  IL_0023:  stloc.1
  IL_0024:  ldloc.1
  IL_0025:  brfalse.s  IL_002f
  IL_0027:  ldloc.1
  IL_0028:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_002d:  add
  IL_002e:  stloc.1
  IL_002f:  ldnull
  IL_0030:  stloc.2
  IL_0031:  ldstr      ""not pinned""
  IL_0036:  callvirt   ""string object.ToString()""
  IL_003b:  stloc.0
  IL_003c:  ldarg.0
  IL_003d:  ldloc.0
  IL_003e:  ldarg.0
  IL_003f:  ldloc.0
  IL_0040:  call       ""int C.this[string].get""
  IL_0045:  ldc.i4.2
  IL_0046:  add
  IL_0047:  call       ""void C.this[string].set""
  IL_004c:  ldstr      ""pinned""
  IL_0051:  stloc.2
  IL_0052:  ldloc.2
  IL_0053:  conv.u
  IL_0054:  stloc.3
  IL_0055:  ldloc.3
  IL_0056:  brfalse.s  IL_0060
  IL_0058:  ldloc.3
  IL_0059:  call       ""int System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData.get""
  IL_005e:  add
  IL_005f:  stloc.3
  IL_0060:  ldnull
  IL_0061:  stloc.2
  IL_0062:  ret
}");
        }
 
        [WorkItem(544229, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544229")]
        [Fact]
        public void UnsafeTypeAsAttributeArgument()
        {
            var template = @"
using System;
 
namespace System
{{
    class Int32 {{ }}
}}
 
 
[A(Type = typeof({0}))]
class A : Attribute
{{
    public Type Type;
    static void Main()
    {{
        var a = (A)typeof(A).GetCustomAttributes(false)[0];
        Console.WriteLine(a.Type == typeof({0}));
    }}
}}
";
            CompileAndVerify(string.Format(template, "int"), options: TestOptions.UnsafeReleaseExe, expectedOutput: @"True", verify: Verification.Passes);
            CompileAndVerify(string.Format(template, "int*"), options: TestOptions.UnsafeReleaseExe, expectedOutput: @"True", verify: Verification.Passes);
            CompileAndVerify(string.Format(template, "int**"), options: TestOptions.UnsafeReleaseExe, expectedOutput: @"True", verify: Verification.Passes);
            CompileAndVerify(string.Format(template, "int[]"), options: TestOptions.UnsafeReleaseExe, expectedOutput: @"True", verify: Verification.Passes);
            CompileAndVerify(string.Format(template, "int[][]"), options: TestOptions.UnsafeReleaseExe, expectedOutput: @"True", verify: Verification.Passes);
            CompileAndVerify(string.Format(template, "int*[]"), options: TestOptions.UnsafeReleaseExe, expectedOutput: @"True", verify: Verification.Passes);
        }
 
        #endregion Functional tests
 
        #region Regression tests
 
        [WorkItem(545026, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545026")]
        [Fact]
        public void MixedSafeAndUnsafeFields()
        {
            var text =
@"struct Perf_Contexts
{
    int data;
    private int SuppressUnused(int x) { data = x; return data; }
}
 
public sealed class ChannelServices
{
    static unsafe Perf_Contexts* GetPrivateContextsPerfCounters() { return null; }
    private static int I1 = 12;
    unsafe private static Perf_Contexts* perf_Contexts = GetPrivateContextsPerfCounters();
    private static int I2 = 13;
    private static int SuppressUnused(int x) { return I1 + I2; }
}
 
public class Test
{
    public static void Main()
    {
    }
}
";
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.FailsPEVerify with
            {
                PEVerifyMessage = """
                    [ : ChannelServices::.cctor][offset 0x0000000C][found unmanaged pointer][expected unmanaged pointer] Unexpected type on the stack.
                    [ : ChannelServices::GetPrivateContextsPerfCounters][offset 0x00000002][found Native Int][expected unmanaged pointer] Unexpected type on the stack.
                    """,
            }).VerifyDiagnostics();
        }
 
        [WorkItem(545026, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545026")]
        [Fact]
        public void SafeFieldBeforeUnsafeField()
        {
            var text = @"
class C
{
    int x = 1;
    unsafe int* p = (int*)2;
}
";
            var c = CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.FailsPEVerify with
            {
                PEVerifyMessage = "[ : C::.ctor][offset 0x0000000A][found Native Int][expected unmanaged pointer] Unexpected type on the stack."
            });
 
            c.VerifyDiagnostics(
                // (4,9): warning CS0414: The field 'C.x' is assigned but its value is never used
                //     int x = 1;
                Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "x").WithArguments("C.x"));
        }
 
        [WorkItem(545026, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545026")]
        [Fact]
        public void SafeFieldAfterUnsafeField()
        {
            var text = @"
class C
{
    unsafe int* p = (int*)2;
    int x = 1;
}
";
            var c = CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.FailsPEVerify with
            {
                PEVerifyMessage = "[ : C::.ctor][offset 0x00000003][found Native Int][expected unmanaged pointer] Unexpected type on the stack."
            });
 
            c.VerifyDiagnostics(
                // (5,9): warning CS0414: The field 'C.x' is assigned but its value is never used
                //     int x = 1;
                Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "x").WithArguments("C.x"));
        }
 
        [WorkItem(545026, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545026"), WorkItem(598170, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/598170")]
        [Fact]
        public void FixedPassByRef()
        {
            var text = @"
class Test
{
    unsafe static int printAddress(out int* pI)
    {
        pI = null;
        System.Console.WriteLine((ulong)pI);
        return 1;
    }
 
    unsafe static int printAddress1(ref int* pI)
    {
        pI = null;
        System.Console.WriteLine((ulong)pI);
        return 1;
    }
 
    static int Main()
    {
        int retval = 0;
        S s = new S();
        unsafe
        {
            retval = Test.printAddress(out s.i);
            retval = Test.printAddress1(ref s.i);
        }
 
        if (retval == 0)
            System.Console.WriteLine(""Failed."");
 
        return retval;
    }
}
unsafe struct S
{
    public fixed int i[1];
}
 
";
            var comp = CreateCompilation(text, options: TestOptions.UnsafeReleaseDll);
            comp.VerifyDiagnostics(
                // (24,44): error CS1510: A ref or out argument must be an assignable variable
                //             retval = Test.printAddress(out s.i);
                Diagnostic(ErrorCode.ERR_RefLvalueExpected, "s.i"),
                // (25,45): error CS1510: A ref or out argument must be an assignable variable
                //             retval = Test.printAddress1(ref s.i);
                Diagnostic(ErrorCode.ERR_RefLvalueExpected, "s.i"));
        }
 
        [Fact, WorkItem(545293, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545293"), WorkItem(881188, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/881188")]
        public void EmptyAndFixedBufferStructIsInitialized()
        {
            var text = @"
public struct EmptyStruct { }
unsafe public struct FixedStruct { fixed char c[10]; }
 
public struct OuterStruct 
{
    EmptyStruct ES;
    FixedStruct FS;
    override public string ToString() { return (ES.ToString() + FS.ToString()); }
}
";
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Passes).VerifyDiagnostics(
                // (8,17): warning CS0649: Field 'OuterStruct.FS' is never assigned to, and will always have its default value 
                //     FixedStruct FS;
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "FS").WithArguments("OuterStruct.FS", "").WithLocation(8, 17),
                // (7,17): warning CS0649: Field 'OuterStruct.ES' is never assigned to, and will always have its default value 
                //     EmptyStruct ES;
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "ES").WithArguments("OuterStruct.ES", "").WithLocation(7, 17)
                );
        }
 
        [Fact, WorkItem(545296, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545296"), WorkItem(545999, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545999")]
        public void FixedBufferAndStatementWithFixedArrayElementAsInitializer()
        {
            var text = @"
unsafe public struct FixedStruct 
{
    fixed int i[1];
    fixed char c[10];
    override public string ToString()  { 
        fixed (char* pc = this.c) { return pc[0].ToString(); } 
    }
}
";
            var comp = CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyDiagnostics();
 
            comp.VerifyIL("FixedStruct.ToString", @"
{
  // Code size       20 (0x14)
  .maxstack  1
  .locals init (pinned char& V_0)
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""char* FixedStruct.c""
  IL_0006:  ldflda     ""char FixedStruct.<c>e__FixedBuffer.FixedElementField""
  IL_000b:  stloc.0
  IL_000c:  ldloc.0
  IL_000d:  conv.u
  IL_000e:  call       ""string char.ToString()""
  IL_0013:  ret
}
");
        }
 
        [Fact]
        public void FixedBufferAndStatementWithFixedArrayElementAsInitializerExe()
        {
            var text = @"
    class Program
    {
        unsafe static void Main(string[] args)
        {
            FixedStruct s = new FixedStruct();
 
            s.c[0] = 'A';
            s.c[1] = 'B';
            s.c[2] = 'C';
 
            FixedStruct[] arr = { s };
 
            System.Console.Write(arr[0].ToString());
        }
    }
 
    unsafe public struct FixedStruct
    {
        public fixed char c[10];
 
        override public string ToString()
        {
            fixed (char* pc = this.c)
            {
                System.Console.Write(pc[0]);
                System.Console.Write(pc[1].ToString());
                return pc[2].ToString();
            }
        }
    }";
            var comp = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "ABC", verify: Verification.Fails).VerifyDiagnostics();
 
            comp.VerifyIL("FixedStruct.ToString", @"
{
  // Code size       45 (0x2d)
  .maxstack  3
  .locals init (pinned char& V_0)
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""char* FixedStruct.c""
  IL_0006:  ldflda     ""char FixedStruct.<c>e__FixedBuffer.FixedElementField""
  IL_000b:  stloc.0
  IL_000c:  ldloc.0
  IL_000d:  conv.u
  IL_000e:  dup
  IL_000f:  ldind.u2
  IL_0010:  call       ""void System.Console.Write(char)""
  IL_0015:  dup
  IL_0016:  ldc.i4.2
  IL_0017:  add
  IL_0018:  call       ""string char.ToString()""
  IL_001d:  call       ""void System.Console.Write(string)""
  IL_0022:  ldc.i4.2
  IL_0023:  conv.i
  IL_0024:  ldc.i4.2
  IL_0025:  mul
  IL_0026:  add
  IL_0027:  call       ""string char.ToString()""
  IL_002c:  ret
}
");
        }
 
        [Fact, WorkItem(545299, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545299")]
        public void FixedStatementInlambda()
        {
            var text = @"
using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
 
unsafe class C<T> where T : struct
{
    public void Goo()
    {
        Func<T, char> d = delegate
        {
            fixed (char* p = ""blah"")
            {
                for (char* pp = p; pp != null; pp++)
                    return *pp;
            }
            return 'c';
        };
 
        Console.WriteLine(d(default(T)));
    }
}
 
class A
{
    static void Main()
    {
        new C<int>().Goo();
    }
}
";
            CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "b", verify: Verification.Fails);
        }
 
        [Fact, WorkItem(546865, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546865")]
        public void DontStackScheduleLocalPerformingPointerConversion()
        {
            var text = @"
using System;
 
unsafe struct S1
{
    public char* charPointer;
}
 
unsafe class Test
{
    static void Main()
    {
        S1 s1 = new S1();
        fixed (char* p = ""hello"")
        {
            s1.charPointer = p;
            ulong UserData = (ulong)&s1;
            Test1(UserData);
        }
    }
 
    static void Test1(ulong number)
    {
        S1* structPointer = (S1*)number;
        Console.WriteLine(new string(structPointer->charPointer));
    }
 
    static ulong Test2()
    {
        S1* structPointer = (S1*)null; // null to pointer
        int* intPointer = (int*)structPointer; // pointer to pointer
        void* voidPointer = (void*)intPointer; // pointer to void
        ulong number = (ulong)voidPointer; // pointer to integer
        return number;
    }
}
";
 
            var verifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "hello", verify: Verification.Fails);
 
            // Note that the pointer local is not scheduled on the stack.
            verifier.VerifyIL("Test.Test1", @"
{
  // Code size       20 (0x14)
  .maxstack  1
  .locals init (S1* V_0) //structPointer
  IL_0000:  ldarg.0
  IL_0001:  conv.u
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  ldfld      ""char* S1.charPointer""
  IL_0009:  newobj     ""string..ctor(char*)""
  IL_000e:  call       ""void System.Console.WriteLine(string)""
  IL_0013:  ret
}");
 
            // All locals retained.
            verifier.VerifyIL("Test.Test2", @"
{
  // Code size       10 (0xa)
  .maxstack  1
  .locals init (S1* V_0, //structPointer
  int* V_1, //intPointer
                void* V_2) //voidPointer
  IL_0000:  ldc.i4.0
  IL_0001:  conv.u
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  stloc.1
  IL_0005:  ldloc.1
  IL_0006:  stloc.2
  IL_0007:  ldloc.2
  IL_0008:  conv.u8
  IL_0009:  ret
}");
        }
 
        [Fact, WorkItem(546807, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546807")]
        public void PointerMemberAccessReadonlyField()
        {
            var text = @"
using System;
 
unsafe class C
{
    public S1* S1;
}
 
unsafe struct S1
{
    public readonly int* X;
    public int* Y;
}
 
unsafe class Test
{
    static void Main()
    {
        S1 s1 = new S1();
        C c = new C();
        c.S1 = &s1;
        Console.WriteLine(null == c.S1->X);
        Console.WriteLine(null == c.S1->Y);
    }
}
";
 
            var verifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails, expectedOutput: @"
True
True");
 
            // NOTE: ldobj before ldfld S1.X, but not before ldfld S1.Y.
            verifier.VerifyIL("Test.Main", @"
{
  // Code size       64 (0x40)
  .maxstack  2
  .locals init (S1 V_0, //s1
  C V_1) //c
  IL_0000:  ldloca.s   V_0
  IL_0002:  initobj    ""S1""
  IL_0008:  newobj     ""C..ctor()""
  IL_000d:  stloc.1
  IL_000e:  ldloc.1
  IL_000f:  ldloca.s   V_0
  IL_0011:  conv.u
  IL_0012:  stfld      ""S1* C.S1""
  IL_0017:  ldc.i4.0
  IL_0018:  conv.u
  IL_0019:  ldloc.1
  IL_001a:  ldfld      ""S1* C.S1""
  IL_001f:  ldfld      ""int* S1.X""
  IL_0024:  ceq
  IL_0026:  call       ""void System.Console.WriteLine(bool)""
  IL_002b:  ldc.i4.0
  IL_002c:  conv.u
  IL_002d:  ldloc.1
  IL_002e:  ldfld      ""S1* C.S1""
  IL_0033:  ldfld      ""int* S1.Y""
  IL_0038:  ceq
  IL_003a:  call       ""void System.Console.WriteLine(bool)""
  IL_003f:  ret
}
");
        }
 
        [Fact, WorkItem(546807, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546807")]
        public void PointerMemberAccessCall()
        {
            var text = @"
using System;
 
unsafe class C
{
    public S1* S1;
}
 
unsafe struct S1
{
    public int X;
 
    public void Instance()
    {
        Console.WriteLine(this.X);
    }
}
 
static class Extensions
{
    public static void Extension(this S1 s1)
    {
        Console.WriteLine(s1.X);
    }
}
 
unsafe class Test
{
    static void Main()
    {
        S1 s1 = new S1 { X = 2 };
        C c = new C();
        c.S1 = &s1;
        c.S1->Instance();
        c.S1->Extension();
    }
}
";
 
            var verifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails, expectedOutput: @"
2
2");
 
            // NOTE: ldobj before extension call, but not before instance call.
            verifier.VerifyIL("Test.Main", @"
{
  // Code size       59 (0x3b)
  .maxstack  3
  .locals init (S1 V_0, //s1
  S1 V_1)
  IL_0000:  ldloca.s   V_1
  IL_0002:  initobj    ""S1""
  IL_0008:  ldloca.s   V_1
  IL_000a:  ldc.i4.2
  IL_000b:  stfld      ""int S1.X""
  IL_0010:  ldloc.1
  IL_0011:  stloc.0
  IL_0012:  newobj     ""C..ctor()""
  IL_0017:  dup
  IL_0018:  ldloca.s   V_0
  IL_001a:  conv.u
  IL_001b:  stfld      ""S1* C.S1""
  IL_0020:  dup
  IL_0021:  ldfld      ""S1* C.S1""
  IL_0026:  call       ""void S1.Instance()""
  IL_002b:  ldfld      ""S1* C.S1""
  IL_0030:  ldobj      ""S1""
  IL_0035:  call       ""void Extensions.Extension(S1)""
  IL_003a:  ret
}");
        }
 
        [Fact, WorkItem(531327, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/531327")]
        public void PointerParameter()
        {
            var text = @"
using System;
 
unsafe struct S1
{
    static void M(N.S2* ps2){}
}
namespace N
{
  public struct S2
  {
    public int F;
  }
}
";
 
            var verifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll.WithConcurrentBuild(false), verify: Verification.Passes);
        }
 
        [Fact, WorkItem(531327, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/531327")]
        public void PointerReturn()
        {
            var text = @"
using System;
 
namespace N
{
  public struct S2
  {
    public int F;
  }
}
 
unsafe struct S1
{
    static N.S2* M(int ps2){return null;}
}
 
";
 
            var verifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll.WithConcurrentBuild(false), verify: Verification.FailsPEVerify);
        }
 
        [Fact, WorkItem(748530, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/748530")]
        public void Repro748530()
        {
            var text = @"
unsafe class A
{
    public unsafe struct ListNode
    {
        internal ListNode(int data, ListNode* pNext)
        {
        }
    }
}
";
 
            var comp = CreateCompilation(text, options: TestOptions.UnsafeReleaseDll);
            comp.VerifyDiagnostics();
        }
 
        [WorkItem(682584, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/682584")]
        [Fact]
        public void UnsafeMathConv()
        {
            var text = @"
using System;
 
unsafe class C
{
    static void Main(string[] args)
    {
        byte* data = (byte*)0x76543210;
        uint offset = 0x80000000;
        byte* wrong = data + offset;
        Console.WriteLine(""{0:X}"", (ulong)wrong);
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "F6543210", verify: Verification.Fails);
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       36 (0x24)
  .maxstack  2
  .locals init (byte* V_0, //data
                uint V_1, //offset
                byte* V_2) //wrong
  IL_0000:  ldc.i4     0x76543210
  IL_0005:  conv.i
  IL_0006:  stloc.0
  IL_0007:  ldc.i4     0x80000000
  IL_000c:  stloc.1
  IL_000d:  ldloc.0
  IL_000e:  ldloc.1
  IL_000f:  conv.u
  IL_0010:  add
  IL_0011:  stloc.2
  IL_0012:  ldstr      ""{0:X}""
  IL_0017:  ldloc.2
  IL_0018:  conv.u8
  IL_0019:  box        ""ulong""
  IL_001e:  call       ""void System.Console.WriteLine(string, object)""
  IL_0023:  ret
}
");
        }
 
        [WorkItem(682584, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/682584")]
        [Fact]
        public void UnsafeMathConv001()
        {
            var text = @"
using System;
 
unsafe class C
{
    static void Main(string[] args)
    {
        short* data = (short*)0x76543210;
        uint offset = 0x40000000;
        short* wrong = data + offset;
        Console.WriteLine(""{0:X}"", (ulong)wrong);
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "F6543210", verify: Verification.Fails);
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       40 (0x28)
  .maxstack  3
  .locals init (short* V_0, //data
                uint V_1, //offset
                short* V_2) //wrong
  IL_0000:  ldc.i4     0x76543210
  IL_0005:  conv.i
  IL_0006:  stloc.0
  IL_0007:  ldc.i4     0x40000000
  IL_000c:  stloc.1
  IL_000d:  ldloc.0
  IL_000e:  ldloc.1
  IL_000f:  conv.u8
  IL_0010:  ldc.i4.2
  IL_0011:  conv.i8
  IL_0012:  mul
  IL_0013:  conv.i
  IL_0014:  add
  IL_0015:  stloc.2
  IL_0016:  ldstr      ""{0:X}""
  IL_001b:  ldloc.2
  IL_001c:  conv.u8
  IL_001d:  box        ""ulong""
  IL_0022:  call       ""void System.Console.WriteLine(string, object)""
  IL_0027:  ret
}
");
        }
 
        [WorkItem(682584, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/682584")]
        [Fact]
        public void UnsafeMathConv002()
        {
            var text = @"
using System;
 
unsafe class C
{
    static void Main(string[] args)
    {
        byte* data = (byte*)0x76543210;
        byte* wrong = data + 0x80000000u;
        Console.WriteLine(""{0:X}"", (ulong)wrong);
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "F6543210", verify: Verification.Fails);
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       34 (0x22)
  .maxstack  2
  .locals init (byte* V_0, //data
                byte* V_1) //wrong
  IL_0000:  ldc.i4     0x76543210
  IL_0005:  conv.i
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldc.i4     0x80000000
  IL_000d:  conv.u
  IL_000e:  add
  IL_000f:  stloc.1
  IL_0010:  ldstr      ""{0:X}""
  IL_0015:  ldloc.1
  IL_0016:  conv.u8
  IL_0017:  box        ""ulong""
  IL_001c:  call       ""void System.Console.WriteLine(string, object)""
  IL_0021:  ret
}
");
        }
 
        [WorkItem(682584, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/682584")]
        [Fact]
        public void UnsafeMathConv002a()
        {
            var text = @"
using System;
 
unsafe class C
{
    static void Main(string[] args)
    {
        byte* data = (byte*)0x76543210;
        byte* wrong = data + 0x7FFFFFFFu;
        Console.WriteLine(""{0:X}"", (ulong)wrong);
    }
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "F654320F", verify: Verification.Fails);
            compVerifier.VerifyIL("C.Main", @"
{
  // Code size       33 (0x21)
  .maxstack  2
  .locals init (byte* V_0, //data
                byte* V_1) //wrong
  IL_0000:  ldc.i4     0x76543210
  IL_0005:  conv.i
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldc.i4     0x7fffffff
  IL_000d:  add
  IL_000e:  stloc.1
  IL_000f:  ldstr      ""{0:X}""
  IL_0014:  ldloc.1
  IL_0015:  conv.u8
  IL_0016:  box        ""ulong""
  IL_001b:  call       ""void System.Console.WriteLine(string, object)""
  IL_0020:  ret
}
");
        }
 
        [WorkItem(857598, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/857598")]
        [Fact]
        public void VoidToNullable()
        {
            var text = @"
unsafe class C
{    
	public int? x = (int?)(void*)0;
}
 
class c1
{
	public static void Main()
	{
		var x = new C();
		System.Console.WriteLine(x.x);
	}
}
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "0", verify: Verification.Passes);
            compVerifier.VerifyIL("C..ctor", @"
{
  // Code size       21 (0x15)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  conv.i
  IL_0003:  conv.i4
  IL_0004:  newobj     ""int?..ctor(int)""
  IL_0009:  stfld      ""int? C.x""
  IL_000e:  ldarg.0
  IL_000f:  call       ""object..ctor()""
  IL_0014:  ret
}
");
        }
 
        [WorkItem(907771, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/907771")]
        [Fact]
        public void UnsafeBeforeReturn001()
        {
            var text = @"
 
using System;
 
public unsafe class C
{
    private static readonly byte[] _emptyArray = new byte[0];
 
    public static void Main()
    {
        System.Console.WriteLine(ToManagedByteArray(2));
    }
 
    public static byte[] ToManagedByteArray(uint byteCount)
    {
        if (byteCount == 0)
        {
            return _emptyArray; // degenerate case
        }
        else
        {
            byte[] bytes = new byte[byteCount];
            fixed (byte* pBytes = bytes)
            {
 
            }
            return bytes;
        }
    }
}
 
";
            var compVerifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "System.Byte[]", verify: Verification.Fails);
            compVerifier.VerifyIL("C.ToManagedByteArray", @"
{
  // Code size       42 (0x2a)
  .maxstack  3
  .locals init (byte* V_0, //pBytes
                pinned byte[] V_1)
  IL_0000:  ldarg.0
  IL_0001:  brtrue.s   IL_0009
  IL_0003:  ldsfld     ""byte[] C._emptyArray""
  IL_0008:  ret
  IL_0009:  ldarg.0
  IL_000a:  newarr     ""byte""
  IL_000f:  dup
  IL_0010:  dup
  IL_0011:  stloc.1
  IL_0012:  brfalse.s  IL_0019
  IL_0014:  ldloc.1
  IL_0015:  ldlen
  IL_0016:  conv.i4
  IL_0017:  brtrue.s   IL_001e
  IL_0019:  ldc.i4.0
  IL_001a:  conv.u
  IL_001b:  stloc.0
  IL_001c:  br.s       IL_0027
  IL_001e:  ldloc.1
  IL_001f:  ldc.i4.0
  IL_0020:  ldelema    ""byte""
  IL_0025:  conv.u
  IL_0026:  stloc.0
  IL_0027:  ldnull
  IL_0028:  stloc.1
  IL_0029:  ret
}
");
        }
 
        [WorkItem(907771, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/907771")]
        [Fact]
        public void UnsafeBeforeReturn002()
        {
            var text = @"
 
using System;
 
public unsafe class C
{
    private static readonly byte[] _emptyArray = new byte[0];
 
    public static void Main()
    {
        System.Console.WriteLine(ToManagedByteArray(2));
    }
 
    public static byte[] ToManagedByteArray(uint byteCount)
    {
        if (byteCount == 0)
        {
            return _emptyArray; // degenerate case
        }
        else
        {
            byte[] bytes = new byte[byteCount];
            fixed (byte* pBytes = bytes)
            {
 
            }
            return bytes;
        }
    }
}
 
";
            var v = CompileAndVerify(text, options: TestOptions.UnsafeDebugExe, expectedOutput: "System.Byte[]", verify: Verification.Fails);
            v.VerifyIL("C.ToManagedByteArray", @"
{
  // Code size       64 (0x40)
  .maxstack  2
  .locals init (bool V_0,
                byte[] V_1,
                byte[] V_2, //bytes
                byte* V_3, //pBytes
                pinned byte[] V_4)
 -IL_0000:  nop
 -IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  ceq
  IL_0005:  stloc.0
 ~IL_0006:  ldloc.0
  IL_0007:  brfalse.s  IL_0012
 -IL_0009:  nop
 -IL_000a:  ldsfld     ""byte[] C._emptyArray""
  IL_000f:  stloc.1
  IL_0010:  br.s       IL_003e
 -IL_0012:  nop
 -IL_0013:  ldarg.0
  IL_0014:  newarr     ""byte""
  IL_0019:  stloc.2
 -IL_001a:  ldloc.2
  IL_001b:  dup
  IL_001c:  stloc.s    V_4
  IL_001e:  brfalse.s  IL_0026
  IL_0020:  ldloc.s    V_4
  IL_0022:  ldlen
  IL_0023:  conv.i4
  IL_0024:  brtrue.s   IL_002b
  IL_0026:  ldc.i4.0
  IL_0027:  conv.u
  IL_0028:  stloc.3
  IL_0029:  br.s       IL_0035
  IL_002b:  ldloc.s    V_4
  IL_002d:  ldc.i4.0
  IL_002e:  ldelema    ""byte""
  IL_0033:  conv.u
  IL_0034:  stloc.3
 -IL_0035:  nop
 -IL_0036:  nop
 ~IL_0037:  ldnull
  IL_0038:  stloc.s    V_4
 -IL_003a:  ldloc.2
  IL_003b:  stloc.1
  IL_003c:  br.s       IL_003e
 -IL_003e:  ldloc.1
  IL_003f:  ret
}
", sequencePoints: "C.ToManagedByteArray");
        }
 
        [ClrOnlyFact(ClrOnlyReason.Ilasm)]
        public void SystemIntPtrInSignature_BreakingChange()
        {
            // NOTE: the IL is intentionally not compliant with ECMA spec 
            //       in particular Metadata spec II.23.2.16 (Short form signatures) says that 
            //       [mscorlib]System.IntPtr   is not supposed to be used in metadata
            //       and short-version   'native int' is supposed to be used instead.
            var ilSource =
@"
.class public AddressHelper{
    .method public hidebysig static valuetype [mscorlib]System.IntPtr AddressOf<T>(!!0& t){
        ldarg 0
        ldind.i
        ret
    }    
}
";
            var csharpSource =
@"
    class Program
    {
        static void Main(string[] args)
        {
            var s = string.Empty;
            var i = AddressHelper.AddressOf(ref s);
            System.Console.WriteLine(i);
        }
    }
";
            var cscomp = CreateCompilationWithILAndMscorlib40(csharpSource, ilSource);
 
            var expected = new[] {
                // (7,35): error CS0570: 'AddressHelper.AddressOf<T>(?)' is not supported by the language
                //             var i = AddressHelper.AddressOf(ref s);
                Diagnostic(ErrorCode.ERR_BindToBogus, "AddressOf").WithArguments("AddressHelper.AddressOf<T>(?)").WithLocation(7, 35)
            };
 
            cscomp.VerifyDiagnostics(expected);
        }
 
        [ClrOnlyFact(ClrOnlyReason.Ilasm)]
        public void SystemIntPtrInSignature_BreakingChange_001()
        {
            var ilSource =
@"
.class public AddressHelper{
    .method public hidebysig static native int AddressOf<T>(!!0& t){
        ldc.i4.5
	    conv.u
	    ret
    }    
}
";
            var csharpSource =
@"
    class Program
    {
        static void Main(string[] args)
        {
            var s = string.Empty;
            var i = AddressHelper.AddressOf(ref s);
            System.Console.WriteLine(i);
        }
    }
";
            var compilation = CreateCompilationWithILAndMscorlib40(csharpSource, ilSource, targetFramework: TargetFramework.Mscorlib40, options: TestOptions.ReleaseExe);
 
            compilation.VerifyDiagnostics();
 
            var result = CompileAndVerify(compilation, expectedOutput: "5");
        }
 
        [Fact, WorkItem(7550, "https://github.com/dotnet/roslyn/issues/7550")]
        public void EnsureNullPointerIsPoppedIfUnused()
        {
            string source = @"
public class A
{
    public unsafe byte* Ptr;
 
    static void Main()
    {
        unsafe
        {
            var x = new A();
            byte* ptr = (x == null) ? null : x.Ptr;
        }
        System.Console.WriteLine(""OK"");
    }
}
";
            CompileAndVerify(source, options: TestOptions.UnsafeReleaseExe, expectedOutput: "OK", verify: Verification.Passes);
        }
 
        [Fact, WorkItem(40768, "https://github.com/dotnet/roslyn/issues/40768")]
        public void DoesNotEmitArrayDotEmptyForEmptyPointerArrayParams()
        {
            var source = @"
 
using System;
 
public static class Program
{
   public static unsafe void Main()
   {
      Console.WriteLine(Test());
   }
    
   public static unsafe int Test(params int*[] types)
   {
       return types.Length;
   }
}";
            // PEVerify:
            // [ : Program::Main][mdToken= 0x6000001][offset 0x00000001] Unmanaged pointers are not a verifiable type.
            // [ : Program::Main][mdToken = 0x6000001][offset 0x00000001] Unable to resolve token.
            var comp = CompileAndVerify(source, options: TestOptions.UnsafeReleaseExe, expectedOutput: "0", verify: Verification.FailsPEVerify);
            comp.VerifyIL("Program.Main", @"
{
  // Code size       17 (0x11)
  .maxstack  1
  IL_0000:  ldc.i4.0
  IL_0001:  newarr     ""int*""
  IL_0006:  call       ""int Program.Test(params int*[])""
  IL_000b:  call       ""void System.Console.WriteLine(int)""
  IL_0010:  ret
}");
        }
 
        [Fact]
        public void DoesEmitArrayDotEmptyForEmptyPointerArrayArrayParams()
        {
            var source = @"
 
using System;
 
public static class Program
{
   public static unsafe void Main()
   {
      Console.WriteLine(Test());
   }
    
   public static unsafe int Test(params int*[][] types)
   {
       return types.Length;
   }
}";
            var comp = CompileAndVerify(source, options: TestOptions.UnsafeReleaseExe, expectedOutput: "0");
            comp.VerifyIL("Program.Main", @"
{
  // Code size       16 (0x10)
  .maxstack  1
  IL_0000:  call       ""int*[][] System.Array.Empty<int*[]>()""
  IL_0005:  call       ""int Program.Test(params int*[][])""
  IL_000a:  call       ""void System.Console.WriteLine(int)""
  IL_000f:  ret
}");
        }
 
        #endregion
    }
}