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.
#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
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. */
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;
{
{
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 ();
last_expr_type = expr ? TREE_TYPE (expr) : NULL_TREE;
}
+
/* Begin an if-statement. Returns a newly created IF_STMT if
appropriate. */
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;
}
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
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. */
void
begin_else_clause ()
{
- if (!building_stmt_tree ())
- expand_start_else ();
}
/* Finish the else-clause of an if-statement, which may be given by
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. */
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. */
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
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. */
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 ();
}
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. */
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
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 ();
}
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)
{
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 ();
}
{
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 ();
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 ();
}
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
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
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 ();
}
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. */
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
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;
}
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);
}
}
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. */
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. */
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
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
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. */
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;
}
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. */
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. */
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;
}
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. */
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
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
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
/* 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. */
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
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])
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. */
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
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
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. */
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
{
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)
{
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
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);
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);
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. */
/* 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;
}
/* 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);
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
{
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);
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:
}
/* 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)
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;
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;
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. */
{
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 ();
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);
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);
}
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;
}
}
/* 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. */
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. */
|| ! CLASSTYPE_INTERFACE_ONLY (t))
CLASSTYPE_VTABLE_NEEDS_WRITING (t) = 1;
}
-#if 0
- tmp = TYPE_IDENTIFIER ($<ttype>0);
- if (tmp && IDENTIFIER_TEMPLATE (tmp))
- overload_template_name (tmp, 1);
-#endif
reset_specialization();
/* Make a declaration for this class in its own scope. */
= (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.
{
/* 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;
note_got_semicolon (t);
}
- pop_obstacks ();
-
if (! semi)
check_for_missing_semicolon (t);
if (pop_scope_p)
void
begin_inline_definitions ()
{
- if (pending_inlines
- && current_scope () == current_function_decl)
+ if (current_scope () == current_function_decl)
do_pending_inlines ();
}
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. */
{
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;
}
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. */
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
|| (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. */
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;
}