Merge remote-tracking branch 'origin/topic/jsiwek/no-switch-fallthrough'

* origin/topic/jsiwek/no-switch-fallthrough:
  Add "fallthrough" keyword, require a flow statement to end case blocks.
  Disable automatic case fallthrough in switch stmts.  Addresses #754.

I've added a test for the error case where no break/fallthrough/return
is given.

Closes #754.
This commit is contained in:
Robin Sommer 2013-01-23 14:41:23 -08:00
commit dcd675280e
10 changed files with 154 additions and 27 deletions

View file

@ -23,7 +23,7 @@ const char* stmt_name(BroStmtTag t)
"print", "event", "expr", "if", "when", "switch",
"for", "next", "break", "return", "add", "delete",
"list", "bodylist",
"<init>",
"<init>", "fallthrough",
"null",
};
@ -584,6 +584,32 @@ bool IfStmt::DoUnserialize(UnserialInfo* info)
return s2 != 0;
}
static BroStmtTag get_last_stmt_tag(const Stmt* stmt)
{
if ( ! stmt )
return STMT_NULL;
if ( stmt->Tag() != STMT_LIST )
return stmt->Tag();
const StmtList* stmts = stmt->AsStmtList();
int len = stmts->Stmts().length();
if ( len == 0 )
return STMT_LIST;
return get_last_stmt_tag(stmts->Stmts()[len - 1]);
}
Case::Case(ListExpr* c, Stmt* arg_s)
: cases(simplify_expr_list(c, SIMPLIFY_GENERAL)), s(arg_s)
{
BroStmtTag t = get_last_stmt_tag(Body());
if ( t != STMT_BREAK && t != STMT_FALLTHROUGH && t != STMT_RETURN )
Error("case block must end in break/fallthrough/return statement");
}
Case::~Case()
{
Unref(cases);
@ -802,16 +828,13 @@ Val* SwitchStmt::DoExec(Frame* f, Val* v, stmt_flow_type& flow) const
flow = FLOW_NEXT;
rval = c->Body()->Exec(f, flow);
if ( flow == FLOW_BREAK )
{
flow = FLOW_NEXT;
break;
}
if ( flow == FLOW_RETURN )
if ( flow == FLOW_BREAK || flow == FLOW_RETURN )
break;
}
if ( flow != FLOW_RETURN )
flow = FLOW_NEXT;
return rval;
}
@ -1467,6 +1490,47 @@ bool BreakStmt::DoUnserialize(UnserialInfo* info)
return true;
}
Val* FallthroughStmt::Exec(Frame* /* f */, stmt_flow_type& flow) const
{
RegisterAccess();
flow = FLOW_FALLTHROUGH;
return 0;
}
int FallthroughStmt::IsPure() const
{
return 1;
}
void FallthroughStmt::Describe(ODesc* d) const
{
Stmt::Describe(d);
Stmt::DescribeDone(d);
}
TraversalCode FallthroughStmt::Traverse(TraversalCallback* cb) const
{
TraversalCode tc = cb->PreStmt(this);
HANDLE_TC_STMT_PRE(tc);
tc = cb->PostStmt(this);
HANDLE_TC_STMT_POST(tc);
}
IMPLEMENT_SERIAL(FallthroughStmt, SER_FALLTHROUGH_STMT);
bool FallthroughStmt::DoSerialize(SerialInfo* info) const
{
DO_SERIALIZE(SER_FALLTHROUGH_STMT, Stmt);
return true;
}
bool FallthroughStmt::DoUnserialize(UnserialInfo* info)
{
DO_UNSERIALIZE(Stmt);
return true;
}
ReturnStmt::ReturnStmt(Expr* arg_e) : ExprStmt(STMT_RETURN, arg_e)
{
Scope* s = current_scope();