From: Robert Pengelly Date: Thu, 20 Aug 2026 14:01:40 +0000 (+0100) Subject: Added noreturn support X-Git-Url: https://git.candlhat.org/?a=commitdiff_plain;h=fa984882f508f638a510a13fbb3585a4620d6f67;p=scc.git Added noreturn support --- diff --git a/amd64.c b/amd64.c index ef55b2b..e6f9613 100644 --- a/amd64.c +++ b/amd64.c @@ -97,8 +97,11 @@ static void clear_rhs_last_pointer_info (void) { } static int current_function_has_return_statement = 0; +static int statement_ends_control_flow = 0; + static int current_parse_block_depth = 0; static int current_function_is_void = 0; +static int current_function_is_noreturn = 0; static int current_function_is_floating = 0; static int current_function_return_size = DATA_NONE; static int current_function_return_is_unsigned = 0; @@ -453,6 +456,7 @@ static void clear_global_symbols (void) { global_symbols[i].is_unsigned = 0; global_symbols[i].is_floating = 0; global_symbols[i].returns_void = 0; + global_symbols[i].is_noreturn = 0; global_symbols[i].calling_convention = TOK_EOF; @@ -925,6 +929,16 @@ static void set_global_symbol_returns_void (const char *name, int returns_void) } +static void set_global_symbol_noreturn (const char *name, int is_noreturn) { + + int i = find_global_symbol (name); + + if (i >= 0) { + global_symbols[i].is_noreturn = is_noreturn ? 1 : 0; + } + +} + static void set_global_symbol_calling_convention (const char *name, enum token_kind calling_convention) { int i = find_global_symbol (name); @@ -947,6 +961,18 @@ static int get_global_symbol_returns_void (const char *name) { } +static int get_global_symbol_noreturn (const char *name) { + + int i = find_global_symbol (name); + + if (i >= 0 && global_symbols[i].kind == GLOBAL_SYMBOL_FUNCTION) { + return global_symbols[i].is_noreturn; + } + + return 0; + +} + static void set_global_symbol_param_count (const char *name, int param_count, int has_prototype, int is_variadic) { int i = find_global_symbol (name); @@ -1114,6 +1140,7 @@ static int add_global_symbol (const char *name, int kind, int is_extern, const c global_symbols[global_symbol_count].pointed_is_floating = 0; global_symbols[global_symbol_count].pointed_is_unsigned = 0; global_symbols[global_symbol_count].returns_void = 0; + global_symbols[global_symbol_count].is_noreturn = 0; global_symbols[global_symbol_count].calling_convention = TOK_EOF; { @@ -8605,6 +8632,8 @@ static void parse_block (void) { char static_label[128]; int declaration_dllimport = parsed_dllimport; + int declaration_noreturn = parsed_noreturn; + int declared_pointer_depth; int declared_pointed_size; int declared_type_size; @@ -8617,6 +8646,8 @@ static void parse_block (void) { parse_declarator (&name); declaration_dllimport = declaration_dllimport || parsed_dllimport || declarator_dllimport; + declaration_noreturn = declaration_noreturn || parsed_noreturn || declarator_noreturn; + apply_typedef_array_to_declarator (); if (declarator_has_array && declarator_array_unsized && tok.kind == TOK_ASSIGN) { @@ -8686,6 +8717,10 @@ static void parse_block (void) { set_global_symbol_floating (name, (declarator_is_pointer || (declarator_has_function && declarator_function_is_pointer)) ? 0 : parsed_type_is_floating); set_global_symbol_returns_void (name, declarator_has_function && parsed_type_is_void && !declarator_is_pointer && !declarator_function_is_pointer); + if (declaration_noreturn) { + set_global_symbol_noreturn (name, 1); + } + if (declarator_has_function) { set_global_symbol_param_count (name, declarator_function_param_count, declarator_function_has_prototype || declarator_function_param_count > 0, declarator_function_is_variadic); @@ -25848,6 +25883,10 @@ static void emit_call_identifier_to_reg_now (const char *name, const char *reg, int hidden_struct_return_arg = 0; int effective_argc = 0; + if (get_global_symbol_noreturn (name)) { + statement_ends_control_flow = 1; + } + if (tok.kind != TOK_LPAREN) { return; } @@ -26516,6 +26555,10 @@ static int goto_ref_count = 0; static int current_break_label = -1; static int current_continue_label = -1; +/* Track escapes from the innermost loop for fall-through analysis. */ +static int *current_loop_escape_seen = 0; +static int current_loop_break_label_for_flow = -1; + static long current_break_cleanup_base = 0; static long current_continue_cleanup_base = 0; @@ -26531,6 +26574,7 @@ struct switch_case_entry { struct switch_context { struct switch_case_entry cases[MAX_SWITCH_CASES]; + int case_count; int default_label; int break_label; @@ -26538,7 +26582,6 @@ struct switch_context { }; static struct switch_context *current_switch_context = 0; -static int statement_ends_control_flow = 0; static void reset_goto_labels (void) { @@ -34497,6 +34540,12 @@ static void parse_for_statement (void) { int cond_known = 0; int cond_value = 1; + int condition_is_infinite = 0; + int loop_escape_seen = 0; + + int *old_loop_escape_seen = current_loop_escape_seen; + int old_loop_break_label_for_flow = current_loop_break_label_for_flow; + FILE *saved_ofp; FILE *step_tmp = 0; @@ -34512,7 +34561,10 @@ static void parse_for_statement (void) { emit_statement_label (loop_label); if (tok.kind == TOK_SEMI) { + + condition_is_infinite = 1; get_token (); + } else { emit_statement_jump_if_false (break_label); @@ -34520,6 +34572,8 @@ static void parse_for_statement (void) { cond_known = statement_condition_constant_known; cond_value = statement_condition_constant_value; + condition_is_infinite = cond_known && cond_value; + if (tok.kind != TOK_SEMI) { skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF); } @@ -34553,6 +34607,8 @@ static void parse_for_statement (void) { current_break_label = break_label; current_continue_label = continue_label; + current_loop_escape_seen = &loop_escape_seen; + current_loop_break_label_for_flow = break_label; current_break_cleanup_base = current_block_cleanup_bytes; current_continue_cleanup_base = current_block_cleanup_bytes; @@ -34587,10 +34643,12 @@ static void parse_for_statement (void) { current_break_label = old_break_label; current_continue_label = old_continue_label; + current_loop_escape_seen = old_loop_escape_seen; + current_loop_break_label_for_flow = old_loop_break_label_for_flow; current_break_cleanup_base = old_break_cleanup_base; current_continue_cleanup_base = old_continue_cleanup_base; - statement_ends_control_flow = 0; + statement_ends_control_flow = condition_is_infinite && !loop_escape_seen; } @@ -34608,6 +34666,11 @@ static void parse_while_statement (void) { int cond_known; int cond_value; + int loop_escape_seen = 0; + + int *old_loop_escape_seen = current_loop_escape_seen; + int old_loop_break_label_for_flow = current_loop_break_label_for_flow; + get_token (); expect (TOK_LPAREN, "("); @@ -34625,6 +34688,8 @@ static void parse_while_statement (void) { current_break_label = break_label; current_continue_label = loop_label; + current_loop_escape_seen = &loop_escape_seen; + current_loop_break_label_for_flow = break_label; current_break_cleanup_base = current_block_cleanup_bytes; current_continue_cleanup_base = current_block_cleanup_bytes; @@ -34647,10 +34712,12 @@ static void parse_while_statement (void) { current_break_label = old_break_label; current_continue_label = old_continue_label; + current_loop_escape_seen = old_loop_escape_seen; + current_loop_break_label_for_flow = old_loop_break_label_for_flow; current_break_cleanup_base = old_break_cleanup_base; current_continue_cleanup_base = old_continue_cleanup_base; - statement_ends_control_flow = 0; + statement_ends_control_flow = cond_known && cond_value && !loop_escape_seen; } @@ -34668,10 +34735,17 @@ static void parse_do_statement (void) { int cond_known = 0; int cond_value = 0; + int loop_escape_seen = 0; + + int *old_loop_escape_seen = current_loop_escape_seen; + int old_loop_break_label_for_flow = current_loop_break_label_for_flow; + get_token (); current_break_label = break_label; current_continue_label = cond_label; + current_loop_escape_seen = &loop_escape_seen; + current_loop_break_label_for_flow = break_label; current_break_cleanup_base = current_block_cleanup_bytes; current_continue_cleanup_base = current_block_cleanup_bytes; @@ -34709,10 +34783,12 @@ static void parse_do_statement (void) { current_break_label = old_break_label; current_continue_label = old_continue_label; + current_loop_escape_seen = old_loop_escape_seen; + current_loop_break_label_for_flow = old_loop_break_label_for_flow; current_break_cleanup_base = old_break_cleanup_base; current_continue_cleanup_base = old_continue_cleanup_base; - statement_ends_control_flow = 0; + statement_ends_control_flow = cond_known && cond_value && !loop_escape_seen; } @@ -37075,6 +37151,14 @@ static void parse_statement (void) { } + if (current_function_is_noreturn) { + + if (state->warn & WARN_NO_RETURN) { + report_line_at (get_filename (), ret_line, REPORT_WARNING, ret_start, ret_caret, "return in function declared '__declspec(noreturn)'"); + } + + } + if (current_function_is_void && has_value) { if (state->warn & WARN_NO_RETURN) { @@ -37295,8 +37379,12 @@ static void parse_statement (void) { */ reference_goto_label (label_name, label_line, label_start, label_caret); - statement_ends_control_flow = 1; + if (current_loop_escape_seen) { + *current_loop_escape_seen = 1; + } + + statement_ends_control_flow = 1; free (label_name); } else { @@ -37326,6 +37414,11 @@ static void parse_statement (void) { } emit_statement_jump (target_label); + + if (current_loop_escape_seen && target_label == current_loop_break_label_for_flow) { + *current_loop_escape_seen = 1; + } + statement_ends_control_flow = 1; } @@ -37429,7 +37522,18 @@ static void parse_statement (void) { } - emit_load_assignment_rhs_expression_to_reg ("rax"); + { + + int expression_ends_control_flow = (tok.kind == TOK_IDENT && tok.ident && + token_identifier_is_function_call_rhs_now () && get_global_symbol_noreturn (tok.ident)); + + emit_load_assignment_rhs_expression_to_reg ("rax"); + + if (expression_ends_control_flow) { + statement_ends_control_flow = 1; + } + + } if (tok.kind == TOK_SEMI) { @@ -37449,12 +37553,14 @@ static void parse_statement (void) { } -static void parse_function_body (const char *name, int storage_class, int is_inline, int return_is_void, int return_is_floating, int return_is_unsigned, int return_size, int return_pointer_depth, unsigned long function_line, const char *function_start, const char *function_caret) { +static void parse_function_body (const char *name, int storage_class, int is_inline, int is_noreturn, int return_is_void, int return_is_floating, int return_is_unsigned, int return_size, int return_pointer_depth, unsigned long function_line, const char *function_start, const char *function_caret) { int old_return_label = current_return_label; int should_emit = 1; int emit_body = 1; int emit_public = 1; + + int effective_noreturn = is_noreturn || get_global_symbol_noreturn (name); int emit_inline_definition_to_output = 1; FILE *saved_ofp; @@ -37472,6 +37578,7 @@ static void parse_function_body (const char *name, int storage_class, int is_inl int saved_current_section = current_section; int old_function_is_void; + int old_function_is_noreturn; int old_function_is_floating; int old_function_return_size; int old_function_return_is_unsigned; @@ -37542,6 +37649,7 @@ static void parse_function_body (const char *name, int storage_class, int is_inl set_global_symbol_unsigned (name, 0); set_global_symbol_floating (name, return_is_floating); set_global_symbol_returns_void (name, return_is_void); + set_global_symbol_noreturn (name, effective_noreturn); set_global_symbol_calling_convention (name, (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention); set_global_symbol_dllimport (name, 0); set_global_symbol_param_count (name, saved_declarator_function_param_count, saved_declarator_function_has_prototype || saved_declarator_function_param_count > 0, saved_declarator_function_is_variadic); @@ -37557,6 +37665,7 @@ static void parse_function_body (const char *name, int storage_class, int is_inl old_function_has_return_statement = current_function_has_return_statement; old_function_is_void = current_function_is_void; + old_function_is_noreturn = current_function_is_noreturn; old_function_is_floating = current_function_is_floating; old_function_return_size = current_function_return_size; old_function_return_is_unsigned = current_function_return_is_unsigned; @@ -37564,6 +37673,7 @@ static void parse_function_body (const char *name, int storage_class, int is_inl old_function_returns_aggregate = current_function_returns_aggregate; current_function_is_void = return_is_void; + current_function_is_noreturn = effective_noreturn; current_function_is_floating = return_is_floating; current_function_return_is_unsigned = return_is_unsigned; current_function_return_size = return_size; @@ -37618,10 +37728,18 @@ static void parse_function_body (const char *name, int storage_class, int is_inl current_function_frame_enabled = (!is_inline && capture_function_body); emit_function_start (name, !emit_public); + statement_ends_control_flow = 0; + parse_block (); check_goto_labels (); - if (!current_function_is_void && !current_function_has_return_statement) { + if (current_function_is_noreturn && !current_function_has_return_statement && !statement_ends_control_flow) { + + if (state->warn & WARN_NO_RETURN) { + report_line_at (function_filename_copy ? function_filename_copy : get_filename (), function_line, REPORT_WARNING, function_start, function_caret, "function declared '__declspec(noreturn)' may return"); + } + + } else if (!current_function_is_void && !current_function_has_return_statement && !statement_ends_control_flow) { if (state->warn & WARN_NO_RETURN) { report_line_at (function_filename_copy ? function_filename_copy : get_filename (), function_line, REPORT_WARNING, function_start, function_caret, "control reaches end of non-void function"); @@ -37690,6 +37808,7 @@ static void parse_function_body (const char *name, int storage_class, int is_inl current_function_has_return_statement = old_function_has_return_statement; current_function_is_void = old_function_is_void; + current_function_is_noreturn = old_function_is_noreturn; current_function_is_floating = old_function_is_floating; current_function_return_size = old_function_return_size; current_function_return_is_unsigned = old_function_return_is_unsigned; @@ -37859,7 +37978,7 @@ static int parse_possible_knr_function (void) { if (is_type_start (tok.kind) || tok.kind == TOK_LBRACE) { - parse_function_body (name, STORAGE_NONE, 0, 0, 0, 0, DATA_INT & 0x1f, 0, name_line, name_start, name_caret); + parse_function_body (name, STORAGE_NONE, 0, 0, 0, 0, 0, DATA_INT & 0x1f, 0, name_line, name_start, name_caret); if (parsed_dllexport || declarator_dllexport) { @@ -39166,6 +39285,8 @@ static void parse_external_after_type (void) { int declaration_is_inline; int declaration_storage; + + int declaration_noreturn = 0; int declaration_dllimport = 0; int declaration_dllexport = 0; @@ -39191,11 +39312,13 @@ static void parse_external_after_type (void) { declaration_is_inline = parsed_type_is_inline; declaration_storage = parsed_storage_class; + declaration_noreturn = parsed_noreturn; declaration_dllimport = parsed_dllimport; declaration_dllexport = parsed_dllexport; parse_declarator (&name); + declaration_noreturn = declaration_noreturn || parsed_noreturn || declarator_noreturn; declaration_dllimport = declaration_dllimport || parsed_dllimport || declarator_dllimport; declaration_dllexport = declaration_dllexport || parsed_dllexport || declarator_dllexport; @@ -39267,7 +39390,7 @@ static void parse_external_after_type (void) { } - parse_function_body (name, declaration_storage, declaration_is_inline, + parse_function_body (name, declaration_storage, declaration_is_inline, declaration_noreturn, (parsed_type_is_void && !declarator_is_pointer), (declarator_is_pointer ? 0 : parsed_type_is_floating), (declarator_is_pointer ? 0 : parsed_type_is_unsigned), @@ -39403,8 +39526,12 @@ static void parse_external_after_type (void) { set_global_symbol_unsigned (name, 0); set_global_symbol_floating (name, declarator_is_pointer ? 0 : parsed_type_is_floating); set_global_symbol_returns_void (name, parsed_type_is_void && !declarator_is_pointer && !declarator_function_is_pointer); - set_global_symbol_param_count (name, declarator_function_param_count, declarator_function_has_prototype || declarator_function_param_count > 0, declarator_function_is_variadic); + if (declaration_noreturn) { + set_global_symbol_noreturn (name, 1); + } + + set_global_symbol_param_count (name, declarator_function_param_count, declarator_function_has_prototype || declarator_function_param_count > 0, declarator_function_is_variadic); set_global_symbol_calling_convention (name, (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention); set_global_symbol_dllimport (name, declaration_dllimport); diff --git a/i386.c b/i386.c index 98f1ba5..b4388e6 100644 --- a/i386.c +++ b/i386.c @@ -70,8 +70,11 @@ static void clear_rhs_last_pointer_info (void) { } static int current_function_has_return_statement = 0; +static int statement_ends_control_flow = 0; + static int current_parse_block_depth = 0; static int current_function_is_void = 0; +static int current_function_is_noreturn = 0; static int current_function_is_floating = 0; static int current_function_return_size = DATA_NONE; static int current_function_return_is_unsigned = 0; @@ -253,6 +256,7 @@ static void clear_global_symbols (void) { global_symbols[i].is_unsigned = 0; global_symbols[i].is_floating = 0; global_symbols[i].returns_void = 0; + global_symbols[i].is_noreturn = 0; global_symbols[i].calling_convention = TOK_EOF; @@ -728,6 +732,16 @@ static void set_global_symbol_returns_void (const char *name, int returns_void) } +static void set_global_symbol_noreturn (const char *name, int is_noreturn) { + + int i = find_global_symbol (name); + + if (i >= 0) { + global_symbols[i].is_noreturn = is_noreturn ? 1 : 0; + } + +} + static void set_global_symbol_calling_convention (const char *name, enum token_kind calling_convention) { int i = find_global_symbol (name); @@ -762,6 +776,18 @@ static int get_global_symbol_returns_void (const char *name) { } +static int get_global_symbol_noreturn (const char *name) { + + int i = find_global_symbol (name); + + if (i >= 0 && global_symbols[i].kind == GLOBAL_SYMBOL_FUNCTION) { + return global_symbols[i].is_noreturn; + } + + return 0; + +} + static void set_global_symbol_param_count (const char *name, int param_count, int has_prototype, int is_variadic) { int i = find_global_symbol (name); @@ -929,6 +955,7 @@ static int add_global_symbol (const char *name, int kind, int is_extern, const c global_symbols[global_symbol_count].pointed_is_floating = 0; global_symbols[global_symbol_count].pointed_is_unsigned = 0; global_symbols[global_symbol_count].returns_void = 0; + global_symbols[global_symbol_count].is_noreturn = 0; global_symbols[global_symbol_count].calling_convention = TOK_EOF; { @@ -7862,6 +7889,7 @@ static void parse_block (void) { char static_label[128]; int declaration_dllimport = parsed_dllimport; + int declaration_noreturn = parsed_noreturn; for (i = 0; i < MAX_AGG_FIELDS; i++) { init_symbols[i] = 0; @@ -7870,6 +7898,8 @@ static void parse_block (void) { parse_declarator (&name); declaration_dllimport = declaration_dllimport || parsed_dllimport || declarator_dllimport; + declaration_noreturn = declaration_noreturn || parsed_noreturn || declarator_noreturn; + apply_typedef_array_to_declarator (); if (declarator_has_array && declarator_array_unsized && tok.kind == TOK_ASSIGN) { @@ -7924,6 +7954,10 @@ static void parse_block (void) { set_global_symbol_floating (name, (declarator_is_pointer || (declarator_has_function && declarator_function_is_pointer)) ? 0 : parsed_type_is_floating); set_global_symbol_returns_void (name, declarator_has_function && parsed_type_is_void && !declarator_is_pointer && !declarator_function_is_pointer); + if (declaration_noreturn) { + set_global_symbol_noreturn (name, 1); + } + if (declarator_has_function) { set_global_symbol_param_count (name, declarator_function_param_count, declarator_function_has_prototype || declarator_function_param_count > 0, declarator_function_is_variadic); @@ -23087,6 +23121,10 @@ static void emit_call_identifier_to_reg_now (const char *name, const char *reg, FILE **arg_tmp_ofps = 0; FILE **new_arg_tmp_ofps = 0; + if (get_global_symbol_noreturn (name)) { + statement_ends_control_flow = 1; + } + if (tok.kind != TOK_LPAREN) { return; } @@ -23643,6 +23681,10 @@ static int goto_ref_count = 0; static int current_break_label = -1; static int current_continue_label = -1; +/* Track escapes from the innermost loop for fall-through analysis. */ +static int *current_loop_escape_seen = 0; +static int current_loop_break_label_for_flow = -1; + static long current_break_cleanup_base = 0; static long current_continue_cleanup_base = 0; @@ -23658,6 +23700,7 @@ struct switch_case_entry { struct switch_context { struct switch_case_entry cases[MAX_SWITCH_CASES]; + int case_count; int default_label; int break_label; @@ -23665,7 +23708,6 @@ struct switch_context { }; static struct switch_context *current_switch_context = 0; -static int statement_ends_control_flow = 0; static void reset_goto_labels (void) { @@ -31976,6 +32018,12 @@ static void parse_for_statement (void) { int cond_known = 0; int cond_value = 1; + int condition_is_infinite = 0; + int loop_escape_seen = 0; + + int *old_loop_escape_seen = current_loop_escape_seen; + int old_loop_break_label_for_flow = current_loop_break_label_for_flow; + FILE *saved_ofp; FILE *step_tmp = 0; @@ -31991,7 +32039,10 @@ static void parse_for_statement (void) { emit_statement_label (loop_label); if (tok.kind == TOK_SEMI) { + + condition_is_infinite = 1; get_token (); + } else { emit_statement_jump_if_false (break_label); @@ -31999,6 +32050,8 @@ static void parse_for_statement (void) { cond_known = statement_condition_constant_known; cond_value = statement_condition_constant_value; + condition_is_infinite = cond_known && cond_value; + if (tok.kind != TOK_SEMI) { skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF); } @@ -32032,6 +32085,8 @@ static void parse_for_statement (void) { current_break_label = break_label; current_continue_label = continue_label; + current_loop_escape_seen = &loop_escape_seen; + current_loop_break_label_for_flow = break_label; current_break_cleanup_base = current_block_cleanup_bytes; current_continue_cleanup_base = current_block_cleanup_bytes; @@ -32066,10 +32121,12 @@ static void parse_for_statement (void) { current_break_label = old_break_label; current_continue_label = old_continue_label; + current_loop_escape_seen = old_loop_escape_seen; + current_loop_break_label_for_flow = old_loop_break_label_for_flow; current_break_cleanup_base = old_break_cleanup_base; current_continue_cleanup_base = old_continue_cleanup_base; - statement_ends_control_flow = 0; + statement_ends_control_flow = condition_is_infinite && !loop_escape_seen; } @@ -32087,6 +32144,11 @@ static void parse_while_statement (void) { int cond_known; int cond_value; + int loop_escape_seen = 0; + + int *old_loop_escape_seen = current_loop_escape_seen; + int old_loop_break_label_for_flow = current_loop_break_label_for_flow; + get_token (); expect (TOK_LPAREN, "("); @@ -32104,6 +32166,8 @@ static void parse_while_statement (void) { current_break_label = break_label; current_continue_label = loop_label; + current_loop_escape_seen = &loop_escape_seen; + current_loop_break_label_for_flow = break_label; current_break_cleanup_base = current_block_cleanup_bytes; current_continue_cleanup_base = current_block_cleanup_bytes; @@ -32126,10 +32190,12 @@ static void parse_while_statement (void) { current_break_label = old_break_label; current_continue_label = old_continue_label; + current_loop_escape_seen = old_loop_escape_seen; + current_loop_break_label_for_flow = old_loop_break_label_for_flow; current_break_cleanup_base = old_break_cleanup_base; current_continue_cleanup_base = old_continue_cleanup_base; - statement_ends_control_flow = 0; + statement_ends_control_flow = cond_known && cond_value && !loop_escape_seen; } @@ -32147,10 +32213,17 @@ static void parse_do_statement (void) { int cond_known = 0; int cond_value = 0; + int loop_escape_seen = 0; + + int *old_loop_escape_seen = current_loop_escape_seen; + int old_loop_break_label_for_flow = current_loop_break_label_for_flow; + get_token (); current_break_label = break_label; current_continue_label = cond_label; + current_loop_escape_seen = &loop_escape_seen; + current_loop_break_label_for_flow = break_label; current_break_cleanup_base = current_block_cleanup_bytes; current_continue_cleanup_base = current_block_cleanup_bytes; @@ -32188,10 +32261,12 @@ static void parse_do_statement (void) { current_break_label = old_break_label; current_continue_label = old_continue_label; + current_loop_escape_seen = old_loop_escape_seen; + current_loop_break_label_for_flow = old_loop_break_label_for_flow; current_break_cleanup_base = old_break_cleanup_base; current_continue_cleanup_base = old_continue_cleanup_base; - statement_ends_control_flow = 0; + statement_ends_control_flow = cond_known && cond_value && !loop_escape_seen; } @@ -34529,6 +34604,14 @@ static void parse_statement (void) { } + if (current_function_is_noreturn) { + + if (state->warn & WARN_NO_RETURN) { + report_line_at (get_filename (), ret_line, REPORT_WARNING, ret_start, ret_caret, "return in function declared '__declspec(noreturn)'"); + } + + } + if (current_function_is_void && has_value) { if (state->warn & WARN_NO_RETURN) { @@ -34743,8 +34826,12 @@ static void parse_statement (void) { */ reference_goto_label (label_name, label_line, label_start, label_caret); - statement_ends_control_flow = 1; + if (current_loop_escape_seen) { + *current_loop_escape_seen = 1; + } + + statement_ends_control_flow = 1; free (label_name); } else { @@ -34774,6 +34861,11 @@ static void parse_statement (void) { } emit_statement_jump (target_label); + + if (current_loop_escape_seen && target_label == current_loop_break_label_for_flow) { + *current_loop_escape_seen = 1; + } + statement_ends_control_flow = 1; } @@ -34877,7 +34969,18 @@ static void parse_statement (void) { } - emit_load_assignment_rhs_expression_to_reg ("eax"); + { + + int expression_ends_control_flow = (tok.kind == TOK_IDENT && tok.ident && + token_identifier_is_function_call_rhs_now () && get_global_symbol_noreturn (tok.ident)); + + emit_load_assignment_rhs_expression_to_reg ("eax"); + + if (expression_ends_control_flow) { + statement_ends_control_flow = 1; + } + + } if (tok.kind == TOK_SEMI) { @@ -34897,12 +35000,14 @@ static void parse_statement (void) { } -static void parse_function_body (const char *name, int storage_class, int is_inline, int return_is_void, int return_is_floating, int return_is_unsigned, int return_size, unsigned long function_line, const char *function_start, const char *function_caret) { +static void parse_function_body (const char *name, int storage_class, int is_inline, int is_noreturn, int return_is_void, int return_is_floating, int return_is_unsigned, int return_size, unsigned long function_line, const char *function_start, const char *function_caret) { int old_return_label = current_return_label; int should_emit = 1; int emit_body = 1; int emit_public = 1; + + int effective_noreturn = is_noreturn || get_global_symbol_noreturn (name); int emit_inline_definition_to_output = 1; FILE *saved_ofp; @@ -34920,6 +35025,7 @@ static void parse_function_body (const char *name, int storage_class, int is_inl int saved_current_section = current_section; int old_function_is_void; + int old_function_is_noreturn; int old_function_is_floating; int old_function_return_size; int old_function_return_is_unsigned; @@ -34989,6 +35095,7 @@ static void parse_function_body (const char *name, int storage_class, int is_inl set_global_symbol_unsigned (name, 0); set_global_symbol_floating (name, return_is_floating); set_global_symbol_returns_void (name, return_is_void); + set_global_symbol_noreturn (name, effective_noreturn); set_global_symbol_calling_convention (name, (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention); set_global_symbol_dllimport (name, 0); set_global_symbol_param_count (name, saved_declarator_function_param_count, saved_declarator_function_has_prototype || saved_declarator_function_param_count > 0, saved_declarator_function_is_variadic); @@ -35004,12 +35111,14 @@ static void parse_function_body (const char *name, int storage_class, int is_inl old_function_has_return_statement = current_function_has_return_statement; old_function_is_void = current_function_is_void; + old_function_is_noreturn = current_function_is_noreturn; old_function_is_floating = current_function_is_floating; old_function_return_size = current_function_return_size; old_function_return_is_unsigned = current_function_return_is_unsigned; old_function_returns_aggregate = current_function_returns_aggregate; current_function_is_void = return_is_void; + current_function_is_noreturn = effective_noreturn; current_function_is_floating = return_is_floating; current_function_return_is_unsigned = return_is_unsigned; current_function_return_size = return_size; @@ -35061,10 +35170,18 @@ static void parse_function_body (const char *name, int storage_class, int is_inl current_function_frame_enabled = (!is_inline && capture_function_body); emit_function_start (name, !emit_public); + statement_ends_control_flow = 0; + parse_block (); check_goto_labels (); - if (!current_function_is_void && !current_function_has_return_statement) { + if (current_function_is_noreturn && !current_function_has_return_statement && !statement_ends_control_flow) { + + if (state->warn & WARN_NO_RETURN) { + report_line_at (function_filename_copy ? function_filename_copy : get_filename (), function_line, REPORT_WARNING, function_start, function_caret, "function declared '__declspec(noreturn)' may return"); + } + + } else if (!current_function_is_void && !current_function_has_return_statement && !statement_ends_control_flow) { if (state->warn & WARN_NO_RETURN) { report_line_at (function_filename_copy ? function_filename_copy : get_filename (), function_line, REPORT_WARNING, function_start, function_caret, "control reaches end of non-void function"); @@ -35132,6 +35249,7 @@ static void parse_function_body (const char *name, int storage_class, int is_inl current_function_has_return_statement = old_function_has_return_statement; current_function_is_void = old_function_is_void; + current_function_is_noreturn = old_function_is_noreturn; current_function_is_floating = old_function_is_floating; current_function_return_size = old_function_return_size; current_function_return_is_unsigned = old_function_return_is_unsigned; @@ -35300,7 +35418,7 @@ static int parse_possible_knr_function (void) { if (is_type_start (tok.kind) || tok.kind == TOK_LBRACE) { - parse_function_body (name, STORAGE_NONE, 0, 0, 0, 0, DATA_INT & 0x1f, name_line, name_start, name_caret); + parse_function_body (name, STORAGE_NONE, 0, 0, 0, 0, 0, DATA_INT & 0x1f, name_line, name_start, name_caret); if (parsed_dllexport || declarator_dllexport) { @@ -36500,6 +36618,8 @@ static void parse_external_after_type (void) { int declaration_is_inline; int declaration_storage; + + int declaration_noreturn = 0; int declaration_dllimport = 0; int decl_is_pointer; @@ -36525,10 +36645,13 @@ static void parse_external_after_type (void) { declaration_is_inline = parsed_type_is_inline; declaration_storage = parsed_storage_class; declaration_dllimport = parsed_dllimport; + declaration_noreturn = parsed_noreturn; parse_declarator (&name); declaration_dllimport = declaration_dllimport || parsed_dllimport || declarator_dllimport; + declaration_noreturn = declaration_noreturn || parsed_noreturn || declarator_noreturn; + apply_typedef_array_to_declarator (); decl_is_pointer = declarator_is_pointer; @@ -36596,7 +36719,7 @@ static void parse_external_after_type (void) { } - parse_function_body (name, declaration_storage, declaration_is_inline, + parse_function_body (name, declaration_storage, declaration_is_inline, declaration_noreturn, (parsed_type_is_void && !declarator_is_pointer), (declarator_is_pointer ? 0 : parsed_type_is_floating), (declarator_is_pointer ? 0 : parsed_type_is_unsigned), @@ -36731,8 +36854,12 @@ static void parse_external_after_type (void) { set_global_symbol_unsigned (name, 0); set_global_symbol_floating (name, declarator_is_pointer ? 0 : parsed_type_is_floating); set_global_symbol_returns_void (name, parsed_type_is_void && !declarator_is_pointer && !declarator_function_is_pointer); - set_global_symbol_param_count (name, declarator_function_param_count, declarator_function_has_prototype || declarator_function_param_count > 0, declarator_function_is_variadic); + if (declaration_noreturn) { + set_global_symbol_noreturn (name, 1); + } + + set_global_symbol_param_count (name, declarator_function_param_count, declarator_function_has_prototype || declarator_function_param_count > 0, declarator_function_is_variadic); set_global_symbol_calling_convention (name, (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention); set_global_symbol_dllimport (name, declaration_dllimport); diff --git a/parse.c b/parse.c index 11160d5..5e82a0c 100644 --- a/parse.c +++ b/parse.c @@ -23,8 +23,10 @@ enum token_kind postfix_member_calling_convention = TOK_EOF; enum token_kind parsed_calling_convention = TOK_EOF; struct vector vec_dllexports = { 0 }; + int parsed_dllexport = 0; int parsed_dllimport = 0; +int parsed_noreturn = 0; int parsed_type_size = DATA_NONE; int parsed_type_is_inline = 0; @@ -57,9 +59,11 @@ int declarator_function_has_prototype = 0; int declarator_function_is_variadic = 0; int declarator_array_unsized = 0; -int declarator_is_pointer = 0; int declarator_pointer_depth = 0; +int declarator_is_pointer = 0; + int declarator_has_array = 0; +int declarator_noreturn = 0; int declarator_dllexport = 0; int declarator_dllimport = 0; @@ -467,6 +471,19 @@ static void parse_decl_modifier (void) { get_token (); + } else if (strcmp (tok.ident, "noreturn") == 0) { + + if (parsed_noreturn || declarator_noreturn) { + report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.report_start, tok.report_caret, "duplicate '__declspec(noreturn)'"); + } else { + + declarator_noreturn = 1; + parsed_noreturn = 1; + + } + + get_token (); + } else { report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.report_start, tok.report_caret, "unsupported '__declspec' attribute '%s'", tok.ident); @@ -580,6 +597,7 @@ void parse_declarator (char **out_name) { int saved_declarator_dllexport = declarator_dllexport; int saved_declarator_dllimport = declarator_dllimport; + int saved_declarator_noreturn = declarator_noreturn; unsigned long saved_captured_declarator_name_line = captured_declarator_name_line; @@ -594,6 +612,7 @@ void parse_declarator (char **out_name) { declarator_dllexport = 0; declarator_dllimport = 0; + declarator_noreturn = 0; captured_declarator_name_location = 0; captured_declarator_name_start = 0; @@ -658,6 +677,7 @@ void parse_declarator (char **out_name) { declarator_calling_convention = saved_declarator_calling_convention; declarator_dllexport = saved_declarator_dllexport; declarator_dllimport = saved_declarator_dllimport; + declarator_noreturn = saved_declarator_noreturn; } @@ -2486,6 +2506,7 @@ void parse_type_spec (void) { parsed_dllexport = 0; parsed_dllimport = 0; + parsed_noreturn = 0; clear_parsed_fields (); diff --git a/parse.h b/parse.h index ab491d1..edef0cb 100644 --- a/parse.h +++ b/parse.h @@ -19,8 +19,10 @@ extern enum token_kind postfix_member_calling_convention; extern enum token_kind parsed_calling_convention; extern struct vector vec_dllexports; + extern int parsed_dllexport; extern int parsed_dllimport; +extern int parsed_noreturn; extern int parsed_type_size; extern int parsed_type_is_inline; @@ -59,6 +61,7 @@ extern int declarator_has_array; extern int declarator_dllexport; extern int declarator_dllimport; +extern int declarator_noreturn; extern enum token_kind declarator_calling_convention; extern int global_initializer_accept_symbol_addresses; @@ -218,6 +221,7 @@ struct global_symbol_entry { int pointed_is_floating; int pointed_is_unsigned; int returns_void; + int is_noreturn; int param_count; int has_prototype;