Bug 21697 – Absurd limitations when passing lambda as alias parameter and bad error message
Status
RESOLVED
Resolution
DUPLICATE
Severity
major
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
x86
OS
All
Creation time
2021-03-10T01:23:30Z
Last change time
2024-03-19T10:05:37Z
Assigned to
No Owner
Creator
deadalnix
Comments
Comment #0 by deadalnix — 2021-03-10T01:23:30Z
See sample code:
module test;
struct S {
void foo() {}
void run(alias f)() { f(); }
void bar() {
// OK
run!foo();
// OK
void bar() {
foo();
}
run!bar();
// Error
run!(() { foo(); })();
}
}
The limitation of the 3rd syntax seems rather arbitrary. The error message is also rather inscrutable for someone who's not very familiar with D:
test.d(5): Error: function test.S.bar.run!(delegate () @system
{
this.foo();
}
).run cannot get frame pointer to test.S.bar.__lambda2
My interpretation of what is happening is that the lambda gets instantiated at the call site, and dmd assumes it needs a context when it doesn't. Note that the error message doesn't refers to the line at which the error occurs at all!
Comment #1 by john.loughran.colvin — 2021-03-10T13:37:22Z
The problem is triggered by the lambda being a template, yes
I expanded this to cover a bunch of cases to make sure I understood what was happening, maybe it will be useful to someone trying to solve it and/or as a comprehensive test.
module test;
import std.stdio;
//@safe:
struct S {
//@safe:
void foo() { writeln(&this); }
void foo2()() { writeln(&this); }
void runInsideDirect(alias f)() {
write("runInsideDirect!" ~ __traits(identifier, f) ~ ": ");
f();
}
void runInsideIndirect(alias f)() {
write("runInsideIndirect!" ~ __traits(identifier, f) ~ ": ");
auto b = &f;
b();
}
void runInsideTemplateDirect(alias f)() {
write("runInsideTemplateDirect!" ~ __traits(identifier, f) ~ ": ");
f!()();
}
void runInsideTemplateIndirect(alias f)() {
write("runInsideTemplateIndirect!" ~ __traits(identifier, f) ~ ": ");
auto b = &f!();
b();
}
void bar() {
runInsideDirect!foo();
runInsideIndirect!foo();
//runOutsideDirect!foo(); // Error: need this
runOutsideIndirect!foo(); // wrong this, caught by @safe
runInsideTemplateDirect!foo2();
runInsideTemplateIndirect!foo2();
//runOutsideTemplateDirect!foo2(); // Error: need this
runOutsideTemplateIndirect!foo2(); // wrong this, caught by @safe
runInsideDirect!(foo2!())();
runInsideIndirect!(foo2!())();
//runOutsideDirect!(foo2!())(); // Error: need this
runOutsideIndirect!(foo2!())(); // wrong this, caught by @safe
void bar() //@safe
{
foo();
}
void bar2()() //@safe
{
foo();
}
runInsideDirect!bar();
runInsideIndirect!bar();
runOutsideDirect!bar();
runOutsideIndirect!bar();
//runInsideTemplateDirect!bar2(); // Error: need this, but no "Error instantiating" message??
//runInsideTemplateIndirect!bar2(); // Error: need this, but no "Error instantiating" message??
//runOutsideTemplateDirect!bar2(); // Error: need this
//runOutsideTemplateIndirect!bar2(); // Error: need this
runInsideDirect!(bar2!())();
runInsideIndirect!(bar2!())();
runOutsideDirect!(bar2!())();
runOutsideIndirect!(bar2!())();
}
}
void runOutsideDirect(alias f)() {
write("runOutsideDirect!" ~ __traits(identifier, f) ~ ": ");
f();
}
void runOutsideIndirect(alias f)() {
write("runOutsideIndirect!" ~ __traits(identifier, f) ~ ": ");
auto b = &f;
b();
}
void runOutsideTemplateDirect(alias f)() {
write("runOutsideTemplateDirect!" ~ __traits(identifier, f) ~ ": ");
f!()();
}
void runOutsideTemplateIndirect(alias f)() {
write("runOutsideTemplateIndirect!" ~ __traits(identifier, f) ~ ": ");
auto b = &f!();
b();
}
void main() {
S s;
s.bar();
}
Comment #2 by snarwin+bugzilla — 2021-03-10T14:33:10Z
Probably related to issue 21287, although in that case it's the lambda that works and the nested function that fails.
Comment #3 by dfj1esp02 — 2024-03-19T10:05:37Z
*** This issue has been marked as a duplicate of issue 20922 ***