void AggregateDeclaration::semantic3(Scope *sc) { //printf("AggregateDeclaration::semantic3(%s) type = %s, errors = %d\n", toChars(), type->toChars(), errors); if (!members) return; StructDeclaration *sd = isStructDeclaration(); if (!sc) // from runDeferredSemantic3 for TypeInfo generation { assert(sd); sd->semanticTypeInfoMembers(); return; } 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; for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; s->semantic3(sc2); } sc2->pop(); // don't do it for unused deprecated types // or error types if (!getRTInfo && Type::rtinfo && (!isDeprecated() || global.params.useDeprecated) && (type && type->ty != Terror)) { // Evaluate: RTinfo!type Objects *tiargs = new Objects(); tiargs->push(type); TemplateInstance *ti = new TemplateInstance(loc, Type::rtinfo, tiargs); ti->semantic(sc); ti->semantic2(sc); ti->semantic3(sc); Dsymbol *s = ti->toAlias(); Expression *e = new DsymbolExp(Loc(), s, 0); Scope *sc3 = ti->tempdecl->scope->startCTFE(); sc3->tinst = sc->tinst; e = e->semantic(sc3); sc3->endCTFE(); e = e->ctfeInterpret(); getRTInfo = e; } if (sd) sd->semanticTypeInfoMembers(); }
void StructDeclaration::finalizeSize(Scope *sc) { //printf("StructDeclaration::finalizeSize() %s\n", toChars()); if (sizeok != SIZEOKnone) return; // Set the offsets of the fields and determine the size of the struct unsigned offset = 0; bool isunion = isUnionDeclaration() != NULL; for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; s->setFieldOffset(this, &offset, isunion); } if (sizeok == SIZEOKfwd) return; // 0 sized struct's are set to 1 byte if (structsize == 0) { structsize = 1; alignsize = 1; } // Round struct size up to next alignsize boundary. // This will ensure that arrays of structs will get their internals // aligned properly. if (alignment == STRUCTALIGN_DEFAULT) structsize = (structsize + alignsize - 1) & ~(alignsize - 1); else structsize = (structsize + alignment - 1) & ~(alignment - 1); sizeok = SIZEOKdone; }
void AggregateDeclaration::makeNested() { if (!enclosing && sizeok != SIZEOKdone && !isUnionDeclaration() && !isInterfaceDeclaration()) { // If nested struct, add in hidden 'this' pointer to outer scope if (!(storage_class & STCstatic)) { Dsymbol *s = toParent2(); if (s) { AggregateDeclaration *ad = s->isAggregateDeclaration(); FuncDeclaration *fd = s->isFuncDeclaration(); if (fd) { enclosing = fd; } else if (isClassDeclaration() && ad && ad->isClassDeclaration()) { enclosing = ad; } else if (isStructDeclaration() && ad) { if (TemplateInstance *ti = ad->parent->isTemplateInstance()) { enclosing = ti->enclosing; } } if (enclosing) { //printf("makeNested %s, enclosing = %s\n", toChars(), enclosing->toChars()); Type *t; if (ad) t = ad->handleType(); else if (fd) { AggregateDeclaration *ad2 = fd->isMember2(); if (ad2) t = ad2->handleType(); else t = Type::tvoidptr; } else assert(0); if (t->ty == Tstruct) t = Type::tvoidptr; // t should not be a ref type assert(!vthis); vthis = new ThisDeclaration(loc, t); //vthis->storage_class |= STCref; members->push(vthis); } } } } }
void AggregateDeclaration::makeNested() { if (enclosing) // if already nested return; if (sizeok == SIZEOKdone) return; if (isUnionDeclaration() || isInterfaceDeclaration()) return; if (storage_class & STCstatic) return; // If nested struct, add in hidden 'this' pointer to outer scope Dsymbol *s = toParent2(); if (!s) return; AggregateDeclaration *ad = s->isAggregateDeclaration(); FuncDeclaration *fd = s->isFuncDeclaration(); Type *t = NULL; if (fd) { enclosing = fd; AggregateDeclaration *agg = fd->isMember2(); t = agg ? agg->handleType() : Type::tvoidptr; } else if (ad) { if (isClassDeclaration() && ad->isClassDeclaration()) { enclosing = ad; } else if (isStructDeclaration()) { if (TemplateInstance *ti = ad->parent->isTemplateInstance()) { enclosing = ti->enclosing; } } t = ad->handleType(); } if (enclosing) { //printf("makeNested %s, enclosing = %s\n", toChars(), enclosing->toChars()); assert(t); if (t->ty == Tstruct) t = Type::tvoidptr; // t should not be a ref type assert(!vthis); vthis = new ThisDeclaration(loc, t); //vthis->storage_class |= STCref; members->push(vthis); } }
int StructDeclaration::needOpEquals() { #define X 0 if (X) printf("StructDeclaration::needOpEquals() %s\n", toChars()); if (hasIdentityEquals) goto Lneed; #if 0 if (isUnionDeclaration()) goto Ldontneed; #endif /* If any of the fields has an opEquals, then we * need it too. */ 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(); #if 0 if (tv->isfloating()) goto Lneed; if (tv->ty == Tarray) goto Lneed; if (tv->ty == Tclass) goto Lneed; #endif 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 (sd->needOpEquals()) goto Lneed; } } Ldontneed: if (X) printf("\tdontneed\n"); return 0; Lneed: if (X) printf("\tneed\n"); return 1; #undef X }
/**************************************** * Count the number of fields starting at firstIndex which are part of the * same union as field[firstIndex]. If not a union, return 1. */ int AggregateDeclaration::numFieldsInUnion(int firstIndex) { VarDeclaration * vd = fields[firstIndex]; /* If it is a zero-length field, AND we can't find an earlier non-zero * sized field with the same offset, we assume it's not part of a union. */ if (vd->size(loc) == 0 && !isUnionDeclaration() && firstFieldInUnion(firstIndex) == firstIndex) return 1; int count = 1; for (size_t i = firstIndex+1; i < fields.dim; ++i) { VarDeclaration * v = fields[i]; // If offsets are different, they are not in the same union if (v->offset != vd->offset) break; ++count; } return count; }
/**************************************** * If field[indx] is not part of a union, return indx. * Otherwise, return the lowest field index of the union. */ int AggregateDeclaration::firstFieldInUnion(int indx) { if (isUnionDeclaration()) return 0; VarDeclaration * vd = fields[indx]; int firstNonZero = indx; // first index in the union with non-zero size for (; ;) { if (indx == 0) return firstNonZero; VarDeclaration * v = fields[indx - 1]; if (v->offset != vd->offset) return firstNonZero; --indx; /* If it is a zero-length field, it's ambiguous: we don't know if it is * in the union unless we find an earlier non-zero sized field with the * same offset. */ if (v->size(loc) != 0) firstNonZero = indx; } }
void StructDeclaration::makeNested() { if (!isnested && sizeok != SIZEOKdone && !isUnionDeclaration()) { // If nested struct, add in hidden 'this' pointer to outer scope if (!(storage_class & STCstatic)) { Dsymbol *s = toParent2(); if (s) { AggregateDeclaration *ad = s->isAggregateDeclaration(); FuncDeclaration *fd = s->isFuncDeclaration(); TemplateInstance *ti; if (ad && (ti = ad->parent->isTemplateInstance()) != NULL && ti->isnested || fd) { isnested = true; Type *t; if (ad) t = ad->handle; else if (fd) { AggregateDeclaration *ad = fd->isMember2(); if (ad) t = ad->handle; else t = Type::tvoidptr; } else assert(0); if (t->ty == Tstruct) t = Type::tvoidptr; // t should not be a ref type assert(!vthis); vthis = new ThisDeclaration(loc, t); //vthis->storage_class |= STCref; members->push(vthis); } } } } }
void ClassDeclaration::semantic(Scope *sc) { //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : ""); //printf("sc->stc = %x\n", sc->stc); //{ static int n; if (++n == 20) *(char*)0=0; } if (!ident) // if anonymous class { const char *id = "__anonclass"; ident = Identifier::generateId(id); } if (!sc) sc = scope; if (!parent && sc->parent && !sc->parent->isModule()) parent = sc->parent; type = type->semantic(loc, sc); handle = type; if (!members) // if opaque declaration { //printf("\tclass '%s' is forward referenced\n", toChars()); return; } if (symtab) { if (sizeok == SIZEOKdone || !scope) { //printf("\tsemantic for '%s' is already completed\n", toChars()); return; // semantic() already completed } } else symtab = new DsymbolTable(); Scope *scx = NULL; if (scope) { sc = scope; scx = scope; // save so we don't make redundant copies scope = NULL; } unsigned dprogress_save = Module::dprogress; int errors = global.errors; if (sc->stc & STCdeprecated) { isdeprecated = true; } userAttributes = sc->userAttributes; if (sc->linkage == LINKcpp) error("cannot create C++ classes"); // Expand any tuples in baseclasses[] for (size_t i = 0; i < baseclasses->dim; ) { BaseClass *b = (*baseclasses)[i]; b->type = b->type->semantic(loc, sc); Type *tb = b->type->toBasetype(); if (tb->ty == Ttuple) { TypeTuple *tup = (TypeTuple *)tb; enum PROT protection = b->protection; baseclasses->remove(i); size_t dim = Parameter::dim(tup->arguments); for (size_t j = 0; j < dim; j++) { Parameter *arg = Parameter::getNth(tup->arguments, j); b = new BaseClass(arg->type, protection); baseclasses->insert(i + j, b); } } else i++; } // See if there's a base class as first in baseclasses[] if (baseclasses->dim) { TypeClass *tc; BaseClass *b; Type *tb; b = (*baseclasses)[0]; //b->type = b->type->semantic(loc, sc); tb = b->type->toBasetype(); if (tb->ty != Tclass) { if (b->type != Type::terror) error("base type must be class or interface, not %s", b->type->toChars()); baseclasses->remove(0); } else { tc = (TypeClass *)(tb); if (tc->sym->isDeprecated()) { if (!isDeprecated()) { // Deriving from deprecated class makes this one deprecated too isdeprecated = true; tc->checkDeprecated(loc, sc); } } if (tc->sym->isInterfaceDeclaration()) ; else { for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass) { if (cdb == this) { error("circular inheritance"); baseclasses->remove(0); goto L7; } } if (!tc->sym->symtab || tc->sym->sizeok == SIZEOKnone) { // Try to resolve forward reference if (/*doAncestorsSemantic == SemanticIn &&*/ tc->sym->scope) tc->sym->semantic(NULL); } if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == SIZEOKnone) { //printf("%s: forward reference of base class %s\n", toChars(), tc->sym->toChars()); //error("forward reference of base class %s", baseClass->toChars()); // Forward reference of base class, try again later //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars()); scope = scx ? scx : new Scope(*sc); scope->setNoFree(); if (tc->sym->scope) tc->sym->scope->module->addDeferredSemantic(tc->sym); scope->module->addDeferredSemantic(this); return; } else { baseClass = tc->sym; b->base = baseClass; } L7: ; } } } // Treat the remaining entries in baseclasses as interfaces // Check for errors, handle forward references for (size_t i = (baseClass ? 1 : 0); i < baseclasses->dim; ) { TypeClass *tc; BaseClass *b; Type *tb; b = (*baseclasses)[i]; b->type = b->type->semantic(loc, sc); tb = b->type->toBasetype(); if (tb->ty == Tclass) tc = (TypeClass *)tb; else tc = NULL; if (!tc || !tc->sym->isInterfaceDeclaration()) { if (b->type != Type::terror) error("base type must be interface, not %s", b->type->toChars()); baseclasses->remove(i); continue; } else { if (tc->sym->isDeprecated()) { if (!isDeprecated()) { // Deriving from deprecated class makes this one deprecated too isdeprecated = true; tc->checkDeprecated(loc, sc); } } // Check for duplicate interfaces for (size_t j = (baseClass ? 1 : 0); j < i; j++) { BaseClass *b2 = (*baseclasses)[j]; if (b2->base == tc->sym) error("inherits from duplicate interface %s", b2->base->toChars()); } if (!tc->sym->symtab) { // Try to resolve forward reference if (/*doAncestorsSemantic == SemanticIn &&*/ tc->sym->scope) tc->sym->semantic(NULL); } b->base = tc->sym; if (!b->base->symtab || b->base->scope) { //error("forward reference of base class %s", baseClass->toChars()); // Forward reference of base, try again later //printf("\ttry later, forward reference of base %s\n", baseClass->toChars()); scope = scx ? scx : new Scope(*sc); scope->setNoFree(); if (tc->sym->scope) tc->sym->scope->module->addDeferredSemantic(tc->sym); scope->module->addDeferredSemantic(this); return; } } i++; } if (doAncestorsSemantic == SemanticIn) doAncestorsSemantic = SemanticDone; // If no base class, and this is not an Object, use Object as base class if (!baseClass && ident != Id::Object) { if (!object) { error("missing or corrupt object.d"); fatal(); } Type *t = object->type; t = t->semantic(loc, sc)->toBasetype(); assert(t->ty == Tclass); TypeClass *tc = (TypeClass *)t; BaseClass *b = new BaseClass(tc, PROTpublic); baseclasses->shift(b); baseClass = tc->sym; assert(!baseClass->isInterfaceDeclaration()); b->base = baseClass; } interfaces_dim = baseclasses->dim; interfaces = baseclasses->tdata(); if (baseClass) { if (baseClass->storage_class & STCfinal) error("cannot inherit from final class %s", baseClass->toChars()); interfaces_dim--; interfaces++; // Copy vtbl[] from base class vtbl.setDim(baseClass->vtbl.dim); memcpy(vtbl.tdata(), baseClass->vtbl.tdata(), sizeof(void *) * vtbl.dim); // Inherit properties from base class com = baseClass->isCOMclass(); isscope = baseClass->isscope; vthis = baseClass->vthis; enclosing = baseClass->enclosing; storage_class |= baseClass->storage_class & STC_TYPECTOR; } else { // No base class, so this is the root of the class hierarchy vtbl.setDim(0); vtbl.push(this); // leave room for classinfo as first member } protection = sc->protection; storage_class |= sc->stc; if (sizeok == SIZEOKnone) { interfaceSemantic(sc); for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; s->addMember(sc, this, 1); } /* If this is a nested class, add the hidden 'this' * member which is a pointer to the enclosing scope. */ if (vthis) // if inheriting from nested class { // Use the base class's 'this' member if (storage_class & STCstatic) error("static class cannot inherit from nested class %s", baseClass->toChars()); if (toParent2() != baseClass->toParent2() && (!toParent2() || !baseClass->toParent2()->getType() || !baseClass->toParent2()->getType()->isBaseOf(toParent2()->getType(), NULL))) { if (toParent2()) { error("is nested within %s, but super class %s is nested within %s", toParent2()->toChars(), baseClass->toChars(), baseClass->toParent2()->toChars()); } else { error("is not nested, but super class %s is nested within %s", baseClass->toChars(), baseClass->toParent2()->toChars()); } enclosing = NULL; } } else makeNested(); } if (storage_class & STCauto) error("storage class 'auto' is invalid when declaring a class, did you mean to use 'scope'?"); if (storage_class & STCscope) isscope = 1; if (storage_class & STCabstract) isabstract = 1; sc = sc->push(this); //sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic | STCabstract | STCdeprecated | STC_TYPECTOR | STCtls | STCgshared); //sc->stc |= storage_class & STC_TYPECTOR; sc->stc &= STCsafe | STCtrusted | STCsystem; sc->parent = this; sc->inunion = 0; if (isCOMclass()) { #if IN_LLVM if (global.params.targetTriple.isOSWindows()) #else if (global.params.isWindows) #endif sc->linkage = LINKwindows; else /* This enables us to use COM objects under Linux and * work with things like XPCOM */ sc->linkage = LINKc; } sc->protection = PROTpublic; sc->explicitProtection = 0; sc->structalign = STRUCTALIGN_DEFAULT; if (baseClass) { sc->offset = baseClass->structsize; alignsize = baseClass->alignsize; // if (enclosing) // sc->offset += Target::ptrsize; // room for uplevel context pointer } else { sc->offset = Target::ptrsize * 2; // allow room for __vptr and __monitor alignsize = Target::ptrsize; } sc->userAttributes = NULL; structsize = sc->offset; Scope scsave = *sc; size_t members_dim = members->dim; sizeok = SIZEOKnone; /* 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]; /* There are problems doing this in the general case because * Scope keeps track of things like 'offset' */ if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident) || s->isTemplateMixin() || s->isAttribDeclaration() || s->isAliasDeclaration()) { //printf("[%d] setScope %s %s, sc = %p\n", i, s->kind(), s->toChars(), sc); s->setScope(sc); } } for (size_t i = 0; i < members_dim; i++) { Dsymbol *s = (*members)[i]; s->semantic(sc); } // Set the offsets of the fields and determine the size of the class unsigned offset = structsize; bool isunion = isUnionDeclaration() != NULL; for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; s->setFieldOffset(this, &offset, false); } sc->offset = structsize; if (global.errors != errors) { // The type is no good. type = Type::terror; } if (sizeok == SIZEOKfwd) // failed due to forward references { // semantic() failed due to forward references // Unwind what we did, and defer it for later for (size_t i = 0; i < fields.dim; i++) { Dsymbol *s = fields[i]; VarDeclaration *vd = s->isVarDeclaration(); if (vd) vd->offset = 0; } fields.setDim(0); structsize = 0; alignsize = 0; // structalign = 0; sc = sc->pop(); scope = scx ? scx : new Scope(*sc); scope->setNoFree(); scope->module->addDeferredSemantic(this); Module::dprogress = dprogress_save; //printf("\tsemantic('%s') failed due to forward references\n", toChars()); return; } //printf("\tsemantic('%s') successful\n", toChars()); //members->print(); /* Look for special member functions. * They must be in this class, not in a base class. */ ctor = search(Loc(), Id::ctor, 0); #if DMDV1 if (ctor && (ctor->toParent() != this || !ctor->isCtorDeclaration())) ctor = NULL; #else if (ctor && (ctor->toParent() != this || !(ctor->isCtorDeclaration() || ctor->isTemplateDeclaration()))) ctor = NULL; // search() looks through ancestor classes if (!ctor && noDefaultCtor) { // A class object is always created by constructor, so this check is legitimate. for (size_t i = 0; i < fields.dim; i++) { VarDeclaration *v = fields[i]->isVarDeclaration(); if (v->storage_class & STCnodefaultctor) ::error(v->loc, "field %s must be initialized in constructor", v->toChars()); } } #endif // dtor = (DtorDeclaration *)search(Id::dtor, 0); // if (dtor && dtor->toParent() != this) // dtor = NULL; inv = buildInv(sc); // Can be in base class aggNew = (NewDeclaration *)search(Loc(), Id::classNew, 0); aggDelete = (DeleteDeclaration *)search(Loc(), Id::classDelete, 0); // If this class has no constructor, but base class has a default // ctor, create a constructor: // this() { } if (!ctor && baseClass && baseClass->ctor) { if (resolveFuncCall(loc, sc, baseClass->ctor, NULL, NULL, NULL, 1)) { //printf("Creating default this(){} for class %s\n", toChars()); Type *tf = new TypeFunction(NULL, NULL, 0, LINKd, 0); CtorDeclaration *ctor = new CtorDeclaration(loc, Loc(), 0, tf); ctor->fbody = new CompoundStatement(Loc(), new Statements()); members->push(ctor); ctor->addMember(sc, this, 1); *sc = scsave; // why? What about sc->nofree? ctor->semantic(sc); this->ctor = ctor; defaultCtor = ctor; } else { error("Cannot implicitly generate a default ctor when base class %s is missing a default ctor", baseClass->toPrettyChars()); } } #if 0 if (baseClass) { if (!aggDelete) aggDelete = baseClass->aggDelete; if (!aggNew) aggNew = baseClass->aggNew; } #endif // Allocate instance of each new interface sc->offset = structsize; for (size_t i = 0; i < vtblInterfaces->dim; i++) { BaseClass *b = (*vtblInterfaces)[i]; unsigned thissize = Target::ptrsize; alignmember(STRUCTALIGN_DEFAULT, thissize, &sc->offset); assert(b->offset == 0); b->offset = sc->offset; // Take care of single inheritance offsets while (b->baseInterfaces_dim) { b = &b->baseInterfaces[0]; b->offset = sc->offset; } sc->offset += thissize; if (alignsize < thissize) alignsize = thissize; } structsize = sc->offset; #if IN_LLVM if (sc->structalign == STRUCTALIGN_DEFAULT) structsize = (structsize + alignsize - 1) & ~(alignsize - 1); else structsize = (structsize + sc->structalign - 1) & ~(sc->structalign - 1); #endif sizeok = SIZEOKdone; Module::dprogress++; dtor = buildDtor(sc); if (FuncDeclaration *f = hasIdentityOpAssign(sc)) { if (!(f->storage_class & STCdisable)) error("identity assignment operator overload is illegal"); } sc->pop(); #if 0 // Do not call until toObjfile() because of forward references // Fill in base class vtbl[]s for (i = 0; i < vtblInterfaces->dim; i++) { BaseClass *b = (*vtblInterfaces)[i]; //b->fillVtbl(this, &b->vtbl, 1); } #endif //printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type); if (deferred && !global.gag) { deferred->semantic2(sc); deferred->semantic3(sc); } #if 0 if (type->ty == Tclass && ((TypeClass *)type)->sym != this) { printf("this = %p %s\n", this, this->toChars()); printf("type = %d sym = %p\n", type->ty, ((TypeClass *)type)->sym); } #endif assert(type->ty != Tclass || ((TypeClass *)type)->sym == this); }
void StructDeclaration::finalizeSize(Scope *sc) { //printf("StructDeclaration::finalizeSize() %s\n", toChars()); if (sizeok != SIZEOKnone) return; // Set the offsets of the fields and determine the size of the struct unsigned offset = 0; bool isunion = isUnionDeclaration() != NULL; for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; s->setFieldOffset(this, &offset, isunion); } if (sizeok == SIZEOKfwd) return; // 0 sized struct's are set to 1 byte if (structsize == 0) { structsize = 1; alignsize = 1; } // Round struct size up to next alignsize boundary. // This will ensure that arrays of structs will get their internals // aligned properly. if (alignment == STRUCTALIGN_DEFAULT) structsize = (structsize + alignsize - 1) & ~(alignsize - 1); else structsize = (structsize + alignment - 1) & ~(alignment - 1); sizeok = SIZEOKdone; // Calculate fields[i]->overlapped fill(loc, NULL, true); // 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; } } } } // Look for the constructor, for the struct literal/constructor call expression ctor = searchCtor(); if (ctor) { // Finish all constructors semantics to determine this->noDefaultCtor. struct SearchCtor { static int fp(Dsymbol *s, void *ctxt) { CtorDeclaration *f = s->isCtorDeclaration(); if (f && f->semanticRun == PASSinit) f->semantic(NULL); return 0; } }; for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; s->apply(&SearchCtor::fp, NULL); } } }
void StructDeclaration::toDebug() { unsigned leaf; unsigned property; unsigned nfields; unsigned fnamelen; const char *id; targ_size_t size; unsigned numidx; debtyp_t *d,*dt; unsigned len; int i; int count; // COUNT field in LF_CLASS unsigned char *p; idx_t typidx = 0; //printf("StructDeclaration::toDebug('%s')\n", toChars()); assert(config.fulltypes >= CV4); if (isAnonymous()) return /*0*/; if (typidx) // if reference already generated return /*typidx*/; // use already existing reference property = 0; if (!members) { size = 0; property |= 0x80; // forward reference } else size = structsize; if (parent->isAggregateDeclaration()) // if class is nested property |= 8; // if (st->Sctor || st->Sdtor) // property |= 2; // class has ctors and/or dtors // if (st->Sopoverload) // property |= 4; // class has overloaded operators // if (st->Scastoverload) // property |= 0x40; // class has casting methods // if (st->Sopeq && !(st->Sopeq->Sfunc->Fflags & Fnodebug)) // property |= 0x20; // class has overloaded assignment id = toPrettyChars(); numidx = isUnionDeclaration() ? 8 : 12; len = numidx + cv4_numericbytes(size); d = debtyp_alloc(len + cv_stringbytes(id)); cv4_storenumeric(d->data + numidx,size); len += cv_namestring(d->data + len,id); leaf = isUnionDeclaration() ? LF_UNION : LF_STRUCTURE; if (!isUnionDeclaration()) { TOWORD(d->data + 8,0); // dList TOWORD(d->data + 10,0); // vshape is 0 (no virtual functions) } TOWORD(d->data,leaf); // Assign a number to prevent infinite recursion if a struct member // references the same struct. d->length = 0; // so cv_debtyp() will allocate new typidx = cv_debtyp(d); d->length = len; // restore length if (!members) // if reference only { TOWORD(d->data + 2,0); // count: number of fields is 0 TOWORD(d->data + 4,0); // field list is 0 TOWORD(d->data + 6,property); return /*typidx*/; } // Compute the number of fields, and the length of the fieldlist record nfields = 0; fnamelen = 2; count = nfields; for (i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; int nwritten; nwritten = s->cvMember(NULL); if (nwritten) { fnamelen += nwritten; nfields++; count++; } } TOWORD(d->data + 2,count); TOWORD(d->data + 6,property); // Generate fieldlist type record dt = debtyp_alloc(fnamelen); p = dt->data; // And fill it in TOWORD(p,LF_FIELDLIST); p += 2; for (i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; p += s->cvMember(p); } //dbg_printf("fnamelen = %d, p-dt->data = %d\n",fnamelen,p-dt->data); assert(p - dt->data == fnamelen); TOWORD(d->data + 4,cv_debtyp(dt)); // cv4_outsym(s); unsigned char *debsym; unsigned length; len = strlen(id); debsym = (unsigned char *) alloca(39 + IDOHD + len); // Output a 'user-defined type' for the tag name TOWORD(debsym + 2,S_UDT); TOIDX(debsym + 4,typidx); length = 2 + 2 + cgcv.sz_idx; length += cv_namestring(debsym + length,id); TOWORD(debsym,length - 2); assert(length <= 40 + len); obj_write_bytes(SegData[DEBSYM],length,debsym); // return typidx; }
void ClassDeclaration::toDebug() { unsigned leaf; unsigned property; unsigned nfields; unsigned fnamelen; const char *id; targ_size_t size; unsigned numidx; debtyp_t *d,*dt; unsigned len; int i; int count; // COUNT field in LF_CLASS unsigned char *p; idx_t typidx = 0; //printf("ClassDeclaration::toDebug('%s')\n", toChars()); assert(config.fulltypes >= CV4); if (isAnonymous()) return /*0*/; if (typidx) // if reference already generated return /*typidx*/; // use already existing reference property = 0; if (!members) { size = 0; property |= 0x80; // forward reference } else size = structsize; if (parent->isAggregateDeclaration()) // if class is nested property |= 8; if (ctor || dtors.dim) property |= 2; // class has ctors and/or dtors // if (st->Sopoverload) // property |= 4; // class has overloaded operators // if (st->Scastoverload) // property |= 0x40; // class has casting methods // if (st->Sopeq && !(st->Sopeq->Sfunc->Fflags & Fnodebug)) // property |= 0x20; // class has overloaded assignment id = toPrettyChars(); numidx = isUnionDeclaration() ? 8 : 12; len = numidx + cv4_numericbytes(size); d = debtyp_alloc(len + cv_stringbytes(id)); cv4_storenumeric(d->data + numidx,size); len += cv_namestring(d->data + len,id); leaf = LF_CLASS; TOWORD(d->data + 8,0); // dList if (1) { debtyp_t *vshape; unsigned n; unsigned char descriptor; n = vtbl.dim; // number of virtual functions if (n == 0) { TOWORD(d->data + 10,0); // vshape is 0 } else { int i; vshape = debtyp_alloc(4 + (n + 1) / 2); TOWORD(vshape->data,LF_VTSHAPE); TOWORD(vshape->data + 2,1); n = 0; descriptor = 0; for (i = 0; i < vtbl.dim; i++) { FuncDeclaration *fd = (FuncDeclaration *)vtbl.data[i]; tym_t ty; //if (intsize == 4) descriptor |= 5; vshape->data[4 + n / 2] = descriptor; descriptor <<= 4; n++; } TOWORD(d->data + 10,cv_debtyp(vshape)); // vshape } } else TOWORD(d->data + 10,0); // vshape is 0 (no virtual functions) TOWORD(d->data,leaf); // Assign a number to prevent infinite recursion if a struct member // references the same struct. d->length = 0; // so cv_debtyp() will allocate new typidx = cv_debtyp(d); d->length = len; // restore length if (!members) // if reference only { TOWORD(d->data + 2,0); // count: number of fields is 0 TOWORD(d->data + 4,0); // field list is 0 TOWORD(d->data + 6,property); return /*typidx*/; } // Compute the number of fields, and the length of the fieldlist record nfields = 0; fnamelen = 2; // Add in base classes for (i = 0; i < baseclasses.dim; i++) { BaseClass *bc = (BaseClass *)baseclasses.data[i]; nfields++; fnamelen += 6 + cv4_numericbytes(bc->offset); } count = nfields; for (i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; int nwritten; nwritten = s->cvMember(NULL); if (nwritten) { fnamelen += nwritten; nfields++; count++; } } TOWORD(d->data + 2,count); TOWORD(d->data + 6,property); // Generate fieldlist type record dt = debtyp_alloc(fnamelen); p = dt->data; // And fill it in TOWORD(p,LF_FIELDLIST); p += 2; // Add in base classes for (i = 0; i < baseclasses.dim; i++) { BaseClass *bc = (BaseClass *)baseclasses.data[i]; idx_t typidx; unsigned attribute; typidx = cv4_typidx(bc->base->type->toCtype()->Tnext); attribute = PROTtoATTR(bc->protection); TOWORD(p,LF_BCLASS); TOWORD(p + 2,typidx); TOWORD(p + 4,attribute); p += 6; cv4_storenumeric(p, bc->offset); p += cv4_numericbytes(bc->offset); } for (i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; p += s->cvMember(p); } //dbg_printf("fnamelen = %d, p-dt->data = %d\n",fnamelen,p-dt->data); assert(p - dt->data == fnamelen); TOWORD(d->data + 4,cv_debtyp(dt)); // cv4_outsym(s); unsigned char *debsym; unsigned length; len = strlen(id); debsym = (unsigned char *) alloca(39 + IDOHD + len); // Output a 'user-defined type' for the tag name TOWORD(debsym + 2,S_UDT); TOIDX(debsym + 4,typidx); length = 2 + 2 + cgcv.sz_idx; length += cv_namestring(debsym + length,id); TOWORD(debsym,length - 2); assert(length <= 40 + len); obj_write_bytes(SegData[DEBSYM],length,debsym); // return typidx; }
void StructDeclaration::semantic(Scope *sc) { Scope *sc2; //printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", this, toChars(), sizeok); //static int count; if (++count == 20) halt(); assert(type); if (!members) // if forward reference return; if (symtab) { if (sizeok == 1 || !scope) { //printf("already completed\n"); scope = NULL; return; // semantic() already completed } } else symtab = new DsymbolTable(); Scope *scx = NULL; if (scope) { sc = scope; scx = scope; // save so we don't make redundant copies scope = NULL; } unsigned dprogress_save = Module::dprogress; #ifdef IN_GCC methods.setDim(0); #endif parent = sc->parent; type = type->semantic(loc, sc); #if STRUCTTHISREF handle = type; #else handle = type->pointerTo(); #endif structalign = sc->structalign; protection = sc->protection; if (sc->stc & STCdeprecated) isdeprecated = 1; assert(!isAnonymous()); if (sc->stc & STCabstract) error("structs, unions cannot be abstract"); #if DMDV2 if (storage_class & STCimmutable) type = type->invariantOf(); else if (storage_class & STCconst) type = type->constOf(); #endif #if IN_GCC if (attributes) attributes->append(sc->attributes); else attributes = sc->attributes; #endif if (sizeok == 0) // if not already done the addMember step { for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars()); s->addMember(sc, this, 1); } } sizeok = 0; sc2 = sc->push(this); sc2->stc = 0; #if IN_GCC sc2->attributes = NULL; #endif sc2->parent = this; if (isUnionDeclaration()) sc2->inunion = 1; sc2->protection = PROTpublic; sc2->explicitProtection = 0; size_t members_dim = members->dim; /* 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 = (Dsymbol *)members->data[i]; /* There are problems doing this in the general case because * Scope keeps track of things like 'offset' */ if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident)) { //printf("setScope %s %s\n", s->kind(), s->toChars()); s->setScope(sc2); } } for (size_t i = 0; i < members_dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; s->semantic(sc2); #if 0 if (sizeok == 2) { //printf("forward reference\n"); break; } #endif } #if DMDV1 /* This doesn't work for DMDV2 because (ref S) and (S) parameter * lists will overload the same. */ /* The TypeInfo_Struct is expecting an opEquals and opCmp with * a parameter that is a pointer to the struct. But if there * isn't one, but is an opEquals or opCmp with a value, write * another that is a shell around the value: * int opCmp(struct *p) { return opCmp(*p); } */ TypeFunction *tfeqptr; { Parameters *arguments = new Parameters; Parameter *arg = new Parameter(STCin, handle, Id::p, NULL); arguments->push(arg); tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc); } TypeFunction *tfeq; { Parameters *arguments = new Parameters; Parameter *arg = new Parameter(STCin, type, NULL, NULL); arguments->push(arg); tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd); tfeq = (TypeFunction *)tfeq->semantic(0, sc); } Identifier *id = Id::eq; for (int i = 0; i < 2; i++) { Dsymbol *s = search_function(this, id); FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr); if (!fd) { fd = fdx->overloadExactMatch(tfeq); if (fd) { // Create the thunk, fdptr FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr); Expression *e = new IdentifierExp(loc, Id::p); e = new PtrExp(loc, e); Expressions *args = new Expressions(); args->push(e); e = new IdentifierExp(loc, id); e = new CallExp(loc, e, args); fdptr->fbody = new ReturnStatement(loc, e); ScopeDsymbol *s = fdx->parent->isScopeDsymbol(); assert(s); s->members->push(fdptr); fdptr->addMember(sc, s, 1); fdptr->semantic(sc2); } } } id = Id::cmp; } #endif #if DMDV2 /* Try to find the opEquals function. Build it if necessary. */ TypeFunction *tfeqptr; { // bool opEquals(const T*) const; Parameters *parameters = new Parameters; #if STRUCTTHISREF // bool opEquals(ref const T) const; Parameter *param = new Parameter(STCref, type->constOf(), NULL, NULL); #else // bool opEquals(const T*) const; Parameter *param = new Parameter(STCin, type->pointerTo(), NULL, NULL); #endif parameters->push(param); tfeqptr = new TypeFunction(parameters, Type::tbool, 0, LINKd); tfeqptr->mod = MODconst; tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc2); Dsymbol *s = search_function(this, Id::eq); FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { eq = fdx->overloadExactMatch(tfeqptr); if (!eq) fdx->error("type signature should be %s not %s", tfeqptr->toChars(), fdx->type->toChars()); } TemplateDeclaration *td = s ? s->isTemplateDeclaration() : NULL; // BUG: should also check that td is a function template, not just a template if (!eq && !td) eq = buildOpEquals(sc2); } dtor = buildDtor(sc2); postblit = buildPostBlit(sc2); cpctor = buildCpCtor(sc2); buildOpAssign(sc2); #endif sc2->pop(); if (sizeok == 2) { // semantic() failed because of forward references. // Unwind what we did, and defer it for later fields.setDim(0); structsize = 0; alignsize = 0; structalign = 0; scope = scx ? scx : new Scope(*sc); scope->setNoFree(); scope->module->addDeferredSemantic(this); Module::dprogress = dprogress_save; //printf("\tdeferring %s\n", toChars()); return; } // 0 sized struct's are set to 1 byte if (structsize == 0) { structsize = 1; alignsize = 1; } // Round struct size up to next alignsize boundary. // This will ensure that arrays of structs will get their internals // aligned properly. structsize = (structsize + alignsize - 1) & ~(alignsize - 1); sizeok = 1; Module::dprogress++; //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++) { Dsymbol *s = (Dsymbol *)fields.data[i]; VarDeclaration *vd = s->isVarDeclaration(); if (vd && !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; } } } } /* Look for special member functions. */ #if DMDV2 ctor = search(0, Id::ctor, 0); #endif inv = (InvariantDeclaration *)search(0, Id::classInvariant, 0); aggNew = (NewDeclaration *)search(0, Id::classNew, 0); aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); if (sc->func) { semantic2(sc); semantic3(sc); } }
void StructDeclaration::toDebug() { idx_t typidx = 0; //printf("StructDeclaration::toDebug('%s')\n", toChars()); assert(config.fulltypes >= CV4); if (isAnonymous()) return /*0*/; if (typidx) // if reference already generated return /*typidx*/; // use already existing reference targ_size_t size; unsigned property = 0; if (!members) { size = 0; property |= 0x80; // forward reference } else size = structsize; if (parent->isAggregateDeclaration()) // if class is nested property |= 8; // if (st->Sctor || st->Sdtor) // property |= 2; // class has ctors and/or dtors // if (st->Sopoverload) // property |= 4; // class has overloaded operators // if (st->Scastoverload) // property |= 0x40; // class has casting methods // if (st->Sopeq && !(st->Sopeq->Sfunc->Fflags & Fnodebug)) // property |= 0x20; // class has overloaded assignment const char *id = toPrettyChars(); unsigned leaf = isUnionDeclaration() ? LF_UNION : LF_STRUCTURE; if (config.fulltypes == CV8) leaf = leaf == LF_UNION ? LF_UNION_V3 : LF_STRUCTURE_V3; unsigned numidx; switch (leaf) { case LF_UNION: numidx = 8; break; case LF_UNION_V3: numidx = 10; break; case LF_STRUCTURE: numidx = 12; break; case LF_STRUCTURE_V3: numidx = 18; break; } unsigned len = numidx + cv4_numericbytes(size); debtyp_t *d = debtyp_alloc(len + cv_stringbytes(id)); cv4_storenumeric(d->data + numidx,size); len += cv_namestring(d->data + len,id); if (leaf == LF_STRUCTURE) { TOWORD(d->data + 8,0); // dList TOWORD(d->data + 10,0); // vshape is 0 (no virtual functions) } else if (leaf == LF_STRUCTURE_V3) { TOLONG(d->data + 10,0); // dList TOLONG(d->data + 14,0); // vshape is 0 (no virtual functions) } TOWORD(d->data,leaf); // Assign a number to prevent infinite recursion if a struct member // references the same struct. unsigned length_save = d->length; d->length = 0; // so cv_debtyp() will allocate new typidx = cv_debtyp(d); d->length = length_save; // restore length if (!members) // if reference only { if (config.fulltypes == CV8) { TOWORD(d->data + 2,0); // count: number of fields is 0 TOLONG(d->data + 6,0); // field list is 0 TOWORD(d->data + 4,property); } else { TOWORD(d->data + 2,0); // count: number of fields is 0 TOWORD(d->data + 4,0); // field list is 0 TOWORD(d->data + 6,property); } return /*typidx*/; } // Compute the number of fields (nfields), and the length of the fieldlist record (fnamelen) CvMemberCount mc; mc.nfields = 0; mc.fnamelen = 2; for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; s->apply(&cv_mem_count, &mc); } unsigned nfields = mc.nfields; unsigned fnamelen = mc.fnamelen; int count = nfields; // COUNT field in LF_CLASS // Generate fieldlist type record debtyp_t *dt = debtyp_alloc(fnamelen); unsigned char *p = dt->data; // And fill it in TOWORD(p,config.fulltypes == CV8 ? LF_FIELDLIST_V2 : LF_FIELDLIST); p += 2; for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; s->apply(&cv_mem_p, &p); } //dbg_printf("fnamelen = %d, p-dt->data = %d\n",fnamelen,p-dt->data); assert(p - dt->data == fnamelen); idx_t fieldlist = cv_debtyp(dt); TOWORD(d->data + 2,count); if (config.fulltypes == CV8) { TOWORD(d->data + 4,property); TOLONG(d->data + 6,fieldlist); } else { TOWORD(d->data + 4,fieldlist); TOWORD(d->data + 6,property); } // cv4_outsym(s); if (config.fulltypes == CV8) cv8_udt(id, typidx); else { size_t idlen = strlen(id); unsigned char *debsym = (unsigned char *) alloca(39 + IDOHD + idlen); // Output a 'user-defined type' for the tag name TOWORD(debsym + 2,S_UDT); TOIDX(debsym + 4,typidx); unsigned length = 2 + 2 + cgcv.sz_idx; length += cv_namestring(debsym + length,id); TOWORD(debsym,length - 2); assert(length <= 40 + idlen); objmod->write_bytes(SegData[DEBSYM],length,debsym); } // return typidx; }
void StructDeclaration::semantic(Scope *sc) { Scope *sc2; //printf("+StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", this, parent->toChars(), toChars(), sizeok); //static int count; if (++count == 20) halt(); assert(type); if (!members) // if forward reference return; if (symtab) { if (sizeok == 1 || !scope) { //printf("already completed\n"); scope = NULL; return; // semantic() already completed } } else symtab = new DsymbolTable(); Scope *scx = NULL; if (scope) { sc = scope; scx = scope; // save so we don't make redundant copies scope = NULL; } int errors = global.gaggedErrors; unsigned dprogress_save = Module::dprogress; parent = sc->parent; type = type->semantic(loc, sc); #if STRUCTTHISREF handle = type; #else handle = type->pointerTo(); #endif structalign = sc->structalign; protection = sc->protection; storage_class |= sc->stc; if (sc->stc & STCdeprecated) isdeprecated = true; assert(!isAnonymous()); if (sc->stc & STCabstract) error("structs, unions cannot be abstract"); #if DMDV2 if (storage_class & STCimmutable) type = type->addMod(MODimmutable); if (storage_class & STCconst) type = type->addMod(MODconst); if (storage_class & STCshared) type = type->addMod(MODshared); #endif if (sizeok == 0) // if not already done the addMember step { int hasfunctions = 0; for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = members->tdata()[i]; //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars()); s->addMember(sc, this, 1); if (s->isFuncDeclaration()) hasfunctions = 1; } // If nested struct, add in hidden 'this' pointer to outer scope if (hasfunctions && !(storage_class & STCstatic)) { Dsymbol *s = toParent2(); if (s) { AggregateDeclaration *ad = s->isAggregateDeclaration(); FuncDeclaration *fd = s->isFuncDeclaration(); TemplateInstance *ti; if (ad && (ti = ad->parent->isTemplateInstance()) != NULL && ti->isnested || fd) { isnested = 1; Type *t; if (ad) t = ad->handle; else if (fd) { AggregateDeclaration *ad = fd->isMember2(); if (ad) t = ad->handle; else t = Type::tvoidptr; } else assert(0); if (t->ty == Tstruct) t = Type::tvoidptr; // t should not be a ref type assert(!vthis); vthis = new ThisDeclaration(loc, t); //vthis->storage_class |= STCref; members->push(vthis); } } } } sizeok = 0; sc2 = sc->push(this); sc2->stc &= STCsafe | STCtrusted | STCsystem; sc2->parent = this; if (isUnionDeclaration()) sc2->inunion = 1; sc2->protection = PROTpublic; sc2->explicitProtection = 0; size_t members_dim = members->dim; /* 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]; /* There are problems doing this in the general case because * Scope keeps track of things like 'offset' */ if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident)) { //printf("setScope %s %s\n", s->kind(), s->toChars()); s->setScope(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 == 0 && s->isAliasDeclaration()) finalizeSize(); } // Ungag errors when not speculative unsigned oldgag = global.gag; if (global.isSpeculativeGagging() && !isSpeculative()) global.gag = 0; s->semantic(sc2); global.gag = oldgag; } if (sizeok == 2) { // semantic() failed because of forward references. // Unwind what we did, and defer it for later fields.setDim(0); structsize = 0; alignsize = 0; structalign = 0; scope = scx ? scx : new Scope(*sc); scope->setNoFree(); scope->module->addDeferredSemantic(this); Module::dprogress = dprogress_save; //printf("\tdeferring %s\n", toChars()); return; } finalizeSize(); Module::dprogress++; //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++) { Dsymbol *s = fields.tdata()[i]; VarDeclaration *vd = s->isVarDeclaration(); if (vd && !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; } } } } #if DMDV1 /* This doesn't work for DMDV2 because (ref S) and (S) parameter * lists will overload the same. */ /* The TypeInfo_Struct is expecting an opEquals and opCmp with * a parameter that is a pointer to the struct. But if there * isn't one, but is an opEquals or opCmp with a value, write * another that is a shell around the value: * int opCmp(struct *p) { return opCmp(*p); } */ TypeFunction *tfeqptr; { Parameters *arguments = new Parameters; Parameter *arg = new Parameter(STCin, handle, Id::p, NULL); arguments->push(arg); tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc); } TypeFunction *tfeq; { Parameters *arguments = new Parameters; Parameter *arg = new Parameter(STCin, type, NULL, NULL); arguments->push(arg); tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd); tfeq = (TypeFunction *)tfeq->semantic(0, sc); } Identifier *id = Id::eq; for (int i = 0; i < 2; i++) { Dsymbol *s = search_function(this, id); FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr); if (!fd) { fd = fdx->overloadExactMatch(tfeq); if (fd) { // Create the thunk, fdptr FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr); Expression *e = new IdentifierExp(loc, Id::p); e = new PtrExp(loc, e); Expressions *args = new Expressions(); args->push(e); e = new IdentifierExp(loc, id); e = new CallExp(loc, e, args); fdptr->fbody = new ReturnStatement(loc, e); ScopeDsymbol *s = fdx->parent->isScopeDsymbol(); assert(s); s->members->push(fdptr); fdptr->addMember(sc, s, 1); fdptr->semantic(sc2); } } } id = Id::cmp; } #endif #if DMDV2 dtor = buildDtor(sc2); postblit = buildPostBlit(sc2); cpctor = buildCpCtor(sc2); buildOpAssign(sc2); hasIdentityEquals = (buildOpEquals(sc2) != NULL); xeq = buildXopEquals(sc2); #endif sc2->pop(); /* Look for special member functions. */ #if DMDV2 ctor = search(0, Id::ctor, 0); #endif inv = (InvariantDeclaration *)search(0, Id::classInvariant, 0); aggNew = (NewDeclaration *)search(0, Id::classNew, 0); aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); if (sc->func) { semantic2(sc); semantic3(sc); } if (global.gag && global.gaggedErrors != errors) { // The type is no good, yet the error messages were gagged. type = Type::terror; } if (deferred && !global.gag) { deferred->semantic2(sc); deferred->semantic3(sc); } }
void StructDeclaration::semantic(Scope *sc) { Scope *sc2; //printf("+StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", this, parent->toChars(), toChars(), sizeok); //static int count; if (++count == 20) halt(); assert(type); if (!members) // if opaque declaration { return; } if (symtab) { if (sizeok == SIZEOKdone || !scope) { //printf("already completed\n"); scope = NULL; return; // semantic() already completed } } else symtab = new DsymbolTable(); Scope *scx = NULL; if (scope) { sc = scope; scx = scope; // save so we don't make redundant copies scope = NULL; } int errors = global.errors; unsigned dprogress_save = Module::dprogress; parent = sc->parent; type = type->semantic(loc, sc); handle = type; protection = sc->protection; alignment = sc->structalign; storage_class |= sc->stc; if (sc->stc & STCdeprecated) isdeprecated = true; assert(!isAnonymous()); if (sc->stc & STCabstract) error("structs, unions cannot be abstract"); userAttributes = sc->userAttributes; 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; sc2 = sc->push(this); sc2->stc &= STCsafe | STCtrusted | STCsystem; sc2->parent = this; if (isUnionDeclaration()) sc2->inunion = 1; sc2->protection = PROTpublic; sc2->explicitProtection = 0; sc2->structalign = STRUCTALIGN_DEFAULT; sc2->userAttributes = 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]; /* There are problems doing this in the general case because * Scope keeps track of things like 'offset' */ //if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident)) { //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]; /* 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); } // Ungag errors when not speculative unsigned oldgag = global.gag; if (global.isSpeculativeGagging() && !isSpeculative()) { global.gag = 0; } s->semantic(sc2); global.gag = oldgag; } 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++) { Dsymbol *s = fields[i]; VarDeclaration *vd = s->isVarDeclaration(); if (vd) vd->offset = 0; } fields.setDim(0); structsize = 0; alignsize = 0; // structalign = 0; scope = scx ? scx : new Scope(*sc); scope->setNoFree(); scope->module->addDeferredSemantic(this); Module::dprogress = dprogress_save; //printf("\tdeferring %s\n", toChars()); return; } Module::dprogress++; //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++) { Dsymbol *s = fields[i]; VarDeclaration *vd = s->isVarDeclaration(); if (vd && !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; } } } } #if DMDV1 /* This doesn't work for DMDV2 because (ref S) and (S) parameter * lists will overload the same. */ /* The TypeInfo_Struct is expecting an opEquals and opCmp with * a parameter that is a pointer to the struct. But if there * isn't one, but is an opEquals or opCmp with a value, write * another that is a shell around the value: * int opCmp(struct *p) { return opCmp(*p); } */ TypeFunction *tfeqptr; { Parameters *arguments = new Parameters; Parameter *arg = new Parameter(STCin, handle, Id::p, NULL); arguments->push(arg); tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); tfeqptr = (TypeFunction *)tfeqptr->semantic(Loc(), sc); } TypeFunction *tfeq; { Parameters *arguments = new Parameters; Parameter *arg = new Parameter(STCin, type, NULL, NULL); arguments->push(arg); tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd); tfeq = (TypeFunction *)tfeq->semantic(Loc(), sc); } Identifier *id = Id::eq; for (int i = 0; i < 2; i++) { Dsymbol *s = search_function(this, id); FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr); if (!fd) { fd = fdx->overloadExactMatch(tfeq); if (fd) { // Create the thunk, fdptr FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr); Expression *e = new IdentifierExp(loc, Id::p); e = new PtrExp(loc, e); Expressions *args = new Expressions(); args->push(e); e = new IdentifierExp(loc, id); e = new CallExp(loc, e, args); fdptr->fbody = new ReturnStatement(loc, e); ScopeDsymbol *s = fdx->parent->isScopeDsymbol(); assert(s); s->members->push(fdptr); fdptr->addMember(sc, s, 1); fdptr->semantic(sc2); } } } id = Id::cmp; } #endif #if DMDV2 dtor = buildDtor(sc2); postblit = buildPostBlit(sc2); cpctor = buildCpCtor(sc2); buildOpAssign(sc2); buildOpEquals(sc2); #endif inv = buildInv(sc2); sc2->pop(); /* Look for special member functions. */ #if DMDV2 ctor = search(Loc(), Id::ctor, 0); #endif aggNew = (NewDeclaration *)search(Loc(), Id::classNew, 0); aggDelete = (DeleteDeclaration *)search(Loc(), Id::classDelete, 0); TypeTuple *tup = type->toArgTypes(); 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); semantic3(sc); } if (global.errors != errors) { // The type is no good. type = Type::terror; } 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 StructDeclaration::semantic(Scope *sc) { int i; Scope *sc2; //printf("+StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); //static int count; if (++count == 20) *(char*)0=0; assert(type); if (!members) // if forward reference return; if (symtab) { if (!scope) return; // semantic() already completed } else symtab = new DsymbolTable(); Scope *scx = NULL; if (scope) { sc = scope; scx = scope; // save so we don't make redundant copies scope = NULL; } parent = sc->parent; handle = type->pointerTo(); structalign = sc->structalign; protection = sc->protection; storage_class |= sc->stc; assert(!isAnonymous()); if (sc->stc & STCabstract) error("structs, unions cannot be abstract"); if (storage_class & STCinvariant) type = type->invariantOf(); else if (storage_class & STCconst) type = type->constOf(); if (sizeok == 0) // if not already done the addMember step { for (i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars()); s->addMember(sc, this, 1); } } sizeok = 0; sc2 = sc->push(this); sc2->stc &= storage_class & (STCconst | STCinvariant); sc2->parent = this; if (isUnionDeclaration()) sc2->inunion = 1; sc2->protection = PROTpublic; sc2->explicitProtection = 0; int members_dim = members->dim; for (i = 0; i < members_dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; s->semantic(sc2); if (isUnionDeclaration()) sc2->offset = 0; #if 0 if (sizeok == 2) { //printf("forward reference\n"); break; } #endif } /* The TypeInfo_Struct is expecting an opEquals and opCmp with * a parameter that is a pointer to the struct. But if there * isn't one, but is an opEquals or opCmp with a value, write * another that is a shell around the value: * int opCmp(struct *p) { return opCmp(*p); } */ TypeFunction *tfeqptr; { Arguments *arguments = new Arguments; Argument *arg = new Argument(STCin, handle, Id::p, NULL); arguments->push(arg); tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc); } TypeFunction *tfeq; { Arguments *arguments = new Arguments; Argument *arg = new Argument(STCin, type, NULL, NULL); arguments->push(arg); tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd); tfeq = (TypeFunction *)tfeq->semantic(0, sc); } Identifier *id = Id::eq; for (int i = 0; i < 2; i++) { Dsymbol *s = search_function(this, id); FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr); if (!fd) { fd = fdx->overloadExactMatch(tfeq); if (fd) { // Create the thunk, fdptr FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr); Expression *e = new IdentifierExp(loc, Id::p); e = new PtrExp(loc, e); Expressions *args = new Expressions(); args->push(e); e = new IdentifierExp(loc, id); e = new CallExp(loc, e, args); fdptr->fbody = new ReturnStatement(loc, e); ScopeDsymbol *s = fdx->parent->isScopeDsymbol(); assert(s); s->members->push(fdptr); fdptr->addMember(sc, s, 1); fdptr->semantic(sc2); } } } id = Id::cmp; } dtor = buildDtor(sc2); postblit = buildPostBlit(sc2); cpctor = buildCpCtor(sc2); buildOpAssign(sc2); sc2->pop(); if (sizeok == 2) { // semantic() failed because of forward references. // Unwind what we did, and defer it for later fields.setDim(0); structsize = 0; alignsize = 0; structalign = 0; scope = scx ? scx : new Scope(*sc); scope->setNoFree(); scope->module->addDeferredSemantic(this); //printf("\tdeferring %s\n", toChars()); return; } // 0 sized struct's are set to 1 byte if (structsize == 0) { structsize = 1; alignsize = 1; } // Round struct size up to next alignsize boundary. // This will ensure that arrays of structs will get their internals // aligned properly. structsize = (structsize + alignsize - 1) & ~(alignsize - 1); sizeok = 1; Module::dprogress++; //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); // Determine if struct is all zeros or not zeroInit = 1; for (i = 0; i < fields.dim; i++) { Dsymbol *s = (Dsymbol *)fields.data[i]; VarDeclaration *vd = s->isVarDeclaration(); if (vd && !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()) { zeroInit = 0; break; } } } } /* Look for special member functions. */ inv = (InvariantDeclaration *)search(0, Id::classInvariant, 0); aggNew = (NewDeclaration *)search(0, Id::classNew, 0); aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); if (sc->func) { semantic2(sc); semantic3(sc); } }
void StructDeclaration::semantic(Scope *sc) { Scope *sc2; //printf("+StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", this, parent->toChars(), toChars(), sizeok); //static int count; if (++count == 20) halt(); assert(type); if (!members) // if opaque declaration { return; } if (symtab) { if (sizeok == SIZEOKdone || !scope) { //printf("already completed\n"); scope = NULL; return; // semantic() already completed } } else symtab = new DsymbolTable(); Scope *scx = NULL; if (scope) { sc = scope; scx = scope; // save so we don't make redundant copies scope = NULL; } unsigned dprogress_save = Module::dprogress; int errors = global.errors; parent = sc->parent; type = type->semantic(loc, sc); handle = type; protection = sc->protection; alignment = sc->structalign; storage_class |= sc->stc; if (sc->stc & STCdeprecated) isdeprecated = true; assert(!isAnonymous()); if (sc->stc & STCabstract) error("structs, unions cannot be abstract"); userAttributes = sc->userAttributes; 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; sc2 = sc->push(this); sc2->stc &= STCsafe | STCtrusted | STCsystem; sc2->parent = this; if (isUnionDeclaration()) sc2->inunion = 1; sc2->protection = PROTpublic; sc2->explicitProtection = 0; sc2->structalign = STRUCTALIGN_DEFAULT; sc2->userAttributes = 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]; /* 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); } // Ungag errors when not speculative Ungag ungag = ungagSpeculative(); 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++) { Dsymbol *s = fields[i]; VarDeclaration *vd = s->isVarDeclaration(); if (vd) vd->offset = 0; } fields.setDim(0); structsize = 0; alignsize = 0; // structalign = 0; scope = scx ? scx : new Scope(*sc); scope->setNoFree(); scope->module->addDeferredSemantic(this); Module::dprogress = dprogress_save; //printf("\tdeferring %s\n", toChars()); return; } Module::dprogress++; //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); // Determine if struct is all zeros or not zeroInit = calcZeroInit(); dtor = buildDtor(sc2); postblit = buildPostBlit(sc2); cpctor = buildCpCtor(sc2); buildOpAssign(sc2); buildOpEquals(sc2); xeq = buildXopEquals(sc2); xcmp = buildXopCmp(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 Type::getTypeInfo(). */ inv = buildInv(sc2); sc2->pop(); /* Look for special member functions. */ searchCtor(); aggNew = (NewDeclaration *)search(Loc(), Id::classNew, 0); aggDelete = (DeleteDeclaration *)search(Loc(), Id::classDelete, 0); TypeTuple *tup = type->toArgTypes(); 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); semantic3(sc); } #if 1 { // build a literal now to initialize vtinfo of element types StructLiteralExp *sle = new StructLiteralExp(loc, this, NULL); Expression *e = sle->fill(true); } #endif if (global.errors != errors) { // The type is no good. type = Type::terror; this->errors = true; } if (deferred && !global.gag) { deferred->semantic2(sc); deferred->semantic3(sc); } if (type->ty == Tstruct && ((TypeStruct *)type)->sym != this) { error("failed semantic analysis"); this->errors = true; type = Type::terror; } }
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 AggregateDeclaration::addField(Scope *sc, VarDeclaration *v) { unsigned memsize; // size of member unsigned memalignsize; // size of member for alignment purposes unsigned xalign; // alignment boundaries //printf("AggregateDeclaration::addField('%s') %s\n", v->toChars(), toChars()); // Check for forward referenced types which will fail the size() call Type *t = v->type->toBasetype(); if (t->ty == Tstruct /*&& isStructDeclaration()*/) { TypeStruct *ts = (TypeStruct *)t; #if DMDV2 if (ts->sym == this) { error("cannot have field %s with same struct type", v->toChars()); } #endif if (ts->sym->sizeok != 1 && ts->sym->scope) ts->sym->semantic(NULL); if (ts->sym->sizeok != 1) { sizeok = 2; // cannot finish; flag as forward referenced return; } } if (t->ty == Tident) { sizeok = 2; // cannot finish; flag as forward referenced return; } memsize = v->type->size(loc); memalignsize = v->type->alignsize(); xalign = v->type->memalign(sc->structalign); #if 0 alignmember(xalign, memalignsize, &sc->offset); v->offset = sc->offset; sc->offset += memsize; if (sc->offset > structsize) structsize = sc->offset; #else unsigned ofs = sc->offset; alignmember(xalign, memalignsize, &ofs); v->offset = ofs; ofs += memsize; if (ofs > structsize) structsize = ofs; if (!isUnionDeclaration()) sc->offset = ofs; #endif if (global.params.is64bit && sc->structalign == 8 && memalignsize == 16) /* Not sure how to handle this */ ; else if (sc->structalign < memalignsize) memalignsize = sc->structalign; if (alignsize < memalignsize) alignsize = memalignsize; //printf("\t%s: alignsize = %d\n", toChars(), alignsize); v->storage_class |= STCfield; //printf(" addField '%s' to '%s' at offset %d, size = %d\n", v->toChars(), toChars(), v->offset, memsize); fields.push(v); }
void AggregateDeclaration::semantic3(Scope *sc) { //printf("AggregateDeclaration::semantic3(%s) type = %s, errors = %d\n", toChars(), type->toChars(), errors); if (!members) return; StructDeclaration *sd = isStructDeclaration(); if (!sc) // from runDeferredSemantic3 for TypeInfo generation { assert(sd); sd->semanticTypeInfoMembers(); return; } 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; for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; s->semantic3(sc2); } sc2->pop(); // don't do it for unused deprecated types // or error types if (!getRTInfo && Type::rtinfo && (!isDeprecated() || global.params.useDeprecated) && (type && type->ty != Terror)) { // we do not want to report deprecated uses of this type during RTInfo // generation, so we disable reporting deprecation temporarily // WARNING: Muting messages during analysis of RTInfo might silently instantiate // templates that use (other) deprecated types. If these template instances // are used in other parts of the program later, they will be reused without // ever producing the deprecation message. The implementation here restricts // muting to the types that RTInfo is currently generated for. bool wasmuted = mutedeprecation; mutedeprecation = true; // Evaluate: RTinfo!type Objects *tiargs = new Objects(); tiargs->push(type); TemplateInstance *ti = new TemplateInstance(loc, Type::rtinfo, tiargs); ti->semantic(sc); ti->semantic2(sc); ti->semantic3(sc); Dsymbol *s = ti->toAlias(); Expression *e = new DsymbolExp(Loc(), s, 0); Scope *sc3 = ti->tempdecl->scope->startCTFE(); sc3->tinst = sc->tinst; e = e->semantic(sc3); sc3->endCTFE(); e = e->ctfeInterpret(); getRTInfo = e; mutedeprecation = wasmuted; } if (sd) sd->semanticTypeInfoMembers(); }