diff options
38 files changed, 1245 insertions, 769 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 189eb2c..d3a8a6b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,130 @@ +2000-09-16 Mark Mitchell <mark@codesourcery.com> + + 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. + 2000-09-16 Geoffrey Keating <geoffk@cygnus.com> * configure.in: Define macros that affect features before diff --git a/gcc/Makefile.in b/gcc/Makefile.in index dd08a84..2734aeb 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -782,6 +782,9 @@ GCC_H = gcc.h version.h GGC_H = ggc.h varray.h TIMEVAR_H = timevar.h timevar.def INSN_ATTR_H = insn-attr.h $(srcdir)/insn-addr.h $(srcdir)/varray.h +C_COMMON_H = c-common.h $(SPLAY_TREE_H) +C_TREE_H = c-tree.h $(C_COMMON_H) + # # Language makefile fragments. @@ -1077,10 +1080,10 @@ s-crt0: $(CRT0_S) $(MCRT0_S) $(GCC_PASSES) $(CONFIG_H) # C language specific files. -c-errors.o: c-errors.c $(CONFIG_H) system.h $(TREE_H) c-tree.h flags.h \ +c-errors.o: c-errors.c $(CONFIG_H) system.h $(TREE_H) $(C_TREE_H) flags.h \ diagnostic.h c-parse.o : $(srcdir)/c-parse.c $(CONFIG_H) $(TREE_H) c-lex.h $(GGC_H) intl.h \ - c-tree.h c-common.h input.h flags.h system.h toplev.h output.h cpplib.h + $(C_TREE_H) input.h flags.h system.h toplev.h output.h cpplib.h $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c $(srcdir)/c-parse.c $(srcdir)/c-parse.c: $(srcdir)/c-parse.y @@ -1092,18 +1095,19 @@ $(srcdir)/c-parse.y: c-parse.in $(srcdir)/c-parse.in >>tmp-c-parse.y $(SHELL) $(srcdir)/move-if-change tmp-c-parse.y $(srcdir)/c-parse.y -c-decl.o : c-decl.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) c-tree.h \ - c-common.h $(GGC_H) c-lex.h flags.h function.h output.h $(EXPR_H) \ +c-decl.o : c-decl.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) $(C_TREE_H) \ + $(GGC_H) c-lex.h flags.h function.h output.h $(EXPR_H) \ toplev.h defaults.h intl.h -c-typeck.o : c-typeck.c $(CONFIG_H) system.h $(TREE_H) c-tree.h c-common.h \ +c-typeck.o : c-typeck.c $(CONFIG_H) system.h $(TREE_H) $(C_TREE_H) \ flags.h intl.h output.h $(EXPR_H) $(RTL_H) toplev.h -c-lang.o : c-lang.c $(CONFIG_H) system.h $(TREE_H) c-tree.h c-common.h \ - $(GGC_H) c-lex.h toplev.h diagnostic.h output.h function.h -c-lex.o : c-lex.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) c-lex.h c-tree.h \ - c-common.h c-pragma.h input.h intl.h flags.h toplev.h output.h \ - mbchar.h $(GGC_H) cpplib.h $(SPLAY_TREE_H) -c-aux-info.o : c-aux-info.c $(CONFIG_H) system.h $(TREE_H) c-tree.h \ - c-common.h flags.h toplev.h +c-lang.o : c-lang.c $(CONFIG_H) system.h $(TREE_H) $(C_TREE_H) \ + $(GGC_H) c-lex.h toplev.h diagnostic.h output.h function.h \ + $(RTL_H) $(EXPR_H) +c-lex.o : c-lex.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) c-lex.h $(C_TREE_H) \ + c-pragma.h input.h intl.h flags.h toplev.h output.h \ + mbchar.h $(GGC_H) cpplib.h $(EXPR_H) +c-aux-info.o : c-aux-info.c $(CONFIG_H) system.h $(TREE_H) $(C_TREE_H) \ + flags.h toplev.h c-convert.o : c-convert.c $(CONFIG_H) system.h $(TREE_H) flags.h toplev.h c-pragma.o: c-pragma.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) function.h \ defaults.h c-pragma.h toplev.h $(GGC_H) @@ -1157,11 +1161,11 @@ s-under: $(GCC_PASSES) # A file used by all variants of C. c-common.o : c-common.c $(CONFIG_H) system.h $(TREE_H) \ - c-common.h flags.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) \ + $(C_COMMON_H) flags.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) \ $(EXPR_H) -c-semantics.o : c-semantics.c $(CONFIG_H) system.h $(TREE_H) c-tree.h c-lex.h \ - c-common.h flags.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) \ +c-semantics.o : c-semantics.c $(CONFIG_H) system.h $(TREE_H) $(C_TREE_H) \ + c-lex.h flags.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) \ $(EXPR_H) # Language-independent files. @@ -1406,8 +1410,8 @@ regrename.o : regrename.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h \ ifcvt.o : ifcvt.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) \ flags.h insn-config.h function.h $(RECOG_H) $(BASIC_BLOCK_H) $(EXPR_H) \ output.h -dependence.o : dependence.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) c-common.h \ - flags.h varray.h +dependence.o : dependence.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) \ + $(C_COMMON_H) flags.h varray.h $(EXPR_H) $(out_object_file): $(out_file) $(CONFIG_H) $(TREE_H) $(GGC_H) \ $(RTL_H) $(REGS_H) hard-reg-set.h real.h insn-config.h conditions.h \ 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, diff --git a/gcc/c-common.h b/gcc/c-common.h index 389f32a..2477a0f 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -22,6 +22,8 @@ Boston, MA 02111-1307, USA. */ #ifndef GCC_C_COMMON_H #define GCC_C_COMMON_H +#include "splay-tree.h" + /* Usage of TREE_LANG_FLAG_?: 0: COMPOUND_STMT_NO_SCOPE (in COMPOUND_STMT). TREE_NEGATED_INT (in INTEGER_CST). @@ -194,6 +196,10 @@ enum c_tree_index extern tree c_global_trees[CTI_MAX]; +/* Mark which labels are explicitly declared. + These may be shadowed, and may be referenced from nested functions. */ +#define C_DECLARED_LABEL_FLAG(label) TREE_LANG_FLAG_1 (label) + typedef enum c_language_kind { clk_c, /* A dialect of C: K&R C, ANSI/ISO C89, C2000, @@ -237,6 +243,11 @@ struct language_function { /* While we are parsing the function, this contains information about the statement-tree that we are building. */ struct stmt_tree_s x_stmt_tree; + /* The stack of SCOPE_STMTs for the current function. */ + tree x_scope_stmt_stack; + /* Nonzero if __FUNCTION__ and its ilk have been declared in this + function. */ + int x_function_name_declared_p; }; /* When building a statement-tree, this is the last statement added to @@ -248,6 +259,25 @@ struct language_function { #define last_expr_type (current_stmt_tree ()->x_last_expr_type) +/* LAST_TREE contains the last statement parsed. These are chained + together through the TREE_CHAIN field, but often need to be + re-organized since the parse is performed bottom-up. This macro + makes LAST_TREE the indicated SUBSTMT of STMT. */ + +#define RECHAIN_STMTS(stmt, substmt) \ + do { \ + substmt = TREE_CHAIN (stmt); \ + TREE_CHAIN (stmt) = NULL_TREE; \ + last_tree = stmt; \ + } while (0) + +/* Language-specific hooks. */ + +extern int (*lang_statement_code_p) PARAMS ((enum tree_code)); +extern void (*lang_expand_stmt) PARAMS ((tree)); +extern void (*lang_expand_decl_stmt) PARAMS ((tree)); +extern void (*lang_expand_function_end) PARAMS ((void)); + /* The type of a function that walks over tree structure. */ typedef tree (*walk_tree_fn) PARAMS ((tree *, @@ -255,30 +285,39 @@ typedef tree (*walk_tree_fn) PARAMS ((tree *, void *)); extern stmt_tree current_stmt_tree PARAMS ((void)); +extern tree *current_scope_stmt_stack PARAMS ((void)); extern void begin_stmt_tree PARAMS ((tree *)); extern tree add_stmt PARAMS ((tree)); +extern void add_decl_stmt PARAMS ((tree)); +extern tree add_scope_stmt PARAMS ((int, int)); extern void finish_stmt_tree PARAMS ((tree *)); extern int statement_code_p PARAMS ((enum tree_code)); -extern int (*lang_statement_code_p) PARAMS ((enum tree_code)); extern tree walk_stmt_tree PARAMS ((tree *, walk_tree_fn, void *)); extern void prep_stmt PARAMS ((tree)); -extern void (*lang_expand_stmt) PARAMS ((tree)); extern void expand_stmt PARAMS ((tree)); +extern void mark_stmt_tree PARAMS ((void *)); -/* LAST_TREE contains the last statement parsed. These are chained - together through the TREE_CHAIN field, but often need to be - re-organized since the parse is performed bottom-up. This macro - makes LAST_TREE the indicated SUBSTMT of STMT. */ +/* Extra information associated with a DECL. Other C dialects extend + this structure in various ways. The C front-end only uses this + structure for FUNCTION_DECLs; all other DECLs have a NULL + DECL_LANG_SPECIFIC field. */ -#define RECHAIN_STMTS(stmt, substmt) \ - do { \ - substmt = TREE_CHAIN (stmt); \ - TREE_CHAIN (stmt) = NULL_TREE; \ - last_tree = stmt; \ - } while (0) +struct c_lang_decl { + /* In a FUNCTION_DECL, this is DECL_SAVED_TREE. */ + tree saved_tree; +}; + +/* In a FUNCTION_DECL, the saved representation of the body of the + entire function. Usually a COMPOUND_STMT, but in C++ this may also + be a RETURN_INIT, CTOR_INITIALIZER, or TRY_BLOCK. */ +#define DECL_SAVED_TREE(NODE) \ + (((struct c_lang_decl *) DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (NODE))) \ + ->saved_tree) + +extern void c_mark_lang_decl PARAMS ((struct c_lang_decl *)); /* The variant of the C language being processed. Each C language front-end defines this variable. */ @@ -363,8 +402,10 @@ extern void c_apply_type_quals_to_decl PARAMS ((int, tree)); NOP_EXPR is used as a special case (see truthvalue_conversion). */ extern void binary_op_error PARAMS ((enum tree_code)); extern void c_expand_expr_stmt PARAMS ((tree)); -extern void c_expand_start_cond PARAMS ((tree, int, int)); +extern void c_expand_start_cond PARAMS ((tree, int)); +extern void c_finish_then PARAMS ((void)); extern void c_expand_start_else PARAMS ((void)); +extern void c_finish_else PARAMS ((void)); extern void c_expand_end_cond PARAMS ((void)); /* Validate the expression after `case' and apply default promotions. */ extern tree check_case_value PARAMS ((tree)); @@ -589,8 +630,6 @@ extern void genrtl_asm_stmt PARAMS ((tree, tree, tree)); extern void genrtl_decl_cleanup PARAMS ((tree, tree)); extern int stmts_are_full_exprs_p PARAMS ((void)); -typedef void (*expand_expr_stmt_fn) PARAMS ((tree)); -extern expand_expr_stmt_fn lang_expand_expr_stmt; extern int anon_aggr_type_p PARAMS ((tree)); /* For a VAR_DECL that is an anonymous union, these are the various @@ -611,8 +650,6 @@ extern tree build_return_stmt PARAMS ((tree)); #define COMPOUND_STMT_NO_SCOPE(NODE) TREE_LANG_FLAG_0 (NODE) extern void c_expand_asm_operands PARAMS ((tree, tree, tree, tree, int, const char *, int)); -extern int current_function_name_declared PARAMS ((void)); -extern void set_current_function_name_declared PARAMS ((int)); /* These functions must be defined by each front-end which implements a variant of the C language. They are used in c-common.c. */ @@ -637,6 +674,25 @@ extern tree decl_constant_value PARAMS ((tree)); after entering or leaving a header file. */ extern void extract_interface_info PARAMS ((void)); +extern void mark_c_language_function PARAMS ((struct language_function *)); + +extern int case_compare PARAMS ((splay_tree_key, + splay_tree_key)); + +extern tree c_add_case_label PARAMS ((splay_tree, + tree, tree, + tree)); + +#ifdef RTX_CODE + +extern struct rtx_def *c_expand_expr PARAMS ((tree, rtx, + enum machine_mode, + enum expand_modifier)); + +extern int c_safe_from_p PARAMS ((rtx, tree)); + +#endif + /* Information recorded about each file examined during compilation. */ struct c_fileinfo diff --git a/gcc/c-decl.c b/gcc/c-decl.c index bc1857c..b8421a7 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -125,6 +125,19 @@ static tree current_function_parm_tags; static const char *current_function_prototype_file; static int current_function_prototype_line; +/* The current statement tree. */ + +static struct stmt_tree_s c_stmt_tree; + +/* The current scope statement stack. */ + +static tree c_scope_stmt_stack; + +/* Nonzero if __FUNCTION__ and its ilk have been declared in this + function. */ + +static int c_function_name_declared_p; + /* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function that have names. Here so we can clear out their names' definitions at the end of the function. */ @@ -296,6 +309,7 @@ static tree grokdeclarator PARAMS ((tree, tree, enum decl_context, static tree grokparms PARAMS ((tree, int)); static void layout_array_type PARAMS ((tree)); static tree c_make_fname_decl PARAMS ((tree, const char *, int)); +static void c_expand_body PARAMS ((tree, int)); /* C-specific option variables. */ @@ -471,10 +485,6 @@ int warn_float_equal = 0; int warn_multichar = 1; -/* Wrapper since C and C++ expand_expr_stmt are different. */ - -expand_expr_stmt_fn lang_expand_expr_stmt = c_expand_expr_stmt; - /* The variant of the C language being processed. */ c_language_kind c_language = clk_c; @@ -1088,12 +1098,6 @@ poplevel (keep, reverse, functionbody) if (DECL_ABSTRACT_ORIGIN (decl) != 0 && DECL_ABSTRACT_ORIGIN (decl) != decl) TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1; - else if (DECL_SAVED_INSNS (decl) != 0) - { - push_function_context (); - output_inline_function (decl); - pop_function_context (); - } } /* If there were any declarations or structure tags in that level, @@ -1235,6 +1239,7 @@ poplevel (keep, reverse, functionbody) if (block) TREE_USED (block) = 1; + return block; } @@ -2063,8 +2068,8 @@ pushdecl (x) /* A local extern declaration for a function doesn't constitute nesting. A local auto declaration does, since it's a forward decl for a nested function coming later. */ - if (TREE_CODE (x) == FUNCTION_DECL && DECL_INITIAL (x) == 0 - && DECL_EXTERNAL (x)) + if ((TREE_CODE (x) == FUNCTION_DECL || TREE_CODE (x) == VAR_DECL) + && DECL_INITIAL (x) == 0 && DECL_EXTERNAL (x)) DECL_CONTEXT (x) = 0; if (warn_nested_externs && DECL_EXTERNAL (x) && b != global_binding_level @@ -2618,7 +2623,7 @@ redeclaration_error_message (newdecl, olddecl) return 1; return 0; } - else if (current_binding_level == global_binding_level) + else if (DECL_CONTEXT (newdecl) == NULL_TREE) { /* Objects declared at top level: */ /* If at least one is a reference, it's ok. */ @@ -2678,9 +2683,6 @@ lookup_label (id) decl = build_decl (LABEL_DECL, id, void_type_node); - /* Make sure every label has an rtx. */ - label_rtx (decl); - /* A label not explicitly declared must be local to where it's ref'd. */ DECL_CONTEXT (decl) = current_function_decl; @@ -3217,6 +3219,8 @@ init_decl_processing () /* Record our roots. */ ggc_add_tree_root (c_global_trees, CTI_MAX); + ggc_add_root (&c_stmt_tree, 1, sizeof c_stmt_tree, mark_stmt_tree); + ggc_add_tree_root (&c_scope_stmt_stack, 1); ggc_add_tree_root (&named_labels, 1); ggc_add_tree_root (&shadowed_labels, 1); ggc_add_root (¤t_binding_level, 1, sizeof current_binding_level, @@ -3553,7 +3557,8 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes) /* But not if this is a duplicate decl and we preserved the rtl from the previous one (which may or may not happen). */ - && DECL_RTL (tem) == 0) + && DECL_RTL (tem) == 0 + && !DECL_CONTEXT (tem)) { if (COMPLETE_TYPE_P (TREE_TYPE (tem))) expand_decl (tem); @@ -3703,9 +3708,17 @@ finish_decl (decl, init, asmspec_tree) { /* This is a no-op in c-lang.c or something real in objc-actions.c. */ maybe_objc_check_decl (decl); - rest_of_decl_compilation (decl, asmspec, - (DECL_CONTEXT (decl) == 0 - || TREE_ASM_WRITTEN (decl)), 0); + + if (!DECL_CONTEXT (decl)) + rest_of_decl_compilation (decl, asmspec, + (DECL_CONTEXT (decl) == 0 + || TREE_ASM_WRITTEN (decl)), 0); + else + { + if (asmspec) + DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec); + add_decl_stmt (decl); + } if (DECL_CONTEXT (decl) != 0) { @@ -3719,11 +3732,7 @@ finish_decl (decl, init, asmspec_tree) /* If it's still incomplete now, no init will save it. */ if (DECL_SIZE (decl) == 0) DECL_INITIAL (decl) = 0; - expand_decl (decl); } - /* Compute and store the initial value. */ - if (TREE_CODE (decl) != FUNCTION_DECL) - expand_decl_init (decl); } } @@ -5784,6 +5793,7 @@ build_enumerator (name, value) return tree_cons (decl, value, NULL_TREE); } + /* Create the FUNCTION_DECL for a function definition. DECLSPECS, DECLARATOR, PREFIX_ATTRIBUTES and ATTRIBUTES are the parts of @@ -6432,25 +6442,20 @@ store_parm_decls () init_function_start (fndecl, input_filename, lineno); - /* If this is a varargs function, inform function.c. */ - - if (c_function_varargs) - mark_varargs (); + /* Begin the statement tree for this function. */ + DECL_LANG_SPECIFIC (current_function_decl) + =((struct lang_decl *) ggc_alloc (sizeof (struct lang_decl))); + begin_stmt_tree (&DECL_SAVED_TREE (current_function_decl)); - /* Declare __FUNCTION__ and __PRETTY_FUNCTION__ for this function. */ - - declare_function_name (); + /* This function is being processed in whole-function mode. */ + cfun->x_whole_function_mode_p = 1; - /* Set up parameters and prepare for return, for the function. */ - - expand_function_start (fndecl, 0); - - /* If this function is `main', emit a call to `__main' - to run global initializers, etc. */ - if (DECL_NAME (fndecl) - && MAIN_NAME_P (DECL_NAME (fndecl)) - && DECL_CONTEXT (fndecl) == NULL_TREE) - expand_main_function (); + /* Even though we're inside a function body, we still don't want to + call expand_expr to calculate the size of a variable-sized array. + We haven't necessarily assigned RTL to all variables yet, so it's + not safe to try to expand expressions involving them. */ + immediate_size_expand = 0; + cfun->x_dont_save_pending_sizes_p = 1; } /* SPECPARMS is an identifier list--a chain of TREE_LIST nodes @@ -6650,6 +6655,82 @@ finish_function (nested) } } + /* Tie off the statement tree for this function. */ + finish_stmt_tree (&DECL_SAVED_TREE (fndecl)); + /* Clear out memory we no longer need. */ + free_after_parsing (cfun); + /* Since we never call rest_of_compilation, we never clear + CFUN. Do so explicitly. */ + free_after_compilation (cfun); + cfun = NULL; + + if (! nested) + { + /* Generate RTL for the body of this function. */ + c_expand_body (fndecl, nested); + /* Let the error reporting routines know that we're outside a + function. For a nested function, this value is used in + pop_c_function_context and then reset via pop_function_context. */ + current_function_decl = NULL; + } +} + +/* Generate the RTL for the body of FNDECL. If NESTED_P is non-zero, + then we are already in the process of generating RTL for another + function. */ + +static void +c_expand_body (fndecl, nested_p) + tree fndecl; + int nested_p; +{ + /* Squirrel away our current state. */ + if (nested_p) + push_function_context (); + + /* Initialize the RTL code for the function. */ + current_function_decl = fndecl; + init_function_start (fndecl, input_filename, lineno); + + /* This function is being processed in whole-function mode. */ + cfun->x_whole_function_mode_p = 1; + + /* Even though we're inside a function body, we still don't want to + call expand_expr to calculate the size of a variable-sized array. + We haven't necessarily assigned RTL to all variables yet, so it's + not safe to try to expand expressions involving them. */ + immediate_size_expand = 0; + cfun->x_dont_save_pending_sizes_p = 1; + + /* Set up parameters and prepare for return, for the function. */ + expand_function_start (fndecl, 0); + + /* If this function is `main', emit a call to `__main' + to run global initializers, etc. */ + if (DECL_NAME (fndecl) + && MAIN_NAME_P (DECL_NAME (fndecl)) + && DECL_CONTEXT (fndecl) == NULL_TREE) + expand_main_function (); + + /* If this is a varargs function, inform function.c. */ + if (c_function_varargs) + mark_varargs (); + + /* Generate the RTL for this function. */ + expand_stmt (DECL_SAVED_TREE (fndecl)); + /* Allow the body of the function to be garbage collected. */ + DECL_SAVED_TREE (fndecl) = NULL_TREE; + + /* We hard-wired immediate_size_expand to zero in start_function. + expand_function_end will decrement this variable. So, we set the + variable to one here, so that after the decrement it will remain + zero. */ + immediate_size_expand = 1; + + /* Allow language dialects to perform special processing. */ + if (lang_expand_function_end) + (*lang_expand_function_end) (); + /* Generate rtl for function exit. */ expand_function_end (input_filename, lineno, 0); @@ -6658,14 +6739,14 @@ finish_function (nested) /* If this is a nested function, protect the local variables in the stack above us from being collected while we're compiling this function. */ - if (nested) + if (nested_p) ggc_push_context (); /* Run the optimizers and output the assembler code for this function. */ rest_of_compilation (fndecl); /* Undo the GC context switch. */ - if (nested) + if (nested_p) ggc_pop_context (); current_function_returns_null |= can_reach_end; @@ -6715,7 +6796,7 @@ finish_function (nested) } } - if (DECL_SAVED_INSNS (fndecl) == 0 && ! nested) + if (DECL_SAVED_INSNS (fndecl) == 0 && ! nested_p) { /* Stop pointing to the local nodes about to be freed. But DECL_INITIAL must remain nonzero so we know this @@ -6748,13 +6829,20 @@ finish_function (nested) assemble_destructor (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl))); } - if (! nested) + if (nested_p) { - /* Let the error reporting routines know that we're outside a - function. For a nested function, this value is used in - pop_c_function_context and then reset via pop_function_context. */ - current_function_decl = NULL; + /* Return to the enclosing function. */ + pop_function_context (); + /* If the nested function was inline, write it out if that is + necessary. */ + if (!TREE_ASM_WRITTEN (fndecl) && TREE_ADDRESSABLE (fndecl)) + { + push_function_context (); + output_inline_function (fndecl); + pop_function_context (); + } } + } /* Save and restore the variables in this file and elsewhere @@ -6785,6 +6873,9 @@ push_c_function_context (f) xmalloc (sizeof (struct c_language_function))); f->language = (struct language_function *) p; + p->base.x_stmt_tree = c_stmt_tree; + p->base.x_scope_stmt_stack = c_scope_stmt_stack; + p->base.x_function_name_declared_p = c_function_name_declared_p; p->named_labels = named_labels; p->shadowed_labels = shadowed_labels; p->returns_value = current_function_returns_value; @@ -6810,7 +6901,8 @@ pop_c_function_context (f) IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link))) = TREE_VALUE (link); - if (DECL_SAVED_INSNS (current_function_decl) == 0) + if (DECL_SAVED_INSNS (current_function_decl) == 0 + && DECL_SAVED_TREE (current_function_decl) == NULL_TREE) { /* Stop pointing to the local nodes about to be freed. */ /* But DECL_INITIAL must remain nonzero so we know this @@ -6819,6 +6911,9 @@ pop_c_function_context (f) DECL_ARGUMENTS (current_function_decl) = 0; } + c_stmt_tree = p->base.x_stmt_tree; + c_scope_stmt_stack = p->base.x_scope_stmt_stack; + c_function_name_declared_p = p->base.x_function_name_declared_p; named_labels = p->named_labels; shadowed_labels = p->shadowed_labels; current_function_returns_value = p->returns_value; @@ -6843,18 +6938,27 @@ mark_c_function_context (f) if (p == 0) return; + mark_c_language_function (&p->base); ggc_mark_tree (p->shadowed_labels); ggc_mark_tree (p->named_labels); mark_binding_level (&p->binding_level); } -/* integrate_decl_tree calls this function, but since we don't use the - DECL_LANG_SPECIFIC field, this is a no-op. */ +/* Copy the DECL_LANG_SEPECIFIC data associated with NODE. */ void -copy_lang_decl (node) - tree node ATTRIBUTE_UNUSED; +copy_lang_decl (decl) + tree decl; { + struct lang_decl *ld; + + if (!DECL_LANG_SPECIFIC (decl)) + return; + + ld = (struct lang_decl *) ggc_alloc (sizeof (struct lang_decl)); + bcopy ((char *)DECL_LANG_SPECIFIC (decl), (char *)ld, + sizeof (struct lang_decl)); + DECL_LANG_SPECIFIC (decl) = ld; } /* Mark ARG for GC. */ @@ -6886,6 +6990,11 @@ lang_mark_tree (t) } else if (TYPE_P (t) && TYPE_LANG_SPECIFIC (t)) ggc_mark (TYPE_LANG_SPECIFIC (t)); + else if (DECL_P (t) && DECL_LANG_SPECIFIC (t)) + { + ggc_mark (DECL_LANG_SPECIFIC (t)); + c_mark_lang_decl (&DECL_LANG_SPECIFIC (t)->base); + } } /* The functions below are required for functionality of doing @@ -6910,7 +7019,15 @@ stmts_are_full_exprs_p () stmt_tree current_stmt_tree () { - return cfun ? &cfun->language->x_stmt_tree : NULL; + return &c_stmt_tree; +} + +/* Returns the stack of SCOPE_STMTs for the current function. */ + +tree * +current_scope_stmt_stack () +{ + return &c_scope_stmt_stack; } /* Nonzero if TYPE is an anonymous union or struct type. Always 0 in @@ -6923,94 +7040,46 @@ anon_aggr_type_p (node) return 0; } -/* One if we have already declared __FUNCTION__ (and related - variables) in the current function. Two if we are in the process - of doing so. */ +/* Dummy function in place of callback used by C++. */ -int -current_function_name_declared () +void +extract_interface_info () { - abort (); - return 0; } -/* Code to generate the RTL for a case label in C. */ +/* Return a new COMPOUND_STMT, after adding it to the current + statement tree. */ -void -do_case (low_value, high_value) - tree low_value; - tree high_value; +tree +c_begin_compound_stmt () { - tree value1 = NULL_TREE, value2 = NULL_TREE, label; - - if (low_value != NULL_TREE) - value1 = check_case_value (low_value); - if (high_value != NULL_TREE) - value2 = check_case_value (high_value); - - label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + tree stmt; - if (pedantic && (high_value != NULL_TREE)) - pedwarn ("ISO C forbids case ranges"); - - if (value1 != error_mark_node && value2 != error_mark_node) + /* Create the COMPOUND_STMT. */ + stmt = add_stmt (build_stmt (COMPOUND_STMT, NULL_TREE)); + /* If we haven't already declared __FUNCTION__ and its ilk then this + is the opening curly brace of the function. Declare them now. */ + if (!c_function_name_declared_p) { - tree duplicate; - int success; - - if (high_value == NULL_TREE && value1 != NULL_TREE && - pedantic && ! INTEGRAL_TYPE_P (TREE_TYPE (value1))) - pedwarn ("label must have integral type in ISO C"); - - if (low_value == NULL_TREE) - success = pushcase (NULL_TREE, 0, label, &duplicate); - else if (high_value == NULL_TREE) - success = pushcase (value1, convert_and_check, label, &duplicate); - else - success = pushcase_range (value1, value2, convert_and_check, - label, &duplicate); - - if (success == 1) - { - if (low_value == NULL_TREE) - error ("default label not within a switch statement"); - else - error ("case label not within a switch statement"); - } - else if (success == 2) - { - if (low_value == NULL_TREE) - { - error ("multiple default labels in one switch"); - error_with_decl (duplicate, "this is the first default label"); - } - else - error ("duplicate case value"); - if (high_value != NULL_TREE) - error_with_decl (duplicate, - "this is the first entry for that value"); - } - else if (low_value != NULL_TREE) - { - if (success == 3) - warning ("case value out of range"); - else if (success == 5) - error ("case label within scope of cleanup or variable array"); - } + c_function_name_declared_p = 1; + declare_function_name (); } + + return stmt; } -/* Accessor to set the 'current_function_name_declared' flag. */ +/* Expand T (a DECL_STMT) if it declares an entity not handled by the + common code. */ void -set_current_function_name_declared (i) - int i ATTRIBUTE_UNUSED; -{ - abort (); -} - -/* Dummy function in place of callback used by C++. */ -void -extract_interface_info () +c_expand_decl_stmt (t) + tree t; { + tree decl = DECL_STMT_DECL (t); + + /* Expand nested functions. */ + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_CONTEXT (decl) == current_function_decl + && DECL_SAVED_TREE (decl)) + c_expand_body (decl, /*nested_p=*/1); } diff --git a/gcc/c-lang.c b/gcc/c-lang.c index f8dd30b..21b8f0f 100644 --- a/gcc/c-lang.c +++ b/gcc/c-lang.c @@ -25,13 +25,15 @@ Boston, MA 02111-1307, USA. */ #include "tree.h" #include "function.h" #include "input.h" -#include "c-tree.h" -#include "c-lex.h" #include "toplev.h" #include "diagnostic.h" #include "output.h" #include "flags.h" #include "ggc.h" +#include "rtl.h" +#include "expr.h" +#include "c-tree.h" +#include "c-lex.h" static int c_tree_printer PARAMS ((output_buffer *)); @@ -88,8 +90,10 @@ lang_init () save_lang_status = &push_c_function_context; restore_lang_status = &pop_c_function_context; mark_lang_status = &mark_c_function_context; - - lang_printer = c_tree_printer; + lang_expand_expr = &c_expand_expr; + lang_safe_from_p = &c_safe_from_p; + lang_printer = &c_tree_printer; + lang_expand_decl_stmt = &c_expand_decl_stmt; c_parse_init (); } diff --git a/gcc/c-lex.c b/gcc/c-lex.c index f9c5cb4..f853fd0 100644 --- a/gcc/c-lex.c +++ b/gcc/c-lex.c @@ -23,6 +23,7 @@ Boston, MA 02111-1307, USA. */ #include "system.h" #include "rtl.h" +#include "expr.h" #include "tree.h" #include "input.h" #include "output.h" diff --git a/gcc/c-parse.in b/gcc/c-parse.in index 7f0fbd5..c590f31 100644 --- a/gcc/c-parse.in +++ b/gcc/c-parse.in @@ -173,7 +173,8 @@ end ifc %type <ttype> maybe_attribute attributes attribute attribute_list attrib %type <ttype> any_word extension -%type <ttype> compstmt compstmt_nostart compstmt_primary_start +%type <ttype> compstmt compstmt_start compstmt_nostart compstmt_primary_start +%type <ttype> do_stmt_start poplevel %type <ttype> declarator %type <ttype> notype_declarator after_type_declarator @@ -661,33 +662,26 @@ primary: | '(' error ')' { $$ = error_mark_node; } | compstmt_primary_start compstmt_nostart ')' - { tree rtl_exp; - if (pedantic) - pedwarn ("ISO C forbids braced-groups within expressions"); + { tree saved_last_tree; + + if (pedantic) + pedwarn ("ISO C forbids braced-groups within expressions"); pop_label_level (); - rtl_exp = expand_end_stmt_expr ($1); - /* The statements have side effects, so the group does. */ - TREE_SIDE_EFFECTS (rtl_exp) = 1; - if (TREE_CODE ($2) == BLOCK) - { - /* Make a BIND_EXPR for the BLOCK already made. */ - $$ = build (BIND_EXPR, TREE_TYPE (rtl_exp), - NULL_TREE, rtl_exp, $2); - /* Remove the block from the tree at this point. - It gets put back at the proper place - when the BIND_EXPR is expanded. */ - delete_block ($2); - } - else - $$ = $2; + saved_last_tree = COMPOUND_BODY ($1); + RECHAIN_STMTS ($1, COMPOUND_BODY ($1)); + last_tree = saved_last_tree; + TREE_CHAIN (last_tree) = NULL_TREE; + if (!last_expr_type) + last_expr_type = void_type_node; + $$ = build1 (STMT_EXPR, last_expr_type, $1); + TREE_SIDE_EFFECTS ($$) = 1; } | compstmt_primary_start error ')' { - /* Make sure we call expand_end_stmt_expr. Otherwise - we are likely to lose sequences and crash later. */ pop_label_level (); - expand_end_stmt_expr ($1); + last_tree = COMPOUND_BODY ($1); + TREE_CHAIN (last_tree) = NULL_TREE; $$ = error_mark_node; } | primary '(' exprlist ')' %prec '.' @@ -1196,8 +1190,10 @@ nested_function: There followed a repeated execution of that same rule, which called YYERROR1 again, and so on. */ compstmt - { finish_function (1); - pop_function_context (); } + { tree decl = current_function_decl; + finish_function (1); + pop_function_context (); + add_decl_stmt (decl); } ; notype_nested_function: @@ -1222,8 +1218,10 @@ notype_nested_function: There followed a repeated execution of that same rule, which called YYERROR1 again, and so on. */ compstmt - { finish_function (1); - pop_function_context (); } + { tree decl = current_function_decl; + finish_function (1); + pop_function_context (); + add_decl_stmt (decl); } ; /* Any kind of declarator (thus, all declarators allowed @@ -1604,10 +1602,9 @@ errstmt: error ';' ; pushlevel: /* empty */ - { emit_line_note (input_filename, lineno); - pushlevel (0); + { pushlevel (0); clear_last_expr (); - expand_start_bindings (0); + add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0); ifobjc if (objc_method_context) add_objc_decls (); @@ -1615,6 +1612,9 @@ end ifobjc } ; +poplevel: /* empty */ + { $$ = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0); } + /* Read zero or more forward-declarations for labels that nested functions can jump to. */ maybe_label_decls: @@ -1636,7 +1636,7 @@ label_decl: { tree label = shadow_label (TREE_VALUE (link)); C_DECLARED_LABEL_FLAG (label) = 1; - declare_nonlocal_label (label); + add_decl_stmt (label); } } ; @@ -1649,22 +1649,26 @@ compstmt_or_error: | error compstmt ; -compstmt_start: '{' { compstmt_count++; } +compstmt_start: '{' { compstmt_count++; + $$ = c_begin_compound_stmt (); } compstmt_nostart: '}' { $$ = convert (void_type_node, integer_zero_node); } - | pushlevel maybe_label_decls decls xstmts '}' - { emit_line_note (input_filename, lineno); - expand_end_bindings (getdecls (), 1, 0); - $$ = poplevel (1, 1, 0); } - | pushlevel maybe_label_decls error '}' - { emit_line_note (input_filename, lineno); - expand_end_bindings (getdecls (), kept_level_p (), 0); - $$ = poplevel (kept_level_p (), 0, 0); } - | pushlevel maybe_label_decls stmts '}' - { emit_line_note (input_filename, lineno); - expand_end_bindings (getdecls (), kept_level_p (), 0); - $$ = poplevel (kept_level_p (), 0, 0); } + | pushlevel maybe_label_decls decls xstmts '}' poplevel + { $$ = poplevel (1, 1, 0); + SCOPE_STMT_BLOCK (TREE_PURPOSE ($6)) + = SCOPE_STMT_BLOCK (TREE_VALUE ($6)) + = $$; } + | pushlevel maybe_label_decls error '}' poplevel + { $$ = poplevel (kept_level_p (), 0, 0); + SCOPE_STMT_BLOCK (TREE_PURPOSE ($5)) + = SCOPE_STMT_BLOCK (TREE_VALUE ($5)) + = $$; } + | pushlevel maybe_label_decls stmts '}' poplevel + { $$ = poplevel (kept_level_p (), 0, 0); + SCOPE_STMT_BLOCK (TREE_PURPOSE ($5)) + = SCOPE_STMT_BLOCK (TREE_VALUE ($5)) + = $$; } ; compstmt_primary_start: @@ -1680,17 +1684,19 @@ compstmt_primary_start: that are contained in it. */ keep_next_level (); push_label_level (); - $$ = expand_start_stmt_expr (); compstmt_count++; + $$ = add_stmt (build_stmt (COMPOUND_STMT, last_tree)); } compstmt: compstmt_start compstmt_nostart - { $$ = $2; } + { RECHAIN_STMTS ($1, COMPOUND_BODY ($1)); + $$ = $2; } ; /* Value is number of statements counted as of the closeparen. */ simple_if: if_prefix lineno_labeled_stmt + { c_finish_then (); } /* Make sure c_expand_end_cond is run once for each call to c_expand_start_cond. Otherwise a crash is likely. */ @@ -1699,8 +1705,7 @@ simple_if: if_prefix: IF '(' expr ')' - { emit_line_note ($<filename>-1, $<lineno>0); - c_expand_start_cond (truthvalue_conversion ($3), 0, + { c_expand_start_cond (truthvalue_conversion ($3), compstmt_count); $<itype>$ = stmt_count; if_stmt_file = $<filename>-1; @@ -1714,12 +1719,17 @@ do_stmt_start: DO { stmt_count++; compstmt_count++; - emit_line_note ($<filename>-1, $<lineno>0); - /* See comment in `while' alternative, above. */ - emit_nop (); - expand_start_loop_continue_elsewhere (1); } + $<ttype>$ + = 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 ($<ttype>$) = error_mark_node; } lineno_labeled_stmt WHILE - { expand_loop_continue_here (); } + { $$ = $<ttype>2; + RECHAIN_STMTS ($$, DO_BODY ($$)); } ; /* The forced readahead in here is because we might be at the end of a @@ -1765,25 +1775,13 @@ stmt: { stmt_count++; } | expr ';' { stmt_count++; - emit_line_note ($<filename>-1, $<lineno>0); -/* It appears that this should not be done--that a non-lvalue array - shouldn't get an error if the value isn't used. - Section 3.2.2.1 says that an array lvalue gets converted to a pointer - if it appears as a top-level expression, - but says nothing about non-lvalue arrays. */ -#if 0 - /* Call default_conversion to get an error - on referring to a register array if pedantic. */ - if (TREE_CODE (TREE_TYPE ($1)) == ARRAY_TYPE - || TREE_CODE (TREE_TYPE ($1)) == FUNCTION_TYPE) - $1 = default_conversion ($1); -#endif - expand_expr_stmt ($1); } + c_expand_expr_stmt ($1); } | simple_if ELSE { c_expand_start_else (); $<itype>1 = stmt_count; } lineno_labeled_stmt - { c_expand_end_cond (); + { c_finish_else (); + c_expand_end_cond (); if (extra_warnings && stmt_count == $<itype>1) warning ("empty body in an else-statement"); } | simple_if %prec IF @@ -1801,83 +1799,43 @@ stmt: | simple_if ELSE error { c_expand_end_cond (); } | WHILE - { stmt_count++; - emit_line_note ($<filename>-1, $<lineno>0); - /* The emit_nop used to come before emit_line_note, - but that made the nop seem like part of the preceding line. - And that was confusing when the preceding line was - inside of an if statement and was not really executed. - I think it ought to work to put the nop after the line number. - We will see. --rms, July 15, 1991. */ - emit_nop (); } + { stmt_count++; } '(' expr ')' - { /* Don't start the loop till we have succeeded - in parsing the end test. This is to make sure - that we end every loop we start. */ - expand_start_loop (1); - emit_line_note (input_filename, lineno); - expand_exit_loop_if_false (NULL_PTR, - truthvalue_conversion ($4)); } + { $4 = truthvalue_conversion ($4); + $<ttype>$ + = add_stmt (build_stmt (WHILE_STMT, $4, NULL_TREE)); } lineno_labeled_stmt - { expand_end_loop (); } + { RECHAIN_STMTS ($<ttype>6, WHILE_BODY ($<ttype>6)); } | do_stmt_start '(' expr ')' ';' - { emit_line_note (input_filename, lineno); - expand_exit_loop_if_false (NULL_PTR, - truthvalue_conversion ($3)); - expand_end_loop (); } -/* This rule is needed to make sure we end every loop we start. */ + { DO_COND ($1) = truthvalue_conversion ($3); } | do_stmt_start error - { expand_end_loop (); } + { } | FOR '(' xexpr ';' { stmt_count++; - emit_line_note ($<filename>-1, $<lineno>0); - /* See comment in `while' alternative, above. */ - emit_nop (); - if ($3) c_expand_expr_stmt ($3); - /* Next step is to call expand_start_loop_continue_elsewhere, - but wait till after we parse the entire for (...). - Otherwise, invalid input might cause us to call that - fn without calling expand_end_loop. */ + $3 = build_stmt (EXPR_STMT, $3); + $<ttype>$ = build_stmt (FOR_STMT, $3, NULL_TREE, + NULL_TREE, NULL_TREE); + add_stmt ($<ttype>$); } xexpr ';' - /* Can't emit now; wait till after expand_start_loop... */ - { $<lineno>7 = lineno; - $<filename>$ = input_filename; } + { FOR_COND ($<ttype>5) = $6; } xexpr ')' - { - /* Start the loop. Doing this after parsing - all the expressions ensures we will end the loop. */ - expand_start_loop_continue_elsewhere (1); - /* Emit the end-test, with a line number. */ - emit_line_note ($<filename>8, $<lineno>7); - if ($6) - expand_exit_loop_if_false (NULL_PTR, - truthvalue_conversion ($6)); - $<lineno>7 = lineno; - $<filename>8 = input_filename; } + { FOR_EXPR ($<ttype>5) = $9; } lineno_labeled_stmt - { /* Emit the increment expression, with a line number. */ - emit_line_note ($<filename>8, $<lineno>7); - expand_loop_continue_here (); - if ($9) - c_expand_expr_stmt ($9); - expand_end_loop (); } + { RECHAIN_STMTS ($<ttype>5, FOR_BODY ($<ttype>5)); } | SWITCH '(' expr ')' { stmt_count++; - emit_line_note ($<filename>-1, $<lineno>0); - c_expand_start_case ($3); } + $<ttype>$ = c_start_case ($3); } lineno_labeled_stmt - { expand_end_case ($3); } + { c_finish_case (); } | BREAK ';' - { build_break_stmt (); - stmt_count++; - genrtl_break_stmt (); } + { stmt_count++; + add_stmt (build_break_stmt ()); } | CONTINUE ';' - { build_continue_stmt (); - stmt_count++; - genrtl_continue_stmt (); } + { stmt_count++; + add_stmt (build_continue_stmt ()); } | RETURN ';' { stmt_count++; c_expand_return (NULL_TREE); } @@ -1886,25 +1844,29 @@ stmt: c_expand_return ($2); } | ASM_KEYWORD maybe_type_qual '(' expr ')' ';' { stmt_count++; - emit_line_note ($<filename>-1, $<lineno>0); STRIP_NOPS ($4); if ((TREE_CODE ($4) == ADDR_EXPR && TREE_CODE (TREE_OPERAND ($4, 0)) == STRING_CST) || TREE_CODE ($4) == STRING_CST) - expand_asm ($4); + { + if (TREE_CODE ($4) == ADDR_EXPR) + $4 = TREE_OPERAND ($4, 0); + if (TREE_CHAIN ($4)) + $4 = combine_strings ($4); + add_stmt (build_stmt (ASM_STMT, NULL_TREE, $4, + NULL_TREE, NULL_TREE, NULL_TREE)); + } else error ("argument of `asm' is not a constant string"); } /* This is the case with just output operands. */ | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ')' ';' { stmt_count++; - emit_line_note ($<filename>-1, $<lineno>0); c_expand_asm_operands ($4, $6, NULL_TREE, NULL_TREE, $2 == ridpointers[(int)RID_VOLATILE], input_filename, lineno); } /* This is the case with input operands as well. */ | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ':' asm_operands ')' ';' { stmt_count++; - emit_line_note ($<filename>-1, $<lineno>0); c_expand_asm_operands ($4, $6, $8, NULL_TREE, $2 == ridpointers[(int)RID_VOLATILE], input_filename, lineno); } @@ -1912,27 +1874,25 @@ stmt: | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ':' asm_operands ':' asm_clobbers ')' ';' { stmt_count++; - emit_line_note ($<filename>-1, $<lineno>0); c_expand_asm_operands ($4, $6, $8, $10, $2 == ridpointers[(int)RID_VOLATILE], input_filename, lineno); } | GOTO identifier ';' { tree decl; stmt_count++; - emit_line_note ($<filename>-1, $<lineno>0); decl = lookup_label ($2); if (decl != 0) { TREE_USED (decl) = 1; - expand_goto (decl); + add_stmt (build_stmt (GOTO_STMT, decl)); } } | GOTO '*' expr ';' { if (pedantic) pedwarn ("ISO C forbids `goto *expr;'"); stmt_count++; - emit_line_note ($<filename>-1, $<lineno>0); - expand_computed_goto (convert (ptr_type_node, $3)); } + $3 = convert (ptr_type_node, $3); + add_stmt (build_stmt (GOTO_STMT, $3)); } | ';' ; @@ -1952,11 +1912,10 @@ label: CASE expr_no_commas ':' | identifier save_filename save_lineno ':' maybe_attribute { tree label = define_label ($2, $3, $1); stmt_count++; - emit_nop (); if (label) { - expand_label (label); decl_attributes (label, $5, NULL_TREE); + add_stmt (build_stmt (LABEL_STMT, label)); } } ; diff --git a/gcc/c-semantics.c b/gcc/c-semantics.c index f1b54c4..b349bd3 100644 --- a/gcc/c-semantics.c +++ b/gcc/c-semantics.c @@ -40,6 +40,13 @@ Boston, MA 02111-1307, USA. */ expanding statements. */ void (*lang_expand_stmt) PARAMS ((tree)); +/* If non-NULL, the address of a language-specific function for + expanding a DECL_STMT. After the language-independent cases are + handled, this function will be called. If this function is not + defined, it is assumed that declarations other than those for + variables and labels do not require any RTL generation. */ +void (*lang_expand_decl_stmt) PARAMS ((tree)); + static tree prune_unused_decls PARAMS ((tree *, int *, void *)); /* Create an empty statement tree rooted at T. */ @@ -71,6 +78,63 @@ add_stmt (t) return t; } +/* Create a declaration statement for the declaration given by the + DECL. */ + +void +add_decl_stmt (decl) + tree decl; +{ + tree decl_stmt; + + /* We need the type to last until instantiation time. */ + decl_stmt = build_stmt (DECL_STMT, decl); + add_stmt (decl_stmt); +} + +/* Add a scope-statement to the statement-tree. BEGIN_P indicates + whether this statements opens or closes a scope. PARTIAL_P is true + for a partial scope, i.e, the scope that begins after a label when + an object that needs a cleanup is created. If BEGIN_P is nonzero, + returns a new TREE_LIST representing the top of the SCOPE_STMT + stack. The TREE_PURPOSE is the new SCOPE_STMT. If BEGIN_P is + zero, returns a TREE_LIST whose TREE_VALUE is the new SCOPE_STMT, + and whose TREE_PURPOSE is the matching SCOPE_STMT iwth + SCOPE_BEGIN_P set. */ + +tree +add_scope_stmt (begin_p, partial_p) + int begin_p; + int partial_p; +{ + tree ss; + tree top; + + /* Build the statement. */ + ss = build_stmt (SCOPE_STMT, NULL_TREE); + SCOPE_BEGIN_P (ss) = begin_p; + SCOPE_PARTIAL_P (ss) = partial_p; + + /* Keep the scope stack up to date. */ + if (begin_p) + { + *current_scope_stmt_stack () + = tree_cons (ss, NULL_TREE, *current_scope_stmt_stack ()); + top = *current_scope_stmt_stack (); + } + else + { + top = *current_scope_stmt_stack (); + TREE_VALUE (top) = ss; + *current_scope_stmt_stack () = TREE_CHAIN (top); + } + + /* Add the new statement to the statement-tree. */ + add_stmt (ss); + + return top; +} + /* Remove declarations of internal variables that are not used from a stmt tree. To qualify, the variable must have a name and must have a zero DECL_SOURCE_LINE. We tried to remove all variables for @@ -145,7 +209,7 @@ finish_stmt_tree (t) /* Remove unused decls from the stmt tree. */ walk_stmt_tree (t, prune_unused_decls, NULL); - if (cfun) + if (cfun && stmt) { /* The line-number recorded in the outermost statement in a function is the line number of the end of the function. */ @@ -305,7 +369,8 @@ genrtl_expr_stmt (expr) if (stmts_are_full_exprs_p ()) expand_start_target_temps (); - lang_expand_expr_stmt (expr); + if (expr != error_mark_node) + expand_expr_stmt (expr); if (stmts_are_full_exprs_p ()) expand_end_target_temps (); @@ -348,6 +413,11 @@ genrtl_decl_stmt (t) else make_rtl_for_local_static (decl); } + else if (TREE_CODE (decl) == LABEL_DECL + && C_DECLARED_LABEL_FLAG (decl)) + declare_nonlocal_label (decl); + else if (lang_expand_decl_stmt) + (*lang_expand_decl_stmt) (t); } /* Generate the RTL for T, which is an IF_STMT. */ @@ -448,30 +518,43 @@ void genrtl_for_stmt (t) tree t; { - tree tmp; tree cond; + const char *saved_filename; + int saved_lineno; + if (NEW_FOR_SCOPE_P (t)) genrtl_do_pushlevel (); expand_stmt (FOR_INIT_STMT (t)); + /* Expand the initialization. */ emit_nop (); emit_line_note (input_filename, lineno); expand_start_loop_continue_elsewhere (1); genrtl_do_pushlevel (); cond = expand_cond (FOR_COND (t)); + + /* Save the filename and line number so that we expand the FOR_EXPR + we can reset them back to the saved values. */ + saved_filename = input_filename; + saved_lineno = lineno; + + /* Expand the condition. */ emit_line_note (input_filename, lineno); if (cond) expand_exit_loop_if_false (0, cond); - genrtl_do_pushlevel (); - tmp = FOR_EXPR (t); + /* Expand the body. */ + genrtl_do_pushlevel (); expand_stmt (FOR_BODY (t)); + /* Expand the increment expression. */ + input_filename = saved_filename; + lineno = saved_lineno; emit_line_note (input_filename, lineno); expand_loop_continue_here (); - if (tmp) - genrtl_expr_stmt (tmp); + if (FOR_EXPR (t)) + genrtl_expr_stmt (FOR_EXPR (t)); expand_end_loop (); } @@ -575,6 +658,22 @@ genrtl_case_label (case_label) tree case_label; { tree duplicate; + tree cleanup; + + cleanup = last_cleanup_this_contour (); + if (cleanup) + { + static int explained = 0; + warning_with_decl (TREE_PURPOSE (cleanup), + "destructor needed for `%#D'"); + warning ("where case label appears here"); + if (!explained) + { + warning ("(enclose actions of previous case statements requiring destructors in their own scope.)"); + explained = 1; + } + } + add_case_node (CASE_LOW (case_label), CASE_HIGH (case_label), CASE_LABEL_DECL (case_label), &duplicate); } @@ -585,16 +684,6 @@ void genrtl_compound_stmt (t) tree t; { - /* If this is the outermost block of the function, declare the - variables __FUNCTION__, __PRETTY_FUNCTION__, and so forth. */ - if (cfun - && !current_function_name_declared () - && !COMPOUND_STMT_NO_SCOPE (t)) - { - set_current_function_name_declared (1); - declare_function_name (); - } - expand_stmt (COMPOUND_BODY (t)); } @@ -609,9 +698,6 @@ genrtl_asm_stmt (cv_qualifier, string, output_operands, tree input_operands; tree clobbers; { - if (TREE_CHAIN (string)) - string = combine_strings (string); - if (cv_qualifier != NULL_TREE && cv_qualifier != ridpointers[(int) RID_VOLATILE]) { @@ -733,6 +819,10 @@ expand_stmt (t) ASM_OUTPUTS (t), ASM_INPUTS (t), ASM_CLOBBERS (t)); break; + case SCOPE_STMT: + genrtl_scope_stmt (t); + break; + default: if (lang_expand_stmt) (*lang_expand_stmt) (t); diff --git a/gcc/c-tree.h b/gcc/c-tree.h index 92f0b45..5531731 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -42,6 +42,14 @@ struct lang_identifier enum rid rid_code; }; +/* Wrapping c_lang_decl in another struct is an unfortunate + necessity. */ + +struct lang_decl +{ + struct c_lang_decl base; +}; + /* Macros for access to language-specific slots in an identifier. */ /* Each of these slots contains a DECL node or null. */ @@ -103,10 +111,6 @@ struct lang_type tree elts[1]; }; -/* Mark which labels are explicitly declared. - These may be shadowed, and may be referenced from nested functions. */ -#define C_DECLARED_LABEL_FLAG(label) TREE_LANG_FLAG_1 (label) - /* Record whether a type or decl was written with nonconstant size. Note that TYPE_SIZE may have simplified to a constant. */ #define C_TYPE_VARIABLE_SIZE(type) TYPE_LANG_FLAG_1 (type) @@ -230,6 +234,8 @@ extern tree start_decl PARAMS ((tree, tree, int, extern tree start_struct PARAMS ((enum tree_code, tree)); extern void store_parm_decls PARAMS ((void)); extern tree xref_tag PARAMS ((enum tree_code, tree)); +extern tree c_begin_compound_stmt PARAMS ((void)); +extern void c_expand_decl_stmt PARAMS ((tree)); /* in c-typeck.c */ extern tree require_complete_type PARAMS ((tree)); @@ -268,7 +274,8 @@ extern void set_init_label PARAMS ((tree)); extern void process_init_element PARAMS ((tree)); extern void pedwarn_c99 PARAMS ((const char *, ...)) ATTRIBUTE_PRINTF_1; -extern tree c_expand_start_case PARAMS ((tree)); +extern tree c_start_case PARAMS ((tree)); +extern void c_finish_case PARAMS ((void)); /* Set to 0 at beginning of a function definition, set to 1 if a return statement that specifies a return value is seen. */ diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 002d4e7..f4b42b9 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -4999,7 +4999,8 @@ start_init (decl, asmspec_tree, top_level) || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE || TREE_CODE (TREE_TYPE (decl)) == QUAL_UNION_TYPE)); locus = IDENTIFIER_POINTER (DECL_NAME (decl)); - constructor_incremental |= TREE_STATIC (decl); + constructor_incremental + |= (TREE_STATIC (decl) && !DECL_CONTEXT (decl)); } else { @@ -6541,7 +6542,7 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line) if (TREE_CODE (string) == ADDR_EXPR) string = TREE_OPERAND (string, 0); - if (TREE_CODE (string) != STRING_CST) + if (last_tree && TREE_CODE (string) != STRING_CST) { error ("asm template is not a string constant"); return; @@ -6567,7 +6568,8 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line) || TREE_CODE (output) == FIX_CEIL_EXPR) output = TREE_OPERAND (output, 0); - lvalue_or_else (o[i], "invalid lvalue in asm statement"); + if (last_tree) + lvalue_or_else (o[i], "invalid lvalue in asm statement"); } /* Perform default conversions on array and function inputs. */ @@ -6578,6 +6580,14 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line) || TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == FUNCTION_TYPE) TREE_VALUE (tail) = default_conversion (TREE_VALUE (tail)); + if (last_tree) + { + add_stmt (build_stmt (ASM_STMT, + vol ? ridpointers[(int) RID_VOLATILE] : NULL_TREE, + string, outputs, inputs, clobbers)); + return; + } + /* Generate the ASM_OPERANDS insn; store into the TREE_VALUEs of OUTPUTS some trees for where the values were actually stored. */ @@ -6703,53 +6713,115 @@ c_expand_return (retval) current_function_returns_value = 1; } - genrtl_return_stmt (build_return_stmt (retval)); + add_stmt (build_return_stmt (retval)); } -/* Start a C switch statement, testing expression EXP. - Return EXP if it is valid, an error node otherwise. */ +struct c_switch { + /* The SWITCH_STMT being built. */ + tree switch_stmt; + /* A splay-tree mapping the low element of a case range to the high + element, or NULL_TREE if there is no high element. Used to + determine whether or not a new case label duplicates an old case + label. We need a tree, rather than simply a hash table, because + of the GNU case range extension. */ + splay_tree cases; + /* The next node on the stack. */ + struct c_switch *next; +}; + +/* A stack of the currently active switch statements. The innermost + switch statement is on the top of the stack. There is no need to + mark the stack for garbage collection because it is only active + during the processing of the body of a function, and we never + collect at that point. */ + +static struct c_switch *switch_stack; + +/* Start a C switch statement, testing expression EXP. Return the new + SWITCH_STMT. */ tree -c_expand_start_case (exp) +c_start_case (exp) tree exp; { register enum tree_code code; tree type; + struct c_switch *cs; - if (TREE_CODE (exp) == ERROR_MARK) - return exp; + if (exp != error_mark_node) + { + code = TREE_CODE (TREE_TYPE (exp)); + type = TREE_TYPE (exp); - code = TREE_CODE (TREE_TYPE (exp)); - type = TREE_TYPE (exp); + if (code != INTEGER_TYPE + && code != ENUMERAL_TYPE + && code != ERROR_MARK) + { + error ("switch quantity not an integer"); + exp = integer_zero_node; + } + else + { + tree index; + type = TYPE_MAIN_VARIANT (TREE_TYPE (exp)); - if (code != INTEGER_TYPE && code != ENUMERAL_TYPE && code != ERROR_MARK) - { - error ("switch quantity not an integer"); - exp = error_mark_node; + if (warn_traditional && !in_system_header + && (type == long_integer_type_node + || type == long_unsigned_type_node)) + warning ("`long' switch expression not converted to `int' in ISO C"); + + exp = default_conversion (exp); + type = TREE_TYPE (exp); + index = get_unwidened (exp, NULL_TREE); + /* We can't strip a conversion from a signed type to an + unsigned, because if we did, int_fits_type_p would do the + wrong thing when checking case values for being in range, + and it's too hard to do the right thing. */ + if (TREE_UNSIGNED (TREE_TYPE (exp)) + == TREE_UNSIGNED (TREE_TYPE (index))) + exp = index; + } } + + /* Add this new SWITCH_STMT to the stack. */ + cs = (struct c_switch *) xmalloc (sizeof (cs)); + cs->switch_stmt = build_stmt (SWITCH_STMT, exp, NULL_TREE, NULL_TREE); + cs->cases = splay_tree_new (case_compare, NULL, NULL); + cs->next = switch_stack; + switch_stack = cs; + + return add_stmt (switch_stack->switch_stmt); +} + +/* Process a case label. */ + +void +do_case (low_value, high_value) + tree low_value; + tree high_value; +{ + if (switch_stack) + c_add_case_label (switch_stack->cases, + SWITCH_COND (switch_stack->switch_stmt), + low_value, + high_value); + else if (low_value) + error ("case label not within a switch statement"); else - { - tree index; - type = TYPE_MAIN_VARIANT (TREE_TYPE (exp)); + error ("`default' label not within a switch statement"); +} - if (warn_traditional && !in_system_header - && (type == long_integer_type_node - || type == long_unsigned_type_node)) - warning ("`long' switch expression not converted to `int' in ISO C"); +/* Finish the switch statement. */ - exp = default_conversion (exp); - type = TREE_TYPE (exp); - index = get_unwidened (exp, NULL_TREE); - /* We can't strip a conversion from a signed type to an unsigned, - because if we did, int_fits_type_p would do the wrong thing - when checking case values for being in range, - and it's too hard to do the right thing. */ - if (TREE_UNSIGNED (TREE_TYPE (exp)) - == TREE_UNSIGNED (TREE_TYPE (index))) - exp = index; - } +void +c_finish_case () +{ + struct c_switch *cs = switch_stack; - expand_start_case (1, exp, type, "switch statement"); + RECHAIN_STMTS (cs->switch_stmt, SWITCH_BODY (cs->switch_stmt)); - return exp; + /* Pop the stack. */ + switch_stack = switch_stack->next; + splay_tree_delete (cs->cases); + free (cs); } diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f54d9b3..66e3975 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,54 @@ +2000-09-16 Mark Mitchell <mark@codesourcery.com> + + * 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. + 2000-09-14 Joseph S. Myers <jsm28@cam.ac.uk> * lex.c (reswords): Add _Complex. diff --git a/gcc/cp/Makefile.in b/gcc/cp/Makefile.in index 839e574..b81c4f0 100644 --- a/gcc/cp/Makefile.in +++ b/gcc/cp/Makefile.in @@ -265,7 +265,7 @@ class.o : class.c $(CXX_TREE_H) $(srcdir)/../flags.h \ call.o : call.c $(CXX_TREE_H) $(srcdir)/../flags.h \ $(srcdir)/../toplev.h $(RTL_H) $(EXPR_H) $(GGC_H) friend.o : friend.c $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \ - $(srcdir)/../toplev.h + $(srcdir)/../toplev.h $(EXPR_H) init.o : init.c $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \ $(EXPR_H) $(srcdir)/../toplev.h $(GGC_H) \ $(srcdir)/../except.h diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index de76e52..b7bc919 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -878,7 +878,6 @@ struct cp_language_function tree x_current_class_ptr; tree x_current_class_ref; tree x_eh_spec_try_block; - tree x_scope_stmt_stack; tree x_in_charge_parm; tree *x_vcalls_possible_p; @@ -889,7 +888,6 @@ struct cp_language_function int returns_null; int in_function_try_handler; int x_expanding_p; - int name_declared; int vtbls_set_up_p; struct named_label_use_list *x_named_label_uses; @@ -928,10 +926,6 @@ struct cp_language_function #define current_eh_spec_try_block cp_function_chain->x_eh_spec_try_block -/* The stack of SCOPE_STMTs for the current function. */ - -#define current_scope_stmt_stack cp_function_chain->x_scope_stmt_stack - /* The `__in_chrg' parameter for the current function. Only used for destructors. */ @@ -978,6 +972,12 @@ struct cp_language_function #define in_function_try_handler cp_function_chain->in_function_try_handler +/* Nonzero if __FUNCTION__ and its ilk have been declared in this + function. */ + +#define function_name_declared_p \ + (cp_function_chain->base.x_function_name_declared_p) + extern tree current_function_return_value; extern tree global_namespace; @@ -1811,6 +1811,8 @@ struct lang_type struct lang_decl_flags { + struct c_lang_decl base; + ENUM_BITFIELD(languages) language : 8; unsigned operator_attr : 1; @@ -1839,8 +1841,6 @@ struct lang_decl_flags unsigned generate_with_vtable_p : 1; unsigned dummy : 1; - tree context; - union { /* In a FUNCTION_DECL, VAR_DECL, TYPE_DECL, or TEMPLATE_DECL, this is DECL_TEMPLATE_INFO. */ @@ -1872,8 +1872,9 @@ struct lang_decl tree befriending_classes; - /* In a FUNCTION_DECL, this is DECL_SAVED_TREE. */ - tree saved_tree; + /* For a virtual FUNCTION_DECL, this is DECL_VIRTUAL_CONTEXT. For a + non-virtual FUNCTION_DECL, this is DECL_FRIEND_CONTEXT. */ + tree context; /* In a FUNCTION_DECL, this is DECL_CLONED_FUNCTION. */ tree cloned_function; @@ -2168,12 +2169,12 @@ struct lang_decl the DECL_FRIEND_CONTEXT for `f' will be `S'. */ #define DECL_FRIEND_CONTEXT(NODE) \ ((DECL_FRIEND_P (NODE) && !DECL_FUNCTION_MEMBER_P (NODE)) \ - ? DECL_LANG_SPECIFIC (NODE)->decl_flags.context \ + ? DECL_LANG_SPECIFIC (NODE)->context \ : NULL_TREE) /* Set the DECL_FRIEND_CONTEXT for NODE to CONTEXT. */ #define SET_DECL_FRIEND_CONTEXT(NODE, CONTEXT) \ - (DECL_LANG_SPECIFIC (NODE)->decl_flags.context = (CONTEXT)) + (DECL_LANG_SPECIFIC (NODE)->context = (CONTEXT)) /* NULL_TREE in DECL_CONTEXT represents the global namespace. */ #define CP_DECL_CONTEXT(NODE) \ @@ -2183,7 +2184,7 @@ struct lang_decl /* For a virtual function, the base where we find its vtable entry. For a non-virtual function, the base where it is defined. */ #define DECL_VIRTUAL_CONTEXT(NODE) \ - (DECL_LANG_SPECIFIC (NODE)->decl_flags.context) + (DECL_LANG_SPECIFIC (NODE)->context) /* 1 iff NODE has namespace scope, including the global namespace. */ #define DECL_NAMESPACE_SCOPE_P(NODE) \ @@ -2409,12 +2410,6 @@ struct lang_decl the class definition is complete. */ #define TEMPLATE_PARMS_FOR_INLINE(NODE) TREE_LANG_FLAG_1 (NODE) -/* In a FUNCTION_DECL, the saved representation of the body of the - entire function. Usually a COMPOUND_STMT, but this may also be a - RETURN_INIT, CTOR_INITIALIZER, or TRY_BLOCK. */ -#define DECL_SAVED_TREE(NODE) \ - (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (NODE))->saved_tree) - /* In a FUNCTION_DECL, the saved language-specific per-function data. */ #define DECL_SAVED_FUNCTION_DATA(NODE) \ (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (NODE))->u.saved_language_function) @@ -2532,10 +2527,6 @@ extern int flag_new_for_scope; #define ARITHMETIC_TYPE_P(TYPE) \ (CP_INTEGRAL_TYPE_P (TYPE) || TREE_CODE (TYPE) == REAL_TYPE) -/* Mark which labels are explicitly declared. - These may be shadowed, and may be referenced from nested functions. */ -#define C_DECLARED_LABEL_FLAG(label) TREE_LANG_FLAG_1 (label) - /* Nonzero for _TYPE means that the _TYPE defines at least one constructor. */ #define TYPE_HAS_CONSTRUCTOR(NODE) (TYPE_LANG_FLAG_1(NODE)) @@ -3904,7 +3895,6 @@ extern tree start_method PARAMS ((tree, tree, tree)); extern tree finish_method PARAMS ((tree)); extern void hack_incomplete_structures PARAMS ((tree)); extern tree maybe_build_cleanup PARAMS ((tree)); -extern void cplus_expand_expr_stmt PARAMS ((tree)); extern void finish_stmt PARAMS ((void)); extern void replace_defarg PARAMS ((tree, tree)); extern void print_other_binding_stack PARAMS ((struct binding_level *)); @@ -4356,12 +4346,10 @@ extern tree finish_base_specifier PARAMS ((tree, tree)); extern void finish_member_declaration PARAMS ((tree)); extern void check_multiple_declarators PARAMS ((void)); extern tree finish_typeof PARAMS ((tree)); -extern void add_decl_stmt PARAMS ((tree)); extern void finish_decl_cleanup PARAMS ((tree, tree)); extern void finish_named_return_value PARAMS ((tree, tree)); extern void expand_body PARAMS ((tree)); extern void prep_stmt PARAMS ((tree)); -extern tree add_scope_stmt PARAMS ((int, int)); extern void do_pushlevel PARAMS ((void)); extern tree do_poplevel PARAMS ((void)); extern void finish_mem_initializers PARAMS ((tree)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 4430d55..3b2a057 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -159,7 +159,6 @@ static void mark_named_label_lists PARAMS ((void *, void *)); static void mark_cp_function_context PARAMS ((struct function *)); static void mark_saved_scope PARAMS ((void *)); static void mark_lang_function PARAMS ((struct cp_language_function *)); -static void mark_stmt_tree PARAMS ((stmt_tree)); static void save_function_data PARAMS ((tree)); static void check_function_type PARAMS ((tree, tree)); static void destroy_local_var PARAMS ((tree)); @@ -176,7 +175,6 @@ static tree check_special_function_return_type PARAMS ((special_function_kind, tree, tree, tree)); static tree push_cp_library_fn PARAMS ((enum tree_code, tree)); static tree build_cp_library_fn PARAMS ((tree, enum tree_code, tree)); -static int case_compare PARAMS ((splay_tree_key, splay_tree_key)); static void store_parm_decls PARAMS ((tree)); #if defined (DEBUG_CP_BINDING_LEVELS) @@ -2411,16 +2409,6 @@ pop_nested_namespace (ns) scope isn't enough, because more binding levels may be pushed. */ struct saved_scope *scope_chain; -/* Mark ST for GC. */ - -static void -mark_stmt_tree (st) - stmt_tree st; -{ - ggc_mark_tree (st->x_last_stmt); - ggc_mark_tree (st->x_last_expr_type); -} - /* Mark ARG (which is really a struct saved_scope **) for GC. */ static void @@ -5156,21 +5144,6 @@ struct cp_switch static struct cp_switch *switch_stack; -static 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); -} - /* Called right after a switch-statement condition is parsed. SWITCH_STMT is the switch statement being parsed. */ @@ -5206,12 +5179,7 @@ finish_case_label (low_value, high_value) tree low_value; tree high_value; { - tree label; - tree cleanup; - tree type; tree cond; - tree case_label; - splay_tree_node node; if (! switch_stack) { @@ -5225,13 +5193,13 @@ finish_case_label (low_value, high_value) return; } - label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); - DECL_CONTEXT (label) = current_function_decl; - if (processing_template_decl) { + tree label; + /* For templates, just add the case label; we'll do semantic analysis at instantiation-time. */ + label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); add_stmt (build_case_label (low_value, high_value, label)); return; } @@ -5240,124 +5208,8 @@ finish_case_label (low_value, high_value) cond = SWITCH_COND (switch_stack->switch_stmt); if (cond && TREE_CODE (cond) == TREE_LIST) cond = TREE_VALUE (cond); - /* If there was an error processing the switch condition, bail now - before we get more confused. */ - if (!cond || cond == error_mark_node) - return; - type = TREE_TYPE (cond); - - 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) - pedwarn ("ISO C++ forbids range expressions in switch statement"); - - 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) - return; - - /* 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 (switch_stack->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 (switch_stack->cases, - (splay_tree_key) low_value); - high_bound = splay_tree_successor (switch_stack->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"); - cp_error_at ("this is the first entry overlapping that value", - duplicate); - } - else if (low_value) - { - cp_error ("duplicate case value `%E'", low_value) ; - cp_error_at ("previously used here", duplicate); - } - else - { - error ("multiple default labels in one switch"); - cp_error_at ("this is the first default label", duplicate); - } - return; - } - - cleanup = last_cleanup_this_contour (); - if (cleanup) - { - static int explained = 0; - cp_warning_at ("destructor needed for `%#D'", TREE_PURPOSE (cleanup)); - warning ("where case label appears here"); - if (!explained) - { - warning ("(enclose actions of previous case statements requiring destructors in their own scope.)"); - explained = 1; - } - } + c_add_case_label (switch_stack->cases, cond, low_value, high_value); check_switch_goto (switch_stack->level); @@ -5365,16 +5217,6 @@ finish_case_label (low_value, high_value) own new (temporary) binding contour. */ current_binding_level->more_cleanups_ok = 0; current_function_return_value = NULL_TREE; - - /* Add a representation for the case label to the statement - tree. */ - case_label = build_case_label (low_value, high_value, label); - add_stmt (case_label); - - /* Register this case label in the splay tree. */ - splay_tree_insert (switch_stack->cases, - (splay_tree_key) low_value, - (splay_tree_value) case_label); } /* Return the list of declarations of the current level. @@ -6462,11 +6304,11 @@ init_decl_processing () /* Create all the identifiers we need. */ initialize_predefined_identifiers (); - /* Let the back-end now how to save and restore language-specific - per-function globals. */ + /* Fill in back-end hooks. */ init_lang_status = &push_cp_function_context; free_lang_status = &pop_cp_function_context; mark_lang_status = &mark_cp_function_context; + lang_safe_from_p = &c_safe_from_p; cp_parse_init (); init_decl2 (); @@ -13557,7 +13399,7 @@ build_enumerator (name, value, enumtype) if (context && context == current_class_type) /* This enum declaration is local to the class. We need the full - lang_decl so that we can record DECL_CLASS_CONTEXT, for example. */ + lang_decl so that we can record DECL_CLASS_CONTEXT, for example. */ decl = build_lang_decl (CONST_DECL, name, type); else /* It's a global enum, or it's local to a function. (Note local to @@ -14696,31 +14538,6 @@ maybe_build_cleanup (decl) return 0; } -/* Expand a C++ expression at the statement level. - This is needed to ferret out nodes which have UNKNOWN_TYPE. - The C++ type checker should get all of these out when - expressions are combined with other, type-providing, expressions, - leaving only orphan expressions, such as: - - &class::bar; / / takes its address, but does nothing with it. */ - -void -cplus_expand_expr_stmt (exp) - tree exp; -{ -#if 0 - /* We should do this eventually, but right now this causes regex.o from - libg++ to miscompile, and tString to core dump. */ - exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp); -#endif - - /* If we don't do this, we end up down inside expand_expr - trying to do TYPE_MODE on the ERROR_MARK, and really - go outside the bounds of the type. */ - if (exp != error_mark_node) - expand_expr_stmt (exp); -} - /* When a stmt has been parsed, this function is called. */ void @@ -14801,17 +14618,17 @@ mark_lang_function (p) if (!p) return; + mark_c_language_function (&p->base); + ggc_mark_tree (p->x_ctor_label); ggc_mark_tree (p->x_dtor_label); ggc_mark_tree (p->x_current_class_ptr); ggc_mark_tree (p->x_current_class_ref); ggc_mark_tree (p->x_eh_spec_try_block); - ggc_mark_tree (p->x_scope_stmt_stack); ggc_mark_rtx (p->x_result_rtx); mark_named_label_lists (&p->x_named_labels, &p->x_named_label_uses); - mark_stmt_tree (&p->base.x_stmt_tree); mark_binding_level (&p->bindings); } @@ -14872,13 +14689,13 @@ lang_mark_tree (t) if (ld) { ggc_mark (ld); + c_mark_lang_decl (&ld->decl_flags.base); if (!DECL_GLOBAL_CTOR_P (t) && !DECL_GLOBAL_DTOR_P (t) && !DECL_THUNK_P (t)) ggc_mark_tree (ld->decl_flags.u2.access); else if (DECL_THUNK_P (t)) ggc_mark_tree (ld->decl_flags.u2.vcall_offset); - ggc_mark_tree (ld->decl_flags.context); if (TREE_CODE (t) != NAMESPACE_DECL) ggc_mark_tree (ld->decl_flags.u.template_info); else @@ -14886,7 +14703,7 @@ lang_mark_tree (t) if (CAN_HAVE_FULL_LANG_DECL_P (t)) { ggc_mark_tree (ld->befriending_classes); - ggc_mark_tree (ld->saved_tree); + ggc_mark_tree (ld->context); ggc_mark_tree (ld->cloned_function); if (!DECL_OVERLOADED_OPERATOR_P (t)) ggc_mark_tree (ld->u2.vtt_parm); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index a2cdb1d..b579f59 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -32,13 +32,13 @@ Boston, MA 02111-1307, USA. */ #include "system.h" #include "tree.h" #include "rtl.h" +#include "expr.h" #include "flags.h" #include "cp-tree.h" #include "decl.h" #include "lex.h" #include "output.h" #include "except.h" -#include "expr.h" #include "defaults.h" #include "toplev.h" #include "dwarf2out.h" diff --git a/gcc/cp/except.c b/gcc/cp/except.c index e872859..ee2cf44 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -27,10 +27,10 @@ Boston, MA 02111-1307, USA. */ #include "system.h" #include "tree.h" #include "rtl.h" +#include "expr.h" #include "cp-tree.h" #include "flags.h" #include "obstack.h" -#include "expr.h" #include "output.h" #include "except.h" #include "defaults.h" diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c index 39095ec..c49a2f9 100644 --- a/gcc/cp/expr.c +++ b/gcc/cp/expr.c @@ -133,28 +133,8 @@ cplus_expand_expr (exp, target, tmode, modifier) /* We don't need to generate any code for an empty class. */ return const0_rtx; - 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: - break; + return c_expand_expr (exp, target, tmode, modifier); } my_friendly_abort (40); /* NOTREACHED */ diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c index 950169a..1cc99052 100644 --- a/gcc/cp/friend.c +++ b/gcc/cp/friend.c @@ -22,6 +22,7 @@ Boston, MA 02111-1307, USA. */ #include "system.h" #include "tree.h" #include "rtl.h" +#include "expr.h" #include "cp-tree.h" #include "flags.h" #include "output.h" diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 5a86965..89619ee 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -26,11 +26,11 @@ Boston, MA 02111-1307, USA. */ #include "system.h" #include "tree.h" #include "rtl.h" +#include "expr.h" #include "cp-tree.h" #include "flags.h" #include "output.h" #include "except.h" -#include "expr.h" #include "toplev.h" #include "ggc.h" diff --git a/gcc/cp/lex.h b/gcc/cp/lex.h index 1439c18..272a917 100644 --- a/gcc/cp/lex.h +++ b/gcc/cp/lex.h @@ -88,6 +88,4 @@ extern int pending_lang_change; extern int yylex PARAMS ((void)); -extern struct lang_decl *free_lang_decl_chain; - #endif /* _CP_LEX_H */ diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index fdc1a52..be53216 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -1004,7 +1004,7 @@ maybe_clone_body (fn) VARRAY_FREE (id.fns); /* Now, expand this function into RTL, if appropriate. */ - cp_function_chain->name_declared = 1; + function_name_declared_p = 1; expand_body (finish_function (0)); pop_from_top_level (); } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 99443b5..e3357a0 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -1985,7 +1985,8 @@ build_template_decl (decl, parms) DECL_CONTEXT (tmpl) = DECL_CONTEXT (decl); if (DECL_LANG_SPECIFIC (decl)) { - DECL_VIRTUAL_CONTEXT (tmpl) = DECL_VIRTUAL_CONTEXT (decl); + if (CAN_HAVE_FULL_LANG_DECL_P (decl)) + DECL_VIRTUAL_CONTEXT (tmpl) = DECL_VIRTUAL_CONTEXT (decl); DECL_STATIC_FUNCTION_P (tmpl) = DECL_STATIC_FUNCTION_P (decl); DECL_CONSTRUCTOR_P (tmpl) = DECL_CONSTRUCTOR_P (decl); DECL_NONCONVERTING_P (tmpl) = DECL_NONCONVERTING_P (decl); @@ -9689,7 +9690,7 @@ instantiate_decl (d, defer_ok) /* We already set up __FUNCTION__, etc., so we don't want to do it again now. */ - cp_function_chain->name_declared = 1; + function_name_declared_p = 1; /* Substitute into the body of the function. */ tsubst_expr (DECL_SAVED_TREE (code_pattern), args, diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 88eaa72..2f4432f 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -77,19 +77,6 @@ static void genrtl_finish_function PARAMS ((tree)); substmt = cond; \ } while (0) -/* Wrapper since C and C++ expand_expr_stmt are different. */ - -expand_expr_stmt_fn lang_expand_expr_stmt = cplus_expand_expr_stmt; - -/* Wrapper function instead of #define for use with c-common code. */ - -void -set_current_function_name_declared (i) - int i; -{ - cp_function_chain->name_declared = i; -} - /* Returns non-zero if the current statement is a full expression, i.e. temporaries created during that statement should be destroyed at the end of the statement. */ @@ -112,16 +99,6 @@ current_stmt_tree () : &scope_chain->x_stmt_tree); } -/* One if we have already declared __FUNCTION__ (and related - variables) in the current function. Two if we are in the process - of doing so. */ - -int -current_function_name_declared () -{ - return cp_function_chain->name_declared; -} - /* Nonzero if TYPE is an anonymous union or struct type. We have to use a flag for this because "A union for which objects or pointers are declared is not an anonymous union" [class.union]. */ @@ -863,10 +840,10 @@ begin_compound_stmt (has_no_scope) /* If this is the outermost block of the function, declare the variables __FUNCTION__, __PRETTY_FUNCTION__, and so forth. */ if (cfun - && !(current_function_name_declared () ) + && !function_name_declared_p && !has_no_scope) { - cp_function_chain->name_declared = 1; + function_name_declared_p = 1; declare_function_name (); } @@ -962,20 +939,6 @@ finish_label_decl (name) add_decl_stmt (decl); } -/* Create a declaration statement for the declaration given by the - DECL. */ - -void -add_decl_stmt (decl) - tree decl; -{ - tree decl_stmt; - - /* We need the type to last until instantiation time. */ - decl_stmt = build_stmt (DECL_STMT, decl); - add_stmt (decl_stmt); -} - /* Generate the RTL for a SUBOBJECT. */ static void @@ -1216,10 +1179,10 @@ setup_vtbl_ptr (member_init_list, base_init_list) /* Don't declare __PRETTY_FUNCTION__ and friends here when we open the block for the if-body. */ - saved_cfnd = current_function_name_declared (); - cp_function_chain->name_declared = 1; + saved_cfnd = function_name_declared_p; + function_name_declared_p = 1; compound_stmt = begin_compound_stmt (/*has_no_scope=*/0); - cp_function_chain->name_declared = saved_cfnd; + function_name_declared_p = saved_cfnd; /* Make all virtual function table pointers in non-virtual base classes point to CURRENT_CLASS_TYPE's virtual function @@ -1240,48 +1203,12 @@ setup_vtbl_ptr (member_init_list, base_init_list) vtbls_set_up_p = 1; } +/* Returns the stack of SCOPE_STMTs for the current function. */ -/* Add a scope-statement to the statement-tree. BEGIN_P indicates - whether this statements opens or closes a scope. PARTIAL_P is true - for a partial scope, i.e, the scope that begins after a label when - an object that needs a cleanup is created. If BEGIN_P is nonzero, - returns a new TREE_LIST representing the top of the SCOPE_STMT - stack. The TREE_PURPOSE is the new SCOPE_STMT. If BEGIN_P is - zero, returns a TREE_LIST whose TREE_VALUE is the new SCOPE_STMT, - and whose TREE_PURPOSE is the matching SCOPE_STMT iwth - SCOPE_BEGIN_P set. */ - -tree -add_scope_stmt (begin_p, partial_p) - int begin_p; - int partial_p; +tree * +current_scope_stmt_stack () { - tree ss; - tree top; - - /* Build the statement. */ - ss = build_stmt (SCOPE_STMT, NULL_TREE); - SCOPE_BEGIN_P (ss) = begin_p; - SCOPE_PARTIAL_P (ss) = partial_p; - - /* Keep the scope stack up to date. */ - if (begin_p) - { - current_scope_stmt_stack - = tree_cons (ss, NULL_TREE, current_scope_stmt_stack); - top = current_scope_stmt_stack; - } - else - { - top = current_scope_stmt_stack; - TREE_VALUE (top) = ss; - current_scope_stmt_stack = TREE_CHAIN (top); - } - - /* Add the new statement to the statement-tree. */ - add_stmt (ss); - - return top; + return &cfun->language->x_scope_stmt_stack; } /* Finish a parenthesized expression EXPR. */ @@ -2236,10 +2163,6 @@ cp_expand_stmt (t) genrtl_subobject (SUBOBJECT_CLEANUP (t)); break; - case SCOPE_STMT: - genrtl_scope_stmt (t); - break; - case RETURN_INIT: genrtl_named_return_value (); break; @@ -2483,7 +2406,7 @@ expand_body (fn) /* We don't need to redeclare __FUNCTION__, __PRETTY_FUNCTION__, or any of the other magic variables we set up when starting a function body. */ - cp_function_chain->name_declared = 1; + function_name_declared_p = 1; /* Expand the body. */ expand_stmt (DECL_SAVED_TREE (fn)); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 396b5c4..9b5e2be 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1081,7 +1081,6 @@ cp_statement_code_p (code) case CLEANUP_STMT: case START_CATCH_STMT: case CTOR_STMT: - case SCOPE_STMT: case CTOR_INITIALIZER: case RETURN_INIT: case TRY_BLOCK: diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index e15a724..3a16526 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -34,11 +34,11 @@ Boston, MA 02111-1307, USA. */ #include "system.h" #include "tree.h" #include "rtl.h" +#include "expr.h" #include "cp-tree.h" #include "tm_p.h" #include "flags.h" #include "output.h" -#include "expr.h" #include "toplev.h" #include "defaults.h" @@ -54,9 +54,6 @@ static int comp_except_types PARAMS ((tree, tree, int)); static int comp_array_types PARAMS ((int (*) (tree, tree, int), tree, tree, int)); static tree common_base_type PARAMS ((tree, tree)); -#if 0 -static tree convert_sequence PARAMS ((tree, tree)); -#endif static tree lookup_anon_field PARAMS ((tree, tree)); static tree pointer_diff PARAMS ((tree, tree, tree)); static tree build_component_addr PARAMS ((tree, tree)); @@ -4745,35 +4742,6 @@ build_unary_op (code, xarg, noconvert) return error_mark_node; } -#if 0 -/* If CONVERSIONS is a conversion expression or a nested sequence of such, - convert ARG with the same conversions in the same order - and return the result. */ - -static tree -convert_sequence (conversions, arg) - tree conversions; - tree arg; -{ - switch (TREE_CODE (conversions)) - { - case NOP_EXPR: - case CONVERT_EXPR: - case FLOAT_EXPR: - case FIX_TRUNC_EXPR: - case FIX_FLOOR_EXPR: - case FIX_ROUND_EXPR: - case FIX_CEIL_EXPR: - return cp_convert (TREE_TYPE (conversions), - convert_sequence (TREE_OPERAND (conversions, 0), - arg)); - - default: - return arg; - } -} -#endif - /* Apply unary lvalue-demanding operator CODE to the expression ARG for certain kinds of expressions which are not really lvalues but which we can accept as lvalues. diff --git a/gcc/dependence.c b/gcc/dependence.c index 141d9ac..3bfe34a 100644 --- a/gcc/dependence.c +++ b/gcc/dependence.c @@ -27,6 +27,7 @@ Boston, MA 02111-1307, USA. */ #include "system.h" #include "rtl.h" +#include "expr.h" #include "tree.h" #include "c-common.h" #include "flags.h" @@ -58,7 +59,7 @@ Boston, MA 02111-1307, USA. */ dependence to the dep_chain */ -enum dependence_type {flow, anti, output, none}; +enum dependence_type {dt_flow, dt_anti, dt_output, dt_none}; #if 0 static const char * dependence_string [] = {"flow", "anti", "output", "none"}; #endif @@ -756,23 +757,23 @@ check_node_dependence (du) dep_ptr->next = 0; if (def_ptr < use_ptr && use_ptr->type == use) - dep_ptr->dependence = flow; + dep_ptr->dependence = dt_flow; else if (def_ptr > use_ptr && use_ptr->type == use) - dep_ptr->dependence = anti; - else dep_ptr->dependence = output; + dep_ptr->dependence = dt_anti; + else dep_ptr->dependence = dt_output; for (j = 1 ; j <= i - 1 ; j++) { if (direction[j][0] == gt) { - dep_ptr->dependence = anti; + dep_ptr->dependence = dt_anti; direction[j][0] = lt; distance[j][0] = -distance[j][0]; break; } else if (direction[j][0] == lt) { - dep_ptr->dependence = flow; + dep_ptr->dependence = dt_flow; break; } } @@ -796,7 +797,7 @@ check_node_dependence (du) dep_root_ptr = VARRAY_TOP (dep_chain, generic); dep_root_ptr->source = 0; dep_root_ptr->destination = def_ptr->expression; - dep_root_ptr->dependence = none; + dep_root_ptr->dependence = dt_none; dep_root_ptr->next = dep_ptr; def_ptr->dep = dep_ptr; } @@ -85,6 +85,15 @@ Boston, MA 02111-1307, USA. */ #define CASE_VECTOR_PC_RELATIVE 0 #endif +/* Hook called by safe_from_p for language-specific tree codes. It is + up to the language front-end to install a hook if it has any such + codes that safe_from_p needs to know about. Since same_from_p will + recursively explore the TREE_OPERANDs of an expression, this hook + should not reexamine those pieces. This routine may recursively + call safe_from_p; it should always pass `0' as the TOP_P + parameter. */ +int (*lang_safe_from_p) PARAMS ((rtx, tree)); + /* If this is nonzero, we do not bother generating VOLATILE around volatile memory references, and we are willing to output indirect addresses. If cse is to follow, we reject @@ -168,7 +177,6 @@ static enum memory_use_mode get_memory_usage_from_modifier PARAMS ((enum expand_modifier)); static tree save_noncopied_parts PARAMS ((tree, tree)); static tree init_noncopied_parts PARAMS ((tree, tree)); -static int safe_from_p PARAMS ((rtx, tree, int)); static int fixed_type_p PARAMS ((tree)); static rtx var_rtx PARAMS ((tree)); static int readonly_fields_p PARAMS ((tree)); @@ -5396,7 +5404,7 @@ init_noncopied_parts (lhs, list) It is always safe for this routine to return zero since it merely searches for optimization opportunities. */ -static int +int safe_from_p (x, exp, top_p) rtx x; tree exp; @@ -5595,11 +5603,18 @@ safe_from_p (x, exp, top_p) if (exp_rtl) break; - nops = TREE_CODE_LENGTH (TREE_CODE (exp)); + nops = first_rtl_op (TREE_CODE (exp)); for (i = 0; i < nops; i++) if (TREE_OPERAND (exp, i) != 0 && ! safe_from_p (x, TREE_OPERAND (exp, i), 0)) return 0; + + /* If this is a language-specific tree code, it may require + special handling. */ + if (TREE_CODE (exp) >= LAST_AND_UNUSED_TREE_CODE + && lang_safe_from_p + && !(*lang_safe_from_p) (x, exp)) + return 0; } /* If we have an rtl, find any enclosed object. Then see if we conflict @@ -1257,6 +1257,17 @@ extern rtx (*lang_expand_expr) PARAMS ((union tree_node *, rtx, such codes that output_constant needs to know about. Returns a language-independent constant equivalent to its input. */ extern tree (*lang_expand_constant) PARAMS ((tree)); + +extern int safe_from_p PARAMS ((rtx, tree, int)); + +/* Hook called by safe_from_p for language-specific tree codes. It is + up to the language front-end to install a hook if it has any such + codes that safe_from_p needs to know about. Since same_from_p will + recursively explore the TREE_OPERANDs of an expression, this hook + should not reexamine those pieces. This routine may recursively + call safe_from_p; it should always pass `0' as the TOP_P + parameter. */ +extern int (*lang_safe_from_p) PARAMS ((rtx, tree)); #endif extern void init_all_optabs PARAMS ((void)); diff --git a/gcc/objc/Make-lang.in b/gcc/objc/Make-lang.in index 7ece705..9206838 100644 --- a/gcc/objc/Make-lang.in +++ b/gcc/objc/Make-lang.in @@ -1,5 +1,5 @@ # Top level makefile fragment for GNU Objective-C -# Copyright (C) 1997, 1998 Free Software Foundation, Inc. +# Copyright (C) 1997, 1998, 2000 Free Software Foundation, Inc. #This file is part of GNU CC. @@ -85,7 +85,7 @@ $(srcdir)/objc/objc-parse.y: $(srcdir)/c-parse.in $(SHELL) $(srcdir)/move-if-change tmp-objc-prs.y $(srcdir)/objc/objc-parse.y objc-act.o : $(srcdir)/objc/objc-act.c \ - $(CONFIG_H) $(TREE_H) $(RTL_H) system.h \ + $(CONFIG_H) $(TREE_H) $(RTL_H) system.h $(EXPR_H) \ $(srcdir)/c-tree.h $(srcdir)/c-common.h $(srcdir)/c-lex.h \ $(srcdir)/toplev.h $(srcdir)/flags.h $(srcdir)/objc/objc-act.h \ $(srcdir)/input.h $(srcdir)/function.h $(srcdir)/output.h diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index ba5837a..5bb4fcd 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -42,8 +42,11 @@ Boston, MA 02111-1307, USA. */ #include "config.h" #include "system.h" #include "tree.h" +#include "rtl.h" +#include "expr.h" #include "c-tree.h" #include "c-lex.h" +#include "c-common.h" #include "flags.h" #include "objc-act.h" #include "input.h" @@ -198,6 +201,7 @@ static void encode_aggregate_within PARAMS ((tree, int, int, int, int)); static const char *objc_demangle PARAMS ((const char *)); static const char *objc_printable_name PARAMS ((tree, int)); +static void objc_expand_function_end PARAMS ((void)); /* Misc. bookkeeping */ @@ -7410,12 +7414,18 @@ encode_method_def (func_decl) return result; } -void -finish_method_def () +static void +objc_expand_function_end () { METHOD_ENCODING (method_context) = encode_method_def (current_function_decl); +} +void +finish_method_def () +{ + lang_expand_function_end = objc_expand_function_end; finish_function (0); + lang_expand_function_end = NULL; /* Required to implement _msgSuper. This must be done AFTER finish_function, since the optimizer may find "may be used before set" errors. */ @@ -8172,7 +8182,7 @@ init_objc () { /* Add the special tree codes of Objective C to the tables. */ -#define LAST_CODE LAST_AND_UNUSED_TREE_CODE +#define LAST_CODE LAST_C_TREE_CODE gcc_obstack_init (&util_obstack); util_firstobj = (char *) obstack_finish (&util_obstack); @@ -8193,6 +8203,8 @@ init_objc () /* Change the default error function */ decl_printable_name = objc_printable_name; + lang_expand_expr = c_expand_expr; + lang_expand_decl_stmt = c_expand_decl_stmt; } static void diff --git a/gcc/objc/objc-act.h b/gcc/objc/objc-act.h index 05f7ad6..f13acc8 100644 --- a/gcc/objc/objc-act.h +++ b/gcc/objc/objc-act.h @@ -110,7 +110,7 @@ enum objc_tree_code { #ifdef OBJCPLUS dummy_tree_code = LAST_CPLUS_TREE_CODE, #else - dummy_tree_code = LAST_AND_UNUSED_TREE_CODE, + dummy_tree_code = LAST_C_TREE_CODE, #endif #include "objc-tree.def" LAST_OBJC_TREE_CODE @@ -1923,11 +1923,14 @@ expand_expr_stmt (exp) if (expr_stmts_for_value && TREE_CODE (TREE_TYPE (exp)) == FUNCTION_TYPE) exp = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp); - last_expr_type = TREE_TYPE (exp); + /* The call to `expand_expr' could cause last_expr_type and + last_expr_value to get reset. Therefore, we set last_expr_value + and last_expr_type *after* calling expand_expr. */ last_expr_value = expand_expr (exp, (expr_stmts_for_value ? NULL_RTX : const0_rtx), VOIDmode, 0); + last_expr_type = TREE_TYPE (exp); /* If all we do is reference a volatile value in memory, copy it to a register to be sure it is actually touched. */ diff --git a/gcc/testsuite/gcc.dg/noncompile/920923-1.c b/gcc/testsuite/gcc.dg/noncompile/920923-1.c index 57d4065..f0748e7 100644 --- a/gcc/testsuite/gcc.dg/noncompile/920923-1.c +++ b/gcc/testsuite/gcc.dg/noncompile/920923-1.c @@ -75,7 +75,7 @@ caddr_t v_addr; /* { dg-error "parse error" } */ p_addr = fill_item_entry(va_op, v_addr); goto page_type; case((caddr_t)1): /* { dg-error "parse error" } */ - default: /* { dg-error "default label" } */ + default: ((void)(((0))?0:(__eprintf("Failed assertion`%s'at line%d of`%s'.\n", "FALSE", 327, "b.c"), 0))); } diff --git a/gcc/toplev.c b/gcc/toplev.c index fb41c78..333cde6 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -2566,7 +2566,11 @@ rest_of_decl_compilation (decl, asmspec, top_level, at_end) make_decl_rtl (decl, asmspec, top_level); } else - error ("invalid register name `%s' for register variable", asmspec); + { + error ("invalid register name `%s' for register variable", asmspec); + DECL_REGISTER (decl) = 0; + make_decl_rtl (decl, NULL, top_level); + } } #if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) else if ((write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) @@ -2794,11 +2794,15 @@ int contains_placeholder_p (exp) tree exp; { - register enum tree_code code = TREE_CODE (exp); + register enum tree_code code; int result; + if (!exp) + return 0; + /* If we have a WITH_RECORD_EXPR, it "cancels" any PLACEHOLDER_EXPR in it since it is supplying a value for it. */ + code = TREE_CODE (exp); if (code == WITH_RECORD_EXPR) return 0; else if (code == PLACEHOLDER_EXPR) diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog index 1e5efa2..853b242 100644 --- a/libiberty/ChangeLog +++ b/libiberty/ChangeLog @@ -1,3 +1,7 @@ +2000-09-16 Mark Mitchell <mark@codesourcery.com> + + * splay-tree.c (splay_tree_predecessor): Fix typo in comment. + 2000-09-14 Michael Sokolov <msokolov@ivan.Harhan.ORG> * splay-tree.c: #include <stdio.h>. diff --git a/libiberty/splay-tree.c b/libiberty/splay-tree.c index 319349b..eb88814 100644 --- a/libiberty/splay-tree.c +++ b/libiberty/splay-tree.c @@ -392,7 +392,7 @@ splay_tree_predecessor (sp, key) if (comparison < 0) return sp->root; - /* Otherwise, find the rightmost element of the left subtree. */ + /* Otherwise, find the leftmost element of the right subtree. */ node = sp->root->left; if (node) while (node->right) |