// PERMUTE_ARGS: -unittest -O -release -inline -fPIC -g
// REQUIRED_ARGS: -preview=dtorfields
/*
TEST_OUTPUT:
---
S7353
---
*/

import core.vararg;
// FIXME: Shouldn't tests that use this go in core.memory now that `delete` has been removed?
import core.memory : __delete;

extern (C) int printf(const(char*) fmt, ...) nothrow;

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

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

int sdtor;

struct S1
{
    ~this() { printf("~S()\n"); sdtor++; }
}

void test1()
{
    S1* s = new S1();
    __delete(s);
    assert(sdtor == 1);
}

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

int sdtor3;

struct S3
{   int a;
    ~this() { printf("~S3()\n"); sdtor3++; assert(a == 3); }
}

struct T3
{
    int i;
    S3 s;
}

void test3()
{
    T3* s = new T3();
    s.s.a = 3;
    __delete(s);
    assert(sdtor3 == 1);
}

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

int sdtor4;

struct S4
{   int a = 3;
    ~this()
    {   printf("~S4()\n");
        if (a == 4)
            assert(sdtor4 == 2);
        else
        {   assert(a == 3);
            assert(sdtor4 == 1);
        }
        sdtor4++;
    }
}

struct T4
{
    int i;
    S4 s;
    ~this() { printf("~T4()\n"); assert(sdtor4 == 0); sdtor4++; }
    S4 t;
}

void test4()
{
    T4* s = new T4();
    s.s.a = 4;
    __delete(s);
    assert(sdtor4 == 3);
}

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

int sdtor5;

template M5()
{  ~this()
   {
        printf("~M5()\n"); assert(sdtor5 == 1); sdtor5++;
   }
}

struct T5
{
    mixin M5 m;
    ~this() { printf("~T5()\n"); assert(sdtor5 == 0); sdtor5++; }
}

void test5()
{
    T5* s = new T5();
    __delete(s);
    assert(sdtor5 == 2);
}

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

int sdtor6;

struct S6
{   int b = 7;
    ~this()
    {
        printf("~S6()\n"); assert(b == 7); assert(sdtor6 == 1); sdtor6++;
    }
}

class T6
{
    int a = 3;
    S6 s;
    ~this() { printf("~T6()\n"); assert(a == 3); assert(sdtor6 == 0); sdtor6++; }
}

void test6()
{
    T6 s = new T6();
    __delete(s);
    assert(sdtor6 == 2);
}

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

int sdtor7;

struct S7
{   int b = 7;
    ~this()
    {
        printf("~S7()\n");
        assert(b == 7);
        assert(sdtor7 >= 1 && sdtor7 <= 3);
        sdtor7++;
    }
}

struct T7
{
    int a = 3;
    S7[3] s;
    ~this()
    {   printf("~T7() %d\n", sdtor7);
        assert(a == 3);
        assert(sdtor7 == 0);
        sdtor7++;
    }
}

void test7()
{
    T7* s = new T7();
    __delete(s);
    assert(sdtor7 == 4);
}

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

int sdtor8;

struct S8
{   int b = 7;
    int c;
    ~this()
    {
        printf("~S8() %d\n", sdtor8);
        assert(b == 7);
        assert(sdtor8 == c);
        sdtor8++;
    }
}

void test8()
{
    S8[] s = new S8[3];
    s[0].c = 2;
    s[1].c = 1;
    s[2].c = 0;
    __delete(s);
    assert(sdtor8 == 3);
}

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

int sdtor9;

struct S9
{   int b = 7;
    ~this()
    {
        printf("~S9() %d\n", sdtor9);
        assert(b == 7);
        sdtor9++;
    }
}

void test9()
{
    {
    S9 s;
    }
    assert(sdtor9 == 1);
}

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

int sdtor10;

struct S10
{   int b = 7;
    int c;
    ~this()
    {
        printf("~S10() %d\n", sdtor10);
        assert(b == 7);
        assert(sdtor10 == c);
        sdtor10++;
    }
}

void test10()
{
    {
    S10[3] s;
    s[0].c = 2;
    s[1].c = 1;
    s[2].c = 0;
    }
    assert(sdtor10 == 3);
}

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

int sdtor11;

template M11()
{   ~this()
    {
        printf("~M11()\n"); assert(sdtor11 == 1); sdtor11++;
    }
}

class T11
{
    mixin M11 m;
    ~this() { printf("~T11()\n"); assert(sdtor11 == 0); sdtor11++; }
}

void test11()
{
    T11 s = new T11();
    __delete(s);
    assert(sdtor11 == 2);
}

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

int sdtor12;

struct S12
{   int a = 3;
    ~this() { printf("~S12() %d\n", sdtor12); sdtor12++; }
}

void foo12(S12 s)
{
}

void test12()
{
    {
    S12 s;
    foo12(s);
    s.a = 4;
    }
    assert(sdtor12 == 2);
}

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

struct S13
{   int a = 3;
    int opAssign(S13 s)
    {
        printf("S13.opAssign(%p)\n", &this);
        a = 4;
        return s.a + 2;
    }
}

void test13()
{
    S13 s;
    S13 t;
    assert((s = t) == 5);
    assert(s.a == 4);
}

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

struct S14
{   int a = 3;
    int opAssign(ref S14 s)
    {
        printf("S14.opAssign(%p)\n", &this);
        a = 4;
        return s.a + 2;
    }
}

void test14()
{
    S14 s;
    S14 t;
    assert((s = t) == 5);
    assert(s.a == 4);
}

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

struct S15
{   int a = 3;
    int opAssign(ref const S15 s)
    {
        printf("S15.opAssign(%p)\n", &this);
        a = 4;
        return s.a + 2;
    }
}

void test15()
{
    S15 s;
    S15 t;
    assert((s = t) == 5);
    assert(s.a == 4);
}

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

struct S16
{   int a = 3;
    int opAssign(S16 s, ...)
    {
        printf("S16.opAssign(%p)\n", &this);
        a = 4;
        return s.a + 2;
    }
}

void test16()
{
    S16 s;
    S16 t;
    assert((s = t) == 5);
    assert(s.a == 4);
}

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

struct S17
{   int a = 3;
    int opAssign(...)
    {
        printf("S17.opAssign(%p)\n", &this);
        a = 4;
        return 5;
    }
}

void test17()
{
    S17 s;
    S17 t;
    assert((s = t) == 5);
    assert(s.a == 4);
}

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

struct S18
{   int a = 3;
    int opAssign(S18 s, int x = 7)
    {
        printf("S18.opAssign(%p)\n", &this);
        a = 4;
        assert(x == 7);
        return s.a + 2;
    }
}

void test18()
{
    S18 s;
    S18 t;
    assert((s = t) == 5);
    assert(s.a == 4);
}

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

struct S19
{
    int a,b,c,d;
    this(this) { printf("this(this) %p\n", &this); }
    ~this() { printf("~this() %p\n", &this); }
}

S19 foo19()
{
    S19 s;
    void bar() { s.a++; }
    bar();
    return s;
}

void test19()
{
    S19 t = foo19();
    printf("-main()\n");
}

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

struct S20
{
    static char[] r;
    int a,b,c=2,d;
    this(this) { printf("this(this) %p\n", &this); r ~= '='; }
    ~this() { printf("~this() %p\n", &this); r ~= '~'; }
}

void foo20()
{
    S20 s;
    S20[3] a;
    assert(S20.r == "");
    a = s;
    assert(S20.r == "=~=~=~");
}

void test20()
{
    foo20();
    assert(S20.r == "=~=~=~~~~~");
    printf("-main()\n");
}

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

struct S21
{
    static char[] r;
    int a,b,c=2,d;
    this(this) { printf("this(this) %p\n", &this); r ~= '='; }
    ~this() { printf("~this() %p\n", &this); r ~= '~'; }
}

void foo21()
{
    S21 s;
    S21[3] a = s;
    assert(S21.r == "===");
    S21.r = null;
    S21[3][2] b = s;
    assert(S21.r == "======");
    S21.r = null;
}

void test21()
{
    foo21();
    assert(S21.r == "~~~~~~~~~~");
    printf("-main()\n");
}

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

struct S22
{
    static char[] r;
    int a,b,c=2,d;
    this(this) { printf("this(this) %p\n", &this); r ~= '='; }
    ~this() { printf("~this() %p\n", &this); r ~= '~'; }
}

void foo22()
{
    S22[3] s;
    S22[3][2] a;
    assert(S22.r == "");
    a = s;
    assert(S22.r == "===~~~===~~~");
    S22.r = null;
}

void test22()
{
    foo22();
    assert(S22.r == "~~~~~~~~~");
    printf("-main()\n");
}


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

struct S23
{
    int m = 4, n, o, p, q;

    this(int x)
    {
        printf("S23(%d)\n", x);
        assert(x == 3);
        assert(m == 4 && n == 0 && o == 0 && p == 0 && q == 0);
        q = 7;
    }
}

void test23()
{
  {
    auto s = S23(3);
    printf("s.m = %d, s.n = %d, s.q = %d\n", s.m, s.n, s.q);
    assert(s.m == 4 && s.n == 0 && s.o == 0 && s.p == 0 && s.q == 7);
  }
  {
    auto s = new S23(3);
    printf("s.m = %d, s.n = %d, s.q = %d\n", s.m, s.n, s.q);
    assert(s.m == 4 && s.n == 0 && s.o == 0 && s.p == 0 && s.q == 7);
  }
  {
    S23 s;
    s = S23(3);
    printf("s.m = %d, s.n = %d, s.q = %d\n", s.m, s.n, s.q);
    assert(s.m == 4 && s.n == 0 && s.o == 0 && s.p == 0 && s.q == 7);
  }
}

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

struct S24
{
    int m, n, o, p, q;

    this(int x)
    {
        printf("S24(%d)\n", x);
        assert(x == 3);
        assert(m == 0 && n == 0 && o == 0 && p == 0 && q == 0);
        q = 7;
    }
}

void test24()
{
  {
    auto s = S24(3);
    printf("s.m = %d, s.n = %d, s.q = %d\n", s.m, s.n, s.q);
    assert(s.m == 0 && s.n == 0 && s.o == 0 && s.p == 0 && s.q == 7);
  }
  {
    auto s = new S24(3);
    printf("s.m = %d, s.n = %d, s.q = %d\n", s.m, s.n, s.q);
    assert(s.m == 0 && s.n == 0 && s.o == 0 && s.p == 0 && s.q == 7);
  }
  {
    S24 s;
    s = S24(3);
    printf("s.m = %d, s.n = %d, s.q = %d\n", s.m, s.n, s.q);
    assert(s.m == 0 && s.n == 0 && s.o == 0 && s.p == 0 && s.q == 7);
  }
}

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

struct S25
{
    this(int s) {}
}

void test25()
{
    auto a = S25();
}

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

int z26;

struct A26
{
    int id;
    this(int x) { id = x; printf("Created A from scratch: %d\n", x); z26++; }
    this(this) { printf("Copying A: %d\n", id); z26 += 10; }
    ~this() { printf("Destroying A: %d\n", id); z26 += 100; }
}

struct B26
{
    A26 member;
    this(this) { printf("Copying B: %d\n", member.id); assert(0); }
}

B26 foo26()
{
    A26 a = A26(45);
    printf("1\n");
    assert(z26 == 1);
    return B26(a);
}

void test26()
{
    {
    auto b = foo26();
    assert(z26 == 111);
    printf("2\n");
    }
    assert(z26 == 211);
}

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

int z27;

struct A27
{
    int id;
    this(int x) { id = x; printf("Ctor A27: %d\n", x); z27++; }
    this(this) { printf("Copying A27: %d\n", id); z27 += 10; }
    ~this() { printf("Destroying A27: %d\n", id); z27 += 100; }
}

struct B27
{
    A27[2][3] member;
}

void test27()
{
  {
    A27[2][3] a;
    assert(z27 == 0);
    B27 b = B27(a);
    assert(z27 == 60);
  }
  assert(z27 == 1260);
}


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

string s28;

struct A28
{
    this(this)
    {
        printf("A's copy\n");
        s28 ~= "A";
    }
}

struct B28
{
    A28 member;
    this(this)
    {
        printf("B's copy\n");
        s28 ~= "B";
    }
}

void test28()
{
    B28 b1;
    B28 b2 = b1;
    assert(s28 == "AB");
}


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

string s29;

template Templ29 ()
{
    this(int i) { this(0.0); s29 ~= "i"; }
    this(double d) { s29 ~= "d"; }
}

class C29 { mixin Templ29; }
struct S29 { mixin Templ29; }

void test29()
{
    auto r = S29(1);
    assert(s29 == "di");

    r = S29(2.0);
    assert(s29 == "did");

    auto c = new C29(2);
    assert(s29 == "diddi");

    auto c2 = new C29(2.0);
    assert(s29 == "diddid");
}

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

struct S30
{
    int x;
    this(T)(T args) { x = args + 1; }
}

void test30()
{
    auto s = S30(3);
    assert(s.x == 4);
}

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

struct S31
{
    int x;
    this(T...)(T args) { x = args[0] + 1; }
}

void test31()
{
    auto s = S31(3);
    assert(s.x == 4);
}

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

struct S32
{
    static int x;

    this(int i)
    {
        printf("ctor %p(%d)\n", &this, i);
        x += 1;
    }

    this(this)
    {
        printf("postblit %p\n", &this);
        x += 0x10;
    }

    ~this()
    {
        printf("dtor %p\n", &this);
        x += 0x100;
    }
}

S32 foo32()
{
    printf("test1\n");
    return S32(1);
}

S32 bar32()
{
    printf("test1\n");
    S32 f = S32(1);
    printf("test2\n");
    return f;
}

void test32()
{
  {
    S32 s = foo32();
  }
  assert(S32.x == 0x101);

  S32.x = 0;
  {
    S32 s = bar32();
  }
  assert(S32.x == 0x101);
}

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

struct S33
{
    static int x;

    this(int i)
    {
        printf("ctor %p(%d)\n", &this, i);
        x += 1;
    }

    this(this)
    {
        printf("postblit %p\n", &this);
        x += 0x10;
    }

    ~this()
    {
        printf("dtor %p\n", &this);
        x += 0x100;
    }
}

struct T33
{
    S33 foo()
    {
        return t;
    }

    S33 t;
}

void test33()
{
    {
        T33 t;
        S33 s = t.foo();
    }
    printf("S.x = %x\n", S33.x);
    assert(S33.x == 0x210);
}

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

struct X34 {
    int i;
    this(this) {
        printf("postblit %p\n", &this);
        ++i;
    }

    ~this() {
        printf("dtor %p\n", &this);
    }
}

void test34()
{
    X34[2] xs;
//  xs[0][0] = X34();
    printf("foreach\n");
    for (int j = 0; j < xs.length; j++) {
        j++,j--;
        auto x = xs[j];
        //foreach(x; xs)
        //printf("foreach x.i = %d\n", x[0].i);
        //assert(x[0].i == 1);
        printf("foreach x.i = %d\n", x.i);
        assert(x.i == 1);
    }
    printf("loop done\n");
}

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

struct X35 {
    __gshared int k;
    int i;
    this(this) {
        printf("postblit %p\n", &this);
        ++i;
    }

    ~this() {
        printf("dtor %p\n", &this);
        k++;
    }
}

void test35()
{
    {
        X35[2] xs;
        printf("foreach\n");
        foreach(ref x; xs) {
            printf("foreach x.i = %d\n", x.i);
            assert(x.i == 0);
        }
        printf("loop done\n");
    }
    assert(X35.k == 2);
}

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

struct X36 {
    __gshared int k;
    int i;
    this(this) {
        printf("postblit %p\n", &this);
        ++i;
    }

    ~this() {
        printf("dtor %p\n", &this);
        k++;
    }
}

void test36()
{
    {
        X36[2] xs;
        printf("foreach\n");
        foreach(x; xs) {
            printf("foreach x.i = %d\n", x.i);
            assert(x.i == 1);
        }
        printf("loop done\n");
    }
    assert(X36.k == 4);
}

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

struct X37 {
    __gshared int k;
    int i;
    this(this) {
        printf("postblit %p\n", &this);
        ++i;
    }

    ~this() {
        printf("dtor %p\n", &this);
        k++;
    }
}

void test37() {
    {
        X37[2][3] xs;
        printf("foreach\n");
        foreach(ref x; xs) {
            printf("foreach x.i = %d\n", x[0].i);
            assert(x[0].i == 0);
        }
        printf("loop done\n");
    }
  assert(X37.k == 6);
}

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

struct S38 {
    __gshared int count;
    __gshared int postblit;

    this(int x) {
        printf("this(%d)\n", x);
        assert(this.x == 0);
        this.x = x;
        count++;
    }
    this(this) {
        printf("this(this) with %d\n", x);
        assert(x == 1 || x == 2);
        count++;
        postblit++;
    }
    ~this() {
        printf("~this(%d)\n", x);
        assert(x == 1 || x == 2);
        x = 0;
        count--;
    }
    int x;
}

S38 foo38() {
    auto s = S38(1);
    return s;
}

S38 bar38() {
    return S38(2);
}

void test38()
{
  {
    auto s1 = foo38();
    assert(S38.count == 1);
    assert(S38.postblit == 0);
  }
  assert(S38.count == 0);
  S38.postblit = 0;

  {
    auto s2 = bar38();
    assert(S38.count == 1);
    assert(S38.postblit == 0);
  }
  assert(S38.count == 0);
}


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

struct Foo39
{
    int x;
    this(int v){ x = v + 1; }
    void opAssign(int v){
        x = v + 3;
    }
}

void test39()
{
    int y = 5;
    Foo39 f = y;
    assert(f.x == 6);
    f = y;
    assert(f.x == 8);
//  f = Foo39(y);

}

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

bool approxEqual(float a, float b)
{
    return a < b ? b-a < .001 : a-b < .001;
}

struct Point {
    float x = 0, y = 0;
    const bool opEquals(const ref Point rhs)
    {
        return approxEqual(x, rhs.x) && approxEqual(y, rhs.y);
    }
}

struct Rectangle {
   Point leftBottom, rightTop;
}

void test40()
{
   Rectangle a, b;
   assert(a == b);
   a.leftBottom.x = 1e-8;
   assert(a == b);
   a.rightTop.y = 5;
   assert(a != b);
}

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

struct S41 {
   this(int) immutable {   }
}

void test41()
{
    auto s = new immutable S41(3);
    //writeln(typeid(typeof(s)));
    static assert(is(typeof(s) == immutable(S41)*));

    auto t = immutable S41(3);
    //writeln(typeid(typeof(t)));
    static assert(is(typeof(t) == immutable(S41)));
}

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

class C42 {
   this(int) immutable {
   }
}

void test42()
{
    static assert(!__traits(compiles, new C42(3)));
    //writeln(typeid(typeof(c)));
    //static assert(is(typeof(c) == immutable(C42)));

    auto d = new immutable(C42)(3);
    //writeln(typeid(typeof(d)));
    static assert(is(typeof(d) == immutable(C42)));
}

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

struct S43 {
    int i;
    int* p;
//  this(int i, int* t) immutable { this.i = i; p = t;  }
}

void test43()
{
    int i;
    assert(!__traits(compiles, immutable(S43)(3, &i)));
    immutable int j = 4;
    auto s = immutable(S43)(3, &j);
    //writeln(typeid(typeof(s)));
    static assert(is(typeof(s) == immutable(S43)));
}

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

struct S44 {
    int i;
    immutable(int)* p;
    this(int i, immutable(int)* t) immutable { this.i = i; this.p = t;  }
}

void test44()
{
    int i;
    assert(!__traits(compiles, immutable(S44)(3, &i)));
    immutable int j = 4;
    auto s = immutable(S44)(3, &j);
    //writeln(typeid(typeof(s)));
    static assert(is(typeof(s) == immutable(S44)));
}

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

class C45 {
    C45 next;
    this(int[] data) immutable {
        next = new immutable(C45)(data[1 .. $]);
    }
}

void test45()
{
}

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

struct SiberianHamster
{
   int rat = 813;
   this(string z) { }
}

void test46()
{
   SiberianHamster basil = "cybil";
   assert(basil.rat == 813);
}

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

struct Vec8741
{
    this(float x)
    {
        m[0] = x;
        m[1] = 58;
    }
    float[2] m;
    static Vec8741 zzz = Vec8741(7);
}

void test8741()
{
    assert(Vec8741.zzz.m[0] == 7);
    assert(Vec8741.zzz.m[1] == 58);
}

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

struct Segfault3984
{
    int a;
    this(int x){
        a = x;
    }
}

void test47()
{
    //static
    assert(Segfault3984(3).a == 3);
}

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

void test48()
{
    struct B {
        void foo()  {   }
    }
    B x = B.init;
}

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

struct Foo49 {
   int z;
   this(int a){z=a;}
}

void bar49(Foo49 a = Foo49(1))
{
    assert(a.z == 1);
}

void test49()
{
    bar49();
    bar49();
}

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

struct aStruct{
    int    m_Int;

    this(int a){
        m_Int = a;
    }
}

class aClass{
    void aFunc(aStruct a = aStruct(44))
    {
        assert(a.m_Int == 44);
    }
}

void test50()
{
    aClass a = new aClass();
    a.aFunc();
    a.aFunc();
}

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

int A51_a;

struct A51
{
    ~this() { ++A51_a; }
}

void test51()
{
  A51_a = 0; { while(0) A51 a;                      } assert(A51_a == 0);
  A51_a = 0; { if(0) A51 a;                         } assert(A51_a == 0);
  A51_a = 0; { if(1){} else A51 a;                  } assert(A51_a == 0);
  A51_a = 0; { for(;0;) A51 a;                      } assert(A51_a == 0);
  A51_a = 0; { if (1) { A51 a; }                    } assert(A51_a == 1);
  A51_a = 0; { if (1) A51 a;                        } assert(A51_a == 1);
  A51_a = 0; { if(0) {} else A51 a;                 } assert(A51_a == 1);
  A51_a = 0; { if (0) for(A51 a;;) {}               } assert(A51_a == 0);
  A51_a = 0; { if (0) for(;;) A51 a;                } assert(A51_a == 0);
  A51_a = 0; { do A51 a; while(0);                  } assert(A51_a == 1);
  A51_a = 0; { if (0) while(1) A51 a;               } assert(A51_a == 0);
  A51_a = 0; { try A51 a; catch(Error e) {}         } assert(A51_a == 1);
  A51_a = 0; { if (0) final switch(1) A51 a;        } assert(A51_a == 0); // should fail to build
//  A51_a = 0; { if (0) switch(1) { A51 a; default: } } assert(A51_a == 0);
  A51_a = 0; { if (0) switch(1) { default: A51 a; } } assert(A51_a == 0);
//  A51_a = 0; { if (1) switch(1) { A51 a; default: } } assert(A51_a == 1); // should be 0, right?
  A51_a = 0; { if (1) switch(1) { default: A51 a; } } assert(A51_a == 1);
//  A51_a = 0; { final switch(0) A51 a;               } assert(A51_a == 0);
  A51_a = 0; { A51 a; with(a) A51 b;                } assert(A51_a == 2);
}

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

string s52;

struct A52
{
    int m;
    this(this)
    {
        printf("this(this) %p\n", &this);
        s52 ~= 'a';
    }
    ~this()
    {
        printf("~this() %p\n", &this);
        s52 ~= 'b';
    }
    A52 copy()
    {
        s52 ~= 'c';
        A52 another = this;
        return another;
    }
}

void test52()
{
  {
    A52 a;
    A52 b = a.copy();
    printf("a: %p, b: %p\n", &a, &b);
  }
    printf("s = '%.*s'\n", cast(int)s52.length, s52.ptr);
    assert(s52 == "cabb");
}

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

struct A53 {
    invariant() {   }
    ~this() { }
    void opAssign(A53 a) {}
    int blah(A53 a) { return 0; }
}

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

struct S54
{
    int x = 1;

    int bar() { return x; }

    this(int i)
    {
        printf("ctor %p(%d)\n", &this, i);
        t ~= "a";
    }

    this(this)
    {
        printf("postblit %p\n", &this);
        t ~= "b";
    }

    ~this()
    {
        printf("dtor %p\n", &this);
        t ~= "c";
    }

    static string t;
}

void bar54(S54 s) { }

S54 abc54() { return S54(1); }

void test54()
{
    {   S54.t = null;
        S54 s = S54(1);
    }
    assert(S54.t == "ac");

    {   S54.t = null;
        S54 s = S54();
    }
    assert(S54.t == "c");

    {   S54.t = null;
        int b = 1 && (){ bar54(S54(1)); return 1;}();
    }
    assert(S54.t == "ac");

    {   S54.t = null;
        int b = 0 && (){ bar54(S54(1)); return 1;}();
    }
    assert(S54.t == "");

    {   S54.t = null;
        int b = 0 || (){ bar54(S54(1)); return 1;}();
    }
    assert(S54.t == "ac");

    {   S54.t = null;
        int b = 1 || (){ bar54(S54(1)); return 1;}();
    }
    assert(S54.t == "");

    {
    S54.t = null;
    { const S54 s = S54(1); }
        assert(S54.t == "ac");
    }
    {
        S54.t = null;
        abc54();
        assert(S54.t == "ac");
    }
    {
        S54.t = null;
        abc54().x += 1;
        assert(S54.t == "ac");
    }
}

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

void test55()
{
    S55 s;
    auto t = s.copy();
    assert(t.count == 1);   // (5)
}

struct S55
{
    int count;
    this(this) { ++count; }
    S55 copy() { return this; }
}

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

struct S56
{
    int x = 1;

    int bar() { return x; }

    this(int i)
    {
        printf("ctor %p(%d)\n", &this, i);
        t ~= "a";
    }

    this(this)
    {
        printf("postblit %p\n", &this);
        t ~= "b";
    }

    ~this()
    {
        printf("dtor %p\n", &this);
        t ~= "c";
    }

    static string t;
}

int foo56()
{
    throw new Throwable("hello");
    return 5;
}


void test56()
{
    int i;
    int j;
    try
    {
        j |= 1;
        i = S56(1).x + foo56() + 1;
        j |= 2;
    }
    catch (Throwable o)
    {
        printf("caught\n");
        j |= 4;
    }
    printf("i = %d, j = %d\n", i, j);
    assert(i == 0);
    assert(j == 5);
}

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

int dtor_cnt = 0;
struct S57
{
    int v;
    this(int n){ v = n; printf("S.ctor v=%d\n", v); }
    ~this(){ ++dtor_cnt; printf("S.dtor v=%d\n", v); }
    bool opCast(T:bool)(){ printf("S.cast v=%d\n", v); return true; }
}
S57 f(int n){ return S57(n); }

void test57()
{
    printf("----\n");
    dtor_cnt = 0;
    if (auto s = S57(10))
    {
        printf("ifbody\n");
    }
    else assert(0);
    assert(dtor_cnt == 1);

    printf("----\n");    //+
    dtor_cnt = 0;
    S57(1), S57(2);
    if (auto s = S57(10))
    {
        assert(dtor_cnt == 2);
        printf("ifbody\n");
    }
    else assert(0);
    assert(dtor_cnt == 3);  // +/

    printf("----\n");
    dtor_cnt = 0;
    try{
        if (auto s = S57(10))
        {
            printf("ifbody\n");
            throw new Exception("test");
        }
        else assert(0);
    }catch (Exception e){}
    assert(dtor_cnt == 1);



    printf("----\n");
    dtor_cnt = 0;
    if (auto s = f(10))
    {
        printf("ifbody\n");
    }
    else assert(0);
    assert(dtor_cnt == 1);

    printf("----\n");    //+
    dtor_cnt = 0;
    f(1), f(2);
    if (auto s = f(10))
    {
        assert(dtor_cnt == 2);
        printf("ifbody\n");
    }
    else assert(0);
    assert(dtor_cnt == 3);  // +/

    printf("----\n");
    dtor_cnt = 0;
    try{
        if (auto s = f(10))
        {
            printf("ifbody\n");
            throw new Exception("test");
        }
        else assert(0);
    }catch (Exception e){}
    assert(dtor_cnt == 1);




    printf("----\n");
    dtor_cnt = 0;
    if (S57(10))
    {
        assert(dtor_cnt == 1);
        printf("ifbody\n");
    }
    else assert(0);

    printf("----\n");
    dtor_cnt = 0;
    S57(1), S57(2);
    if (S57(10))
    {
        assert(dtor_cnt == 3);
        printf("ifbody\n");
    }
    else assert(0);

    printf("----\n");
    dtor_cnt = 0;
    try{
        if (auto s = S57(10))
        {
            printf("ifbody\n");
            throw new Exception("test");
        }
        else assert(0);
    }catch (Exception e){}
    assert(dtor_cnt == 1);



    printf("----\n");
    dtor_cnt = 0;
    if (f(10))
    {
        assert(dtor_cnt == 1);
        printf("ifbody\n");
    }
    else assert(0);

    printf("----\n");
    dtor_cnt = 0;
    f(1), f(2);
    if (f(10))
    {
        assert(dtor_cnt == 3);
        printf("ifbody\n");
    }
    else assert(0);

    printf("----\n");
    dtor_cnt = 0;
    try{
        if (auto s = f(10))
        {
            printf("ifbody\n");
            throw new Exception("test");
        }
        else assert(0);
    }catch (Exception e){}
    assert(dtor_cnt == 1);
}

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

struct foo5574a
{
    ~this() {}
}
class bar5574a
{
    foo5574a[1] frop;
}

struct foo5574b
{
    this(this){}
}
struct bar5574b
{
    foo5574b[1] frop;
}

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

int sdtor58 = 0;
S58* ps58;

struct S58
{
    @disable this(this);
    ~this(){ ++sdtor58; }
}

S58 makeS58()
{
    S58 s;
    ps58 = &s;
    return s;
}

void test58()
{
    auto s1 = makeS58();
    assert(ps58 == &s1);
    assert(sdtor58 == 0);
}

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

struct C59
{
    void oops()
    {
        throw new Throwable("Oops!");
    }

    ~this()
    {
    }
}

void foo59()
{
    C59().oops();
//  auto c = C(); c.oops();
}


void test59()
{
    int i = 0;
    try
        foo59();
    catch (Throwable)
    {   i = 1;
    }
    assert(i == 1);
}

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

void test5737()
{
    static struct S
    {
        static int destroyed;
        static int copied;

        this(this)
        {
            copied++;
        }

        ~this()
        {
            destroyed++;
        }
    }

    static S s;

    ref S foo()
    {
        return s;
    }

    {
        auto s2 = foo();
    }

    assert(S.copied == 1); // fail, s2 was not copied;
    assert(S.destroyed == 1); // ok, s2 was destroyed
}

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

void test6119()
{
    int postblit = 0;
    int dtor = 0;

    struct Test
    {
        this(this) { ++postblit; }
        ~this()    { ++dtor; }
    }

    void takesVal(Test x) {}
    ref Test returnsRef(ref Test x) { return x; }

    void f(ref Test x) { takesVal( x ); }

    Test x;

    postblit = dtor = 0;
    takesVal(returnsRef(x));
    assert(postblit == 1);
    assert(dtor == 1);

    postblit = dtor = 0;
    f(x);
    assert(postblit == 1);
    assert(dtor == 1);
}

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

struct Foo6364
{
    int state = 1;

    ~this()
    {
        state = 0;
    }
}

void testfoo6364()
{
    static Foo6364 foo;
    printf("%d\n", foo.state);
    assert(foo.state == 1);
}

void test6364()
{
    testfoo6364();
    testfoo6364();
}

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

struct S6499
{
    string m = "<not set>";

    this(string s)
    {
        m = s;
        printf("Constructor - %.*s\n", cast(int)m.length, m.ptr);
        if (m == "foo") { ++sdtor; assert(sdtor == 1); }
        if (m == "bar") { ++sdtor; assert(sdtor == 2); }
    }
    this(this)
    {
        printf("Postblit    - %.*s\n", cast(int)m.length, m.ptr);
        assert(0);
    }
    ~this()
    {
        printf("Destructor  - %.*s\n", cast(int)m.length, m.ptr);
        if (m == "bar") { assert(sdtor == 2); --sdtor; }
        if (m == "foo") { assert(sdtor == 1); --sdtor; }
    }
    S6499 bar()     { return S6499("bar"); }
    S6499 baz()()   { return S6499("baz"); }
}

void test6499()
{
    S6499 foo() { return S6499("foo"); }

    {
        sdtor = 0;
        scope(exit) assert(sdtor == 0);
        foo().bar();
    }
    {
        sdtor = 0;
        scope(exit) assert(sdtor == 0);
        foo().baz();
    }
}

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

template isImplicitlyConvertible(From, To)
{
    enum bool isImplicitlyConvertible = is(typeof({
                        void fun(ref From v) {
                            void gun(To) {}
                            gun(v);
                        }
                    }()));
}

void test60()
{
    static struct X1
    {
        void* ptr;
        this(this){}
    }
    static struct S1
    {
        X1 x;
    }

    static struct X2
    {
        int ptr;
        this(this){}
    }
    static struct S2
    {
        X2 x;
    }

    {
              S1  ms;
              S1  ms2 = ms; // mutable to mutable
        const(S1) cs2 = ms; // mutable to const                         // NG -> OK
    }
    {
        const(S1) cs;
        static assert(!__traits(compiles,{                              // NG -> OK
              S1 ms2 = cs;  // field has reference, then const to mutable is invalid
        }));
        const(S1) cs2 = cs; // const to const                           // NG -> OK
    }
    static assert( isImplicitlyConvertible!(      S1 ,       S1 ) );
    static assert( isImplicitlyConvertible!(      S1 , const(S1)) );    // NG -> OK
    static assert(!isImplicitlyConvertible!(const(S1),       S1 ) );
    static assert( isImplicitlyConvertible!(const(S1), const(S1)) );    // NG -> OK


    {
              S2  ms;
              S2  ms2 = ms; // mutable to mutable
        const(S2) cs2 = ms; // mutable to const                         // NG -> OK
    }
    {
        const(S2) cs;
              S2  ms2 = cs; // all fields are value, then const to mutable is OK
        const(S2) cs2 = cs; // const to const                           // NG -> OK
    }

    static assert( isImplicitlyConvertible!(      S2 ,       S2 ) );
    static assert( isImplicitlyConvertible!(      S2 , const(S2)) );    // NG -> OK
    static assert( isImplicitlyConvertible!(const(S2),       S2 ) );
    static assert( isImplicitlyConvertible!(const(S2), const(S2)) );    // NG -> OK
}

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

struct A4316
{
    this(this) @safe { }
}

@safe void test4316()
{
    A4316 a;
    auto b = a; // Error: safe function 'main' cannot call system function'__cpctor'
}

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

struct F6177
{
    ~this()    {}
}

struct G6177
{
    this(F6177[] p...) {}
}

void test6177()
{
    F6177 c;
    auto g = G6177(c);
}


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

struct S6470
{
    static int spblit;

    this(this){ ++spblit; }
}

void test6470()
{
    S6470[] a1;
    S6470[] a2;
    a1.length = 3;
    a2.length = 3;
    a1[] = a2[];
    assert(S6470.spblit == 3);

    S6470 s;

    S6470[] a3;
    a3.length = 3;
    a3 = [s, s, s];
    assert(S6470.spblit == 6);

    void func(S6470[] a){}
    func([s, s, s]);
    assert(S6470.spblit == 9);
}

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

struct S6636
{
    ~this()
    {
        ++sdtor;
    }
}

void func6636(S6636[3] sa) {}

void test6636()
{
    sdtor = 0;

    S6636[3] sa;
    func6636(sa);
    assert(sdtor == 3);
}

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

struct S6637
{
    static int spblit;

    this(this){ ++spblit; }
}

void test6637()
{
    void func(S6637[3] sa){}

    S6637[3] sa;
    func(sa);
    assert(S6637.spblit == 3);
}

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

struct S7353
{
    static uint ci = 0;
    uint i;

    this(int x) { i = ci++; /*writeln("new: ", i);*/ }
    this(this)  { i = ci++; /*writeln("copy ", i);*/ }
    ~this()     {           /*writeln("del ", i);*/ }

    S7353 save1() // produces 2 copies in total
    {
        S7353 s = this;
        return s;
    }
    auto save2() // produces 3 copies in total
    {
        S7353 s = this;
        return s;
        pragma(msg, typeof(return));
    }
}
void test7353()
{
    {
        auto s = S7353(1), t = S7353(1);
        t = s.save1();
        assert(S7353.ci == 3);
    }
    S7353.ci = 0; //writeln("-");
    {
        auto s = S7353(1), t = S7353(1);
        t = s.save2();
        assert(S7353.ci == 3);
    }
}

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

struct S8036a
{
    ~this() {}
}
struct S8036b // or class
{
    S8036a[0] s;
}

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

struct S61
{
    this(long length)
    {
        this.length = length;
    }

    long length;
}


const(S61) copy(const S61 s)
{
    return s;
}


void test61()
{
    S61 t = S61(42);
    const S61 u = t;

    assert(t == u);
    assert(copy(t) == u);
    assert(t == copy(u));
}

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

void test7506()
{
    static struct S
    {
        static uint ci = 0;
        static uint di = 0;
        uint i;

        this(int x) { i = ci++; /*writeln("new: ", i);*/ }
        this(this)  { i = ci++; /*writeln("copy ", i);*/ }
        ~this()     { ++di;     /*writeln("del: ", i);*/ }

        S save3()
        {
            return this;
        }
    }

    {
        auto s = S(1), t = S(1);
        assert(S.ci == 2);
        t = s.save3();
        assert(S.ci == 3);  // line 23
    }
    assert(S.di == 3);
}

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

struct S7516
{
    int val;

    this(int n) { val = n; }
    this(this) { val *= 3; }
}

// CondExp on return statement
void test7516a()
{
    alias S = S7516;
    S s1 = S(1);
    S s2 = S(2);

    S foo(bool f) { return f ?  s1  :  s2;  }
    S hoo(bool f) { return f ? S(1) : S(2); }
    S bar(bool f) { return f ?  s1  : S(2); }
    S baz(bool f) { return f ? S(1) :  s2;  }

    auto r1 = foo(true);    assert(r1.val == 3);
    auto r2 = foo(false);   assert(r2.val == 6);
    auto r3 = hoo(true);    assert(r3.val == 1);
    auto r4 = hoo(false);   assert(r4.val == 2);
    auto r5 = bar(true);    assert(r5.val == 3);
    auto r6 = bar(false);   assert(r6.val == 2);
    auto r7 = baz(true);    assert(r7.val == 1);
    auto r8 = baz(false);   assert(r8.val == 6);
}

// CondExp on function argument
void test7516b()
{
    alias S = S7516;
    S s1 = S(1);
    S s2 = S(2);
    S func(S s) { return s; }

    S foo(bool f) { return func(f ?  s1  :  s2 ); }
    S hoo(bool f) { return func(f ? S(1) : S(2)); }
    S bar(bool f) { return func(f ?  s1  : S(2)); }
    S baz(bool f) { return func(f ? S(1) :  s2 ); }

    auto r1 = foo(true);    assert(r1.val == 3 * 3);
    auto r2 = foo(false);   assert(r2.val == 6 * 3);
    auto r3 = hoo(true);    assert(r3.val == 1 * 3);
    auto r4 = hoo(false);   assert(r4.val == 2 * 3);
    auto r5 = bar(true);    assert(r5.val == 3 * 3);
    auto r6 = bar(false);   assert(r6.val == 2 * 3);
    auto r7 = baz(true);    assert(r7.val == 1 * 3);
    auto r8 = baz(false);   assert(r8.val == 6 * 3);
}

// CondExp on array literal
void test7516c()
{
    alias S = S7516;
    S s1 = S(1);
    S s2 = S(2);

    S[] foo(bool f) { return [f ?  s1  :  s2 ]; }
    S[] hoo(bool f) { return [f ? S(1) : S(2)]; }
    S[] bar(bool f) { return [f ?  s1  : S(2)]; }
    S[] baz(bool f) { return [f ? S(1) :  s2 ]; }

    auto r1 = foo(true);    assert(r1[0].val == 3);
    auto r2 = foo(false);   assert(r2[0].val == 6);
    auto r3 = hoo(true);    assert(r3[0].val == 1);
    auto r4 = hoo(false);   assert(r4[0].val == 2);
    auto r5 = bar(true);    assert(r5[0].val == 3);
    auto r6 = bar(false);   assert(r6[0].val == 2);
    auto r7 = baz(true);    assert(r7[0].val == 1);
    auto r8 = baz(false);   assert(r8[0].val == 6);
}

// CondExp on rhs of cat assign
void test7516d()
{
    alias S = S7516;
    S s1 = S(1);
    S s2 = S(2);

    S[] foo(bool f) { S[] a; a ~= f ?  s1  :  s2 ; return a; }
    S[] hoo(bool f) { S[] a; a ~= f ? S(1) : S(2); return a; }
    S[] bar(bool f) { S[] a; a ~= f ?  s1  : S(2); return a; }
    S[] baz(bool f) { S[] a; a ~= f ? S(1) :  s2 ; return a; }

    auto r1 = foo(true);    assert(r1[0].val == 3);
    auto r2 = foo(false);   assert(r2[0].val == 6);
    auto r3 = hoo(true);    assert(r3[0].val == 1);
    auto r4 = hoo(false);   assert(r4[0].val == 2);
    auto r5 = bar(true);    assert(r5[0].val == 3);
    auto r6 = bar(false);   assert(r6[0].val == 2);
    auto r7 = baz(true);    assert(r7[0].val == 1);
    auto r8 = baz(false);   assert(r8[0].val == 6);
}

// CondExp on struct literal element
void test7516e()
{
    alias S = S7516;
    S s1 = S(1);
    S s2 = S(2);
    struct X { S s; }

    X foo(bool f) { return X(f ?  s1  :  s2 ); }
    X hoo(bool f) { return X(f ? S(1) : S(2)); }
    X bar(bool f) { return X(f ?  s1  : S(2)); }
    X baz(bool f) { return X(f ? S(1) :  s2 ); }

    auto r1 = foo(true);    assert(r1.s.val == 3);
    auto r2 = foo(false);   assert(r2.s.val == 6);
    auto r3 = hoo(true);    assert(r3.s.val == 1);
    auto r4 = hoo(false);   assert(r4.s.val == 2);
    auto r5 = bar(true);    assert(r5.s.val == 3);
    auto r6 = bar(false);   assert(r6.s.val == 2);
    auto r7 = baz(true);    assert(r7.s.val == 1);
    auto r8 = baz(false);   assert(r8.s.val == 6);
}

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

void test7530()
{
    static struct S
    {
        int val;

        this(int n) { val = n; }
        this(this) { val *= 3; }
    }

    S[] sa = new S[](1);
    sa[0].val = 1;
    S foo()
    {
        return sa[0];
    }
    auto s = foo();
    assert(s.val == 3);
}

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

struct S62
{
    this(int length)
    {
        _length = length;
    }

    int opBinary(string op)(in S62 rhs) const
        if(op == "-")
    {
        return this.length - rhs.length;
    }

    @property int length() const
    {
        return _length;
    }

    invariant()
    {
        assert(_length == 1);
    }

    int _length  = 1;
}


void test62()
{
    immutable result = S62.init - S62.init;
}

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

void test7579a()
{
    static struct S
    {
        // postblit can also have no body because isn't called
        @disable this(this) { assert(0); }
    }

    @property S fs() { return S(); }
    @property S[3] fsa() { return [S(), S(), S()]; }

    S s0;
    S s1 = S();
    static assert(!__traits(compiles, { S s2 = s1; }));         // OK
    S s2 = fs;
    static assert(!__traits(compiles, { s2 = s1; }));           // OK

    // static array
    S[3] sa0;
    S[3] sa1 = [S(), S(), S()];
    static assert(!__traits(compiles, { S[3] sa2 = sa1; }));    // fixed
    S[3] sa2 = fsa;
    static assert(!__traits(compiles, { sa2 = sa1; }));         // fixed
    sa2 = [S(), S(), S()];
    sa2 = fsa;

    S[] da1 = new S[3];
    S[] da2 = new S[3];
    static assert(!__traits(compiles, { da2[] = da1[]; }));     // fixed

    // concatenation and appending
    static assert(!__traits(compiles, { da1 ~= s1; }));         // fixed
    static assert(!__traits(compiles, { da1 ~= S(); }));
    static assert(!__traits(compiles, { da1 ~= fsa; }));
    static assert(!__traits(compiles, { da1 ~= fsa[]; }));
    static assert(!__traits(compiles, { da1 = da1 ~ s1; }));    // fixed
    static assert(!__traits(compiles, { da1 = s1 ~ da1; }));    // fixed
    static assert(!__traits(compiles, { da1 = da1 ~ S(); }));
    static assert(!__traits(compiles, { da1 = da1 ~ fsa; }));
    static assert(!__traits(compiles, { da1 = da1 ~ da; }));
}

void test7579b()
{
    static struct S
    {
        // postblit asserts in runtime
        this(this) { assert(0); }
    }

    @property S fs() { return S(); }
    @property S[3] fsa() { return [S(), S(), S()]; }

    S s0;
    S s1 = S();
    S s2 = fs;

    // static array
    S[3] sa0;
    S[3] sa1 = [S(), S(), S()];
    S[3] sa2 = fsa;
    sa2 = [S(), S(), S()];
    sa2 = fsa;

    S[] da1 = new S[3];
    S[] da2 = new S[3];

    // concatenation and appending always run postblits
}

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

struct S8335
{
    static int postblit;

    int i;
    this(this) { ++postblit; }
}

void f8335(ref S8335[3] arr)
{
    arr[0].i = 7;
}

void g8335(lazy S8335[3] arr)
{
    assert(S8335.postblit == 0);
    auto x = arr;
    assert(S8335.postblit == 3);
}

void h8335(lazy S8335 s)
{
    assert(S8335.postblit == 0);
    auto x = s;
    assert(S8335.postblit == 1);
}

void test8335()
{
    S8335[3] arr;
    f8335(arr);
    assert(S8335.postblit == 0);
    assert(arr[0].i == 7);

    g8335(arr);
    assert(S8335.postblit == 3);

    S8335.postblit = 0;
    S8335 s;
    h8335(s);
    assert(S8335.postblit == 1);
}

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

void test8356()
{
    static struct S
    {
        @disable this(this) { assert(0); }
    }

    S s;
    S[3] sa;

  static assert(!__traits(compiles, {
    S fs() { return s; }
  }));

  static assert(!__traits(compiles, {
    S[3] fsa() { return sa; }
  }));
}

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

T func8475(T)(T x) @safe pure
{
    return T();
}

template X8475(bool something)
{
    struct XY
    {
        this(this) @safe pure {}
        void func(XY x) @safe pure
        {
            XY y = x; //Error: see below
            func8475(x);
            func8475(y);
        }
    }
}

alias X8475!(true).XY Xtrue;

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

struct Foo9320 {
    real x;

    this(real x) {
        this.x = x;
    }

    Foo9320 opBinary(string op)(Foo9320 other) {
        return Foo9320(mixin("x" ~ op ~ "other.x"));
    }
}

Foo9320 test9320(Foo9320 a, Foo9320 b, Foo9320 c) {
    return (a + b) / (a * b) - c;
}

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

struct Test9386
{
    string name;
    static char[25] op;
    static size_t i;

    static @property string sop() { return cast(string)op[0..i]; }

    this(string name)
    {
        this.name = name;
        printf("Created %.*s...\n", cast(int)name.length, name.ptr);
        assert(i + 1 < op.length);
        op[i++] = 'a';
    }

    this(this)
    {
        printf("Copied %.*s...\n", cast(int)name.length, name.ptr);
        assert(i + 1 < op.length);
        op[i++] = 'b';
    }

    ~this()
    {
        printf("Deleted %.*s\n", cast(int)name.length, name.ptr);
        assert(i + 1 < op.length);
        op[i++] = 'c';
    }

    const int opCmp(ref const Test9386 t)
    {
        return op[0] - t.op[0];
    }
}

void test9386()
{
    {
        Test9386.op[] = 0;
        Test9386.i = 0;

        Test9386[] tests =
            [ Test9386("one"),
              Test9386("two"),
              Test9386("three"),
              Test9386("four") ];

        assert(Test9386.sop == "aaaa");
        Test9386.op[] = 0;
        Test9386.i = 0;

        printf("----\n");
        foreach (Test9386 test; tests)
        {
            printf("\tForeach %.*s\n", cast(int)test.name.length, test.name.ptr);
            Test9386.op[Test9386.i++] = 'x';
        }

        assert(Test9386.sop == "bxcbxcbxcbxc");
        Test9386.op[] = 0;
        Test9386.i = 0;

        printf("----\n");
        foreach (ref Test9386 test; tests)
        {
            printf("\tForeach %.*s\n", cast(int)test.name.length, test.name.ptr);
            Test9386.op[Test9386.i++] = 'x';
        }
        assert(Test9386.sop == "xxxx");
    }
    printf("====\n");
    {
        Test9386.op[] = 0;
        Test9386.i = 0;

        Test9386[Test9386] tests =
            [ Test9386("1") : Test9386("one"),
              Test9386("2") : Test9386("two"),
              Test9386("3") : Test9386("three"),
              Test9386("4") : Test9386("four") ];

        Test9386.op[] = 0;
        Test9386.i = 0;

        printf("----\n");
        foreach (Test9386 k, Test9386 v; tests)
        {
            printf("\tForeach %.*s : %.*s\n", cast(int)k.name.length, k.name.ptr,
                                              cast(int)v.name.length, v.name.ptr);
            Test9386.op[Test9386.i++] = 'x';
        }

        assert(Test9386.sop == "bbxccbbxccbbxccbbxcc");
        Test9386.op[] = 0;
        Test9386.i = 0;

        printf("----\n");
        foreach (Test9386 k, ref Test9386 v; tests)
        {
            printf("\tForeach %.*s : %.*s\n", cast(int)k.name.length, k.name.ptr,
                                              cast(int)v.name.length, v.name.ptr);
            Test9386.op[Test9386.i++] = 'x';
        }
        assert(Test9386.sop == "bxcbxcbxcbxc");
        Test9386.op[] = 0;
        Test9386.i = 0;
    }
}

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

auto x9441 = X9441(0.123);

struct X9441
{
    int a;
    this(double x) { a = cast(int)(x * 100); }
}

void test9441()
{
    assert(x9441.a == 12);
}

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

struct Payload
{
    size_t _capacity; //Comment me
    int[] _pay;       //Comment me

    size_t insertBack(Data d)
    {
        immutable newLen   = _pay.length + 3;
        _pay.length = newLen;
        _pay = _pay[0 .. newLen]; //Comment me
        return 3;
    }
}

struct Impl
{
    Payload _payload;
    size_t _count;
}

struct Data
{
    Impl* _store;

    this(int i)
    {
        _store = new Impl;
        _store._payload = Payload.init;
    }

    ~this()
    {
        printf("%zd\n", _store._count);
        --_store._count;
    }
}


void test9720()
{
    auto a = Data(1);
    auto b = Data(1);
    a._store._payload.insertBack(b); //Fails
}

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

struct S9899
{
    @safe pure nothrow ~this() {}
}

struct MemberS9899
{
    S9899 s;
}

void test9899() @safe pure nothrow
{
    MemberS9899 s; // 11
}

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

void test9907()
{
    static struct SX(bool hasCtor, bool hasDtor)
    {
        int i;
        static size_t assign;
        static size_t dtor;

        static if (hasCtor)
        {
            this(int i) { this.i = i; }
        }

        void opAssign(SX rhs)
        {
            printf("%08zX(%d) from Rvalue %08zX(%d)\n", cast(size_t)&this.i, this.i, cast(size_t)&rhs.i, rhs.i);
            ++assign;
        }

        void opAssign(ref SX rhs)
        {
            printf("%08zX(%d) from Lvalue %08zX(%d)\n", cast(size_t)&this.i, this.i, cast(size_t)&rhs.i, rhs.i);
            assert(0);
        }

        static if (hasDtor)
        {
            ~this()
            {
                printf("destroying %08zX(%d)\n", cast(size_t)&this.i, this.i);
                ++dtor;
            }
        }
    }

    S test(S)(int i)
    {
        return S(i);
    }

    foreach (hasCtor; TypeTuple!(false, true))
    foreach (hasDtor; TypeTuple!(false, true))
    {
        alias S = SX!(hasCtor, hasDtor);
        alias test!S foo;

        printf("----\n");
        auto s = S(1);

        // Assignment from two kinds of rvalues
        assert(S.assign == 0);
        s = foo(2);
        static if (hasDtor) assert(S.dtor == 1);
        assert(S.assign == 1);
        s = S(3);
        assert(S.assign == 2);
        static if (hasDtor) assert(S.dtor == 2);
    }
    printf("----\n");
}

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

struct S9985
{
    ubyte* b;
    ubyte[128] buf;
    this(this) { assert(0); }

    static void* ptr;
}
auto ref makeS9985() @system
{
    S9985 s;
    s.b = s.buf.ptr;
    S9985.ptr = &s;
    return s;
}
void test9985()
{
    S9985 s = makeS9985();
    assert(S9985.ptr == &s);    // NRVO

    static const int n = 1;
    static auto ref retN()
    {
        return n;
    }
    auto p = &(retN());        // OK
    assert(p == &n);
    alias pure nothrow @nogc @safe ref const(int) F1();
    static assert(is(typeof(retN) == F1));

    enum const(int) x = 1;
    static auto ref retX()
    {
        return x;
    }
    static assert(!__traits(compiles, { auto q = &(retX()); }));
    alias pure nothrow @nogc @safe const(int) F2();
    static assert(is(typeof(retX) == F2));
}

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

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

void delegate() dg17457;

struct S17457 {
    ulong[10] data;

    this(int seconds) {
        dg17457 = &mfunc;
    }
    @disable this(this);
    void mfunc() {}
}

auto foo17457() {
    pragma(inline, false);
    return S17457(18);
}

void test17457()
{
    auto x = foo17457();
    //printf("%p vs %p\n", &x, dg17457.ptr);
    assert(&x == dg17457.ptr);
}

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

void test9994()
{
    static struct S
    {
        static int dtor;
        ~this() { ++dtor; }
    }

    S s;
    static assert( __traits(compiles, s.opAssign(s)));
    static assert(!__traits(compiles, s.__postblit()));

    assert(S.dtor == 0);
    s = s;
    assert(S.dtor == 1);
}

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

struct S10053A
{
    pure ~this() {}
}

struct S10053B
{
    S10053A sa;
    ~this() {}
}

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

void test10055a()
{
    static struct SX { pure nothrow @safe ~this() {} }
    static struct SY { pure nothrow @safe ~this() {} }
    static struct SZ {           @disable ~this() {} }

    // function to check merge result of the dtor attributes
    static void check(S)() { S s; }

    static struct S1 {                                             }
    static struct S2 {                                  ~this() {} }
    static struct SA { SX sx; SY sy;                               }
    static struct SB { SX sx; SY sy; pure nothrow @safe ~this() {} }
    static struct SC { SX sx; SY sy;      nothrow @safe ~this() {} }
    static struct SD { SX sx; SY sy; pure         @safe ~this() {} }
    static struct SE { SX sx; SY sy; pure nothrow       ~this() {} }
    static struct SF { SX sx; SY sy;              @safe ~this() {} }
    static struct SG { SX sx; SY sy;      nothrow       ~this() {} }
    static struct SH { SX sx; SY sy; pure               ~this() {} }
    static struct SI { SX sx; SY sy;                    ~this() {} }
    static assert(is( typeof(&check!S1) == void function() pure nothrow @nogc @safe ));
    static assert(is( typeof(&check!S2) == void function()                    ));
    static assert(is( typeof(&check!SA) == void function() pure nothrow @safe ));
    static assert(is( typeof(&check!SB) == void function() pure nothrow @safe ));
    static assert(is( typeof(&check!SC) == void function()      nothrow @safe ));
    static assert(is( typeof(&check!SD) == void function() pure         @safe ));
    static assert(is( typeof(&check!SE) == void function() pure nothrow       ));
    static assert(is( typeof(&check!SF) == void function()              @safe ));
    static assert(is( typeof(&check!SG) == void function()      nothrow       ));
    static assert(is( typeof(&check!SH) == void function() pure               ));
    static assert(is( typeof(&check!SI) == void function()                    ));

    static struct S1x {                                             SZ sz; }
    static struct S2x {                                  ~this() {} SZ sz; }
    static struct SAx { SX sx; SY sy;                               SZ sz; }
    static struct SBx { SX sx; SY sy; pure nothrow @safe ~this() {} SZ sz; }
    static struct SCx { SX sx; SY sy;      nothrow @safe ~this() {} SZ sz; }
    static struct SDx { SX sx; SY sy; pure         @safe ~this() {} SZ sz; }
    static struct SEx { SX sx; SY sy; pure nothrow       ~this() {} SZ sz; }
    static struct SFx { SX sx; SY sy;              @safe ~this() {} SZ sz; }
    static struct SGx { SX sx; SY sy;      nothrow       ~this() {} SZ sz; }
    static struct SHx { SX sx; SY sy; pure               ~this() {} SZ sz; }
    static struct SIx { SX sx; SY sy;                    ~this() {} SZ sz; }
    foreach (Sx; TypeTuple!(S1x, S2x, SAx, SBx, SCx, SDx, SEx, SFx, SGx, SHx, SIx))
    {
        static assert(!__traits(compiles, &check!Sx));
    }
}

void test10055b()
{
    static struct SX { pure nothrow @safe this(this) {} }
    static struct SY { pure nothrow @safe this(this) {} }
    static struct SZ {           @disable this(this) {} }

    // function to check merge result of the postblit attributes
    static void check(S)() { S s; S s2 = s; }

    static struct S1 {                                               }
    static struct S2 {                                  this(this) {} }
    static struct SA { SX sx; SY sy;                                  }
    static struct SB { SX sx; SY sy; pure nothrow @safe this(this) {} }
    static struct SC { SX sx; SY sy;      nothrow @safe this(this) {} }
    static struct SD { SX sx; SY sy; pure         @safe this(this) {} }
    static struct SE { SX sx; SY sy; pure nothrow       this(this) {} }
    static struct SF { SX sx; SY sy;              @safe this(this) {} }
    static struct SG { SX sx; SY sy;      nothrow       this(this) {} }
    static struct SH { SX sx; SY sy; pure               this(this) {} }
    static struct SI { SX sx; SY sy;                    this(this) {} }
    static assert(is( typeof(&check!S1) == void function() pure nothrow @nogc @safe ));
    static assert(is( typeof(&check!S2) == void function()                    ));
    static assert(is( typeof(&check!SA) == void function() pure nothrow @safe ));
    static assert(is( typeof(&check!SB) == void function() pure nothrow @safe ));
    static assert(is( typeof(&check!SC) == void function()      nothrow @safe ));
    static assert(is( typeof(&check!SD) == void function() pure         @safe ));
    static assert(is( typeof(&check!SE) == void function() pure nothrow       ));
    static assert(is( typeof(&check!SF) == void function()              @safe ));
    static assert(is( typeof(&check!SG) == void function()      nothrow       ));
    static assert(is( typeof(&check!SH) == void function() pure               ));
    static assert(is( typeof(&check!SI) == void function()                    ));

    static struct S1x {                                                SZ sz; }
    static struct S2x {                                  this(this) {} SZ sz; }
    static struct SAx { SX sx; SY sy;                                  SZ sz; }
    static struct SBx { SX sx; SY sy; pure nothrow @safe this(this) {} SZ sz; }
    static struct SCx { SX sx; SY sy;      nothrow @safe this(this) {} SZ sz; }
    static struct SDx { SX sx; SY sy; pure         @safe this(this) {} SZ sz; }
    static struct SEx { SX sx; SY sy; pure nothrow       this(this) {} SZ sz; }
    static struct SFx { SX sx; SY sy;              @safe this(this) {} SZ sz; }
    static struct SGx { SX sx; SY sy;      nothrow       this(this) {} SZ sz; }
    static struct SHx { SX sx; SY sy; pure               this(this) {} SZ sz; }
    static struct SIx { SX sx; SY sy;                    this(this) {} SZ sz; }
    foreach (Sx; TypeTuple!(S1x, S2x, SAx, SBx, SCx, SDx, SEx, SFx, SGx, SHx, SIx))
    {
        static assert(!__traits(compiles, &check!Sx));
    }
}

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

struct S10160 { this(this) {} }

struct X10160a { S10160 s; const int x;     }
struct X10160b { S10160 s; enum int x = 1; }

void test10160()
{
    X10160a xa;
    X10160b xb;
}

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

void test10094()
{
    static void* p;
    const string[4] i2s = ()
    {
        string[4] tmp;
        p = &tmp[0];
        for (int i = 0; i < 4; ++i)
        {
            char[1] buf = [cast(char)('0' + i)];
            string str = buf.idup;
            tmp[i] = str;
        }
        return tmp; // NRVO should work
    }();
    assert(p == cast(void*)&i2s[0]);
    assert(i2s == ["0", "1", "2", "3"]);
}

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

// dtor || postblit
struct S10079a
{
    this(this) pure nothrow @safe {}
}
struct S10079b
{
    ~this() pure nothrow @safe {}
}
struct S10079c
{
    this(this) pure nothrow @safe {}
    ~this() pure nothrow @safe {}
}
struct S10079d
{
    this(this) {}
}
struct S10079e
{
    this(this) {}
    ~this() pure nothrow @safe {}
}

// memberwise
struct S10079f
{
    S10079a a;
    S10079b b;
    S10079c c;
    S10079d d;
    S10079e e;
}

void check10079(S)(ref S s) pure nothrow @safe { s = S(); }

// Assignment is pure, nothrow, and @safe in all cases.
static assert(__traits(compiles, &check10079!S10079a));
static assert(__traits(compiles, &check10079!S10079b));
static assert(__traits(compiles, &check10079!S10079c));
static assert(__traits(compiles, &check10079!S10079d));
static assert(__traits(compiles, &check10079!S10079e));
static assert(__traits(compiles, &check10079!S10079f));

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

void test10244()
{
    static struct Foo
    {
        string _str;
        long _num;

        template DeclareConstructor(string fieldName)
        {
            enum code =
                `this(typeof(_` ~ fieldName ~ `) value)` ~
                `{ this._` ~ fieldName ~ ` = value; }`;
            mixin(code);
        }

        mixin DeclareConstructor!"str";
        mixin DeclareConstructor!"num";
    }

    Foo value1 = Foo("D");
    Foo value2 = Foo(128);
    assert(value1._str == "D");
    assert(value2._num == 128);
}

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

struct Foo10694 { ~this() { } }

void test10694() pure
{
    static Foo10694 i1;
    __gshared Foo10694 i2;
    void foo() pure
    {
        static Foo10694 j1;
        __gshared Foo10694 j2;
    }
}

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

int global10787;

static ~this() nothrow pure @safe
{
    int* p;
    static assert(!__traits(compiles, ++p));
    static assert(!__traits(compiles, ++global10787));
}

shared static ~this() nothrow pure @safe
{
    int* p;
    static assert(!__traits(compiles, ++p));
    static assert(!__traits(compiles, ++global10787));
}

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

struct S10789
{
    static int count;
    int value;

    this(int)  { value = ++count; }
    ~this()    { --count; }
    this(this) { value = ++count; assert(value == 3); }
}

S10789 fun10789a(bool isCondExp)(bool cond)
{
    S10789 s1 = S10789(42), s2 = S10789(24);
    assert(S10789.count == 2);
    static if (isCondExp)
    {
        return cond ? s1 : s2;
    }
    else
    {
        if (cond)
            return s1;
        else
            return s2;
    }
}

auto fun10789b(bool isCondExp)(bool cond)
{
    S10789 s1 = S10789(42), s2 = S10789(24);
    assert(S10789.count == 2);
    static if (isCondExp)
    {
        return cond ? s1 : s2;
    }
    else
    {
        if (cond)
            return s1;
        else
            return s2;
    }
}

void test10789()
{
    foreach (fun; TypeTuple!(fun10789a, fun10789b))
    foreach (isCondExp; TypeTuple!(false, true))
    {
        {
            S10789 s = fun!isCondExp(true);
            assert(S10789.count == 1);
            assert(s.value == 3);
        }
        assert(S10789.count == 0);
        {
            S10789 s = fun!isCondExp(false);
            assert(S10789.count == 1);
            assert(s.value == 3);
        }
        assert(S10789.count == 0);
    }
}

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

int test10972()
{
    string result;

    struct A
    {
        this(this)  { result ~= "pA"; version(none) printf("copied A\n"); }
        ~this()     { result ~= "dA"; version(none) printf("destroy A\n"); }
    }
    struct B
    {
        this(this)
        {
            result ~= "(pB)"; version(none) printf("B says what?\n");
            throw new Exception("BOOM!");
        }
        ~this() { result ~= "dB"; version(none) printf("destroy B\n"); }
    }
    struct S
    {
        A a;
        B b;
    }

    result = "{";
    {
        S s1;
        result ~= "[";
        try
        {
            S s3 = s1;
            assert(0);
        }
        catch (Exception e)
        {}
        result ~= "]";
    }
    result ~= "}";
    assert(result == "{[pA(pB)dA]dBdA}", result);

    result = "{";
    {
        S s1;
        S s2;
        result ~= "[";
        try
        {
            s2 = s1;
            assert(0);
        }
        catch (Exception e)
        {}
        result ~= "]";
    }
    result ~= "}";
    assert(result == "{[pA(pB)dA]dBdAdBdA}", result);

    return 1;
}
static assert(test10972()); // CTFE

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

void test11134()
{
    void test(S)()
    {
        S s;
        S[2] sa;
        S[2][] dsa = [[S(), S()]];
        dsa.reserve(dsa.length + 2);    // avoid postblit calls by GC

        S.count = 0;
        dsa ~= sa;
        assert(S.count == 2);

        S.count = 0;
        dsa ~= [s, s];
        assert(S.count == 2);
    }

    static struct SS
    {
        static int count;
        this(this) { ++count; }
    }
    test!SS();

    struct NS
    {
        static int count;
        this(this) { ++count; }
    }
    test!NS();
}

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

struct S11197a
{
    this(bool) {}
    this(this) {}
}

struct S11197b
{
    //this(bool) {}
    this(this) {}
}

void test11197()
{
    S11197a[][string] aa1;
    aa1["test"] ~= S11197a.init;

    S11197b[][string] aa2;
    aa2["test"] ~= S11197b.init;
}

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

struct S7474 {
  float x;
  ~this() {}
}

void fun7474(T...)() { T x; }
void test7474() { fun7474!S7474(); }

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

struct A11286
{
    ~this() {}
}

A11286 getA11286() pure nothrow
{
    return A11286();
}

void test11286()
{
    A11286 a = getA11286();
}

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

struct Foo11505
{
    Bar11505 b;
}

struct Bar11505
{
    ~this() @safe { }
    void* p;
}

void test11505()
{
    Foo11505 f;
    f = Foo11505();
}

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

bool test12045()
{
    string dtor;
    void* ptr;

    struct S12045
    {
        string val;

        this(this) { assert(0); }
        ~this() { dtor ~= val; }
    }

    auto makeS12045(bool thrown)
    {
        auto s1 = S12045("1");
        auto s2 = S12045("2");
        ptr = &s1;

        if (thrown)
            throw new Exception("");

        return s1;  // NRVO
    }

    dtor = null, ptr = null;
    try
    {
        S12045 s = makeS12045(true);
        assert(0);
    }
    catch (Exception e)
    {
        assert(dtor == "21", dtor);
    }

    dtor = null, ptr = null;
    {
        S12045 s = makeS12045(false);
        assert(dtor == "2");
        if (!__ctfe) assert(ptr is &s);   // NRVO
    }
    assert(dtor == "21");

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

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

struct S12591(T)
{
    this(this)
    {}
}

struct Tuple12591(Types...)
{
    Types expand;
    this(Types values)
    {
        expand[] = values[];
    }
}

void test12591()
{
    alias T1 = Tuple12591!(S12591!int);
}

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

struct X12660
{
    this(this) @nogc {}
    ~this() @nogc {}
    void opAssign(X12660) @nogc {}
    @nogc invariant() {}
}
struct Y12660
{
    X12660 x;

    this(this) @nogc {}
    ~this() @nogc {}
    @nogc invariant() {}
}
struct Z12660
{
    Y12660 y;
}

class C12660
{
    this() @nogc {}
    @nogc invariant() {}
}

void test12660() @nogc
{
    X12660 x;
    x = x;

    Y12660 y = { x };
    y = y;

    Z12660 z = { y };
    z = z;
}

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

struct Foo12686
{
    static int count;

    invariant() { ++count; }

    @disable this(this);

    Foo12686 bar()
    {
        Foo12686 f;
        return f;
    }
}

void test12686()
{
    Foo12686 f;
    Foo12686 f2 = f.bar();
    version (unittest)
    { }
    else
        assert(Foo12686.count == 2);
}

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

struct S13089
{
    @disable this(this);    // non nothrow
    int val;
}

void* p13089;

S13089[1000] foo13089() nothrow
{
    typeof(return) data;
    p13089 = &data;
    return data;
}

void test13089() nothrow
{
    immutable data = foo13089();
    assert(p13089 == &data);
}

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

struct NoDtortest11763 {}

struct HasDtortest11763
{
    NoDtortest11763 func()
    {
        return NoDtortest11763();
    }
    ~this() {}
}

void test11763()
{
    HasDtortest11763().func();
}

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

struct Buf { }

struct Variant
{
    ~this() { }

    Buf get() { Buf b; return b; }
}

Variant value() { Variant v; return v; }

void test13303()
{
    value.get();
}

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

struct S13673
{
    string _name;
    ~this() {}
}

string name13673;

void test13673()
{
    S13673(name13673);
    S13673(name13673);
}

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

void test13586()
{
    static struct S {
        __gshared int count;
        ~this() { ++count; printf("~S\n"); }
    }

    static struct T {
        __gshared int count;
        ~this() { ++count; printf("~T\n"); }
    }

    static int foo(bool flag)
    {
        if (flag)
            throw new Exception("hello");
        return 1;
    }

    static void func(S s, int f, T t)
    {
        printf("func()\n");
    }

    static class C
    {
        this(S s, int f, T t)
        {
            printf("C()\n");
        }
    }

  {
    bool threw = false;
    try
    {
        func(S(), foo(true), T());
        printf("not reach\n");
    }
    catch (Exception e)
    {
        threw = true;
    }
    printf("threw %d S %d T %d\n", threw, S.count, T.count);
    assert(threw && S.count == 1 && T.count == 0);
    S.count = 0;
    T.count = 0;
  }
  {
    bool threw = false;
    try
    {
        func(S(), foo(false), T());
        printf("reached\n");
    }
    catch (Exception e)
    {
        threw = true;
    }
    printf("threw %d S %d T %d\n", threw, S.count, T.count);
    assert(!threw && S.count == 1 && T.count == 1);
    S.count = 0;
    T.count = 0;
  }
  {
    bool threw = false;
    try
    {
        new C(S(), foo(true), T());
        printf("not reach\n");
    }
    catch (Exception e)
    {
        threw = true;
    }
    printf("threw %d S %d T %d\n", threw, S.count, T.count);
    assert(threw && S.count == 1 && T.count == 0);
    S.count = 0;
    T.count = 0;
  }
}

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

T enforce14443(E : Throwable = Exception, T)(T value)
{
    if (!value)
        throw new E("Enforcement failed");
    return value;
}

struct RefCounted14443(T)
if (!is(T == class) && !(is(T == interface)))
{
    struct RefCountedStore
    {
        private struct Impl
        {
            T _payload;
            size_t _count;
        }

        private Impl* _store;

        private void initialize(A...)(auto ref A args)
        {
            import core.stdc.stdlib : malloc;

            // enforce is necessary
            _store = cast(Impl*) enforce14443(malloc(Impl.sizeof));

            // emulate 'emplace'
            static if (args.length > 0)
                _store._payload.tupleof = args;
            else
                _store._payload = T.init;

            _store._count = 1;
        }

        @property bool isInitialized() const nothrow @safe
        {
            return _store !is null;
        }

        void ensureInitialized()
        {
            if (!isInitialized) initialize();
        }

    }
    RefCountedStore _refCounted;

    this(A...)(auto ref A args) if (A.length > 0)
    {
        _refCounted.initialize(args);
    }

    this(this)
    {
        if (!_refCounted.isInitialized)
            return;
        ++_refCounted._store._count;
        //printf("RefCounted count = %d (inc)\n", _refCounted._store._count);
    }

    ~this()
    {
        if (!_refCounted.isInitialized)
            return;
        assert(_refCounted._store._count > 0);
        if (--_refCounted._store._count)
        {
            //printf("RefCounted count = %u\n", _refCounted._store._count);
            return;
        }

        import core.stdc.stdlib : free;
        free(_refCounted._store);
        _refCounted._store = null;
    }

    void opAssign(typeof(this) rhs) { assert(0); }
    void opAssign(T rhs) { assert(0); }

    @property ref T refCountedPayload()
    {
        _refCounted.ensureInitialized();
        return _refCounted._store._payload;
    }

    alias refCountedPayload this;
}

struct Path14443
{
    struct Payload
    {
        int p;
    }
    RefCounted14443!Payload data;
}

struct PathRange14443
{
    Path14443 path;
    size_t i;

    @property PathElement14443 front()
    {
        return PathElement14443(this, path.data.p);
    }
}

struct PathElement14443
{
    PathRange14443 range;

    this(PathRange14443 range, int)
    {
        this.range = range;
    }
}

void test14443()
{
    auto path = Path14443(RefCounted14443!(Path14443.Payload)(12));
    assert(path.data.p == 12);

    @property refCount() { return path.data._refCounted._store._count; }
    assert(refCount == 1);

    {
        auto _r = PathRange14443(path);
        assert(refCount == 2);
        // foreach
        {
            auto element = _r.front;
            assert(refCount == 3);  // fail with 2.067
        }
        assert(refCount == 2);
    }
    assert(refCount == 1);
}

/**********************************/
// postblit/dtor call on static array assignment
// https://issues.dlang.org/show_bug.cgi?id=13661
// https://issues.dlang.org/show_bug.cgi?id=14022
// https://issues.dlang.org/show_bug.cgi?id=14023

bool test13661()
{
    string op;

    struct S
    {
        char x = 'x';
        this(this) { op ~= x-0x20; }    // upper case
        ~this()    { op ~= x; }         // lower case

        ref auto opAssign(T)(T arg)
        {
            assert(0);
            return this;
        }
    }

    {
        S[2] a;

        a[0].x = 'a';
        a[1].x = 'b';
        a = a.init;
        assert(op == "ab");
        assert(a[0].x == 'x' && a[1].x == 'x');

        a[0].x = 'c';
        a[1].x = 'd';
        a = [S(), S()];   // equivalent a = a.init
        assert(op == "abcd");
        assert(a[0].x == 'x' && a[1].x == 'x');
    }
    assert(op == "abcdxx");

    return true;
}
bool test13661a()
{
    string op;

    struct S
    {
        char x = 'x';
        this(this) { op ~= x-0x20; }    // upper case
        ~this()    { op ~= x; }         // lower case
    }

    {
        S[3] sa = [S('a'), S('b'), S('c')];
        S[2] sb = sa[1..3];
        assert(sa == [S('a'), S('b'), S('c')]);
        assert(sb == [S('b'), S('c')]);
        sb[0].x = 'x';
        sb[1].x = 'y';
        assert(sa != [S('a'), S('x'), S('y')]); // OK <- incorrectly fails
        assert(sa == [S('a'), S('b'), S('c')]); // OK <- incorrectly fails
        assert(sb == [S('x'), S('y')]);
    }
    return true;
}
static assert(test13661());     // CTFE
static assert(test13661a());

bool test14022()
{
    string op;

    struct S
    {
        char x = 'x';
        this(this) { op ~= x-0x20; }    // upper case
        ~this()    { op ~= x; }         // lower case
    }

    S[2] makeSA() { return [S('p'), S('q')]; }

    struct T
    {
        S[2] sb;

        this(ref S[2] sa)
        {
            assert(op == "");
            this.sb = sa;   // TOKconstruct
            assert(op == "BC", op);
            assert(sb == [S('b'), S('c')]);
        }
        void test(ref S[2] sa)
        {
            this.sb = sa;    // dotvar: resolveSlice(newva)
            assert(op == "BxCy");
        }
    }

    op = null;
    {
        S[2] sa = [S('a'), S('b')];
        T t;    t.sb[0].x = 'x';
                t.sb[1].x = 'y';
        assert(op == "");
        t.sb = sa;
        assert(op == "AxBy");
        t.sb = makeSA();
        assert(op == "AxByab");
    }
    assert(op == "AxByabqpba");

    op = null;
    {
        S[3] sa = [S('a'), S('b'), S('c')];
        T t = T(sa[1..3]);
        t.sb[0].x = 'x';
        t.sb[1].x = 'y';
        assert(sa == [S('a'), S('b'), S('c')]);
        assert(t.sb == [S('x'), S('y')]);
        assert(op == "BC");
    }
    assert(op == "BCyxcba");

    op = null;
    {
        S[3] sx = [S('a'), S('b'), S('c')];
        T t;    t.sb[0].x = 'x';
                t.sb[1].x = 'y';
        t.test(sx[1..3]);
        assert(op == "BxCy");
        assert(t.sb == [S('b'), S('c')]);
    }
    assert(op == "BxCycbcba");

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

bool test14023()
{
    string op;

    struct S
    {
        char x = 'x';
        this(this) { op ~= x-0x20; }    // upper case
        ~this()    { op ~= x; }         // lower case
    }

    S[2] makeSA() { return [S('p'), S('q')]; }

    struct T
    {
        S[2][1] sb;
        this(ref S[2] sa)
        {
            assert(op == "");
            this.sb[0] = sa;   // TOKconstruct
            assert(sa    == [S('b'), S('c')]);
            assert(sb[0] == [S('b'), S('c')]);
        }
    }

    void test(ref S[2] sa)
    {
        S[2][] a;
        //a.length = 1; // will cause runtine AccessViolation
        a ~= (S[2]).init;
        assert(op == "");
        a[0] = sa;      // index <-- resolveSlice(newva)
        assert(op == "BxCx");
        assert(a[0] == [S('b'), S('c')]);
    }

    op = null;
    {
        S[3] sa = [S('a'), S('b'), S('c')];
        T t = T(sa[1..3]);
        t.sb[0][0].x = 'x';
        t.sb[0][1].x = 'y';
        assert(sa      != [S('a'), S('x'), S('y')]);    // OK <- incorrectly fails
        assert(sa      == [S('a'), S('b'), S('c')]);    // OK <- incorrectly fails
        assert(t.sb[0] == [S('x'), S('y')]);
    }

    op = null;
    {
        S[2] sa = [S('a'), S('b')];
        S[2][] a = [[S('x'), S('y')]];
        assert(op == "");
        a[0] = sa;
        assert(op == "AxBy");
        a[0] = makeSA();
        assert(op == "AxByab");
    }
    assert(op == "AxByabba");

    op = null;
    {
        S[3] sa = [S('a'), S('b'), S('c')];
        test(sa[1..3]);
        assert(op == "BxCx");
    }
    assert(op == "BxCxcba");

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

/************************************************/
// https://issues.dlang.org/show_bug.cgi?id=13669 - dtor call on static array variable

bool test13669()
{
    string dtor;

    struct S
    {
        char x = 'x';
        ~this() { dtor ~= x; }
    }

    { S[2] a; }
    assert(dtor == "xx");
    dtor = "";

    { S[2] a = [S('a'), S('b')]; }
    assert(dtor == "ba");   // reverse order. See also: TypeInfo_StaticArray.destroy()

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

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

__gshared bool b13095 = false;

void bar13095() { throw new Exception(""); }

struct S13095
{
    this(int) { printf("ctor %p\n", &this); bar13095(); }

    ~this() { b13095 = true; printf("dtor %p\n", &this); }
}

void test13095()
{
    try {
        S13095(0);
    } catch(Exception) { printf("catch\n"); }
    assert(!b13095);
}

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

void test14264()
{
    static int dtor;
    static struct Foo
    {
        ~this() { ++dtor; }
        T opCast(T:bool)() { return true; }
    }

    Foo makeFoo()
    {
        return Foo();
    }

    assert(dtor == 0);

    makeFoo();
    assert(dtor == 1);

    makeFoo;
    assert(dtor == 2);

    if (makeFoo()) {}
    assert(dtor == 3);

    if (makeFoo) {}
    assert(dtor == 4);
}

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

int test14686()
{
    string r;

    struct S
    {
        int n;
        this(this) { r ~= cast(char)('0' + n); }
    }

    S s1 = S(1);
    S s2 = S(2);
    S[] a1 = [S(1)];

    S[2] sa1 = [s1, s2];
    assert(r == "12", r);       // OK

    r = "";
    S[] a2 = a1 ~ s2;           // runtime concatenation
    assert(r == "12", r);       // OK <- NG only in CTFE

    r = "";
    S[2] sa2a = [s1] ~ s2;
    assert(r == "12", r);       // OK <- NG, s2 is not copied

    r = "";
    S[2] sa2b = s2 ~ [s1];
    assert(r == "21", r);       // OK <- NG, s2 is not copied

    r = "";
    S[3] sa3a = ([s1] ~ [s1]) ~ s2;
    assert(r == "112", r);      // OK <- NG, s2 is not copied

    r = "";
    S[3] sa3b = s2 ~ ([s1] ~ [s1]);
    assert(r == "211", r);      // OK <- NG, s2 is not copied

    return 1;
}
static assert(test14686());

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

int test14815()
{
    uint dtorCount;

    struct S
    {
        uint x;
        ~this() { ++dtorCount; }
    }

    S[2] sa1;
    sa1[0].x = 42;
    sa1 = (S[2]).init;      // S[2] <- rvalue
    assert(sa1[0].x == 0);
    assert(dtorCount == 2);

    S[2] sa2;
    sa2[0].x = 42;
    S[] da2 = sa2[];
    da2[] = (S[2]).init[];  // S[] <- rvalue slice
    assert(sa2[0].x == 0);
    assert(dtorCount == 4);

    S[2] sa3;
    S[2] sa4;
    sa3[0].x = 42;
    sa3 = sa4;              // S[2] <- lvalue
    assert(sa3[0].x == 0);
    assert(dtorCount == 6);

    S[2] sa5;
    S[] da4 = sa4[];
    da4[] = sa5[];          // S[] <- lvalue slice
    assert(sa4[0].x == 0);
    assert(dtorCount == 8);

    return 1;
}
static assert(test14815());

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

struct Elem {
    static string r;
    int x = -1;
    this(this) { r ~= 'p'; printf("POSTBLIT %d\n", x++); }
    ~this()    { r ~= 'd'; printf("DTOR %d\n"    , x++); }
}

struct Ctr {
    Elem[3] arr;
}

void test16197() {
    { auto p = Ctr(); }
    assert(Elem.r == "ddd");
}

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

int test14860()
{
    uint dtorCount;

    struct S
    {
        uint x;
        ~this() { ++dtorCount; }
    }

    S[] a = [S(42)];
    a[] = S();

    assert(a[0].x == 0);
    assert(dtorCount == 1);

    return 1;
}
static assert(test14860());

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

struct A14246 {
     int a = 3;
     static string s;
     this( int var ) { printf("A()\n"); a += var; s ~= "a"; }

     ~this() { printf("~A()\n"); s ~= "b"; }
}

struct B14246 {
     int i;
     A14246 a;

     this( int var ) {
         A14246.s ~= "c";
         a = A14246(var+1);
         throw new Exception("An exception");
     }
}

void test14246() {
    try {
         auto b = B14246(2);
    } catch( Exception ex ) {
        printf("Caught ex\n");
        A14246.s ~= "d";
    }
    assert(A14246.s == "cabd");
}

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

void test14696(int len = 2)
{
    string result;

    struct S
    {
        int n;

        void* get(void* p = null)
        {
            result ~= "get(" ~ cast(char)(n+'0') ~ ").";
            return null;
        }

        ~this()
        {
            result ~= "dtor(" ~ cast(char)(n+'0') ~ ").";
        }
    }

    S makeS(int n)
    {
        result ~= "makeS(" ~ cast(char)(n+'0') ~ ").";
        return S(n);
    }
    void foo(void* x, void* y = null)
    {
        result ~= "foo.";
    }
    void fooThrow(void* x, void* y = null)
    {
        result ~= "fooThrow.";
        throw new Exception("fail!");
    }

    void check(void delegate() dg, string r, string file = __FILE__, size_t line = __LINE__)
    {
        import core.exception;

        result = null;
        try { dg(); } catch (Exception e) {}
        if (result != r)
            throw new AssertError(result, file, line);
    }

    // temporary in condition
    check({ foo(len == 2 ?        makeS(1).get() : null); }, "makeS(1).get(1).foo.dtor(1).");
    check({ foo(len == 2 ? null : makeS(1).get()       ); }, "foo.");
    check({ foo(len != 2 ?        makeS(1).get() : null); }, "foo.");
    check({ foo(len != 2 ? null : makeS(1).get()       ); }, "makeS(1).get(1).foo.dtor(1).");

    // temporary in nesting conditions
    check({ foo(len >= 2 ?        (len == 2 ?        makeS(1).get() : null) : null); }, "makeS(1).get(1).foo.dtor(1).");
    check({ foo(len >= 2 ?        (len == 2 ? null : makeS(1).get()       ) : null); }, "foo.");
    check({ foo(len >= 2 ?        (len != 2 ?        makeS(1).get() : null) : null); }, "foo.");
    check({ foo(len >= 2 ?        (len != 2 ? null : makeS(1).get()       ) : null); }, "makeS(1).get(1).foo.dtor(1).");
    check({ foo(len >= 2 ? null : (len == 2 ?        makeS(1).get() : null)       ); }, "foo.");
    check({ foo(len >= 2 ? null : (len == 2 ? null : makeS(1).get()       )       ); }, "foo.");
    check({ foo(len >= 2 ? null : (len != 2 ?        makeS(1).get() : null)       ); }, "foo.");
    check({ foo(len >= 2 ? null : (len != 2 ? null : makeS(1).get()       )       ); }, "foo.");
    check({ foo(len >  2 ?        (len == 2 ?        makeS(1).get() : null) : null); }, "foo.");
    check({ foo(len >  2 ?        (len == 2 ? null : makeS(1).get()       ) : null); }, "foo.");
    check({ foo(len >  2 ?        (len != 2 ?        makeS(1).get() : null) : null); }, "foo.");
    check({ foo(len >  2 ?        (len != 2 ? null : makeS(1).get()       ) : null); }, "foo.");
    check({ foo(len >  2 ? null : (len == 2 ?        makeS(1).get() : null)       ); }, "makeS(1).get(1).foo.dtor(1).");
    check({ foo(len >  2 ? null : (len == 2 ? null : makeS(1).get()       )       ); }, "foo.");
    check({ foo(len >  2 ? null : (len != 2 ?        makeS(1).get() : null)       ); }, "foo.");
    check({ foo(len >  2 ? null : (len != 2 ? null : makeS(1).get()       )       ); }, "makeS(1).get(1).foo.dtor(1).");

    // temporary in condition and throwing callee
    // check({ fooThrow(len == 2 ?        makeS(1).get() : null); }, "makeS(1).get(1).fooThrow.dtor(1).");
    // check({ fooThrow(len == 2 ? null : makeS(1).get()       ); }, "fooThrow.");
    // check({ fooThrow(len != 2 ?        makeS(1).get() : null); }, "fooThrow.");
    // check({ fooThrow(len != 2 ? null : makeS(1).get()       ); }, "makeS(1).get(1).fooThrow.dtor(1).");

    // temporary in nesting condititions and throwing callee
    // check({ fooThrow(len >= 2 ?        (len == 2 ?        makeS(1).get() : null) : null); }, "makeS(1).get(1).fooThrow.dtor(1).");
    // check({ fooThrow(len >= 2 ?        (len == 2 ? null : makeS(1).get()       ) : null); }, "fooThrow.");
    // check({ fooThrow(len >= 2 ?        (len != 2 ?        makeS(1).get() : null) : null); }, "fooThrow.");
    // check({ fooThrow(len >= 2 ?        (len != 2 ? null : makeS(1).get()       ) : null); }, "makeS(1).get(1).fooThrow.dtor(1).");
    // check({ fooThrow(len >= 2 ? null : (len == 2 ?        makeS(1).get() : null)       ); }, "fooThrow.");
    // check({ fooThrow(len >= 2 ? null : (len == 2 ? null : makeS(1).get()       )       ); }, "fooThrow.");
    // check({ fooThrow(len >= 2 ? null : (len != 2 ?        makeS(1).get() : null)       ); }, "fooThrow.");
    // check({ fooThrow(len >= 2 ? null : (len != 2 ? null : makeS(1).get()       )       ); }, "fooThrow.");
    // check({ fooThrow(len >  2 ?        (len == 2 ?        makeS(1).get() : null) : null); }, "fooThrow.");
    // check({ fooThrow(len >  2 ?        (len == 2 ? null : makeS(1).get()       ) : null); }, "fooThrow.");
    // check({ fooThrow(len >  2 ?        (len != 2 ?        makeS(1).get() : null) : null); }, "fooThrow.");
    // check({ fooThrow(len >  2 ?        (len != 2 ? null : makeS(1).get()       ) : null); }, "fooThrow.");
    // check({ fooThrow(len >  2 ? null : (len == 2 ?        makeS(1).get() : null)       ); }, "makeS(1).get(1).fooThrow.dtor(1).");
    // check({ fooThrow(len >  2 ? null : (len == 2 ? null : makeS(1).get()       )       ); }, "fooThrow.");
    // check({ fooThrow(len >  2 ? null : (len != 2 ?        makeS(1).get() : null)       ); }, "fooThrow.");
    // check({ fooThrow(len >  2 ? null : (len != 2 ? null : makeS(1).get()       )       ); }, "makeS(1).get(1).fooThrow.dtor(1).");

    // temporaries in each conditions
    check({ foo(len == 2 ? makeS(1).get() : null, len == 2 ? makeS(2).get() : null); }, "makeS(1).get(1).makeS(2).get(2).foo.dtor(2).dtor(1).");
    check({ foo(len == 2 ? makeS(1).get() : null, len != 2 ? makeS(2).get() : null); }, "makeS(1).get(1).foo.dtor(1).");
    check({ foo(len != 2 ? makeS(1).get() : null, len == 2 ? makeS(2).get() : null); }, "makeS(2).get(2).foo.dtor(2).");
    check({ foo(len != 2 ? makeS(1).get() : null, len != 2 ? makeS(2).get() : null); }, "foo.");

    // nesting temporaries in conditions
    check({ foo(len == 2 ? makeS(1).get(len == 2 ? makeS(2).get() : null) : null); }, "makeS(1).makeS(2).get(2).get(1).foo.dtor(2).dtor(1).");
    check({ foo(len == 2 ? makeS(1).get(len != 2 ? makeS(2).get() : null) : null); }, "makeS(1).get(1).foo.dtor(1).");
    check({ foo(len != 2 ? makeS(1).get(len == 2 ? makeS(2).get() : null) : null); }, "foo.");
    check({ foo(len != 2 ? makeS(1).get(len != 2 ? makeS(2).get() : null) : null); }, "foo.");
    check({ foo(len == 2 ? makeS(makeS(2).n - 1).get() : null); }, "makeS(2).makeS(1).get(1).foo.dtor(1).dtor(2).");
    check({ foo(len != 2 ? makeS(makeS(2).n - 1).get() : null); }, "foo.");
}

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

int test14838() pure nothrow @safe
{
    int dtor;

    struct S14838(T)
    {
        ~this() { ++dtor; }
    }
    struct X14838
    {
              S14838!int ms;
        const S14838!int cs;

              S14838!int[2] ma;
        const S14838!int[2] ca;

              S14838!int[2][2] ma2x2;
        const S14838!int[2][2] ca2x2;

        // number of S14838 = 1*2 + 2*2 + 4*2 = 14
    }

    void test(Dg)(scope Dg code)
    {
        dtor = 0;
        code();
    }

    test(delegate{       S14838!int a; }); assert(dtor == 1);
    test(delegate{ const S14838!int a; }); assert(dtor == 1);

    test(delegate{       S14838!int[2] a; }); assert(dtor == 2);
    test(delegate{ const S14838!int[2] a; }); assert(dtor == 2);

    test(delegate{       S14838!int[2][2] a; }); assert(dtor == 4);
    test(delegate{ const S14838!int[2][2] a; }); assert(dtor == 4);

    test(delegate{       X14838 a; }); assert(dtor == 1 * 14);
    test(delegate{ const X14838 a; }); assert(dtor == 1 * 14);

    test(delegate{       X14838[2] a; }); assert(dtor == 2 * 14);
    test(delegate{ const X14838[2] a; }); assert(dtor == 2 * 14);

    test(delegate{       X14838[2][2] a; }); assert(dtor == 4 * 14);
    test(delegate{ const X14838[2][2] a; }); assert(dtor == 4 * 14);

    return 1;
}
static assert(test14838());

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

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

struct Biggy {
    ulong[50000] a;
    @disable this(this);
}

__gshared Biggy biggy;

void test14639() {
    biggy = Biggy.init;
}

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

struct S63
{
    private long p = 87;

    this(int x)
    {
        assert(p == 87);
        p += x;
    }

    ~this() { }

    this(this) { }

    void funky() { assert(p == 90); }

    static void tester()
    {
        S63(3).funky();
    }
}

void test63()
{
    S63.tester();
}

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

struct X64
{
    static int dtor;

    ~this() { ++dtor; }
}

struct S64
{
    int n;
    long[10] dummy;     // S64 needs to be passed by stack
}

S64 foo64()
{
    X64();
    return S64(1);
}

void test64()
{
    auto s = foo64();
    assert(X64.dtor == 1);
}

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

struct S65
{
    static string t;

    void bar(int a, int b)
    {
        t ~= "d";
    }
}

S65 foo65a()
{
    S65.t ~= "a";
    return S65();
}

int foo65b()
{
    S65.t ~= "b";
    return 1;
}

int foo65c()
{
    S65.t ~= "c";
    return 2;
}

void test65()
{
    import core.stdc.stdio;
    foo65a().bar(foo65b(), foo65c());
    printf("'%.*s'\n", cast(int)S65.t.length, S65.t.ptr);
    assert(S65.t == "abcd");
}

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

struct X15661
{
    ~this() {}
}

X15661 createX15661() { return X15661(); }

struct Y15661
{
    static int dtor;

    @disable this();
    @disable this(this);
    this(X15661 a1, X15661 a2) {}
    ~this() { ++dtor; }
}

struct Z15661
{
    this(int)
    {
        b = Y15661(createX15661(), createX15661());
        assert(Y15661.dtor == 0);
    }

    private Y15661 b;
}

void test15661()
{
    {
        auto v = Z15661(5);
        assert(Y15661.dtor == 0);
    }
    assert(Y15661.dtor == 1);
}

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

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

struct A18045
{
  nothrow:
    __gshared int r;
    int state;
    this(this) { printf("postblit: A(%d)\n", state); r += 1; }
    ~this() { printf("dtor: A(%d)\n", state); r *= 3; }
}

A18045 fun18045() nothrow
{
    __gshared a = A18045(42);
    return a;
}

void test18045() nothrow
{
    alias A = A18045;

    __gshared a = A(-42);
    if (fun18045() == a)
        assert(0);
    else
        assert(A.r == 3);

    A.r = 0;
    if (a == fun18045())
        assert(0);
    else
        assert(A.r == 3);
}

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

struct S66
{
    ~this() { }
}

nothrow void notthrow() { }

class C66
{
    S66 s;

    this() nothrow { notthrow(); }
}

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

struct Vector
{
    this(ubyte a)
    {
        pragma(inline, false);
        buf = a;
    }

    ~this()
    {
        pragma(inline, false);
        buf = 0;
    }

    ubyte buf;
}

int bar16652(ubyte* v)
{
    pragma(inline, true);
    assert(*v == 1);
    return 0;
}

void test16652()
{
    bar16652(&Vector(1).buf);
}


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

void test19676()
{
    static struct S
    {
        __gshared int count;
        ~this() { ++count; }
    }

    static S foo() { return S(); }

    static void test1()
    {
        cast(void)foo();
    }

    static void test2()
    {
        foo();
    }

    test1();
    assert(S.count == 1);
    test2();
    assert(S.count == 2);
}

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

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

__gshared bool dtor14078 = false;

struct S14078
{
    int n;

    void* get(void* p = null)
    {
        return null;
    }

    ~this()
    {
        //printf("dtor\n");
        dtor14078 = true;
    }
}

S14078 makeS14078(int n)
{
    return S14078(n);
}

void foo14078(void* x)
{
    throw new Exception("fail!");
}

void test(int len = 2)
{
    foo14078(makeS14078(1).get());
    // A temporary is allocated on stack for the
    // return value from makeS14078(1).
    // When foo14078 throws exception, it's dtor should be called
    // during unwinding stack, but it does not happen in Win64.
}

void test14078()
{
    try
    {
        test();
    } catch (Exception e) {}
    assert(dtor14078);   // fails!
}

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

void test67()
{
    char[] deleted;

    struct S
    {
        char* p;

        ~this() { deleted ~= *p; }

        void opAssign(S rhs)
        {
            // swap
            char* tmp = p;
            this.p = rhs.p;
            rhs.p = tmp;
        }
    }

    char a = 'a', b = 'b';
    {
        S s = S(&a);
        s = S(&b);
    }
    assert(deleted == "ab", deleted);
}

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

void test68()
{
    static struct S
    {
        int i;
        bool opEquals(S) { return false; }
        ~this() {}
    }

    assert(S(0) != S(1));
}

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

// https://github.com/dlang/dmd/pull/12012

extern (C++)
{
struct S12012
{
    int* ctr;
    ~this() { }
}

void bar12012(int value, S12012 s)
{
}

S12012 abc12012(ref S12012 s)
{
    s.ctr = null;
    return s;
}

int def12012(ref S12012 s)
{
    return *s.ctr; // seg fault is here
}

void testPR12012()
{
    int i;
    S12012 s = S12012(&i);
    // def must be executed before abc else seg fault
    bar12012(def12012(s), abc12012(s));
}
}

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

int main()
{
    test1();

    test3();
    test4();
    test5();
    test6();
    test7();
    test8();
    test9();
    test10();
    test11();
    test12();
    test13();
    test14();
    test15();
    test16();
    test17();
    test18();
    test19();
    test20();
    test21();
    test22();
    test23();
    test24();
    test25();
    test26();
    test27();
    test28();
    test29();
    test30();
    test31();
    test32();
    test33();
    test34();
    test35();
    test36();
    test37();
    test38();
    test39();
    test40();
    test41();
    test42();
    test43();
    test44();
    test45();
    test46();
    test47();
    test48();
    test49();
    test50();
    test51();
    test52();

    test54();
    test55();
    test56();
    test57();
    test58();
    test59();
    test5737();
    test6119();
    test8741();
    test6364();
    test6499();
    test60();
    test4316();
    test6177();
    test6470();
    test6636();
    test6637();
    test7353();
    test61();
    test7506();
    test7516a();
    test7516b();
    test7516c();
    test7516d();
    test7516e();
    test7530();
    test62();
    test7579a();
    test7579b();
    test8335();
    test8356();
    test9386();
    test9441();
    test9720();
    test9899();
    test9907();
    test9985();
    test17457();
    test9994();
    test10094();
    test10244();
    test10694();
    test10789();
    test10972();
    test11134();
    test11197();
    test7474();
    test11505();
    test12045();
    test12591();
    test12660();
    test12686();
    test13089();
    test11763();
    test13303();
    test13673();
    test13586();
    test14443();
    test13661();
    test13661a();
    test14022();
    test14023();
    test13669();
    test13095();
    test14264();
    test14686();
    test14815();
    test16197();
    test14860();
    test14246();
    test14696();
    test14838();
    test14639();
    test63();
    test64();
    test65();
    test15661();
    test18045();
    test16652();
    test19676();
    test14078();
    test67();
    test68();
    testPR12012();

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