Commit b35d4555 by Mark Mitchell Committed by Mark Mitchell

Turn on function-at-a-time processing.

	* cp-tree.h (doing_semantic_analysis_p): New macro.
	(SF_DEFAULT): Define to zero, not SF_EXPAND.
	(start_handler_parms): Change prototype.
	(expand_start_catch_block): Likewise.
	(expand_end_catch_block): Likewise.
	(expand_start_eh_spec): Likewise.
	(expand_end_eh_spec): Declare.
	(finish_handler_parms): Change prototype.
	(begin_catch_block): Declare.
	(finish_handler): Change prototype.
	(do_pushlevel): Declare.
	(do_poplevel): Likewise.
	* decl.c (pushlevel): Don't create
	binding levels when not doing semantic analysis.
	(poplevel): Don't pop them.
	(pushdecl): Assert that we are never called when not doing
	semantic analysis.
	(pushdecl_top_level): Use push_to_top_level.
	(make_label_decl): Don't fiddle with obstacks.  Make RTL For the
	label when expanding.
	(cp_finish_decl): Only inject for-scope variables when doing
	semantic analysis.  Add comments.
	(start_handler_parms): Return the handler parm.
	(start_function): Reorganize.  Don't clear DECL_INITIAL if it is
	already set.  Reinitialize from saved function data if available.
	Don't pushlevel when not doing semantic analysis.
	(store_parm_decls): Only generate RTL when expanding.  Only
	pushdecl when doing semantic analysis.  Set
	current_eh_spec_try_block if appropriate.
	(finish_function): Simplify.  Use do_pushlevel and do_poplevel.
	Combine common code.  Don't poplevel when not doing semantic
	analysis.
	(push_cp_function_context): Don't expand functions without an
	explicit call to expand_body.
	(mark_lang_function): Make eh_spec_try_block and
	x_scope_stmt_stack.
	* except.c (expand_end_eh_spec): Don't
	declare.
	(process_start_catch_block): Likewise.
	(push_eh_cleanup): Use finish_decl_cleanup.
	(initialize_handler_parm): New function.
	(expand_start_catch_block): Use it.
	(expand_end_catch_block): Use tree-generation functions, not
	RTL-generation functions.
	(expand_start_eh_spec): Likewise.
	(expand_end_eh_spec): Likewise.
	(expand_exception_blocks): Simplify.
	(start_anon_func): Use do_pushlevel.
	(end_anon_func): Use do_poplvel.  Call expand_body for the
	function.
	* expr.c (do_case): Don't call define_case_label.
	* init.c (create_temporary_var): Set DECL_CONTEXT for local
	variables.
	* method.c (emit_thunk): Call expand_body for the
	thunk.
	(sythesize_method): Likewise.
	* parse.y (handler_args): Give it ttype.
	(eat_saved_input): Call expand_body.
	(base_init): Use do_pushlevel.
	(pending_inline): Call expand_body.
	(handler): Adjust calls to finish_handler_parms and
	finish_handler.
	(handler_args): Don't call expand_start_catch_block.  Return the
	catch parameter.  * pt.c (tsubst_expr): Adjust HANDLER handling.
	* parse.c: Regenerated.
	* rtti.c (synthesize_tinfo_fn): Call finish_function.
	* semantics.c (do_pushlevel): Give it external linkage.  Build
	SCOPE_STMTs.
	(do_poplevel): Likewise.
	(finish_case_label): Call define_case_label when doing semantic
	analysis.
	(finish_goto_stmt): Create RTL for labels.
	(finish_function_try_block): Set in_function_try_handler
	unconditionally.
	(finish_function_handler_sequence): Unset it.
	(finish_handler_parms): Use expand_start_catch_block even when
	building a statement-tree.
	(begin_catch_block): New function.
	(finish_handler): Move a little RTL-generation logic here.
	(finish_decl_cleanup): Allow cleanups for empty declarations.
	(finish_named_return_value): Don't pushdecl when not doing
	semantic analysis.
	(expand_stmt): Don't do semantic analysis for variable
	declarations.  Handle START_CATCH_STMT.  Call expand_label
	directly for a LABEL_STMT.  Tweak handling of GOTO_STMT.  Adjust
	HANDLERs.  Handle SCOPE_STMT, CTOR_INITIALIZER, and RETURN_INIT.
	(expand_body): Let expand_stmt handle CTOR_INITIALIZER,
	RETURN_INIT and function try blocks.

From-SVN: r29490
parent 2c146a76
1999-09-17 Mark Mitchell <mark@codesourcery.com> 1999-09-17 Mark Mitchell <mark@codesourcery.com>
Turn on function-at-a-time processing.
* cp-tree.h (doing_semantic_analysis_p): New macro.
(SF_DEFAULT): Define to zero, not SF_EXPAND.
(start_handler_parms): Change prototype.
(expand_start_catch_block): Likewise.
(expand_end_catch_block): Likewise.
(expand_start_eh_spec): Likewise.
(expand_end_eh_spec): Declare.
(finish_handler_parms): Change prototype.
(begin_catch_block): Declare.
(finish_handler): Change prototype.
(do_pushlevel): Declare.
(do_poplevel): Likewise.
* decl.c (pushlevel): Don't create
binding levels when not doing semantic analysis.
(poplevel): Don't pop them.
(pushdecl): Assert that we are never called when not doing
semantic analysis.
(pushdecl_top_level): Use push_to_top_level.
(make_label_decl): Don't fiddle with obstacks. Make RTL For the
label when expanding.
(cp_finish_decl): Only inject for-scope variables when doing
semantic analysis. Add comments.
(start_handler_parms): Return the handler parm.
(start_function): Reorganize. Don't clear DECL_INITIAL if it is
already set. Reinitialize from saved function data if available.
Don't pushlevel when not doing semantic analysis.
(store_parm_decls): Only generate RTL when expanding. Only
pushdecl when doing semantic analysis. Set
current_eh_spec_try_block if appropriate.
(finish_function): Simplify. Use do_pushlevel and do_poplevel.
Combine common code. Don't poplevel when not doing semantic
analysis.
(push_cp_function_context): Don't expand functions without an
explicit call to expand_body.
(mark_lang_function): Make eh_spec_try_block and
x_scope_stmt_stack.
* except.c (expand_end_eh_spec): Don't
declare.
(process_start_catch_block): Likewise.
(push_eh_cleanup): Use finish_decl_cleanup.
(initialize_handler_parm): New function.
(expand_start_catch_block): Use it.
(expand_end_catch_block): Use tree-generation functions, not
RTL-generation functions.
(expand_start_eh_spec): Likewise.
(expand_end_eh_spec): Likewise.
(expand_exception_blocks): Simplify.
(start_anon_func): Use do_pushlevel.
(end_anon_func): Use do_poplvel. Call expand_body for the
function.
* expr.c (do_case): Don't call define_case_label.
* init.c (create_temporary_var): Set DECL_CONTEXT for local
variables.
* method.c (emit_thunk): Call expand_body for the
thunk.
(sythesize_method): Likewise.
* parse.y (handler_args): Give it ttype.
(eat_saved_input): Call expand_body.
(base_init): Use do_pushlevel.
(pending_inline): Call expand_body.
(handler): Adjust calls to finish_handler_parms and
finish_handler.
(handler_args): Don't call expand_start_catch_block. Return the
catch parameter. * pt.c (tsubst_expr): Adjust HANDLER handling.
* parse.c: Regenerated.
* rtti.c (synthesize_tinfo_fn): Call finish_function.
* semantics.c (do_pushlevel): Give it external linkage. Build
SCOPE_STMTs.
(do_poplevel): Likewise.
(finish_case_label): Call define_case_label when doing semantic
analysis.
(finish_goto_stmt): Create RTL for labels.
(finish_function_try_block): Set in_function_try_handler
unconditionally.
(finish_function_handler_sequence): Unset it.
(finish_handler_parms): Use expand_start_catch_block even when
building a statement-tree.
(begin_catch_block): New function.
(finish_handler): Move a little RTL-generation logic here.
(finish_decl_cleanup): Allow cleanups for empty declarations.
(finish_named_return_value): Don't pushdecl when not doing
semantic analysis.
(expand_stmt): Don't do semantic analysis for variable
declarations. Handle START_CATCH_STMT. Call expand_label
directly for a LABEL_STMT. Tweak handling of GOTO_STMT. Adjust
HANDLERs. Handle SCOPE_STMT, CTOR_INITIALIZER, and RETURN_INIT.
(expand_body): Let expand_stmt handle CTOR_INITIALIZER,
RETURN_INIT and function try blocks.
* cp-tree.h (language_function): Add x_eh_spec_try_block. Add * cp-tree.h (language_function): Add x_eh_spec_try_block. Add
x_scope_stmt_stack. Add x_in_charge_parm. x_scope_stmt_stack. Add x_in_charge_parm.
(current_eh_spec_try_block): New macro. (current_eh_spec_try_block): New macro.
......
...@@ -747,6 +747,12 @@ struct language_function ...@@ -747,6 +747,12 @@ struct language_function
#define expanding_p cp_function_chain->x_expanding_p #define expanding_p cp_function_chain->x_expanding_p
/* Non-zero if we are in the semantic analysis phase for the current
function. */
#define doing_semantic_analysis_p() \
(!expanding_p || !current_function->x_whole_function_mode_p)
/* Non-zero if we should treat statements as full expressions. In /* Non-zero if we should treat statements as full expressions. In
particular, this variable is no-zero if at the end of a statement particular, this variable is no-zero if at the end of a statement
we should destroy any temporaries created during that statement. we should destroy any temporaries created during that statement.
...@@ -3022,11 +3028,7 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, OP_FLAG, TYPENAME_FLAG }; ...@@ -3022,11 +3028,7 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, OP_FLAG, TYPENAME_FLAG };
result of a using declaration. */ result of a using declaration. */
/* Used with start function. */ /* Used with start function. */
#define SF_DEFAULT SF_EXPAND #define SF_DEFAULT 0 /* No flags. */
/* No flags. Temporarily, this is
SF_EXPAND. Once we are fully
function-at-a-time, this will be
0. */
#define SF_PRE_PARSED 1 /* The function declaration has #define SF_PRE_PARSED 1 /* The function declaration has
already been parsed. */ already been parsed. */
#define SF_INCLASS_INLINE 2 /* The function is an inline, defined #define SF_INCLASS_INLINE 2 /* The function is an inline, defined
...@@ -3237,7 +3239,7 @@ extern void finish_decl PROTO((tree, tree, tree)); ...@@ -3237,7 +3239,7 @@ extern void finish_decl PROTO((tree, tree, tree));
extern void maybe_inject_for_scope_var PROTO((tree)); extern void maybe_inject_for_scope_var PROTO((tree));
extern void initialize_local_var PROTO((tree, tree, int)); extern void initialize_local_var PROTO((tree, tree, int));
extern void expand_static_init PROTO((tree, tree)); extern void expand_static_init PROTO((tree, tree));
extern void start_handler_parms PROTO((tree, tree)); extern tree start_handler_parms PROTO((tree, tree));
extern int complete_array_type PROTO((tree, tree, int)); extern int complete_array_type PROTO((tree, tree, int));
extern tree build_ptrmemfunc_type PROTO((tree)); extern tree build_ptrmemfunc_type PROTO((tree));
/* the grokdeclarator prototype is in decl.h */ /* the grokdeclarator prototype is in decl.h */
...@@ -3389,10 +3391,11 @@ extern int cp_line_of PROTO((tree)); ...@@ -3389,10 +3391,11 @@ extern int cp_line_of PROTO((tree));
/* in except.c */ /* in except.c */
extern void init_exception_processing PROTO((void)); extern void init_exception_processing PROTO((void));
extern void expand_start_catch_block PROTO((tree)); extern tree expand_start_catch_block PROTO((tree));
extern void expand_end_catch_block PROTO((void)); extern void expand_end_catch_block PROTO((tree));
extern void expand_builtin_throw PROTO((void)); extern void expand_builtin_throw PROTO((void));
extern void expand_start_eh_spec PROTO((void)); extern tree expand_start_eh_spec PROTO((void));
extern void expand_end_eh_spec PROTO((tree, tree));
extern void expand_exception_blocks PROTO((void)); extern void expand_exception_blocks PROTO((void));
extern tree start_anon_func PROTO((void)); extern tree start_anon_func PROTO((void));
extern void end_anon_func PROTO((void)); extern void end_anon_func PROTO((void));
...@@ -3660,9 +3663,9 @@ extern void finish_function_try_block PROTO((tree)); ...@@ -3660,9 +3663,9 @@ extern void finish_function_try_block PROTO((tree));
extern void finish_function_handler_sequence PROTO((tree)); extern void finish_function_handler_sequence PROTO((tree));
extern void finish_cleanup_try_block PROTO((tree)); extern void finish_cleanup_try_block PROTO((tree));
extern tree begin_handler PROTO((void)); extern tree begin_handler PROTO((void));
extern void start_handler_parms PROTO((tree, tree)); extern tree finish_handler_parms PROTO((tree, tree));
extern void finish_handler_parms PROTO((tree)); extern void begin_catch_block PROTO((tree));
extern void finish_handler PROTO((tree)); extern void finish_handler PROTO((tree, tree));
extern void finish_cleanup PROTO((tree, tree)); extern void finish_cleanup PROTO((tree, tree));
extern tree begin_compound_stmt PROTO((int)); extern tree begin_compound_stmt PROTO((int));
extern tree finish_compound_stmt PROTO((int, tree)); extern tree finish_compound_stmt PROTO((int, tree));
...@@ -3713,6 +3716,8 @@ extern void expand_body PROTO((tree)); ...@@ -3713,6 +3716,8 @@ extern void expand_body PROTO((tree));
extern void begin_stmt_tree PROTO((tree)); extern void begin_stmt_tree PROTO((tree));
extern void finish_stmt_tree PROTO((tree)); extern void finish_stmt_tree PROTO((tree));
extern void prep_stmt PROTO((tree)); extern void prep_stmt PROTO((tree));
extern void do_pushlevel PROTO((void));
extern tree do_poplevel PROTO((void));
/* Non-zero if we are presently building a statement tree, rather /* Non-zero if we are presently building a statement tree, rather
than expanding each statement as we encounter it. */ than expanding each statement as we encounter it. */
#define building_stmt_tree() \ #define building_stmt_tree() \
......
...@@ -822,10 +822,12 @@ void ...@@ -822,10 +822,12 @@ void
pushlevel (tag_transparent) pushlevel (tag_transparent)
int tag_transparent; int tag_transparent;
{ {
register struct binding_level *newlevel = NULL_BINDING_LEVEL; struct binding_level *newlevel;
/* Reuse or create a struct for this binding level. */ if (current_function && !doing_semantic_analysis_p ())
return;
/* Reuse or create a struct for this binding level. */
#if defined(DEBUG_CP_BINDING_LEVELS) #if defined(DEBUG_CP_BINDING_LEVELS)
if (0) if (0)
#else /* !defined(DEBUG_CP_BINDING_LEVELS) */ #else /* !defined(DEBUG_CP_BINDING_LEVELS) */
...@@ -1185,18 +1187,25 @@ poplevel (keep, reverse, functionbody) ...@@ -1185,18 +1187,25 @@ poplevel (keep, reverse, functionbody)
Put it into forward order, just for cleanliness. */ Put it into forward order, just for cleanliness. */
tree decls; tree decls;
int tmp = functionbody; int tmp = functionbody;
int real_functionbody = current_binding_level->keep == 2 int real_functionbody;
? ((functionbody = 0), tmp) : functionbody; tree tags;
tree tags = functionbody >= 0 ? current_binding_level->tags : 0; tree subblocks;
tree subblocks = functionbody >= 0 ? current_binding_level->blocks : 0;
tree block = NULL_TREE; tree block = NULL_TREE;
tree decl; tree decl;
int block_previously_created; int block_previously_created;
int leaving_for_scope; int leaving_for_scope;
if (current_function && !doing_semantic_analysis_p ())
return NULL_TREE;
my_friendly_assert (current_binding_level->parm_flag != 2, my_friendly_assert (current_binding_level->parm_flag != 2,
19990916); 19990916);
real_functionbody = (current_binding_level->keep == 2
? ((functionbody = 0), tmp) : functionbody);
tags = functionbody >= 0 ? current_binding_level->tags : 0;
subblocks = functionbody >= 0 ? current_binding_level->blocks : 0;
my_friendly_assert (!current_binding_level->class_shadowed, my_friendly_assert (!current_binding_level->class_shadowed,
19990414); 19990414);
...@@ -3631,8 +3640,16 @@ pushdecl (x) ...@@ -3631,8 +3640,16 @@ pushdecl (x)
tree x; tree x;
{ {
register tree t; register tree t;
register tree name = DECL_ASSEMBLER_NAME (x); register tree name;
int need_new_binding = 1; int need_new_binding;
/* We shouldn't be calling pushdecl when we're generating RTL for a
function that we already did semantic analysis on previously. */
my_friendly_assert (!current_function || doing_semantic_analysis_p (),
19990913);
name = DECL_ASSEMBLER_NAME (x);
need_new_binding = 1;
if (DECL_TEMPLATE_PARM_P (x)) if (DECL_TEMPLATE_PARM_P (x))
/* Template parameters have no context; they are not X::T even /* Template parameters have no context; they are not X::T even
...@@ -4119,10 +4136,9 @@ tree ...@@ -4119,10 +4136,9 @@ tree
pushdecl_top_level (x) pushdecl_top_level (x)
tree x; tree x;
{ {
tree cur_namespace = current_namespace; push_to_top_level ();
current_namespace = global_namespace;
x = pushdecl_namespace_level (x); x = pushdecl_namespace_level (x);
current_namespace = cur_namespace; pop_from_top_level ();
return x; return x;
} }
...@@ -4606,12 +4622,8 @@ make_label_decl (id, local_p) ...@@ -4606,12 +4622,8 @@ make_label_decl (id, local_p)
{ {
tree decl; tree decl;
if (building_stmt_tree ())
push_permanent_obstack ();
decl = build_decl (LABEL_DECL, id, void_type_node); decl = build_decl (LABEL_DECL, id, void_type_node);
if (building_stmt_tree ()) if (expanding_p)
pop_obstacks ();
else
/* Make sure every label has an rtx. */ /* Make sure every label has an rtx. */
label_rtx (decl); label_rtx (decl);
...@@ -7742,9 +7754,6 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags) ...@@ -7742,9 +7754,6 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL
|| TREE_CODE (decl) == RESULT_DECL) || TREE_CODE (decl) == RESULT_DECL)
{ {
/* ??? FIXME: What about nested classes? */
int toplev = toplevel_bindings_p ();
if (TREE_CODE (decl) == VAR_DECL) if (TREE_CODE (decl) == VAR_DECL)
maybe_commonize_var (decl); maybe_commonize_var (decl);
...@@ -7773,10 +7782,11 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags) ...@@ -7773,10 +7782,11 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
|| TYPE_NEEDS_DESTRUCTOR (type)) || TYPE_NEEDS_DESTRUCTOR (type))
expand_static_init (decl, init); expand_static_init (decl, init);
} }
else if (! toplev) else if (TREE_CODE (CP_DECL_CONTEXT (decl)) == FUNCTION_DECL)
{ {
/* This is a local declaration. */ /* This is a local declaration. */
maybe_inject_for_scope_var (decl); if (doing_semantic_analysis_p ())
maybe_inject_for_scope_var (decl);
/* Initialize the local variable. But, if we're building a /* Initialize the local variable. But, if we're building a
statement-tree, we'll do the initialization when we statement-tree, we'll do the initialization when we
expand the tree. */ expand the tree. */
...@@ -7787,8 +7797,11 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags) ...@@ -7787,8 +7797,11 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
} }
else else
{ {
/* If we're not building RTL, then we need to do so
now. */
if (!building_stmt_tree ()) if (!building_stmt_tree ())
emit_local_var (decl); emit_local_var (decl);
/* Initialize the variable. */
initialize_local_var (decl, init, flags); initialize_local_var (decl, init, flags);
/* Clean up the variable. */ /* Clean up the variable. */
destroy_local_var (decl); destroy_local_var (decl);
...@@ -8043,7 +8056,7 @@ expand_static_init (decl, init) ...@@ -8043,7 +8056,7 @@ expand_static_init (decl, init)
/* Finish the declaration of a catch-parameter. */ /* Finish the declaration of a catch-parameter. */
void tree
start_handler_parms (declspecs, declarator) start_handler_parms (declspecs, declarator)
tree declspecs; tree declspecs;
tree declarator; tree declarator;
...@@ -8058,7 +8071,8 @@ start_handler_parms (declspecs, declarator) ...@@ -8058,7 +8071,8 @@ start_handler_parms (declspecs, declarator)
} }
else else
decl = NULL_TREE; decl = NULL_TREE;
expand_start_catch_block (decl);
return decl;
} }
...@@ -12767,6 +12781,16 @@ start_function (declspecs, declarator, attrs, flags) ...@@ -12767,6 +12781,16 @@ start_function (declspecs, declarator, attrs, flags)
} }
} }
} }
/* Sometimes we don't notice that a function is a static member, and
build a METHOD_TYPE for it. Fix that up now. */
if (ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1)
&& TREE_CODE (TREE_TYPE (decl1)) == METHOD_TYPE)
{
revert_static_member_fn (&decl1, NULL, NULL);
last_function_parms = TREE_CHAIN (last_function_parms);
ctype = NULL_TREE;
}
/* Warn if function was previously implicitly declared /* Warn if function was previously implicitly declared
(but not if we warned then). */ (but not if we warned then). */
...@@ -12798,7 +12822,8 @@ start_function (declspecs, declarator, attrs, flags) ...@@ -12798,7 +12822,8 @@ start_function (declspecs, declarator, attrs, flags)
/* Make the init_value nonzero so pushdecl knows this is not tentative. /* Make the init_value nonzero so pushdecl knows this is not tentative.
error_mark_node is replaced below (in poplevel) with the BLOCK. */ error_mark_node is replaced below (in poplevel) with the BLOCK. */
DECL_INITIAL (decl1) = error_mark_node; if (!DECL_INITIAL (decl1))
DECL_INITIAL (decl1) = error_mark_node;
#ifdef SET_DEFAULT_DECL_ATTRIBUTES #ifdef SET_DEFAULT_DECL_ATTRIBUTES
SET_DEFAULT_DECL_ATTRIBUTES (decl1, attrs); SET_DEFAULT_DECL_ATTRIBUTES (decl1, attrs);
...@@ -12892,6 +12917,48 @@ start_function (declspecs, declarator, attrs, flags) ...@@ -12892,6 +12917,48 @@ start_function (declspecs, declarator, attrs, flags)
current_function_decl = decl1; current_function_decl = decl1;
current_function->decl = decl1; current_function->decl = decl1;
/* Initialize the per-function data. */
if (!DECL_PENDING_INLINE_P (decl1) && DECL_SAVED_FUNCTION_DATA (decl1))
{
/* If we already parsed this function, and we're just expanding it
now, restore saved state. */
struct binding_level *bl = current_binding_level;
*cp_function_chain = *DECL_SAVED_FUNCTION_DATA (decl1);
current_binding_level = bl;
/* This function has not assigned to `this' yet. */
current_function_assigns_this = 0;
current_function_just_assigned_this = 0;
/* This function is being processed in whole-function mode; we
already did semantic analysis. */
current_function->x_whole_function_mode_p = 1;
/* We don't need the saved data anymore. */
free (DECL_SAVED_FUNCTION_DATA (decl1));
DECL_SAVED_FUNCTION_DATA (decl1) = NULL;
}
else if (ctype && !doing_friend && !DECL_STATIC_FUNCTION_P (decl1))
{
/* We know that this was set up by `grokclassfn'. We do not
wait until `store_parm_decls', since evil parse errors may
never get us to that point. Here we keep the consistency
between `current_class_type' and `current_class_ptr'. */
tree t = DECL_ARGUMENTS (decl1);
my_friendly_assert (t != NULL_TREE && TREE_CODE (t) == PARM_DECL,
162);
my_friendly_assert (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE,
19990811);
cp_function_chain->x_current_class_ref
= build_indirect_ref (t, NULL_PTR);
cp_function_chain->x_current_class_ptr = t;
if (DECL_DESTRUCTOR_P (decl1))
current_in_charge_parm = TREE_CHAIN (t);
}
if (DECL_INTERFACE_KNOWN (decl1)) if (DECL_INTERFACE_KNOWN (decl1))
{ {
tree ctx = hack_decl_function_context (decl1); tree ctx = hack_decl_function_context (decl1);
...@@ -12957,62 +13024,12 @@ start_function (declspecs, declarator, attrs, flags) ...@@ -12957,62 +13024,12 @@ start_function (declspecs, declarator, attrs, flags)
DECL_INTERFACE_KNOWN (decl1) = 1; DECL_INTERFACE_KNOWN (decl1) = 1;
} }
if (ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1)) if (doing_semantic_analysis_p ())
{ {
if (TREE_CODE (fntype) == METHOD_TYPE) pushlevel (0);
TREE_TYPE (decl1) = fntype current_binding_level->parm_flag = 1;
= build_function_type (TREE_TYPE (fntype),
TREE_CHAIN (TYPE_ARG_TYPES (fntype)));
current_function_parms = TREE_CHAIN (current_function_parms);
DECL_ARGUMENTS (decl1) = current_function_parms;
ctype = NULL_TREE;
}
my_friendly_assert (current_class_ptr == NULL_TREE, 19990908);
my_friendly_assert (current_class_ref == NULL_TREE, 19990908);
if (ctype)
{
/* If we're compiling a friend function, neither of the variables
current_class_ptr nor current_class_type will have values. */
if (! doing_friend)
{
/* We know that this was set up by `grokclassfn'.
We do not wait until `store_parm_decls', since evil
parse errors may never get us to that point. Here
we keep the consistency between `current_class_type'
and `current_class_ptr'. */
tree t = current_function_parms;
int i;
my_friendly_assert (t != NULL_TREE
&& TREE_CODE (t) == PARM_DECL, 162);
my_friendly_assert (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE,
19990811);
if (! hack_decl_function_context (decl1))
temporary_allocation ();
i = suspend_momentary ();
/* Normally, build_indirect_ref returns current_class_ref
whenever current_class_ptr is dereferenced. This time,
however, we want it to *create* current_class_ref, so we
temporarily clear current_class_ptr to fool it. */
cp_function_chain->x_current_class_ref
= build_indirect_ref (t, NULL_PTR);
cp_function_chain->x_current_class_ptr = t;
if (DECL_DESTRUCTOR_P (decl1))
current_in_charge_parm = TREE_CHAIN (t);
resume_momentary (i);
if (! hack_decl_function_context (decl1))
end_temporary_allocation ();
}
} }
pushlevel (0);
current_binding_level->parm_flag = 1;
if (attrs) if (attrs)
cplus_decl_attributes (decl1, NULL_TREE, attrs); cplus_decl_attributes (decl1, NULL_TREE, attrs);
...@@ -13057,16 +13074,9 @@ start_function (declspecs, declarator, attrs, flags) ...@@ -13057,16 +13074,9 @@ start_function (declspecs, declarator, attrs, flags)
if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl1)) if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl1))
&& DECL_LANGUAGE (decl1) == lang_cplusplus) && DECL_LANGUAGE (decl1) == lang_cplusplus)
{ dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); else if (DECL_CONSTRUCTOR_P (decl1))
ctor_label = NULL_TREE; ctor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
}
else
{
dtor_label = NULL_TREE;
if (DECL_CONSTRUCTOR_P (decl1))
ctor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
}
return 1; return 1;
} }
...@@ -13096,9 +13106,6 @@ store_parm_decls () ...@@ -13096,9 +13106,6 @@ store_parm_decls ()
int parms_have_cleanups = 0; int parms_have_cleanups = 0;
tree cleanups = NULL_TREE; tree cleanups = NULL_TREE;
/* This is either a chain of PARM_DECLs (when a prototype is used). */
tree specparms = current_function_parms;
/* This is a list of types declared among parms in a prototype. */ /* This is a list of types declared among parms in a prototype. */
tree parmtags = current_function_parm_tags; tree parmtags = current_function_parm_tags;
...@@ -13107,39 +13114,48 @@ store_parm_decls () ...@@ -13107,39 +13114,48 @@ store_parm_decls ()
then CONST_DECLs for foo and bar are put here. */ then CONST_DECLs for foo and bar are put here. */
tree nonparms = NULL_TREE; tree nonparms = NULL_TREE;
if (toplevel_bindings_p ())
fatal ("parse errors have confused me too much");
/* Create a binding level for the parms. */ /* Create a binding level for the parms. */
expand_start_bindings (0); if (!building_stmt_tree ())
expand_start_bindings (2);
if (specparms != NULL_TREE) if (current_function_parms)
{ {
/* This case is when the function was defined with an ANSI prototype. /* This case is when the function was defined with an ANSI prototype.
The parms already have decls, so we need not do anything here The parms already have decls, so we need not do anything here
except record them as in effect except record them as in effect
and complain if any redundant old-style parm decls were written. */ and complain if any redundant old-style parm decls were written. */
register tree next; tree specparms = current_function_parms;
tree next;
if (doing_semantic_analysis_p ())
{
/* Must clear this because it might contain TYPE_DECLs declared
at class level. */
storedecls (NULL_TREE);
/* Must clear this because it might contain TYPE_DECLs declared /* If we're doing semantic analysis, then we'll call pushdecl
at class level. */ for each of these. We must do them in reverse order so that
storedecls (NULL_TREE); they end in the correct forward order. */
specparms = nreverse (specparms);
}
for (parm = nreverse (specparms); parm; parm = next) for (parm = specparms; parm; parm = next)
{ {
next = TREE_CHAIN (parm); next = TREE_CHAIN (parm);
if (TREE_CODE (parm) == PARM_DECL) if (TREE_CODE (parm) == PARM_DECL)
{ {
tree cleanup; tree cleanup;
if (DECL_NAME (parm) == NULL_TREE)
if (doing_semantic_analysis_p ())
{ {
pushdecl (parm); if (DECL_NAME (parm) == NULL_TREE
|| TREE_CODE (TREE_TYPE (parm)) != VOID_TYPE)
pushdecl (parm);
else
cp_error ("parameter `%D' declared void", parm);
} }
else if (TREE_CODE (TREE_TYPE (parm)) == VOID_TYPE)
cp_error ("parameter `%D' declared void", parm);
else
pushdecl (parm);
if (! building_stmt_tree () if (! building_stmt_tree ()
&& (cleanup = maybe_build_cleanup (parm), cleanup)) && (cleanup = maybe_build_cleanup (parm), cleanup))
{ {
...@@ -13159,12 +13175,17 @@ store_parm_decls () ...@@ -13159,12 +13175,17 @@ store_parm_decls ()
} }
} }
/* Get the decls in their original chain order if (doing_semantic_analysis_p ())
and record in the function. This is all and only the {
PARM_DECLs that were pushed into scope by the loop above. */ /* Get the decls in their original chain order
DECL_ARGUMENTS (fndecl) = getdecls (); and record in the function. This is all and only the
PARM_DECLs that were pushed into scope by the loop above. */
DECL_ARGUMENTS (fndecl) = getdecls ();
storetags (chainon (parmtags, gettags ()));
storetags (chainon (parmtags, gettags ())); /* We built up the cleanups in reversed order. */
cleanups = nreverse (cleanups);
}
} }
else else
DECL_ARGUMENTS (fndecl) = NULL_TREE; DECL_ARGUMENTS (fndecl) = NULL_TREE;
...@@ -13173,8 +13194,8 @@ store_parm_decls () ...@@ -13173,8 +13194,8 @@ store_parm_decls ()
as the decl-chain of the current lexical scope. as the decl-chain of the current lexical scope.
Put the enumerators in as well, at the front so that Put the enumerators in as well, at the front so that
DECL_ARGUMENTS is not modified. */ DECL_ARGUMENTS is not modified. */
if (doing_semantic_analysis_p ())
storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl))); storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl)));
/* Initialize the RTL code for the function. */ /* Initialize the RTL code for the function. */
DECL_SAVED_INSNS (fndecl) = 0; DECL_SAVED_INSNS (fndecl) = 0;
...@@ -13192,17 +13213,15 @@ store_parm_decls () ...@@ -13192,17 +13213,15 @@ store_parm_decls ()
cleanups. We cannot do this before, since expand_decl_cleanup cleanups. We cannot do this before, since expand_decl_cleanup
should not be called before the parm can be used. */ should not be called before the parm can be used. */
if (cleanups && !building_stmt_tree ()) if (cleanups && !building_stmt_tree ())
{ while (cleanups)
for (cleanups = nreverse (cleanups); {
cleanups; if (! expand_decl_cleanup (TREE_PURPOSE (cleanups),
cleanups = TREE_CHAIN (cleanups)) TREE_VALUE (cleanups)))
{ cp_error ("parser lost in parsing declaration of `%D'",
if (! expand_decl_cleanup (TREE_PURPOSE (cleanups), TREE_PURPOSE (cleanups));
TREE_VALUE (cleanups)))
cp_error ("parser lost in parsing declaration of `%D'", cleanups = TREE_CHAIN (cleanups);
TREE_PURPOSE (cleanups)); }
}
}
/* Create a binding contour which can be used to catch /* Create a binding contour which can be used to catch
cleanup-generated temporaries. Also, if the return value needs or cleanup-generated temporaries. Also, if the return value needs or
...@@ -13211,15 +13230,14 @@ store_parm_decls () ...@@ -13211,15 +13230,14 @@ store_parm_decls ()
{ {
pushlevel (0); pushlevel (0);
if (!building_stmt_tree ()) if (!building_stmt_tree ())
expand_start_bindings (0); expand_start_bindings (2);
} }
if (! building_stmt_tree () && flag_exceptions) /* Do the starting of the exception specifications, if we have any. */
{ if (flag_exceptions && !processing_template_decl
/* Do the starting of the exception specifications, if we have any. */ && building_stmt_tree ()
if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl))) && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
expand_start_eh_spec (); current_eh_spec_try_block = expand_start_eh_spec ();
}
last_parm_cleanup_insn = get_last_insn (); last_parm_cleanup_insn = get_last_insn ();
last_dtor_insn = get_last_insn (); last_dtor_insn = get_last_insn ();
...@@ -13306,7 +13324,6 @@ finish_function (lineno, flags) ...@@ -13306,7 +13324,6 @@ finish_function (lineno, flags)
rtx fn_last_parm_insn, insns; rtx fn_last_parm_insn, insns;
/* Label to use if this function is supposed to return a value. */ /* Label to use if this function is supposed to return a value. */
tree no_return_label = NULL_TREE; tree no_return_label = NULL_TREE;
tree decls = NULL_TREE;
int call_poplevel = (flags & 1) != 0; int call_poplevel = (flags & 1) != 0;
int inclass_inline = (flags & 2) != 0; int inclass_inline = (flags & 2) != 0;
int expand_p; int expand_p;
...@@ -13334,20 +13351,14 @@ finish_function (lineno, flags) ...@@ -13334,20 +13351,14 @@ finish_function (lineno, flags)
if (building_stmt_tree ()) if (building_stmt_tree ())
{ {
if (DECL_CONSTRUCTOR_P (fndecl) && call_poplevel) if (DECL_CONSTRUCTOR_P (fndecl) && call_poplevel)
{ do_poplevel ();
decls = getdecls ();
expand_end_bindings (decls, decls != NULL_TREE, 0);
poplevel (decls != NULL_TREE, 0, 0);
}
/* Because we do not call expand_function_end, we won't call /* Finish dealing with exception specifiers. */
expand_end_bindings to match the call to if (flag_exceptions && !processing_template_decl
expand_start_bindings we did in store_parm_decls. Therefore, && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
we explicitly call expand_end_bindings here. However, we expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS
really shouldn't be calling expand_start_bindings at all when (TREE_TYPE (current_function_decl)),
building_stmt_tree; it's conceptually an RTL-generation current_eh_spec_try_block);
function, rather than a front-end function. */
expand_end_bindings (0, 0, 0);
} }
else else
{ {
...@@ -13401,8 +13412,7 @@ finish_function (lineno, flags) ...@@ -13401,8 +13412,7 @@ finish_function (lineno, flags)
/* These initializations might go inline. Protect /* These initializations might go inline. Protect
the binding level of the parms. */ the binding level of the parms. */
pushlevel (0); do_pushlevel ();
expand_start_bindings (0);
if (current_function_assigns_this) if (current_function_assigns_this)
{ {
...@@ -13511,8 +13521,7 @@ finish_function (lineno, flags) ...@@ -13511,8 +13521,7 @@ finish_function (lineno, flags)
} }
/* End of destructor. */ /* End of destructor. */
expand_end_bindings (NULL_TREE, getdecls () != NULL_TREE, 0); do_poplevel ();
poplevel (getdecls () != NULL_TREE, 0, 0);
/* Back to the top of destructor. */ /* Back to the top of destructor. */
/* Don't execute destructor code if `this' is NULL. */ /* Don't execute destructor code if `this' is NULL. */
...@@ -13560,77 +13569,59 @@ finish_function (lineno, flags) ...@@ -13560,77 +13569,59 @@ finish_function (lineno, flags)
if (! ok_to_optimize_dtor) if (! ok_to_optimize_dtor)
expand_end_cond (); expand_end_cond ();
} }
else if (current_function_assigns_this) else if (DECL_CONSTRUCTOR_P (fndecl))
{ {
/* Does not need to call emit_base_init, because /* If the current function assigns to `this', then code to
that is done (if needed) just after assignment to this initialize members and base-classes will be generated
is seen. */ directly after the assignment. */
if (!current_function_assigns_this)
if (DECL_CONSTRUCTOR_P (current_function_decl))
{ {
end_protect_partials (); start_sequence ();
expand_label (ctor_label);
ctor_label = NULL_TREE;
if (call_poplevel) if (flag_this_is_variable > 0)
{ {
decls = getdecls (); /* Allow constructor for a type to get a new instance of
expand_end_bindings (decls, decls != NULL_TREE, 0); the object using `build_new'. */
poplevel (decls != NULL_TREE, 0, 0); tree cond = NULL_TREE, thenclause = NULL_TREE;
tree abstract_virtuals
= CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type);
CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = NULL_TREE;
cond = build_binary_op (EQ_EXPR,
current_class_ptr, integer_zero_node);
expand_start_cond (cond, 0);
thenclause
= build_modify_expr (current_class_ptr, NOP_EXPR,
build_new (NULL_TREE,
current_class_type,
void_type_node, 0));
CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type)
= abstract_virtuals;
expand_expr_stmt (thenclause);
expand_end_cond ();
} }
/* c_expand_return knows to return 'this' from a constructor. */
c_expand_return (NULL_TREE);
}
else if (TREE_CODE (TREE_TYPE (DECL_RESULT (current_function_decl))) != VOID_TYPE
&& return_label != NULL_RTX)
no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
current_function_assigns_this = 0;
current_function_just_assigned_this = 0;
base_init_expr = NULL_TREE;
}
else if (DECL_CONSTRUCTOR_P (fndecl))
{
tree cond = NULL_TREE, thenclause = NULL_TREE;
/* Allow constructor for a type to get a new instance of the object
using `build_new'. */
tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type);
CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = NULL_TREE;
if (flag_this_is_variable > 0) /* Emit insns from `emit_base_init' which sets up
{ virtual function table pointer(s). Don't do this for
cond = build_binary_op (EQ_EXPR, a function which assigns to `this' as we will emit
current_class_ptr, integer_zero_node); the appropriate code right after the assignment. */
thenclause = build_modify_expr (current_class_ptr, NOP_EXPR, if (!current_function_assigns_this && base_init_expr)
build_new (NULL_TREE, current_class_type, void_type_node, 0)); {
} expand_expr_stmt (base_init_expr);
base_init_expr = NULL_TREE;
CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = abstract_virtuals; }
start_sequence (); insns = get_insns ();
end_sequence ();
if (flag_this_is_variable > 0) emit_insns_after (insns, last_parm_cleanup_insn);
{
expand_start_cond (cond, 0);
expand_expr_stmt (thenclause);
expand_end_cond ();
} }
/* Emit insns from `emit_base_init' which sets up virtual /* This is where the body of the constructor begins. All
function table pointer(s). */ subobjects have been fully constructed at this point. */
if (base_init_expr)
{
expand_expr_stmt (base_init_expr);
base_init_expr = NULL_TREE;
}
insns = get_insns ();
end_sequence ();
/* This is where the body of the constructor begins. */
emit_insns_after (insns, last_parm_cleanup_insn);
end_protect_partials (); end_protect_partials ();
/* This is where the body of the constructor ends. */ /* This is where the body of the constructor ends. */
...@@ -13638,11 +13629,7 @@ finish_function (lineno, flags) ...@@ -13638,11 +13629,7 @@ finish_function (lineno, flags)
ctor_label = NULL_TREE; ctor_label = NULL_TREE;
if (call_poplevel) if (call_poplevel)
{ do_poplevel ();
decls = getdecls ();
expand_end_bindings (decls, decls != NULL_TREE, 0);
poplevel (decls != NULL_TREE, 1, 0);
}
/* c_expand_return knows to return 'this' from a constructor. */ /* c_expand_return knows to return 'this' from a constructor. */
c_expand_return (NULL_TREE); c_expand_return (NULL_TREE);
...@@ -13660,8 +13647,13 @@ finish_function (lineno, flags) ...@@ -13660,8 +13647,13 @@ finish_function (lineno, flags)
#endif #endif
} }
else if (return_label != NULL_RTX else if (return_label != NULL_RTX
&& current_function_return_value == NULL_TREE && ((flag_this_is_variable <= 0
&& ! DECL_NAME (DECL_RESULT (current_function_decl))) && current_function_return_value == NULL_TREE
&& ! DECL_NAME (DECL_RESULT (current_function_decl)))
|| (flag_this_is_variable > 0
&& (TREE_CODE (TREE_TYPE (DECL_RESULT
(current_function_decl)))
== VOID_TYPE))))
no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
if (flag_exceptions) if (flag_exceptions)
...@@ -13743,9 +13735,12 @@ finish_function (lineno, flags) ...@@ -13743,9 +13735,12 @@ finish_function (lineno, flags)
/* This must come after expand_function_end because cleanups might /* This must come after expand_function_end because cleanups might
have declarations (from inline functions) that need to go into have declarations (from inline functions) that need to go into
this function's blocks. */ this function's blocks. */
if (current_binding_level->parm_flag != 1) if (doing_semantic_analysis_p ())
my_friendly_abort (122); {
poplevel (1, 0, 1); if (current_binding_level->parm_flag != 1)
my_friendly_abort (122);
poplevel (1, 0, 1);
}
/* Remember that we were in class scope. */ /* Remember that we were in class scope. */
if (current_class_name) if (current_class_name)
...@@ -13887,7 +13882,7 @@ finish_function (lineno, flags) ...@@ -13887,7 +13882,7 @@ finish_function (lineno, flags)
if (! nested) if (! nested)
permanent_allocation (1); permanent_allocation (1);
if (DECL_SAVED_INSNS (fndecl) == 0) if (!DECL_SAVED_INSNS (fndecl) && !DECL_SAVED_FUNCTION_DATA (fndecl))
{ {
tree t; tree t;
...@@ -14314,9 +14309,9 @@ push_cp_function_context (f) ...@@ -14314,9 +14309,9 @@ push_cp_function_context (f)
xcalloc (1, sizeof (struct language_function))); xcalloc (1, sizeof (struct language_function)));
f->language = p; f->language = p;
/* For now, we always assume we're expanding all the way to RTL /* It takes an explicit call to expand_body to generate RTL for a
unless we're explicitly doing otherwise. */ function. */
expanding_p = 1; expanding_p = 0;
/* Whenever we start a new function, we destroy temporaries in the /* Whenever we start a new function, we destroy temporaries in the
usual way. */ usual way. */
...@@ -14353,6 +14348,8 @@ mark_lang_function (p) ...@@ -14353,6 +14348,8 @@ mark_lang_function (p)
ggc_mark_tree (p->x_current_class_ref); ggc_mark_tree (p->x_current_class_ref);
ggc_mark_tree (p->x_last_tree); ggc_mark_tree (p->x_last_tree);
ggc_mark_tree (p->x_last_expr_type); ggc_mark_tree (p->x_last_expr_type);
ggc_mark_tree (p->x_eh_spec_try_block);
ggc_mark_tree (p->x_scope_stmt_stack);
ggc_mark_rtx (p->x_last_dtor_insn); ggc_mark_rtx (p->x_last_dtor_insn);
ggc_mark_rtx (p->x_last_parm_cleanup_insn); ggc_mark_rtx (p->x_last_parm_cleanup_insn);
......
...@@ -39,7 +39,6 @@ Boston, MA 02111-1307, USA. */ ...@@ -39,7 +39,6 @@ Boston, MA 02111-1307, USA. */
static void push_eh_cleanup PROTO((void)); static void push_eh_cleanup PROTO((void));
static tree build_eh_type_type PROTO((tree)); static tree build_eh_type_type PROTO((tree));
static tree build_eh_type PROTO((tree)); static tree build_eh_type PROTO((tree));
static void expand_end_eh_spec PROTO((tree));
static tree call_eh_info PROTO((void)); static tree call_eh_info PROTO((void));
static void push_eh_info PROTO((void)); static void push_eh_info PROTO((void));
static tree get_eh_info PROTO((void)); static tree get_eh_info PROTO((void));
...@@ -50,11 +49,11 @@ static tree get_eh_caught PROTO((void)); ...@@ -50,11 +49,11 @@ static tree get_eh_caught PROTO((void));
static tree get_eh_handlers PROTO((void)); static tree get_eh_handlers PROTO((void));
#endif #endif
static tree do_pop_exception PROTO((void)); static tree do_pop_exception PROTO((void));
static void process_start_catch_block PROTO((tree));
static tree build_eh_type_type_ref PROTO((tree)); static tree build_eh_type_type_ref PROTO((tree));
static tree build_terminate_handler PROTO((void)); static tree build_terminate_handler PROTO((void));
static tree alloc_eh_object PROTO((tree)); static tree alloc_eh_object PROTO((tree));
static int complete_ptr_ref_or_void_ptr_p PROTO((tree, tree)); static int complete_ptr_ref_or_void_ptr_p PROTO((tree, tree));
static void initialize_handler_parm PROTO((tree));
#if 0 #if 0
/* This is the startup, and finish stuff per exception table. */ /* This is the startup, and finish stuff per exception table. */
...@@ -483,7 +482,7 @@ push_eh_cleanup () ...@@ -483,7 +482,7 @@ push_eh_cleanup ()
yes = suspend_momentary (); yes = suspend_momentary ();
/* All cleanups must last longer than normal. */ /* All cleanups must last longer than normal. */
expand_decl_cleanup (NULL_TREE, do_pop_exception ()); finish_decl_cleanup (NULL_TREE, do_pop_exception ());
resume_momentary (yes); resume_momentary (yes);
} }
...@@ -499,131 +498,96 @@ build_terminate_handler () ...@@ -499,131 +498,96 @@ build_terminate_handler ()
return term; return term;
} }
/* Call this to start a catch block. Typename is the typename, and identifier /* Initialize the catch parameter DECL. */
is the variable to place the object in or NULL if the variable doesn't
matter. If typename is NULL, that means its a "catch (...)" or catch
everything. In that case we don't need to do any type checking.
(ie: it ends up as the "else" clause rather than an "else if" clause) */
void
expand_start_catch_block (decl)
tree decl;
{
if (building_stmt_tree ())
{
if (decl)
{
/* We must ensure that DECL_CONTEXT is set up before we call
push_template_decl; that code depends on DECL_CONTEXT
being set correctly. */
DECL_CONTEXT (decl) = current_function_decl;
if (processing_template_decl)
decl = push_template_decl (decl);
pushdecl (decl);
add_decl_stmt (decl);
}
return;
}
if (! doing_eh (1))
return;
process_start_catch_block (decl);
}
/* This function performs the expand_start_catch_block functionality for
exceptions implemented in the new style. __throw determines whether
a handler needs to be called or not, so the handler itself has to do
nothing additional. */
static void static void
process_start_catch_block (decl) initialize_handler_parm (decl)
tree decl; tree decl;
{ {
tree exp;
tree init; tree init;
tree init_type;
/* Create a binding level for the eh_info and the exception object /* Make sure we mark the catch param as used, otherwise we'll get a
cleanup. */ warning about an unused ((anonymous)). */
pushlevel (0); TREE_USED (decl) = 1;
expand_start_bindings (0);
if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE))
decl = NULL_TREE;
if (decl)
start_catch_handler (build_eh_type_type_ref (TREE_TYPE (decl)));
else
start_catch_handler (CATCH_ALL_TYPE);
emit_line_note (input_filename, lineno); /* Figure out the type that the initializer is. */
init_type = TREE_TYPE (decl);
if (TREE_CODE (init_type) != REFERENCE_TYPE
&& TREE_CODE (init_type) != POINTER_TYPE)
init_type = build_reference_type (init_type);
push_eh_info (); exp = get_eh_value ();
if (decl) /* Since pointers are passed by value, initialize a reference to
{ pointer catch parm with the address of the value slot. */
tree exp; if (TREE_CODE (init_type) == REFERENCE_TYPE
tree init_type; && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
exp = build_unary_op (ADDR_EXPR, exp, 1);
/* Make sure we mark the catch param as used, otherwise we'll get exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
a warning about an unused ((anonymous)). */
TREE_USED (decl) = 1;
/* Figure out the type that the initializer is. */ init = convert_from_reference (exp);
init_type = TREE_TYPE (decl);
if (TREE_CODE (init_type) != REFERENCE_TYPE
&& TREE_CODE (init_type) != POINTER_TYPE)
init_type = build_reference_type (init_type);
exp = get_eh_value (); /* If the constructor for the catch parm exits via an exception, we
must call terminate. See eh23.C. */
if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
{
/* Generate the copy constructor call directly so we can wrap it.
See also expand_default_init. */
init = ocp_convert (TREE_TYPE (decl), init,
CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
build_terminate_handler ());
}
/* Since pointers are passed by value, initialize a reference to /* Let `cp_finish_decl' know that this initializer is ok. */
pointer catch parm with the address of the value slot. */ DECL_INITIAL (decl) = error_mark_node;
if (TREE_CODE (init_type) == REFERENCE_TYPE decl = pushdecl (decl);
&& TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
exp = build_unary_op (ADDR_EXPR, exp, 1);
exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0); start_decl_1 (decl);
cp_finish_decl (decl, init, NULL_TREE, 0,
LOOKUP_ONLYCONVERTING|DIRECT_BIND);
}
push_eh_cleanup (); /* Call this to start a catch block. DECL is the catch parameter. */
/* Create a binding level for the parm. */ tree
pushlevel (0); expand_start_catch_block (decl)
expand_start_bindings (0); tree decl;
{
tree compound_stmt_1;
tree compound_stmt_2;
tree type;
init = convert_from_reference (exp); if (! doing_eh (1))
return NULL_TREE;
/* If the constructor for the catch parm exits via an exception, we /* Make sure this declaration is reasonable. */
must call terminate. See eh23.C. */ if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE))
if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) decl = NULL_TREE;
{
/* Generate the copy constructor call directly so we can wrap it.
See also expand_default_init. */
init = ocp_convert (TREE_TYPE (decl), init,
CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
build_terminate_handler ());
}
/* Let `cp_finish_decl' know that this initializer is ok. */ /* Create a binding level for the eh_info and the exception object
DECL_INITIAL (decl) = init; cleanup. */
decl = pushdecl (decl); compound_stmt_1 = begin_compound_stmt (/*has_no_scope=*/0);
start_decl_1 (decl); if (decl)
cp_finish_decl (decl, init, NULL_TREE, 0, type = build_eh_type_type_ref (TREE_TYPE (decl));
LOOKUP_ONLYCONVERTING|DIRECT_BIND);
}
else else
{ type = NULL_TREE;
push_eh_cleanup (); begin_catch_block (type);
/* Create a binding level for the parm. */ push_eh_info ();
pushlevel (0); push_eh_cleanup ();
expand_start_bindings (0);
/* Fall into the catch all section. */ /* Create a binding level for the parm. */
} compound_stmt_2 = begin_compound_stmt (/*has_no_scope=*/0);
emit_line_note (input_filename, lineno); if (decl)
initialize_handler_parm (decl);
return build_tree_list (compound_stmt_1, compound_stmt_2);
} }
...@@ -632,8 +596,12 @@ process_start_catch_block (decl) ...@@ -632,8 +596,12 @@ process_start_catch_block (decl)
the label to jump to if this catch block didn't match. */ the label to jump to if this catch block didn't match. */
void void
expand_end_catch_block () expand_end_catch_block (blocks)
tree blocks;
{ {
tree compound_stmt_1 = blocks ? TREE_PURPOSE (blocks): NULL_TREE;
tree compound_stmt_2 = blocks ? TREE_VALUE (blocks): NULL_TREE;
if (! doing_eh (1)) if (! doing_eh (1))
return; return;
...@@ -642,22 +610,12 @@ expand_end_catch_block () ...@@ -642,22 +610,12 @@ expand_end_catch_block ()
if (in_function_try_handler if (in_function_try_handler
&& (DECL_CONSTRUCTOR_P (current_function_decl) && (DECL_CONSTRUCTOR_P (current_function_decl)
|| DECL_DESTRUCTOR_P (current_function_decl))) || DECL_DESTRUCTOR_P (current_function_decl)))
expand_throw (NULL_TREE); finish_expr_stmt (build_throw (NULL_TREE));
/* Cleanup the EH parameter. */ /* Cleanup the EH parameter. */
expand_end_bindings (getdecls (), kept_level_p (), 0); finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1);
poplevel (kept_level_p (), 1, 0); /* Cleanup the EH object. */
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_2);
/* Cleanup the EH object. */
expand_end_bindings (getdecls (), kept_level_p (), 0);
poplevel (kept_level_p (), 1, 0);
/* 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 ();
} }
/* An exception spec is implemented more or less like: /* An exception spec is implemented more or less like:
...@@ -671,21 +629,25 @@ expand_end_catch_block () ...@@ -671,21 +629,25 @@ expand_end_catch_block ()
__check_eh_spec in exception.cc handles all the details. */ __check_eh_spec in exception.cc handles all the details. */
void tree
expand_start_eh_spec () expand_start_eh_spec ()
{ {
expand_start_try_stmts (); return begin_try_block ();
} }
static void void
expand_end_eh_spec (raises) expand_end_eh_spec (raises, try_block)
tree raises; tree raises;
tree try_block;
{ {
tree tmp, fn, decl, types = NULL_TREE; tree tmp, fn, decl, types = NULL_TREE;
tree blocks;
tree handler;
int count = 0; int count = 0;
expand_start_all_catch (); finish_try_block (try_block);
expand_start_catch_block (NULL_TREE); handler = begin_handler ();
blocks = finish_handler_parms (NULL_TREE, handler);
/* Build up an array of type_infos. */ /* Build up an array of type_infos. */
for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises)) for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
...@@ -733,10 +695,10 @@ expand_end_eh_spec (raises) ...@@ -733,10 +695,10 @@ expand_end_eh_spec (raises)
tmp = tree_cons (NULL_TREE, build_int_2 (count, 0), tmp = tree_cons (NULL_TREE, build_int_2 (count, 0),
tree_cons (NULL_TREE, decl, NULL_TREE)); tree_cons (NULL_TREE, decl, NULL_TREE));
tmp = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), tmp); tmp = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), tmp);
expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL); finish_expr_stmt (tmp);
expand_end_catch_block (); finish_handler (blocks, handler);
expand_end_all_catch (); finish_handler_sequence (try_block);
} }
/* This is called to expand all the toplevel exception handling /* This is called to expand all the toplevel exception handling
...@@ -753,21 +715,6 @@ expand_exception_blocks () ...@@ -753,21 +715,6 @@ expand_exception_blocks ()
catch_clauses = get_insns (); catch_clauses = get_insns ();
end_sequence (); end_sequence ();
/* Do this after we expand leftover cleanups, so that the
expand_eh_region_end that expand_end_eh_spec does will match the
right expand_eh_region_start, and make sure it comes out before
the terminate protected region. */
if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
{
expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
do_pending_stack_adjust ();
push_to_sequence (catch_clauses);
expand_leftover_cleanups ();
do_pending_stack_adjust ();
catch_clauses = get_insns ();
end_sequence ();
}
if (catch_clauses) if (catch_clauses)
{ {
rtx funcend = gen_label_rtx (); rtx funcend = gen_label_rtx ();
...@@ -815,12 +762,7 @@ start_anon_func () ...@@ -815,12 +762,7 @@ start_anon_func ()
start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"), start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
void_list_node), void_list_node),
t, NULL_TREE, SF_DEFAULT); t, NULL_TREE, SF_DEFAULT);
store_parm_decls (); do_pushlevel ();
pushlevel (0);
clear_last_expr ();
push_momentary ();
expand_start_bindings (0);
emit_line_note (input_filename, lineno);
interface_unknown = old_interface_unknown; interface_unknown = old_interface_unknown;
...@@ -832,11 +774,9 @@ start_anon_func () ...@@ -832,11 +774,9 @@ start_anon_func ()
void void
end_anon_func () end_anon_func ()
{ {
expand_end_bindings (getdecls (), 1, 0); do_poplevel ();
poplevel (1, 0, 0);
pop_momentary ();
finish_function (lineno, 0); expand_body (finish_function (lineno, 0));
pop_from_top_level (); pop_from_top_level ();
} }
......
...@@ -456,5 +456,6 @@ do_case (start, end) ...@@ -456,5 +456,6 @@ do_case (start, end)
cp_error ("case label `%E' within scope of cleanup or variable array", start); cp_error ("case label `%E' within scope of cleanup or variable array", start);
} }
} }
define_case_label ();
current_function_return_value = NULL_TREE;
} }
...@@ -2656,6 +2656,7 @@ create_temporary_var (type) ...@@ -2656,6 +2656,7 @@ create_temporary_var (type)
DECL_SOURCE_FILE (decl) = input_filename; DECL_SOURCE_FILE (decl) = input_filename;
DECL_SOURCE_LINE (decl) = lineno; DECL_SOURCE_LINE (decl) = lineno;
DECL_IGNORED_P (decl) = 1; DECL_IGNORED_P (decl) = 1;
DECL_CONTEXT (decl) = current_function_decl;
return decl; return decl;
} }
......
...@@ -2149,7 +2149,7 @@ emit_thunk (thunk_fndecl) ...@@ -2149,7 +2149,7 @@ emit_thunk (thunk_fndecl)
t = build_call (function, TREE_TYPE (TREE_TYPE (function)), t); t = build_call (function, TREE_TYPE (TREE_TYPE (function)), t);
finish_return_stmt (t); finish_return_stmt (t);
finish_function (lineno, 0); expand_body (finish_function (lineno, 0));
/* Don't let the backend defer this function. */ /* Don't let the backend defer this function. */
if (DECL_DEFER_OUTPUT (thunk_fndecl)) if (DECL_DEFER_OUTPUT (thunk_fndecl))
...@@ -2402,7 +2402,7 @@ synthesize_method (fndecl) ...@@ -2402,7 +2402,7 @@ synthesize_method (fndecl)
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt); finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
} }
finish_function (lineno, 0); expand_body (finish_function (lineno, 0));
extract_interface_info (); extract_interface_info ();
if (! context) if (! context)
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -282,7 +282,7 @@ empty_parms () ...@@ -282,7 +282,7 @@ empty_parms ()
%token TYPENAME_DEFN IDENTIFIER_DEFN PTYPENAME_DEFN %token TYPENAME_DEFN IDENTIFIER_DEFN PTYPENAME_DEFN
%type <ttype> named_class_head_sans_basetype_defn %type <ttype> named_class_head_sans_basetype_defn
%type <ttype> identifier_defn IDENTIFIER_DEFN TYPENAME_DEFN PTYPENAME_DEFN %type <ttype> identifier_defn IDENTIFIER_DEFN TYPENAME_DEFN PTYPENAME_DEFN
%type <ttype> handler_args
%type <ttype> self_template_type .finish_template_type %type <ttype> self_template_type .finish_template_type
%token NSNAME %token NSNAME
...@@ -660,9 +660,9 @@ eat_saved_input: ...@@ -660,9 +660,9 @@ eat_saved_input:
fndef: fndef:
fn.def1 maybe_return_init ctor_initializer_opt compstmt_or_error fn.def1 maybe_return_init ctor_initializer_opt compstmt_or_error
{ finish_function (lineno, (int)$3); } { expand_body (finish_function (lineno, (int)$3)); }
| fn.def1 maybe_return_init function_try_block | fn.def1 maybe_return_init function_try_block
{ finish_function (lineno, (int)$3); } { expand_body (finish_function (lineno, (int)$3)); }
| fn.def1 maybe_return_init error | fn.def1 maybe_return_init error
{ } { }
; ;
...@@ -805,12 +805,8 @@ base_init: ...@@ -805,12 +805,8 @@ base_init:
store_parm_decls (); store_parm_decls ();
if (DECL_CONSTRUCTOR_P (current_function_decl)) if (DECL_CONSTRUCTOR_P (current_function_decl))
{ /* Make a contour for the initializer list. */
/* Make a contour for the initializer list. */ do_pushlevel ();
pushlevel (0);
clear_last_expr ();
expand_start_bindings (0);
}
else if (current_class_type == NULL_TREE) else if (current_class_type == NULL_TREE)
error ("base initializers not allowed for non-member functions"); error ("base initializers not allowed for non-member functions");
else if (! DECL_CONSTRUCTOR_P (current_function_decl)) else if (! DECL_CONSTRUCTOR_P (current_function_decl))
...@@ -2073,12 +2069,12 @@ fn.defpen: ...@@ -2073,12 +2069,12 @@ fn.defpen:
pending_inline: pending_inline:
fn.defpen maybe_return_init ctor_initializer_opt compstmt_or_error fn.defpen maybe_return_init ctor_initializer_opt compstmt_or_error
{ {
finish_function (lineno, (int)$3 | 2); expand_body (finish_function (lineno, (int)$3 | 2));
process_next_inline ($1); process_next_inline ($1);
} }
| fn.defpen maybe_return_init function_try_block | fn.defpen maybe_return_init function_try_block
{ {
finish_function (lineno, (int)$3 | 2); expand_body (finish_function (lineno, (int)$3 | 2));
process_next_inline ($1); process_next_inline ($1);
} }
| fn.defpen maybe_return_init error | fn.defpen maybe_return_init error
...@@ -3368,9 +3364,9 @@ handler: ...@@ -3368,9 +3364,9 @@ handler:
CATCH CATCH
{ $<ttype>$ = begin_handler(); } { $<ttype>$ = begin_handler(); }
handler_args handler_args
{ finish_handler_parms ($<ttype>2); } { $<ttype>$ = finish_handler_parms ($3, $<ttype>2); }
compstmt compstmt
{ finish_handler ($<ttype>2); } { finish_handler ($<ttype>4, $<ttype>2); }
; ;
type_specifier_seq: type_specifier_seq:
...@@ -3380,7 +3376,7 @@ type_specifier_seq: ...@@ -3380,7 +3376,7 @@ type_specifier_seq:
handler_args: handler_args:
'(' ELLIPSIS ')' '(' ELLIPSIS ')'
{ expand_start_catch_block (NULL_TREE); } { $$ = NULL_TREE; }
/* This doesn't allow reference parameters, the below does. /* This doesn't allow reference parameters, the below does.
| '(' type_specifier_seq absdcl ')' | '(' type_specifier_seq absdcl ')'
{ check_for_new_type ("inside exception declarations", $2); { check_for_new_type ("inside exception declarations", $2);
...@@ -3398,8 +3394,8 @@ handler_args: ...@@ -3398,8 +3394,8 @@ handler_args:
| '(' parm ')' | '(' parm ')'
{ {
check_for_new_type ("inside exception declarations", $2); check_for_new_type ("inside exception declarations", $2);
start_handler_parms (TREE_PURPOSE ($2.t), $$ = start_handler_parms (TREE_PURPOSE ($2.t),
TREE_VALUE ($2.t)); TREE_VALUE ($2.t));
} }
; ;
......
...@@ -7475,19 +7475,25 @@ tsubst_expr (t, args, complain, in_decl) ...@@ -7475,19 +7475,25 @@ tsubst_expr (t, args, complain, in_decl)
finish_handler_sequence (stmt); finish_handler_sequence (stmt);
} }
break; break;
case HANDLER: case HANDLER:
prep_stmt (t); {
stmt = begin_handler (); tree decl;
if (HANDLER_PARMS (t)) tree blocks;
expand_start_catch_block
(tsubst (DECL_STMT_DECL (HANDLER_PARMS (t)), prep_stmt (t);
args, complain, in_decl)); stmt = begin_handler ();
else if (HANDLER_PARMS (t))
expand_start_catch_block (NULL_TREE); {
finish_handler_parms (stmt); decl = DECL_STMT_DECL (HANDLER_PARMS (t));
tsubst_expr (HANDLER_BODY (t), args, complain, in_decl); decl = tsubst (decl, args, complain, in_decl);
finish_handler (stmt); }
else
decl = NULL_TREE;
blocks = finish_handler_parms (decl, stmt);
tsubst_expr (HANDLER_BODY (t), args, complain, in_decl);
finish_handler (blocks, stmt);
}
break; break;
case TAG_DEFN: case TAG_DEFN:
......
...@@ -1196,5 +1196,5 @@ synthesize_tinfo_fn (fndecl) ...@@ -1196,5 +1196,5 @@ synthesize_tinfo_fn (fndecl)
pop_momentary (); pop_momentary ();
/* Finish the function body. */ /* Finish the function body. */
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt); finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
finish_function (lineno, 0); expand_body (finish_function (lineno, 0));
} }
...@@ -41,8 +41,6 @@ ...@@ -41,8 +41,6 @@
parsing into this file; that will make implementing the new parser parsing into this file; that will make implementing the new parser
much easier since it will be able to make use of these routines. */ much easier since it will be able to make use of these routines. */
static void do_pushlevel PROTO((void));
static tree do_poplevel PROTO((void));
static void finish_expr_stmt_real PROTO((tree, int)); static void finish_expr_stmt_real PROTO((tree, int));
static tree expand_cond PROTO((tree)); static tree expand_cond PROTO((tree));
static tree maybe_convert_cond PROTO((tree)); static tree maybe_convert_cond PROTO((tree));
...@@ -623,7 +621,12 @@ finish_case_label (low_value, high_value) ...@@ -623,7 +621,12 @@ finish_case_label (low_value, high_value)
{ {
if (building_stmt_tree ()) 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)); 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; return;
} }
...@@ -648,6 +651,7 @@ finish_goto_stmt (destination) ...@@ -648,6 +651,7 @@ finish_goto_stmt (destination)
if (TREE_CODE (destination) == LABEL_DECL) if (TREE_CODE (destination) == LABEL_DECL)
{ {
TREE_USED (destination) = 1; TREE_USED (destination) = 1;
label_rtx (destination);
expand_goto (destination); expand_goto (destination);
} }
else else
...@@ -761,8 +765,9 @@ finish_function_try_block (try_block) ...@@ -761,8 +765,9 @@ finish_function_try_block (try_block)
{ {
end_protect_partials (); end_protect_partials ();
expand_start_all_catch (); 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 /* Finish a handler-sequence for a try-block, which may be given by
...@@ -784,13 +789,12 @@ void ...@@ -784,13 +789,12 @@ void
finish_function_handler_sequence (try_block) finish_function_handler_sequence (try_block)
tree try_block; tree try_block;
{ {
in_function_try_handler = 0;
if (building_stmt_tree ()) if (building_stmt_tree ())
RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block)); RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
else else
{ expand_end_all_catch ();
in_function_try_handler = 0;
expand_end_all_catch ();
}
} }
/* Begin a handler. Returns a HANDLER if appropriate. */ /* Begin a handler. Returns a HANDLER if appropriate. */
...@@ -814,26 +818,71 @@ begin_handler () ...@@ -814,26 +818,71 @@ begin_handler ()
} }
/* Finish the handler-parameters for a handler, which may be given by /* 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 tree
finish_handler_parms (handler) finish_handler_parms (decl, handler)
tree decl;
tree handler; 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 ()) if (building_stmt_tree ())
RECHAIN_STMTS (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 void
finish_handler (handler) finish_handler (blocks, handler)
tree blocks;
tree handler; tree handler;
{ {
if (!processing_template_decl)
{
if (building_stmt_tree ())
expand_end_catch_block (blocks);
if (!building_stmt_tree ())
{
/* Fall to outside the try statement when done executing
handler and we fall off end of handler. This is jump
Lresume in the documentation. */
expand_goto (top_label_entry (&caught_return_label_stack));
end_catch_handler ();
}
}
if (building_stmt_tree ()) if (building_stmt_tree ())
RECHAIN_STMTS (handler, HANDLER_BODY (handler)); RECHAIN_STMTS (handler, HANDLER_BODY (handler));
else
expand_end_catch_block ();
do_poplevel (); do_poplevel ();
} }
...@@ -1044,7 +1093,8 @@ finish_decl_cleanup (decl, cleanup) ...@@ -1044,7 +1093,8 @@ finish_decl_cleanup (decl, cleanup)
{ {
if (building_stmt_tree ()) if (building_stmt_tree ())
add_tree (build_min_nt (CLEANUP_STMT, decl, cleanup)); add_tree (build_min_nt (CLEANUP_STMT, decl, cleanup));
else if (DECL_SIZE (decl) && TREE_TYPE (decl) != error_mark_node) else if (!decl
|| (DECL_SIZE (decl) && TREE_TYPE (decl) != error_mark_node))
expand_decl_cleanup (decl, cleanup); expand_decl_cleanup (decl, cleanup);
} }
...@@ -1089,7 +1139,8 @@ finish_named_return_value (return_id, init) ...@@ -1089,7 +1139,8 @@ finish_named_return_value (return_id, init)
{ {
/* Let `cp_finish_decl' know that this initializer is ok. */ /* Let `cp_finish_decl' know that this initializer is ok. */
DECL_INITIAL (decl) = init; DECL_INITIAL (decl) = init;
pushdecl (decl); if (doing_semantic_analysis_p ())
pushdecl (decl);
if (building_stmt_tree ()) if (building_stmt_tree ())
add_tree (build_min_nt (RETURN_INIT, return_id, init)); add_tree (build_min_nt (RETURN_INIT, return_id, init));
...@@ -1127,7 +1178,7 @@ setup_vtbl_ptr () ...@@ -1127,7 +1178,7 @@ setup_vtbl_ptr ()
/* Begin a new scope. */ /* Begin a new scope. */
static void void
do_pushlevel () do_pushlevel ()
{ {
if (!building_stmt_tree ()) if (!building_stmt_tree ())
...@@ -1137,24 +1188,53 @@ do_pushlevel () ...@@ -1137,24 +1188,53 @@ do_pushlevel ()
} }
push_momentary (); push_momentary ();
if (stmts_are_full_exprs_p) if (stmts_are_full_exprs_p)
pushlevel (0); {
if (!building_stmt_tree () && stmts_are_full_exprs_p) pushlevel (0);
expand_start_bindings (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. */ /* Finish a scope. */
static tree tree
do_poplevel () 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) if (stmts_are_full_exprs_p)
t = poplevel (kept_level_p (), 1, 0); {
else if (!building_stmt_tree ()
t = NULL_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 (); pop_momentary ();
return t; return t;
} }
...@@ -2141,41 +2221,20 @@ expand_stmt (t) ...@@ -2141,41 +2221,20 @@ expand_stmt (t)
emit_line_note (input_filename, lineno); emit_line_note (input_filename, lineno);
decl = DECL_STMT_DECL (t); decl = DECL_STMT_DECL (t);
if (TREE_CODE (decl) == LABEL_DECL) /* If this is a declaration for an automatic local
finish_label_decl (DECL_NAME (decl)); variable, initialize it. Note that we might also see a
else declaration for a namespace-scope object (declared with
{ `extern') or an object with static storage duration
/* If we marked this variable as dead when we processed it (declared with `static'). We don't have to handle the
before, we must undo that now. The variable has been initialization of those objects here; the former can
resuscitated. */ never be a definition (only a declaration), and the
if (TREE_CODE (decl) == VAR_DECL) latter is handled in finish_file. */
DECL_DEAD_FOR_LOCAL (decl) = 0; if (TREE_CODE (decl) == VAR_DECL
/* We need to clear DECL_CONTEXT so that maybe_push_decl && !TREE_STATIC (decl)
will push it into the current scope. */ && !DECL_EXTERNAL (decl))
if (DECL_CONTEXT (decl) == current_function_decl) /* Let the back-end know about this variable. */
{ emit_local_var (decl);
DECL_CONTEXT (decl) = NULL_TREE;
maybe_push_decl (decl);
}
/* 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') or an object with static storage duration
(declared with `static'). We don't have to handle the
initialization of those objects here; the former can
never be a definition (only a declaration), and the
latter is handled in finish_file. */
if (TREE_CODE (decl) == VAR_DECL
&& !TREE_STATIC (decl)
&& !DECL_EXTERNAL (decl))
{
/* Support the old for-scope rules for backwards
compatibility. */
maybe_inject_for_scope_var (decl);
/* Let the back-end know about this variable. */
emit_local_var (decl);
}
}
resume_momentary (i); resume_momentary (i);
} }
break; break;
...@@ -2184,6 +2243,10 @@ expand_stmt (t) ...@@ -2184,6 +2243,10 @@ expand_stmt (t)
finish_decl_cleanup (CLEANUP_DECL (t), CLEANUP_EXPR (t)); finish_decl_cleanup (CLEANUP_DECL (t), CLEANUP_EXPR (t));
break; break;
case START_CATCH_STMT:
begin_catch_block (TREE_TYPE (t));
break;
case FOR_STMT: case FOR_STMT:
{ {
tree tmp; tree tmp;
...@@ -2266,14 +2329,11 @@ expand_stmt (t) ...@@ -2266,14 +2329,11 @@ expand_stmt (t)
break; break;
case LABEL_STMT: case LABEL_STMT:
finish_label_stmt (DECL_NAME (LABEL_STMT_LABEL (t))); expand_label (LABEL_STMT_LABEL (t));
break; break;
case GOTO_STMT: case GOTO_STMT:
if (TREE_CODE (GOTO_DESTINATION (t)) == LABEL_DECL) finish_goto_stmt (GOTO_DESTINATION (t));
finish_goto_stmt (DECL_NAME (GOTO_DESTINATION (t)));
else
finish_goto_stmt (GOTO_DESTINATION (t));
break; break;
case ASM_STMT: case ASM_STMT:
...@@ -2291,29 +2351,59 @@ expand_stmt (t) ...@@ -2291,29 +2351,59 @@ expand_stmt (t)
} }
else else
{ {
begin_try_block (); if (FN_TRY_BLOCK_P (t))
begin_function_try_block ();
else
begin_try_block ();
expand_stmt (TRY_STMTS (t)); expand_stmt (TRY_STMTS (t));
finish_try_block (NULL_TREE);
expand_stmt (TRY_HANDLERS (t)); if (FN_TRY_BLOCK_P (t))
finish_handler_sequence (NULL_TREE); {
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; break;
case HANDLER: case HANDLER:
begin_handler (); 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)); expand_stmt (HANDLER_BODY (t));
finish_handler (NULL_TREE); finish_handler (NULL_TREE, NULL_TREE);
break; break;
case SUBOBJECT: case SUBOBJECT:
finish_subobject (SUBOBJECT_CLEANUP (t)); finish_subobject (SUBOBJECT_CLEANUP (t));
break; 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 CTOR_INITIALIZER:
current_member_init_list = TREE_OPERAND (t, 0);
current_base_init_list = TREE_OPERAND (t, 1);
setup_vtbl_ptr ();
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: default:
my_friendly_abort (19990810); my_friendly_abort (19990810);
break; break;
...@@ -2337,8 +2427,6 @@ expand_body (fn) ...@@ -2337,8 +2427,6 @@ expand_body (fn)
{ {
int saved_lineno; int saved_lineno;
char *saved_input_filename; char *saved_input_filename;
tree t;
tree try_block;
/* When the parser calls us after finishing the body of a template /* 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 function, we don't really want to expand the body. When we're
...@@ -2367,48 +2455,8 @@ expand_body (fn) ...@@ -2367,48 +2455,8 @@ expand_body (fn)
function body. */ function body. */
current_function_name_declared = 1; current_function_name_declared = 1;
/* 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);
}
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);
}
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);
}
/* If this is a constructor, we need to initialize our members and
base-classes. */
setup_vtbl_ptr ();
/* Expand the body. */ /* 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);
expand_stmt (TRY_HANDLERS (try_block));
finish_function_handler_sequence (NULL_TREE);
}
/* Statements should always be full-expressions at the outermost set /* Statements should always be full-expressions at the outermost set
of curly braces for a function. */ of curly braces for a function. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment