int lambdaUseValue(Expression *e, void *param) { switch (e->op) { case TOKcomma: { CommaExp *ce = (CommaExp *)e; discardValue(ce->E1); break; } default: break; } return 0; }
/*********************************** * 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 discardValue(Expression *e) { if (hasSideEffect(e)) return; 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; } break; // complain } case TOKerror: return; case TOKcall: /* Issue 3882: */ if (global.params.warnings && !global.gag) { 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 { CallExp *ce = (CallExp *)e; e->warning("Call to strictly pure function %s discards return value of type %s, prepend a cast(void) if intentional", ce->f->toPrettyChars(), e->type->toChars()); } } return; case TOKimport: e->error("%s has no effect", e->toChars()); return; case TOKandand: { AndAndExp *aae = (AndAndExp *)e; discardValue(aae->e2); return; } case TOKoror: { OrOrExp *ooe = (OrOrExp *)e; discardValue(ooe->e2); return; } case TOKquestion: { CondExp *ce = (CondExp *)e; discardValue(ce->e1); discardValue(ce->e2); return; } 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; } // Don't check e1 until we cast(void) the a,b code generation //discardValue(ce->e1); discardValue(ce->e2); return; } 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; default: break; } e->error("%s has no effect in expression (%s)", Token::toChars(e->op), e->toChars()); }