X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fcp%2Fsemantics.c;h=28c0f35b0754390e7ef5e8bd9f09818ecd3af564;hp=eb1767e850eac44143d7f07e0b4c99e3ff14d438;hb=87ed0134d982ea4a876c3f179a6a83eec22dc1a9;hpb=76a248697516cab85361352ea7a8c62dac90a213 diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index eb1767e850e..28c0f35b075 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3,7 +3,7 @@ building RTL. These routines are used both during actual parsing and during the instantiation of template functions. - Copyright (C) 1998, 1999 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. Written by Mark Mitchell (mmitchell@usa.net) based on code found formerly in parse.y and pt.c. @@ -32,6 +32,10 @@ #include "lex.h" #include "toplev.h" #include "flags.h" +#include "ggc.h" +#include "rtl.h" +#include "output.h" +#include "timevar.h" /* There routines provide a modular interface to perform many parsing operations. They may therefore be used during actual parsing, or @@ -42,27 +46,19 @@ parsing into this file; that will make implementing the new parser much easier since it will be able to make use of these routines. */ -static tree expand_cond PROTO((tree)); -static tree maybe_convert_cond PROTO((tree)); - -/* Record the fact that STMT was the last statement added to the - statement tree. */ - -#define SET_LAST_STMT(stmt) \ - (current_stmt_tree->x_last_stmt = (stmt)) - -/* When parsing a template, 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; \ - SET_LAST_STMT (stmt); \ - } while (0) +static tree maybe_convert_cond PARAMS ((tree)); +static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *)); +static void deferred_type_access_control PARAMS ((void)); +static void emit_associated_thunks PARAMS ((tree)); +static void genrtl_try_block PARAMS ((tree)); +static void genrtl_handler PARAMS ((tree)); +static void genrtl_catch_block PARAMS ((tree)); +static void genrtl_ctor_stmt PARAMS ((tree)); +static void genrtl_subobject PARAMS ((tree)); +static void genrtl_named_return_value PARAMS ((void)); +static void cp_expand_stmt PARAMS ((tree)); +static void genrtl_start_function PARAMS ((tree)); +static void genrtl_finish_function PARAMS ((tree)); /* Finish processing the COND, the SUBSTMT condition for STMT. */ @@ -80,27 +76,108 @@ static tree maybe_convert_cond PROTO((tree)); else \ substmt = cond; \ } while (0) - -/* T is a statement. Add it to the statement-tree. */ + +/* 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. */ + +int +stmts_are_full_exprs_p () +{ + return current_stmt_tree ()->stmts_are_full_exprs_p; +} + +/* Returns the stmt_tree (if any) to which statements are currently + being added. If there is no active statement-tree, NULL is + returned. */ + +stmt_tree +current_stmt_tree () +{ + return (cfun + ? &cfun->language->x_stmt_tree + : &scope_chain->x_stmt_tree); +} + +/* 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]. */ + +int +anon_aggr_type_p (node) + tree node; +{ + return (CLASS_TYPE_P (node) && TYPE_LANG_SPECIFIC(node)->anon_aggr); +} + +/* Finish a scope. */ + +tree +do_poplevel () +{ + tree block = NULL_TREE; + + if (stmts_are_full_exprs_p ()) + { + tree scope_stmts = NULL_TREE; + + if (!processing_template_decl) + scope_stmts = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0); + + block = poplevel (kept_level_p (), 1, 0); + if (block && !processing_template_decl) + { + SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmts)) = block; + SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmts)) = block; + } + } + + return block; +} + +/* Begin a new scope. */ void -add_tree (t) - tree t; +do_pushlevel () +{ + if (stmts_are_full_exprs_p ()) + { + pushlevel (0); + if (!processing_template_decl) + add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0); + } +} + +/* Finish a goto-statement. */ + +void +finish_goto_stmt (destination) + tree destination; { - /* Add T to the statement-tree. */ - TREE_CHAIN (last_tree) = t; - SET_LAST_STMT (t); + if (TREE_CODE (destination) == IDENTIFIER_NODE) + destination = lookup_label (destination); + + /* We warn about unused labels with -Wunused. That means we have to + mark the used labels as used. */ + if (TREE_CODE (destination) == LABEL_DECL) + TREE_USED (destination) = 1; + + if (TREE_CODE (destination) != LABEL_DECL) + /* We don't inline calls to functions with computed gotos. + Those functions are typically up to some funny business, + and may be depending on the labels being at particular + addresses, or some such. */ + DECL_UNINLINABLE (current_function_decl) = 1; + + check_goto (destination); - /* When we expand a statement-tree, we must know whether or not the - statements are full-expresions. We record that fact here. */ - if (building_stmt_tree ()) - STMT_IS_FULL_EXPR_P (last_tree) = stmts_are_full_exprs_p; + add_stmt (build_stmt (GOTO_STMT, destination)); } /* COND is the condition-expression for an if, while, etc., statement. Convert it to a boolean value, if appropriate. */ -static tree +tree maybe_convert_cond (cond) tree cond; { @@ -125,30 +202,20 @@ finish_expr_stmt (expr) { if (expr != NULL_TREE) { - if (building_stmt_tree ()) - add_tree (build_min_nt (EXPR_STMT, expr)); - else - { - emit_line_note (input_filename, lineno); - /* Do default conversion if safe and possibly important, - in case within ({...}). */ - if (!stmts_are_full_exprs_p && - ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE - && lvalue_p (expr)) - || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)) - expr = default_conversion (expr); - - if (stmts_are_full_exprs_p) - expand_start_target_temps (); - - cplus_expand_expr_stmt (expr); - - if (stmts_are_full_exprs_p) - { - expand_end_target_temps (); - clear_momentary (); - } - } + if (!processing_template_decl + && !(stmts_are_full_exprs_p ()) + && ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE + && lvalue_p (expr)) + || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)) + expr = default_conversion (expr); + + if (stmts_are_full_exprs_p ()) + expr = convert_to_void (expr, "statement"); + + if (!processing_template_decl) + expr = break_out_cleanups (expr); + + add_stmt (build_stmt (EXPR_STMT, expr)); } finish_stmt (); @@ -158,6 +225,7 @@ finish_expr_stmt (expr) last_expr_type = expr ? TREE_TYPE (expr) : NULL_TREE; } + /* Begin an if-statement. Returns a newly created IF_STMT if appropriate. */ @@ -165,17 +233,9 @@ tree begin_if_stmt () { tree r; - do_pushlevel (); - - if (building_stmt_tree ()) - { - r = build_min_nt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE); - add_tree (r); - } - else - r = NULL_TREE; - + r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE); + add_stmt (r); return r; } @@ -188,14 +248,7 @@ finish_if_stmt_cond (cond, if_stmt) tree if_stmt; { cond = maybe_convert_cond (cond); - - if (building_stmt_tree ()) - FINISH_COND (cond, if_stmt, IF_COND (if_stmt)); - else - { - emit_line_note (input_filename, lineno); - expand_start_cond (cond, 0); - } + FINISH_COND (cond, if_stmt, IF_COND (if_stmt)); } /* Finish the then-clause of an if-statement, which may be given by @@ -205,14 +258,9 @@ tree finish_then_clause (if_stmt) tree if_stmt; { - if (building_stmt_tree ()) - { - RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt)); - SET_LAST_STMT (if_stmt); - return if_stmt; - } - else - return NULL_TREE; + RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt)); + last_tree = if_stmt; + return if_stmt; } /* Begin the else-clause of an if-statement. */ @@ -220,8 +268,6 @@ finish_then_clause (if_stmt) void begin_else_clause () { - if (!building_stmt_tree ()) - expand_start_else (); } /* Finish the else-clause of an if-statement, which may be given by @@ -231,8 +277,7 @@ void finish_else_clause (if_stmt) tree if_stmt; { - if (building_stmt_tree ()) - RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt)); + RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt)); } /* Finsh an if-statement. */ @@ -240,13 +285,23 @@ finish_else_clause (if_stmt) void finish_if_stmt () { - if (!building_stmt_tree ()) - expand_end_cond (); - do_poplevel (); finish_stmt (); } +void +clear_out_block () +{ + /* If COND wasn't a declaration, clear out the + block we made for it and start a new one here so the + optimization in expand_end_loop will work. */ + if (getdecls () == NULL_TREE) + { + do_poplevel (); + do_pushlevel (); + } +} + /* Begin a while-statement. Returns a newly created WHILE_STMT if appropriate. */ @@ -254,26 +309,13 @@ tree begin_while_stmt () { tree r; - - if (building_stmt_tree ()) - { - r = build_min_nt (WHILE_STMT, NULL_TREE, NULL_TREE); - add_tree (r); - } - else - { - emit_nop (); - emit_line_note (input_filename, lineno); - expand_start_loop (1); - r = NULL_TREE; - } - + r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE); + add_stmt (r); do_pushlevel (); - return r; } -/* Process the COND of an if-statement, which may be given by +/* Process the COND of a while-statement, which may be given by WHILE_STMT. */ void @@ -282,23 +324,8 @@ finish_while_stmt_cond (cond, while_stmt) tree while_stmt; { cond = maybe_convert_cond (cond); - - if (building_stmt_tree ()) - FINISH_COND (cond, while_stmt, WHILE_COND (while_stmt)); - else - { - emit_line_note (input_filename, lineno); - expand_exit_loop_if_false (0, cond); - } - - /* If COND wasn't a declaration, clear out the - block we made for it and start a new one here so the - optimization in expand_end_loop will work. */ - if (getdecls () == NULL_TREE) - { - do_poplevel (); - do_pushlevel (); - } + FINISH_COND (cond, while_stmt, WHILE_COND (while_stmt)); + clear_out_block (); } /* Finish a while-statement, which may be given by WHILE_STMT. */ @@ -308,11 +335,7 @@ finish_while_stmt (while_stmt) tree while_stmt; { do_poplevel (); - - if (building_stmt_tree ()) - RECHAIN_STMTS (while_stmt, WHILE_BODY (while_stmt)); - else - expand_end_loop (); + RECHAIN_STMTS (while_stmt, WHILE_BODY (while_stmt)); finish_stmt (); } @@ -322,19 +345,9 @@ finish_while_stmt (while_stmt) tree begin_do_stmt () { - if (building_stmt_tree ()) - { - tree r = build_min_nt (DO_STMT, NULL_TREE, NULL_TREE); - add_tree (r); - return r; - } - else - { - emit_nop (); - emit_line_note (input_filename, lineno); - expand_start_loop_continue_elsewhere (1); - return NULL_TREE; - } + tree r = build_stmt (DO_STMT, NULL_TREE, NULL_TREE); + add_stmt (r); + return r; } /* Finish the body of a do-statement, which may be given by DO_STMT. */ @@ -343,10 +356,7 @@ void finish_do_body (do_stmt) tree do_stmt; { - if (building_stmt_tree ()) - RECHAIN_STMTS (do_stmt, DO_BODY (do_stmt)); - else - expand_loop_continue_here (); + RECHAIN_STMTS (do_stmt, DO_BODY (do_stmt)); } /* Finish a do-statement, which may be given by DO_STMT, and whose @@ -358,17 +368,7 @@ finish_do_stmt (cond, do_stmt) tree do_stmt; { cond = maybe_convert_cond (cond); - - if (building_stmt_tree ()) - DO_COND (do_stmt) = cond; - else - { - emit_line_note (input_filename, lineno); - expand_exit_loop_if_false (0, cond); - expand_end_loop (); - } - - clear_momentary (); + DO_COND (do_stmt) = cond; finish_stmt (); } @@ -379,10 +379,9 @@ void finish_return_stmt (expr) tree expr; { - if (doing_semantic_analysis_p () && !processing_template_decl) + if (!processing_template_decl) expr = check_return_expr (expr); - - if (doing_semantic_analysis_p () && !processing_template_decl) + if (!processing_template_decl) { if (DECL_CONSTRUCTOR_P (current_function_decl) && ctor_label) { @@ -405,15 +404,7 @@ finish_return_stmt (expr) return; } } - - if (building_stmt_tree ()) - add_tree (build_min_nt (RETURN_STMT, expr)); - else - { - emit_line_note (input_filename, lineno); - c_expand_return (expr); - } - + add_stmt (build_stmt (RETURN_STMT, expr)); finish_stmt (); } @@ -424,16 +415,11 @@ begin_for_stmt () { tree r; - if (building_stmt_tree ()) - { - r = build_min_nt (FOR_STMT, NULL_TREE, NULL_TREE, - NULL_TREE, NULL_TREE); - add_tree (r); - } - else - r = NULL_TREE; - - if (flag_new_for_scope > 0) + r = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE, + NULL_TREE, NULL_TREE); + NEW_FOR_SCOPE_P (r) = flag_new_for_scope > 0; + add_stmt (r); + if (NEW_FOR_SCOPE_P (r)) { do_pushlevel (); note_level_for_for (); @@ -449,18 +435,8 @@ void finish_for_init_stmt (for_stmt) tree for_stmt; { - if (building_stmt_tree ()) - { - if (last_tree != for_stmt) - RECHAIN_STMTS (for_stmt, FOR_INIT_STMT (for_stmt)); - } - else - { - emit_nop (); - emit_line_note (input_filename, lineno); - expand_start_loop_continue_elsewhere (1); - } - + if (last_tree != for_stmt) + RECHAIN_STMTS (for_stmt, FOR_INIT_STMT (for_stmt)); do_pushlevel (); } @@ -473,24 +449,8 @@ finish_for_cond (cond, for_stmt) tree for_stmt; { cond = maybe_convert_cond (cond); - - if (building_stmt_tree ()) - FINISH_COND (cond, for_stmt, FOR_COND (for_stmt)); - else - { - emit_line_note (input_filename, lineno); - if (cond) - expand_exit_loop_if_false (0, cond); - } - - /* If the cond wasn't a declaration, clear out the - block we made for it and start a new one here so the - optimization in expand_end_loop will work. */ - if (getdecls () == NULL_TREE) - { - do_poplevel (); - do_pushlevel (); - } + FINISH_COND (cond, for_stmt, FOR_COND (for_stmt)); + clear_out_block (); } /* Finish the increment-EXPRESSION in a for-statement, which may be @@ -501,12 +461,7 @@ finish_for_expr (expr, for_stmt) tree expr; tree for_stmt; { - if (building_stmt_tree ()) - FOR_EXPR (for_stmt) = expr; - - /* Don't let the tree nodes for EXPR be discarded - by clear_momentary during the parsing of the next stmt. */ - push_momentary (); + FOR_EXPR (for_stmt) = expr; } /* Finish the body of a for-statement, which may be given by @@ -514,29 +469,14 @@ finish_for_expr (expr, for_stmt) provided. */ void -finish_for_stmt (expr, for_stmt) - tree expr; +finish_for_stmt (for_stmt) tree for_stmt; { /* Pop the scope for the body of the loop. */ do_poplevel (); - - if (building_stmt_tree ()) - RECHAIN_STMTS (for_stmt, FOR_BODY (for_stmt)); - else - { - emit_line_note (input_filename, lineno); - expand_loop_continue_here (); - if (expr) - finish_expr_stmt (expr); - expand_end_loop (); - } - - pop_momentary (); - - if (flag_new_for_scope > 0) + RECHAIN_STMTS (for_stmt, FOR_BODY (for_stmt)); + if (NEW_FOR_SCOPE_P (for_stmt)) do_poplevel (); - finish_stmt (); } @@ -545,11 +485,7 @@ finish_for_stmt (expr, for_stmt) void finish_break_stmt () { - emit_line_note (input_filename, lineno); - if (building_stmt_tree ()) - add_tree (build_min_nt (BREAK_STMT)); - else if ( ! expand_exit_something ()) - cp_error ("break statement not within loop or switch"); + add_stmt (build_break_stmt ()); } /* Finish a continue-statement. */ @@ -557,11 +493,7 @@ finish_break_stmt () void finish_continue_stmt () { - emit_line_note (input_filename, lineno); - if (building_stmt_tree ()) - add_tree (build_min_nt (CONTINUE_STMT)); - else if (! expand_continue_loop (0)) - cp_error ("continue statement not within a loop"); + add_stmt (build_continue_stmt ()); } /* Begin a switch-statement. Returns a new SWITCH_STMT if @@ -571,17 +503,9 @@ tree begin_switch_stmt () { tree r; - - if (building_stmt_tree ()) - { - r = build_min_nt (SWITCH_STMT, NULL_TREE, NULL_TREE); - add_tree (r); - } - else - r = NULL_TREE; - + r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE); + add_stmt (r); do_pushlevel (); - return r; } @@ -592,91 +516,86 @@ finish_switch_cond (cond, switch_stmt) tree cond; tree switch_stmt; { - if (building_stmt_tree ()) - FINISH_COND (cond, switch_stmt, SWITCH_COND (switch_stmt)); - else if (cond != error_mark_node) + if (!processing_template_decl) { - emit_line_note (input_filename, lineno); - c_expand_start_case (cond); - } - else - /* The code is in error, but we don't want expand_end_case to - crash. */ - c_expand_start_case (boolean_false_node); + tree type; + tree index; - push_switch (); + /* Convert the condition to an integer or enumeration type. */ + cond = build_expr_type_conversion (WANT_INT | WANT_ENUM, cond, 1); + if (cond == NULL_TREE) + { + error ("switch quantity not an integer"); + cond = error_mark_node; + } + if (cond != error_mark_node) + { + cond = default_conversion (cond); + cond = fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (cond), cond)); + } - /* Don't let the tree nodes for COND be discarded by - clear_momentary during the parsing of the next stmt. */ - push_momentary (); + type = TREE_TYPE (cond); + index = get_unwidened (cond, 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 (cond)) + == TREE_UNSIGNED (TREE_TYPE (index))) + cond = index; + } + FINISH_COND (cond, switch_stmt, SWITCH_COND (switch_stmt)); + push_switch (switch_stmt); } /* Finish the body of a switch-statement, which may be given by SWITCH_STMT. The COND to switch on is indicated. */ void -finish_switch_stmt (cond, switch_stmt) - tree cond; +finish_switch_stmt (switch_stmt) tree switch_stmt; { - if (building_stmt_tree ()) - RECHAIN_STMTS (switch_stmt, SWITCH_BODY (switch_stmt)); - else - expand_end_case (cond); - pop_momentary (); + RECHAIN_STMTS (switch_stmt, SWITCH_BODY (switch_stmt)); pop_switch (); do_poplevel (); finish_stmt (); } -/* Finish a case-label. */ +/* Generate the RTL for T, which is a TRY_BLOCK. */ -void -finish_case_label (low_value, high_value) - tree low_value; - tree high_value; +static void +genrtl_try_block (t) + tree t; { - if (building_stmt_tree ()) + if (CLEANUP_P (t)) { - /* Add a representation for the case label to the statement - tree. */ - add_tree (build_min_nt (CASE_LABEL, low_value, high_value)); - /* And warn about crossing initializations, etc. */ - if (!processing_template_decl) - define_case_label (); - return; + expand_eh_region_start (); + expand_stmt (TRY_STMTS (t)); + expand_eh_region_end (protect_with_terminate (TRY_HANDLERS (t))); } - - do_case (low_value, high_value); -} - -/* Finish a goto-statement. */ - -void -finish_goto_stmt (destination) - tree destination; -{ - if (TREE_CODE (destination) == IDENTIFIER_NODE) - destination = lookup_label (destination); - - /* We warn about unused labels with -Wunused. That means we have to - mark the used labels as used. */ - if (TREE_CODE (destination) == LABEL_DECL) - TREE_USED (destination) = 1; - - if (building_stmt_tree ()) - add_tree (build_min_nt (GOTO_STMT, destination)); else { - emit_line_note (input_filename, lineno); + if (!FN_TRY_BLOCK_P (t)) + emit_line_note (input_filename, lineno); + expand_start_try_stmts (); - if (TREE_CODE (destination) == LABEL_DECL) + expand_stmt (TRY_STMTS (t)); + + if (FN_TRY_BLOCK_P (t)) { - label_rtx (destination); - expand_goto (destination); + end_protect_partials (); + expand_start_all_catch (); + in_function_try_handler = 1; + expand_stmt (TRY_HANDLERS (t)); + in_function_try_handler = 0; + expand_end_all_catch (); + } + else + { + expand_start_all_catch (); + expand_stmt (TRY_HANDLERS (t)); + expand_end_all_catch (); } - else - expand_computed_goto (destination); } } @@ -686,19 +605,9 @@ finish_goto_stmt (destination) tree begin_try_block () { - if (building_stmt_tree ()) - { - tree r = build_min_nt (TRY_BLOCK, NULL_TREE, - NULL_TREE); - add_tree (r); - return r; - } - else - { - emit_line_note (input_filename, lineno); - expand_start_try_stmts (); - return NULL_TREE; - } + tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE); + add_stmt (r); + return r; } /* Likewise, for a function-try-block. */ @@ -706,21 +615,10 @@ begin_try_block () tree begin_function_try_block () { - if (building_stmt_tree ()) - { - tree r = build_min_nt (TRY_BLOCK, NULL_TREE, - NULL_TREE); - FN_TRY_BLOCK_P (r) = 1; - add_tree (r); - return r; - } - else - { - if (! current_function_parms_stored) - store_parm_decls (); - expand_start_early_try_stmts (); - return NULL_TREE; - } + tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE); + FN_TRY_BLOCK_P (r) = 1; + add_stmt (r); + return r; } /* Finish a try-block, which may be given by TRY_BLOCK. */ @@ -729,10 +627,7 @@ void finish_try_block (try_block) tree try_block; { - if (building_stmt_tree ()) - RECHAIN_STMTS (try_block, TRY_STMTS (try_block)); - else - expand_start_all_catch (); + RECHAIN_STMTS (try_block, TRY_STMTS (try_block)); } /* Finish the body of a cleanup try-block, which may be given by @@ -742,8 +637,7 @@ void finish_cleanup_try_block (try_block) tree try_block; { - if (building_stmt_tree ()) - RECHAIN_STMTS (try_block, TRY_STMTS (try_block)); + RECHAIN_STMTS (try_block, TRY_STMTS (try_block)); } /* Finish an implicitly generated try-block, with a cleanup is given @@ -754,13 +648,8 @@ finish_cleanup (cleanup, try_block) tree cleanup; tree try_block; { - if (building_stmt_tree ()) - { - TRY_HANDLERS (try_block) = cleanup; - CLEANUP_P (try_block) = 1; - } - else - expand_eh_region_end (protect_with_terminate (cleanup)); + TRY_HANDLERS (try_block) = cleanup; + CLEANUP_P (try_block) = 1; } /* Likewise, for a function-try-block. */ @@ -769,25 +658,16 @@ void finish_function_try_block (try_block) tree try_block; { - if (building_stmt_tree ()) + if (TREE_CHAIN (try_block) + && TREE_CODE (TREE_CHAIN (try_block)) == CTOR_INITIALIZER) { - if (TREE_CHAIN (try_block) - && TREE_CODE (TREE_CHAIN (try_block)) == CTOR_INITIALIZER) - { - /* Chain the compound statement after the CTOR_INITIALIZER. */ - TREE_CHAIN (TREE_CHAIN (try_block)) = last_tree; - /* And make the CTOR_INITIALIZER the body of the try-block. */ - RECHAIN_STMTS (try_block, TRY_STMTS (try_block)); - } - else - RECHAIN_STMTS (try_block, TRY_STMTS (try_block)); + /* Chain the compound statement after the CTOR_INITIALIZER. */ + TREE_CHAIN (TREE_CHAIN (try_block)) = last_tree; + /* And make the CTOR_INITIALIZER the body of the try-block. */ + RECHAIN_STMTS (try_block, TRY_STMTS (try_block)); } else - { - end_protect_partials (); - expand_start_all_catch (); - } - + RECHAIN_STMTS (try_block, TRY_STMTS (try_block)); in_function_try_handler = 1; } @@ -798,10 +678,8 @@ void finish_handler_sequence (try_block) tree try_block; { - if (building_stmt_tree ()) - RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block)); - else - expand_end_all_catch (); + RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block)); + check_handlers (TRY_HANDLERS (try_block)); } /* Likewise, for a function-try-block. */ @@ -811,11 +689,26 @@ finish_function_handler_sequence (try_block) tree try_block; { in_function_try_handler = 0; + RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block)); + check_handlers (TRY_HANDLERS (try_block)); +} - if (building_stmt_tree ()) - RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block)); - else - expand_end_all_catch (); +/* Generate the RTL for T, which is a HANDLER. */ + +static void +genrtl_handler (t) + tree t; +{ + genrtl_do_pushlevel (); + expand_stmt (HANDLER_BODY (t)); + if (!processing_template_decl) + { + /* Fall to outside the try statement when done executing + handler and we fall off end of handler. This is jump + Lresume in the documentation. */ + expand_goto (top_label_entry (&caught_return_label_stack)); + end_catch_handler (); + } } /* Begin a handler. Returns a HANDLER if appropriate. */ @@ -824,17 +717,9 @@ tree begin_handler () { tree r; - - if (building_stmt_tree ()) - { - r = build_min_nt (HANDLER, NULL_TREE, NULL_TREE); - add_tree (r); - } - else - r = NULL_TREE; - + r = build_stmt (HANDLER, NULL_TREE, NULL_TREE); + add_stmt (r); do_pushlevel (); - return r; } @@ -859,12 +744,24 @@ finish_handler_parms (decl, handler) RECHAIN_STMTS (handler, HANDLER_PARMS (handler)); } } - else if (building_stmt_tree ()) + else blocks = expand_start_catch_block (decl); + if (decl) + TREE_TYPE (handler) = TREE_TYPE (decl); + return blocks; } +/* Generate the RTL for a CATCH_BLOCK. */ + +static void +genrtl_catch_block (type) + tree type; +{ + start_catch_handler (type); +} + /* Note the beginning of a handler for TYPE. This function is called at the point to which control should be transferred when an appropriately-typed exception is thrown. */ @@ -873,10 +770,7 @@ void begin_catch_block (type) tree type; { - if (building_stmt_tree ()) - add_tree (build (START_CATCH_STMT, type)); - else - start_catch_handler (type); + add_stmt (build (START_CATCH_STMT, type)); } /* Finish a handler, which may be given by HANDLER. The BLOCKs are @@ -888,24 +782,24 @@ finish_handler (blocks, handler) tree handler; { if (!processing_template_decl) - { - if (building_stmt_tree ()) - expand_end_catch_block (blocks); - - if (!building_stmt_tree ()) - { - /* Fall to outside the try statement when done executing - handler and we fall off end of handler. This is jump - Lresume in the documentation. */ - expand_goto (top_label_entry (&caught_return_label_stack)); - end_catch_handler (); - } - } + expand_end_catch_block (blocks); + do_poplevel (); + RECHAIN_STMTS (handler, HANDLER_BODY (handler)); +} - if (building_stmt_tree ()) - RECHAIN_STMTS (handler, HANDLER_BODY (handler)); +/* Generate the RTL for T, which is a CTOR_STMT. */ - do_poplevel (); +static void +genrtl_ctor_stmt (t) + tree t; +{ + if (CTOR_BEGIN_P (t)) + begin_protect_partials (); + else + /* After this point, any exceptions will cause the + destructor to be executed, so we no longer need to worry + about destroying the various subobjects ourselves. */ + end_protect_partials (); } /* Begin a compound-statement. If HAS_NO_SCOPE is non-zero, the @@ -917,21 +811,25 @@ begin_compound_stmt (has_no_scope) int has_no_scope; { tree r; + int is_try = 0; - if (building_stmt_tree ()) - { - r = build_min_nt (COMPOUND_STMT, NULL_TREE); - add_tree (r); - if (has_no_scope) - COMPOUND_STMT_NO_SCOPE (r) = 1; - } - else - r = NULL_TREE; + r = build_stmt (COMPOUND_STMT, NULL_TREE); + + if (last_tree && TREE_CODE (last_tree) == TRY_BLOCK) + is_try = 1; + + add_stmt (r); + if (has_no_scope) + COMPOUND_STMT_NO_SCOPE (r) = 1; last_expr_type = NULL_TREE; if (!has_no_scope) - do_pushlevel (); + { + do_pushlevel (); + if (is_try) + note_level_for_eh (); + } else /* Normally, we try hard to keep the BLOCK for a statement-expression. But, if it's a statement-expression with @@ -941,19 +839,17 @@ 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 (current_function - && !current_function_name_declared - && !processing_template_decl + if (cfun + && !function_name_declared_p && !has_no_scope) { + function_name_declared_p = 1; declare_function_name (); - current_function_name_declared = 1; } return r; } - /* Finish a compound-statement, which may be given by COMPOUND_STMT. If HAS_NO_SCOPE is non-zero, the compound statement does not define a scope. */ @@ -971,8 +867,7 @@ finish_compound_stmt (has_no_scope, compound_stmt) else r = NULL_TREE; - if (building_stmt_tree ()) - RECHAIN_STMTS (compound_stmt, COMPOUND_BODY (compound_stmt)); + RECHAIN_STMTS (compound_stmt, COMPOUND_BODY (compound_stmt)); /* When we call finish_stmt we will lose LAST_EXPR_TYPE. But, since the precise purpose of that variable is store the type of the @@ -998,18 +893,11 @@ finish_asm_stmt (cv_qualifier, string, output_operands, tree input_operands; tree clobbers; { - if (TREE_CHAIN (string)) - { - if (building_stmt_tree ()) - /* We need to build the combined string on the permanent - obstack so that we can use it during instantiations. */ - push_permanent_obstack (); - - string = combine_strings (string); + tree r; + tree t; - if (building_stmt_tree ()) - pop_obstacks (); - } + if (TREE_CHAIN (string)) + string = combine_strings (string); if (cv_qualifier != NULL_TREE && cv_qualifier != ridpointers[(int) RID_VOLATILE]) @@ -1019,35 +907,14 @@ finish_asm_stmt (cv_qualifier, string, output_operands, cv_qualifier = NULL_TREE; } - if (building_stmt_tree ()) - { - tree r = build_min_nt (ASM_STMT, cv_qualifier, string, - output_operands, input_operands, - clobbers); - add_tree (r); - } - else - { - emit_line_note (input_filename, lineno); - if (output_operands != NULL_TREE || input_operands != NULL_TREE - || clobbers != NULL_TREE) - { - tree t; - - for (t = input_operands; t; t = TREE_CHAIN (t)) - TREE_VALUE (t) = decay_conversion (TREE_VALUE (t)); + if (!processing_template_decl) + for (t = input_operands; t; t = TREE_CHAIN (t)) + TREE_VALUE (t) = decay_conversion (TREE_VALUE (t)); - c_expand_asm_operands (string, output_operands, - input_operands, - clobbers, - cv_qualifier != NULL_TREE, - input_filename, lineno); - } - else - expand_asm (string); - - finish_stmt (); - } + r = build_stmt (ASM_STMT, cv_qualifier, string, + output_operands, input_operands, + clobbers); + add_stmt (r); } /* Finish a label with the indicated NAME. */ @@ -1057,11 +924,7 @@ finish_label_stmt (name) tree name; { tree decl = define_label (input_filename, lineno, name); - - if (building_stmt_tree ()) - add_tree (build_min_nt (LABEL_STMT, decl)); - else if (decl) - expand_label (decl); + add_stmt (build_stmt (LABEL_STMT, decl)); } /* Finish a series of declarations for local labels. G++ allows users @@ -1073,22 +936,16 @@ finish_label_decl (name) tree name; { tree decl = declare_local_label (name); - if (building_stmt_tree ()) - add_decl_stmt (decl); + add_decl_stmt (decl); } -/* Create a declaration statement for the declaration given by the - DECL. */ +/* Generate the RTL for a SUBOBJECT. */ -void -add_decl_stmt (decl) - tree decl; +static void +genrtl_subobject (cleanup) + tree cleanup; { - tree decl_stmt; - - /* We need the type to last until instantiation time. */ - decl_stmt = build_min_nt (DECL_STMT, decl); - add_tree (decl_stmt); + add_partial_entry (cleanup); } /* We're in a constructor, and have just constructed a a subobject of @@ -1099,13 +956,8 @@ void finish_subobject (cleanup) tree cleanup; { - if (building_stmt_tree ()) - { - tree r = build_min_nt (SUBOBJECT, cleanup); - add_tree (r); - } - else - add_partial_entry (cleanup); + tree r = build_stmt (SUBOBJECT, cleanup); + add_stmt (r); } /* When DECL goes out of scope, make sure that CLEANUP is executed. */ @@ -1115,11 +967,33 @@ finish_decl_cleanup (decl, cleanup) tree decl; tree cleanup; { - if (building_stmt_tree ()) - add_tree (build_min_nt (CLEANUP_STMT, decl, cleanup)); - else if (!decl - || (DECL_SIZE (decl) && TREE_TYPE (decl) != error_mark_node)) - expand_decl_cleanup (decl, cleanup); + add_stmt (build_stmt (CLEANUP_STMT, decl, cleanup)); +} + +/* Generate the RTL for a RETURN_INIT. */ + +static void +genrtl_named_return_value () +{ + tree decl = DECL_RESULT (current_function_decl); + + /* If this named return value comes in a register, put it in a + pseudo-register. */ + if (DECL_REGISTER (decl)) + { + /* Note that the mode of the old DECL_RTL may be wider than the + mode of DECL_RESULT, depending on the calling conventions for + the processor. For example, on the Alpha, a 32-bit integer + is returned in a DImode register -- the DECL_RESULT has + SImode but the DECL_RTL for the DECL_RESULT has DImode. So, + here, we use the mode the back-end has already assigned for + the return value. */ + DECL_RTL (decl) = gen_reg_rtx (GET_MODE (DECL_RTL (decl))); + if (TREE_ADDRESSABLE (decl)) + put_var_into_stack (decl); + } + + emit_local_var (decl); } /* Bind a name and initialization to the return value of @@ -1131,11 +1005,12 @@ finish_named_return_value (return_id, init) { tree decl = DECL_RESULT (current_function_decl); + /* Give this error as many times as there are occurrences, so that + users can use Emacs compilation buffers to find and fix all such + places. */ if (pedantic) - /* Give this error as many times as there are occurrences, - so that users can use Emacs compilation buffers to find - and fix all such places. */ - pedwarn ("ANSI C++ does not permit named return values"); + pedwarn ("ISO C++ does not permit named return values"); + cp_deprecated ("the named return value extension"); if (return_id != NULL_TREE) { @@ -1165,15 +1040,78 @@ finish_named_return_value (return_id, init) DECL_INITIAL (decl) = init; if (doing_semantic_analysis_p ()) pushdecl (decl); + if (!processing_template_decl) + { + cp_finish_decl (decl, init, NULL_TREE, 0); + add_stmt (build_stmt (RETURN_INIT, NULL_TREE, NULL_TREE)); + } + else + add_stmt (build_stmt (RETURN_INIT, return_id, init)); + } + + /* Don't use tree-inlining for functions with named return values. + That doesn't work properly because we don't do any translation of + the RETURN_INITs when they are copied. */ + DECL_UNINLINABLE (current_function_decl) = 1; +} + +/* The INIT_LIST is a list of mem-initializers, in the order they were + written by the user. The TREE_VALUE of each node is a list of + initializers for a particular subobject. The TREE_PURPOSE is a + FIELD_DECL is the initializer is for a non-static data member, and + a class type if the initializer is for a base class. */ + +void +finish_mem_initializers (init_list) + tree init_list; +{ + tree member_init_list; + tree base_init_list; + tree last_base_warned_about; + tree next; + tree init; + + member_init_list = NULL_TREE; + base_init_list = NULL_TREE; + last_base_warned_about = NULL_TREE; + + for (init = init_list; init; init = next) + { + next = TREE_CHAIN (init); + if (TREE_CODE (TREE_PURPOSE (init)) == FIELD_DECL) + { + TREE_CHAIN (init) = member_init_list; + member_init_list = init; + + /* We're running through the initializers from right to left + as we process them here. So, if we see a data member + initializer after we see a base initializer, that + actually means that the base initializer preceeded the + data member initializer. */ + if (warn_reorder && last_base_warned_about != base_init_list) + { + tree base; + + for (base = base_init_list; + base != last_base_warned_about; + base = TREE_CHAIN (base)) + { + cp_warning ("base initializer for `%T'", + TREE_PURPOSE (base)); + warning (" will be re-ordered to precede member initializations"); + } - if (building_stmt_tree ()) - add_tree (build_min_nt (RETURN_INIT, return_id, init)); + last_base_warned_about = base_init_list; + } + } else { - cp_finish_decl (decl, init, NULL_TREE, 0, 0); - store_return_init (decl); + TREE_CHAIN (init) = base_init_list; + base_init_list = init; } } + + setup_vtbl_ptr (member_init_list, base_init_list); } /* Cache the value of this class's main virtual function table pointer @@ -1181,7 +1119,9 @@ finish_named_return_value (return_id, init) more than one virtual function call is made this function. */ void -setup_vtbl_ptr () +setup_vtbl_ptr (member_init_list, base_init_list) + tree member_init_list; + tree base_init_list; { my_friendly_assert (doing_semantic_analysis_p (), 19990919); @@ -1192,47 +1132,59 @@ setup_vtbl_ptr () if (DECL_CONSTRUCTOR_P (current_function_decl)) { if (processing_template_decl) - add_tree (build_min_nt + add_stmt (build_min_nt (CTOR_INITIALIZER, - current_member_init_list, current_base_init_list)); + member_init_list, base_init_list)); else - finish_expr_stmt (emit_base_init (current_class_type)); + { + tree ctor_stmt; + + /* Mark the beginning of the constructor. */ + ctor_stmt = build_stmt (CTOR_STMT); + CTOR_BEGIN_P (ctor_stmt) = 1; + add_stmt (ctor_stmt); + + /* And actually initialize the base-classes and members. */ + emit_base_init (member_init_list, base_init_list); + } } else if (DECL_DESTRUCTOR_P (current_function_decl) && !processing_template_decl) { - tree binfo = TYPE_BINFO (current_class_type); tree if_stmt; tree compound_stmt; + int saved_cfnd; - /* If the dtor is empty, and we know there is not possible way we - could use any vtable entries, before they are possibly set by - a base class dtor, we don't have to setup the vtables, as we - know that any base class dtoring will set up any vtables it - needs. We avoid MI, because one base class dtor can do a + /* If the dtor is empty, and we know there is not any possible + way we could use any vtable entries, before they are possibly + set by a base class dtor, we don't have to setup the vtables, + as we know that any base class dtor will set up any vtables + it needs. We avoid MI, because one base class dtor can do a virtual dispatch to an overridden function that would need to have a non-related vtable set up, we cannot avoid setting up - vtables in that case. We could change this to see if there is - just one vtable. */ + vtables in that case. We could change this to see if there + is just one vtable. */ if_stmt = begin_if_stmt (); /* If it is not safe to avoid setting up the vtables, then someone will change the condition to be boolean_true_node. (Actually, for now, we do not have code to set the condition - appropriate, so we just assume that we always need to + appropriately, so we just assume that we always need to initialize the vtables.) */ finish_if_stmt_cond (boolean_true_node, if_stmt); current_vcalls_possible_p = &IF_COND (if_stmt); + + /* Don't declare __PRETTY_FUNCTION__ and friends here when we + open the block for the if-body. */ + saved_cfnd = function_name_declared_p; + function_name_declared_p = 1; compound_stmt = begin_compound_stmt (/*has_no_scope=*/0); + 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 tables. */ - expand_direct_vtbls_init (binfo, binfo, 1, 0, current_class_ptr); - - if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) - expand_indirect_vtbls_init (binfo, current_class_ref, - current_class_ptr); + initialize_vtbl_ptrs (current_class_ptr); finish_compound_stmt (/*has_no_scope=*/0, compound_stmt); finish_then_clause (if_stmt); @@ -1248,67 +1200,12 @@ setup_vtbl_ptr () vtbls_set_up_p = 1; } -/* Begin a new scope. */ +/* Returns the stack of SCOPE_STMTs for the current function. */ -void -do_pushlevel () -{ - if (!building_stmt_tree ()) - { - emit_line_note (input_filename, lineno); - clear_last_expr (); - } - push_momentary (); - if (stmts_are_full_exprs_p) - { - pushlevel (0); - if (!building_stmt_tree () - && !current_function->x_whole_function_mode_p) - expand_start_bindings (0); - else if (building_stmt_tree () && !processing_template_decl) - { - tree ss = build_min_nt (SCOPE_STMT); - SCOPE_BEGIN_P (ss) = 1; - add_tree (ss); - current_scope_stmt_stack - = tree_cons (NULL_TREE, ss, current_scope_stmt_stack); - } - } -} - -/* Finish a scope. */ - -tree -do_poplevel () +tree * +current_scope_stmt_stack () { - tree t = NULL_TREE; - - if (stmts_are_full_exprs_p) - { - if (!building_stmt_tree () - && !current_function->x_whole_function_mode_p) - expand_end_bindings (getdecls (), kept_level_p (), 0); - else if (building_stmt_tree () && !processing_template_decl) - { - tree ss = build_min_nt (SCOPE_STMT); - SCOPE_NULLIFIED_P (ss) = !kept_level_p (); - SCOPE_NULLIFIED_P (TREE_VALUE (current_scope_stmt_stack)) - = SCOPE_NULLIFIED_P (ss); - add_tree (ss); - current_scope_stmt_stack = TREE_CHAIN (current_scope_stmt_stack); - - /* When not in function-at-a-time mode, expand_end_bindings - will warn about unused variables. But, in - function-at-a-time mode expand_end_bindings is not passed - the list of variables in the current scope, and therefore - no warning is emitted. So, we explicitly warn here. */ - warn_about_unused_variables (getdecls ()); - } - - t = poplevel (kept_level_p (), 1, 0); - } - pop_momentary (); - return t; + return &cfun->language->x_scope_stmt_stack; } /* Finish a parenthesized expression EXPR. */ @@ -1321,6 +1218,10 @@ finish_parenthesized_expr (expr) /* This inhibits warnings in truthvalue_conversion. */ C_SET_EXP_ORIGINAL_CODE (expr, ERROR_MARK); + if (TREE_CODE (expr) == OFFSET_REF) + /* [expr.unary.op]/3 The qualified id of a pointer-to-member must not be + enclosed in parentheses. */ + PTRMEM_OK_P (expr) = 0; return expr; } @@ -1333,7 +1234,7 @@ begin_stmt_expr () /* If we're outside a function, we won't have a statement-tree to work with. But, if we see a statement-expression we need to create one. */ - if (!current_function && !last_tree) + if (! cfun && !last_tree) begin_stmt_tree (&scope_chain->x_saved_tree); keep_next_level (1); @@ -1341,7 +1242,37 @@ begin_stmt_expr () statement will be chained onto the tree structure, starting at last_tree. We return last_tree so that we can later unhook the compound statement. */ - return building_stmt_tree () ? last_tree : expand_start_stmt_expr(); + return last_tree; +} + +/* Used when beginning a statement-expression outside function scope. + For example, when handling a file-scope initializer, we use this + function. */ + +tree +begin_global_stmt_expr () +{ + if (! cfun && !last_tree) + begin_stmt_tree (&scope_chain->x_saved_tree); + + keep_next_level (1); + + return (last_tree != NULL_TREE) ? last_tree : expand_start_stmt_expr(); +} + +/* Finish the STMT_EXPR last begun with begin_global_stmt_expr. */ + +tree +finish_global_stmt_expr (stmt_expr) + tree stmt_expr; +{ + stmt_expr = expand_end_stmt_expr (stmt_expr); + + if (! cfun + && TREE_CHAIN (scope_chain->x_saved_tree) == NULL_TREE) + finish_stmt_tree (&scope_chain->x_saved_tree); + + return stmt_expr; } /* Finish a statement-expression. RTL_EXPR should be the value @@ -1355,33 +1286,21 @@ finish_stmt_expr (rtl_expr) { tree result; - if (!building_stmt_tree ()) - { - rtl_expr = expand_end_stmt_expr (rtl_expr); - /* The statements have side effects, so the group does too. */ - TREE_SIDE_EFFECTS (rtl_expr) = 1; - } - - if (building_stmt_tree ()) - { - /* If the last thing in the statement-expression was not an - expression-statement, then it has type `void'. */ - if (!last_expr_type) - last_expr_type = void_type_node; - result = build_min (STMT_EXPR, last_expr_type, last_tree); - TREE_SIDE_EFFECTS (result) = 1; - - /* Remove the compound statement from the tree structure; it is - now saved in the STMT_EXPR. */ - SET_LAST_STMT (rtl_expr); - TREE_CHAIN (last_tree) = NULL_TREE; - } - else - result = rtl_expr; + /* If the last thing in the statement-expression was not an + expression-statement, then it has type `void'. */ + if (!last_expr_type) + last_expr_type = void_type_node; + result = build_min (STMT_EXPR, last_expr_type, last_tree); + TREE_SIDE_EFFECTS (result) = 1; + + /* Remove the compound statement from the tree structure; it is + now saved in the STMT_EXPR. */ + last_tree = rtl_expr; + TREE_CHAIN (last_tree) = NULL_TREE; /* If we created a statement-tree for this statement-expression, remove it now. */ - if (!current_function + if (! cfun && TREE_CHAIN (scope_chain->x_saved_tree) == NULL_TREE) finish_stmt_tree (&scope_chain->x_saved_tree); @@ -1484,7 +1403,7 @@ finish_object_call_expr (fn, object, args) tree real_fn = build_component_ref (object, fn, NULL_TREE, 1); return finish_call_expr (real_fn, args); #else - if (TREE_CODE (fn) == TYPE_DECL) + if (DECL_DECLARES_TYPE_P (fn)) { if (processing_template_decl) /* This can happen on code like: @@ -1508,7 +1427,7 @@ finish_object_call_expr (fn, object, args) } /* Finish a qualified member function call using OBJECT and ARGS as - arguments to FN. Returns an expressino for the call. */ + arguments to FN. Returns an expression for the call. */ tree finish_qualified_object_call_expr (fn, object, args) @@ -1578,6 +1497,9 @@ finish_label_address_expr (label) TREE_USED (label) = 1; result = build1 (ADDR_EXPR, ptr_type_node, label); TREE_CONSTANT (result) = 1; + /* This function cannot be inlined. All jumps to the addressed + label should wind up at the same point. */ + DECL_UNINLINABLE (current_function_decl) = 1; } return result; @@ -1591,7 +1513,13 @@ finish_unary_op_expr (code, expr) tree expr; { tree result = build_x_unary_op (code, expr); - if (code == NEGATE_EXPR && TREE_CODE (expr) == INTEGER_CST) + /* Inside a template, build_x_unary_op does not fold the + expression. So check whether the result is folded before + setting TREE_NEGATED_INT. */ + if (code == NEGATE_EXPR && TREE_CODE (expr) == INTEGER_CST + && TREE_CODE (result) == INTEGER_CST + && !TREE_UNSIGNED (TREE_TYPE (result)) + && INT_CST_LT (result, integer_zero_node)) TREE_NEGATED_INT (result) = 1; overflow_warning (result); return result; @@ -1609,33 +1537,55 @@ finish_id_expr (expr) return expr; } -/* Begin a new-placement. */ +static tree current_type_lookups; -int -begin_new_placement () +/* Perform deferred access control for types used in the type of a + declaration. */ + +static void +deferred_type_access_control () { - /* The arguments to a placement new might be passed to a - deallocation function, in the event that the allocation throws an - exception. Since we don't expand exception handlers until the - end of a function, we must make sure the arguments stay around - that long. */ - return suspend_momentary (); + tree lookup = type_lookups; + + if (lookup == error_mark_node) + return; + + for (; lookup; lookup = TREE_CHAIN (lookup)) + enforce_access (TREE_PURPOSE (lookup), TREE_VALUE (lookup)); } -/* Finish a new-placement. The ARGS are the placement arguments. The - COOKIE is the value returned by the previous call to - begin_new_placement. */ +void +decl_type_access_control (decl) + tree decl; +{ + tree save_fn; + + if (type_lookups == error_mark_node) + return; -tree -finish_new_placement (args, cookie) - tree args; - int cookie; + save_fn = current_function_decl; + + if (decl && TREE_CODE (decl) == FUNCTION_DECL) + current_function_decl = decl; + + deferred_type_access_control (); + + current_function_decl = save_fn; + + /* Now strip away the checks for the current declarator; they were + added to type_lookups after typed_declspecs saved the copy that + ended up in current_type_lookups. */ + type_lookups = current_type_lookups; +} + +void +save_type_access_control (lookups) + tree lookups; { - resume_momentary (cookie); - return args; + current_type_lookups = lookups; } -/* Begin a function defniition declared with DECL_SPECS and +/* Begin a function definition declared with DECL_SPECS and DECLARATOR. Returns non-zero if the function-declaration is legal. */ @@ -1646,11 +1596,14 @@ begin_function_definition (decl_specs, declarator) { tree specs; tree attrs; + split_specs_attrs (decl_specs, &specs, &attrs); if (!start_function (specs, declarator, attrs, SF_DEFAULT)) return 0; - - reinit_parse_for_function (); + + deferred_type_access_control (); + type_lookups = error_mark_node; + /* The things we're about to see are not directly qualified by any template headers we've seen thus far. */ reset_specialization (); @@ -1728,7 +1681,7 @@ finish_template_template_parm (aggr, identifier) tree tmpl = build_lang_decl (TEMPLATE_DECL, identifier, NULL_TREE); DECL_TEMPLATE_PARMS (tmpl) = current_template_parms; DECL_TEMPLATE_RESULT (tmpl) = decl; - SET_DECL_ARTIFICIAL (decl); + DECL_ARTIFICIAL (decl) = 1; end_template_decl (); return finish_template_type_parm (aggr, tmpl); @@ -1758,12 +1711,10 @@ tree begin_class_definition (t) tree t; { - push_permanent_obstack (); - if (t == error_mark_node || ! IS_AGGR_TYPE (t)) { - t = make_lang_type (RECORD_TYPE); + t = make_aggr_type (RECORD_TYPE); pushtag (make_anon_name (), t, 0); } @@ -1811,6 +1762,7 @@ begin_class_definition (t) TYPE_FIELDS (t) = NULL_TREE; TYPE_METHODS (t) = NULL_TREE; CLASSTYPE_TAGS (t) = NULL_TREE; + CLASSTYPE_VBASECLASSES (t) = NULL_TREE; TYPE_SIZE (t) = NULL_TREE; } @@ -1819,7 +1771,7 @@ begin_class_definition (t) } /* If this type was already complete, and we see another definition, that's an error. */ - else if (TYPE_SIZE (t)) + else if (COMPLETE_TYPE_P (t)) duplicate_tag_error (t); /* Update the location of the decl. */ @@ -1828,12 +1780,13 @@ begin_class_definition (t) if (TYPE_BEING_DEFINED (t)) { - t = make_lang_type (TREE_CODE (t)); + t = make_aggr_type (TREE_CODE (t)); pushtag (TYPE_IDENTIFIER (t), t, 0); } maybe_process_partial_specialization (t); pushclass (t, 1); TYPE_BEING_DEFINED (t) = 1; + TYPE_PACKED (t) = flag_pack_struct; /* Reset the interface data, at the earliest possible moment, as it might have been set via a class foo; before. */ @@ -1853,11 +1806,6 @@ begin_class_definition (t) || ! CLASSTYPE_INTERFACE_ONLY (t)) CLASSTYPE_VTABLE_NEEDS_WRITING (t) = 1; } -#if 0 - tmp = TYPE_IDENTIFIER ($0); - if (tmp && IDENTIFIER_TEMPLATE (tmp)) - overload_template_name (tmp, 1); -#endif reset_specialization(); /* Make a declaration for this class in its own scope. */ @@ -1890,19 +1838,19 @@ finish_member_declaration (decl) = (current_access_specifier == access_protected_node); if (TREE_CODE (decl) == TEMPLATE_DECL) { - TREE_PRIVATE (DECL_RESULT (decl)) = TREE_PRIVATE (decl); - TREE_PROTECTED (DECL_RESULT (decl)) = TREE_PROTECTED (decl); + TREE_PRIVATE (DECL_TEMPLATE_RESULT (decl)) = TREE_PRIVATE (decl); + TREE_PROTECTED (DECL_TEMPLATE_RESULT (decl)) = TREE_PROTECTED (decl); } /* Mark the DECL as a member of the current class. */ - if (TREE_CODE (decl) == FUNCTION_DECL - || DECL_FUNCTION_TEMPLATE_P (decl)) - /* Historically, DECL_CONTEXT was not set for a FUNCTION_DECL in - finish_struct. Presumably it is already set as the function is - parsed. Perhaps DECL_CLASS_CONTEXT is already set, too? */ - DECL_CLASS_CONTEXT (decl) = current_class_type; - else - DECL_CONTEXT (decl) = current_class_type; + DECL_CONTEXT (decl) = current_class_type; + + /* [dcl.link] + + A C language linkage is ignored for the names of class members + and the member function type of class member functions. */ + if (DECL_LANG_SPECIFIC (decl) && DECL_LANGUAGE (decl) == lang_c) + DECL_LANGUAGE (decl) = lang_cplusplus; /* Put functions on the TYPE_METHODS list and everything else on the TYPE_FIELDS list. Note that these are built up in reverse order. @@ -1912,7 +1860,7 @@ finish_member_declaration (decl) { /* We also need to add this function to the CLASSTYPE_METHOD_VEC. */ - add_method (current_class_type, 0, decl); + add_method (current_class_type, decl, /*error_p=*/0); TREE_CHAIN (decl) = TYPE_METHODS (current_class_type); TYPE_METHODS (current_class_type) = decl; @@ -1981,8 +1929,6 @@ finish_class_definition (t, attributes, semi, pop_scope_p) note_got_semicolon (t); } - pop_obstacks (); - if (! semi) check_for_missing_semicolon (t); if (pop_scope_p) @@ -1999,8 +1945,7 @@ finish_class_definition (t, attributes, semi, pop_scope_p) void begin_inline_definitions () { - if (pending_inlines - && current_scope () == current_function_decl) + if (current_scope () == current_function_decl) do_pending_inlines (); } @@ -2059,7 +2004,7 @@ finish_template_decl (parms) end_specialization (); } -/* Finish processing a a template-id (which names a type) of the form +/* Finish processing a template-id (which names a type) of the form NAME < ARGS >. Return the TYPE_DECL for the type named by the template-id. If ENTERING_SCOPE is non-zero we are about to enter the scope of template-id indicated. */ @@ -2173,10 +2118,8 @@ finish_typeof (expr) { tree t; - push_permanent_obstack (); - t = make_lang_type (TYPEOF_TYPE); + t = make_aggr_type (TYPEOF_TYPE); TYPE_FIELDS (t) = expr; - pop_obstacks (); return t; } @@ -2184,307 +2127,178 @@ finish_typeof (expr) return TREE_TYPE (expr); } -/* Create an empty statement tree rooted at T. */ +/* Generate RTL for the statement T, and its substatements, and any + other statements at its nesting level. */ -void -begin_stmt_tree (t) - tree *t; -{ - /* We create a trivial EXPR_STMT so that last_tree is never NULL in - what follows. We remove the extraneous statement in - finish_stmt_tree. */ - *t = build_nt (EXPR_STMT, void_zero_node); - SET_LAST_STMT (*t); - last_expr_type = NULL_TREE; -} +static void +cp_expand_stmt (t) + tree t; +{ + switch (TREE_CODE (t)) + { + case CLEANUP_STMT: + genrtl_decl_cleanup (CLEANUP_DECL (t), CLEANUP_EXPR (t)); + break; -/* Finish the statement tree rooted at T. */ + case START_CATCH_STMT: + genrtl_catch_block (TREE_TYPE (t)); + break; -void -finish_stmt_tree (t) - tree *t; -{ - tree stmt; - - /* Remove the fake extra statement added in begin_stmt_tree. */ - stmt = TREE_CHAIN (*t); - *t = stmt; - SET_LAST_STMT (NULL_TREE); + case CTOR_STMT: + genrtl_ctor_stmt (t); + break; - if (current_function) - { - /* The line-number recorded in the outermost statement in a function - is the line number of the end of the function. */ - STMT_LINENO (stmt) = lineno; - STMT_LINENO_FOR_FN_P (stmt) = 1; - } -} + case TRY_BLOCK: + genrtl_try_block (t); + break; -/* We're about to expand T, a statement. Set up appropriate context - for the substitution. */ + case HANDLER: + genrtl_handler (t); + break; -void -prep_stmt (t) - tree t; -{ - if (!STMT_LINENO_FOR_FN_P (t)) - lineno = STMT_LINENO (t); - stmts_are_full_exprs_p = STMT_IS_FULL_EXPR_P (t); -} + case SUBOBJECT: + genrtl_subobject (SUBOBJECT_CLEANUP (t)); + break; -/* Some statements, like for-statements or if-statements, require a - condition. This condition can be a declaration. If T is such a - declaration it is processed, and an expression appropriate to use - as the condition is returned. Otherwise, T itself is returned. */ + case RETURN_INIT: + genrtl_named_return_value (); + break; -static tree -expand_cond (t) - tree t; -{ - if (t && TREE_CODE (t) == TREE_LIST) - { - expand_stmt (TREE_PURPOSE (t)); - return TREE_VALUE (t); + default: + my_friendly_abort (19990810); + break; } - else - return t; } -/* Generate RTL for the statement T, and its substatements, and any - other statements at its nesting level. */ +/* Called from expand_body via walk_tree. Replace all AGGR_INIT_EXPRs + will equivalent CALL_EXPRs. */ -tree -expand_stmt (t) - tree t; -{ - tree rval = NULL_TREE; +static tree +simplify_aggr_init_exprs_r (tp, walk_subtrees, data) + tree *tp; + int *walk_subtrees ATTRIBUTE_UNUSED; + void *data ATTRIBUTE_UNUSED; +{ + tree aggr_init_expr; + tree call_expr; + tree fn; + tree args; + tree slot; + tree type; + tree call_type; + int copy_from_buffer_p; + + aggr_init_expr = *tp; + /* We don't need to walk into types; there's nothing in a type that + needs simplification. (And, furthermore, there are places we + actively don't want to go. For example, we don't want to wander + into the default arguments for a FUNCTION_DECL that appears in a + CALL_EXPR.) */ + if (TYPE_P (aggr_init_expr)) + { + *walk_subtrees = 0; + return NULL_TREE; + } + /* Only AGGR_INIT_EXPRs are interesting. */ + else if (TREE_CODE (aggr_init_expr) != AGGR_INIT_EXPR) + return NULL_TREE; + + /* Form an appropriate CALL_EXPR. */ + fn = TREE_OPERAND (aggr_init_expr, 0); + args = TREE_OPERAND (aggr_init_expr, 1); + slot = TREE_OPERAND (aggr_init_expr, 2); + type = TREE_TYPE (aggr_init_expr); + call_type = type; + if (AGGR_INIT_VIA_CTOR_P (aggr_init_expr)) + { + /* Replace the first argument with the address of the third + argument to the AGGR_INIT_EXPR. */ + call_type = build_pointer_type (type); + mark_addressable (slot); + args = tree_cons (NULL_TREE, build1 (ADDR_EXPR, call_type, slot), + TREE_CHAIN (args)); + } + call_expr = build (CALL_EXPR, call_type, fn, args, NULL_TREE); + TREE_SIDE_EFFECTS (call_expr) = 1; + + /* If we're using the non-reentrant PCC calling convention, then we + need to copy the returned value out of the static buffer into the + SLOT. */ + copy_from_buffer_p = 0; +#ifdef PCC_STATIC_STRUCT_RETURN + if (!AGGR_INIT_VIA_CTOR_P (aggr_init_expr) && aggregate_value_p (type)) + { + int old_ac; + + flag_access_control = 0; + call_expr = build_aggr_init (slot, call_expr, LOOKUP_ONLYCONVERTING); + flag_access_control = old_ac; + copy_from_buffer_p = 1; + } +#endif - while (t && t != error_mark_node) + /* If this AGGR_INIT_EXPR indicates the value returned by a + function, then we want to use the value of the initialized + location as the result. */ + if (AGGR_INIT_VIA_CTOR_P (aggr_init_expr) || copy_from_buffer_p) { - int saved_stmts_are_full_exprs_p; + call_expr = build (COMPOUND_EXPR, type, + call_expr, slot); + TREE_SIDE_EFFECTS (call_expr) = 1; + } - /* Assume we'll have nothing to return. */ - rval = NULL_TREE; + /* Replace the AGGR_INIT_EXPR with the CALL_EXPR. */ + TREE_CHAIN (call_expr) = TREE_CHAIN (aggr_init_expr); + *tp = call_expr; - /* Set up context appropriately for handling this statement. */ - saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p; - prep_stmt (t); + /* Keep iterating. */ + return NULL_TREE; +} - switch (TREE_CODE (t)) - { - case RETURN_STMT: - finish_return_stmt (RETURN_EXPR (t)); - break; - - case EXPR_STMT: - finish_expr_stmt (EXPR_STMT_EXPR (t)); - break; - - case DECL_STMT: - { - tree decl; - int i = suspend_momentary (); - - emit_line_note (input_filename, lineno); - decl = DECL_STMT_DECL (t); - /* If this is a declaration for an automatic local - variable, initialize it. Note that we might also see a - declaration for a namespace-scope object (declared with - `extern'). We don't have to handle the initialization - of those objects here; they can only be declarations, - rather than definitions. */ - if (TREE_CODE (decl) == VAR_DECL - && !TREE_STATIC (decl) - && !DECL_EXTERNAL (decl)) - { - /* Let the back-end know about this variable. */ - if (!ANON_AGGR_TYPE_P (TREE_TYPE (decl))) - emit_local_var (decl); - else - expand_anon_union_decl (decl, NULL_TREE, - DECL_ANON_UNION_ELEMS (decl)); - } - else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)) - rest_of_decl_compilation - (decl, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), - /*top_level=*/0, /*at_end=*/0); - - resume_momentary (i); - } - break; - - case CLEANUP_STMT: - finish_decl_cleanup (CLEANUP_DECL (t), CLEANUP_EXPR (t)); - break; - - case START_CATCH_STMT: - begin_catch_block (TREE_TYPE (t)); - break; - - case FOR_STMT: - { - tree tmp; - - begin_for_stmt (); - expand_stmt (FOR_INIT_STMT (t)); - finish_for_init_stmt (NULL_TREE); - finish_for_cond (expand_cond (FOR_COND (t)), NULL_TREE); - tmp = FOR_EXPR (t); - finish_for_expr (tmp, NULL_TREE); - expand_stmt (FOR_BODY (t)); - finish_for_stmt (tmp, NULL_TREE); - } - break; - - case WHILE_STMT: - { - begin_while_stmt (); - finish_while_stmt_cond (expand_cond (WHILE_COND (t)), NULL_TREE); - expand_stmt (WHILE_BODY (t)); - finish_while_stmt (NULL_TREE); - } - break; - - case DO_STMT: - { - begin_do_stmt (); - expand_stmt (DO_BODY (t)); - finish_do_body (NULL_TREE); - finish_do_stmt (DO_COND (t), NULL_TREE); - } - break; - - case IF_STMT: - begin_if_stmt (); - finish_if_stmt_cond (expand_cond (IF_COND (t)), NULL_TREE); - if (THEN_CLAUSE (t)) - { - expand_stmt (THEN_CLAUSE (t)); - finish_then_clause (NULL_TREE); - } - if (ELSE_CLAUSE (t)) - { - begin_else_clause (); - expand_stmt (ELSE_CLAUSE (t)); - finish_else_clause (NULL_TREE); - } - finish_if_stmt (); - break; - - case COMPOUND_STMT: - begin_compound_stmt (COMPOUND_STMT_NO_SCOPE (t)); - expand_stmt (COMPOUND_BODY (t)); - rval = finish_compound_stmt (COMPOUND_STMT_NO_SCOPE (t), - NULL_TREE); - break; - - case BREAK_STMT: - finish_break_stmt (); - break; - - case CONTINUE_STMT: - finish_continue_stmt (); - break; - - case SWITCH_STMT: - { - tree cond; - - begin_switch_stmt (); - cond = expand_cond (SWITCH_COND (t)); - finish_switch_cond (cond, NULL_TREE); - expand_stmt (SWITCH_BODY (t)); - finish_switch_stmt (cond, NULL_TREE); - } - break; - - case CASE_LABEL: - finish_case_label (CASE_LOW (t), CASE_HIGH (t)); - break; - - case LABEL_STMT: - expand_label (LABEL_STMT_LABEL (t)); - break; - - case GOTO_STMT: - finish_goto_stmt (GOTO_DESTINATION (t)); - break; - - case ASM_STMT: - finish_asm_stmt (ASM_CV_QUAL (t), ASM_STRING (t), ASM_OUTPUTS - (t), ASM_INPUTS (t), ASM_CLOBBERS (t)); - break; - - case TRY_BLOCK: - if (CLEANUP_P (t)) - { - expand_eh_region_start (); - expand_stmt (TRY_STMTS (t)); - finish_cleanup_try_block (NULL_TREE); - finish_cleanup (TRY_HANDLERS (t), NULL_TREE); - } - else - { - if (FN_TRY_BLOCK_P (t)) - begin_function_try_block (); - else - begin_try_block (); +/* Emit all thunks to FN that should be emitted when FN is emitted. */ - expand_stmt (TRY_STMTS (t)); +static void +emit_associated_thunks (fn) + tree fn; +{ + /* When we use vcall offsets, we emit thunks with the virtual + functions to which they thunk. The whole point of vcall offsets + is so that you can know statically the entire set of thunks that + will ever be needed for a given virtual function, thereby + enabling you to output all the thunks with the function itself. */ + if (vcall_offsets_in_vtable_p () && DECL_VIRTUAL_P (fn)) + { + tree binfo; + tree v; + + for (binfo = TYPE_BINFO (DECL_CONTEXT (fn)); + binfo; + binfo = TREE_CHAIN (binfo)) + for (v = BINFO_VIRTUALS (binfo); v; v = TREE_CHAIN (v)) + if (BV_FN (v) == fn + && (!integer_zerop (BV_DELTA (v)) + || BV_VCALL_INDEX (v))) + { + tree thunk; + tree vcall_index; - if (FN_TRY_BLOCK_P (t)) + if (BV_USE_VCALL_INDEX_P (v)) { - finish_function_try_block (NULL_TREE); - expand_stmt (TRY_HANDLERS (t)); - finish_function_handler_sequence (NULL_TREE); + vcall_index = BV_VCALL_INDEX (v); + my_friendly_assert (vcall_index != NULL_TREE, 20000621); } else - { - finish_try_block (NULL_TREE); - expand_stmt (TRY_HANDLERS (t)); - finish_handler_sequence (NULL_TREE); - } + vcall_index = NULL_TREE; + + thunk = make_thunk (build1 (ADDR_EXPR, + vfunc_ptr_type_node, + fn), + BV_DELTA (v), + vcall_index, + /*generate_with_vtable_p=*/0); + use_thunk (thunk, /*emit_p=*/1); } - break; - - case HANDLER: - begin_handler (); - expand_stmt (HANDLER_BODY (t)); - finish_handler (NULL_TREE, NULL_TREE); - break; - - case SUBOBJECT: - finish_subobject (SUBOBJECT_CLEANUP (t)); - break; - - case SCOPE_STMT: - if (SCOPE_BEGIN_P (t)) - expand_start_bindings (2 * SCOPE_NULLIFIED_P (t)); - else if (SCOPE_END_P (t)) - expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 0); - break; - - case RETURN_INIT: - /* Clear this out so that finish_named_return_value can set it - again. */ - DECL_NAME (DECL_RESULT (current_function_decl)) = NULL_TREE; - finish_named_return_value (TREE_OPERAND (t, 0), - TREE_OPERAND (t, 1)); - break; - - default: - my_friendly_abort (19990810); - break; - } - - /* Restore saved state. */ - stmts_are_full_exprs_p = saved_stmts_are_full_exprs_p; - - /* Go on to the next statement in this scope. */ - t = TREE_CHAIN (t); } - - return rval; } /* Generate RTL for FN. */ @@ -2494,7 +2308,7 @@ expand_body (fn) tree fn; { int saved_lineno; - char *saved_input_filename; + const char *saved_input_filename; /* When the parser calls us after finishing the body of a template function, we don't really want to expand the body. When we're @@ -2505,13 +2319,76 @@ expand_body (fn) || (DECL_LANG_SPECIFIC (fn) && DECL_TEMPLATE_INFO (fn) && uses_template_parms (DECL_TI_ARGS (fn)))) - return; + { + /* Normally, collection only occurs in rest_of_compilation. So, + if we don't collect here, we never collect junk generated + during the processing of templates until we hit a + non-template function. */ + ggc_collect (); + return; + } + + /* Replace AGGR_INIT_EXPRs with appropriate CALL_EXPRs. */ + walk_tree_without_duplicates (&DECL_SAVED_TREE (fn), + simplify_aggr_init_exprs_r, + NULL); + + /* If this is a constructor or destructor body, we have to clone it + under the new ABI. */ + if (maybe_clone_body (fn)) + { + /* We don't want to process FN again, so pretend we've written + it out, even though we haven't. */ + TREE_ASM_WRITTEN (fn) = 1; + return; + } /* There's no reason to do any of the work here if we're only doing semantic analysis; this code just generates RTL. */ if (flag_syntax_only) return; + /* If possible, avoid generating RTL for this function. Instead, + just record it as an inline function, and wait until end-of-file + to decide whether to write it out or not. */ + if (/* We have to generate RTL if it's not an inline function. */ + (DECL_INLINE (fn) || DECL_COMDAT (fn)) + /* Or if we have to keep all inline functions anyhow. */ + && !flag_keep_inline_functions + /* Or if we actually have a reference to the function. */ + && !DECL_NEEDED_P (fn) + /* Or if this is a nested function. */ + && !decl_function_context (fn)) + { + /* Give the function RTL now so that we can assign it to a + function pointer, etc. */ + make_function_rtl (fn); + /* Set DECL_EXTERNAL so that assemble_external will be called as + necessary. We'll clear it again in finish_file. */ + if (!DECL_EXTERNAL (fn)) + { + DECL_NOT_REALLY_EXTERN (fn) = 1; + DECL_EXTERNAL (fn) = 1; + } + /* Remember this function. In finish_file we'll decide if + we actually need to write this function out. */ + defer_fn (fn); + /* Let the back-end know that this funtion exists. */ + note_deferral_of_defined_inline_function (fn); + return; + } + + /* Emit any thunks that should be emitted at the same time as FN. */ + emit_associated_thunks (fn); + + timevar_push (TV_INTEGRATION); + + /* Optimize the body of the function before expanding it. */ + optimize_function (fn); + + timevar_pop (TV_INTEGRATION); + timevar_push (TV_EXPAND); + /* Save the current file name and line number. When we expand the body of the function, we'll set LINENO and INPUT_FILENAME so that error-mesages come out in the right places. */ @@ -2520,29 +2397,299 @@ expand_body (fn) lineno = DECL_SOURCE_LINE (fn); input_filename = DECL_SOURCE_FILE (fn); - start_function (NULL_TREE, fn, NULL_TREE, SF_PRE_PARSED | SF_EXPAND); - store_parm_decls (); + genrtl_start_function (fn); + current_function_is_thunk = DECL_THUNK_P (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. */ - current_function_name_declared = 1; + function_name_declared_p = 1; /* Expand the body. */ expand_stmt (DECL_SAVED_TREE (fn)); /* Statements should always be full-expressions at the outermost set of curly braces for a function. */ - my_friendly_assert (stmts_are_full_exprs_p, 19990831); + my_friendly_assert (stmts_are_full_exprs_p (), 19990831); /* The outermost statement for a function contains the line number recorded when we finished processing the function. */ lineno = STMT_LINENO (DECL_SAVED_TREE (fn)); /* Generate code for the function. */ - finish_function (lineno, 0); + genrtl_finish_function (fn); + + /* If possible, obliterate the body of the function so that it can + be garbage collected. */ + if (flag_dump_translation_unit) + /* Keep the body; we're going to dump it. */ + ; + else if (DECL_INLINE (fn) && flag_inline_trees) + /* We might need the body of this function so that we can expand + it inline somewhere else. */ + ; + else + /* We don't need the body; blow it away. */ + DECL_SAVED_TREE (fn) = NULL_TREE; /* And restore the current source position. */ lineno = saved_lineno; input_filename = saved_input_filename; + extract_interface_info (); + + timevar_pop (TV_EXPAND); +} + +/* Start generating the RTL for FN. */ + +static void +genrtl_start_function (fn) + tree fn; +{ + tree parm; + + /* Tell everybody what function we're processing. */ + current_function_decl = fn; + /* Get the RTL machinery going for this function. */ + init_function_start (fn, DECL_SOURCE_FILE (fn), DECL_SOURCE_LINE (fn)); + /* Let everybody know that we're expanding this function, not doing + semantic analysis. */ + expanding_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; + + /* Let the user know we're compiling this function. */ + announce_function (fn); + + /* Initialize the per-function data. */ + my_friendly_assert (!DECL_PENDING_INLINE_P (fn), 20000911); + if (DECL_SAVED_FUNCTION_DATA (fn)) + { + /* If we already parsed this function, and we're just expanding it + now, restore saved state. */ + *cp_function_chain = *DECL_SAVED_FUNCTION_DATA (fn); + + /* This function is being processed in whole-function mode; we + already did semantic analysis. */ + cfun->x_whole_function_mode_p = 1; + + /* If we decided that we didn't want to inline this function, + make sure the back-end knows that. */ + if (!current_function_cannot_inline) + current_function_cannot_inline = cp_function_chain->cannot_inline; + + /* We don't need the saved data anymore. */ + free (DECL_SAVED_FUNCTION_DATA (fn)); + DECL_SAVED_FUNCTION_DATA (fn) = NULL; + } + + /* Tell the cross-reference machinery that we're defining this + function. */ + GNU_xref_function (fn, DECL_ARGUMENTS (fn)); + + /* Keep track of how many functions we're presently expanding. */ + ++function_depth; + + /* Create a binding level for the parameters. */ + expand_start_bindings (2); + /* Clear out any previously saved instructions for this function, in + case it was defined more than once. */ + DECL_SAVED_INSNS (fn) = NULL; + /* Go through the PARM_DECLs for this function to see if any need + cleanups. */ + for (parm = DECL_ARGUMENTS (fn); parm; parm = TREE_CHAIN (parm)) + if (TREE_TYPE (parm) != error_mark_node + && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (parm))) + { + expand_function_start (fn, /*parms_have_cleanups=*/1); + break; + } + if (!parm) + expand_function_start (fn, /*parms_have_cleanups=*/0); + /* If this function is `main'. */ + if (DECL_MAIN_P (fn)) + expand_main_function (); + /* Create a binding contour which can be used to catch + cleanup-generated temporaries. */ + expand_start_bindings (2); +} + +/* Finish generating the RTL for FN. */ + +static void +genrtl_finish_function (fn) + tree fn; +{ + tree no_return_label = NULL_TREE; + +#if 0 + if (write_symbols != NO_DEBUG) + { + /* Keep this code around in case we later want to control debug info + based on whether a type is "used". (jason 1999-11-11) */ + + tree ttype = target_type (fntype); + tree parmdecl; + + if (IS_AGGR_TYPE (ttype)) + /* Let debugger know it should output info for this type. */ + note_debug_info_needed (ttype); + + for (parmdecl = DECL_ARGUMENTS (fndecl); parmdecl; parmdecl = TREE_CHAIN (parmdecl)) + { + ttype = target_type (TREE_TYPE (parmdecl)); + if (IS_AGGR_TYPE (ttype)) + /* Let debugger know it should output info for this type. */ + note_debug_info_needed (ttype); + } + } +#endif + + /* Clean house because we will need to reorder insns here. */ + do_pending_stack_adjust (); + + if (!dtor_label && !DECL_CONSTRUCTOR_P (fn) + && return_label != NULL_RTX + && current_function_return_value == NULL_TREE + && ! DECL_NAME (DECL_RESULT (current_function_decl))) + no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + + if (flag_exceptions) + expand_exception_blocks (); + + /* If this function is supposed to return a value, ensure that + we do not fall into the cleanups by mistake. The end of our + function will look like this: + + user code (may have return stmt somewhere) + goto no_return_label + cleanup_label: + cleanups + goto return_label + no_return_label: + NOTE_INSN_FUNCTION_END + return_label: + things for return + + If the user omits a return stmt in the USER CODE section, we + will have a control path which reaches NOTE_INSN_FUNCTION_END. + Otherwise, we won't. */ + if (no_return_label) + { + DECL_CONTEXT (no_return_label) = fn; + DECL_INITIAL (no_return_label) = error_mark_node; + DECL_SOURCE_FILE (no_return_label) = input_filename; + DECL_SOURCE_LINE (no_return_label) = lineno; + expand_goto (no_return_label); + } + + if (cleanup_label) + { + /* Remove the binding contour which is used to catch + cleanup-generated temporaries. */ + expand_end_bindings (0, 0, 0); + poplevel (0, 0, 0); + + /* Emit label at beginning of cleanup code for parameters. */ + emit_label (cleanup_label); + } + + /* Finish building code that will trigger warnings if users forget + to make their functions return values. */ + emit_jump (return_label); + if (no_return_label) + { + /* We don't need to call `expand_*_return' here because we don't + need any cleanups here--this path of code is only for error + checking purposes. */ + expand_label (no_return_label); + } + + /* 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; + + /* Generate rtl for function exit. */ + expand_function_end (input_filename, lineno, 1); + + /* If this is a nested function (like a template instantiation that + we're compiling in the midst of compiling something else), push a + new GC context. That will keep local variables on the stack from + being collected while we're doing the compilation of this + function. */ + if (function_depth > 1) + ggc_push_context (); + + /* Run the optimizers and output the assembler code for this + function. */ + rest_of_compilation (fn); + + /* Undo the call to ggc_push_context above. */ + if (function_depth > 1) + ggc_pop_context (); + + if (DECL_SAVED_INSNS (fn) && ! TREE_ASM_WRITTEN (fn)) + { + /* Set DECL_EXTERNAL so that assemble_external will be called as + necessary. We'll clear it again in finish_file. */ + if (! DECL_EXTERNAL (fn)) + DECL_NOT_REALLY_EXTERN (fn) = 1; + DECL_EXTERNAL (fn) = 1; + defer_fn (fn); + } + +#if 0 + /* Keep this code around in case we later want to control debug info + based on whether a type is "used". (jason 1999-11-11) */ + + if (ctype && TREE_ASM_WRITTEN (fn)) + note_debug_info_needed (ctype); +#endif + + /* If this function is marked with the constructor attribute, add it + to the list of functions to be called along with constructors + from static duration objects. */ + if (DECL_STATIC_CONSTRUCTOR (fn)) + static_ctors = tree_cons (NULL_TREE, fn, static_ctors); + + /* If this function is marked with the destructor attribute, add it + to the list of functions to be called along with destructors from + static duration objects. */ + if (DECL_STATIC_DESTRUCTOR (fn)) + static_dtors = tree_cons (NULL_TREE, fn, static_dtors); + + --function_depth; + + if (!DECL_SAVED_INSNS (fn) + && !(flag_inline_trees && DECL_INLINE (fn))) + { + tree t; + + /* Stop pointing to the local nodes about to be freed. */ + /* But DECL_INITIAL must remain nonzero so we know this + was an actual function definition. */ + DECL_INITIAL (fn) = error_mark_node; + for (t = DECL_ARGUMENTS (fn); t; t = TREE_CHAIN (t)) + DECL_RTL (t) = DECL_INCOMING_RTL (t) = NULL_RTX; + } + + /* Let the error reporting routines know that we're outside a + function. For a nested function, this value is used in + pop_cp_function_context and then reset via pop_function_context. */ + current_function_decl = NULL_TREE; +} + +/* Perform initialization related to this module. */ + +void +init_cp_semantics () +{ + lang_expand_stmt = cp_expand_stmt; }