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>
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
x_scope_stmt_stack. Add x_in_charge_parm.
(current_eh_spec_try_block): New macro.
......
......@@ -747,6 +747,12 @@ struct language_function
#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
particular, this variable is no-zero if at the end of a 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 };
result of a using declaration. */
/* Used with start function. */
#define SF_DEFAULT SF_EXPAND
/* No flags. Temporarily, this is
SF_EXPAND. Once we are fully
function-at-a-time, this will be
0. */
#define SF_DEFAULT 0 /* No flags. */
#define SF_PRE_PARSED 1 /* The function declaration has
already been parsed. */
#define SF_INCLASS_INLINE 2 /* The function is an inline, defined
......@@ -3237,7 +3239,7 @@ extern void finish_decl PROTO((tree, tree, tree));
extern void maybe_inject_for_scope_var PROTO((tree));
extern void initialize_local_var PROTO((tree, tree, int));
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 tree build_ptrmemfunc_type PROTO((tree));
/* the grokdeclarator prototype is in decl.h */
......@@ -3389,10 +3391,11 @@ extern int cp_line_of PROTO((tree));
/* in except.c */
extern void init_exception_processing PROTO((void));
extern void expand_start_catch_block PROTO((tree));
extern void expand_end_catch_block PROTO((void));
extern tree expand_start_catch_block PROTO((tree));
extern void expand_end_catch_block PROTO((tree));
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 tree start_anon_func PROTO((void));
extern void end_anon_func PROTO((void));
......@@ -3660,9 +3663,9 @@ extern void finish_function_try_block PROTO((tree));
extern void finish_function_handler_sequence PROTO((tree));
extern void finish_cleanup_try_block PROTO((tree));
extern tree begin_handler PROTO((void));
extern void start_handler_parms PROTO((tree, tree));
extern void finish_handler_parms PROTO((tree));
extern void finish_handler PROTO((tree));
extern tree finish_handler_parms PROTO((tree, tree));
extern void begin_catch_block PROTO((tree));
extern void finish_handler PROTO((tree, tree));
extern void finish_cleanup PROTO((tree, tree));
extern tree begin_compound_stmt PROTO((int));
extern tree finish_compound_stmt PROTO((int, tree));
......@@ -3713,6 +3716,8 @@ extern void expand_body PROTO((tree));
extern void begin_stmt_tree PROTO((tree));
extern void finish_stmt_tree 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
than expanding each statement as we encounter it. */
#define building_stmt_tree() \
......
......@@ -822,10 +822,12 @@ void
pushlevel (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 (0)
#else /* !defined(DEBUG_CP_BINDING_LEVELS) */
......@@ -1185,18 +1187,25 @@ poplevel (keep, reverse, functionbody)
Put it into forward order, just for cleanliness. */
tree decls;
int tmp = functionbody;
int real_functionbody = current_binding_level->keep == 2
? ((functionbody = 0), tmp) : functionbody;
tree tags = functionbody >= 0 ? current_binding_level->tags : 0;
tree subblocks = functionbody >= 0 ? current_binding_level->blocks : 0;
int real_functionbody;
tree tags;
tree subblocks;
tree block = NULL_TREE;
tree decl;
int block_previously_created;
int leaving_for_scope;
if (current_function && !doing_semantic_analysis_p ())
return NULL_TREE;
my_friendly_assert (current_binding_level->parm_flag != 2,
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,
19990414);
......@@ -3631,8 +3640,16 @@ pushdecl (x)
tree x;
{
register tree t;
register tree name = DECL_ASSEMBLER_NAME (x);
int need_new_binding = 1;
register tree name;
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))
/* Template parameters have no context; they are not X::T even
......@@ -4119,10 +4136,9 @@ tree
pushdecl_top_level (x)
tree x;
{
tree cur_namespace = current_namespace;
current_namespace = global_namespace;
push_to_top_level ();
x = pushdecl_namespace_level (x);
current_namespace = cur_namespace;
pop_from_top_level ();
return x;
}
......@@ -4606,12 +4622,8 @@ make_label_decl (id, local_p)
{
tree decl;
if (building_stmt_tree ())
push_permanent_obstack ();
decl = build_decl (LABEL_DECL, id, void_type_node);
if (building_stmt_tree ())
pop_obstacks ();
else
if (expanding_p)
/* Make sure every label has an rtx. */
label_rtx (decl);
......@@ -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
|| TREE_CODE (decl) == RESULT_DECL)
{
/* ??? FIXME: What about nested classes? */
int toplev = toplevel_bindings_p ();
if (TREE_CODE (decl) == VAR_DECL)
maybe_commonize_var (decl);
......@@ -7773,9 +7782,10 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
|| TYPE_NEEDS_DESTRUCTOR (type))
expand_static_init (decl, init);
}
else if (! toplev)
else if (TREE_CODE (CP_DECL_CONTEXT (decl)) == FUNCTION_DECL)
{
/* This is a local declaration. */
if (doing_semantic_analysis_p ())
maybe_inject_for_scope_var (decl);
/* Initialize the local variable. But, if we're building a
statement-tree, we'll do the initialization when we
......@@ -7787,8 +7797,11 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
}
else
{
/* If we're not building RTL, then we need to do so
now. */
if (!building_stmt_tree ())
emit_local_var (decl);
/* Initialize the variable. */
initialize_local_var (decl, init, flags);
/* Clean up the variable. */
destroy_local_var (decl);
......@@ -8043,7 +8056,7 @@ expand_static_init (decl, init)
/* Finish the declaration of a catch-parameter. */
void
tree
start_handler_parms (declspecs, declarator)
tree declspecs;
tree declarator;
......@@ -8058,7 +8071,8 @@ start_handler_parms (declspecs, declarator)
}
else
decl = NULL_TREE;
expand_start_catch_block (decl);
return decl;
}
......@@ -12768,6 +12782,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
(but not if we warned then). */
if (! warn_implicit
......@@ -12798,6 +12822,7 @@ start_function (declspecs, declarator, attrs, flags)
/* Make the init_value nonzero so pushdecl knows this is not tentative.
error_mark_node is replaced below (in poplevel) with the BLOCK. */
if (!DECL_INITIAL (decl1))
DECL_INITIAL (decl1) = error_mark_node;
#ifdef SET_DEFAULT_DECL_ATTRIBUTES
......@@ -12892,6 +12917,48 @@ start_function (declspecs, declarator, attrs, flags)
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))
{
tree ctx = hack_decl_function_context (decl1);
......@@ -12957,61 +13024,11 @@ start_function (declspecs, declarator, attrs, flags)
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)
TREE_TYPE (decl1) = fntype
= 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)
cplus_decl_attributes (decl1, NULL_TREE, attrs);
......@@ -13057,16 +13074,9 @@ start_function (declspecs, declarator, attrs, flags)
if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl1))
&& DECL_LANGUAGE (decl1) == lang_cplusplus)
{
dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
ctor_label = NULL_TREE;
}
else
{
dtor_label = NULL_TREE;
if (DECL_CONSTRUCTOR_P (decl1))
else if (DECL_CONSTRUCTOR_P (decl1))
ctor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
}
return 1;
}
......@@ -13096,9 +13106,6 @@ store_parm_decls ()
int parms_have_cleanups = 0;
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. */
tree parmtags = current_function_parm_tags;
......@@ -13107,39 +13114,48 @@ store_parm_decls ()
then CONST_DECLs for foo and bar are put here. */
tree nonparms = NULL_TREE;
if (toplevel_bindings_p ())
fatal ("parse errors have confused me too much");
/* 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.
The parms already have decls, so we need not do anything here
except record them as in effect
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);
for (parm = nreverse (specparms); parm; parm = next)
/* If we're doing semantic analysis, then we'll call pushdecl
for each of these. We must do them in reverse order so that
they end in the correct forward order. */
specparms = nreverse (specparms);
}
for (parm = specparms; parm; parm = next)
{
next = TREE_CHAIN (parm);
if (TREE_CODE (parm) == PARM_DECL)
{
tree cleanup;
if (DECL_NAME (parm) == NULL_TREE)
if (doing_semantic_analysis_p ())
{
if (DECL_NAME (parm) == NULL_TREE
|| TREE_CODE (TREE_TYPE (parm)) != VOID_TYPE)
pushdecl (parm);
}
else if (TREE_CODE (TREE_TYPE (parm)) == VOID_TYPE)
cp_error ("parameter `%D' declared void", parm);
else
pushdecl (parm);
cp_error ("parameter `%D' declared void", parm);
}
if (! building_stmt_tree ()
&& (cleanup = maybe_build_cleanup (parm), cleanup))
{
......@@ -13159,12 +13175,17 @@ store_parm_decls ()
}
}
if (doing_semantic_analysis_p ())
{
/* Get the decls in their original chain order
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 ()));
/* We built up the cleanups in reversed order. */
cleanups = nreverse (cleanups);
}
}
else
DECL_ARGUMENTS (fndecl) = NULL_TREE;
......@@ -13173,7 +13194,7 @@ store_parm_decls ()
as the decl-chain of the current lexical scope.
Put the enumerators in as well, at the front so that
DECL_ARGUMENTS is not modified. */
if (doing_semantic_analysis_p ())
storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl)));
/* Initialize the RTL code for the function. */
......@@ -13192,16 +13213,14 @@ store_parm_decls ()
cleanups. We cannot do this before, since expand_decl_cleanup
should not be called before the parm can be used. */
if (cleanups && !building_stmt_tree ())
{
for (cleanups = nreverse (cleanups);
cleanups;
cleanups = TREE_CHAIN (cleanups))
while (cleanups)
{
if (! expand_decl_cleanup (TREE_PURPOSE (cleanups),
TREE_VALUE (cleanups)))
cp_error ("parser lost in parsing declaration of `%D'",
TREE_PURPOSE (cleanups));
}
cleanups = TREE_CHAIN (cleanups);
}
/* Create a binding contour which can be used to catch
......@@ -13211,15 +13230,14 @@ store_parm_decls ()
{
pushlevel (0);
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 (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
expand_start_eh_spec ();
}
if (flag_exceptions && !processing_template_decl
&& building_stmt_tree ()
&& TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
current_eh_spec_try_block = expand_start_eh_spec ();
last_parm_cleanup_insn = get_last_insn ();
last_dtor_insn = get_last_insn ();
......@@ -13306,7 +13324,6 @@ finish_function (lineno, flags)
rtx fn_last_parm_insn, insns;
/* Label to use if this function is supposed to return a value. */
tree no_return_label = NULL_TREE;
tree decls = NULL_TREE;
int call_poplevel = (flags & 1) != 0;
int inclass_inline = (flags & 2) != 0;
int expand_p;
......@@ -13334,20 +13351,14 @@ finish_function (lineno, flags)
if (building_stmt_tree ())
{
if (DECL_CONSTRUCTOR_P (fndecl) && call_poplevel)
{
decls = getdecls ();
expand_end_bindings (decls, decls != NULL_TREE, 0);
poplevel (decls != NULL_TREE, 0, 0);
}
do_poplevel ();
/* Because we do not call expand_function_end, we won't call
expand_end_bindings to match the call to
expand_start_bindings we did in store_parm_decls. Therefore,
we explicitly call expand_end_bindings here. However, we
really shouldn't be calling expand_start_bindings at all when
building_stmt_tree; it's conceptually an RTL-generation
function, rather than a front-end function. */
expand_end_bindings (0, 0, 0);
/* Finish dealing with exception specifiers. */
if (flag_exceptions && !processing_template_decl
&& TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS
(TREE_TYPE (current_function_decl)),
current_eh_spec_try_block);
}
else
{
......@@ -13401,8 +13412,7 @@ finish_function (lineno, flags)
/* These initializations might go inline. Protect
the binding level of the parms. */
pushlevel (0);
expand_start_bindings (0);
do_pushlevel ();
if (current_function_assigns_this)
{
......@@ -13511,8 +13521,7 @@ finish_function (lineno, flags)
}
/* End of destructor. */
expand_end_bindings (NULL_TREE, getdecls () != NULL_TREE, 0);
poplevel (getdecls () != NULL_TREE, 0, 0);
do_poplevel ();
/* Back to the top of destructor. */
/* Don't execute destructor code if `this' is NULL. */
......@@ -13560,65 +13569,46 @@ finish_function (lineno, flags)
if (! ok_to_optimize_dtor)
expand_end_cond ();
}
else if (current_function_assigns_this)
else if (DECL_CONSTRUCTOR_P (fndecl))
{
/* Does not need to call emit_base_init, because
that is done (if needed) just after assignment to this
is seen. */
if (DECL_CONSTRUCTOR_P (current_function_decl))
/* If the current function assigns to `this', then code to
initialize members and base-classes will be generated
directly after the assignment. */
if (!current_function_assigns_this)
{
end_protect_partials ();
expand_label (ctor_label);
ctor_label = NULL_TREE;
if (call_poplevel)
{
decls = getdecls ();
expand_end_bindings (decls, decls != NULL_TREE, 0);
poplevel (decls != NULL_TREE, 0, 0);
}
/* 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);
start_sequence ();
current_function_assigns_this = 0;
current_function_just_assigned_this = 0;
base_init_expr = NULL_TREE;
}
else if (DECL_CONSTRUCTOR_P (fndecl))
if (flag_this_is_variable > 0)
{
/* Allow constructor for a type to get a new instance of
the object using `build_new'. */
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);
tree abstract_virtuals
= CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type);
CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = NULL_TREE;
if (flag_this_is_variable > 0)
{
cond = build_binary_op (EQ_EXPR,
current_class_ptr, integer_zero_node);
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_start_cond (cond, 0);
start_sequence ();
thenclause
= build_modify_expr (current_class_ptr, NOP_EXPR,
build_new (NULL_TREE,
current_class_type,
if (flag_this_is_variable > 0)
{
expand_start_cond (cond, 0);
void_type_node, 0));
CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type)
= abstract_virtuals;
expand_expr_stmt (thenclause);
expand_end_cond ();
}
/* Emit insns from `emit_base_init' which sets up virtual
function table pointer(s). */
if (base_init_expr)
/* Emit insns from `emit_base_init' which sets up
virtual function table pointer(s). Don't do this for
a function which assigns to `this' as we will emit
the appropriate code right after the assignment. */
if (!current_function_assigns_this && base_init_expr)
{
expand_expr_stmt (base_init_expr);
base_init_expr = NULL_TREE;
......@@ -13627,10 +13617,11 @@ finish_function (lineno, flags)
insns = get_insns ();
end_sequence ();
/* This is where the body of the constructor begins. */
emit_insns_after (insns, last_parm_cleanup_insn);
}
/* This is where the body of the constructor begins. All
subobjects have been fully constructed at this point. */
end_protect_partials ();
/* This is where the body of the constructor ends. */
......@@ -13638,11 +13629,7 @@ finish_function (lineno, flags)
ctor_label = NULL_TREE;
if (call_poplevel)
{
decls = getdecls ();
expand_end_bindings (decls, decls != NULL_TREE, 0);
poplevel (decls != NULL_TREE, 1, 0);
}
do_poplevel ();
/* c_expand_return knows to return 'this' from a constructor. */
c_expand_return (NULL_TREE);
......@@ -13660,8 +13647,13 @@ finish_function (lineno, flags)
#endif
}
else if (return_label != NULL_RTX
&& ((flag_this_is_variable <= 0
&& 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);
if (flag_exceptions)
......@@ -13743,9 +13735,12 @@ finish_function (lineno, flags)
/* This must come after expand_function_end because cleanups might
have declarations (from inline functions) that need to go into
this function's blocks. */
if (doing_semantic_analysis_p ())
{
if (current_binding_level->parm_flag != 1)
my_friendly_abort (122);
poplevel (1, 0, 1);
}
/* Remember that we were in class scope. */
if (current_class_name)
......@@ -13887,7 +13882,7 @@ finish_function (lineno, flags)
if (! nested)
permanent_allocation (1);
if (DECL_SAVED_INSNS (fndecl) == 0)
if (!DECL_SAVED_INSNS (fndecl) && !DECL_SAVED_FUNCTION_DATA (fndecl))
{
tree t;
......@@ -14314,9 +14309,9 @@ push_cp_function_context (f)
xcalloc (1, sizeof (struct language_function)));
f->language = p;
/* For now, we always assume we're expanding all the way to RTL
unless we're explicitly doing otherwise. */
expanding_p = 1;
/* It takes an explicit call to expand_body to generate RTL for a
function. */
expanding_p = 0;
/* Whenever we start a new function, we destroy temporaries in the
usual way. */
......@@ -14353,6 +14348,8 @@ mark_lang_function (p)
ggc_mark_tree (p->x_current_class_ref);
ggc_mark_tree (p->x_last_tree);
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_parm_cleanup_insn);
......
......@@ -39,7 +39,6 @@ Boston, MA 02111-1307, USA. */
static void push_eh_cleanup PROTO((void));
static tree build_eh_type_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 void push_eh_info PROTO((void));
static tree get_eh_info PROTO((void));
......@@ -50,11 +49,11 @@ static tree get_eh_caught PROTO((void));
static tree get_eh_handlers PROTO((void));
#endif
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_terminate_handler PROTO((void));
static tree alloc_eh_object PROTO((tree));
static int complete_ptr_ref_or_void_ptr_p PROTO((tree, tree));
static void initialize_handler_parm PROTO((tree));
#if 0
/* This is the startup, and finish stuff per exception table. */
......@@ -483,7 +482,7 @@ push_eh_cleanup ()
yes = suspend_momentary ();
/* 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);
}
......@@ -499,73 +498,18 @@ build_terminate_handler ()
return term;
}
/* Call this to start a catch block. Typename is the typename, and identifier
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. */
/* Initialize the catch parameter DECL. */
static void
process_start_catch_block (decl)
initialize_handler_parm (decl)
tree decl;
{
tree init;
/* Create a binding level for the eh_info and the exception object
cleanup. */
pushlevel (0);
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);
push_eh_info ();
if (decl)
{
tree exp;
tree init;
tree init_type;
/* Make sure we mark the catch param as used, otherwise we'll get
a warning about an unused ((anonymous)). */
/* Make sure we mark the catch param as used, otherwise we'll get a
warning about an unused ((anonymous)). */
TREE_USED (decl) = 1;
/* Figure out the type that the initializer is. */
......@@ -584,12 +528,6 @@ process_start_catch_block (decl)
exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
push_eh_cleanup ();
/* Create a binding level for the parm. */
pushlevel (0);
expand_start_bindings (0);
init = convert_from_reference (exp);
/* If the constructor for the catch parm exits via an exception, we
......@@ -605,25 +543,51 @@ process_start_catch_block (decl)
}
/* Let `cp_finish_decl' know that this initializer is ok. */
DECL_INITIAL (decl) = init;
DECL_INITIAL (decl) = error_mark_node;
decl = pushdecl (decl);
start_decl_1 (decl);
cp_finish_decl (decl, init, NULL_TREE, 0,
LOOKUP_ONLYCONVERTING|DIRECT_BIND);
}
}
/* Call this to start a catch block. DECL is the catch parameter. */
tree
expand_start_catch_block (decl)
tree decl;
{
tree compound_stmt_1;
tree compound_stmt_2;
tree type;
if (! doing_eh (1))
return NULL_TREE;
/* Make sure this declaration is reasonable. */
if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE))
decl = NULL_TREE;
/* Create a binding level for the eh_info and the exception object
cleanup. */
compound_stmt_1 = begin_compound_stmt (/*has_no_scope=*/0);
if (decl)
type = build_eh_type_type_ref (TREE_TYPE (decl));
else
{
type = NULL_TREE;
begin_catch_block (type);
push_eh_info ();
push_eh_cleanup ();
/* Create a binding level for the parm. */
pushlevel (0);
expand_start_bindings (0);
compound_stmt_2 = begin_compound_stmt (/*has_no_scope=*/0);
/* Fall into the catch all section. */
}
if (decl)
initialize_handler_parm (decl);
emit_line_note (input_filename, lineno);
return build_tree_list (compound_stmt_1, compound_stmt_2);
}
......@@ -632,8 +596,12 @@ process_start_catch_block (decl)
the label to jump to if this catch block didn't match. */
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))
return;
......@@ -642,22 +610,12 @@ expand_end_catch_block ()
if (in_function_try_handler
&& (DECL_CONSTRUCTOR_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. */
expand_end_bindings (getdecls (), kept_level_p (), 0);
poplevel (kept_level_p (), 1, 0);
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1);
/* 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 ();
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_2);
}
/* An exception spec is implemented more or less like:
......@@ -671,21 +629,25 @@ expand_end_catch_block ()
__check_eh_spec in exception.cc handles all the details. */
void
tree
expand_start_eh_spec ()
{
expand_start_try_stmts ();
return begin_try_block ();
}
static void
expand_end_eh_spec (raises)
void
expand_end_eh_spec (raises, try_block)
tree raises;
tree try_block;
{
tree tmp, fn, decl, types = NULL_TREE;
tree blocks;
tree handler;
int count = 0;
expand_start_all_catch ();
expand_start_catch_block (NULL_TREE);
finish_try_block (try_block);
handler = begin_handler ();
blocks = finish_handler_parms (NULL_TREE, handler);
/* Build up an array of type_infos. */
for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
......@@ -733,10 +695,10 @@ expand_end_eh_spec (raises)
tmp = tree_cons (NULL_TREE, build_int_2 (count, 0),
tree_cons (NULL_TREE, decl, NULL_TREE));
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 ();
expand_end_all_catch ();
finish_handler (blocks, handler);
finish_handler_sequence (try_block);
}
/* This is called to expand all the toplevel exception handling
......@@ -753,21 +715,6 @@ expand_exception_blocks ()
catch_clauses = get_insns ();
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)
{
rtx funcend = gen_label_rtx ();
......@@ -815,12 +762,7 @@ start_anon_func ()
start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
void_list_node),
t, NULL_TREE, SF_DEFAULT);
store_parm_decls ();
pushlevel (0);
clear_last_expr ();
push_momentary ();
expand_start_bindings (0);
emit_line_note (input_filename, lineno);
do_pushlevel ();
interface_unknown = old_interface_unknown;
......@@ -832,11 +774,9 @@ start_anon_func ()
void
end_anon_func ()
{
expand_end_bindings (getdecls (), 1, 0);
poplevel (1, 0, 0);
pop_momentary ();
do_poplevel ();
finish_function (lineno, 0);
expand_body (finish_function (lineno, 0));
pop_from_top_level ();
}
......
......@@ -456,5 +456,6 @@ do_case (start, end)
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)
DECL_SOURCE_FILE (decl) = input_filename;
DECL_SOURCE_LINE (decl) = lineno;
DECL_IGNORED_P (decl) = 1;
DECL_CONTEXT (decl) = current_function_decl;
return decl;
}
......
......@@ -2149,7 +2149,7 @@ emit_thunk (thunk_fndecl)
t = build_call (function, TREE_TYPE (TREE_TYPE (function)), t);
finish_return_stmt (t);
finish_function (lineno, 0);
expand_body (finish_function (lineno, 0));
/* Don't let the backend defer this function. */
if (DECL_DEFER_OUTPUT (thunk_fndecl))
......@@ -2402,7 +2402,7 @@ synthesize_method (fndecl)
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
}
finish_function (lineno, 0);
expand_body (finish_function (lineno, 0));
extract_interface_info ();
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 ()
%token TYPENAME_DEFN IDENTIFIER_DEFN PTYPENAME_DEFN
%type <ttype> named_class_head_sans_basetype_defn
%type <ttype> identifier_defn IDENTIFIER_DEFN TYPENAME_DEFN PTYPENAME_DEFN
%type <ttype> handler_args
%type <ttype> self_template_type .finish_template_type
%token NSNAME
......@@ -660,9 +660,9 @@ eat_saved_input:
fndef:
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
{ finish_function (lineno, (int)$3); }
{ expand_body (finish_function (lineno, (int)$3)); }
| fn.def1 maybe_return_init error
{ }
;
......@@ -805,12 +805,8 @@ base_init:
store_parm_decls ();
if (DECL_CONSTRUCTOR_P (current_function_decl))
{
/* Make a contour for the initializer list. */
pushlevel (0);
clear_last_expr ();
expand_start_bindings (0);
}
do_pushlevel ();
else if (current_class_type == NULL_TREE)
error ("base initializers not allowed for non-member functions");
else if (! DECL_CONSTRUCTOR_P (current_function_decl))
......@@ -2073,12 +2069,12 @@ fn.defpen:
pending_inline:
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);
}
| 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);
}
| fn.defpen maybe_return_init error
......@@ -3368,9 +3364,9 @@ handler:
CATCH
{ $<ttype>$ = begin_handler(); }
handler_args
{ finish_handler_parms ($<ttype>2); }
{ $<ttype>$ = finish_handler_parms ($3, $<ttype>2); }
compstmt
{ finish_handler ($<ttype>2); }
{ finish_handler ($<ttype>4, $<ttype>2); }
;
type_specifier_seq:
......@@ -3380,7 +3376,7 @@ type_specifier_seq:
handler_args:
'(' ELLIPSIS ')'
{ expand_start_catch_block (NULL_TREE); }
{ $$ = NULL_TREE; }
/* This doesn't allow reference parameters, the below does.
| '(' type_specifier_seq absdcl ')'
{ check_for_new_type ("inside exception declarations", $2);
......@@ -3398,7 +3394,7 @@ handler_args:
| '(' parm ')'
{
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));
}
;
......
......@@ -7477,17 +7477,23 @@ tsubst_expr (t, args, complain, in_decl)
break;
case HANDLER:
{
tree decl;
tree blocks;
prep_stmt (t);
stmt = begin_handler ();
if (HANDLER_PARMS (t))
expand_start_catch_block
(tsubst (DECL_STMT_DECL (HANDLER_PARMS (t)),
args, complain, in_decl));
{
decl = DECL_STMT_DECL (HANDLER_PARMS (t));
decl = tsubst (decl, args, complain, in_decl);
}
else
expand_start_catch_block (NULL_TREE);
finish_handler_parms (stmt);
decl = NULL_TREE;
blocks = finish_handler_parms (decl, stmt);
tsubst_expr (HANDLER_BODY (t), args, complain, in_decl);
finish_handler (stmt);
finish_handler (blocks, stmt);
}
break;
case TAG_DEFN:
......
......@@ -1196,5 +1196,5 @@ synthesize_tinfo_fn (fndecl)
pop_momentary ();
/* Finish the function body. */
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
finish_function (lineno, 0);
expand_body (finish_function (lineno, 0));
}
......@@ -41,8 +41,6 @@
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 do_pushlevel PROTO((void));
static tree do_poplevel PROTO((void));
static void finish_expr_stmt_real PROTO((tree, int));
static tree expand_cond PROTO((tree));
static tree maybe_convert_cond PROTO((tree));
......@@ -623,7 +621,12 @@ finish_case_label (low_value, high_value)
{
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;
}
......@@ -648,6 +651,7 @@ finish_goto_stmt (destination)
if (TREE_CODE (destination) == LABEL_DECL)
{
TREE_USED (destination) = 1;
label_rtx (destination);
expand_goto (destination);
}
else
......@@ -761,8 +765,9 @@ finish_function_try_block (try_block)
{
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
......@@ -784,13 +789,12 @@ void
finish_function_handler_sequence (try_block)
tree try_block;
{
in_function_try_handler = 0;
if (building_stmt_tree ())
RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
else
{
in_function_try_handler = 0;
expand_end_all_catch ();
}
}
/* Begin a handler. Returns a HANDLER if appropriate. */
......@@ -814,26 +818,71 @@ begin_handler ()
}
/* 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;
{
if (building_stmt_tree ())
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 ())
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 (handler, HANDLER_BODY (handler));
else
expand_end_catch_block ();
do_poplevel ();
}
......@@ -1044,7 +1093,8 @@ finish_decl_cleanup (decl, cleanup)
{
if (building_stmt_tree ())
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);
}
......@@ -1089,6 +1139,7 @@ finish_named_return_value (return_id, init)
{
/* Let `cp_finish_decl' know that this initializer is ok. */
DECL_INITIAL (decl) = init;
if (doing_semantic_analysis_p ())
pushdecl (decl);
if (building_stmt_tree ())
......@@ -1127,7 +1178,7 @@ setup_vtbl_ptr ()
/* Begin a new scope. */
static void
void
do_pushlevel ()
{
if (!building_stmt_tree ())
......@@ -1137,24 +1188,53 @@ do_pushlevel ()
}
push_momentary ();
if (stmts_are_full_exprs_p)
{
pushlevel (0);
if (!building_stmt_tree () && stmts_are_full_exprs_p)
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)
{
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);
else
t = NULL_TREE;
}
pop_momentary ();
return t;
}
......@@ -2141,22 +2221,6 @@ expand_stmt (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
{
/* 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;
/* 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;
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
......@@ -2168,14 +2232,9 @@ expand_stmt (t)
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);
}
break;
......@@ -2184,6 +2243,10 @@ expand_stmt (t)
finish_decl_cleanup (CLEANUP_DECL (t), CLEANUP_EXPR (t));
break;
case START_CATCH_STMT:
begin_catch_block (TREE_TYPE (t));
break;
case FOR_STMT:
{
tree tmp;
......@@ -2266,13 +2329,10 @@ expand_stmt (t)
break;
case LABEL_STMT:
finish_label_stmt (DECL_NAME (LABEL_STMT_LABEL (t)));
expand_label (LABEL_STMT_LABEL (t));
break;
case GOTO_STMT:
if (TREE_CODE (GOTO_DESTINATION (t)) == LABEL_DECL)
finish_goto_stmt (DECL_NAME (GOTO_DESTINATION (t)));
else
finish_goto_stmt (GOTO_DESTINATION (t));
break;
......@@ -2291,29 +2351,59 @@ expand_stmt (t)
}
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 ();
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);
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 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:
my_friendly_abort (19990810);
break;
......@@ -2337,8 +2427,6 @@ expand_body (fn)
{
int saved_lineno;
char *saved_input_filename;
tree t;
tree try_block;
/* 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
......@@ -2367,48 +2455,8 @@ expand_body (fn)
function body. */
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_stmt (t);
/* 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);
}
expand_stmt (DECL_SAVED_TREE (fn));
/* Statements should always be full-expressions at the outermost set
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