building RTL. These routines are used both during actual parsing
and during the instantiation of template functions.
- Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
Written by Mark Mitchell (mmitchell@usa.net) based on code found
formerly in parse.y and pt.c.
#include "flags.h"
#include "ggc.h"
#include "rtl.h"
+#include "expr.h"
#include "output.h"
#include "timevar.h"
static tree maybe_convert_cond PARAMS ((tree));
static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *));
-static tree prune_unused_decls PARAMS ((tree *, int *, void *));
static void deferred_type_access_control PARAMS ((void));
static void emit_associated_thunks PARAMS ((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 void genrtl_try_block PARAMS ((tree));
+static void genrtl_eh_spec_block PARAMS ((tree));
+static void genrtl_handler 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));
+static tree clear_decl_rtl PARAMS ((tree *, int *, void *));
/* Finish processing the COND, the SUBSTMT condition for STMT. */
substmt = cond; \
} while (0)
-/* Wrapper since C and C++ expand_expr_stmt are different. */
-
-expand_expr_stmt_fn lang_expand_expr_stmt = cplus_expand_expr_stmt;
-
-/* Wrapper function instead of #define for use with c-common code. */
-
-void
-set_current_function_name_declared (i)
- int i;
-{
- cp_function_chain->name_declared = i;
-}
-
/* Returns non-zero if the current statement is a full expression,
i.e. temporaries created during that statement should be destroyed
at the end of the statement. */
int
stmts_are_full_exprs_p ()
{
- return current_stmt_tree->stmts_are_full_exprs_p;
+ return current_stmt_tree ()->stmts_are_full_exprs_p;
}
-/* One if we have already declared __FUNCTION__ (and related
- variables) in the current function. Two if we are in the process
- of doing so. */
+/* Returns the stmt_tree (if any) to which statements are currently
+ being added. If there is no active statement-tree, NULL is
+ returned. */
-int
-current_function_name_declared ()
+stmt_tree
+current_stmt_tree ()
{
- return cp_function_chain->name_declared;
+ 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
}
}
-/* T is a statement. Add it to the statement-tree. */
-
-void
-add_tree (t)
- tree t;
-{
- /* Add T to the statement-tree. */
- TREE_CHAIN (last_tree) = t;
- SET_LAST_STMT (t);
- /* When we expand a statement-tree, we must know whether or not the
- statements are full-expresions. We record that fact here. */
- STMT_IS_FULL_EXPR_P (last_tree) = stmts_are_full_exprs_p ();
-}
-
/* Finish a goto-statement. */
-void
+tree
finish_goto_stmt (destination)
tree destination;
{
check_goto (destination);
- add_tree (build_stmt (GOTO_STMT, destination));
+ return add_stmt (build_stmt (GOTO_STMT, destination));
}
/* COND is the condition-expression for an if, while, etc.,
/* Finish an expression-statement, whose EXPRESSION is as indicated. */
-void
+tree
finish_expr_stmt (expr)
tree expr;
{
+ tree r = NULL_TREE;
+
if (expr != NULL_TREE)
{
if (!processing_template_decl
if (stmts_are_full_exprs_p ())
expr = convert_to_void (expr, "statement");
- if (!processing_template_decl)
- expr = break_out_cleanups (expr);
-
- add_tree (build_stmt (EXPR_STMT, expr));
+ r = add_stmt (build_stmt (EXPR_STMT, expr));
}
finish_stmt ();
/* This was an expression-statement, so we save the type of the
expression. */
last_expr_type = expr ? TREE_TYPE (expr) : NULL_TREE;
+
+ return r;
}
tree r;
do_pushlevel ();
r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
- add_tree (r);
+ add_stmt (r);
return r;
}
tree if_stmt;
{
RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt));
- SET_LAST_STMT (if_stmt);
+ last_tree = if_stmt;
return if_stmt;
}
RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt));
}
-/* Finsh an if-statement. */
+/* Finish an if-statement. */
void
finish_if_stmt ()
{
tree r;
r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE);
- add_tree (r);
+ add_stmt (r);
do_pushlevel ();
return r;
}
begin_do_stmt ()
{
tree r = build_stmt (DO_STMT, NULL_TREE, NULL_TREE);
- add_tree (r);
+ add_stmt (r);
return r;
}
/* Finish a return-statement. The EXPRESSION returned, if any, is as
indicated. */
-void
+tree
finish_return_stmt (expr)
tree expr;
{
+ tree r;
+
if (!processing_template_decl)
expr = check_return_expr (expr);
if (!processing_template_decl)
return a value there. When we finally generate the real
return statement, CTOR_LABEL is no longer set, and we fall
through into the normal return-processing code below. */
- finish_goto_stmt (ctor_label);
- return;
+ return finish_goto_stmt (ctor_label);
}
else if (DECL_DESTRUCTOR_P (current_function_decl))
{
/* Similarly, all destructors must run destructors for
base-classes before returning. So, all returns in a
- destructor get sent to the DTOR_LABEL; finsh_function emits
+ destructor get sent to the DTOR_LABEL; finish_function emits
code to return a value there. */
- finish_goto_stmt (dtor_label);
- return;
+ return finish_goto_stmt (dtor_label);
}
}
- add_tree (build_stmt (RETURN_STMT, expr));
+ r = add_stmt (build_stmt (RETURN_STMT, expr));
finish_stmt ();
+
+ return r;
}
/* Begin a for-statement. Returns a new FOR_STMT if appropriate. */
r = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE,
NULL_TREE, NULL_TREE);
NEW_FOR_SCOPE_P (r) = flag_new_for_scope > 0;
- add_tree (r);
+ add_stmt (r);
if (NEW_FOR_SCOPE_P (r))
{
do_pushlevel ();
/* Finish a break-statement. */
-void
+tree
finish_break_stmt ()
{
- add_tree (build_stmt (BREAK_STMT));
+ return add_stmt (build_break_stmt ());
}
/* Finish a continue-statement. */
-void
+tree
finish_continue_stmt ()
{
- add_tree (build_stmt (CONTINUE_STMT));
+ return add_stmt (build_continue_stmt ());
}
/* Begin a switch-statement. Returns a new SWITCH_STMT if
{
tree r;
r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE);
- add_tree (r);
+ add_stmt (r);
do_pushlevel ();
return r;
}
{
if (!processing_template_decl)
{
+ tree type;
+ tree index;
+
/* Convert the condition to an integer or enumeration type. */
cond = build_expr_type_conversion (WANT_INT | WANT_ENUM, cond, 1);
if (cond == NULL_TREE)
cond = default_conversion (cond);
cond = fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (cond), cond));
}
+
+ 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 ();
+ push_switch (switch_stmt);
}
/* Finish the body of a switch-statement, which may be given by
finish_stmt ();
}
-/* Finish a case-label. */
-
-void
-finish_case_label (low_value, high_value)
- tree low_value;
- tree high_value;
-{
- /* Add a representation for the case label to the statement
- tree. */
- add_tree (build_stmt (CASE_LABEL, low_value, high_value));
- /* And warn about crossing initializations, etc. */
- if (!processing_template_decl)
- define_case_label ();
-}
-
/* Generate the RTL for T, which is a TRY_BLOCK. */
-void genrtl_try_block (t)
+static void
+genrtl_try_block (t)
tree t;
{
if (CLEANUP_P (t))
{
expand_eh_region_start ();
expand_stmt (TRY_STMTS (t));
- expand_eh_region_end (protect_with_terminate (TRY_HANDLERS (t)));
+ expand_eh_region_end_cleanup (TRY_HANDLERS (t));
}
else
{
- if (FN_TRY_BLOCK_P (t)) {
- if (! current_function_parms_stored)
- store_parm_decls ();
- expand_start_early_try_stmts ();
- }
- else {
+ if (!FN_TRY_BLOCK_P (t))
emit_line_note (input_filename, lineno);
- expand_start_try_stmts ();
- }
+ expand_eh_region_start ();
expand_stmt (TRY_STMTS (t));
if (FN_TRY_BLOCK_P (t))
}
}
+/* Generate the RTL for T, which is an EH_SPEC_BLOCK. */
+
+static void
+genrtl_eh_spec_block (t)
+ tree t;
+{
+ expand_eh_region_start ();
+ expand_stmt (EH_SPEC_STMTS (t));
+ expand_eh_region_end_allowed (EH_SPEC_RAISES (t),
+ build_call (call_unexpected_node,
+ tree_cons (NULL_TREE,
+ build_exc_ptr (),
+ NULL_TREE)));
+}
+
/* Begin a try-block. Returns a newly-created TRY_BLOCK if
appropriate. */
begin_try_block ()
{
tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
- add_tree (r);
+ add_stmt (r);
return r;
}
{
tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
FN_TRY_BLOCK_P (r) = 1;
- add_tree (r);
+ add_stmt (r);
return r;
}
/* Generate the RTL for T, which is a HANDLER. */
-void
+static void
genrtl_handler (t)
tree t;
{
genrtl_do_pushlevel ();
+ if (!processing_template_decl)
+ expand_start_catch (HANDLER_TYPE (t));
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 ();
- }
+ expand_end_catch ();
}
/* Begin a handler. Returns a HANDLER if appropriate. */
{
tree r;
r = build_stmt (HANDLER, NULL_TREE, NULL_TREE);
- add_tree (r);
+ add_stmt (r);
+ /* Create a binding level for the eh_info and the exception object
+ cleanup. */
do_pushlevel ();
+ note_level_for_catch ();
return r;
}
HANDLER. DECL is the declaration for the catch parameter, or NULL
if this is a `catch (...)' clause. */
-tree
+void
finish_handler_parms (decl, handler)
tree decl;
tree handler;
{
- tree blocks = NULL_TREE;
-
+ tree type = NULL_TREE;
if (processing_template_decl)
{
if (decl)
decl = push_template_decl (decl);
add_decl_stmt (decl);
RECHAIN_STMTS (handler, HANDLER_PARMS (handler));
+ type = TREE_TYPE (decl);
}
}
else
- blocks = expand_start_catch_block (decl);
+ type = expand_start_catch_block (decl);
- if (decl)
- TREE_TYPE (handler) = TREE_TYPE (decl);
-
- return blocks;
-}
-
-/* Generate the RTL for a CATCH_BLOCK. */
-
-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. */
-
-void
-begin_catch_block (type)
- tree type;
-{
- add_tree (build (START_CATCH_STMT, type));
+ HANDLER_TYPE (handler) = type;
}
/* Finish a handler, which may be given by HANDLER. The BLOCKs are
the return value from the matching call to finish_handler_parms. */
void
-finish_handler (blocks, handler)
- tree blocks;
+finish_handler (handler)
tree handler;
{
if (!processing_template_decl)
- expand_end_catch_block (blocks);
+ expand_end_catch_block ();
do_poplevel ();
RECHAIN_STMTS (handler, HANDLER_BODY (handler));
}
/* Generate the RTL for T, which is a CTOR_STMT. */
-void
+static void
genrtl_ctor_stmt (t)
tree t;
{
if (last_tree && TREE_CODE (last_tree) == TRY_BLOCK)
is_try = 1;
- add_tree (r);
+ add_stmt (r);
if (has_no_scope)
COMPOUND_STMT_NO_SCOPE (r) = 1;
{
do_pushlevel ();
if (is_try)
- note_level_for_eh ();
+ note_level_for_try ();
}
else
/* Normally, we try hard to keep the BLOCK for a
to accidentally keep a block *inside* the scopeless block. */
keep_next_level (0);
- /* If this is the outermost block of the function, declare the
- variables __FUNCTION__, __PRETTY_FUNCTION__, and so forth. */
- if (cfun
- && !(current_function_name_declared () )
- && !has_no_scope)
- {
- cp_function_chain->name_declared = 1;
- declare_function_name ();
- }
-
return r;
}
STRING, some OUTPUT_OPERANDS, some INPUT_OPERANDS, and some
CLOBBERS. */
-void
+tree
finish_asm_stmt (cv_qualifier, string, output_operands,
input_operands, clobbers)
tree cv_qualifier;
if (!processing_template_decl)
for (t = input_operands; t; t = TREE_CHAIN (t))
- TREE_VALUE (t) = decay_conversion (TREE_VALUE (t));
+ {
+ tree converted_operand
+ = decay_conversion (TREE_VALUE (t));
+
+ /* If the type of the operand hasn't been determined (e.g.,
+ because it involves an overloaded function), then issue an
+ error message. There's no context available to resolve the
+ overloading. */
+ if (TREE_TYPE (converted_operand) == unknown_type_node)
+ {
+ cp_error ("type of asm operand `%E' could not be determined",
+ TREE_VALUE (t));
+ converted_operand = error_mark_node;
+ }
+ TREE_VALUE (t) = converted_operand;
+ }
r = build_stmt (ASM_STMT, cv_qualifier, string,
output_operands, input_operands,
clobbers);
- add_tree (r);
+ return add_stmt (r);
}
/* Finish a label with the indicated NAME. */
tree name;
{
tree decl = define_label (input_filename, lineno, name);
- add_tree (build_stmt (LABEL_STMT, decl));
+ add_stmt (build_stmt (LABEL_STMT, decl));
}
/* Finish a series of declarations for local labels. G++ allows users
add_decl_stmt (decl);
}
-/* Create a declaration statement for the declaration given by the
- DECL. */
-
-void
-add_decl_stmt (decl)
- tree decl;
-{
- tree decl_stmt;
-
- /* We need the type to last until instantiation time. */
- decl_stmt = build_stmt (DECL_STMT, decl);
- add_tree (decl_stmt);
-}
-
/* Generate the RTL for a SUBOBJECT. */
-void
+static void
genrtl_subobject (cleanup)
tree cleanup;
{
tree cleanup;
{
tree r = build_stmt (SUBOBJECT, cleanup);
- add_tree (r);
+ add_stmt (r);
}
/* When DECL goes out of scope, make sure that CLEANUP is executed. */
tree decl;
tree cleanup;
{
- add_tree (build_stmt (CLEANUP_STMT, decl, cleanup));
+ add_stmt (build_stmt (CLEANUP_STMT, decl, cleanup));
}
/* Generate the RTL for a RETURN_INIT. */
-void
-genrtl_named_return_value (return_id, init)
- tree return_id, init;
+static void
+genrtl_named_return_value ()
{
- tree decl;
- /* Clear this out so that finish_named_return_value can set it
- again. */
- DECL_NAME (DECL_RESULT (current_function_decl)) = NULL_TREE;
-
- decl = DECL_RESULT (current_function_decl);
- 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 ("ISO C++ does not permit named return values");
-
- if (return_id != NULL_TREE)
- {
- if (DECL_NAME (decl) == NULL_TREE)
- {
- DECL_NAME (decl) = return_id;
- DECL_ASSEMBLER_NAME (decl) = return_id;
- }
- else
- {
- cp_error ("return identifier `%D' already in place", return_id);
- return;
- }
- }
-
- /* Can't let this happen for constructors. */
- if (DECL_CONSTRUCTOR_P (current_function_decl))
- {
- error ("can't redefine default return value for constructors");
- return;
- }
+ tree decl = DECL_RESULT (current_function_decl);
- /* If we have a named return value, put that in our scope as well. */
- if (DECL_NAME (decl) != NULL_TREE)
+ /* If this named return value comes in a register, put it in a
+ pseudo-register. */
+ if (DECL_REGISTER (decl))
{
- /* Let `cp_finish_decl' know that this initializer is ok. */
- DECL_INITIAL (decl) = init;
- cp_finish_decl (decl, init, NULL_TREE, 0);
- store_return_init (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. */
+ SET_DECL_RTL (decl, gen_reg_rtx (GET_MODE (DECL_RTL (decl))));
+ if (TREE_ADDRESSABLE (decl))
+ put_var_into_stack (decl);
}
- /* 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;
+ 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 ("ISO C++ does not permit named return values");
+ cp_deprecated ("the named return value extension");
if (return_id != NULL_TREE)
{
if (DECL_NAME (decl) == NULL_TREE)
- {
- DECL_NAME (decl) = return_id;
- DECL_ASSEMBLER_NAME (decl) = return_id;
- }
+ DECL_NAME (decl) = return_id;
else
{
cp_error ("return identifier `%D' already in place", return_id);
DECL_INITIAL (decl) = init;
if (doing_semantic_analysis_p ())
pushdecl (decl);
- add_tree (build_stmt (RETURN_INIT, return_id, init));
+ 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.
if (DECL_CONSTRUCTOR_P (current_function_decl))
{
if (processing_template_decl)
- add_tree (build_min_nt
+ add_stmt (build_min_nt
(CTOR_INITIALIZER,
member_init_list, base_init_list));
else
/* Mark the beginning of the constructor. */
ctor_stmt = build_stmt (CTOR_STMT);
CTOR_BEGIN_P (ctor_stmt) = 1;
- add_tree (ctor_stmt);
+ add_stmt (ctor_stmt);
/* And actually initialize the base-classes and members. */
emit_base_init (member_init_list, base_init_list);
{
tree if_stmt;
tree compound_stmt;
- int saved_cfnd;
/* If the dtor is empty, and we know there is not any possible
way we could use any vtable entries, before they are possibly
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 = current_function_name_declared ();
- cp_function_chain->name_declared = 1;
compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
- cp_function_chain->name_declared = saved_cfnd;
/* Make all virtual function table pointers in non-virtual base
classes point to CURRENT_CLASS_TYPE's virtual function
vtbls_set_up_p = 1;
}
+/* Returns the stack of SCOPE_STMTs for the current function. */
-/* Add a scope-statement to the statement-tree. BEGIN_P indicates
- whether this statements opens or closes a scope. PARTIAL_P is true
- for a partial scope, i.e, the scope that begins after a label when
- an object that needs a cleanup is created. If BEGIN_P is nonzero,
- returns a new TREE_LIST representing the top of the SCOPE_STMT
- stack. The TREE_PURPOSE is the new SCOPE_STMT. If BEGIN_P is
- zero, returns a TREE_LIST whose TREE_VALUE is the new SCOPE_STMT,
- and whose TREE_PURPOSE is the matching SCOPE_STMT iwth
- SCOPE_BEGIN_P set. */
-
-tree
-add_scope_stmt (begin_p, partial_p)
- int begin_p;
- int partial_p;
+tree *
+current_scope_stmt_stack ()
{
- tree ss;
- tree top;
-
- /* Build the statement. */
- ss = build_stmt (SCOPE_STMT, NULL_TREE);
- SCOPE_BEGIN_P (ss) = begin_p;
- SCOPE_PARTIAL_P (ss) = partial_p;
-
- /* Keep the scope stack up to date. */
- if (begin_p)
- {
- current_scope_stmt_stack
- = tree_cons (ss, NULL_TREE, current_scope_stmt_stack);
- top = current_scope_stmt_stack;
- }
- else
- {
- top = current_scope_stmt_stack;
- TREE_VALUE (top) = ss;
- current_scope_stmt_stack = TREE_CHAIN (top);
- }
-
- /* Add the new statement to the statement-tree. */
- add_tree (ss);
-
- return top;
+ return &cfun->language->x_scope_stmt_stack;
}
/* Finish a parenthesized expression EXPR. */
/* Remove the compound statement from the tree structure; it is
now saved in the STMT_EXPR. */
- SET_LAST_STMT (rtl_expr);
+ last_tree = rtl_expr;
TREE_CHAIN (last_tree) = NULL_TREE;
/* If we created a statement-tree for this statement-expression,
}
/* 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)
args);
}
-/* Finish an expression taking the address of LABEL. Returns an
- expression for the address. */
-
-tree
-finish_label_address_expr (label)
- tree label;
-{
- tree result;
-
- label = lookup_label (label);
- if (label == NULL_TREE)
- result = null_pointer_node;
- else
- {
- 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;
-}
-
/* Finish an expression of the form CODE EXPR. */
tree
if (TREE_CODE (expr) == IDENTIFIER_NODE)
expr = do_identifier (expr, 1, NULL_TREE);
+ if (TREE_TYPE (expr) == error_mark_node)
+ expr = error_mark_node;
return expr;
}
added to type_lookups after typed_declspecs saved the copy that
ended up in current_type_lookups. */
type_lookups = current_type_lookups;
+
+ current_type_lookups = NULL_TREE;
}
+/* Record the lookups, if we're doing deferred access control. */
+
void
save_type_access_control (lookups)
tree lookups;
{
- current_type_lookups = lookups;
+ if (type_lookups != error_mark_node)
+ {
+ my_friendly_assert (!current_type_lookups, 20010301);
+ current_type_lookups = lookups;
+ }
+ else
+ my_friendly_assert (!lookups || lookups == error_mark_node, 20010301);
+}
+
+/* Set things up so that the next deferred access control will succeed.
+ This is needed for friend declarations see grokdeclarator for details. */
+
+void
+skip_type_access_control ()
+{
+ type_lookups = NULL_TREE;
+}
+
+/* Reset the deferred access control. */
+
+void
+reset_type_access_control ()
+{
+ type_lookups = NULL_TREE;
+ current_type_lookups = NULL_TREE;
}
/* Begin a function definition declared with DECL_SPECS and
tree scope;
tree name;
{
- tree result = build_parse_node (SCOPE_REF, scope, name);
+ tree result = build_nt (SCOPE_REF, scope, name);
enter_scope_of (result);
return result;
}
pop_everything ();
while (current_namespace != global_namespace)
pop_namespace ();
+
+ /* Do file scope __FUNCTION__ et al. */
+ finish_fname_decls ();
+
finish_file ();
}
DECL_ARTIFICIAL (decl) = 1;
end_template_decl ();
+ my_friendly_assert (DECL_TEMPLATE_PARMS (tmpl), 20010110);
+
return finish_template_type_parm (aggr, tmpl);
}
tree parms;
int ellipsis;
{
- if (!ellipsis)
- chainon (parms, void_list_node);
- /* We mark the PARMS as a parmlist so that declarator processing can
- disambiguate certain constructs. */
- if (parms != NULL_TREE)
- TREE_PARMLIST (parms) = 1;
-
+ if (parms)
+ {
+ /* We mark the PARMS as a parmlist so that declarator processing can
+ disambiguate certain constructs. */
+ TREE_PARMLIST (parms) = 1;
+ /* We do not append void_list_node here, but leave it to grokparms
+ to do that. */
+ PARMLIST_ELLIPSIS_P (parms) = ellipsis;
+ }
return parms;
}
begin_class_definition (t)
tree t;
{
+ /* Check the bases are accessible. */
+ decl_type_access_control (TYPE_NAME (t));
+ reset_type_access_control ();
+
+ if (processing_template_parmlist)
+ {
+ cp_error ("definition of `%#T' inside template parameter list", t);
+ return error_mark_node;
+ }
if (t == error_mark_node
|| ! IS_AGGR_TYPE (t))
{
/* Reset the interface data, at the earliest possible
moment, as it might have been set via a class foo;
before. */
- {
- tree name = TYPE_IDENTIFIER (t);
-
- if (! ANON_AGGRNAME_P (name))
- {
- CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
- SET_CLASSTYPE_INTERFACE_UNKNOWN_X
- (t, interface_unknown);
- }
-
- /* Only leave this bit clear if we know this
- class is part of an interface-only specification. */
- if (! CLASSTYPE_INTERFACE_KNOWN (t)
- || ! CLASSTYPE_INTERFACE_ONLY (t))
- CLASSTYPE_VTABLE_NEEDS_WRITING (t) = 1;
- }
+ if (! TYPE_ANONYMOUS_P (t))
+ {
+ CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
+ SET_CLASSTYPE_INTERFACE_UNKNOWN_X
+ (t, interface_unknown);
+ }
reset_specialization();
/* Make a declaration for this class in its own scope. */
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;
+ SET_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.
check_for_missing_semicolon (t);
if (pop_scope_p)
pop_scope (CP_DECL_CONTEXT (TYPE_MAIN_DECL (t)));
+ if (current_function_decl)
+ type_lookups = error_mark_node;
if (current_scope () == current_function_decl)
do_pending_defargs ();
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 decl;
decl = lookup_template_class (name, args,
- NULL_TREE, NULL_TREE, entering_scope);
+ NULL_TREE, NULL_TREE,
+ entering_scope, /*complain=*/1);
if (decl != error_mark_node)
decl = TYPE_STUB_DECL (decl);
tree access_specifier;
tree base_class;
{
- tree type;
tree result;
- if (base_class == NULL_TREE)
- {
- error ("invalid base class");
- type = error_mark_node;
- }
- else
- type = TREE_TYPE (base_class);
-
- if (! is_aggr_type (type, 1))
+ if (! is_aggr_type (base_class, 1))
result = NULL_TREE;
else
- result = build_tree_list (access_specifier, type);
+ {
+ if (CP_TYPE_QUALS (base_class) != 0)
+ {
+ cp_error ("base class `%T' has cv qualifiers", base_class);
+ base_class = TYPE_MAIN_VARIANT (base_class);
+ }
+ result = build_tree_list (access_specifier, base_class);
+ }
return result;
}
return t;
}
- return TREE_TYPE (expr);
-}
-
-/* Remove declarations of internal variables that are not used from a
- stmt tree. To qualify, the variable must have a name and must have
- a zero DECL_SOURCE_LINE. We tried to remove all variables for
- which TREE_USED was false, but it turns out that there's tons of
- variables for which TREE_USED is false but that are still in fact
- used. */
-
-static tree
-prune_unused_decls (tp, walk_subtrees, data)
- tree *tp;
- int *walk_subtrees ATTRIBUTE_UNUSED;
- void *data ATTRIBUTE_UNUSED;
-{
- tree t = *tp;
-
- if (t == NULL_TREE)
- {
- *walk_subtrees = 0;
- return NULL_TREE;
- }
-
- if (TREE_CODE (t) == DECL_STMT)
- {
- tree d = DECL_STMT_DECL (t);
- if (!TREE_USED (d) && DECL_NAME (d) && DECL_SOURCE_LINE (d) == 0)
- {
- *tp = TREE_CHAIN (t);
- /* Recurse on the new value of tp, otherwise we will skip
- the next statement. */
- return prune_unused_decls (tp, walk_subtrees, data);
- }
- }
- else if (TREE_CODE (t) == BLOCK)
- {
- /* walk_tree doesn't inspect BLOCK_VARS, so we must do it by hand. */
- tree *vp;
-
- for (vp = &BLOCK_VARS (t); *vp; )
- {
- tree v = *vp;
- if (! TREE_USED (v) && DECL_NAME (v) && DECL_SOURCE_LINE (v) == 0)
- *vp = TREE_CHAIN (v); /* drop */
- else
- vp = &TREE_CHAIN (v); /* advance */
- }
- if (BLOCK_VARS (t) == NULL_TREE)
- TREE_USED (t) = 0;
- }
- return NULL_TREE;
-}
-
-/* Create an empty statement tree rooted at T. */
-
-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;
-}
-
-/* Finish the statement tree rooted at T. */
-
-void
-finish_stmt_tree (t)
- tree *t;
-{
- tree stmt;
- int old_lineno;
-
- /* Remove the fake extra statement added in begin_stmt_tree. */
- stmt = TREE_CHAIN (*t);
- *t = stmt;
- SET_LAST_STMT (NULL_TREE);
-
- /* Remove unused decls from the stmt tree. walk_tree messes with
- the line number, so save/restore it. */
- old_lineno = lineno;
- walk_tree_without_duplicates (t, prune_unused_decls, NULL);
- lineno = old_lineno;
-
- if (cfun)
- {
- /* 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;
- }
-}
-
-/* We're about to expand T, a statement. Set up appropriate context
- for the substitution. */
+ if (TREE_CODE (expr) == OFFSET_REF)
+ expr = resolve_offset_ref (expr);
-void
-prep_stmt (t)
- tree t;
-{
- if (!STMT_LINENO_FOR_FN_P (t))
- lineno = STMT_LINENO (t);
- current_stmt_tree->stmts_are_full_exprs_p = STMT_IS_FULL_EXPR_P (t);
+ return TREE_TYPE (expr);
}
/* Generate RTL for the statement T, and its substatements, and any
other statements at its nesting level. */
-tree
-lang_expand_stmt (t)
+static void
+cp_expand_stmt (t)
tree t;
{
- tree rval = NULL_TREE;
-
- while (t && t != error_mark_node)
+ switch (TREE_CODE (t))
{
- int saved_stmts_are_full_exprs_p;
+ case CLEANUP_STMT:
+ genrtl_decl_cleanup (CLEANUP_DECL (t), CLEANUP_EXPR (t));
+ break;
- /* Assume we'll have nothing to return. */
- rval = NULL_TREE;
+ case CTOR_STMT:
+ genrtl_ctor_stmt (t);
+ break;
- /* Set up context appropriately for handling this statement. */
- saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
- prep_stmt (t);
+ case TRY_BLOCK:
+ genrtl_try_block (t);
+ break;
- switch (TREE_CODE (t))
- {
- case RETURN_STMT:
- genrtl_return_stmt (RETURN_EXPR (t));
- break;
-
- case EXPR_STMT:
- genrtl_expr_stmt (EXPR_STMT_EXPR (t));
- break;
-
- case DECL_STMT:
- genrtl_decl_stmt (t);
- break;
-
- case CLEANUP_STMT:
- genrtl_decl_cleanup (CLEANUP_DECL (t), CLEANUP_EXPR (t));
- break;
-
- case START_CATCH_STMT:
- genrtl_catch_block (TREE_TYPE (t));
- break;
-
- case CTOR_STMT:
- genrtl_ctor_stmt (t);
- break;
-
- case FOR_STMT:
- genrtl_for_stmt (t);
- break;
-
- case WHILE_STMT:
- genrtl_while_stmt (t);
- break;
-
- case DO_STMT:
- genrtl_do_stmt (t);
- break;
-
- case IF_STMT:
- genrtl_if_stmt (t);
- break;
-
- case COMPOUND_STMT:
- genrtl_compound_stmt (t);
- break;
-
- case BREAK_STMT:
- genrtl_break_stmt ();
- break;
-
- case CONTINUE_STMT:
- genrtl_continue_stmt ();
- break;
-
- case SWITCH_STMT:
- genrtl_switch_stmt (t);
- break;
-
- case CASE_LABEL:
- genrtl_case_label (CASE_LOW (t), CASE_HIGH (t));
- break;
-
- case LABEL_STMT:
- expand_label (LABEL_STMT_LABEL (t));
- break;
-
- case GOTO_STMT:
- genrtl_goto_stmt (GOTO_DESTINATION (t));
- break;
-
- case ASM_STMT:
- genrtl_asm_stmt (ASM_CV_QUAL (t), ASM_STRING (t),
- ASM_OUTPUTS (t), ASM_INPUTS (t), ASM_CLOBBERS (t));
- break;
-
- case TRY_BLOCK:
- genrtl_try_block (t);
- break;
-
- case HANDLER:
- genrtl_handler (t);
- break;
-
- case SUBOBJECT:
- genrtl_subobject (SUBOBJECT_CLEANUP (t));
- break;
-
- case SCOPE_STMT:
- genrtl_scope_stmt (t);
- break;
-
- case RETURN_INIT:
- genrtl_named_return_value (TREE_OPERAND (t, 0),
- TREE_OPERAND (t, 1));
- break;
-
- default:
- my_friendly_abort (19990810);
- break;
- }
+ case EH_SPEC_BLOCK:
+ genrtl_eh_spec_block (t);
+ break;
- /* Restore saved state. */
- current_stmt_tree->stmts_are_full_exprs_p = saved_stmts_are_full_exprs_p;
+ case HANDLER:
+ genrtl_handler (t);
+ break;
- /* Go on to the next statement in this scope. */
- t = TREE_CHAIN (t);
- }
+ case SUBOBJECT:
+ genrtl_subobject (SUBOBJECT_CLEANUP (t));
+ break;
- return rval;
+ case RETURN_INIT:
+ genrtl_named_return_value ();
+ break;
+
+ case USING_STMT:
+ break;
+
+ default:
+ my_friendly_abort (19990810);
+ break;
+ }
}
/* Called from expand_body via walk_tree. Replace all AGGR_INIT_EXPRs
tree args;
tree slot;
tree type;
- tree call_type;
int copy_from_buffer_p;
aggr_init_expr = *tp;
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),
+ args = tree_cons (NULL_TREE,
+ build1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (slot)),
+ slot),
TREE_CHAIN (args));
}
- call_expr = build (CALL_EXPR, call_type, fn, args, NULL_TREE);
+ call_expr = build (CALL_EXPR,
+ TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
+ fn, args, NULL_TREE);
TREE_SIDE_EFFECTS (call_expr) = 1;
/* If we're using the non-reentrant PCC calling convention, then we
#ifdef PCC_STATIC_STRUCT_RETURN
if (!AGGR_INIT_VIA_CTOR_P (aggr_init_expr) && aggregate_value_p (type))
{
- int old_ac;
+ int old_ac = flag_access_control;
flag_access_control = 0;
call_expr = build_aggr_init (slot, call_expr, LOOKUP_ONLYCONVERTING);
}
}
-
/* Generate RTL for FN. */
void
/* 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))
return;
}
+ /* Compute the appropriate object-file linkage for inline
+ functions. */
+ if (DECL_DECLARED_INLINE_P (fn))
+ import_export_decl (fn);
+
/* 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);
+ /* Optimize the body of the function before expanding it. We do not
+ optimize thunks, as (1) the backend tries to optimize the call to
+ the thunkee, (b) the tree based inliner breaks that optimization,
+ (c) virtual functions are rarely inlineable, and (d)
+ ASM_OUTPUT_MI_THUNK is there to DTRT anyway. */
+ if (!DECL_THUNK_P (fn))
+ optimize_function (fn);
timevar_pop (TV_INTEGRATION);
timevar_push (TV_EXPAND);
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. */
- cp_function_chain->name_declared = 1;
-
/* Expand the body. */
expand_stmt (DECL_SAVED_TREE (fn));
lineno = STMT_LINENO (DECL_SAVED_TREE (fn));
/* Generate code for the function. */
- finish_function (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)
+ if (dump_enabled_p (TDI_all))
/* Keep the body; we're going to dump it. */
;
else if (DECL_INLINE (fn) && flag_inline_trees)
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 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. */
+ if (return_label)
+ 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 ();
+
+ /* There's no need to defer outputting this function any more; we
+ know we want to output it. */
+ DECL_DEFER_OUTPUT (fn) = 0;
+
+ /* 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 we don't need the RTL for this function anymore, stop pointing
+ to it. That's especially important for LABEL_DECLs, since you
+ can reach all the instructions in the function from the
+ CODE_LABEL stored in the DECL_RTL for the LABEL_DECL. */
+ if (!DECL_SAVED_INSNS (fn))
+ {
+ tree t;
+
+ /* Walk the BLOCK-tree, clearing DECL_RTL for LABEL_DECLs and
+ non-static local variables. */
+ walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
+ clear_decl_rtl,
+ NULL);
+
+ /* Clear out the RTL for the arguments. */
+ for (t = DECL_ARGUMENTS (fn); t; t = TREE_CHAIN (t))
+ {
+ SET_DECL_RTL (t, NULL_RTX);
+ DECL_INCOMING_RTL (t) = NULL_RTX;
+ }
+
+ if (!(flag_inline_trees && DECL_INLINE (fn)))
+ /* DECL_INITIAL must remain nonzero so we know this was an
+ actual function definition. */
+ DECL_INITIAL (fn) = error_mark_node;
+ }
+
+ /* 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;
+}
+
+/* Clear out the DECL_RTL for the non-static variables in BLOCK and
+ its sub-blocks. */
+
+static tree
+clear_decl_rtl (tp, walk_subtrees, data)
+ tree *tp;
+ int *walk_subtrees ATTRIBUTE_UNUSED;
+ void *data ATTRIBUTE_UNUSED;
+{
+ if (nonstatic_local_decl_p (*tp))
+ SET_DECL_RTL (*tp, NULL_RTX);
+
+ return NULL_TREE;
+}
+
+/* Perform initialization related to this module. */
+
+void
+init_cp_semantics ()
+{
+ lang_expand_stmt = cp_expand_stmt;
+}