This is definitely a bug.

http://d.puremagic.com/issues/show_bug.cgi?id=9907 

Kenji Hara

2013/4/9 Ali Çehreli <acehreli@yahoo.com>
On 04/08/2013 12:24 PM, Maxim Fomin wrote:

> DMD often inserts temporaries when they are unexpected (or users do not
> expect when they should).
>
> D main function in destructor case is rewritten as:
>
>     S s = S(1);
>     s.opAssign(foo(2));
>     s.opAssign((S __sl1779 = S(3); , __sl1779))

Have you manually typed those lines or is there a tool that outputs that "preprocessor" ;) output?


>
> Hence, ref version is taken in account because '__sl1779' is a good lvalue.
>
> Troubles seems to come from
> https://github.com/D-Programming-Language/dmd/blob/master/src/expression.c#L4203
>

Thank you very much for finding the related line. :) Quoting:

Expression *StructLiteralExp::semantic(Scope *sc)
{ Expression *e;

// ...

    /* If struct requires a destructor, rewrite as:
     * (S tmp = S()),tmp
     * so that the destructor can be hung on tmp.
     */
    if (sd->dtor && sc->func)
    {
        Identifier *idtmp = Lexer::uniqueId("__sl");
        VarDeclaration *tmp = new VarDeclaration(loc, type, idtmp, new ExpInitializer(0, this));
        tmp->storage_class |= STCctfe;
        Expression *ae = new DeclarationExp(loc, tmp);
        Expression *e = new CommaExp(loc, ae, new VarExp(loc, tmp));
        e = e->semantic(sc);
        return e;
    }

    return this;
}

Is it because destructors cannot be "hung" on literals?

It is inconsistent that function-returned rvalues do not behave the same as literal-rvalues.

Ali