Bug 16481 – invalid code accepted leading to linker error
Status
RESOLVED
Resolution
DUPLICATE
Severity
major
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2016-09-09T13:40:47Z
Last change time
2022-11-10T14:24:02Z
Keywords
accepts-invalid
Assigned to
No Owner
Creator
John Colvin
Comments
Comment #0 by john.loughran.colvin — 2016-09-09T13:40:47Z
% cat mod.d
void blah()
{
import std.algorithm;
import std.conv;
int[][] a;
a.map!(x => x.map!to);
}
% dmd mod.d
Undefined symbols for architecture x86_64:
"_D3std9algorithm9iteration32__T9MapResultS123std4conv2toTAiZ9MapResult6__ctorMFNaNbNcNiNfAiZS3std9algorithm9iteration32__T9MapResultS123std4conv2toTAiZ9MapResult", referenced from:
_D3std9algorithm9iteration23__T3mapS123std4conv2toZ11__T3mapTAiZ3mapFNaNbNiNfAiZS3std9algorithm9iteration32__T9MapResultS123std4conv2toTAiZ9MapResult in mod.o
"_main", referenced from:
implicit entry/start for main executable
(maybe you meant: __d_main_args, _D4core6thread6Thread7sm_mainC4core6thread6Thread )
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
--- errorlevel 1
That code shouldn't compile (because of using std.conv.to without a target type), so it should never hit the linker at all.
Comment #1 by john.loughran.colvin — 2016-09-09T14:03:40Z
Reduced version without phobos imports:
void blah()
{
int[] a;
a.map!(x => x.map!to);
}
template to()
{
}
template map(fun...)
{
auto map(Range)(Range r)
{
alias RE = Range;
alias _fun = unaryFun!fun;
assert(!is(typeof(_fun(RE.init))));
MapResult!(_fun, Range)(r);
}
}
struct MapResult(alias fun, Range)
{
alias R = Range;
R _input;
this(R)
{
}
@property front()
{
fun(_input);
}
}
template unaryFun(alias fun)
{
alias unaryFun = fun;
}
Undefined symbols for architecture x86_64:
"_D3mod26__T9MapResultS73mod2toTAiZ9MapResult6__ctorMFNaNbNcNiNfAiZS3mod26__T9MapResultS73mod2toTAiZ9MapResult", referenced from:
_D3mod17__T3mapS73mod2toZ11__T3mapTAiZ3mapFNaNbNiNfAiZv in mod.o
If you comment out the assert then you get this error instead:
mod.d(34): Error: template mod.to cannot deduce function from argument types !()(int[]), candidates are:
mod.d(8): mod.to()
mod.d(19): Error: template instance mod.MapResult!(to, int[]) error instantiating
mod.d(5): instantiated from here: map!(int[])
mod.d(34): instantiated from here: __lambda1!(int[])
mod.d(19): instantiated from here: MapResult!(__lambda1, int[])
mod.d(5): instantiated from here: map!(int[])
which is what I expect and looks ok.
Comment #2 by ag0aep6g — 2016-09-09T14:50:27Z
Reduced further:
----
enum e = is(typeof(fun!()));
void fun()() { auto m = MapResult!()(0); }
alias f = fun!();
struct MapResult()
{
this(int) {}
void front() { undefined(); }
}
----
Looks similar to issue 16239.
When the 0 in `MapResult!()(0)` is removed, the program compiles and links (with -main). => accepts-invalid
Comment #3 by john.loughran.colvin — 2020-12-14T13:58:31Z
(In reply to ag0aep6g from comment #2)
> Reduced further:
>
> ----
> enum e = is(typeof(fun!()));
> void fun()() { auto m = MapResult!()(0); }
> alias f = fun!();
>
> struct MapResult()
> {
> this(int) {}
> void front() { undefined(); }
> }
> ----
>
> Looks similar to issue 16239.
>
> When the 0 in `MapResult!()(0)` is removed, the program compiles and links
> (with -main). => accepts-invalid
A little further info:
if you remove the enum e line, then compilation fails as expected, complaining about undefined.
If you change alias f = fun!() to void bar() { fun!(); } then there is no change (confirming that it's not a question of whether the unused fun instantiation needs to be emitted)
Comment #4 by razvan.nitu1305 — 2022-11-10T14:24:02Z
*** This issue has been marked as a duplicate of issue 15459 ***