/***************************************** * 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; }
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; } }
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; } }