/*
REQUIRED_ARGS: -preview=rvaluerefparam
TEST_OUTPUT:
---
\	S1	S2a	S2b	S3a	S3b	S4a	S4b
-	true	true	true	true	true	true	true
Xa	true	true	true	true	true	true	true
Xb	true	true	true	true	true	true	true
Xc	true	true	true	true	true	true	true
Xd	true	true	true	true	true	true	true
Xe	true	true	true	true	true	true	true
Xf	true	true	true	true	true	true	true
Xg	true	true	true	true	true	true	true
---

RUN_OUTPUT:
---
Success
---
*/

import core.stdc.stdio;

template TypeTuple(T...){ alias T TypeTuple; }

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

struct Pair {
    immutable uint g1;
    uint g2;
}

void test1() {
    Pair[1] stuff;
    static assert(!__traits(compiles, (stuff[0] = Pair(1, 2))));
}

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

struct ID
{
    immutable int value;
}

struct Data
{
    ID id;
}
void test2()
{
    Data data = Data(ID(1));
    immutable int* val = &data.id.value;
    static assert(!__traits(compiles, data = Data(ID(2))));
}

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

struct S31A
{
    union
    {
        immutable int field1;
        immutable int field2;
    }

    enum result = false;
}
struct S31B
{
    union
    {
        immutable int field1;
        int field2;
    }

    enum result = true;
}
struct S31C
{
    union
    {
        int field1;
        immutable int field2;
    }

    enum result = true;
}
struct S31D
{
    union
    {
        int field1;
        int field2;
    }

    enum result = true;
}

struct S32A
{
    int dummy0;
    union
    {
        immutable int field1;
        int field2;
    }

    enum result = true;
}
struct S32B
{
    immutable int dummy0;
    union
    {
        immutable int field1;
        int field2;
    }

    enum result = false;
}


struct S32C
{
    union
    {
        immutable int field1;
        int field2;
    }
    int dummy1;

    enum result = true;
}
struct S32D
{
    union
    {
        immutable int field1;
        int field2;
    }
    immutable int dummy1;

    enum result = false;
}

void test3()
{
    foreach (S; TypeTuple!(S31A,S31B,S31C,S31D, S32A,S32B,S32C,S32D))
    {
        S s;
        static assert(__traits(compiles, s = s) == S.result);
    }
}

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

struct S4
{
    private int _prop = 42;
    ref int property() return { return _prop; }
}

void test4()
{
    S4 s;
    assert(s.property == 42);
    s.property = 23;    // Rewrite to s.property() = 23
    assert(s.property == 23);
}

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

struct S5
{
    int mX;
    string mY;

    ref int x() return
    {
        return mX;
    }
    ref string y() return
    {
        return mY;
    }

    ref int err(Object)
    {
        static int v;
        return v;
    }
}

void test5()
{
    S5 s;
    s.x += 4;
    assert(s.mX == 4);
    s.x -= 2;
    assert(s.mX == 2);
    s.x *= 4;
    assert(s.mX == 8);
    s.x /= 2;
    assert(s.mX == 4);
    s.x %= 3;
    assert(s.mX == 1);
    s.x <<= 3;
    assert(s.mX == 8);
    s.x >>= 1;
    assert(s.mX == 4);
    s.x >>>= 1;
    assert(s.mX == 2);
    s.x &= 0xF;
    assert(s.mX == 0x2);
    s.x |= 0x8;
    assert(s.mX == 0xA);
    s.x ^= 0xF;
    assert(s.mX == 0x5);

    s.x ^^= 2;
    assert(s.mX == 25);

    s.mY = "ABC";
    s.y ~= "def";
    assert(s.mY == "ABCdef");

    static assert(!__traits(compiles, s.err += 1));
}

void test6()
{
    int dtors;
    struct S6
    {
        @disable this(this);
        ~this() { dtors++; }
    }

    S6[2] arr;
    arr = S6();

    assert(dtors == 2);
}

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

void test4424()
{
    static struct S
    {
        this(this) {}
        void opAssign(T)(T rhs) if (!is(T == S)) {}
    }
}

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

struct CtorTest6174(Data)
{
    const Data data;

    const Data[2] sa1;
    const Data[2][1] sa2;
    const Data[][2] sa3;

    const Data[] da1;
    const Data[2][] da2;

    this(Data a)
    {
        auto pdata = &data;

        // If compiler can determine that an assignment really sets the fields
        // which belongs to `this` object, it can bypass const qualifier.
        // For example, sa3, da1, da2, and pdata have indirections.
        // As long as you don't try to rewrite values beyond the indirections,
        // an assignment will always be succeeded inside constructor.

        static assert( is(typeof( data        = a         )));    // OK
      static if (is(Data == struct))
      {
        static assert( is(typeof( data.x      = 1         )));    // OK
        static assert( is(typeof( data.y      = 2         )));    // OK
      }
        static assert(!is(typeof( *pdata      = a         )));    // NG
        static assert( is(typeof( *&data      = a         )));    // OK

        static assert( is(typeof( sa1         = [a,a]     )));    // OK
        static assert( is(typeof( sa1[0]      = a         )));    // OK
        static assert( is(typeof( sa1[]       = a         )));    // OK
        static assert( is(typeof( sa1[][]     = a         )));    // OK

        static assert( is(typeof( sa2         = [[a,a]]   )));    // OK
        static assert( is(typeof( sa2[0][0]   = a         )));    // OK
        static assert( is(typeof( sa2[][0][]  = a         )));    // OK
        static assert( is(typeof( sa2[0][][0] = a         )));    // OK

        static assert( is(typeof( sa3         = [[a],[]]  )));    // OK
        static assert( is(typeof( sa3[0]      = [a,a]     )));    // OK
        static assert(!is(typeof( sa3[0][0]   = a         )));    // NG
        static assert( is(typeof( sa3[]       = [a]       )));    // OK
        static assert( is(typeof( sa3[][0]    = [a]       )));    // OK
        static assert(!is(typeof( sa3[][0][0] = a         )));    // NG

        static assert( is(typeof( da1         = [a,a]     )));    // OK
        static assert(!is(typeof( da1[0]      = a         )));    // NG
        static assert(!is(typeof( da1[]       = a         )));    // NG

        static assert( is(typeof( da2         = [[a,a]]   )));    // OK
        static assert(!is(typeof( da2[0][0]   = a         )));    // NG
        static assert(!is(typeof( da2[]       = [a,a]     )));    // NG
        static assert(!is(typeof( da2[][0]    = a         )));    // NG
        static assert(!is(typeof( da2[0][]    = a         )));    // NG
    }
    void func(Data a)
    {
        auto pdata = &data;

        static assert(!is(typeof( data        = a         )));    // NG
      static if (is(Data == struct))
      {
        static assert(!is(typeof( data.x      = 1         )));    // NG
        static assert(!is(typeof( data.y      = 2         )));    // NG
      }
        static assert(!is(typeof( *pdata      = a         )));    // NG
        static assert(!is(typeof( *&data      = a         )));    // NG

        static assert(!is(typeof( sa1         = [a,a]     )));    // NG
        static assert(!is(typeof( sa1[0]      = a         )));    // NG
        static assert(!is(typeof( sa1[]       = a         )));    // NG
        static assert(!is(typeof( sa1[][]     = a         )));    // NG

        static assert(!is(typeof( sa2         = [[a,a]]   )));    // NG
        static assert(!is(typeof( sa2[0][0]   = a         )));    // NG
        static assert(!is(typeof( sa2[][0][]  = a         )));    // NG
        static assert(!is(typeof( sa2[0][][0] = a         )));    // NG

        static assert(!is(typeof( sa3         = [[a],[]]  )));    // NG
        static assert(!is(typeof( sa3[0]      = [a,a]     )));    // NG
        static assert(!is(typeof( sa3[0][0]   = a         )));    // NG
        static assert(!is(typeof( sa3[]       = [a]       )));    // NG
        static assert(!is(typeof( sa3[][0]    = [a]       )));    // NG
        static assert(!is(typeof( sa3[][0][0] = a         )));    // NG

        static assert(!is(typeof( da1         = [a,a]     )));    // NG
        static assert(!is(typeof( da1[0]      = a         )));    // NG
        static assert(!is(typeof( da1[]       = a         )));    // NG

        static assert(!is(typeof( da2         = [[a,a]]   )));    // NG
        static assert(!is(typeof( da2[0][0]   = a         )));    // NG
        static assert(!is(typeof( da2[]       = [a,a]     )));    // NG
        static assert(!is(typeof( da2[][0]    = a         )));    // NG
        static assert(!is(typeof( da2[0][]    = a         )));    // NG
    }
}

const char gc6174;
const char[1] ga6174;
shared static this()
{
    gc6174 = 'a';    // OK
    ga6174[0] = 'a'; // line 5, Err
}
struct Foo6174
{
    const char cc;
    const char[1] array;
    const char[1] arr;
    this(char c)
    {
        cc = c;       // OK
        array = [c];  // line 12, Err
        arr[0] = c;   // line 12, Err
    }
}
void test6174a()
{
    static struct Pair
    {
        const int x;
        int y;
    }
    alias CtorTest6174!long CtorTest1;
    alias CtorTest6174!Pair CtorTest2;

    auto foo = Foo6174('c');
}

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

template Select(bool cond, T, F)
{
    static if (cond)
        alias Select = T;
    else
        alias Select = F;
}

void test6174b()
{
    enum { none, unrelated, mutable, constant }

    static struct FieldStruct(bool c, int k)
    {
        enum fieldConst = c;
        enum assignKind = k;

        Select!(fieldConst, const int, int) x;
        int y;

        static if (assignKind == none)      {}
        static if (assignKind == unrelated) void opAssign(int) {}
        static if (assignKind == mutable)   void opAssign(FieldStruct) {}
        static if (assignKind == constant)  void opAssign(FieldStruct) const {}
    }
    static struct TestStruct(F, bool fieldConst)
    {
        int w;
        Select!(fieldConst, const F, F) f;
        Select!(fieldConst, const int, int) z;

        this(int)
        {
            // If F has an identity `opAssign`,it is used even for initializing.
            // Otherwise, initializing  will always succeed, by bypassing const qualifier.
            static assert(is(typeof( f = F() )) == (
                            F.assignKind == none ||
                            F.assignKind == unrelated ||
                            F.assignKind == mutable ||
                            F.assignKind == constant));

            static assert(is(typeof(   w = 1000 )) == true);
            static assert(is(typeof( f.x = 1000 )) == true);
            static assert(is(typeof( f.y = 1000 )) == true);
            static assert(is(typeof(   z = 1000 )) == true);
        }
        void func()
        {
            // In mutable member functions, identity assignment is allowed
            // when all of the fields are identity assignable,
            // or identity `opAssign`, which callable from mutable object, is defined.
            static assert(__traits(compiles, f = F()) == (
                            F.assignKind == none      && !fieldConst && !F.fieldConst ||
                            F.assignKind == unrelated && !fieldConst && !F.fieldConst ||
                            F.assignKind == constant ||
                            F.assignKind == mutable   && !fieldConst));

            static assert(__traits(compiles,   w = 1000) == true);
            static assert(__traits(compiles, f.x = 1000) == (!fieldConst && !F.fieldConst));
            static assert(__traits(compiles, f.y = 1000) == (!fieldConst && true         ));
            static assert(__traits(compiles,   z = 1000) == !fieldConst);
        }
        void func() const
        {
            // In non-mutable member functions, identity assignment is allowed
            // just only user-defined identity `opAssign` is qualified.
            static assert(__traits(compiles, f = F()) == (F.assignKind == constant));

            static assert(__traits(compiles,   w = 1000) == false);
            static assert(__traits(compiles, f.x = 1000) == false);
            static assert(__traits(compiles, f.y = 1000) == false);
            static assert(__traits(compiles,   z = 1000) == false);
        }
    }
    foreach (fieldConst; TypeTuple!(false, true))
    foreach (  hasConst; TypeTuple!(false, true))
    foreach (assignKind; TypeTuple!(none, unrelated, mutable, constant))
    {
        alias TestStruct!(FieldStruct!(hasConst, assignKind), fieldConst) TestX;
    }
}

void test6174c()
{
    static assert(!is(typeof({
        int func1a(int n)
        in{ n = 10; }
        do { return n; }
    })));
    static assert(!is(typeof({
        int func1b(int n)
        out(r){ r = 20; }
        do{ return n; }
    })));

    struct DataX
    {
        int x;
    }
    static assert(!is(typeof({
        DataX func2a(DataX n)
        in{ n.x = 10; }
        do { return n; }
    })));
    static assert(!is(typeof({
        DataX func2b(DataX n)
        in{}
        out(r){ r.x = 20; }
        do{ return n; }
    })));
}

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

void test6216a()
{
    static class C{}

    static struct Xa{ int n; }
    static struct Xb{ int[] a; }
    static struct Xc{ C c; }
    static struct Xd{ void opAssign(typeof(this) rhs){} }
    static struct Xe{ void opAssign(T)(T rhs){} }
    static struct Xf{ void opAssign(int rhs){} }
    static struct Xg{ void opAssign(T)(T rhs)if(!is(T==typeof(this))){} }

    // has value type as member
    static struct S1 (X){ static if (!is(X==void)) X x; int n; }

    // has reference type as member
    static struct S2a(X){ static if (!is(X==void)) X x; int[] a; }
    static struct S2b(X){ static if (!is(X==void)) X x; C c; }

    // has identity opAssign
    static struct S3a(X){ static if (!is(X==void)) X x; void opAssign(typeof(this) rhs){} }
    static struct S3b(X){ static if (!is(X==void)) X x; void opAssign(T)(T rhs){} }

    // has non identity opAssign
    static struct S4a(X){ static if (!is(X==void)) X x; void opAssign(int rhs){} }
    static struct S4b(X){ static if (!is(X==void)) X x; void opAssign(T)(T rhs)if(!is(T==typeof(this))){} }

    enum result = [
        /*S1,   S2a,    S2b,    S3a,    S3b,    S4a,    S4b*/
/*- */  [true,  true,   true,   true,   true,   true,   true],
/*Xa*/  [true,  true,   true,   true,   true,   true,   true],
/*Xb*/  [true,  true,   true,   true,   true,   true,   true],
/*Xc*/  [true,  true,   true,   true,   true,   true,   true],
/*Xd*/  [true,  true,   true,   true,   true,   true,   true],
/*Xe*/  [true,  true,   true,   true,   true,   true,   true],
/*Xf*/  [true,  true,   true,   true,   true,   true,   true],
/*Xg*/  [true,  true,   true,   true,   true,   true,   true],
    ];

    pragma(msg, "\\\tS1\tS2a\tS2b\tS3a\tS3b\tS4a\tS4b");
    foreach (i, X; TypeTuple!(void,Xa,Xb,Xc,Xd,Xe,Xf,Xg))
    {
        S1!X  s1;
        S2a!X s2a;
        S2b!X s2b;
        S3a!X s3a;
        S3b!X s3b;
        S4a!X s4a;
        S4b!X s4b;

        pragma(msg,
                is(X==void) ? "-" : X.stringof,
                "\t", __traits(compiles, (s1  = s1)),
                "\t", __traits(compiles, (s2a = s2a)),
                "\t", __traits(compiles, (s2b = s2b)),
                "\t", __traits(compiles, (s3a = s3a)),
                "\t", __traits(compiles, (s3b = s3b)),
                "\t", __traits(compiles, (s4a = s4a)),
                "\t", __traits(compiles, (s4b = s4b))  );

        static assert(result[i] ==
            [   __traits(compiles, (s1  = s1)),
                __traits(compiles, (s2a = s2a)),
                __traits(compiles, (s2b = s2b)),
                __traits(compiles, (s3a = s3a)),
                __traits(compiles, (s3b = s3b)),
                __traits(compiles, (s4a = s4a)),
                __traits(compiles, (s4b = s4b))  ]);
    }
}

void test6216b()
{
    static int cnt = 0;

    static struct X
    {
        int n;
        void opAssign(X rhs){ cnt = 1; }
    }
    static struct S
    {
        int n;
        X x;
    }

    S s;
    s = s;
    assert(cnt == 1);
    // Built-in opAssign runs member's opAssign
}

void test6216c()
{
    static int cnt = 0;

    static struct X
    {
        int n;
        void opAssign(const X rhs) const { cnt = 2; }
    }
    static struct S
    {
        int n;
        const(X) x;
    }

    S s;
    const(S) cs;
    s = s;
    s = cs;     // cs is copied as mutable and assigned into s
    assert(cnt == 2);
    static assert(!__traits(compiles, cs = cs));
                // built-in opAssin is only allowed with mutable object
}

void test6216d()
{
    static int cnt = 0;

    static struct X
    {
        int[] arr;  // X has mutable indirection
        void opAssign(const X rhs) const { ++cnt; }
    }
    static struct S
    {
        int n;
        const(X) x;
    }

    X mx;
    const X cx;
    mx = mx;    // copying mx to const X is possible
    assert(cnt == 1);
    mx = cx;
    assert(cnt == 2);
    cx = mx;    // copying mx to const X is possible
    assert(cnt == 3);

    S s;
    const(S) cs;
    s = s;
    s = cs;
    //assert(cnt == 4);
    static assert(!__traits(compiles, cs = cs));
                // built-in opAssin is only allowed with mutable object
}

void test6216e()
{
    static struct X
    {
        int x;
        @disable void opAssign(X);
    }
    static struct S
    {
        X x;
    }
    S s;
    static assert(!__traits(compiles, s = s));
                // built-in generated opAssin is marked as @disable.
}

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

void test6286()
{
    const(int)[4] src = [1, 2, 3, 4];
    int[4] dst;
    dst = src;
    dst[] = src[];
    dst = 4;
    int[4][4] x;
    x = dst;
}

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

void test6336()
{
    // structs aren't identity assignable
    static struct S1
    {
        immutable int n;
    }
    static struct S2
    {
        void opAssign(int n){ assert(0); }
    }

    S1 s1;
    S2 s2;

    void f(S)(out S s){}
    static assert(!__traits(compiles, f(s1)));
    f(s2);
    // Out parameters refuse only S1 because it isn't blit assignable

    ref S g(S)(ref S s){ return s; }
    g(s1);
    g(s2);
    // Allow return by ref both S1 and S2
}

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

struct Foo8783
{
    int[1] bar;
}

const Foo8783[1] foos8783;

shared static this()
{
    foreach (i; 0 .. foos8783.length)
        foos8783[i].bar[i] = 1; // OK
    foreach (i, ref f; foos8783)
        f.bar[i] = 1; // line 9, Error
}

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

struct S9077a
{
    void opAssign(int n) {}
    void test() { typeof(this) s; s = this; }
    this(this) {}
}
struct S9077b
{
    void opAssign()(int n) {}
    void test() { typeof(this) s; s = this; }
    this(this) {}
}

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

immutable(int)[] bar9140()
out(result) {
    foreach (ref r; result) {}
} do {
    return null;
}

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

struct S9154a
{
    int x;
    void opAssign(ref S9154a s) { }
}
struct S9154b
{
    int x;
    void opAssign(X)(ref X s) { }
}
struct T9154
{
    S9154a member1;
    S9154b member2;
}

void test9154()
{
    T9154 t1, t2;
    t1 = t2;
}

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

class A9258 {}
class B9258 : A9258 // Error: class test.B9258 identity assignment operator overload is illegal
{
    void opAssign(A9258 b) {}
}

class C9258
{
    int n;
    alias n this;
    void opAssign(int n) {}
}
class D9258
{
    int n;
    alias n this;
    void opAssign(int n, int y = 0) {}
}
class E9258 : A9258
{
    void set(A9258 a) {}
    alias set opAssign;
}

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

struct S9416
{
    void opAssign()(S9416)
    {
        static assert(0);
    }
}
struct U9416
{
    S9416 s;
}
void test9416()
{
    U9416 u;
    static assert(__traits(allMembers, U9416)[$-1] == "opAssign");
    static assert(!__traits(compiles, u = u));
}

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

struct S9658
{
    private bool _isNull = true;
    this(int v) const
    {
        _isNull = false;    // cannot modify const expression this._isNull
    }
}

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

void test11187()
{
    static struct X
    {
        int[] arr;
    }
    static struct S
    {
        const(X) cx;
    }
    static assert(is(typeof((const S).init.cx.arr) == const(int[])));
    static assert(is(typeof((      S).init.cx.arr) == const(int[])));
    const S sc;
    S sm = sc;
    static assert(is(const S : S));
}

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

struct X12131
{
    void opAssign()(X12131 y) pure {}
}

struct Y12131
{
    X12131 a;
}

void test12131() pure
{
    X12131 x;
    x = X12131();   // OK

    Y12131 y;
    y = Y12131();   // OK <- Error
}

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

void test12211()
{
    int a = 0;
    void foo(ref int x)
    {
        assert(x == 10);
        assert(&x == &a);
        x = 3;
    }
    foo(a = 10);
    assert(a == 3);
    foo(a += 7);
    assert(a == 3);

    // array ops should make rvalue
    int[3] sa, sb;
    void bar(ref int[]) {}
    static assert(__traits(compiles, bar(sa[]  = sb[])));
    static assert(__traits(compiles, bar(sa[] += sb[])));
}

/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=4791 (dup of 12212)

void test4791()
{
    int[2] na;
    na = na;

    static struct S
    {
        static string res;
        int n;
        this(this) { ++n; res ~= "p" ~ cast(char)('0' + n); }
        ~this()    {      res ~= "d" ~ cast(char)('0' + n); }
    }
    {
        S[3] sa;
        sa[0].n = 1, sa[1].n = 2, sa[2].n = 3;

        S.res = null;
        sa = sa;
        assert(S.res == "p2d1p3d2p4d3");
        assert(sa[0].n == 2 && sa[1].n == 3 && sa[2].n == 4);

        S.res = null;
    }
    assert(S.res == "d4d3d2");
}

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

void test12212()
{
    struct S
    {
        int x, y;
        static int cpctor;
        this(this) { cpctor++; }
    }

    void funcVal(E)(E[3] x) {}
    auto funcRef(E)(ref E[3] x) { return &x; }
    ref get(E)(ref E[3] a){ return a; }

    {
        int[3] a, b;
        funcVal(a = b);

        auto p = funcRef(a = b);
        assert(p == &a);
    }

    {
        S.cpctor = 0;

        S[3] a, b;
        assert(S.cpctor == 0);

        S[3] c = a;
        //printf("cpctpr = %d\n", S.cpctor);
        assert(S.cpctor == 3);
        S.cpctor = 0;

        c = a;
        //printf("cpctpr = %d\n", S.cpctor);
        assert(S.cpctor == 3);
        S.cpctor = 0;

        c = (a = b);
        //printf("cpctpr = %d\n", S.cpctor);
        assert(S.cpctor == 6);
        S.cpctor = 0;

        c = (get(a) = b);
        //printf("cpctpr = %d\n", S.cpctor);
        assert(S.cpctor == 6);
        S.cpctor = 0;
    }
    {
        S.cpctor = 0;

        S[3] a, b;
        assert(S.cpctor == 0);

        funcVal(a = b);
        //printf("cpctpr = %d\n", S.cpctor);
        assert(S.cpctor == 6);
        S.cpctor = 0;

        funcVal(get(a) = b);
        //printf("cpctpr = %d\n", S.cpctor);
        assert(S.cpctor == 6);
        S.cpctor = 0;
    }
    {
        S.cpctor = 0;

        S[3] a, b;
        assert(S.cpctor == 0);

        S[3]* p;

        p = funcRef(a = b);
        //printf("cpctpr = %d\n", S.cpctor);
        assert(p == &a);
        assert(S.cpctor == 3);
        S.cpctor = 0;

        p = funcRef(get(a) = b);
        assert(p == &a);
        //printf("cpctpr = %d\n", S.cpctor);
        assert(S.cpctor == 3);
        S.cpctor = 0;
    }
}

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

void test12650()
{
    // AssignExp::toElem should make an lvalue of e1.
    static class A1
    {
        struct S { int a; }

        static foo(ref const(S) s)
        {
            assert(s.a == 2);
            return &s;
        }

        S s;

        this()
        {
            const v = S(2);

            // (this.s = v) will become ConstructExp
            auto p = foo(s = v);
            assert(p == &s);
        }
    }
    assert(new A1().s.a == 2);

    static class A2
    {
        static foo(ref int[2] sa)
        {
            assert(sa[1] == 2);
            return &sa;
        }

        int[2] sa;

        this()
        {
            // (this.sa = [1,2]) will become ConstructExp
            auto p = foo(sa = [1,2]);
            assert(p == &sa);
        }
    }
    assert(new A2().sa[1] == 2);

    static class A3
    {
        static foo(ref int n)
        {
            assert(n == 2);
            return &n;
        }

        int n;

        this()
        {
            const v = 2;

            // (this.n = v) will become ConstructExp
            auto p = foo(n = v);
            assert(p == &n);
        }
    }
    assert(new A3().n == 2);
}

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

void test13044()
{
    static struct Good
    {
        const int i;
    }

    static struct Bad
    {
        const int i;
        ~this() {}
    }

    Good good1, good2;
    static assert(!__traits(compiles, { good1 = good2; })); // OK

    Bad bad1, bad2;
    static assert(!__traits(compiles, { bad1 = bad2; }));   // OK <- fails
}

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

void test12500()
{
    size_t foo;
    ++foo *= 1.5;   // Rewrite to: (foo += 1) *= 1.5;
}

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

void test14672()
{
    interface I {}

    class B {}
    class D : B, I {}

    D d = new D();
    D[] da = [d];
    B[] ba = [null];
    I[] ia = [null];

    // ba and da points different payloads,
    // so element-wise assignment should work.
    ba[] = da[];    // OK <- e2ir ICE
    assert(ba[0] is d);

    // Today element-wise assignment is implemented as memcpy, For that reason
    // the conversion from derived classes to base interfaces is disallowed
    // because it requries offset adjustments.
    static assert(!__traits(compiles, { ia[] = da[]; }));

    // after the assignment, ba will wongly point the payload of da,
    // that's typed as D[]. To aboid type system breaking, it's disallowed.
    static assert(!__traits(compiles, { ba = da; }));

    // the assigned array literal is a new payload,
    // so rebinding ba should work.
    ba = [d];       // OK
    assert(ba[0] is d);
}

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

void destroy15044(T)(ref T obj)
{
    static if (__traits(hasMember, T, "__xdtor"))
        obj.__xdtor();
    else
        static assert(0, T.stringof);
}

struct V15044
{
    ~this()
    {
    }

    RC15044!V15044 dup() return
    {
        return RC15044!V15044(&this);
    }
}

struct RC15044(T)
{
    ~this()
    {
        destroy15044(*t);
        static assert(__traits(hasMember, T, "__xdtor"));
    }
    T* t;
}

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

int main()
{
    test1();
    test2();
    test3();
    test4();
    test5();
    test6();
    test4424();
    test6174a();
    test6174b();
    test6174c();
    test6216a();
    test6216b();
    test6216c();
    test6216d();
    test6216e();
    test6286();
    test6336();
    test9154();
    test9416();
    test11187();
    test12131();
    test12211();
    test4791();
    test12212();
    test12650();
    test13044();
    test12500();
    test14672();

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