The below should compile without errors:
struct S
{
~this()
{
}
}
void main()
{
S s;
enum error = __traits(compiles, { auto s1 = s; }));
static assert(!error); // line 1
}
----
Error: static assert (!true) is false
Comment out "line 1" to get the error that explains the problem:
Error: variable test.main.s has scoped destruction, cannot build closure
Comment #1 by bugzilla — 2011-03-12T00:50:04Z
Right. {auto s1=s;} is a delegate literal. Delegate literals need to be able to survive the end of the function they are defined inside. Since s is destroyed upon the exit from main(), then this will not work, hence the error message.
This is expected behavior, not a bug.
Comment #2 by samukha — 2011-03-12T01:53:09Z
No, no. The bug is not about the impossibility to build a closure. It is about __traits(compiles) not handling the compilation error properly. It should suppress the error and evaluate to false.
Another example:
struct S
{
~this()
{
}
}
void main()
{
S s;
static if (__traits(compiles, { auto s1 = s; }))
pragma(msg, "Can build closure");
else
pragma(msg, "Cannot build closure");
}
----
The compiler outputs:
Can build closure
Error: variable test.main.s has scoped destruction, cannot build closure
Instead, the above should compile successfully, printing "Cannot build closure" at compile time.
Comment #3 by samukha — 2011-03-12T02:37:00Z
Changed the title
Comment #4 by clugdbug — 2011-03-12T11:48:11Z
This is happening because the "has scoped destruction" error is generated in the glue layer, not in the front-end. The same issue applies to any error message generated in e2ir.c, toir.c, or s2ir.c.
Comment #5 by k.hara.pg — 2015-07-07T17:08:57Z
(In reply to Max Samukha from comment #2)
> No, no. The bug is not about the impossibility to build a closure. It is
> about __traits(compiles) not handling the compilation error properly. It
> should suppress the error and evaluate to false.
Today, a delegate literal in __traits(compiles) does not make the outer function closure, because the delegate is just a thing only in compile time.
I'd provide better example code:
struct S
{
~this() {}
}
void main()
{
enum r = __traits(compiles, {
auto madeClosure()
{
S s;
auto dg = { auto s1 = s; };
return dg;
}
});
static assert(!r); // line 1
}
The madeClosure function will be made a closure, because the dg that refers local variable s will escape from that. Then the "has scoped destruction..." error needs to be captured by the __traits(compile) and r should be false.
Comment #6 by razvan.nitu1305 — 2021-03-16T08:30:56Z
Today this code compiles succesfully and prints "destructor":
struct S
{
~this()
{
import std.stdio;
writeln("destructor");
}
}
void main()
{
S s;
enum error = __traits(compiles, { auto s1 = s; });
//static assert(!error); // line 1
}
It seems that the compiler is able to allocate the closure and also track it with the gc.
Closing as fixed.
Comment #7 by ibuclaw — 2022-03-28T13:06:20Z
Related test still fails though.
struct S10666
{
int val;
~this() {}
}
void foo10666(S10666 s1)
{
// Error: s1 has scoped destruction, cannot build closure.
auto f1 = (){ return () => s1.val; }();
enum r1 = __traits(compiles, {
auto f1 = (){ return () => s1.val; }();
});
static assert(!r1); // Error: static assert: `!r1` is false
}
Comment #8 by robert.schadek — 2024-12-13T17:55:04Z