void StructDeclaration::semantic(Scope *sc) { //printf("+StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", this, parent->toChars(), toChars(), sizeok); //static int count; if (++count == 20) halt(); if (semanticRun >= PASSsemanticdone) return; unsigned dprogress_save = Module::dprogress; int errors = global.errors; Scope *scx = NULL; if (scope) { sc = scope; scx = scope; // save so we don't make redundant copies scope = NULL; } if (!parent) { assert(sc->parent && sc->func); parent = sc->parent; } assert(parent && !isAnonymous()); type = type->semantic(loc, sc); if (type->ty == Tstruct && ((TypeStruct *)type)->sym != this) { TemplateInstance *ti = ((TypeStruct *)type)->sym->isInstantiated(); if (ti && isError(ti)) ((TypeStruct *)type)->sym = this; } // Ungag errors when not speculative Ungag ungag = ungagSpeculative(); if (semanticRun == PASSinit) { protection = sc->protection; alignment = sc->structalign; storage_class |= sc->stc; if (storage_class & STCdeprecated) isdeprecated = true; if (storage_class & STCabstract) error("structs, unions cannot be abstract"); userAttribDecl = sc->userAttribDecl; } else if (symtab) { if (sizeok == SIZEOKdone || !scx) { semanticRun = PASSsemanticdone; return; } } semanticRun = PASSsemantic; if (!members) // if opaque declaration { semanticRun = PASSsemanticdone; return; } if (!symtab) symtab = new DsymbolTable(); if (sizeok == SIZEOKnone) // if not already done the addMember step { for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars()); s->addMember(sc, this, 1); } } sizeok = SIZEOKnone; Scope *sc2 = sc->push(this); sc2->stc &= STCsafe | STCtrusted | STCsystem; sc2->parent = this; if (isUnionDeclaration()) sc2->inunion = 1; sc2->protection = Prot(PROTpublic); sc2->explicitProtection = 0; sc2->structalign = STRUCTALIGN_DEFAULT; sc2->userAttribDecl = NULL; /* Set scope so if there are forward references, we still might be able to * resolve individual members like enums. */ for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; //printf("struct: setScope %s %s\n", s->kind(), s->toChars()); s->setScope(sc2); } for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; s->importAll(sc2); } for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; /* If this is the last member, see if we can finish setting the size. * This could be much better - finish setting the size after the last * field was processed. The problem is the chicken-and-egg determination * of when that is. See Bugzilla 7426 for more info. */ if (i + 1 == members->dim) { if (sizeok == SIZEOKnone && s->isAliasDeclaration()) finalizeSize(sc2); } s->semantic(sc2); } finalizeSize(sc2); if (sizeok == SIZEOKfwd) { // semantic() failed because of forward references. // Unwind what we did, and defer it for later for (size_t i = 0; i < fields.dim; i++) { VarDeclaration *vd = fields[i]; vd->offset = 0; } fields.setDim(0); structsize = 0; alignsize = 0; scope = scx ? scx : sc->copy(); scope->setNoFree(); scope->module->addDeferredSemantic(this); Module::dprogress = dprogress_save; //printf("\tdeferring %s\n", toChars()); return; } Module::dprogress++; semanticRun = PASSsemanticdone; //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); // Determine if struct is all zeros or not zeroInit = 1; for (size_t i = 0; i < fields.dim; i++) { VarDeclaration *vd = fields[i]; if (!vd->isDataseg()) { if (vd->init) { // Should examine init to see if it is really all 0's zeroInit = 0; break; } else { if (!vd->type->isZeroInit(loc)) { zeroInit = 0; break; } } } } dtor = buildDtor(this, sc2); postblit = buildPostBlit(this, sc2); cpctor = buildCpCtor(this, sc2); buildOpAssign(this, sc2); buildOpEquals(this, sc2); xeq = buildXopEquals(this, sc2); xcmp = buildXopCmp(this, sc2); xhash = buildXtoHash(this, sc2); /* Even if the struct is merely imported and its semantic3 is not run, * the TypeInfo object would be speculatively stored in each object * files. To set correct function pointer, run semantic3 for xeq and xcmp. */ //if ((xeq && xeq != xerreq || xcmp && xcmp != xerrcmp) && isImportedSym(this)) // Module::addDeferredSemantic3(this); /* Defer requesting semantic3 until TypeInfo generation is actually invoked. * See semanticTypeInfo(). */ inv = buildInv(this, sc2); sc2->pop(); /* Look for special member functions. */ ctor = searchCtor(); aggNew = (NewDeclaration *)search(Loc(), Id::classNew); aggDelete = (DeleteDeclaration *)search(Loc(), Id::classDelete); if (ctor) { Dsymbol *scall = search(Loc(), Id::call); if (scall) { unsigned xerrors = global.startGagging(); sc = sc->push(); sc->speculative = true; FuncDeclaration *fcall = resolveFuncCall(loc, sc, scall, NULL, NULL, NULL, 1); sc = sc->pop(); global.endGagging(xerrors); if (fcall && fcall->isStatic()) { error(fcall->loc, "static opCall is hidden by constructors and can never be called"); errorSupplemental(fcall->loc, "Please use a factory method instead, or replace all constructors with static opCall."); } } } TypeTuple *tup = toArgTypes(type); size_t dim = tup->arguments->dim; if (dim >= 1) { assert(dim <= 2); arg1type = (*tup->arguments)[0]->type; if (dim == 2) arg2type = (*tup->arguments)[1]->type; } if (sc->func) semantic2(sc); if (global.errors != errors) { // The type is no good. type = Type::terror; this->errors = true; if (deferred) deferred->errors = true; } if (deferred && !global.gag) { deferred->semantic2(sc); deferred->semantic3(sc); } #if 0 if (type->ty == Tstruct && ((TypeStruct *)type)->sym != this) { printf("this = %p %s\n", this, this->toChars()); printf("type = %d sym = %p\n", type->ty, ((TypeStruct *)type)->sym); } #endif assert(type->ty != Tstruct || ((TypeStruct *)type)->sym == this); }
void visit(TypeStruct *t) { //printf("TypeStruct::toArgTypes() %s\n", t->toChars()); if (!t->sym->isPOD() || t->sym->fields.dim == 0) { Lmemory: //printf("\ttoArgTypes() %s => [ ]\n", t->toChars()); result = new TypeTuple(); // pass on the stack return; } Type *t1 = NULL; Type *t2 = NULL; const d_uns64 sz = t->size(Loc()); assert(sz < 0xFFFFFFFF); switch ((unsigned)sz) { case 1: t1 = Type::tint8; break; case 2: t1 = Type::tint16; break; case 3: if (!global.params.is64bit) goto Lmemory; /* fall through */ case 4: t1 = Type::tint32; break; case 5: case 6: case 7: if (!global.params.is64bit) goto Lmemory; /* fall through */ case 8: t1 = Type::tint64; break; case 16: t1 = NULL; // could be a TypeVector break; case 9: case 10: case 11: case 12: case 13: case 14: case 15: if (!global.params.is64bit) goto Lmemory; t1 = NULL; break; default: goto Lmemory; } if (global.params.is64bit && t->sym->fields.dim) { t1 = NULL; for (size_t i = 0; i < t->sym->fields.dim; i++) { VarDeclaration *f = t->sym->fields[i]; //printf(" [%d] %s f->type = %s\n", (int)i, f->toChars(), f->type->toChars()); TypeTuple *tup = toArgTypes(f->type); if (!tup) goto Lmemory; size_t dim = tup->arguments->dim; Type *ft1 = NULL; Type *ft2 = NULL; switch (dim) { case 2: ft1 = (*tup->arguments)[0]->type; ft2 = (*tup->arguments)[1]->type; break; case 1: if (f->offset < 8) ft1 = (*tup->arguments)[0]->type; else ft2 = (*tup->arguments)[0]->type; break; default: goto Lmemory; } if (f->offset & 7) { // Misaligned fields goto Lmemory unsigned alignsz = f->type->alignsize(); if (f->offset & (alignsz - 1)) goto Lmemory; // Fields that overlap the 8byte boundary goto Lmemory const d_uns64 fieldsz = f->type->size(Loc()); assert(fieldsz != SIZE_INVALID && fieldsz < UINT64_MAX - UINT32_MAX); if (f->offset < 8 && (f->offset + fieldsz) > 8) goto Lmemory; } // First field in 8byte must be at start of 8byte assert(t1 || f->offset == 0); //printf("ft1 = %s\n", ft1 ? ft1->toChars() : "null"); //printf("ft2 = %s\n", ft2 ? ft2->toChars() : "null"); if (ft1) { t1 = argtypemerge(t1, ft1, f->offset); if (!t1) goto Lmemory; } if (ft2) { unsigned off2 = f->offset; if (ft1) off2 = 8; if (!t2 && off2 != 8) goto Lmemory; assert(t2 || off2 == 8); t2 = argtypemerge(t2, ft2, off2 - 8); if (!t2) goto Lmemory; } } if (t2) { if (t1->isfloating() && t2->isfloating()) { if ((t1->ty == Tfloat32 || t1->ty == Tfloat64) && (t2->ty == Tfloat32 || t2->ty == Tfloat64)) ; else goto Lmemory; } else if (t1->isfloating()) goto Lmemory; else if (t2->isfloating()) goto Lmemory; else { } } } //printf("\ttoArgTypes() %s => [%s,%s]\n", t->toChars(), t1 ? t1->toChars() : "", t2 ? t2->toChars() : ""); if (t1) { //if (t1) printf("test1: %s => %s\n", toChars(), t1->toChars()); if (t2) result = new TypeTuple(t1, t2); else result = new TypeTuple(t1); } else goto Lmemory; }