diff options
author | Mark Mitchell <mark@codesourcery.com> | 2000-09-17 07:38:23 +0000 |
---|---|---|
committer | Mark Mitchell <mmitchel@gcc.gnu.org> | 2000-09-17 07:38:23 +0000 |
commit | 8f17b5c5cbf15d0f3a548e94928caff9ffcfd7b8 (patch) | |
tree | 45edb9dcda813de0e477165a8b093d17332bda80 /gcc/c-common.c | |
parent | 4797e955c6b44df4bef1d8d1c2ae9074480c6cf4 (diff) | |
download | gcc-8f17b5c5cbf15d0f3a548e94928caff9ffcfd7b8.zip gcc-8f17b5c5cbf15d0f3a548e94928caff9ffcfd7b8.tar.gz gcc-8f17b5c5cbf15d0f3a548e94928caff9ffcfd7b8.tar.bz2 |
splay-tree.c (splay_tree_predecessor): Fix typo in comment.
* splay-tree.c (splay_tree_predecessor): Fix typo in comment.
Convert the C front-end to use function-at-a-time mode.
* c-common.h: Include splay-tree.h.
(C_DECLARED_LABEL_FLAG): New macro.
(struct language_function): Add x_scope_stmt_stack and
x_function_name_declared_p.
(RECHAIN_STMTS): Move definition.
(lang_statment_code_p): Likewise.
(lang_expand_stmt): Likewise.
(lang_expand_decl_stmt): New variable.
(lang_expand_function_end): Likewise.
(current_scope_stmt_stack): New function.
(add_decl_stmt): Likewise.
(add_scope_stmt): Likewise.
(mark_stmt_tree): Likewise.
(struct c_lang_decl): New structure.
(DECL_SAVED_TREE): Define.
(c_mark_lang_decl): New function.
(c_expand_start_cond): Change prototype.
(c_finish_then): New function.
(c_finish_else): Likewise.
(current_function_name_declared): Remove.
(set_current_function_name_declared): Likewise.
(mark_c_language_function): Declare.
(case_compare): Likewise.
(c_add_case_label): Likewise.
(c_expand_expr): Likewise.
(c_safe_from_p): Likewise.
* c-common.c (lang_expand_function_end): New variable.
(struct if_elt): Add if_stmt.
(c_expand_start_cond): Add the if-statement to the statement-tree,
rather than generating RTL.
(c_finish_then): New function.
(c_expand_start_else): Don't generate RTL.
(c_finish_else): New function.
(c_expand_expr_stmt): Don't generate RTL.
(statement_code_p): Add SCOPE_STMT.
(case_compare): New function.
(c_add_case_label): Likewise.
(mark_stmt_tree): Likewise.
(c_mark_lang_decl): Likewise.
(mark_c_language_function): Likewise.
(c_expand_expr): Likewise.
(c_safe_from_p): Likewise.
* c-decl.c (c_stmt_tree): New variable
(c_scope_stmt_stack): Likewise.
(c_function_name_declared_p): Likewise.
(lang_expand_expr_stmt): Remove.
(poplevel): Don't call output_inline_function for nested
functions.
(pushdecl): Don't set DECL_CONTEXT for a local declaration of an
`extern' function.
(redeclaration_error_message): Change means of computing whether
or not a function is nested.
(lookup_label): Don't call label_rtx.
(init_decl_processing): Add more GC roots.
(start_decl): Add DECL_STMTs to the statement-tree, rather than
calling rest_of_decl_compilation.
(finish_decl): Don't call expand_decl.
(store_parm_decls): Begin the statement-tree, but don't generate
RTL.
(finish_function): Tie off the statement-tree. Call c_expand_body
if appropriate.
(c_expand_body): New function.
(push_c_function_context): Save more information.
(pop_c_function_contxt): Likewise.
(copy_lang_decl): Now that we use DECL_LANG_SPECIFIC, copy it.
(lang_mark_tree): Mark it.
(current_stmt_tree): Adjust.
(current_scope_stmt_stack): New function.
(do_case): Remove.
(set_current_name_declared): Likewise.
(c_begin_compound_stmt): Define.
(c_expand_decl_stmt): Likewise.
* c-lang.c: Include rtl.h and expr.h.
(lang_init): Set more language-specific hooks.
* c-lex.c: Include expr.h.
* c-parse.in: Changes throughout to add statements to the
statement-tree, rather than generating RTL after every statement.
* c-semantics.c (lang_expand_decl_stmt): Define.
(add_decl_stmt): New function.
(add_scope_stmt): Likewise.
(finish_stmt_tree): Tweak.
(genrtl_expr_stmt): Likewise.
(genrtl_decl_stmt): Handle local labels, and call
lang_expand_decl_stmt if required.
(genrtl_for_stmt): Fix line-number handling.
(genrtl_case_label): Handle cleanups.
(genrtl_asm_stmt): Don't call combine_strings.
(genrtl_compound_stmt): Simplify.
(expand_stmt): Handle SCOPE_STMTs.
* c-tree.h (struct lang_decl): New structure.
(C_DECLARED_LABEL_FLAG): Remove.
(c_begin_compound_stmt): Declare.
(c_expand_decl_stmt): Likewise.
(c_expand_start_case): Rename to c_start_case.
(c_finish_case): New function.
* c-typeck.c (start_init): Tweak setting of
constructor_incremental.
(c_expand_asm_operands): Tweak error-handling. Add to the
statement-tree.
(c_expand_return): Add to the statement-tree.
(c_expand_start_case): Rename to ...
(c_start_case): ... this.
(struct c_switch): New type.
(switch_stack): New variable.
(do_case): Simplify.
(c_finish_case): New function.
* dependence.c: Include expr.h.
(enum dependence_type): Change spelling of enumerals.
(check_node_dependence): Adjust.
* expr.h (lang_safe_from_p): Declare.
(safe_from_p): Likewise.
* expr.c (lang_safe_from_p): New variable.
(safe_from_p): Give it external linkage. Use lang_safe_from_p.
* stmt.c (expand_expr_stmt): Avoid clobberring of last_expr_type.
* toplev.c (rest_of_decl_compilation): Robustify.
* tree.c (contains_placeholder_p): Likewise.
* Makefile.in: Update dependencies.
* objc/objc-act.h: Adjust calculation of value for dummy_tree_code.
* objc/objc-act.c: Include rtl.h, expr.h, and c-common.h.
(objc_expand_function_end): New function.
(finish_method_def): Use it.
(init_objc): Initialize more language-specific hooks.
* objc/Make-lang.in: Update dependencies.
* cp-tree.h (struct cp_language_function): Remove
x_scope_stmt_stack and name_declared.
(current_scope_stmt_stack): Remove.
(function_name_declared_p): New macro.
(struct lang_decl_flags): Use c_lang_decl as a base class.
(context): Remove.
(struct lang_decl): Replace saved_tree with context.
(DECL_FRIEND_CONTEXT): Adjust accordingly.
(SET_DECL_FRIEND_CONTEXT): Likewise.
(DECL_VIRTUAL_CONTEXT): Likewise.
(DECL_SAVED_TREE): Remove.
(C_DECLARED_LABEL_FLAG): Likewise.
(cplus_expand_expr_stmt): Don't declare.
(add_decl_stmt): Likewise.
(add_scope_stmt): Likewise.
* decl.c (mark_stmt_tree): Remove.
(case_compare): Likewise.
(finish_case_label): Use c_add_case_label.
(init_decl_processing): Set more language-specific hooks.
(build_enumerator): Fix typo in comment.
(cplus_expand_expr_stmt): Remove.
(mark_lang_function): Use mark_c_language_function.
(lang_mark_tree): Use c_mark_lang_decl.
* decl2.c: Change order of inclusion.
* except.c: Likewise.
* expr.c (cplus_expand_expr): Remove handling of STMT_EXPR. Fall
back on c_expand_expr.
* friend.c: Include expr.h.
* init.c: Change order of inclusion.
* Makefile.in: Update dependencies.
* lex.h (free_lang_decl_chain): Remove.
* optimize.c (maybe_clone_body): Use function_name_declared_p.
* pt.c (build_template_decl): Don't copy DECL_VIRTUAL_CONTEXT if
it doesn't exist.
(instantiate_decl): Use function_name_declared_p.
* semantics.c (lang_expand_expr_stmt): Remove.
(set_current_function_name_declared): Likewise.
(current_function_name_declared): Likewise.
(begin_compound_stmt): Use function_name_declared_p.
(add_decl_stmt): Remove.
(setup_vtbl_ptr): Use function_name_declared_p.
(add_scope_stmt): Remove.
(current_scope_stmt_stack): New function.
(cp_expand_stmt): Don't handle SCOPE_STMTs.
(expand_body): Use function_name_declared_p.
* tree.c (cp_statement_code_p): Don't include SCOPE_STMT.
* typeck.c: Change order of includes.
(convert_sequence): Remove.
From-SVN: r36464
Diffstat (limited to 'gcc/c-common.c')
-rw-r--r-- | gcc/c-common.c | 327 |
1 files changed, 317 insertions, 10 deletions
diff --git a/gcc/c-common.c b/gcc/c-common.c index 2f35541..54335dd 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -22,7 +22,6 @@ Boston, MA 02111-1307, USA. */ #include "config.h" #include "system.h" #include "tree.h" -#include "c-common.h" #include "flags.h" #include "toplev.h" #include "output.h" @@ -30,6 +29,7 @@ Boston, MA 02111-1307, USA. */ #include "rtl.h" #include "ggc.h" #include "expr.h" +#include "c-common.h" #include "tm_p.h" #include "intl.h" @@ -149,6 +149,10 @@ tree (*make_fname_decl) PARAMS ((tree, const char *, int)); returns 1 for language-specific statement codes. */ int (*lang_statement_code_p) PARAMS ((enum tree_code)); +/* If non-NULL, the address of a language-specific function that takes + any action required right before expand_function_end is called. */ +void (*lang_expand_function_end) PARAMS ((void)); + /* Nonzero means the expression being parsed will never be evaluated. This is a count, since unevaluated expressions can nest. */ int skip_evaluation; @@ -181,6 +185,7 @@ typedef struct int line; const char *file; int needs_warning; + tree if_stmt; } if_elt; static void tfaff PARAMS ((void)); @@ -192,15 +197,16 @@ static int if_stack_space = 0; /* Stack pointer. */ static int if_stack_pointer = 0; -/* Generate RTL for the start of an if-then, and record the start of it +/* Record the start of an if-then, and record the start of it for ambiguous else detection. */ void -c_expand_start_cond (cond, exitflag, compstmt_count) +c_expand_start_cond (cond, compstmt_count) tree cond; - int exitflag; int compstmt_count; { + tree if_stmt; + /* Make sure there is enough space on the stack. */ if (if_stack_space == 0) { @@ -213,17 +219,29 @@ c_expand_start_cond (cond, exitflag, compstmt_count) if_stack = (if_elt *)xrealloc (if_stack, if_stack_space * sizeof (if_elt)); } + if_stmt = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE); + IF_COND (if_stmt) = cond; + add_stmt (if_stmt); + /* Record this if statement. */ if_stack[if_stack_pointer].compstmt_count = compstmt_count; if_stack[if_stack_pointer].file = input_filename; if_stack[if_stack_pointer].line = lineno; if_stack[if_stack_pointer].needs_warning = 0; + if_stack[if_stack_pointer].if_stmt = if_stmt; if_stack_pointer++; +} - expand_start_cond (cond, exitflag); +/* Called after the then-clause for an if-statement is processed. */ + +void +c_finish_then () +{ + tree if_stmt = if_stack[if_stack_pointer - 1].if_stmt; + RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt)); } -/* Generate RTL for the end of an if-then. Optionally warn if a nested +/* Record the end of an if-then. Optionally warn if a nested if statement had an ambiguous else clause. */ void @@ -234,10 +252,10 @@ c_expand_end_cond () warning_with_file_and_line (if_stack[if_stack_pointer].file, if_stack[if_stack_pointer].line, "suggest explicit braces to avoid ambiguous `else'"); - expand_end_cond (); + last_expr_type = NULL_TREE; } -/* Generate RTL between the then-clause and the else-clause +/* Called between the then-clause and the else-clause of an if-then-else. */ void @@ -256,8 +274,15 @@ c_expand_start_else () case. Also don't warn for any if statements nested in this else. */ if_stack[if_stack_pointer - 1].needs_warning = 0; if_stack[if_stack_pointer - 1].compstmt_count--; +} + +/* Called after the else-clause for an if-statement is processed. */ - expand_start_else (); +void +c_finish_else () +{ + tree if_stmt = if_stack[if_stack_pointer - 1].if_stmt; + RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt)); } /* Make bindings for __FUNCTION__, __PRETTY_FUNCTION__, and __func__. */ @@ -2770,7 +2795,8 @@ c_expand_expr_stmt (expr) && TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE) error ("expression statement has incomplete type"); - expand_expr_stmt (expr); + last_expr_type = TREE_TYPE (expr); + add_stmt (build_stmt (EXPR_STMT, expr)); } /* Validate the expression after `case' and apply default promotions. */ @@ -4540,6 +4566,7 @@ statement_code_p (code) case RETURN_STMT: case BREAK_STMT: case CONTINUE_STMT: + case SCOPE_STMT: case SWITCH_STMT: case GOTO_STMT: case LABEL_STMT: @@ -4627,6 +4654,286 @@ walk_stmt_tree (tp, func, data) #undef WALK_SUBTREE } +/* Used to compare case labels. K1 and K2 are actually tree nodes + representing case labels, or NULL_TREE for a `default' label. + Returns -1 if K1 is ordered before K2, -1 if K1 is ordered after + K2, and 0 if K1 and K2 are equal. */ + +int +case_compare (k1, k2) + splay_tree_key k1; + splay_tree_key k2; +{ + /* Consider a NULL key (such as arises with a `default' label) to be + smaller than anything else. */ + if (!k1) + return k2 ? -1 : 0; + else if (!k2) + return k1 ? 1 : 0; + + return tree_int_cst_compare ((tree) k1, (tree) k2); +} + +/* Process a case label for the range LOW_VALUE ... HIGH_VALUE. If + LOW_VALUE and HIGH_VALUE are both NULL_TREE then this case label is + actually a `default' label. If only HIGH_VALUE is NULL_TREE, then + case label was declared using the usual C/C++ syntax, rather than + the GNU case range extension. CASES is a tree containing all the + case ranges processed so far; COND is the condition for the + switch-statement itself. Returns the CASE_LABEL created, or + ERROR_MARK_NODE if no CASE_LABEL is created. */ + +tree +c_add_case_label (cases, cond, low_value, high_value) + splay_tree cases; + tree cond; + tree low_value; + tree high_value; +{ + tree type; + tree label; + tree case_label; + splay_tree_node node; + + /* Create the LABEL_DECL itself. */ + label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + DECL_CONTEXT (label) = current_function_decl; + + /* If there was an error processing the switch condition, bail now + before we get more confused. */ + if (!cond || cond == error_mark_node) + { + /* Add a label anyhow so that the back-end doesn't think that + the beginning of the switch is unreachable. */ + if (!cases->root) + add_stmt (build_case_label (NULL_TREE, NULL_TREE, label)); + return error_mark_node; + } + + if ((low_value && TREE_TYPE (low_value) + && POINTER_TYPE_P (TREE_TYPE (low_value))) + || (high_value && TREE_TYPE (high_value) + && POINTER_TYPE_P (TREE_TYPE (high_value)))) + error ("pointers are not permitted as case values"); + + /* Case ranges are a GNU extension. */ + if (high_value && pedantic) + { + if (c_language == clk_cplusplus) + pedwarn ("ISO C++ forbids range expressions in switch statements"); + else + pedwarn ("ISO C forbids range expressions in switch statements"); + } + + type = TREE_TYPE (cond); + if (low_value) + { + low_value = check_case_value (low_value); + low_value = convert_and_check (type, low_value); + } + if (high_value) + { + high_value = check_case_value (high_value); + high_value = convert_and_check (type, high_value); + } + + /* If an error has occurred, bail out now. */ + if (low_value == error_mark_node || high_value == error_mark_node) + { + if (!cases->root) + add_stmt (build_case_label (NULL_TREE, NULL_TREE, label)); + return error_mark_node; + } + + /* If the LOW_VALUE and HIGH_VALUE are the same, then this isn't + really a case range, even though it was written that way. Remove + the HIGH_VALUE to simplify later processing. */ + if (tree_int_cst_equal (low_value, high_value)) + high_value = NULL_TREE; + if (low_value && high_value + && !tree_int_cst_lt (low_value, high_value)) + warning ("empty range specified"); + + /* Look up the LOW_VALUE in the table of case labels we already + have. */ + node = splay_tree_lookup (cases, (splay_tree_key) low_value); + /* If there was not an exact match, check for overlapping ranges. + There's no need to do this if there's no LOW_VALUE or HIGH_VALUE; + that's a `default' label and the only overlap is an exact match. */ + if (!node && (low_value || high_value)) + { + splay_tree_node low_bound; + splay_tree_node high_bound; + + /* Even though there wasn't an exact match, there might be an + overlap between this case range and another case range. + Since we've (inductively) not allowed any overlapping case + ranges, we simply need to find the greatest low case label + that is smaller that LOW_VALUE, and the smallest low case + label that is greater than LOW_VALUE. If there is an overlap + it will occur in one of these two ranges. */ + low_bound = splay_tree_predecessor (cases, + (splay_tree_key) low_value); + high_bound = splay_tree_successor (cases, + (splay_tree_key) low_value); + + /* Check to see if the LOW_BOUND overlaps. It is smaller than + the LOW_VALUE, so there is no need to check unless the + LOW_BOUND is in fact itself a case range. */ + if (low_bound + && CASE_HIGH ((tree) low_bound->value) + && tree_int_cst_compare (CASE_HIGH ((tree) low_bound->value), + low_value) >= 0) + node = low_bound; + /* Check to see if the HIGH_BOUND overlaps. The low end of that + range is bigger than the low end of the current range, so we + are only interested if the current range is a real range, and + not an ordinary case label. */ + else if (high_bound + && high_value + && (tree_int_cst_compare ((tree) high_bound->key, + high_value) + <= 0)) + node = high_bound; + } + /* If there was an overlap, issue an error. */ + if (node) + { + tree duplicate = CASE_LABEL_DECL ((tree) node->value); + + if (high_value) + { + error ("duplicate (or overlapping) case value"); + error_with_decl (duplicate, + "this is the first entry overlapping that value"); + } + else if (low_value) + { + error ("duplicate case value") ; + error_with_decl (duplicate, "previously used here"); + } + else + { + error ("multiple default labels in one switch"); + error_with_decl (duplicate, "this is the first default label"); + } + if (!cases->root) + add_stmt (build_case_label (NULL_TREE, NULL_TREE, label)); + } + + /* Add a CASE_LABEL to the statement-tree. */ + case_label = add_stmt (build_case_label (low_value, high_value, label)); + /* Register this case label in the splay tree. */ + splay_tree_insert (cases, + (splay_tree_key) low_value, + (splay_tree_value) case_label); + + return case_label; +} + +/* Mark P (a stmt_tree) for GC. The use of a `void *' for the + parameter allows this function to be used as a GC-marking + function. */ + +void +mark_stmt_tree (p) + void *p; +{ + stmt_tree st = (stmt_tree) p; + + ggc_mark_tree (st->x_last_stmt); + ggc_mark_tree (st->x_last_expr_type); +} + +/* Mark LD for GC. */ + +void +c_mark_lang_decl (c) + struct c_lang_decl *c; +{ + ggc_mark_tree (c->saved_tree); +} + +/* Mark F for GC. */ + +void +mark_c_language_function (f) + struct language_function *f; +{ + if (!f) + return; + + mark_stmt_tree (&f->x_stmt_tree); + ggc_mark_tree (f->x_scope_stmt_stack); +} + +/* Hook used by expand_expr to expand language-specific tree codes. */ + +rtx +c_expand_expr (exp, target, tmode, modifier) + tree exp; + rtx target; + enum machine_mode tmode; + enum expand_modifier modifier; +{ + switch (TREE_CODE (exp)) + { + case STMT_EXPR: + { + tree rtl_expr; + rtx result; + + /* Since expand_expr_stmt calls free_temp_slots after every + expression statement, we must call push_temp_slots here. + Otherwise, any temporaries in use now would be considered + out-of-scope after the first EXPR_STMT from within the + STMT_EXPR. */ + push_temp_slots (); + rtl_expr = expand_start_stmt_expr (); + expand_stmt (STMT_EXPR_STMT (exp)); + expand_end_stmt_expr (rtl_expr); + result = expand_expr (rtl_expr, target, tmode, modifier); + pop_temp_slots (); + return result; + } + break; + + default: + abort (); + } + + abort (); + return NULL; +} + +/* Hook used by safe_from_p to handle language-specific tree codes. */ + +int +c_safe_from_p (target, exp) + rtx target; + tree exp; +{ + /* We can see statements here when processing the body of a + statement-expression. For a declaration statement declaring a + variable, look at the variable's initializer. */ + if (TREE_CODE (exp) == DECL_STMT) + { + tree decl = DECL_STMT_DECL (exp); + + if (TREE_CODE (decl) == VAR_DECL + && DECL_INITIAL (decl) + && !safe_from_p (target, DECL_INITIAL (decl), /*top_p=*/0)) + return 0; + } + + /* For any statement, we must follow the statement-chain. */ + if (statement_code_p (TREE_CODE (exp)) && TREE_CHAIN (exp)) + return safe_from_p (target, TREE_CHAIN (exp), /*top_p=*/0); + + /* Assume everything else is safe. */ + return 1; +} + /* Tree code classes. */ #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE, |