From 506e2710352a43151c4d5df8673606a9bf395885 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 24 Jun 2004 16:12:30 -0700 Subject: [PATCH] c-decl.c (c_in_iteration_stmt, [...]): Remove. * c-decl.c (c_in_iteration_stmt, c_in_case_stmt): Remove. (c_break_label, c_cont_label): New. (start_function): Update initializations. (c_push_function_context): Update saves. (c_pop_function_context): Update restores. * c-parse.in: Update expected conflicts. (stmt_count, compstmt_count): Remove. Remove all updates. (if_prefix, simple_if, do_stmt_start): Remove. (lineno_labeled_stmt): Remove. (lineno_labels): New. (c99_block_lineno_labeled_stmt): Use it. (lineno_stmt, lineno_label): Don't clear EXPR_LOCUS before calling annotate_with_locus. (select_or_iter_stmt): Replace by ... (condition, if_statement_1, if_statement_2, if_statement, start_break, start_continue, while_statement, do_statement, for_cond_expr, for_incr_expr, for_statement, switch_statement): New. (stmt): Split out ... (stmt_nocomp): ... this. Use c_finish_bc_stmt, c_finish_goto_label, c_finish_goto_ptr. * c-semantics.c (add_stmt): Don't add line numbers to labels. * c-tree.h: Update prototypes. (struct language_function): Remove x_in_iteration_stmt, x_in_case_stmt; add x_break_label, x_cont_label, x_switch_stack. (c_switch_stack): Declare. * c-typeck.c (c_finish_goto_label, c_finish_goto_ptr): New. (c_finish_return): Return the statement. (c_switch_stack): Rename from switch_stack; export. (if_elt, if_stack, if_stack_space, if_stack_pointer): Remove. (c_begin_if_stmt, c_finish_if_cond, c_finish_then, c_begin_else, c_finish_else): Remove. (c_finish_if_stmt): Rewrite to perform the entire operation. (c_begin_while_stmt, c_finish_while_stmt_cond, c_finish_while_stmt, c_begin_for_stmt, c_finish_for_stmt_init, c_finish_for_stmt_cond, c_finish_for_stmt_incr, c_finish_for_stmt): Remove. (c_finish_loop): New. (c_finish_bc_stmt): New. (c_finish_expr_stmt): Return the statement. Split out... (c_process_expr_stmt): ... this. Don't add locus to error marks. * gimplify.c (gimplify_cond_expr): Accept NULL type statements. * tree-gimple.c (is_gimple_stmt): Likewise. * tree-pretty-print.c (dump_generic_node ): Likewise. (print_struct_decl): Delete empty compound statement. * objc/objc-act.c (objc_build_throw_stmt): Return the statement. * objc/objc-act.h: Update decl. From-SVN: r83620 --- gcc/ChangeLog | 48 +++++ gcc/c-decl.c | 22 ++- gcc/c-parse.in | 335 +++++++++++++++++------------------ gcc/c-semantics.c | 4 +- gcc/c-tree.h | 34 ++-- gcc/c-typeck.c | 380 ++++++++++++++++++++-------------------- gcc/gimplify.c | 8 +- gcc/objc/objc-act.c | 14 +- gcc/objc/objc-act.h | 2 +- gcc/tree-gimple.c | 2 +- gcc/tree-pretty-print.c | 6 +- 11 files changed, 450 insertions(+), 405 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d46bb0a8f0a..16ad75d409a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,51 @@ +2004-06-24 Richard Henderson + + * c-decl.c (c_in_iteration_stmt, c_in_case_stmt): Remove. + (c_break_label, c_cont_label): New. + (start_function): Update initializations. + (c_push_function_context): Update saves. + (c_pop_function_context): Update restores. + * c-parse.in: Update expected conflicts. + (stmt_count, compstmt_count): Remove. Remove all updates. + (if_prefix, simple_if, do_stmt_start): Remove. + (lineno_labeled_stmt): Remove. + (lineno_labels): New. + (c99_block_lineno_labeled_stmt): Use it. + (lineno_stmt, lineno_label): Don't clear EXPR_LOCUS before calling + annotate_with_locus. + (select_or_iter_stmt): Replace by ... + (condition, if_statement_1, if_statement_2, if_statement, + start_break, start_continue, while_statement, do_statement, + for_cond_expr, for_incr_expr, for_statement, switch_statement): New. + (stmt): Split out ... + (stmt_nocomp): ... this. Use c_finish_bc_stmt, c_finish_goto_label, + c_finish_goto_ptr. + * c-semantics.c (add_stmt): Don't add line numbers to labels. + * c-tree.h: Update prototypes. + (struct language_function): Remove x_in_iteration_stmt, x_in_case_stmt; + add x_break_label, x_cont_label, x_switch_stack. + (c_switch_stack): Declare. + * c-typeck.c (c_finish_goto_label, c_finish_goto_ptr): New. + (c_finish_return): Return the statement. + (c_switch_stack): Rename from switch_stack; export. + (if_elt, if_stack, if_stack_space, if_stack_pointer): Remove. + (c_begin_if_stmt, c_finish_if_cond, c_finish_then, c_begin_else, + c_finish_else): Remove. + (c_finish_if_stmt): Rewrite to perform the entire operation. + (c_begin_while_stmt, c_finish_while_stmt_cond, c_finish_while_stmt, + c_begin_for_stmt, c_finish_for_stmt_init, c_finish_for_stmt_cond, + c_finish_for_stmt_incr, c_finish_for_stmt): Remove. + (c_finish_loop): New. + (c_finish_bc_stmt): New. + (c_finish_expr_stmt): Return the statement. Split out... + (c_process_expr_stmt): ... this. Don't add locus to error marks. + * gimplify.c (gimplify_cond_expr): Accept NULL type statements. + * tree-gimple.c (is_gimple_stmt): Likewise. + * tree-pretty-print.c (dump_generic_node ): Likewise. + (print_struct_decl): Delete empty compound statement. + * objc/objc-act.c (objc_build_throw_stmt): Return the statement. + * objc/objc-act.h: Update decl. + 2004-06-24 Richard Kenner * tree-pretty-print.c (dump_generic_node, case TYPE_DECL): diff --git a/gcc/c-decl.c b/gcc/c-decl.c index f3170207a0e..7aeba0896c2 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -109,8 +109,8 @@ static location_t current_function_prototype_locus; static GTY(()) struct stmt_tree_s c_stmt_tree; /* State saving variables. */ -int c_in_iteration_stmt; -int c_in_case_stmt; +tree c_break_label; +tree c_cont_label; /* Linked list of TRANSLATION_UNIT_DECLS for the translation units included in this invocation. Note that the current translation @@ -5592,8 +5592,12 @@ start_function (tree declspecs, tree declarator, tree attributes) current_function_returns_abnormally = 0; warn_about_return_type = 0; current_extern_inline = 0; - c_in_iteration_stmt = 0; - c_in_case_stmt = 0; + c_switch_stack = NULL; + + /* Indicate no valid break/continue context by setting these variables + to some non-null, non-label value. We'll notice and emit the proper + error message in c_finish_bc_stmt. */ + c_break_label = c_cont_label = size_zero_node; /* Don't expand any sizes in the return type of the function. */ immediate_size_expand = 0; @@ -6410,8 +6414,9 @@ c_push_function_context (struct function *f) f->language = p; p->base.x_stmt_tree = c_stmt_tree; - p->x_in_iteration_stmt = c_in_iteration_stmt; - p->x_in_case_stmt = c_in_case_stmt; + p->x_break_label = c_break_label; + p->x_cont_label = c_cont_label; + p->x_switch_stack = c_switch_stack; p->returns_value = current_function_returns_value; p->returns_null = current_function_returns_null; p->returns_abnormally = current_function_returns_abnormally; @@ -6437,8 +6442,9 @@ c_pop_function_context (struct function *f) } c_stmt_tree = p->base.x_stmt_tree; - c_in_iteration_stmt = p->x_in_iteration_stmt; - c_in_case_stmt = p->x_in_case_stmt; + c_break_label = p->x_break_label; + c_cont_label = p->x_cont_label; + c_switch_stack = p->x_switch_stack; current_function_returns_value = p->returns_value; current_function_returns_null = p->returns_null; current_function_returns_abnormally = p->returns_abnormally; diff --git a/gcc/c-parse.in b/gcc/c-parse.in index b7acb711718..a96241a3e5c 100644 --- a/gcc/c-parse.in +++ b/gcc/c-parse.in @@ -29,7 +29,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA written by AT&T, but I have never seen it. */ @@ifc -%expect 10 /* shift/reduce conflicts, and no reduce/reduce conflicts. */ +%expect 13 /* shift/reduce conflicts, and no reduce/reduce conflicts. */ @@end_ifc %{ @@ -210,9 +210,10 @@ do { \ %type any_word %type compstmt compstmt_start compstmt_primary_start -%type do_stmt_start stmt label +%type stmt label stmt_nocomp start_break start_continue %type c99_block_start c99_block_lineno_labeled_stmt +%type if_statement_1 if_statement_2 %type declarator %type notype_declarator after_type_declarator %type parm_declarator @@ -227,7 +228,8 @@ do { \ %type struct_head union_head enum_head %type typename absdcl absdcl1 absdcl1_ea absdcl1_noea %type direct_absdcl1 absdcl_maybe_attribute -%type xexpr parms parm firstparm identifiers +%type condition xexpr for_cond_expr for_incr_expr +%type parms parm firstparm identifiers %type parmlist parmlist_1 parmlist_2 %type parmlist_or_identifiers parmlist_or_identifiers_1 @@ -254,11 +256,6 @@ do { \ @@end_ifobjc %{ -/* Number of statements (loosely speaking) and compound statements - seen so far. */ -static int stmt_count; -static int compstmt_count; - /* List of types and structure classes of the current declaration. */ static GTY(()) tree current_declspecs; static GTY(()) tree prefix_attributes; @@ -2032,8 +2029,7 @@ compstmt_or_error: | error compstmt ; -compstmt_start: '{' { compstmt_count++; - $$ = c_begin_compound_stmt (true); } +compstmt_start: '{' { $$ = c_begin_compound_stmt (true); } ; compstmt_nostart: '}' @@ -2053,7 +2049,6 @@ compstmt_primary_start: "only inside a function"); YYERROR; } - compstmt_count++; $$ = c_begin_stmt_expr (); } ; @@ -2062,47 +2057,6 @@ compstmt: compstmt_start compstmt_nostart { $$ = c_end_compound_stmt ($1, true); } ; -if_prefix: - /* We must build the if statement node before parsing its - condition so that we get its location pointing to the - line containing the "if", and not the line containing - the close-parenthesis. */ - IF - { c_begin_if_stmt (); } - '(' expr ')' - { c_finish_if_cond ($4, compstmt_count, ++stmt_count); } - ; - -simple_if: - if_prefix c99_block_lineno_labeled_stmt - { c_finish_then ($2); } - /* Make sure c_finish_if_stmt is run for each call to - c_begin_if_stmt. Otherwise a crash is likely. */ - | if_prefix error - ; - -/* This is a subroutine of stmt. - It is used twice, once for valid DO statements - and once for catching errors in parsing the end test. */ -do_stmt_start: - DO - { stmt_count++; - compstmt_count++; - c_in_iteration_stmt++; - $$ - = add_stmt (build_stmt (DO_STMT, NULL_TREE, - NULL_TREE)); - /* In the event that a parse error prevents - parsing the complete do-statement, set the - condition now. Otherwise, we can get crashes at - RTL-generation time. */ - DO_COND ($$) = error_mark_node; } - c99_block_lineno_labeled_stmt WHILE - { $$ = $2; - DO_BODY ($$) = $3; - c_in_iteration_stmt--; } - ; - /* The forced readahead in here is because we might be at the end of a line, and the line and file won't be bumped until yylex absorbs the first token on the next line. */ @@ -2113,14 +2067,14 @@ save_location: $$ = input_location; } ; -lineno_labeled_stmt: - lineno_stmt - | lineno_label lineno_labeled_stmt +lineno_labels: + /* empty */ + | lineno_labels lineno_label ; -/* Like lineno_labeled_stmt, but a block in C99. */ +/* A labeled statement. In C99 it also generates an implicit block. */ c99_block_lineno_labeled_stmt: - c99_block_start lineno_labeled_stmt + c99_block_start lineno_labels lineno_stmt { $$ = c_end_compound_stmt ($1, flag_isoc99); } ; @@ -2138,74 +2092,91 @@ lineno_stmt: because (recursively) all of the component statments should already have line numbers assigned. */ if ($2 && EXPR_P ($2)) - { - SET_EXPR_LOCUS ($2, NULL); - annotate_with_locus ($2, $1); - } + annotate_with_locus ($2, $1); } ; lineno_label: save_location label - { if ($2) - { - SET_EXPR_LOCUS ($2, NULL); - annotate_with_locus ($2, $1); - } - } + { if ($2) annotate_with_locus ($2, $1); } ; -select_or_iter_stmt: - simple_if ELSE - { c_begin_else (stmt_count); } - c99_block_lineno_labeled_stmt - { c_finish_else ($4); c_finish_if_stmt (stmt_count); } - | simple_if %prec IF - { c_finish_if_stmt (stmt_count); } - | simple_if ELSE error - { c_finish_if_stmt (stmt_count + 1); } - /* We must build the WHILE_STMT node before parsing its - condition so that EXPR_LOCUS refers to the line - containing the "while", and not the line containing - the close-parenthesis. - - c_begin_while_stmt returns the WHILE_STMT node, which - we later pass to c_finish_while_stmt_cond to fill - in the condition and other tidbits. */ - | WHILE - { stmt_count++; - $$ = c_begin_while_stmt (); } - '(' expr ')' - { c_in_iteration_stmt++; - c_finish_while_stmt_cond ($4, $2); } - c99_block_lineno_labeled_stmt - { c_in_iteration_stmt--; - c_finish_while_stmt ($7, $2); } - | do_stmt_start - '(' expr ')' ';' - { DO_COND ($1) = lang_hooks.truthvalue_conversion ($3); } - | do_stmt_start error - { } - | FOR - { $$ = c_begin_for_stmt (); } - '(' for_init_stmt - { stmt_count++; - c_finish_for_stmt_init ($2); } - xexpr ';' - { c_finish_for_stmt_cond ($6, $2); } - xexpr ')' - { c_in_iteration_stmt++; - c_finish_for_stmt_incr ($9, $2); } - c99_block_lineno_labeled_stmt - { c_finish_for_stmt ($12, $2); - c_in_iteration_stmt--; } - | SWITCH '(' expr ')' - { stmt_count++; - $$ = c_start_case ($3); - c_in_case_stmt++; } - c99_block_lineno_labeled_stmt - { c_finish_case ($6); - c_in_case_stmt--; } +condition: save_location expr + { $$ = lang_hooks.truthvalue_conversion ($2); + if (EXPR_P ($$)) + annotate_with_locus ($$, $1); } + ; + +/* Implement -Wparenthesis by special casing IF statement directly nested + within IF statement. This requires some amount of duplication of the + productions under c99_block_lineno_labeled_stmt in order to work out. + But it's still likely more maintainable than lots of state outside the + parser... */ + +if_statement_1: + c99_block_start lineno_labels if_statement + { $$ = c_end_compound_stmt ($1, flag_isoc99); } + ; + +if_statement_2: + c99_block_start lineno_labels ';' + { if (extra_warnings) + add_stmt (build (NOP_EXPR, NULL_TREE, NULL_TREE)); + $$ = c_end_compound_stmt ($1, flag_isoc99); } + | c99_block_lineno_labeled_stmt + ; + +if_statement: + IF c99_block_start save_location '(' condition ')' + if_statement_1 ELSE if_statement_2 + { c_finish_if_stmt ($3, $5, $7, $9, true); + add_stmt (c_end_compound_stmt ($2, flag_isoc99)); } + | IF c99_block_start save_location '(' condition ')' + if_statement_2 ELSE if_statement_2 + { c_finish_if_stmt ($3, $5, $7, $9, false); + add_stmt (c_end_compound_stmt ($2, flag_isoc99)); } + | IF c99_block_start save_location '(' condition ')' + if_statement_1 %prec IF + { c_finish_if_stmt ($3, $5, $7, NULL, true); + add_stmt (c_end_compound_stmt ($2, flag_isoc99)); } + | IF c99_block_start save_location '(' condition ')' + if_statement_2 %prec IF + { c_finish_if_stmt ($3, $5, $7, NULL, false); + add_stmt (c_end_compound_stmt ($2, flag_isoc99)); } + ; + +start_break: /* empty */ + { $$ = c_break_label; c_break_label = NULL; } + ; + +start_continue: /* empty */ + { $$ = c_cont_label; c_cont_label = NULL; } + ; + +while_statement: + WHILE c99_block_start save_location '(' condition ')' + start_break start_continue c99_block_lineno_labeled_stmt + { c_finish_loop ($3, $5, NULL, $9, c_break_label, + c_cont_label, true); + add_stmt (c_end_compound_stmt ($2, flag_isoc99)); + c_break_label = $7; c_cont_label = $8; } + ; + +do_statement: + DO c99_block_start save_location start_break start_continue + c99_block_lineno_labeled_stmt WHILE + { $$ = c_break_label; c_break_label = $4; } + { $$ = c_cont_label; c_cont_label = $5; } + '(' condition ')' ';' + { c_finish_loop ($3, $11, NULL, $6, $8, + $9, false); + add_stmt (c_end_compound_stmt ($2, flag_isoc99)); } + ; + +xexpr: + /* empty */ + { $$ = NULL_TREE; } + | expr ; for_init_stmt: @@ -2215,64 +2186,82 @@ for_init_stmt: { check_for_loop_decls (); } ; -xexpr: - /* empty */ - { $$ = NULL_TREE; } - | expr +for_cond_expr: save_location xexpr + { if ($2) + { + $$ = lang_hooks.truthvalue_conversion ($2); + if (EXPR_P ($$)) + annotate_with_locus ($$, $1); + } + else + $$ = NULL; + } ; -/* Parse a single real statement, not including any labels. */ -stmt: - compstmt - { stmt_count++; add_stmt ($1); } - | expr ';' - { stmt_count++; c_finish_expr_stmt ($1); } - | c99_block_start select_or_iter_stmt - { add_stmt (c_end_compound_stmt ($1, flag_isoc99)); } +for_incr_expr: xexpr + { $$ = c_process_expr_stmt ($1); } + ; + +for_statement: + FOR c99_block_start '(' for_init_stmt + save_location for_cond_expr ';' for_incr_expr ')' + start_break start_continue c99_block_lineno_labeled_stmt + { c_finish_loop ($5, $6, $8, $12, c_break_label, + c_cont_label, true); + add_stmt (c_end_compound_stmt ($2, flag_isoc99)); + c_break_label = $10; c_cont_label = $11; } + ; + +switch_statement: + SWITCH c99_block_start '(' expr ')' + { $$ = c_start_case ($4); } + start_break c99_block_lineno_labeled_stmt + { c_finish_case ($8); + if (c_break_label) + add_stmt (build (LABEL_EXPR, void_type_node, + c_break_label)); + c_break_label = $7; + add_stmt (c_end_compound_stmt ($2, flag_isoc99)); } + ; + +/* Parse a single real statement, not including any labels or compounds. */ +stmt_nocomp: + expr ';' + { $$ = c_finish_expr_stmt ($1); } + | if_statement + { $$ = NULL_TREE; } + | while_statement + { $$ = NULL_TREE; } + | do_statement + { $$ = NULL_TREE; } + | for_statement + { $$ = NULL_TREE; } + | switch_statement + { $$ = NULL_TREE; } | BREAK ';' - { stmt_count++; - if (!(c_in_iteration_stmt || c_in_case_stmt)) - error ("break statement not within loop or switch"); - else - add_stmt (build_break_stmt ()); } + { $$ = c_finish_bc_stmt (&c_break_label, true); } | CONTINUE ';' - { stmt_count++; - if (!c_in_iteration_stmt) - error ("continue statement not within a loop"); - else - add_stmt (build_continue_stmt ()); } + { $$ = c_finish_bc_stmt (&c_cont_label, false); } | RETURN ';' - { stmt_count++; c_finish_return (NULL_TREE); } + { $$ = c_finish_return (NULL_TREE); } | RETURN expr ';' - { stmt_count++; c_finish_return ($2); } + { $$ = c_finish_return ($2); } | asm_stmt | GOTO identifier ';' - { tree decl; - stmt_count++; - decl = lookup_label ($2); - if (decl != 0) - { - TREE_USED (decl) = 1; - add_stmt (build_stmt (GOTO_EXPR, decl)); - } - } + { $$ = c_finish_goto_label ($2); } | GOTO '*' expr ';' - { if (pedantic) - pedwarn ("ISO C forbids `goto *expr;'"); - stmt_count++; - $3 = convert (ptr_type_node, $3); - add_stmt (build_stmt (GOTO_EXPR, $3)); } + { $$ = c_finish_goto_ptr ($3); } | ';' - { } + { $$ = NULL_TREE; } @@ifobjc | AT_THROW expr ';' - { stmt_count++; objc_build_throw_stmt ($2); } + { $$ = objc_build_throw_stmt ($2); } | AT_THROW ';' - { stmt_count++; objc_build_throw_stmt (NULL_TREE); } + { $$ = objc_build_throw_stmt (NULL_TREE); } | objc_try_catch_stmt - { } - | AT_SYNCHRONIZED '(' expr ')' save_location compstmt - { stmt_count++; objc_build_synchronized ($5, $3, $6); } + { $$ = NULL_TREE; } + | AT_SYNCHRONIZED save_location '(' expr ')' compstmt + { objc_build_synchronized ($2, $4, $6); $$ = NULL_TREE; } ; objc_catch_prefix: @@ -2294,7 +2283,7 @@ objc_opt_catch_list: objc_try_catch_clause: AT_TRY save_location compstmt - { stmt_count++; objc_begin_try_stmt ($2, $3); } + { objc_begin_try_stmt ($2, $3); } objc_opt_catch_list ; @@ -2311,22 +2300,25 @@ objc_try_catch_stmt: @@end_ifobjc ; +/* Parse a single or compound real statement, not including any labels. */ +stmt: + compstmt + { add_stmt ($1); $$ = NULL_TREE; } + | stmt_nocomp + ; + /* Any kind of label, including jump labels and case labels. ANSI C accepts labels only before statements, but we allow them also at the end of a compound statement. */ label: CASE expr_no_commas ':' - { stmt_count++; - $$ = do_case ($2, NULL_TREE); } + { $$ = do_case ($2, NULL_TREE); } | CASE expr_no_commas ELLIPSIS expr_no_commas ':' - { stmt_count++; - $$ = do_case ($2, $4); } + { $$ = do_case ($2, $4); } | DEFAULT ':' - { stmt_count++; - $$ = do_case (NULL_TREE, NULL_TREE); } + { $$ = do_case (NULL_TREE, NULL_TREE); } | identifier save_location ':' maybe_attribute { tree label = define_label ($2, $1); - stmt_count++; if (label) { decl_attributes (&label, $4, 0); @@ -2367,8 +2359,7 @@ asmdef: asm_stmt: ASM_KEYWORD maybe_volatile stop_string_translation '(' asm_argument ')' start_string_translation ';' - { stmt_count++; - $$ = build_asm_stmt ($2, $5); } + { $$ = build_asm_stmt ($2, $5); } ; asm_argument: diff --git a/gcc/c-semantics.c b/gcc/c-semantics.c index ee04417ad08..9512947216c 100644 --- a/gcc/c-semantics.c +++ b/gcc/c-semantics.c @@ -128,7 +128,9 @@ pop_stmt_list (tree t) tree add_stmt (tree t) { - if (EXPR_P (t) || STATEMENT_CODE_P (TREE_CODE (t))) + enum tree_code code = TREE_CODE (t); + + if ((EXPR_P (t) || STATEMENT_CODE_P (code)) && code != LABEL_EXPR) { if (!EXPR_LOCUS (t)) annotate_with_locus (t, input_location); diff --git a/gcc/c-tree.h b/gcc/c-tree.h index 66691eba299..4d99c409f3b 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -126,13 +126,14 @@ struct lang_type GTY(()) struct language_function GTY(()) { struct c_language_function base; + tree x_break_label; + tree x_cont_label; + struct c_switch * GTY((skip)) x_switch_stack; int returns_value; int returns_null; int returns_abnormally; int warn_about_return_type; int extern_inline; - int x_in_iteration_stmt; - int x_in_case_stmt; }; @@ -143,8 +144,8 @@ extern void c_parse_init (void); extern void gen_aux_info_record (tree, int, int, int); /* in c-decl.c */ -extern int c_in_iteration_stmt; -extern int c_in_case_stmt; +extern tree c_break_label; +extern tree c_cont_label; extern int global_bindings_p (void); extern void push_scope (void); @@ -212,6 +213,7 @@ extern bool c_warn_unused_global_decl (tree); #define c_sizeof_nowarn(T) c_sizeof_or_alignof_type (T, SIZEOF_EXPR, 0) /* in c-typeck.c */ +extern struct c_switch *c_switch_stack; extern tree require_complete_type (tree); extern int same_translation_unit_p (tree, tree); @@ -254,24 +256,16 @@ extern tree c_convert_parm_for_inlining (tree, tree, tree, int); extern int c_types_compatible_p (tree, tree); extern tree c_begin_compound_stmt (bool); extern tree c_end_compound_stmt (tree, bool); -extern void c_begin_if_stmt (void); -extern void c_finish_if_cond (tree, int, int); -extern void c_finish_then (tree); -extern void c_begin_else (int); -extern void c_finish_else (tree); -extern void c_finish_if_stmt (int); -extern tree c_begin_while_stmt (void); -extern void c_finish_while_stmt_cond (tree, tree); -extern void c_finish_while_stmt (tree, tree); -extern tree c_begin_for_stmt (void); -extern void c_finish_for_stmt_init (tree); -extern void c_finish_for_stmt_cond (tree, tree); -extern void c_finish_for_stmt_incr (tree, tree); -extern void c_finish_for_stmt (tree, tree); +extern void c_finish_if_stmt (location_t, tree, tree, tree, bool); +extern void c_finish_loop (location_t, tree, tree, tree, tree, tree, bool); extern tree c_begin_stmt_expr (void); extern tree c_finish_stmt_expr (tree); -extern void c_finish_expr_stmt (tree); -extern void c_finish_return (tree); +extern tree c_process_expr_stmt (tree); +extern tree c_finish_expr_stmt (tree); +extern tree c_finish_return (tree); +extern tree c_finish_bc_stmt (tree *, bool); +extern tree c_finish_goto_label (tree); +extern tree c_finish_goto_ptr (tree); extern tree build_offsetof (tree, tree); /* Set to 0 at beginning of a function definition, set to 1 if diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 8a5d06f5761..ededd617a23 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -6249,10 +6249,34 @@ c_expand_asm_operands (tree string, tree outputs, tree inputs, emit_queue (); } +/* Generate a goto statement to LABEL. */ + +tree +c_finish_goto_label (tree label) +{ + tree decl = lookup_label (label); + if (!decl) + return NULL_TREE; + + TREE_USED (decl) = 1; + return add_stmt (build (GOTO_EXPR, void_type_node, decl)); +} + +/* Generate a computed goto statement to EXPR. */ + +tree +c_finish_goto_ptr (tree expr) +{ + if (pedantic) + pedwarn ("ISO C forbids `goto *expr;'"); + expr = convert (ptr_type_node, expr); + return add_stmt (build (GOTO_EXPR, void_type_node, expr)); +} + /* Generate a C `return' statement. RETVAL is the expression for what to return, or a null pointer for `return;' with no value. */ -void +tree c_finish_return (tree retval) { tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl)); @@ -6282,7 +6306,7 @@ c_finish_return (tree retval) current_function_returns_value = 1; if (t == error_mark_node) - return; + return NULL_TREE; inner = t = convert (TREE_TYPE (res), t); @@ -6340,7 +6364,7 @@ c_finish_return (tree retval) retval = build (MODIFY_EXPR, TREE_TYPE (res), res, t); } - add_stmt (build_stmt (RETURN_EXPR, retval)); + return add_stmt (build_stmt (RETURN_EXPR, retval)); } struct c_switch { @@ -6362,7 +6386,7 @@ struct c_switch { during the processing of the body of a function, and we never collect at that point. */ -static struct c_switch *switch_stack; +struct c_switch *c_switch_stack; /* Start a C switch statement, testing expression EXP. Return the new SWITCH_STMT. */ @@ -6403,10 +6427,10 @@ c_start_case (tree exp) cs = xmalloc (sizeof (*cs)); cs->switch_stmt = build_stmt (SWITCH_STMT, exp, NULL_TREE, orig_type); cs->cases = splay_tree_new (case_compare, NULL, NULL); - cs->next = switch_stack; - switch_stack = cs; + cs->next = c_switch_stack; + c_switch_stack = cs; - return add_stmt (switch_stack->switch_stmt); + return add_stmt (cs->switch_stmt); } /* Process a case label. */ @@ -6416,10 +6440,10 @@ do_case (tree low_value, tree high_value) { tree label = NULL_TREE; - if (switch_stack) + if (c_switch_stack) { - label = c_add_case_label (switch_stack->cases, - SWITCH_COND (switch_stack->switch_stmt), + label = c_add_case_label (c_switch_stack->cases, + SWITCH_COND (c_switch_stack->switch_stmt), low_value, high_value); if (label == error_mark_node) label = NULL_TREE; @@ -6437,7 +6461,7 @@ do_case (tree low_value, tree high_value) void c_finish_case (tree body) { - struct c_switch *cs = switch_stack; + struct c_switch *cs = c_switch_stack; SWITCH_BODY (cs->switch_stmt) = body; @@ -6445,206 +6469,171 @@ c_finish_case (tree body) c_do_switch_warnings (cs->cases, cs->switch_stmt); /* Pop the stack. */ - switch_stack = switch_stack->next; + c_switch_stack = cs->next; splay_tree_delete (cs->cases); free (cs); } -/* Keep a stack of if statements. We record the number of compound - statements seen up to the if keyword, as well as the line number - and file of the if. If a potentially ambiguous else is seen, that - fact is recorded; the warning is issued when we can be sure that - the enclosing if statement does not have an else branch. */ -typedef struct -{ - tree if_stmt; - location_t empty_locus; - int compstmt_count; - int stmt_count; - unsigned int needs_warning : 1; - unsigned int saw_else : 1; -} if_elt; - -static if_elt *if_stack; - -/* Amount of space in the if statement stack. */ -static int if_stack_space = 0; - -/* Stack pointer. */ -static int if_stack_pointer = 0; - -/* Begin an if-statement. */ +/* Emit an if statement. IF_LOCUS is the location of the 'if'. COND, + THEN_BLOCK and ELSE_BLOCK are expressions to be used; ELSE_BLOCK + may be null. NESTED_IF is true if THEN_BLOCK contains another IF + statement, and was not surrounded with parenthesis. */ void -c_begin_if_stmt (void) +c_finish_if_stmt (location_t if_locus, tree cond, tree then_block, + tree else_block, bool nested_if) { - tree r; - if_elt *elt; + tree stmt; - /* Make sure there is enough space on the stack. */ - if (if_stack_space == 0) + /* Diagnose an ambiguous else if if-then-else is nested inside if-then. */ + if (warn_parentheses && nested_if && else_block == NULL) { - if_stack_space = 10; - if_stack = xmalloc (10 * sizeof (if_elt)); - } - else if (if_stack_space == if_stack_pointer) - { - if_stack_space += 10; - if_stack = xrealloc (if_stack, if_stack_space * sizeof (if_elt)); - } - - r = add_stmt (build_stmt (COND_EXPR, NULL_TREE, NULL_TREE, NULL_TREE)); - - /* Record this if statement. */ - elt = &if_stack[if_stack_pointer++]; - memset (elt, 0, sizeof (*elt)); - elt->if_stmt = r; -} - -/* Record the start of an if-then, and record the start of it - for ambiguous else detection. + tree inner_if = then_block; - COND is the condition for the if-then statement. - - IF_STMT is the statement node that has already been created for - this if-then statement. It is created before parsing the - condition to keep line number information accurate. */ - -void -c_finish_if_cond (tree cond, int compstmt_count, int stmt_count) -{ - if_elt *elt = &if_stack[if_stack_pointer - 1]; - elt->compstmt_count = compstmt_count; - elt->stmt_count = stmt_count; - COND_EXPR_COND (elt->if_stmt) = lang_hooks.truthvalue_conversion (cond); -} - -/* Called after the then-clause for an if-statement is processed. */ - -void -c_finish_then (tree then_stmt) -{ - if_elt *elt = &if_stack[if_stack_pointer - 1]; - COND_EXPR_THEN (elt->if_stmt) = then_stmt; - elt->empty_locus = input_location; -} - -/* Called between the then-clause and the else-clause - of an if-then-else. */ - -void -c_begin_else (int stmt_count) -{ - if_elt *elt = &if_stack[if_stack_pointer - 1]; - - /* An ambiguous else warning must be generated for the enclosing if - statement, unless we see an else branch for that one, too. */ - if (warn_parentheses - && if_stack_pointer > 1 - && (elt[0].compstmt_count == elt[-1].compstmt_count)) - elt[-1].needs_warning = 1; - - /* Even if a nested if statement had an else branch, it can't be - ambiguous if this one also has an else. So don't warn in that - case. Also don't warn for any if statements nested in this else. */ - elt->needs_warning = 0; - elt->compstmt_count--; - elt->saw_else = 1; - elt->stmt_count = stmt_count; -} - -/* Called after the else-clause for an if-statement is processed. */ - -void -c_finish_else (tree else_stmt) -{ - if_elt *elt = &if_stack[if_stack_pointer - 1]; - COND_EXPR_ELSE (elt->if_stmt) = else_stmt; - elt->empty_locus = input_location; -} - -/* Record the end of an if-then. Optionally warn if a nested - if statement had an ambiguous else clause. */ - -void -c_finish_if_stmt (int stmt_count) -{ - if_elt *elt = &if_stack[--if_stack_pointer]; + /* We know from the grammer productions that there is an IF nested + within THEN_BLOCK. Due to labels and c99 conditional declarations, + it might not be exactly THEN_BLOCK, but should be the last + non-container statement within. */ + while (1) + switch (TREE_CODE (inner_if)) + { + case COND_EXPR: + goto found; + case BIND_EXPR: + inner_if = BIND_EXPR_BODY (inner_if); + break; + case STATEMENT_LIST: + inner_if = expr_last (then_block); + break; + case TRY_FINALLY_EXPR: + case TRY_CATCH_EXPR: + inner_if = TREE_OPERAND (inner_if, 0); + break; + default: + abort (); + } + found: - if (elt->needs_warning) - warning ("%Hsuggest explicit braces to avoid ambiguous `else'", - EXPR_LOCUS (elt->if_stmt)); + if (COND_EXPR_ELSE (inner_if)) + warning ("%Hsuggest explicit braces to avoid ambiguous `else'", + &if_locus); + } - if (extra_warnings && stmt_count == elt->stmt_count) + /* Diagnose ";" via the special empty statement node that we create. */ + if (extra_warnings) { - if (elt->saw_else) - warning ("%Hempty body in an else-statement", &elt->empty_locus); - else - warning ("%Hempty body in an if-statement", &elt->empty_locus); + if (TREE_CODE (then_block) == NOP_EXPR && !TREE_TYPE (then_block)) + { + if (!else_block) + warning ("%Hempty body in an if-statement", + EXPR_LOCUS (then_block)); + then_block = alloc_stmt_list (); + } + if (else_block + && TREE_CODE (else_block) == NOP_EXPR + && !TREE_TYPE (else_block)) + { + warning ("%Hempty body in an else-statement", + EXPR_LOCUS (else_block)); + else_block = alloc_stmt_list (); + } } -} - -/* Begin a while statement. Returns a newly created WHILE_STMT if - appropriate. */ -tree -c_begin_while_stmt (void) -{ - tree r; - r = add_stmt (build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE)); - return r; + stmt = build3 (COND_EXPR, NULL_TREE, cond, then_block, else_block); + annotate_with_locus (stmt, if_locus); + add_stmt (stmt); } -void -c_finish_while_stmt_cond (tree cond, tree while_stmt) -{ - WHILE_COND (while_stmt) = (*lang_hooks.truthvalue_conversion) (cond); -} +/* Emit a general-purpose loop construct. START_LOCUS is the location of + the beginning of the loop. COND is the loop condition. COND_IS_FIRST + is false for DO loops. INCR is the FOR increment expression. BODY is + the statement controled by the loop. BLAB is the break label. CLAB is + the continue label. Everything is allowed to be NULL. */ void -c_finish_while_stmt (tree body, tree while_stmt) +c_finish_loop (location_t start_locus, tree cond, tree incr, tree body, + tree blab, tree clab, bool cond_is_first) { - WHILE_BODY (while_stmt) = body; + tree entry = NULL, exit = NULL, t; + + /* Force zeros to NULL so that we don't test them. */ + if (cond && integer_zerop (cond)) + cond = NULL; + + /* Detect do { ... } while (0) and don't generate loop construct. */ + if (cond_is_first || cond) + { + tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE); + + /* If we have an exit condition, then we build an IF with gotos either + out of the loop, or to the top of it. If there's no exit condition, + then we just build a jump back to the top. */ + exit = build_and_jump (&LABEL_EXPR_LABEL (top)); + + if (cond) + { + /* Canonicalize the loop condition to the end. This means + generating a branch to the loop condition. Reuse the + continue label, if possible. */ + if (cond_is_first) + { + if (incr || !clab) + { + entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE); + t = build_and_jump (&LABEL_EXPR_LABEL (entry)); + } + else + t = build1 (GOTO_EXPR, void_type_node, clab); + annotate_with_locus (t, start_locus); + add_stmt (t); + } + + t = build_and_jump (&blab); + exit = build (COND_EXPR, void_type_node, cond, exit, t); + exit = fold (exit); + if (cond_is_first) + annotate_with_locus (exit, start_locus); + else + annotate_with_locus (exit, input_location); + } + + add_stmt (top); + } + + if (body) + add_stmt (body); + if (clab) + add_stmt (build1 (LABEL_EXPR, void_type_node, clab)); + if (incr) + add_stmt (incr); + if (entry) + add_stmt (entry); + if (exit) + add_stmt (exit); + if (blab) + add_stmt (build1 (LABEL_EXPR, void_type_node, blab)); } - -/* Create a for statement. */ tree -c_begin_for_stmt (void) +c_finish_bc_stmt (tree *label_p, bool is_break) { - tree r; - r = add_stmt (build_stmt (FOR_STMT, NULL_TREE, NULL_TREE, - NULL_TREE, NULL_TREE)); - FOR_INIT_STMT (r) = push_stmt_list (); - return r; -} - -void -c_finish_for_stmt_init (tree for_stmt) -{ - FOR_INIT_STMT (for_stmt) = pop_stmt_list (FOR_INIT_STMT (for_stmt)); -} + tree label = *label_p; -void -c_finish_for_stmt_cond (tree cond, tree for_stmt) -{ - if (cond) - FOR_COND (for_stmt) = lang_hooks.truthvalue_conversion (cond); -} + if (!label) + *label_p = label = create_artificial_label (); + else if (TREE_CODE (label) != LABEL_DECL) + { + if (is_break) + error ("break statement not within loop or switch"); + else + error ("continue statement not within a loop"); + return NULL_TREE; + } -void -c_finish_for_stmt_incr (tree expr, tree for_stmt) -{ - FOR_EXPR (for_stmt) = expr; + return add_stmt (build (GOTO_EXPR, void_type_node, label)); } -void -c_finish_for_stmt (tree body, tree for_stmt) -{ - FOR_BODY (for_stmt) = body; -} - -/* A helper routine for c_finish_expr_stmt and c_finish_stmt_expr. */ +/* A helper routine for c_process_expr_stmt and c_finish_stmt_expr. */ static void emit_side_effect_warnings (tree expr) @@ -6661,13 +6650,14 @@ emit_side_effect_warnings (tree expr) warn_if_unused_value (expr, input_location); } -/* Emit an expression as a statement. */ +/* Process an expression as if it were a complete statement. Emit + diagnostics, but do not call ADD_STMT. */ -void -c_finish_expr_stmt (tree expr) +tree +c_process_expr_stmt (tree expr) { if (!expr) - return; + return NULL_TREE; /* Do default conversion if safe and possibly important, in case within ({...}). */ @@ -6696,7 +6686,21 @@ c_finish_expr_stmt (tree expr) if (DECL_P (expr) || TREE_CODE_CLASS (TREE_CODE (expr)) == 'c') expr = build1 (NOP_EXPR, TREE_TYPE (expr), expr); - add_stmt (expr); + if (EXPR_P (expr)) + annotate_with_locus (expr, input_location); + + return expr; +} + +/* Emit an expression as a statement. */ + +tree +c_finish_expr_stmt (tree expr) +{ + if (expr) + return add_stmt (c_process_expr_stmt (expr)); + else + return NULL; } /* Do the opposite and emit a statement as an expression. To begin, diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 308f3e9b6a2..a050b2080c3 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -2511,12 +2511,16 @@ static enum gimplify_status gimplify_cond_expr (tree *expr_p, tree *pre_p, tree target) { tree expr = *expr_p; - tree tmp; + tree tmp, type; enum gimplify_status ret; + type = TREE_TYPE (expr); + if (!type) + TREE_TYPE (expr) = void_type_node; + /* If this COND_EXPR has a value, copy the values into a temporary within the arms. */ - if (! VOID_TYPE_P (TREE_TYPE (expr))) + else if (! VOID_TYPE_P (type)) { if (target) { diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 39e6f765ae7..2ecd03000f4 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -3188,10 +3188,12 @@ objc_finish_try_stmt (void) free (c); } -void +tree objc_build_throw_stmt (tree throw_expr) { - tree func_params; + tree args; + + objc_init_exceptions (); if (throw_expr == NULL) { @@ -3201,7 +3203,7 @@ objc_build_throw_stmt (tree throw_expr) || cur_try_context->current_catch == NULL) { error ("%<@throw%> (rethrow) used outside of a @catch block"); - return; + return NULL_TREE; } /* Otherwise the object is still sitting in the EXC_PTR_EXPR @@ -3211,10 +3213,8 @@ objc_build_throw_stmt (tree throw_expr) /* A throw is just a call to the runtime throw function with the object as a parameter. */ - func_params = tree_cons (NULL, throw_expr, NULL); - add_stmt (build_function_call (objc_exception_throw_decl, func_params)); - - objc_init_exceptions (); + args = tree_cons (NULL, throw_expr, NULL); + return add_stmt (build_function_call (objc_exception_throw_decl, args)); } void diff --git a/gcc/objc/objc-act.h b/gcc/objc/objc-act.h index ab2ea08fd1e..2472bfe711f 100644 --- a/gcc/objc/objc-act.h +++ b/gcc/objc/objc-act.h @@ -39,7 +39,7 @@ void finish_method_def (void); tree start_protocol (enum tree_code, tree, tree); void finish_protocol (tree); -void objc_build_throw_stmt (tree); +tree objc_build_throw_stmt (tree); void objc_begin_try_stmt (location_t, tree); void objc_begin_catch_clause (tree); void objc_finish_catch_clause (void); diff --git a/gcc/tree-gimple.c b/gcc/tree-gimple.c index 2deee183964..f90e9acc488 100644 --- a/gcc/tree-gimple.c +++ b/gcc/tree-gimple.c @@ -348,7 +348,7 @@ is_gimple_stmt (tree t) case BIND_EXPR: case COND_EXPR: /* These are only valid if they're void. */ - return VOID_TYPE_P (TREE_TYPE (t)); + return TREE_TYPE (t) == NULL || VOID_TYPE_P (TREE_TYPE (t)); case SWITCH_EXPR: case GOTO_EXPR: diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 477c2830b32..5fe5a4f677a 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -767,7 +767,7 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, break; case COND_EXPR: - if (TREE_TYPE (node) == void_type_node) + if (TREE_TYPE (node) == NULL || TREE_TYPE (node) == void_type_node) { pp_string (buffer, "if ("); dump_generic_node (buffer, COND_EXPR_COND (node), spc, flags, false); @@ -1543,10 +1543,6 @@ print_struct_decl (pretty_printer *buffer, tree node, int spc, int flags) print_declaration (buffer, tmp, spc+2, flags); pp_newline (buffer); } - else - { - - } tmp = TREE_CHAIN (tmp); } } -- 2.30.2