int ClassDeclaration::isFuncHidden(FuncDeclaration *fd) { //printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd->toChars()); Dsymbol *s = search(0, fd->ident, 4|2); if (!s) { //printf("not found\n"); /* Because, due to a hack, if there are multiple definitions * of fd->ident, NULL is returned. */ return 0; } s = s->toAlias(); OverloadSet *os = s->isOverloadSet(); if (os) { for (int i = 0; i < os->a.dim; i++) { Dsymbol *s = (Dsymbol *)os->a.data[i]; FuncDeclaration *f2 = s->isFuncDeclaration(); if (f2 && overloadApply(f2, &isf, fd)) return 0; } return 1; } else { FuncDeclaration *fdstart = s->isFuncDeclaration(); //printf("%s fdstart = %p\n", s->kind(), fdstart); return !overloadApply(fdstart, &isf, fd); } }
int AliasDeclaration::overloadInsert(Dsymbol *s) { /* Don't know yet what the aliased symbol is, so assume it can * be overloaded and check later for correctness. */ //printf("AliasDeclaration::overloadInsert('%s')\n", s->toChars()); if (aliassym) // see test/test56.d { Dsymbol *a = aliassym->toAlias(); FuncDeclaration *f = a->isFuncDeclaration(); if (f) // BUG: what if it's a template? { FuncAliasDeclaration *fa = new FuncAliasDeclaration(f); aliassym = fa; return fa->overloadInsert(s); } } if (overnext == NULL) { if (s == this) { return TRUE; } overnext = s; return TRUE; } else { return overnext->overloadInsert(s); } }
FuncDeclaration *ScopeDsymbol::findGetMembers() { Dsymbol *s = search_function(this, Id::getmembers); FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; #if 0 // Finish static TypeFunction *tfgetmembers; if (!tfgetmembers) { Scope sc; Parameters *arguments = new Parameters; Parameters *arg = new Parameter(STCin, Type::tchar->constOf()->arrayOf(), NULL, NULL); arguments->push(arg); Type *tret = NULL; tfgetmembers = new TypeFunction(arguments, tret, 0, LINKd); tfgetmembers = (TypeFunction *)tfgetmembers->semantic(0, &sc); } if (fdx) fdx = fdx->overloadExactMatch(tfgetmembers); #endif if (fdx && fdx->isVirtual()) fdx = NULL; return fdx; }
static FuncDeclaration* getParentFunc(Dsymbol* sym, bool stopOnStatic) { if (!sym) return NULL; Dsymbol* parent = sym->parent; assert(parent); while (parent && !parent->isFuncDeclaration()) { if (stopOnStatic) { Declaration* decl = sym->isDeclaration(); if (decl && decl->isStatic()) return NULL; } parent = parent->parent; } return (parent ? parent->isFuncDeclaration() : NULL); }
int ClassDeclaration::isFuncHidden(FuncDeclaration *fd) { //printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd->toChars()); Dsymbol *s = search(Loc(), fd->ident, IgnoreAmbiguous | IgnoreErrors); if (!s) { //printf("not found\n"); /* Because, due to a hack, if there are multiple definitions * of fd->ident, NULL is returned. */ return 0; } s = s->toAlias(); OverloadSet *os = s->isOverloadSet(); if (os) { for (size_t i = 0; i < os->a.dim; i++) { Dsymbol *s2 = os->a[i]; FuncDeclaration *f2 = s2->isFuncDeclaration(); if (f2 && overloadApply(f2, (void *)fd, &isf)) return 0; } return 1; } else { FuncDeclaration *fdstart = s->isFuncDeclaration(); //printf("%s fdstart = %p\n", s->kind(), fdstart); if (overloadApply(fdstart, (void *)fd, &isf)) return 0; return !fd->parent->isTemplateMixin(); } }
void visit(TemplateInstance *ti) { OutBuffer buf; #if 0 printf("TemplateInstance::mangle() %p %s", ti, ti->toChars()); if (ti->parent) printf(" parent = %s %s", ti->parent->kind(), ti->parent->toChars()); printf("\n"); #endif ti->getIdent(); const char *id = ti->ident ? ti->ident->toChars() : ti->toChars(); if (!ti->tempdecl) ti->error("is not defined"); else { Dsymbol *par = ti->isTemplateMixin() ? ti->parent : ti->tempdecl->parent; if (par) { FuncDeclaration *f = par->isFuncDeclaration(); if (f) mangleExact(f); else par->accept(this); if (result[0] == '_' && result[1] == 'D') result += 2; buf.writestring(result); } } buf.printf("%llu%s", (ulonglong)strlen(id), id); id = buf.extractString(); //printf("TemplateInstance::mangle() %s = %s\n", ti->toChars(), ti->id); result = id; }
bool Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident) { //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0); Dsymbol *s = NULL; if (members) { for (size_t i = 0; i < members->dim; i++) { Dsymbol *sx = (*members)[i]; bool x = sx->oneMember(ps, ident); //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); if (!x) { //printf("\tfalse 1\n"); assert(*ps == NULL); return false; } if (*ps) { assert(ident); if (!(*ps)->ident || !(*ps)->ident->equals(ident)) continue; if (!s) s = *ps; else if (s->isOverloadable() && (*ps)->isOverloadable()) { // keep head of overload set FuncDeclaration *f1 = s->isFuncDeclaration(); FuncDeclaration *f2 = (*ps)->isFuncDeclaration(); if (f1 && f2) { assert(!f1->isFuncAliasDeclaration()); assert(!f2->isFuncAliasDeclaration()); for (; f1 != f2; f1 = f1->overnext0) { if (f1->overnext0 == NULL) { f1->overnext0 = f2; break; } } } } else // more than one symbol { *ps = NULL; //printf("\tfalse 2\n"); return false; } } } } *ps = s; // s is the one symbol, NULL if none //printf("\ttrue\n"); return true; }
char *mangle(Declaration *sthis) { OutBuffer buf; char *id; Dsymbol *s; //printf("::mangle(%s)\n", sthis->toChars()); s = sthis; do { //printf("mangle: s = %p, '%s', parent = %p\n", s, s->toChars(), s->parent); if (s->ident) { FuncDeclaration *fd = s->isFuncDeclaration(); if (s != sthis && fd) { id = mangle(fd); buf.prependstring(id); goto L1; } else { id = s->ident->toChars(); int len = strlen(id); char tmp[sizeof(len) * 3 + 1]; buf.prependstring(id); sprintf(tmp, "%d", len); buf.prependstring(tmp); } } else buf.prependstring("0"); s = s->parent; } while (s); // buf.prependstring("_D"); L1: //printf("deco = '%s'\n", sthis->type->deco ? sthis->type->deco : "null"); //printf("sthis->type = %s\n", sthis->type->toChars()); FuncDeclaration *fd = sthis->isFuncDeclaration(); if (fd && (fd->needThis() || fd->isNested())) buf.writeByte(Type::needThisPrefix()); if (sthis->type->deco) buf.writestring(sthis->type->deco); else { #ifdef DEBUG if (!fd->inferRetType) printf("%s\n", fd->toChars()); #endif assert(fd && fd->inferRetType); } id = buf.toChars(); buf.data = NULL; return id; }
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); } }
/********************************** * Determine if smember has access to private members of this declaration. */ bool hasPrivateAccess(AggregateDeclaration *ad, Dsymbol *smember) { if (smember) { AggregateDeclaration *cd = NULL; Dsymbol *smemberparent = smember->toParent(); if (smemberparent) cd = smemberparent->isAggregateDeclaration(); #if LOG printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n", ad->toChars(), smember->toChars()); #endif if (ad == cd) // smember is a member of this class { #if LOG printf("\tyes 1\n"); #endif return true; // so we get private access } // If both are members of the same module, grant access while (1) { Dsymbol *sp = smember->toParent(); if (sp->isFuncDeclaration() && smember->isFuncDeclaration()) smember = sp; else break; } if (!cd && ad->toParent() == smember->toParent()) { #if LOG printf("\tyes 2\n"); #endif return true; } if (!cd && ad->getAccessModule() == smember->getAccessModule()) { #if LOG printf("\tyes 3\n"); #endif return true; } } #if LOG printf("\tno\n"); #endif return false; }
static FuncDeclaration* find_method_overload(AggregateDeclaration* ad, Identifier* id, TypeFunction* tf, Module* mod) { Dsymbol *s = search_function(ad, id); FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { FuncDeclaration *fd = fdx->overloadExactMatch(tf, mod); if (fd) { return fd; } } return NULL; }
void visit(PragmaStatement *s) { //printf("PragmaStatement::toIR()\n"); if (s->ident == Id::startaddress) { assert(s->args && s->args->dim == 1); Expression *e = (*s->args)[0]; Dsymbol *sa = getDsymbol(e); FuncDeclaration *f = sa->isFuncDeclaration(); assert(f); Symbol *sym = toSymbol(f); while (irs->prev) irs = irs->prev; irs->startaddress = sym; } }
void PragmaStatement::toIR(IRState *irs) { //printf("PragmaStatement::toIR()\n"); if (ident == Id::startaddress) { assert(args && args->dim == 1); Expression *e = args->tdata()[0]; Dsymbol *sa = getDsymbol(e); FuncDeclaration *f = sa->isFuncDeclaration(); assert(f); Symbol *s = f->toSymbol(); while (irs->prev) irs = irs->prev; irs->startaddress = s; } }
/*************************************** * Search toString member function for TypeInfo_Struct. * string toString(); */ FuncDeclaration *search_toString(StructDeclaration *sd) { Dsymbol *s = search_function(sd, Id::tostring); FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL; if (fd) { static TypeFunction *tftostring; if (!tftostring) { tftostring = new TypeFunction(NULL, Type::tstring, 0, LINKd); tftostring = (TypeFunction *)tftostring->merge(); } fd = fd->overloadExactMatch(tftostring); } return fd; }
/*************************************** * Search toHash member function for TypeInfo_Struct. * const hash_t toHash(); */ FuncDeclaration *search_toHash(StructDeclaration *sd) { Dsymbol *s = search_function(sd, Id::tohash); FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL; if (fd) { static TypeFunction *tftohash; if (!tftohash) { tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd); tftohash->mod = MODconst; tftohash = (TypeFunction *)tftohash->merge(); } fd = fd->overloadExactMatch(tftohash); } return fd; }
Expression *isFuncX(TraitsExp *e, bool (*fp)(FuncDeclaration *f)) { int result = 0; if (!e->args || !e->args->dim) goto Lfalse; for (size_t i = 0; i < e->args->dim; i++) { Dsymbol *s = getDsymbol((*e->args)[i]); if (!s) goto Lfalse; FuncDeclaration *f = s->isFuncDeclaration(); if (!f || !fp(f)) goto Lfalse; } result = 1; Lfalse: return new IntegerExp(e->loc, result, Type::tbool); }
void PragmaDeclaration::toObjFile(int multiobj) { if (ident == Id::lib) { assert(args && args->dim == 1); Expression *e = (Expression *)args->data[0]; assert(e->op == TOKstring); StringExp *se = (StringExp *)e; char *name = (char *)mem.malloc(se->len + 1); memcpy(name, se->string, se->len); name[se->len] = 0; #if OMFOBJ /* The OMF format allows library names to be inserted * into the object file. The linker will then automatically * search that library, too. */ obj_includelib(name); #elif ELFOBJ || MACHOBJ /* The format does not allow embedded library names, * so instead append the library name to the list to be passed * to the linker. */ global.params.libfiles->push((void *) name); #else error("pragma lib not supported"); #endif } #if DMDV2 else if (ident == Id::startaddress) { assert(args && args->dim == 1); Expression *e = (Expression *)args->data[0]; Dsymbol *sa = getDsymbol(e); FuncDeclaration *f = sa->isFuncDeclaration(); assert(f); Symbol *s = f->toSymbol(); obj_startaddress(s); } #endif AttribDeclaration::toObjFile(multiobj); }
static int fp(void *param, Dsymbol *s) { if (!isCPP(s)) return 0; auto fd = s->isFuncDeclaration(); auto td = static_cast<cpp::TemplateDeclaration*>( s->isTemplateDeclaration()); DEquals *p = (DEquals *)param; decltype(D) s_D = fd ? getFD(fd) : td->TempOrSpec; if (p->D == getCanonicalDecl(s_D)) { p->s = s; return 1; } return 0; }
void PragmaDeclaration::toObjFile(int multiobj) { if (ident == Id::lib) { assert(args && args->dim == 1); Expression *e = (*args)[0]; assert(e->op == TOKstring); StringExp *se = (StringExp *)e; char *name = (char *)mem.malloc(se->len + 1); memcpy(name, se->string, se->len); name[se->len] = 0; /* Embed the library names into the object file. * The linker will then automatically * search that library, too. */ if (!obj_includelib(name)) { /* The format does not allow embedded library names, * so instead append the library name to the list to be passed * to the linker. */ global.params.libfiles->push(name); } } #if DMDV2 else if (ident == Id::startaddress) { assert(args && args->dim == 1); Expression *e = (*args)[0]; Dsymbol *sa = getDsymbol(e); FuncDeclaration *f = sa->isFuncDeclaration(); assert(f); Symbol *s = f->toSymbol(); obj_startaddress(s); } #endif AttribDeclaration::toObjFile(multiobj); }
/*********************************************** * This is mostly the same as UnaryExp::op_overload(), but has * a different rewrite. */ Expression *CastExp::op_overload(Scope *sc) { //printf("CastExp::op_overload() (%s)\n", toChars()); AggregateDeclaration *ad = isAggregate(e1->type); if (ad) { Dsymbol *fd = NULL; /* Rewrite as: * e1.opCast!(T)(); */ fd = search_function(ad, Id::cast); if (fd) { #if 1 // Backwards compatibility with D1 if opCast is a function, not a template if (fd->isFuncDeclaration()) { // Rewrite as: e1.opCast() return build_overload(loc, sc, e1, NULL, fd); } #endif Objects *targsi = new Objects(); targsi->push(to); Expression *e = new DotTemplateInstanceExp(loc, e1, fd->ident, targsi); e = new CallExp(loc, e); e = e->semantic(sc); return e; } // Didn't find it. Forward to aliasthis if (ad->aliasthis) { /* Rewrite op(e1) as: * op(e1.aliasthis) */ Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); Expression *e = copy(); ((UnaExp *)e)->e1 = e1; e = e->trySemantic(sc); return e; } } return NULL; }
void visit(PragmaDeclaration *pd) { if (pd->ident == Id::lib) { assert(pd->args && pd->args->dim == 1); Expression *e = (*pd->args)[0]; assert(e->op == TOKstring); StringExp *se = (StringExp *)e; char *name = (char *)mem.xmalloc(se->numberOfCodeUnits() + 1); se->writeTo(name, true); /* Embed the library names into the object file. * The linker will then automatically * search that library, too. */ if (!obj_includelib(name)) { /* The format does not allow embedded library names, * so instead append the library name to the list to be passed * to the linker. */ global.params.libfiles->push(name); } } else if (pd->ident == Id::startaddress) { assert(pd->args && pd->args->dim == 1); Expression *e = (*pd->args)[0]; Dsymbol *sa = getDsymbol(e); FuncDeclaration *f = sa->isFuncDeclaration(); assert(f); Symbol *s = toSymbol(f); obj_startaddress(s); } visit((AttribDeclaration *)pd); }
/************************* * Initialize the hidden aggregate member, vthis, with * the context pointer. * Returns: * *(ey + ad.vthis.offset) = this; */ elem *setEthis(Loc loc, IRState *irs, elem *ey, AggregateDeclaration *ad) { elem *ethis; FuncDeclaration *thisfd = irs->getFunc(); int offset = 0; Dsymbol *adp = ad->toParent2(); // class/func we're nested in //printf("[%s] setEthis(ad = %s, adp = %s, thisfd = %s)\n", loc.toChars(), ad->toChars(), adp->toChars(), thisfd->toChars()); if (adp == thisfd) { ethis = getEthis(loc, irs, ad); } else if (thisfd->vthis && (adp == thisfd->toParent2() || (adp->isClassDeclaration() && adp->isClassDeclaration()->isBaseOf(thisfd->toParent2()->isClassDeclaration(), &offset) ) ) ) { /* Class we're new'ing is at the same level as thisfd */ assert(offset == 0); // BUG: should handle this case ethis = el_var(irs->sthis); } else { ethis = getEthis(loc, irs, adp); FuncDeclaration *fdp = adp->isFuncDeclaration(); if (fdp && fdp->hasNestedFrameRefs()) ethis = el_una(OPaddr, TYnptr, ethis); } ey = el_bin(OPadd, TYnptr, ey, el_long(TYsize_t, ad->vthis->offset)); ey = el_una(OPind, TYnptr, ey); ey = el_bin(OPeq, TYnptr, ey, ethis); return ey; }
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); } } } } }
/************************* * Find all variables accessed by this delegate that are * in functions enclosing it. * Params: * fd = function * vars = array to append found variables to */ void findAllOuterAccessedVariables(FuncDeclaration *fd, VarDeclarations *vars) { for (Dsymbol *p = fd->parent; p; p = p->parent) { FuncDeclaration *fdp = p->isFuncDeclaration(); if (fdp) { for (size_t i = 0; i < fdp->closureVars.dim; i++) { VarDeclaration *v = fdp->closureVars[i]; for (size_t j = 0; j < v->nestedrefs.dim; j++) { FuncDeclaration *fdv = v->nestedrefs[j]; if (fdv == fd) { //printf("accessed: %s, type %s\n", v->toChars(), v->type->toChars()); vars->push(v); } } } } } }
std::vector<llvm::Type*> IrTypeClass::buildVtblType(Type* first, Array* vtbl_array) { IF_LOG Logger::println("Building vtbl type for class %s", cd->toPrettyChars()); LOG_SCOPE; std::vector<llvm::Type*> types; types.reserve(vtbl_array->dim); // first comes the classinfo types.push_back(DtoType(first)); // then come the functions ArrayIter<Dsymbol> it(*vtbl_array); it.index = 1; for (; !it.done(); it.next()) { Dsymbol* dsym = it.get(); if (dsym == NULL) { // FIXME // why is this null? // happens for mini/s.d types.push_back(getVoidPtrType()); continue; } FuncDeclaration* fd = dsym->isFuncDeclaration(); assert(fd && "invalid vtbl entry"); IF_LOG Logger::println("Adding type of %s", fd->toPrettyChars()); types.push_back(DtoType(fd->type->pointerTo())); } return types; }
void mangleParent(Dsymbol *s) { Dsymbol *p; if (TemplateInstance *ti = s->isTemplateInstance()) p = ti->isTemplateMixin() ? ti->parent : ti->tempdecl->parent; else p = s->parent; if (p) { mangleParent(p); if (p->getIdent()) { const char *id = p->ident->toChars(); toBuffer(id, s); if (FuncDeclaration *f = p->isFuncDeclaration()) mangleFunc(f, true); } else buf->writeByte('0'); } }
void mangleParent(OutBuffer *buf, Dsymbol *s) { Dsymbol *p; if (TemplateInstance *ti = s->isTemplateInstance()) p = ti->isTemplateMixin() ? ti->parent : ti->tempdecl->parent; else p = s->parent; if (p) { mangleParent(buf, p); if (p->getIdent()) { const char *id = p->ident->toChars(); buf->printf("%llu%s", (ulonglong)strlen(id), id); if (FuncDeclaration *f = p->isFuncDeclaration()) mangleFunc(buf, f, true); } else buf->writeByte('0'); } }
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); }
FuncDeclaration *StructDeclaration::buildXopEquals(Scope *sc) { if (!search_function(this, Id::eq)) return NULL; /* static bool__xopEquals(in void* p, in void* q) { * return ( *cast(const S*)(p) ).opEquals( *cast(const S*)(q) ); * } */ Parameters *parameters = new Parameters; parameters->push(new Parameter(STCin, Type::tvoidptr, Id::p, NULL)); parameters->push(new Parameter(STCin, Type::tvoidptr, Id::q, NULL)); TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd); tf = (TypeFunction *)tf->semantic(0, sc); Identifier *id = Lexer::idPool("__xopEquals"); FuncDeclaration *fop = new FuncDeclaration(0, 0, id, STCstatic, tf); Expression *e = new CallExp(0, new DotIdExp(0, new PtrExp(0, new CastExp(0, new IdentifierExp(0, Id::p), type->pointerTo()->constOf())), Id::eq), new PtrExp(0, new CastExp(0, new IdentifierExp(0, Id::q), type->pointerTo()->constOf()))); fop->fbody = new ReturnStatement(0, e); size_t index = members->dim; members->push(fop); unsigned errors = global.startGagging(); // Do not report errors, even if the unsigned oldspec = global.speculativeGag; // template opAssign fbody makes it. global.speculativeGag = global.gag; Scope *sc2 = sc->push(); sc2->stc = 0; sc2->linkage = LINKd; sc2->speculative = true; fop->semantic(sc2); fop->semantic2(sc2); fop->semantic3(sc2); sc2->pop(); global.speculativeGag = oldspec; if (global.endGagging(errors)) // if errors happened { members->remove(index); if (!xerreq) { Expression *e = new IdentifierExp(0, Id::empty); e = new DotIdExp(0, e, Id::object); e = new DotIdExp(0, e, Lexer::idPool("_xopEquals")); e = e->semantic(sc); Dsymbol *s = getDsymbol(e); FuncDeclaration *fd = s->isFuncDeclaration(); xerreq = fd; } fop = xerreq; } else fop->addMember(sc, this, 1); return fop; }