This is a MAJOR refactoring of assignment in CTFE. The assign function was a big mess. A lot of work, and there's not really much to show for it from
a user's perspective. But it's a solid platform to allow the final CTFE bugs to be fixed.
To install this patch, you need to add a single function to mtype.c, and completely replace interpret.c with the attachment.(There are so many changes, that a patch doesn't make sense).
Fortunately the test suite file interpret.d is getting quite extensive.
And these new tests do some pretty evil things...
==
New features:
* Arbitrary nested struct assignment now works in CTFE.
a.b.c.d = e;
a[i].b.c.d = e;
* ref return values now work in CTFE (D2 only).
BUGS FIXED:
3842 ICE(expression.c) using pointer in CTFE
3899 CTFE: poor error message for use of uninitialized variable
3900 CTFE: Wrong return value for array.var assignment
========================================================
============ PATCH for mtype.c: =======================
========================================================
--- mtype.c (revision 409)
+++ mtype.c (working copy)
@@ -3451,6 +3451,21 @@
return next->isZeroInit(loc);
}
+Expression *TypeSArray::defaultInitLiteral(Loc loc)
+{
+#if LOGDEFAULTINIT
+ printf("TypeSArray::defaultInitLiteral() '%s'\n", toChars());
+#endif
+ size_t d = dim->toInteger();
+ Expression *elementinit = next->defaultInitLiteral(loc);
+ Expressions *elements = new Expressions();
+ elements->setDim(d);
+ for (size_t i = 0; i < d; i++)
+ elements->data[i] = elementinit;
+ ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements);
+ ae->type = this;
+ return ae;
+}
Expression *TypeSArray::toExpression()
{
Index: mtype.h
===================================================================
--- mtype.h (revision 409)
+++ mtype.h (working copy)
@@ -406,6 +406,7 @@
MATCH constConv(Type *to);
MATCH implicitConvTo(Type *to);
Expression *defaultInit(Loc loc);
+ Expression *defaultInitLiteral(Loc loc);
dt_t **toDt(dt_t **pdt);
dt_t **toDtElem(dt_t **pdt, Expression *e);
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
========================================================
========= Test cases for test suite. ===================
========================================================
struct ArrayRet{
int x;
}
int arrayRetTest(int z)
{
ArrayRet[6] w;
int q = (w[3].x = z);
return q;
}
static assert(arrayRetTest(51)==51);
// Bugzilla 3842 -- must not segfault
int ice3842(int z)
{
ArrayRet w;
return arrayRetTest((*(&w)).x);
}
static assert(true || is(typeof(compiles!(ice3842(51)))));
int arrayret2(){
int [5] a;
int [3] b;
b[] = a[1..$-1] = 5;
return b[1];
}
static assert(arrayret2()==5);
struct DotVarTest
{
ArrayRet z;
}
struct DotVarTest2
{
ArrayRet z;
DotVarTest p;
}
int dotvar1()
{
DotVarTest w;
w.z.x = 3;
return w.z.x;
}
int dotvar2()
{
DotVarTest2[4] m;
m[2].z.x = 3;
m[1].p.z.x = 5;
return m[2].z.x + 7;
}
static assert(dotvar1()==3);
static assert(dotvar2()==10);
struct RetRefStruct{
int x;
char c;
}
// Return value reference tests, for D2 only.
ref RetRefStruct reffunc1(ref RetRefStruct a)
{
int y = a.x;
return a;
}
ref RetRefStruct reffunc2(ref RetRefStruct a)
{
RetRefStruct z = a;
return reffunc1(a);
}
ref int reffunc7(ref RetRefStruct aa)
{
return reffunc1(aa).x;
}
ref int reffunc3(ref int a)
{
return a;
}
struct RefTestStruct
{
RetRefStruct r;
ref RefTestStruct reffunc4(ref RetRefStruct[3] a)
{
return this;
}
ref int reffunc6()
{
return this.r.x;
}
}
ref RetRefStruct reffunc5(ref RetRefStruct[3] a)
{
int t = 1;
for (int i=0; i<10; ++i)
{ if (i==7) ++t;}
return a[reffunc3(t)];
}
int retRefTest1()
{
RetRefStruct b = RetRefStruct(0,'a');
reffunc1(b).x =3;
return b.x-1;
}
int retRefTest2()
{
RetRefStruct b = RetRefStruct(0,'a');
reffunc2(b).x =3;
RetRefStruct[3] z;
RefTestStruct w;
w.reffunc4(z).reffunc4(z).r.x = 4;
assert(w.r.x == 4);
w.reffunc6() = 218;
assert(w.r.x == 218);
z[2].x = 3;
int q=4;
int u = reffunc5(z).x + reffunc3(q);
assert(u==7);
reffunc5(z).x += 7;
assert(z[2].x == 10);
RetRefStruct m = RetRefStruct(7, 'c');
m.x = 6;
reffunc7(m)+=3;
assert(m.x==9);
return b.x-1;
}
int retRefTest3()
{
RetRefStruct b = RetRefStruct(0,'a');
auto deleg = function (RetRefStruct a){ return a;};
typeof(deleg)[3] z;
z[] = deleg;
auto y = deleg(b).x + 27;
b.x = 5;
assert(y == 27);
y = z[1](b).x + 22;
return y - 1;
}
int retRefTest4()
{
RetRefStruct b = RetRefStruct(0,'a');
reffunc3(b.x) = 218;
assert(b.x == 218);
return b.x;
}
static assert(retRefTest1()==2);
static assert(retRefTest2()==2);
static assert(retRefTest3()==26);
static assert(retRefTest4()==218);
Comment #1 by clugdbug — 2010-03-08T11:32:25Z
Created attachment 586
Patch against DMD2.041 svn 409.
Drop-in replacement for interpret.c for DMD2.041. Also works without modification for D1. Also needs the change to mtype.c.
Comment #2 by bearophile_hugs — 2010-03-08T13:21:44Z
Thank you for all such big work.
> New features:
...
> * ref return values now work in CTFE (D2 only).
So is this fixing bug 2411 too?
Comment #3 by clugdbug — 2010-03-09T01:57:49Z
(In reply to comment #2)
> Thank you for all such big work.
>
>
> > New features:
> ...
> > * ref return values now work in CTFE (D2 only).
>
> So is this fixing bug 2411 too?
Unfortunately not. This fixes the 'ref' part of the problem, but bug 1330 still prevents it from working.
Bug 1330 is actually the fundamental CTFE problem: once it is fixed, almost everything will work. This patch cleans everything up so that there's a chance of fixing 1330.