diff options
Diffstat (limited to 'gcc/d/dmd/sideeffect.c')
-rw-r--r-- | gcc/d/dmd/sideeffect.c | 432 |
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; -} |