Commit 24bef158 by Mark Mitchell Committed by Mark Mitchell

cp-tree.def (CLEANUP_STMT): New node.

	* cp-tree.def (CLEANUP_STMT): New node.
	* cp-tree.h (language_function): Add name_declared.
	(current_function_name_declared): New macro.
	(CLEANUP_DECL): New macro.
	(CLEANUP_EXPR): Likewise.
	(emit_local_var): Likewise.
	(finish_decl_cleanup): New function.
	* cvt.c (build_up_reference): Simplify.
	(ocp_convert): Remove dead code.
	* decl.c (start_decl): Remove call to add_decl_stmt.
	(grok_reference_init): Adjust, to handle bindings temporaries to
	references.  Remove dead code.
	(initialize_local_var): Don't generate RTL for
	declarations here, or build cleanups here.  Don't fuss with
	obstacks.  Replace expand_start_target_temps calls with explicit
	setting of stms_are_full_exprs_p.
	(destroy_local_var): New function.
	(emit_local_var): Likewise.
	(cp_finish_decl): Use them, as appropriate.
	(start_function): Announce template functions.
	(store_parm_decls): Don't call declare_function_name here.
	(finish_stmt): Don't start emit base-initialization code when just
	building the statement-tree.
	* init.c (create_temporary_var): Move add_decl_stmt call ...
	(get_temp_regvar): Here.
	* pt.c (tsubst_expr): Make DECL_INITIAL look like what
	cp_finish_decl would expect.  Don't call add_decl_stmt.
	* semantics.c (begin_compound_stmt): Call declare_function_name,
	if appropriate.
	(finish_decl_cleanup): New function.
	(expand_stmt): Use emit_local_var to output variables.
	(expand_body): Set current_funtion_name_declared.

From-SVN: r29348
parent fcf6eeb6
1999-09-11 Mark Mitchell <mark@codesourcery.com>
* cp-tree.def (CLEANUP_STMT): New node.
* cp-tree.h (language_function): Add name_declared.
(current_function_name_declared): New macro.
(CLEANUP_DECL): New macro.
(CLEANUP_EXPR): Likewise.
(emit_local_var): Likewise.
(finish_decl_cleanup): New function.
* cvt.c (build_up_reference): Simplify.
(ocp_convert): Remove dead code.
* decl.c (start_decl): Remove call to add_decl_stmt.
(grok_reference_init): Adjust, to handle bindings temporaries to
references. Remove dead code.
(initialize_local_var): Don't generate RTL for
declarations here, or build cleanups here. Don't fuss with
obstacks. Replace expand_start_target_temps calls with explicit
setting of stms_are_full_exprs_p.
(destroy_local_var): New function.
(emit_local_var): Likewise.
(cp_finish_decl): Use them, as appropriate.
(start_function): Announce template functions.
(store_parm_decls): Don't call declare_function_name here.
(finish_stmt): Don't start emit base-initialization code when just
building the statement-tree.
* init.c (create_temporary_var): Move add_decl_stmt call ...
(get_temp_regvar): Here.
* pt.c (tsubst_expr): Make DECL_INITIAL look like what
cp_finish_decl would expect. Don't call add_decl_stmt.
* semantics.c (begin_compound_stmt): Call declare_function_name,
if appropriate.
(finish_decl_cleanup): New function.
(expand_stmt): Use emit_local_var to output variables.
(expand_body): Set current_funtion_name_declared.
1999-09-10 Mark Mitchell <mark@codesourcery.com>
* cp-tree.h (finish_cleanup_try_block): New function.
......
......@@ -235,6 +235,10 @@ DEFTREECODE (ASM_STMT, "asm_stmt", 'e', 5)
run if an exception is thrown before the end of the enclosing
function. */
DEFTREECODE (SUBOBJECT, "subobject", 'e', 1)
/* A CLEANUP_STMT marks the point at which a declaration is fully
constructed. If, after this point, the CLEANUP_DECL goes out of
scope, the CLEANUP_EXPR must be run. */
DEFTREECODE (CLEANUP_STMT, "cleanup", 'e', 2)
DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 2)
DEFTREECODE (CASE_LABEL, "case_label", 'e', 2)
DEFTREECODE (RETURN_INIT, "return_init", 'e', 2)
......
......@@ -636,6 +636,7 @@ struct language_function
int in_function_try_handler;
int x_expanding_p;
int stmts_are_full_exprs_p;
int name_declared;
struct named_label_list *x_named_label_uses;
struct binding_level *bindings;
......@@ -708,6 +709,12 @@ struct language_function
#define current_function_parms_stored \
cp_function_chain->parms_stored
/* Non-zero if we have already declared __FUNCTION__ (and related
variables) in the current function. */
#define current_function_name_declared \
cp_function_chain->name_declared
/* Used to help generate temporary names which are unique within
a function. Reset to 0 by start_function. */
......@@ -2437,6 +2444,8 @@ extern int flag_new_for_scope;
#define DECL_STMT_DECL(NODE) TREE_OPERAND (NODE, 0)
#define STMT_EXPR_STMT(NODE) TREE_OPERAND (NODE, 0)
#define SUBOBJECT_CLEANUP(NODE) TREE_OPERAND (NODE, 0)
#define CLEANUP_DECL(NODE) TREE_OPERAND (NODE, 0)
#define CLEANUP_EXPR(NODE) TREE_OPERAND (NODE, 1)
#define LABEL_STMT_LABEL(NODE) TREE_OPERAND (NODE, 0)
/* Nonzero for an ASM_STMT if the assembly statement is volatile. */
......@@ -3237,6 +3246,7 @@ extern int wrapup_globals_for_namespace PROTO((tree, void *));
extern tree cp_namespace_decls PROTO((tree));
extern tree create_implicit_typedef PROTO((tree, tree));
extern tree maybe_push_decl PROTO((tree));
extern void emit_local_var PROTO((tree));
/* in decl2.c */
extern void init_decl2 PROTO((void));
......@@ -3651,6 +3661,7 @@ extern void finish_member_declaration PROTO((tree));
extern void check_multiple_declarators PROTO((void));
extern tree finish_typeof PROTO((tree));
extern void add_decl_stmt PROTO((tree));
extern void finish_decl_cleanup PROTO((tree, tree));
extern void finish_named_return_value PROTO((tree, tree));
extern tree expand_stmt PROTO((tree));
extern void expand_body PROTO((tree));
......
......@@ -345,8 +345,6 @@ build_up_reference (type, arg, flags)
if ((flags & DIRECT_BIND) && ! real_lvalue_p (arg))
{
tree compound_stmt;
/* Create a new temporary variable. */
tree targ = arg;
if (toplevel_bindings_p ())
......@@ -355,25 +353,12 @@ build_up_reference (type, arg, flags)
{
arg = pushdecl (build_decl (VAR_DECL, NULL_TREE, argtype));
DECL_ARTIFICIAL (arg) = 1;
/* Generate code to initialize it. We wrap it in a
statement-expression so that when we are building a
statement-tree we will have a representation of this
declaration. */
begin_init_stmts (&stmt_expr, &compound_stmt);
}
/* Process the initializer for the declaration. */
DECL_INITIAL (arg) = targ;
cp_finish_decl (arg, targ, NULL_TREE, 0,
LOOKUP_ONLYCONVERTING|DIRECT_BIND);
/* And wrap up the statement-expression, if necessary. */
if (!toplevel_bindings_p ())
{
if (building_stmt_tree ())
add_decl_stmt (arg);
stmt_expr = finish_init_stmts (stmt_expr, compound_stmt);
}
}
else if (!(flags & DIRECT_BIND) && ! lvalue_p (arg))
{
......@@ -719,13 +704,6 @@ ocp_convert (type, expr, convtype, flags)
return e;
}
#if 0
/* This is incorrect. A truncation can't be stripped this way.
Extensions will be stripped by the use of get_unwidened. */
if (TREE_CODE (e) == NOP_EXPR)
return cp_convert (type, TREE_OPERAND (e, 0));
#endif
/* Just convert to the type of the member. */
if (code == OFFSET_TYPE)
{
......@@ -733,13 +711,6 @@ ocp_convert (type, expr, convtype, flags)
code = TREE_CODE (type);
}
#if 0
if (code == REFERENCE_TYPE)
return fold (convert_to_reference (type, e, convtype, flags, NULL_TREE));
else if (TREE_CODE (TREE_TYPE (e)) == REFERENCE_TYPE)
e = convert_from_reference (e);
#endif
if (TREE_CODE (e) == OFFSET_REF)
e = resolve_offset_ref (e);
......
......@@ -179,6 +179,7 @@ static void mark_cp_function_context PROTO((struct function *));
static void mark_saved_scope PROTO((void *));
static void check_function_type PROTO((tree));
static void destroy_local_static PROTO((tree));
static void destroy_local_var PROTO((tree));
#if defined (DEBUG_CP_BINDING_LEVELS)
static void indent PROTO((void));
......@@ -6843,15 +6844,9 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
{
if (at_function_scope_p ())
push_permanent_obstack ();
tem = push_template_decl (tem);
/* In a a local scope, add a representation of this declaration
to the statement tree. */
if (at_function_scope_p ())
{
add_decl_stmt (decl);
pop_obstacks ();
}
pop_obstacks ();
}
......@@ -6987,7 +6982,14 @@ grok_reference_init (decl, type, init)
/* Note: default conversion is only called in very special cases. */
init = default_conversion (init);
}
/* Convert INIT to the reference type TYPE. This may involve the
creation of a temporary, whose lifetime must be the same as that
of the reference. If so, a DECL_STMT for the temporary will be
added just after the DECL_STMT for DECL. That's why we don't set
DECL_INITIAL for local references (instead assigning to them
explicitly); we need to allow the temporary to be initialized
first. */
tmp = convert_to_reference
(type, init, CONV_IMPLICIT,
LOOKUP_SPECULATIVELY|LOOKUP_NORMAL|DIRECT_BIND, decl);
......@@ -6997,7 +6999,18 @@ grok_reference_init (decl, type, init)
else if (tmp != NULL_TREE)
{
init = tmp;
DECL_INITIAL (decl) = save_expr (init);
tmp = save_expr (tmp);
if (building_stmt_tree ())
{
/* Initialize the declaration. */
tmp = build (INIT_EXPR, TREE_TYPE (decl), decl, tmp);
/* Setting TREE_SIDE_EFFECTS prevents expand_expr from
omitting this expression entirely. */
TREE_SIDE_EFFECTS (tmp) = 1;
finish_expr_stmt (tmp);
}
else
DECL_INITIAL (decl) = tmp;
}
else
{
......@@ -7005,11 +7018,6 @@ grok_reference_init (decl, type, init)
return;
}
/* ?? Can this be optimized in some cases to
hand back the DECL_INITIAL slot?? */
if (TYPE_SIZE (TREE_TYPE (type)))
init = convert_from_reference (decl);
if (TREE_STATIC (decl) && ! TREE_CONSTANT (DECL_INITIAL (decl)))
{
expand_static_init (decl, DECL_INITIAL (decl));
......@@ -7526,12 +7534,9 @@ initialize_local_var (decl, init, flags)
int flags;
{
tree type;
tree cleanup;
type = complete_type (TREE_TYPE (decl));
cleanup = build_cleanup_on_safe_obstack (decl);
if (DECL_SIZE (decl) == NULL_TREE && !TREE_STATIC (decl))
{
/* If we used it already as memory, it must stay in memory. */
......@@ -7539,16 +7544,6 @@ initialize_local_var (decl, init, flags)
TREE_ADDRESSABLE (decl) = TREE_USED (decl);
}
if (DECL_RTL (decl))
/* Only a RESULT_DECL should have non-NULL RTL when arriving here.
All other local variables are assigned RTL in this function. */
my_friendly_assert (TREE_CODE (decl) == RESULT_DECL, 19990828);
else
/* Create RTL for this variable. */
expand_decl (decl);
expand_start_target_temps ();
if (DECL_SIZE (decl) && type != error_mark_node)
{
int already_used;
......@@ -7558,21 +7553,15 @@ initialize_local_var (decl, init, flags)
if (init || TYPE_NEEDS_CONSTRUCTING (type))
{
int saved_stmts_are_full_exprs_p;
emit_line_note (DECL_SOURCE_FILE (decl),
DECL_SOURCE_LINE (decl));
/* We call push_momentary here so that when
finish_expr_stmt clears the momentary obstack it
doesn't destory any momentary expressions we may
have lying around. Although cp_finish_decl is
usually called at the end of a declaration
statement, it may also be called for a temporary
object in the middle of an expression. */
push_momentary ();
saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p;
stmts_are_full_exprs_p = 1;
finish_expr_stmt (build_aggr_init (decl, init, flags));
pop_momentary ();
stmts_are_full_exprs_p = saved_stmts_are_full_exprs_p;
}
else
expand_decl_init (decl);
/* Set this to 0 so we can tell whether an aggregate which was
initialized was ever used. Don't do this if it has a
......@@ -7582,22 +7571,48 @@ initialize_local_var (decl, init, flags)
marked used. (see TREE_USED, above.) */
if (TYPE_NEEDS_CONSTRUCTING (type)
&& ! already_used
&& cleanup == NULL_TREE
&& !TYPE_NEEDS_DESTRUCTOR (type)
&& DECL_NAME (decl))
TREE_USED (decl) = 0;
else if (already_used)
TREE_USED (decl) = 1;
}
}
/* Cleanup any temporaries needed for the initial value. */
expand_end_target_temps ();
/* Generate code to destroy DECL (a local variable). */
void
destroy_local_var (decl)
tree decl;
{
tree cleanup = build_cleanup_on_safe_obstack (decl);
/* Record the cleanup required for this declaration. */
if (DECL_SIZE (decl)
&& type != error_mark_node
&& cleanup
&& !expand_decl_cleanup (decl, cleanup))
cp_error ("parser lost in parsing declaration of `%D'", decl);
if (DECL_SIZE (decl) && TREE_TYPE (decl) != error_mark_node
&& cleanup)
finish_decl_cleanup (decl, cleanup);
}
/* Let the back-end know about DECL. */
void
emit_local_var (decl)
tree decl;
{
/* Create RTL for this variable. */
if (DECL_RTL (decl))
/* Only a RESULT_DECL should have non-NULL RTL when
arriving here. All other local variables are
assigned RTL in this function. */
my_friendly_assert (TREE_CODE (decl) == RESULT_DECL,
19990828);
else
expand_decl (decl);
/* Actually do the initialization. */
expand_start_target_temps ();
expand_decl_init (decl);
expand_end_target_temps ();
}
/* Finish processing of a declaration;
......@@ -7680,9 +7695,14 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
return;
}
/* Add this declaration to the statement-tree. */
if (building_stmt_tree ()
&& TREE_CODE (current_scope ()) == FUNCTION_DECL)
add_decl_stmt (decl);
if (TYPE_HAS_MUTABLE_P (type))
TREE_READONLY (decl) = 0;
if (processing_template_decl)
{
if (init && DECL_INITIAL (decl))
......@@ -7808,10 +7828,19 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
/* Initialize the local variable. But, if we're building a
statement-tree, we'll do the initialization when we
expand the tree. */
if (!building_stmt_tree ())
initialize_local_var (decl, init, flags);
else if (init || DECL_INITIAL (decl) == error_mark_node)
DECL_INITIAL (decl) = init;
if (processing_template_decl)
{
if (init || DECL_INITIAL (decl) == error_mark_node)
DECL_INITIAL (decl) = init;
}
else
{
if (!building_stmt_tree ())
emit_local_var (decl);
initialize_local_var (decl, init, flags);
/* Clean up the variable. */
destroy_local_var (decl);
}
}
finish_end0:
......@@ -12900,7 +12929,7 @@ start_function (declspecs, declarator, attrs, flags)
get_pending_sizes ();
/* Let the user know we're compiling this function. */
if (!building_stmt_tree ())
if (processing_template_decl || !building_stmt_tree ())
announce_function (decl1);
/* Record the decl so that the function name is defined.
......@@ -13210,9 +13239,6 @@ store_parm_decls ()
storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl)));
/* Declare __FUNCTION__ and __PRETTY_FUNCTION__ for this function. */
declare_function_name ();
/* Initialize the RTL code for the function. */
DECL_SAVED_INSNS (fndecl) = 0;
if (! building_stmt_tree ())
......@@ -14222,7 +14248,8 @@ finish_stmt ()
if (!current_function_assigns_this
&& current_function_just_assigned_this)
{
if (DECL_CONSTRUCTOR_P (current_function_decl))
if (DECL_CONSTRUCTOR_P (current_function_decl)
&& !building_stmt_tree ())
{
/* Constructors must wait until we are out of control
zones before calling base constructors. */
......
......@@ -2668,9 +2668,6 @@ create_temporary_var (type)
DECL_SOURCE_LINE (decl) = lineno;
DECL_IGNORED_P (decl) = 1;
if (building_stmt_tree ())
add_decl_stmt (decl);
return decl;
}
......@@ -2688,6 +2685,8 @@ get_temp_regvar (type, init)
tree decl;
decl = create_temporary_var (type);
if (building_stmt_tree ())
add_decl_stmt (decl);
DECL_REGISTER (decl) = 1;
if (!building_stmt_tree ())
DECL_RTL (decl) = assign_temp (type, 2, 0, 1);
......
......@@ -7284,7 +7284,8 @@ tsubst_expr (t, args, complain, in_decl)
init = DECL_INITIAL (decl);
decl = tsubst (decl, args, complain, in_decl);
init = tsubst_expr (init, args, complain, in_decl);
DECL_INITIAL (decl) = init;
if (init)
DECL_INITIAL (decl) = error_mark_node;
/* By marking the declaration as instantiated, we avoid
trying to instantiate it. Since instantiate_decl can't
handle local variables, and since we've already done
......@@ -7293,8 +7294,7 @@ tsubst_expr (t, args, complain, in_decl)
if (TREE_CODE (decl) == VAR_DECL)
DECL_TEMPLATE_INSTANTIATED (decl) = 1;
maybe_push_decl (decl);
cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0, 0);
add_decl_stmt (decl);
cp_finish_decl (decl, init, NULL_TREE, 0, 0);
}
resume_momentary (i);
return decl;
......
......@@ -869,6 +869,14 @@ begin_compound_stmt (has_no_scope)
to accidentally keep a block *inside* the scopeless block. */
keep_next_level (0);
/* If this is the outermost block of the function, declare the
variables __FUNCTION__, __PRETTY_FUNCTION__, and so forth. */
if (!current_function_name_declared && !processing_template_decl)
{
declare_function_name ();
current_function_name_declared = 1;
}
return r;
}
......@@ -1027,6 +1035,19 @@ finish_subobject (cleanup)
add_partial_entry (cleanup);
}
/* When DECL goes out of scope, make sure that CLEANUP is executed. */
void
finish_decl_cleanup (decl, cleanup)
tree decl;
tree cleanup;
{
if (building_stmt_tree ())
add_tree (build_min_nt (CLEANUP_STMT, decl, cleanup));
else if (DECL_SIZE (decl) && TREE_TYPE (decl) != error_mark_node)
expand_decl_cleanup (decl, cleanup);
}
/* Bind a name and initialization to the return value of
the current function. */
......@@ -2153,13 +2174,17 @@ expand_stmt (t)
compatibility. */
maybe_inject_for_scope_var (decl);
/* Let the back-end know about this variable. */
initialize_local_var (decl, DECL_INITIAL (decl), 0);
emit_local_var (decl);
}
}
resume_momentary (i);
}
break;
case CLEANUP_STMT:
finish_decl_cleanup (CLEANUP_DECL (t), CLEANUP_EXPR (t));
break;
case FOR_STMT:
{
tree tmp;
......@@ -2338,6 +2363,11 @@ expand_body (fn)
start_function (NULL_TREE, fn, NULL_TREE, SF_PRE_PARSED | SF_EXPAND);
store_parm_decls ();
/* We don't need to redeclare __FUNCTION__, __PRETTY_FUNCTION__, or
any of the other magic variables we set up when starting a
function body. */
current_function_name_declared = 1;
/* 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. */
......
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