changeset 823:794c8af186ce

Fixed non-static struct initializers.
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Wed, 03 Dec 2008 01:40:28 +0100
parents 43178a913a28
children b972fec8a5f5
files gen/toir.cpp tests/mini/structinit3.d
diffstat 2 files changed, 133 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/gen/toir.cpp	Tue Dec 02 02:45:31 2008 +0100
+++ b/gen/toir.cpp	Wed Dec 03 01:40:28 2008 +0100
@@ -2335,33 +2335,98 @@
     LOG_SCOPE;
 
     // get arrays 
-    size_t n = elements->dim;
+    size_t nexprs = elements->dim;;
     Expression** exprs = (Expression**)elements->data;
 
-    assert(sd->fields.dim == n);
+    size_t nvars = sd->fields.dim;
     VarDeclaration** vars = (VarDeclaration**)sd->fields.data;
 
+    assert(nexprs <= nvars);
+
+    // first locate all explicit initializers
+    std::vector<VarDeclaration*> explicitInits;
+    for (size_t i=0; i < nexprs; i++)
+    {
+        if (exprs[i])
+        {
+            explicitInits.push_back(vars[i]);
+        }
+    }
+
     // vector of values to build aggregate from
     std::vector<llvm::Value*> values;
 
-    // trackers
+    // offset trackers
     size_t lastoffset = 0;
     size_t lastsize = 0;
 
+    // index of next explicit init
+    size_t exidx = 0;
+    // number of explicit inits
+    size_t nex = explicitInits.size();
+
     // for through each field and build up the struct, padding with zeros
-    for (size_t i=0; i<n; i++)
+    size_t i;
+    for (i=0; i<nvars; i++)
     {
-        Expression* e = exprs[i];
+        Expression* e = (nexprs > i) ? exprs[i] : NULL;
         VarDeclaration* var = vars[i];
 
-        // field is skipped
+        // get var info
+        size_t os = var->offset;
+        size_t sz = var->type->size();
+
+        // get next explicit
+        VarDeclaration* nextVar = NULL;
+        size_t nextOs = 0;
+        if (exidx < nex)
+        {
+            nextVar = explicitInits[exidx];
+            nextOs = nextVar->offset;
+        }
+        // none, rest is defaults
+        else
+        {
+            break;
+        }
+
+        // not explicit initializer, default initialize if there is room, otherwise skip
         if (!e)
+        {
+            // default init if there is room
+            // (past current offset) and (small enough to fit before next explicit)
+            if ((os >= lastoffset + lastsize) && (os+sz <= nextOs))
+            {
+                // add any 0 padding needed before this field
+                if (os > lastoffset + lastsize)
+                {
+                    //printf("1added %lu zeros\n", os - lastoffset - lastsize);
+                    addZeros(values, lastoffset + lastsize, os);
+                }
+
+                // get field default init
+                IrField* f = var->ir.irField;
+                assert(f);
+                if (!f->constInit)
+                    f->constInit = DtoConstInitializer(var->loc, var->type, var->init);
+
+                values.push_back(f->constInit);
+
+                lastoffset = os;
+                lastsize = sz;
+                //printf("added default: %s : %lu (%lu)\n", var->toChars(), os, sz);
+            }
+            // skip
             continue;
+        }
+
+        assert(nextVar == var);
 
         // add any 0 padding needed before this field
-        if (var->offset > lastoffset + lastsize)
+        if (os > lastoffset + lastsize)
         {
-            addZeros(values, lastoffset + lastsize, var->offset);
+            //printf("added %lu zeros\n", os - lastoffset - lastsize);
+            addZeros(values, lastoffset + lastsize, os);
         }
 
         // add the expression value
@@ -2369,21 +2434,64 @@
         values.push_back(v->getRVal());
 
         // update offsets
-        lastoffset = var->offset;
-        lastsize = var->type->size();
+        lastoffset = os;
+        lastsize = sz;
+
+        // go to next explicit init
+        exidx++;
+
+        //printf("added field: %s : %lu (%lu)\n", var->toChars(), os, sz);
     }
 
-    // add any 0 padding needed at the end of the literal
+    // fill out rest with default initializers
     const LLType* structtype = DtoType(sd->type);
     size_t structsize = getABITypeSize(structtype);
 
+    // FIXME: this could probably share some code with the above
     if (structsize > lastoffset+lastsize)
     {
+        for (/*continue from first loop*/; i < nvars; i++)
+        {
+            VarDeclaration* var = vars[i];
+
+            // get var info
+            size_t os = var->offset;
+            size_t sz = var->type->size();
+
+            // skip?
+            if (os < lastoffset + lastsize)
+                continue;
+
+            // add any 0 padding needed before this field
+            if (os > lastoffset + lastsize)
+            {
+                //printf("2added %lu zeros\n", os - lastoffset - lastsize);
+                addZeros(values, lastoffset + lastsize, os);
+            }
+
+            // get field default init
+            IrField* f = var->ir.irField;
+            assert(f);
+            if (!f->constInit)
+                f->constInit = DtoConstInitializer(var->loc, var->type, var->init);
+
+            values.push_back(f->constInit);
+
+            lastoffset = os;
+            lastsize = sz;
+            //printf("2added default: %s : %lu (%lu)\n", var->toChars(), os, sz);
+        }
+    }
+
+    // add any 0 padding needed at the end of the literal
+    if (structsize > lastoffset+lastsize)
+    {
+        //printf("3added %lu zeros\n", structsize - lastoffset - lastsize);
         addZeros(values, lastoffset + lastsize, structsize);
     }
 
     // get the struct type from the values
-    n = values.size();
+    size_t n = values.size();
     std::vector<const LLType*> types(n, NULL);
 
     for (size_t i=0; i<n; i++)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/mini/structinit3.d	Wed Dec 03 01:40:28 2008 +0100
@@ -0,0 +1,13 @@
+struct S {
+    int a; int b; int c; int d = 7;
+}
+void test(int i) {
+    S s = { 1, i };   // q.a = 1, q.b = i, q.c = 0, q.d = 7
+    assert(s.a == 1);
+    assert(s.b == i);
+    assert(s.c == 0); // line 8
+    assert(s.d == 7);
+}
+void main() {
+    test(42);
+}