import core.stdc.stdio; template TypeTuple(T...){ alias T TypeTuple; } /***************************************************/ // 2625 struct Pair { immutable uint g1; uint g2; } void test1() { Pair[1] stuff; static assert(!__traits(compiles, (stuff[0] = Pair(1, 2)))); } /***************************************************/ // 5327 struct ID { immutable int value; } struct Data { ID id; } void test2() { Data data = Data(ID(1)); immutable int* val = &data.id.value; static assert(!__traits(compiles, data = Data(ID(2)))); } /***************************************************/ struct S31A { union { immutable int field1; immutable int field2; } enum result = false; } struct S31B { union { immutable int field1; int field2; } enum result = true; } struct S31C { union { int field1; immutable int field2; } enum result = true; } struct S31D { union { int field1; int field2; } enum result = true; } struct S32A { int dummy0; union { immutable int field1; int field2; } enum result = true; } struct S32B { immutable int dummy0; union { immutable int field1; int field2; } enum result = false; } struct S32C { union { immutable int field1; int field2; } int dummy1; enum result = true; } struct S32D { union { immutable int field1; int field2; } immutable int dummy1; enum result = false; } void test3() { foreach (S; TypeTuple!(S31A,S31B,S31C,S31D, S32A,S32B,S32C,S32D)) { S s; static assert(__traits(compiles, s = s) == S.result); } } /***************************************************/ // 3511 struct S4 { private int _prop = 42; ref int property() { return _prop; } } void test4() { S4 s; assert(s.property == 42); s.property = 23; // Rewrite to s.property() = 23 assert(s.property == 23); } /***************************************************/ struct S5 { int mX; string mY; ref int x() { return mX; } ref string y() { return mY; } ref int err(Object) { static int v; return v; } } void test5() { S5 s; s.x += 4; assert(s.mX == 4); s.x -= 2; assert(s.mX == 2); s.x *= 4; assert(s.mX == 8); s.x /= 2; assert(s.mX == 4); s.x %= 3; assert(s.mX == 1); s.x <<= 3; assert(s.mX == 8); s.x >>= 1; assert(s.mX == 4); s.x >>>= 1; assert(s.mX == 2); s.x &= 0xF; assert(s.mX == 0x2); s.x |= 0x8; assert(s.mX == 0xA); s.x ^= 0xF; assert(s.mX == 0x5); s.x ^^= 2; assert(s.mX == 25); s.mY = "ABC"; s.y ~= "def"; assert(s.mY == "ABCdef"); static assert(!__traits(compiles, s.err += 1)); } /***************************************************/ // 4424 void test4424() { static struct S { this(this) {} void opAssign(T)(T rhs) if (!is(T == S)) {} } } /***************************************************/ // 6174 struct CtorTest6174(Data) { const Data data; const Data[2] sa1; const Data[2][1] sa2; const Data[][2] sa3; const Data[] da1; const Data[2][] da2; this(Data a) { auto pdata = &data; // If compiler can determine that an assignment really sets the fields // which belongs to `this` object, it can bypass const qualifier. // For example, sa3, da1, da2, and pdata have indirections. // As long as you don't try to rewrite values beyond the indirections, // an assignment will always be succeeded inside constructor. static assert( is(typeof( data = a ))); // OK static if (is(Data == struct)) { static assert( is(typeof( data.x = 1 ))); // OK static assert( is(typeof( data.y = 2 ))); // OK } static assert(!is(typeof( *pdata = a ))); // NG static assert( is(typeof( *&data = a ))); // OK static assert( is(typeof( sa1 = [a,a] ))); // OK static assert( is(typeof( sa1[0] = a ))); // OK static assert( is(typeof( sa1[] = a ))); // OK static assert( is(typeof( sa1[][] = a ))); // OK static assert( is(typeof( sa2 = [[a,a]] ))); // OK static assert( is(typeof( sa2[0][0] = a ))); // OK static assert( is(typeof( sa2[][0][] = a ))); // OK static assert( is(typeof( sa2[0][][0] = a ))); // OK static assert( is(typeof( sa3 = [[a],[]] ))); // OK static assert( is(typeof( sa3[0] = [a,a] ))); // OK static assert(!is(typeof( sa3[0][0] = a ))); // NG static assert( is(typeof( sa3[] = [a] ))); // OK static assert( is(typeof( sa3[][0] = [a] ))); // OK static assert(!is(typeof( sa3[][0][0] = a ))); // NG static assert( is(typeof( da1 = [a,a] ))); // OK static assert(!is(typeof( da1[0] = a ))); // NG static assert(!is(typeof( da1[] = a ))); // NG static assert( is(typeof( da2 = [[a,a]] ))); // OK static assert(!is(typeof( da2[0][0] = a ))); // NG static assert(!is(typeof( da2[] = [a,a] ))); // NG static assert(!is(typeof( da2[][0] = a ))); // NG static assert(!is(typeof( da2[0][] = a ))); // NG } void func(Data a) { auto pdata = &data; static assert(!is(typeof( data = a ))); // NG static if (is(Data == struct)) { static assert(!is(typeof( data.x = 1 ))); // NG static assert(!is(typeof( data.y = 2 ))); // NG } static assert(!is(typeof( *pdata = a ))); // NG static assert(!is(typeof( *&data = a ))); // NG static assert(!is(typeof( sa1 = [a,a] ))); // NG static assert(!is(typeof( sa1[0] = a ))); // NG static assert(!is(typeof( sa1[] = a ))); // NG static assert(!is(typeof( sa1[][] = a ))); // NG static assert(!is(typeof( sa2 = [[a,a]] ))); // NG static assert(!is(typeof( sa2[0][0] = a ))); // NG static assert(!is(typeof( sa2[][0][] = a ))); // NG static assert(!is(typeof( sa2[0][][0] = a ))); // NG static assert(!is(typeof( sa3 = [[a],[]] ))); // NG static assert(!is(typeof( sa3[0] = [a,a] ))); // NG static assert(!is(typeof( sa3[0][0] = a ))); // NG static assert(!is(typeof( sa3[] = [a] ))); // NG static assert(!is(typeof( sa3[][0] = [a] ))); // NG static assert(!is(typeof( sa3[][0][0] = a ))); // NG static assert(!is(typeof( da1 = [a,a] ))); // NG static assert(!is(typeof( da1[0] = a ))); // NG static assert(!is(typeof( da1[] = a ))); // NG static assert(!is(typeof( da2 = [[a,a]] ))); // NG static assert(!is(typeof( da2[0][0] = a ))); // NG static assert(!is(typeof( da2[] = [a,a] ))); // NG static assert(!is(typeof( da2[][0] = a ))); // NG static assert(!is(typeof( da2[0][] = a ))); // NG } } const char gc6174; const char[1] ga6174; static this() { gc6174 = 'a'; // OK ga6174[0] = 'a'; // line 5, Err } struct Foo6174 { const char cc; const char[1] array; const char[1] arr; this(char c) { cc = c; // OK array = [c]; // line 12, Err arr[0] = c; // line 12, Err } } void test6174a() { static struct Pair { const int x; int y; } alias CtorTest6174!long CtorTest1; alias CtorTest6174!Pair CtorTest2; auto foo = Foo6174('c'); } /***************************************************/ template Select(bool cond, T, F) { static if (cond) alias Select = T; else alias Select = F; } void test6174b() { enum { none, unrelated, mutable, constant } static struct FieldStruct(bool c, int k) { enum fieldConst = c; enum assignKind = k; Select!(fieldConst, const int, int) x; int y; static if (assignKind == none) {} static if (assignKind == unrelated) void opAssign(int) {} static if (assignKind == mutable) void opAssign(FieldStruct) {} static if (assignKind == constant) void opAssign(FieldStruct) const {} } static struct TestStruct(F, bool fieldConst) { int w; Select!(fieldConst, const F, F) f; Select!(fieldConst, const int, int) z; this(int) { // If F has an identity `opAssign`,it is used even for initializing. // Otherwise, initializing will always succeed, by bypassing const qualifier. static assert(is(typeof( f = F() )) == ( F.assignKind == none || F.assignKind == unrelated || F.assignKind == mutable || F.assignKind == constant)); static assert(is(typeof( w = 1000 )) == true); static assert(is(typeof( f.x = 1000 )) == true); static assert(is(typeof( f.y = 1000 )) == true); static assert(is(typeof( z = 1000 )) == true); } void func() { // In mutable member functions, identity assignment is allowed // when all of the fields are identity assignable, // or identity `opAssign`, which callable from mutable object, is defined. static assert(__traits(compiles, f = F()) == ( F.assignKind == none && !fieldConst && !F.fieldConst || F.assignKind == unrelated && !fieldConst && !F.fieldConst || F.assignKind == constant || F.assignKind == mutable && !fieldConst)); static assert(__traits(compiles, w = 1000) == true); static assert(__traits(compiles, f.x = 1000) == (!fieldConst && !F.fieldConst)); static assert(__traits(compiles, f.y = 1000) == (!fieldConst && true )); static assert(__traits(compiles, z = 1000) == !fieldConst); } void func() const { // In non-mutable member functions, identity assignment is allowed // just only user-defined identity `opAssign` is qualified. static assert(__traits(compiles, f = F()) == (F.assignKind == constant)); static assert(__traits(compiles, w = 1000) == false); static assert(__traits(compiles, f.x = 1000) == false); static assert(__traits(compiles, f.y = 1000) == false); static assert(__traits(compiles, z = 1000) == false); } } foreach (fieldConst; TypeTuple!(false, true)) foreach ( hasConst; TypeTuple!(false, true)) foreach (assignKind; TypeTuple!(none, unrelated, mutable, constant)) { alias TestStruct!(FieldStruct!(hasConst, assignKind), fieldConst) TestX; } } void test6174c() { static assert(!is(typeof({ int func1a(int n) in{ n = 10; } body { return n; } }))); static assert(!is(typeof({ int func1b(int n) out(r){ r = 20; } body{ return n; } }))); struct DataX { int x; } static assert(!is(typeof({ DataX func2a(DataX n) in{ n.x = 10; } body { return n; } }))); static assert(!is(typeof({ DataX func2b(DataX n) in{} out(r){ r.x = 20; } body{ return n; } }))); } /***************************************************/ // 6216 void test6216a() { static class C{} static struct Xa{ int n; } static struct Xb{ int[] a; } static struct Xc{ C c; } static struct Xd{ void opAssign(typeof(this) rhs){} } static struct Xe{ void opAssign(T)(T rhs){} } static struct Xf{ void opAssign(int rhs){} } static struct Xg{ void opAssign(T)(T rhs)if(!is(T==typeof(this))){} } // has value type as member static struct S1 (X){ static if (!is(X==void)) X x; int n; } // has reference type as member static struct S2a(X){ static if (!is(X==void)) X x; int[] a; } static struct S2b(X){ static if (!is(X==void)) X x; C c; } // has identity opAssign static struct S3a(X){ static if (!is(X==void)) X x; void opAssign(typeof(this) rhs){} } static struct S3b(X){ static if (!is(X==void)) X x; void opAssign(T)(T rhs){} } // has non identity opAssign static struct S4a(X){ static if (!is(X==void)) X x; void opAssign(int rhs){} } static struct S4b(X){ static if (!is(X==void)) X x; void opAssign(T)(T rhs)if(!is(T==typeof(this))){} } enum result = [ /*S1, S2a, S2b, S3a, S3b, S4a, S4b*/ /*- */ [true, true, true, true, true, true, true], /*Xa*/ [true, true, true, true, true, true, true], /*Xb*/ [true, true, true, true, true, true, true], /*Xc*/ [true, true, true, true, true, true, true], /*Xd*/ [true, true, true, true, true, true, true], /*Xe*/ [true, true, true, true, true, true, true], /*Xf*/ [true, true, true, true, true, true, true], /*Xg*/ [true, true, true, true, true, true, true], ]; pragma(msg, "\\\tS1\tS2a\tS2b\tS3a\tS3b\tS4a\tS4b"); foreach (i, X; TypeTuple!(void,Xa,Xb,Xc,Xd,Xe,Xf,Xg)) { S1!X s1; S2a!X s2a; S2b!X s2b; S3a!X s3a; S3b!X s3b; S4a!X s4a; S4b!X s4b; pragma(msg, is(X==void) ? "-" : X.stringof, "\t", __traits(compiles, (s1 = s1)), "\t", __traits(compiles, (s2a = s2a)), "\t", __traits(compiles, (s2b = s2b)), "\t", __traits(compiles, (s3a = s3a)), "\t", __traits(compiles, (s3b = s3b)), "\t", __traits(compiles, (s4a = s4a)), "\t", __traits(compiles, (s4b = s4b)) ); static assert(result[i] == [ __traits(compiles, (s1 = s1)), __traits(compiles, (s2a = s2a)), __traits(compiles, (s2b = s2b)), __traits(compiles, (s3a = s3a)), __traits(compiles, (s3b = s3b)), __traits(compiles, (s4a = s4a)), __traits(compiles, (s4b = s4b)) ]); } } void test6216b() { static int cnt = 0; static struct X { int n; void opAssign(X rhs){ cnt = 1; } } static struct S { int n; X x; } S s; s = s; assert(cnt == 1); // Built-in opAssign runs member's opAssign } void test6216c() { static int cnt = 0; static struct X { int n; void opAssign(const X rhs) const { cnt = 2; } } static struct S { int n; const(X) x; } S s; const(S) cs; s = s; s = cs; // cs is copied as mutable and assigned into s assert(cnt == 2); static assert(!__traits(compiles, cs = cs)); // built-in opAssin is only allowed with mutable object } void test6216d() { static int cnt = 0; static struct X { int[] arr; // X has mutable indirection void opAssign(const X rhs) const { ++cnt; } } static struct S { int n; const(X) x; } X mx; const X cx; mx = mx; // copying mx to const X is possible assert(cnt == 1); mx = cx; assert(cnt == 2); cx = mx; // copying mx to const X is possible assert(cnt == 3); S s; const(S) cs; s = s; s = cs; //assert(cnt == 4); static assert(!__traits(compiles, cs = cs)); // built-in opAssin is only allowed with mutable object } void test6216e() { static struct X { int x; @disable void opAssign(X); } static struct S { X x; } S s; static assert(!__traits(compiles, s = s)); // built-in generated opAssin is marked as @disable. } /***************************************************/ // 6286 void test6286() { const(int)[4] src = [1, 2, 3, 4]; int[4] dst; dst = src; dst[] = src[]; dst = 4; int[4][4] x; x = dst; } /***************************************************/ // 6336 void test6336() { // structs aren't identity assignable static struct S1 { immutable int n; } static struct S2 { void opAssign(int n){ assert(0); } } S1 s1; S2 s2; void f(S)(out S s){} static assert(!__traits(compiles, f(s1))); f(s2); // Out parameters refuse only S1 because it isn't blit assignable ref S g(S)(ref S s){ return s; } g(s1); g(s2); // Allow return by ref both S1 and S2 } /***************************************************/ // 8783 struct Foo8783 { int[1] bar; } const Foo8783[1] foos8783; static this() { foreach (i; 0 .. foos8783.length) foos8783[i].bar[i] = 1; // OK foreach (i, ref f; foos8783) f.bar[i] = 1; // line 9, Error } /***************************************************/ // 9077 struct S9077a { void opAssign(int n) {} void test() { typeof(this) s; s = this; } this(this) {} } struct S9077b { void opAssign()(int n) {} void test() { typeof(this) s; s = this; } this(this) {} } /***************************************************/ // 9140 immutable(int)[] bar9140() out(result) { foreach (ref r; result) {} } body { return null; } /***************************************************/ // 9154 struct S9154a { int x; void opAssign(ref S9154a s) { } } struct S9154b { int x; void opAssign(X)(ref X s) { } } struct T9154 { S9154a member1; S9154b member2; } void test9154() { T9154 t1, t2; t1 = t2; } /***************************************************/ // 9258 class A9258 {} class B9258 : A9258 // Error: class test.B9258 identity assignment operator overload is illegal { void opAssign(A9258 b) {} } class C9258 { int n; alias n this; void opAssign(int n) {} } class D9258 { int n; alias n this; void opAssign(int n, int y = 0) {} } class E9258 : A9258 { void set(A9258 a) {} alias set opAssign; } /***************************************************/ // 9416 struct S9416 { void opAssign()(S9416) { static assert(0); } } struct U9416 { S9416 s; } void test9416() { U9416 u; static assert(__traits(allMembers, U9416)[$-1] == "opAssign"); static assert(!__traits(compiles, u = u)); } /***************************************************/ // 9658 struct S9658 { private bool _isNull = true; this(int v) const { _isNull = false; // cannot modify const expression this._isNull } } /***************************************************/ // 11187 void test11187() { static struct X { int[] arr; } static struct S { const(X) cx; } static assert(is(typeof((const S).init.cx.arr) == const(int[]))); static assert(is(typeof(( S).init.cx.arr) == const(int[]))); const S sc; S sm = sc; static assert(is(const S : S)); } /***************************************************/ // 12131 struct X12131 { void opAssign()(X12131 y) pure {} } struct Y12131 { X12131 a; } void test12131() pure { X12131 x; x = X12131(); // OK Y12131 y; y = Y12131(); // OK <- Error } /***************************************************/ // 12211 void test12211() { int a = 0; void foo(ref int x) { assert(x == 10); assert(&x == &a); x = 3; } foo(a = 10); assert(a == 3); foo(a += 7); assert(a == 3); // array ops should make rvalue int[3] sa, sb; void bar(ref int[]) {} static assert(!__traits(compiles, bar(sa[] = sb[]))); static assert(!__traits(compiles, bar(sa[] += sb[]))); } /***************************************************/ // 4791 (dup of 12212) void test4791() { int[2] na; na = na; static struct S { static string res; int n; this(this) { ++n; res ~= "p" ~ cast(char)('0' + n); } ~this() { res ~= "d" ~ cast(char)('0' + n); } } { S[3] sa; sa[0].n = 1, sa[1].n = 2, sa[2].n = 3; S.res = null; sa = sa; assert(S.res == "p2d1p3d2p4d3"); assert(sa[0].n == 2 && sa[1].n == 3 && sa[2].n == 4); S.res = null; } assert(S.res == "d4d3d2"); } /***************************************************/ // 12212 void test12212() { struct S { int x, y; static int cpctor; this(this) { cpctor++; } } void funcVal(E)(E[3] x) {} auto funcRef(E)(ref E[3] x) { return &x; } ref get(E)(ref E[3] a){ return a; } { int[3] a, b; funcVal(a = b); auto p = funcRef(a = b); assert(p == &a); } { S.cpctor = 0; S[3] a, b; assert(S.cpctor == 0); S[3] c = a; //printf("cpctpr = %d\n", S.cpctor); assert(S.cpctor == 3); S.cpctor = 0; c = a; //printf("cpctpr = %d\n", S.cpctor); assert(S.cpctor == 3); S.cpctor = 0; c = (a = b); //printf("cpctpr = %d\n", S.cpctor); assert(S.cpctor == 6); S.cpctor = 0; c = (get(a) = b); //printf("cpctpr = %d\n", S.cpctor); assert(S.cpctor == 6); S.cpctor = 0; } { S.cpctor = 0; S[3] a, b; assert(S.cpctor == 0); funcVal(a = b); //printf("cpctpr = %d\n", S.cpctor); assert(S.cpctor == 6); S.cpctor = 0; funcVal(get(a) = b); //printf("cpctpr = %d\n", S.cpctor); assert(S.cpctor == 6); S.cpctor = 0; } { S.cpctor = 0; S[3] a, b; assert(S.cpctor == 0); S[3]* p; p = funcRef(a = b); //printf("cpctpr = %d\n", S.cpctor); assert(p == &a); assert(S.cpctor == 3); S.cpctor = 0; p = funcRef(get(a) = b); assert(p == &a); //printf("cpctpr = %d\n", S.cpctor); assert(S.cpctor == 3); S.cpctor = 0; } } /***************************************************/ // 12650 void test12650() { // AssignExp::toElem should make an lvalue of e1. static class A1 { struct S { int a; } static foo(ref const(S) s) { assert(s.a == 2); return &s; } S s; this() { const v = S(2); // (this.s = v) will become ConstructExp auto p = foo(s = v); assert(p == &s); } } assert(new A1().s.a == 2); static class A2 { static foo(ref int[2] sa) { assert(sa[1] == 2); return &sa; } int[2] sa; this() { // (this.sa = [1,2]) will become ConstructExp auto p = foo(sa = [1,2]); assert(p == &sa); } } assert(new A2().sa[1] == 2); static class A3 { static foo(ref int n) { assert(n == 2); return &n; } int n; this() { const v = 2; // (this.n = v) will become ConstructExp auto p = foo(n = v); assert(p == &n); } } assert(new A3().n == 2); } /***************************************************/ // 13044 void test13044() { static struct Good { const int i; } static struct Bad { const int i; ~this() {} } Good good1, good2; static assert(!__traits(compiles, { good1 = good2; })); // OK Bad bad1, bad2; static assert(!__traits(compiles, { bad1 = bad2; })); // OK <- fails } /***************************************************/ // 12500 void test12500() { size_t foo; ++foo *= 1.5; // Rewrite to: (foo += 1) *= 1.5; } /***************************************************/ // 14672 void test14672() { interface I {} class B {} class D : B, I {} D d = new D(); D[] da = [d]; B[] ba = [null]; I[] ia = [null]; // ba and da points different payloads, // so element-wise assignment should work. ba[] = da[]; // OK <- e2ir ICE assert(ba[0] is d); // Today element-wise assignment is implemented as memcpy, For that reason // the conversion from derived classes to base interfaces is disallowed // because it requries offset adjustments. static assert(!__traits(compiles, { ia[] = da[]; })); // after the assignment, ba will wongly point the payload of da, // that's typed as D[]. To aboid type system breaking, it's disallowed. static assert(!__traits(compiles, { ba = da; })); // the assigned array literal is a new payload, // so rebinding ba should work. ba = [d]; // OK assert(ba[0] is d); } /***************************************************/ // 15044 void destroy15044(T)(ref T obj) { static if (__traits(hasMember, T, "__xdtor")) obj.__xdtor(); else static assert(0, T.stringof); } struct V15044 { ~this() { } RC15044!V15044 dup() { return RC15044!V15044(&this); } } struct RC15044(T) { ~this() { destroy15044(*t); static assert(__traits(hasMember, T, "__xdtor")); } T* t; } /***************************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test4424(); test6174a(); test6174b(); test6174c(); test6216a(); test6216b(); test6216c(); test6216d(); test6216e(); test6286(); test6336(); test9154(); test9416(); test11187(); test12131(); test12211(); test4791(); test12212(); test12650(); test13044(); test12500(); test14672(); printf("Success\n"); return 0; }