]>
git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/d/dmd/blockexit.c
2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2019 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
10 #include "statement.h"
11 #include "declaration.h"
12 #include "aggregate.h"
15 /* Only valid after semantic analysis
16 * If 'mustNotThrow' is true, generate an error if it throws
18 int blockExit(Statement
*s
, FuncDeclaration
*func
, bool mustNotThrow
)
20 class BlockExit
: public Visitor
23 FuncDeclaration
*func
;
27 BlockExit(FuncDeclaration
*func
, bool mustNotThrow
)
28 : func(func
), mustNotThrow(mustNotThrow
)
33 void visit(Statement
*s
)
35 printf("Statement::blockExit(%p)\n", s
);
36 printf("%s\n", s
->toChars());
41 void visit(ErrorStatement
*)
46 void visit(ExpStatement
*s
)
51 if (s
->exp
->op
== TOKhalt
)
56 if (s
->exp
->op
== TOKassert
)
58 AssertExp
*a
= (AssertExp
*)s
->exp
;
59 if (a
->e1
->isBool(false)) // if it's an assert(0)
65 if (canThrow(s
->exp
, func
, mustNotThrow
))
70 void visit(CompileStatement
*)
72 assert(global
.errors
);
76 void visit(CompoundStatement
*cs
)
78 //printf("CompoundStatement::blockExit(%p) %d result = x%X\n", cs, cs->statements->dim, result);
80 Statement
*slast
= NULL
;
81 for (size_t i
= 0; i
< cs
->statements
->dim
; i
++)
83 Statement
*s
= (*cs
->statements
)[i
];
86 //printf("result = x%x\n", result);
87 //printf("s: %s\n", s->toChars());
88 if (result
& BEfallthru
&& slast
)
90 slast
= slast
->last();
91 if (slast
&& (slast
->isCaseStatement() || slast
->isDefaultStatement()) &&
92 (s
->isCaseStatement() || s
->isDefaultStatement()))
94 // Allow if last case/default was empty
95 CaseStatement
*sc
= slast
->isCaseStatement();
96 DefaultStatement
*sd
= slast
->isDefaultStatement();
97 if (sc
&& (!sc
->statement
->hasCode() || sc
->statement
->isCaseStatement() || sc
->statement
->isErrorStatement()))
99 else if (sd
&& (!sd
->statement
->hasCode() || sd
->statement
->isCaseStatement() || sd
->statement
->isErrorStatement()))
103 const char *gototype
= s
->isCaseStatement() ? "case" : "default";
104 s
->deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype
);
109 if (!(result
& BEfallthru
) && !s
->comeFrom())
111 if (blockExit(s
, func
, mustNotThrow
) != BEhalt
&& s
->hasCode())
112 s
->warning("statement is not reachable");
116 result
&= ~BEfallthru
;
117 result
|= blockExit(s
, func
, mustNotThrow
);
124 void visit(UnrolledLoopStatement
*uls
)
127 for (size_t i
= 0; i
< uls
->statements
->dim
; i
++)
129 Statement
*s
= (*uls
->statements
)[i
];
132 int r
= blockExit(s
, func
, mustNotThrow
);
133 result
|= r
& ~(BEbreak
| BEcontinue
| BEfallthru
);
134 if ((r
& (BEfallthru
| BEcontinue
| BEbreak
)) == 0)
135 result
&= ~BEfallthru
;
140 void visit(ScopeStatement
*s
)
142 //printf("ScopeStatement::blockExit(%p)\n", s->statement);
143 result
= s
->statement
? blockExit(s
->statement
, func
, mustNotThrow
) : BEfallthru
;
146 void visit(WhileStatement
*)
148 assert(global
.errors
);
152 void visit(DoStatement
*s
)
156 result
= blockExit(s
->_body
, func
, mustNotThrow
);
157 if (result
== BEbreak
)
162 if (result
& BEcontinue
)
163 result
|= BEfallthru
;
167 if (result
& BEfallthru
)
169 if (canThrow(s
->condition
, func
, mustNotThrow
))
171 if (!(result
& BEbreak
) && s
->condition
->isBool(true))
172 result
&= ~BEfallthru
;
174 result
&= ~(BEbreak
| BEcontinue
);
177 void visit(ForStatement
*s
)
182 result
= blockExit(s
->_init
, func
, mustNotThrow
);
183 if (!(result
& BEfallthru
))
188 if (canThrow(s
->condition
, func
, mustNotThrow
))
190 if (s
->condition
->isBool(true))
191 result
&= ~BEfallthru
;
192 else if (s
->condition
->isBool(false))
196 result
&= ~BEfallthru
; // the body must do the exiting
199 int r
= blockExit(s
->_body
, func
, mustNotThrow
);
200 if (r
& (BEbreak
| BEgoto
))
201 result
|= BEfallthru
;
202 result
|= r
& ~(BEfallthru
| BEbreak
| BEcontinue
);
204 if (s
->increment
&& canThrow(s
->increment
, func
, mustNotThrow
))
208 void visit(ForeachStatement
*s
)
211 if (canThrow(s
->aggr
, func
, mustNotThrow
))
214 result
|= blockExit(s
->_body
, func
, mustNotThrow
) & ~(BEbreak
| BEcontinue
);
217 void visit(ForeachRangeStatement
*)
219 assert(global
.errors
);
223 void visit(IfStatement
*s
)
225 //printf("IfStatement::blockExit(%p)\n", s);
228 if (canThrow(s
->condition
, func
, mustNotThrow
))
230 if (s
->condition
->isBool(true))
233 result
|= blockExit(s
->ifbody
, func
, mustNotThrow
);
235 result
|= BEfallthru
;
237 else if (s
->condition
->isBool(false))
240 result
|= blockExit(s
->elsebody
, func
, mustNotThrow
);
242 result
|= BEfallthru
;
247 result
|= blockExit(s
->ifbody
, func
, mustNotThrow
);
249 result
|= BEfallthru
;
251 result
|= blockExit(s
->elsebody
, func
, mustNotThrow
);
253 result
|= BEfallthru
;
255 //printf("IfStatement::blockExit(%p) = x%x\n", s, result);
258 void visit(ConditionalStatement
*s
)
260 result
= blockExit(s
->ifbody
, func
, mustNotThrow
);
262 result
|= blockExit(s
->elsebody
, func
, mustNotThrow
);
265 void visit(PragmaStatement
*)
270 void visit(StaticAssertStatement
*)
275 void visit(SwitchStatement
*s
)
278 if (canThrow(s
->condition
, func
, mustNotThrow
))
282 result
|= blockExit(s
->_body
, func
, mustNotThrow
);
283 if (result
& BEbreak
)
285 result
|= BEfallthru
;
290 result
|= BEfallthru
;
293 void visit(CaseStatement
*s
)
295 result
= blockExit(s
->statement
, func
, mustNotThrow
);
298 void visit(DefaultStatement
*s
)
300 result
= blockExit(s
->statement
, func
, mustNotThrow
);
303 void visit(GotoDefaultStatement
*)
308 void visit(GotoCaseStatement
*)
313 void visit(SwitchErrorStatement
*)
315 // Switch errors are non-recoverable
319 void visit(ReturnStatement
*s
)
322 if (s
->exp
&& canThrow(s
->exp
, func
, mustNotThrow
))
326 void visit(BreakStatement
*s
)
328 //printf("BreakStatement::blockExit(%p) = x%x\n", s, s->ident ? BEgoto : BEbreak);
329 result
= s
->ident
? BEgoto
: BEbreak
;
332 void visit(ContinueStatement
*s
)
334 result
= s
->ident
? BEgoto
: BEcontinue
;
337 void visit(SynchronizedStatement
*s
)
339 result
= s
->_body
? blockExit(s
->_body
, func
, mustNotThrow
) : BEfallthru
;
342 void visit(WithStatement
*s
)
345 if (canThrow(s
->exp
, func
, mustNotThrow
))
348 result
|= blockExit(s
->_body
, func
, mustNotThrow
);
350 result
|= BEfallthru
;
353 void visit(TryCatchStatement
*s
)
356 result
= blockExit(s
->_body
, func
, false);
359 for (size_t i
= 0; i
< s
->catches
->dim
; i
++)
361 Catch
*c
= (*s
->catches
)[i
];
362 if (c
->type
== Type::terror
)
367 cresult
= blockExit(c
->handler
, func
, mustNotThrow
);
369 cresult
= BEfallthru
;
371 /* If we're catching Object, then there is no throwing
373 Identifier
*id
= c
->type
->toBasetype()->isClassHandle()->ident
;
374 if (c
->internalCatch
&& (cresult
& BEfallthru
))
376 // Bugzilla 11542: leave blockExit flags of the body
377 cresult
&= ~BEfallthru
;
379 else if (id
== Id::Object
|| id
== Id::Throwable
)
381 result
&= ~(BEthrow
| BEerrthrow
);
383 else if (id
== Id::Exception
)
387 catchresult
|= cresult
;
389 if (mustNotThrow
&& (result
& BEthrow
))
391 // now explain why this is nothrow
392 blockExit(s
->_body
, func
, mustNotThrow
);
394 result
|= catchresult
;
397 void visit(TryFinallyStatement
*s
)
401 result
= blockExit(s
->_body
, func
, false);
403 // check finally body as well, it may throw (bug #4082)
404 int finalresult
= BEfallthru
;
406 finalresult
= blockExit(s
->finalbody
, func
, false);
408 // If either body or finalbody halts
409 if (result
== BEhalt
)
410 finalresult
= BEnone
;
411 if (finalresult
== BEhalt
)
416 // now explain why this is nothrow
417 if (s
->_body
&& (result
& BEthrow
))
418 blockExit(s
->_body
, func
, mustNotThrow
);
419 if (s
->finalbody
&& (finalresult
& BEthrow
))
420 blockExit(s
->finalbody
, func
, mustNotThrow
);
424 // Bugzilla 13201: Mask to prevent spurious warnings for
425 // destructor call, exit of synchronized statement, etc.
426 if (result
== BEhalt
&& finalresult
!= BEhalt
&& s
->finalbody
&&
427 s
->finalbody
->hasCode())
429 s
->finalbody
->warning("statement is not reachable");
433 if (!(finalresult
& BEfallthru
))
434 result
&= ~BEfallthru
;
435 result
|= finalresult
& ~BEfallthru
;
438 void visit(OnScopeStatement
*)
440 // At this point, this statement is just an empty placeholder
444 void visit(ThrowStatement
*s
)
446 if (s
->internalThrow
)
448 // Bugzilla 8675: Allow throwing 'Throwable' object even if mustNotThrow.
453 Type
*t
= s
->exp
->type
->toBasetype();
454 ClassDeclaration
*cd
= t
->isClassHandle();
457 if (cd
== ClassDeclaration::errorException
||
458 ClassDeclaration::errorException
->isBaseOf(cd
, NULL
))
464 s
->error("%s is thrown but not caught", s
->exp
->type
->toChars());
469 void visit(GotoStatement
*)
471 //printf("GotoStatement::blockExit(%p)\n", s);
475 void visit(LabelStatement
*s
)
477 //printf("LabelStatement::blockExit(%p)\n", s);
478 result
= s
->statement
? blockExit(s
->statement
, func
, mustNotThrow
) : BEfallthru
;
480 result
|= BEfallthru
;
483 void visit(CompoundAsmStatement
*s
)
485 if (mustNotThrow
&& !(s
->stc
& STCnothrow
))
486 s
->deprecation("asm statement is assumed to throw - mark it with 'nothrow' if it does not");
489 result
= BEfallthru
| BEreturn
| BEgoto
| BEhalt
;
490 if (!(s
->stc
& STCnothrow
)) result
|= BEthrow
;
493 void visit(ImportStatement
*)
501 BlockExit
be(func
, mustNotThrow
);