April 09, 2022

Hello,
Why doesn't this code compile?


static struct Foo{
    void *ptr;

    void proxySwap1(scope ref typeof(this) rhs)scope pure nothrow @trusted @nogc{
        auto tmp = this.ptr;
        this.ptr = rhs.ptr;
        rhs.ptr = tmp;
    }
    void proxySwap2()(scope ref typeof(this) rhs)scope pure nothrow @trusted @nogc{
        this.proxySwap1(rhs);
    }
    void proxySwap3()(scope ref typeof(this) rhs)scope pure nothrow @trusted @nogc{
        auto tmp = this.ptr;
        this.ptr = rhs.ptr;
        rhs.ptr = tmp;
    }
}

void main()@safe{

    scope Foo a;
    scope Foo b;

    a.proxySwap1(b);	//OK
    a.proxySwap2(b);	//OK
    a.proxySwap3(b);	//Error: scope variable `b` assigned to `a` with longer lifetime
}
April 09, 2022

On Saturday, 9 April 2022 at 10:39:33 UTC, vit wrote:

>

Why doesn't this code compile?

proxySwap1 is lying about its attributes. It says rhs is scope, but it escapes by assignment this.ptr = rhs.ptr;. The compiler doesn't raise an error because it's marked @trusted.

proxySwap2 is simply a template function wrapping proxySwap1, attributes are inferred based on the signature you specified for proxySwap1 (even if it's wrong).

proxySwap3 is a template function, so the compiler infers rhs to be return scope. While a @trusted function allows you to escape scope variables, the compiler will still try to infer scope, return scope or return ref on its parameters as far as it can, and that can spawn errors in its @safe callers.

Swapping scope variables is not something you can do in @safe code with dip1000's current design, because of this:

void main() @safe {
    scope Foo a;
	{
		int x;
		scope Foo b = Foo(&x);
		a.proxySwap3(b); // scope variable `b` assigned to `a` with longer lifetime
	}
	// a is now a dangling pointer
}