void AggregateDeclaration::semantic2(Scope *sc) { //printf("AggregateDeclaration::semantic2(%s)\n", toChars()); if (scope && members) { error("has forward references"); return; } if (members) { sc = sc->push(this); for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; s->semantic2(sc); } sc->pop(); } }
void AttribDeclaration::semantic2(Scope *sc) { Dsymbols *d = include(sc, NULL); if (d) { Scope *sc2 = newScope(sc); for (size_t i = 0; i < d->dim; i++) { Dsymbol *s = (*d)[i]; s->semantic2(sc2); } if (sc2 != sc) sc2->pop(); } }
void Nspace::semantic2(Scope *sc) { if (semanticRun >= PASSsemantic2) return; semanticRun = PASSsemantic2; if (members) { assert(sc); sc = sc->push(this); sc->linkage = LINKcpp; for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; s->semantic2(sc); } sc->pop(); } }
void Module::semantic2() { if (deferred.dim) { for (size_t i = 0; i < deferred.dim; i++) { Dsymbol *sd = deferred[i]; sd->error("unable to resolve forward reference in definition"); } return; } //printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent); if (semanticRun == 0) // semantic() not completed yet - could be recursive call return; if (semanticstarted >= 2) return; assert(semanticstarted == 1); semanticstarted = 2; // Note that modules get their own scope, from scratch. // This is so regardless of where in the syntax a module // gets imported, it is unaffected by context. Scope *sc = Scope::createGlobal(this); // create root scope //printf("Module = %p\n", sc.scopesym); // Pass 2 semantic routines: do initializers and function bodies for (size_t i = 0; i < members->dim; i++) { Dsymbol *s; s = (*members)[i]; s->semantic2(sc); } sc = sc->pop(); sc->pop(); semanticRun = semanticstarted; //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent); }
void AggregateDeclaration::semantic2(Scope *sc) { //printf("AggregateDeclaration::semantic2(%s)\n", toChars()); if (scope && members) { error("has forward references"); return; } if (members) { sc = sc->push(this); sc->parent = this; for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; //printf("\t[%d] %s\n", i, s->toChars()); s->semantic2(sc); } if (StructDeclaration *sd = isStructDeclaration()) { /* Even if the struct exists in imported module, calculating * xeq and xcmp is necessary in order to generate correct TypeInfo. * However, immediately doing it at the end of StructDeclaration::semantic * might cause forward reference error during instantiation of * template opEquals/opCmp. So should be done at the end of semantic2. */ //if (sd->xeq != NULL) printf("sd = %s xeq @ [%s]\n", sd->toChars(), sd->loc.toChars()); //assert(sd->xeq == NULL); if (sd->xeq == NULL) sd->xeq = sd->buildXopEquals(sc); if (sd->xcmp == NULL) sd->xcmp = sd->buildXopCmp(sc); } sc->pop(); } }
FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc) { Dsymbol *assign = search_function(this, Id::assign); if (assign) { if (FuncDeclaration *f = hasIdentityOpAssign(sc, assign)) return f; // Even if non-identity opAssign is defined, built-in identity opAssign // will be defined. (Is this an exception of operator overloading rule?) } if (!needOpAssign()) return NULL; //printf("StructDeclaration::buildOpAssign() %s\n", toChars()); Parameters *fparams = new Parameters; fparams->push(new Parameter(STCnodtor, type, Id::p, NULL)); Type *ftype = new TypeFunction(fparams, handle, FALSE, LINKd); ((TypeFunction *)ftype)->isref = 1; FuncDeclaration *fop = new FuncDeclaration(loc, 0, Id::assign, STCundefined, ftype); Expression *e = NULL; if (postblit) { /* Swap: * 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(0, type, idtmp, new VoidInitializer(0)); tmp->noscope = 1; tmp->storage_class |= STCctfe; e = new DeclarationExp(0, tmp); ec = new AssignExp(0, new VarExp(0, tmp), new ThisExp(0) ); ec->op = TOKblit; e = Expression::combine(e, ec); } ec = new AssignExp(0, new ThisExp(0), new IdentifierExp(0, 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(0, new VarExp(0, tmp), dtor, 0); ec2 = new CallExp(0, 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(0, new DotVarExp(0, new ThisExp(0), v, 0), new DotVarExp(0, new IdentifierExp(0, Id::p), v, 0)); e = Expression::combine(e, ec); } } Statement *s1 = new ExpStatement(0, e); /* Add: * return this; */ e = new ThisExp(0); Statement *s2 = new ReturnStatement(0, e); fop->fbody = new CompoundStatement(0, s1, s2); Dsymbol *s = fop; 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; } 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 *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 *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", 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->dtor) { 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) { TypeStruct *ts = (TypeStruct *)tv; if (FuncDeclaration *f = hasIdentityOpAssign(ts->sym, sc)) stc = mergeFuncAttrs(stc, f); } } } Parameters *fparams = new Parameters; fparams->push(new Parameter(STCnodtor, sd->type, Id::p, NULL)); Type *tf = new TypeFunction(fparams, sd->handleType(), 0, LINKd, stc | STCref); FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), Id::assign, stc, tf); Expression *e = NULL; if (stc & STCdisable) { } else if (sd->dtor || sd->postblit) { /* Do swap this and rhs * tmp = this; this = s; tmp.dtor(); */ //printf("\tswap copy\n"); Identifier *idtmp = Lexer::uniqueId("__tmp"); 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); } Dsymbol *s = fop; sd->members->push(s); s->addMember(sc, sd, 1); sd->hasIdentityAssign = true; // 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; }