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
11 #include "root/dsystem.h"
15 #include "expression.h"
17 #include "statement.h"
20 #include "declaration.h"
21 #include "aggregate.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
43 void visit(Expression
*e
)
45 /* Bugzilla 11201: CallExp is always non trivial expression,
46 * especially for inlining.
54 // stop walking if we determine this expression has side effects
55 stop
= lambdaHasSideEffect(e
);
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
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.
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())
100 assert(f
->type
->ty
== Tfunction
);
101 TypeFunction
*tf
= (TypeFunction
*)f
->type
;
104 PURE purity
= f
->isPure();
105 if (purity
== PUREstrong
)
107 if (purity
== PUREconst
)
113 int callSideEffectLevel(Type
*t
)
118 if (t
->ty
== Tdelegate
)
119 tf
= (TypeFunction
*)((TypeDelegate
*)t
)->next
;
122 assert(t
->ty
== Tfunction
);
123 tf
= (TypeFunction
*)t
;
127 PURE purity
= tf
->purity
;
128 if (t
->ty
== Tdelegate
&& purity
> PUREweak
)
132 else if (!tf
->isImmutable())
138 if (purity
== PUREstrong
)
140 if (purity
== PUREconst
)
146 bool lambdaHasSideEffect(Expression
*e
)
150 // Sort the cases by most frequently used first
176 case TOKnewanonclass
:
181 CallExp
*ce
= (CallExp
*)e
;
182 /* Calling a function or delegate that is pure nothrow
183 * has no side effects.
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)
203 CastExp
*ce
= (CastExp
*)e
;
205 * cast(classtype)func() // because it may throw
207 if (ce
->to
->ty
== Tclass
&& ce
->e1
->op
== TOKcall
&& ce
->e1
->type
->ty
== Tclass
)
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).
223 * true if expression has no side effects
225 bool discardValue(Expression
*e
)
227 if (lambdaHasSideEffect(e
)) // check side-effect shallowly
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
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.
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)
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();
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());
300 e
->error("%s has no effect", e
->toChars());
305 AndAndExp
*aae
= (AndAndExp
*)e
;
306 return discardValue(aae
->e2
);
311 OrOrExp
*ooe
= (OrOrExp
*)e
;
312 return discardValue(ooe
->e2
);
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; }
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
);
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
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
)
363 // Don't check e1 until we cast(void) the a,b code generation
364 //discardValue(ce->e1);
365 return discardValue(ce
->e2
);
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
))
380 e
->error("%s has no effect in expression (%s)", Token::toChars(e
->op
), e
->toChars());
384 /**************************************************
385 * Build a temporary variable to copy the value of e into.
387 * stc = storage classes will be added to the made temporary variable
388 * name = name for temporary variable
389 * e = original expression
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
405 /**************************************************
406 * Build a temporary variable to extract e's evaluation, if e is not trivial.
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.
414 * When e is trivial and alwaysCopy == false, e itself is returned.
415 * Otherwise, a new VarExp is returned.
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
))
425 VarDeclaration
*vd
= copyToTemp(0, name
, e
);
427 vd
->storage_class
|= STCref
;
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
);