Bug 18267 – array comparison broken in 2.078.3

Status
RESOLVED
Resolution
WORKSFORME
Severity
regression
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2018-01-19T18:22:30Z
Last change time
2024-08-23T07:24:49Z
Keywords
industry
Assigned to
No Owner
Creator
Atila Neves

Attachments

IDFilenameSummaryContent-TypeSize
1677oops.dThe module that generates code that can't be linked totext/x-dsrc1742

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.