Set enclosingScopeExit in glue layer after semantic is done

Otherwise, we may end up with a wrong enclosing statement. It could
happen if a try-finally is rewritten as a try-catch (see NrvoWalker).
In this case, enclosingScopeExit will still point to the old unused
try-finally.
This commit is contained in:
Alexey Prokhin 2014-08-23 19:44:39 +04:00
parent d4f1950ee6
commit ce1a41305b
6 changed files with 232 additions and 45 deletions

View file

@ -3153,9 +3153,8 @@ SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b, bool isFi
this->body = b;
this->isFinal = isFinal;
sdefault = NULL;
#if !IN_LLVM
tf = NULL;
#else
#if IN_LLVM
enclosingScopeExit = NULL;
#endif
cases = NULL;
@ -3174,13 +3173,10 @@ Statement *SwitchStatement::syntaxCopy()
Statement *SwitchStatement::semantic(Scope *sc)
{
//printf("SwitchStatement::semantic(%p)\n", this);
tf = sc->tf;
if (cases)
return this; // already run
#if IN_LLVM
enclosingScopeExit = sc->enclosingScopeExit;
#endif
condition = condition->semantic(sc);
condition = resolveProperties(sc, condition);
TypeEnum *te = NULL;
@ -3355,13 +3351,6 @@ Statement *CaseStatement::semantic(Scope *sc)
sc = sc->endCTFE();
if (sw)
{
#if IN_LLVM
enclosingScopeExit = sc->enclosingScopeExit;
if (enclosingScopeExit != sw->enclosingScopeExit)
{
error("case must be inside the same try, synchronized or volatile level as switch");
}
#endif
exp = exp->implicitCastTo(sc, sw->condition->type);
exp = exp->optimize(WANTvalue);
@ -3417,10 +3406,8 @@ Statement *CaseStatement::semantic(Scope *sc)
sw->gotoCases.remove(i); // remove from array
}
}
#if IN_DMD
if (sc->sw->tf != sc->tf)
error("switch and case are in different finally blocks");
#endif
}
else
error("case not in switch statement");
@ -3558,12 +3545,9 @@ Statement *DefaultStatement::semantic(Scope *sc)
}
sc->sw->sdefault = this;
#if !IN_LLVM
if (sc->sw->tf != sc->tf)
error("switch and default are in different finally blocks");
#else
enclosingScopeExit = sc->sw->enclosingScopeExit;
#endif
if (sc->sw->isFinal)
error("default statement not allowed in final switch statement");
}
@ -4350,16 +4334,7 @@ Statement *SynchronizedStatement::semantic(Scope *sc)
}
Lbody:
if (body)
#if IN_LLVM
{
Statement* oldScopeExit = sc->enclosingScopeExit;
sc->enclosingScopeExit = this;
#endif
body = body->semantic(sc);
#if IN_LLVM
sc->enclosingScopeExit = oldScopeExit;
}
#endif
if (body && body->isErrorStatement())
return body;
return this;
@ -4682,14 +4657,7 @@ Statement *TryFinallyStatement::syntaxCopy()
Statement *TryFinallyStatement::semantic(Scope *sc)
{
//printf("TryFinallyStatement::semantic()\n");
#if IN_LLVM
Statement* oldScopeExit = sc->enclosingScopeExit;
sc->enclosingScopeExit = this;
#endif
body = body->semantic(sc);
#if IN_LLVM
sc->enclosingScopeExit = oldScopeExit;
#endif
sc = sc->push();
sc->tf = this;
sc->sbreak = NULL;
@ -4937,9 +4905,6 @@ Statement *GotoStatement::semantic(Scope *sc)
this->fd = sc->func;
tf = sc->tf;
os = sc->os;
#if IN_LLVM
enclosingScopeExit = sc->enclosingScopeExit;
#endif
label = fd->searchLabel(ident);
if (!label->statement && sc->fes)
{
@ -5068,9 +5033,6 @@ Statement *LabelStatement::semantic(Scope *sc)
ls->statement = this;
tf = sc->tf;
os = sc->os;
#if IN_LLVM
enclosingScopeExit = sc->enclosingScopeExit;
#endif
sc = sc->push();
sc->scopesym = sc->enclosing->scopesym;
sc->callSuper |= CSXlabel;

View file

@ -458,9 +458,7 @@ public:
bool isFinal;
DefaultStatement *sdefault;
#if !IN_LLVM
TryFinallyStatement *tf;
#endif
GotoCaseStatements gotoCases; // array of unresolved GotoCaseStatement's
CaseStatements *cases; // array of CaseStatement's
int hasNoDefault; // !=0 if no default statement

View file

@ -1196,7 +1196,7 @@ void DtoDefineFunction(FuncDeclaration* fd)
}
// output function body
Statement_toIR(fd->fbody, gIR);
codegenFunction(fd->fbody, gIR);
irfunction->gen = 0;
// TODO: clean up this mess

View file

@ -238,6 +238,7 @@ llvm::CallSite IRState::CreateCallOrInvoke(LLValue* Callee, const T &args, const
}
}
void codegenFunction(Statement *s, IRState *irs);
void Statement_toIR(Statement *s, IRState *irs);
#endif // LDC_GEN_IRSTATE_H

View file

@ -104,6 +104,225 @@ static LLValue* call_string_switch_runtime(llvm::Value* table, Expression* e)
//////////////////////////////////////////////////////////////////////////////
/* A visitor to walk entire tree of statements.
*/
class StatementVisitor : public Visitor
{
void visitStmt(Statement *s) { s->accept(this); }
public:
void visit(ErrorStatement *s) { }
void visit(PeelStatement *s)
{
if (s->s)
visitStmt(s->s);
}
void visit(ExpStatement *s) { }
void visit(DtorExpStatement *s) { }
void visit(CompileStatement *s) { }
void visit(CompoundStatement *s)
{
if (s->statements && s->statements->dim)
{
for (size_t i = 0; i < s->statements->dim; i++)
{
if ((*s->statements)[i])
visitStmt((*s->statements)[i]);
}
}
}
void visit(CompoundDeclarationStatement *s) { visit((CompoundStatement *)s); }
void visit(UnrolledLoopStatement *s)
{
if (s->statements && s->statements->dim)
{
for (size_t i = 0; i < s->statements->dim; i++)
{
if ((*s->statements)[i])
visitStmt((*s->statements)[i]);
}
}
}
void visit(ScopeStatement *s)
{
if (s->statement)
visitStmt(s->statement);
}
void visit(WhileStatement *s)
{
if (s->body)
visitStmt(s->body);
}
void visit(DoStatement *s)
{
if (s->body)
visitStmt(s->body);
}
void visit(ForStatement *s)
{
if (s->init)
visitStmt(s->init);
if (s->body)
visitStmt(s->body);
}
void visit(ForeachStatement *s)
{
if (s->body)
visitStmt(s->body);
}
void visit(ForeachRangeStatement *s)
{
if (s->body)
visitStmt(s->body);
}
void visit(IfStatement *s)
{
if (s->ifbody)
visitStmt(s->ifbody);
if (s->elsebody)
visitStmt(s->elsebody);
}
void visit(ConditionalStatement *s) { }
void visit(PragmaStatement *s) { }
void visit(StaticAssertStatement *s) { }
void visit(SwitchStatement *s)
{
if (s->body)
visitStmt(s->body);
}
void visit(CaseStatement *s)
{
if (s->statement)
visitStmt(s->statement);
}
void visit(CaseRangeStatement *s)
{
if (s->statement)
visitStmt(s->statement);
}
void visit(DefaultStatement *s)
{
if (s->statement)
visitStmt(s->statement);
}
void visit(GotoDefaultStatement *s) { }
void visit(GotoCaseStatement *s) { }
void visit(SwitchErrorStatement *s) { }
void visit(ReturnStatement *s) { }
void visit(BreakStatement *s) { }
void visit(ContinueStatement *s) { }
void visit(SynchronizedStatement *s)
{
if (s->body)
visitStmt(s->body);
}
void visit(WithStatement *s)
{
if (s->body)
visitStmt(s->body);
}
void visit(TryCatchStatement *s)
{
if (s->body)
visitStmt(s->body);
if (s->catches && s->catches->dim)
{
for (size_t i = 0; i < s->catches->dim; i++)
{
Catch *c = (*s->catches)[i];
if (c && c->handler)
visitStmt(c->handler);
}
}
}
void visit(TryFinallyStatement *s)
{
if (s->body)
visitStmt(s->body);
if (s->finalbody)
visitStmt(s->finalbody);
}
void visit(OnScopeStatement *s) { }
void visit(ThrowStatement *s) { }
void visit(DebugStatement *s)
{
if (s->statement)
visitStmt(s->statement);
}
void visit(GotoStatement *s) { }
void visit(LabelStatement *s)
{
if (s->statement)
visitStmt(s->statement);
}
void visit(AsmStatement *s) { }
void visit(ImportStatement *s) { }
void visit(AsmBlockStatement *s) { }
};
//////////////////////////////////////////////////////////////////////////////
class FindEnclosingTryFinally : public StatementVisitor {
std::stack<TryFinallyStatement*> m_tryFinally;
std::stack<SwitchStatement*> m_switches;
public:
TryFinallyStatement *enclosingTryFinally() const
{
return m_tryFinally.empty() ? 0 : m_tryFinally.top();
}
SwitchStatement *enclosingSwitch() const
{
return m_switches.empty() ? 0 : m_switches.top();
}
void visit(SwitchStatement *s)
{
m_switches.push(s);
s->enclosingScopeExit = enclosingTryFinally();
StatementVisitor::visit(s);
m_switches.pop();
}
void visit(CaseStatement *s)
{
s->enclosingScopeExit = enclosingTryFinally();
if (s->enclosingScopeExit != enclosingSwitch()->enclosingScopeExit)
s->error("switch and case are in different try blocks");
StatementVisitor::visit(s);
}
void visit(DefaultStatement *s)
{
s->enclosingScopeExit = enclosingTryFinally();
if (s->enclosingScopeExit != enclosingSwitch()->enclosingScopeExit)
s->error("switch and default case are in different try blocks");
StatementVisitor::visit(s);
}
void visit(TryFinallyStatement *s)
{
m_tryFinally.push(s);
s->body->accept(this);
m_tryFinally.pop();
s->finalbody->accept(this);
}
void visit(LabelStatement *s)
{
s->enclosingScopeExit = enclosingTryFinally();
StatementVisitor::visit(s);
}
void visit(GotoStatement *s)
{
s->enclosingScopeExit = enclosingTryFinally();
StatementVisitor::visit(s);
}
};
//////////////////////////////////////////////////////////////////////////////
class ToIRVisitor : public Visitor {
IRState *irs;
public:
@ -1573,6 +1792,13 @@ public:
//////////////////////////////////////////////////////////////////////////////
void codegenFunction(Statement *s, IRState *irs)
{
FindEnclosingTryFinally v;
s->accept(&v);
Statement_toIR(s, irs);
}
void Statement_toIR(Statement *s, IRState *irs)
{
ToIRVisitor v(irs);

@ -1 +1 @@
Subproject commit cbde5d8fe8699e1781eb5236c0de0669b593b90a
Subproject commit a7cd1422e7019ee41279d3c48c3cf79b075378f9