void AliasThis::semantic(Scope *sc) { Dsymbol *p = sc->parent->pastMixin(); AggregateDeclaration *ad = p->isAggregateDeclaration(); if (!ad) { ::error(loc, "alias this can only be a member of aggregate, not %s %s", p->kind(), p->toChars()); return; } assert(ad->members); Dsymbol *s = ad->search(loc, ident); if (!s) { s = sc->search(loc, ident, NULL); if (s) ::error(loc, "%s is not a member of %s", s->toChars(), ad->toChars()); else ::error(loc, "undefined identifier %s", ident->toChars()); return; } else if (ad->aliasthis && s != ad->aliasthis) { ::error(loc, "there can be only one alias this"); return; } if (ad->type->ty == Tstruct && ((TypeStruct *)ad->type)->sym != ad) { AggregateDeclaration *ad2 = ((TypeStruct *)ad->type)->sym; assert(ad2->type == Type::terror); ad->aliasthis = ad2->aliasthis; return; } /* disable the alias this conversion so the implicit conversion check * doesn't use it. */ ad->aliasthis = NULL; Dsymbol *sx = s; if (sx->isAliasDeclaration()) sx = sx->toAlias(); Declaration *d = sx->isDeclaration(); if (d && !d->isTupleDeclaration()) { Type *t = d->type; assert(t); if (ad->type->implicitConvTo(t) > MATCHnomatch) { ::error(loc, "alias this is not reachable as %s already converts to %s", ad->toChars(), t->toChars()); } } ad->aliasthis = s; }
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); }
Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) { //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0; // Look in symbols declared in this module Dsymbol *s = symtab ? symtab->lookup(ident) : NULL; //printf("\ts = %p, imports = %p, %d\n", s, imports, imports ? imports->dim : 0); // hide the aliases generated by selective or renamed private imports if (s && flags & 1) if (AliasDeclaration* ad = s->isAliasDeclaration()) // may be a private alias to a function that is overloaded. these // are sorted out during overload resolution, accept them here if (ad->importprot == PROTprivate && !ad->aliassym->isFuncAliasDeclaration()) s = NULL; if (s) { //printf("\ts = '%s.%s'\n",toChars(),s->toChars()); } else if (imports) { // Look in imported modules for (size_t i = 0; i < imports->dim; i++) { Dsymbol *ss = (*imports)[i]; Dsymbol *s2; // If private import, don't search it if (flags & 1 && prots[i] == PROTprivate) continue; //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); /* Don't find private members if ss is a module */ s2 = ss->search(loc, ident, ss->isImport() ? 1 : 0); if (!s) s = s2; else if (s2 && s != s2) { if (s->toAlias() == s2->toAlias()) { /* After following aliases, we found the same symbol, * so it's not an ambiguity. * But if one alias is deprecated, prefer the other. */ if (s->isDeprecated()) s = s2; } else { /* Two imports of the same module should be regarded as * the same. */ Import *i1 = s->isImport(); Import *i2 = s2->isImport(); if (!(i1 && i2 && (i1->mod == i2->mod || (!i1->parent->isImport() && !i2->parent->isImport() && i1->ident->equals(i2->ident)) ) ) ) { ScopeDsymbol::multiplyDefined(loc, s, s2); break; } } } } if (s) { Declaration *d = s->isDeclaration(); if (d && d->protection == PROTprivate && !d->parent->isTemplateMixin()) error(loc, "%s is private", d->toPrettyChars()); } } return s; }
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::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 Import::load(Scope *sc) { //printf("Import::load('%s') %p\n", toPrettyChars(), this); // See if existing module DsymbolTable *dst = Package::resolve(packages, NULL, &pkg); #if 0 if (pkg && pkg->isModule()) { ::error(loc, "can only import from a module, not from a member of module %s. Did you mean `import %s : %s`?", pkg->toChars(), pkg->toPrettyChars(), id->toChars()); mod = pkg->isModule(); // Error recovery - treat as import of that module return; } #endif Dsymbol *s = dst->lookup(id); if (s) { if (s->isModule()) mod = (Module *)s; else { if (s->isAliasDeclaration()) { ::error(loc, "%s %s conflicts with %s", s->kind(), s->toPrettyChars(), id->toChars()); } else if (Package *p = s->isPackage()) { if (p->isPkgMod == PKGunknown) { mod = Module::load(loc, packages, id); if (!mod) p->isPkgMod = PKGpackage; else assert(p->isPkgMod == PKGmodule); } else { mod = p->isPackageMod(); } if (!mod) { ::error(loc, "can only import from a module, not from package %s.%s", p->toPrettyChars(), id->toChars()); } } else if (pkg) { ::error(loc, "can only import from a module, not from package %s.%s", pkg->toPrettyChars(), id->toChars()); } else { ::error(loc, "can only import from a module, not from package %s", id->toChars()); } } } if (!mod) { // Load module mod = Module::load(loc, packages, id); if (mod) { dst->insert(id, mod); // id may be different from mod->ident, // if so then insert alias } } if (mod && !mod->importedFrom) mod->importedFrom = sc ? sc->module->importedFrom : Module::rootModule; if (!pkg) pkg = mod; //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg); }
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 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); } }