Home | History | Annotate | Line # | Download | only in rt
minfo.d revision 1.1
      1  1.1  mrg /**
      2  1.1  mrg  * Written in the D programming language.
      3  1.1  mrg  * Module initialization routines.
      4  1.1  mrg  *
      5  1.1  mrg  * Copyright: Copyright Digital Mars 2000 - 2013.
      6  1.1  mrg  * License: Distributed under the
      7  1.1  mrg  *      $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
      8  1.1  mrg  *    (See accompanying file LICENSE)
      9  1.1  mrg  * Authors:   Walter Bright, Sean Kelly
     10  1.1  mrg  * Source: $(DRUNTIMESRC src/rt/_minfo.d)
     11  1.1  mrg  */
     12  1.1  mrg 
     13  1.1  mrg module rt.minfo;
     14  1.1  mrg 
     15  1.1  mrg import core.stdc.stdlib;  // alloca
     16  1.1  mrg import core.stdc.string;  // memcpy
     17  1.1  mrg import rt.sections;
     18  1.1  mrg 
     19  1.1  mrg enum
     20  1.1  mrg {
     21  1.1  mrg     MIctorstart  = 0x1,   // we've started constructing it
     22  1.1  mrg     MIctordone   = 0x2,   // finished construction
     23  1.1  mrg     MIstandalone = 0x4,   // module ctor does not depend on other module
     24  1.1  mrg                         // ctors being done first
     25  1.1  mrg     MItlsctor    = 8,
     26  1.1  mrg     MItlsdtor    = 0x10,
     27  1.1  mrg     MIctor       = 0x20,
     28  1.1  mrg     MIdtor       = 0x40,
     29  1.1  mrg     MIxgetMembers = 0x80,
     30  1.1  mrg     MIictor      = 0x100,
     31  1.1  mrg     MIunitTest   = 0x200,
     32  1.1  mrg     MIimportedModules = 0x400,
     33  1.1  mrg     MIlocalClasses = 0x800,
     34  1.1  mrg     MIname       = 0x1000,
     35  1.1  mrg }
     36  1.1  mrg 
     37  1.1  mrg /*****
     38  1.1  mrg  * A ModuleGroup is an unordered collection of modules.
     39  1.1  mrg  * There is exactly one for:
     40  1.1  mrg  *  1. all statically linked in D modules, either directely or as shared libraries
     41  1.1  mrg  *  2. each call to rt_loadLibrary()
     42  1.1  mrg  */
     43  1.1  mrg 
     44  1.1  mrg struct ModuleGroup
     45  1.1  mrg {
     46  1.1  mrg     this(immutable(ModuleInfo*)[] modules) nothrow @nogc
     47  1.1  mrg     {
     48  1.1  mrg         _modules = modules;
     49  1.1  mrg     }
     50  1.1  mrg 
     51  1.1  mrg     @property immutable(ModuleInfo*)[] modules() const nothrow @nogc
     52  1.1  mrg     {
     53  1.1  mrg         return _modules;
     54  1.1  mrg     }
     55  1.1  mrg 
     56  1.1  mrg     // this function initializes the bookeeping necessary to create the
     57  1.1  mrg     // cycle path, and then creates it. It is a precondition that src and
     58  1.1  mrg     // target modules are involved in a cycle.
     59  1.1  mrg     //
     60  1.1  mrg     // The return value is malloc'd using C, so it must be freed after use.
     61  1.1  mrg     private size_t[] genCyclePath(size_t srcidx, size_t targetidx, int[][] edges)
     62  1.1  mrg     {
     63  1.1  mrg         import core.bitop : bt, btc, bts;
     64  1.1  mrg 
     65  1.1  mrg         // set up all the arrays.
     66  1.1  mrg         size_t[] cyclePath = (cast(size_t*)malloc(size_t.sizeof * _modules.length * 2))[0 .. _modules.length * 2];
     67  1.1  mrg         size_t totalMods;
     68  1.1  mrg         int[] distance = (cast(int*)malloc(int.sizeof * _modules.length))[0 .. _modules.length];
     69  1.1  mrg         scope(exit)
     70  1.1  mrg             .free(distance.ptr);
     71  1.1  mrg 
     72  1.1  mrg         // determine the shortest path between two modules. Uses dijkstra
     73  1.1  mrg         // without a priority queue. (we can be a bit slow here, in order to
     74  1.1  mrg         // get a better printout).
     75  1.1  mrg         void shortest(size_t start, size_t target)
     76  1.1  mrg         {
     77  1.1  mrg             // initial setup
     78  1.1  mrg             distance[] = int.max;
     79  1.1  mrg             int curdist = 0;
     80  1.1  mrg             distance[start] = 0;
     81  1.1  mrg             while (true)
     82  1.1  mrg             {
     83  1.1  mrg                 bool done = true;
     84  1.1  mrg                 foreach (i, x; distance)
     85  1.1  mrg                 {
     86  1.1  mrg                     if (x == curdist)
     87  1.1  mrg                     {
     88  1.1  mrg                         if (i == target)
     89  1.1  mrg                         {
     90  1.1  mrg                             done = true;
     91  1.1  mrg                             break;
     92  1.1  mrg                         }
     93  1.1  mrg                         foreach (n; edges[i])
     94  1.1  mrg                         {
     95  1.1  mrg                             if (distance[n] == int.max)
     96  1.1  mrg                             {
     97  1.1  mrg                                 distance[n] = curdist + 1;
     98  1.1  mrg                                 done = false;
     99  1.1  mrg                             }
    100  1.1  mrg                         }
    101  1.1  mrg                     }
    102  1.1  mrg                 }
    103  1.1  mrg                 if (done)
    104  1.1  mrg                     break;
    105  1.1  mrg                 ++curdist;
    106  1.1  mrg             }
    107  1.1  mrg             // it should be impossible to not get to target, this is just a
    108  1.1  mrg             // sanity check. Not an assert, because druntime is compiled in
    109  1.1  mrg             // release mode.
    110  1.1  mrg             if (distance[target] != curdist)
    111  1.1  mrg             {
    112  1.1  mrg                 throw new Error("internal error printing module cycle");
    113  1.1  mrg             }
    114  1.1  mrg 
    115  1.1  mrg             // determine the path. This is tricky, because we have to
    116  1.1  mrg             // follow the edges in reverse to get back to the original. We
    117  1.1  mrg             // don't have a reverse mapping, so it takes a bit of looping.
    118  1.1  mrg             totalMods += curdist;
    119  1.1  mrg             auto subpath = cyclePath[totalMods - curdist .. totalMods];
    120  1.1  mrg             while (true)
    121  1.1  mrg             {
    122  1.1  mrg                 --curdist;
    123  1.1  mrg                 subpath[curdist] = target;
    124  1.1  mrg                 if (curdist == 0)
    125  1.1  mrg                     break;
    126  1.1  mrg             distloop:
    127  1.1  mrg                 // search for next (previous) module in cycle.
    128  1.1  mrg                 foreach (int m, d; distance)
    129  1.1  mrg                 {
    130  1.1  mrg                     if (d == curdist)
    131  1.1  mrg                     {
    132  1.1  mrg                         // determine if m can reach target
    133  1.1  mrg                         foreach (e; edges[m])
    134  1.1  mrg                         {
    135  1.1  mrg                             if (e == target)
    136  1.1  mrg                             {
    137  1.1  mrg                                 // recurse
    138  1.1  mrg                                 target = m;
    139  1.1  mrg                                 break distloop;
    140  1.1  mrg                             }
    141  1.1  mrg                         }
    142  1.1  mrg                     }
    143  1.1  mrg                 }
    144  1.1  mrg             }
    145  1.1  mrg         }
    146  1.1  mrg 
    147  1.1  mrg         // first get to the target
    148  1.1  mrg         shortest(srcidx, targetidx);
    149  1.1  mrg         // now get back.
    150  1.1  mrg         shortest(targetidx, srcidx);
    151  1.1  mrg 
    152  1.1  mrg         return cyclePath[0 .. totalMods];
    153  1.1  mrg     }
    154  1.1  mrg 
    155  1.1  mrg     /******************************
    156  1.1  mrg      * Allocate and fill in _ctors[] and _tlsctors[].
    157  1.1  mrg      * Modules are inserted into the arrays in the order in which the constructors
    158  1.1  mrg      * need to be run.
    159  1.1  mrg      *
    160  1.1  mrg      * Params:
    161  1.1  mrg      *  cycleHandling - string indicating option for cycle handling
    162  1.1  mrg      * Throws:
    163  1.1  mrg      *  Exception if it fails.
    164  1.1  mrg      */
    165  1.1  mrg     void sortCtors(string cycleHandling)
    166  1.1  mrg     {
    167  1.1  mrg         import core.bitop : bts, btr, bt, BitRange;
    168  1.1  mrg         import rt.util.container.hashtab;
    169  1.1  mrg 
    170  1.1  mrg         enum OnCycle
    171  1.1  mrg         {
    172  1.1  mrg             deprecate,
    173  1.1  mrg             abort,
    174  1.1  mrg             print,
    175  1.1  mrg             ignore
    176  1.1  mrg         }
    177  1.1  mrg 
    178  1.1  mrg         auto onCycle = OnCycle.abort;
    179  1.1  mrg 
    180  1.1  mrg         switch (cycleHandling) with(OnCycle)
    181  1.1  mrg         {
    182  1.1  mrg         case "deprecate":
    183  1.1  mrg             onCycle = deprecate;
    184  1.1  mrg             break;
    185  1.1  mrg         case "abort":
    186  1.1  mrg             onCycle = abort;
    187  1.1  mrg             break;
    188  1.1  mrg         case "print":
    189  1.1  mrg             onCycle = print;
    190  1.1  mrg             break;
    191  1.1  mrg         case "ignore":
    192  1.1  mrg             onCycle = ignore;
    193  1.1  mrg             break;
    194  1.1  mrg         case "":
    195  1.1  mrg             // no option passed
    196  1.1  mrg             break;
    197  1.1  mrg         default:
    198  1.1  mrg             // invalid cycle handling option.
    199  1.1  mrg             throw new Error("DRT invalid cycle handling option: " ~ cycleHandling);
    200  1.1  mrg         }
    201  1.1  mrg 
    202  1.1  mrg         debug (printModuleDependencies)
    203  1.1  mrg         {
    204  1.1  mrg             import core.stdc.stdio : printf;
    205  1.1  mrg 
    206  1.1  mrg             foreach (_m; _modules)
    207  1.1  mrg             {
    208  1.1  mrg                 printf("%s%s%s:", _m.name.ptr, (_m.flags & MIstandalone)
    209  1.1  mrg                         ? "+".ptr : "".ptr, (_m.flags & (MIctor | MIdtor)) ? "*".ptr : "".ptr);
    210  1.1  mrg                 foreach (_i; _m.importedModules)
    211  1.1  mrg                     printf(" %s", _i.name.ptr);
    212  1.1  mrg                 printf("\n");
    213  1.1  mrg             }
    214  1.1  mrg         }
    215  1.1  mrg 
    216  1.1  mrg         immutable uint len = cast(uint) _modules.length;
    217  1.1  mrg         if (!len)
    218  1.1  mrg             return; // nothing to do.
    219  1.1  mrg 
    220  1.1  mrg         // allocate some stack arrays that will be used throughout the process.
    221  1.1  mrg         immutable nwords = (len + 8 * size_t.sizeof - 1) / (8 * size_t.sizeof);
    222  1.1  mrg         immutable flagbytes = nwords * size_t.sizeof;
    223  1.1  mrg         auto ctorstart = cast(size_t*) malloc(flagbytes); // ctor/dtor seen
    224  1.1  mrg         auto ctordone = cast(size_t*) malloc(flagbytes); // ctor/dtor processed
    225  1.1  mrg         auto relevant = cast(size_t*) malloc(flagbytes); // has ctors/dtors
    226  1.1  mrg         scope (exit)
    227  1.1  mrg         {
    228  1.1  mrg             .free(ctorstart);
    229  1.1  mrg             .free(ctordone);
    230  1.1  mrg             .free(relevant);
    231  1.1  mrg         }
    232  1.1  mrg 
    233  1.1  mrg         void clearFlags(size_t* flags)
    234  1.1  mrg         {
    235  1.1  mrg             memset(flags, 0, flagbytes);
    236  1.1  mrg         }
    237  1.1  mrg 
    238  1.1  mrg 
    239  1.1  mrg         // build the edges between each module. We may need this for printing,
    240  1.1  mrg         // and also allows avoiding keeping a hash around for module lookups.
    241  1.1  mrg         int[][] edges = (cast(int[]*)malloc((int[]).sizeof * _modules.length))[0 .. _modules.length];
    242  1.1  mrg         {
    243  1.1  mrg             HashTab!(immutable(ModuleInfo)*, int) modIndexes;
    244  1.1  mrg             foreach (i, m; _modules)
    245  1.1  mrg                 modIndexes[m] = cast(int) i;
    246  1.1  mrg 
    247  1.1  mrg             auto reachable = cast(size_t*) malloc(flagbytes);
    248  1.1  mrg             scope(exit)
    249  1.1  mrg                 .free(reachable);
    250  1.1  mrg 
    251  1.1  mrg             foreach (i, m; _modules)
    252  1.1  mrg             {
    253  1.1  mrg                 // use bit array to prevent duplicates
    254  1.1  mrg                 // https://issues.dlang.org/show_bug.cgi?id=16208
    255  1.1  mrg                 clearFlags(reachable);
    256  1.1  mrg                 // preallocate enough space to store all the indexes
    257  1.1  mrg                 int *edge = cast(int*)malloc(int.sizeof * _modules.length);
    258  1.1  mrg                 size_t nEdges = 0;
    259  1.1  mrg                 foreach (imp; m.importedModules)
    260  1.1  mrg                 {
    261  1.1  mrg                     if (imp is m) // self-import
    262  1.1  mrg                         continue;
    263  1.1  mrg                     if (auto impidx = imp in modIndexes)
    264  1.1  mrg                     {
    265  1.1  mrg                         if (!bts(reachable, *impidx))
    266  1.1  mrg                             edge[nEdges++] = *impidx;
    267  1.1  mrg                     }
    268  1.1  mrg                 }
    269  1.1  mrg                 // trim space to what is needed.
    270  1.1  mrg                 edges[i] = (cast(int*)realloc(edge, int.sizeof * nEdges))[0 .. nEdges];
    271  1.1  mrg             }
    272  1.1  mrg         }
    273  1.1  mrg 
    274  1.1  mrg         // free all the edges after we are done
    275  1.1  mrg         scope(exit)
    276  1.1  mrg         {
    277  1.1  mrg             foreach (e; edges)
    278  1.1  mrg                 if (e.ptr)
    279  1.1  mrg                     .free(e.ptr);
    280  1.1  mrg             .free(edges.ptr);
    281  1.1  mrg         }
    282  1.1  mrg 
    283  1.1  mrg         void buildCycleMessage(size_t sourceIdx, size_t cycleIdx, scope void delegate(string) sink)
    284  1.1  mrg         {
    285  1.1  mrg             version (Windows)
    286  1.1  mrg                 enum EOL = "\r\n";
    287  1.1  mrg             else
    288  1.1  mrg                 enum EOL = "\n";
    289  1.1  mrg 
    290  1.1  mrg             sink("Cyclic dependency between module ");
    291  1.1  mrg             sink(_modules[sourceIdx].name);
    292  1.1  mrg             sink(" and ");
    293  1.1  mrg             sink(_modules[cycleIdx].name);
    294  1.1  mrg             sink(EOL);
    295  1.1  mrg             auto cyclePath = genCyclePath(sourceIdx, cycleIdx, edges);
    296  1.1  mrg             scope(exit) .free(cyclePath.ptr);
    297  1.1  mrg 
    298  1.1  mrg             sink(_modules[sourceIdx].name);
    299  1.1  mrg             sink("* ->" ~ EOL);
    300  1.1  mrg             foreach (x; cyclePath[0 .. $ - 1])
    301  1.1  mrg             {
    302  1.1  mrg                 sink(_modules[x].name);
    303  1.1  mrg                 sink(bt(relevant, x) ? "* ->" ~ EOL : " ->" ~ EOL);
    304  1.1  mrg             }
    305  1.1  mrg             sink(_modules[sourceIdx].name);
    306  1.1  mrg             sink("*" ~ EOL);
    307  1.1  mrg         }
    308  1.1  mrg 
    309  1.1  mrg         // find all the non-trivial dependencies (that is, dependencies that have a
    310  1.1  mrg         // ctor or dtor) of a given module.  Doing this, we can 'skip over' the
    311  1.1  mrg         // trivial modules to get at the non-trivial ones.
    312  1.1  mrg         //
    313  1.1  mrg         // If a cycle is detected, returns the index of the module that completes the cycle.
    314  1.1  mrg         // Returns: true for success, false for a deprecated cycle error
    315  1.1  mrg         bool findDeps(size_t idx, size_t* reachable)
    316  1.1  mrg         {
    317  1.1  mrg             static struct stackFrame
    318  1.1  mrg             {
    319  1.1  mrg                 size_t curMod;
    320  1.1  mrg                 size_t curDep;
    321  1.1  mrg             }
    322  1.1  mrg 
    323  1.1  mrg             // initialize "stack"
    324  1.1  mrg             auto stack = cast(stackFrame*) malloc(stackFrame.sizeof * len);
    325  1.1  mrg             scope (exit)
    326  1.1  mrg                 .free(stack);
    327  1.1  mrg             auto stacktop = stack + len;
    328  1.1  mrg             auto sp = stack;
    329  1.1  mrg             sp.curMod = cast(int) idx;
    330  1.1  mrg             sp.curDep = 0;
    331  1.1  mrg 
    332  1.1  mrg             // initialize reachable by flagging source module
    333  1.1  mrg             clearFlags(reachable);
    334  1.1  mrg             bts(reachable, idx);
    335  1.1  mrg 
    336  1.1  mrg             for (;;)
    337  1.1  mrg             {
    338  1.1  mrg                 auto m = _modules[sp.curMod];
    339  1.1  mrg                 if (sp.curDep >= edges[sp.curMod].length)
    340  1.1  mrg                 {
    341  1.1  mrg                     // return
    342  1.1  mrg                     if (sp == stack) // finished the algorithm
    343  1.1  mrg                         break;
    344  1.1  mrg                     --sp;
    345  1.1  mrg                 }
    346  1.1  mrg                 else
    347  1.1  mrg                 {
    348  1.1  mrg                     auto midx = edges[sp.curMod][sp.curDep];
    349  1.1  mrg                     if (!bts(reachable, midx))
    350  1.1  mrg                     {
    351  1.1  mrg                         if (bt(relevant, midx))
    352  1.1  mrg                         {
    353  1.1  mrg                             // need to process this node, don't recurse.
    354  1.1  mrg                             if (bt(ctorstart, midx))
    355  1.1  mrg                             {
    356  1.1  mrg                                 // was already started, this is a cycle.
    357  1.1  mrg                                 final switch (onCycle) with(OnCycle)
    358  1.1  mrg                                 {
    359  1.1  mrg                                 case deprecate:
    360  1.1  mrg                                     // check with old algorithm
    361  1.1  mrg                                     if (sortCtorsOld(edges))
    362  1.1  mrg                                     {
    363  1.1  mrg                                         // unwind to print deprecation message.
    364  1.1  mrg                                         return false;   // deprecated cycle error
    365  1.1  mrg                                     }
    366  1.1  mrg                                     goto case abort; // fall through
    367  1.1  mrg                                 case abort:
    368  1.1  mrg 
    369  1.1  mrg                                     string errmsg = "";
    370  1.1  mrg                                     buildCycleMessage(idx, midx, (string x) {errmsg ~= x;});
    371  1.1  mrg                                     throw new Error(errmsg, __FILE__, __LINE__);
    372  1.1  mrg                                 case ignore:
    373  1.1  mrg                                     break;
    374  1.1  mrg                                 case print:
    375  1.1  mrg                                     // print the message
    376  1.1  mrg                                     buildCycleMessage(idx, midx, (string x) {
    377  1.1  mrg                                                       import core.stdc.stdio : fprintf, stderr;
    378  1.1  mrg                                                       fprintf(stderr, "%.*s", cast(int) x.length, x.ptr);
    379  1.1  mrg                                                       });
    380  1.1  mrg                                     // continue on as if this is correct.
    381  1.1  mrg                                     break;
    382  1.1  mrg                                 }
    383  1.1  mrg                             }
    384  1.1  mrg                         }
    385  1.1  mrg                         else if (!bt(ctordone, midx))
    386  1.1  mrg                         {
    387  1.1  mrg                             // non-relevant, and hasn't been exhaustively processed, recurse.
    388  1.1  mrg                             if (++sp >= stacktop)
    389  1.1  mrg                             {
    390  1.1  mrg                                 // stack overflow, this shouldn't happen.
    391  1.1  mrg                                 import core.internal.abort : abort;
    392  1.1  mrg 
    393  1.1  mrg                                 abort("stack overflow on dependency search");
    394  1.1  mrg                             }
    395  1.1  mrg                             sp.curMod = midx;
    396  1.1  mrg                             sp.curDep = 0;
    397  1.1  mrg                             continue;
    398  1.1  mrg                         }
    399  1.1  mrg                     }
    400  1.1  mrg                 }
    401  1.1  mrg 
    402  1.1  mrg                 // next dependency
    403  1.1  mrg                 ++sp.curDep;
    404  1.1  mrg             }
    405  1.1  mrg             return true; // success
    406  1.1  mrg         }
    407  1.1  mrg 
    408  1.1  mrg         // The list of constructors that will be returned by the sorting.
    409  1.1  mrg         immutable(ModuleInfo)** ctors;
    410  1.1  mrg         // current element being inserted into ctors list.
    411  1.1  mrg         size_t ctoridx = 0;
    412  1.1  mrg 
    413  1.1  mrg         // This function will determine the order of construction/destruction and
    414  1.1  mrg         // check for cycles. If a cycle is found, the cycle path is transformed
    415  1.1  mrg         // into a string and thrown as an error.
    416  1.1  mrg         //
    417  1.1  mrg         // Each call into this function is given a module that has static
    418  1.1  mrg         // ctor/dtors that must be dealt with. It recurses only when it finds
    419  1.1  mrg         // dependencies that also have static ctor/dtors.
    420  1.1  mrg         // Returns: true for success, false for a deprecated cycle error
    421  1.1  mrg         bool processMod(size_t curidx)
    422  1.1  mrg         {
    423  1.1  mrg             immutable ModuleInfo* current = _modules[curidx];
    424  1.1  mrg 
    425  1.1  mrg             // First, determine what modules are reachable.
    426  1.1  mrg             auto reachable = cast(size_t*) malloc(flagbytes);
    427  1.1  mrg             scope (exit)
    428  1.1  mrg                 .free(reachable);
    429  1.1  mrg             if (!findDeps(curidx, reachable))
    430  1.1  mrg                 return false;   // deprecated cycle error
    431  1.1  mrg 
    432  1.1  mrg             // process the dependencies. First, we process all relevant ones
    433  1.1  mrg             bts(ctorstart, curidx);
    434  1.1  mrg             auto brange = BitRange(reachable, len);
    435  1.1  mrg             foreach (i; brange)
    436  1.1  mrg             {
    437  1.1  mrg                 // note, don't check for cycles here, because the config could have been set to ignore cycles.
    438  1.1  mrg                 // however, don't recurse if there is one, so still check for started ctor.
    439  1.1  mrg                 if (i != curidx && bt(relevant, i) && !bt(ctordone, i) && !bt(ctorstart, i))
    440  1.1  mrg                 {
    441  1.1  mrg                     if (!processMod(i))
    442  1.1  mrg                         return false; // deprecated cycle error
    443  1.1  mrg                 }
    444  1.1  mrg             }
    445  1.1  mrg 
    446  1.1  mrg             // now mark this node, and all nodes reachable from this module as done.
    447  1.1  mrg             bts(ctordone, curidx);
    448  1.1  mrg             btr(ctorstart, curidx);
    449  1.1  mrg             foreach (i; brange)
    450  1.1  mrg             {
    451  1.1  mrg                 // Since relevant dependencies are already marked as done
    452  1.1  mrg                 // from recursion above (or are going to be handled up the call
    453  1.1  mrg                 // stack), no reason to check for relevance, that is a wasted
    454  1.1  mrg                 // op.
    455  1.1  mrg                 bts(ctordone, i);
    456  1.1  mrg             }
    457  1.1  mrg 
    458  1.1  mrg             // add this module to the construction order list
    459  1.1  mrg             ctors[ctoridx++] = current;
    460  1.1  mrg             return true;
    461  1.1  mrg         }
    462  1.1  mrg 
    463  1.1  mrg         // returns `false` if deprecated cycle error otherwise set `result`.
    464  1.1  mrg         bool doSort(size_t relevantFlags, ref immutable(ModuleInfo)*[] result)
    465  1.1  mrg         {
    466  1.1  mrg             clearFlags(relevant);
    467  1.1  mrg             clearFlags(ctorstart);
    468  1.1  mrg             clearFlags(ctordone);
    469  1.1  mrg 
    470  1.1  mrg             // pre-allocate enough space to hold all modules.
    471  1.1  mrg             ctors = (cast(immutable(ModuleInfo)**).malloc(len * (void*).sizeof));
    472  1.1  mrg             ctoridx = 0;
    473  1.1  mrg             foreach (int idx, m; _modules)
    474  1.1  mrg             {
    475  1.1  mrg                 if (m.flags & relevantFlags)
    476  1.1  mrg                 {
    477  1.1  mrg                     if (m.flags & MIstandalone)
    478  1.1  mrg                     {
    479  1.1  mrg                         // can run at any time. Just run it first.
    480  1.1  mrg                         ctors[ctoridx++] = m;
    481  1.1  mrg                     }
    482  1.1  mrg                     else
    483  1.1  mrg                     {
    484  1.1  mrg                         bts(relevant, idx);
    485  1.1  mrg                     }
    486  1.1  mrg                 }
    487  1.1  mrg             }
    488  1.1  mrg 
    489  1.1  mrg             // now run the algorithm in the relevant ones
    490  1.1  mrg             foreach (idx; BitRange(relevant, len))
    491  1.1  mrg             {
    492  1.1  mrg                 if (!bt(ctordone, idx))
    493  1.1  mrg                 {
    494  1.1  mrg                     if (!processMod(idx))
    495  1.1  mrg                         return false;
    496  1.1  mrg                 }
    497  1.1  mrg             }
    498  1.1  mrg 
    499  1.1  mrg             if (ctoridx == 0)
    500  1.1  mrg             {
    501  1.1  mrg                 // no ctors in the list.
    502  1.1  mrg                 .free(ctors);
    503  1.1  mrg             }
    504  1.1  mrg             else
    505  1.1  mrg             {
    506  1.1  mrg                 ctors = cast(immutable(ModuleInfo)**).realloc(ctors, ctoridx * (void*).sizeof);
    507  1.1  mrg                 if (ctors is null)
    508  1.1  mrg                     assert(0);
    509  1.1  mrg                 result = ctors[0 .. ctoridx];
    510  1.1  mrg             }
    511  1.1  mrg             return true;
    512  1.1  mrg         }
    513  1.1  mrg 
    514  1.1  mrg         // finally, do the sorting for both shared and tls ctors. If either returns false,
    515  1.1  mrg         // print the deprecation warning.
    516  1.1  mrg         if (!doSort(MIctor | MIdtor, _ctors) ||
    517  1.1  mrg             !doSort(MItlsctor | MItlsdtor, _tlsctors))
    518  1.1  mrg         {
    519  1.1  mrg             // print a warning
    520  1.1  mrg             import core.stdc.stdio : fprintf, stderr;
    521  1.1  mrg             fprintf(stderr, "Deprecation 16211 warning:\n"
    522  1.1  mrg                 ~ "A cycle has been detected in your program that was undetected prior to DMD\n"
    523  1.1  mrg                 ~ "2.072. This program will continue, but will not operate when using DMD 2.074\n"
    524  1.1  mrg                 ~ "to compile. Use runtime option --DRT-oncycle=print to see the cycle details.\n");
    525  1.1  mrg 
    526  1.1  mrg         }
    527  1.1  mrg     }
    528  1.1  mrg 
    529  1.1  mrg     /// ditto
    530  1.1  mrg     void sortCtors()
    531  1.1  mrg     {
    532  1.1  mrg         import rt.config : rt_configOption;
    533  1.1  mrg         sortCtors(rt_configOption("oncycle"));
    534  1.1  mrg     }
    535  1.1  mrg 
    536  1.1  mrg     /******************************
    537  1.1  mrg      * This is the old ctor sorting algorithm that does not find all cycles.
    538  1.1  mrg      *
    539  1.1  mrg      * It is here to allow the deprecated behavior from the original algorithm
    540  1.1  mrg      * until people have fixed their code.
    541  1.1  mrg      *
    542  1.1  mrg      * If no cycles are found, the _ctors and _tlsctors are replaced with the
    543  1.1  mrg      * ones generated by this algorithm to preserve the old incorrect ordering
    544  1.1  mrg      * behavior.
    545  1.1  mrg      *
    546  1.1  mrg      * Params:
    547  1.1  mrg      *   edges - The module edges as found in the `importedModules` member of
    548  1.1  mrg      *          each ModuleInfo. Generated in sortCtors.
    549  1.1  mrg      * Returns:
    550  1.1  mrg      *   true if no cycle is found, false if one was.
    551  1.1  mrg      */
    552  1.1  mrg     bool sortCtorsOld(int[][] edges)
    553  1.1  mrg     {
    554  1.1  mrg         immutable len = edges.length;
    555  1.1  mrg         assert(len == _modules.length);
    556  1.1  mrg 
    557  1.1  mrg         static struct StackRec
    558  1.1  mrg         {
    559  1.1  mrg             @property int mod()
    560  1.1  mrg             {
    561  1.1  mrg                 return _mods[_idx];
    562  1.1  mrg             }
    563  1.1  mrg 
    564  1.1  mrg             int[] _mods;
    565  1.1  mrg             size_t         _idx;
    566  1.1  mrg         }
    567  1.1  mrg 
    568  1.1  mrg         auto stack = (cast(StackRec*).calloc(len, StackRec.sizeof))[0 .. len];
    569  1.1  mrg         // TODO: reuse GCBits by moving it to rt.util.container or core.internal
    570  1.1  mrg         immutable nwords = (len + 8 * size_t.sizeof - 1) / (8 * size_t.sizeof);
    571  1.1  mrg         auto ctorstart = cast(size_t*).malloc(nwords * size_t.sizeof);
    572  1.1  mrg         auto ctordone = cast(size_t*).malloc(nwords * size_t.sizeof);
    573  1.1  mrg         int[] initialEdges = (cast(int *)malloc(int.sizeof * len))[0 .. len];
    574  1.1  mrg         if (!stack.ptr || ctorstart is null || ctordone is null || !initialEdges.ptr)
    575  1.1  mrg             assert(0);
    576  1.1  mrg         scope (exit)
    577  1.1  mrg         {
    578  1.1  mrg             .free(stack.ptr);
    579  1.1  mrg             .free(ctorstart);
    580  1.1  mrg             .free(ctordone);
    581  1.1  mrg             .free(initialEdges.ptr);
    582  1.1  mrg         }
    583  1.1  mrg 
    584  1.1  mrg         // initialize the initial edges
    585  1.1  mrg         foreach (int i, ref v; initialEdges)
    586  1.1  mrg             v = i;
    587  1.1  mrg 
    588  1.1  mrg         bool sort(ref immutable(ModuleInfo)*[] ctors, uint mask)
    589  1.1  mrg         {
    590  1.1  mrg             import core.bitop;
    591  1.1  mrg 
    592  1.1  mrg             ctors = (cast(immutable(ModuleInfo)**).malloc(len * size_t.sizeof))[0 .. len];
    593  1.1  mrg             if (!ctors.ptr)
    594  1.1  mrg                 assert(0);
    595  1.1  mrg 
    596  1.1  mrg             // clean flags
    597  1.1  mrg             memset(ctorstart, 0, nwords * size_t.sizeof);
    598  1.1  mrg             memset(ctordone, 0, nwords * size_t.sizeof);
    599  1.1  mrg             size_t stackidx = 0;
    600  1.1  mrg             size_t cidx;
    601  1.1  mrg 
    602  1.1  mrg             int[] mods = initialEdges;
    603  1.1  mrg 
    604  1.1  mrg             size_t idx;
    605  1.1  mrg             while (true)
    606  1.1  mrg             {
    607  1.1  mrg                 while (idx < mods.length)
    608  1.1  mrg                 {
    609  1.1  mrg                     auto m = mods[idx];
    610  1.1  mrg 
    611  1.1  mrg                     if (bt(ctordone, m))
    612  1.1  mrg                     {
    613  1.1  mrg                         // this module has already been processed, skip
    614  1.1  mrg                         ++idx;
    615  1.1  mrg                         continue;
    616  1.1  mrg                     }
    617  1.1  mrg                     else if (bt(ctorstart, m))
    618  1.1  mrg                     {
    619  1.1  mrg                         /* Trace back to the begin of the cycle.
    620  1.1  mrg                          */
    621  1.1  mrg                         bool ctorInCycle;
    622  1.1  mrg                         size_t start = stackidx;
    623  1.1  mrg                         while (start--)
    624  1.1  mrg                         {
    625  1.1  mrg                             auto sm = stack[start].mod;
    626  1.1  mrg                             if (sm == m)
    627  1.1  mrg                                 break;
    628  1.1  mrg                             assert(sm >= 0);
    629  1.1  mrg                             if (bt(ctorstart, sm))
    630  1.1  mrg                                 ctorInCycle = true;
    631  1.1  mrg                         }
    632  1.1  mrg                         assert(stack[start].mod == m);
    633  1.1  mrg                         if (ctorInCycle)
    634  1.1  mrg                         {
    635  1.1  mrg                             return false;
    636  1.1  mrg                         }
    637  1.1  mrg                         else
    638  1.1  mrg                         {
    639  1.1  mrg                             /* This is also a cycle, but the import chain does not constrain
    640  1.1  mrg                              * the order of initialization, either because the imported
    641  1.1  mrg                              * modules have no ctors or the ctors are standalone.
    642  1.1  mrg                              */
    643  1.1  mrg                             ++idx;
    644  1.1  mrg                         }
    645  1.1  mrg                     }
    646  1.1  mrg                     else
    647  1.1  mrg                     {
    648  1.1  mrg                         auto curmod = _modules[m];
    649  1.1  mrg                         if (curmod.flags & mask)
    650  1.1  mrg                         {
    651  1.1  mrg                             if (curmod.flags & MIstandalone || !edges[m].length)
    652  1.1  mrg                             {   // trivial ctor => sort in
    653  1.1  mrg                                 ctors[cidx++] = curmod;
    654  1.1  mrg                                 bts(ctordone, m);
    655  1.1  mrg                             }
    656  1.1  mrg                             else
    657  1.1  mrg                             {   // non-trivial ctor => defer
    658  1.1  mrg                                 bts(ctorstart, m);
    659  1.1  mrg                             }
    660  1.1  mrg                         }
    661  1.1  mrg                         else    // no ctor => mark as visited
    662  1.1  mrg                         {
    663  1.1  mrg                             bts(ctordone, m);
    664  1.1  mrg                         }
    665  1.1  mrg 
    666  1.1  mrg                         if (edges[m].length)
    667  1.1  mrg                         {
    668  1.1  mrg                             /* Internal runtime error, recursion exceeds number of modules.
    669  1.1  mrg                              */
    670  1.1  mrg                             (stackidx < len) || assert(0);
    671  1.1  mrg 
    672  1.1  mrg                             // recurse
    673  1.1  mrg                             stack[stackidx++] = StackRec(mods, idx);
    674  1.1  mrg                             idx  = 0;
    675  1.1  mrg                             mods = edges[m];
    676  1.1  mrg                         }
    677  1.1  mrg                     }
    678  1.1  mrg                 }
    679  1.1  mrg 
    680  1.1  mrg                 if (stackidx)
    681  1.1  mrg                 {   // pop old value from stack
    682  1.1  mrg                     --stackidx;
    683  1.1  mrg                     mods    = stack[stackidx]._mods;
    684  1.1  mrg                     idx     = stack[stackidx]._idx;
    685  1.1  mrg                     auto m  = mods[idx++];
    686  1.1  mrg                     if (bt(ctorstart, m) && !bts(ctordone, m))
    687  1.1  mrg                         ctors[cidx++] = _modules[m];
    688  1.1  mrg                 }
    689  1.1  mrg                 else // done
    690  1.1  mrg                     break;
    691  1.1  mrg             }
    692  1.1  mrg             // store final number and shrink array
    693  1.1  mrg             ctors = (cast(immutable(ModuleInfo)**).realloc(ctors.ptr, cidx * size_t.sizeof))[0 .. cidx];
    694  1.1  mrg             return true;
    695  1.1  mrg         }
    696  1.1  mrg 
    697  1.1  mrg         /* Do two passes: ctor/dtor, tlsctor/tlsdtor
    698  1.1  mrg          */
    699  1.1  mrg         immutable(ModuleInfo)*[] _ctors2;
    700  1.1  mrg         immutable(ModuleInfo)*[] _tlsctors2;
    701  1.1  mrg         auto result = sort(_ctors2, MIctor | MIdtor) && sort(_tlsctors2, MItlsctor | MItlsdtor);
    702  1.1  mrg         if (result) // no cycle
    703  1.1  mrg         {
    704  1.1  mrg             // fall back to original ordering as part of the deprecation.
    705  1.1  mrg             if (_ctors.ptr)
    706  1.1  mrg                 .free(_ctors.ptr);
    707  1.1  mrg             _ctors = _ctors2;
    708  1.1  mrg             if (_tlsctors.ptr)
    709  1.1  mrg                 .free(_tlsctors.ptr);
    710  1.1  mrg             _tlsctors = _tlsctors2;
    711  1.1  mrg         }
    712  1.1  mrg         else
    713  1.1  mrg         {
    714  1.1  mrg             // free any allocated memory that will be forgotten
    715  1.1  mrg             if (_ctors2.ptr)
    716  1.1  mrg                 .free(_ctors2.ptr);
    717  1.1  mrg             if (_tlsctors2.ptr)
    718  1.1  mrg                 .free(_tlsctors2.ptr);
    719  1.1  mrg         }
    720  1.1  mrg         return result;
    721  1.1  mrg     }
    722  1.1  mrg 
    723  1.1  mrg     void runCtors()
    724  1.1  mrg     {
    725  1.1  mrg         // run independent ctors
    726  1.1  mrg         runModuleFuncs!(m => m.ictor)(_modules);
    727  1.1  mrg         // sorted module ctors
    728  1.1  mrg         runModuleFuncs!(m => m.ctor)(_ctors);
    729  1.1  mrg     }
    730  1.1  mrg 
    731  1.1  mrg     void runTlsCtors()
    732  1.1  mrg     {
    733  1.1  mrg         runModuleFuncs!(m => m.tlsctor)(_tlsctors);
    734  1.1  mrg     }
    735  1.1  mrg 
    736  1.1  mrg     void runTlsDtors()
    737  1.1  mrg     {
    738  1.1  mrg         runModuleFuncsRev!(m => m.tlsdtor)(_tlsctors);
    739  1.1  mrg     }
    740  1.1  mrg 
    741  1.1  mrg     void runDtors()
    742  1.1  mrg     {
    743  1.1  mrg         runModuleFuncsRev!(m => m.dtor)(_ctors);
    744  1.1  mrg     }
    745  1.1  mrg 
    746  1.1  mrg     void free()
    747  1.1  mrg     {
    748  1.1  mrg         if (_ctors.ptr)
    749  1.1  mrg             .free(_ctors.ptr);
    750  1.1  mrg         _ctors = null;
    751  1.1  mrg         if (_tlsctors.ptr)
    752  1.1  mrg             .free(_tlsctors.ptr);
    753  1.1  mrg         _tlsctors = null;
    754  1.1  mrg         // _modules = null; // let the owner free it
    755  1.1  mrg     }
    756  1.1  mrg 
    757  1.1  mrg private:
    758  1.1  mrg     immutable(ModuleInfo*)[]  _modules;
    759  1.1  mrg     immutable(ModuleInfo)*[]    _ctors;
    760  1.1  mrg     immutable(ModuleInfo)*[] _tlsctors;
    761  1.1  mrg }
    762  1.1  mrg 
    763  1.1  mrg 
    764  1.1  mrg /********************************************
    765  1.1  mrg  * Iterate over all module infos.
    766  1.1  mrg  */
    767  1.1  mrg 
    768  1.1  mrg int moduleinfos_apply(scope int delegate(immutable(ModuleInfo*)) dg)
    769  1.1  mrg {
    770  1.1  mrg     foreach (ref sg; SectionGroup)
    771  1.1  mrg     {
    772  1.1  mrg         foreach (m; sg.modules)
    773  1.1  mrg         {
    774  1.1  mrg             // TODO: Should null ModuleInfo be allowed?
    775  1.1  mrg             if (m !is null)
    776  1.1  mrg             {
    777  1.1  mrg                 if (auto res = dg(m))
    778  1.1  mrg                     return res;
    779  1.1  mrg             }
    780  1.1  mrg         }
    781  1.1  mrg     }
    782  1.1  mrg     return 0;
    783  1.1  mrg }
    784  1.1  mrg 
    785  1.1  mrg /********************************************
    786  1.1  mrg  * Module constructor and destructor routines.
    787  1.1  mrg  */
    788  1.1  mrg 
    789  1.1  mrg extern (C)
    790  1.1  mrg {
    791  1.1  mrg void rt_moduleCtor()
    792  1.1  mrg {
    793  1.1  mrg     foreach (ref sg; SectionGroup)
    794  1.1  mrg     {
    795  1.1  mrg         sg.moduleGroup.sortCtors();
    796  1.1  mrg         sg.moduleGroup.runCtors();
    797  1.1  mrg     }
    798  1.1  mrg }
    799  1.1  mrg 
    800  1.1  mrg void rt_moduleTlsCtor()
    801  1.1  mrg {
    802  1.1  mrg     foreach (ref sg; SectionGroup)
    803  1.1  mrg     {
    804  1.1  mrg         sg.moduleGroup.runTlsCtors();
    805  1.1  mrg     }
    806  1.1  mrg }
    807  1.1  mrg 
    808  1.1  mrg void rt_moduleTlsDtor()
    809  1.1  mrg {
    810  1.1  mrg     foreach_reverse (ref sg; SectionGroup)
    811  1.1  mrg     {
    812  1.1  mrg         sg.moduleGroup.runTlsDtors();
    813  1.1  mrg     }
    814  1.1  mrg }
    815  1.1  mrg 
    816  1.1  mrg void rt_moduleDtor()
    817  1.1  mrg {
    818  1.1  mrg     foreach_reverse (ref sg; SectionGroup)
    819  1.1  mrg     {
    820  1.1  mrg         sg.moduleGroup.runDtors();
    821  1.1  mrg         sg.moduleGroup.free();
    822  1.1  mrg     }
    823  1.1  mrg }
    824  1.1  mrg 
    825  1.1  mrg version (Win32)
    826  1.1  mrg {
    827  1.1  mrg     // Alternate names for backwards compatibility with older DLL code
    828  1.1  mrg     void _moduleCtor()
    829  1.1  mrg     {
    830  1.1  mrg         rt_moduleCtor();
    831  1.1  mrg     }
    832  1.1  mrg 
    833  1.1  mrg     void _moduleDtor()
    834  1.1  mrg     {
    835  1.1  mrg         rt_moduleDtor();
    836  1.1  mrg     }
    837  1.1  mrg 
    838  1.1  mrg     void _moduleTlsCtor()
    839  1.1  mrg     {
    840  1.1  mrg         rt_moduleTlsCtor();
    841  1.1  mrg     }
    842  1.1  mrg 
    843  1.1  mrg     void _moduleTlsDtor()
    844  1.1  mrg     {
    845  1.1  mrg         rt_moduleTlsDtor();
    846  1.1  mrg     }
    847  1.1  mrg }
    848  1.1  mrg }
    849  1.1  mrg 
    850  1.1  mrg /********************************************
    851  1.1  mrg  */
    852  1.1  mrg 
    853  1.1  mrg void runModuleFuncs(alias getfp)(const(immutable(ModuleInfo)*)[] modules)
    854  1.1  mrg {
    855  1.1  mrg     foreach (m; modules)
    856  1.1  mrg     {
    857  1.1  mrg         if (auto fp = getfp(m))
    858  1.1  mrg             (*fp)();
    859  1.1  mrg     }
    860  1.1  mrg }
    861  1.1  mrg 
    862  1.1  mrg void runModuleFuncsRev(alias getfp)(const(immutable(ModuleInfo)*)[] modules)
    863  1.1  mrg {
    864  1.1  mrg     foreach_reverse (m; modules)
    865  1.1  mrg     {
    866  1.1  mrg         if (auto fp = getfp(m))
    867  1.1  mrg             (*fp)();
    868  1.1  mrg     }
    869  1.1  mrg }
    870  1.1  mrg 
    871  1.1  mrg unittest
    872  1.1  mrg {
    873  1.1  mrg     static void assertThrown(T : Throwable, E)(lazy E expr, string msg)
    874  1.1  mrg     {
    875  1.1  mrg         try
    876  1.1  mrg             expr;
    877  1.1  mrg         catch (T)
    878  1.1  mrg             return;
    879  1.1  mrg         assert(0, msg);
    880  1.1  mrg     }
    881  1.1  mrg 
    882  1.1  mrg     static void stub()
    883  1.1  mrg     {
    884  1.1  mrg     }
    885  1.1  mrg 
    886  1.1  mrg     static struct UTModuleInfo
    887  1.1  mrg     {
    888  1.1  mrg         this(uint flags)
    889  1.1  mrg         {
    890  1.1  mrg             mi._flags = flags;
    891  1.1  mrg         }
    892  1.1  mrg 
    893  1.1  mrg         void setImports(immutable(ModuleInfo)*[] imports...)
    894  1.1  mrg         {
    895  1.1  mrg             import core.bitop;
    896  1.1  mrg             assert(flags & MIimportedModules);
    897  1.1  mrg 
    898  1.1  mrg             immutable nfuncs = popcnt(flags & (MItlsctor|MItlsdtor|MIctor|MIdtor|MIictor));
    899  1.1  mrg             immutable size = nfuncs * (void function()).sizeof +
    900  1.1  mrg                 size_t.sizeof + imports.length * (ModuleInfo*).sizeof;
    901  1.1  mrg             assert(size <= pad.sizeof);
    902  1.1  mrg 
    903  1.1  mrg             pad[nfuncs] = imports.length;
    904  1.1  mrg             .memcpy(&pad[nfuncs+1], imports.ptr, imports.length * imports[0].sizeof);
    905  1.1  mrg         }
    906  1.1  mrg 
    907  1.1  mrg         immutable ModuleInfo mi;
    908  1.1  mrg         size_t[8] pad;
    909  1.1  mrg         alias mi this;
    910  1.1  mrg     }
    911  1.1  mrg 
    912  1.1  mrg     static UTModuleInfo mockMI(uint flags)
    913  1.1  mrg     {
    914  1.1  mrg         auto mi = UTModuleInfo(flags | MIimportedModules);
    915  1.1  mrg         auto p = cast(void function()*)&mi.pad;
    916  1.1  mrg         if (flags & MItlsctor) *p++ = &stub;
    917  1.1  mrg         if (flags & MItlsdtor) *p++ = &stub;
    918  1.1  mrg         if (flags & MIctor) *p++ = &stub;
    919  1.1  mrg         if (flags & MIdtor) *p++ = &stub;
    920  1.1  mrg         if (flags & MIictor) *p++ = &stub;
    921  1.1  mrg         *cast(size_t*)p++ = 0; // number of imported modules
    922  1.1  mrg         assert(cast(void*)p <= &mi + 1);
    923  1.1  mrg         return mi;
    924  1.1  mrg     }
    925  1.1  mrg 
    926  1.1  mrg     static void checkExp2(string testname, bool shouldThrow, string oncycle,
    927  1.1  mrg         immutable(ModuleInfo*)[] modules,
    928  1.1  mrg         immutable(ModuleInfo*)[] dtors=null,
    929  1.1  mrg         immutable(ModuleInfo*)[] tlsdtors=null)
    930  1.1  mrg     {
    931  1.1  mrg         auto mgroup = ModuleGroup(modules);
    932  1.1  mrg         mgroup.sortCtors(oncycle);
    933  1.1  mrg 
    934  1.1  mrg         // if we are expecting sort to throw, don't throw because of unexpected
    935  1.1  mrg         // success!
    936  1.1  mrg         if (!shouldThrow)
    937  1.1  mrg         {
    938  1.1  mrg             foreach (m; mgroup._modules)
    939  1.1  mrg                 assert(!(m.flags & (MIctorstart | MIctordone)), testname);
    940  1.1  mrg             assert(mgroup._ctors    == dtors, testname);
    941  1.1  mrg             assert(mgroup._tlsctors == tlsdtors, testname);
    942  1.1  mrg         }
    943  1.1  mrg     }
    944  1.1  mrg 
    945  1.1  mrg     static void checkExp(string testname, bool shouldThrow,
    946  1.1  mrg         immutable(ModuleInfo*)[] modules,
    947  1.1  mrg         immutable(ModuleInfo*)[] dtors=null,
    948  1.1  mrg         immutable(ModuleInfo*)[] tlsdtors=null)
    949  1.1  mrg     {
    950  1.1  mrg         checkExp2(testname, shouldThrow, "abort", modules, dtors, tlsdtors);
    951  1.1  mrg     }
    952  1.1  mrg 
    953  1.1  mrg 
    954  1.1  mrg     {
    955  1.1  mrg         auto m0 = mockMI(0);
    956  1.1  mrg         auto m1 = mockMI(0);
    957  1.1  mrg         auto m2 = mockMI(0);
    958  1.1  mrg         checkExp("no ctors", false, [&m0.mi, &m1.mi, &m2.mi]);
    959  1.1  mrg     }
    960  1.1  mrg 
    961  1.1  mrg     {
    962  1.1  mrg         auto m0 = mockMI(MIictor);
    963  1.1  mrg         auto m1 = mockMI(0);
    964  1.1  mrg         auto m2 = mockMI(MIictor);
    965  1.1  mrg         auto mgroup = ModuleGroup([&m0.mi, &m1.mi, &m2.mi]);
    966  1.1  mrg         checkExp("independent ctors", false, [&m0.mi, &m1.mi, &m2.mi]);
    967  1.1  mrg     }
    968  1.1  mrg 
    969  1.1  mrg     {
    970  1.1  mrg         auto m0 = mockMI(MIstandalone | MIctor);
    971  1.1  mrg         auto m1 = mockMI(0);
    972  1.1  mrg         auto m2 = mockMI(0);
    973  1.1  mrg         auto mgroup = ModuleGroup([&m0.mi, &m1.mi, &m2.mi]);
    974  1.1  mrg         checkExp("standalone ctor", false, [&m0.mi, &m1.mi, &m2.mi], [&m0.mi]);
    975  1.1  mrg     }
    976  1.1  mrg 
    977  1.1  mrg     {
    978  1.1  mrg         auto m0 = mockMI(MIstandalone | MIctor);
    979  1.1  mrg         auto m1 = mockMI(MIstandalone | MIctor);
    980  1.1  mrg         auto m2 = mockMI(0);
    981  1.1  mrg         m1.setImports(&m0.mi);
    982  1.1  mrg         checkExp("imported standalone => no dependency", false,
    983  1.1  mrg                  [&m0.mi, &m1.mi, &m2.mi], [&m0.mi, &m1.mi]);
    984  1.1  mrg     }
    985  1.1  mrg 
    986  1.1  mrg     {
    987  1.1  mrg         auto m0 = mockMI(MIstandalone | MIctor);
    988  1.1  mrg         auto m1 = mockMI(MIstandalone | MIctor);
    989  1.1  mrg         auto m2 = mockMI(0);
    990  1.1  mrg         m0.setImports(&m1.mi);
    991  1.1  mrg         checkExp("imported standalone => no dependency (2)", false,
    992  1.1  mrg                 [&m0.mi, &m1.mi, &m2.mi], [&m0.mi, &m1.mi]);
    993  1.1  mrg     }
    994  1.1  mrg 
    995  1.1  mrg     {
    996  1.1  mrg         auto m0 = mockMI(MIstandalone | MIctor);
    997  1.1  mrg         auto m1 = mockMI(MIstandalone | MIctor);
    998  1.1  mrg         auto m2 = mockMI(0);
    999  1.1  mrg         m0.setImports(&m1.mi);
   1000  1.1  mrg         m1.setImports(&m0.mi);
   1001  1.1  mrg         checkExp("standalone may have cycle", false,
   1002  1.1  mrg                 [&m0.mi, &m1.mi, &m2.mi], [&m0.mi, &m1.mi]);
   1003  1.1  mrg     }
   1004  1.1  mrg 
   1005  1.1  mrg     {
   1006  1.1  mrg         auto m0 = mockMI(MIctor);
   1007  1.1  mrg         auto m1 = mockMI(MIctor);
   1008  1.1  mrg         auto m2 = mockMI(0);
   1009  1.1  mrg         m1.setImports(&m0.mi);
   1010  1.1  mrg         checkExp("imported ctor => ordered ctors", false,
   1011  1.1  mrg                 [&m0.mi, &m1.mi, &m2.mi], [&m0.mi, &m1.mi], []);
   1012  1.1  mrg     }
   1013  1.1  mrg 
   1014  1.1  mrg     {
   1015  1.1  mrg         auto m0 = mockMI(MIctor);
   1016  1.1  mrg         auto m1 = mockMI(MIctor);
   1017  1.1  mrg         auto m2 = mockMI(0);
   1018  1.1  mrg         m0.setImports(&m1.mi);
   1019  1.1  mrg         checkExp("imported ctor => ordered ctors (2)", false,
   1020  1.1  mrg                 [&m0.mi, &m1.mi, &m2.mi], [&m1.mi, &m0.mi], []);
   1021  1.1  mrg     }
   1022  1.1  mrg 
   1023  1.1  mrg     {
   1024  1.1  mrg         auto m0 = mockMI(MIctor);
   1025  1.1  mrg         auto m1 = mockMI(MIctor);
   1026  1.1  mrg         auto m2 = mockMI(0);
   1027  1.1  mrg         m0.setImports(&m1.mi);
   1028  1.1  mrg         m1.setImports(&m0.mi);
   1029  1.1  mrg         assertThrown!Throwable(checkExp("", true, [&m0.mi, &m1.mi, &m2.mi]),
   1030  1.1  mrg                 "detects ctors cycles");
   1031  1.1  mrg         assertThrown!Throwable(checkExp2("", true, "deprecate",
   1032  1.1  mrg                                         [&m0.mi, &m1.mi, &m2.mi]),
   1033  1.1  mrg                 "detects ctors cycles (dep)");
   1034  1.1  mrg     }
   1035  1.1  mrg 
   1036  1.1  mrg     {
   1037  1.1  mrg         auto m0 = mockMI(MIctor);
   1038  1.1  mrg         auto m1 = mockMI(MIctor);
   1039  1.1  mrg         auto m2 = mockMI(0);
   1040  1.1  mrg         m0.setImports(&m2.mi);
   1041  1.1  mrg         m1.setImports(&m2.mi);
   1042  1.1  mrg         m2.setImports(&m0.mi, &m1.mi);
   1043  1.1  mrg         assertThrown!Throwable(checkExp("", true, [&m0.mi, &m1.mi, &m2.mi]),
   1044  1.1  mrg                 "detects cycle with repeats");
   1045  1.1  mrg     }
   1046  1.1  mrg 
   1047  1.1  mrg     {
   1048  1.1  mrg         auto m0 = mockMI(MIctor);
   1049  1.1  mrg         auto m1 = mockMI(MIctor);
   1050  1.1  mrg         auto m2 = mockMI(MItlsctor);
   1051  1.1  mrg         m0.setImports(&m1.mi, &m2.mi);
   1052  1.1  mrg         checkExp("imported ctor/tlsctor => ordered ctors/tlsctors", false,
   1053  1.1  mrg                 [&m0.mi, &m1.mi, &m2.mi], [&m1.mi, &m0.mi], [&m2.mi]);
   1054  1.1  mrg     }
   1055  1.1  mrg 
   1056  1.1  mrg     {
   1057  1.1  mrg         auto m0 = mockMI(MIctor | MItlsctor);
   1058  1.1  mrg         auto m1 = mockMI(MIctor);
   1059  1.1  mrg         auto m2 = mockMI(MItlsctor);
   1060  1.1  mrg         m0.setImports(&m1.mi, &m2.mi);
   1061  1.1  mrg         checkExp("imported ctor/tlsctor => ordered ctors/tlsctors (2)", false,
   1062  1.1  mrg                 [&m0.mi, &m1.mi, &m2.mi], [&m1.mi, &m0.mi], [&m2.mi, &m0.mi]);
   1063  1.1  mrg     }
   1064  1.1  mrg 
   1065  1.1  mrg     {
   1066  1.1  mrg         auto m0 = mockMI(MIctor);
   1067  1.1  mrg         auto m1 = mockMI(MIctor);
   1068  1.1  mrg         auto m2 = mockMI(MItlsctor);
   1069  1.1  mrg         m0.setImports(&m1.mi, &m2.mi);
   1070  1.1  mrg         m2.setImports(&m0.mi);
   1071  1.1  mrg         checkExp("no cycle between ctors/tlsctors", false,
   1072  1.1  mrg                 [&m0.mi, &m1.mi, &m2.mi], [&m1.mi, &m0.mi], [&m2.mi]);
   1073  1.1  mrg     }
   1074  1.1  mrg 
   1075  1.1  mrg     {
   1076  1.1  mrg         auto m0 = mockMI(MItlsctor);
   1077  1.1  mrg         auto m1 = mockMI(MIctor);
   1078  1.1  mrg         auto m2 = mockMI(MItlsctor);
   1079  1.1  mrg         m0.setImports(&m2.mi);
   1080  1.1  mrg         m2.setImports(&m0.mi);
   1081  1.1  mrg         assertThrown!Throwable(checkExp("", true, [&m0.mi, &m1.mi, &m2.mi]),
   1082  1.1  mrg                 "detects tlsctors cycle");
   1083  1.1  mrg         assertThrown!Throwable(checkExp2("", true, "deprecate",
   1084  1.1  mrg                                          [&m0.mi, &m1.mi, &m2.mi]),
   1085  1.1  mrg                 "detects tlsctors cycle (dep)");
   1086  1.1  mrg     }
   1087  1.1  mrg 
   1088  1.1  mrg     {
   1089  1.1  mrg         auto m0 = mockMI(MItlsctor);
   1090  1.1  mrg         auto m1 = mockMI(MIctor);
   1091  1.1  mrg         auto m2 = mockMI(MItlsctor);
   1092  1.1  mrg         m0.setImports(&m1.mi);
   1093  1.1  mrg         m1.setImports(&m0.mi, &m2.mi);
   1094  1.1  mrg         m2.setImports(&m1.mi);
   1095  1.1  mrg         assertThrown!Throwable(checkExp("", true, [&m0.mi, &m1.mi, &m2.mi]),
   1096  1.1  mrg                 "detects tlsctors cycle with repeats");
   1097  1.1  mrg     }
   1098  1.1  mrg 
   1099  1.1  mrg     {
   1100  1.1  mrg         auto m0 = mockMI(MIctor);
   1101  1.1  mrg         auto m1 = mockMI(MIstandalone | MIctor);
   1102  1.1  mrg         auto m2 = mockMI(MIstandalone | MIctor);
   1103  1.1  mrg         m0.setImports(&m1.mi);
   1104  1.1  mrg         m1.setImports(&m2.mi);
   1105  1.1  mrg         m2.setImports(&m0.mi);
   1106  1.1  mrg         // NOTE: this is implementation dependent, sorted order shouldn't be tested.
   1107  1.1  mrg         checkExp("closed ctors cycle", false, [&m0.mi, &m1.mi, &m2.mi],
   1108  1.1  mrg                 [&m1.mi, &m2.mi, &m0.mi]);
   1109  1.1  mrg         //checkExp("closed ctors cycle", false, [&m0.mi, &m1.mi, &m2.mi], [&m0.mi, &m1.mi, &m2.mi]);
   1110  1.1  mrg     }
   1111  1.1  mrg }
   1112  1.1  mrg 
   1113  1.1  mrg version (CRuntime_Microsoft)
   1114  1.1  mrg {
   1115  1.1  mrg     // Dummy so Win32 code can still call it
   1116  1.1  mrg     extern(C) void _minit() { }
   1117  1.1  mrg }
   1118