1 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 8 */ 9 10 #include "statement.h" 11 #include "declaration.h" 12 #include "aggregate.h" 13 #include "id.h" 14 15 /* Only valid after semantic analysis 16 * If 'mustNotThrow' is true, generate an error if it throws 17 */ 18 int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow) 19 { 20 class BlockExit : public Visitor 21 { 22 public: 23 FuncDeclaration *func; 24 bool mustNotThrow; 25 int result; 26 27 BlockExit(FuncDeclaration *func, bool mustNotThrow) 28 : func(func), mustNotThrow(mustNotThrow) 29 { 30 result = BEnone; 31 } 32 33 void visit(Statement *s) 34 { 35 printf("Statement::blockExit(%p)\n", s); 36 printf("%s\n", s->toChars()); 37 assert(0); 38 result = BEany; 39 } 40 41 void visit(ErrorStatement *) 42 { 43 result = BEany; 44 } 45 46 void visit(ExpStatement *s) 47 { 48 result = BEfallthru; 49 if (s->exp) 50 { 51 if (s->exp->op == TOKhalt) 52 { 53 result = BEhalt; 54 return; 55 } 56 if (s->exp->op == TOKassert) 57 { 58 AssertExp *a = (AssertExp *)s->exp; 59 if (a->e1->isBool(false)) // if it's an assert(0) 60 { 61 result = BEhalt; 62 return; 63 } 64 } 65 if (canThrow(s->exp, func, mustNotThrow)) 66 result |= BEthrow; 67 } 68 } 69 70 void visit(CompileStatement *) 71 { 72 assert(global.errors); 73 result = BEfallthru; 74 } 75 76 void visit(CompoundStatement *cs) 77 { 78 //printf("CompoundStatement::blockExit(%p) %d result = x%X\n", cs, cs->statements->dim, result); 79 result = BEfallthru; 80 Statement *slast = NULL; 81 for (size_t i = 0; i < cs->statements->dim; i++) 82 { 83 Statement *s = (*cs->statements)[i]; 84 if (s) 85 { 86 //printf("result = x%x\n", result); 87 //printf("s: %s\n", s->toChars()); 88 if (result & BEfallthru && slast) 89 { 90 slast = slast->last(); 91 if (slast && (slast->isCaseStatement() || slast->isDefaultStatement()) && 92 (s->isCaseStatement() || s->isDefaultStatement())) 93 { 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())) 98 ; 99 else if (sd && (!sd->statement->hasCode() || sd->statement->isCaseStatement() || sd->statement->isErrorStatement())) 100 ; 101 else 102 { 103 const char *gototype = s->isCaseStatement() ? "case" : "default"; 104 s->deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype); 105 } 106 } 107 } 108 109 if (!(result & BEfallthru) && !s->comeFrom()) 110 { 111 if (blockExit(s, func, mustNotThrow) != BEhalt && s->hasCode()) 112 s->warning("statement is not reachable"); 113 } 114 else 115 { 116 result &= ~BEfallthru; 117 result |= blockExit(s, func, mustNotThrow); 118 } 119 slast = s; 120 } 121 } 122 } 123 124 void visit(UnrolledLoopStatement *uls) 125 { 126 result = BEfallthru; 127 for (size_t i = 0; i < uls->statements->dim; i++) 128 { 129 Statement *s = (*uls->statements)[i]; 130 if (s) 131 { 132 int r = blockExit(s, func, mustNotThrow); 133 result |= r & ~(BEbreak | BEcontinue | BEfallthru); 134 if ((r & (BEfallthru | BEcontinue | BEbreak)) == 0) 135 result &= ~BEfallthru; 136 } 137 } 138 } 139 140 void visit(ScopeStatement *s) 141 { 142 //printf("ScopeStatement::blockExit(%p)\n", s->statement); 143 result = s->statement ? blockExit(s->statement, func, mustNotThrow) : BEfallthru; 144 } 145 146 void visit(WhileStatement *) 147 { 148 assert(global.errors); 149 result = BEfallthru; 150 } 151 152 void visit(DoStatement *s) 153 { 154 if (s->_body) 155 { 156 result = blockExit(s->_body, func, mustNotThrow); 157 if (result == BEbreak) 158 { 159 result = BEfallthru; 160 return; 161 } 162 if (result & BEcontinue) 163 result |= BEfallthru; 164 } 165 else 166 result = BEfallthru; 167 if (result & BEfallthru) 168 { 169 if (canThrow(s->condition, func, mustNotThrow)) 170 result |= BEthrow; 171 if (!(result & BEbreak) && s->condition->isBool(true)) 172 result &= ~BEfallthru; 173 } 174 result &= ~(BEbreak | BEcontinue); 175 } 176 177 void visit(ForStatement *s) 178 { 179 result = BEfallthru; 180 if (s->_init) 181 { 182 result = blockExit(s->_init, func, mustNotThrow); 183 if (!(result & BEfallthru)) 184 return; 185 } 186 if (s->condition) 187 { 188 if (canThrow(s->condition, func, mustNotThrow)) 189 result |= BEthrow; 190 if (s->condition->isBool(true)) 191 result &= ~BEfallthru; 192 else if (s->condition->isBool(false)) 193 return; 194 } 195 else 196 result &= ~BEfallthru; // the body must do the exiting 197 if (s->_body) 198 { 199 int r = blockExit(s->_body, func, mustNotThrow); 200 if (r & (BEbreak | BEgoto)) 201 result |= BEfallthru; 202 result |= r & ~(BEfallthru | BEbreak | BEcontinue); 203 } 204 if (s->increment && canThrow(s->increment, func, mustNotThrow)) 205 result |= BEthrow; 206 } 207 208 void visit(ForeachStatement *s) 209 { 210 result = BEfallthru; 211 if (canThrow(s->aggr, func, mustNotThrow)) 212 result |= BEthrow; 213 if (s->_body) 214 result |= blockExit(s->_body, func, mustNotThrow) & ~(BEbreak | BEcontinue); 215 } 216 217 void visit(ForeachRangeStatement *) 218 { 219 assert(global.errors); 220 result = BEfallthru; 221 } 222 223 void visit(IfStatement *s) 224 { 225 //printf("IfStatement::blockExit(%p)\n", s); 226 227 result = BEnone; 228 if (canThrow(s->condition, func, mustNotThrow)) 229 result |= BEthrow; 230 if (s->condition->isBool(true)) 231 { 232 if (s->ifbody) 233 result |= blockExit(s->ifbody, func, mustNotThrow); 234 else 235 result |= BEfallthru; 236 } 237 else if (s->condition->isBool(false)) 238 { 239 if (s->elsebody) 240 result |= blockExit(s->elsebody, func, mustNotThrow); 241 else 242 result |= BEfallthru; 243 } 244 else 245 { 246 if (s->ifbody) 247 result |= blockExit(s->ifbody, func, mustNotThrow); 248 else 249 result |= BEfallthru; 250 if (s->elsebody) 251 result |= blockExit(s->elsebody, func, mustNotThrow); 252 else 253 result |= BEfallthru; 254 } 255 //printf("IfStatement::blockExit(%p) = x%x\n", s, result); 256 } 257 258 void visit(ConditionalStatement *s) 259 { 260 result = blockExit(s->ifbody, func, mustNotThrow); 261 if (s->elsebody) 262 result |= blockExit(s->elsebody, func, mustNotThrow); 263 } 264 265 void visit(PragmaStatement *) 266 { 267 result = BEfallthru; 268 } 269 270 void visit(StaticAssertStatement *) 271 { 272 result = BEfallthru; 273 } 274 275 void visit(SwitchStatement *s) 276 { 277 result = BEnone; 278 if (canThrow(s->condition, func, mustNotThrow)) 279 result |= BEthrow; 280 if (s->_body) 281 { 282 result |= blockExit(s->_body, func, mustNotThrow); 283 if (result & BEbreak) 284 { 285 result |= BEfallthru; 286 result &= ~BEbreak; 287 } 288 } 289 else 290 result |= BEfallthru; 291 } 292 293 void visit(CaseStatement *s) 294 { 295 result = blockExit(s->statement, func, mustNotThrow); 296 } 297 298 void visit(DefaultStatement *s) 299 { 300 result = blockExit(s->statement, func, mustNotThrow); 301 } 302 303 void visit(GotoDefaultStatement *) 304 { 305 result = BEgoto; 306 } 307 308 void visit(GotoCaseStatement *) 309 { 310 result = BEgoto; 311 } 312 313 void visit(SwitchErrorStatement *) 314 { 315 // Switch errors are non-recoverable 316 result = BEhalt; 317 } 318 319 void visit(ReturnStatement *s) 320 { 321 result = BEreturn; 322 if (s->exp && canThrow(s->exp, func, mustNotThrow)) 323 result |= BEthrow; 324 } 325 326 void visit(BreakStatement *s) 327 { 328 //printf("BreakStatement::blockExit(%p) = x%x\n", s, s->ident ? BEgoto : BEbreak); 329 result = s->ident ? BEgoto : BEbreak; 330 } 331 332 void visit(ContinueStatement *s) 333 { 334 result = s->ident ? BEgoto : BEcontinue; 335 } 336 337 void visit(SynchronizedStatement *s) 338 { 339 result = s->_body ? blockExit(s->_body, func, mustNotThrow) : BEfallthru; 340 } 341 342 void visit(WithStatement *s) 343 { 344 result = BEnone; 345 if (canThrow(s->exp, func, mustNotThrow)) 346 result = BEthrow; 347 if (s->_body) 348 result |= blockExit(s->_body, func, mustNotThrow); 349 else 350 result |= BEfallthru; 351 } 352 353 void visit(TryCatchStatement *s) 354 { 355 assert(s->_body); 356 result = blockExit(s->_body, func, false); 357 358 int catchresult = 0; 359 for (size_t i = 0; i < s->catches->dim; i++) 360 { 361 Catch *c = (*s->catches)[i]; 362 if (c->type == Type::terror) 363 continue; 364 365 int cresult; 366 if (c->handler) 367 cresult = blockExit(c->handler, func, mustNotThrow); 368 else 369 cresult = BEfallthru; 370 371 /* If we're catching Object, then there is no throwing 372 */ 373 Identifier *id = c->type->toBasetype()->isClassHandle()->ident; 374 if (c->internalCatch && (cresult & BEfallthru)) 375 { 376 // Bugzilla 11542: leave blockExit flags of the body 377 cresult &= ~BEfallthru; 378 } 379 else if (id == Id::Object || id == Id::Throwable) 380 { 381 result &= ~(BEthrow | BEerrthrow); 382 } 383 else if (id == Id::Exception) 384 { 385 result &= ~BEthrow; 386 } 387 catchresult |= cresult; 388 } 389 if (mustNotThrow && (result & BEthrow)) 390 { 391 // now explain why this is nothrow 392 blockExit(s->_body, func, mustNotThrow); 393 } 394 result |= catchresult; 395 } 396 397 void visit(TryFinallyStatement *s) 398 { 399 result = BEfallthru; 400 if (s->_body) 401 result = blockExit(s->_body, func, false); 402 403 // check finally body as well, it may throw (bug #4082) 404 int finalresult = BEfallthru; 405 if (s->finalbody) 406 finalresult = blockExit(s->finalbody, func, false); 407 408 // If either body or finalbody halts 409 if (result == BEhalt) 410 finalresult = BEnone; 411 if (finalresult == BEhalt) 412 result = BEnone; 413 414 if (mustNotThrow) 415 { 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); 421 } 422 423 #if 0 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()) 428 { 429 s->finalbody->warning("statement is not reachable"); 430 } 431 #endif 432 433 if (!(finalresult & BEfallthru)) 434 result &= ~BEfallthru; 435 result |= finalresult & ~BEfallthru; 436 } 437 438 void visit(OnScopeStatement *) 439 { 440 // At this point, this statement is just an empty placeholder 441 result = BEfallthru; 442 } 443 444 void visit(ThrowStatement *s) 445 { 446 if (s->internalThrow) 447 { 448 // Bugzilla 8675: Allow throwing 'Throwable' object even if mustNotThrow. 449 result = BEfallthru; 450 return; 451 } 452 453 Type *t = s->exp->type->toBasetype(); 454 ClassDeclaration *cd = t->isClassHandle(); 455 assert(cd); 456 457 if (cd == ClassDeclaration::errorException || 458 ClassDeclaration::errorException->isBaseOf(cd, NULL)) 459 { 460 result = BEerrthrow; 461 return; 462 } 463 if (mustNotThrow) 464 s->error("%s is thrown but not caught", s->exp->type->toChars()); 465 466 result = BEthrow; 467 } 468 469 void visit(GotoStatement *) 470 { 471 //printf("GotoStatement::blockExit(%p)\n", s); 472 result = BEgoto; 473 } 474 475 void visit(LabelStatement *s) 476 { 477 //printf("LabelStatement::blockExit(%p)\n", s); 478 result = s->statement ? blockExit(s->statement, func, mustNotThrow) : BEfallthru; 479 if (s->breaks) 480 result |= BEfallthru; 481 } 482 483 void visit(CompoundAsmStatement *s) 484 { 485 if (mustNotThrow && !(s->stc & STCnothrow)) 486 s->deprecation("asm statement is assumed to throw - mark it with 'nothrow' if it does not"); 487 488 // Assume the worst 489 result = BEfallthru | BEreturn | BEgoto | BEhalt; 490 if (!(s->stc & STCnothrow)) result |= BEthrow; 491 } 492 493 void visit(ImportStatement *) 494 { 495 result = BEfallthru; 496 } 497 }; 498 499 if (!s) 500 return BEfallthru; 501 BlockExit be(func, mustNotThrow); 502 s->accept(&be); 503 return be.result; 504 } 505