summaryrefslogtreecommitdiff
path: root/gcc/d/dmd/sideeffect.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/d/dmd/sideeffect.c')
-rw-r--r--gcc/d/dmd/sideeffect.c432
1 files changed, 0 insertions, 432 deletions
diff --git a/gcc/d/dmd/sideeffect.c b/gcc/d/dmd/sideeffect.c
deleted file mode 100644
index 661bd43134c..00000000000
--- a/gcc/d/dmd/sideeffect.c
+++ /dev/null
@@ -1,432 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/sideeffect.c
- */
-
-#include "root/dsystem.h"
-
-#include "mars.h"
-#include "init.h"
-#include "expression.h"
-#include "template.h"
-#include "statement.h"
-#include "mtype.h"
-#include "utf.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "scope.h"
-#include "attrib.h"
-#include "tokens.h"
-
-bool walkPostorder(Expression *e, StoppableVisitor *v);
-bool lambdaHasSideEffect(Expression *e);
-
-/**************************************************
- * Front-end expression rewriting should create temporary variables for
- * non trivial sub-expressions in order to:
- * 1. save evaluation order
- * 2. prevent sharing of sub-expression in AST
- */
-bool isTrivialExp(Expression *e)
-{
- class IsTrivialExp : public StoppableVisitor
- {
- public:
- IsTrivialExp() {}
-
- void visit(Expression *e)
- {
- /* Bugzilla 11201: CallExp is always non trivial expression,
- * especially for inlining.
- */
- if (e->op == TOKcall)
- {
- stop = true;
- return;
- }
-
- // stop walking if we determine this expression has side effects
- stop = lambdaHasSideEffect(e);
- }
- };
-
- IsTrivialExp v;
- return walkPostorder(e, &v) == false;
-}
-
-/********************************************
- * Determine if Expression has any side effects.
- */
-
-bool hasSideEffect(Expression *e)
-{
- class LambdaHasSideEffect : public StoppableVisitor
- {
- public:
- LambdaHasSideEffect() {}
-
- void visit(Expression *e)
- {
- // stop walking if we determine this expression has side effects
- stop = lambdaHasSideEffect(e);
- }
- };
-
- LambdaHasSideEffect v;
- return walkPostorder(e, &v);
-}
-
-/********************************************
- * Determine if the call of f, or function type or delegate type t1, has any side effects.
- * Returns:
- * 0 has any side effects
- * 1 nothrow + constant purity
- * 2 nothrow + strong purity
- */
-
-int callSideEffectLevel(FuncDeclaration *f)
-{
- /* Bugzilla 12760: ctor call always has side effects.
- */
- if (f->isCtorDeclaration())
- return 0;
-
- assert(f->type->ty == Tfunction);
- TypeFunction *tf = (TypeFunction *)f->type;
- if (tf->isnothrow)
- {
- PURE purity = f->isPure();
- if (purity == PUREstrong)
- return 2;
- if (purity == PUREconst)
- return 1;
- }
- return 0;
-}
-
-int callSideEffectLevel(Type *t)
-{
- t = t->toBasetype();
-
- TypeFunction *tf;
- if (t->ty == Tdelegate)
- tf = (TypeFunction *)((TypeDelegate *)t)->next;
- else
- {
- assert(t->ty == Tfunction);
- tf = (TypeFunction *)t;
- }
-
- tf->purityLevel();
- PURE purity = tf->purity;
- if (t->ty == Tdelegate && purity > PUREweak)
- {
- if (tf->isMutable())
- purity = PUREweak;
- else if (!tf->isImmutable())
- purity = PUREconst;
- }
-
- if (tf->isnothrow)
- {
- if (purity == PUREstrong)
- return 2;
- if (purity == PUREconst)
- return 1;
- }
- return 0;
-}
-
-bool lambdaHasSideEffect(Expression *e)
-{
- switch (e->op)
- {
- // Sort the cases by most frequently used first
- case TOKassign:
- case TOKplusplus:
- case TOKminusminus:
- case TOKdeclaration:
- case TOKconstruct:
- case TOKblit:
- case TOKaddass:
- case TOKminass:
- case TOKcatass:
- case TOKmulass:
- case TOKdivass:
- case TOKmodass:
- case TOKshlass:
- case TOKshrass:
- case TOKushrass:
- case TOKandass:
- case TOKorass:
- case TOKxorass:
- case TOKpowass:
- case TOKin:
- case TOKremove:
- case TOKassert:
- case TOKhalt:
- case TOKdelete:
- case TOKnew:
- case TOKnewanonclass:
- return true;
-
- case TOKcall:
- {
- CallExp *ce = (CallExp *)e;
- /* Calling a function or delegate that is pure nothrow
- * has no side effects.
- */
- 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)
- {
- }
- else
- return true;
- }
- break;
- }
-
- case TOKcast:
- {
- CastExp *ce = (CastExp *)e;
- /* if:
- * cast(classtype)func() // because it may throw
- */
- if (ce->to->ty == Tclass && ce->e1->op == TOKcall && ce->e1->type->ty == Tclass)
- return true;
- break;
- }
-
- default:
- break;
- }
- return false;
-}
-
-
-/***********************************
- * 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:
- case TOKoror:
- {
- LogicalExp *aae = (LogicalExp *)e;
- return discardValue(aae->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;
-}
-
-/**************************************************
- * Build a temporary variable to copy the value of e into.
- * Params:
- * stc = storage classes will be added to the made temporary variable
- * name = name for temporary variable
- * e = original expression
- * Returns:
- * Newly created temporary variable.
- */
-VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e)
-{
- assert(name && name[0] == '_' && name[1] == '_');
- Identifier *id = Identifier::generateId(name);
- ExpInitializer *ez = new ExpInitializer(e->loc, e);
- VarDeclaration *vd = new VarDeclaration(e->loc, e->type, id, ez);
- vd->storage_class = stc;
- vd->storage_class |= STCtemp;
- vd->storage_class |= STCctfe; // temporary is always CTFEable
- return vd;
-}
-
-/**************************************************
- * Build a temporary variable to extract e's evaluation, if e is not trivial.
- * Params:
- * sc = scope
- * name = name for temporary variable
- * e0 = a new side effect part will be appended to it.
- * e = original expression
- * alwaysCopy = if true, build new temporary variable even if e is trivial.
- * Returns:
- * When e is trivial and alwaysCopy == false, e itself is returned.
- * Otherwise, a new VarExp is returned.
- * Note:
- * e's lvalue-ness will be handled well by STCref or STCrvalue.
- */
-Expression *extractSideEffect(Scope *sc, const char *name,
- Expression **e0, Expression *e, bool alwaysCopy = false)
-{
- if (!alwaysCopy && isTrivialExp(e))
- return e;
-
- VarDeclaration *vd = copyToTemp(0, name, e);
- if (e->isLvalue())
- vd->storage_class |= STCref;
- else
- vd->storage_class |= STCrvalue;
-
- Expression *de = new DeclarationExp(vd->loc, vd);
- Expression *ve = new VarExp(vd->loc, vd);
- de = expressionSemantic(de, sc);
- ve = expressionSemantic(ve, sc);
-
- *e0 = Expression::combine(*e0, de);
- return ve;
-}