The following code worked with 2.087.1, but doesn't link since 2.088.0:
//////////////////// test.d ///////////////////
import std.uni, std.stdio;
class C
{
size_t number;
}
int main()
{
C inst;
mixin({
while(false)
{
dchar current;
CodepointSet(current);
}
return "";
}());
writefln("%d %d %d", inst.number, C.sizeof, inst.number );
return 0;
}
///////////////////////////////////////////////
With 2.088.0 it produces the following link error:
/usr/bin/ld: test.o: in function `_D3std6format__T14formattedWriteTSQBg5stdio4File17LockingTextWriterTaTmTmTmZQCiFNfKQByMxAammmZk':
test.d:(.text._D3std6format__T14formattedWriteTSQBg5stdio4File17LockingTextWriterTaTmTmTmZQCiFNfKQByMxAammmZk[_D3std6format__T14formattedWriteTSQBg5stdio4File17LockingTextWriterTaTmTmTmZQCiFNfKQByMxAammmZk]+0xd6): undefined reference to `_D3std6format__T9getNthIntVAyaa13_696e7465676572207769647468TmTmTmZQBzFNaNfkmmmZi'
/usr/bin/ld: test.d:(.text._D3std6format__T14formattedWriteTSQBg5stdio4File17LockingTextWriterTaTmTmTmZQCiFNfKQByMxAammmZk[_D3std6format__T14formattedWriteTSQBg5stdio4File17LockingTextWriterTaTmTmTmZQCiFNfKQByMxAammmZk]+0x16f): undefined reference to `_D3std6format__T9getNthIntVAyaa13_696e7465676572207769647468TmTmTmZQBzFNaNfkmmmZi'
/usr/bin/ld: test.d:(.text._D3std6format__T14formattedWriteTSQBg5stdio4File17LockingTextWriterTaTmTmTmZQCiFNfKQByMxAammmZk[_D3std6format__T14formattedWriteTSQBg5stdio4File17LockingTextWriterTaTmTmTmZQCiFNfKQByMxAammmZk]+0x1c6): undefined reference to `_D3std6format__T9getNthIntVAyaa17_696e746567657220707265636973696f6eTmTmTmZQChFNaNfkmmmZi'
/usr/bin/ld: test.d:(.text._D3std6format__T14formattedWriteTSQBg5stdio4File17LockingTextWriterTaTmTmTmZQCiFNfKQByMxAammmZk[_D3std6format__T14formattedWriteTSQBg5stdio4File17LockingTextWriterTaTmTmTmZQCiFNfKQByMxAammmZk]+0x254): undefined reference to `_D3std6format__T9getNthIntVAyaa17_696e746567657220707265636973696f6eTmTmTmZQChFNaNfkmmmZi'
/usr/bin/ld: test.d:(.text._D3std6format__T14formattedWriteTSQBg5stdio4File17LockingTextWriterTaTmTmTmZQCiFNfKQByMxAammmZk[_D3std6format__T14formattedWriteTSQBg5stdio4File17LockingTextWriterTaTmTmTmZQCiFNfKQByMxAammmZk]+0x2a0): undefined reference to `_D3std6format__T9getNthIntVAyaa21_736570617261746f72206469676974207769647468TmTmTmZQCpFNaNfkmmmZi'
/usr/bin/ld: test.d:(.text._D3std6format__T14formattedWriteTSQBg5stdio4File17LockingTextWriterTaTmTmTmZQCiFNfKQByMxAammmZk[_D3std6format__T14formattedWriteTSQBg5stdio4File17LockingTextWriterTaTmTmTmZQCiFNfKQByMxAammmZk]+0x2c9): undefined reference to `_D3std6format__T6getNthVAyaa19_736570617261746f7220636861726163746572SQCq6traits10isSomeCharTwTmTmTmZQDhFNaNfkmmmZw'
collect2: Fehler: ld gab 1 als Ende-Status zurück
It may be related to issue 17155, but since it was introduced in a different release I have created a separate issue.
Comment #1 by ibuclaw — 2023-01-10T18:17:38Z
Now:
---
issue20802.o: in function `_D4core8internal7switch___T14__switch_errorZQrFNaNbNiNfAyamZv':
issue20802.d:(.text._D4core8internal7switch___T14__switch_errorZQrFNaNbNiNfAyamZv[_D4core8internal7switch___T14__switch_errorZQrFNaNbNiNfAyamZv]+0x19): undefined reference to `_D4core9exception__T15__switch_errorTZQsFNaNbNiNeAyamZv'
collect2: error: ld returned 1 exit status
Error: linker exited with status 1
Comment #2 by alphaglosined — 2024-02-07T11:52:51Z
Another more slimmed down version that was experienced by someone on the N.G.
```d
import std.uni, std.stdio;
void main() {
auto c1 = CodepointSet('a','z'+1);
writefln("%s", c1);
}
```
```
/dlang/dmd/linux/bin64/../../src/druntime/import/core/internal/switch_.d:189: error: undefined reference to '_D4core9exception__T15__switch_errorTZQsFNaNbNiNeAyamZv'
```
https://forum.dlang.org/post/[email protected]
Comment #3 by spoov0.707 — 2024-02-11T11:04:38Z
The example can be simplified a bit, same error as in previous comment:
############ test.d ##############
import std.uni;
void main()
{
CodepointSet('a', 'z');
dstring s;
decodeGrapheme(s);
}
##################################
Reducing std.uni yields the code below, same error as above:
#### phobos/std/uni/package.d ####
module std.uni;
enum TransformRes { goOn }
void writeAligned()()
{
final switch (TransformRes.goOn) { case TransformRes.goOn: break; }
}
struct GcPolicy {}
alias CodepointSet = InversionList!GcPolicy;
struct InversionList(SP=GcPolicy)
{
this()(uint[] intervals...)
{
sanitize();
}
void sanitize()
{
throw new Exception("");
writeAligned();
}
}
void decodeGrapheme(Input)(ref Input inp)
{
final switch (TransformRes.goOn) { case TransformRes.goOn: break; }
}
##################################
A final switch generates a call to core.internal.switch_.__switch_error for handling the default case.
core.internal.switch_.__switch_error calls core.exception.__switch_errorT.
Both functions are templates.
By default a D program links with libphobos2.a.
libphobos2.a contains sanitize and writeAligned but not __switch_error and __switch_errorT.
This is because libphobos2.a gets build in release mode which causes the call to __switch_error to be replaced with a ud2 instruction.
The linker error shows that __switch_error is present but __switch_errorT is missing.
In the compiler is this code
https://github.com/dlang/dmd/blob/8ab0636400d890a777889b3c84b09bcaa119fd57/compiler/src/dmd/dsymbolsem.d#L4666
which handles the case where a template that got instantiated from a non-root module,
gets instantiated from a root module.
The code fixes the template instantiation, but misses the template instantiations that are caused by it.
Because of this __switch_errorT is not emitted to the object file.
The following three files form a minimal example that reproduces the issue:
############# a.d ################
import b;
extern(C) void main() => bar!true;
############# b.d ################
void missing()() {}
void foo()() => missing();
void bar(bool b)() { version (Release) {} else foo(); }
enum fptr = &bar!false;
########## object.d ##############
// empty to make debugging simpler
$ dmd -c -version=Release b.d
$ dmd a.d b.o
a.o: In function `_D1b__T3fooZQfFNaNbNiNfZv':
a.d:(.text._D1b__T3fooZQfFNaNbNiNfZv[_D1b__T3fooZQfFNaNbNiNfZv]+0x5): undefined reference to `_D1b__T7missingZQjFNaNbNiNfZv'
collect2: error: ld returned 1 exit status
Error: linker exited with status 1
Comment #4 by dlang-bot — 2024-02-18T12:21:24Z
@tim-dlang created dlang/dmd pull request #16200 "Fix Bugzilla 20802 - Link failure with writefln" fixing this issue:
- Fix Bugzilla 20802 - Link failure with writefln
The issue is caused by compiling druntime/phobos and the application
with different flags. The template instance for __switch_errorT is not
included in the build of druntime/phobos, because they are compiled
with -release. DMD will also not include it in an application compiled
without -release, because it assumes, that it is already in druntime.
See comment https://issues.dlang.org/show_bug.cgi?id=20802#c3 by Spoov.
As a workaround the template instance for __switch_errorT is now always
instantiated in druntime.
https://github.com/dlang/dmd/pull/16200
Comment #5 by dlang-bot — 2024-02-18T22:35:06Z
dlang/dmd pull request #16200 "Fix Bugzilla 20802 - Link failure with writefln" was merged into stable:
- f4ee5234bccf21a4d2b5ca6d3962ccc3dd7a7d06 by Tim Schendekehl:
Fix Bugzilla 20802 - Link failure with writefln
The issue is caused by compiling druntime/phobos and the application
with different flags. The template instance for __switch_errorT is not
included in the build of druntime/phobos, because they are compiled
with -release. DMD will also not include it in an application compiled
without -release, because it assumes, that it is already in druntime.
See comment https://issues.dlang.org/show_bug.cgi?id=20802#c3 by Spoov.
The template instance for __switch_errorT is now always instantiated in
druntime, so it is part of the ABI of druntime.
https://github.com/dlang/dmd/pull/16200
Comment #6 by dfj1esp02 — 2024-02-19T07:28:13Z
This looks like a rather fundamental collision between speculative instantiation and conditional compilation. __switch_errorT can't be in druntime unconditionally because its behavior changes depending on compilation options.
Comment #7 by ibuclaw — 2024-02-20T13:22:39Z
(In reply to anonymous4 from comment #6)
> This looks like a rather fundamental collision between speculative
> instantiation and conditional compilation. __switch_errorT can't be in
> druntime unconditionally because its behavior changes depending on
> compilation options.
Because it's a weak symbol, any local instantiation would override the unconditional instantiation in druntime.
Comment #8 by ibuclaw — 2024-02-20T13:23:37Z
*** Issue 23255 has been marked as a duplicate of this issue. ***
Comment #9 by ibuclaw — 2024-02-20T13:23:59Z
*** Issue 23209 has been marked as a duplicate of this issue. ***
Comment #10 by dlang-bot — 2024-03-01T23:56:54Z
dlang/dmd pull request #16276 "merge stable" was merged into master:
- 6a2fe78ba45b4fcd495f7ab340f784640b9daf01 by Tim Schendekehl:
Fix Bugzilla 20802 - Link failure with writefln (#16200)
The issue is caused by compiling druntime/phobos and the application
with different flags. The template instance for __switch_errorT is not
included in the build of druntime/phobos, because they are compiled
with -release. DMD will also not include it in an application compiled
without -release, because it assumes, that it is already in druntime.
See comment https://issues.dlang.org/show_bug.cgi?id=20802#c3 by Spoov.
The template instance for __switch_errorT is now always instantiated in
druntime, so it is part of the ABI of druntime.
https://github.com/dlang/dmd/pull/16276