/************************************************** * Front-end expression rewriting should create temporary variables for * non trivial sub-expressions in order to: * 1. save evaluation order * 2. prevent sharing of sub-expression in AST */ bool isTrivialExp(Expression *e) { class IsTrivialExp : public StoppableVisitor { public: IsTrivialExp() {} void visit(Expression *e) { /* Bugzilla 11201: CallExp is always non trivial expression, * especially for inlining. */ if (e->op == TOKcall) { stop = true; return; } // stop walking if we determine this expression has side effects stop = lambdaHasSideEffect(e); } }; IsTrivialExp v; return walkPostorder(e, &v) == false; }
void expressionInlineCost(Expression *e) { //printf("expressionInlineCost()\n"); //e->print(); if (e) { class LambdaInlineCost : public StoppableVisitor { InlineCostVisitor *icv; public: LambdaInlineCost(InlineCostVisitor *icv) : icv(icv) {} void visit(Expression *e) { e->accept(icv); stop = icv->cost >= COST_MAX; } }; InlineCostVisitor icv(this); LambdaInlineCost lic(&icv); walkPostorder(e, &lic); cost += icv.cost; } }
Expression *checkGC(Scope *sc, Expression *e) { FuncDeclaration *f = sc->func; if (e && e->op != TOKerror && f && sc->intypeof != 1 && !(sc->flags & SCOPEctfe) && (f->type->ty == Tfunction && ((TypeFunction *)f->type)->isnogc || (f->flags & FUNCFLAGnogcInprocess) || global.params.vgc)) { NOGCVisitor gcv(f); walkPostorder(e, &gcv); if (gcv.err) return new ErrorExp(); } return e; }
bool hasSideEffect(Expression *e) { class LambdaHasSideEffect : public StoppableVisitor { public: LambdaHasSideEffect() {} void visit(Expression *e) { // stop walking if we determine this expression has side effects stop = lambdaHasSideEffect(e); } }; LambdaHasSideEffect v; return walkPostorder(e, &v); }
/****************************************** * Patch the parent of declarations to be the new function literal. */ void lambdaSetParent(Expression *e, Scope *sc) { class LambdaSetParent : public StoppableVisitor { Scope *sc; public: LambdaSetParent(Scope *sc) : sc(sc) {} void visit(Expression *) { } void visit(DeclarationExp *e) { e->declaration->parent = sc->parent; } void visit(IndexExp *e) { if (e->lengthVar) { //printf("lengthVar\n"); e->lengthVar->parent = sc->parent; } } void visit(SliceExp *e) { if (e->lengthVar) { //printf("lengthVar\n"); e->lengthVar->parent = sc->parent; } } }; LambdaSetParent lsp(sc); walkPostorder(e, &lsp); }
/******************************************* * Look for references to variables in a scope enclosing the new function literal. * Returns true if error occurs. */ bool lambdaCheckForNestedRef(Expression *e, Scope *sc) { class LambdaCheckForNestedRef : public StoppableVisitor { public: Scope *sc; bool result; LambdaCheckForNestedRef(Scope *sc) : sc(sc), result(false) { } void visit(Expression *) { } void visit(SymOffExp *e) { VarDeclaration *v = e->var->isVarDeclaration(); if (v) result = v->checkNestedReference(sc, Loc()); } void visit(VarExp *e) { VarDeclaration *v = e->var->isVarDeclaration(); if (v) result = v->checkNestedReference(sc, Loc()); } void visit(ThisExp *e) { if (e->var) result = e->var->checkNestedReference(sc, Loc()); } 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); } } } }; LambdaCheckForNestedRef v(sc); walkPostorder(e, &v); return v.result; }
void doCond(Expression *exp) { if (exp) walkPostorder(exp, this); }
bool hasSideEffect(Expression *e) { class LambdaHasSideEffect : public StoppableVisitor { public: LambdaHasSideEffect() {} void visit(Expression *e) { switch (e->op) { // Sort the cases by most frequently used first case TOKassign: case TOKplusplus: case TOKminusminus: case TOKdeclaration: case TOKconstruct: case TOKblit: case TOKaddass: case TOKminass: case TOKcatass: case TOKmulass: case TOKdivass: case TOKmodass: case TOKshlass: case TOKshrass: case TOKushrass: case TOKandass: case TOKorass: case TOKxorass: case TOKpowass: case TOKin: case TOKremove: case TOKassert: case TOKhalt: case TOKdelete: case TOKnew: case TOKnewanonclass: // stop walking if we determine this expression has side effects stop = true; break; case TOKcall: { CallExp *ce = (CallExp *)e; /* Calling a function or delegate that is pure nothrow * has no side effects. */ if (ce->e1->type) { Type *t = ce->e1->type->toBasetype(); if ((t->ty == Tfunction && ((TypeFunction *)t)->purity > PUREweak && ((TypeFunction *)t)->isnothrow) || (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->purity > PUREweak && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow) ) { } else stop = true; } break; } case TOKcast: { CastExp *ce = (CastExp *)e; /* if: * cast(classtype)func() // because it may throw */ if (ce->to->ty == Tclass && ce->e1->op == TOKcall && ce->e1->type->ty == Tclass) stop = true; break; } default: break; } } }; LambdaHasSideEffect v; return walkPostorder(e, &v); }