예제 #1
0
파일: clone.c 프로젝트: 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;
}
예제 #2
0
파일: clone.c 프로젝트: Ingrater/dmd
FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc)
{
    //printf("StructDeclaration::buildPostBlit() %s\n", toChars());
    Expression *e = NULL;
    StorageClass stc = 0;

    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->postblit && dim)
            {
                stc |= sd->postblit->storage_class & STCdisable;

                if (stc & STCdisable)
                {
                    e = NULL;
                    break;
                }

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

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

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

                    ex = new CallExp(0, 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(loc, 0, stc, Lexer::idPool("__fieldPostBlit"));
        dd->fbody = new ExpStatement(0, e);
        postblits.shift(dd);
        members->push(dd);
        dd->semantic(sc);
    }

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

        case 1:
            return postblits[0];

        default:
            e = NULL;
            for (size_t i = 0; i < postblits.dim; i++)
            {   FuncDeclaration *fd = postblits[i];
                stc |= fd->storage_class & STCdisable;
                if (stc & STCdisable)
                {
                    e = NULL;
                    break;
                }
                Expression *ex = new ThisExp(0);
                ex = new DotVarExp(0, ex, fd, 0);
                ex = new CallExp(0, ex);
                e = Expression::combine(e, ex);
            }
            PostBlitDeclaration *dd = new PostBlitDeclaration(loc, 0, stc, Lexer::idPool("__aggrPostBlit"));
            dd->fbody = new ExpStatement(0, e);
            members->push(dd);
            dd->semantic(sc);
            return dd;
    }
}
예제 #3
0
파일: clone.c 프로젝트: 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;
    }
}