diff options
Diffstat (limited to 'gcc/d/dmd/blockexit.c')
-rw-r--r-- | gcc/d/dmd/blockexit.c | 506 |
1 files changed, 0 insertions, 506 deletions
diff --git a/gcc/d/dmd/blockexit.c b/gcc/d/dmd/blockexit.c deleted file mode 100644 index 1895d36fb1e..00000000000 --- a/gcc/d/dmd/blockexit.c +++ /dev/null @@ -1,506 +0,0 @@ - -/* Compiler implementation of the D programming language - * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved - * written by Walter Bright - * http://www.digitalmars.com - * Distributed under the Boost Software License, Version 1.0. - * http://www.boost.org/LICENSE_1_0.txt - */ - -#include "statement.h" -#include "declaration.h" -#include "aggregate.h" -#include "id.h" - -/* Only valid after semantic analysis - * If 'mustNotThrow' is true, generate an error if it throws - */ -int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow) -{ - class BlockExit : public Visitor - { - public: - FuncDeclaration *func; - bool mustNotThrow; - int result; - - BlockExit(FuncDeclaration *func, bool mustNotThrow) - : func(func), mustNotThrow(mustNotThrow) - { - result = BEnone; - } - - void visit(Statement *s) - { - printf("Statement::blockExit(%p)\n", s); - printf("%s\n", s->toChars()); - assert(0); - result = BEany; - } - - void visit(ErrorStatement *) - { - result = BEany; - } - - void visit(ExpStatement *s) - { - result = BEfallthru; - if (s->exp) - { - if (s->exp->op == TOKhalt) - { - result = BEhalt; - return; - } - if (s->exp->op == TOKassert) - { - AssertExp *a = (AssertExp *)s->exp; - if (a->e1->isBool(false)) // if it's an assert(0) - { - result = BEhalt; - return; - } - } - if (s->exp->type->toBasetype()->isTypeNoreturn()) - result = BEhalt; - if (canThrow(s->exp, func, mustNotThrow)) - result |= BEthrow; - } - } - - void visit(CompileStatement *) - { - assert(global.errors); - result = BEfallthru; - } - - void visit(CompoundStatement *cs) - { - //printf("CompoundStatement::blockExit(%p) %d result = x%X\n", cs, cs->statements->length, result); - result = BEfallthru; - Statement *slast = NULL; - for (size_t i = 0; i < cs->statements->length; i++) - { - Statement *s = (*cs->statements)[i]; - if (s) - { - //printf("result = x%x\n", result); - //printf("s: %s\n", s->toChars()); - if (result & BEfallthru && slast) - { - slast = slast->last(); - if (slast && (slast->isCaseStatement() || slast->isDefaultStatement()) && - (s->isCaseStatement() || s->isDefaultStatement())) - { - // Allow if last case/default was empty - CaseStatement *sc = slast->isCaseStatement(); - DefaultStatement *sd = slast->isDefaultStatement(); - if (sc && (!sc->statement->hasCode() || sc->statement->isCaseStatement() || sc->statement->isErrorStatement())) - ; - else if (sd && (!sd->statement->hasCode() || sd->statement->isCaseStatement() || sd->statement->isErrorStatement())) - ; - else - { - const char *gototype = s->isCaseStatement() ? "case" : "default"; - s->deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype); - } - } - } - - if (!(result & BEfallthru) && !s->comeFrom()) - { - if (blockExit(s, func, mustNotThrow) != BEhalt && s->hasCode()) - s->warning("statement is not reachable"); - } - else - { - result &= ~BEfallthru; - result |= blockExit(s, func, mustNotThrow); - } - slast = s; - } - } - } - - void visit(UnrolledLoopStatement *uls) - { - result = BEfallthru; - for (size_t i = 0; i < uls->statements->length; i++) - { - Statement *s = (*uls->statements)[i]; - if (s) - { - int r = blockExit(s, func, mustNotThrow); - result |= r & ~(BEbreak | BEcontinue | BEfallthru); - if ((r & (BEfallthru | BEcontinue | BEbreak)) == 0) - result &= ~BEfallthru; - } - } - } - - void visit(ScopeStatement *s) - { - //printf("ScopeStatement::blockExit(%p)\n", s->statement); - result = s->statement ? blockExit(s->statement, func, mustNotThrow) : BEfallthru; - } - - void visit(WhileStatement *) - { - assert(global.errors); - result = BEfallthru; - } - - void visit(DoStatement *s) - { - if (s->_body) - { - result = blockExit(s->_body, func, mustNotThrow); - if (result == BEbreak) - { - result = BEfallthru; - return; - } - if (result & BEcontinue) - result |= BEfallthru; - } - else - result = BEfallthru; - if (result & BEfallthru) - { - if (canThrow(s->condition, func, mustNotThrow)) - result |= BEthrow; - if (!(result & BEbreak) && s->condition->isBool(true)) - result &= ~BEfallthru; - } - result &= ~(BEbreak | BEcontinue); - } - - void visit(ForStatement *s) - { - result = BEfallthru; - if (s->_init) - { - result = blockExit(s->_init, func, mustNotThrow); - if (!(result & BEfallthru)) - return; - } - if (s->condition) - { - if (canThrow(s->condition, func, mustNotThrow)) - result |= BEthrow; - if (s->condition->isBool(true)) - result &= ~BEfallthru; - else if (s->condition->isBool(false)) - return; - } - else - result &= ~BEfallthru; // the body must do the exiting - if (s->_body) - { - int r = blockExit(s->_body, func, mustNotThrow); - if (r & (BEbreak | BEgoto)) - result |= BEfallthru; - result |= r & ~(BEfallthru | BEbreak | BEcontinue); - } - if (s->increment && canThrow(s->increment, func, mustNotThrow)) - result |= BEthrow; - } - - void visit(ForeachStatement *s) - { - result = BEfallthru; - if (canThrow(s->aggr, func, mustNotThrow)) - result |= BEthrow; - if (s->_body) - result |= blockExit(s->_body, func, mustNotThrow) & ~(BEbreak | BEcontinue); - } - - void visit(ForeachRangeStatement *) - { - assert(global.errors); - result = BEfallthru; - } - - void visit(IfStatement *s) - { - //printf("IfStatement::blockExit(%p)\n", s); - - result = BEnone; - if (canThrow(s->condition, func, mustNotThrow)) - result |= BEthrow; - if (s->condition->isBool(true)) - { - if (s->ifbody) - result |= blockExit(s->ifbody, func, mustNotThrow); - else - result |= BEfallthru; - } - else if (s->condition->isBool(false)) - { - if (s->elsebody) - result |= blockExit(s->elsebody, func, mustNotThrow); - else - result |= BEfallthru; - } - else - { - if (s->ifbody) - result |= blockExit(s->ifbody, func, mustNotThrow); - else - result |= BEfallthru; - if (s->elsebody) - result |= blockExit(s->elsebody, func, mustNotThrow); - else - result |= BEfallthru; - } - //printf("IfStatement::blockExit(%p) = x%x\n", s, result); - } - - void visit(ConditionalStatement *s) - { - result = blockExit(s->ifbody, func, mustNotThrow); - if (s->elsebody) - result |= blockExit(s->elsebody, func, mustNotThrow); - } - - void visit(PragmaStatement *) - { - result = BEfallthru; - } - - void visit(StaticAssertStatement *) - { - result = BEfallthru; - } - - void visit(SwitchStatement *s) - { - result = BEnone; - if (canThrow(s->condition, func, mustNotThrow)) - result |= BEthrow; - if (s->_body) - { - result |= blockExit(s->_body, func, mustNotThrow); - if (result & BEbreak) - { - result |= BEfallthru; - result &= ~BEbreak; - } - } - else - result |= BEfallthru; - } - - void visit(CaseStatement *s) - { - result = blockExit(s->statement, func, mustNotThrow); - } - - void visit(DefaultStatement *s) - { - result = blockExit(s->statement, func, mustNotThrow); - } - - void visit(GotoDefaultStatement *) - { - result = BEgoto; - } - - void visit(GotoCaseStatement *) - { - result = BEgoto; - } - - void visit(SwitchErrorStatement *) - { - // Switch errors are non-recoverable - result = BEhalt; - } - - void visit(ReturnStatement *s) - { - result = BEreturn; - if (s->exp && canThrow(s->exp, func, mustNotThrow)) - result |= BEthrow; - } - - void visit(BreakStatement *s) - { - //printf("BreakStatement::blockExit(%p) = x%x\n", s, s->ident ? BEgoto : BEbreak); - result = s->ident ? BEgoto : BEbreak; - } - - void visit(ContinueStatement *s) - { - result = s->ident ? BEgoto : BEcontinue; - } - - void visit(SynchronizedStatement *s) - { - result = s->_body ? blockExit(s->_body, func, mustNotThrow) : BEfallthru; - } - - void visit(WithStatement *s) - { - result = BEnone; - if (canThrow(s->exp, func, mustNotThrow)) - result = BEthrow; - if (s->_body) - result |= blockExit(s->_body, func, mustNotThrow); - else - result |= BEfallthru; - } - - void visit(TryCatchStatement *s) - { - assert(s->_body); - result = blockExit(s->_body, func, false); - - int catchresult = 0; - for (size_t i = 0; i < s->catches->length; i++) - { - Catch *c = (*s->catches)[i]; - if (c->type == Type::terror) - continue; - - int cresult; - if (c->handler) - cresult = blockExit(c->handler, func, mustNotThrow); - else - cresult = BEfallthru; - - /* If we're catching Object, then there is no throwing - */ - Identifier *id = c->type->toBasetype()->isClassHandle()->ident; - if (c->internalCatch && (cresult & BEfallthru)) - { - // Bugzilla 11542: leave blockExit flags of the body - cresult &= ~BEfallthru; - } - else if (id == Id::Object || id == Id::Throwable) - { - result &= ~(BEthrow | BEerrthrow); - } - else if (id == Id::Exception) - { - result &= ~BEthrow; - } - catchresult |= cresult; - } - if (mustNotThrow && (result & BEthrow)) - { - // now explain why this is nothrow - blockExit(s->_body, func, mustNotThrow); - } - result |= catchresult; - } - - void visit(TryFinallyStatement *s) - { - result = BEfallthru; - if (s->_body) - result = blockExit(s->_body, func, false); - - // check finally body as well, it may throw (bug #4082) - int finalresult = BEfallthru; - if (s->finalbody) - finalresult = blockExit(s->finalbody, func, false); - - // If either body or finalbody halts - if (result == BEhalt) - finalresult = BEnone; - if (finalresult == BEhalt) - result = BEnone; - - if (mustNotThrow) - { - // now explain why this is nothrow - if (s->_body && (result & BEthrow)) - blockExit(s->_body, func, mustNotThrow); - if (s->finalbody && (finalresult & BEthrow)) - blockExit(s->finalbody, func, mustNotThrow); - } - - #if 0 - // Bugzilla 13201: Mask to prevent spurious warnings for - // destructor call, exit of synchronized statement, etc. - if (result == BEhalt && finalresult != BEhalt && s->finalbody && - s->finalbody->hasCode()) - { - s->finalbody->warning("statement is not reachable"); - } - #endif - - if (!(finalresult & BEfallthru)) - result &= ~BEfallthru; - result |= finalresult & ~BEfallthru; - } - - void visit(ScopeGuardStatement *) - { - // At this point, this statement is just an empty placeholder - result = BEfallthru; - } - - void visit(ThrowStatement *s) - { - if (s->internalThrow) - { - // Bugzilla 8675: Allow throwing 'Throwable' object even if mustNotThrow. - result = BEfallthru; - return; - } - - Type *t = s->exp->type->toBasetype(); - ClassDeclaration *cd = t->isClassHandle(); - assert(cd); - - if (cd == ClassDeclaration::errorException || - ClassDeclaration::errorException->isBaseOf(cd, NULL)) - { - result = BEerrthrow; - return; - } - if (mustNotThrow) - s->error("%s is thrown but not caught", s->exp->type->toChars()); - - result = BEthrow; - } - - void visit(GotoStatement *) - { - //printf("GotoStatement::blockExit(%p)\n", s); - result = BEgoto; - } - - void visit(LabelStatement *s) - { - //printf("LabelStatement::blockExit(%p)\n", s); - result = s->statement ? blockExit(s->statement, func, mustNotThrow) : BEfallthru; - if (s->breaks) - result |= BEfallthru; - } - - void visit(CompoundAsmStatement *s) - { - if (mustNotThrow && !(s->stc & STCnothrow)) - s->deprecation("asm statement is assumed to throw - mark it with `nothrow` if it does not"); - - // Assume the worst - result = BEfallthru | BEreturn | BEgoto | BEhalt; - if (!(s->stc & STCnothrow)) result |= BEthrow; - } - - void visit(ImportStatement *) - { - result = BEfallthru; - } - }; - - if (!s) - return BEfallthru; - BlockExit be(func, mustNotThrow); - s->accept(&be); - return be.result; -} |