www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 15318] New: Templates not emitted for two "partial cycles"

https://issues.dlang.org/show_bug.cgi?id=15318

          Issue ID: 15318
           Summary: Templates not emitted for two "partial cycles"
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: regression
          Priority: P1
         Component: dmd
          Assignee: nobody puremagic.com
          Reporter: code klickverbot.at

Consider the following program:

---
module A;

import C;
---
module B;

import E;
alias value = bar!5;
void foo() {
    import core.stdc.stdio;
    printf("%p\n", &value);
}
---
module C;

import E;
alias value = bar!5;
void foo() {
    import core.stdc.stdio;
    printf("%p\n", &value);
}
---
module D;

import B;
---
module E;

immutable bar(int v) = v;
---

If you compile it like this using DMD 2.068.2 or 2.069.1
---
dmd -c -offirst.o A.d B.d
dmd -c -ofsecond.o C.d D.d
dmd -main E.d first.o second.o
---
you'll get an undefined symbol for the bar!5 instance. The same occurs when
using -lib instead of "-c -of…", and E.d is of course unnecessary to compile
in
this case, but just added for completeness.

The issue is that when compiling the first "package" (this test case is derived
from problems using by-package compilation in a big code base), i.e. A and B,
the symbol is determined to be instantiated by a non-root module (A -> C), so
even though it is instantiated in B, it doesn't get emitted into the object
file. But when compiling the second package, the D -> B import causes that
instance in C not to be emitted either.

One fix/workaround is to remove the following piece of logic from
TemplateInstance.needsCodegen():

--- dtemplate.d
    if (tnext && !tnext.needsCodegen() && tnext.minst)
    {
        minst = tnext.minst; // cache result
        assert(!minst.isRoot());
        return false;
    }
---

Now, of course, this fix is not ideal in the sense that it also causes more
work to be done in cases that are currently handled correctly. But
fundamentally I can't see how eliding instances that are being done directly in
root modules (B and C in this case) would ever be possible. There can always be
parts of the global module dependency graph for a whole executable that are not
visible from the local point of view when compiling a subset of the modules.
For instance, in the above example there is no way the compiler can know about
the existence of D when compiling A and B.

Marked as a regression, as the issue didn't occur using 2.067.1 in said large
real-world code base, but my suspicion is that the template instantiation logic
was broken before too.

--
Nov 11 2015