mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 20:11:17 +00:00
Fix fallthrough case handling.
This commit is contained in:
@@ -254,6 +254,8 @@ func int testReturnSwitch()
|
||||
int i = 0;
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
case 3:
|
||||
case 1:
|
||||
return 2;
|
||||
case 2:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user