From 8ed9aca755087d3ee9e50f4eb5791241ce1bcc09 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Mon, 7 Oct 2024 16:16:22 +0900 Subject: [PATCH] Assume case/default follows a statemet --- src/cc/backend/codegen.c | 2 ++ src/cc/frontend/ast.c | 1 + src/cc/frontend/ast.h | 1 + src/cc/frontend/fe_misc.c | 8 +++++++- src/cc/frontend/parser.c | 8 ++++++++ src/wcc/gen_wasm.c | 6 +++--- src/wcc/traverse.c | 1 + tests/valtest.c | 7 +++++++ 8 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/cc/backend/codegen.c b/src/cc/backend/codegen.c index cc64e5f2d..d524a74b8 100644 --- a/src/cc/backend/codegen.c +++ b/src/cc/backend/codegen.c @@ -22,6 +22,7 @@ static void gen_expr_stmt(Expr *expr); void set_curbb(BB *bb) { + assert(bb != NULL); assert(curfunc != NULL); if (curbb != NULL) curbb->next = bb; @@ -510,6 +511,7 @@ static void gen_switch(Stmt *stmt) { inline void gen_case(Stmt *stmt) { set_curbb(stmt->case_.bb); + gen_stmt(stmt->case_.stmt); } static void gen_while(Stmt *stmt) { diff --git a/src/cc/frontend/ast.c b/src/cc/frontend/ast.c index b2d52d5ad..f95e7d4d1 100644 --- a/src/cc/frontend/ast.c +++ b/src/cc/frontend/ast.c @@ -265,6 +265,7 @@ Stmt *new_stmt_case(const Token *token, Stmt *swtch, Expr *value) { Stmt *stmt = new_stmt(ST_CASE, token); stmt->case_.swtch = swtch; stmt->case_.value = value; + stmt->case_.stmt = NULL; stmt->case_.bb = NULL; return stmt; } diff --git a/src/cc/frontend/ast.h b/src/cc/frontend/ast.h index 4aab53603..7da45ea6f 100644 --- a/src/cc/frontend/ast.h +++ b/src/cc/frontend/ast.h @@ -398,6 +398,7 @@ typedef struct Stmt { struct { struct Stmt *swtch; Expr *value; // NULL => default + struct Stmt *stmt; // BB *bb; } case_; diff --git a/src/cc/frontend/fe_misc.c b/src/cc/frontend/fe_misc.c index 6ae730aaa..f41209e35 100644 --- a/src/cc/frontend/fe_misc.c +++ b/src/cc/frontend/fe_misc.c @@ -1558,6 +1558,10 @@ static void check_reachability_stmt(Stmt *stmt) { stmt->break_.parent->reach &= ~REACH_STOP; stmt->reach |= REACH_STOP; break; + case ST_CASE: + check_reachability_stmt(stmt->case_.stmt); + stmt->reach = stmt->case_.stmt->reach; + break; case ST_GOTO: // TODO: stmt->reach |= REACH_STOP; @@ -1585,7 +1589,7 @@ static void check_reachability_stmt(Stmt *stmt) { } } break; - case ST_EMPTY: case ST_CASE: case ST_VARDECL: case ST_ASM: + case ST_EMPTY: case ST_VARDECL: case ST_ASM: stmt->reach = 0; break; } @@ -1968,6 +1972,8 @@ static Stmt *duplicate_inline_function_stmt(Function *targetfunc, Scope *targets // Value is constant so reuse. assert(is_const(stmt->case_.value)); } + dup->case_.stmt = duplicate_inline_function_stmt(targetfunc, targetscope, stmt->case_.stmt); + // Find index. Stmt *org_swtch = stmt->case_.swtch; Vector *org_cases = org_swtch->switch_.cases; diff --git a/src/cc/frontend/parser.c b/src/cc/frontend/parser.c index f13775bb0..61aa77aa0 100644 --- a/src/cc/frontend/parser.c +++ b/src/cc/frontend/parser.c @@ -351,6 +351,14 @@ static Stmt *parse_case(const Token *tok) { vec_push(swtch->switch_.cases, stmt); if (tok->kind == TK_DEFAULT) swtch->switch_.default_ = stmt; + + Stmt *next = parse_stmt(); + if (next == NULL) { + parse_error(PE_NOFATAL, tok, "statement expected"); + next = new_stmt(ST_EMPTY, tok); // Dummy + } + stmt->case_.stmt = next; + return stmt; } diff --git a/src/wcc/gen_wasm.c b/src/wcc/gen_wasm.c index 0f79561e6..87b2e889d 100644 --- a/src/wcc/gen_wasm.c +++ b/src/wcc/gen_wasm.c @@ -1202,11 +1202,11 @@ static void gen_switch(Stmt *stmt) { break_depth = save_depth; } -static void gen_case(Stmt *stmt) { - UNUSED(stmt); +static void gen_case(Stmt *stmt, bool is_last) { ADD_CODE(OP_END); --cur_depth; assert(cur_depth >= 0); + gen_stmt(stmt->case_.stmt, is_last); } static void gen_while(Stmt *stmt) { @@ -1445,7 +1445,7 @@ static void gen_stmt(Stmt *stmt, bool is_last) { case ST_BLOCK: gen_block(stmt, is_last); break; case ST_IF: gen_if(stmt, is_last); break; case ST_SWITCH: gen_switch(stmt); break; - case ST_CASE: gen_case(stmt); break; + case ST_CASE: gen_case(stmt, is_last); break; case ST_WHILE: gen_while(stmt); break; case ST_DO_WHILE: gen_do_while(stmt); break; case ST_FOR: gen_for(stmt); break; diff --git a/src/wcc/traverse.c b/src/wcc/traverse.c index 38258349e..07cc242bc 100644 --- a/src/wcc/traverse.c +++ b/src/wcc/traverse.c @@ -591,6 +591,7 @@ static void traverse_switch(Stmt *stmt) { static void traverse_case(Stmt *stmt) { if (branching_stmt->kind != ST_SWITCH) parse_error(PE_FATAL, stmt->token, "case/default inside branch not supported"); + traverse_stmt(stmt->case_.stmt); } static void traverse_while(Stmt *stmt) { diff --git a/tests/valtest.c b/tests/valtest.c index 2112e71cb..5c9fc112c 100644 --- a/tests/valtest.c +++ b/tests/valtest.c @@ -425,6 +425,13 @@ TEST(all) { } EXPECT("switch fallthrough", 11, x); } + { + int x = 44; + switch (x) + case 1: + x = 55; + EXPECT("switch w/o bracket", 44, x); + } { int x = 10, *p = &x; ++(*p);