void scanVar(Dsymbol *s, InlineScanState *iss) { VarDeclaration *vd = s->isVarDeclaration(); if (vd) { TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); if (td) { for (size_t i = 0; i < td->objects->dim; i++) { DsymbolExp *se = (DsymbolExp *)td->objects->data[i]; assert(se->op == TOKdsymbol); scanVar(se->s, iss); } } else { // Scan initializer (vd->init) if (vd->init) { ExpInitializer *ie = vd->init->isExpInitializer(); if (ie) { ie->exp = ie->exp->inlineScan(iss); } } } } }
Expression *scanVar(Dsymbol *s, InlineScanState *iss) { //printf("scanVar(%s %s)\n", s->kind(), s->toPrettyChars()); VarDeclaration *vd = s->isVarDeclaration(); if (vd) { TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); if (td) { for (size_t i = 0; i < td->objects->dim; i++) { DsymbolExp *se = (DsymbolExp *)(*td->objects)[i]; assert(se->op == TOKdsymbol); scanVar(se->s, iss); // TODO } } else if (vd->init) { if (ExpInitializer *ie = vd->init->isExpInitializer()) { Expression *e = ie->exp->inlineScan(iss); if (vd->init != ie) // DeclareExp with vd appears in e return e; ie->exp = e; } } } else { s->inlineScan(); } return NULL; }
/*************************************** * Return true if struct is POD (Plain Old Data). * This is defined as: * not nested * no postblits, constructors, destructors, or assignment operators * no fields with with any of those * The idea being these are compatible with C structs. * * Note that D struct constructors can mean POD, since there is always default * construction with no ctor, but that interferes with OPstrpar which wants it * on the stack in memory, not in registers. */ bool StructDeclaration::isPOD() { if (enclosing || cpctor || postblit || ctor || dtor) return false; /* Recursively check any fields have a constructor. * We should cache the results of this. */ for (size_t i = 0; i < fields.dim; i++) { Dsymbol *s = fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->isField()); if (v->storage_class & STCref) continue; Type *tv = v->type->toBasetype(); while (tv->ty == Tsarray) { TypeSArray *ta = (TypeSArray *)tv; tv = tv->nextOf()->toBasetype(); } if (tv->ty == Tstruct) { TypeStruct *ts = (TypeStruct *)tv; StructDeclaration *sd = ts->sym; if (!sd->isPOD()) return false; } } return true; }
void visit(DeclarationExp *e) { VarDeclaration *v = e->declaration->isVarDeclaration(); if (v) { result = v->checkNestedReference(sc, Loc()); if (result) return; /* Some expressions cause the frontend to create a temporary. * For example, structs with cpctors replace the original * expression e with: * __cpcttmp = __cpcttmp.cpctor(e); * * In this instance, we need to ensure that the original * expression e does not have any nested references by * checking the declaration initializer too. */ if (v->_init && v->_init->isExpInitializer()) { Expression *ie = initializerToExpression(v->_init); result = lambdaCheckForNestedRef(ie, sc); } } }
void visit(IndexExp *e) { if (e->e1->op == TOKvar) { VarDeclaration *v = ((VarExp *)e->e1)->var->isVarDeclaration(); if (v && v->toParent2() == sc->func) { Type *tb = v->type->toBasetype(); if (tb->ty == Tarray || tb->ty == Tsarray) { if (v->storage_class & STCvariadic) { error(e->loc, "escaping reference to the payload of variadic parameter %s", v); return; } } } } Type *tb = e->e1->type->toBasetype(); if (tb->ty == Tsarray) { e->e1->accept(this); } }
void VarExp::scanForNestedRef(Scope *sc) { //printf("VarExp::scanForNestedRef(%s)\n", toChars()); VarDeclaration *v = var->isVarDeclaration(); if (v) v->checkNestedReference(sc, 0); }
void visit(VarExp *e) { VarDeclaration *v = e->var->isVarDeclaration(); if (v) { Type *tb = v->type->toBasetype(); if (v->isScope()) { /* Today, scope attribute almost doesn't work for escape analysis. * Until the semantics will be completed, it should be left as-is. * See also: fail_compilation/fail_scope.d */ if (tb->ty == Tarray || tb->ty == Tsarray || tb->ty == Tclass || tb->ty == Tdelegate) { if ((!v->noscope || tb->ty == Tclass)) { error(e->loc, "escaping reference to scope local %s", v); return; } } } if (v->storage_class & STCvariadic) { if (tb->ty == Tarray || tb->ty == Tsarray) error(e->loc, "escaping reference to variadic parameter %s", v); } } }
Expression *DeclarationExp::doInline(InlineDoState *ids) { DeclarationExp *de = (DeclarationExp *)copy(); VarDeclaration *vd; //printf("DeclarationExp::doInline(%s)\n", toChars()); vd = declaration->isVarDeclaration(); if (vd) { #if 0 // Need to figure this out before inlining can work for tuples TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); if (td) { for (size_t i = 0; i < td->objects->dim; i++) { DsymbolExp *se = (DsymbolExp *)td->objects->data[i]; assert(se->op == TOKdsymbol); se->s; } return st->objects->dim; } #endif if (vd->isStatic() || vd->isConst()) ; else { VarDeclaration *vto; vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); *vto = *vd; vto->parent = ids->parent; #if IN_DMD vto->csym = NULL; vto->isym = NULL; #endif ids->from.push(vd); ids->to.push(vto); if (vd->init) { if (vd->init->isVoidInitializer()) { vto->init = new VoidInitializer(vd->init->loc); } else { ExpInitializer *ie = vd->init->isExpInitializer(); assert(ie); vto->init = new ExpInitializer(ie->loc, ie->exp->doInline(ids)); } } de->declaration = (Dsymbol *) (void *)vto; } } /* This needs work, like DeclarationExp::toElem(), if we are * to handle TemplateMixin's. For now, we just don't inline them. */ return de; }
int DeclarationExp::inlineCost3(InlineCostState *ics) { int cost = 0; VarDeclaration *vd; //printf("DeclarationExp::inlineCost3()\n"); vd = declaration->isVarDeclaration(); if (vd) { TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); if (td) { #if 1 return COST_MAX; // finish DeclarationExp::doInline #else for (size_t i = 0; i < td->objects->dim; i++) { Object *o = (*td->objects)[i]; if (o->dyncast() != DYNCAST_EXPRESSION) return COST_MAX; Expression *eo = (Expression *)o; if (eo->op != TOKdsymbol) return COST_MAX; } return td->objects->dim; #endif } if (!ics->hdrscan && vd->isDataseg()) return COST_MAX; cost += 1; #if DMDV2 if (vd->edtor) // if destructor required return COST_MAX; // needs work to make this work #endif // Scan initializer (vd->init) if (vd->init) { ExpInitializer *ie = vd->init->isExpInitializer(); if (ie) { cost += expressionInlineCost(ie->exp, ics); } } } // These can contain functions, which when copied, get output twice. if (declaration->isStructDeclaration() || declaration->isClassDeclaration() || declaration->isFuncDeclaration() || declaration->isTypedefDeclaration() || #if DMDV2 declaration->isAttribDeclaration() || #endif declaration->isTemplateMixin()) return COST_MAX; //printf("DeclarationExp::inlineCost3('%s')\n", toChars()); return cost; }
void StructDeclaration::toDt(dt_t **pdt) { unsigned offset; unsigned i; dt_t *dt; //printf("StructDeclaration::toDt(), this='%s'\n", toChars()); offset = 0; // Note equivalence of this loop to class's for (i = 0; i < fields.dim; i++) { VarDeclaration *v = (VarDeclaration *)fields.data[i]; //printf("\tfield '%s' voffset %d, offset = %d\n", v->toChars(), v->offset, offset); dt = NULL; int sz; if (v->storage_class & STCref) { sz = PTRSIZE; if (v->offset >= offset) dtnzeros(&dt, sz); } else { sz = v->type->size(); Initializer *init = v->init; if (init) { //printf("\t\thas initializer %s\n", init->toChars()); ExpInitializer *ei = init->isExpInitializer(); Type *tb = v->type->toBasetype(); if (ei && tb->ty == Tsarray) ((TypeSArray *)tb)->toDtElem(&dt, ei->exp); else dt = init->toDt(); } else if (v->offset >= offset) v->type->toDt(&dt); } if (dt) { if (v->offset < offset) error("overlapping initialization for struct %s.%s", toChars(), v->toChars()); else { if (offset < v->offset) dtnzeros(pdt, v->offset - offset); dtcat(pdt, dt); offset = v->offset + sz; } } } if (offset < structsize) dtnzeros(pdt, structsize - offset); dt_optimize(*pdt); }
void StructDeclaration::toDt(dt_t **pdt) { if (zeroInit) { dtnzeros(pdt, structsize); return; } unsigned offset; dt_t *dt; dt_t *sdt = NULL; //printf("StructDeclaration::toDt(), this='%s'\n", toChars()); offset = 0; // Note equivalence of this loop to class's for (size_t i = 0; i < fields.dim; i++) { VarDeclaration *v = (VarDeclaration *)fields.data[i]; Initializer *init; //printf("\tfield '%s' voffset %d, offset = %d\n", v->toChars(), v->offset, offset); dt = NULL; init = v->init; if (init) { //printf("\t\thas initializer %s\n", init->toChars()); ExpInitializer *ei = init->isExpInitializer(); Type *tb = v->type->toBasetype(); if (ei && tb->ty == Tsarray) ((TypeSArray *)tb)->toDtElem(&dt, ei->exp); else dt = init->toDt(); } else if (v->offset >= offset) v->type->toDt(&dt); if (dt) { if (v->offset < offset) error("overlapping initialization for struct %s.%s", toChars(), v->toChars()); else { if (offset < v->offset) dtnzeros(&sdt, v->offset - offset); dtcat(&sdt, dt); offset = v->offset + v->type->size(); } } } if (offset < structsize) dtnzeros(&sdt, structsize - offset); #ifdef IN_GCC dtcontainer(pdt, type, sdt); #else dtcat(pdt, sdt); #endif dt_optimize(*pdt); }
int DeclarationExp::inlineCost(InlineCostState *ics) { int cost = 0; VarDeclaration *vd; //printf("DeclarationExp::inlineCost()\n"); vd = declaration->isVarDeclaration(); if (vd) { TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); if (td) { #if 1 return COST_MAX; // finish DeclarationExp::doInline #else for (size_t i = 0; i < td->objects->dim; i++) { Object *o = (*td->objects)[i]; if (o->dyncast() != DYNCAST_EXPRESSION) return COST_MAX; Expression *eo = (Expression *)o; if (eo->op != TOKdsymbol) return COST_MAX; } return td->objects->dim; #endif } // This breaks on LDC too, since nested static variables have internal // linkage and thus can't be referenced from other objects. if (!ics->hdrscan && vd->isDataseg()) return COST_MAX; cost += 1; // Scan initializer (vd->init) if (vd->init) { ExpInitializer *ie = vd->init->isExpInitializer(); if (ie) { cost += ie->exp->inlineCost(ics); } } } // These can contain functions, which when copied, get output twice. // These break on LDC too, since nested static variables and functions have // internal linkage and thus can't be referenced from other objects. if (declaration->isStructDeclaration() || declaration->isClassDeclaration() || declaration->isFuncDeclaration() || declaration->isTypedefDeclaration() || declaration->isTemplateMixin()) return COST_MAX; //printf("DeclarationExp::inlineCost('%s')\n", toChars()); return cost; }
void check(Loc loc, Declaration *d) { assert(d); VarDeclaration *v = d->isVarDeclaration(); if (v && v->toParent2() == sc->func) { if (v->isDataseg()) return; if ((v->storage_class & (STCref | STCout)) == 0) { error(loc, "escaping reference to local variable %s", v); return; } if (global.params.useDIP25 && (v->storage_class & (STCref | STCout)) && !(v->storage_class & (STCreturn | STCforeach))) { if (sc->func->flags & FUNCFLAGreturnInprocess) { //printf("inferring 'return' for variable '%s'\n", v->toChars()); v->storage_class |= STCreturn; if (v == sc->func->vthis) { TypeFunction *tf = (TypeFunction *)sc->func->type; if (tf->ty == Tfunction) { //printf("'this' too\n"); tf->isreturn = true; } } } else if (sc->module && sc->module->isRoot()) { //printf("escaping reference to local ref variable %s\n", v->toChars()); //printf("storage class = x%llx\n", v->storage_class); error(loc, "escaping reference to local ref variable %s", v); } return; } if (v->storage_class & STCref && v->storage_class & (STCforeach | STCtemp) && v->init) { // (ref v = ex; ex) if (ExpInitializer *ez = v->init->isExpInitializer()) { assert(ez->exp && ez->exp->op == TOKconstruct); Expression *ex = ((ConstructExp *)ez->exp)->e2; ex->accept(this); return; } } } }
/*************************************** * Fit elements[] to the corresponding type of field[]. * Input: * loc * sc * elements The explicit arguments that given to construct object. * stype The constructed object type. * Returns false if any errors occur. * Otherwise, returns true and elements[] are rewritten for the output. */ bool StructDeclaration::fit(Loc loc, Scope *sc, Expressions *elements, Type *stype) { if (!elements) return true; size_t nfields = fields.dim - isNested(); size_t offset = 0; for (size_t i = 0; i < elements->dim; i++) { Expression *e = (*elements)[i]; if (!e) continue; e = resolveProperties(sc, e); if (i >= nfields) { if (i == fields.dim - 1 && isNested() && e->op == TOKnull) { // CTFE sometimes creates null as hidden pointer; we'll allow this. continue; } ::error(loc, "more initializers than fields (%d) of %s", nfields, toChars()); return false; } VarDeclaration *v = fields[i]; if (v->offset < offset) { ::error(loc, "overlapping initialization for %s", v->toChars()); return false; } offset = (unsigned)(v->offset + v->type->size()); Type *telem = v->type; if (stype) telem = telem->addMod(stype->mod); Type *origType = telem; while (!e->implicitConvTo(telem) && telem->toBasetype()->ty == Tsarray) { /* Static array initialization, as in: * T[3][5] = e; */ telem = telem->toBasetype()->nextOf(); } if (!e->implicitConvTo(telem)) telem = origType; // restore type for better diagnostic e = e->implicitCastTo(sc, telem); if (e->op == TOKerror) return false; (*elements)[i] = e->isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e); } return true; }
void scanVar(Dsymbol *s, InlineScanState *iss) { VarDeclaration *vd = s->isVarDeclaration(); if (vd) { TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); if (td) { for (size_t i = 0; i < td->objects->dim; i++) { DsymbolExp *se = (DsymbolExp *)td->objects->tdata()[i]; assert(se->op == TOKdsymbol); scanVar(se->s, iss); } } else { // Scan initializer (vd->init) if (vd->init) { ExpInitializer *ie = vd->init->isExpInitializer(); if (ie) { #if DMDV2 if (vd->type) { Type *tb = vd->type->toBasetype(); if (tb->ty == Tstruct) { StructDeclaration *sd = ((TypeStruct *)tb)->sym; if (sd->cpctor) { /* The problem here is that if the initializer is a * function call that returns a struct S with a cpctor: * S s = foo(); * the postblit is done by the return statement in foo() * in s2ir.c, the intermediate code generator. * But, if foo() is inlined and now the code looks like: * S s = x; * the postblit is not there, because such assignments * are rewritten as s.cpctor(&x) by the front end. * So, the inlining won't get the postblit called. * Work around by not inlining these cases. * A proper fix would be to move all the postblit * additions to the front end. */ return; } } } #endif ie->exp = ie->exp->inlineScan(iss); } } } } }
void check(Loc loc, Declaration *d) { VarDeclaration *v = d->isVarDeclaration(); if (v && v->toParent2() == sc->func) { if (v->isDataseg()) return; if ((v->storage_class & (STCref | STCout)) == 0) error(loc, "escaping reference to local %s", v); } }
int StructDeclaration::needOpEquals() { #define X 0 if (X) printf("StructDeclaration::needOpEquals() %s\n", toChars()); if (hasIdentityEquals) goto Lneed; #if 0 if (isUnionDeclaration()) goto Ldontneed; #endif /* If any of the fields has an opEquals, then we * need it too. */ for (size_t i = 0; i < fields.dim; i++) { Dsymbol *s = fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->isField()); if (v->storage_class & STCref) continue; Type *tv = v->type->toBasetype(); #if 0 if (tv->isfloating()) goto Lneed; if (tv->ty == Tarray) goto Lneed; if (tv->ty == Tclass) goto Lneed; #endif while (tv->ty == Tsarray) { TypeSArray *ta = (TypeSArray *)tv; tv = tv->nextOf()->toBasetype(); } if (tv->ty == Tstruct) { TypeStruct *ts = (TypeStruct *)tv; StructDeclaration *sd = ts->sym; if (sd->needOpEquals()) goto Lneed; } } Ldontneed: if (X) printf("\tdontneed\n"); return 0; Lneed: if (X) printf("\tneed\n"); return 1; #undef X }
void visit(DeclarationExp *e) { //printf("DeclarationExp::inlineCost3()\n"); VarDeclaration *vd = e->declaration->isVarDeclaration(); if (vd) { TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); if (td) { cost = COST_MAX; // finish DeclarationExp::doInline return; } if (!hdrscan && vd->isDataseg()) { cost = COST_MAX; return; } if (vd->edtor) { // if destructor required // needs work to make this work cost = COST_MAX; return; } // Scan initializer (vd->init) if (vd->_init) { ExpInitializer *ie = vd->_init->isExpInitializer(); if (ie) { expressionInlineCost(ie->exp); } } cost += 1; } // These can contain functions, which when copied, get output twice. if (e->declaration->isStructDeclaration() || e->declaration->isClassDeclaration() || e->declaration->isFuncDeclaration() || e->declaration->isAttribDeclaration() || e->declaration->isTemplateMixin()) { cost = COST_MAX; return; } //printf("DeclarationExp::inlineCost3('%s')\n", toChars()); }
/* Returns: * 0 this member doesn't need further processing to determine struct size * 1 this member does */ static int func(Dsymbol *s, void *param) { SV *psv = (SV *)param; VarDeclaration *v = s->isVarDeclaration(); if (v) { if (v->scope) v->semantic(NULL); if (v->storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCctfe | STCtemplateparameter)) return 0; if (v->isField() && v->sem >= SemanticDone) return 0; return 1; } return 0; }
Expression *fromConstInitializer(Expression *e1) { //printf("fromConstInitializer(%s)\n", e1->toChars()); if (e1->op == TOKvar) { VarExp *ve = (VarExp *)e1; VarDeclaration *v = ve->var->isVarDeclaration(); if (v && !v->originalType && v->scope) // semantic() not yet run v->semantic (v->scope); if (v && v->isConst() && v->init) { Expression *ei = v->init->toExpression(); if (ei && ei->type) e1 = ei; } } return e1; }
void ldc::DIBuilder::AddBaseFields(ClassDeclaration *sd, llvm::DIFile file, std::vector<llvm::Value*> &elems) { if (sd->baseClass) { AddBaseFields(sd->baseClass, file, elems); } ArrayIter<VarDeclaration> it(sd->fields); size_t narr = sd->fields.dim; elems.reserve(narr); for (; !it.done(); it.next()) { VarDeclaration* vd = it.get(); elems.push_back(CreateMemberType(vd->loc.linnum, vd->type, file, vd->toChars(), vd->offset)); } }
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(DeclarationExp *e) { // Note that, walkPostorder does not support DeclarationExp today. VarDeclaration *v = e->declaration->isVarDeclaration(); if (v && !(v->storage_class & STCmanifest) && !v->isDataseg() && v->init) { if (v->init->isVoidInitializer()) { } else { ExpInitializer *ei = v->init->isExpInitializer(); assert(ei); doCond(ei->exp); } } }
void visit(VarExp *e) override { IF_LOG Logger::print("VarExp::toConstElem: %s @ %s\n", e->toChars(), e->type->toChars()); LOG_SCOPE; if (SymbolDeclaration *sdecl = e->var->isSymbolDeclaration()) { // this seems to be the static initialiser for structs Type *sdecltype = sdecl->type->toBasetype(); IF_LOG Logger::print("Sym: type=%s\n", sdecltype->toChars()); assert(sdecltype->ty == Tstruct); TypeStruct *ts = static_cast<TypeStruct *>(sdecltype); DtoResolveStruct(ts->sym); result = getIrAggr(ts->sym)->getDefaultInit(); return; } if (TypeInfoDeclaration *ti = e->var->isTypeInfoDeclaration()) { LLType *vartype = DtoType(e->type); result = DtoTypeInfoOf(ti->tinfo, false); if (result->getType() != getPtrToType(vartype)) { result = llvm::ConstantExpr::getBitCast(result, vartype); } return; } VarDeclaration *vd = e->var->isVarDeclaration(); if (vd && vd->isConst() && vd->_init) { if (vd->inuse) { e->error("recursive reference %s", e->toChars()); result = llvm::UndefValue::get(DtoType(e->type)); } else { vd->inuse++; // return the initializer result = DtoConstInitializer(e->loc, e->type, vd->_init); vd->inuse--; } } // fail else { e->error("non-constant expression %s", e->toChars()); result = llvm::UndefValue::get(DtoType(e->type)); } }
int StructDeclaration::needOpAssign() { #define X 0 if (X) printf("StructDeclaration::needOpAssign() %s\n", toChars()); if (hasIdentityAssign) goto Lneed; // because has identity==elaborate opAssign if (dtor || postblit) goto Lneed; /* If any of the fields need an opAssign, then we * need it too. */ for (size_t i = 0; i < fields.dim; i++) { Dsymbol *s = fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->isField()); if (v->storage_class & STCref) continue; Type *tv = v->type->toBasetype(); while (tv->ty == Tsarray) { TypeSArray *ta = (TypeSArray *)tv; tv = tv->nextOf()->toBasetype(); } if (tv->ty == Tstruct) { TypeStruct *ts = (TypeStruct *)tv; StructDeclaration *sd = ts->sym; if (sd->needOpAssign()) goto Lneed; } } Ldontneed: if (X) printf("\tdontneed\n"); return 0; Lneed: if (X) printf("\tneed\n"); return 1; #undef X }
Expression *fromConstInitializer(int result, Expression *e1) { //printf("fromConstInitializer(result = %x, %s)\n", result, e1->toChars()); //static int xx; if (xx++ == 10) assert(0); Expression *e = e1; if (e1->op == TOKvar) { VarExp *ve = (VarExp *)e1; VarDeclaration *v = ve->var->isVarDeclaration(); e = expandVar(result, v); if (e) { // If it is a comma expression involving a declaration, we mustn't // perform a copy -- we'd get two declarations of the same variable. // See bugzilla 4465. if (e->op == TOKcomma && ((CommaExp *)e)->e1->op == TOKdeclaration) e = e1; else if (e->type != e1->type && e1->type && e1->type->ty != Tident) { // Type 'paint' operation e = e->copy(); e->type = e1->type; } e->loc = e1->loc; } else { e = e1; /* If we needed to interpret, generate an error. * Don't give an error if it's a template parameter */ if (v && (result & WANTinterpret) && !(v->storage_class & STCtemplateparameter)) { e1->error("variable %s cannot be read at compile time", v->toChars()); e = e->copy(); e->type = Type::terror; } } } return e; }
/**************************************** * Count the number of fields starting at firstIndex which are part of the * same union as field[firstIndex]. If not a union, return 1. */ int AggregateDeclaration::numFieldsInUnion(int firstIndex) { VarDeclaration * vd = fields[firstIndex]; /* If it is a zero-length field, AND we can't find an earlier non-zero * sized field with the same offset, we assume it's not part of a union. */ if (vd->size(loc) == 0 && !isUnionDeclaration() && firstFieldInUnion(firstIndex) == firstIndex) return 1; int count = 1; for (size_t i = firstIndex+1; i < fields.dim; ++i) { VarDeclaration * v = fields[i]; // If offsets are different, they are not in the same union if (v->offset != vd->offset) break; ++count; } return count; }
Expression *DeclarationExp::interpret(InterState *istate) { #if LOG printf("DeclarationExp::interpret() %s\n", toChars()); #endif Expression *e; VarDeclaration *v = declaration->isVarDeclaration(); if (v) { Dsymbol *s = v->toAlias(); if (s == v && !v->isStatic() && v->init) { ExpInitializer *ie = v->init->isExpInitializer(); if (ie) e = ie->exp->interpret(istate); else if (v->init->isVoidInitializer()) e = NULL; } #if V2 else if (s == v && (v->isConst() || v->isInvariant()) && v->init) #else else if (s == v && v->isConst() && v->init) #endif { e = v->init->toExpression(); if (!e) e = EXP_CANT_INTERPRET; else if (!e->type) e->type = v->type; } } else if (declaration->isAttribDeclaration() ||
/************************************ * Detect cases where pointers to the stack can 'escape' the * lifetime of the stack frame when throwing `e`. * Print error messages when these are detected. * Params: * sc = used to determine current function and module * e = expression to check for any pointers to the stack * gag = do not print error messages * Returns: * true if pointers to the stack can escape */ bool checkThrowEscape(Scope *sc, Expression *e, bool gag) { //printf("[%s] checkThrowEscape, e = %s\n", e->loc->toChars(), e->toChars()); EscapeByResults er; escapeByValue(e, &er); if (!er.byref.dim && !er.byvalue.dim && !er.byexp.dim) return false; bool result = false; for (size_t i = 0; i < er.byvalue.dim; i++) { VarDeclaration *v = er.byvalue[i]; //printf("byvalue %s\n", v->toChars()); if (v->isDataseg()) continue; if (v->isScope()) { if (sc->_module && sc->_module->isRoot()) { // Only look for errors if in module listed on command line if (global.params.vsafe) // https://issues.dlang.org/show_bug.cgi?id=17029 { if (!gag) error(e->loc, "scope variable %s may not be thrown", v->toChars()); result = true; } continue; } } else { //printf("no infer for %s\n", v->toChars()); v->doNotInferScope = true; } } return result; }
/**************************************** * If field[indx] is not part of a union, return indx. * Otherwise, return the lowest field index of the union. */ int AggregateDeclaration::firstFieldInUnion(int indx) { if (isUnionDeclaration()) return 0; VarDeclaration * vd = fields[indx]; int firstNonZero = indx; // first index in the union with non-zero size for (; ;) { if (indx == 0) return firstNonZero; VarDeclaration * v = fields[indx - 1]; if (v->offset != vd->offset) return firstNonZero; --indx; /* If it is a zero-length field, it's ambiguous: we don't know if it is * in the union unless we find an earlier non-zero sized field with the * same offset. */ if (v->size(loc) != 0) firstNonZero = indx; } }