1
2/* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2019 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 */
10
11#include "root/dsystem.h"
12
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"
25
26bool walkPostorder(Expression *e, StoppableVisitor *v);
27bool lambdaHasSideEffect(Expression *e);
28Expression *semantic(Expression *e, Scope *sc);
29
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
35 */
36bool isTrivialExp(Expression *e)
37{
38    class IsTrivialExp : public StoppableVisitor
39    {
40    public:
41        IsTrivialExp() {}
42
43        void visit(Expression *e)
44        {
45            /* Bugzilla 11201: CallExp is always non trivial expression,
46             * especially for inlining.
47             */
48            if (e->op == TOKcall)
49            {
50                stop = true;
51                return;
52            }
53
54            // stop walking if we determine this expression has side effects
55            stop = lambdaHasSideEffect(e);
56        }
57    };
58
59    IsTrivialExp v;
60    return walkPostorder(e, &v) == false;
61}
62
63/********************************************
64 * Determine if Expression has any side effects.
65 */
66
67bool hasSideEffect(Expression *e)
68{
69    class LambdaHasSideEffect : public StoppableVisitor
70    {
71    public:
72        LambdaHasSideEffect() {}
73
74        void visit(Expression *e)
75        {
76            // stop walking if we determine this expression has side effects
77            stop = lambdaHasSideEffect(e);
78        }
79    };
80
81    LambdaHasSideEffect v;
82    return walkPostorder(e, &v);
83}
84
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
91 */
92
93int callSideEffectLevel(FuncDeclaration *f)
94{
95    /* Bugzilla 12760: ctor call always has side effects.
96     */
97    if (f->isCtorDeclaration())
98        return 0;
99
100    assert(f->type->ty == Tfunction);
101    TypeFunction *tf = (TypeFunction *)f->type;
102    if (tf->isnothrow)
103    {
104        PURE purity = f->isPure();
105        if (purity == PUREstrong)
106            return 2;
107        if (purity == PUREconst)
108            return 1;
109    }
110    return 0;
111}
112
113int callSideEffectLevel(Type *t)
114{
115    t = t->toBasetype();
116
117    TypeFunction *tf;
118    if (t->ty == Tdelegate)
119        tf = (TypeFunction *)((TypeDelegate *)t)->next;
120    else
121    {
122        assert(t->ty == Tfunction);
123        tf = (TypeFunction *)t;
124    }
125
126    tf->purityLevel();
127    PURE purity = tf->purity;
128    if (t->ty == Tdelegate && purity > PUREweak)
129    {
130        if (tf->isMutable())
131            purity = PUREweak;
132        else if (!tf->isImmutable())
133            purity = PUREconst;
134    }
135
136    if (tf->isnothrow)
137    {
138        if (purity == PUREstrong)
139            return 2;
140        if (purity == PUREconst)
141            return 1;
142    }
143    return 0;
144}
145
146bool lambdaHasSideEffect(Expression *e)
147{
148    switch (e->op)
149    {
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;
178
179        case TOKcall:
180        {
181            CallExp *ce = (CallExp *)e;
182            /* Calling a function or delegate that is pure nothrow
183             * has no side effects.
184             */
185            if (ce->e1->type)
186            {
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)
193                {
194                }
195                else
196                    return true;
197            }
198            break;
199        }
200
201        case TOKcast:
202        {
203            CastExp *ce = (CastExp *)e;
204            /* if:
205             *  cast(classtype)func()  // because it may throw
206             */
207            if (ce->to->ty == Tclass && ce->e1->op == TOKcall && ce->e1->type->ty == Tclass)
208                return true;
209            break;
210        }
211
212        default:
213            break;
214    }
215    return false;
216}
217
218
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
224 */
225bool discardValue(Expression *e)
226{
227    if (lambdaHasSideEffect(e))     // check side-effect shallowly
228        return false;
229    switch (e->op)
230    {
231        case TOKcast:
232        {
233            CastExp *ce = (CastExp *)e;
234            if (ce->to->equals(Type::tvoid))
235            {
236                /*
237                 * Don't complain about an expression with no effect if it was cast to void
238                 */
239                return false;
240            }
241            break;          // complain
242        }
243
244        case TOKerror:
245            return false;
246
247        case TOKvar:
248        {
249            VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
250            if (v && (v->storage_class & STCtemp))
251            {
252                // Bugzilla 5810: Don't complain about an internal generated variable.
253                return false;
254            }
255            break;
256        }
257        case TOKcall:
258            /* Issue 3882: */
259            if (global.params.warnings != DIAGNOSTICoff && !global.gag)
260            {
261                CallExp *ce = (CallExp *)e;
262                if (e->type->ty == Tvoid)
263                {
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.
267                     *
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)
270                     */
271                }
272                else if (ce->e1->type)
273                {
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)
280                    {
281                        const char *s;
282                        if (ce->f)
283                            s = ce->f->toPrettyChars();
284                        else if (ce->e1->op == TOKstar)
285                        {
286                            // print 'fp' if ce->e1 is (*fp)
287                            s = ((PtrExp *)ce->e1)->e1->toChars();
288                        }
289                        else
290                            s = ce->e1->toChars();
291
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());
294                    }
295                }
296            }
297            return false;
298
299        case TOKscope:
300            e->error("%s has no effect", e->toChars());
301            return true;
302
303        case TOKandand:
304        {
305            AndAndExp *aae = (AndAndExp *)e;
306            return discardValue(aae->e2);
307        }
308
309        case TOKoror:
310        {
311            OrOrExp *ooe = (OrOrExp *)e;
312            return discardValue(ooe->e2);
313        }
314
315        case TOKquestion:
316        {
317            CondExp *ce = (CondExp *)e;
318
319            /* Bugzilla 6178 & 14089: Either CondExp::e1 or e2 may have
320             * redundant expression to make those types common. For example:
321             *
322             *  struct S { this(int n); int v; alias v this; }
323             *  S[int] aa;
324             *  aa[1] = 0;
325             *
326             * The last assignment statement will be rewitten to:
327             *
328             *  1 in aa ? aa[1].value = 0 : (aa[1] = 0, aa[1].this(0)).value;
329             *
330             * The last DotVarExp is necessary to take assigned value.
331             *
332             *  int value = (aa[1] = 0);    // value = aa[1].value
333             *
334             * To avoid false error, discardValue() should be called only when
335             * the both tops of e1 and e2 have actually no side effects.
336             */
337            if (!lambdaHasSideEffect(ce->e1) &&
338                !lambdaHasSideEffect(ce->e2))
339            {
340                return discardValue(ce->e1) |
341                       discardValue(ce->e2);
342            }
343            return false;
344        }
345
346        case TOKcomma:
347        {
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
353             */
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)
360            {
361                return false;
362            }
363            // Don't check e1 until we cast(void) the a,b code generation
364            //discardValue(ce->e1);
365            return discardValue(ce->e2);
366        }
367
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.
372             */
373            if (!hasSideEffect(e))
374                break;
375            return false;
376
377        default:
378            break;
379    }
380    e->error("%s has no effect in expression (%s)", Token::toChars(e->op), e->toChars());
381    return true;
382}
383
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.
392 */
393VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e)
394{
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;
403}
404
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.
418 */
419Expression *extractSideEffect(Scope *sc, const char *name,
420    Expression **e0, Expression *e, bool alwaysCopy = false)
421{
422    if (!alwaysCopy && isTrivialExp(e))
423        return e;
424
425    VarDeclaration *vd = copyToTemp(0, name, e);
426    if (e->isLvalue())
427        vd->storage_class |= STCref;
428    else
429        vd->storage_class |= STCrvalue;
430
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);
435
436    *e0 = Expression::combine(*e0, de);
437    return ve;
438}
439