// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
//
// This test is primarily for detecting bad reverse copy prop on 
// newobj calls.   If the intended target has any interference with the sources 
// of the newobj call, then you can't safely do the reverse copy prop.
//
// s = new S(ref s);
//
// It is similar to restrictions on general return value optimizations using
// a hidden parameter.
//
// Reference: TF Bug 1187059

using System;

public struct  S {
    public int a;
    public int b;

    // Straight forward constructor
    public S(int a, int b) {
        this.a = a;
        this.b = b;
    }
    // Swapping constructor
    public S(ref S s) {
        this.a = s.b;
        this.b = s.a;
    }
    // Swapping constructor
    public S(ref U u) {
        this.a = u.s.b;
        this.b = u.s.a;
    }
    // Swapping constructor
    public unsafe S(ref V v) {
        this.a = v.sRef->b;
        this.b = v.sRef->a;
    }
    // Swapping constructor
    public unsafe S(V v) {
        this.a = v.sRef->b;
        this.b = v.sRef->a;
    }

}

public struct T {
    public S s;

    // Straight forward constructor
    public T(int a, int b) {
        s = new S(a, b);
    }
}

public class U {
    public S s;

    // Straight forward constructor
    public U(int a, int b) {
        s = new S(a, b);
    }
}

public unsafe struct V {
    public S *sRef;

    // Straight forward constructor
    public unsafe V(S * sRef) {
        this.sRef = sRef;
    }
}


public class Bug {
    static S ss;
    public static unsafe int Main() {
        int fail = 0;

        S s = new S(1, 2);
        s = new S(ref s);
        if ((s.a != 2) || (s.b != 1))
            fail += 0x1;

        ss = new S(1, 2);
        ss = new S(ref ss);
        if ((ss.a != 2) || (ss.b != 1))
            fail += 0x2;

        T t = new T(1, 2);
        t.s = new S(ref t.s);
        if ((t.s.a != 2) || (t.s.b != 1))
            fail += 0x4;

        U u = new U(1, 2);
        u.s = new S(ref u.s);
        if ((u.s.a != 2) || (u.s.b != 1))
            fail += 0x8;

        u = new U(1, 2);
        u.s = new S(ref u);
        if ((u.s.a != 2) || (u.s.b != 1))
            fail += 0x10;

        s = new S(1, 2);
        V v = new V(&s);
        s = new S(v);
        if ((s.a != 2) || (s.b != 1))
            fail += 0x20;

        if (fail != 0)
        {
            Console.WriteLine("Fail 0x{0:X}", fail);
            return -1;
        }
        else
        {
            Console.WriteLine("Pass");
            return 100;
        }
    }
}

