-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathcanthrow.c
189 lines (172 loc) · 5.25 KB
/
canthrow.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// 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)
{
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->tdata()[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->tdata()[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->tdata()[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;
}