mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 13:10:12 +03:00

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