void Scope::deprecation10378(Loc loc, Dsymbol *sold, Dsymbol *snew) { // Bugzilla 15857 // // The overloadset found via the new lookup rules is either // equal or a subset of the overloadset found via the old // lookup rules, so it suffices to compare the dimension to // check for equality. OverloadSet *osold = NULL; OverloadSet *osnew = NULL; if (sold && (osold = sold->isOverloadSet()) != NULL && snew && (osnew = snew->isOverloadSet()) != NULL && osold->a.dim == osnew->a.dim) return; OutBuffer buf; buf.writestring("local import search method found "); if (osold) buf.printf("%s %s (%d overloads)", sold->kind(), sold->toPrettyChars(), (int)osold->a.dim); else if (sold) buf.printf("%s %s", sold->kind(), sold->toPrettyChars()); else buf.writestring("nothing"); buf.writestring(" instead of "); if (osnew) buf.printf("%s %s (%d overloads)", snew->kind(), snew->toPrettyChars(), (int)osnew->a.dim); else if (snew) buf.printf("%s %s", snew->kind(), snew->toPrettyChars()); else buf.writestring("nothing"); deprecation(loc, "%s", buf.peekString()); }
char *Loc::toChars() { OutBuffer buf; if (filename) { buf.printf("%s", filename); } if (linnum) buf.printf("(%d)", linnum); buf.writeByte(0); return (char *)buf.extractData(); }
void visit(TemplateInstance *ti) { OutBuffer buf; #if 0 printf("TemplateInstance::mangle() %p %s", ti, ti->toChars()); if (ti->parent) printf(" parent = %s %s", ti->parent->kind(), ti->parent->toChars()); printf("\n"); #endif ti->getIdent(); const char *id = ti->ident ? ti->ident->toChars() : ti->toChars(); if (!ti->tempdecl) ti->error("is not defined"); else { Dsymbol *par = ti->isTemplateMixin() ? ti->parent : ti->tempdecl->parent; if (par) { FuncDeclaration *f = par->isFuncDeclaration(); if (f) mangleExact(f); else par->accept(this); if (result[0] == '_' && result[1] == 'D') result += 2; buf.writestring(result); } } buf.printf("%llu%s", (ulonglong)strlen(id), id); id = buf.extractString(); //printf("TemplateInstance::mangle() %s = %s\n", ti->toChars(), ti->id); result = id; }
char *TemplateInstance::mangle() { OutBuffer buf; #if 0 printf("TemplateInstance::mangle() %p %s", this, toChars()); if (parent) printf(" parent = %s %s", parent->kind(), parent->toChars()); printf("\n"); #endif char *id = ident ? ident->toChars() : toChars(); if (!tempdecl) error("is not defined"); else { Dsymbol *par = isnested || isTemplateMixin() ? parent : tempdecl->parent; if (par) { char *p = par->mangle(); if (p[0] == '_' && p[1] == 'D') p += 2; buf.writestring(p); } } buf.printf("%zu%s", strlen(id), id); id = buf.toChars(); buf.data = NULL; //printf("TemplateInstance::mangle() %s = %s\n", toChars(), id); return id; }
char *TemplateInstance::mangle() { OutBuffer buf; char *id; #if 0 printf("TemplateInstance::mangle() %s", toChars()); if (parent) printf(" parent = %s %s", parent->kind(), parent->toChars()); printf("\n"); #endif id = ident ? ident->toChars() : toChars(); if (tempdecl->parent) { char *p = tempdecl->parent->mangle(); if (p[0] == '_' && p[1] == 'D') p += 2; buf.writestring(p); } buf.printf(ZU "%s", strlen(id), id); id = buf.toChars(); buf.data = NULL; //printf("TemplateInstance::mangle() %s = %s\n", toChars(), id); return id; }
void visit(Dsymbol *s) { #if 0 printf("Dsymbol::mangle() '%s'", s->toChars()); if (s->parent) printf(" parent = %s %s", s->parent->kind(), s->parent->toChars()); printf("\n"); #endif char *id = s->ident ? s->ident->toChars() : s->toChars(); OutBuffer buf; if (s->parent) { FuncDeclaration *f = s->parent->isFuncDeclaration(); if (f) mangleExact(f); else s->parent->accept(this); if (result[0] == '_' && result[1] == 'D') result += 2; buf.writestring(result); } buf.printf("%llu%s", (ulonglong)strlen(id), id); id = buf.extractString(); //printf("Dsymbol::mangle() %s = %s\n", s->toChars(), id); result = id; }
char *Dsymbol::mangle() { OutBuffer buf; char *id; #if 0 printf("Dsymbol::mangle() '%s'", toChars()); if (parent) printf(" parent = %s %s", parent->kind(), parent->toChars()); printf("\n"); #endif id = ident ? ident->toChars() : toChars(); if (parent) { char *p = parent->mangle(); if (p[0] == '_' && p[1] == 'D') p += 2; buf.writestring(p); } buf.printf("%zu%s", strlen(id), id); id = buf.toChars(); buf.data = NULL; //printf("Dsymbol::mangle() %s = %s\n", toChars(), id); return id; }
void visit(TypeSArray *t) { if (substitute(t)) return; buf.printf("A%llu_", t->dim ? t->dim->toInteger() : 0); t->next->accept(this); store(t); }
// Helper for printing dependency information void printDepsConditional(Scope *sc, DVCondition* condition, const char* depType) { if (!global.params.moduleDeps || global.params.moduleDepsFile) return; OutBuffer *ob = global.params.moduleDeps; Module* imod = sc ? (sc->instantiatingModule ? sc->instantiatingModule : sc->module) : condition->mod; if (!imod) return; ob->writestring(depType); ob->writestring(imod->toPrettyChars()); ob->writestring(" ("); escapePath(ob, imod->srcfile->toChars()); ob->writestring(") : "); if (condition->ident) ob->printf("%s\n", condition->ident->toChars()); else ob->printf("%d\n", condition->level); }
char *Loc::toChars() { OutBuffer buf; if (filename) { buf.printf("%s", filename); } if (linnum) { buf.printf("(%d", linnum); if (global.params.showColumns && charnum) buf.printf(",%d", charnum); buf.writeByte(')'); } return buf.extractString(); }
Identifier *Identifier::generateId(const char *prefix, size_t i) { OutBuffer buf; buf.writestring(prefix); buf.printf("%llu", (ulonglong)i); char *id = buf.peekString(); return idPool(id); }
Identifier *Identifier::generateId(const char *prefix, size_t i) { OutBuffer buf; buf.writestring(prefix); buf.printf("%llu", (ulonglong)i); char *id = buf.toChars(); buf.data = NULL; return Lexer::idPool(id); }
Identifier *Identifier::generateId(char *prefix) { OutBuffer buf; char *id; static unsigned i; buf.writestring(prefix); buf.printf("%u", ++i); id = buf.toChars(); buf.data = NULL; return new Identifier(id, TOKidentifier); }
void visit(Type *t) { /* Make this the 'vendor extended type' when there is no * C++ analog. * u <source-name> */ if (substitute(t)) return; assert(t->deco); buf.printf("u%d%s", strlen(t->deco), t->deco); store(t); }
Type *TupleDeclaration::getType() { /* If this tuple represents a type, return that type */ //printf("TupleDeclaration::getType() %s\n", toChars()); if (isexp) return NULL; if (!tupletype) { /* It's only a type tuple if all the Object's are types */ for (size_t i = 0; i < objects->dim; i++) { Object *o = (Object *)objects->data[i]; if (o->dyncast() != DYNCAST_TYPE) { //printf("\tnot[%d], %p, %d\n", i, o, o->dyncast()); return NULL; } } /* We know it's a type tuple, so build the TypeTuple */ Parameters *args = new Parameters(); args->setDim(objects->dim); OutBuffer buf; int hasdeco = 1; for (size_t i = 0; i < objects->dim; i++) { Type *t = (Type *)objects->data[i]; //printf("type = %s\n", t->toChars()); #if 0 buf.printf("_%s_%d", ident->toChars(), i); char *name = (char *)buf.extractData(); Identifier *id = new Identifier(name, TOKidentifier); Parameter *arg = new Parameter(STCin, t, id, NULL); #else Parameter *arg = new Parameter(STCin, t, NULL, NULL); #endif args->data[i] = (void *)arg; if (!t->deco) hasdeco = 0; } tupletype = new TypeTuple(args); if (hasdeco) return tupletype->semantic(0, NULL); } return tupletype; }
void visit(TypeSArray *t) { if (!substitute(t)) store(t); if (t->isImmutable() || t->isShared()) { visit((Type *)t); } if (t->isConst()) buf.writeByte('K'); buf.printf("A%llu_", t->dim ? t->dim->toInteger() : 0); t->next->accept(this); }
void JsonOut::stringPart(const char *s) { for (; *s; s++) { utf8_t c = (utf8_t) *s; switch (c) { case '\n': buf->writestring("\\n"); break; case '\r': buf->writestring("\\r"); break; case '\t': buf->writestring("\\t"); break; case '\"': buf->writestring("\\\""); break; case '\\': buf->writestring("\\\\"); break; case '\b': buf->writestring("\\b"); break; case '\f': buf->writestring("\\f"); break; default: if (c < 0x20) buf->printf("\\u%04x", c); else // Note that UTF-8 chars pass through here just fine buf->writeByte(c); break; } } }
char *Dsymbol::mangle() { OutBuffer buf; char *id; //printf("Dsymbol::mangle() '%s'\n", toChars()); id = ident ? ident->toChars() : toChars(); if (parent) { //printf(" parent = '%s', kind = '%s'\n", parent->mangle(), parent->kind()); buf.writestring(parent->mangle()); } buf.printf("%d%s", strlen(id), id); //buf.writestring("_"); //buf.writestring(id); id = buf.toChars(); buf.data = NULL; return id; }
void visit(Dsymbol *s) { #if 0 printf("Dsymbol::mangle() '%s'", s->toChars()); if (s->parent) printf(" parent = %s %s", s->parent->kind(), s->parent->toChars()); printf("\n"); #endif OutBuffer buf; mangleParent(&buf, s); char *id = s->ident ? s->ident->toChars() : s->toChars(); buf.printf("%llu%s", (ulonglong)strlen(id), id); id = buf.extractString(); //printf("Dsymbol::mangle() %s = %s\n", s->toChars(), id); result = id; }
void Module::genhdrfile() { OutBuffer hdrbufr; hdrbufr.doindent = 1; hdrbufr.printf("// D import file generated from '%s'", srcfile->toChars()); hdrbufr.writenl(); HdrGenState hgs; memset(&hgs, 0, sizeof(hgs)); hgs.hdrgen = 1; toCBuffer(&hdrbufr, &hgs); // Transfer image to file hdrfile->setbuffer(hdrbufr.data, hdrbufr.offset); hdrbufr.data = NULL; ensurePathToNameExists(Loc(), hdrfile->toChars()); writeFile(loc, hdrfile); }
void Module::gensymfile() { OutBuffer buf; HdrGenState hgs; //printf("Module::gensymfile()\n"); buf.printf("// Sym file generated from '%s'", srcfile->toChars()); buf.writenl(); for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; s->toCBuffer(&buf, &hgs); } // Transfer image to file symfile->setbuffer(buf.data, buf.offset); buf.data = NULL; writeFile(loc, symfile); }
void Module::genhdrfile() { OutBuffer hdrbufr; hdrbufr.printf("// D import file generated from '%s'", srcfile->toChars()); hdrbufr.writenl(); HdrGenState hgs; memset(&hgs, 0, sizeof(hgs)); hgs.hdrgen = 1; toCBuffer(&hdrbufr, &hgs); // Transfer image to file hdrfile->setbuffer(hdrbufr.data, hdrbufr.offset); hdrbufr.data = NULL; char *pt = FileName::path(hdrfile->toChars()); if (*pt) FileName::ensurePathExists(pt); mem.free(pt); hdrfile->writev(); }
void visit(TemplateInstance *ti) { #if 0 printf("TemplateInstance::mangle() %p %s", ti, ti->toChars()); if (ti->parent) printf(" parent = %s %s", ti->parent->kind(), ti->parent->toChars()); printf("\n"); #endif OutBuffer buf; if (!ti->tempdecl) ti->error("is not defined"); else mangleParent(&buf, ti); ti->getIdent(); const char *id = ti->ident ? ti->ident->toChars() : ti->toChars(); buf.printf("%llu%s", (ulonglong)strlen(id), id); id = buf.extractString(); //printf("TemplateInstance::mangle() %s = %s\n", ti->toChars(), ti->id); result = id; }
void obj_write_deferred(Library *library) { for (int i = 0; i < obj_symbols_towrite.dim; i++) { Dsymbol *s = (Dsymbol *)obj_symbols_towrite.data[i]; Module *m = s->getModule(); char *mname; if (m) { mname = m->srcfile->toChars(); lastmname = mname; } else { //mname = s->ident->toChars(); mname = lastmname; assert(mname); } obj_start(mname); static int count; count++; // sequence for generating names /* Create a module that's a doppelganger of m, with just * enough to be able to create the moduleinfo. */ OutBuffer idbuf; idbuf.printf("%s.%d", m ? m->ident->toChars() : mname, count); char *idstr = idbuf.toChars(); idbuf.data = NULL; Identifier *id = new Identifier(idstr, TOKidentifier); Module *md = new Module(mname, id, 0, 0); md->members = new Array(); md->members->push(s); // its only 'member' is s if (m) { md->doppelganger = 1; // identify this module as doppelganger md->md = m->md; md->aimports.push(m); // it only 'imports' m md->massert = m->massert; md->marray = m->marray; } md->genobjfile(0); /* Set object file name to be source name with sequence number, * as mangled symbol names get way too long. */ char *fname = FileName::removeExt(mname); OutBuffer namebuf; unsigned hash = 0; for (char *p = s->toChars(); *p; p++) hash += *p; namebuf.printf("%s_%x_%x.%s", fname, count, hash, global.obj_ext); namebuf.writeByte(0); mem.free(fname); fname = (char *)namebuf.extractData(); //printf("writing '%s'\n", fname); File *objfile = new File(fname); obj_end(library, objfile); } obj_symbols_towrite.dim = 0; }
void TryCatchScope::emitCatchBodies(IRState &irs, llvm::Value *ehPtrSlot) { assert(catchBlocks.empty()); auto &PGO = irs.funcGen().pgo; const auto entryCount = PGO.setCurrentStmt(stmt); struct CBPrototype { Type *t; llvm::BasicBlock *catchBB; uint64_t catchCount; uint64_t uncaughtCount; }; llvm::SmallVector<CBPrototype, 8> cbPrototypes; cbPrototypes.reserve(stmt->catches->dim); for (auto c : *stmt->catches) { auto catchBB = irs.insertBBBefore(endbb, llvm::Twine("catch.") + c->type->toChars()); irs.scope() = IRScope(catchBB); irs.DBuilder.EmitBlockStart(c->loc); PGO.emitCounterIncrement(c); bool isCPPclass = false; if (auto lp = c->langPlugin()) // CALYPSO lp->codegen()->toBeginCatch(irs, c); else { const auto cd = c->type->toBasetype()->isClassHandle(); isCPPclass = cd->isCPPclass(); const auto enterCatchFn = getRuntimeFunction( Loc(), irs.module, isCPPclass ? "__cxa_begin_catch" : "_d_eh_enter_catch"); const auto ptr = DtoLoad(ehPtrSlot); const auto throwableObj = irs.ir->CreateCall(enterCatchFn, ptr); // For catches that use the Throwable object, create storage for it. // We will set it in the code that branches from the landing pads // (there might be more than one) to catchBB. if (c->var) { // This will alloca if we haven't already and take care of nested refs // if there are any. DtoDeclarationExp(c->var); // Copy the exception reference over from the _d_eh_enter_catch return // value. DtoStore(DtoBitCast(throwableObj, DtoType(c->var->type)), getIrLocal(c->var)->value); } } // Emit handler, if there is one. The handler is zero, for instance, // when building 'catch { debug foo(); }' in non-debug mode. if (isCPPclass) { // from DMD: /* C++ catches need to end with call to __cxa_end_catch(). * Create: * try { handler } finally { __cxa_end_catch(); } * Note that this is worst case code because it always sets up an * exception handler. At some point should try to do better. */ FuncDeclaration *fdend = FuncDeclaration::genCfunc(nullptr, Type::tvoid, "__cxa_end_catch"); Expression *efunc = VarExp::create(Loc(), fdend); Expression *ecall = CallExp::create(Loc(), efunc); ecall->type = Type::tvoid; Statement *call = ExpStatement::create(Loc(), ecall); Statement *stmt = c->handler ? TryFinallyStatement::create(Loc(), c->handler, call) : call; Statement_toIR(stmt, &irs); } else { if (c->handler) Statement_toIR(c->handler, &irs); } if (!irs.scopereturned()) { // CALYPSO FIXME: _cxa_end_catch won't be called if it has already returned if (auto lp = c->langPlugin()) lp->codegen()->toEndCatch(irs, c); irs.ir->CreateBr(endbb); } irs.DBuilder.EmitBlockEnd(); // PGO information, currently unused auto catchCount = PGO.getRegionCount(c); // uncaughtCount is handled in a separate pass below cbPrototypes.push_back({c->type->toBasetype(), catchBB, catchCount, 0}); // CALYPSO } // Total number of uncaught exceptions is equal to the execution count at // the start of the try block minus the one after the continuation. // uncaughtCount keeps track of the exception type mismatch count while // iterating through the catch block prototypes in reversed order. auto uncaughtCount = entryCount - PGO.getRegionCount(stmt); for (auto it = cbPrototypes.rbegin(), end = cbPrototypes.rend(); it != end; ++it) { it->uncaughtCount = uncaughtCount; // Add this catch block's match count to the uncaughtCount, because these // failed to match the remaining (lexically preceding) catch blocks. uncaughtCount += it->catchCount; } catchBlocks.reserve(stmt->catches->dim); auto c_it = stmt->catches->begin(); // CALYPSO for (const auto &p : cbPrototypes) { auto branchWeights = PGO.createProfileWeights(p.catchCount, p.uncaughtCount); LLGlobalVariable *ci; if (auto lp = (*c_it)->langPlugin()) // CALYPSO ci = lp->codegen()->toCatchScopeType(irs, p.t); else { ClassDeclaration *cd = p.t->isClassHandle(); DtoResolveClass(cd); if (cd->isCPPclass()) { const char *name = Target::cppTypeInfoMangle(cd); auto cpp_ti = getOrCreateGlobal( cd->loc, irs.module, getVoidPtrType(), /*isConstant=*/true, LLGlobalValue::ExternalLinkage, /*init=*/nullptr, name); // Wrap std::type_info pointers inside a __cpp_type_info_ptr class instance so that // the personality routine may differentiate C++ catch clauses from D ones. OutBuffer mangleBuf; mangleBuf.writestring("_D"); mangleToBuffer(cd, &mangleBuf); mangleBuf.printf("%d%s", 18, "_cpp_type_info_ptr"); const auto wrapperMangle = getIRMangledVarName(mangleBuf.peekString(), LINKd); RTTIBuilder b(ClassDeclaration::cpp_type_info_ptr); b.push(cpp_ti); auto wrapperType = llvm::cast<llvm::StructType>( static_cast<IrTypeClass*>(ClassDeclaration::cpp_type_info_ptr->type->ctype)->getMemoryLLType()); auto wrapperInit = b.get_constant(wrapperType); ci = getOrCreateGlobal( cd->loc, irs.module, wrapperType, /*isConstant=*/true, LLGlobalValue::LinkOnceODRLinkage, wrapperInit, wrapperMangle); } else { ci = getIrAggr(cd)->getClassInfoSymbol(); } } catchBlocks.push_back({ci, p.catchBB, branchWeights}); c_it++; } }
void obj_write_deferred(Library *library) { for (size_t i = 0; i < obj_symbols_towrite.dim; i++) { Dsymbol *s = obj_symbols_towrite[i]; Module *m = s->getModule(); char *mname; if (m) { mname = m->srcfile->toChars(); lastmname = mname; } else { //mname = s->ident->toChars(); mname = lastmname; assert(mname); } obj_start(mname); static int count; count++; // sequence for generating names /* Create a module that's a doppelganger of m, with just * enough to be able to create the moduleinfo. */ OutBuffer idbuf; idbuf.printf("%s.%d", m ? m->ident->toChars() : mname, count); char *idstr = idbuf.peekString(); if (!m) { // it doesn't make sense to make up a module if we don't know where to put the symbol // so output it into it's own object file without ModuleInfo objmod->initfile(idstr, NULL, mname); toObjFile(s, false); objmod->termfile(); } else { idbuf.data = NULL; Identifier *id = Identifier::create(idstr, TOKidentifier); Module *md = Module::create(mname, id, 0, 0); md->members = Dsymbols_create(); md->members->push(s); // its only 'member' is s md->doppelganger = 1; // identify this module as doppelganger md->md = m->md; md->aimports.push(m); // it only 'imports' m md->massert = m->massert; md->munittest = m->munittest; md->marray = m->marray; genObjFile(md, false); } /* Set object file name to be source name with sequence number, * as mangled symbol names get way too long. */ const char *fname = FileName::removeExt(mname); OutBuffer namebuf; unsigned hash = 0; for (char *p = s->toChars(); *p; p++) hash += *p; namebuf.printf("%s_%x_%x.%s", fname, count, hash, global.obj_ext); FileName::free((char *)fname); fname = namebuf.extractString(); //printf("writing '%s'\n", fname); File *objfile = File::create(fname); obj_end(library, objfile); } obj_symbols_towrite.dim = 0; }
void Import::semantic(Scope *sc) { //printf("Import::semantic('%s')\n", toChars()); // Load if not already done so if (!mod) { load(sc); if (mod) mod->importAll(0); } if (mod) { #if 0 if (mod->loc.linnum != 0) { /* If the line number is not 0, then this is not * a 'root' module, i.e. it was not specified on the command line. */ mod->importedFrom = sc->module->importedFrom; assert(mod->importedFrom); } #endif // Modules need a list of each imported module //printf("%s imports %s\n", sc->module->toChars(), mod->toChars()); sc->module->aimports.push(mod); if (!isstatic && !aliasId && !names.dim) { if (sc->explicitProtection) protection = sc->protection; for (Scope *scd = sc; scd; scd = scd->enclosing) { if (scd->scopesym) { scd->scopesym->importScope(mod, protection); break; } } } mod->semantic(); if (mod->needmoduleinfo) { //printf("module4 %s because of %s\n", sc->module->toChars(), mod->toChars()); sc->module->needmoduleinfo = 1; } sc = sc->push(mod); /* BUG: Protection checks can't be enabled yet. The issue is * that Dsymbol::search errors before overload resolution. */ #if 0 sc->protection = protection; #else sc->protection = PROTpublic; #endif for (size_t i = 0; i < aliasdecls.dim; i++) { Dsymbol *s = aliasdecls[i]; //printf("\tImport alias semantic('%s')\n", s->toChars()); if (mod->search(loc, names[i], 0)) s->semantic(sc); else { s = mod->search_correct(names[i]); if (s) mod->error(loc, "import '%s' not found, did you mean '%s %s'?", names[i]->toChars(), s->kind(), s->toChars()); else mod->error(loc, "import '%s' not found", names[i]->toChars()); } } sc = sc->pop(); } if (global.params.moduleDeps != NULL && // object self-imports itself, so skip that (Bugzilla 7547) !(id == Id::object && sc->module->ident == Id::object)) { /* The grammar of the file is: * ImportDeclaration * ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> " * ModuleAliasIdentifier ] "\n" * * BasicImportDeclaration * ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection * " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")" * * FilePath * - any string with '(', ')' and '\' escaped with the '\' character */ OutBuffer *ob = global.params.moduleDeps; ob->writestring(sc->module->toPrettyChars()); ob->writestring(" ("); escapePath(ob, sc->module->srcfile->toChars()); ob->writestring(") : "); // use protection instead of sc->protection because it couldn't be // resolved yet, see the comment above ProtDeclaration::protectionToCBuffer(ob, protection); if (isstatic) StorageClassDeclaration::stcToCBuffer(ob, STCstatic); ob->writestring(": "); if (packages) { for (size_t i = 0; i < packages->dim; i++) { Identifier *pid = (*packages)[i]; ob->printf("%s.", pid->toChars()); } } ob->writestring(id->toChars()); ob->writestring(" ("); if (mod) escapePath(ob, mod->srcfile->toChars()); else ob->writestring("???"); ob->writebyte(')'); for (size_t i = 0; i < names.dim; i++) { if (i == 0) ob->writebyte(':'); else ob->writebyte(','); Identifier *name = names[i]; Identifier *alias = aliases[i]; if (!alias) { ob->printf("%s", name->toChars()); alias = name; } else ob->printf("%s=%s", alias->toChars(), name->toChars()); } if (aliasId) ob->printf(" -> %s", aliasId->toChars()); ob->writenl(); } //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg); }
void Import::semantic(Scope *sc) { //printf("Import::semantic('%s')\n", toChars()); // Load if not already done so if (!mod) { load(sc); mod->importAll(0); } if (mod) { #if 0 if (mod->loc.linnum != 0) { /* If the line number is not 0, then this is not * a 'root' module, i.e. it was not specified on the command line. */ mod->importedFrom = sc->module->importedFrom; assert(mod->importedFrom); } #endif // Modules need a list of each imported module //printf("%s imports %s\n", sc->module->toChars(), mod->toChars()); sc->module->aimports.push(mod); if (!isstatic && !aliasId && !names.dim) { /* Default to private importing */ enum PROT prot = sc->protection; if (!sc->explicitProtection) prot = PROTprivate; sc->scopesym->importScope(mod, prot); } mod->semantic(); if (mod->needmoduleinfo) sc->module->needmoduleinfo = 1; sc = sc->push(mod); for (size_t i = 0; i < aliasdecls.dim; i++) { Dsymbol *s = (Dsymbol *)aliasdecls.data[i]; //printf("\tImport alias semantic('%s')\n", s->toChars()); if (!mod->search(loc, (Identifier *)names.data[i], 0)) error("%s not found", ((Identifier *)names.data[i])->toChars()); s->semantic(sc); } sc = sc->pop(); } if (global.params.moduleDeps != NULL) { /* The grammar of the file is: * ImportDeclaration * ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> " * ModuleAliasIdentifier ] "\n" * * BasicImportDeclaration * ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection * " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")" * * FilePath * - any string with '(', ')' and '\' escaped with the '\' character */ OutBuffer *ob = global.params.moduleDeps; ob->writestring(sc->module->toPrettyChars()); ob->writestring(" ("); escapePath(ob, sc->module->srcfile->toChars()); ob->writestring(") : "); ProtDeclaration::protectionToCBuffer(ob, sc->protection); if (isstatic) StorageClassDeclaration::stcToCBuffer(ob, STCstatic); ob->writestring(": "); if (packages) { for (size_t i = 0; i < packages->dim; i++) { Identifier *pid = (Identifier *)packages->data[i]; ob->printf("%s.", pid->toChars()); } } ob->writestring(id->toChars()); ob->writestring(" ("); if (mod) escapePath(ob, mod->srcfile->toChars()); else ob->writestring("???"); ob->writebyte(')'); for (size_t i = 0; i < names.dim; i++) { if (i == 0) ob->writebyte(':'); else ob->writebyte(','); Identifier *name = (Identifier *)names.data[i]; Identifier *alias = (Identifier *)aliases.data[i]; if (!alias) { ob->printf("%s", name->toChars()); alias = name; } else ob->printf("%s=%s", alias->toChars(), name->toChars()); } if (aliasId) ob->printf(" -> %s", aliasId->toChars()); ob->writenl(); } //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg); }
llvm::GlobalVariable * IrAggr::getInterfaceVtbl(BaseClass * b, bool new_instance, size_t interfaces_index) { ClassGlobalMap::iterator it = interfaceVtblMap.find(b->base); if (it != interfaceVtblMap.end()) return it->second; IF_LOG Logger::println("Building vtbl for implementation of interface %s in class %s", b->base->toPrettyChars(), aggrdecl->toPrettyChars()); LOG_SCOPE; ClassDeclaration* cd = aggrdecl->isClassDeclaration(); assert(cd && "not a class aggregate"); FuncDeclarations vtbl_array; b->fillVtbl(cd, &vtbl_array, new_instance); std::vector<llvm::Constant*> constants; constants.reserve(vtbl_array.dim); if (!b->base->isCPPinterface()) { // skip interface info for CPP interfaces // start with the interface info VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3); // index into the interfaces array llvm::Constant* idxs[2] = { DtoConstSize_t(0), DtoConstSize_t(interfaces_index) }; llvm::Constant* c = llvm::ConstantExpr::getGetElementPtr( getInterfaceArraySymbol(), idxs, true); constants.push_back(c); } // add virtual function pointers size_t n = vtbl_array.dim; for (size_t i = b->base->vtblOffset(); i < n; i++) { Dsymbol* dsym = static_cast<Dsymbol*>(vtbl_array.data[i]); if (dsym == NULL) { // FIXME // why is this null? // happens for mini/s.d constants.push_back(getNullValue(getVoidPtrType())); continue; } FuncDeclaration* fd = dsym->isFuncDeclaration(); assert(fd && "vtbl entry not a function"); assert((!fd->isAbstract() || fd->fbody) && "null symbol in interface implementation vtable"); fd->codegen(Type::sir); assert(fd->ir.irFunc && "invalid vtbl function"); LLFunction *fn = fd->ir.irFunc->func; // If the base is a cpp interface, 'this' parameter is a pointer to // the interface not the underlying object as expected. Instead of // the function, we place into the vtable a small wrapper, called thunk, // that casts 'this' to the object and then pass it to the real function. if (b->base->isCPPinterface()) { TypeFunction *f = (TypeFunction*)fd->type->toBasetype(); assert(f->fty.arg_this); // create the thunk function OutBuffer name; name.writestring("Th"); name.printf("%i", b->offset); name.writestring(fd->mangle()); LLFunction *thunk = LLFunction::Create(isaFunction(fn->getType()->getContainedType(0)), DtoLinkage(fd), name.toChars(), gIR->module); // create entry and end blocks llvm::BasicBlock* beginbb = llvm::BasicBlock::Create(gIR->context(), "entry", thunk); llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "endentry", thunk); gIR->scopes.push_back(IRScope(beginbb, endbb)); // copy the function parameters, so later we can pass them to the real function std::vector<LLValue*> args; llvm::Function::arg_iterator iarg = thunk->arg_begin(); for (; iarg != thunk->arg_end(); ++iarg) args.push_back(iarg); // cast 'this' to Object LLValue* &thisArg = args[(f->fty.arg_sret == 0) ? 0 : 1]; LLType* thisType = thisArg->getType(); thisArg = DtoBitCast(thisArg, getVoidPtrType()); thisArg = DtoGEP1(thisArg, DtoConstInt(-b->offset)); thisArg = DtoBitCast(thisArg, thisType); // call the real vtbl function. LLValue *retVal = gIR->ir->CreateCall(fn, args); // return from the thunk if (thunk->getReturnType() == LLType::getVoidTy(gIR->context())) llvm::ReturnInst::Create(gIR->context(), beginbb); else llvm::ReturnInst::Create(gIR->context(), retVal, beginbb); // clean up gIR->scopes.pop_back(); thunk->getBasicBlockList().pop_back(); fn = thunk; } constants.push_back(fn); } // build the vtbl constant llvm::Constant* vtbl_constant = LLConstantStruct::getAnon(gIR->context(), constants, false); // create the global variable to hold it llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); std::string mangle("_D"); mangle.append(cd->mangle()); mangle.append("11__interface"); mangle.append(b->base->mangle()); mangle.append("6__vtblZ"); llvm::GlobalVariable* GV = getOrCreateGlobal(cd->loc, *gIR->module, vtbl_constant->getType(), true, _linkage, vtbl_constant, mangle ); // insert into the vtbl map interfaceVtblMap.insert(std::make_pair(b->base, GV)); return GV; }
void VarDeclaration::semantic(Scope *sc) { #if 0 printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars()); printf(" type = %s\n", type ? type->toChars() : "null"); printf(" stc = x%x\n", sc->stc); printf(" storage_class = x%x\n", storage_class); printf("linkage = %d\n", sc->linkage); //if (strcmp(toChars(), "mul") == 0) halt(); #endif storage_class |= sc->stc; if (storage_class & STCextern && init) error("extern symbols cannot have initializers"); AggregateDeclaration *ad = isThis(); if (ad) storage_class |= ad->storage_class & STC_TYPECTOR; /* If auto type inference, do the inference */ int inferred = 0; if (!type) { inuse++; type = init->inferType(sc); inuse--; inferred = 1; /* This is a kludge to support the existing syntax for RAII * declarations. */ storage_class &= ~STCauto; originalType = type; } else { if (!originalType) originalType = type; type = type->semantic(loc, sc); } //printf(" semantic type = %s\n", type ? type->toChars() : "null"); type->checkDeprecated(loc, sc); linkage = sc->linkage; this->parent = sc->parent; //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars()); protection = sc->protection; //printf("sc->stc = %x\n", sc->stc); //printf("storage_class = x%x\n", storage_class); #if DMDV2 if (storage_class & STCgshared && global.params.safe && !sc->module->safe) { error("__gshared not allowed in safe mode; use shared"); } #endif Dsymbol *parent = toParent(); FuncDeclaration *fd = parent->isFuncDeclaration(); Type *tb = type->toBasetype(); if (tb->ty == Tvoid && !(storage_class & STClazy)) { error("voids have no value"); type = Type::terror; tb = type; } if (tb->ty == Tfunction) { error("cannot be declared to be a function"); type = Type::terror; tb = type; } if (tb->ty == Tstruct) { TypeStruct *ts = (TypeStruct *)tb; if (!ts->sym->members) { error("no definition of struct %s", ts->toChars()); } } if ((storage_class & STCauto) && !inferred) error("storage class 'auto' has no effect if type is not inferred, did you mean 'scope'?"); if (tb->ty == Ttuple) { /* Instead, declare variables for each of the tuple elements * and add those. */ TypeTuple *tt = (TypeTuple *)tb; size_t nelems = Parameter::dim(tt->arguments); Objects *exps = new Objects(); exps->setDim(nelems); Expression *ie = init ? init->toExpression() : NULL; for (size_t i = 0; i < nelems; i++) { Parameter *arg = Parameter::getNth(tt->arguments, i); OutBuffer buf; buf.printf("_%s_field_%zu", ident->toChars(), i); buf.writeByte(0); const char *name = (const char *)buf.extractData(); Identifier *id = Lexer::idPool(name); Expression *einit = ie; if (ie && ie->op == TOKtuple) { einit = (Expression *)((TupleExp *)ie)->exps->data[i]; } Initializer *ti = init; if (einit) { ti = new ExpInitializer(einit->loc, einit); } VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti); //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars()); v->semantic(sc); #if !IN_LLVM // removed for LDC since TupleDeclaration::toObj already creates the fields; // adding them to the scope again leads to duplicates if (sc->scopesym) { //printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars()); if (sc->scopesym->members) sc->scopesym->members->push(v); } #endif Expression *e = new DsymbolExp(loc, v); exps->data[i] = e; } TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps); v2->isexp = 1; aliassym = v2; return; } if (storage_class & STCconst && !init && !fd) // Initialize by constructor only storage_class = (storage_class & ~STCconst) | STCctorinit; if (isConst()) { } else if (isStatic()) { } else if (isSynchronized()) { error("variable %s cannot be synchronized", toChars()); } else if (isOverride()) { error("override cannot be applied to variable"); } else if (isAbstract()) { error("abstract cannot be applied to variable"); } else if (storage_class & STCtemplateparameter) { } else if (storage_class & STCctfe) { } else { AggregateDeclaration *aad = sc->anonAgg; if (!aad) aad = parent->isAggregateDeclaration(); if (aad) { #if DMDV2 assert(!(storage_class & (STCextern | STCstatic | STCtls | STCgshared))); if (storage_class & (STCconst | STCimmutable) && init) { if (!type->toBasetype()->isTypeBasic()) storage_class |= STCstatic; } else #endif aad->addField(sc, this); } InterfaceDeclaration *id = parent->isInterfaceDeclaration(); if (id) { error("field not allowed in interface"); } /* Templates cannot add fields to aggregates */ TemplateInstance *ti = parent->isTemplateInstance(); if (ti) { // Take care of nested templates while (1) { TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); if (!ti2) break; ti = ti2; } // If it's a member template AggregateDeclaration *ad = ti->tempdecl->isMember(); if (ad && storage_class != STCundefined) { error("cannot use template to add field to aggregate '%s'", ad->toChars()); } } } #if DMDV2 if ((storage_class & (STCref | STCparameter | STCforeach)) == STCref && ident != Id::This) { error("only parameters or foreach declarations can be ref"); } #endif if (type->isscope() && !noscope) { if (storage_class & (STCfield | STCout | STCref | STCstatic) || !fd) { error("globals, statics, fields, ref and out parameters cannot be auto"); } if (!(storage_class & STCscope)) { if (!(storage_class & STCparameter) && ident != Id::withSym) error("reference to scope class must be scope"); } } enum TOK op = TOKconstruct; if (!init && !sc->inunion && !isStatic() && !isConst() && fd && !(storage_class & (STCfield | STCin | STCforeach)) && type->size() != 0) { // Provide a default initializer //printf("Providing default initializer for '%s'\n", toChars()); if (type->ty == Tstruct && ((TypeStruct *)type)->sym->zeroInit == 1) { /* If a struct is all zeros, as a special case * set it's initializer to the integer 0. * In AssignExp::toElem(), we check for this and issue * a memset() to initialize the struct. * Must do same check in interpreter. */ Expression *e = new IntegerExp(loc, 0, Type::tint32); Expression *e1; e1 = new VarExp(loc, this); e = new AssignExp(loc, e1, e); e->op = TOKconstruct; e->type = e1->type; // don't type check this, it would fail init = new ExpInitializer(loc, e); return; } else if (type->ty == Ttypedef) { TypeTypedef *td = (TypeTypedef *)type; if (td->sym->init) { init = td->sym->init; ExpInitializer *ie = init->isExpInitializer(); if (ie) // Make copy so we can modify it init = new ExpInitializer(ie->loc, ie->exp); } else init = getExpInitializer(); } else { init = getExpInitializer(); } // Default initializer is always a blit op = TOKblit; } if (init) { sc = sc->push(); sc->stc &= ~(STC_TYPECTOR | STCpure | STCnothrow | STCref); ArrayInitializer *ai = init->isArrayInitializer(); if (ai && tb->ty == Taarray) { init = ai->toAssocArrayInitializer(); } StructInitializer *si = init->isStructInitializer(); ExpInitializer *ei = init->isExpInitializer(); // See if initializer is a NewExp that can be allocated on the stack if (ei && isScope() && ei->exp->op == TOKnew) { NewExp *ne = (NewExp *)ei->exp; if (!(ne->newargs && ne->newargs->dim)) { ne->onstack = 1; onstack = 1; if (type->isBaseOf(ne->newtype->semantic(loc, sc), NULL)) onstack = 2; } } // If inside function, there is no semantic3() call if (sc->func) { // If local variable, use AssignExp to handle all the various // possibilities. if (fd && !isStatic() && !isConst() && !init->isVoidInitializer()) { //printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars()); if (!ei) { Expression *e = init->toExpression(); if (!e) { init = init->semantic(sc, type); e = init->toExpression(); if (!e) { error("is not a static and cannot have static initializer"); return; } } ei = new ExpInitializer(init->loc, e); init = ei; } Expression *e1 = new VarExp(loc, this); Type *t = type->toBasetype(); if (t->ty == Tsarray && !(storage_class & (STCref | STCout))) { ei->exp = ei->exp->semantic(sc); if (!ei->exp->implicitConvTo(type)) { int dim = ((TypeSArray *)t)->dim->toInteger(); // If multidimensional static array, treat as one large array while (1) { t = t->nextOf()->toBasetype(); if (t->ty != Tsarray) break; dim *= ((TypeSArray *)t)->dim->toInteger(); e1->type = new TypeSArray(t->nextOf(), new IntegerExp(0, dim, Type::tindex)); } } e1 = new SliceExp(loc, e1, NULL, NULL); } else if (t->ty == Tstruct) { ei->exp = ei->exp->semantic(sc); ei->exp = resolveProperties(sc, ei->exp); StructDeclaration *sd = ((TypeStruct *)t)->sym; #if DMDV2 /* Look to see if initializer is a call to the constructor */ if (sd->ctor && // there are constructors ei->exp->type->ty == Tstruct && // rvalue is the same struct ((TypeStruct *)ei->exp->type)->sym == sd && ei->exp->op == TOKstar) { /* Look for form of constructor call which is: * *__ctmp.ctor(arguments...) */ PtrExp *pe = (PtrExp *)ei->exp; if (pe->e1->op == TOKcall) { CallExp *ce = (CallExp *)pe->e1; if (ce->e1->op == TOKdotvar) { DotVarExp *dve = (DotVarExp *)ce->e1; if (dve->var->isCtorDeclaration()) { /* It's a constructor call, currently constructing * a temporary __ctmp. */ /* Before calling the constructor, initialize * variable with a bit copy of the default * initializer */ Expression *e = new AssignExp(loc, new VarExp(loc, this), t->defaultInit(loc)); e->op = TOKblit; e->type = t; ei->exp = new CommaExp(loc, e, ei->exp); /* Replace __ctmp being constructed with e1 */ dve->e1 = e1; return; } } } } #endif if (!ei->exp->implicitConvTo(type)) { /* Look for opCall * See bugzilla 2702 for more discussion */ Type *ti = ei->exp->type->toBasetype(); // Don't cast away invariant or mutability in initializer if (search_function(sd, Id::call) && /* Initializing with the same type is done differently */ !(ti->ty == Tstruct && t->toDsymbol(sc) == ti->toDsymbol(sc))) { // Rewrite as e1.call(arguments) Expression * eCall = new DotIdExp(loc, e1, Id::call); ei->exp = new CallExp(loc, eCall, ei->exp); } } } ei->exp = new AssignExp(loc, e1, ei->exp); ei->exp->op = TOKconstruct; canassign++; ei->exp = ei->exp->semantic(sc); canassign--; ei->exp->optimize(WANTvalue); } else { init = init->semantic(sc, type); if (fd && isConst() && !isStatic()) { // Make it static storage_class |= STCstatic; } } } else if (isConst() || isFinal() || parent->isAggregateDeclaration()) { /* Because we may need the results of a const declaration in a * subsequent type, such as an array dimension, before semantic2() * gets ordinarily run, try to run semantic2() now. * Ignore failure. */ if (!global.errors && !inferred) { unsigned errors = global.errors; global.gag++; //printf("+gag\n"); Expression *e; Initializer *i2 = init; inuse++; if (ei) { e = ei->exp->syntaxCopy(); e = e->semantic(sc); e = e->implicitCastTo(sc, type); } else if (si || ai) { i2 = init->syntaxCopy(); i2 = i2->semantic(sc, type); } inuse--; global.gag--; //printf("-gag\n"); if (errors != global.errors) // if errors happened { if (global.gag == 0) global.errors = errors; // act as if nothing happened #if DMDV2 /* Save scope for later use, to try again */ scope = new Scope(*sc); scope->setNoFree(); #endif } else if (ei) { if (isDataseg() || (storage_class & STCmanifest)) e = e->optimize(WANTvalue | WANTinterpret); else e = e->optimize(WANTvalue); switch (e->op) { case TOKint64: case TOKfloat64: case TOKstring: case TOKarrayliteral: case TOKassocarrayliteral: case TOKstructliteral: case TOKnull: ei->exp = e; // no errors, keep result break; default: #if DMDV2 /* Save scope for later use, to try again */ scope = new Scope(*sc); scope->setNoFree(); #endif break; } } else init = i2; // no errors, keep result } } sc = sc->pop(); } }