www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Something wrong with reflection inside struct destructor

reply Jack Applegame <japplegame gmail.com> writes:
I'm trying to write reference counted dynamic array and 
encountered a trouble with compile time reflection at recursive 
template instantiation.

for dynamic arrays (and AA too) it is normal to use recursive 
declarations:

struct S {
     S[] arr;
}

struct S {
     Array!S arr;
}

Look at this code: (DPaste - https://dpaste.dzfl.pl/2010191369fe)
import std.string : format;

struct Bar(E) {
     void fun() {
         pragma(msg, format("fun:   Foo.__xdtor - %s", 
__traits(hasMember, E, "__xdtor")));
         pragma(msg, format("fun:   Bar.__xdtor - %s", 
__traits(hasMember, Bar, "__xdtor")));
         pragma(msg, format("fun:   Foo.__dtor - %s", 
__traits(hasMember, E, "__dtor")));
         pragma(msg, format("fun:   Bar.__dtor - %s", 
__traits(hasMember, Bar, "__dtor")));
     }
     ~this() {
         pragma(msg, format("~this:   Foo.__xdtor - %s", 
__traits(hasMember, E, "__xdtor")));
         pragma(msg, format("~this:   Bar.__xdtor - %s", 
__traits(hasMember, Bar, "__xdtor")));
         pragma(msg, format("~this:   Foo.__dtor - %s", 
__traits(hasMember, E, "__dtor")));
         pragma(msg, format("~this:   Bar.__dtor - %s", 
__traits(hasMember, Bar, "__dtor")));
     }
}

struct Foo {
     Bar!Foo foo;
     ~this() {}
}

void main() {}

Output:
~this: Foo.__dtor - true        <--- Foo has __dtor, OK,
~this: Bar.__dtor - true
~this: Foo.__xdtor - false      <--- but hasn't __xdtor. WAT???
~this: Bar.__xdtor - true
fun: Foo.__dtor - true
fun: Bar.__dtor - true
fun: Foo.__xdtor - true
fun: Bar.__xdtor - true

Global object.destroy(ref T) function detects destructor presence 
by __traits(hasMember, T, "__xdtor") 
(https://github.com/dlang/druntime/blob/v2.073.2/src/object.d#L2440) and does
nothing in such cases.

Workaround:
Avoid reflection in the destructor. Do reflection in normal 
function and then call it from destructor.

But it looks weird and should be fixed.

Also see related topic: 
https://forum.dlang.org/thread/okbzqkjijuwvmvstjnzk forum.dlang.org
Mar 14 2017
parent reply Jack Applegame <japplegame gmail.com> writes:
On Tuesday, 14 March 2017 at 12:44:16 UTC, Jack Applegame wrote:
 Workaround:
 Avoid reflection in the destructor. Do reflection in normal 
 function and then call it from destructor.
This doesn't work - https://dpaste.dzfl.pl/5a1d93f7a277 Call from destructor changes compiler behavior. This is terrible.
Mar 14 2017
next sibling parent Jack Applegame <japplegame gmail.com> writes:
This is completely unacceptable:

DPaste(https://dpaste.dzfl.pl/f54f578c4ec9)

import std.stdio;
import std.string;
import std.experimental.allocator;
import std.experimental.allocator.mallocator : Mallocator;

struct Bar(E) {
     E* ptr = null;
     void allocate(int m) { ptr = Mallocator.instance.make!Foo(m); 
}
     ~this() {
         if(ptr !is null) Mallocator.instance.dispose(ptr);
     }
}

struct A {
     int m;
     ~this() { writefln("A.~this(%s)", m); }
}

struct Foo {
     A a;
     Bar!Foo bar;
     this(int m) { a = A(m); }
}

void main() {
     auto foo = Foo(1);
     foo.bar.allocate(10);
}

Output:
A.~this(1)

Expected output:
A.~this(10)
A.~this(1)

Can someone to fix this ASAP for $100?
Mar 14 2017
prev sibling parent reply John Colvin <john.loughran.colvin gmail.com> writes:
On Tuesday, 14 March 2017 at 13:38:52 UTC, Jack Applegame wrote:
 On Tuesday, 14 March 2017 at 12:44:16 UTC, Jack Applegame wrote:
 Workaround:
 Avoid reflection in the destructor. Do reflection in normal 
 function and then call it from destructor.
This doesn't work - https://dpaste.dzfl.pl/5a1d93f7a277 Call from destructor changes compiler behavior. This is terrible.
bug report?
Mar 14 2017
parent Jack Applegame <japplegame gmail.com> writes:
On Tuesday, 14 March 2017 at 14:33:49 UTC, John Colvin wrote:
 bug report?
https://issues.dlang.org/show_bug.cgi?id=17257
Mar 14 2017