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); }
void visit(Expression *e) { // stop walking if we determine this expression has side effects stop = lambdaHasSideEffect(e); }
/*********************************** * The result of this expression will be discarded. * Print error messages if the operation has no side effects (and hence is meaningless). * Returns: * true if expression has no side effects */ bool discardValue(Expression *e) { if (lambdaHasSideEffect(e)) // check side-effect shallowly return false; switch (e->op) { case TOKcast: { CastExp *ce = (CastExp *)e; if (ce->to->equals(Type::tvoid)) { /* * Don't complain about an expression with no effect if it was cast to void */ return false; } break; // complain } case TOKerror: return false; case TOKvar: { VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration(); if (v && (v->storage_class & STCtemp)) { // Bugzilla 5810: Don't complain about an internal generated variable. return false; } break; } case TOKcall: /* Issue 3882: */ if (global.params.warnings != DIAGNOSTICoff && !global.gag) { CallExp *ce = (CallExp *)e; if (e->type->ty == Tvoid) { /* Don't complain about calling void-returning functions with no side-effect, * because purity and nothrow are inferred, and because some of the * runtime library depends on it. Needs more investigation. * * One possible solution is to restrict this message to only be called in hierarchies that * never call assert (and or not called from inside unittest blocks) */ } else if (ce->e1->type) { Type *t = ce->e1->type->toBasetype(); if (t->ty == Tdelegate) t = ((TypeDelegate *)t)->next; if (t->ty == Tfunction && (ce->f ? callSideEffectLevel(ce->f) : callSideEffectLevel(ce->e1->type)) > 0) { const char *s; if (ce->f) s = ce->f->toPrettyChars(); else if (ce->e1->op == TOKstar) { // print 'fp' if ce->e1 is (*fp) s = ((PtrExp *)ce->e1)->e1->toChars(); } else s = ce->e1->toChars(); e->warning("calling %s without side effects discards return value of type %s, prepend a cast(void) if intentional", s, e->type->toChars()); } } } return false; case TOKscope: e->error("%s has no effect", e->toChars()); return true; case TOKandand: { AndAndExp *aae = (AndAndExp *)e; return discardValue(aae->e2); } case TOKoror: { OrOrExp *ooe = (OrOrExp *)e; return discardValue(ooe->e2); } case TOKquestion: { CondExp *ce = (CondExp *)e; /* Bugzilla 6178 & 14089: Either CondExp::e1 or e2 may have * redundant expression to make those types common. For example: * * struct S { this(int n); int v; alias v this; } * S[int] aa; * aa[1] = 0; * * The last assignment statement will be rewitten to: * * 1 in aa ? aa[1].value = 0 : (aa[1] = 0, aa[1].this(0)).value; * * The last DotVarExp is necessary to take assigned value. * * int value = (aa[1] = 0); // value = aa[1].value * * To avoid false error, discardValue() should be called only when * the both tops of e1 and e2 have actually no side effects. */ if (!lambdaHasSideEffect(ce->e1) && !lambdaHasSideEffect(ce->e2)) { return discardValue(ce->e1) | discardValue(ce->e2); } return false; } case TOKcomma: { CommaExp *ce = (CommaExp *)e; /* Check for compiler-generated code of the form auto __tmp, e, __tmp; * In such cases, only check e for side effect (it's OK for __tmp to have * no side effect). * See Bugzilla 4231 for discussion */ CommaExp *firstComma = ce; while (firstComma->e1->op == TOKcomma) firstComma = (CommaExp *)firstComma->e1; if (firstComma->e1->op == TOKdeclaration && ce->e2->op == TOKvar && ((DeclarationExp *)firstComma->e1)->declaration == ((VarExp*)ce->e2)->var) { return false; } // Don't check e1 until we cast(void) the a,b code generation //discardValue(ce->e1); return discardValue(ce->e2); } case TOKtuple: /* Pass without complaint if any of the tuple elements have side effects. * Ideally any tuple elements with no side effects should raise an error, * this needs more investigation as to what is the right thing to do. */ if (!hasSideEffect(e)) break; return false; default: break; } e->error("%s has no effect in expression (%s)", Token::toChars(e->op), e->toChars()); return true; }
/*********************************** * The result of this expression will be discarded. * Complain if the operation has no side effects (and hence is meaningless). */ void Expression::discardValue() { bool has = FALSE; lambdaHasSideEffect(this, &has); if (!has) { switch (op) { case TOKcast: { CastExp *ce = (CastExp *)this; if (ce->to->equals(Type::tvoid)) { /* * Don't complain about an expression with no effect if it was cast to void */ ce->e1->useValue(); break; } goto Ldefault; // complain } case TOKerror: break; case TOKcall: /* Don't complain about calling functions with no effect, * because purity and nothrow are inferred, and because some of the * runtime library depends on it. Needs more investigation. */ break; case TOKimport: error("%s has no effect", toChars()); break; case TOKandand: { AndAndExp *aae = (AndAndExp *)this; aae->e1->useValue(); aae->e2->discardValue(); break; } case TOKoror: { OrOrExp *ooe = (OrOrExp *)this; ooe->e1->useValue(); ooe->e2->discardValue(); break; } case TOKquestion: { CondExp *ce = (CondExp *)this; ce->econd->useValue(); ce->e1->discardValue(); ce->e2->discardValue(); break; } case TOKcomma: { CommaExp *ce = (CommaExp *)this; /* Check for compiler-generated code of the form auto __tmp, e, __tmp; * In such cases, only check e for side effect (it's OK for __tmp to have * no side effect). * See Bugzilla 4231 for discussion */ CommaExp* firstComma = ce; while (firstComma->e1->op == TOKcomma) firstComma = (CommaExp *)firstComma->e1; if (firstComma->e1->op == TOKdeclaration && ce->e2->op == TOKvar && ((DeclarationExp *)firstComma->e1)->declaration == ((VarExp*)ce->e2)->var) { ce->e1->useValue(); break; } // Don't check e1 until we cast(void) the a,b code generation //ce->e1->discardValue(); ce->e2->discardValue(); break; } case TOKtuple: /* Pass without complaint if any of the tuple elements have side effects. * Ideally any tuple elements with no side effects should raise an error, * this needs more investigation as to what is the right thing to do. */ if (!hasSideEffect()) goto Ldefault; break; default: Ldefault: error("%s has no effect in expression (%s)", Token::toChars(op), toChars()); break; } } else { useValue(); } }