Example #1
0
File: clone.c Project: 1100110/dmd
FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc)
{
    /* Copy constructor is only necessary if there is a postblit function,
     * otherwise the code generator will just do a bit copy.
     */
    if (!postblit)
        return NULL;

    //printf("StructDeclaration::buildCpCtor() %s\n", toChars());
    StorageClass stc = STCsafe | STCnothrow | STCpure;
    Loc declLoc = postblit->loc;
    Loc loc = Loc();    // internal code should have no loc to prevent coverage

    stc = mergeFuncAttrs(stc, postblit->storage_class);
    if (stc & STCsafe)  // change to @trusted for unsafe casts
        stc = (stc & ~STCsafe) | STCtrusted;

    Parameters *fparams = new Parameters;
    fparams->push(new Parameter(STCref, type->constOf(), Id::p, NULL));
    Type *tf = new TypeFunction(fparams, Type::tvoid, 0, LINKd, stc);
    tf->mod = MODconst;

    FuncDeclaration *fcp = new FuncDeclaration(declLoc, Loc(), Id::cpctor, stc, tf);

    if (!(stc & STCdisable))
    {
        // Build *this = p;
        Expression *e = new ThisExp(loc);
        AssignExp *ea = new AssignExp(loc,
            new PtrExp(loc, new CastExp(loc, new AddrExp(loc, e), type->mutableOf()->pointerTo())),
            new PtrExp(loc, new CastExp(loc, new AddrExp(loc, new IdentifierExp(loc, Id::p)), type->mutableOf()->pointerTo()))
        );
        ea->op = TOKblit;
        Statement *s = new ExpStatement(loc, ea);

        // Build postBlit();
        e = new ThisExp(loc);
        e = new PtrExp(loc, new CastExp(loc, new AddrExp(loc, e), type->mutableOf()->pointerTo()));
        e = new DotVarExp(loc, e, postblit, 0);
        e = new CallExp(loc, e);

        s = new CompoundStatement(loc, s, new ExpStatement(loc, e));
        fcp->fbody = s;
    }

    members->push(fcp);

    sc = sc->push();
    sc->stc = 0;
    sc->linkage = LINKd;

    fcp->semantic(sc);

    sc->pop();

    return fcp;
}
Example #2
0
File: clone.c Project: nrTQgc/ldc
/******************************************
 * Create inclusive invariant for struct/class by aggregating
 * all the invariants in invs[].
 *      void __invariant() const [pure nothrow @trusted]
 *      {
 *          invs[0](), invs[1](), ...;
 *      }
 */
FuncDeclaration *buildInv(AggregateDeclaration *ad, Scope *sc)
{
    StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
    Loc declLoc = ad->loc;
    Loc loc = Loc();    // internal code should have no loc to prevent coverage

    switch (ad->invs.dim)
    {
        case 0:
            return NULL;

        case 1:
            // Don't return invs[0] so it has uniquely generated name.
            /* fall through */

        default:
            Expression *e = NULL;
            StorageClass stcx = 0;
            for (size_t i = 0; i < ad->invs.dim; i++)
            {
                stc = mergeFuncAttrs(stc, ad->invs[i]);
                if (stc & STCdisable)
                {
                    // What should do?
                }
                StorageClass stcy = (ad->invs[i]->storage_class & STCsynchronized) |
                                    (ad->invs[i]->type->mod & MODshared ? STCshared : 0);
                if (i == 0)
                    stcx = stcy;
                else if (stcx ^ stcy)
                {
            #if 1   // currently rejects
                    ad->error(ad->invs[i]->loc, "mixing invariants with shared/synchronized differene is not supported");
                    e = NULL;
                    break;
            #endif
                }
                e = Expression::combine(e, new CallExp(loc, new VarExp(loc, ad->invs[i])));
            }
            InvariantDeclaration *inv;
            inv = new InvariantDeclaration(declLoc, Loc(), stc | stcx, Id::classInvariant);
            inv->fbody = new ExpStatement(loc, e);
            ad->members->push(inv);
            inv->semantic(sc);
            return inv;
    }
}
Example #3
0
File: clone.c Project: nrTQgc/ldc
/*****************************************
 * Create inclusive destructor for struct/class by aggregating
 * all the destructors in dtors[] with the destructors for
 * all the members.
 * Note the close similarity with StructDeclaration::buildPostBlit(),
 * and the ordering changes (runs backward instead of forwards).
 */
FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc)
{
    //printf("AggregateDeclaration::buildDtor() %s\n", ad->toChars());
    StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
    Loc declLoc = ad->dtors.dim ? ad->dtors[0]->loc : ad->loc;
    Loc loc = Loc();    // internal code should have no loc to prevent coverage

    Expression *e = NULL;
    for (size_t i = 0; i < ad->fields.dim; i++)
    {
        VarDeclaration *v = ad->fields[i];
        if (v->storage_class & STCref)
            continue;
        Type *tv = v->type->baseElemOf();
        if (tv->ty != Tstruct || !v->type->size())
            continue;
        StructDeclaration *sdv = ((TypeStruct *)tv)->sym;
        if (!sdv->dtor)
            continue;
        sdv->dtor->functionSemantic();

        stc = mergeFuncAttrs(stc, sdv->dtor);
        if (stc & STCdisable)
        {
            e = NULL;
            break;
        }

        Expression *ex = new ThisExp(loc);
        ex = new DotVarExp(loc, ex, v, 0);
        if (v->type->toBasetype()->ty == Tstruct)
        {
            // this.v.__xdtor()

            // This is a hack so we can call destructors on const/immutable objects.
            ex = new AddrExp(loc, ex);
            ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo());
            ex = new PtrExp(loc, ex);
            if (stc & STCsafe)
                stc = (stc & ~STCsafe) | STCtrusted;

            ex = new DotVarExp(loc, ex, sdv->dtor, 0);
            ex = new CallExp(loc, ex);
        }
        else
        {
            // _ArrayDtor((cast(S*)this.v.ptr)[0 .. n])

            // This is a hack so we can call destructors on const/immutable objects.
            ex = new DotIdExp(loc, ex, Id::ptr);
            ex = new CastExp(loc, ex, sdv->type->pointerTo());
            if (stc & STCsafe)
                stc = (stc & ~STCsafe) | STCtrusted;

            uinteger_t n = v->type->size() / sdv->type->size();
            ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t),
                                       new IntegerExp(loc, n, Type::tsize_t));
            // Prevent redundant bounds check
            ((SliceExp *)ex)->upperIsInBounds = true;
            ((SliceExp *)ex)->lowerIsLessThanUpper = true;

            ex = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayDtor), ex);
        }
        e = Expression::combine(ex, e); // combine in reverse order
    }

    /* Build our own "destructor" which executes e
     */
    if (e || (stc & STCdisable))
    {
        //printf("Building __fieldDtor()\n");
        DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Id::__fieldDtor);
        dd->storage_class |= STCinference;
        dd->fbody = new ExpStatement(loc, e);
        ad->dtors.shift(dd);
        ad->members->push(dd);
        dd->semantic(sc);
    }

    FuncDeclaration *xdtor = NULL;
    switch (ad->dtors.dim)
    {
        case 0:
            break;

        case 1:
            xdtor = ad->dtors[0];
            break;

        default:
            e = NULL;
            stc = STCsafe | STCnothrow | STCpure | STCnogc;
            for (size_t i = 0; i < ad->dtors.dim; i++)
            {
                FuncDeclaration *fd = ad->dtors[i];
                stc = mergeFuncAttrs(stc, fd);
                if (stc & STCdisable)
                {
                    e = NULL;
                    break;
                }
                Expression *ex = new ThisExp(loc);
                ex = new DotVarExp(loc, ex, fd, 0);
                ex = new CallExp(loc, ex);
                e = Expression::combine(ex, e);
            }
            DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Id::__aggrDtor);
            dd->storage_class |= STCinference;
            dd->fbody = new ExpStatement(loc, e);
            ad->members->push(dd);
            dd->semantic(sc);
            xdtor = dd;
            break;
    }
    // Add an __xdtor alias to make the inclusive dtor accessible
    if (xdtor)
    {
        AliasDeclaration *alias = new AliasDeclaration(Loc(), Id::__xdtor, xdtor);
        alias->semantic(sc);
        ad->members->push(alias);
        alias->addMember(sc, ad); // add to symbol table
    }
    return xdtor;
}
Example #4
0
File: clone.c Project: nrTQgc/ldc
/*****************************************
 * Create inclusive postblit for struct by aggregating
 * all the postblits in postblits[] with the postblits for
 * all the members.
 * Note the close similarity with AggregateDeclaration::buildDtor(),
 * and the ordering changes (runs forward instead of backwards).
 */
FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc)
{
    //printf("StructDeclaration::buildPostBlit() %s\n", sd->toChars());
    StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
    Loc declLoc = sd->postblits.dim ? sd->postblits[0]->loc : sd->loc;
    Loc loc = Loc();    // internal code should have no loc to prevent coverage

    for (size_t i = 0; i < sd->postblits.dim; i++)
    {
        stc |= sd->postblits[i]->storage_class & STCdisable;
    }

    Statements *a = NULL;
    for (size_t i = 0; i < sd->fields.dim && !(stc & STCdisable); i++)
    {
        VarDeclaration *v = sd->fields[i];
        if (v->storage_class & STCref)
            continue;
        Type *tv = v->type->baseElemOf();
        if (tv->ty != Tstruct || !v->type->size())
            continue;
        StructDeclaration *sdv = ((TypeStruct *)tv)->sym;
        if (!sdv->postblit)
            continue;
        sdv->postblit->functionSemantic();

        stc = mergeFuncAttrs(stc, sdv->postblit);
        stc = mergeFuncAttrs(stc, sdv->dtor);
        if (stc & STCdisable)
        {
            a = NULL;
            break;
        }
        if (!a)
            a = new Statements();

        Expression *ex = new ThisExp(loc);
        ex = new DotVarExp(loc, ex, v, 0);
        if (v->type->toBasetype()->ty == Tstruct)
        {
            // this.v.__xpostblit()

            // This is a hack so we can call postblits on const/immutable objects.
            ex = new AddrExp(loc, ex);
            ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo());
            ex = new PtrExp(loc, ex);
            if (stc & STCsafe)
                stc = (stc & ~STCsafe) | STCtrusted;

            ex = new DotVarExp(loc, ex, sdv->postblit, 0);
            ex = new CallExp(loc, ex);
        }
        else
        {
            // _ArrayPostblit((cast(S*)this.v.ptr)[0 .. n])

            // This is a hack so we can call postblits on const/immutable objects.
            ex = new DotIdExp(loc, ex, Id::ptr);
            ex = new CastExp(loc, ex, sdv->type->pointerTo());
            if (stc & STCsafe)
                stc = (stc & ~STCsafe) | STCtrusted;

            uinteger_t n = v->type->size() / sdv->type->size();
            ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t),
                                       new IntegerExp(loc, n, Type::tsize_t));
            // Prevent redundant bounds check
            ((SliceExp *)ex)->upperIsInBounds = true;
            ((SliceExp *)ex)->lowerIsLessThanUpper = true;

            ex = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayPostblit), ex);
        }
        a->push(new ExpStatement(loc, ex)); // combine in forward order

        /* Bugzilla 10972: When the following field postblit calls fail,
         * this field should be destructed for Exception Safety.
         */
        if (!sdv->dtor)
            continue;
        sdv->dtor->functionSemantic();

        ex = new ThisExp(loc);
        ex = new DotVarExp(loc, ex, v, 0);
        if (v->type->toBasetype()->ty == Tstruct)
        {
            // this.v.__xdtor()

            // This is a hack so we can call destructors on const/immutable objects.
            ex = new AddrExp(loc, ex);
            ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo());
            ex = new PtrExp(loc, ex);
            if (stc & STCsafe)
                stc = (stc & ~STCsafe) | STCtrusted;

            ex = new DotVarExp(loc, ex, sdv->dtor, 0);
            ex = new CallExp(loc, ex);
        }
        else
        {
            // _ArrayDtor((cast(S*)this.v.ptr)[0 .. n])

            // This is a hack so we can call destructors on const/immutable objects.
            ex = new DotIdExp(loc, ex, Id::ptr);
            ex = new CastExp(loc, ex, sdv->type->pointerTo());
            if (stc & STCsafe)
                stc = (stc & ~STCsafe) | STCtrusted;

            uinteger_t n = v->type->size() / sdv->type->size();
            ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t),
                                       new IntegerExp(loc, n, Type::tsize_t));
            // Prevent redundant bounds check
            ((SliceExp *)ex)->upperIsInBounds = true;
            ((SliceExp *)ex)->lowerIsLessThanUpper = true;

            ex = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayDtor), ex);
        }
        a->push(new OnScopeStatement(loc, TOKon_scope_failure, new ExpStatement(loc, ex)));
    }

    /* Build our own "postblit" which executes a
     */
    if (a || (stc & STCdisable))
    {
        //printf("Building __fieldPostBlit()\n");
        PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Id::__fieldPostblit);
        dd->storage_class |= STCinference;
        dd->fbody = a ? new CompoundStatement(loc, a) : NULL;
        sd->postblits.shift(dd);
        sd->members->push(dd);
        dd->semantic(sc);
    }

    FuncDeclaration *xpostblit = NULL;
    switch (sd->postblits.dim)
    {
        case 0:
            break;

        case 1:
            xpostblit = sd->postblits[0];
            break;

        default:
            Expression *e = NULL;
            stc = STCsafe | STCnothrow | STCpure | STCnogc;
            for (size_t i = 0; i < sd->postblits.dim; i++)
            {
                FuncDeclaration *fd = sd->postblits[i];
                stc = mergeFuncAttrs(stc, fd);
                if (stc & STCdisable)
                {
                    e = NULL;
                    break;
                }
                Expression *ex = new ThisExp(loc);
                ex = new DotVarExp(loc, ex, fd, 0);
                ex = new CallExp(loc, ex);
                e = Expression::combine(e, ex);
            }
            PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Id::__aggrPostblit);
            dd->storage_class |= STCinference;
            dd->fbody = new ExpStatement(loc, e);
            sd->members->push(dd);
            dd->semantic(sc);
            xpostblit = dd;
            break;
    }
    // Add an __xpostblit alias to make the inclusive postblit accessible
    if (xpostblit)
    {
        AliasDeclaration *alias = new AliasDeclaration(Loc(), Id::__xpostblit, xpostblit);
        alias->semantic(sc);
        sd->members->push(alias);
        alias->addMember(sc, sd); // add to symbol table
    }
    return xpostblit;
}
Example #5
0
File: clone.c Project: nrTQgc/ldc
/******************************************
 * Build opAssign for struct.
 *      ref S opAssign(S s) { ... }
 *
 * Note that s will be constructed onto the stack, and probably
 * copy-constructed in caller site.
 *
 * If S has copy copy construction and/or destructor,
 * the body will make bit-wise object swap:
 *          S __swap = this; // bit copy
 *          this = s;        // bit copy
 *          __swap.dtor();
 * Instead of running the destructor on s, run it on tmp instead.
 *
 * Otherwise, the body will make member-wise assignments:
 * Then, the body is:
 *          this.field1 = s.field1;
 *          this.field2 = s.field2;
 *          ...;
 */
FuncDeclaration *buildOpAssign(StructDeclaration *sd, Scope *sc)
{
    if (FuncDeclaration *f = hasIdentityOpAssign(sd, sc))
    {
        sd->hasIdentityAssign = true;
        return f;
    }
    // Even if non-identity opAssign is defined, built-in identity opAssign
    // will be defined.

    if (!needOpAssign(sd))
        return NULL;

    //printf("StructDeclaration::buildOpAssign() %s\n", sd->toChars());
    StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
    Loc declLoc = sd->loc;
    Loc loc = Loc();    // internal code should have no loc to prevent coverage

    if (sd->dtor || sd->postblit)
    {
        if (!sd->type->isAssignable())  // Bugzilla 13044
            return NULL;
        stc = mergeFuncAttrs(stc, sd->dtor);
        if (stc & STCsafe)
            stc = (stc & ~STCsafe) | STCtrusted;
    }
    else
    {
        for (size_t i = 0; i < sd->fields.dim; i++)
        {
            VarDeclaration *v = sd->fields[i];
            if (v->storage_class & STCref)
                continue;
            Type *tv = v->type->baseElemOf();
            if (tv->ty != Tstruct)
                continue;

            StructDeclaration *sdv = ((TypeStruct *)tv)->sym;
            stc = mergeFuncAttrs(stc, hasIdentityOpAssign(sdv, sc));
        }
    }

    Parameters *fparams = new Parameters;
    fparams->push(new Parameter(STCnodtor, sd->type, Id::p, NULL));
    TypeFunction *tf = new TypeFunction(fparams, sd->handleType(), 0, LINKd, stc | STCref);

    FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), Id::assign, stc, tf);
    fop->storage_class |= STCinference;

    Expression *e = NULL;
    if (stc & STCdisable)
    {
    }
    else if (sd->dtor || sd->postblit)
    {
        /* Do swap this and rhs
         *    __swap = this; this = s; __swap.dtor();
         */
        //printf("\tswap copy\n");
        Identifier *idtmp = Identifier::generateId("__swap");
        VarDeclaration *tmp = NULL;
        AssignExp *ec = NULL;
        if (sd->dtor)
        {
            tmp = new VarDeclaration(loc, sd->type, idtmp, new VoidInitializer(loc));
            tmp->noscope = 1;
            tmp->storage_class |= STCtemp | STCctfe;
            e = new DeclarationExp(loc, tmp);
            ec = new BlitExp(loc, new VarExp(loc, tmp), new ThisExp(loc));
            e = Expression::combine(e, ec);
        }
        ec = new BlitExp(loc, new ThisExp(loc), new IdentifierExp(loc, Id::p));
        e = Expression::combine(e, ec);
        if (sd->dtor)
        {
            /* Instead of running the destructor on s, run it
             * on tmp. This avoids needing to copy tmp back in to s.
             */
            Expression *ec2 = new DotVarExp(loc, new VarExp(loc, tmp), sd->dtor, 0);
            ec2 = new CallExp(loc, ec2);
            e = Expression::combine(e, ec2);
        }
    }
    else
    {
        /* Do memberwise copy
         */
        //printf("\tmemberwise copy\n");
        for (size_t i = 0; i < sd->fields.dim; i++)
        {
            VarDeclaration *v = sd->fields[i];
            // this.v = s.v;
            AssignExp *ec = new AssignExp(loc,
                new DotVarExp(loc, new ThisExp(loc), v, 0),
                new DotVarExp(loc, new IdentifierExp(loc, Id::p), v, 0));
            e = Expression::combine(e, ec);
        }
    }
    if (e)
    {
        Statement *s1 = new ExpStatement(loc, e);

        /* Add:
         *   return this;
         */
        e = new ThisExp(loc);
        Statement *s2 = new ReturnStatement(loc, e);

        fop->fbody = new CompoundStatement(loc, s1, s2);
        tf->isreturn = true;
    }

    sd->members->push(fop);
    fop->addMember(sc, sd);
    sd->hasIdentityAssign = true;        // temporary mark identity assignable

    unsigned errors = global.startGagging();    // Do not report errors, even if the
    Scope *sc2 = sc->push();
    sc2->stc = 0;
    sc2->linkage = LINKd;

    fop->semantic(sc2);
    fop->semantic2(sc2);
    // Bugzilla 15044: fop->semantic3 isn't run here for lazy forward reference resolution.

    sc2->pop();
    if (global.endGagging(errors))    // if errors happened
    {
        // Disable generated opAssign, because some members forbid identity assignment.
        fop->storage_class |= STCdisable;
        fop->fbody = NULL;  // remove fbody which contains the error
    }

    //printf("-StructDeclaration::buildOpAssign() %s, errors = %d\n", sd->toChars(), (fop->storage_class & STCdisable) != 0);

    return fop;
}
Example #6
0
File: clone.c Project: 1100110/dmd
FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc)
{
    //printf("AggregateDeclaration::buildDtor() %s\n", toChars());
    StorageClass stc = STCsafe | STCnothrow | STCpure;
    Loc declLoc = dtors.dim ? dtors[0]->loc : this->loc;
    Loc loc = Loc();    // internal code should have no loc to prevent coverage

    Expression *e = NULL;
#if DMDV2
    for (size_t i = 0; i < fields.dim; i++)
    {
        Dsymbol *s = fields[i];
        VarDeclaration *v = s->isVarDeclaration();
        assert(v && v->isField());
        if (v->storage_class & STCref)
            continue;
        Type *tv = v->type->toBasetype();
        dinteger_t dim = 1;
        while (tv->ty == Tsarray)
        {   TypeSArray *ta = (TypeSArray *)tv;
            dim *= ((TypeSArray *)tv)->dim->toInteger();
            tv = tv->nextOf()->toBasetype();
        }
        if (tv->ty == Tstruct)
        {   TypeStruct *ts = (TypeStruct *)tv;
            StructDeclaration *sd = ts->sym;
            if (sd->dtor && dim)
            {
                stc = mergeFuncAttrs(stc, sd->dtor->storage_class);
                if (stc & STCdisable)
                {
                    e = NULL;
                    break;
                }

                // this.v
                Expression *ex = new ThisExp(loc);
                ex = new DotVarExp(loc, ex, v, 0);

                if (v->type->toBasetype()->ty == Tstruct)
                {   // this.v.dtor()
                    ex = new DotVarExp(loc, ex, sd->dtor, 0);
                    ex = new CallExp(loc, ex);
                }
                else
                {
                    // Typeinfo.destroy(cast(void*)&this.v);
                    Expression *ea = new AddrExp(loc, ex);
                    ea = new CastExp(loc, ea, Type::tvoid->pointerTo());

                    Expression *et = v->type->getTypeInfo(sc);
                    et = new DotIdExp(loc, et, Id::destroy);

                    ex = new CallExp(loc, et, ea);
                }
                e = Expression::combine(ex, e); // combine in reverse order
            }
        }
    }

    /* Build our own "destructor" which executes e
     */
    if (e || (stc & STCdisable))
    {   //printf("Building __fieldDtor()\n");
        DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Lexer::idPool("__fieldDtor"));
        dd->fbody = new ExpStatement(loc, e);
        dtors.shift(dd);
        members->push(dd);
        dd->semantic(sc);
    }
#endif

    switch (dtors.dim)
    {
        case 0:
            return NULL;

        case 1:
            return dtors[0];

        default:
            e = NULL;
            stc = STCsafe | STCnothrow | STCpure;
            for (size_t i = 0; i < dtors.dim; i++)
            {
                FuncDeclaration *fd = dtors[i];
                stc = mergeFuncAttrs(stc, fd->storage_class);
                if (stc & STCdisable)
                {
                    e = NULL;
                    break;
                }
                Expression *ex = new ThisExp(loc);
                ex = new DotVarExp(loc, ex, fd, 0);
                ex = new CallExp(loc, ex);
                e = Expression::combine(ex, e);
            }
            DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Lexer::idPool("__aggrDtor"));
            dd->fbody = new ExpStatement(loc, e);
            members->push(dd);
            dd->semantic(sc);
            return dd;
    }
}
Example #7
0
File: clone.c Project: 1100110/dmd
FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc)
{
    if (FuncDeclaration *f = hasIdentityOpAssign(sc))
    {
        hasIdentityAssign = 1;
        return f;
    }
    // Even if non-identity opAssign is defined, built-in identity opAssign
    // will be defined.

    if (!needOpAssign())
        return NULL;

    //printf("StructDeclaration::buildOpAssign() %s\n", toChars());
    StorageClass stc = STCsafe | STCnothrow | STCpure;
    Loc declLoc = this->loc;
    Loc loc = Loc();    // internal code should have no loc to prevent coverage

    if (dtor || postblit)
    {
        if (dtor)
            stc = mergeFuncAttrs(stc, dtor->storage_class);
    }
    else
    {
        for (size_t i = 0; i < fields.dim; i++)
        {
            Dsymbol *s = fields[i];
            VarDeclaration *v = s->isVarDeclaration();
            assert(v && v->isField());
            if (v->storage_class & STCref)
                continue;
            Type *tv = v->type->toBasetype();
            while (tv->ty == Tsarray)
            {   TypeSArray *ta = (TypeSArray *)tv;
                tv = tv->nextOf()->toBasetype();
            }
            if (tv->ty == Tstruct)
            {   TypeStruct *ts = (TypeStruct *)tv;
                StructDeclaration *sd = ts->sym;
                if (FuncDeclaration *f = sd->hasIdentityOpAssign(sc))
                    stc = mergeFuncAttrs(stc, f->storage_class);
            }
        }
    }

    Parameters *fparams = new Parameters;
    fparams->push(new Parameter(STCnodtor, type, Id::p, NULL));
    Type *tf = new TypeFunction(fparams, handle, 0, LINKd, stc | STCref);

    FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), Id::assign, stc, tf);

    Expression *e = NULL;
    if (stc & STCdisable)
    {
    }
    else if (dtor || postblit)
    {
        /* Do swap this and rhs
         *    tmp = this; this = s; tmp.dtor();
         */
        //printf("\tswap copy\n");
        Identifier *idtmp = Lexer::uniqueId("__tmp");
        VarDeclaration *tmp;
        AssignExp *ec = NULL;
        if (dtor)
        {
            tmp = new VarDeclaration(loc, type, idtmp, new VoidInitializer(loc));
            tmp->noscope = 1;
            tmp->storage_class |= STCctfe;
            e = new DeclarationExp(loc, tmp);
            ec = new AssignExp(loc,
                new VarExp(loc, tmp),
                new ThisExp(loc)
                );
            ec->op = TOKblit;
            e = Expression::combine(e, ec);
        }
        ec = new AssignExp(loc,
                new ThisExp(loc),
                new IdentifierExp(loc, Id::p));
        ec->op = TOKblit;
        e = Expression::combine(e, ec);
        if (dtor)
        {
            /* Instead of running the destructor on s, run it
             * on tmp. This avoids needing to copy tmp back in to s.
             */
            Expression *ec2 = new DotVarExp(loc, new VarExp(loc, tmp), dtor, 0);
            ec2 = new CallExp(loc, ec2);
            e = Expression::combine(e, ec2);
        }
    }
    else
    {
        /* Do memberwise copy
         */
        //printf("\tmemberwise copy\n");
        for (size_t i = 0; i < fields.dim; i++)
        {
            Dsymbol *s = fields[i];
            VarDeclaration *v = s->isVarDeclaration();
            assert(v && v->isField());
            // this.v = s.v;
            AssignExp *ec = new AssignExp(loc,
                new DotVarExp(loc, new ThisExp(loc), v, 0),
                new DotVarExp(loc, new IdentifierExp(loc, Id::p), v, 0));
            e = Expression::combine(e, ec);
        }
    }
    if (e)
    {
        Statement *s1 = new ExpStatement(loc, e);

        /* Add:
         *   return this;
         */
        e = new ThisExp(loc);
        Statement *s2 = new ReturnStatement(loc, e);

        fop->fbody = new CompoundStatement(loc, s1, s2);
    }

    Dsymbol *s = fop;
#if 1   // workaround until fixing issue 1528
    Dsymbol *assign = search_function(this, Id::assign);
    if (assign && assign->isTemplateDeclaration())
    {
        // Wrap a template around the function declaration
        TemplateParameters *tpl = new TemplateParameters();
        Dsymbols *decldefs = new Dsymbols();
        decldefs->push(s);
        TemplateDeclaration *tempdecl =
            new TemplateDeclaration(assign->loc, fop->ident, tpl, NULL, decldefs, 0);
        s = tempdecl;
    }
#endif
    members->push(s);
    s->addMember(sc, this, 1);
    this->hasIdentityAssign = 1;        // temporary mark identity assignable

    unsigned errors = global.startGagging();    // Do not report errors, even if the
    unsigned oldspec = global.speculativeGag;   // template opAssign fbody makes it.
    global.speculativeGag = global.gag;
    Scope *sc2 = sc->push();
    sc2->stc = 0;
    sc2->linkage = LINKd;
    sc2->speculative = true;

    s->semantic(sc2);
    s->semantic2(sc2);
    s->semantic3(sc2);

    sc2->pop();
    global.speculativeGag = oldspec;
    if (global.endGagging(errors))    // if errors happened
    {   // Disable generated opAssign, because some members forbid identity assignment.
        fop->storage_class |= STCdisable;
        fop->fbody = NULL;  // remove fbody which contains the error
    }

    //printf("-StructDeclaration::buildOpAssign() %s %s, errors = %d\n", toChars(), s->kind(), (fop->storage_class & STCdisable) != 0);

    return fop;
}
Example #8
0
File: clone.c Project: Axure/ldc
FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc)
{
    //printf("StructDeclaration::buildPostBlit() %s\n", sd->toChars());
    StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
    Loc declLoc = sd->postblits.dim ? sd->postblits[0]->loc : sd->loc;
    Loc loc = Loc();    // internal code should have no loc to prevent coverage

    Expression *e = NULL;
    for (size_t i = 0; i < sd->fields.dim; i++)
    {
        VarDeclaration *v = sd->fields[i];
        if (v->storage_class & STCref)
            continue;
        Type *tv = v->type->toBasetype();
        dinteger_t dim = 1;
        while (tv->ty == Tsarray)
        {
            TypeSArray *tsa = (TypeSArray *)tv;
            dim *= tsa->dim->toInteger();
            tv = tsa->next->toBasetype();
        }
        if (tv->ty == Tstruct)
        {
            TypeStruct *ts = (TypeStruct *)tv;
            StructDeclaration *sd2 = ts->sym;
            if (sd2->postblit && dim)
            {
                stc = mergeFuncAttrs(stc, sd2->postblit);
                if (stc & STCdisable)
                {
                    e = NULL;
                    break;
                }

                // this.v
                Expression *ex = new ThisExp(loc);
                ex = new DotVarExp(loc, ex, v, 0);

                if (v->type->toBasetype()->ty == Tstruct)
                {   // this.v.postblit()
                    ex = new DotVarExp(loc, ex, sd2->postblit, 0);
                    ex = new CallExp(loc, ex);
                }
                else
                {
                    // Typeinfo.postblit(cast(void*)&this.v);
                    Expression *ea = new AddrExp(loc, ex);
                    ea = new CastExp(loc, ea, Type::tvoid->pointerTo());

                    Expression *et = v->type->getTypeInfo(sc);
                    et = new DotIdExp(loc, et, Id::postblit);

                    ex = new CallExp(loc, et, ea);
                }
                e = Expression::combine(e, ex); // combine in forward order
            }
        }
    }

    /* Build our own "postblit" which executes e
     */
    if (e || (stc & STCdisable))
    {
        //printf("Building __fieldPostBlit()\n");
        PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Lexer::idPool("__fieldPostBlit"));
        dd->fbody = new ExpStatement(loc, e);
        sd->postblits.shift(dd);
        sd->members->push(dd);
        dd->semantic(sc);
    }

    switch (sd->postblits.dim)
    {
        case 0:
            return NULL;

        case 1:
            return sd->postblits[0];

        default:
            e = NULL;
            stc = STCsafe | STCnothrow | STCpure | STCnogc;
            for (size_t i = 0; i < sd->postblits.dim; i++)
            {
                FuncDeclaration *fd = sd->postblits[i];
                stc = mergeFuncAttrs(stc, fd);
                if (stc & STCdisable)
                {
                    e = NULL;
                    break;
                }
                Expression *ex = new ThisExp(loc);
                ex = new DotVarExp(loc, ex, fd, 0);
                ex = new CallExp(loc, ex);
                e = Expression::combine(e, ex);
            }
            PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Lexer::idPool("__aggrPostBlit"));
            dd->fbody = new ExpStatement(loc, e);
            sd->members->push(dd);
            dd->semantic(sc);
            return dd;
    }
}