changeset 116:fd7ad91fd713 trunk

[svn r120] ModuleInfo implementation is now almost complete. Fixed some nasty static array-initializer bugs. Fixed bug in DtoArrayLen and DtoArrayPtr for full slices of static arrays.
author lindquist
date Sun, 25 Nov 2007 18:55:52 +0100
parents 5ba6d286c941
children 56a21f3e5d3e
files gen/arrays.cpp gen/functions.cpp gen/irstate.h gen/toir.cpp gen/tollvm.cpp gen/tollvm.h gen/toobj.cpp lphobos/internal/objectimpl.d lphobos/object.d lphobos/std/moduleinit.d test/bug51.d test/moduleinfo1.d
diffstat 12 files changed, 335 insertions(+), 180 deletions(-) [+]
line wrap: on
line diff
--- a/gen/arrays.cpp	Sun Nov 25 03:58:55 2007 +0100
+++ b/gen/arrays.cpp	Sun Nov 25 18:55:52 2007 +0100
@@ -285,22 +285,32 @@
 
     std::vector<llvm::Constant*> inits(tdim, NULL);
 
+    Type* arrnext = arrinittype->next;
     const llvm::Type* elemty = DtoType(arrinittype->next);
 
     assert(arrinit->index.dim == arrinit->value.dim);
     for (unsigned i=0,j=0; i < tdim; ++i)
     {
         Initializer* init = 0;
-        Expression* idx = (Expression*)arrinit->index.data[j];
+        Expression* idx;
+
+        if (j < arrinit->index.dim)
+            idx = (Expression*)arrinit->index.data[j];
+        else
+            idx = NULL;
+
+        llvm::Constant* v = NULL;
 
         if (idx)
         {
+            Logger::println("%d has idx", i);
             // this is pretty weird :/ idx->type turned out NULL for the initializer:
             //     const in6_addr IN6ADDR_ANY = { s6_addr8: [0] };
             // in std.c.linux.socket
             if (idx->type) {
+                Logger::println("has idx->type", i);
                 //integer_t k = idx->toInteger();
-                Logger::println("getting value for exp: %s | %s", idx->toChars(), idx->type->toChars());
+                //Logger::println("getting value for exp: %s | %s", idx->toChars(), arrnext->toChars());
                 llvm::Constant* cc = idx->toConstElem(gIR);
                 Logger::println("value gotten");
                 assert(cc != NULL);
@@ -317,11 +327,16 @@
         }
         else
         {
-            init = (Initializer*)arrinit->value.data[j];
-            ++j;
+            if (j < arrinit->value.dim) {
+                init = (Initializer*)arrinit->value.data[j];
+                ++j;
+            }
+            else
+                v = arrnext->defaultInit()->toConstElem(gIR);
         }
 
-        llvm::Constant* v = DtoConstInitializer(t->next, init);
+        if (!v)
+            v = DtoConstInitializer(t->next, init);
         assert(v);
 
         inits[i] = v;
@@ -784,16 +799,22 @@
 //////////////////////////////////////////////////////////////////////////////////////////
 llvm::Value* DtoArrayLen(DValue* v)
 {
+    Logger::println("DtoArrayLen");
+    LOG_SCOPE;
     Type* t = DtoDType(v->getType());
     if (t->ty == Tarray) {
         if (DSliceValue* s = v->isSlice()) {
-            if (s->len) return s->len;
-            DValue* next = new DVarValue(t,s->ptr,true);
-            return DtoArrayLen(next);
+            if (s->len) {
+                return s->len;
+            }
+            const llvm::ArrayType* arrTy = isaArray(s->ptr->getType()->getContainedType(0));
+            assert(arrTy);
+            return DtoConstSize_t(arrTy->getNumElements());
         }
         return DtoLoad(DtoGEPi(v->getRVal(), 0,0, "tmp"));
     }
     else if (t->ty == Tsarray) {
+        assert(!v->isSlice());
         llvm::Value* rv = v->getRVal();
         Logger::cout() << "casting: " << *rv << '\n';
         const llvm::ArrayType* t = isaArray(rv->getType()->getContainedType(0));
@@ -810,8 +831,9 @@
     if (t->ty == Tarray) {
         if (DSliceValue* s = v->isSlice()) {
             if (s->len) return s->ptr;
-            DValue* next = new DVarValue(t,s->ptr,true);
-            return DtoArrayPtr(next);
+            const llvm::ArrayType* arrTy = isaArray(s->ptr->getType()->getContainedType(0));
+            assert(arrTy);
+            return DtoGEPi(s->ptr, 0,0, "tmp");
         }
         return DtoLoad(DtoGEPi(v->getRVal(), 0,1, "tmp"));
     }
--- a/gen/functions.cpp	Sun Nov 25 03:58:55 2007 +0100
+++ b/gen/functions.cpp	Sun Nov 25 18:55:52 2007 +0100
@@ -368,10 +368,20 @@
     fdecl->llvmValue = func;
     assert(llvm::isa<llvm::FunctionType>(f->llvmType->get()));
 
+    // main
     if (fdecl->isMain()) {
         gIR->mainFunc = func;
     }
 
+    // static ctor
+    if (fdecl->isStaticCtorDeclaration()) {
+        gIR->ctors.push_back(fdecl);
+    }
+    // static dtor
+    else if (fdecl->isStaticDtorDeclaration()) {
+        gIR->dtors.push_back(fdecl);
+    }
+
     // name parameters
     llvm::Function::arg_iterator iarg = func->arg_begin();
     int k = 0;
--- a/gen/irstate.h	Sun Nov 25 03:58:55 2007 +0100
+++ b/gen/irstate.h	Sun Nov 25 18:55:52 2007 +0100
@@ -218,6 +218,12 @@
     DsymbolList constInitList;
     // dsymbols that need definitions
     DsymbolList defineList;
+
+    // static ctors/dtors/unittests
+    typedef std::vector<FuncDeclaration*> FuncDeclVector;
+    FuncDeclVector ctors;
+    FuncDeclVector dtors;
+    FuncDeclVector unitTests;
 };
 
 #endif // LLVMDC_GEN_IRSTATE_H
--- a/gen/toir.cpp	Sun Nov 25 03:58:55 2007 +0100
+++ b/gen/toir.cpp	Sun Nov 25 18:55:52 2007 +0100
@@ -1491,6 +1491,9 @@
         emem = vmem;
     }
 
+    if (earg) Logger::cout() << "slice exp result, length = " << *earg << '\n';
+    Logger::cout() << "slice exp result, ptr = " << *emem << '\n';
+
     return new DSliceValue(type,earg,emem);
 }
 
--- a/gen/tollvm.cpp	Sun Nov 25 03:58:55 2007 +0100
+++ b/gen/tollvm.cpp	Sun Nov 25 18:55:52 2007 +0100
@@ -1617,6 +1617,38 @@
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
+void DtoEmptyAllLists()
+{
+    for(;;)
+    {
+        Dsymbol* dsym;
+        if (!gIR->resolveList.empty()) {
+            dsym = gIR->resolveList.front();
+            gIR->resolveList.pop_front();
+            DtoResolveDsymbol(dsym);
+        }
+        else if (!gIR->declareList.empty()) {
+            dsym = gIR->declareList.front();
+            gIR->declareList.pop_front();
+            DtoDeclareDsymbol(dsym);
+        }
+        else if (!gIR->constInitList.empty()) {
+            dsym = gIR->constInitList.front();
+            gIR->constInitList.pop_front();
+            DtoConstInitDsymbol(dsym);
+        }
+        else if (!gIR->defineList.empty()) {
+            dsym = gIR->defineList.front();
+            gIR->defineList.pop_front();
+            DtoDefineDsymbol(dsym);
+        }
+        else {
+            break;
+        }
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
 
 void DtoForceDeclareDsymbol(Dsymbol* dsym)
 {
--- a/gen/tollvm.h	Sun Nov 25 03:58:55 2007 +0100
+++ b/gen/tollvm.h	Sun Nov 25 18:55:52 2007 +0100
@@ -69,6 +69,7 @@
 void DtoEmptyResolveList();
 void DtoEmptyDeclareList();
 void DtoEmptyConstInitList();
+void DtoEmptyAllLists();
 void DtoForceDeclareDsymbol(Dsymbol* dsym);
 void DtoForceConstInitDsymbol(Dsymbol* dsym);
 void DtoForceDefineDsymbol(Dsymbol* dsym);
--- a/gen/toobj.cpp	Sun Nov 25 03:58:55 2007 +0100
+++ b/gen/toobj.cpp	Sun Nov 25 18:55:52 2007 +0100
@@ -106,36 +106,11 @@
     }
 
     // main driver loop
-    for(;;)
-    {
-        Dsymbol* dsym;
-        if (!ir.resolveList.empty()) {
-            dsym = ir.resolveList.front();
-            ir.resolveList.pop_front();
-            DtoResolveDsymbol(dsym);
-        }
-        else if (!ir.declareList.empty()) {
-            dsym = ir.declareList.front();
-            ir.declareList.pop_front();
-            DtoDeclareDsymbol(dsym);
-        }
-        else if (!ir.constInitList.empty()) {
-            dsym = ir.constInitList.front();
-            ir.constInitList.pop_front();
-            DtoConstInitDsymbol(dsym);
-        }
-        else if (!ir.defineList.empty()) {
-            dsym = ir.defineList.front();
-            ir.defineList.pop_front();
-            DtoDefineDsymbol(dsym);
-        }
-        else {
-            break;
-        }
-    }
-
+    DtoEmptyAllLists();
     // generate ModuleInfo
     genmoduleinfo();
+    // do this again as moduleinfo might have pulled something in!
+    DtoEmptyAllLists();
 
     gTargetData = 0;
 
@@ -181,6 +156,72 @@
 
 /* ================================================================== */
 
+// build module ctor
+
+static llvm::Function* build_module_ctor()
+{
+    if (gIR->ctors.empty())
+        return NULL;
+
+    size_t n = gIR->ctors.size();
+    if (n == 1)
+        return llvm::cast<llvm::Function>(gIR->ctors[0]->llvmValue);
+
+    std::string name("_D");
+    name.append(gIR->dmodule->mangle());
+    name.append("6__ctorZ");
+
+    std::vector<const llvm::Type*> argsTy;
+    const llvm::FunctionType* fnTy = llvm::FunctionType::get(llvm::Type::VoidTy,argsTy,false);
+    llvm::Function* fn = new llvm::Function(fnTy, llvm::GlobalValue::InternalLinkage, name, gIR->module);
+    fn->setCallingConv(llvm::CallingConv::Fast);
+
+    llvm::BasicBlock* bb = new llvm::BasicBlock("entry", fn);
+    LLVMBuilder builder(bb);
+
+    for (size_t i=0; i<n; i++) {
+        llvm::Function* f = llvm::cast<llvm::Function>(gIR->ctors[i]->llvmValue);
+        llvm::CallInst* call = builder.CreateCall(f,"");
+        call->setCallingConv(llvm::CallingConv::Fast);
+    }
+
+    builder.CreateRetVoid();
+    return fn;
+}
+
+// build module dtor
+
+static llvm::Function* build_module_dtor()
+{
+    if (gIR->dtors.empty())
+        return NULL;
+
+    size_t n = gIR->dtors.size();
+    if (n == 1)
+        return llvm::cast<llvm::Function>(gIR->dtors[0]->llvmValue);
+
+    std::string name("_D");
+    name.append(gIR->dmodule->mangle());
+    name.append("6__dtorZ");
+
+    std::vector<const llvm::Type*> argsTy;
+    const llvm::FunctionType* fnTy = llvm::FunctionType::get(llvm::Type::VoidTy,argsTy,false);
+    llvm::Function* fn = new llvm::Function(fnTy, llvm::GlobalValue::InternalLinkage, name, gIR->module);
+    fn->setCallingConv(llvm::CallingConv::Fast);
+
+    llvm::BasicBlock* bb = new llvm::BasicBlock("entry", fn);
+    LLVMBuilder builder(bb);
+
+    for (size_t i=0; i<n; i++) {
+        llvm::Function* f = llvm::cast<llvm::Function>(gIR->dtors[i]->llvmValue);
+        llvm::CallInst* call = builder.CreateCall(f,"");
+        call->setCallingConv(llvm::CallingConv::Fast);
+    }
+
+    builder.CreateRetVoid();
+    return fn;
+}
+
 // Put out instance of ModuleInfo for this Module
 
 void Module::genmoduleinfo()
@@ -198,139 +239,131 @@
 //         void *unitTest;
 //        }
 
-    if (moduleinfo) {
-        Logger::println("moduleinfo");
-    }
-    if (vmoduleinfo) {
-        Logger::println("vmoduleinfo");
-    }
-    if (needModuleInfo()) {
-        Logger::attention("module info is needed but skipped");
-    }
+    // resolve ModuleInfo
+    assert(moduleinfo);
+    DtoForceConstInitDsymbol(moduleinfo);
 
+    // moduleinfo llvm struct type
+    const llvm::StructType* moduleinfoTy = isaStruct(moduleinfo->type->llvmType->get());
 
-    /*
-    Symbol *msym = toSymbol();
-    unsigned offset;
-    unsigned sizeof_ModuleInfo = 12 * PTRSIZE;
-
-    //////////////////////////////////////////////
-
-    csym->Sclass = SCglobal;
-    csym->Sfl = FLdata;
+    // classinfo llvm struct type
+    const llvm::StructType* classinfoTy = isaStruct(ClassDeclaration::classinfo->type->llvmType->get());
 
-//      The layout is:
-//        {
-//         void **vptr;
-//         monitor_t monitor;
-//         char[] name;        // class name
-//         ModuleInfo importedModules[];
-//         ClassInfo localClasses[];
-//         uint flags;         // initialization state
-//         void *ctor;
-//         void *dtor;
-//         void *unitTest;
-//        }
-    dt_t *dt = NULL;
+    // initializer vector
+    std::vector<llvm::Constant*> initVec;
+    llvm::Constant* c = 0;
+
+    // vtable
+    c = moduleinfo->llvmVtbl;
+    initVec.push_back(c);
 
-    if (moduleinfo)
-    dtxoff(&dt, moduleinfo->toVtblSymbol(), 0, TYnptr); // vtbl for ModuleInfo
-    else
-    dtdword(&dt, 0);        // BUG: should be an assert()
-    dtdword(&dt, 0);            // monitor
-
-    // name[]
-    char *name = toPrettyChars();
-    size_t namelen = strlen(name);
-    dtdword(&dt, namelen);
-    dtabytes(&dt, TYnptr, 0, namelen + 1, name);
+    // monitor
+    c = llvm::ConstantPointerNull::get(llvm::PointerType::get(llvm::Type::Int8Ty));
+    initVec.push_back(c);
 
-    ClassDeclarations aclasses;
-    int i;
-
-    //printf("members->dim = %d\n", members->dim);
-    for (i = 0; i < members->dim; i++)
-    {
-    Dsymbol *member;
-
-    member = (Dsymbol *)members->data[i];
-    //printf("\tmember '%s'\n", member->toChars());
-    member->addLocalClass(&aclasses);
-    }
+    // name
+    char *name = toPrettyChars();
+    c = DtoConstString(name);
+    initVec.push_back(c);
 
     // importedModules[]
     int aimports_dim = aimports.dim;
-    for (i = 0; i < aimports.dim; i++)
-    {   Module *m = (Module *)aimports.data[i];
-    if (!m->needModuleInfo())
-        aimports_dim--;
+    std::vector<llvm::Constant*> importInits;
+    for (size_t i = 0; i < aimports.dim; i++)
+    {
+        Module *m = (Module *)aimports.data[i];
+        if (!m->needModuleInfo())
+            aimports_dim--;
+        else { // declare
+            // create name
+            std::string m_name("_D");
+            m_name.append(m->mangle());
+            m_name.append("8__ModuleZ");
+            llvm::GlobalVariable* m_gvar = new llvm::GlobalVariable(moduleinfoTy, false, llvm::GlobalValue::ExternalLinkage, NULL, m_name, gIR->module);
+            importInits.push_back(m_gvar);
+        }
     }
-    dtdword(&dt, aimports_dim);
-    if (aimports.dim)
-    dtxoff(&dt, csym, sizeof_ModuleInfo, TYnptr);
+    // has import array?
+    if (!importInits.empty()) {
+        const llvm::ArrayType* importArrTy = llvm::ArrayType::get(llvm::PointerType::get(moduleinfoTy), importInits.size());
+        c = llvm::ConstantArray::get(importArrTy, importInits);
+        std::string m_name("_D");
+        m_name.append(mangle());
+        m_name.append("9__importsZ");
+        llvm::GlobalVariable* m_gvar = new llvm::GlobalVariable(importArrTy, true, llvm::GlobalValue::InternalLinkage, c, m_name, gIR->module);
+        c = llvm::ConstantExpr::getBitCast(m_gvar, llvm::PointerType::get(importArrTy->getElementType()));
+        c = DtoConstSlice(DtoConstSize_t(importInits.size()), c);
+    }
     else
-    dtdword(&dt, 0);
+        c = moduleinfo->llvmInitZ->getOperand(3);
+    initVec.push_back(c);
 
     // localClasses[]
-    dtdword(&dt, aclasses.dim);
-    if (aclasses.dim)
-    dtxoff(&dt, csym, sizeof_ModuleInfo + aimports_dim * PTRSIZE, TYnptr);
-    else
-    dtdword(&dt, 0);
-
-    if (needmoduleinfo)
-    dtdword(&dt, 0);        // flags (4 means MIstandalone)
-    else
-    dtdword(&dt, 4);        // flags (4 means MIstandalone)
+    ClassDeclarations aclasses;
+    //printf("members->dim = %d\n", members->dim);
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *member;
 
-    if (sctor)
-    dtxoff(&dt, sctor, 0, TYnptr);
-    else
-    dtdword(&dt, 0);
-
-    if (sdtor)
-    dtxoff(&dt, sdtor, 0, TYnptr);
-    else
-    dtdword(&dt, 0);
-
-    if (stest)
-    dtxoff(&dt, stest, 0, TYnptr);
-    else
-    dtdword(&dt, 0);
-
-    //////////////////////////////////////////////
-
-    for (i = 0; i < aimports.dim; i++)
+        member = (Dsymbol *)members->data[i];
+        //printf("\tmember '%s'\n", member->toChars());
+        member->addLocalClass(&aclasses);
+    }
+    // fill inits
+    std::vector<llvm::Constant*> classInits;
+    for (size_t i = 0; i < aclasses.dim; i++)
     {
-    Module *m;
+        ClassDeclaration* cd = (ClassDeclaration*)aclasses.data[i];
+        assert(cd->llvmClass);
+        classInits.push_back(cd->llvmClass);
+    }
+    // has class array?
+    if (!classInits.empty()) {
+        const llvm::ArrayType* classArrTy = llvm::ArrayType::get(llvm::PointerType::get(classinfoTy), classInits.size());
+        c = llvm::ConstantArray::get(classArrTy, classInits);
+        std::string m_name("_D");
+        m_name.append(mangle());
+        m_name.append("9__classesZ");
+        llvm::GlobalVariable* m_gvar = new llvm::GlobalVariable(classArrTy, true, llvm::GlobalValue::InternalLinkage, c, m_name, gIR->module);
+        c = llvm::ConstantExpr::getBitCast(m_gvar, llvm::PointerType::get(classArrTy->getElementType()));
+        c = DtoConstSlice(DtoConstSize_t(classInits.size()), c);
+    }
+    else
+        c = moduleinfo->llvmInitZ->getOperand(4);
+    initVec.push_back(c);
 
-    m = (Module *)aimports.data[i];
-    if (m->needModuleInfo())
-    {   Symbol *s = m->toSymbol();
-        s->Sflags |= SFLweak;
-        dtxoff(&dt, s, 0, TYnptr);
-    }
-    }
-
-    for (i = 0; i < aclasses.dim; i++)
-    {
-    ClassDeclaration *cd;
+    // flags
+    if (needmoduleinfo)
+        c = DtoConstUint(0);        // flags (4 means MIstandalone)
+    else
+        c = DtoConstUint(4);        // flags (4 means MIstandalone)
+    initVec.push_back(c);
 
-    cd = (ClassDeclaration *)aclasses.data[i];
-    dtxoff(&dt, cd->toSymbol(), 0, TYnptr);
-    }
+    // ctor
+    llvm::Function* fctor = build_module_ctor();
+    c = fctor ? fctor : moduleinfo->llvmInitZ->getOperand(6);
+    initVec.push_back(c);
+
+    // dtor
+    llvm::Function* fdtor = build_module_dtor();
+    c = fdtor ? fdtor : moduleinfo->llvmInitZ->getOperand(7);
+    initVec.push_back(c);
 
-    csym->Sdt = dt;
-#if ELFOBJ
-    // Cannot be CONST because the startup code sets flag bits in it
-    csym->Sseg = DATA;
-#endif
-    outdata(csym);
+    // unitTest
+    c = moduleinfo->llvmInitZ->getOperand(8);
+    initVec.push_back(c);
+
+    // create initializer
+    llvm::Constant* constMI = llvm::ConstantStruct::get(moduleinfoTy, initVec);
 
-    //////////////////////////////////////////////
+    // create name
+    std::string MIname("_D");
+    MIname.append(mangle());
+    MIname.append("8__ModuleZ");
 
-    obj_moduleinfo(msym);
-    */
+    // declare
+    // flags will be modified at runtime so can't make it constant
+    llvm::GlobalVariable* gvar = new llvm::GlobalVariable(moduleinfoTy, false, llvm::GlobalValue::ExternalLinkage, constMI, MIname, gIR->module);
 }
 
 /* ================================================================== */
--- a/lphobos/internal/objectimpl.d	Sun Nov 25 03:58:55 2007 +0100
+++ b/lphobos/internal/objectimpl.d	Sun Nov 25 18:55:52 2007 +0100
@@ -33,7 +33,8 @@
  */
 
 /*
- * This copy is modified to work with LLVMDC by Tomas Lindquist Olsen 2007
+ * This copy is modified to work with LLVMDC
+ * by Tomas Lindquist Olsen, September 2007
  */
 
 module object;
@@ -1120,6 +1121,30 @@
 }
 
 /**
+ * Information about each module.
+ */
+class ModuleInfo
+{
+    char[] name;
+    ModuleInfo[] importedModules;
+    ClassInfo[] localClasses;
+
+    uint flags;     // initialization state
+
+    void function() ctor;
+    void function() dtor;
+    void function() unitTest;
+
+    /******************
+     * Return collection of all modules in the program.
+     */
+    static ModuleInfo[] modules()
+    {
+    return std.moduleinit._moduleinfo_array;
+    }
+}
+
+/**
  * All recoverable exceptions should be derived from class Exception.
  */
 class Exception : Object
--- a/lphobos/object.d	Sun Nov 25 03:58:55 2007 +0100
+++ b/lphobos/object.d	Sun Nov 25 18:55:52 2007 +0100
@@ -162,6 +162,22 @@
 {
 }
 
+class ModuleInfo
+{
+    char[] name;
+    ModuleInfo[] importedModules;
+    ClassInfo[] localClasses;
+
+    uint flags;     // initialization state
+
+    void function() ctor;
+    void function() dtor;
+    void function() unitTest;
+
+    // Return collection of all modules in the program.
+    static ModuleInfo[] modules();
+}
+
 // Recoverable errors
 
 class Exception : Object
--- a/lphobos/std/moduleinit.d	Sun Nov 25 03:58:55 2007 +0100
+++ b/lphobos/std/moduleinit.d	Sun Nov 25 18:55:52 2007 +0100
@@ -18,29 +18,8 @@
 			// ctors being done first
 }
 
-/***********************
- * Information about each module.
- */
-class ModuleInfo
-{
-    char[] name;
-    ModuleInfo[] importedModules;
-    ClassInfo[] localClasses;
-
-    uint flags;		// initialization state
-
-    void function() ctor;
-    void function() dtor;
-    void function() unitTest;
-
-    /******************
-     * Return collection of all modules in the program.
-     */
-    static ModuleInfo[] modules()
-    {
-	return _moduleinfo_array;
-    }
-}
+// had to move the class to object.d, as its declaration is needed in the compiler code,
+// otherwise the DMDFE Module::moduleinfo member is NULL
 
 class ModuleCtorError : Exception
 {
--- a/test/bug51.d	Sun Nov 25 03:58:55 2007 +0100
+++ b/test/bug51.d	Sun Nov 25 18:55:52 2007 +0100
@@ -1,7 +1,10 @@
 module bug51;
-const ubyte[3] arr1 = 0;
-const ubyte[3] arr2 = [0];
+const ubyte[3] arr1 = 1;
+const ubyte[3] arr2 = [1];
 const ubyte[3] arr3 = [1:1];
 void main()
 {
+    assert(arr1 == [cast(ubyte)1,1,1][]);
+    assert(arr2 == [cast(ubyte)1,0,0][]);
+    assert(arr3 == [cast(ubyte)0,1,0][]);
 }
--- a/test/moduleinfo1.d	Sun Nov 25 03:58:55 2007 +0100
+++ b/test/moduleinfo1.d	Sun Nov 25 18:55:52 2007 +0100
@@ -1,11 +1,36 @@
 module moduleinfo1;
 
+// has static this
+import std.outofmemory;
+
+static this()
+{
+}
+
+static this()
+{
+}
+
+static ~this()
+{
+}
+
+static ~this()
+{
+}
+
+unittest
+{
+}
+
 class C
 {
 }
 
+class D : C
+{
+}
+
 void main()
 {
-    C c;
 }
-