Fix fallthrough case handling.

This commit is contained in:
Christoffer Lerno
2020-04-18 23:55:53 +02:00
parent 982a9e7b58
commit df0433d746
4 changed files with 16 additions and 21 deletions

View File

@@ -438,7 +438,7 @@ void gencontext_emit_switch(GenContext *context, Ast *ast)
}
Ast *default_case = NULL;
VECEACH(ast->switch_stmt.cases, i)
for (unsigned i = 0; i < cases; i++)
{
Ast *case_stmt = ast->switch_stmt.cases[i];
if (!case_stmt->case_stmt.expr)
@@ -457,6 +457,7 @@ void gencontext_emit_switch(GenContext *context, Ast *ast)
LLVMBasicBlockRef exit_block = gencontext_create_free_block(context, "switch.exit");
// We will now treat the fallthrough cases:
// switch (i)
// {
@@ -465,33 +466,24 @@ void gencontext_emit_switch(GenContext *context, Ast *ast)
// do_something();
// default:
// }
VECEACH(ast->switch_stmt.cases, i)
LLVMBasicBlockRef next_block = exit_block;
for (unsigned i = cases; i > 0; i--)
{
Ast *case_stmt = ast->switch_stmt.cases[i];
if (case_stmt->case_stmt.backend_value != NULL) continue;
Ast *case_stmt = ast->switch_stmt.cases[i - 1];
if (case_stmt->case_stmt.backend_value)
{
next_block = case_stmt->case_stmt.backend_value;
continue;
}
// Look forward for a block
for (size_t j = i + 1; j < cases; j++)
{
Ast *other_case = ast->switch_stmt.cases[j];
if (other_case->case_stmt.backend_value != NULL)
{
case_stmt->case_stmt.backend_value = other_case->case_stmt.backend_value;
break;
}
}
// No block found? Then the block is the exit block.
if (!case_stmt->case_stmt.backend_value)
{
case_stmt->case_stmt.backend_value = exit_block;
}
case_stmt->case_stmt.backend_value = next_block;
}
gencontext_push_break_continue(context, exit_block, NULL, NULL);
LLVMValueRef switch_stmt = LLVMBuildSwitch(context->builder, switch_value, default_case ? default_case->case_stmt.backend_value : exit_block, cases);
context->current_block = NULL;
VECEACH(ast->switch_stmt.cases, i)
for (unsigned i = 0; i < cases; i++)
{
Ast *case_stmt = ast->switch_stmt.cases[i];
LLVMBasicBlockRef block = case_stmt->case_stmt.backend_value;

View File

@@ -160,6 +160,7 @@ static inline bool token_type_ends_case(TokenType type)
static inline Ast *parse_case_stmts(Context *context)
{
if (token_type_ends_case(context->tok.type)) return NULL;
Ast *compound = AST_NEW_TOKEN(AST_COMPOUND_STMT, context->tok);
while (!token_type_ends_case(context->tok.type))
{

View File

@@ -690,7 +690,7 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
{
context_push_scope_with_flags(context, SCOPE_NEXT | SCOPE_BREAK);
}
success = success && sema_analyse_compound_statement_no_scope(context, stmt->case_stmt.body);
success = success && (!stmt->case_stmt.body || sema_analyse_compound_statement_no_scope(context, stmt->case_stmt.body));
ExitType case_exit = context->current_scope->exit;
if (case_exit != lowest_exit)
{