Merge dmd upstream 6243fa6d2
[official-gcc.git] / gcc / d / dmd / sideeffect.c
blob56d7d078027ad00240e52213eaab855e540b4d81
2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
4 * written by Walter Bright
5 * http://www.digitalmars.com
6 * Distributed under the Boost Software License, Version 1.0.
7 * http://www.boost.org/LICENSE_1_0.txt
8 * https://github.com/D-Programming-Language/dmd/blob/master/src/sideeffect.c
9 */
11 #include "root/dsystem.h"
13 #include "mars.h"
14 #include "init.h"
15 #include "expression.h"
16 #include "template.h"
17 #include "statement.h"
18 #include "mtype.h"
19 #include "utf.h"
20 #include "declaration.h"
21 #include "aggregate.h"
22 #include "scope.h"
23 #include "attrib.h"
24 #include "tokens.h"
26 bool walkPostorder(Expression *e, StoppableVisitor *v);
27 bool lambdaHasSideEffect(Expression *e);
28 Expression *semantic(Expression *e, Scope *sc);
30 /**************************************************
31 * Front-end expression rewriting should create temporary variables for
32 * non trivial sub-expressions in order to:
33 * 1. save evaluation order
34 * 2. prevent sharing of sub-expression in AST
36 bool isTrivialExp(Expression *e)
38 class IsTrivialExp : public StoppableVisitor
40 public:
41 IsTrivialExp() {}
43 void visit(Expression *e)
45 /* Bugzilla 11201: CallExp is always non trivial expression,
46 * especially for inlining.
48 if (e->op == TOKcall)
50 stop = true;
51 return;
54 // stop walking if we determine this expression has side effects
55 stop = lambdaHasSideEffect(e);
59 IsTrivialExp v;
60 return walkPostorder(e, &v) == false;
63 /********************************************
64 * Determine if Expression has any side effects.
67 bool hasSideEffect(Expression *e)
69 class LambdaHasSideEffect : public StoppableVisitor
71 public:
72 LambdaHasSideEffect() {}
74 void visit(Expression *e)
76 // stop walking if we determine this expression has side effects
77 stop = lambdaHasSideEffect(e);
81 LambdaHasSideEffect v;
82 return walkPostorder(e, &v);
85 /********************************************
86 * Determine if the call of f, or function type or delegate type t1, has any side effects.
87 * Returns:
88 * 0 has any side effects
89 * 1 nothrow + constant purity
90 * 2 nothrow + strong purity
93 int callSideEffectLevel(FuncDeclaration *f)
95 /* Bugzilla 12760: ctor call always has side effects.
97 if (f->isCtorDeclaration())
98 return 0;
100 assert(f->type->ty == Tfunction);
101 TypeFunction *tf = (TypeFunction *)f->type;
102 if (tf->isnothrow)
104 PURE purity = f->isPure();
105 if (purity == PUREstrong)
106 return 2;
107 if (purity == PUREconst)
108 return 1;
110 return 0;
113 int callSideEffectLevel(Type *t)
115 t = t->toBasetype();
117 TypeFunction *tf;
118 if (t->ty == Tdelegate)
119 tf = (TypeFunction *)((TypeDelegate *)t)->next;
120 else
122 assert(t->ty == Tfunction);
123 tf = (TypeFunction *)t;
126 tf->purityLevel();
127 PURE purity = tf->purity;
128 if (t->ty == Tdelegate && purity > PUREweak)
130 if (tf->isMutable())
131 purity = PUREweak;
132 else if (!tf->isImmutable())
133 purity = PUREconst;
136 if (tf->isnothrow)
138 if (purity == PUREstrong)
139 return 2;
140 if (purity == PUREconst)
141 return 1;
143 return 0;
146 bool lambdaHasSideEffect(Expression *e)
148 switch (e->op)
150 // Sort the cases by most frequently used first
151 case TOKassign:
152 case TOKplusplus:
153 case TOKminusminus:
154 case TOKdeclaration:
155 case TOKconstruct:
156 case TOKblit:
157 case TOKaddass:
158 case TOKminass:
159 case TOKcatass:
160 case TOKmulass:
161 case TOKdivass:
162 case TOKmodass:
163 case TOKshlass:
164 case TOKshrass:
165 case TOKushrass:
166 case TOKandass:
167 case TOKorass:
168 case TOKxorass:
169 case TOKpowass:
170 case TOKin:
171 case TOKremove:
172 case TOKassert:
173 case TOKhalt:
174 case TOKdelete:
175 case TOKnew:
176 case TOKnewanonclass:
177 return true;
179 case TOKcall:
181 CallExp *ce = (CallExp *)e;
182 /* Calling a function or delegate that is pure nothrow
183 * has no side effects.
185 if (ce->e1->type)
187 Type *t = ce->e1->type->toBasetype();
188 if (t->ty == Tdelegate)
189 t = ((TypeDelegate *)t)->next;
190 if (t->ty == Tfunction &&
191 (ce->f ? callSideEffectLevel(ce->f)
192 : callSideEffectLevel(ce->e1->type)) > 0)
195 else
196 return true;
198 break;
201 case TOKcast:
203 CastExp *ce = (CastExp *)e;
204 /* if:
205 * cast(classtype)func() // because it may throw
207 if (ce->to->ty == Tclass && ce->e1->op == TOKcall && ce->e1->type->ty == Tclass)
208 return true;
209 break;
212 default:
213 break;
215 return false;
219 /***********************************
220 * The result of this expression will be discarded.
221 * Print error messages if the operation has no side effects (and hence is meaningless).
222 * Returns:
223 * true if expression has no side effects
225 bool discardValue(Expression *e)
227 if (lambdaHasSideEffect(e)) // check side-effect shallowly
228 return false;
229 switch (e->op)
231 case TOKcast:
233 CastExp *ce = (CastExp *)e;
234 if (ce->to->equals(Type::tvoid))
237 * Don't complain about an expression with no effect if it was cast to void
239 return false;
241 break; // complain
244 case TOKerror:
245 return false;
247 case TOKvar:
249 VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
250 if (v && (v->storage_class & STCtemp))
252 // Bugzilla 5810: Don't complain about an internal generated variable.
253 return false;
255 break;
257 case TOKcall:
258 /* Issue 3882: */
259 if (global.params.warnings != DIAGNOSTICoff && !global.gag)
261 CallExp *ce = (CallExp *)e;
262 if (e->type->ty == Tvoid)
264 /* Don't complain about calling void-returning functions with no side-effect,
265 * because purity and nothrow are inferred, and because some of the
266 * runtime library depends on it. Needs more investigation.
268 * One possible solution is to restrict this message to only be called in hierarchies that
269 * never call assert (and or not called from inside unittest blocks)
272 else if (ce->e1->type)
274 Type *t = ce->e1->type->toBasetype();
275 if (t->ty == Tdelegate)
276 t = ((TypeDelegate *)t)->next;
277 if (t->ty == Tfunction &&
278 (ce->f ? callSideEffectLevel(ce->f)
279 : callSideEffectLevel(ce->e1->type)) > 0)
281 const char *s;
282 if (ce->f)
283 s = ce->f->toPrettyChars();
284 else if (ce->e1->op == TOKstar)
286 // print 'fp' if ce->e1 is (*fp)
287 s = ((PtrExp *)ce->e1)->e1->toChars();
289 else
290 s = ce->e1->toChars();
292 e->warning("calling %s without side effects discards return value of type %s, prepend a cast(void) if intentional",
293 s, e->type->toChars());
297 return false;
299 case TOKscope:
300 e->error("%s has no effect", e->toChars());
301 return true;
303 case TOKandand:
305 AndAndExp *aae = (AndAndExp *)e;
306 return discardValue(aae->e2);
309 case TOKoror:
311 OrOrExp *ooe = (OrOrExp *)e;
312 return discardValue(ooe->e2);
315 case TOKquestion:
317 CondExp *ce = (CondExp *)e;
319 /* Bugzilla 6178 & 14089: Either CondExp::e1 or e2 may have
320 * redundant expression to make those types common. For example:
322 * struct S { this(int n); int v; alias v this; }
323 * S[int] aa;
324 * aa[1] = 0;
326 * The last assignment statement will be rewitten to:
328 * 1 in aa ? aa[1].value = 0 : (aa[1] = 0, aa[1].this(0)).value;
330 * The last DotVarExp is necessary to take assigned value.
332 * int value = (aa[1] = 0); // value = aa[1].value
334 * To avoid false error, discardValue() should be called only when
335 * the both tops of e1 and e2 have actually no side effects.
337 if (!lambdaHasSideEffect(ce->e1) &&
338 !lambdaHasSideEffect(ce->e2))
340 return discardValue(ce->e1) |
341 discardValue(ce->e2);
343 return false;
346 case TOKcomma:
348 CommaExp *ce = (CommaExp *)e;
349 /* Check for compiler-generated code of the form auto __tmp, e, __tmp;
350 * In such cases, only check e for side effect (it's OK for __tmp to have
351 * no side effect).
352 * See Bugzilla 4231 for discussion
354 CommaExp *firstComma = ce;
355 while (firstComma->e1->op == TOKcomma)
356 firstComma = (CommaExp *)firstComma->e1;
357 if (firstComma->e1->op == TOKdeclaration &&
358 ce->e2->op == TOKvar &&
359 ((DeclarationExp *)firstComma->e1)->declaration == ((VarExp*)ce->e2)->var)
361 return false;
363 // Don't check e1 until we cast(void) the a,b code generation
364 //discardValue(ce->e1);
365 return discardValue(ce->e2);
368 case TOKtuple:
369 /* Pass without complaint if any of the tuple elements have side effects.
370 * Ideally any tuple elements with no side effects should raise an error,
371 * this needs more investigation as to what is the right thing to do.
373 if (!hasSideEffect(e))
374 break;
375 return false;
377 default:
378 break;
380 e->error("%s has no effect in expression (%s)", Token::toChars(e->op), e->toChars());
381 return true;
384 /**************************************************
385 * Build a temporary variable to copy the value of e into.
386 * Params:
387 * stc = storage classes will be added to the made temporary variable
388 * name = name for temporary variable
389 * e = original expression
390 * Returns:
391 * Newly created temporary variable.
393 VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e)
395 assert(name && name[0] == '_' && name[1] == '_');
396 Identifier *id = Identifier::generateId(name);
397 ExpInitializer *ez = new ExpInitializer(e->loc, e);
398 VarDeclaration *vd = new VarDeclaration(e->loc, e->type, id, ez);
399 vd->storage_class = stc;
400 vd->storage_class |= STCtemp;
401 vd->storage_class |= STCctfe; // temporary is always CTFEable
402 return vd;
405 /**************************************************
406 * Build a temporary variable to extract e's evaluation, if e is not trivial.
407 * Params:
408 * sc = scope
409 * name = name for temporary variable
410 * e0 = a new side effect part will be appended to it.
411 * e = original expression
412 * alwaysCopy = if true, build new temporary variable even if e is trivial.
413 * Returns:
414 * When e is trivial and alwaysCopy == false, e itself is returned.
415 * Otherwise, a new VarExp is returned.
416 * Note:
417 * e's lvalue-ness will be handled well by STCref or STCrvalue.
419 Expression *extractSideEffect(Scope *sc, const char *name,
420 Expression **e0, Expression *e, bool alwaysCopy = false)
422 if (!alwaysCopy && isTrivialExp(e))
423 return e;
425 VarDeclaration *vd = copyToTemp(0, name, e);
426 if (e->isLvalue())
427 vd->storage_class |= STCref;
428 else
429 vd->storage_class |= STCrvalue;
431 Expression *de = new DeclarationExp(vd->loc, vd);
432 Expression *ve = new VarExp(vd->loc, vd);
433 de = semantic(de, sc);
434 ve = semantic(ve, sc);
436 *e0 = Expression::combine(*e0, de);
437 return ve;