Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident) { //printf("Module::load(ident = '%s')\n", ident->toChars()); // Build module filename by turning: // foo.bar.baz // into: // foo\bar\baz char *filename = ident->toChars(); if (packages && packages->dim) { OutBuffer buf; for (size_t i = 0; i < packages->dim; i++) { Identifier *pid = (*packages)[i]; buf.writestring(pid->toChars()); #if _WIN32 buf.writeByte('\\'); #else buf.writeByte('/'); #endif } buf.writestring(filename); buf.writeByte(0); filename = (char *)buf.extractData(); } Module *m = new Module(filename, ident, 0, 0); m->loc = loc; /* Look for the source file */ const char *result = lookForSourceFile(filename); if (result) m->srcfile = new File(result); if (!m->read(loc)) return NULL; if (global.params.verbose) { fprintf(global.stdmsg, "import "); if (packages) { for (size_t i = 0; i < packages->dim; i++) { Identifier *pid = (*packages)[i]; fprintf(global.stdmsg, "%s.", pid->toChars()); } } fprintf(global.stdmsg, "%s\t(%s)\n", ident->toChars(), m->srcfile->toChars()); } m->parse(); Target::loadModule(m); return m; }
Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, RootObject *id) { //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); Dsymbol *s = toAlias(); Dsymbol *sm; switch (id->dyncast()) { case DYNCAST_IDENTIFIER: sm = s->search(loc, (Identifier *)id, 0); break; case DYNCAST_DSYMBOL: { // It's a template instance //printf("\ttemplate instance id\n"); Dsymbol *st = (Dsymbol *)id; TemplateInstance *ti = st->isTemplateInstance(); Identifier *id = ti->name; sm = s->search(loc, id, 0); if (!sm) { sm = s->search_correct(id); if (sm) error("template identifier '%s' is not a member of '%s %s', did you mean '%s %s'?", id->toChars(), s->kind(), s->toChars(), sm->kind(), sm->toChars()); else error("template identifier '%s' is not a member of '%s %s'", id->toChars(), s->kind(), s->toChars()); return NULL; } sm = sm->toAlias(); TemplateDeclaration *td = sm->isTemplateDeclaration(); if (!td) { error("%s is not a template, it is a %s", id->toChars(), sm->kind()); return NULL; } ti->tempdecl = td; if (!ti->semanticRun) ti->semantic(sc); sm = ti->toAlias(); break; } default: assert(0); } return sm; }
dt_t* ModuleEmitter::createTls(Field& f) { block& tls = getTlsBlock(f.getDecl().loc); Identifier* id = Identifier::generateId("$data_", tls.size()); dt_t* dt = new TlsData(f, id->toChars()); tls.add(*dt); return dt; }
Dsymbol *DsymbolTable::update(Dsymbol *s) { StringValue *sv; Identifier *ident; ident = s->ident; sv = tab->update(ident->toChars(), ident->len); sv->ptrvalue = s; return s; }
void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { if (hgs->hdrgen && id == Id::object) return; // object is imported by default if (isstatic) buf->writestring("static "); buf->writestring("import "); if (aliasId) { buf->printf("%s = ", aliasId->toChars()); } if (packages && packages->dim) { for (size_t i = 0; i < packages->dim; i++) { Identifier *pid = (Identifier *)packages->data[i]; buf->printf("%s.", pid->toChars()); } } buf->printf("%s", id->toChars()); if (names.dim > 0) { buf->writebyte(':'); for (size_t i = 0; i < names.dim; i++) { if (i > 0) { buf->writebyte(','); } Identifier *name = (Identifier *)names.data[i]; Identifier *alias = (Identifier *)aliases.data[i]; if (!alias) { buf->printf("%s", name->toChars()); alias = name; } else { buf->printf("%s=%s", alias->toChars(), name->toChars()); } } } buf->writebyte(';'); buf->writenl(); }
void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { if (hgs->hdrgen && id == Id::object) return; // object is imported by default if (isstatic) buf->writestring("static "); buf->writestring("import "); if (aliasId) { buf->printf("%s = ", aliasId->toChars()); } if (packages && packages->dim) { for (size_t i = 0; i < packages->dim; i++) { Identifier *pid = (*packages)[i]; buf->printf("%s.", pid->toChars()); } } buf->printf("%s", id->toChars()); if (names.dim) { buf->writestring(" : "); for (size_t i = 0; i < names.dim; i++) { Identifier *name = names[i]; Identifier *alias = aliases[i]; if (alias) buf->printf("%s = %s", alias->toChars(), name->toChars()); else buf->printf("%s", name->toChars()); if (i < names.dim - 1) buf->writestring(", "); } } buf->printf(";"); buf->writenl(); }
Dsymbol *DsymbolTable::update(Dsymbol *s) { Identifier *ident = s->ident; #if STRINGTABLE StringValue *sv = tab->update(ident->toChars(), ident->len); sv->ptrvalue = s; return s; #else Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); *ps = s; return s; #endif }
Dsymbol *DsymbolTable::insert(Dsymbol *s) { StringValue *sv; Identifier *ident; //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars()); ident = s->ident; #ifdef DEBUG assert(ident); assert(tab); #endif sv = tab->insert(ident->toChars(), ident->len); if (!sv) return NULL; // already in table sv->ptrvalue = s; return s; }
char *ModuleDeclaration::toChars() { OutBuffer buf; if (packages && packages->dim) { for (size_t i = 0; i < packages->dim; i++) { Identifier *pid = (*packages)[i]; buf.writestring(pid->toChars()); buf.writeByte('.'); } } buf.writestring(id->toChars()); return buf.extractString(); }
char *ModuleDeclaration::toChars() { OutBuffer buf; int i; if (packages && packages->dim) { for (i = 0; i < packages->dim; i++) { Identifier *pid = (Identifier *)packages->data[i]; buf.writestring(pid->toChars()); buf.writeByte('.'); } } buf.writestring(id->toChars()); buf.writeByte(0); return (char *)buf.extractData(); }
static int dg(void *ctx, size_t n, Dsymbol *sm) { if (!sm) return 1; //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars()); if (sm->ident) { if (sm->ident != Id::ctor && sm->ident != Id::dtor && sm->ident != Id::_postblit && memcmp(sm->ident->string, "__", 2) == 0) { return 0; } //printf("\t%s\n", sm->ident->toChars()); Identifiers *idents = (Identifiers *)ctx; /* Skip if already present in idents[] */ for (size_t j = 0; j < idents->dim; j++) { Identifier *id = (*idents)[j]; if (id == sm->ident) return 0; #ifdef DEBUG // Avoid using strcmp in the first place due to the performance impact in an O(N^2) loop. assert(strcmp(id->toChars(), sm->ident->toChars()) != 0); #endif } idents->push(sm->ident); } else { EnumDeclaration *ed = sm->isEnumDeclaration(); if (ed) { ScopeDsymbol::foreach(NULL, ed->members, &PushIdentsDg::dg, (Identifiers *)ctx); } } return 0; }
Import::Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId, int isstatic) : Dsymbol(NULL) { assert(id); #if 0 printf("Import::Import("); if (packages && packages->dim) { for (size_t i = 0; i < packages->dim; i++) { Identifier *id = (*packages)[i]; printf("%s.", id->toChars()); } } printf("%s)\n", id->toChars()); #endif this->loc = loc; this->packages = packages; this->id = id; this->aliasId = aliasId; this->isstatic = isstatic; this->protection = PROTprivate; // default to private this->pkg = NULL; this->mod = NULL; // Set symbol name (bracketed) if (aliasId) { // import [cstdio] = std.stdio; this->ident = aliasId; } else if (packages && packages->dim) { // import [std].stdio; this->ident = (*packages)[0]; } else { // import [foo]; this->ident = id; } }
void Module::jsonProperties(JsonOut *json) { #if 0 Dsymbol::jsonProperties(json); if (md && md->packages) { json->propertyStart("package"); json->arrayStart(); for (size_t i = 0; i < md->packages->dim; i++) { Identifier *pid = (*md->packages)[i]; json->item(pid->toChars()); } json->arrayEnd(); } json->property("prettyName", toPrettyChars()); #endif }
void StructInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { //printf("StructInitializer::toCBuffer()\n"); buf->writebyte('{'); for (size_t i = 0; i < field.dim; i++) { if (i > 0) buf->writebyte(','); Identifier *id = field[i]; if (id) { buf->writestring(id->toChars()); buf->writebyte(':'); } Initializer *iz = value[i]; if (iz) iz->toCBuffer(buf, hgs); } buf->writebyte('}'); }
Dsymbol *DsymbolTable::insert(Dsymbol *s) { //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars()); Identifier *ident = s->ident; #if STRINGTABLE #ifdef DEBUG assert(ident); assert(tab); #endif StringValue *sv = tab->insert(ident->toChars(), ident->len); if (!sv) return NULL; // already in table sv->ptrvalue = s; return s; #else Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); if (*ps) return NULL; // already in table *ps = s; return s; #endif }
void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { if (hgs->hdrgen && id == Id::object) return; // object is imported by default if (isstatic) buf->writestring("static "); buf->writestring("import "); if (aliasId) { buf->printf("%s = ", aliasId->toChars()); } if (packages && packages->dim) { for (size_t i = 0; i < packages->dim; i++) { Identifier *pid = (Identifier *)packages->data[i]; buf->printf("%s.", pid->toChars()); } } buf->printf("%s;", id->toChars()); buf->writenl(); }
/*************************************** * This works by transforming a struct initializer into * a struct literal. In the future, the two should be the * same thing. */ Expression *StructInitializer::toExpression() { Expression *e; //printf("StructInitializer::toExpression() %s\n", toChars()); if (!ad) // if fwd referenced { return NULL; } StructDeclaration *sd = ad->isStructDeclaration(); if (!sd) return NULL; Expressions *elements = new Expressions(); elements->setDim(ad->fields.dim); for (int i = 0; i < elements->dim; i++) { elements->data[i] = NULL; } unsigned fieldi = 0; for (int i = 0; i < value.dim; i++) { Identifier *id = (Identifier *)field.data[i]; if (id) { Dsymbol * s = ad->search(loc, id, 0); if (!s) { error(loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars()); goto Lno; } // Find out which field index it is for (fieldi = 0; 1; fieldi++) { if (fieldi >= ad->fields.dim) { s->error("is not a per-instance initializable field"); goto Lno; } if (s == (Dsymbol *)ad->fields.data[fieldi]) break; } } else if (fieldi >= ad->fields.dim) { error(loc, "too many initializers for '%s'", ad->toChars()); goto Lno; } Initializer *iz = (Initializer *)value.data[i]; if (!iz) goto Lno; Expression *ex = iz->toExpression(); if (!ex) goto Lno; if (elements->data[fieldi]) { error(loc, "duplicate initializer for field '%s'", ((Dsymbol *)ad->fields.data[fieldi])->toChars()); goto Lno; } elements->data[fieldi] = ex; ++fieldi; } // Now, fill in any missing elements with default initializers. // We also need to validate any anonymous unions for (int i = 0; i < elements->dim; ) { VarDeclaration * vd = ((Dsymbol *)ad->fields.data[i])->isVarDeclaration(); int unionSize = ad->numFieldsInUnion(i); if (unionSize == 1) { // Not a union -- default initialize if missing if (!elements->data[i]) elements->data[i] = vd->type->defaultInit(); } else { // anonymous union -- check for errors int found = -1; // index of the first field with an initializer for (int j = i; j < i + unionSize; ++j) { if (!elements->data[j]) continue; if (found >= 0) { VarDeclaration * v1 = ((Dsymbol *)ad->fields.data[found])->isVarDeclaration(); VarDeclaration * v = ((Dsymbol *)ad->fields.data[j])->isVarDeclaration(); error(loc, "%s cannot have initializers for fields %s and %s in same union", ad->toChars(), v1->toChars(), v->toChars()); goto Lno; } found = j; } if (found == -1) { error(loc, "no initializer for union that contains field %s", vd->toChars()); goto Lno; } } i += unionSize; } e = new StructLiteralExp(loc, sd, elements); e->type = sd->type; return e; Lno: delete elements; return NULL; }
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); }
/*************************************** * This works by transforming a struct initializer into * a struct literal. In the future, the two should be the * same thing. */ Expression *StructInitializer::toExpression() { Expression *e; size_t offset; //printf("StructInitializer::toExpression() %s\n", toChars()); if (!ad) // if fwd referenced return NULL; StructDeclaration *sd = ad->isStructDeclaration(); if (!sd) return NULL; Expressions *elements = new Expressions(); size_t nfields = ad->fields.dim; #if DMDV2 if (sd->isnested) nfields--; #endif elements->setDim(nfields); for (size_t i = 0; i < elements->dim; i++) { (*elements)[i] = NULL; } unsigned fieldi = 0; for (size_t i = 0; i < value.dim; i++) { Identifier *id = field[i]; if (id) { Dsymbol * s = ad->search(loc, id, 0); if (!s) { error(loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars()); goto Lno; } s = s->toAlias(); // Find out which field index it is for (fieldi = 0; 1; fieldi++) { if (fieldi >= nfields) { s->error("is not a per-instance initializable field"); goto Lno; } if (s == ad->fields[fieldi]) break; } } else if (fieldi >= nfields) { error(loc, "too many initializers for '%s'", ad->toChars()); goto Lno; } Initializer *iz = value[i]; if (!iz) goto Lno; Expression *ex = iz->toExpression(); if (!ex) goto Lno; if ((*elements)[fieldi]) { error(loc, "duplicate initializer for field '%s'", ad->fields[fieldi]->toChars()); goto Lno; } (*elements)[fieldi] = ex; ++fieldi; } // Now, fill in any missing elements with default initializers. // We also need to validate any anonymous unions offset = 0; for (size_t i = 0; i < elements->dim; ) { VarDeclaration * vd = ad->fields[i]->isVarDeclaration(); //printf("test2 [%d] : %s %d %d\n", i, vd->toChars(), (int)offset, (int)vd->offset); if (vd->offset < offset) { // Only the first field of a union can have an initializer if ((*elements)[i]) goto Lno; } else { if (!(*elements)[i]) // Default initialize (*elements)[i] = vd->type->defaultInit(); } offset = vd->offset + vd->type->size(); i++; #if 0 int unionSize = ad->numFieldsInUnion(i); if (unionSize == 1) { // Not a union -- default initialize if missing if (!(*elements)[i]) (*elements)[i] = vd->type->defaultInit(); } else { // anonymous union -- check for errors int found = -1; // index of the first field with an initializer for (size_t j = i; j < i + unionSize; ++j) { if (!(*elements)[j]) continue; if (found >= 0) { VarDeclaration * v1 = ((Dsymbol *)ad->fields.data[found])->isVarDeclaration(); VarDeclaration * v = ((Dsymbol *)ad->fields.data[j])->isVarDeclaration(); error(loc, "%s cannot have initializers for fields %s and %s in same union", ad->toChars(), v1->toChars(), v->toChars()); goto Lno; } found = j; } if (found == -1) { error(loc, "no initializer for union that contains field %s", vd->toChars()); goto Lno; } } i += unionSize; #endif } e = new StructLiteralExp(loc, sd, elements); e->type = sd->type; return e; Lno: delete elements; return NULL; }
Initializer *StructInitializer::semantic(Scope *sc, Type *t, int needInterpret) { int errors = 0; //printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars()); vars.setDim(field.dim); t = t->toBasetype(); if (t->ty == Tstruct) { unsigned fieldi = 0; TypeStruct *ts = (TypeStruct *)t; ad = ts->sym; if (ad->ctor) error(loc, "%s %s has constructors, cannot use { initializers }, use %s( initializers ) instead", ad->kind(), ad->toChars(), ad->toChars()); StructDeclaration *sd = ad->isStructDeclaration(); assert(sd); sd->size(loc); if (sd->sizeok != SIZEOKdone) { error(loc, "struct %s is forward referenced", sd->toChars()); errors = 1; goto Lerror; } size_t nfields = sd->fields.dim; if (sd->isnested) nfields--; for (size_t i = 0; i < field.dim; i++) { Identifier *id = field[i]; Initializer *val = value[i]; Dsymbol *s; VarDeclaration *v; if (id == NULL) { if (fieldi >= nfields) { error(loc, "too many initializers for %s", ad->toChars()); errors = 1; field.remove(i); i--; continue; } else { s = ad->fields[fieldi]; } } else { //s = ad->symtab->lookup(id); s = ad->search(loc, id, 0); if (!s) { s = ad->search_correct(id); if (s) error(loc, "'%s' is not a member of '%s', did you mean '%s %s'?", id->toChars(), t->toChars(), s->kind(), s->toChars()); else error(loc, "'%s' is not a member of '%s'", id->toChars(), t->toChars()); errors = 1; continue; } s = s->toAlias(); // Find out which field index it is for (fieldi = 0; 1; fieldi++) { if (fieldi >= nfields) { error(loc, "%s.%s is not a per-instance initializable field", t->toChars(), s->toChars()); errors = 1; break; } if (s == ad->fields[fieldi]) break; } } if (s && (v = s->isVarDeclaration()) != NULL) { val = val->semantic(sc, v->type, needInterpret); value[i] = val; vars[i] = v; } else { error(loc, "%s is not a field of %s", id ? id->toChars() : s->toChars(), ad->toChars()); errors = 1; } fieldi++; } } else if (t->ty == Tdelegate && value.dim == 0) { /* Rewrite as empty delegate literal { } */ Parameters *arguments = new Parameters; Type *tf = new TypeFunction(arguments, NULL, 0, LINKd); FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, 0, tf, TOKdelegate, NULL); fd->fbody = new CompoundStatement(loc, new Statements()); fd->endloc = loc; Expression *e = new FuncExp(loc, fd); ExpInitializer *ie = new ExpInitializer(loc, e); return ie->semantic(sc, t, needInterpret); } else { error(loc, "a struct is not a valid initializer for a %s", t->toChars()); errors = 1; } Lerror: if (errors) { field.setDim(0); value.setDim(0); vars.setDim(0); } return this; }
void StorageClassDeclaration::stcToCBuffer(OutBuffer *buf, StorageClass stc) { struct SCstring { StorageClass stc; enum TOK tok; }; static SCstring table[] = { { STCauto, TOKauto }, { STCscope, TOKscope }, { STCstatic, TOKstatic }, { STCextern, TOKextern }, { STCconst, TOKconst }, { STCfinal, TOKfinal }, { STCabstract, TOKabstract }, { STCsynchronized, TOKsynchronized }, { STCdeprecated, TOKdeprecated }, { STCoverride, TOKoverride }, { STClazy, TOKlazy }, { STCalias, TOKalias }, { STCout, TOKout }, { STCin, TOKin }, #if DMDV2 { STCimmutable, TOKimmutable }, { STCshared, TOKshared }, { STCnothrow, TOKnothrow }, { STCpure, TOKpure }, { STCref, TOKref }, { STCtls, TOKtls }, { STCgshared, TOKgshared }, { STCproperty, TOKat }, { STCsafe, TOKat }, { STCtrusted, TOKat }, { STCdisable, TOKat }, #endif }; for (int i = 0; i < sizeof(table)/sizeof(table[0]); i++) { if (stc & table[i].stc) { enum TOK tok = table[i].tok; #if DMDV2 if (tok == TOKat) { Identifier *id; if (stc & STCproperty) id = Id::property; else if (stc & STCsafe) id = Id::safe; else if (stc & STCtrusted) id = Id::trusted; else if (stc & STCdisable) id = Id::disable; else assert(0); buf->writeByte('@'); buf->writestring(id->toChars()); } else #endif buf->writestring(Token::toChars(tok)); buf->writeByte(' '); } } }
Initializer *StructInitializer::semantic(Scope *sc, Type *t, int needInterpret) { int errors = 0; //printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars()); vars.setDim(field.dim); t = t->toBasetype(); if (t->ty == Tstruct) { unsigned fieldi = 0; TypeStruct *ts = (TypeStruct *)t; ad = ts->sym; size_t nfields = ad->fields.dim; #if DMDV2 if (((StructDeclaration *)ad)->isnested) nfields--; // don't count pointer to outer #endif for (size_t i = 0; i < field.dim; i++) { Identifier *id = (Identifier *)field.data[i]; Initializer *val = (Initializer *)value.data[i]; Dsymbol *s; VarDeclaration *v; if (id == NULL) { if (fieldi >= nfields) { error(loc, "too many initializers for %s", ad->toChars()); errors = 1; field.remove(i); i--; continue; } else { s = (Dsymbol *)ad->fields.data[fieldi]; } } else { //s = ad->symtab->lookup(id); s = ad->search(loc, id, 0); if (!s) { error(loc, "'%s' is not a member of '%s'", id->toChars(), t->toChars()); errors = 1; continue; } // Find out which field index it is for (fieldi = 0; 1; fieldi++) { if (fieldi >= nfields) { error(loc, "%s.%s is not a per-instance initializable field", t->toChars(), s->toChars()); errors = 1; break; } if (s == (Dsymbol *)ad->fields.data[fieldi]) break; } } if (s && (v = s->isVarDeclaration()) != NULL) { val = val->semantic(sc, v->type, needInterpret); value.data[i] = (void *)val; vars.data[i] = (void *)v; } else { error(loc, "%s is not a field of %s", id ? id->toChars() : s->toChars(), ad->toChars()); errors = 1; } fieldi++; } } else if (t->ty == Tdelegate && value.dim == 0) { /* Rewrite as empty delegate literal { } */ Parameters *arguments = new Parameters; Type *tf = new TypeFunction(arguments, NULL, 0, LINKd); FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, 0, tf, TOKdelegate, NULL); fd->fbody = new CompoundStatement(loc, new Statements()); fd->endloc = loc; Expression *e = new FuncExp(loc, fd); ExpInitializer *ie = new ExpInitializer(loc, e); return ie->semantic(sc, t, needInterpret); } else { error(loc, "a struct is not a valid initializer for a %s", t->toChars()); errors = 1; } if (errors) { field.setDim(0); value.setDim(0); vars.setDim(0); } return this; }
void DtoCheckPragma(PragmaDeclaration *decl, Dsymbol *s, Pragma llvm_internal, const std::string &arg1str) { if (llvm_internal == LLVMnone || llvm_internal == LLVMignore) return; if (s->llvmInternal) { error("multiple LDC specific pragmas not allowed not affect the same " "declaration ('%s' at '%s')", s->toChars(), s->loc.toChars()); fatal(); } Identifier *ident = decl->ident; switch(llvm_internal) { case LLVMintrinsic: if (FuncDeclaration* fd = s->isFuncDeclaration()) { fd->llvmInternal = llvm_internal; fd->intrinsicName = arg1str; fd->linkage = LINKintrinsic; static_cast<TypeFunction*>(fd->type)->linkage = LINKintrinsic; } else if (TemplateDeclaration* td = s->isTemplateDeclaration()) { td->llvmInternal = llvm_internal; td->intrinsicName = arg1str; } else { error("only allowed on function declarations"); fatal(); } break; case LLVMglobal_crt_ctor: case LLVMglobal_crt_dtor: if (FuncDeclaration* fd = s->isFuncDeclaration()) { assert(fd->type->ty == Tfunction); TypeFunction* type = static_cast<TypeFunction*>(fd->type); Type* retType = type->next; if (retType->ty != Tvoid || type->parameters->dim > 0 || ( #if DMDV2 fd->isAggregateMember() #else fd->isThis() #endif && !fd->isStatic())) { error(fd->loc, "the '%s' pragma is only allowed on void functions which take no arguments", ident->toChars()); fd->llvmInternal = LLVMnone; break; } fd->llvmInternal = llvm_internal; fd->priority = std::atoi(arg1str.c_str()); } else { error(s->loc, "the '%s' pragma is only allowed on function declarations", ident->toChars()); s->llvmInternal = LLVMnone; } break; case LLVMatomic_rmw: if (TemplateDeclaration* td = s->isTemplateDeclaration()) { td->llvmInternal = llvm_internal; td->intrinsicName = arg1str; } else { error("the '%s' pragma is only allowed on template declarations", ident->toChars()); fatal(); } break; case LLVMva_start: case LLVMva_arg: case LLVMatomic_load: case LLVMatomic_store: case LLVMatomic_cmp_xchg: if (TemplateDeclaration* td = s->isTemplateDeclaration()) { if (td->parameters->dim != 1) { error("the '%s' pragma template must have exactly one template parameter", ident->toChars()); fatal(); } else if (!td->onemember) { error("the '%s' pragma template must have exactly one member", ident->toChars()); fatal(); } else if (td->overnext || td->overroot) { error("the '%s' pragma template must not be overloaded", ident->toChars()); fatal(); } td->llvmInternal = llvm_internal; } else { error("the '%s' pragma is only allowed on template declarations", ident->toChars()); fatal(); } break; case LLVMva_copy: case LLVMva_end: case LLVMfence: case LLVMbitop_bt: case LLVMbitop_btc: case LLVMbitop_btr: case LLVMbitop_bts: if (FuncDeclaration* fd = s->isFuncDeclaration()) { fd->llvmInternal = llvm_internal; } else { error("the '%s' pragma is only allowed on function declarations", ident->toChars()); fatal(); } break; case LLVMno_typeinfo: s->llvmInternal = llvm_internal; break; case LLVMalloca: if (FuncDeclaration* fd = s->isFuncDeclaration()) { fd->llvmInternal = llvm_internal; } else { error("the '%s' pragma must only be used on function declarations " "of type 'void* function(uint nbytes)'", ident->toChars()); fatal(); } break; case LLVMinline_asm: if (TemplateDeclaration* td = s->isTemplateDeclaration()) { if (td->parameters->dim > 1) { error("the '%s' pragma template must have exactly zero or one " "template parameters", ident->toChars()); fatal(); } else if (!td->onemember) { error("the '%s' pragma template must have exactly one member", ident->toChars()); fatal(); } td->llvmInternal = llvm_internal; } else { error("the '%s' pragma is only allowed on template declarations", ident->toChars()); fatal(); } break; case LLVMinline_ir: if (TemplateDeclaration* td = s->isTemplateDeclaration()) { Dsymbol* member = td->onemember; if (!member) { error("the '%s' pragma template must have exactly one member", ident->toChars()); fatal(); } FuncDeclaration* fun = member->isFuncDeclaration(); if (!fun) { error("the '%s' pragma template's member must be a function declaration", ident->toChars()); fatal(); } TemplateParameters& params = *td->parameters; bool valid_params = params.dim == 3 && params[1]->isTemplateTypeParameter() && params[2]->isTemplateTupleParameter(); if(valid_params) { TemplateValueParameter* p0 = params[0]->isTemplateValueParameter(); valid_params = valid_params && p0 && p0->valType == Type::tstring; } if(!valid_params) { error("the '%s' pragma template must have exactly three parameters: " "a string, a type and a type tuple", ident->toChars()); fatal(); } td->llvmInternal = llvm_internal; } else { error("the '%s' pragma is only allowed on template declarations", ident->toChars()); fatal(); } break; default: warning(Loc(), "the LDC specific pragma '%s' is not yet implemented, ignoring", ident->toChars()); } }
void DtoCheckPragma(PragmaDeclaration *decl, Dsymbol *s, Pragma llvm_internal, const std::string &arg1str) { if (llvm_internal == LLVMnone || llvm_internal == LLVMignore) return; if (s->llvmInternal) { error(Loc(), "multiple LDC specific pragmas not allowed not affect the same " "declaration ('%s' at '%s')", s->toChars(), s->loc.toChars()); fatal(); } Identifier *ident = decl->ident; switch(llvm_internal) { case LLVMintrinsic: if (FuncDeclaration* fd = s->isFuncDeclaration()) { fd->llvmInternal = llvm_internal; fd->intrinsicName = arg1str; fd->mangleOverride = strdup(fd->intrinsicName.c_str()); } else if (TemplateDeclaration* td = s->isTemplateDeclaration()) { td->llvmInternal = llvm_internal; td->intrinsicName = arg1str; } else { error(s->loc, "the '%s' pragma is only allowed on function or template declarations", ident->toChars()); fatal(); } break; case LLVMglobal_crt_ctor: case LLVMglobal_crt_dtor: if (FuncDeclaration* fd = s->isFuncDeclaration()) { assert(fd->type->ty == Tfunction); TypeFunction* type = static_cast<TypeFunction*>(fd->type); Type* retType = type->next; if (retType->ty != Tvoid || type->parameters->dim > 0 || ( fd->isAggregateMember() && !fd->isStatic())) { error(s->loc, "the '%s' pragma is only allowed on void functions which take no arguments", ident->toChars()); fd->llvmInternal = LLVMnone; break; } fd->llvmInternal = llvm_internal; fd->priority = std::atoi(arg1str.c_str()); } else { error(s->loc, "the '%s' pragma is only allowed on function declarations", ident->toChars()); s->llvmInternal = LLVMnone; } break; case LLVMatomic_rmw: if (TemplateDeclaration* td = s->isTemplateDeclaration()) { td->llvmInternal = llvm_internal; td->intrinsicName = arg1str; } else { error(s->loc, "the '%s' pragma is only allowed on template declarations", ident->toChars()); fatal(); } break; case LLVMva_start: case LLVMva_arg: case LLVMatomic_load: case LLVMatomic_store: case LLVMatomic_cmp_xchg: if (TemplateDeclaration* td = s->isTemplateDeclaration()) { if (td->parameters->dim != 1) { error(s->loc, "the '%s' pragma template must have exactly one template parameter", ident->toChars()); fatal(); } else if (!td->onemember) { error(s->loc, "the '%s' pragma template must have exactly one member", ident->toChars()); fatal(); } else if (td->overnext || td->overroot) { error(s->loc, "the '%s' pragma template must not be overloaded", ident->toChars()); fatal(); } td->llvmInternal = llvm_internal; } else { error(s->loc, "the '%s' pragma is only allowed on template declarations", ident->toChars()); fatal(); } break; case LLVMva_copy: case LLVMva_end: case LLVMfence: case LLVMbitop_bt: case LLVMbitop_btc: case LLVMbitop_btr: case LLVMbitop_bts: case LLVMbitop_vld: case LLVMbitop_vst: if (FuncDeclaration* fd = s->isFuncDeclaration()) { fd->llvmInternal = llvm_internal; } else { error(s->loc, "the '%s' pragma is only allowed on function declarations", ident->toChars()); fatal(); } break; case LLVMno_typeinfo: s->llvmInternal = llvm_internal; break; case LLVMalloca: if (FuncDeclaration* fd = s->isFuncDeclaration()) { fd->llvmInternal = llvm_internal; } else { error(s->loc, "the '%s' pragma must only be used on function declarations " "of type 'void* function(uint nbytes)'", ident->toChars()); fatal(); } break; case LLVMinline_asm: if (TemplateDeclaration* td = s->isTemplateDeclaration()) { if (td->parameters->dim > 1) { error(s->loc, "the '%s' pragma template must have exactly zero or one " "template parameters", ident->toChars()); fatal(); } else if (!td->onemember) { error(s->loc, "the '%s' pragma template must have exactly one member", ident->toChars()); fatal(); } td->llvmInternal = llvm_internal; } else { error(s->loc, "the '%s' pragma is only allowed on template declarations", ident->toChars()); fatal(); } break; case LLVMinline_ir: if (TemplateDeclaration* td = s->isTemplateDeclaration()) { Dsymbol* member = td->onemember; if (!member) { error(s->loc, "the '%s' pragma template must have exactly one member", ident->toChars()); fatal(); } FuncDeclaration* fun = member->isFuncDeclaration(); if (!fun) { error(s->loc, "the '%s' pragma template's member must be a function declaration", ident->toChars()); fatal(); } TemplateParameters& params = *td->parameters; bool valid_params = params.dim == 3 && params[1]->isTemplateTypeParameter() && params[2]->isTemplateTupleParameter(); if(valid_params) { TemplateValueParameter* p0 = params[0]->isTemplateValueParameter(); valid_params = valid_params && p0 && p0->valType == Type::tstring; } if(!valid_params) { error(s->loc, "the '%s' pragma template must have exactly three parameters: " "a string, a type and a type tuple", ident->toChars()); fatal(); } td->llvmInternal = llvm_internal; } else { error(s->loc, "the '%s' pragma is only allowed on template declarations", ident->toChars()); fatal(); } break; case LLVMextern_weak: if (VarDeclaration* vd = s->isVarDeclaration()) { if (!vd->isDataseg() || !(vd->storage_class & STCextern)) { error(s->loc, "'%s' requires storage class 'extern'", ident->toChars()); fatal(); } // It seems like the interaction between weak symbols and thread-local // storage is not well-defined (the address of an undefined weak TLS // symbol is non-zero on the ELF static TLS model on Linux x86_64). // Thus, just disallow this altogether. if (vd->isThreadlocal()) { error(s->loc, "'%s' cannot be applied to thread-local variable '%s'", ident->toChars(), vd->toPrettyChars()); fatal(); } vd->llvmInternal = llvm_internal; } else { // Currently, things like "pragma(LDC_extern_weak) extern int foo;" // fail because 'extern' creates an intermediate // StorageClassDeclaration. This might eventually be fixed by making // extern_weak a proper storage class. error(s->loc, "the '%s' pragma can only be specified directly on " "variable declarations for now", ident->toChars()); fatal(); } break; default: warning(s->loc, "the LDC specific pragma '%s' is not yet implemented, ignoring", ident->toChars()); } }
FuncDeclaration *StructDeclaration::buildXopEquals(Scope *sc) { if (!needOpEquals()) return NULL; // bitwise comparison would work //printf("StructDeclaration::buildXopEquals() %s\n", toChars()); if (Dsymbol *eq = search_function(this, Id::eq)) { if (FuncDeclaration *fd = eq->isFuncDeclaration()) { TypeFunction *tfeqptr; { Scope sc; /* const bool opEquals(ref const S s); */ Parameters *parameters = new Parameters; parameters->push(new Parameter(STCref | STCconst, type, NULL, NULL)); tfeqptr = new TypeFunction(parameters, Type::tbool, 0, LINKd); tfeqptr->mod = MODconst; tfeqptr = (TypeFunction *)tfeqptr->semantic(Loc(), &sc); } fd = fd->overloadExactMatch(tfeqptr); if (fd) return fd; } } if (!xerreq) { Identifier *id = Lexer::idPool("_xopEquals"); Expression *e = new IdentifierExp(loc, Id::empty); e = new DotIdExp(loc, e, Id::object); e = new DotIdExp(loc, e, id); e = e->semantic(sc); Dsymbol *s = getDsymbol(e); if (!s) { ::error(Loc(), "ICE: %s not found in object module. You must update druntime", id->toChars()); fatal(); } assert(s); 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, type, Id::p, NULL)); parameters->push(new Parameter(STCref | STCconst, type, Id::q, NULL)); TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd); tf = (TypeFunction *)tf->semantic(loc, sc); Identifier *id = Lexer::idPool("__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 = xerreq; return fop; }
Expression *semanticTraits(TraitsExp *e, Scope *sc) { #if LOGSEMANTIC printf("TraitsExp::semantic() %s\n", e->toChars()); #endif if (e->ident != Id::compiles && e->ident != Id::isSame && e->ident != Id::identifier && e->ident != Id::getProtection) { if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 1)) return new ErrorExp(); } size_t dim = e->args ? e->args->dim : 0; if (e->ident == Id::isArithmetic) { return isTypeX(e, &isTypeArithmetic); } else if (e->ident == Id::isFloating) { return isTypeX(e, &isTypeFloating); } else if (e->ident == Id::isIntegral) { return isTypeX(e, &isTypeIntegral); } else if (e->ident == Id::isScalar) { return isTypeX(e, &isTypeScalar); } else if (e->ident == Id::isUnsigned) { return isTypeX(e, &isTypeUnsigned); } else if (e->ident == Id::isAssociativeArray) { return isTypeX(e, &isTypeAssociativeArray); } else if (e->ident == Id::isStaticArray) { return isTypeX(e, &isTypeStaticArray); } else if (e->ident == Id::isAbstractClass) { return isTypeX(e, &isTypeAbstractClass); } else if (e->ident == Id::isFinalClass) { return isTypeX(e, &isTypeFinalClass); } else if (e->ident == Id::isPOD) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Type *t = isType(o); StructDeclaration *sd; if (!t) { e->error("type expected as second argument of __traits %s instead of %s", e->ident->toChars(), o->toChars()); goto Lfalse; } Type *tb = t->baseElemOf(); if (tb->ty == Tstruct && ((sd = (StructDeclaration *)(((TypeStruct *)tb)->sym)) != NULL)) { if (sd->isPOD()) goto Ltrue; else goto Lfalse; } goto Ltrue; } else if (e->ident == Id::isNested) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); AggregateDeclaration *a; FuncDeclaration *f; if (!s) { } else if ((a = s->isAggregateDeclaration()) != NULL) { if (a->isNested()) goto Ltrue; else goto Lfalse; } else if ((f = s->isFuncDeclaration()) != NULL) { if (f->isNested()) goto Ltrue; else goto Lfalse; } e->error("aggregate or function expected instead of '%s'", o->toChars()); goto Lfalse; } else if (e->ident == Id::isAbstractFunction) { return isFuncX(e, &isFuncAbstractFunction); } else if (e->ident == Id::isVirtualFunction) { return isFuncX(e, &isFuncVirtualFunction); } else if (e->ident == Id::isVirtualMethod) { return isFuncX(e, &isFuncVirtualMethod); } else if (e->ident == Id::isFinalFunction) { return isFuncX(e, &isFuncFinalFunction); } else if (e->ident == Id::isOverrideFunction) { return isFuncX(e, &isFuncOverrideFunction); } else if (e->ident == Id::isStaticFunction) { return isFuncX(e, &isFuncStaticFunction); } else if (e->ident == Id::isRef) { return isDeclX(e, &isDeclRef); } else if (e->ident == Id::isOut) { return isDeclX(e, &isDeclOut); } else if (e->ident == Id::isLazy) { return isDeclX(e, &isDeclLazy); } else if (e->ident == Id::identifier) { // Get identifier for symbol as a string literal /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that * a symbol should not be folded to a constant. * Bit 1 means don't convert Parameter to Type if Parameter has an identifier */ if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 2)) return new ErrorExp(); if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Parameter *po = isParameter(o); Identifier *id; if (po) { id = po->ident; assert(id); } else { Dsymbol *s = getDsymbol(o); if (!s || !s->ident) { e->error("argument %s has no identifier", o->toChars()); goto Lfalse; } id = s->ident; } StringExp *se = new StringExp(e->loc, id->toChars()); return se->semantic(sc); } else if (e->ident == Id::getProtection) { if (dim != 1) goto Ldimerror; Scope *sc2 = sc->push(); sc2->flags = sc->flags | SCOPEnoaccesscheck; bool ok = TemplateInstance::semanticTiargs(e->loc, sc2, e->args, 1); sc2->pop(); if (!ok) return new ErrorExp(); RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); if (!s) { if (!isError(o)) e->error("argument %s has no protection", o->toChars()); goto Lfalse; } if (s->scope) s->semantic(s->scope); PROT protection = s->prot(); const char *protName = Pprotectionnames[protection]; assert(protName); StringExp *se = new StringExp(e->loc, (char *) protName); return se->semantic(sc); } else if (e->ident == Id::parent) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); if (s) { if (FuncDeclaration *fd = s->isFuncDeclaration()) // Bugzilla 8943 s = fd->toAliasFunc(); if (!s->isImport()) // Bugzilla 8922 s = s->toParent(); } if (!s || s->isImport()) { e->error("argument %s has no parent", o->toChars()); goto Lfalse; } if (FuncDeclaration *f = s->isFuncDeclaration()) { if (TemplateDeclaration *td = getFuncTemplateDecl(f)) { if (td->overroot) // if not start of overloaded list of TemplateDeclaration's td = td->overroot; // then get the start Expression *ex = new TemplateExp(e->loc, td, f); ex = ex->semantic(sc); return ex; } if (FuncLiteralDeclaration *fld = f->isFuncLiteralDeclaration()) { // Directly translate to VarExp instead of FuncExp Expression *ex = new VarExp(e->loc, fld, 1); return ex->semantic(sc); } } return (new DsymbolExp(e->loc, s))->semantic(sc); } else if (e->ident == Id::hasMember || e->ident == Id::getMember || e->ident == Id::getOverloads || e->ident == Id::getVirtualMethods || e->ident == Id::getVirtualFunctions) { if (dim != 2) goto Ldimerror; RootObject *o = (*e->args)[0]; Expression *ex = isExpression((*e->args)[1]); if (!ex) { e->error("expression expected as second argument of __traits %s", e->ident->toChars()); goto Lfalse; } ex = ex->ctfeInterpret(); StringExp *se = ex->toStringExp(); if (!se || se->length() == 0) { e->error("string expected as second argument of __traits %s instead of %s", e->ident->toChars(), ex->toChars()); goto Lfalse; } se = se->toUTF8(sc); if (se->sz != 1) { e->error("string must be chars"); goto Lfalse; } Identifier *id = Lexer::idPool((char *)se->string); /* Prefer dsymbol, because it might need some runtime contexts. */ Dsymbol *sym = getDsymbol(o); if (sym) { ex = new DsymbolExp(e->loc, sym); ex = new DotIdExp(e->loc, ex, id); } else if (Type *t = isType(o)) ex = typeDotIdExp(e->loc, t, id); else if (Expression *ex2 = isExpression(o)) ex = new DotIdExp(e->loc, ex2, id); else { e->error("invalid first argument"); goto Lfalse; } if (e->ident == Id::hasMember) { if (sym) { Dsymbol *sm = sym->search(e->loc, id); if (sm) goto Ltrue; } /* Take any errors as meaning it wasn't found */ Scope *sc2 = sc->push(); ex = ex->trySemantic(sc2); sc2->pop(); if (!ex) goto Lfalse; else goto Ltrue; } else if (e->ident == Id::getMember) { ex = ex->semantic(sc); return ex; } else if (e->ident == Id::getVirtualFunctions || e->ident == Id::getVirtualMethods || e->ident == Id::getOverloads) { unsigned errors = global.errors; Expression *eorig = ex; ex = ex->semantic(sc); if (errors < global.errors) e->error("%s cannot be resolved", eorig->toChars()); /* Create tuple of functions of ex */ //ex->print(); Expressions *exps = new Expressions(); FuncDeclaration *f; if (ex->op == TOKvar) { VarExp *ve = (VarExp *)ex; f = ve->var->isFuncDeclaration(); ex = NULL; } else if (ex->op == TOKdotvar) { DotVarExp *dve = (DotVarExp *)ex; f = dve->var->isFuncDeclaration(); if (dve->e1->op == TOKdottype || dve->e1->op == TOKthis) ex = NULL; else ex = dve->e1; } else f = NULL; Ptrait p; p.exps = exps; p.e1 = ex; p.ident = e->ident; overloadApply(f, &p, &fptraits); TupleExp *tup = new TupleExp(e->loc, exps); return tup->semantic(sc); } else assert(0); } else if (e->ident == Id::classInstanceSize) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); ClassDeclaration *cd; if (!s || (cd = s->isClassDeclaration()) == NULL) { e->error("first argument is not a class"); goto Lfalse; } if (cd->sizeok == SIZEOKnone) { if (cd->scope) cd->semantic(cd->scope); } if (cd->sizeok != SIZEOKdone) { e->error("%s %s is forward referenced", cd->kind(), cd->toChars()); goto Lfalse; } return new IntegerExp(e->loc, cd->structsize, Type::tsize_t); } else if (e->ident == Id::getAliasThis) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); AggregateDeclaration *ad; if (!s || (ad = s->isAggregateDeclaration()) == NULL) { e->error("argument is not an aggregate type"); goto Lfalse; } Expressions *exps = new Expressions(); if (ad->aliasthis) exps->push(new StringExp(e->loc, ad->aliasthis->ident->toChars())); Expression *ex = new TupleExp(e->loc, exps); ex = ex->semantic(sc); return ex; } else if (e->ident == Id::getAttributes) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); if (!s) { #if 0 Expression *x = isExpression(o); Type *t = isType(o); if (x) printf("e = %s %s\n", Token::toChars(x->op), x->toChars()); if (t) printf("t = %d %s\n", t->ty, t->toChars()); #endif e->error("first argument is not a symbol"); goto Lfalse; } //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttributes, s->userAttributesScope); UserAttributeDeclaration *udad = s->userAttribDecl; TupleExp *tup = new TupleExp(e->loc, udad ? udad->getAttributes() : new Expressions()); return tup->semantic(sc); } else if (e->ident == Id::getFunctionAttributes) { /// extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs. if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); Type *t = isType(o); TypeFunction *tf = NULL; if (s) { if (FuncDeclaration *f = s->isFuncDeclaration()) t = f->type; else if (VarDeclaration *v = s->isVarDeclaration()) t = v->type; } if (t) { if (t->ty == Tfunction) tf = (TypeFunction *)t; else if (t->ty == Tdelegate) tf = (TypeFunction *)t->nextOf(); else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction) tf = (TypeFunction *)t->nextOf(); } if (!tf) { e->error("first argument is not a function"); goto Lfalse; } Expressions *mods = new Expressions(); PushAttributes pa; pa.mods = mods; tf->modifiersApply(&pa, &PushAttributes::fp); tf->attributesApply(&pa, &PushAttributes::fp, TRUSTformatSystem); TupleExp *tup = new TupleExp(e->loc, mods); return tup->semantic(sc); } else if (e->ident == Id::allMembers || e->ident == Id::derivedMembers) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); ScopeDsymbol *sds; if (!s) { e->error("argument has no members"); goto Lfalse; } Import *import; if ((import = s->isImport()) != NULL) { // Bugzilla 9692 sds = import->mod; } else if ((sds = s->isScopeDsymbol()) == NULL) { e->error("%s %s has no members", s->kind(), s->toChars()); goto Lfalse; } // use a struct as local function struct PushIdentsDg { static int dg(void *ctx, size_t n, Dsymbol *sm) { if (!sm) return 1; //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars()); if (sm->ident) { if (sm->ident != Id::ctor && sm->ident != Id::dtor && sm->ident != Id::_postblit && memcmp(sm->ident->string, "__", 2) == 0) { return 0; } //printf("\t%s\n", sm->ident->toChars()); Identifiers *idents = (Identifiers *)ctx; /* Skip if already present in idents[] */ for (size_t j = 0; j < idents->dim; j++) { Identifier *id = (*idents)[j]; if (id == sm->ident) return 0; #ifdef DEBUG // Avoid using strcmp in the first place due to the performance impact in an O(N^2) loop. assert(strcmp(id->toChars(), sm->ident->toChars()) != 0); #endif } idents->push(sm->ident); } else { EnumDeclaration *ed = sm->isEnumDeclaration(); if (ed) { ScopeDsymbol::foreach(NULL, ed->members, &PushIdentsDg::dg, (Identifiers *)ctx); } } return 0; } }; Identifiers *idents = new Identifiers; ScopeDsymbol::foreach(sc, sds->members, &PushIdentsDg::dg, idents); ClassDeclaration *cd = sds->isClassDeclaration(); if (cd && e->ident == Id::allMembers) { struct PushBaseMembers { static void dg(ClassDeclaration *cd, Identifiers *idents) { for (size_t i = 0; i < cd->baseclasses->dim; i++) { ClassDeclaration *cb = (*cd->baseclasses)[i]->base; ScopeDsymbol::foreach(NULL, cb->members, &PushIdentsDg::dg, idents); if (cb->baseclasses->dim) dg(cb, idents); } } }; PushBaseMembers::dg(cd, idents); } // Turn Identifiers into StringExps reusing the allocated array assert(sizeof(Expressions) == sizeof(Identifiers)); Expressions *exps = (Expressions *)idents; for (size_t i = 0; i < idents->dim; i++) { Identifier *id = (*idents)[i]; StringExp *se = new StringExp(e->loc, id->toChars()); (*exps)[i] = se; } /* Making this a tuple is more flexible, as it can be statically unrolled. * To make an array literal, enclose __traits in [ ]: * [ __traits(allMembers, ...) ] */ Expression *ex = new TupleExp(e->loc, exps); ex = ex->semantic(sc); return ex; } else if (e->ident == Id::compiles) { /* Determine if all the objects - types, expressions, or symbols - * compile without error */ if (!dim) goto Lfalse; for (size_t i = 0; i < dim; i++) { unsigned errors = global.startGagging(); unsigned oldspec = global.speculativeGag; global.speculativeGag = global.gag; Scope *sc2 = sc->push(); sc2->speculative = true; sc2->flags = sc->flags & ~SCOPEctfe | SCOPEcompile; bool err = false; RootObject *o = (*e->args)[i]; Type *t = isType(o); Expression *ex = t ? t->toExpression() : isExpression(o); if (!ex && t) { Dsymbol *s; t->resolve(e->loc, sc2, &ex, &t, &s); if (t) { t->semantic(e->loc, sc2); if (t->ty == Terror) err = true; } else if (s && s->errors) err = true; } if (ex) { ex = ex->semantic(sc2); ex = resolvePropertiesOnly(sc2, ex); ex = ex->optimize(WANTvalue); ex = checkGC(sc2, ex); if (ex->op == TOKerror) err = true; } sc2->pop(); global.speculativeGag = oldspec; if (global.endGagging(errors) || err) { goto Lfalse; } } goto Ltrue; } else if (e->ident == Id::isSame) { /* Determine if two symbols are the same */ if (dim != 2) goto Ldimerror; if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 0)) return new ErrorExp(); RootObject *o1 = (*e->args)[0]; RootObject *o2 = (*e->args)[1]; Dsymbol *s1 = getDsymbol(o1); Dsymbol *s2 = getDsymbol(o2); //printf("isSame: %s, %s\n", o1->toChars(), o2->toChars()); #if 0 printf("o1: %p\n", o1); printf("o2: %p\n", o2); if (!s1) { Expression *ea = isExpression(o1); if (ea) printf("%s\n", ea->toChars()); Type *ta = isType(o1); if (ta) printf("%s\n", ta->toChars()); goto Lfalse; } else printf("%s %s\n", s1->kind(), s1->toChars()); #endif if (!s1 && !s2) { Expression *ea1 = isExpression(o1); Expression *ea2 = isExpression(o2); if (ea1 && ea2) { if (ea1->equals(ea2)) goto Ltrue; } } if (!s1 || !s2) goto Lfalse; s1 = s1->toAlias(); s2 = s2->toAlias(); if (s1->isFuncAliasDeclaration()) s1 = ((FuncAliasDeclaration *)s1)->toAliasFunc(); if (s2->isFuncAliasDeclaration()) s2 = ((FuncAliasDeclaration *)s2)->toAliasFunc(); if (s1 == s2) goto Ltrue; else goto Lfalse; } else if (e->ident == Id::getUnitTests) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); if (!s) { e->error("argument %s to __traits(getUnitTests) must be a module or aggregate", o->toChars()); goto Lfalse; } Import *imp = s->isImport(); if (imp) // Bugzilla 10990 s = imp->mod; ScopeDsymbol* scope = s->isScopeDsymbol(); if (!scope) { e->error("argument %s to __traits(getUnitTests) must be a module or aggregate, not a %s", s->toChars(), s->kind()); goto Lfalse; } Expressions* unitTests = new Expressions(); Dsymbols* symbols = scope->members; if (global.params.useUnitTests && symbols) { // Should actually be a set AA* uniqueUnitTests = NULL; collectUnitTests(symbols, uniqueUnitTests, unitTests); } TupleExp *tup = new TupleExp(e->loc, unitTests); return tup->semantic(sc); } else if(e->ident == Id::getVirtualIndex) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); FuncDeclaration *fd; if (!s || (fd = s->isFuncDeclaration()) == NULL) { e->error("first argument to __traits(getVirtualIndex) must be a function"); goto Lfalse; } fd = fd->toAliasFunc(); // Neccessary to support multiple overloads. return new IntegerExp(e->loc, fd->vtblIndex, Type::tptrdiff_t); } else { if (const char *sub = (const char *)speller(e->ident->toChars(), &trait_search_fp, NULL, idchars)) e->error("unrecognized trait '%s', did you mean '%s'?", e->ident->toChars(), sub); else e->error("unrecognized trait '%s'", e->ident->toChars()); goto Lfalse; } return NULL; Ldimerror: e->error("wrong number of arguments %d", (int)dim); goto Lfalse; Lfalse: return new IntegerExp(e->loc, 0, Type::tbool); Ltrue: return new IntegerExp(e->loc, 1, Type::tbool); }
void Import::toJson(JsonOut *json) { if (id == Id::object) return; json->objectStart(); json->propertyStart("name"); json->stringStart(); if (packages && packages->dim) { for (size_t i = 0; i < packages->dim; i++) { Identifier *pid = (*packages)[i]; json->stringPart(pid->toChars()); json->buf->writeByte('.'); } } json->stringPart(id->toChars()); json->stringEnd(); json->comma(); json->property("kind", kind()); json->property("comment", (const char *)comment); json->property("line", &loc); if (prot() != PROTpublic) json->property("protection", Pprotectionnames[prot()]); if (aliasId) json->property("alias", aliasId->toChars()); bool hasRenamed = false; bool hasSelective = false; for (size_t i = 0; i < aliases.dim; i++) { // avoid empty "renamed" and "selective" sections if (hasRenamed && hasSelective) break; else if (aliases[i]) hasRenamed = true; else hasSelective = true; } if (hasRenamed) { // import foo : alias1 = target1; json->propertyStart("renamed"); json->objectStart(); for (size_t i = 0; i < aliases.dim; i++) { Identifier *name = names[i]; Identifier *alias = aliases[i]; if (alias) json->property(alias->toChars(), name->toChars()); } json->objectEnd(); } if (hasSelective) { // import foo : target1; json->propertyStart("selective"); json->arrayStart(); for (size_t i = 0; i < names.dim; i++) { Identifier *name = names[i]; if (!aliases[i]) json->item(name->toChars()); } json->arrayEnd(); } json->objectEnd(); }
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); }
Module *Module::load(Loc loc, Array *packages, Identifier *ident) { Module *m; char *filename; //printf("Module::load(ident = '%s')\n", ident->toChars()); // Build module filename by turning: // foo.bar.baz // into: // foo\bar\baz filename = ident->toChars(); if (packages && packages->dim) { OutBuffer buf; int i; for (i = 0; i < packages->dim; i++) { Identifier *pid = (Identifier *)packages->data[i]; buf.writestring(pid->toChars()); #if _WIN32 buf.writeByte('\\'); #else buf.writeByte('/'); #endif } buf.writestring(filename); buf.writeByte(0); filename = (char *)buf.extractData(); } m = new Module(filename, ident, 0, 0); m->loc = loc; /* Search along global.path for .di file, then .d file. */ char *result = NULL; FileName *fdi = FileName::forceExt(filename, global.hdr_ext); FileName *fd = FileName::forceExt(filename, global.mars_ext); char *sdi = fdi->toChars(); char *sd = fd->toChars(); if (FileName::exists(sdi)) result = sdi; else if (FileName::exists(sd)) result = sd; else if (FileName::absolute(filename)) ; else if (!global.path) ; else { for (size_t i = 0; i < global.path->dim; i++) { char *p = (char *)global.path->data[i]; char *n = FileName::combine(p, sdi); if (FileName::exists(n)) { result = n; break; } mem.free(n); n = FileName::combine(p, sd); if (FileName::exists(n)) { result = n; break; } mem.free(n); } } if (result) m->srcfile = new File(result); if (global.params.verbose) { printf("import "); if (packages) { for (size_t i = 0; i < packages->dim; i++) { Identifier *pid = (Identifier *)packages->data[i]; printf("%s.", pid->toChars()); } } printf("%s\t(%s)\n", ident->toChars(), m->srcfile->toChars()); } m->read(loc); m->parse(); #ifdef IN_GCC d_gcc_magic_module(m); #endif return m; }
FuncDeclaration *StructDeclaration::buildXopCmp(Scope *sc) { //printf("StructDeclaration::buildXopCmp() %s\n", toChars()); if (Dsymbol *cmp = search_function(this, Id::cmp)) { if (FuncDeclaration *fd = cmp->isFuncDeclaration()) { TypeFunction *tfcmpptr; { Scope sc; /* const int opCmp(ref const S s); */ Parameters *parameters = new Parameters; parameters->push(new Parameter(STCref | STCconst, type, NULL, NULL)); tfcmpptr = new TypeFunction(parameters, Type::tint32, 0, LINKd); tfcmpptr->mod = MODconst; tfcmpptr = (TypeFunction *)tfcmpptr->semantic(Loc(), &sc); } 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(loc, this); e = new DotIdExp(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 (!xerrcmp) { Identifier *id = Lexer::idPool("_xopCmp"); Expression *e = new IdentifierExp(loc, Id::empty); e = new DotIdExp(loc, e, Id::object); e = new DotIdExp(loc, e, id); e = e->semantic(sc); Dsymbol *s = getDsymbol(e); if (!s) { ::error(Loc(), "ICE: %s not found in object module. You must update druntime", id->toChars()); fatal(); } assert(s); 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, type, Id::p, NULL)); parameters->push(new Parameter(STCref | STCconst, type, Id::q, NULL)); TypeFunction *tf = new TypeFunction(parameters, Type::tint32, 0, LINKd); tf = (TypeFunction *)tf->semantic(loc, sc); Identifier *id = Lexer::idPool("__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, e1, Id::cmp), 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 = xerrcmp; return fop; }