Files
ldc/dmd2/canthrow.c
David Nadlinger 837ef30fec Merged DMD 2.060 frontend.
Upstream Git tag v2.060 (e8fe11c20249cb9e42538be88c99b74ede4d12e3).
2012-09-07 03:51:31 +02:00

191 lines
5.3 KiB
C

// Compiler implementation of the D programming language
// Copyright (c) 1999-2011 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 Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow);
int lambdaCanThrow(Expression *e, void *param);
/********************************************
* Convert from expression to delegate that returns the expression,
* i.e. convert:
* expr
* to:
* t delegate() { return expr; }
*/
struct CanThrow
{
bool can;
bool mustnot;
};
int Expression::canThrow(bool mustNotThrow)
{
//printf("Expression::canThrow(%d) %s\n", mustNotThrow, toChars());
CanThrow ct;
ct.can = FALSE;
ct.mustnot = mustNotThrow;
apply(&lambdaCanThrow, &ct);
return ct.can;
}
int lambdaCanThrow(Expression *e, void *param)
{
CanThrow *pct = (CanThrow *)param;
switch (e->op)
{
case TOKdeclaration:
{ DeclarationExp *de = (DeclarationExp *)e;
pct->can = Dsymbol_canThrow(de->declaration, pct->mustnot);
break;
}
case TOKcall:
{ CallExp *ce = (CallExp *)e;
if (global.errors && !ce->e1->type)
break; // error recovery
/* If calling a function or delegate that is typed as nothrow,
* then this expression cannot throw.
* Note that pure functions can throw.
*/
Type *t = ce->e1->type->toBasetype();
if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow)
;
else if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow)
;
else
{
if (pct->mustnot)
e->error("%s is not nothrow", ce->e1->toChars());
pct->can = TRUE;
}
break;
}
case TOKnew:
{ NewExp *ne = (NewExp *)e;
if (ne->member)
{
// See if constructor call can throw
Type *t = ne->member->type->toBasetype();
if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
{
if (pct->mustnot)
e->error("constructor %s is not nothrow", ne->member->toChars());
pct->can = TRUE;
}
}
// regard storage allocation failures as not recoverable
break;
}
case TOKnewanonclass:
assert(0); // should have been lowered by semantic()
break;
default:
break;
}
return pct->can; // stop walking if we determine this expression can throw
}
/**************************************
* Does symbol, when initialized, throw?
* Mirrors logic in Dsymbol_toElem().
*/
int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow)
{
AttribDeclaration *ad;
VarDeclaration *vd;
TemplateMixin *tm;
TupleDeclaration *td;
//printf("Dsymbol_toElem() %s\n", s->toChars());
ad = s->isAttribDeclaration();
if (ad)
{
Dsymbols *decl = ad->include(NULL, NULL);
if (decl && decl->dim)
{
for (size_t i = 0; i < decl->dim; i++)
{
s = (*decl)[i];
if (Dsymbol_canThrow(s, mustNotThrow))
return 1;
}
}
}
else if ((vd = s->isVarDeclaration()) != NULL)
{
s = s->toAlias();
if (s != vd)
return Dsymbol_canThrow(s, mustNotThrow);
if (vd->storage_class & STCmanifest)
;
else if (vd->isStatic() || vd->storage_class & (STCextern | STCtls | STCgshared))
;
else
{
if (vd->init)
{ ExpInitializer *ie = vd->init->isExpInitializer();
if (ie && ie->exp->canThrow(mustNotThrow))
return 1;
}
if (vd->edtor && !vd->noscope)
return vd->edtor->canThrow(mustNotThrow);
}
}
else if ((tm = s->isTemplateMixin()) != NULL)
{
//printf("%s\n", tm->toChars());
if (tm->members)
{
for (size_t i = 0; i < tm->members->dim; i++)
{
Dsymbol *sm = (*tm->members)[i];
if (Dsymbol_canThrow(sm, mustNotThrow))
return 1;
}
}
}
else if ((td = s->isTupleDeclaration()) != NULL)
{
for (size_t i = 0; i < td->objects->dim; i++)
{ Object *o = (*td->objects)[i];
if (o->dyncast() == DYNCAST_EXPRESSION)
{ Expression *eo = (Expression *)o;
if (eo->op == TOKdsymbol)
{ DsymbolExp *se = (DsymbolExp *)eo;
if (Dsymbol_canThrow(se->s, mustNotThrow))
return 1;
}
}
}
}
return 0;
}