/*
REQUIRED_ARGS: -preview=rvaluerefparam
RUN_OUTPUT:
---
Success
---
*/

import core.stdc.stdio;

struct S
{
    int x;
    int y;
}

/********************************************/

void test1()
{
    S s = S(1,2);
    assert(s.x == 1);
    assert(s.y == 2);
}

/********************************************/

void foo2(S s)
{
    assert(s.x == 1);
    assert(s.y == 2);
}

void test2()
{
    foo2( S(1,2) );
}

/********************************************/

S foo3()
{
    return S(1, 2);
}

void test3()
{
    S s = foo3();
    assert(s.x == 1);
    assert(s.y == 2);
}

/********************************************/

struct S4
{
    long x;
    long y;
    long z;
}

S4 foo4()
{
    return S4(1, 2, 3);
}

void test4()
{
    S4 s = foo4();
    assert(s.x == 1);
    assert(s.y == 2);
    assert(s.z == 3);
}

/********************************************/

struct S5
{
    long x;
    char y;
    long z;
}

S5 foo5()
{
    return S5(1, 2, 3);
}

void test5()
{
    S5 s = foo5();
    assert(s.x == 1);
    assert(s.y == 2);
    assert(s.z == 3);
}

/********************************************/

struct S6
{
    long x;
    char y;
    long z;
}

void test6()
{
    S6 s1 = S6(1,2,3);
    S6 s2 = S6(1,2,3);
    assert(s1 == s2);

    s1 = S6(4,5,6);
    s2 = S6(4,5,6);
    assert(s1 == s2);

    S6* p1 = &s1;
    S6* p2 = &s2;
    *p1 = S6(7,8,9);
    *p2 = S6(7,8,9);
    assert(*p1 == *p2);
}

/********************************************/

struct S7
{
    long x;
    char y;
    long z;
}

void test7()
{
    static S7 s1 = S7(1,2,3);
    static S7 s2 = S7(1,2,3);
    assert(s1 == s2);
}

/********************************************/

struct S8
{
    int i;
    string s;
}

void test8()
{
    S8 s = S8(3, "hello");
    assert(s.i == 3);
    assert(s.s == "hello");

    static S8 t = S8(4, "betty");
    assert(t.i == 4);
    assert(t.s == "betty");

    S8 u = S8(3, ['h','e','l','l','o']);
    assert(u.i == 3);
    assert(u.s == "hello");

    static S8 v = S8(4, ['b','e','t','t','y']);
    assert(v.i == 4);
    assert(v.s == "betty");
}

/********************************************/

struct S9
{
    int i;
    char[5] s;
}

void test9()
{
    S9 s = S9(3, "hello");
    assert(s.i == 3);
    assert(s.s == "hello");

    static S9 t = S9(4, "betty");
    assert(t.i == 4);
    assert(t.s == "betty");

    S9 u = S9(3, ['h','e','l','l','o']);
    assert(u.i == 3);
    assert(u.s == "hello");

    static S9 v = S9(4, ['b','e','t','t','y']);
    assert(v.i == 4);
    assert(v.s == "betty");
}

/********************************************/

alias int myint10;

struct S10
{
    int i;
    union
    {
        int x = 2;
        int y;
    }
    int j = 3;
    myint10 k = 4;
}

void test10()
{
    S10 s = S10( 1 );
    assert(s.i == 1);
    assert(s.x == 2);
    assert(s.y == 2);
    assert(s.j == 3);
    assert(s.k == 4);

    static S10 t = S10( 1 );
    assert(t.i == 1);
    assert(t.x == 2);
    assert(t.y == 2);
    assert(t.j == 3);
    assert(t.k == 4);

    S10 u = S10( 1, 5 );
    assert(u.i == 1);
    assert(u.x == 5);
    assert(u.y == 5);
    assert(u.j == 3);
    assert(u.k == 4);

    static S10 v = S10( 1, 6 );
    assert(v.i == 1);
    assert(v.x == 6);
    assert(v.y == 6);
    assert(v.j == 3);
    assert(v.k == 4);
}

/********************************************/

struct S11
{
    int i;
    int j = 3;
}


void test11()
{
    static const s = S11( 1, 5 );
    static const i = s.i;
    assert(i == 1);
    static assert(s.j == 5);
}

/********************************************/

struct S12
{
    int[5] x;
    int[5] y = 3;
}

void test12()
{
    S12 s = S12();
    foreach (v; s.x)
        assert(v == 0);
    foreach (v; s.y)
        assert(v == 3);
}

/********************************************/

struct S13
{
    int[5] x;
    int[5] y;
    int[6][3] z;
}

void test13()
{
    S13 s = S13(0,3,4);
    foreach (v; s.x)
        assert(v == 0);
    foreach (v; s.y)
        assert(v == 3);
    for (int i = 0; i < 6; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            assert(s.z[j][i] == 4);
        }
    }
}

/********************************************/

struct S14a { int n; }
struct S14b { this(int n){} }

void foo14(ref S14a s) {}
void foo14(ref S14b s) {}
void hoo14()(ref S14a s) {}
void hoo14()(ref S14b s) {}
void poo14(S)(ref S s) {}

void bar14(S14a s) {}
void bar14(S14b s) {}
void var14()(S14a s) {}
void var14()(S14b s) {}
void war14(S)(S s) {}

int baz14(    S14a s) { return 1; }
int baz14(ref S14a s) { return 2; }
int baz14(    S14b s) { return 1; }
int baz14(ref S14b s) { return 2; }
int vaz14()(    S14a s) { return 1; }
int vaz14()(ref S14a s) { return 2; }
int vaz14()(    S14b s) { return 1; }
int vaz14()(ref S14b s) { return 2; }
int waz14(S)(    S s) { return 1; }
int waz14(S)(ref S s) { return 2; }

void test14()
{
    // can bind rvalue-sl with ref
    foo14(S14a(0));
    foo14(S14b(0));
    hoo14(S14a(0));
    hoo14(S14b(0));
    poo14(S14a(0));
    poo14(S14b(0));

    // still can bind rvalue-sl with non-ref
    bar14(S14a(0));
    bar14(S14b(0));
    var14(S14a(0));
    var14(S14b(0));
    war14(S14a(0));
    war14(S14b(0));

    // preferred binding of rvalue-sl in overload resolution
    assert(baz14(S14a(0)) == 1);
    assert(baz14(S14b(0)) == 1);
    assert(vaz14(S14a(0)) == 1);
    assert(vaz14(S14b(0)) == 1);
    assert(waz14(S14a(0)) == 1);
    assert(waz14(S14b(0)) == 1);
}

/********************************************/

void check15(T, ubyte results, A...)(A args)
{
                         // m c i s sc
    enum m  = (results & 0b_1_0_0_0_0) != 0;
    enum c  = (results & 0b_0_1_0_0_0) != 0;
    enum i  = (results & 0b_0_0_1_0_0) != 0;
    enum s  = (results & 0b_0_0_0_1_0) != 0;
    enum sc = (results & 0b_0_0_0_0_1) != 0;

    // allocation on stack
    static assert((is(typeof(                  T(args) ) U) && is(U ==              T  )) == m);
    static assert((is(typeof(            const T(args) ) U) && is(U ==        const(T) )) == c);
    static assert((is(typeof(        immutable T(args) ) U) && is(U ==    immutable(T) )) == i);
    static assert((is(typeof(           shared T(args) ) U) && is(U ==       shared(T) )) == s);
    static assert((is(typeof(     shared const T(args) ) U) && is(U == shared(const T) )) == sc);

    // allocation on heap
    static assert((is(typeof( new              T(args) ) U) && is(U ==              T *)) == m);
    static assert((is(typeof( new        const T(args) ) U) && is(U ==        const(T)*)) == c);
    static assert((is(typeof( new    immutable T(args) ) U) && is(U ==    immutable(T)*)) == i);
    static assert((is(typeof( new       shared T(args) ) U) && is(U ==       shared(T)*)) == s);
    static assert((is(typeof( new shared const T(args) ) U) && is(U == shared(const T)*)) == sc);
}
void test15a()
{
    static struct Foo1 { this(int v) {}                int value; }
    static struct Boo1 { this(int v) const {}          int[] value; }
    static struct Bar1 { this(int[] v) {}              int[] value; }
    static struct Baz1 { this(const int[] v) pure {}   int[] value; }  // unique ctor
    static struct Coo1 { this(int[] v) immutable {}    int[] value; }
    static struct Car1 { this(int[] v) immutable {}    immutable(int)[] value; }
    check15!(Foo1, 0b_1_1_0_0_0)(1);
    check15!(Boo1, 0b_0_1_0_0_0)(1);
    check15!(Bar1, 0b_1_1_0_0_0)(null);
    check15!(Baz1, 0b_1_1_1_1_1)(null);
    check15!(Coo1, 0b_0_1_1_0_1)(null);
    check15!(Car1, 0b_0_1_1_0_1)(null);
                   // m c i s sc

    // Template constructor should work as same as non-template ones
    static struct Foo2 { this()(int v) {}              int value; }
    static struct Boo2 { this()(int v) const {}        int[] value; }
    static struct Bar2 { this()(int[] v) {}            int[] value; }  // has mutable indieection
    static struct Baz2 { this()(const int[] v) pure {} int[] value; }  // unique ctor
    static struct Coo2 { this()(int[] v) immutable {}  int[] value; }
    static struct Car2 { this()(int[] v) immutable {}  immutable(int)[] value; }
    check15!(Foo2, 0b_1_1_0_0_0)(1);
    check15!(Boo2, 0b_0_1_0_0_0)(1);
    check15!(Bar2, 0b_1_1_0_0_0)(null);
    check15!(Baz2, 0b_1_1_1_1_1)(null);
    check15!(Coo2, 0b_0_1_1_0_1)(null);
    check15!(Car2, 0b_0_1_1_0_1)(null);
                   // m c i s sc

    // Except Bar!().__ctor, their constructors are inferred to pure, then they become unique ctors.
    static struct Foo3() { this(int v) {}              int value; }
    static struct Boo3() { this(int v) const {}        int[] value; }
    static struct Bar3() { this(int[] v) {}            int[] value; }  // has mutable indieection
    static struct Baz3() { this(const int[] v) pure {} int[] value; }  // unique ctor
    static struct Coo3() { this(int[] v) immutable {}  int[] value; }
    static struct Car3() { this(int[] v) immutable {}  immutable(int)[] value; }
    check15!(Foo3!(), 0b_1_1_1_1_1)(1);
    check15!(Boo3!(), 0b_1_1_1_1_1)(1);
    check15!(Bar3!(), 0b_1_1_0_0_0)(null);
    check15!(Baz3!(), 0b_1_1_1_1_1)(null);
    check15!(Coo3!(), 0b_1_1_1_1_1)(null);
    check15!(Car3!(), 0b_1_1_1_1_1)(null);
                      // m c i s sc
}

// inout constructor works as like unique constructor in many cases
void test15b()
{
    static struct Nullable1
    {
        private int[] _value;
        private bool _isNull = true;
        this(inout int[] v) inout //pure
        {
            _value = v;
            //static int g; auto x = g; // impure access
            _isNull = false;
        }
    }
    static assert( __traits(compiles,           Nullable1([1,2,3])));
    static assert(!__traits(compiles,           Nullable1([1,2,3].idup)));
    static assert(!__traits(compiles, immutable Nullable1([1,2,3])));
    static assert( __traits(compiles, immutable Nullable1([1,2,3].idup)));
    static assert(!__traits(compiles,    shared Nullable1([1,2,3])));
    static assert(!__traits(compiles,    shared Nullable1([1,2,3].idup)));

    static struct Nullable2(T)
    {
        private T _value;
        private bool _isNull = true;
        this(inout T v) inout //pure
        {
            _value = v;
            //static int g; auto x = g; // impure access
            _isNull = false;
        }
    }
    static assert( __traits(compiles,           Nullable2!(int[])([1,2,3])));
    static assert(!__traits(compiles,           Nullable2!(int[])([1,2,3].idup)));
    static assert(!__traits(compiles, immutable Nullable2!(int[])([1,2,3])));
    static assert( __traits(compiles, immutable Nullable2!(int[])([1,2,3].idup)));
    static assert(!__traits(compiles,    shared Nullable2!(int[])([1,2,3])));
    static assert(!__traits(compiles,    shared Nullable2!(int[])([1,2,3].idup)));

    // ctor is inout pure, but cannot create unique object.
    struct S
    {
        int[] marr;
        const int[] carr;
        immutable int[] iarr;
        this(int[] m, const int[] c, immutable int[] i) inout pure
        {
            static assert(!__traits(compiles, marr = m));
            static assert(!__traits(compiles, carr = c));  // cannot implicitly convertible const(int[]) to inout(const(int[]))
            iarr = i;
        }
    }
    static assert(!__traits(compiles, { int[] ma; immutable int[] ia; auto m =           S(ma, ma, ia); }));
    static assert( __traits(compiles, { int[] ma; immutable int[] ia; auto c =     const S(ma, ma, ia); }));
    static assert(!__traits(compiles, { int[] ma; immutable int[] ia; auto i = immutable S(ma, ma, ia); }));
}

// TemplateThisParameter with constructor should work
void test15c()
{
    static class C
    {
        this(this This)()
        {
            static assert(is(This == immutable C));
        }

        this(T = void, this This)(int)
        {
            static assert(is(This == immutable C));
        }
    }
    auto c1 = new immutable C;
    auto c2 = new immutable C(1);
}

void test15d()  // https://issues.dlang.org/show_bug.cgi?id=9974
{
    class CM { this() {} }
    auto cm = new CM();

    const class CC { this() {} }
    const cc = new const CC();

    immutable class CI { this() {} }
    immutable ci = new immutable CI();

    shared class CS { this() {} }
    shared cs = new shared CS();

    shared const class CSC { this() {} }
    shared const csc = new shared const CSC();


    struct SM { this(int) {} }
    auto sm = new SM(1);

    const struct SC { this(int) {} }
    const sc = new const SC(1);

    immutable struct SI { this(int) {} }
    immutable si = new immutable SI(1);

    shared struct SS { this(int) {} }
    shared ss = new shared SS(1);

    shared const struct SSC { this(int) {} }
    shared const ssc = new shared const SSC(1);
}

void test15e()  // https://issues.dlang.org/show_bug.cgi?id=10005
{
    // struct literal
    static struct S
    {
        int[] a;
    }
    int[] marr = [1,2,3];
    static assert( __traits(compiles, {           S m =           S(marr); }));
    static assert( __traits(compiles, {     const S c =           S(marr); }));
    static assert(!__traits(compiles, { immutable S i =           S(marr); }));
    immutable int[] iarr = [1,2,3];
    static assert(!__traits(compiles, {           S m = immutable S(iarr); }));
    static assert( __traits(compiles, {     const S c = immutable S(iarr); }));
    static assert( __traits(compiles, { immutable S i = immutable S(iarr); }));

    // mutable constructor
    static struct MS
    {
        int[] a;
        this(int n) { a = new int[](n); }
    }
    static assert( __traits(compiles, {           MS m =           MS(3); }));
    static assert( __traits(compiles, {     const MS c =           MS(3); }));
    static assert(!__traits(compiles, { immutable MS i =           MS(3); }));
    static assert(!__traits(compiles, {           MS m = immutable MS(3); }));
    static assert(!__traits(compiles, {     const MS c = immutable MS(3); }));
    static assert(!__traits(compiles, { immutable MS i = immutable MS(3); }));

    // immutable constructor
    static struct IS
    {
        int[] a;
        this(int n) immutable { a = new int[](n); }
    }
    static assert(!__traits(compiles, {           IS m =           IS(3); }));
    static assert(!__traits(compiles, {     const IS c =           IS(3); }));
    static assert(!__traits(compiles, { immutable IS i =           IS(3); }));
    static assert(!__traits(compiles, {           IS m = immutable IS(3); }));
    static assert( __traits(compiles, {     const IS c = immutable IS(3); }));
    static assert( __traits(compiles, { immutable IS i = immutable IS(3); }));
}

struct Foo9984
{
    int[] p;
    // Prefix storage class and tempalte constructor
    inout this()(inout int[] a) { p = a; }
    auto foo() inout { return inout(Foo9984)(p); }
}

void test9993a()
{
    static class A
    {
        int x;
        this()           { x = 13; }
        this() immutable { x = 42; }
    }
              A ma = new           A;   assert(ma.x == 13);
    immutable A ia = new immutable A;   assert(ia.x == 42);
    static assert(!__traits(compiles, { immutable A ia = new A; }));

    static class B
    {
        int x;
        this()       { x = 13; }
        this() const { x = 42; }
    }
    const B mb = new       B;           assert(mb.x == 13);
    const B cb = new const B;           assert(cb.x == 42);
    static assert(!__traits(compiles, { immutable B ib = new B; }));

    static class C
    {
        int x;
        this() const     { x = 13; }
        this() immutable { x = 42; }
    }
        const C cc = new     const C;   assert(cc.x == 13);
    immutable C ic = new immutable C;   assert(ic.x == 42);
    static assert(!__traits(compiles, { C mc = new C; }));
}
void test9993b()
{
    static class A
    {
        int x;
        this()()           { x = 13; }
        this()() immutable { x = 42; }
    }
              A ma = new           A;   assert(ma.x == 13);
    immutable A ia = new immutable A;   assert(ia.x == 42);
    static assert(__traits(compiles, { immutable A ia = new A; }));

    static class B
    {
        int x;
        this()()       { x = 13; }
        this()() const { x = 42; }
    }
    const B mb = new       B;           assert(mb.x == 13);
    const B cb = new const B;           assert(cb.x == 42);
    static assert(__traits(compiles, { immutable B ib = new B; }));

    static class C
    {
        int x;
        this()() const     { x = 13; }
        this()() immutable { x = 42; }
    }
        const C cc = new     const C;   assert(cc.x == 13);
    immutable C ic = new immutable C;   assert(ic.x == 42);
    static assert(!__traits(compiles, { C mc = new C; }));
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=1914

struct Bug1914a
{
    const char[10] i = [1,0,0,0,0,0,0,0,0,0];
    char[10] x = i;
    int y = 5;
}

struct Bug1914b
{
    const char[10] i = [0,0,0,0,0,0,0,0,0,0];
    char[10] x = i;
    int y = 5;
}

struct Bug1914c
{
    const char[2] i = ['a', 'b'];
    const char[2][3] j = [['x', 'y'], ['p', 'q'], ['r', 's']];
    const char[2][3] k = ["cd", "ef", "gh"];
    const char[2][3] l = [['x', 'y'], ['p'], ['h', 'k']];
    char[2][3] x = i;
    int y = 5;
    char[2][3] z = j;
    char[2][3] w = k;
    int v = 27;
    char[2][3] u = l;
    int t = 718;
}

struct T3198
{
    int g = 1;
}

class Foo3198
{
    int[5] x = 6;
    T3198[5] y = T3198(4);
}

void test3198and1914()
{
    Bug1914a a;
    assert(a.y == 5, "bug 1914, non-zero init");
    Bug1914b b;
    assert(b.y == 5, "bug 1914, zero init");
    Bug1914c c;
    assert(c.y == 5, "bug 1914, multilevel init");
    assert(c.v == 27, "bug 1914, multilevel init2");
    assert(c.x[2][1] == 'b');
    assert(c.t == 718, "bug 1914, multi3");
    assert(c.u[1][0] == 'p');
    assert(c.u[1][1] == char.init);
    auto f = new Foo3198();
    assert(f.x[0] == 6);
    assert(f.y[0].g == 4, "bug 3198");
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=14996

enum E14996a : string { confirm = "confirm" }
enum E14996b : long[] { confirm = [1,2,3,4] }

struct S14996
{
    E14996a[1] data1;
    E14996b[1] data2;
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=2427

void test2427()
{
    struct S
    {
        int x;
    }

    int foo(int i)
    {
        return i;
    }

    int i;
    S s = { foo(i) };
}

/********************************************/

struct T5885 {
    uint a, b;
}

double mulUintToDouble(T5885 t, double m) {
    return t.a * m;
}

void test5885()
{
    enum ae = mulUintToDouble(T5885(10, 0), 10.0);
    enum be = mulUintToDouble(T5885(10, 20), 10.0);
    static assert(ae == be);

    auto a = mulUintToDouble(T5885(10, 0), 10.0);
    auto b = mulUintToDouble(T5885(10, 20), 10.0);
    assert(a == b);
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=5889

struct S5889a { int n; }
struct S5889b { this(int n){} }

bool isLvalue(S)(auto ref S s){ return __traits(isRef, s); }

int foo(ref S5889a s) { return 1; }
int foo(    S5889a s) { return 2; }
int foo(ref S5889b s) { return 1; }
int foo(    S5889b s) { return 2; }

int goo(ref const(S5889a) s) { return 1; }
int goo(    const(S5889a) s) { return 2; }
int goo(ref const(S5889b) s) { return 1; }
int goo(    const(S5889b) s) { return 2; }

int too(S)(ref S s) { return 1; }
int too(S)(    S s) { return 2; }

S makeRvalue(S)(){ S s; return s; }

void test5889()
{
    S5889a sa;
    S5889b sb;

    assert( isLvalue(sa));
    assert( isLvalue(sb));
    assert(!isLvalue(S5889a(0)));
    assert(!isLvalue(S5889b(0)));
    assert(!isLvalue(makeRvalue!S5889a()));
    assert(!isLvalue(makeRvalue!S5889b()));

    assert(foo(sa) == 1);
    assert(foo(sb) == 1);
    assert(foo(S5889a(0)) == 2);
    assert(foo(S5889b(0)) == 2);
    assert(foo(makeRvalue!S5889a()) == 2);
    assert(foo(makeRvalue!S5889b()) == 2);

    assert(goo(sa) == 1);
    assert(goo(sb) == 1);
    assert(goo(S5889a(0)) == 2);
    assert(goo(S5889b(0)) == 2);
    assert(goo(makeRvalue!S5889a()) == 2);
    assert(goo(makeRvalue!S5889b()) == 2);

    assert(too(sa) == 1);
    assert(too(sb) == 1);
    assert(too(S5889a(0)) == 2);
    assert(too(S5889b(0)) == 2);
    assert(too(makeRvalue!S5889a()) == 2);
    assert(too(makeRvalue!S5889b()) == 2);
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=4147

struct S4247
{
    int n = 1024;
    this(int x) { n = x; }
}
void test4247()
{
    auto p1 = S4247();
    assert(p1.n == 1024);

    auto p2 = S4247(1);
    assert(p2.n == 1);
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=6937

void test6937()
{
    static struct S
    {
        int x, y;
    }

    auto s1 = S(1, 2);
    auto ps1 = new S(1, 2);
    assert(ps1.x == 1);
    assert(ps1.y == 2);
    assert(*ps1 == s1);

    auto ps2 = new S(1);
    assert(ps2.x == 1);
    assert(ps2.y == 0);
    assert(*ps2 == S(1, 0));

    static assert(!__traits(compiles, new S(1,2,3)));

    int v = 0;
    struct NS
    {
        int x;
        void foo() { v = x; }
    }
    auto ns = NS(1);
    ns.foo();
    assert(ns.x == 1);
    assert(v == 1);
    auto pns = new NS(2);
    assert(pns.x == 2);
    pns.foo();
    assert(v == 2);
    pns.x = 1;
    assert(*pns == ns);

    static struct X {
        int v;
        this(this) { ++v; }
    }
    static struct Y {
        X x;
    }
    Y y = Y(X(1));
    assert(y.x.v == 1);
    auto py1 = new Y(X(1));
    assert(py1.x.v == 1);
    assert(*py1 == y);
    auto py2 = new Y(y.x);
    assert(py2.x.v == 2);
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=12681

struct HasUnion12774
{
    union
    {
        int a, b;
    }
}

bool test12681()
{
    immutable int x = 42;

    static struct S1
    {
        immutable int *p;
    }
    immutable s1 = new S1(&x);
    assert(s1.p == &x);

    struct S2
    {
        immutable int *p;
        void foo() {}
    }
    auto s2 = new S2(&x);
    assert(s2.p == &x);

    struct S3
    {
        immutable int *p;
        int foo() { return x; }
    }
    auto s3 = new S3(&x);
    assert(s3.p == &x);
    assert(s3.foo() == 42);

    auto x12774 = new HasUnion12774();

    return true;
}
static assert(test12681());

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=3991

union X3991
{
    int   a = void;
    dchar b = void;
}

union Y3991
{
    dchar b = 'a';
    int   a = void;
}

union Z3991
{
    int   a = 123;
    dchar b = void;
}

void test3991()
{
    X3991 x;

    Y3991 y;
    assert(y.b == 'a');

    Z3991 z;
    assert(z.a == 123);
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=7727

union U7727A1 { int i;       double d;       }
union U7727A2 { int i = 123; double d;       }
//union U7727A3 { int i;       double d = 2.5; }

union U7727B1 { double d;       int i;       }
union U7727B2 { double d = 2.5; int i;       }
//union U7727B3 { double d;       int i = 123; }

void test7727()
{
    import core.stdc.math : isnan;

    { U7727A1 u;                assert(u.i == 0); }
    { U7727A1 u = { i: 1024 };  assert(u.i == 1024); }
    { U7727A1 u = { d: 1.225 }; assert(u.d == 1.225); }
  static assert(!__traits(compiles,
    { U7727A1 u = { i: 1024, d: 1.225 }; }
  ));

    { U7727A2 u;                assert(u.i == 123); }
    { U7727A2 u = { i: 1024 };  assert(u.i == 1024); }
    { U7727A2 u = { d: 1.225 }; assert(u.d == 1.225); }
  static assert(!__traits(compiles,
    { U7727A2 u = { i: 1024, d: 1.225 }; }
  ));

// Blocked by https://issues.dlang.org/show_bug.cgi?id=1432
//    { U7727A3 u;                assert(u.d == 2.5); }
//    { U7727A3 u = { i: 1024 };  assert(u.i == 1024); }
//    { U7727A3 u = { d: 1.225 }; assert(u.d == 1.225); }
//  static assert(!__traits(compiles,
//    { U7727A3 u = { i: 1024, d: 1.225 }; }
//  ));

    { U7727B1 u;                assert(isnan(u.d)); }
    { U7727B1 u = { i: 1024 };  assert(u.i == 1024); }
    { U7727B1 u = { d: 1.225 }; assert(u.d == 1.225); }
  static assert(!__traits(compiles,
    { U7727B1 u = { i: 1024, d: 1.225 }; }
  ));

    { U7727B2 u;                assert(u.d == 2.5); }
    { U7727B2 u = { i: 1024 };  assert(u.i == 1024); }
    { U7727B2 u = { d: 1.225 }; assert(u.d == 1.225); }
  static assert(!__traits(compiles,
    { U7727B2 u = { i: 1024, d: 1.225 }; }
  ));

// Blocked by https://issues.dlang.org/show_bug.cgi?id=1432
//    { U7727B3 u;                assert(u.i == 123); }
//    { U7727B3 u = { i: 1024 };  assert(u.i == 1024); }
//    { U7727B3 u = { d: 1.225 }; assert(u.d == 1.225); }
//  static assert(!__traits(compiles,
//    { U7727B3 u = { i: 1024, d: 1.225 }; }
//  ));


    test7727a();
    test7727b();
}

// --------

struct Foo7727a
{
    ushort bar2;
}
struct Foo7727b
{
    union
    {
        ubyte[2] bar1;
        ushort bar2;
    }
}

void test7727a()
{
    immutable Foo7727a foo1 = { bar2: 100 }; // OK
    immutable Foo7727b foo2 = { bar2: 100 }; // OK <-- error
}

// --------

struct S7727 { int i; double d; }
union U7727 { int i; double d; }

void test7727b()
{
    S7727 s = { d: 5 }; // OK
    U7727 u = { d: 5 }; // OK <-- Error: is not a static and cannot have static initializer
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=7929

void test7929()
{
    static struct S
    {
        int [] numbers;
    }

    const int [] numbers = new int[2];
    const S si = {numbers};
    // Error: cannot implicitly convert expression (numbers) of type const(int[]) to int[]

    const S se = const(S)(numbers);
    // OK
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=7021

struct S7021
{
    @disable this();
}

void test7021()
{
  static assert(!is(typeof({
    auto s = S7021();
  })));
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=8738

void test8738()
{
    int[3] a = [1, 2, 3];

    struct S { int a, b, c; }
    S s = S(1, 2, 3);

    a = [4, a[0], 6];
    s = S(4, s.a, 6);

    assert(a == [4, 1, 6]);
    assert(s == S(4, 1, 6));
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=8763

void test8763()
{
    struct S
    {
        this(int) {}
    }

    void foo(T, Args...)(Args args)
    {
        T t = T(args);
        // Error: constructor main.S.this (int) is not callable using argument types ()
    }

    S t = S(); // OK, initialize to S.init
    foo!S();
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=8902

union U8902 { int a, b; }

enum U8902 u8902a = U8902.init; // No errors
U8902 u8902b;                   // No errors
U8902 u8902c = U8902.init;      // Error: duplicate union initialization for b

void test8902()
{
    U8902 u8902d = U8902.init;                  // No errors
    immutable U8902 u8902e = U8902.init;        // No errors
    immutable static U8902 u8902f = U8902.init; // Error: duplicate union...
    static U8902 u8902g = u8902e;               // Error: duplicate union...
    static U8902 u8902h = U8902.init;           // Error: duplicate union...
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=9116

void test9116()
{
    static struct X
    {
        int v;
        this(this) { ++v; }
    }
    static struct Y
    {
        X x;
    }
    X x = X(1);
    assert(x.v == 1);
    Y y = Y(X(1));
    //printf("y.x.v = %d\n", y.x.v);  // print 2, but should 1
    assert(y.x.v == 1); // fails
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=9293

void test9293()
{
    static struct A
    {
    //  enum A zero = A(); // This works as expected
        enum A zero = {};  // Note the difference here

        int opCmp(const ref A a) const
        {
            assert(0);
        }

        int opCmp(const A a) const
        {
            return 0;
        }
    }

    A a;
    auto b = a >= A.zero;  // Error: A() is not an lvalue
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=9566

void test9566()
{
    static struct ExpandData
    {
        ubyte[4096] window = 0;
    }
    ExpandData a;
    auto b = ExpandData.init;   // bug
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=9775

enum Month9775 : ubyte { jan = 1, }
struct Date9775
{
    this(int year, int month, int day) pure
    {
        _year  = cast(short)year;
        _month = cast(Month9775)month;
        _day   = cast(ubyte)day;
    }
    short     _year  = 1;
    Month9775 _month = Month9775.jan;
    ubyte     _day   = 1;
}

const Date9775 date9775c1 = Date9775(2012, 12, 21);
const          date9775c2 = Date9775(2012, 12, 21);
enum  Date9775 date9775e1 = Date9775(2012, 12, 21);
enum           date9775e2 = Date9775(2012, 12, 21);

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=11105

struct S11105
{
    int[2][1] a21;
}

void test11105()
{
    S11105 s = S11105([1, 2]);
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=11147

struct V11147
{
    union
    {
        struct
        {
            float x = 0;
            float y = 0;
            float z = 0;
        }
        struct
        {
            float r;
            float g;
            float b;
        }
    }
}

void test11147()
{
    auto v = V11147.init;
    assert(v.x == 0f);
    assert(v.y == 0f);
    assert(v.z == 0f);
    assert(v.r == 0f);
    assert(v.g == 0f);
    assert(v.b == 0f);
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=11256

struct S11256 { @disable this(); }

struct Z11256a(Ranges...)
{
    Ranges ranges;
    this(Ranges rs) { ranges = rs; }
}
struct Z11256b(Ranges...)
{
    Ranges ranges = Ranges.init;    // Internal error: e2ir.c 5321
    this(Ranges rs) { ranges = rs; }
}
struct Z11256c(Ranges...)
{
    Ranges ranges = void;           // todt.c(475) v->type->ty == Tsarray && vsz == 0
    this(Ranges rs) { ranges = rs; }
}

struct F11256(alias pred)
{
    this(int[]) { }
}

Z!Ranges z11256(alias Z, Ranges...)(Ranges ranges)
{
    return Z!Ranges(ranges);
}

void test11256()
{
    z11256!Z11256a(S11256.init, F11256!(gv => true)(null));
    z11256!Z11256b(S11256.init, F11256!(gv => true)(null));
    z11256!Z11256c(S11256.init, F11256!(gv => true)(null));
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=11269

struct Atom
{
    union
    {
        int i;
        struct
        {
            ulong first, rest;
        }
        struct
        {
            uint a, b;
        }
    }
}

void test11269()
{
    Atom a1;
    Atom a2 = {i:1, rest:10, b:2};
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=11427

struct S11427
{
    union
    {
        ubyte a;
        int x;
    }
    void[] arr;
}

int foo11427() @safe
{
    S11427 s1 = S11427();
    S11427 s2;
    return 0;
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=12011

struct S12011a
{
    int f() { return i; }
    enum e = this.init.f();
    int i = 1, j = 2;
}

struct S12011b
{
    int f() { return i; }
    enum e = S12011b().f();
    int i = 1, j = 2;
}

void test12011()
{
    static assert(S12011a.e == 1);
    static assert(S12011b.e == 1);
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=13021

void test13021()
{
    static union U1
    {
        float a;
        int b;
    }

    static union U2
    {
        double a;
        long b;
    }

    static union U3
    {
        real a;
        struct B { long b1, b2; } // ICE happens only if B.sizeof == real.sizeof
        B b;
    }

    static union U4
    {
        real a;
        long[2] b; // ditto
    }

    auto f = U1(1.0);  auto ok = f.b;

    auto fail1 = U1(1.0).b; // OK <- Internal error: e2ir.c 1162
    auto fail2 = U2(1.0).b; // OK <- Internal error: e2ir.c 1162
    auto fail3 = U3(1.0).b; // OK <- Internal error: e2ir.c 1162
    auto fail4 = U4(1.0).b; // OK <- Internal error: backend/el.c 2904
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=14556

enum E14556 { a = 1 }

struct S14556a
{
    this(int) {}
    E14556[1] data;
}

struct S14556b
{
    this(int) {}
    void[1] data;
}

void test14556()
{
    auto sa = S14556a(0);
    assert(sa.data == [E14556.a]);

    auto sb = S14556b(0);
    assert(sb.data[] == cast(ubyte[1])[0]);
}

/********************************************/
// https://issues.dlang.org/show_bug.cgi?id=17622

struct S17622
{
    int i;

    this(ubyte)
    {
        return;
    }

    void fun()
    {
        assert(i == 0);
    }
}

S17622 make()
{
    return S17622(0);
}

void test17622()
{
    S17622 s = make();

    auto rdg = (){ s.fun(); };

    s.fun();
}

/********************************************/

int main()
{
    test1();
    test2();
    test3();
    test4();
    test5();
    test6();
    test7();
    test8();
    test9();
    test10();
    test11();
    test12();
    test13();
    test14();
    test15a();
    test15b();
    test15c();
    test15d();
    test15e();
    test9993a();
    test9993b();
    test3198and1914();
    test2427();
    test5885();
    test5889();
    test4247();
    test6937();
    test12681();
    test3991();
    test7727();
    test7929();
    test7021();
    test8738();
    test8763();
    test8902();
    test9116();
    test9293();
    test9566();
    test11105();
    test11147();
    test11256();
    test13021();
    test14556();
    test17622();

    printf("Success\n");
    return 0;
}
