From 24bef15854919b1b36f74ea8208c71b146975a0b Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Sun, 12 Sep 1999 01:12:59 +0000 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 35 ++++++++++++++ gcc/cp/cp-tree.def | 4 ++ gcc/cp/cp-tree.h | 11 +++++ gcc/cp/cvt.c | 29 ----------- gcc/cp/decl.c | 139 ++++++++++++++++++++++++++++++++--------------------- gcc/cp/init.c | 5 +- gcc/cp/pt.c | 6 +-- gcc/cp/semantics.c | 32 +++++++++++- 8 files changed, 169 insertions(+), 92 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 06c874f..ab9ece6 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,38 @@ +1999-09-11 Mark Mitchell + + * 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 * cp-tree.h (finish_cleanup_try_block): New function. diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 3322786..53e3e1a 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -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) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d40fe75..5b43829 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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)); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 7ea55bd..382a9b2 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -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); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index ee68023..547f7c6 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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. */ diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 46e207b1..a5b2417 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -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); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index a214317..1cb315d 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index eaa5354..657c3dd 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -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. */ -- 2.7.4