Merge dmd upstream 6243fa6d2
[official-gcc.git] / gcc / d / dmd / canthrow.c
blobec15153eb4efd28f479f0516f35a0f74ce409b53
2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
4 * written by Walter Bright
5 * http://www.digitalmars.com
6 * Distributed under the Boost Software License, Version 1.0.
7 * http://www.boost.org/LICENSE_1_0.txt
8 * https://github.com/D-Programming-Language/dmd/blob/master/src/canthrow.c
9 */
11 #include "root/dsystem.h"
13 #include "mars.h"
14 #include "init.h"
15 #include "expression.h"
16 #include "template.h"
17 #include "statement.h"
18 #include "mtype.h"
19 #include "utf.h"
20 #include "declaration.h"
21 #include "aggregate.h"
22 #include "scope.h"
23 #include "attrib.h"
24 #include "tokens.h"
26 bool Dsymbol_canThrow(Dsymbol *s, FuncDeclaration *func, bool mustNotThrow);
27 bool walkPostorder(Expression *e, StoppableVisitor *v);
29 /********************************************
30 * Returns true if the expression may throw exceptions.
31 * If 'mustNotThrow' is true, generate an error if it throws
34 bool canThrow(Expression *e, FuncDeclaration *func, bool mustNotThrow)
36 //printf("Expression::canThrow(%d) %s\n", mustNotThrow, toChars());
38 // stop walking if we determine this expression can throw
39 class CanThrow : public StoppableVisitor
41 FuncDeclaration *func;
42 bool mustNotThrow;
44 public:
45 CanThrow(FuncDeclaration *func, bool mustNotThrow)
46 : func(func), mustNotThrow(mustNotThrow)
50 void visit(Expression *)
54 void visit(DeclarationExp *de)
56 stop = Dsymbol_canThrow(de->declaration, func, mustNotThrow);
59 void visit(CallExp *ce)
61 if (global.errors && !ce->e1->type)
62 return; // error recovery
64 /* If calling a function or delegate that is typed as nothrow,
65 * then this expression cannot throw.
66 * Note that pure functions can throw.
68 Type *t = ce->e1->type->toBasetype();
69 if (ce->f && ce->f == func)
70 return;
71 if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow)
72 return;
73 if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow)
74 return;
76 if (mustNotThrow)
78 if (ce->f)
80 ce->error("%s '%s' is not nothrow",
81 ce->f->kind(), ce->f->toPrettyChars());
83 else
85 Expression *e1 = ce->e1;
86 if (e1->op == TOKstar) // print 'fp' if e1 is (*fp)
87 e1 = ((PtrExp *)e1)->e1;
88 ce->error("'%s' is not nothrow", e1->toChars());
91 stop = true;
94 void visit(NewExp *ne)
96 if (ne->member)
98 if (ne->allocator)
100 // Bugzilla 14407
101 Type *t = ne->allocator->type->toBasetype();
102 if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
104 if (mustNotThrow)
106 ne->error("%s '%s' is not nothrow",
107 ne->allocator->kind(), ne->allocator->toPrettyChars());
109 stop = true;
112 // See if constructor call can throw
113 Type *t = ne->member->type->toBasetype();
114 if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
116 if (mustNotThrow)
118 ne->error("%s '%s' is not nothrow",
119 ne->member->kind(), ne->member->toPrettyChars());
121 stop = true;
124 // regard storage allocation failures as not recoverable
127 void visit(DeleteExp *de)
129 Type *tb = de->e1->type->toBasetype();
130 AggregateDeclaration *ad = NULL;
131 switch (tb->ty)
133 case Tclass:
134 ad = ((TypeClass *)tb)->sym;
135 break;
137 case Tpointer:
138 tb = ((TypePointer *)tb)->next->toBasetype();
139 if (tb->ty == Tstruct)
140 ad = ((TypeStruct *)tb)->sym;
141 break;
143 case Tarray:
145 Type *tv = tb->nextOf()->baseElemOf();
146 if (tv->ty == Tstruct)
148 ad = ((TypeStruct *)tv)->sym;
149 break;
153 default:
154 break;
156 if (!ad)
157 return;
159 if (ad->dtor)
161 Type *t = ad->dtor->type->toBasetype();
162 if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
164 if (mustNotThrow)
166 de->error("%s '%s' is not nothrow",
167 ad->dtor->kind(), ad->dtor->toPrettyChars());
169 stop = true;
172 if (ad->aggDelete && tb->ty != Tarray)
174 Type *t = ad->aggDelete->type;
175 if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
177 if (mustNotThrow)
179 de->error("%s '%s' is not nothrow",
180 ad->aggDelete->kind(), ad->aggDelete->toPrettyChars());
182 stop = true;
187 void visit(AssignExp *ae)
189 // blit-init cannot throw
190 if (ae->op == TOKblit)
191 return;
193 /* Element-wise assignment could invoke postblits.
195 Type *t;
196 if (ae->type->toBasetype()->ty == Tsarray)
198 if (!ae->e2->isLvalue())
199 return;
200 t = ae->type;
202 else if (ae->e1->op == TOKslice)
203 t = ((SliceExp *)ae->e1)->e1->type;
204 else
205 return;
207 Type *tv = t->baseElemOf();
208 if (tv->ty != Tstruct)
209 return;
210 StructDeclaration *sd = ((TypeStruct *)tv)->sym;
211 if (!sd->postblit || sd->postblit->type->ty != Tfunction)
212 return;
214 if (((TypeFunction *)sd->postblit->type)->isnothrow)
216 else
218 if (mustNotThrow)
220 ae->error("%s '%s' is not nothrow",
221 sd->postblit->kind(), sd->postblit->toPrettyChars());
223 stop = true;
227 void visit(NewAnonClassExp *)
229 assert(0); // should have been lowered by semantic()
233 CanThrow ct(func, mustNotThrow);
234 return walkPostorder(e, &ct);
237 /**************************************
238 * Does symbol, when initialized, throw?
239 * Mirrors logic in Dsymbol_toElem().
242 bool Dsymbol_canThrow(Dsymbol *s, FuncDeclaration *func, bool mustNotThrow)
244 AttribDeclaration *ad;
245 VarDeclaration *vd;
246 TemplateMixin *tm;
247 TupleDeclaration *td;
249 //printf("Dsymbol_toElem() %s\n", s->toChars());
250 ad = s->isAttribDeclaration();
251 if (ad)
253 Dsymbols *decl = ad->include(NULL, NULL);
254 if (decl && decl->dim)
256 for (size_t i = 0; i < decl->dim; i++)
258 s = (*decl)[i];
259 if (Dsymbol_canThrow(s, func, mustNotThrow))
260 return true;
264 else if ((vd = s->isVarDeclaration()) != NULL)
266 s = s->toAlias();
267 if (s != vd)
268 return Dsymbol_canThrow(s, func, mustNotThrow);
269 if (vd->storage_class & STCmanifest)
271 else if (vd->isStatic() || vd->storage_class & (STCextern | STCtls | STCgshared))
273 else
275 if (vd->_init)
277 ExpInitializer *ie = vd->_init->isExpInitializer();
278 if (ie && canThrow(ie->exp, func, mustNotThrow))
279 return true;
281 if (vd->needsScopeDtor())
282 return canThrow(vd->edtor, func, mustNotThrow);
285 else if ((tm = s->isTemplateMixin()) != NULL)
287 //printf("%s\n", tm->toChars());
288 if (tm->members)
290 for (size_t i = 0; i < tm->members->dim; i++)
292 Dsymbol *sm = (*tm->members)[i];
293 if (Dsymbol_canThrow(sm, func, mustNotThrow))
294 return true;
298 else if ((td = s->isTupleDeclaration()) != NULL)
300 for (size_t i = 0; i < td->objects->dim; i++)
302 RootObject *o = (*td->objects)[i];
303 if (o->dyncast() == DYNCAST_EXPRESSION)
305 Expression *eo = (Expression *)o;
306 if (eo->op == TOKdsymbol)
308 DsymbolExp *se = (DsymbolExp *)eo;
309 if (Dsymbol_canThrow(se->s, func, mustNotThrow))
310 return true;
315 return false;