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
11 #include "root/dsystem.h"
15 #include "expression.h"
17 #include "statement.h"
20 #include "declaration.h"
21 #include "aggregate.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
;
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
)
71 if (t
->ty
== Tfunction
&& ((TypeFunction
*)t
)->isnothrow
)
73 if (t
->ty
== Tdelegate
&& ((TypeFunction
*)((TypeDelegate
*)t
)->next
)->isnothrow
)
80 ce
->error("%s '%s' is not nothrow",
81 ce
->f
->kind(), ce
->f
->toPrettyChars());
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());
94 void visit(NewExp
*ne
)
101 Type
*t
= ne
->allocator
->type
->toBasetype();
102 if (t
->ty
== Tfunction
&& !((TypeFunction
*)t
)->isnothrow
)
106 ne
->error("%s '%s' is not nothrow",
107 ne
->allocator
->kind(), ne
->allocator
->toPrettyChars());
112 // See if constructor call can throw
113 Type
*t
= ne
->member
->type
->toBasetype();
114 if (t
->ty
== Tfunction
&& !((TypeFunction
*)t
)->isnothrow
)
118 ne
->error("%s '%s' is not nothrow",
119 ne
->member
->kind(), ne
->member
->toPrettyChars());
124 // regard storage allocation failures as not recoverable
127 void visit(DeleteExp
*de
)
129 Type
*tb
= de
->e1
->type
->toBasetype();
130 AggregateDeclaration
*ad
= NULL
;
134 ad
= ((TypeClass
*)tb
)->sym
;
138 tb
= ((TypePointer
*)tb
)->next
->toBasetype();
139 if (tb
->ty
== Tstruct
)
140 ad
= ((TypeStruct
*)tb
)->sym
;
145 Type
*tv
= tb
->nextOf()->baseElemOf();
146 if (tv
->ty
== Tstruct
)
148 ad
= ((TypeStruct
*)tv
)->sym
;
161 Type
*t
= ad
->dtor
->type
->toBasetype();
162 if (t
->ty
== Tfunction
&& !((TypeFunction
*)t
)->isnothrow
)
166 de
->error("%s '%s' is not nothrow",
167 ad
->dtor
->kind(), ad
->dtor
->toPrettyChars());
172 if (ad
->aggDelete
&& tb
->ty
!= Tarray
)
174 Type
*t
= ad
->aggDelete
->type
;
175 if (t
->ty
== Tfunction
&& !((TypeFunction
*)t
)->isnothrow
)
179 de
->error("%s '%s' is not nothrow",
180 ad
->aggDelete
->kind(), ad
->aggDelete
->toPrettyChars());
187 void visit(AssignExp
*ae
)
189 // blit-init cannot throw
190 if (ae
->op
== TOKblit
)
193 /* Element-wise assignment could invoke postblits.
196 if (ae
->type
->toBasetype()->ty
== Tsarray
)
198 if (!ae
->e2
->isLvalue())
202 else if (ae
->e1
->op
== TOKslice
)
203 t
= ((SliceExp
*)ae
->e1
)->e1
->type
;
207 Type
*tv
= t
->baseElemOf();
208 if (tv
->ty
!= Tstruct
)
210 StructDeclaration
*sd
= ((TypeStruct
*)tv
)->sym
;
211 if (!sd
->postblit
|| sd
->postblit
->type
->ty
!= Tfunction
)
214 if (((TypeFunction
*)sd
->postblit
->type
)->isnothrow
)
220 ae
->error("%s '%s' is not nothrow",
221 sd
->postblit
->kind(), sd
->postblit
->toPrettyChars());
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
;
247 TupleDeclaration
*td
;
249 //printf("Dsymbol_toElem() %s\n", s->toChars());
250 ad
= s
->isAttribDeclaration();
253 Dsymbols
*decl
= ad
->include(NULL
, NULL
);
254 if (decl
&& decl
->dim
)
256 for (size_t i
= 0; i
< decl
->dim
; i
++)
259 if (Dsymbol_canThrow(s
, func
, mustNotThrow
))
264 else if ((vd
= s
->isVarDeclaration()) != NULL
)
268 return Dsymbol_canThrow(s
, func
, mustNotThrow
);
269 if (vd
->storage_class
& STCmanifest
)
271 else if (vd
->isStatic() || vd
->storage_class
& (STCextern
| STCtls
| STCgshared
))
277 ExpInitializer
*ie
= vd
->_init
->isExpInitializer();
278 if (ie
&& canThrow(ie
->exp
, func
, mustNotThrow
))
281 if (vd
->needsScopeDtor())
282 return canThrow(vd
->edtor
, func
, mustNotThrow
);
285 else if ((tm
= s
->isTemplateMixin()) != NULL
)
287 //printf("%s\n", tm->toChars());
290 for (size_t i
= 0; i
< tm
->members
->dim
; i
++)
292 Dsymbol
*sm
= (*tm
->members
)[i
];
293 if (Dsymbol_canThrow(sm
, func
, mustNotThrow
))
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
))