]>
git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/d/dmd/sideeffect.c
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
16 #include "expression.h"
18 #include "statement.h"
21 #include "declaration.h"
22 #include "aggregate.h"
27 bool walkPostorder(Expression
*e
, StoppableVisitor
*v
);
28 bool lambdaHasSideEffect(Expression
*e
);
29 Expression
*semantic(Expression
*e
, Scope
*sc
);
31 /**************************************************
32 * Front-end expression rewriting should create temporary variables for
33 * non trivial sub-expressions in order to:
34 * 1. save evaluation order
35 * 2. prevent sharing of sub-expression in AST
37 bool isTrivialExp(Expression
*e
)
39 class IsTrivialExp
: public StoppableVisitor
44 void visit(Expression
*e
)
46 /* Bugzilla 11201: CallExp is always non trivial expression,
47 * especially for inlining.
55 // stop walking if we determine this expression has side effects
56 stop
= lambdaHasSideEffect(e
);
61 return walkPostorder(e
, &v
) == false;
64 /********************************************
65 * Determine if Expression has any side effects.
68 bool hasSideEffect(Expression
*e
)
70 class LambdaHasSideEffect
: public StoppableVisitor
73 LambdaHasSideEffect() {}
75 void visit(Expression
*e
)
77 // stop walking if we determine this expression has side effects
78 stop
= lambdaHasSideEffect(e
);
82 LambdaHasSideEffect v
;
83 return walkPostorder(e
, &v
);
86 /********************************************
87 * Determine if the call of f, or function type or delegate type t1, has any side effects.
89 * 0 has any side effects
90 * 1 nothrow + constant purity
91 * 2 nothrow + strong purity
94 int callSideEffectLevel(FuncDeclaration
*f
)
96 /* Bugzilla 12760: ctor call always has side effects.
98 if (f
->isCtorDeclaration())
101 assert(f
->type
->ty
== Tfunction
);
102 TypeFunction
*tf
= (TypeFunction
*)f
->type
;
105 PURE purity
= f
->isPure();
106 if (purity
== PUREstrong
)
108 if (purity
== PUREconst
)
114 int callSideEffectLevel(Type
*t
)
119 if (t
->ty
== Tdelegate
)
120 tf
= (TypeFunction
*)((TypeDelegate
*)t
)->next
;
123 assert(t
->ty
== Tfunction
);
124 tf
= (TypeFunction
*)t
;
128 PURE purity
= tf
->purity
;
129 if (t
->ty
== Tdelegate
&& purity
> PUREweak
)
133 else if (!tf
->isImmutable())
139 if (purity
== PUREstrong
)
141 if (purity
== PUREconst
)
147 bool lambdaHasSideEffect(Expression
*e
)
151 // Sort the cases by most frequently used first
177 case TOKnewanonclass
:
182 CallExp
*ce
= (CallExp
*)e
;
183 /* Calling a function or delegate that is pure nothrow
184 * has no side effects.
188 Type
*t
= ce
->e1
->type
->toBasetype();
189 if (t
->ty
== Tdelegate
)
190 t
= ((TypeDelegate
*)t
)->next
;
191 if (t
->ty
== Tfunction
&&
192 (ce
->f
? callSideEffectLevel(ce
->f
)
193 : callSideEffectLevel(ce
->e1
->type
)) > 0)
204 CastExp
*ce
= (CastExp
*)e
;
206 * cast(classtype)func() // because it may throw
208 if (ce
->to
->ty
== Tclass
&& ce
->e1
->op
== TOKcall
&& ce
->e1
->type
->ty
== Tclass
)
220 /***********************************
221 * The result of this expression will be discarded.
222 * Print error messages if the operation has no side effects (and hence is meaningless).
224 * true if expression has no side effects
226 bool discardValue(Expression
*e
)
228 if (lambdaHasSideEffect(e
)) // check side-effect shallowly
234 CastExp
*ce
= (CastExp
*)e
;
235 if (ce
->to
->equals(Type::tvoid
))
238 * Don't complain about an expression with no effect if it was cast to void
250 VarDeclaration
*v
= ((VarExp
*)e
)->var
->isVarDeclaration();
251 if (v
&& (v
->storage_class
& STCtemp
))
253 // Bugzilla 5810: Don't complain about an internal generated variable.
260 if (global
.params
.warnings
!= DIAGNOSTICoff
&& !global
.gag
)
262 CallExp
*ce
= (CallExp
*)e
;
263 if (e
->type
->ty
== Tvoid
)
265 /* Don't complain about calling void-returning functions with no side-effect,
266 * because purity and nothrow are inferred, and because some of the
267 * runtime library depends on it. Needs more investigation.
269 * One possible solution is to restrict this message to only be called in hierarchies that
270 * never call assert (and or not called from inside unittest blocks)
273 else if (ce
->e1
->type
)
275 Type
*t
= ce
->e1
->type
->toBasetype();
276 if (t
->ty
== Tdelegate
)
277 t
= ((TypeDelegate
*)t
)->next
;
278 if (t
->ty
== Tfunction
&&
279 (ce
->f
? callSideEffectLevel(ce
->f
)
280 : callSideEffectLevel(ce
->e1
->type
)) > 0)
284 s
= ce
->f
->toPrettyChars();
285 else if (ce
->e1
->op
== TOKstar
)
287 // print 'fp' if ce->e1 is (*fp)
288 s
= ((PtrExp
*)ce
->e1
)->e1
->toChars();
291 s
= ce
->e1
->toChars();
293 e
->warning("calling %s without side effects discards return value of type %s, prepend a cast(void) if intentional",
294 s
, e
->type
->toChars());
301 e
->error("%s has no effect", e
->toChars());
306 AndAndExp
*aae
= (AndAndExp
*)e
;
307 return discardValue(aae
->e2
);
312 OrOrExp
*ooe
= (OrOrExp
*)e
;
313 return discardValue(ooe
->e2
);
318 CondExp
*ce
= (CondExp
*)e
;
320 /* Bugzilla 6178 & 14089: Either CondExp::e1 or e2 may have
321 * redundant expression to make those types common. For example:
323 * struct S { this(int n); int v; alias v this; }
327 * The last assignment statement will be rewitten to:
329 * 1 in aa ? aa[1].value = 0 : (aa[1] = 0, aa[1].this(0)).value;
331 * The last DotVarExp is necessary to take assigned value.
333 * int value = (aa[1] = 0); // value = aa[1].value
335 * To avoid false error, discardValue() should be called only when
336 * the both tops of e1 and e2 have actually no side effects.
338 if (!lambdaHasSideEffect(ce
->e1
) &&
339 !lambdaHasSideEffect(ce
->e2
))
341 return discardValue(ce
->e1
) |
342 discardValue(ce
->e2
);
349 CommaExp
*ce
= (CommaExp
*)e
;
350 /* Check for compiler-generated code of the form auto __tmp, e, __tmp;
351 * In such cases, only check e for side effect (it's OK for __tmp to have
353 * See Bugzilla 4231 for discussion
355 CommaExp
*firstComma
= ce
;
356 while (firstComma
->e1
->op
== TOKcomma
)
357 firstComma
= (CommaExp
*)firstComma
->e1
;
358 if (firstComma
->e1
->op
== TOKdeclaration
&&
359 ce
->e2
->op
== TOKvar
&&
360 ((DeclarationExp
*)firstComma
->e1
)->declaration
== ((VarExp
*)ce
->e2
)->var
)
364 // Don't check e1 until we cast(void) the a,b code generation
365 //discardValue(ce->e1);
366 return discardValue(ce
->e2
);
370 /* Pass without complaint if any of the tuple elements have side effects.
371 * Ideally any tuple elements with no side effects should raise an error,
372 * this needs more investigation as to what is the right thing to do.
374 if (!hasSideEffect(e
))
381 e
->error("%s has no effect in expression (%s)", Token::toChars(e
->op
), e
->toChars());
385 /**************************************************
386 * Build a temporary variable to copy the value of e into.
388 * stc = storage classes will be added to the made temporary variable
389 * name = name for temporary variable
390 * e = original expression
392 * Newly created temporary variable.
394 VarDeclaration
*copyToTemp(StorageClass stc
, const char *name
, Expression
*e
)
396 assert(name
&& name
[0] == '_' && name
[1] == '_');
397 Identifier
*id
= Identifier::generateId(name
);
398 ExpInitializer
*ez
= new ExpInitializer(e
->loc
, e
);
399 VarDeclaration
*vd
= new VarDeclaration(e
->loc
, e
->type
, id
, ez
);
400 vd
->storage_class
= stc
;
401 vd
->storage_class
|= STCtemp
;
402 vd
->storage_class
|= STCctfe
; // temporary is always CTFEable
406 /**************************************************
407 * Build a temporary variable to extract e's evaluation, if e is not trivial.
410 * name = name for temporary variable
411 * e0 = a new side effect part will be appended to it.
412 * e = original expression
413 * alwaysCopy = if true, build new temporary variable even if e is trivial.
415 * When e is trivial and alwaysCopy == false, e itself is returned.
416 * Otherwise, a new VarExp is returned.
418 * e's lvalue-ness will be handled well by STCref or STCrvalue.
420 Expression
*extractSideEffect(Scope
*sc
, const char *name
,
421 Expression
**e0
, Expression
*e
, bool alwaysCopy
= false)
423 if (!alwaysCopy
&& isTrivialExp(e
))
426 VarDeclaration
*vd
= copyToTemp(0, name
, e
);
428 vd
->storage_class
|= STCref
;
430 vd
->storage_class
|= STCrvalue
;
432 Expression
*de
= new DeclarationExp(vd
->loc
, vd
);
433 Expression
*ve
= new VarExp(vd
->loc
, vd
);
434 de
= semantic(de
, sc
);
435 ve
= semantic(ve
, sc
);
437 *e0
= Expression::combine(*e0
, de
);