* 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
+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.
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)
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;
#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. */
#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. */
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));
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));
if ((flags & DIRECT_BIND) && ! real_lvalue_p (arg))
{
- tree compound_stmt;
-
/* Create a new temporary variable. */
tree targ = arg;
if (toplevel_bindings_p ())
{
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))
{
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)
{
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);
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));
{
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 ();
}
/* 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);
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
{
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));
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. */
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;
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
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;
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))
/* 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:
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.
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 ())
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. */
DECL_SOURCE_LINE (decl) = lineno;
DECL_IGNORED_P (decl) = 1;
- if (building_stmt_tree ())
- add_decl_stmt (decl);
-
return decl;
}
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);
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
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;
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;
}
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. */
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;
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. */