[Dlang-internal] Enable more pass-by-move of structs

Per Nordlöw per.nordlow at gmail.com
Fri Oct 26 11:56:51 UTC 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);
         return;
     }
     else
     {
         /* 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 at 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.


More information about the Dlang-internal mailing list