/// Sanitizes the MIPS ABI in the feature string. static void addMipsABI(const llvm::Triple &triple, std::vector<std::string> &attrs) { enum ABI { O32 = 1<<0, N32 = 1<<1, N64 = 1<<2, EABI = 1<<3 }; const bool is64Bit = triple.getArch() == llvm::Triple::mips64 || triple.getArch() == llvm::Triple::mips64el; const uint32_t defaultABI = is64Bit ? N64 : O32; uint32_t bits = defaultABI; std::vector<std::string>::iterator I = attrs.begin(); while (I != attrs.end()) { std::string str = *I; bool enabled = str[0] == '+'; std::string flag = (str[0] == '+' || str[0] == '-') ? str.substr(1) : str; uint32_t newBit = 0; if (flag == "o32") newBit = O32; if (flag == "n32") newBit = N32; if (flag == "n64") newBit = N64; if (flag == "eabi") newBit = EABI; if (newBit) { I = attrs.erase(I); if (enabled) bits |= newBit; else bits &= ~newBit; } else ++I; } switch (bits) { case O32: attrs.push_back("+o32"); break; case N32: attrs.push_back("+n32"); break; case N64: attrs.push_back("+n64"); break; case EABI: attrs.push_back("+eabi"); break; default: error(Loc(), "Only one ABI argument is supported"); fatal(); } if (bits != defaultABI) attrs.push_back(is64Bit ? "-n64" : "-o32"); }
void AggregateDeclaration::generateTypeInfoData(Scope *sc) { if (!getRTInfo && Type::rtinfo && (!isDeprecated() || global.params.useDeprecated) && // don't do it for unused deprecated types (type && type->ty != Terror)) // or error types { // Evaluate: gcinfo!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 *sc2 = ti->tempdecl->scope->startCTFE(); sc2->instantiatingModule = sc->instantiatingModule ? sc->instantiatingModule : sc->module; e = e->semantic(sc2); sc2->endCTFE(); e = e->ctfeInterpret(); getRTInfo = e; } }
bool UWorld::IsTraceHandleValid(const FTraceHandle& Handle, bool bOverlapTrace) { // only valid if it's previous frame or current frame if (Handle._Data.FrameNumber != AsyncTraceState.CurrentFrame - 1 && Handle._Data.FrameNumber != AsyncTraceState.CurrentFrame) { return false; } // make sure it has valid index AsyncTraceData& DataBuffer = AsyncTraceState.GetBufferForFrame(Handle._Data.FrameNumber); // this function basically verifies if the address location // is VALID, not necessarily that location was USED in that frame FBufferIndexPair Loc(Handle._Data.Index); if (bOverlapTrace) { return !!Loc.DatumLookup(DataBuffer.OverlapData); } else { return !!Loc.DatumLookup(DataBuffer.TraceData); } }
Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid) { Dsymbol *s; FuncDeclaration *fd; TemplateDeclaration *td; s = ad->search(Loc(), funcid, 0); if (s) { Dsymbol *s2; //printf("search_function: s = '%s'\n", s->kind()); s2 = s->toAlias(); //printf("search_function: s2 = '%s'\n", s2->kind()); fd = s2->isFuncDeclaration(); if (fd && fd->type->ty == Tfunction) return fd; td = s2->isTemplateDeclaration(); if (td) return td; } return NULL; }
std::string getProgram(const char *name, const llvm::cl::opt<std::string> *opt, const char *envVar) { std::string path; const char *prog = nullptr; if (opt && !opt->empty()) { path = findProgramByName(opt->c_str()); } if (path.empty() && envVar && (prog = getenv(envVar)) && prog[0] != '\0') { path = findProgramByName(prog); } if (path.empty()) { path = findProgramByName(name); } if (path.empty()) { error(Loc(), "failed to locate %s", name); fatal(); } return path; }
void AggregateDeclaration::semantic3(Scope *sc) { //printf("AggregateDeclaration::semantic3(%s)\n", toChars()); if (members) { sc = sc->push(this); sc->parent = this; for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; s->semantic3(sc); } sc = sc->pop(); if (!getRTInfo && Type::rtinfo && (!isDeprecated() || global.params.useDeprecated) && // don't do it for unused deprecated types (type && type->ty != Terror)) // or error types { // Evaluate: gcinfo!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 *sc = ti->tempdecl->scope->startCTFE(); e = e->semantic(sc); sc->endCTFE(); e = e->ctfeInterpret(); getRTInfo = e; } } }
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; }
TypeInfoDeclaration *Type::buildTypeInfo(Scope *sc, bool checkNeedSemantic) { if (vtinfo) return vtinfo; if (sc && checkNeedSemantic && !typeInfoNeedsSemantic()) return 0; //printf("Type::getTypeInfo() %p, %s\n", this, toChars()); if (!Type::dtypeinfo) { error(Loc(), "TypeInfo not found. object.d may be incorrectly installed or corrupt, compile with -v switch"); fatal(); } Type *t = merge2(); // do this since not all Type's are merge'd if (!t->vtinfo) { if (t->isShared()) // does both 'shared' and 'shared const' t->vtinfo = new TypeInfoSharedDeclaration(t); else if (t->isConst()) t->vtinfo = new TypeInfoConstDeclaration(t); else if (t->isImmutable()) t->vtinfo = new TypeInfoInvariantDeclaration(t); else if (t->isWild()) t->vtinfo = new TypeInfoWildDeclaration(t); else t->vtinfo = t->getTypeInfoDeclaration(); assert(t->vtinfo); vtinfo = t->vtinfo; /* If this has a custom implementation in std/typeinfo, then * do not generate a COMDAT for it. */ if (t->ty == Terror) vtinfo->errors = 1; else if (!t->builtinTypeInfo()) { // Generate COMDAT if (sc) // if in semantic() pass { // Find module that will go all the way to an object file Module *m = sc->module->importedFrom; m->members->push(t->vtinfo); if(m->semanticRun >= 3) { Module::addDeferredSemantic3(t->vtinfo); t->vtinfo->deferredScope = sc; sc->setNoFree(); } if (ty == Tstruct) { Dsymbol *s; StructDeclaration *sd = ((TypeStruct *)this)->sym; if (sd->members && (sd->xeq && sd->xeq != sd->xerreq || sd->xcmp && sd->xcmp != sd->xerrcmp || search_toHash(sd) || search_toString(sd) ) && inNonRoot(sd)) { //printf("deferred sem3 for TypeInfo - sd = %s, inNonRoot = %d\n", sd->toChars(), inNonRoot(sd)); Module::addDeferredSemantic3(sd); } } } else // if in obj generation pass { // it is always a problem if this is called from the backend without // being added to the AST for semantic analysis (no RTInfo generated) // to ease transition, modifier types are just put out as they just forward // to the actual TypeInfo if (t->typeInfoNeedsSemantic()) error(Loc(), "ICE: unexpected type info request for %s", t->toChars()); t->vtinfo->toObjFile(global.params.multiobj); } } } if (!vtinfo) vtinfo = t->vtinfo; // Types aren't merged, but we can share the vtinfo's return vtinfo; }
void VersionCondition::addGlobalIdent(const char *ident) { checkPredefined(Loc(), ident); addPredefinedGlobalIdent(ident); }
void FuncDeclaration_toObjFile(FuncDeclaration *fd, bool multiobj) { ClassDeclaration *cd = fd->parent->isClassDeclaration(); //printf("FuncDeclaration::toObjFile(%p, %s.%s)\n", fd, fd->parent->toChars(), fd->toChars()); //if (type) printf("type = %s\n", type->toChars()); #if 0 //printf("line = %d\n", getWhere() / LINEINC); EEcontext *ee = env->getEEcontext(); if (ee->EEcompile == 2) { if (ee->EElinnum < (getWhere() / LINEINC) || ee->EElinnum > (endwhere / LINEINC) ) return; // don't compile this function ee->EEfunc = toSymbol(this); } #endif if (fd->semanticRun >= PASSobj) // if toObjFile() already run return; if (fd->type && fd->type->ty == Tfunction && ((TypeFunction *)fd->type)->next == NULL) return; // If errors occurred compiling it, such as bugzilla 6118 if (fd->type && fd->type->ty == Tfunction && ((TypeFunction *)fd->type)->next->ty == Terror) return; if (global.errors) return; if (!fd->fbody) return; UnitTestDeclaration *ud = fd->isUnitTestDeclaration(); if (ud && !global.params.useUnitTests) return; if (multiobj && !fd->isStaticDtorDeclaration() && !fd->isStaticCtorDeclaration()) { obj_append(fd); return; } if (fd->semanticRun == PASSsemanticdone) { /* What happened is this function failed semantic3() with errors, * but the errors were gagged. * Try to reproduce those errors, and then fail. */ fd->error("errors compiling the function"); return; } assert(fd->semanticRun == PASSsemantic3done); assert(fd->ident != Id::empty); for (FuncDeclaration *fd2 = fd; fd2; ) { if (fd2->inNonRoot()) return; if (fd2->isNested()) fd2 = fd2->toParent2()->isFuncDeclaration(); else break; } FuncDeclaration *fdp = fd->toParent2()->isFuncDeclaration(); if (fd->isNested()) { if (fdp && fdp->semanticRun < PASSobj) { if (fdp->semantic3Errors) return; /* Can't do unittest's out of order, they are order dependent in that their * execution is done in lexical order. */ if (UnitTestDeclaration *udp = fdp->isUnitTestDeclaration()) { udp->deferredNested.push(fd); return; } } } if (fd->isArrayOp && isDruntimeArrayOp(fd->ident)) { // Implementation is in druntime return; } // start code generation fd->semanticRun = PASSobj; if (global.params.verbose) fprintf(global.stdmsg, "function %s\n", fd->toPrettyChars()); Symbol *s = toSymbol(fd); func_t *f = s->Sfunc; // tunnel type of "this" to debug info generation if (AggregateDeclaration* ad = fd->parent->isAggregateDeclaration()) { ::type* t = Type_toCtype(ad->getType()); if (cd) t = t->Tnext; // skip reference f->Fclass = (Classsym *)t; } #if TARGET_WINDOS /* This is done so that the 'this' pointer on the stack is the same * distance away from the function parameters, so that an overriding * function can call the nested fdensure or fdrequire of its overridden function * and the stack offsets are the same. */ if (fd->isVirtual() && (fd->fensure || fd->frequire)) f->Fflags3 |= Ffakeeh; #endif #if TARGET_OSX s->Sclass = SCcomdat; #else s->Sclass = SCglobal; #endif for (Dsymbol *p = fd->parent; p; p = p->parent) { if (p->isTemplateInstance()) { s->Sclass = SCcomdat; break; } } /* Vector operations should be comdat's */ if (fd->isArrayOp) s->Sclass = SCcomdat; if (fd->isNested()) { //if (!(config.flags3 & CFG3pic)) // s->Sclass = SCstatic; f->Fflags3 |= Fnested; /* The enclosing function must have its code generated first, * in order to calculate correct frame pointer offset. */ if (fdp && fdp->semanticRun < PASSobj) { toObjFile(fdp, multiobj); } } else { const char *libname = (global.params.symdebug) ? global.params.debuglibname : global.params.defaultlibname; // Pull in RTL startup code (but only once) if (fd->isMain() && onlyOneMain(fd->loc)) { #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS objmod->external_def("_main"); objmod->ehsections(); // initialize exception handling sections #endif #if TARGET_WINDOS if (global.params.mscoff) { objmod->external_def("main"); objmod->ehsections(); // initialize exception handling sections } else { objmod->external_def("_main"); objmod->external_def("__acrtused_con"); } #endif objmod->includelib(libname); s->Sclass = SCglobal; } else if (strcmp(s->Sident, "main") == 0 && fd->linkage == LINKc) { #if TARGET_WINDOS if (global.params.mscoff) { objmod->includelib("LIBCMT"); objmod->includelib("OLDNAMES"); } else { objmod->external_def("__acrtused_con"); // bring in C startup code objmod->includelib("snn.lib"); // bring in C runtime library } #endif s->Sclass = SCglobal; } #if TARGET_WINDOS else if (fd->isWinMain() && onlyOneMain(fd->loc)) { if (global.params.mscoff) { objmod->includelib("uuid"); objmod->includelib("LIBCMT"); objmod->includelib("OLDNAMES"); objmod->ehsections(); // initialize exception handling sections } else { objmod->external_def("__acrtused"); } objmod->includelib(libname); s->Sclass = SCglobal; } // Pull in RTL startup code else if (fd->isDllMain() && onlyOneMain(fd->loc)) { if (global.params.mscoff) { objmod->includelib("uuid"); objmod->includelib("LIBCMT"); objmod->includelib("OLDNAMES"); objmod->ehsections(); // initialize exception handling sections } else { objmod->external_def("__acrtused_dll"); } objmod->includelib(libname); s->Sclass = SCglobal; } #endif } symtab_t *symtabsave = cstate.CSpsymtab; cstate.CSpsymtab = &f->Flocsym; // Find module m for this function Module *m = NULL; for (Dsymbol *p = fd->parent; p; p = p->parent) { m = p->isModule(); if (m) break; } IRState irs(m, fd); Dsymbols deferToObj; // write these to OBJ file later irs.deferToObj = &deferToObj; symbol *shidden = NULL; Symbol *sthis = NULL; tym_t tyf = tybasic(s->Stype->Tty); //printf("linkage = %d, tyf = x%x\n", linkage, tyf); int reverse = tyrevfunc(s->Stype->Tty); assert(fd->type->ty == Tfunction); TypeFunction *tf = (TypeFunction *)fd->type; RET retmethod = retStyle(tf); if (retmethod == RETstack) { // If function returns a struct, put a pointer to that // as the first argument ::type *thidden = Type_toCtype(tf->next->pointerTo()); char hiddenparam[5+4+1]; static int hiddenparami; // how many we've generated so far sprintf(hiddenparam,"__HID%d",++hiddenparami); shidden = symbol_name(hiddenparam,SCparameter,thidden); shidden->Sflags |= SFLtrue | SFLfree; if (fd->nrvo_can && fd->nrvo_var && fd->nrvo_var->nestedrefs.dim) type_setcv(&shidden->Stype, shidden->Stype->Tty | mTYvolatile); irs.shidden = shidden; fd->shidden = shidden; } else { // Register return style cannot make nrvo. // Auto functions keep the nrvo_can flag up to here, // so we should eliminate it before entering backend. fd->nrvo_can = 0; } if (fd->vthis) { assert(!fd->vthis->csym); sthis = toSymbol(fd->vthis); irs.sthis = sthis; if (!(f->Fflags3 & Fnested)) f->Fflags3 |= Fmember; } // Estimate number of parameters, pi size_t pi = (fd->v_arguments != NULL); if (fd->parameters) pi += fd->parameters->dim; // Create a temporary buffer, params[], to hold function parameters Symbol *paramsbuf[10]; Symbol **params = paramsbuf; // allocate on stack if possible if (pi + 2 > 10) // allow extra 2 for sthis and shidden { params = (Symbol **)malloc((pi + 2) * sizeof(Symbol *)); assert(params); } // Get the actual number of parameters, pi, and fill in the params[] pi = 0; if (fd->v_arguments) { params[pi] = toSymbol(fd->v_arguments); pi += 1; } if (fd->parameters) { for (size_t i = 0; i < fd->parameters->dim; i++) { VarDeclaration *v = (*fd->parameters)[i]; //printf("param[%d] = %p, %s\n", i, v, v->toChars()); assert(!v->csym); params[pi + i] = toSymbol(v); } pi += fd->parameters->dim; } if (reverse) { // Reverse params[] entries for (size_t i = 0; i < pi/2; i++) { Symbol *sptmp = params[i]; params[i] = params[pi - 1 - i]; params[pi - 1 - i] = sptmp; } } if (shidden) { #if 0 // shidden becomes last parameter params[pi] = shidden; #else // shidden becomes first parameter memmove(params + 1, params, pi * sizeof(params[0])); params[0] = shidden; #endif pi++; } if (sthis) { #if 0 // sthis becomes last parameter params[pi] = sthis; #else // sthis becomes first parameter memmove(params + 1, params, pi * sizeof(params[0])); params[0] = sthis; #endif pi++; } if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) && fd->linkage != LINKd && shidden && sthis) { /* swap shidden and sthis */ Symbol *sp = params[0]; params[0] = params[1]; params[1] = sp; } for (size_t i = 0; i < pi; i++) { Symbol *sp = params[i]; sp->Sclass = SCparameter; sp->Sflags &= ~SFLspill; sp->Sfl = FLpara; symbol_add(sp); } // Determine register assignments if (pi) { FuncParamRegs fpr(tyf); for (size_t i = 0; i < pi; i++) { Symbol *sp = params[i]; if (fpr.alloc(sp->Stype, sp->Stype->Tty, &sp->Spreg, &sp->Spreg2)) { sp->Sclass = (config.exe == EX_WIN64) ? SCshadowreg : SCfastpar; sp->Sfl = (sp->Sclass == SCshadowreg) ? FLpara : FLfast; } } } // Done with params if (params != paramsbuf) free(params); params = NULL; if (fd->fbody) { localgot = NULL; Statement *sbody = fd->fbody; Blockx bx; memset(&bx,0,sizeof(bx)); bx.startblock = block_calloc(); bx.curblock = bx.startblock; bx.funcsym = s; bx.scope_index = -1; bx.classdec = cd; bx.member = fd; bx.module = fd->getModule(); irs.blx = &bx; /* Doing this in semantic3() caused all kinds of problems: * 1. couldn't reliably get the final mangling of the function name due to fwd refs * 2. impact on function inlining * 3. what to do when writing out .di files, or other pretty printing */ if (global.params.trace && !fd->isCMain()) { /* The profiler requires TLS, and TLS may not be set up yet when C main() * gets control (i.e. OSX), leading to a crash. */ /* Wrap the entire function body in: * trace_pro("funcname"); * try * body; * finally * _c_trace_epi(); */ StringExp *se = StringExp::create(Loc(), s->Sident); se->type = Type::tstring; se->type = se->type->semantic(Loc(), NULL); Expressions *exps = Expressions_create(); exps->push(se); FuncDeclaration *fdpro = FuncDeclaration::genCfunc(NULL, Type::tvoid, "trace_pro"); Expression *ec = VarExp::create(Loc(), fdpro); Expression *e = CallExp::create(Loc(), ec, exps); e->type = Type::tvoid; Statement *sp = ExpStatement::create(fd->loc, e); FuncDeclaration *fdepi = FuncDeclaration::genCfunc(NULL, Type::tvoid, "_c_trace_epi"); ec = VarExp::create(Loc(), fdepi); e = CallExp::create(Loc(), ec); e->type = Type::tvoid; Statement *sf = ExpStatement::create(fd->loc, e); Statement *stf; if (sbody->blockExit(fd, false) == BEfallthru) stf = CompoundStatement::create(Loc(), sbody, sf); else stf = TryFinallyStatement::create(Loc(), sbody, sf); sbody = CompoundStatement::create(Loc(), sp, stf); } buildClosure(fd, &irs); #if TARGET_WINDOS if (fd->isSynchronized() && cd && config.flags2 & CFG2seh && !fd->isStatic() && !sbody->usesEH() && !global.params.trace) { /* The "jmonitor" hack uses an optimized exception handling frame * which is a little shorter than the more general EH frame. */ s->Sfunc->Fflags3 |= Fjmonitor; } #endif Statement_toIR(sbody, &irs); bx.curblock->BC = BCret; f->Fstartblock = bx.startblock; // einit = el_combine(einit,bx.init); if (fd->isCtorDeclaration()) { assert(sthis); for (block *b = f->Fstartblock; b; b = b->Bnext) { if (b->BC == BCret) { b->BC = BCretexp; b->Belem = el_combine(b->Belem, el_var(sthis)); } } } } // If static constructor if (fd->isSharedStaticCtorDeclaration()) // must come first because it derives from StaticCtorDeclaration { ssharedctors.push(s); } else if (fd->isStaticCtorDeclaration()) { sctors.push(s); } // If static destructor if (fd->isSharedStaticDtorDeclaration()) // must come first because it derives from StaticDtorDeclaration { SharedStaticDtorDeclaration *f = fd->isSharedStaticDtorDeclaration(); assert(f); if (f->vgate) { /* Increment destructor's vgate at construction time */ esharedctorgates.push(f); } sshareddtors.shift(s); } else if (fd->isStaticDtorDeclaration()) { StaticDtorDeclaration *f = fd->isStaticDtorDeclaration(); assert(f); if (f->vgate) { /* Increment destructor's vgate at construction time */ ectorgates.push(f); } sdtors.shift(s); } // If unit test if (ud) { stests.push(s); } if (global.errors) { // Restore symbol table cstate.CSpsymtab = symtabsave; return; } writefunc(s); // Restore symbol table cstate.CSpsymtab = symtabsave; if (fd->isExport()) objmod->export_symbol(s, Para.offset); for (size_t i = 0; i < irs.deferToObj->dim; i++) { Dsymbol *s = (*irs.deferToObj)[i]; toObjFile(s, false); } if (ud) { for (size_t i = 0; i < ud->deferredNested.dim; i++) { FuncDeclaration *fd = ud->deferredNested[i]; toObjFile(fd, false); } } #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS // A hack to get a pointer to this function put in the .dtors segment if (fd->ident && memcmp(fd->ident->toChars(), "_STD", 4) == 0) objmod->staticdtor(s); #endif if (irs.startaddress) { //printf("Setting start address\n"); objmod->startaddress(irs.startaddress); } }
int runLINK() { #if _WIN32 if (global.params.is64bit) { OutBuffer cmdbuf; cmdbuf.writestring("/NOLOGO "); for (size_t i = 0; i < global.params.objfiles->dim; i++) { if (i) cmdbuf.writeByte(' '); const char *p = (*global.params.objfiles)[i]; const char *basename = FileName::removeExt(FileName::name(p)); const char *ext = FileName::ext(p); if (ext && !strchr(basename, '.')) { // Write name sans extension (but not if a double extension) writeFilename(&cmdbuf, p, ext - p - 1); } else writeFilename(&cmdbuf, p); FileName::free(basename); } if (global.params.resfile) { cmdbuf.writeByte(' '); writeFilename(&cmdbuf, global.params.resfile); } cmdbuf.writeByte(' '); if (global.params.exefile) { cmdbuf.writestring("/OUT:"); writeFilename(&cmdbuf, global.params.exefile); } else { /* Generate exe file name from first obj name. * No need to add it to cmdbuf because the linker will default to it. */ const char *n = (*global.params.objfiles)[0]; n = FileName::name(n); global.params.exefile = (char *)FileName::forceExt(n, "exe"); } // Make sure path to exe file exists ensurePathToNameExists(Loc(), global.params.exefile); cmdbuf.writeByte(' '); if (global.params.mapfile) { cmdbuf.writestring("/MAP:"); writeFilename(&cmdbuf, global.params.mapfile); } else if (global.params.map) { const char *fn = FileName::forceExt(global.params.exefile, "map"); const char *path = FileName::path(global.params.exefile); const char *p; if (path[0] == '\0') p = FileName::combine(global.params.objdir, fn); else p = fn; cmdbuf.writestring("/MAP:"); writeFilename(&cmdbuf, p); } for (size_t i = 0; i < global.params.libfiles->dim; i++) { cmdbuf.writeByte(' '); cmdbuf.writestring("/DEFAULTLIB:"); writeFilename(&cmdbuf, (*global.params.libfiles)[i]); } if (global.params.deffile) { cmdbuf.writeByte(' '); cmdbuf.writestring("/DEF:"); writeFilename(&cmdbuf, global.params.deffile); } if (global.params.symdebug) { cmdbuf.writeByte(' '); cmdbuf.writestring("/DEBUG"); // in release mode we need to reactivate /OPT:REF after /DEBUG if (global.params.release) cmdbuf.writestring(" /OPT:REF"); } if (global.params.dll) { cmdbuf.writeByte(' '); cmdbuf.writestring("/DLL"); } for (size_t i = 0; i < global.params.linkswitches->dim; i++) { cmdbuf.writeByte(' '); cmdbuf.writestring((*global.params.linkswitches)[i]); } /* Append the path to the VC lib files, and then the SDK lib files */ const char *vcinstalldir = getenv("VCINSTALLDIR"); if (vcinstalldir) { cmdbuf.writestring(" \"/LIBPATH:"); cmdbuf.writestring(vcinstalldir); cmdbuf.writestring("lib\\amd64\""); } const char *windowssdkdir = getenv("WindowsSdkDir"); if (windowssdkdir) { cmdbuf.writestring(" \"/LIBPATH:"); cmdbuf.writestring(windowssdkdir); cmdbuf.writestring("lib\\x64\""); } char *p = cmdbuf.peekString(); const char *lnkfilename = NULL; size_t plen = strlen(p); if (plen > 7000) { lnkfilename = FileName::forceExt(global.params.exefile, "lnk"); File flnk(lnkfilename); flnk.setbuffer(p, plen); flnk.ref = 1; if (flnk.write()) error(Loc(), "error writing file %s", lnkfilename); if (strlen(lnkfilename) < plen) sprintf(p, "@%s", lnkfilename); } const char *linkcmd = getenv("LINKCMD64"); if (!linkcmd) linkcmd = getenv("LINKCMD"); // backward compatible if (!linkcmd) { if (vcinstalldir) { OutBuffer linkcmdbuf; linkcmdbuf.writestring(vcinstalldir); linkcmdbuf.writestring("bin\\amd64\\link"); linkcmd = linkcmdbuf.extractString(); } else linkcmd = "link"; } int status = executecmd(linkcmd, p); if (lnkfilename) { remove(lnkfilename); FileName::free(lnkfilename); } return status; } else { OutBuffer cmdbuf; global.params.libfiles->push("user32"); global.params.libfiles->push("kernel32"); for (size_t i = 0; i < global.params.objfiles->dim; i++) { if (i) cmdbuf.writeByte('+'); const char *p = (*global.params.objfiles)[i]; const char *basename = FileName::removeExt(FileName::name(p)); const char *ext = FileName::ext(p); if (ext && !strchr(basename, '.')) { // Write name sans extension (but not if a double extension) writeFilename(&cmdbuf, p, ext - p - 1); } else writeFilename(&cmdbuf, p); FileName::free(basename); } cmdbuf.writeByte(','); if (global.params.exefile) writeFilename(&cmdbuf, global.params.exefile); else { /* Generate exe file name from first obj name. * No need to add it to cmdbuf because the linker will default to it. */ const char *n = (*global.params.objfiles)[0]; n = FileName::name(n); global.params.exefile = (char *)FileName::forceExt(n, "exe"); } // Make sure path to exe file exists ensurePathToNameExists(Loc(), global.params.exefile); cmdbuf.writeByte(','); if (global.params.mapfile) writeFilename(&cmdbuf, global.params.mapfile); else if (global.params.map) { const char *fn = FileName::forceExt(global.params.exefile, "map"); const char *path = FileName::path(global.params.exefile); const char *p; if (path[0] == '\0') p = FileName::combine(global.params.objdir, fn); else p = fn; writeFilename(&cmdbuf, p); } else cmdbuf.writestring("nul"); cmdbuf.writeByte(','); for (size_t i = 0; i < global.params.libfiles->dim; i++) { if (i) cmdbuf.writeByte('+'); writeFilename(&cmdbuf, (*global.params.libfiles)[i]); } if (global.params.deffile) { cmdbuf.writeByte(','); writeFilename(&cmdbuf, global.params.deffile); } /* Eliminate unnecessary trailing commas */ while (1) { size_t i = cmdbuf.offset; if (!i || cmdbuf.data[i - 1] != ',') break; cmdbuf.offset--; } if (global.params.resfile) { cmdbuf.writestring("/RC:"); writeFilename(&cmdbuf, global.params.resfile); } if (global.params.map || global.params.mapfile) cmdbuf.writestring("/m"); #if 0 if (debuginfo) cmdbuf.writestring("/li"); if (codeview) { cmdbuf.writestring("/co"); if (codeview3) cmdbuf.writestring(":3"); } #else if (global.params.symdebug) cmdbuf.writestring("/co"); #endif cmdbuf.writestring("/noi"); for (size_t i = 0; i < global.params.linkswitches->dim; i++) { cmdbuf.writestring((*global.params.linkswitches)[i]); } cmdbuf.writeByte(';'); char *p = cmdbuf.peekString(); const char *lnkfilename = NULL; size_t plen = strlen(p); if (plen > 7000) { lnkfilename = FileName::forceExt(global.params.exefile, "lnk"); File flnk(lnkfilename); flnk.setbuffer(p, plen); flnk.ref = 1; if (flnk.write()) error(Loc(), "error writing file %s", lnkfilename); if (strlen(lnkfilename) < plen) sprintf(p, "@%s", lnkfilename); } const char *linkcmd = getenv("LINKCMD"); if (!linkcmd) linkcmd = "link"; int status = executecmd(linkcmd, p); if (lnkfilename) { remove(lnkfilename); FileName::free(lnkfilename); } return status; } #elif __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun pid_t childpid; int status; // Build argv[] Strings argv; const char *cc = getenv("CC"); if (!cc) cc = "gcc"; argv.push(cc); argv.insert(1, global.params.objfiles); #if __APPLE__ // If we are on Mac OS X and linking a dynamic library, // add the "-dynamiclib" flag if (global.params.dll) argv.push("-dynamiclib"); #elif __linux__ || __FreeBSD__ || __OpenBSD__ || __sun if (global.params.dll) argv.push("-shared"); #endif // None of that a.out stuff. Use explicit exe file name, or // generate one from name of first source file. argv.push("-o"); if (global.params.exefile) { argv.push(global.params.exefile); } else if (global.params.run) { #if 1 char name[L_tmpnam + 14 + 1]; strcpy(name, P_tmpdir); strcat(name, "/dmd_runXXXXXX"); int fd = mkstemp(name); if (fd == -1) { error(Loc(), "error creating temporary file"); return 1; } else close(fd); global.params.exefile = mem.strdup(name); argv.push(global.params.exefile); #else /* The use of tmpnam raises the issue of "is this a security hole"? * The hole is that after tmpnam and before the file is opened, * the attacker modifies the file system to get control of the * file with that name. I do not know if this is an issue in * this context. * We cannot just replace it with mkstemp, because this name is * passed to the linker that actually opens the file and writes to it. */ char s[L_tmpnam + 1]; char *n = tmpnam(s); global.params.exefile = mem.strdup(n); argv.push(global.params.exefile); #endif } else { // Generate exe file name from first obj name const char *n = (*global.params.objfiles)[0]; char *ex; n = FileName::name(n); const char *e = FileName::ext(n); if (e) { e--; // back up over '.' ex = (char *)mem.malloc(e - n + 1); memcpy(ex, n, e - n); ex[e - n] = 0; // If generating dll then force dll extension if (global.params.dll) ex = (char *)FileName::forceExt(ex, global.dll_ext); } else ex = (char *)"a.out"; // no extension, so give up argv.push(ex); global.params.exefile = ex; } // Make sure path to exe file exists ensurePathToNameExists(Loc(), global.params.exefile); if (global.params.symdebug) argv.push("-g"); if (global.params.is64bit) argv.push("-m64"); else argv.push("-m32"); if (global.params.map || global.params.mapfile) { argv.push("-Xlinker"); #if __APPLE__ argv.push("-map"); #else argv.push("-Map"); #endif if (!global.params.mapfile) { const char *fn = FileName::forceExt(global.params.exefile, "map"); const char *path = FileName::path(global.params.exefile); const char *p; if (path[0] == '\0') p = FileName::combine(global.params.objdir, fn); else p = fn; global.params.mapfile = (char *)p; } argv.push("-Xlinker"); argv.push(global.params.mapfile); } if (0 && global.params.exefile) { /* This switch enables what is known as 'smart linking' * in the Windows world, where unreferenced sections * are removed from the executable. It eliminates unreferenced * functions, essentially making a 'library' out of a module. * Although it is documented to work with ld version 2.13, * in practice it does not, but just seems to be ignored. * Thomas Kuehne has verified that it works with ld 2.16.1. * BUG: disabled because it causes exception handling to fail * because EH sections are "unreferenced" and elided */ argv.push("-Xlinker"); argv.push("--gc-sections"); } for (size_t i = 0; i < global.params.linkswitches->dim; i++) { const char *p = (*global.params.linkswitches)[i]; if (!p || !p[0] || !(p[0] == '-' && (p[1] == 'l' || p[1] == 'L'))) // Don't need -Xlinker if switch starts with -l or -L. // Eliding -Xlinker is significant for -L since it allows our paths // to take precedence over gcc defaults. argv.push("-Xlinker"); argv.push(p); } /* Add each library, prefixing it with "-l". * The order of libraries passed is: * 1. any libraries passed with -L command line switch * 2. libraries specified on the command line * 3. libraries specified by pragma(lib), which were appended * to global.params.libfiles. * 4. standard libraries. */ for (size_t i = 0; i < global.params.libfiles->dim; i++) { const char *p = (*global.params.libfiles)[i]; size_t plen = strlen(p); if (plen > 2 && p[plen - 2] == '.' && p[plen -1] == 'a') argv.push(p); else { char *s = (char *)mem.malloc(plen + 3); s[0] = '-'; s[1] = 'l'; memcpy(s + 2, p, plen + 1); argv.push(s); } } for (size_t i = 0; i < global.params.dllfiles->dim; i++) { const char *p = (*global.params.dllfiles)[i]; argv.push(p); } /* Standard libraries must go after user specified libraries * passed with -l. */ const char *libname = (global.params.symdebug) ? global.params.debuglibname : global.params.defaultlibname; size_t slen = strlen(libname); if (slen) { char *buf = (char *)malloc(3 + slen + 1); strcpy(buf, "-l"); /* Use "-l:libname.a" if the library name is complete */ if (slen > 3 + 2 && memcmp(libname, "lib", 3) == 0 && (memcmp(libname + slen - 2, ".a", 2) == 0 || memcmp(libname + slen - 3, ".so", 3) == 0) ) { strcat(buf, ":"); } strcat(buf, libname); argv.push(buf); // turns into /usr/lib/libphobos2.a } #ifdef __sun argv.push("-mt"); #endif // argv.push("-ldruntime"); argv.push("-lpthread"); argv.push("-lm"); #if __linux__ // Changes in ld for Ubuntu 11.10 require this to appear after phobos2 argv.push("-lrt"); #endif if (global.params.verbose) { // Print it for (size_t i = 0; i < argv.dim; i++) fprintf(global.stdmsg, "%s ", argv[i]); fprintf(global.stdmsg, "\n"); } argv.push(NULL); // set up pipes int fds[2]; if (pipe(fds) == -1) { perror("Unable to create pipe to linker"); return -1; } childpid = fork(); if (childpid == 0) { // pipe linker stderr to fds[0] dup2(fds[1], STDERR_FILENO); close(fds[0]); execvp(argv[0], (char **)argv.tdata()); perror(argv[0]); // failed to execute return -1; } else if (childpid == -1) { perror("Unable to fork"); return -1; } close(fds[1]); const int nme = findNoMainError(fds[0]); waitpid(childpid, &status, 0); if (WIFEXITED(status)) { status = WEXITSTATUS(status); if (status) { if (nme == -1) { perror("Error with the linker pipe"); return -1; } else { printf("--- errorlevel %d\n", status); if (nme == 1) error(Loc(), "no main function specified"); } } } else if (WIFSIGNALED(status)) { printf("--- killed by signal %d\n", WTERMSIG(status)); status = 1; } return status; #else printf ("Linking is not yet supported for this version of DMD.\n"); return -1; #endif }
FuncDeclaration *buildArrayOp(Identifier *ident, BinExp *exp, Scope *sc) { Parameters *fparams = new Parameters(); Expression *loopbody = buildArrayLoop(exp, fparams); /* Construct the function body: * foreach (i; 0 .. p.length) for (size_t i = 0; i < p.length; i++) * loopbody; * return p; */ Parameter *p = (*fparams)[0]; // foreach (i; 0 .. p.length) Statement *s1 = new ForeachRangeStatement(Loc(), TOKforeach, new Parameter(0, NULL, Id::p, NULL), new IntegerExp(Loc(), 0, Type::tsize_t), new ArrayLengthExp(Loc(), new IdentifierExp(Loc(), p->ident)), new ExpStatement(Loc(), loopbody), Loc()); //printf("%s\n", s1->toChars()); Statement *s2 = new ReturnStatement(Loc(), new IdentifierExp(Loc(), p->ident)); //printf("s2: %s\n", s2->toChars()); Statement *fbody = new CompoundStatement(Loc(), s1, s2); // Built-in array ops should be @trusted, pure, nothrow and nogc StorageClass stc = STCtrusted | STCpure | STCnothrow | STCnogc; /* Construct the function */ TypeFunction *ftype = new TypeFunction(fparams, exp->e1->type, 0, LINKc, stc); //printf("fd: %s %s\n", ident->toChars(), ftype->toChars()); FuncDeclaration *fd = new FuncDeclaration(Loc(), Loc(), ident, STCundefined, ftype); fd->fbody = fbody; fd->protection = Prot(PROTpublic); fd->linkage = LINKc; fd->isArrayOp = 1; sc->_module->importedFrom->members->push(fd); sc = sc->push(); sc->parent = sc->_module->importedFrom; sc->stc = 0; sc->linkage = LINKc; fd->semantic(sc); fd->semantic2(sc); unsigned errors = global.startGagging(); fd->semantic3(sc); if (global.endGagging(errors)) { fd->type = Type::terror; fd->errors = true; fd->fbody = NULL; } sc->pop(); return fd; }
/***************************************** * Create inclusive destructor for struct/class by aggregating * all the destructors in dtors[] with the destructors for * all the members. * Note the close similarity with StructDeclaration::buildPostBlit(), * and the ordering changes (runs backward instead of forwards). */ FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc) { //printf("AggregateDeclaration::buildDtor() %s\n", ad->toChars()); StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc; Loc declLoc = ad->dtors.dim ? ad->dtors[0]->loc : ad->loc; Loc loc = Loc(); // internal code should have no loc to prevent coverage Expression *e = NULL; for (size_t i = 0; i < ad->fields.dim; i++) { VarDeclaration *v = ad->fields[i]; if (v->storage_class & STCref) continue; Type *tv = v->type->baseElemOf(); if (tv->ty != Tstruct || !v->type->size()) continue; StructDeclaration *sdv = ((TypeStruct *)tv)->sym; if (!sdv->dtor) continue; sdv->dtor->functionSemantic(); stc = mergeFuncAttrs(stc, sdv->dtor); if (stc & STCdisable) { e = NULL; break; } Expression *ex = new ThisExp(loc); ex = new DotVarExp(loc, ex, v, 0); if (v->type->toBasetype()->ty == Tstruct) { // this.v.__xdtor() // This is a hack so we can call destructors on const/immutable objects. ex = new AddrExp(loc, ex); ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo()); ex = new PtrExp(loc, ex); if (stc & STCsafe) stc = (stc & ~STCsafe) | STCtrusted; ex = new DotVarExp(loc, ex, sdv->dtor, 0); ex = new CallExp(loc, ex); } else { // _ArrayDtor((cast(S*)this.v.ptr)[0 .. n]) // This is a hack so we can call destructors on const/immutable objects. ex = new DotIdExp(loc, ex, Id::ptr); ex = new CastExp(loc, ex, sdv->type->pointerTo()); if (stc & STCsafe) stc = (stc & ~STCsafe) | STCtrusted; uinteger_t n = v->type->size() / sdv->type->size(); ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t), new IntegerExp(loc, n, Type::tsize_t)); // Prevent redundant bounds check ((SliceExp *)ex)->upperIsInBounds = true; ((SliceExp *)ex)->lowerIsLessThanUpper = true; ex = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayDtor), ex); } e = Expression::combine(ex, e); // combine in reverse order } /* Build our own "destructor" which executes e */ if (e || (stc & STCdisable)) { //printf("Building __fieldDtor()\n"); DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Id::__fieldDtor); dd->storage_class |= STCinference; dd->fbody = new ExpStatement(loc, e); ad->dtors.shift(dd); ad->members->push(dd); dd->semantic(sc); } FuncDeclaration *xdtor = NULL; switch (ad->dtors.dim) { case 0: break; case 1: xdtor = ad->dtors[0]; break; default: e = NULL; stc = STCsafe | STCnothrow | STCpure | STCnogc; for (size_t i = 0; i < ad->dtors.dim; i++) { FuncDeclaration *fd = ad->dtors[i]; stc = mergeFuncAttrs(stc, fd); if (stc & STCdisable) { e = NULL; break; } Expression *ex = new ThisExp(loc); ex = new DotVarExp(loc, ex, fd, 0); ex = new CallExp(loc, ex); e = Expression::combine(ex, e); } DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Id::__aggrDtor); dd->storage_class |= STCinference; dd->fbody = new ExpStatement(loc, e); ad->members->push(dd); dd->semantic(sc); xdtor = dd; break; } // Add an __xdtor alias to make the inclusive dtor accessible if (xdtor) { AliasDeclaration *alias = new AliasDeclaration(Loc(), Id::__xdtor, xdtor); alias->semantic(sc); ad->members->push(alias); alias->addMember(sc, ad); // add to symbol table } return xdtor; }
/***************************************** * Create inclusive postblit for struct by aggregating * all the postblits in postblits[] with the postblits for * all the members. * Note the close similarity with AggregateDeclaration::buildDtor(), * and the ordering changes (runs forward instead of backwards). */ FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc) { //printf("StructDeclaration::buildPostBlit() %s\n", sd->toChars()); StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc; Loc declLoc = sd->postblits.dim ? sd->postblits[0]->loc : sd->loc; Loc loc = Loc(); // internal code should have no loc to prevent coverage for (size_t i = 0; i < sd->postblits.dim; i++) { stc |= sd->postblits[i]->storage_class & STCdisable; } Statements *a = NULL; for (size_t i = 0; i < sd->fields.dim && !(stc & STCdisable); i++) { VarDeclaration *v = sd->fields[i]; if (v->storage_class & STCref) continue; Type *tv = v->type->baseElemOf(); if (tv->ty != Tstruct || !v->type->size()) continue; StructDeclaration *sdv = ((TypeStruct *)tv)->sym; if (!sdv->postblit) continue; sdv->postblit->functionSemantic(); stc = mergeFuncAttrs(stc, sdv->postblit); stc = mergeFuncAttrs(stc, sdv->dtor); if (stc & STCdisable) { a = NULL; break; } if (!a) a = new Statements(); Expression *ex = new ThisExp(loc); ex = new DotVarExp(loc, ex, v, 0); if (v->type->toBasetype()->ty == Tstruct) { // this.v.__xpostblit() // This is a hack so we can call postblits on const/immutable objects. ex = new AddrExp(loc, ex); ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo()); ex = new PtrExp(loc, ex); if (stc & STCsafe) stc = (stc & ~STCsafe) | STCtrusted; ex = new DotVarExp(loc, ex, sdv->postblit, 0); ex = new CallExp(loc, ex); } else { // _ArrayPostblit((cast(S*)this.v.ptr)[0 .. n]) // This is a hack so we can call postblits on const/immutable objects. ex = new DotIdExp(loc, ex, Id::ptr); ex = new CastExp(loc, ex, sdv->type->pointerTo()); if (stc & STCsafe) stc = (stc & ~STCsafe) | STCtrusted; uinteger_t n = v->type->size() / sdv->type->size(); ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t), new IntegerExp(loc, n, Type::tsize_t)); // Prevent redundant bounds check ((SliceExp *)ex)->upperIsInBounds = true; ((SliceExp *)ex)->lowerIsLessThanUpper = true; ex = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayPostblit), ex); } a->push(new ExpStatement(loc, ex)); // combine in forward order /* Bugzilla 10972: When the following field postblit calls fail, * this field should be destructed for Exception Safety. */ if (!sdv->dtor) continue; sdv->dtor->functionSemantic(); ex = new ThisExp(loc); ex = new DotVarExp(loc, ex, v, 0); if (v->type->toBasetype()->ty == Tstruct) { // this.v.__xdtor() // This is a hack so we can call destructors on const/immutable objects. ex = new AddrExp(loc, ex); ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo()); ex = new PtrExp(loc, ex); if (stc & STCsafe) stc = (stc & ~STCsafe) | STCtrusted; ex = new DotVarExp(loc, ex, sdv->dtor, 0); ex = new CallExp(loc, ex); } else { // _ArrayDtor((cast(S*)this.v.ptr)[0 .. n]) // This is a hack so we can call destructors on const/immutable objects. ex = new DotIdExp(loc, ex, Id::ptr); ex = new CastExp(loc, ex, sdv->type->pointerTo()); if (stc & STCsafe) stc = (stc & ~STCsafe) | STCtrusted; uinteger_t n = v->type->size() / sdv->type->size(); ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t), new IntegerExp(loc, n, Type::tsize_t)); // Prevent redundant bounds check ((SliceExp *)ex)->upperIsInBounds = true; ((SliceExp *)ex)->lowerIsLessThanUpper = true; ex = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayDtor), ex); } a->push(new OnScopeStatement(loc, TOKon_scope_failure, new ExpStatement(loc, ex))); } /* Build our own "postblit" which executes a */ if (a || (stc & STCdisable)) { //printf("Building __fieldPostBlit()\n"); PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Id::__fieldPostblit); dd->storage_class |= STCinference; dd->fbody = a ? new CompoundStatement(loc, a) : NULL; sd->postblits.shift(dd); sd->members->push(dd); dd->semantic(sc); } FuncDeclaration *xpostblit = NULL; switch (sd->postblits.dim) { case 0: break; case 1: xpostblit = sd->postblits[0]; break; default: Expression *e = NULL; stc = STCsafe | STCnothrow | STCpure | STCnogc; for (size_t i = 0; i < sd->postblits.dim; i++) { FuncDeclaration *fd = sd->postblits[i]; stc = mergeFuncAttrs(stc, fd); if (stc & STCdisable) { e = NULL; break; } Expression *ex = new ThisExp(loc); ex = new DotVarExp(loc, ex, fd, 0); ex = new CallExp(loc, ex); e = Expression::combine(e, ex); } PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Id::__aggrPostblit); dd->storage_class |= STCinference; dd->fbody = new ExpStatement(loc, e); sd->members->push(dd); dd->semantic(sc); xpostblit = dd; break; } // Add an __xpostblit alias to make the inclusive postblit accessible if (xpostblit) { AliasDeclaration *alias = new AliasDeclaration(Loc(), Id::__xpostblit, xpostblit); alias->semantic(sc); sd->members->push(alias); alias->addMember(sc, sd); // add to symbol table } return xpostblit; }
/****************************************** * Build __xopCmp for TypeInfo_Struct * static bool __xopCmp(ref const S p, ref const S q) * { * return p.opCmp(q); * } * * This is called by TypeInfo.compare(p1, p2). If the struct does not support * const objects comparison, it will throw "not implemented" Error in runtime. */ FuncDeclaration *buildXopCmp(StructDeclaration *sd, Scope *sc) { //printf("StructDeclaration::buildXopCmp() %s\n", toChars()); if (Dsymbol *cmp = search_function(sd, Id::cmp)) { if (FuncDeclaration *fd = cmp->isFuncDeclaration()) { TypeFunction *tfcmpptr; { Scope scx; /* const int opCmp(ref const S s); */ Parameters *parameters = new Parameters; parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL)); tfcmpptr = new TypeFunction(parameters, Type::tint32, 0, LINKd); tfcmpptr->mod = MODconst; tfcmpptr = (TypeFunction *)tfcmpptr->semantic(Loc(), &scx); } fd = fd->overloadExactMatch(tfcmpptr); if (fd) return fd; } } else { #if 0 // FIXME: doesn't work for recursive alias this /* Check opCmp member exists. * Consider 'alias this', but except opDispatch. */ Expression *e = new DsymbolExp(sd->loc, sd); e = new DotIdExp(sd->loc, e, Id::cmp); Scope *sc2 = sc->push(); e = e->trySemantic(sc2); sc2->pop(); if (e) { Dsymbol *s = NULL; switch (e->op) { case TOKoverloadset: s = ((OverExp *)e)->vars; break; case TOKimport: s = ((ScopeExp *)e)->sds; break; case TOKvar: s = ((VarExp *)e)->var; break; default: break; } if (!s || s->ident != Id::cmp) e = NULL; // there's no valid member 'opCmp' } if (!e) return NULL; // bitwise comparison would work /* Essentially, a struct which does not define opCmp is not comparable. * At this time, typeid(S).compare might be correct that throwing "not implement" Error. * But implementing it would break existing code, such as: * * struct S { int value; } // no opCmp * int[S] aa; // Currently AA key uses bitwise comparison * // (It's default behavior of TypeInfo_Strust.compare). * * Not sure we should fix this inconsistency, so just keep current behavior. */ #else return NULL; #endif } if (!sd->xerrcmp) { // object._xopCmp Identifier *id = Identifier::idPool("_xopCmp"); Expression *e = new IdentifierExp(sd->loc, Id::empty); e = new DotIdExp(sd->loc, e, Id::object); e = new DotIdExp(sd->loc, e, id); e = e->semantic(sc); Dsymbol *s = getDsymbol(e); assert(s); sd->xerrcmp = s->isFuncDeclaration(); } Loc declLoc = Loc(); // loc is unnecessary so __xopCmp is never called directly Loc loc = Loc(); // loc is unnecessary so errors are gagged Parameters *parameters = new Parameters; parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL)); parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL)); TypeFunction *tf = new TypeFunction(parameters, Type::tint32, 0, LINKd); Identifier *id = Id::xopCmp; FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf); Expression *e1 = new IdentifierExp(loc, Id::p); Expression *e2 = new IdentifierExp(loc, Id::q); Expression *e = new CallExp(loc, new DotIdExp(loc, e2, Id::cmp), e1); fop->fbody = new ReturnStatement(loc, e); unsigned errors = global.startGagging(); // Do not report errors Scope *sc2 = sc->push(); sc2->stc = 0; sc2->linkage = LINKd; fop->semantic(sc2); fop->semantic2(sc2); sc2->pop(); if (global.endGagging(errors)) // if errors happened fop = sd->xerrcmp; return fop; }
/****************************************** * Build __xopEquals for TypeInfo_Struct * static bool __xopEquals(ref const S p, ref const S q) * { * return p == q; * } * * This is called by TypeInfo.equals(p1, p2). If the struct does not support * const objects comparison, it will throw "not implemented" Error in runtime. */ FuncDeclaration *buildXopEquals(StructDeclaration *sd, Scope *sc) { if (!needOpEquals(sd)) return NULL; // bitwise comparison would work //printf("StructDeclaration::buildXopEquals() %s\n", sd->toChars()); if (Dsymbol *eq = search_function(sd, Id::eq)) { if (FuncDeclaration *fd = eq->isFuncDeclaration()) { TypeFunction *tfeqptr; { Scope scx; /* const bool opEquals(ref const S s); */ Parameters *parameters = new Parameters; parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL)); tfeqptr = new TypeFunction(parameters, Type::tbool, 0, LINKd); tfeqptr->mod = MODconst; tfeqptr = (TypeFunction *)tfeqptr->semantic(Loc(), &scx); } fd = fd->overloadExactMatch(tfeqptr); if (fd) return fd; } } if (!sd->xerreq) { // object._xopEquals Identifier *id = Identifier::idPool("_xopEquals"); Expression *e = new IdentifierExp(sd->loc, Id::empty); e = new DotIdExp(sd->loc, e, Id::object); e = new DotIdExp(sd->loc, e, id); e = e->semantic(sc); Dsymbol *s = getDsymbol(e); assert(s); sd->xerreq = s->isFuncDeclaration(); } Loc declLoc = Loc(); // loc is unnecessary so __xopEquals is never called directly Loc loc = Loc(); // loc is unnecessary so errors are gagged Parameters *parameters = new Parameters; parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL)); parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL)); TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd); Identifier *id = Id::xopEquals; FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf); Expression *e1 = new IdentifierExp(loc, Id::p); Expression *e2 = new IdentifierExp(loc, Id::q); Expression *e = new EqualExp(TOKequal, loc, e1, e2); fop->fbody = new ReturnStatement(loc, e); unsigned errors = global.startGagging(); // Do not report errors Scope *sc2 = sc->push(); sc2->stc = 0; sc2->linkage = LINKd; fop->semantic(sc2); fop->semantic2(sc2); sc2->pop(); if (global.endGagging(errors)) // if errors happened fop = sd->xerreq; return fop; }
/****************************************** * Build opAssign for struct. * ref S opAssign(S s) { ... } * * Note that s will be constructed onto the stack, and probably * copy-constructed in caller site. * * If S has copy copy construction and/or destructor, * the body will make bit-wise object swap: * S __swap = this; // bit copy * this = s; // bit copy * __swap.dtor(); * Instead of running the destructor on s, run it on tmp instead. * * Otherwise, the body will make member-wise assignments: * Then, the body is: * this.field1 = s.field1; * this.field2 = s.field2; * ...; */ FuncDeclaration *buildOpAssign(StructDeclaration *sd, Scope *sc) { if (FuncDeclaration *f = hasIdentityOpAssign(sd, sc)) { sd->hasIdentityAssign = true; return f; } // Even if non-identity opAssign is defined, built-in identity opAssign // will be defined. if (!needOpAssign(sd)) return NULL; //printf("StructDeclaration::buildOpAssign() %s\n", sd->toChars()); StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc; Loc declLoc = sd->loc; Loc loc = Loc(); // internal code should have no loc to prevent coverage if (sd->dtor || sd->postblit) { if (!sd->type->isAssignable()) // Bugzilla 13044 return NULL; stc = mergeFuncAttrs(stc, sd->dtor); if (stc & STCsafe) stc = (stc & ~STCsafe) | STCtrusted; } else { for (size_t i = 0; i < sd->fields.dim; i++) { VarDeclaration *v = sd->fields[i]; if (v->storage_class & STCref) continue; Type *tv = v->type->baseElemOf(); if (tv->ty != Tstruct) continue; StructDeclaration *sdv = ((TypeStruct *)tv)->sym; stc = mergeFuncAttrs(stc, hasIdentityOpAssign(sdv, sc)); } } Parameters *fparams = new Parameters; fparams->push(new Parameter(STCnodtor, sd->type, Id::p, NULL)); TypeFunction *tf = new TypeFunction(fparams, sd->handleType(), 0, LINKd, stc | STCref); FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), Id::assign, stc, tf); fop->storage_class |= STCinference; Expression *e = NULL; if (stc & STCdisable) { } else if (sd->dtor || sd->postblit) { /* Do swap this and rhs * __swap = this; this = s; __swap.dtor(); */ //printf("\tswap copy\n"); Identifier *idtmp = Identifier::generateId("__swap"); VarDeclaration *tmp = NULL; AssignExp *ec = NULL; if (sd->dtor) { tmp = new VarDeclaration(loc, sd->type, idtmp, new VoidInitializer(loc)); tmp->noscope = 1; tmp->storage_class |= STCtemp | STCctfe; e = new DeclarationExp(loc, tmp); ec = new BlitExp(loc, new VarExp(loc, tmp), new ThisExp(loc)); e = Expression::combine(e, ec); } ec = new BlitExp(loc, new ThisExp(loc), new IdentifierExp(loc, Id::p)); e = Expression::combine(e, ec); if (sd->dtor) { /* Instead of running the destructor on s, run it * on tmp. This avoids needing to copy tmp back in to s. */ Expression *ec2 = new DotVarExp(loc, new VarExp(loc, tmp), sd->dtor, 0); ec2 = new CallExp(loc, ec2); e = Expression::combine(e, ec2); } } else { /* Do memberwise copy */ //printf("\tmemberwise copy\n"); for (size_t i = 0; i < sd->fields.dim; i++) { VarDeclaration *v = sd->fields[i]; // this.v = s.v; AssignExp *ec = new AssignExp(loc, new DotVarExp(loc, new ThisExp(loc), v, 0), new DotVarExp(loc, new IdentifierExp(loc, Id::p), v, 0)); e = Expression::combine(e, ec); } } if (e) { Statement *s1 = new ExpStatement(loc, e); /* Add: * return this; */ e = new ThisExp(loc); Statement *s2 = new ReturnStatement(loc, e); fop->fbody = new CompoundStatement(loc, s1, s2); tf->isreturn = true; } sd->members->push(fop); fop->addMember(sc, sd); sd->hasIdentityAssign = true; // temporary mark identity assignable unsigned errors = global.startGagging(); // Do not report errors, even if the Scope *sc2 = sc->push(); sc2->stc = 0; sc2->linkage = LINKd; fop->semantic(sc2); fop->semantic2(sc2); // Bugzilla 15044: fop->semantic3 isn't run here for lazy forward reference resolution. sc2->pop(); if (global.endGagging(errors)) // if errors happened { // Disable generated opAssign, because some members forbid identity assignment. fop->storage_class |= STCdisable; fop->fbody = NULL; // remove fbody which contains the error } //printf("-StructDeclaration::buildOpAssign() %s, errors = %d\n", sd->toChars(), (fop->storage_class & STCdisable) != 0); return fop; }
void FistMove (PointingEvent *e) { if (IsHeeding (e)) IncTranslation (6.0 * FistMotion (e, Loc ())); }
// Runs once per render loop; where we provide input to shaders void AssignShaderInputs () { Vect viewloc = Feld () -> Camera () -> ViewLoc (); SetShaderUniform ("fog_radius", GLOBE_RADIUS); SetShaderUniform ("system_distance", Loc () . DistFrom (viewloc)); SetShaderUniform ("camera_position", viewloc); }
Expression *Type::getTypeInfo(Scope *sc) { //printf("Type::getTypeInfo() %p, %s\n", this, toChars()); if (!Type::dtypeinfo) { error(Loc(), "TypeInfo not found. object.d may be incorrectly installed or corrupt, compile with -v switch"); fatal(); } Type *t = merge2(); // do this since not all Type's are merge'd if (!t->vtinfo) { #if DMDV2 if (t->isShared()) // does both 'shared' and 'shared const' t->vtinfo = new TypeInfoSharedDeclaration(t); else if (t->isConst()) t->vtinfo = new TypeInfoConstDeclaration(t); else if (t->isImmutable()) t->vtinfo = new TypeInfoInvariantDeclaration(t); else if (t->isWild()) t->vtinfo = new TypeInfoWildDeclaration(t); else #endif t->vtinfo = t->getTypeInfoDeclaration(); assert(t->vtinfo); vtinfo = t->vtinfo; /* If this has a custom implementation in std/typeinfo, then * do not generate a COMDAT for it. */ if (!t->builtinTypeInfo()) { // Generate COMDAT if (sc) // if in semantic() pass { // Find module that will go all the way to an object file Module *m = sc->module->importedFrom; m->members->push(t->vtinfo); if (ty == Tstruct) { Dsymbol *s; StructDeclaration *sd = ((TypeStruct *)this)->sym; if ((sd->xeq && sd->xeq != sd->xerreq || sd->xcmp && sd->xcmp != sd->xerrcmp || search_toHash(sd) || search_toString(sd) ) && inNonRoot(sd)) { //printf("deferred sem3 for TypeInfo - sd = %s, inNonRoot = %d\n", sd->toChars(), inNonRoot(sd)); Module::addDeferredSemantic3(sd); } } } else // if in obj generation pass { t->vtinfo->toObjFile(global.params.multiobj); } } } if (!vtinfo) vtinfo = t->vtinfo; // Types aren't merged, but we can share the vtinfo's Expression *e = new VarExp(Loc(), t->vtinfo); e = e->addressOf(sc); e->type = t->vtinfo->type; // do this so we don't get redundant dereference return e; }
void visit(ComExp *e) { Expression *ex1 = buildArrayLoop(e->e1); result = new ComExp(Loc(), ex1); }
llvm::TargetMachine* createTargetMachine( std::string targetTriple, std::string arch, std::string cpu, std::vector<std::string> attrs, ExplicitBitness::Type bitness, FloatABI::Type floatABI, llvm::Reloc::Model relocModel, llvm::CodeModel::Model codeModel, llvm::CodeGenOpt::Level codeGenOptLevel, bool noFramePointerElim, bool noLinkerStripDead) { // Determine target triple. If the user didn't explicitly specify one, use // the one set at LLVM configure time. llvm::Triple triple; if (targetTriple.empty()) { triple = llvm::Triple(llvm::sys::getDefaultTargetTriple()); // Handle -m32/-m64. if (sizeof(void*) == 4 && bitness == ExplicitBitness::M64) { triple = triple.get64BitArchVariant(); } else if (sizeof(void*) == 8 && bitness == ExplicitBitness::M32) { triple = triple.get32BitArchVariant(); } } else { triple = llvm::Triple(llvm::Triple::normalize(targetTriple)); } // Look up the LLVM backend to use. This also updates triple with the // user-specified arch, if any. std::string errMsg; const llvm::Target *target = lookupTarget(arch, triple, errMsg); if (target == 0) { error(Loc(), "%s", errMsg.c_str()); fatal(); } // Package up features to be passed to target/subtarget. llvm::SubtargetFeatures features; features.getDefaultSubtargetFeatures(triple); if (cpu == "native") { llvm::StringMap<bool> hostFeatures; if (llvm::sys::getHostCPUFeatures(hostFeatures)) { llvm::StringMapConstIterator<bool> i = hostFeatures.begin(), end = hostFeatures.end(); for (; i != end; ++i) #if LDC_LLVM_VER >= 305 features.AddFeature(std::string((i->second ? "+" : "-")).append(i->first())); #else features.AddFeature(i->first(), i->second); #endif } } if (triple.getArch() == llvm::Triple::mips || triple.getArch() == llvm::Triple::mipsel || triple.getArch() == llvm::Triple::mips64 || triple.getArch() == llvm::Triple::mips64el) addMipsABI(triple, attrs); for (unsigned i = 0; i < attrs.size(); ++i) features.AddFeature(attrs[i]); // With an empty CPU string, LLVM will default to the host CPU, which is // usually not what we want (expected behavior from other compilers is // to default to "generic"). cpu = getTargetCPU(cpu, triple); if (Logger::enabled()) { Logger::println("Targeting '%s' (CPU '%s' with features '%s')", triple.str().c_str(), cpu.c_str(), features.getString().c_str()); } if (triple.isMacOSX() && relocModel == llvm::Reloc::Default) { // OS X defaults to PIC (and as of 10.7.5/LLVM 3.1-3.3, TLS use leads // to crashes for non-PIC code). LLVM doesn't handle this. relocModel = llvm::Reloc::PIC_; } if (floatABI == FloatABI::Default) { switch (triple.getArch()) { default: // X86, ... floatABI = FloatABI::Hard; break; case llvm::Triple::arm: case llvm::Triple::thumb: floatABI = getARMFloatABI(triple, getLLVMArchSuffixForARM(cpu)); break; } } #if LDC_LLVM_VER < 305 if (triple.getArch() == llvm::Triple::arm && !triple.isOSDarwin()) { // On ARM, we want to use EHABI exception handling, as we don't support // SJLJ EH in druntime. Unfortunately, it is still in a partly // experimental state, and the -arm-enable-ehabi-descriptors command // line option is not exposed via an internal API at all. const char *backendArgs[3] = { "ldc2", // Fake name, irrelevant. "-arm-enable-ehabi", "-arm-enable-ehabi-descriptors" }; llvm::cl::ParseCommandLineOptions(3, backendArgs); } #endif llvm::TargetOptions targetOptions; targetOptions.NoFramePointerElim = noFramePointerElim; switch (floatABI) { default: llvm_unreachable("Floating point ABI type unknown."); case FloatABI::Soft: targetOptions.UseSoftFloat = true; targetOptions.FloatABIType = llvm::FloatABI::Soft; break; case FloatABI::SoftFP: targetOptions.UseSoftFloat = false; targetOptions.FloatABIType = llvm::FloatABI::Soft; break; case FloatABI::Hard: targetOptions.UseSoftFloat = false; targetOptions.FloatABIType = llvm::FloatABI::Hard; break; } // Right now, we only support linker-level dead code elimination on Linux // using the GNU toolchain (based on ld's --gc-sections flag). The Apple ld // on OS X supports a similar flag (-dead_strip) that doesn't require // emitting the symbols into different sections. The MinGW ld doesn't seem // to support --gc-sections at all, and FreeBSD needs more investigation. if (!noLinkerStripDead && (triple.getOS() == llvm::Triple::Linux || triple.getOS() == llvm::Triple::Win32)) { #if LDC_LLVM_VER < 305 llvm::TargetMachine::setDataSections(true); llvm::TargetMachine::setFunctionSections(true); #else targetOptions.FunctionSections = true; targetOptions.DataSections = true; #endif } return target->createTargetMachine( triple.str(), cpu, features.getString(), targetOptions, relocModel, codeModel, codeGenOptLevel ); }
Expression *createTypeInfoArray(Scope *sc, Expression *exps[], size_t dim) { #if 1 /* * Pass a reference to the TypeInfo_Tuple corresponding to the types of the * arguments. Source compatibility is maintained by computing _arguments[] * at the start of the called function by offseting into the TypeInfo_Tuple * reference. */ Parameters *args = new Parameters; args->setDim(dim); for (size_t i = 0; i < dim; i++) { Parameter *arg = new Parameter(STCin, exps[i]->type, NULL, NULL); (*args)[i] = arg; } TypeTuple *tup = new TypeTuple(args); Expression *e = tup->getTypeInfo(sc); e = e->optimize(WANTvalue); assert(e->op == TOKsymoff); // should be SymOffExp return e; #else /* Improvements: * 1) create an array literal instead, * as it would eliminate the extra dereference of loading the * static variable. */ ArrayInitializer *ai = new ArrayInitializer(0); VarDeclaration *v; Type *t; Expression *e; OutBuffer buf; Identifier *id; char *name; // Generate identifier for _arguments[] buf.writestring("_arguments_"); for (int i = 0; i < dim; i++) { t = exps[i]->type; t->toDecoBuffer(&buf); } buf.writeByte(0); id = Lexer::idPool((char *)buf.data); Module *m = sc->module; Dsymbol *s = m->symtab->lookup(id); if (s && s->parent == m) { // Use existing one v = s->isVarDeclaration(); assert(v); } else { // Generate new one for (int i = 0; i < dim; i++) { t = exps[i]->type; e = t->getTypeInfo(sc); ai->addInit(new IntegerExp(i), new ExpInitializer(Loc(), e)); } t = Type::typeinfo->type->arrayOf(); ai->type = t; v = new VarDeclaration(0, t, id, ai); m->members->push(v); m->symtabInsert(v); sc = sc->push(); sc->linkage = LINKc; sc->stc = STCstatic | STCcomdat; ai->semantic(sc, t); v->semantic(sc); v->parent = m; sc = sc->pop(); } e = new VarExp(Loc(), v); e = e->semantic(sc); return e; #endif }
Type *argtypemerge(Type *t1, Type *t2, unsigned offset2) { //printf("argtypemerge(%s, %s, %d)\n", t1 ? t1->toChars() : "", t2 ? t2->toChars() : "", offset2); if (!t1) { assert(!t2 || offset2 == 0); return t2; } if (!t2) return t1; unsigned sz1 = t1->size(Loc()); unsigned sz2 = t2->size(Loc()); if (t1->ty != t2->ty && (t1->ty == Tfloat80 || t2->ty == Tfloat80)) return NULL; // [float,float] => [cfloat] if (t1->ty == Tfloat32 && t2->ty == Tfloat32 && offset2 == 4) return Type::tfloat64; // Merging floating and non-floating types produces the non-floating type if (t1->isfloating()) { if (!t2->isfloating()) t1 = mergeFloatToInt(t1); } else if (t2->isfloating()) t2 = mergeFloatToInt(t2); Type *t; // Pick type with larger size if (sz1 < sz2) t = t2; else t = t1; // If t2 does not lie within t1, need to increase the size of t to enclose both if (offset2 && sz1 < offset2 + sz2) { switch (offset2 + sz2) { case 2: t = Type::tint16; break; case 3: case 4: t = Type::tint32; break; case 5: case 6: case 7: case 8: t = Type::tint64; break; default: assert(0); } } return t; }
unsigned totym(Type *tx) { unsigned t; switch (tx->ty) { case Tvoid: t = TYvoid; break; case Tint8: t = TYschar; break; case Tuns8: t = TYuchar; break; case Tint16: t = TYshort; break; case Tuns16: t = TYushort; break; case Tint32: t = TYint; break; case Tuns32: t = TYuint; break; case Tint64: t = TYllong; break; case Tuns64: t = TYullong; break; case Tfloat32: t = TYfloat; break; case Tfloat64: t = TYdouble; break; case Tfloat80: t = TYldouble; break; case Timaginary32: t = TYifloat; break; case Timaginary64: t = TYidouble; break; case Timaginary80: t = TYildouble; break; case Tcomplex32: t = TYcfloat; break; case Tcomplex64: t = TYcdouble; break; case Tcomplex80: t = TYcldouble; break; case Tbool: t = TYbool; break; case Tchar: t = TYchar; break; case Twchar: t = TYwchar_t; break; #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS case Tdchar: t = TYdchar; break; #else case Tdchar: t = (global.params.symdebug == 1) ? TYdchar : TYulong; break; #endif case Taarray: t = TYaarray; break; case Tclass: case Treference: case Tpointer: t = TYnptr; break; case Tdelegate: t = TYdelegate; break; case Tarray: t = TYdarray; break; case Tsarray: t = TYstruct; break; case Tstruct: t = TYstruct; if (tx->toDsymbol(NULL)->ident == Id::__c_long_double) t = TYdouble; break; case Tenum: t = totym(tx->toBasetype()); break; case Tident: case Ttypeof: #ifdef DEBUG printf("ty = %d, '%s'\n", tx->ty, tx->toChars()); #endif error(Loc(), "forward reference of %s", tx->toChars()); t = TYint; break; case Tnull: t = TYnptr; break; case Tvector: { TypeVector *tv = (TypeVector *)tx; TypeBasic *tb = tv->elementType(); switch (tb->ty) { case Tvoid: case Tint8: t = TYschar16; break; case Tuns8: t = TYuchar16; break; case Tint16: t = TYshort8; break; case Tuns16: t = TYushort8; break; case Tint32: t = TYlong4; break; case Tuns32: t = TYulong4; break; case Tint64: t = TYllong2; break; case Tuns64: t = TYullong2; break; case Tfloat32: t = TYfloat4; break; case Tfloat64: t = TYdouble2; break; default: assert(0); break; } assert(global.params.is64bit || global.params.isOSX); break; } case Tfunction: { TypeFunction *tf = (TypeFunction *)tx; switch (tf->linkage) { case LINKwindows: if (global.params.is64bit) goto Lc; t = (tf->varargs == 1) ? TYnfunc : TYnsfunc; break; case LINKpascal: t = (tf->varargs == 1) ? TYnfunc : TYnpfunc; break; case LINKc: case LINKcpp: Lc: t = TYnfunc; #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS if (I32 && retStyle(tf) == RETstack) t = TYhfunc; #endif break; case LINKd: t = (tf->varargs == 1) ? TYnfunc : TYjfunc; break; default: printf("linkage = %d\n", tf->linkage); assert(0); } if (tf->isnothrow) t |= mTYnothrow; return t; } default: #ifdef DEBUG printf("ty = %d, '%s'\n", tx->ty, tx->toChars()); halt(); #endif assert(0); } // Add modifiers switch (tx->mod) { case 0: break; case MODconst: case MODwild: case MODwildconst: t |= mTYconst; break; case MODshared: t |= mTYshared; break; case MODshared | MODconst: case MODshared | MODwild: case MODshared | MODwildconst: t |= mTYshared | mTYconst; break; case MODimmutable: t |= mTYimmutable; break; default: assert(0); } return t; }
TypeTuple *TypeStruct::toArgTypes() { //printf("TypeStruct::toArgTypes() %s\n", toChars()); if (!sym->isPOD()) { Lmemory: //printf("\ttoArgTypes() %s => [ ]\n", toChars()); return new TypeTuple(); // pass on the stack } Type *t1 = NULL; Type *t2 = NULL; d_uns64 sz = size(Loc()); assert(sz < 0xFFFFFFFF); switch ((unsigned)sz) { case 1: t1 = Type::tint8; break; case 2: t1 = Type::tint16; break; case 4: t1 = Type::tint32; break; case 8: t1 = Type::tint64; break; case 16: t1 = NULL; // could be a TypeVector break; default: goto Lmemory; } if (global.params.is64bit && sym->fields.dim) { #if 1 unsigned sz1 = 0; unsigned sz2 = 0; t1 = NULL; for (size_t i = 0; i < sym->fields.dim; i++) { VarDeclaration *f = sym->fields[i]; //printf("f->type = %s\n", f->type->toChars()); TypeTuple *tup = f->type->toArgTypes(); if (!tup) goto Lmemory; size_t dim = tup->arguments->dim; Type *ft1 = NULL; Type *ft2 = NULL; switch (dim) { case 2: ft1 = (*tup->arguments)[0]->type; ft2 = (*tup->arguments)[1]->type; break; case 1: if (f->offset < 8) ft1 = (*tup->arguments)[0]->type; else ft2 = (*tup->arguments)[0]->type; break; default: goto Lmemory; } if (f->offset & 7) { // Misaligned fields goto Lmemory unsigned alignsz = f->type->alignsize(); if (f->offset & (alignsz - 1)) goto Lmemory; // Fields that overlap the 8byte boundary goto Lmemory unsigned fieldsz = f->type->size(Loc()); if (f->offset < 8 && (f->offset + fieldsz) > 8) goto Lmemory; } // First field in 8byte must be at start of 8byte assert(t1 || f->offset == 0); if (ft1) { t1 = argtypemerge(t1, ft1, f->offset); if (!t1) goto Lmemory; } if (ft2) { unsigned off2 = f->offset; if (ft1) off2 = 8; if (!t2 && off2 != 8) goto Lmemory; assert(t2 || off2 == 8); t2 = argtypemerge(t2, ft2, off2 - 8); if (!t2) goto Lmemory; } } if (t2) { if (t1->isfloating() && t2->isfloating()) { if (t1->ty == Tfloat64 && t2->ty == Tfloat64) ; else goto Lmemory; } else if (t1->isfloating()) goto Lmemory; else if (t2->isfloating()) goto Lmemory; else ; } #else if (sym->fields.dim == 1) { VarDeclaration *f = sym->fields[0]; //printf("f->type = %s\n", f->type->toChars()); TypeTuple *tup = f->type->toArgTypes(); if (tup) { size_t dim = tup->arguments->dim; if (dim == 1) t1 = (*tup->arguments)[0]->type; } } #endif } //printf("\ttoArgTypes() %s => [%s,%s]\n", toChars(), t1 ? t1->toChars() : "", t2 ? t2->toChars() : ""); TypeTuple *t; if (t1) { //if (t1) printf("test1: %s => %s\n", toChars(), t1->toChars()); if (t2) t = new TypeTuple(t1, t2); else t = new TypeTuple(t1); } else goto Lmemory; return t; }
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); if (type->ty == Tclass && ((TypeClass *)type)->sym != this) { TemplateInstance *ti = ((TypeClass *)type)->sym->isInstantiated(); if (ti && ti->errors) ((TypeClass *)type)->sym = this; } 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; } userAttribDecl = sc->userAttribDecl; if (sc->linkage == LINKcpp) cpp = 1; // Expand any tuples in baseclasses[] for (size_t i = 0; i < baseclasses->dim; ) { // Ungag errors when not speculative Ungag ungag = ungagSpeculative(); BaseClass *b = (*baseclasses)[i]; b->type = b->type->semantic(loc, sc); Type *tb = b->type->toBasetype(); if (tb->ty == Ttuple) { TypeTuple *tup = (TypeTuple *)tb; 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) { // Ungag errors when not speculative Ungag ungag = ungagSpeculative(); BaseClass *b = (*baseclasses)[0]; //b->type = b->type->semantic(loc, sc); Type *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 { TypeClass *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->scope) { // Try to resolve forward reference tc->sym->semantic(NULL); } if (tc->sym->symtab && tc->sym->scope == NULL) { /* Bugzilla 11034: Essentailly, class inheritance hierarchy * and instance size of each classes are orthogonal information. * Therefore, even if tc->sym->sizeof == SIZEOKnone, * we need to set baseClass field for class covariance check. */ baseClass = tc->sym; b->base = baseClass; } 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 : sc->copy(); scope->setNoFree(); if (tc->sym->scope) tc->sym->scope->module->addDeferredSemantic(tc->sym); scope->module->addDeferredSemantic(this); return; } 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; ) { // Ungag errors when not speculative Ungag ungag = ungagSpeculative(); BaseClass *b = (*baseclasses)[i]; b->type = b->type->semantic(loc, sc); Type *tb = b->type->toBasetype(); TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : 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->scope) { // Try to resolve forward reference 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 : sc->copy(); 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 (sizeok == SIZEOKnone) { // If no base class, and this is not an Object, use Object as base class if (!baseClass && ident != Id::Object && !cpp) { 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(); if (baseClass->isCPPclass()) cpp = 1; 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); if (vtblOffset()) vtbl.push(this); // leave room for classinfo as first member } protection = sc->protection; storage_class |= sc->stc; 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 = true; 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 (global.params.isWindows) 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; sc->offset = (sc->offset + alignsize - 1) & ~(alignsize - 1); // if (enclosing) // sc->offset += Target::ptrsize; // room for uplevel context pointer } else { if (cpp) sc->offset = Target::ptrsize; // allow room for __vptr else sc->offset = Target::ptrsize * 2; // allow room for __vptr and __monitor alignsize = Target::ptrsize; } sc->userAttribDecl = 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]; //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->importAll(sc); } for (size_t i = 0; i < members_dim; i++) { Dsymbol *s = (*members)[i]; // Ungag errors when not speculative Ungag ungag = ungagSpeculative(); s->semantic(sc); } // Set the offsets of the fields and determine the size of the class unsigned offset = structsize; 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++) { VarDeclaration *v = fields[i]; v->offset = 0; } fields.setDim(0); structsize = 0; alignsize = 0; // structalign = 0; sc = sc->pop(); scope = scx ? scx : sc->copy(); 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. */ searchCtor(); 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]; if (v->storage_class & STCnodefaultctor) ::error(v->loc, "field %s must be initialized in constructor", v->toChars()); } } inv = buildInv(this, sc); // Can be in base class aggNew = (NewDeclaration *)search(Loc(), Id::classNew); aggDelete = (DeleteDeclaration *)search(Loc(), Id::classDelete); // If this class has no constructor, but base class has a default // ctor, create a constructor: // this() { } if (!ctor && baseClass && baseClass->ctor) { FuncDeclaration *fd = resolveFuncCall(loc, sc, baseClass->ctor, NULL, NULL, NULL, 1); if (fd && !fd->errors) { //printf("Creating default this(){} for class %s\n", toChars()); TypeFunction *btf = (TypeFunction *)fd->type; TypeFunction *tf = new TypeFunction(NULL, NULL, 0, LINKd, fd->storage_class); tf->purity = btf->purity; tf->isnothrow = btf->isnothrow; tf->trust = btf->trust; 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; sizeok = SIZEOKdone; Module::dprogress++; dtor = buildDtor(this, sc); if (FuncDeclaration *f = hasIdentityOpAssign(this, sc)) { if (!(f->storage_class & STCdisable)) error(f->loc, "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); }
auto operator()(Tree const& t, node_idx n, Loc l = Loc()) const noexcept { return (*this)(node_location(t, n, l)); }
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); }
int executecmd(char *cmd, char *args, int useenv) { int status; size_t len; if (!global.params.quiet || global.params.verbose) { printf("%s %s\n", cmd, args); fflush(stdout); } if (global.params.is64bit) { } else { if ((len = strlen(args)) > 255) { char *q; static char envname[] = "@_CMDLINE"; envname[0] = '@'; switch (useenv) { case 0: goto L1; case 2: envname[0] = '%'; break; } q = (char *) alloca(sizeof(envname) + len + 1); sprintf(q,"%s=%s", envname + 1, args); status = putenv(q); if (status == 0) args = envname; else { L1: error(Loc(), "command line length of %d is too long",len); } } } #if _WIN32 // Normalize executable path separators, see Bugzilla 9330 for (char *p=cmd; *p; ++p) if (*p == '/') *p = '\\'; #endif status = executearg0(cmd,args); #if _WIN32 if (status == -1) // spawnlp returns intptr_t in some systems, not int status = spawnlp(0,cmd,cmd,args,NULL); #endif // if (global.params.verbose) // printf("\n"); if (status) { if (status == -1) printf("Can't run '%s', check PATH\n", cmd); else printf("--- errorlevel %d\n", status); } return status; }