October 26, 2018
I'm trying to figure out how to enable more pass-by-move of structs in cases such as

    struct S
        @disable this(this);
        double x, y;

    void f()
        S a;
        S b = a; // pass by move for final ref of `a` in `a`'s scope

. The motivation for this has been approved by @andralex and is described and discussed at https://github.com/dlang/phobos/pull/4971.

AFAICT, the block

    if (e2x.isLvalue())
        if (!e2x.type.implicitConvTo(e1x.type))
            exp.error("conversion error from `%s` to `%s`",
                      e2x.type.toChars(), e1x.type.toChars());
            return setError();

        /* Rewrite as:
         *  (e1 = e2).postblit();
         * Blit assignment e1 = e2 returns a reference to the original e1,
         * then call the postblit on it.
        Expression e = e1x.copy();
        e.type = e.type.mutableOf();
        if (e.type.isShared && !sd.type.isShared)
            e.type = e.type.unSharedOf();
        e = new BlitExp(exp.loc, e, e2x);
        e = new DotVarExp(exp.loc, e, sd.postblit, false);
        e = new CallExp(exp.loc, e);
        result = e.expressionSemantic(sc);
        /* The struct value returned from the function is transferred
         * so should not call the destructor on it.
        e2x = valueNoDtor(e2x);

in `ExpressionSemanticVisitor.visit(AssignExp exp)` in the file `expressionsem.d` (currently on line 7874) is where we should modify things.

I'm not sure if it suffices to just do

    e2x = valueNoDtor(e2x);

for the case where `ex2` (`a` in the code example) is the final reference (which I also need to figure out how to do detect). I'm guessing not because `e2x` (variable `a` in the code above) is not an r-value expression.

More specifically it would be nice to have a brief explanation of the meaning of

    Expression e = e1x.copy(); // TODO is this needed in the move case?
    e.type = e.type.mutableOf(); TODO I guess we should keep as is, right?
    if (e.type.isShared && !sd.type.isShared)
        e.type = e.type.unSharedOf(); // TODO I guess we should keep as is, right?
    e = new BlitExp(exp.loc, e, e2x); // TODO I guess we need this for raw data move, right?
    e = new DotVarExp(exp.loc, e, sd.postblit, false); // I guess we don't this, right?
    e = new CallExp(exp.loc, e); // TODO do we need this?
    result = e.expressionSemantic(sc); // TODO I guess we should keep as is, right?

and in what way they should be modified for the move case. I'm presume we need the `BlitExp` for raw data copying from rhs and lhs and to disable the destructor for `e2x` (rhs).

This leads up to two things I need help with:

1. Given that I do figure out a way to detect when an expression is the final reference to an l-value how do I update the AST so that `e2` is moved to `e1` without calling `e1`'s postblit?

2. I also warmly welcome tips on how to detect when a ref to an l-value _is_ the last ref in the scope of that l-value's lifetime.

I tried posting this on dmd-internals list after having registered my email per.nordlow@gmail.com but that errors as

SMTP error: Error (Unexpected MAIL FROM response) while handling line from SMTP server: 451 4.7.1 Please try again later (TEMPFAIL)


Solution will be added to https://github.com/dlang/dmd/pull/8866.