mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-11 18:33:14 +01:00
251 lines
7.0 KiB
C
251 lines
7.0 KiB
C
|
|
// Compiler implementation of the D programming language
|
|
// Copyright (c) 1999-2012 by Digital Mars
|
|
// All Rights Reserved
|
|
// written by Walter Bright
|
|
// http://www.digitalmars.com
|
|
// License for redistribution is by either the Artistic License
|
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
|
// See the included readme.txt for details.
|
|
|
|
#include <stdio.h>
|
|
#include <assert.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"
|
|
|
|
int lambdaHasSideEffect(Expression *e, void *param);
|
|
|
|
/********************************************
|
|
* Determine if Expression has any side effects.
|
|
*/
|
|
|
|
bool Expression::hasSideEffect()
|
|
{
|
|
bool has = FALSE;
|
|
apply(&lambdaHasSideEffect, &has);
|
|
return has;
|
|
}
|
|
|
|
int lambdaHasSideEffect(Expression *e, void *param)
|
|
{
|
|
bool *phas = (bool *)param;
|
|
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:
|
|
*phas = TRUE;
|
|
break;
|
|
|
|
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 == Tfunction && ((TypeFunction *)t)->purity > PUREweak &&
|
|
((TypeFunction *)t)->isnothrow)
|
|
||
|
|
(t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->purity > PUREweak &&
|
|
((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow)
|
|
)
|
|
{
|
|
}
|
|
else
|
|
*phas = 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)
|
|
*phas = TRUE;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return *phas; // stop walking if we determine this expression has side effects
|
|
}
|
|
|
|
|
|
/***********************************
|
|
* The result of this expression will be discarded.
|
|
* Complain if the operation has no side effects (and hence is meaningless).
|
|
*/
|
|
void Expression::discardValue()
|
|
{
|
|
bool has = FALSE;
|
|
lambdaHasSideEffect(this, &has);
|
|
if (!has)
|
|
{
|
|
switch (op)
|
|
{
|
|
case TOKcast:
|
|
{ CastExp *ce = (CastExp *)this;
|
|
if (ce->to->equals(Type::tvoid))
|
|
{ /*
|
|
* Don't complain about an expression with no effect if it was cast to void
|
|
*/
|
|
ce->e1->useValue();
|
|
break;
|
|
}
|
|
goto Ldefault; // complain
|
|
}
|
|
|
|
case TOKerror:
|
|
break;
|
|
|
|
case TOKcall:
|
|
/* Don't complain about calling functions with no effect,
|
|
* because purity and nothrow are inferred, and because some of the
|
|
* runtime library depends on it. Needs more investigation.
|
|
*/
|
|
break;
|
|
|
|
case TOKimport:
|
|
error("%s has no effect", toChars());
|
|
break;
|
|
|
|
case TOKandand:
|
|
{ AndAndExp *aae = (AndAndExp *)this;
|
|
aae->e1->useValue();
|
|
aae->e2->discardValue();
|
|
break;
|
|
}
|
|
|
|
case TOKoror:
|
|
{ OrOrExp *ooe = (OrOrExp *)this;
|
|
ooe->e1->useValue();
|
|
ooe->e2->discardValue();
|
|
break;
|
|
}
|
|
|
|
case TOKquestion:
|
|
{ CondExp *ce = (CondExp *)this;
|
|
ce->econd->useValue();
|
|
ce->e1->discardValue();
|
|
ce->e2->discardValue();
|
|
break;
|
|
}
|
|
|
|
case TOKcomma:
|
|
{ CommaExp *ce = (CommaExp *)this;
|
|
|
|
/* 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)
|
|
{
|
|
ce->e1->useValue();
|
|
break;
|
|
}
|
|
// Don't check e1 until we cast(void) the a,b code generation
|
|
//ce->e1->discardValue();
|
|
ce->e2->discardValue();
|
|
break;
|
|
}
|
|
|
|
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())
|
|
goto Ldefault;
|
|
break;
|
|
|
|
default:
|
|
Ldefault:
|
|
error("%s has no effect in expression (%s)",
|
|
Token::toChars(op), toChars());
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
useValue();
|
|
}
|
|
}
|
|
|
|
/* This isn't used yet because the only way an expression has an unused sub-expression
|
|
* is with the CommaExp, and that currently generates messages from rewrites into comma
|
|
* expressions. Needs more investigation.
|
|
*/
|
|
void Expression::useValue()
|
|
{
|
|
#if 0
|
|
// Disabled because need to cast(void) the a,b code generation
|
|
void *p;
|
|
apply(&lambdaUseValue, &p);
|
|
#endif
|
|
}
|
|
|
|
#if 0
|
|
int lambdaUseValue(Expression *e, void *param)
|
|
{
|
|
switch (e->op)
|
|
{
|
|
case TOKcomma:
|
|
{ CommaExp *ce = (CommaExp *)e;
|
|
discardValue(ce->E1);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|