Thread overview
How to call destroy() in @nogc?
May 24, 2022
cc
May 24, 2022
Tejas
May 24, 2022
cc
May 24, 2022
Adam Ruppe
May 24, 2022
import core.memory;
import core.stdc.stdlib : malloc, free;
import core.lifetime : emplace;

T NEW(T, Args...)(auto ref Args args) /*@nogc*/ if (is(T == class)) {
	enum size = __traits(classInstanceSize, T);
	void* mem = malloc(size);
	scope(failure) free(mem);
	return mem !is null ? emplace!T(mem[0..size], args) : null;
}
void FREE(T)(ref T obj) @nogc if (is(T == class)) {
	auto mem = cast(void*) obj;
	scope(exit) free(mem);
	destroy(obj);
	obj = null;
}

class Foo {
	~this() @nogc {}
}

void main() {
	auto foo = NEW!Foo;
	FREE(foo);
}
Error: `@nogc` function `nogctest.FREE!(Foo).FREE` cannot call non-@nogc function `object.destroy!(true, Foo).destroy`

Is this not currently possible? Found this thread:
https://forum.dlang.org/thread/zanuuhzmqxljadcexmgv@forum.dlang.org?page=1
is it still unresolved?

May 24, 2022

On Tuesday, 24 May 2022 at 02:29:38 UTC, cc wrote:

>
import core.memory;
import core.stdc.stdlib : malloc, free;
import core.lifetime : emplace;

[...]

FWIW your code will compile if you add extern(C++) to Foo

May 24, 2022

On Tuesday, 24 May 2022 at 02:55:06 UTC, Tejas wrote:

>

On Tuesday, 24 May 2022 at 02:29:38 UTC, cc wrote:

>
import core.memory;
import core.stdc.stdlib : malloc, free;
import core.lifetime : emplace;

[...]

FWIW your code will compile if you add extern(C++) to Foo

Interesting, thanks. I noticed something similar when trying to call malloc in a pure function...

std.internal.memory:

extern (C) @nogc nothrow pure private
{
    pragma(mangle, "malloc") void* fakePureMalloc(size_t) @safe;
    pragma(mangle, "calloc") void* fakePureCalloc(size_t nmemb, size_t size) @safe;
    pragma(mangle, "realloc") void* fakePureRealloc(return scope void* ptr, size_t size) @system;
}
May 24, 2022

On 5/23/22 10:29 PM, cc wrote:

>
import core.memory;
import core.stdc.stdlib : malloc, free;
import core.lifetime : emplace;

T NEW(T, Args...)(auto ref Args args) /*@nogc*/ if (is(T == class)) {
     enum size = __traits(classInstanceSize, T);
     void* mem = malloc(size);
     scope(failure) free(mem);
     return mem !is null ? emplace!T(mem[0..size], args) : null;
}
void FREE(T)(ref T obj) @nogc if (is(T == class)) {
     auto mem = cast(void*) obj;
     scope(exit) free(mem);
     destroy(obj);
     obj = null;
}

class Foo {
     ~this() @nogc {}
}

void main() {
     auto foo = NEW!Foo;
     FREE(foo);
}
Error: `@nogc` function `nogctest.FREE!(Foo).FREE` cannot call non-@nogc function `object.destroy!(true, Foo).destroy`

Is this not currently possible?  Found this thread:
https://forum.dlang.org/thread/zanuuhzmqxljadcexmgv@forum.dlang.org?page=1
is it still unresolved?

It's because destroy calls the destructor without any attribute requirements aside from nothrow.

https://github.com/dlang/druntime/blob/bdeee862aaa125e75aebc3118a43d2d5e5ee954d/src/object.d#L4431-L4453

Here is the definition of rt_finalize2: https://github.com/dlang/druntime/blob/bdeee862aaa125e75aebc3118a43d2d5e5ee954d/src/rt/lifetime.d#L1402

Note it has no idea what the real object type is at this point, just that it is an Object (which does not have a @nogc destructor).

-Steve

May 24, 2022

On Tuesday, 24 May 2022 at 14:11:57 UTC, Steven Schveighoffer wrote:

>

Note it has no idea what the real object type is at this point, just that it is an Object (which does not have a @nogc destructor).

It actually has nothing to do with Object. It doesn't have a destructor at all, so there's no problem calling it from any context.

The real problem is that destructors don't actually use the virtual machinery and call super(), meaning it is impossible to tell at compile time what they're doing at all.

I know I wrote at length about this somewhere but can't find it right now. Probably in the chatroom. But even if you know static type, you can't make assumptions about the dynamic type since destructors (for no good reason tbh) don't follow the same rules as other virtual methods, despite the spec saying they are virtual.