mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-09 20:37:25 +03:00
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:
parent
d4f1950ee6
commit
ce1a41305b
6 changed files with 232 additions and 45 deletions
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue