#include "except.h"
#include "lex.h"
#include "toplev.h"
+#include "flags.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 void expand_stmts PROTO((tree));
-static void do_pushlevel PROTO((void));
-static tree do_poplevel PROTO((void));
+static tree expand_cond PROTO((tree));
+static tree maybe_convert_cond PROTO((tree));
/* When parsing a template, LAST_TREE contains the last statement
parsed. These are chained together through the TREE_CHAIN field,
bottom-up. This macro makes LAST_TREE the indicated SUBSTMT of
STMT. */
-#define RECHAIN_STMTS(stmt, substmt, last) \
- do { \
- substmt = last; \
- TREE_CHAIN (stmt) = NULL_TREE; \
- last_tree = stmt; \
+#define RECHAIN_STMTS(stmt, substmt) \
+ do { \
+ substmt = TREE_CHAIN (stmt); \
+ TREE_CHAIN (stmt) = NULL_TREE; \
+ last_tree = stmt; \
} while (0)
-#define RECHAIN_STMTS_FROM_LAST(stmt, substmt) \
- RECHAIN_STMTS (stmt, substmt, last_tree)
+/* Finish processing the COND, the SUBSTMT condition for STMT. */
+
+#define FINISH_COND(cond, stmt, substmt) \
+ do { \
+ if (last_tree != stmt) \
+ { \
+ RECHAIN_STMTS (stmt, substmt); \
+ if (!processing_template_decl) \
+ { \
+ cond = build_tree_list (substmt, cond); \
+ substmt = cond; \
+ } \
+ } \
+ else \
+ substmt = cond; \
+ } while (0)
+
+/* T is a statement. Add it to the statement-tree. */
+
+void
+add_tree (t)
+ tree t;
+{
+ /* Add T to the statement-tree. */
+ last_tree = TREE_CHAIN (last_tree) = t;
+
+ /* 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;
+}
+
+/* COND is the condition-expression for an if, while, etc.,
+ statement. Convert it to a boolean value, if appropriate. */
+
+static tree
+maybe_convert_cond (cond)
+ tree cond;
+{
+ /* Empty conditions remain empty. */
+ if (!cond)
+ return NULL_TREE;
-#define RECHAIN_STMTS_FROM_CHAIN(stmt, substmt) \
- RECHAIN_STMTS (stmt, substmt, TREE_CHAIN (stmt))
+ /* Wait until we instantiate templates before doing conversion. */
+ if (processing_template_decl)
+ return cond;
+
+ /* Do the conversion. */
+ cond = convert_from_reference (cond);
+ return condition_conversion (cond);
+}
/* Finish an expression-statement, whose EXPRESSION is as indicated. */
{
tree r;
+ do_pushlevel ();
+
if (building_stmt_tree ())
{
r = build_min_nt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
else
r = NULL_TREE;
- do_pushlevel ();
-
return r;
}
tree cond;
tree if_stmt;
{
+ cond = maybe_convert_cond (cond);
+
if (building_stmt_tree ())
- {
- if (last_tree != if_stmt)
- RECHAIN_STMTS_FROM_LAST (if_stmt, IF_COND (if_stmt));
- else
- IF_COND (if_stmt) = cond;
- }
+ FINISH_COND (cond, if_stmt, IF_COND (if_stmt));
else
{
emit_line_note (input_filename, lineno);
- expand_start_cond (condition_conversion (cond), 0);
+ expand_start_cond (cond, 0);
}
}
{
if (building_stmt_tree ())
{
- RECHAIN_STMTS_FROM_CHAIN (if_stmt,
- THEN_CLAUSE (if_stmt));
+ RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt));
last_tree = if_stmt;
return if_stmt;
}
tree if_stmt;
{
if (building_stmt_tree ())
- RECHAIN_STMTS_FROM_CHAIN (if_stmt, ELSE_CLAUSE (if_stmt));
+ RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt));
}
/* Finsh an if-statement. */
tree cond;
tree while_stmt;
{
+ cond = maybe_convert_cond (cond);
+
if (building_stmt_tree ())
- {
- if (last_tree != while_stmt)
- RECHAIN_STMTS_FROM_LAST (while_stmt, WHILE_COND (while_stmt));
- else
- TREE_OPERAND (while_stmt, 0) = cond;
- }
+ FINISH_COND (cond, while_stmt, WHILE_COND (while_stmt));
else
{
emit_line_note (input_filename, lineno);
- expand_exit_loop_if_false (0, condition_conversion (cond));
+ expand_exit_loop_if_false (0, cond);
}
/* If COND wasn't a declaration, clear out the
do_poplevel ();
if (building_stmt_tree ())
- RECHAIN_STMTS_FROM_CHAIN (while_stmt, WHILE_BODY (while_stmt));
+ RECHAIN_STMTS (while_stmt, WHILE_BODY (while_stmt));
else
expand_end_loop ();
finish_stmt ();
tree do_stmt;
{
if (building_stmt_tree ())
- RECHAIN_STMTS_FROM_CHAIN (do_stmt, DO_BODY (do_stmt));
+ RECHAIN_STMTS (do_stmt, DO_BODY (do_stmt));
else
expand_loop_continue_here ();
}
tree cond;
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, condition_conversion (cond));
+ expand_exit_loop_if_false (0, cond);
expand_end_loop ();
}
finish_return_stmt (expr)
tree expr;
{
+ if (doing_semantic_analysis_p () && !processing_template_decl)
+ expr = check_return_expr (expr);
+
+ if (doing_semantic_analysis_p () && !processing_template_decl)
+ {
+ if (DECL_CONSTRUCTOR_P (current_function_decl) && ctor_label)
+ {
+ /* Even returns without a value in a constructor must return
+ `this'. We accomplish this by sending all returns in a
+ constructor to the CTOR_LABEL; finish_function emits code to
+ 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;
+ }
+ 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
+ code to return a value there. */
+ finish_goto_stmt (dtor_label);
+ return;
+ }
+ }
+
if (building_stmt_tree ())
add_tree (build_min_nt (RETURN_STMT, expr));
else
if (building_stmt_tree ())
{
if (last_tree != for_stmt)
- RECHAIN_STMTS_FROM_CHAIN (for_stmt, FOR_INIT_STMT (for_stmt));
+ RECHAIN_STMTS (for_stmt, FOR_INIT_STMT (for_stmt));
}
else
{
tree cond;
tree for_stmt;
{
+ cond = maybe_convert_cond (cond);
+
if (building_stmt_tree ())
- {
- if (last_tree != for_stmt)
- RECHAIN_STMTS_FROM_LAST (for_stmt, FOR_COND (for_stmt));
- else
- FOR_COND (for_stmt) = cond;
- }
+ FINISH_COND (cond, for_stmt, FOR_COND (for_stmt));
else
{
emit_line_note (input_filename, lineno);
if (cond)
- expand_exit_loop_if_false (0, condition_conversion (cond));
+ expand_exit_loop_if_false (0, cond);
}
/* If the cond wasn't a declaration, clear out the
do_poplevel ();
if (building_stmt_tree ())
- RECHAIN_STMTS_FROM_CHAIN (for_stmt, FOR_BODY (for_stmt));
+ RECHAIN_STMTS (for_stmt, FOR_BODY (for_stmt));
else
{
emit_line_note (input_filename, lineno);
cp_error ("continue statement not within a loop");
}
-/* Begin a switch-statement. */
+/* Begin a switch-statement. Returns a new SWITCH_STMT if
+ appropriate. */
-void
+tree
begin_switch_stmt ()
{
+ tree r;
+
+ if (building_stmt_tree ())
+ {
+ r = build_min_nt (SWITCH_STMT, NULL_TREE, NULL_TREE);
+ add_tree (r);
+ }
+ else
+ r = NULL_TREE;
+
do_pushlevel ();
+
+ return r;
}
-/* Finish the cond of a switch-statement. Returns a new
- SWITCH_STMT if appropriate. */
+/* Finish the cond of a switch-statement. */
-tree
-finish_switch_cond (cond)
+void
+finish_switch_cond (cond, switch_stmt)
tree cond;
+ tree switch_stmt;
{
- tree r;
-
if (building_stmt_tree ())
- {
- r = build_min_nt (SWITCH_STMT, cond, NULL_TREE);
- add_tree (r);
- }
+ FINISH_COND (cond, switch_stmt, SWITCH_COND (switch_stmt));
else if (cond != error_mark_node)
{
emit_line_note (input_filename, lineno);
c_expand_start_case (cond);
- r = NULL_TREE;
}
else
- {
- /* The code is in error, but we don't want expand_end_case to
- crash. */
- c_expand_start_case (boolean_false_node);
- r = NULL_TREE;
- }
+ /* The code is in error, but we don't want expand_end_case to
+ crash. */
+ c_expand_start_case (boolean_false_node);
push_switch ();
/* Don't let the tree nodes for COND be discarded by
clear_momentary during the parsing of the next stmt. */
push_momentary ();
-
- return r;
}
/* Finish the body of a switch-statement, which may be given by
tree switch_stmt;
{
if (building_stmt_tree ())
- RECHAIN_STMTS_FROM_CHAIN (switch_stmt, SWITCH_BODY (switch_stmt));
+ RECHAIN_STMTS (switch_stmt, SWITCH_BODY (switch_stmt));
else
expand_end_case (cond);
pop_momentary ();
{
if (building_stmt_tree ())
{
+ /* 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;
}
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
if (TREE_CODE (destination) == LABEL_DECL)
{
- TREE_USED (destination) = 1;
+ label_rtx (destination);
expand_goto (destination);
}
else
{
tree r = build_min_nt (TRY_BLOCK, NULL_TREE,
NULL_TREE);
+ FN_TRY_BLOCK_P (r) = 1;
add_tree (r);
return r;
}
tree try_block;
{
if (building_stmt_tree ())
- RECHAIN_STMTS_FROM_LAST (try_block, TRY_STMTS (try_block));
+ RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
else
expand_start_all_catch ();
}
+/* Finish the body of a cleanup try-block, which may be given by
+ TRY_BLOCK. */
+
+void
+finish_cleanup_try_block (try_block)
+ tree try_block;
+{
+ if (building_stmt_tree ())
+ RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
+}
+
/* Finish an implicitly generated try-block, with a cleanup is given
by CLEANUP. */
tree try_block;
{
if (building_stmt_tree ())
- RECHAIN_STMTS_FROM_LAST (try_block, TRY_STMTS (try_block));
+ {
+ 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));
+ }
else
{
end_protect_partials ();
expand_start_all_catch ();
- in_function_try_handler = 1;
}
+
+ in_function_try_handler = 1;
}
/* Finish a handler-sequence for a try-block, which may be given by
tree try_block;
{
if (building_stmt_tree ())
- RECHAIN_STMTS_FROM_CHAIN (try_block, TRY_HANDLERS (try_block));
+ RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
else
expand_end_all_catch ();
}
finish_function_handler_sequence (try_block)
tree try_block;
{
+ in_function_try_handler = 0;
+
if (building_stmt_tree ())
- RECHAIN_STMTS_FROM_CHAIN (try_block, TRY_HANDLERS (try_block));
+ RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
else
- {
- in_function_try_handler = 0;
- expand_end_all_catch ();
- }
+ expand_end_all_catch ();
}
/* Begin a handler. Returns a HANDLER if appropriate. */
}
/* Finish the handler-parameters for a handler, which may be given by
- HANDLER. */
+ HANDLER. DECL is the declaration for the catch parameter, or NULL
+ if this is a `catch (...)' clause. */
-void
-finish_handler_parms (handler)
+tree
+finish_handler_parms (decl, handler)
+ tree decl;
tree handler;
{
+ tree blocks = NULL_TREE;
+
+ if (processing_template_decl)
+ {
+ if (decl)
+ {
+ decl = pushdecl (decl);
+ decl = push_template_decl (decl);
+ add_decl_stmt (decl);
+ RECHAIN_STMTS (handler, HANDLER_PARMS (handler));
+ }
+ }
+ else if (building_stmt_tree ())
+ blocks = expand_start_catch_block (decl);
+
+ return blocks;
+}
+
+/* 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;
+{
if (building_stmt_tree ())
- RECHAIN_STMTS_FROM_CHAIN (handler, HANDLER_PARMS (handler));
+ add_tree (build (START_CATCH_STMT, type));
+ else
+ start_catch_handler (type);
}
-/* Finish a handler, which may be given by HANDLER. */
+/* 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 (handler)
+finish_handler (blocks, handler)
+ tree blocks;
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 ();
+ }
+ }
+
if (building_stmt_tree ())
- RECHAIN_STMTS_FROM_CHAIN (handler, HANDLER_BODY (handler));
- else
- expand_end_catch_block ();
+ RECHAIN_STMTS (handler, HANDLER_BODY (handler));
do_poplevel ();
}
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 (!current_function_name_declared
+ && !processing_template_decl
+ && !has_no_scope)
+ {
+ declare_function_name ();
+ current_function_name_declared = 1;
+ }
+
return r;
}
r = NULL_TREE;
if (building_stmt_tree ())
- RECHAIN_STMTS_FROM_CHAIN (compound_stmt,
- COMPOUND_BODY (compound_stmt));
+ RECHAIN_STMTS (compound_stmt, COMPOUND_BODY (compound_stmt));
- /* When we call finish_stmt we will lost LAST_EXPR_TYPE. But, since
+ /* 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
last expression statement within the last compound statement, we
preserve the value. */
add_partial_entry (cleanup);
}
+/* When DECL goes out of scope, make sure that CLEANUP is executed. */
+
+void
+finish_decl_cleanup (decl, cleanup)
+ tree decl;
+ tree cleanup;
+{
+ if (building_stmt_tree ())
+ add_tree (build_min_nt (CLEANUP_STMT, decl, cleanup));
+ else if (!decl
+ || (DECL_SIZE (decl) && TREE_TYPE (decl) != error_mark_node))
+ expand_decl_cleanup (decl, cleanup);
+}
+
/* Bind a name and initialization to the return value of
the current function. */
{
/* Let `cp_finish_decl' know that this initializer is ok. */
DECL_INITIAL (decl) = init;
- pushdecl (decl);
+ if (doing_semantic_analysis_p ())
+ pushdecl (decl);
if (building_stmt_tree ())
add_tree (build_min_nt (RETURN_INIT, return_id, init));
void
setup_vtbl_ptr ()
{
- if (base_init_expr == 0
- && DECL_CONSTRUCTOR_P (current_function_decl))
+ my_friendly_assert (doing_semantic_analysis_p (), 19990919);
+
+ /* If we've already done this, there's no need to do it again. */
+ if (vtbls_set_up_p)
+ return;
+
+ if (DECL_CONSTRUCTOR_P (current_function_decl))
{
- if (building_stmt_tree ())
+ if (processing_template_decl)
add_tree (build_min_nt
(CTOR_INITIALIZER,
current_member_init_list, current_base_init_list));
else
- emit_base_init (current_class_type);
+ finish_expr_stmt (emit_base_init (current_class_type));
+ }
+ else if (DECL_DESTRUCTOR_P (current_function_decl)
+ && !processing_template_decl)
+ {
+ tree binfo = TYPE_BINFO (current_class_type);
+ tree if_stmt;
+ tree compound_stmt;
+
+ /* 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
+ 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. */
+ 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
+ initialize the vtables.) */
+ finish_if_stmt_cond (boolean_true_node, if_stmt);
+ current_vcalls_possible_p = &IF_COND (if_stmt);
+ compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
+
+ /* 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);
+
+ finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
+ finish_then_clause (if_stmt);
+ finish_if_stmt ();
}
/* Always keep the BLOCK node associated with the outermost pair of
- curley braces of a function. These are needed for correct
+ curly braces of a function. These are needed for correct
operation of dwarfout.c. */
keep_next_level (1);
+
+ /* The virtual function tables are set up now. */
+ vtbls_set_up_p = 1;
}
/* Begin a new scope. */
-static void
+void
do_pushlevel ()
{
if (!building_stmt_tree ())
}
push_momentary ();
if (stmts_are_full_exprs_p)
- pushlevel (0);
- if (!building_stmt_tree () && stmts_are_full_exprs_p)
- expand_start_bindings (0);
+ {
+ 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. */
-static tree
+tree
do_poplevel ()
{
- tree t;
+ tree t = NULL_TREE;
- if (!building_stmt_tree () && stmts_are_full_exprs_p)
- expand_end_bindings (getdecls (), kept_level_p (), 0);
if (stmts_are_full_exprs_p)
- t = poplevel (kept_level_p (), 1, 0);
- else
- t = NULL_TREE;
+ {
+ 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;
}
statement-expression. */
tree
-finish_stmt_expr (rtl_expr, expr)
+finish_stmt_expr (rtl_expr)
tree rtl_expr;
- tree expr;
{
tree result;
if (!building_stmt_tree ())
{
rtl_expr = expand_end_stmt_expr (rtl_expr);
- /* The statements have side effects, so the group does. */
+ /* The statements have side effects, so the group does too. */
TREE_SIDE_EFFECTS (rtl_expr) = 1;
}
last_tree = rtl_expr;
TREE_CHAIN (last_tree) = NULL_TREE;
}
- else if (expr && TREE_CODE (expr) == BLOCK)
- {
- result = build (BIND_EXPR, TREE_TYPE (rtl_expr),
- NULL_TREE, rtl_expr, expr);
- delete_block (expr);
- }
- else
+ else
result = rtl_expr;
- if (expr && TREE_CODE (expr) == BLOCK)
- /* Remove the block from the tree at this point. It gets put back
- at the proper place when the STMT_EXPR or BIND_EXPR is
- expanded. */
- delete_block (expr);
-
return result;
}
{
/* In case there were missing closebraces,
get us back to the global binding level. */
- while (! toplevel_bindings_p ())
- poplevel (0, 0, 0);
+ pop_everything ();
while (current_namespace != global_namespace)
pop_namespace ();
finish_file ();
finish_stmt_tree (fn)
tree fn;
{
- DECL_SAVED_TREE (fn) = TREE_CHAIN (DECL_SAVED_TREE (fn));
+ tree stmt;
+
+ /* Remove the fake extra statement added in begin_stmt_tree. */
+ stmt = TREE_CHAIN (DECL_SAVED_TREE (fn));
+ DECL_SAVED_TREE (fn) = stmt;
+
+ /* 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;
}
-/* Generate RTL for the chain of statements T. */
+/* We're about to expand T, a statement. Set up appropriate context
+ for the substitution. */
-static void
-expand_stmts (t)
+void
+prep_stmt (t)
tree t;
{
- while (t)
+ if (!STMT_LINENO_FOR_FN_P (t))
+ lineno = STMT_LINENO (t);
+ stmts_are_full_exprs_p = STMT_IS_FULL_EXPR_P (t);
+}
+
+/* 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. */
+
+static tree
+expand_cond (t)
+ tree t;
+{
+ if (t && TREE_CODE (t) == TREE_LIST)
{
- expand_stmt (t);
- t = TREE_CHAIN (t);
+ expand_stmt (TREE_PURPOSE (t));
+ return TREE_VALUE (t);
}
+ else
+ return t;
}
-/* Generate RTL for the statement T, and its substatements. */
+/* Generate RTL for the statement T, and its substatements, and any
+ other statements at its nesting level. */
tree
expand_stmt (t)
tree t;
{
- if (t == NULL_TREE || t == error_mark_node)
- return NULL_TREE;
+ tree rval = NULL_TREE;
- switch (TREE_CODE (t))
+ while (t && t != error_mark_node)
{
- case RETURN_STMT:
- lineno = STMT_LINENO (t);
- finish_return_stmt (RETURN_EXPR (t));
- break;
+ int saved_stmts_are_full_exprs_p;
- case EXPR_STMT:
- lineno = STMT_LINENO (t);
- finish_expr_stmt (EXPR_STMT_EXPR (t));
- break;
+ /* Assume we'll have nothing to return. */
+ rval = NULL_TREE;
- case DECL_STMT:
- {
- tree decl;
- int i = suspend_momentary ();
-
- lineno = STMT_LINENO (t);
- emit_line_note (input_filename, lineno);
- decl = DECL_STMT_DECL (t);
- if (TREE_CODE (decl) == LABEL_DECL)
- finish_label_decl (DECL_NAME (decl));
- else
+ /* Set up context appropriately for handling this statement. */
+ saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p;
+ prep_stmt (t);
+
+ 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:
{
- /* We need to clear DECL_CONTEXT so that maybe_push_decl
- will push it into the current scope. */
- if (DECL_CONTEXT (decl) == current_function_decl)
- DECL_CONTEXT (decl) = NULL_TREE;
- /* If we marked this variable as dead when we processed it
- before, we must undo that now. The variable has been
- resuscitated. */
- if (TREE_CODE (decl) == VAR_DECL)
- DECL_DEAD_FOR_LOCAL (decl) = 0;
- maybe_push_decl (decl);
- if (TREE_CODE (decl) == VAR_DECL && !TREE_STATIC (decl))
+ 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))
{
- maybe_inject_for_scope_var (decl);
- initialize_local_var (decl, DECL_INITIAL (decl), 0);
+ /* 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);
}
- resume_momentary (i);
- }
- break;
+ break;
- case FOR_STMT:
- {
- tree tmp;
-
- lineno = STMT_LINENO (t);
- begin_for_stmt ();
- for (tmp = FOR_INIT_STMT (t); tmp; tmp = TREE_CHAIN (tmp))
- expand_stmt (tmp);
- finish_for_init_stmt (NULL_TREE);
- finish_for_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 CLEANUP_STMT:
+ finish_decl_cleanup (CLEANUP_DECL (t), CLEANUP_EXPR (t));
+ break;
- case WHILE_STMT:
- {
- lineno = STMT_LINENO (t);
- begin_while_stmt ();
- finish_while_stmt_cond (WHILE_COND (t), NULL_TREE);
- expand_stmt (WHILE_BODY (t));
- finish_while_stmt (NULL_TREE);
- }
- break;
+ case START_CATCH_STMT:
+ begin_catch_block (TREE_TYPE (t));
+ break;
- case DO_STMT:
- {
- lineno = STMT_LINENO (t);
- begin_do_stmt ();
- expand_stmt (DO_BODY (t));
- finish_do_body (NULL_TREE);
- finish_do_stmt (DO_COND (t), NULL_TREE);
- }
- 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 IF_STMT:
- lineno = STMT_LINENO (t);
- begin_if_stmt ();
- finish_if_stmt_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:
- lineno = STMT_LINENO (t);
- begin_compound_stmt (COMPOUND_STMT_NO_SCOPE (t));
- expand_stmts (COMPOUND_BODY (t));
- return finish_compound_stmt (COMPOUND_STMT_NO_SCOPE (t),
- NULL_TREE);
-
- case BREAK_STMT:
- lineno = STMT_LINENO (t);
- finish_break_stmt ();
- break;
-
- case CONTINUE_STMT:
- lineno = STMT_LINENO (t);
- finish_continue_stmt ();
- break;
-
- case SWITCH_STMT:
- lineno = STMT_LINENO (t);
- begin_switch_stmt ();
- finish_switch_cond (SWITCH_COND (t));
- if (TREE_OPERAND (t, 1))
- expand_stmt (SWITCH_BODY (t));
- finish_switch_stmt (SWITCH_COND (t), NULL_TREE);
- break;
-
- case CASE_LABEL:
- finish_case_label (CASE_LOW (t), CASE_HIGH (t));
- break;
-
- case LABEL_STMT:
- lineno = STMT_LINENO (t);
- finish_label_stmt (DECL_NAME (LABEL_STMT_LABEL (t)));
- break;
-
- case GOTO_STMT:
- lineno = STMT_LINENO (t);
- if (TREE_CODE (GOTO_DESTINATION (t)) == LABEL_DECL)
- finish_goto_stmt (DECL_NAME (GOTO_DESTINATION (t)));
- else
- finish_goto_stmt (GOTO_DESTINATION (t));
- break;
-
- case ASM_STMT:
- lineno = STMT_LINENO (t);
- finish_asm_stmt (ASM_CV_QUAL (t), ASM_STRING (t), ASM_OUTPUTS
- (t), ASM_INPUTS (t), ASM_CLOBBERS (t));
- break;
-
- case TRY_BLOCK:
- lineno = STMT_LINENO (t);
- if (CLEANUP_P (t))
- {
- expand_eh_region_start ();
- expand_stmt (TRY_STMTS (t));
- finish_cleanup (TRY_HANDLERS (t), NULL_TREE);
- }
- else
- {
- begin_try_block ();
- expand_stmt (TRY_STMTS (t));
- finish_try_block (NULL_TREE);
- expand_stmts (TRY_HANDLERS (t));
- finish_handler_sequence (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 HANDLER:
- lineno = STMT_LINENO (t);
- begin_handler ();
- if (HANDLER_PARMS (t))
- expand_start_catch_block (DECL_STMT_DECL (HANDLER_PARMS (t)));
- else
- expand_start_catch_block (NULL_TREE);
- finish_handler_parms (NULL_TREE);
- expand_stmt (HANDLER_BODY (t));
- finish_handler (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 SUBOBJECT:
- lineno = STMT_LINENO (t);
- finish_subobject (SUBOBJECT_CLEANUP (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 ();
+
+ expand_stmt (TRY_STMTS (t));
+
+ if (FN_TRY_BLOCK_P (t))
+ {
+ finish_function_try_block (NULL_TREE);
+ expand_stmt (TRY_HANDLERS (t));
+ finish_function_handler_sequence (NULL_TREE);
+ }
+ else
+ {
+ finish_try_block (NULL_TREE);
+ expand_stmt (TRY_HANDLERS (t));
+ finish_handler_sequence (NULL_TREE);
+ }
+ }
+ 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;
- default:
- my_friendly_abort (19990810);
- break;
+ /* Go on to the next statement in this scope. */
+ t = TREE_CHAIN (t);
}
- return NULL_TREE;
+ return rval;
}
/* Generate RTL for FN. */
expand_body (fn)
tree fn;
{
- tree t;
- tree try_block;
-
- start_function (NULL_TREE, fn, NULL_TREE, SF_PRE_PARSED | SF_EXPAND);
- store_parm_decls ();
+ int saved_lineno;
+ 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
+ processing an in-class definition of an inline function,
+ PROCESSING_TEMPLATE_DECL will no longer be set here, so we have
+ to look at the function itself. */
+ if (processing_template_decl
+ || (DECL_LANG_SPECIFIC (fn)
+ && DECL_TEMPLATE_INFO (fn)
+ && uses_template_parms (DECL_TI_ARGS (fn))))
+ return;
- /* There are a few things that we do not handle recursively. For
- example, a function try-block is handled differently from an
- ordinary try-block, so we must handle it here. */
- t = DECL_SAVED_TREE (fn);
- try_block = NULL_TREE;
- if (t && TREE_CODE (t) == TRY_BLOCK)
- {
- try_block = t;
- begin_function_try_block ();
- t = TRY_STMTS (try_block);
- }
+ /* 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 (t && TREE_CODE (t) == RETURN_INIT)
- {
- /* Clear this out so that finish_named_return_value can set it
- again. */
- DECL_NAME (DECL_RESULT (fn)) = NULL_TREE;
- finish_named_return_value (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1));
- t = TREE_CHAIN (t);
- }
+ /* 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. */
+ saved_lineno = lineno;
+ saved_input_filename = input_filename;
+ lineno = DECL_SOURCE_LINE (fn);
+ input_filename = DECL_SOURCE_FILE (fn);
- if (t && TREE_CODE (t) == CTOR_INITIALIZER)
- {
- current_member_init_list = TREE_OPERAND (t, 0);
- current_base_init_list = TREE_OPERAND (t, 1);
- t = TREE_CHAIN (t);
- }
+ start_function (NULL_TREE, fn, NULL_TREE, SF_PRE_PARSED | SF_EXPAND);
+ store_parm_decls ();
- /* If this is a constructor, we need to initialize our members and
- base-classes. */
- setup_vtbl_ptr ();
+ /* 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;
/* Expand the body. */
- expand_stmt (t);
+ expand_stmt (DECL_SAVED_TREE (fn));
- /* If there was a function try-block, expand the handlers. */
- if (try_block)
- {
- finish_function_try_block (NULL_TREE);
- {
- tree handler = TRY_HANDLERS (try_block);
- for (; handler; handler = TREE_CHAIN (handler))
- expand_stmt (handler);
- }
- finish_function_handler_sequence (NULL_TREE);
- }
+ /* 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);
+
+ /* 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);
+
+ /* And restore the current source position. */
+ lineno = saved_lineno;
+ input_filename = saved_input_filename;
}