The module that generates code that can't be linked to
text/x-dsrc
1742
Comments
Comment #0 by atila.neves — 2018-01-19T18:22:30Z
Created attachment 1677
The module that generates code that can't be linked to
Since this commit:
commit 0fc1c36f4e611d92f903db90ee4d62dd7fdc4067 (HEAD)
Author: somzzz <[email protected]>
Date: Mon Oct 16 02:55:59 2017 -0700
array __equals lowering of dynamic arrays
The following very simple dub project no longer links:
dub.sdl:
name "oops"
dependency "std_data_json" version="~>0.18.2"
source/app.d:
void main() { import stdx.data.json.value; }
$ dub build
error: undefined reference to '_D15taggedalgebraic__T15TaggedAlgebraicTS4stdx4data4json5value9JSONValue12PayloadUnionZQCn__T8opEqualsTxSQDz__TQDlTQCxZQDtTxQuZQBiMxFKxQBfZb'
Before the aforementioned commit, things work as expected. This is currently making our builds at work fail due a dependency on std_data_json.
Investigating further, I inlined both std_data_json's value.d module and its dependency taggedalgebraic, and deleted as much code as possible while still getting a linker error and ended up with these two files:
app.d:
void main() { import oops; }
oops.d:
<attached>
To reproduce:
% dmd -g -c oops.d
% dmd -g -debug app.d oops.o
The issue goes away if the second line doesn't contain `-debug`. On this reduced example, what's happening is that the two modules don't agree on the attribute for opEquals. The linker error is that it can't find
_D4oops__T15TaggedAlgebraicTSQBb9JSONValue12PayloadUnionZQBv__T8opEqualsTxSQCv__TQCtTQCfZQDbTxQuZQBiMxFKxQBfZb
demangled:
const bool oops.TaggedAlgebraic!(oops.JSONValue.PayloadUnion).TaggedAlgebraic.opEquals!(const(oops.TaggedAlgebraic!(oops.JSONValue.PayloadUnion).TaggedAlgebraic), const(oops.TaggedAlgebraic!(oops.JSONValue.PayloadUnion).TaggedAlgebraic)).opEquals(ref const(oops.TaggedAlgebraic!(oops.JSONValue.PayloadUnion).TaggedAlgebraic))
oops.o does contain a similar symbol, however:
_D4oops__T15TaggedAlgebraicTSQBb9JSONValue12PayloadUnionZQBv__T8opEqualsTxSQCv__TQCtTQCfZQDbTxQuZQBiMxFNaNfKxQBjZb
demangled:
const pure @safe bool oops.TaggedAlgebraic!(oops.JSONValue.PayloadUnion).TaggedAlgebraic.opEquals!(const(oops.TaggedAlgebraic!(oops.JSONValue.PayloadUnion).TaggedAlgebraic), const(oops.TaggedAlgebraic!(oops.JSONValue.PayloadUnion).TaggedAlgebraic)).opEquals(ref const(oops.TaggedAlgebraic!(oops.JSONValue.PayloadUnion).TaggedAlgebraic))
Notice that the symbol that actually exists is `pure @safe`, whereas the one being looked for by app.d isn't. It seems then that for some reason the attribute inference happens differently when compiling each module.
Comment #1 by dfj1esp02 — 2018-01-25T12:34:05Z
opEquals changes attributes based on debug switch? What if it's marked as @safe?
Comment #2 by atila.neves — 2018-01-25T17:10:07Z
If it's marked as `@safe` then `pure` is still an issue. At least with the very reduced example. I think the specifics depend on the code being compiled.
Comment #3 by john.loughran.colvin — 2018-02-22T15:51:56Z
Here is a standalone file that demonstrates what I think is a symptom of the same bug:
% cat oops.d
struct JSONValue
{
TaggedAlgebraic payload;
alias payload this;
}
struct TaggedAlgebraic
{
auto opEquals(T)(T other) const
{
static assert(is(typeof(performOp!(JSONValue[], T))));
return const(JSONValue[]).init == other;
}
}
bool performOp(T, A)(T value, A arg)
{
return value == arg;
}
% dmd oops.d
Undefined symbols for architecture x86_64:
"_D6object__T8__equalsTxS4oops9JSONValueTxQsZQBgFNbAxQBdQfZb", referenced from:
_D4oops15TaggedAlgebraic__T8opEqualsTAxSQBm9JSONValueZQBbMxFQxZb in oops.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Comment #4 by slavo5150 — 2018-04-27T13:34:04Z
Attributing `opEquals` with `nothrow` resolves the linker error:
struct S
{
P payload;
alias payload this;
}
struct P
{
auto opEquals(T)(T other) const nothrow //*** Needs nothrow ***/
{
static assert(is(typeof(performOp!(S[], T))));
return const(S[]).init == other;
}
}
bool performOp(T, A)(T value, A arg)
{
return value == arg;
}
Comment #5 by razvan.nitu1305 — 2021-11-02T14:13:33Z
This seems to have been fix as I cannot reproduce the example provided by John Colvin.
Comment #6 by john.loughran.colvin — 2021-11-02T20:58:06Z
Atila's original example still fails with dmd master
Comment #7 by razvan.nitu1305 — 2024-08-23T07:24:49Z
@Atilla I have just tried your initial example and it compiles fine with the latest version of master.
What I did:
For the following files:
=================================
// app.d
void main() { import oops; }
=================================
// oops.d
<attached file>
struct Location {
string file;
}
struct JSONValue {
union PayloadUnion {
JSONValue[] array;
}
alias Payload = TaggedAlgebraic!PayloadUnion;
Payload payload;
Location location;
alias payload this;
}
struct TaggedAlgebraic(U)
....
========================
Commands:
% dmd -g -c oops.d
% dmd -g -debug app.d oops.o
I get a binary. So this seems to have been fixed. I am going to preemptively close as WORKSFORME, but please reopen if I'm missing something.