mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-10 12:59:21 +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->body = b;
|
||||||
this->isFinal = isFinal;
|
this->isFinal = isFinal;
|
||||||
sdefault = NULL;
|
sdefault = NULL;
|
||||||
#if !IN_LLVM
|
|
||||||
tf = NULL;
|
tf = NULL;
|
||||||
#else
|
#if IN_LLVM
|
||||||
enclosingScopeExit = NULL;
|
enclosingScopeExit = NULL;
|
||||||
#endif
|
#endif
|
||||||
cases = NULL;
|
cases = NULL;
|
||||||
|
@ -3174,13 +3173,10 @@ Statement *SwitchStatement::syntaxCopy()
|
||||||
Statement *SwitchStatement::semantic(Scope *sc)
|
Statement *SwitchStatement::semantic(Scope *sc)
|
||||||
{
|
{
|
||||||
//printf("SwitchStatement::semantic(%p)\n", this);
|
//printf("SwitchStatement::semantic(%p)\n", this);
|
||||||
|
tf = sc->tf;
|
||||||
if (cases)
|
if (cases)
|
||||||
return this; // already run
|
return this; // already run
|
||||||
|
|
||||||
#if IN_LLVM
|
|
||||||
enclosingScopeExit = sc->enclosingScopeExit;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
condition = condition->semantic(sc);
|
condition = condition->semantic(sc);
|
||||||
condition = resolveProperties(sc, condition);
|
condition = resolveProperties(sc, condition);
|
||||||
TypeEnum *te = NULL;
|
TypeEnum *te = NULL;
|
||||||
|
@ -3355,13 +3351,6 @@ Statement *CaseStatement::semantic(Scope *sc)
|
||||||
sc = sc->endCTFE();
|
sc = sc->endCTFE();
|
||||||
if (sw)
|
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->implicitCastTo(sc, sw->condition->type);
|
||||||
exp = exp->optimize(WANTvalue);
|
exp = exp->optimize(WANTvalue);
|
||||||
|
|
||||||
|
@ -3417,10 +3406,8 @@ Statement *CaseStatement::semantic(Scope *sc)
|
||||||
sw->gotoCases.remove(i); // remove from array
|
sw->gotoCases.remove(i); // remove from array
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if IN_DMD
|
|
||||||
if (sc->sw->tf != sc->tf)
|
if (sc->sw->tf != sc->tf)
|
||||||
error("switch and case are in different finally blocks");
|
error("switch and case are in different finally blocks");
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
error("case not in switch statement");
|
error("case not in switch statement");
|
||||||
|
@ -3558,12 +3545,9 @@ Statement *DefaultStatement::semantic(Scope *sc)
|
||||||
}
|
}
|
||||||
sc->sw->sdefault = this;
|
sc->sw->sdefault = this;
|
||||||
|
|
||||||
#if !IN_LLVM
|
|
||||||
if (sc->sw->tf != sc->tf)
|
if (sc->sw->tf != sc->tf)
|
||||||
error("switch and default are in different finally blocks");
|
error("switch and default are in different finally blocks");
|
||||||
#else
|
|
||||||
enclosingScopeExit = sc->sw->enclosingScopeExit;
|
|
||||||
#endif
|
|
||||||
if (sc->sw->isFinal)
|
if (sc->sw->isFinal)
|
||||||
error("default statement not allowed in final switch statement");
|
error("default statement not allowed in final switch statement");
|
||||||
}
|
}
|
||||||
|
@ -4350,16 +4334,7 @@ Statement *SynchronizedStatement::semantic(Scope *sc)
|
||||||
}
|
}
|
||||||
Lbody:
|
Lbody:
|
||||||
if (body)
|
if (body)
|
||||||
#if IN_LLVM
|
|
||||||
{
|
|
||||||
Statement* oldScopeExit = sc->enclosingScopeExit;
|
|
||||||
sc->enclosingScopeExit = this;
|
|
||||||
#endif
|
|
||||||
body = body->semantic(sc);
|
body = body->semantic(sc);
|
||||||
#if IN_LLVM
|
|
||||||
sc->enclosingScopeExit = oldScopeExit;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (body && body->isErrorStatement())
|
if (body && body->isErrorStatement())
|
||||||
return body;
|
return body;
|
||||||
return this;
|
return this;
|
||||||
|
@ -4682,14 +4657,7 @@ Statement *TryFinallyStatement::syntaxCopy()
|
||||||
Statement *TryFinallyStatement::semantic(Scope *sc)
|
Statement *TryFinallyStatement::semantic(Scope *sc)
|
||||||
{
|
{
|
||||||
//printf("TryFinallyStatement::semantic()\n");
|
//printf("TryFinallyStatement::semantic()\n");
|
||||||
#if IN_LLVM
|
|
||||||
Statement* oldScopeExit = sc->enclosingScopeExit;
|
|
||||||
sc->enclosingScopeExit = this;
|
|
||||||
#endif
|
|
||||||
body = body->semantic(sc);
|
body = body->semantic(sc);
|
||||||
#if IN_LLVM
|
|
||||||
sc->enclosingScopeExit = oldScopeExit;
|
|
||||||
#endif
|
|
||||||
sc = sc->push();
|
sc = sc->push();
|
||||||
sc->tf = this;
|
sc->tf = this;
|
||||||
sc->sbreak = NULL;
|
sc->sbreak = NULL;
|
||||||
|
@ -4937,9 +4905,6 @@ Statement *GotoStatement::semantic(Scope *sc)
|
||||||
this->fd = sc->func;
|
this->fd = sc->func;
|
||||||
tf = sc->tf;
|
tf = sc->tf;
|
||||||
os = sc->os;
|
os = sc->os;
|
||||||
#if IN_LLVM
|
|
||||||
enclosingScopeExit = sc->enclosingScopeExit;
|
|
||||||
#endif
|
|
||||||
label = fd->searchLabel(ident);
|
label = fd->searchLabel(ident);
|
||||||
if (!label->statement && sc->fes)
|
if (!label->statement && sc->fes)
|
||||||
{
|
{
|
||||||
|
@ -5068,9 +5033,6 @@ Statement *LabelStatement::semantic(Scope *sc)
|
||||||
ls->statement = this;
|
ls->statement = this;
|
||||||
tf = sc->tf;
|
tf = sc->tf;
|
||||||
os = sc->os;
|
os = sc->os;
|
||||||
#if IN_LLVM
|
|
||||||
enclosingScopeExit = sc->enclosingScopeExit;
|
|
||||||
#endif
|
|
||||||
sc = sc->push();
|
sc = sc->push();
|
||||||
sc->scopesym = sc->enclosing->scopesym;
|
sc->scopesym = sc->enclosing->scopesym;
|
||||||
sc->callSuper |= CSXlabel;
|
sc->callSuper |= CSXlabel;
|
||||||
|
|
|
@ -458,9 +458,7 @@ public:
|
||||||
bool isFinal;
|
bool isFinal;
|
||||||
|
|
||||||
DefaultStatement *sdefault;
|
DefaultStatement *sdefault;
|
||||||
#if !IN_LLVM
|
|
||||||
TryFinallyStatement *tf;
|
TryFinallyStatement *tf;
|
||||||
#endif
|
|
||||||
GotoCaseStatements gotoCases; // array of unresolved GotoCaseStatement's
|
GotoCaseStatements gotoCases; // array of unresolved GotoCaseStatement's
|
||||||
CaseStatements *cases; // array of CaseStatement's
|
CaseStatements *cases; // array of CaseStatement's
|
||||||
int hasNoDefault; // !=0 if no default statement
|
int hasNoDefault; // !=0 if no default statement
|
||||||
|
|
|
@ -1196,7 +1196,7 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// output function body
|
// output function body
|
||||||
Statement_toIR(fd->fbody, gIR);
|
codegenFunction(fd->fbody, gIR);
|
||||||
irfunction->gen = 0;
|
irfunction->gen = 0;
|
||||||
|
|
||||||
// TODO: clean up this mess
|
// 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);
|
void Statement_toIR(Statement *s, IRState *irs);
|
||||||
|
|
||||||
#endif // LDC_GEN_IRSTATE_H
|
#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 {
|
class ToIRVisitor : public Visitor {
|
||||||
IRState *irs;
|
IRState *irs;
|
||||||
public:
|
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)
|
void Statement_toIR(Statement *s, IRState *irs)
|
||||||
{
|
{
|
||||||
ToIRVisitor v(irs);
|
ToIRVisitor v(irs);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit cbde5d8fe8699e1781eb5236c0de0669b593b90a
|
Subproject commit a7cd1422e7019ee41279d3c48c3cf79b075378f9
|
Loading…
Add table
Add a link
Reference in a new issue