Bug 16994 – Apparently faulty symbol resolution in some cases
Status
RESOLVED
Resolution
DUPLICATE
Severity
major
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2016-12-20T16:20:00Z
Last change time
2017-01-08T22:13:12Z
Assigned to
nobody
Creator
meapineapple
Comments
Comment #0 by meapineapple — 2016-12-20T16:20:25Z
This error is occurring in a large project I'm working on as of this commit:
https://github.com/pineapplemachine/mach.d/commit/e1f7f91db0293ef24a974398fb598bbba3e9f336
These tests can be reproduced by running the following command:
rdmd -I"path/to/cloned/repo/mach.d" -debug -g -unittest --main "path/to/module.d"
When this module is compiled using rdmd, dmd v2.072.0 on OSX Mavericks, unit tests pass:
https://github.com/pineapplemachine/mach.d/blob/e1f7f91db0293ef24a974398fb598bbba3e9f336/mach/range/map/plural.d
When this module, which imports the above plural.d, is compiled by the same means, the unit tests for that module, mach/range/map/plural.d, fail:
https://github.com/pineapplemachine/mach.d/blob/e1f7f91db0293ef24a974398fb598bbba3e9f336/mach/range/readme.d
When this module, which imports the above mach/range/readme.d, is compiled by the same means, the unit tests for all modules - including mach/range/map/plural.d - pass. Same goes for every other module that I have tried compiling and running tests for, which also import the above modules:
https://github.com/pineapplemachine/mach.d/blob/e1f7f91db0293ef24a974398fb598bbba3e9f336/mach/range/package.d
I have verified that in all the above cases, the unit tests are indeed being evaluated; the apparent success of the tests cannot be due to the tests simply being skipped.
One of the dependencies of mach/range/map/plural.d is mach/meta/varreduce.d as seen here:
https://github.com/pineapplemachine/mach.d/blob/e1f7f91db0293ef24a974398fb598bbba3e9f336/mach/meta/varreduce.d
varreduce.d defines `varreduce`, which performs a reduce HOF upon a sequence of variadic arguments. It also defines a number of functions abstracting and calling `varreduce`, including `varmin`, which finds the minimum, and `varsum`, which calculates the sum. For example, `varmin(4, 2, 5) == 2` and `varsum(4, 2, 5) == 11`.
The `length` property of `MapPluralRange` defined in plural.d uses `varmin` to calculate the minimum length of several constituent ranges. (It may help to think of this range as a sort of `zip`, where the length of the resulting range is equivalent to the length of its shortest input.) Except for when these tests are performed as a result of compiling the aforementioned readme.d, this property behaves as expected and does in fact return the shortest length.
When tests are performed as a result of compiling readme.d, the shortest length is returned when there are two or fewer member ranges. (i.e. `varmin` receives two or fewer arguments.) When there are three or more member ranges, the `length` property returns the sum of the lengths instead of the minimum, as though symbol lookup were causing the implementation of `varsum` to be evaluated instead of `varmin`. This behavior has remained consistent across a number of different test cases. I have been unable to reproduce it in any case except for the compilation and testing of mach/range/readme.d.
All of the dependencies of that `length` property, including `varmin`, are thoroughly unit tested and the level of verification makes it very unlikely that this issue could result from an incorrect implementation of any of those dependencies.
Comment #1 by code — 2017-01-08T18:11:14Z
Indeed changing the implementation of varsum to return the minimum length fixes the issue.
This could be a bug in dmd's template instantiation cache.
Note that the issue vanishes with 2.072.2, but likely just as a side effect of some other rearrangements.
Seems to be a duplicate of issue 14894, only in this case the 2 compilations produce different functions with the same mangling instead of causing a linker error.
It just happens that in both compilations a lambda with the same number (__lambda21) is passed to varreduce paired with the same argument types, the linker will just pick the implementation that occurs first.
A workaround is to convert the lambdas
alias VarReduceMin = (a, b) => (a < b ? a : b);
to template functions.
auto VarReduceMin(A, B)(A a, B b) { return (a < b ? a : b); }
Comment #4 by code — 2017-01-08T22:13:12Z
*** This issue has been marked as a duplicate of issue 14894 ***