Symbol *FuncDeclaration::toSymbol() { if (!csym) { Symbol *s; TYPE *t; const char *id; #if 0 id = ident->toChars(); #else id = mangle(); #endif //printf("FuncDeclaration::toSymbol(%s %s)\n", kind(), toChars()); //printf("\tid = '%s'\n", id); //printf("\ttype = %s\n", type->toChars()); s = symbol_calloc(id); slist_add(s); { s->prettyIdent = toPrettyChars(); s->Sclass = SCglobal; symbol_func(s); func_t *f = s->Sfunc; if (isVirtual() && vtblIndex != -1) f->Fflags |= Fvirtual; else if (isMember2() && isStatic()) f->Fflags |= Fstatic; f->Fstartline.Slinnum = loc.linnum; f->Fstartline.Sfilename = (char *)loc.filename; if (endloc.linnum) { f->Fendline.Slinnum = endloc.linnum; f->Fendline.Sfilename = (char *)endloc.filename; } else { f->Fendline.Slinnum = loc.linnum; f->Fendline.Sfilename = (char *)loc.filename; } t = type->toCtype(); } mangle_t msave = t->Tmangle; if (isMain()) { t->Tty = TYnfunc; t->Tmangle = mTYman_c; } else { switch (linkage) { case LINKwindows: t->Tmangle = mTYman_std; break; case LINKpascal: t->Tty = TYnpfunc; t->Tmangle = mTYman_pas; break; case LINKc: t->Tmangle = mTYman_c; break; case LINKd: t->Tmangle = mTYman_d; break; case LINKcpp: { t->Tmangle = mTYman_cpp; if (isThis() && !global.params.is64bit && global.params.isWindows) t->Tty = TYmfunc; s->Sflags |= SFLpublic; Dsymbol *parent = toParent(); ClassDeclaration *cd = parent->isClassDeclaration(); if (cd) { ::type *tc = cd->type->toCtype(); s->Sscope = tc->Tnext->Ttag; } StructDeclaration *sd = parent->isStructDeclaration(); if (sd) { ::type *ts = sd->type->toCtype(); s->Sscope = ts->Ttag; } break; } default: printf("linkage = %d\n", linkage); assert(0); } } if (msave) assert(msave == t->Tmangle); //printf("Tty = %x, mangle = x%x\n", t->Tty, t->Tmangle); t->Tcount++; s->Stype = t; //s->Sfielddef = this; csym = s; } return csym; }
elem *getEthis(Loc loc, IRState *irs, Dsymbol *fd) { elem *ethis; FuncDeclaration *thisfd = irs->getFunc(); Dsymbol *fdparent = fd->toParent2(); //printf("getEthis(thisfd = '%s', fd = '%s', fdparent = '%s')\n", thisfd->toPrettyChars(), fd->toPrettyChars(), fdparent->toPrettyChars()); if (fdparent == thisfd || /* These two are compiler generated functions for the in and out contracts, * and are called from an overriding function, not just the one they're * nested inside, so this hack is so they'll pass */ fd->ident == Id::require || fd->ident == Id::ensure) { /* Going down one nesting level, i.e. we're calling * a nested function from its enclosing function. */ #if DMDV2 if (irs->sclosure) ethis = el_var(irs->sclosure); else #endif if (irs->sthis) { // We have a 'this' pointer for the current function ethis = el_var(irs->sthis); /* If no variables in the current function's frame are * referenced by nested functions, then we can 'skip' * adding this frame into the linked list of stack * frames. */ if (thisfd->hasNestedFrameRefs()) { /* Local variables are referenced, can't skip. * Address of 'this' gives the 'this' for the nested * function */ ethis = el_una(OPaddr, TYnptr, ethis); } } else { /* No 'this' pointer for current function, * use NULL if no references to the current function's frame */ ethis = el_long(TYnptr, 0); if (thisfd->hasNestedFrameRefs()) { /* OPframeptr is an operator that gets the frame pointer * for the current function, i.e. for the x86 it gets * the value of EBP */ ethis->Eoper = OPframeptr; } } //if (fdparent != thisfd) ethis = el_bin(OPadd, TYnptr, ethis, el_long(TYint, 0x18)); } else { if (!irs->sthis) // if no frame pointer for this function { fd->error(loc, "is a nested function and cannot be accessed from %s", irs->getFunc()->toPrettyChars()); ethis = el_long(TYnptr, 0); // error recovery } else { ethis = el_var(irs->sthis); Dsymbol *s = thisfd; while (fd != s) { /* Go up a nesting level, i.e. we need to find the 'this' * of an enclosing function. * Our 'enclosing function' may also be an inner class. */ //printf("\ts = '%s'\n", s->toChars()); thisfd = s->isFuncDeclaration(); if (thisfd) { /* Enclosing function is a function. */ if (fdparent == s->toParent2()) break; if (thisfd->isNested()) { FuncDeclaration *p = s->toParent2()->isFuncDeclaration(); if (!p || p->hasNestedFrameRefs()) ethis = el_una(OPind, TYnptr, ethis); } else if (thisfd->vthis) { } else { // Error should have been caught by front end assert(0); } } else { /* Enclosed by an aggregate. That means the current * function must be a member function of that aggregate. */ ClassDeclaration *cd; StructDeclaration *sd; AggregateDeclaration *ad = s->isAggregateDeclaration(); if (!ad) goto Lnoframe; cd = s->isClassDeclaration(); if (cd && fd->isClassDeclaration() && fd->isClassDeclaration()->isBaseOf(cd, NULL)) break; sd = s->isStructDeclaration(); if (fd == sd) break; if (!ad->isNested() || !ad->vthis) { Lnoframe: irs->getFunc()->error(loc, "cannot get frame pointer to %s", fd->toChars()); return el_long(TYnptr, 0); // error recovery } ethis = el_bin(OPadd, TYnptr, ethis, el_long(TYsize_t, ad->vthis->offset)); ethis = el_una(OPind, TYnptr, ethis); if (fdparent == s->toParent2()) break; if (fd == s->toParent2()) { /* Remember that frames for functions that have no * nested references are skipped in the linked list * of frames. */ if (s->toParent2()->isFuncDeclaration()->hasNestedFrameRefs()) ethis = el_una(OPind, TYnptr, ethis); break; } if (s->toParent2()->isFuncDeclaration()) { /* Remember that frames for functions that have no * nested references are skipped in the linked list * of frames. */ if (s->toParent2()->isFuncDeclaration()->hasNestedFrameRefs()) ethis = el_una(OPind, TYnptr, ethis); } } s = s->toParent2(); assert(s); } } } #if 0 printf("ethis:\n"); elem_print(ethis); printf("\n"); #endif return ethis; }
Symbol *VarDeclaration::toSymbol() { //printf("VarDeclaration::toSymbol(%s)\n", toChars()); //if (needThis()) *(char*)0=0; assert(!needThis()); if (!csym) { TYPE *t; const char *id; if (isDataseg()) id = mangle(); else id = ident->toChars(); Symbol *s = symbol_calloc(id); s->Salignment = alignment; if (storage_class & (STCout | STCref)) { // should be TYref, but problems in back end t = type_pointer(type->toCtype()); } else if (storage_class & STClazy) { if (config.exe == EX_WIN64 && isParameter()) t = type_fake(TYnptr); else t = type_fake(TYdelegate); // Tdelegate as C type t->Tcount++; } else if (isParameter()) { if (config.exe == EX_WIN64 && type->size(Loc()) > REGSIZE) { // should be TYref, but problems in back end t = type_pointer(type->toCtype()); } else { t = type->toCParamtype(); t->Tcount++; } } else { t = type->toCtype(); t->Tcount++; } if (isDataseg()) { if (isThreadlocal()) { /* Thread local storage */ TYPE *ts = t; ts->Tcount++; // make sure a different t is allocated type_setty(&t, t->Tty | mTYthread); ts->Tcount--; if (global.params.vtls) { char *p = loc.toChars(); fprintf(stderr, "%s: %s is thread local\n", p ? p : "", toChars()); if (p) mem.free(p); } } s->Sclass = SCextern; s->Sfl = FLextern; slist_add(s); /* if it's global or static, then it needs to have a qualified but unmangled name. * This gives some explanation of the separation in treating name mangling. * It applies to PDB format, but should apply to CV as PDB derives from CV. * http://msdn.microsoft.com/en-us/library/ff553493(VS.85).aspx */ s->prettyIdent = toPrettyChars(); } else { s->Sclass = SCauto; s->Sfl = FLauto; if (nestedrefs.dim) { /* Symbol is accessed by a nested function. Make sure * it is not put in a register, and that the optimizer * assumes it is modified across function calls and pointer * dereferences. */ //printf("\tnested ref, not register\n"); type_setcv(&t, t->Tty | mTYvolatile); } } if (ident == Id::va_argsave) /* __va_argsave is set outside of the realm of the optimizer, * so we tell the optimizer to leave it alone */ type_setcv(&t, t->Tty | mTYvolatile); mangle_t m = 0; switch (linkage) { case LINKwindows: m = mTYman_std; break; case LINKpascal: m = mTYman_pas; break; case LINKc: m = mTYman_c; break; case LINKd: m = mTYman_d; break; case LINKcpp: { m = mTYman_cpp; s->Sflags = SFLpublic; Dsymbol *parent = toParent(); ClassDeclaration *cd = parent->isClassDeclaration(); if (cd) { ::type *tc = cd->type->toCtype(); s->Sscope = tc->Tnext->Ttag; } StructDeclaration *sd = parent->isStructDeclaration(); if (sd) { ::type *ts = sd->type->toCtype(); s->Sscope = ts->Ttag; } break; } default: printf("linkage = %d\n", linkage); assert(0); } type_setmangle(&t, m); s->Stype = t; csym = s; } return csym; }
/*************************************** * Fill out remainder of elements[] with default initializers for fields[]. * Input: * loc * elements explicit arguments which given to construct object. * ctorinit true if the elements will be used for default initialization. * Returns false if any errors occur. * Otherwise, returns true and the missing arguments will be pushed in elements[]. */ bool StructDeclaration::fill(Loc loc, Expressions *elements, bool ctorinit) { //printf("StructDeclaration::fill() %s\n", toChars()); assert(sizeok == SIZEOKdone); size_t nfields = fields.dim - isNested(); bool errors = false; if (elements) { size_t dim = elements->dim; elements->setDim(nfields); for (size_t i = dim; i < nfields; i++) (*elements)[i] = NULL; } // Fill in missing any elements with default initializers for (size_t i = 0; i < nfields; i++) { if (elements && (*elements)[i]) continue; VarDeclaration *vd = fields[i]; VarDeclaration *vx = vd; if (vd->init && vd->init->isVoidInitializer()) vx = NULL; // Find overlapped fields with the hole [vd->offset .. vd->offset->size()]. size_t fieldi = i; for (size_t j = 0; j < nfields; j++) { if (i == j) continue; VarDeclaration *v2 = fields[j]; bool overlap = (vd->offset < v2->offset + v2->type->size() && v2->offset < vd->offset + vd->type->size()); if (!overlap) continue; // vd and v2 are overlapping. If either has destructors, postblits, etc., then error //printf("overlapping fields %s and %s\n", vd->toChars(), v2->toChars()); VarDeclaration *v = vd; for (int k = 0; k < 2; ++k, v = v2) { Type *tv = v->type->baseElemOf(); Dsymbol *sv = tv->toDsymbol(NULL); if (sv && !errors) { StructDeclaration *sd = sv->isStructDeclaration(); if (sd && (sd->dtor || sd->inv || sd->postblit)) { error("destructors, postblits and invariants are not allowed in overlapping fields %s and %s", vd->toChars(), v2->toChars()); errors = true; break; } } } if (elements) { if ((*elements)[j]) { vx = NULL; break; } } else { vd->overlapped = true; } if (v2->init && v2->init->isVoidInitializer()) continue; if (elements) { /* Prefer first found non-void-initialized field * union U { int a; int b = 2; } * U u; // Error: overlapping initialization for field a and b */ if (!vx) vx = v2, fieldi = j; else if (v2->init) { ::error(loc, "overlapping initialization for field %s and %s", v2->toChars(), vd->toChars()); } } else { // Will fix Bugzilla 1432 by enabling this path always /* Prefer explicitly initialized field * union U { int a; int b = 2; } * U u; // OK (u.b == 2) */ if (!vx || !vx->init && v2->init) vx = v2, fieldi = j; else if (vx != vd && !(vx->offset < v2->offset + v2->type->size() && v2->offset < vx->offset + vx->type->size())) { // Both vx and v2 fills vd, but vx and v2 does not overlap } else if (vx->init && v2->init) { ::error(loc, "overlapping default initialization for field %s and %s", v2->toChars(), vd->toChars()); } else assert(vx->init || !vx->init && !v2->init); } } if (elements && vx) { Expression *e; if (vx->type->size() == 0) { e = NULL; } else if (vx->init) { assert(!vx->init->isVoidInitializer()); e = vx->getConstInitializer(false); } else { if ((vx->storage_class & STCnodefaultctor) && !ctorinit) { ::error(loc, "field %s.%s must be initialized because it has no default constructor", type->toChars(), vx->toChars()); } /* Bugzilla 12509: Get the element of static array type. */ Type *telem = vx->type; if (telem->ty == Tsarray) { /* We cannot use Type::baseElemOf() here. * If the bottom of the Tsarray is an enum type, baseElemOf() * will return the base of the enum, and its default initializer * would be different from the enum's. */ while (telem->toBasetype()->ty == Tsarray) telem = ((TypeSArray *)telem->toBasetype())->next; if (telem->ty == Tvoid) telem = Type::tuns8->addMod(telem->mod); } if (telem->needsNested() && ctorinit) e = telem->defaultInit(loc); else e = telem->defaultInitLiteral(loc); } (*elements)[fieldi] = e; } } if (elements) { for (size_t i = 0; i < elements->dim; i++) { Expression *e = (*elements)[i]; if (e && e->op == TOKerror) return false; } } return !errors; }