void visit(NewExp *e) { if (e->member && !e->member->isNogc() && f->setGC()) { // @nogc-ness is already checked in NewExp::semantic return; } if (e->onstack) return; if (e->allocator) { if (!e->allocator->isNogc() && f->setGC()) { e->error("operator new in @nogc function %s may allocate", f->toChars()); err = true; return; } return; } if (f->setGC()) { e->error("cannot use 'new' in @nogc function %s", f->toChars()); err = true; return; } f->printGCUsage(e->loc, "'new' causes GC allocation"); }
char *mangle(Declaration *sthis) { OutBuffer buf; char *id; Dsymbol *s; //printf("::mangle(%s)\n", sthis->toChars()); s = sthis; do { //printf("mangle: s = %p, '%s', parent = %p\n", s, s->toChars(), s->parent); if (s->ident) { FuncDeclaration *fd = s->isFuncDeclaration(); if (s != sthis && fd) { id = mangle(fd); buf.prependstring(id); goto L1; } else { id = s->ident->toChars(); int len = strlen(id); char tmp[sizeof(len) * 3 + 1]; buf.prependstring(id); sprintf(tmp, "%d", len); buf.prependstring(tmp); } } else buf.prependstring("0"); s = s->parent; } while (s); // buf.prependstring("_D"); L1: //printf("deco = '%s'\n", sthis->type->deco ? sthis->type->deco : "null"); //printf("sthis->type = %s\n", sthis->type->toChars()); FuncDeclaration *fd = sthis->isFuncDeclaration(); if (fd && (fd->needThis() || fd->isNested())) buf.writeByte(Type::needThisPrefix()); if (sthis->type->deco) buf.writestring(sthis->type->deco); else { #ifdef DEBUG if (!fd->inferRetType) printf("%s\n", fd->toChars()); #endif assert(fd && fd->inferRetType); } id = buf.toChars(); buf.data = NULL; return id; }
void visit(CatExp *e) { if (f->setGC()) { e->error("cannot use operator ~ in @nogc function %s", f->toChars()); err = true; return; } f->printGCUsage(e->loc, "operator ~ may cause GC allocation"); }
void visit(ArrayLiteralExp *e) { if (e->type->ty != Tarray || !e->elements || !e->elements->dim) return; if (f->setGC()) { e->error("array literal in @nogc function %s may cause GC allocation", f->toChars()); err = true; return; } f->printGCUsage(e->loc, "array literal may cause GC allocation"); }
void DtoNestedInit(VarDeclaration* vd) { Logger::println("DtoNestedInit for %s", vd->toChars()); LOG_SCOPE IrFunction* irfunc = gIR->func()->decl->ir.irFunc; LLValue* nestedVar = irfunc->nestedVar; if (nestedCtx == NCArray) { // alloca as usual if no value already if (!vd->ir.irLocal->value) vd->ir.irLocal->value = DtoAlloca(vd->type, vd->toChars()); // store the address into the nested vars array assert(vd->ir.irLocal->nestedIndex >= 0); LLValue* gep = DtoGEPi(nestedVar, 0, vd->ir.irLocal->nestedIndex); assert(isaPointer(vd->ir.irLocal->value)); LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType()); DtoAlignedStore(val, gep); } else if (nestedCtx == NCHybrid) { assert(vd->ir.irLocal->value && "Nested variable without storage?"); if (!vd->isParameter() && (vd->isRef() || vd->isOut())) { unsigned vardepth = vd->ir.irLocal->nestedDepth; LLValue* val = NULL; // Retrieve frame pointer if (vardepth == irfunc->depth) { val = nestedVar; } else { FuncDeclaration *parentfunc = getParentFunc(vd, true); assert(parentfunc && "No parent function for nested variable?"); val = DtoGEPi(nestedVar, 0, vardepth); val = DtoAlignedLoad(val, (std::string(".frame.") + parentfunc->toChars()).c_str()); } val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); storeVariable(vd, val); } else { // Already initialized in DtoCreateNestedContext } } else { assert(0 && "Not implemented yet"); } }
void visit(ExpStatement *stmt) override { IF_LOG Logger::println("ExpStatement::toNakedIR(): %s", stmt->loc.toChars()); LOG_SCOPE; // This happens only if there is a ; at the end: // asm { naked; ... }; // Is this a legal AST? if (!stmt->exp) { return; } // only expstmt supported in declarations if (!stmt->exp || stmt->exp->op != TOKdeclaration) { visit(static_cast<Statement *>(stmt)); return; } DeclarationExp *d = static_cast<DeclarationExp *>(stmt->exp); VarDeclaration *vd = d->declaration->isVarDeclaration(); FuncDeclaration *fd = d->declaration->isFuncDeclaration(); EnumDeclaration *ed = d->declaration->isEnumDeclaration(); // and only static variable/function declaration // no locals or nested stuffies! if (!vd && !fd && !ed) { visit(static_cast<Statement *>(stmt)); return; } if (vd && !(vd->storage_class & (STCstatic | STCmanifest))) { error(vd->loc, "non-static variable `%s` not allowed in naked function", vd->toChars()); return; } if (fd && !fd->isStatic()) { error(fd->loc, "non-static nested function `%s` not allowed in naked function", fd->toChars()); return; } // enum decls should always be safe // make sure the symbols gets processed // TODO: codegen() here is likely incorrect Declaration_codegen(d->declaration, irs); }
void visit(DeleteExp *e) { if (e->e1->op == TOKvar) { VarDeclaration *v = ((VarExp *)e->e1)->var->isVarDeclaration(); if (v && v->onstack) return; // delete for scope allocated class object } if (f->setGC()) { e->error("cannot use 'delete' in @nogc function %s", f->toChars()); err = true; return; } f->printGCUsage(e->loc, "'delete' requires GC"); }
void ExpStatement::toNakedIR(IRState *p) { Logger::println("ExpStatement::toNakedIR(): %s", loc.toChars()); LOG_SCOPE; // only expstmt supported in declarations if (exp->op != TOKdeclaration) { Statement::toNakedIR(p); return; } DeclarationExp* d = static_cast<DeclarationExp*>(exp); VarDeclaration* vd = d->declaration->isVarDeclaration(); FuncDeclaration* fd = d->declaration->isFuncDeclaration(); EnumDeclaration* ed = d->declaration->isEnumDeclaration(); // and only static variable/function declaration // no locals or nested stuffies! if (!vd && !fd && !ed) { Statement::toNakedIR(p); return; } else if (vd && !(vd->storage_class & (STCstatic | STCmanifest))) { error("non-static variable '%s' not allowed in naked function", vd->toChars()); return; } else if (fd && !fd->isStatic()) { error("non-static nested function '%s' not allowed in naked function", fd->toChars()); return; } // enum decls should always be safe // make sure the symbols gets processed d->declaration->codegen(Type::sir); }
/****************************************************************************** * isv : for the enclosing auto functions of an inner class/struct type. * An aggregate type which defined inside auto function, it might * become Voldemort Type so its object might be returned. * This flag is necessary due to avoid mutual mangling * between return type and enclosing scope. See bugzilla 8847. */ char *mangleDecl(Declaration *sthis, bool isv) { OutBuffer buf; char *id; Dsymbol *s; //printf("::mangleDecl(%s)\n", sthis->toChars()); s = sthis; do { //printf("mangle: s = %p, '%s', parent = %p\n", s, s->toChars(), s->parent); if (s->getIdent()) { FuncDeclaration *fd = s->isFuncDeclaration(); if (s != sthis && fd) { id = mangleDecl(fd, isv); buf.prependstring(id); goto L1; } else { id = s->ident->toChars(); size_t len = strlen(id); char tmp[sizeof(len) * 3 + 1]; buf.prependstring(id); sprintf(tmp, "%d", (int)len); buf.prependstring(tmp); } } else buf.prependstring("0"); TemplateInstance *ti = s->isTemplateInstance(); if (ti && !ti->isTemplateMixin()) s = ti->tempdecl->parent; else s = s->parent; } while (s); // buf.prependstring("_D"); L1: //printf("deco = '%s'\n", sthis->type->deco ? sthis->type->deco : "null"); //printf("sthis->type = %s\n", sthis->type->toChars()); FuncDeclaration *fd = sthis->isFuncDeclaration(); if (fd && (fd->needThis() || fd->isNested())) buf.writeByte(Type::needThisPrefix()); if (isv && fd && (fd->inferRetType || getFuncTemplateDecl(fd))) { #if DDMD TypeFunction *tfn = (TypeFunction *)sthis->type->copy(); TypeFunction *tfo = (TypeFunction *)sthis->originalType; tfn->purity = tfo->purity; tfn->isnothrow = tfo->isnothrow; tfn->isproperty = tfo->isproperty; tfn->isref = fd->storage_class & STCauto ? false : tfo->isref; tfn->trust = tfo->trust; tfn->next = NULL; // do not mangle return type tfn->toDecoBuffer(&buf, 0); #else TypeFunction tfn = *(TypeFunction *)sthis->type; TypeFunction *tfo = (TypeFunction *)sthis->originalType; tfn.purity = tfo->purity; tfn.isnothrow = tfo->isnothrow; tfn.isproperty = tfo->isproperty; tfn.isref = fd->storage_class & STCauto ? false : tfo->isref; tfn.trust = tfo->trust; tfn.next = NULL; // do not mangle return type tfn.toDecoBuffer(&buf, 0); #endif } else if (sthis->type->deco) buf.writestring(sthis->type->deco); else { #ifdef DEBUG if (!fd->inferRetType) printf("%s\n", fd->toChars()); #endif assert(fd && fd->inferRetType && fd->type->ty == Tfunction); TypeFunction *tf = (TypeFunction *)sthis->type; Type *tn = tf->next; tf->next = NULL; // do not mangle undetermined return type tf->toDecoBuffer(&buf, 0); tf->next = tn; } id = buf.extractString(); return id; }
Expression *SymOffExp::castTo(Scope *sc, Type *t) { #if 0 printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", toChars(), type->toChars(), t->toChars()); #endif Expression *e = this; Type *tb = t->toBasetype(); Type *typeb = type->toBasetype(); if (tb != typeb) { // Look for pointers to functions where the functions are overloaded. FuncDeclaration *f; if (typeb->ty == Tpointer && typeb->next->ty == Tfunction && tb->ty == Tpointer && tb->next->ty == Tfunction) { f = var->isFuncDeclaration(); if (f) { f = f->overloadExactMatch(tb->next, m); if (f) { #if DMDV2 if (tb->ty == Tdelegate) { if (f->needThis() && hasThis(sc)) { e = new DelegateExp(loc, new ThisExp(loc), f); e = e->semantic(sc); } else if (f->isNested()) { e = new DelegateExp(loc, new IntegerExp(0), f); e = e->semantic(sc); } else if (f->needThis()) { error("no 'this' to create delegate for %s", f->toChars()); return new ErrorExp(); } else { error("cannot cast from function pointer to delegate"); return new ErrorExp(); } } else #endif { e = new SymOffExp(loc, f, 0); e->type = t; } #if DMDV2 f->tookAddressOf++; #endif return e; } } } e = Expression::castTo(sc, t); } else { e->type = t; } return e; }
void FuncDeclaration::toObjFile(int multiobj) { FuncDeclaration *func = this; ClassDeclaration *cd = func->parent->isClassDeclaration(); int reverse; int has_arguments; //printf("FuncDeclaration::toObjFile(%p, %s.%s)\n", func, parent->toChars(), func->toChars()); //if (type) printf("type = %s\n", func->type->toChars()); #if 0 //printf("line = %d\n",func->getWhere() / LINEINC); EEcontext *ee = env->getEEcontext(); if (ee->EEcompile == 2) { if (ee->EElinnum < (func->getWhere() / LINEINC) || ee->EElinnum > (func->endwhere / LINEINC) ) return; // don't compile this function ee->EEfunc = func->toSymbol(); } #endif if (semanticRun >= PASSobj) // if toObjFile() already run return; // If errors occurred compiling it, such as bugzilla 6118 if (type && type->ty == Tfunction && ((TypeFunction *)type)->next->ty == Terror) return; if (!func->fbody) { return; } if (func->isUnitTestDeclaration() && !global.params.useUnitTests) return; if (multiobj && !isStaticDtorDeclaration() && !isStaticCtorDeclaration()) { obj_append(this); return; } assert(semanticRun == PASSsemantic3done); semanticRun = PASSobj; if (global.params.verbose) printf("function %s\n",func->toChars()); Symbol *s = func->toSymbol(); func_t *f = s->Sfunc; #if TARGET_WINDOS /* This is done so that the 'this' pointer on the stack is the same * distance away from the function parameters, so that an overriding * function can call the nested fdensure or fdrequire of its overridden function * and the stack offsets are the same. */ if (isVirtual() && (fensure || frequire)) f->Fflags3 |= Ffakeeh; #endif #if TARGET_OSX s->Sclass = SCcomdat; #else s->Sclass = SCglobal; #endif for (Dsymbol *p = parent; p; p = p->parent) { if (p->isTemplateInstance()) { s->Sclass = SCcomdat; break; } } /* Vector operations should be comdat's */ if (isArrayOp) s->Sclass = SCcomdat; if (isNested()) { // if (!(config.flags3 & CFG3pic)) // s->Sclass = SCstatic; f->Fflags3 |= Fnested; } else { const char *libname = (global.params.symdebug) ? global.params.debuglibname : global.params.defaultlibname; // Pull in RTL startup code if (func->isMain()) { objextdef("_main"); #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS obj_ehsections(); // initialize exception handling sections #endif #if TARGET_WINDOS objextdef("__acrtused_con"); #endif obj_includelib(libname); s->Sclass = SCglobal; } else if (strcmp(s->Sident, "main") == 0 && linkage == LINKc) { #if TARGET_WINDOS objextdef("__acrtused_con"); // bring in C startup code obj_includelib("snn.lib"); // bring in C runtime library #endif s->Sclass = SCglobal; } else if (func->isWinMain()) { objextdef("__acrtused"); obj_includelib(libname); s->Sclass = SCglobal; } // Pull in RTL startup code else if (func->isDllMain()) { objextdef("__acrtused_dll"); obj_includelib(libname); s->Sclass = SCglobal; } } cstate.CSpsymtab = &f->Flocsym; // Find module m for this function Module *m = NULL; for (Dsymbol *p = parent; p; p = p->parent) { m = p->isModule(); if (m) break; } IRState irs(m, func); Dsymbols deferToObj; // write these to OBJ file later irs.deferToObj = &deferToObj; TypeFunction *tf; enum RET retmethod; symbol *shidden = NULL; Symbol *sthis = NULL; tym_t tyf; tyf = tybasic(s->Stype->Tty); //printf("linkage = %d, tyf = x%x\n", linkage, tyf); reverse = tyrevfunc(s->Stype->Tty); assert(func->type->ty == Tfunction); tf = (TypeFunction *)(func->type); has_arguments = (tf->linkage == LINKd) && (tf->varargs == 1); retmethod = tf->retStyle(); if (retmethod == RETstack) { // If function returns a struct, put a pointer to that // as the first argument ::type *thidden = tf->next->pointerTo()->toCtype(); char hiddenparam[5+4+1]; static int hiddenparami; // how many we've generated so far sprintf(hiddenparam,"__HID%d",++hiddenparami); shidden = symbol_name(hiddenparam,SCparameter,thidden); shidden->Sflags |= SFLtrue | SFLfree; #if DMDV1 if (func->nrvo_can && func->nrvo_var && func->nrvo_var->nestedref) #else if (func->nrvo_can && func->nrvo_var && func->nrvo_var->nestedrefs.dim) #endif type_setcv(&shidden->Stype, shidden->Stype->Tty | mTYvolatile); irs.shidden = shidden; this->shidden = shidden; } else { // Register return style cannot make nrvo. // Auto functions keep the nrvo_can flag up to here, // so we should eliminate it before entering backend. nrvo_can = 0; } if (vthis) { assert(!vthis->csym); sthis = vthis->toSymbol(); irs.sthis = sthis; if (!(f->Fflags3 & Fnested)) f->Fflags3 |= Fmember; } Symbol **params; unsigned pi; // Estimate number of parameters, pi pi = (v_arguments != NULL); if (parameters) pi += parameters->dim; // Allow extra 2 for sthis and shidden params = (Symbol **)alloca((pi + 2) * sizeof(Symbol *)); // Get the actual number of parameters, pi, and fill in the params[] pi = 0; if (v_arguments) { params[pi] = v_arguments->toSymbol(); pi += 1; } if (parameters) { for (size_t i = 0; i < parameters->dim; i++) { VarDeclaration *v = (*parameters)[i]; if (v->csym) { error("compiler error, parameter '%s', bugzilla 2962?", v->toChars()); assert(0); } params[pi + i] = v->toSymbol(); } pi += parameters->dim; } if (reverse) { // Reverse params[] entries for (size_t i = 0; i < pi/2; i++) { Symbol *sptmp = params[i]; params[i] = params[pi - 1 - i]; params[pi - 1 - i] = sptmp; } } if (shidden) { #if 0 // shidden becomes last parameter params[pi] = shidden; #else // shidden becomes first parameter memmove(params + 1, params, pi * sizeof(params[0])); params[0] = shidden; #endif pi++; } if (sthis) { #if 0 // sthis becomes last parameter params[pi] = sthis; #else // sthis becomes first parameter memmove(params + 1, params, pi * sizeof(params[0])); params[0] = sthis; #endif pi++; } if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) && linkage != LINKd && shidden && sthis) { /* swap shidden and sthis */ Symbol *sp = params[0]; params[0] = params[1]; params[1] = sp; } for (size_t i = 0; i < pi; i++) { Symbol *sp = params[i]; sp->Sclass = SCparameter; sp->Sflags &= ~SFLspill; sp->Sfl = FLpara; symbol_add(sp); } // Determine register assignments if (pi) { size_t numintegerregs = 0, numfloatregs = 0; const unsigned char* argregs = getintegerparamsreglist(tyf, &numintegerregs); const unsigned char* floatregs = getfloatparamsreglist(tyf, &numfloatregs); // Order of assignment of pointer or integer parameters int r = 0; int xmmcnt = 0; for (size_t i = 0; i < pi; i++) { Symbol *sp = params[i]; tym_t ty = tybasic(sp->Stype->Tty); // BUG: doesn't work for structs if (r < numintegerregs) { if ((I64 || (i == 0 && (tyf == TYjfunc || tyf == TYmfunc))) && type_jparam(sp->Stype)) { sp->Sclass = SCfastpar; sp->Spreg = argregs[r]; sp->Sfl = FLauto; ++r; } } if (xmmcnt < numfloatregs) { if (tyxmmreg(ty)) { sp->Sclass = SCfastpar; sp->Spreg = floatregs[xmmcnt]; sp->Sfl = FLauto; ++xmmcnt; } } } } if (func->fbody) { block *b; Blockx bx; Statement *sbody; localgot = NULL; sbody = func->fbody; memset(&bx,0,sizeof(bx)); bx.startblock = block_calloc(); bx.curblock = bx.startblock; bx.funcsym = s; bx.scope_index = -1; bx.classdec = cd; bx.member = func; bx.module = getModule(); irs.blx = &bx; #if DMDV2 buildClosure(&irs); #endif #if 0 if (func->isSynchronized()) { if (cd) { elem *esync; if (func->isStatic()) { // monitor is in ClassInfo esync = el_ptr(cd->toSymbol()); } else { // 'this' is the monitor esync = el_var(sthis); } if (func->isStatic() || sbody->usesEH() || !(config.flags2 & CFG2seh)) { // BUG: what if frequire or fensure uses EH? sbody = new SynchronizedStatement(func->loc, esync, sbody); } else { #if TARGET_WINDOS if (config.flags2 & CFG2seh) { /* The "jmonitor" uses an optimized exception handling frame * which is a little shorter than the more general EH frame. * It isn't strictly necessary. */ s->Sfunc->Fflags3 |= Fjmonitor; } #endif el_free(esync); } } else { error("synchronized function %s must be a member of a class", func->toChars()); } } #elif TARGET_WINDOS if (func->isSynchronized() && cd && config.flags2 & CFG2seh && !func->isStatic() && !sbody->usesEH()) { /* The "jmonitor" hack uses an optimized exception handling frame * which is a little shorter than the more general EH frame. */ s->Sfunc->Fflags3 |= Fjmonitor; } #endif sbody->toIR(&irs); bx.curblock->BC = BCret; f->Fstartblock = bx.startblock; // einit = el_combine(einit,bx.init); if (isCtorDeclaration()) { assert(sthis); for (b = f->Fstartblock; b; b = b->Bnext) { if (b->BC == BCret) { b->BC = BCretexp; b->Belem = el_combine(b->Belem, el_var(sthis)); } } } } // If static constructor #if DMDV2 if (isSharedStaticCtorDeclaration()) // must come first because it derives from StaticCtorDeclaration { ssharedctors.push(s); } else #endif if (isStaticCtorDeclaration()) { sctors.push(s); } // If static destructor #if DMDV2 if (isSharedStaticDtorDeclaration()) // must come first because it derives from StaticDtorDeclaration { SharedStaticDtorDeclaration *f = isSharedStaticDtorDeclaration(); assert(f); if (f->vgate) { /* Increment destructor's vgate at construction time */ esharedctorgates.push(f); } sshareddtors.shift(s); } else #endif if (isStaticDtorDeclaration()) { StaticDtorDeclaration *f = isStaticDtorDeclaration(); assert(f); if (f->vgate) { /* Increment destructor's vgate at construction time */ ectorgates.push(f); } sdtors.shift(s); } // If unit test if (isUnitTestDeclaration()) { stests.push(s); } if (global.errors) return; writefunc(s); if (isExport()) obj_export(s, Poffset); for (size_t i = 0; i < irs.deferToObj->dim; i++) { Dsymbol *s = (*irs.deferToObj)[i]; FuncDeclaration *fd = s->isFuncDeclaration(); if (fd) { FuncDeclaration *fdp = fd->toParent2()->isFuncDeclaration(); if (fdp && fdp->semanticRun < PASSobj) { /* Bugzilla 7595 * FuncDeclaration::buildClosure() relies on nested functions * being toObjFile'd after the outer function. Otherwise, the * v->offset's for the closure variables are wrong. * So, defer fd until after fdp is done. */ fdp->deferred.push(fd); continue; } } s->toObjFile(0); } for (size_t i = 0; i < deferred.dim; i++) { FuncDeclaration *fd = deferred[i]; fd->toObjFile(0); } #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS // A hack to get a pointer to this function put in the .dtors segment if (ident && memcmp(ident->toChars(), "_STD", 4) == 0) obj_staticdtor(s); #endif #if DMDV2 if (irs.startaddress) { printf("Setting start address\n"); obj_startaddress(irs.startaddress); } #endif }
LLConstant * IrAggr::getVtblInit() { if (constVtbl) return constVtbl; IF_LOG Logger::println("Building vtbl initializer"); LOG_SCOPE; ClassDeclaration* cd = aggrdecl->isClassDeclaration(); assert(cd && "not class"); std::vector<llvm::Constant*> constants; constants.reserve(cd->vtbl.dim); // start with the classinfo llvm::Constant* c = getClassInfoSymbol(); c = DtoBitCast(c, DtoType(ClassDeclaration::classinfo->type)); constants.push_back(c); // add virtual function pointers size_t n = cd->vtbl.dim; for (size_t i = 1; i < n; i++) { Dsymbol* dsym = static_cast<Dsymbol*>(cd->vtbl.data[i]); assert(dsym && "null vtbl member"); FuncDeclaration* fd = dsym->isFuncDeclaration(); assert(fd && "vtbl entry not a function"); if (cd->isAbstract() || (fd->isAbstract() && !fd->fbody)) { c = getNullValue(DtoType(fd->type->pointerTo())); } else { fd->codegen(Type::sir); assert(fd->ir.irFunc && "invalid vtbl function"); c = fd->ir.irFunc->func; if (cd->isFuncHidden(fd)) { /* fd is hidden from the view of this class. * If fd overlaps with any function in the vtbl[], then * issue 'hidden' error. */ for (size_t j = 1; j < n; j++) { if (j == i) continue; FuncDeclaration *fd2 = static_cast<Dsymbol *>(cd->vtbl.data[j])->isFuncDeclaration(); if (!fd2->ident->equals(fd->ident)) continue; if (fd->leastAsSpecialized(fd2) || fd2->leastAsSpecialized(fd)) { TypeFunction *tf = static_cast<TypeFunction *>(fd->type); if (tf->ty == Tfunction) cd->deprecation( "use of %s%s hidden by %s is deprecated. Use 'alias %s.%s %s;' to introduce base class overload set.", fd->toPrettyChars(), Parameter::argsTypesToChars(tf->parameters, tf->varargs), cd->toChars(), fd->parent->toChars(), fd->toChars(), fd->toChars() ); else cd->deprecation("use of %s hidden by %s is deprecated", fd->toPrettyChars(), cd->toChars()); c = DtoBitCast(LLVM_D_GetRuntimeFunction(gIR->module, "_d_hidden_func"), c->getType()); break; } } } } constants.push_back(c); } // build the constant struct LLType* vtblTy = stripModifiers(type)->irtype->isClass()->getVtbl(); constVtbl = LLConstantStruct::get(isaStruct(vtblTy), constants); #if 0 IF_LOG Logger::cout() << "constVtbl type: " << *constVtbl->getType() << std::endl; IF_LOG Logger::cout() << "vtbl type: " << *stripModifiers(type)->irtype->isClass()->getVtbl() << std::endl; #endif #if 0 size_t nc = constants.size(); for (size_t i = 0; i < nc; ++i) { if (constVtbl->getOperand(i)->getType() != vtblTy->getContainedType(i)) { Logger::cout() << "type mismatch for entry # " << i << " in vtbl initializer" << std::endl; constVtbl->getOperand(i)->dump(); vtblTy->getContainedType(i)->dump(); } } #endif assert(constVtbl->getType() == stripModifiers(type)->irtype->isClass()->getVtbl() && "vtbl initializer type mismatch"); return constVtbl; }
FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf) { //printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars()); FuncDeclaration *fdmatch = NULL; FuncDeclaration *fdambig = NULL; ClassDeclaration *cd = this; Dsymbols *vtbl = &cd->vtbl; while (1) { for (size_t i = 0; i < vtbl->dim; i++) { FuncDeclaration *fd = (*vtbl)[i]->isFuncDeclaration(); if (!fd) continue; // the first entry might be a ClassInfo //printf("\t[%d] = %s\n", i, fd->toChars()); if (ident == fd->ident && fd->type->covariant(tf) == 1) { //printf("fd->parent->isClassDeclaration() = %p\n", fd->parent->isClassDeclaration()); if (!fdmatch) goto Lfd; if (fd == fdmatch) goto Lfdmatch; { // Function type matcing: exact > covariant MATCH m1 = tf->equals(fd ->type) ? MATCHexact : MATCHnomatch; MATCH m2 = tf->equals(fdmatch->type) ? MATCHexact : MATCHnomatch; if (m1 > m2) goto Lfd; else if (m1 < m2) goto Lfdmatch; } { MATCH m1 = (tf->mod == fd ->type->mod) ? MATCHexact : MATCHnomatch; MATCH m2 = (tf->mod == fdmatch->type->mod) ? MATCHexact : MATCHnomatch; if (m1 > m2) goto Lfd; else if (m1 < m2) goto Lfdmatch; } { // The way of definition: non-mixin > mixin MATCH m1 = fd ->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch; MATCH m2 = fdmatch->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch; if (m1 > m2) goto Lfd; else if (m1 < m2) goto Lfdmatch; } Lambig: fdambig = fd; //printf("Lambig fdambig = %s %s [%s]\n", fdambig->toChars(), fdambig->type->toChars(), fdambig->loc.toChars()); continue; Lfd: fdmatch = fd, fdambig = NULL; //printf("Lfd fdmatch = %s %s [%s]\n", fdmatch->toChars(), fdmatch->type->toChars(), fdmatch->loc.toChars()); continue; Lfdmatch: continue; } //else printf("\t\t%d\n", fd->type->covariant(tf)); } if (!cd) break; vtbl = &cd->vtblFinal; cd = cd->baseClass; } if (fdambig) error("ambiguous virtual function %s", fdambig->toChars()); return fdmatch; }
void visit(ClassDeclaration *cd) { //printf("ClassDeclaration::toObjFile('%s')\n", cd->toChars()); if (cd->type->ty == Terror) { cd->error("had semantic errors when compiling"); return; } if (!cd->members) return; if (multiobj && !cd->hasStaticCtorOrDtor()) { obj_append(cd); return; } if (global.params.symdebug) toDebug(cd); assert(!cd->scope); // semantic() should have been run to completion enum_SC scclass = SCglobal; if (cd->isInstantiated()) scclass = SCcomdat; // Put out the members for (size_t i = 0; i < cd->members->dim; i++) { Dsymbol *member = (*cd->members)[i]; /* There might be static ctors in the members, and they cannot * be put in separate obj files. */ member->accept(this); } // Generate C symbols toSymbol(cd); toVtblSymbol(cd); Symbol *sinit = toInitializer(cd); ////////////////////////////////////////////// // Generate static initializer sinit->Sclass = scclass; sinit->Sfl = FLdata; ClassDeclaration_toDt(cd, &sinit->Sdt); out_readonly(sinit); outdata(sinit); ////////////////////////////////////////////// // Put out the TypeInfo genTypeInfo(cd->type, NULL); //toObjFile(cd->type->vtinfo, multiobj); ////////////////////////////////////////////// // Put out the ClassInfo cd->csym->Sclass = scclass; cd->csym->Sfl = FLdata; /* The layout is: { void **vptr; monitor_t monitor; byte[] initializer; // static initialization data char[] name; // class name void *[] vtbl; Interface[] interfaces; ClassInfo *base; // base class void *destructor; void *invariant; // class invariant ClassFlags flags; void *deallocator; OffsetTypeInfo[] offTi; void *defaultConstructor; //const(MemberInfo[]) function(string) xgetMembers; // module getMembers() function void *xgetRTInfo; //TypeInfo typeinfo; } */ dt_t *dt = NULL; unsigned offset = Target::classinfosize; // must be ClassInfo.size if (Type::typeinfoclass) { if (Type::typeinfoclass->structsize != Target::classinfosize) { #ifdef DEBUG printf("Target::classinfosize = x%x, Type::typeinfoclass->structsize = x%x\n", offset, Type::typeinfoclass->structsize); #endif cd->error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch."); fatal(); } } if (Type::typeinfoclass) dtxoff(&dt, toVtblSymbol(Type::typeinfoclass), 0, TYnptr); // vtbl for ClassInfo else dtsize_t(&dt, 0); // BUG: should be an assert() dtsize_t(&dt, 0); // monitor // initializer[] assert(cd->structsize >= 8 || (cd->cpp && cd->structsize >= 4)); dtsize_t(&dt, cd->structsize); // size dtxoff(&dt, sinit, 0, TYnptr); // initializer // name[] const char *name = cd->ident->toChars(); size_t namelen = strlen(name); if (!(namelen > 9 && memcmp(name, "TypeInfo_", 9) == 0)) { name = cd->toPrettyChars(); namelen = strlen(name); } dtsize_t(&dt, namelen); dtabytes(&dt, TYnptr, 0, namelen + 1, name); // vtbl[] dtsize_t(&dt, cd->vtbl.dim); dtxoff(&dt, cd->vtblsym, 0, TYnptr); // interfaces[] dtsize_t(&dt, cd->vtblInterfaces->dim); if (cd->vtblInterfaces->dim) dtxoff(&dt, cd->csym, offset, TYnptr); // (*) else dtsize_t(&dt, 0); // base if (cd->baseClass) dtxoff(&dt, toSymbol(cd->baseClass), 0, TYnptr); else dtsize_t(&dt, 0); // destructor if (cd->dtor) dtxoff(&dt, toSymbol(cd->dtor), 0, TYnptr); else dtsize_t(&dt, 0); // invariant if (cd->inv) dtxoff(&dt, toSymbol(cd->inv), 0, TYnptr); else dtsize_t(&dt, 0); // flags ClassFlags::Type flags = ClassFlags::hasOffTi; if (cd->isCOMclass()) flags |= ClassFlags::isCOMclass; if (cd->isCPPclass()) flags |= ClassFlags::isCPPclass; flags |= ClassFlags::hasGetMembers; flags |= ClassFlags::hasTypeInfo; if (cd->ctor) flags |= ClassFlags::hasCtor; for (ClassDeclaration *pc = cd; pc; pc = pc->baseClass) { if (pc->dtor) { flags |= ClassFlags::hasDtor; break; } } if (cd->isabstract) flags |= ClassFlags::isAbstract; for (ClassDeclaration *pc = cd; pc; pc = pc->baseClass) { if (pc->members) { for (size_t i = 0; i < pc->members->dim; i++) { Dsymbol *sm = (*pc->members)[i]; //printf("sm = %s %s\n", sm->kind(), sm->toChars()); if (sm->hasPointers()) goto L2; } } } flags |= ClassFlags::noPointers; L2: dtsize_t(&dt, flags); // deallocator if (cd->aggDelete) dtxoff(&dt, toSymbol(cd->aggDelete), 0, TYnptr); else dtsize_t(&dt, 0); // offTi[] dtsize_t(&dt, 0); dtsize_t(&dt, 0); // null for now, fix later // defaultConstructor if (cd->defaultCtor && !(cd->defaultCtor->storage_class & STCdisable)) dtxoff(&dt, toSymbol(cd->defaultCtor), 0, TYnptr); else dtsize_t(&dt, 0); // xgetRTInfo if (cd->getRTInfo) Expression_toDt(cd->getRTInfo, &dt); else if (flags & ClassFlags::noPointers) dtsize_t(&dt, 0); else dtsize_t(&dt, 1); //dtxoff(&dt, toSymbol(type->vtinfo), 0, TYnptr); // typeinfo ////////////////////////////////////////////// // Put out (*vtblInterfaces)[]. Must immediately follow csym, because // of the fixup (*) offset += cd->vtblInterfaces->dim * (4 * Target::ptrsize); for (size_t i = 0; i < cd->vtblInterfaces->dim; i++) { BaseClass *b = (*cd->vtblInterfaces)[i]; ClassDeclaration *id = b->sym; /* The layout is: * struct Interface * { * ClassInfo *interface; * void *[] vtbl; * size_t offset; * } */ // Fill in vtbl[] b->fillVtbl(cd, &b->vtbl, 1); dtxoff(&dt, toSymbol(id), 0, TYnptr); // ClassInfo // vtbl[] dtsize_t(&dt, id->vtbl.dim); dtxoff(&dt, cd->csym, offset, TYnptr); dtsize_t(&dt, b->offset); // this offset offset += id->vtbl.dim * Target::ptrsize; } // Put out the (*vtblInterfaces)[].vtbl[] // This must be mirrored with ClassDeclaration::baseVtblOffset() //printf("putting out %d interface vtbl[]s for '%s'\n", vtblInterfaces->dim, toChars()); for (size_t i = 0; i < cd->vtblInterfaces->dim; i++) { BaseClass *b = (*cd->vtblInterfaces)[i]; ClassDeclaration *id = b->sym; //printf(" interface[%d] is '%s'\n", i, id->toChars()); size_t j = 0; if (id->vtblOffset()) { // First entry is ClassInfo reference //dtxoff(&dt, toSymbol(id), 0, TYnptr); // First entry is struct Interface reference dtxoff(&dt, cd->csym, Target::classinfosize + i * (4 * Target::ptrsize), TYnptr); j = 1; } assert(id->vtbl.dim == b->vtbl.dim); for (; j < id->vtbl.dim; j++) { assert(j < b->vtbl.dim); #if 0 RootObject *o = b->vtbl[j]; if (o) { printf("o = %p\n", o); assert(o->dyncast() == DYNCAST_DSYMBOL); Dsymbol *s = (Dsymbol *)o; printf("s->kind() = '%s'\n", s->kind()); } #endif FuncDeclaration *fd = b->vtbl[j]; if (fd) dtxoff(&dt, toThunkSymbol(fd, b->offset), 0, TYnptr); else dtsize_t(&dt, 0); } } // Put out the overriding interface vtbl[]s. // This must be mirrored with ClassDeclaration::baseVtblOffset() //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset); ClassDeclaration *pc; for (pc = cd->baseClass; pc; pc = pc->baseClass) { for (size_t k = 0; k < pc->vtblInterfaces->dim; k++) { BaseClass *bs = (*pc->vtblInterfaces)[k]; FuncDeclarations bvtbl; if (bs->fillVtbl(cd, &bvtbl, 0)) { //printf("\toverriding vtbl[] for %s\n", bs->sym->toChars()); ClassDeclaration *id = bs->sym; size_t j = 0; if (id->vtblOffset()) { // First entry is ClassInfo reference //dtxoff(&dt, toSymbol(id), 0, TYnptr); // First entry is struct Interface reference dtxoff(&dt, toSymbol(pc), Target::classinfosize + k * (4 * Target::ptrsize), TYnptr); j = 1; } for (; j < id->vtbl.dim; j++) { assert(j < bvtbl.dim); FuncDeclaration *fd = bvtbl[j]; if (fd) dtxoff(&dt, toThunkSymbol(fd, bs->offset), 0, TYnptr); else dtsize_t(&dt, 0); } } } } cd->csym->Sdt = dt; // ClassInfo cannot be const data, because we use the monitor on it outdata(cd->csym); if (cd->isExport()) objmod->export_symbol(cd->csym, 0); ////////////////////////////////////////////// // Put out the vtbl[] //printf("putting out %s.vtbl[]\n", toChars()); dt = NULL; if (cd->vtblOffset()) dtxoff(&dt, cd->csym, 0, TYnptr); // first entry is ClassInfo reference for (size_t i = cd->vtblOffset(); i < cd->vtbl.dim; i++) { FuncDeclaration *fd = cd->vtbl[i]->isFuncDeclaration(); //printf("\tvtbl[%d] = %p\n", i, fd); if (fd && (fd->fbody || !cd->isAbstract())) { // Ensure function has a return value (Bugzilla 4869) fd->functionSemantic(); Symbol *s = toSymbol(fd); if (cd->isFuncHidden(fd)) { /* fd is hidden from the view of this class. * If fd overlaps with any function in the vtbl[], then * issue 'hidden' error. */ for (size_t j = 1; j < cd->vtbl.dim; j++) { if (j == i) continue; FuncDeclaration *fd2 = cd->vtbl[j]->isFuncDeclaration(); if (!fd2->ident->equals(fd->ident)) continue; if (fd->leastAsSpecialized(fd2) || fd2->leastAsSpecialized(fd)) { TypeFunction *tf = (TypeFunction *)fd->type; if (tf->ty == Tfunction) cd->error("use of %s%s is hidden by %s; use 'alias %s = %s.%s;' to introduce base class overload set", fd->toPrettyChars(), parametersTypeToChars(tf->parameters, tf->varargs), cd->toChars(), fd->toChars(), fd->parent->toChars(), fd->toChars()); else cd->error("use of %s is hidden by %s", fd->toPrettyChars(), cd->toChars()); break; } } } dtxoff(&dt, s, 0, TYnptr); } else dtsize_t(&dt, 0); } cd->vtblsym->Sdt = dt; cd->vtblsym->Sclass = scclass; cd->vtblsym->Sfl = FLdata; out_readonly(cd->vtblsym); outdata(cd->vtblsym); if (cd->isExport()) objmod->export_symbol(cd->vtblsym,0); }
void visit(AssignExp *e) { if (e->e1->op == TOKarraylength) { if (f->setGC()) { e->error("setting 'length' in @nogc function %s may cause GC allocation", f->toChars()); err = true; return; } f->printGCUsage(e->loc, "setting 'length' may cause GC allocation"); } }
void visit(IndexExp* e) { Type *t1b = e->e1->type->toBasetype(); if (t1b->ty == Taarray) { if (f->setGC()) { e->error("indexing an associative array in @nogc function %s may cause GC allocation", f->toChars()); err = true; return; } f->printGCUsage(e->loc, "indexing an associative array may cause GC allocation"); } }
LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) { Logger::println("DtoNestedContext for %s", sym->toPrettyChars()); LOG_SCOPE; IrFunction* irfunc = gIR->func(); bool fromParent = true; LLValue* val; // if this func has its own vars that are accessed by nested funcs // use its own context if (irfunc->nestedVar) { val = irfunc->nestedVar; fromParent = false; } // otherwise, it may have gotten a context from the caller else if (irfunc->nestArg) val = DtoLoad(irfunc->nestArg); // or just have a this argument else if (irfunc->thisArg) { AggregateDeclaration* ad = irfunc->decl->isMember2(); val = ad->isClassDeclaration() ? DtoLoad(irfunc->thisArg) : irfunc->thisArg; if (!ad->vthis) { // This is just a plain 'outer' reference of a class nested in a // function (but without any variables in the nested context). return val; } val = DtoLoad(DtoGEPi(val, 0, ad->vthis->ir.irField->index, ".vthis")); } else { // Use null instead of e.g. LLVM's undef to not break bitwise // comparison for instances of nested struct types which don't have any // nested references. return llvm::ConstantPointerNull::get(getVoidPtrType()); } struct FuncDeclaration* fd = 0; if (AggregateDeclaration *ad = sym->isAggregateDeclaration()) // If sym is a nested struct or a nested class, pass the frame // of the function where sym is declared. fd = ad->toParent()->isFuncDeclaration(); else if (FuncDeclaration* symfd = sym->isFuncDeclaration()) { // Make sure we've had a chance to analyze nested context usage DtoCreateNestedContextType(symfd); // if this is for a function that doesn't access variables from // enclosing scopes, it doesn't matter what we pass. // Tell LLVM about it by passing an 'undef'. if (symfd && symfd->ir.irFunc->depth == -1) return llvm::UndefValue::get(getVoidPtrType()); // If sym is a nested function, and it's parent context is different than the // one we got, adjust it. fd = getParentFunc(symfd, true); } if (fd) { Logger::println("For nested function, parent is %s", fd->toChars()); FuncDeclaration* ctxfd = irfunc->decl; Logger::println("Current function is %s", ctxfd->toChars()); if (fromParent) { ctxfd = getParentFunc(ctxfd, true); assert(ctxfd && "Context from outer function, but no outer function?"); } Logger::println("Context is from %s", ctxfd->toChars()); unsigned neededDepth = fd->ir.irFunc->depth; unsigned ctxDepth = ctxfd->ir.irFunc->depth; Logger::cout() << "Needed depth: " << neededDepth << '\n'; Logger::cout() << "Context depth: " << ctxDepth << '\n'; if (neededDepth >= ctxDepth) { // assert(neededDepth <= ctxDepth + 1 && "How are we going more than one nesting level up?"); // fd needs the same context as we do, so all is well Logger::println("Calling sibling function or directly nested function"); } else { val = DtoBitCast(val, LLPointerType::getUnqual(ctxfd->ir.irFunc->frameType)); val = DtoGEPi(val, 0, neededDepth); val = DtoAlignedLoad(val, (std::string(".frame.") + fd->toChars()).c_str()); } } Logger::cout() << "result = " << *val << '\n'; Logger::cout() << "of type " << *val->getType() << '\n'; return val; }
void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember) { int result; FuncDeclaration *f = sc->func; AggregateDeclaration *cdscope = sc->getStructClassScope(); enum PROT access; #if LOG printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n", toChars(), smember->toChars(), f ? f->toChars() : NULL, cdscope ? cdscope->toChars() : NULL); #endif Dsymbol *smemberparent = smember->toParent(); if (!smemberparent || !smemberparent->isAggregateDeclaration()) { #if LOG printf("not an aggregate member\n"); #endif return; // then it is accessible } // BUG: should enable this check //assert(smember->parent->isBaseOf(this, NULL)); if (smemberparent == this) { enum PROT access2 = smember->prot(); result = access2 >= PROTpublic || hasPrivateAccess(f) || isFriendOf(cdscope) || (access2 == PROTpackage && hasPackageAccess(sc, this)); #if LOG printf("result1 = %d\n", result); #endif } else if ((access = this->getAccess(smember)) >= PROTpublic) { result = 1; #if LOG printf("result2 = %d\n", result); #endif } else if (access == PROTpackage && hasPackageAccess(sc, this)) { result = 1; #if LOG printf("result3 = %d\n", result); #endif } else { result = accessCheckX(smember, f, this, cdscope); #if LOG printf("result4 = %d\n", result); #endif } if (!result) { error(loc, "member %s is not accessible", smember->toChars()); } }
void visit(AssocArrayLiteralExp *e) { if (!e->keys->dim) return; if (f->setGC()) { e->error("associative array literal in @nogc function %s may cause GC allocation", f->toChars()); err = true; return; } f->printGCUsage(e->loc, "associative array literal may cause GC allocation"); }
void FuncDeclaration::toObjFile(int multiobj) { Symbol *s; func_t *f; Symbol *senter; Symbol *sexit; FuncDeclaration *func = this; ClassDeclaration *cd = func->parent->isClassDeclaration(); int reverse; int i; int has_arguments; //printf("FuncDeclaration::toObjFile(%p, %s.%s)\n", func, parent->toChars(), func->toChars()); #if 0 //printf("line = %d\n",func->getWhere() / LINEINC); EEcontext *ee = env->getEEcontext(); if (ee->EEcompile == 2) { if (ee->EElinnum < (func->getWhere() / LINEINC) || ee->EElinnum > (func->endwhere / LINEINC) ) return; // don't compile this function ee->EEfunc = func->toSymbol(); } #endif if (multiobj && !isStaticDtorDeclaration() && !isStaticCtorDeclaration()) { obj_append(this); return; } if (semanticRun >= 5) // if toObjFile() already run return; semanticRun = 5; if (!func->fbody) { return; } if (func->isUnitTestDeclaration() && !global.params.useUnitTests) return; if (global.params.verbose) printf("function %s\n",func->toChars()); s = func->toSymbol(); f = s->Sfunc; #if TARGET_WINDOS /* This is done so that the 'this' pointer on the stack is the same * distance away from the function parameters, so that an overriding * function can call the nested fdensure or fdrequire of its overridden function * and the stack offsets are the same. */ if (isVirtual() && (fensure || frequire)) f->Fflags3 |= Ffakeeh; #endif #if TARGET_OSX s->Sclass = SCcomdat; #else s->Sclass = SCglobal; #endif for (Dsymbol *p = parent; p; p = p->parent) { if (p->isTemplateInstance()) { s->Sclass = SCcomdat; break; } } if (isNested()) { // if (!(config.flags3 & CFG3pic)) // s->Sclass = SCstatic; f->Fflags3 |= Fnested; } else { const char *libname = (global.params.symdebug) ? global.params.debuglibname : global.params.defaultlibname; // Pull in RTL startup code if (func->isMain()) { objextdef("_main"); #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS obj_ehsections(); // initialize exception handling sections #else objextdef("__acrtused_con"); #endif obj_includelib(libname); s->Sclass = SCglobal; } else if (strcmp(s->Sident, "main") == 0 && linkage == LINKc) s->Sclass = SCglobal; else if (func->isWinMain()) { objextdef("__acrtused"); obj_includelib(libname); s->Sclass = SCglobal; } // Pull in RTL startup code else if (func->isDllMain()) { objextdef("__acrtused_dll"); obj_includelib(libname); s->Sclass = SCglobal; } } cstate.CSpsymtab = &f->Flocsym; // Find module m for this function Module *m = NULL; for (Dsymbol *p = parent; p; p = p->parent) { m = p->isModule(); if (m) break; } IRState irs(m, func); Array deferToObj; // write these to OBJ file later irs.deferToObj = &deferToObj; TypeFunction *tf; enum RET retmethod; symbol *shidden = NULL; Symbol *sthis = NULL; tym_t tyf; tyf = tybasic(s->Stype->Tty); //printf("linkage = %d, tyf = x%x\n", linkage, tyf); reverse = tyrevfunc(s->Stype->Tty); assert(func->type->ty == Tfunction); tf = (TypeFunction *)(func->type); has_arguments = (tf->linkage == LINKd) && (tf->varargs == 1); retmethod = tf->retStyle(); if (retmethod == RETstack) { // If function returns a struct, put a pointer to that // as the first argument ::type *thidden = tf->next->pointerTo()->toCtype(); char hiddenparam[5+4+1]; static int hiddenparami; // how many we've generated so far sprintf(hiddenparam,"__HID%d",++hiddenparami); shidden = symbol_name(hiddenparam,SCparameter,thidden); shidden->Sflags |= SFLtrue | SFLfree; #if DMDV1 if (func->nrvo_can && func->nrvo_var && func->nrvo_var->nestedref) #else if (func->nrvo_can && func->nrvo_var && func->nrvo_var->nestedrefs.dim) #endif type_setcv(&shidden->Stype, shidden->Stype->Tty | mTYvolatile); irs.shidden = shidden; this->shidden = shidden; } if (vthis) { assert(!vthis->csym); sthis = vthis->toSymbol(); irs.sthis = sthis; if (!(f->Fflags3 & Fnested)) f->Fflags3 |= Fmember; } Symbol **params; unsigned pi; // Estimate number of parameters, pi pi = (v_arguments != NULL); if (parameters) pi += parameters->dim; // Allow extra 2 for sthis and shidden params = (Symbol **)alloca((pi + 2) * sizeof(Symbol *)); // Get the actual number of parameters, pi, and fill in the params[] pi = 0; if (v_arguments) { params[pi] = v_arguments->toSymbol(); pi += 1; } if (parameters) { for (i = 0; i < parameters->dim; i++) { VarDeclaration *v = (VarDeclaration *)parameters->data[i]; if (v->csym) { error("compiler error, parameter '%s', bugzilla 2962?", v->toChars()); assert(0); } params[pi + i] = v->toSymbol(); } pi += i; } if (reverse) { // Reverse params[] entries for (i = 0; i < pi/2; i++) { Symbol *sptmp; sptmp = params[i]; params[i] = params[pi - 1 - i]; params[pi - 1 - i] = sptmp; } } if (shidden) { #if 0 // shidden becomes last parameter params[pi] = shidden; #else // shidden becomes first parameter memmove(params + 1, params, pi * sizeof(params[0])); params[0] = shidden; #endif pi++; } if (sthis) { #if 0 // sthis becomes last parameter params[pi] = sthis; #else // sthis becomes first parameter memmove(params + 1, params, pi * sizeof(params[0])); params[0] = sthis; #endif pi++; } if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) && linkage != LINKd && shidden && sthis) { /* swap shidden and sthis */ Symbol *sp = params[0]; params[0] = params[1]; params[1] = sp; } for (i = 0; i < pi; i++) { Symbol *sp = params[i]; sp->Sclass = SCparameter; sp->Sflags &= ~SFLspill; sp->Sfl = FLpara; symbol_add(sp); } // First parameter goes in register if (pi) { Symbol *sp = params[0]; if ((tyf == TYjfunc || tyf == TYmfunc) && type_jparam(sp->Stype)) { sp->Sclass = SCfastpar; sp->Spreg = (tyf == TYjfunc) ? AX : CX; sp->Sfl = FLauto; //printf("'%s' is SCfastpar\n",sp->Sident); } } if (func->fbody) { block *b; Blockx bx; Statement *sbody; localgot = NULL; sbody = func->fbody; memset(&bx,0,sizeof(bx)); bx.startblock = block_calloc(); bx.curblock = bx.startblock; bx.funcsym = s; bx.scope_index = -1; bx.classdec = cd; bx.member = func; bx.module = getModule(); irs.blx = &bx; buildClosure(&irs); #if 0 if (func->isSynchronized()) { if (cd) { elem *esync; if (func->isStatic()) { // monitor is in ClassInfo esync = el_ptr(cd->toSymbol()); } else { // 'this' is the monitor esync = el_var(sthis); } if (func->isStatic() || sbody->usesEH() || !(config.flags2 & CFG2seh)) { // BUG: what if frequire or fensure uses EH? sbody = new SynchronizedStatement(func->loc, esync, sbody); } else { #if TARGET_WINDOS if (config.flags2 & CFG2seh) { /* The "jmonitor" uses an optimized exception handling frame * which is a little shorter than the more general EH frame. * It isn't strictly necessary. */ s->Sfunc->Fflags3 |= Fjmonitor; } #endif el_free(esync); } } else { error("synchronized function %s must be a member of a class", func->toChars()); } } #elif TARGET_WINDOS if (func->isSynchronized() && cd && config.flags2 & CFG2seh && !func->isStatic() && !sbody->usesEH()) { /* The "jmonitor" hack uses an optimized exception handling frame * which is a little shorter than the more general EH frame. */ s->Sfunc->Fflags3 |= Fjmonitor; } #endif sbody->toIR(&irs); bx.curblock->BC = BCret; f->Fstartblock = bx.startblock; // einit = el_combine(einit,bx.init); if (isCtorDeclaration()) { assert(sthis); for (b = f->Fstartblock; b; b = b->Bnext) { if (b->BC == BCret) { b->BC = BCretexp; b->Belem = el_combine(b->Belem, el_var(sthis)); } } } } // If static constructor if (isStaticConstructor()) { elem *e = el_una(OPucall, TYvoid, el_var(s)); ector = el_combine(ector, e); } // If static destructor if (isStaticDestructor()) { elem *e; #if STATICCTOR e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_FATEXIT]), el_ptr(s)); ector = el_combine(ector, e); dtorcount++; #else StaticDtorDeclaration *f = isStaticDtorDeclaration(); assert(f); if (f->vgate) { /* Increment destructor's vgate at construction time */ ectorgates.push(f); } e = el_una(OPucall, TYvoid, el_var(s)); edtor = el_combine(e, edtor); #endif } // If unit test if (isUnitTestDeclaration()) { elem *e = el_una(OPucall, TYvoid, el_var(s)); etest = el_combine(etest, e); } if (global.errors) return; writefunc(s); if (isExport()) obj_export(s, Poffset); for (i = 0; i < irs.deferToObj->dim; i++) { Dsymbol *s = (Dsymbol *)irs.deferToObj->data[i]; s->toObjFile(0); } #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS // A hack to get a pointer to this function put in the .dtors segment if (ident && memcmp(ident->toChars(), "_STD", 4) == 0) obj_staticdtor(s); #endif #if DMDV2 if (irs.startaddress) { printf("Setting start address\n"); obj_startaddress(irs.startaddress); } #endif }
/******************************* * Do access check for member of this class, this class being the * type of the 'this' pointer used to access smember. * Returns true if the member is not accessible. */ bool checkAccess(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember) { FuncDeclaration *f = sc->func; AggregateDeclaration *cdscope = sc->getStructClassScope(); #if LOG printf("AggregateDeclaration::checkAccess() for %s.%s in function %s() in scope %s\n", ad->toChars(), smember->toChars(), f ? f->toChars() : NULL, cdscope ? cdscope->toChars() : NULL); #endif Dsymbol *smemberparent = smember->toParent(); if (!smemberparent || !smemberparent->isAggregateDeclaration()) { #if LOG printf("not an aggregate member\n"); #endif return false; // then it is accessible } // BUG: should enable this check //assert(smember->parent->isBaseOf(this, NULL)); bool result; Prot access; if (smemberparent == ad) { Prot access2 = smember->prot(); result = access2.kind >= PROTpublic || hasPrivateAccess(ad, f) || isFriendOf(ad, cdscope) || (access2.kind == PROTpackage && hasPackageAccess(sc, ad)) || ad->getAccessModule() == sc->module; #if LOG printf("result1 = %d\n", result); #endif } else if ((access = getAccess(ad, smember)).kind >= PROTpublic) { result = true; #if LOG printf("result2 = %d\n", result); #endif } else if (access.kind == PROTpackage && hasPackageAccess(sc, ad)) { result = true; #if LOG printf("result3 = %d\n", result); #endif } else { result = isAccessible(smember, f, ad, cdscope); #if LOG printf("result4 = %d\n", result); #endif } if (!result) { ad->error(loc, "member %s is not accessible", smember->toChars()); //printf("smember = %s %s, prot = %d, semanticRun = %d\n", // smember->kind(), smember->toPrettyChars(), smember->prot(), smember->semanticRun); return true; } return false; }