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