/****************************************** * Common code for overloading of EqualExp and CmpExp */ Expression *BinExp::compare_overload(Scope *sc, Identifier *id) { //printf("BinExp::compare_overload(id = %s) %s\n", id->toChars(), toChars()); AggregateDeclaration *ad1 = isAggregate(e1->type); AggregateDeclaration *ad2 = isAggregate(e2->type); Dsymbol *s = NULL; Dsymbol *s_r = NULL; if (ad1) { s = search_function(ad1, id); } if (ad2) { s_r = search_function(ad2, id); if (s == s_r) s_r = NULL; } Objects *targsi = NULL; if (s || s_r) { /* Try: * a.opEquals(b) * b.opEquals(a) * and see which is better. */ Expressions args1; Expressions args2; args1.setDim(1); args1.tdata()[0] = e1; args2.setDim(1); args2.tdata()[0] = e2; Match m; memset(&m, 0, sizeof(m)); m.last = MATCHnomatch; if (0 && s && s_r) { printf("s : %s\n", s->toPrettyChars()); printf("s_r: %s\n", s_r->toPrettyChars()); } if (s) { FuncDeclaration *fd = s->isFuncDeclaration(); if (fd) { overloadResolveX(&m, fd, NULL, &args2, sc->module); } else { TemplateDeclaration *td = s->isTemplateDeclaration(); templateResolve(&m, td, sc, loc, targsi, NULL, &args2); } } FuncDeclaration *lastf = m.lastf; int count = m.count; if (s_r) { FuncDeclaration *fd = s_r->isFuncDeclaration(); if (fd) { overloadResolveX(&m, fd, NULL, &args1, sc->module); } else { TemplateDeclaration *td = s_r->isTemplateDeclaration(); templateResolve(&m, td, sc, loc, targsi, NULL, &args1); } } if (m.count > 1) { /* The following if says "not ambiguous" if there's one match * from s and one from s_r, in which case we pick s. * This doesn't follow the spec, but is a workaround for the case * where opEquals was generated from templates and we cannot figure * out if both s and s_r came from the same declaration or not. * The test case is: * import std.typecons; * void main() { * assert(tuple("has a", 2u) == tuple("has a", 1)); * } */ if (!(m.lastf == lastf && m.count == 2 && count == 1)) { // Error, ambiguous error("overloads %s and %s both match argument list for %s", m.lastf->type->toChars(), m.nextf->type->toChars(), m.lastf->toChars()); } } else if (m.last == MATCHnomatch) { m.lastf = m.anyf; } Expression *e; if (lastf && m.lastf == lastf || !s_r && m.last == MATCHnomatch) // Rewrite (e1 op e2) as e1.opfunc(e2) e = build_overload(loc, sc, e1, e2, m.lastf ? m.lastf : s); else { // Rewrite (e1 op e2) as e2.opfunc_r(e1) e = build_overload(loc, sc, e2, e1, m.lastf ? m.lastf : s_r); // When reversing operands of comparison operators, // need to reverse the sense of the op switch (op) { case TOKlt: op = TOKgt; break; case TOKgt: op = TOKlt; break; case TOKle: op = TOKge; break; case TOKge: op = TOKle; break; // Floating point compares case TOKule: op = TOKuge; break; case TOKul: op = TOKug; break; case TOKuge: op = TOKule; break; case TOKug: op = TOKul; break; // The rest are symmetric default: break; } } return e; } // Try alias this on first operand if (ad1 && ad1->aliasthis) { /* Rewrite (e1 op e2) as: * (e1.aliasthis op e2) */ Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); Expression *e = copy(); ((BinExp *)e)->e1 = e1; e = e->trySemantic(sc); return e; } // Try alias this on second operand if (ad2 && ad2->aliasthis) { /* Rewrite (e1 op e2) as: * (e1 op e2.aliasthis) */ Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); Expression *e = copy(); ((BinExp *)e)->e2 = e2; e = e->trySemantic(sc); return e; } return NULL; }
DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd, bool byref) { IF_LOG Logger::println("DtoNestedVariable for %s @ %s", vd->toChars(), loc.toChars()); LOG_SCOPE; //////////////////////////////////// // Locate context value Dsymbol *vdparent = vd->toParent2(); assert(vdparent); IrFunction *irfunc = gIR->func(); // Check whether we can access the needed frame FuncDeclaration *fd = irfunc->decl; while (fd && fd != vdparent) { fd = getParentFunc(fd); } if (!fd) { error(loc, "function `%s` cannot access frame of function `%s`", irfunc->decl->toPrettyChars(), vdparent->toPrettyChars()); return new DLValue(astype, llvm::UndefValue::get(DtoPtrToType(astype))); } // is the nested variable in this scope? if (vdparent == irfunc->decl) { return makeVarDValue(astype, vd); } // get the nested context LLValue *ctx = nullptr; bool skipDIDeclaration = false; auto currentCtx = gIR->funcGen().nestedVar; if (currentCtx) { Logger::println("Using own nested context of current function"); ctx = currentCtx; } else if (irfunc->decl->isMember2()) { Logger::println( "Current function is member of nested class, loading vthis"); AggregateDeclaration *cd = irfunc->decl->isMember2(); LLValue *val = irfunc->thisArg; if (cd->isClassDeclaration()) { val = DtoLoad(val); } ctx = DtoLoad(DtoGEPi(val, 0, getVthisIdx(cd), ".vthis")); skipDIDeclaration = true; } else { Logger::println("Regular nested function, loading context arg"); ctx = DtoLoad(irfunc->nestArg); } assert(ctx); IF_LOG { Logger::cout() << "Context: " << *ctx << '\n'; } DtoCreateNestedContextType(vdparent->isFuncDeclaration()); assert(isIrLocalCreated(vd)); //////////////////////////////////// // Extract variable from nested context const auto frameType = LLPointerType::getUnqual(irfunc->frameType); IF_LOG { Logger::cout() << "casting to: " << *irfunc->frameType << '\n'; } LLValue *val = DtoBitCast(ctx, frameType); IrLocal *const irLocal = getIrLocal(vd); const auto vardepth = irLocal->nestedDepth; const auto funcdepth = irfunc->depth; IF_LOG { Logger::cout() << "Variable: " << vd->toChars() << '\n'; Logger::cout() << "Variable depth: " << vardepth << '\n'; Logger::cout() << "Function: " << irfunc->decl->toChars() << '\n'; Logger::cout() << "Function depth: " << funcdepth << '\n'; } if (vardepth == funcdepth) { // This is not always handled above because functions without // variables accessed by nested functions don't create new frames. IF_LOG Logger::println("Same depth"); } else { // Load frame pointer and index that... IF_LOG Logger::println("Lower depth"); val = DtoGEPi(val, 0, vardepth); IF_LOG Logger::cout() << "Frame index: " << *val << '\n'; val = DtoAlignedLoad( val, (std::string(".frame.") + vdparent->toChars()).c_str()); IF_LOG Logger::cout() << "Frame: " << *val << '\n'; } const auto idx = irLocal->nestedIndex; assert(idx != -1 && "Nested context not yet resolved for variable."); LLSmallVector<int64_t, 2> dwarfAddrOps; LLValue *gep = DtoGEPi(val, 0, idx, vd->toChars()); val = gep; IF_LOG { Logger::cout() << "Addr: " << *val << '\n'; Logger::cout() << "of type: " << *val->getType() << '\n'; } const bool isRefOrOut = vd->isRef() || vd->isOut(); if (isSpecialRefVar(vd)) { // Handled appropriately by makeVarDValue() and EmitLocalVariable(), pass // storage of pointer (reference lvalue). } else if (byref || isRefOrOut) { val = DtoAlignedLoad(val); // ref/out variables get a reference-debuginfo-type in EmitLocalVariable(); // pass the GEP as reference lvalue in that case. if (!isRefOrOut) gIR->DBuilder.OpDeref(dwarfAddrOps); IF_LOG { Logger::cout() << "Was byref, now: " << *irLocal->value << '\n'; Logger::cout() << "of type: " << *irLocal->value->getType() << '\n'; } }
Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) { //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0; // Look in symbols declared in this module Dsymbol *s1 = symtab ? symtab->lookup(ident) : NULL; //printf("\ts1 = %p, imports = %p, %d\n", s1, imports, imports ? imports->dim : 0); if (s1) { //printf("\ts = '%s.%s'\n",toChars(),s1->toChars()); return s1; } else if (!imports) return NULL; else { Dsymbol *s = NULL; OverloadSet *a = NULL; // Look in imported modules for (size_t i = 0; i < imports->dim; i++) { // If private import, don't search it if (flags & 1 && prots[i] == PROTprivate) continue; Dsymbol *ss = (*imports)[i]; //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); /* Don't find private members if ss is a module */ Dsymbol *s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0); if (!s) s = s2; else if (s2 && s != s2) { if (s->toAlias() == s2->toAlias() || s->getType() == s2->getType() && s->getType()) { /* After following aliases, we found the same * symbol, so it's not an ambiguity. But if one * alias is deprecated or less accessible, prefer * the other. */ if (s->isDeprecated() || s2->prot() > s->prot() && s2->prot() != PROTnone) s = s2; } else { /* Two imports of the same module should be regarded as * the same. */ Import *i1 = s->isImport(); Import *i2 = s2->isImport(); if (!(i1 && i2 && (i1->mod == i2->mod || (!i1->parent->isImport() && !i2->parent->isImport() && i1->ident->equals(i2->ident)) ) ) ) { /* Bugzilla 8668: * Public selective import adds AliasDeclaration in module. * To make an overload set, resolve aliases in here and * get actual overload roots which accessible via s and s2. */ s = s->toAlias(); s2 = s2->toAlias(); /* If both s2 and s are overloadable (though we only * need to check s once) */ if (s2->isOverloadable() && (a || s->isOverloadable())) { if (!a) { a = new OverloadSet(s->ident); a->parent = this; } /* Don't add to a[] if s2 is alias of previous sym */ for (size_t j = 0; j < a->a.dim; j++) { Dsymbol *s3 = a->a[j]; if (s2->toAlias() == s3->toAlias()) { if (s3->isDeprecated() || s2->prot() > s3->prot() && s2->prot() != PROTnone) a->a[j] = s2; goto Lcontinue; } } a->push(s2); Lcontinue: continue; } if (flags & 4) // if return NULL on ambiguity return NULL; if (!(flags & 2)) ScopeDsymbol::multiplyDefined(loc, s, s2); break; } } } } /* Build special symbol if we had multiple finds */ if (a) { assert(s); a->push(s); s = a; } if (s) { if (!(flags & 2) && s->prot() == PROTprivate && !s->parent->isTemplateMixin()) { if (!s->isImport()) error(loc, "%s %s is private", s->kind(), s->toPrettyChars()); } } return s; } }
DValue* DtoNestedVariable(Loc& loc, Type* astype, VarDeclaration* vd, bool byref) { IF_LOG Logger::println("DtoNestedVariable for %s @ %s", vd->toChars(), loc.toChars()); LOG_SCOPE; //////////////////////////////////// // Locate context value Dsymbol* vdparent = vd->toParent2(); assert(vdparent); IrFunction* irfunc = gIR->func(); // Check whether we can access the needed frame FuncDeclaration *fd = irfunc->decl; while (fd != vdparent) { if (fd->isStatic()) { error(loc, "function %s cannot access frame of function %s", irfunc->decl->toPrettyChars(), vdparent->toPrettyChars()); return new DVarValue(astype, vd, llvm::UndefValue::get(getPtrToType(DtoType(astype)))); } fd = getParentFunc(fd, false); assert(fd); } // is the nested variable in this scope? if (vdparent == irfunc->decl) { LLValue* val = vd->ir.getIrValue(); return new DVarValue(astype, vd, val); } LLValue *dwarfValue = 0; std::vector<LLValue*> dwarfAddr; // get the nested context LLValue* ctx = 0; if (irfunc->nestedVar) { // If this function has its own nested context struct, always load it. ctx = irfunc->nestedVar; dwarfValue = ctx; } else if (irfunc->decl->isMember2()) { // If this is a member function of a nested class without its own // context, load the vthis member. AggregateDeclaration* cd = irfunc->decl->isMember2(); LLValue* val = irfunc->thisArg; if (cd->isClassDeclaration()) val = DtoLoad(val); ctx = DtoLoad(DtoGEPi(val, 0, cd->vthis->ir.irField->index, ".vthis")); } else { // Otherwise, this is a simple nested function, load from the context // argument. ctx = DtoLoad(irfunc->nestArg); dwarfValue = irfunc->nestArg; if (global.params.symdebug) gIR->DBuilder.OpDeref(dwarfAddr); } assert(ctx); DtoCreateNestedContextType(vdparent->isFuncDeclaration()); assert(vd->ir.irLocal); //////////////////////////////////// // Extract variable from nested context LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(irfunc->frameType)); IF_LOG { Logger::cout() << "Context: " << *val << '\n'; Logger::cout() << "of type: " << *irfunc->frameType << '\n'; } unsigned vardepth = vd->ir.irLocal->nestedDepth; unsigned funcdepth = irfunc->depth; IF_LOG { Logger::cout() << "Variable: " << vd->toChars() << '\n'; Logger::cout() << "Variable depth: " << vardepth << '\n'; Logger::cout() << "Function: " << irfunc->decl->toChars() << '\n'; Logger::cout() << "Function depth: " << funcdepth << '\n'; } if (vardepth == funcdepth) { // This is not always handled above because functions without // variables accessed by nested functions don't create new frames. IF_LOG Logger::println("Same depth"); } else { // Load frame pointer and index that... if (dwarfValue && global.params.symdebug) { gIR->DBuilder.OpOffset(dwarfAddr, val, vd->ir.irLocal->nestedDepth); gIR->DBuilder.OpDeref(dwarfAddr); } IF_LOG Logger::println("Lower depth"); val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth); IF_LOG Logger::cout() << "Frame index: " << *val << '\n'; val = DtoAlignedLoad(val, (std::string(".frame.") + vdparent->toChars()).c_str()); IF_LOG Logger::cout() << "Frame: " << *val << '\n'; } int idx = vd->ir.irLocal->nestedIndex; assert(idx != -1 && "Nested context not yet resolved for variable."); if (dwarfValue && global.params.symdebug) gIR->DBuilder.OpOffset(dwarfAddr, val, idx); val = DtoGEPi(val, 0, idx, vd->toChars()); IF_LOG { Logger::cout() << "Addr: " << *val << '\n'; Logger::cout() << "of type: " << *val->getType() << '\n'; } if (byref || (vd->isParameter() && vd->ir.irParam->arg->byref)) { val = DtoAlignedLoad(val); //dwarfOpDeref(dwarfAddr); IF_LOG { Logger::cout() << "Was byref, now: " << *val << '\n'; Logger::cout() << "of type: " << *val->getType() << '\n'; } }
/************************************ * Perform unqualified name lookup by following the chain of scopes up * until found. * * Params: * loc = location to use for error messages * ident = name to look up * pscopesym = if supplied and name is found, set to scope that ident was found in * flags = modify search based on flags * * Returns: * symbol if found, null if not */ Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags) { // This function is called only for unqualified lookup assert(!(flags & (SearchLocalsOnly | SearchImportsOnly))); /* If ident is "start at module scope", only look at module scope */ if (ident == Id::empty) { // Look for module scope for (Scope *sc = this; sc; sc = sc->enclosing) { assert(sc != sc->enclosing); if (!sc->scopesym) continue; if (Dsymbol *s = sc->scopesym->isModule()) { if (pscopesym) *pscopesym = sc->scopesym; return s; } } return NULL; } if (this->flags & SCOPEignoresymbolvisibility) flags |= IgnoreSymbolVisibility; Dsymbol *sold = NULL; if (global.params.bug10378 || global.params.check10378) { sold = searchScopes(this, loc, ident, pscopesym, flags | IgnoreSymbolVisibility); if (!global.params.check10378) return sold; if (ident == Id::dollar) // Bugzilla 15825 return sold; // Search both ways } // First look in local scopes Dsymbol *s = searchScopes(this, loc, ident, pscopesym, flags | SearchLocalsOnly); if (!s) { // Second look in imported modules s = searchScopes(this, loc, ident, pscopesym, flags | SearchImportsOnly); /** Still find private symbols, so that symbols that weren't access * checked by the compiler remain usable. Once the deprecation is over, * this should be moved to search_correct instead. */ if (!s && !(flags & IgnoreSymbolVisibility)) { s = searchScopes(this, loc, ident, pscopesym, flags | SearchLocalsOnly | IgnoreSymbolVisibility); if (!s) s = searchScopes(this, loc, ident, pscopesym, flags | SearchImportsOnly | IgnoreSymbolVisibility); if (s && !(flags & IgnoreErrors)) ::deprecation(loc, "%s is not visible from module %s", s->toPrettyChars(), _module->toChars()); } } if (global.params.check10378) { Dsymbol *snew = s; if (sold != snew) deprecation10378(loc, sold, snew); if (global.params.bug10378) s = sold; } return s; }
void Import::load(Scope *sc) { //printf("Import::load('%s') %p\n", toPrettyChars(), this); // See if existing module DsymbolTable *dst = Package::resolve(packages, NULL, &pkg); #if 0 if (pkg && pkg->isModule()) { ::error(loc, "can only import from a module, not from a member of module %s. Did you mean `import %s : %s`?", pkg->toChars(), pkg->toPrettyChars(), id->toChars()); mod = pkg->isModule(); // Error recovery - treat as import of that module return; } #endif Dsymbol *s = dst->lookup(id); if (s) { if (s->isModule()) mod = (Module *)s; else { if (s->isAliasDeclaration()) { ::error(loc, "%s %s conflicts with %s", s->kind(), s->toPrettyChars(), id->toChars()); } else if (Package *p = s->isPackage()) { if (p->isPkgMod == PKGunknown) { mod = Module::load(loc, packages, id); if (!mod) p->isPkgMod = PKGpackage; else assert(p->isPkgMod == PKGmodule); } else { mod = p->isPackageMod(); } if (!mod) { ::error(loc, "can only import from a module, not from package %s.%s", p->toPrettyChars(), id->toChars()); } } else if (pkg) { ::error(loc, "can only import from a module, not from package %s.%s", pkg->toPrettyChars(), id->toChars()); } else { ::error(loc, "can only import from a module, not from package %s", id->toChars()); } } } if (!mod) { // Load module mod = Module::load(loc, packages, id); if (mod) { dst->insert(id, mod); // id may be different from mod->ident, // if so then insert alias } } if (mod && !mod->importedFrom) mod->importedFrom = sc ? sc->module->importedFrom : Module::rootModule; if (!pkg) pkg = mod; //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg); }
DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref) { Logger::println("DtoNestedVariable for %s @ %s", vd->toChars(), loc.toChars()); LOG_SCOPE; //////////////////////////////////// // Locate context value Dsymbol* vdparent = vd->toParent2(); assert(vdparent); IrFunction* irfunc = gIR->func(); // Check whether we can access the needed frame FuncDeclaration *fd = irfunc->decl; while (fd != vdparent) { if (fd->isStatic()) { error(loc, "function %s cannot access frame of function %s", irfunc->decl->toPrettyChars(), vdparent->toPrettyChars()); return new DVarValue(astype, vd, llvm::UndefValue::get(getPtrToType(DtoType(astype)))); } fd = getParentFunc(fd, false); assert(fd); } // is the nested variable in this scope? if (vdparent == irfunc->decl) { LLValue* val = vd->ir.getIrValue(); return new DVarValue(astype, vd, val); } LLValue *dwarfValue = 0; std::vector<LLValue*> dwarfAddr; LLType *int64Ty = LLType::getInt64Ty(gIR->context()); // get the nested context LLValue* ctx = 0; if (irfunc->decl->isMember2()) { #if DMDV2 AggregateDeclaration* cd = irfunc->decl->isMember2(); LLValue* val = irfunc->thisArg; if (cd->isClassDeclaration()) val = DtoLoad(val); #else ClassDeclaration* cd = irfunc->decl->isMember2()->isClassDeclaration(); LLValue* val = DtoLoad(irfunc->thisArg); #endif ctx = DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis")); } else if (irfunc->nestedVar) { ctx = irfunc->nestedVar; dwarfValue = ctx; } else { ctx = DtoLoad(irfunc->nestArg); dwarfValue = irfunc->nestArg; if (global.params.symdebug) dwarfOpDeref(dwarfAddr); } assert(ctx); DtoCreateNestedContextType(vdparent->isFuncDeclaration()); assert(vd->ir.irLocal); //////////////////////////////////// // Extract variable from nested context if (nestedCtx == NCArray) { LLValue* val = DtoBitCast(ctx, getPtrToType(getVoidPtrType())); val = DtoGEPi1(val, vd->ir.irLocal->nestedIndex); val = DtoAlignedLoad(val); assert(vd->ir.irLocal->value); val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars()); return new DVarValue(astype, vd, val); } else if (nestedCtx == NCHybrid) { LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(irfunc->frameType)); Logger::cout() << "Context: " << *val << '\n'; Logger::cout() << "of type: " << *val->getType() << '\n'; unsigned vardepth = vd->ir.irLocal->nestedDepth; unsigned funcdepth = irfunc->depth; Logger::cout() << "Variable: " << vd->toChars() << '\n'; Logger::cout() << "Variable depth: " << vardepth << '\n'; Logger::cout() << "Function: " << irfunc->decl->toChars() << '\n'; Logger::cout() << "Function depth: " << funcdepth << '\n'; if (vardepth == funcdepth) { // This is not always handled above because functions without // variables accessed by nested functions don't create new frames. Logger::println("Same depth"); } else { // Load frame pointer and index that... if (dwarfValue && global.params.symdebug) { dwarfOpOffset(dwarfAddr, val, vd->ir.irLocal->nestedDepth); dwarfOpDeref(dwarfAddr); } Logger::println("Lower depth"); val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth); Logger::cout() << "Frame index: " << *val << '\n'; val = DtoAlignedLoad(val, (std::string(".frame.") + vdparent->toChars()).c_str()); Logger::cout() << "Frame: " << *val << '\n'; } if (dwarfValue && global.params.symdebug) dwarfOpOffset(dwarfAddr, val, vd->ir.irLocal->nestedIndex); val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); Logger::cout() << "Addr: " << *val << '\n'; Logger::cout() << "of type: " << *val->getType() << '\n'; if (vd->ir.irLocal->byref || byref) { val = DtoAlignedLoad(val); //dwarfOpDeref(dwarfAddr); Logger::cout() << "Was byref, now: " << *val << '\n'; Logger::cout() << "of type: " << *val->getType() << '\n'; } if (dwarfValue && global.params.symdebug) DtoDwarfLocalVariable(dwarfValue, vd, dwarfAddr); return new DVarValue(astype, vd, val); } else { assert(0 && "Not implemented yet"); } }