* c-common.h (COMPOUND_STMT_BODY_BLOCK): New macro.
* Make-lang.in (parse.h): Separate rule, just depend on parse.c.
Use cleanups to run base and member destructors.
* init.c (push_base_cleanups): New function, split out from...
(build_delete): ...here. Lose !TYPE_HAS_DESTRUCTOR code.
* decl.c (finish_destructor_body): Move vbase destruction code to
push_base_cleanups.
(begin_function_body, finish_function_body): New fns.
(finish_function): Move [cd]tor handling and call_poplevel to
finish_function_body.
(pushdecl): Skip the new level.
* semantics.c (genrtl_try_block): Don't call end_protect_partials.
(setup_vtbl_ptr): Call push_base_cleanups.
* method.c (synthesize_method): Call {begin,end}_function_body.
* pt.c (tsubst_expr): Handle COMPOUND_STMT_BODY_BLOCK.
* cp-tree.h: Declare new fns.
* parse.y (function_body, .begin_function_body): New nonterminals.
(fndef, pending_inline, function_try_block): Use function_body.
(ctor_initializer_opt, function_try_block): No longer has a value.
(base_init): Remove .set_base_init token.
(.set_base_init, compstmt_or_error): Remove.
* Make-lang.in (parse.c): Expect two fewer s/r conflicts.
From-SVN: r47987
+2001-12-13 Jason Merrill <jason@redhat.com>
+
+ * c-common.h (COMPOUND_STMT_BODY_BLOCK): New macro.
+
2001-12-13 Aldy Hernandez <aldyh@redhat.com>
* config/rs6000/rs6000.md (eh_set_lr_di): Change scratch
2001-12-12 Aldy Hernandez <aldyh@redhat.com>
- * config/rs6000/rs6000.c (rs6000_override_options): Add
- SUBSUBTARGET_OVERRIDE_OPTIONS.
+ * config/rs6000/rs6000.c (rs6000_override_options): Add
+ SUBSUBTARGET_OVERRIDE_OPTIONS.
- * config/rs6000/eabialtivec.h: New file.
+ * config/rs6000/eabialtivec.h: New file.
* config/rs6000/linuxaltivec.h: New file.
STMT_IS_FULL_EXPR_P (in _STMT)
2: STMT_LINENO_FOR_FN_P (in _STMT)
3: SCOPE_NO_CLEANUPS_P (in SCOPE_STMT)
+ COMPOUND_STMT_BODY_BLOCK (in COMPOUND_STMT)
4: SCOPE_PARTIAL_P (in SCOPE_STMT)
*/
#define COMPOUND_STMT_NO_SCOPE(NODE) TREE_LANG_FLAG_0 (NODE)
+/* Used by the C++ frontend to mark the block around the member
+ initializers and cleanups. */
+#define COMPOUND_STMT_BODY_BLOCK(NODE) TREE_LANG_FLAG_3 (NODE)
+
extern void c_expand_asm_operands PARAMS ((tree, tree, tree, tree, int, const char *, int));
/* These functions must be defined by each front-end which implements
2001-12-13 Jason Merrill <jason@redhat.com>
+ * Make-lang.in (parse.h): Separate rule, just depend on parse.c.
+
+ Use cleanups to run base and member destructors.
+ * init.c (push_base_cleanups): New function, split out from...
+ (build_delete): ...here. Lose !TYPE_HAS_DESTRUCTOR code.
+ * decl.c (finish_destructor_body): Move vbase destruction code to
+ push_base_cleanups.
+ (begin_function_body, finish_function_body): New fns.
+ (finish_function): Move [cd]tor handling and call_poplevel to
+ finish_function_body.
+ (pushdecl): Skip the new level.
+ * semantics.c (genrtl_try_block): Don't call end_protect_partials.
+ (setup_vtbl_ptr): Call push_base_cleanups.
+ * method.c (synthesize_method): Call {begin,end}_function_body.
+ * pt.c (tsubst_expr): Handle COMPOUND_STMT_BODY_BLOCK.
+ * cp-tree.h: Declare new fns.
+ * parse.y (function_body, .begin_function_body): New nonterminals.
+ (fndef, pending_inline, function_try_block): Use function_body.
+ (ctor_initializer_opt, function_try_block): No longer has a value.
+ (base_init): Remove .set_base_init token.
+ (.set_base_init, compstmt_or_error): Remove.
+ * Make-lang.in (parse.c): Expect two fewer s/r conflicts.
+
* optimize.c (maybe_clone_body): Fix parameter updating.
2001-12-12 Jason Merrill <jason@redhat.com>
gperf -o -C -E -k '1-6,$$' -j1 -D -N 'libc_name_p' \
$(srcdir)/cp/cfns.gperf > $(srcdir)/cp/cfns.h
-$(srcdir)/cp/parse.h $(srcdir)/cp/parse.c: $(srcdir)/cp/parse.y
- @echo "Expect 36 shift/reduce conflicts and 58 reduce/reduce conflicts."
+$(srcdir)/cp/parse.h: $(srcdir)/cp/parse.c
+$(srcdir)/cp/parse.c: $(srcdir)/cp/parse.y
+ @echo "Expect 34 shift/reduce conflicts and 58 reduce/reduce conflicts."
cd $(srcdir)/cp; $(BISON) $(BISONFLAGS) -d -o p$$$$.c parse.y ; \
grep '^#define[ ]*YYEMPTY' p$$$$.c >> p$$$$.h ; \
mv -f p$$$$.c parse.c ; mv -f p$$$$.h parse.h
constructed. If, after this point, the CLEANUP_DECL goes out of
scope, the CLEANUP_EXPR must be run. */
DEFTREECODE (CLEANUP_STMT, "cleanup_stmt", 'e', 2)
+/* CTOR_INITIALIZER is a placeholder in template code for a call to
+ setup_vtbl_pointer (and appears in all functions, not just ctors). */
DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 2)
DEFTREECODE (RETURN_INIT, "return_init", 'e', 2)
DEFTREECODE (TRY_BLOCK, "try_block", 'e', 2)
extern void finish_enum PARAMS ((tree));
extern void build_enumerator PARAMS ((tree, tree, tree));
extern int start_function PARAMS ((tree, tree, tree, int));
+extern tree begin_function_body PARAMS ((void));
+extern void finish_function_body PARAMS ((tree));
extern tree finish_function PARAMS ((int));
extern tree start_method PARAMS ((tree, tree, tree));
extern tree finish_method PARAMS ((tree));
extern tree build_vec_init PARAMS ((tree, tree, int));
extern tree build_x_delete PARAMS ((tree, int, tree));
extern tree build_delete PARAMS ((tree, tree, special_function_kind, int, int));
+extern void push_base_cleanups PARAMS ((void));
extern tree build_vbase_delete PARAMS ((tree, tree));
extern tree build_vec_delete PARAMS ((tree, tree, special_function_kind, int));
extern tree create_temporary_var PARAMS ((tree));
them there. */
struct binding_level *b = current_binding_level->level_chain;
- if (cleanup_label)
- b = b->level_chain;
+ /* Skip the ctor/dtor cleanup level. */
+ b = b->level_chain;
/* ARM $8.3 */
if (b->parm_flag == 1)
}
}
-/* At the end of every constructor we generate to code to return
- `this'. Do that now. */
+/* Add a note to mark the end of the main body of the constructor. This is
+ used to end the cleanup regions for fully-constructed bases and
+ members. */
static void
finish_constructor_body ()
{
- /* Mark the end of the constructor. */
+ /* Mark the end of the cleanups for a partially constructed object.
+
+ ??? These should really be handled automatically by closing the block,
+ as with the destructor cleanups; the only difference is that these are
+ only run if an exception is thrown. */
add_stmt (build_stmt (CTOR_STMT));
}
-/* At the end of every destructor we generate code to restore virtual
- function tables to the values desired by base classes and to call
- to base class destructors. Do that now. */
+/* At the end of every destructor we generate code to delete the object if
+ necessary. Do that now. */
static void
finish_destructor_body ()
{
- tree compound_stmt;
tree exprstmt;
- /* Create a block to contain all the extra code. */
- compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
-
- /* Any return from a destructor will end up here. */
- add_stmt (build_stmt (LABEL_STMT, dtor_label));
-
- /* Generate the code to call destructor on base class. If this
- destructor belongs to a class with virtual functions, then set
- the virtual function table pointer to represent the type of our
- base class. */
-
- /* This side-effect makes call to `build_delete' generate the code
- we have to have at the end of this destructor. `build_delete'
- will set the flag again. */
- TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
-
- exprstmt = build_delete (current_class_type,
- current_class_ref,
- sfk_base_destructor,
- LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
- 0);
-
- if (exprstmt != error_mark_node
- && (TREE_CODE (exprstmt) != NOP_EXPR
- || TREE_OPERAND (exprstmt, 0) != integer_zero_node
- || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)))
- {
- if (exprstmt != void_zero_node)
- /* Don't call `expand_expr_stmt' if we're not going to do
- anything, since -Wall will give a diagnostic. */
- finish_expr_stmt (exprstmt);
-
- /* Run destructors for all virtual baseclasses. */
- if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
- {
- tree vbases;
- tree if_stmt;
-
- if_stmt = begin_if_stmt ();
- finish_if_stmt_cond (build (BIT_AND_EXPR, integer_type_node,
- current_in_charge_parm,
- integer_two_node),
- if_stmt);
-
- vbases = CLASSTYPE_VBASECLASSES (current_class_type);
- /* The CLASSTYPE_VBASECLASSES list is in initialization
- order, so we have to march through it in reverse order. */
- for (vbases = nreverse (copy_list (vbases));
- vbases;
- vbases = TREE_CHAIN (vbases))
- {
- tree vbase = TREE_VALUE (vbases);
- tree base_type = BINFO_TYPE (vbase);
-
- if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (base_type))
- {
- tree base_ptr_type = build_pointer_type (base_type);
- tree expr = current_class_ptr;
-
- /* Convert to the basetype here, as we know the layout is
- fixed. What is more, if we let build_method_call do it,
- it will use the vtable, which may have been clobbered
- by the deletion of our primary base. */
-
- expr = build1 (NOP_EXPR, base_ptr_type, expr);
- expr = build (PLUS_EXPR, base_ptr_type, expr,
- BINFO_OFFSET (vbase));
- expr = build_indirect_ref (expr, NULL);
- expr = build_method_call (expr, base_dtor_identifier,
- NULL_TREE, vbase,
- LOOKUP_NORMAL);
- finish_expr_stmt (expr);
- }
- }
-
- finish_then_clause (if_stmt);
- finish_if_stmt ();
- }
- }
-
/* In a virtual destructor, we must call delete. */
if (DECL_VIRTUAL_P (current_function_decl))
{
/* [class.dtor]
- At the point of definition of a virtual destructor (including
- an implicit definition), non-placement operator delete shall
- be looked up in the scope of the destructor's class and if
- found shall be accessible and unambiguous. */
+ At the point of definition of a virtual destructor (including
+ an implicit definition), non-placement operator delete shall
+ be looked up in the scope of the destructor's class and if
+ found shall be accessible and unambiguous. */
exprstmt = build_op_delete_call
(DELETE_EXPR, current_class_ptr, virtual_size,
LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE);
finish_then_clause (if_stmt);
finish_if_stmt ();
}
+}
- /* Close the block we started above. */
- finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
+/* Do the necessary processing for the beginning of a function body, which
+ in this case includes member-initializers, but not the catch clauses of
+ a function-try-block. Currently, this means opening a binding level
+ for the member-initializers (in a ctor) and member cleanups (in a dtor).
+ In other functions, this isn't necessary, but it doesn't hurt. */
+
+tree
+begin_function_body ()
+{
+ tree stmt = begin_compound_stmt (0);
+ COMPOUND_STMT_BODY_BLOCK (stmt) = 1;
+ return stmt;
}
+/* Do the processing for the end of a function body. Currently, this means
+ closing out the cleanups for fully-constructed bases and members, and in
+ the case of the destructor, deleting the object if desired. Again, this
+ is only meaningful for [cd]tors, since they are the only functions where
+ there is a significant distinction between the main body and any
+ function catch clauses. Handling, say, main() return semantics here
+ would be wrong, as flowing off the end of a function catch clause for
+ main() would also need to return 0. */
+
+void
+finish_function_body (compstmt)
+ tree compstmt;
+{
+ if (processing_template_decl)
+ /* Do nothing now. */;
+ else if (DECL_DESTRUCTOR_P (current_function_decl))
+ /* Any return from a destructor will end up here. Put it before the
+ cleanups so that an explicit return doesn't duplicate them. */
+ add_stmt (build_stmt (LABEL_STMT, dtor_label));
+
+ /* Close the block; in a destructor, run the member cleanups. */
+ finish_compound_stmt (0, compstmt);
+
+ if (processing_template_decl)
+ /* Do nothing now. */;
+ else if (DECL_CONSTRUCTOR_P (current_function_decl))
+ finish_constructor_body ();
+ else if (DECL_DESTRUCTOR_P (current_function_decl))
+ finish_destructor_body ();
+}
+
/* Finish up a function declaration and compile that function
all the way to assembler language output. The free the storage
for the function definition.
FLAGS is a bitwise or of the following values:
- 1 - CALL_POPLEVEL
- An extra call to poplevel (and expand_end_bindings) must be
- made to take care of the binding contour for the base
- initializers. This is only relevant for constructors.
2 - INCLASS_INLINE
We just finished processing the body of an in-class inline
function definition. (This processing will have taken place
{
register tree fndecl = current_function_decl;
tree fntype, ctype = NULL_TREE;
- int call_poplevel = (flags & 1) != 0;
int inclass_inline = (flags & 2) != 0;
int nested;
there's no need to add any extra bits. */
if (!DECL_CLONED_FUNCTION_P (fndecl))
{
- if (DECL_CONSTRUCTOR_P (fndecl))
- {
- finish_constructor_body ();
- if (call_poplevel)
- do_poplevel ();
- }
- else if (DECL_DESTRUCTOR_P (fndecl) && !processing_template_decl)
- finish_destructor_body ();
- else if (DECL_MAIN_P (fndecl))
+ if (DECL_MAIN_P (current_function_decl))
{
/* Make it so that `main' always returns 0 by default. */
#ifdef VMS_TARGET
sfk_deleting_destructor.
FLAGS is the logical disjunction of zero or more LOOKUP_
- flags. See cp-tree.h for more info.
-
- This function does not delete an object's virtual base classes. */
+ flags. See cp-tree.h for more info. */
tree
build_delete (type, addr, auto_delete, flags, use_global_delete)
int flags;
int use_global_delete;
{
- tree member;
tree expr;
if (addr == error_mark_node)
LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL),
NULL_TREE);
}
-
- /* Below, we will reverse the order in which these calls are made.
- If we have a destructor, then that destructor will take care
- of the base classes; otherwise, we must do that here. */
- if (TYPE_HAS_DESTRUCTOR (type))
+ else
{
tree do_delete = NULL_TREE;
tree ifexp;
+ my_friendly_assert (TYPE_HAS_DESTRUCTOR (type), 20011213);
+
/* For `::delete x', we must not use the deleting destructor
since then we would not be sure to get the global `operator
delete'. */
return expr;
}
- else
- {
- /* We only get here from finish_function for a destructor. */
- tree binfos = BINFO_BASETYPES (TYPE_BINFO (type));
- int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (type);
- tree base_binfo = n_baseclasses > 0 ? TREE_VEC_ELT (binfos, 0) : NULL_TREE;
- tree exprstmt = NULL_TREE;
- tree ref = build_indirect_ref (addr, NULL);
+}
- /* Set this again before we call anything, as we might get called
- recursively. */
- TYPE_HAS_DESTRUCTOR (type) = 1;
+/* At the beginning of a destructor, push cleanups that will call the
+ destructors for our base classes and members.
- /* If we have member delete or vbases, we call delete in
- finish_function. */
- my_friendly_assert (auto_delete == sfk_base_destructor, 20000411);
+ Called from setup_vtbl_ptr. */
- /* Take care of the remaining baseclasses. */
- for (i = 0; i < n_baseclasses; i++)
- {
- base_binfo = TREE_VEC_ELT (binfos, i);
- if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo))
- || TREE_VIA_VIRTUAL (base_binfo))
- continue;
-
- expr = build_scoped_method_call (ref, base_binfo,
- base_dtor_identifier,
- NULL_TREE);
+void
+push_base_cleanups ()
+{
+ tree binfos;
+ int i, n_baseclasses;
+ tree member;
+ tree expr;
- exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
- }
+ /* Run destructors for all virtual baseclasses. */
+ if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+ {
+ tree vbases;
+ tree cond = (condition_conversion
+ (build (BIT_AND_EXPR, integer_type_node,
+ current_in_charge_parm,
+ integer_two_node)));
- for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member))
+ vbases = CLASSTYPE_VBASECLASSES (current_class_type);
+ /* The CLASSTYPE_VBASECLASSES list is in initialization
+ order, which is also the right order for pushing cleanups. */
+ for (; vbases;
+ vbases = TREE_CHAIN (vbases))
{
- if (TREE_CODE (member) != FIELD_DECL)
- continue;
- if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (member)))
+ tree vbase = TREE_VALUE (vbases);
+ tree base_type = BINFO_TYPE (vbase);
+
+ if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (base_type))
{
- tree this_member = build_component_ref (ref, DECL_NAME (member), NULL_TREE, 0);
- tree this_type = TREE_TYPE (member);
- expr = build_delete (this_type, this_member,
- sfk_complete_destructor, flags, 0);
- exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
+ tree base_ptr_type = build_pointer_type (base_type);
+ expr = current_class_ptr;
+
+ /* Convert to the basetype here, as we know the layout is
+ fixed. What is more, if we let build_method_call do it,
+ it will use the vtable, which may have been clobbered
+ by the deletion of our primary base. */
+
+ expr = build1 (NOP_EXPR, base_ptr_type, expr);
+ expr = build (PLUS_EXPR, base_ptr_type, expr,
+ BINFO_OFFSET (vbase));
+ expr = build_indirect_ref (expr, NULL);
+ expr = build_method_call (expr, base_dtor_identifier,
+ NULL_TREE, vbase,
+ LOOKUP_NORMAL);
+ expr = build (COND_EXPR, void_type_node, cond,
+ expr, void_zero_node);
+ finish_decl_cleanup (NULL_TREE, expr);
}
}
+ }
+
+ binfos = BINFO_BASETYPES (TYPE_BINFO (current_class_type));
+ n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type);
- if (exprstmt)
- return build_compound_expr (exprstmt);
- /* Virtual base classes make this function do nothing. */
- return void_zero_node;
+ /* Take care of the remaining baseclasses. */
+ for (i = 0; i < n_baseclasses; i++)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+ if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo))
+ || TREE_VIA_VIRTUAL (base_binfo))
+ continue;
+
+ expr = build_scoped_method_call (current_class_ref, base_binfo,
+ base_dtor_identifier,
+ NULL_TREE);
+
+ finish_decl_cleanup (NULL_TREE, expr);
+ }
+
+ for (member = TYPE_FIELDS (current_class_type); member;
+ member = TREE_CHAIN (member))
+ {
+ if (TREE_CODE (member) != FIELD_DECL)
+ continue;
+ if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (member)))
+ {
+ tree this_member = (build_component_ref
+ (current_class_ref, DECL_NAME (member),
+ NULL_TREE, 0));
+ tree this_type = TREE_TYPE (member);
+ expr = build_delete (this_type, this_member,
+ sfk_complete_destructor,
+ LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
+ 0);
+ finish_decl_cleanup (NULL_TREE, expr);
+ }
}
}
int nested = (current_function_decl != NULL_TREE);
tree context = decl_function_context (fndecl);
int need_body = 1;
+ tree stmt;
if (at_eof)
import_export_decl (fndecl);
interface_unknown = 1;
start_function (NULL_TREE, fndecl, NULL_TREE, SF_DEFAULT | SF_PRE_PARSED);
clear_last_expr ();
+ stmt = begin_function_body ();
if (DECL_OVERLOADED_OPERATOR_P (fndecl) == NOP_EXPR)
{
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
}
+ finish_function_body (stmt);
expand_body (finish_function (0));
extract_interface_info ();
%token <pi> PRE_PARSED_FUNCTION_DECL
%type <ttype> component_constructor_declarator
%type <ttype> fn.def2 return_id constructor_declarator
-%type <itype> ctor_initializer_opt function_try_block
+%type <ttype> .begin_function_body
%type <ttype> named_class_head_sans_basetype
%type <ftype> class_head named_class_head
%type <ftype> named_complex_class_head_sans_basetype
ctor_initializer_opt:
nodecls
- { $$ = 0; }
| base_init
- { $$ = 1; }
;
maybe_return_init:
| END_OF_SAVED_INPUT
;
+function_body:
+ .begin_function_body ctor_initializer_opt compstmt
+ {
+ finish_function_body ($1);
+ }
+ ;
+
fndef:
- fn.def1 maybe_return_init ctor_initializer_opt compstmt_or_error
- { expand_body (finish_function ((int)$3)); }
+ fn.def1 maybe_return_init function_body
+ { expand_body (finish_function (0)); }
| fn.def1 maybe_return_init function_try_block
- { expand_body (finish_function ((int)$3)); }
+ { expand_body (finish_function (0)); }
| fn.def1 maybe_return_init error
{ }
;
;
base_init:
- ':' .set_base_init member_init_list
+ ':' member_init_list
{
- if ($3.new_type_flag == 0)
+ if (! DECL_CONSTRUCTOR_P (current_function_decl))
+ error ("only constructors take base initializers");
+ else if ($2.new_type_flag == 0)
error ("no base or member initializers given following ':'");
- finish_mem_initializers ($3.t);
+ finish_mem_initializers ($2.t);
}
;
-.set_base_init:
+.begin_function_body:
/* empty */
{
- if (DECL_CONSTRUCTOR_P (current_function_decl))
- /* Make a contour for the initializer list. */
- 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))
- error ("only constructors take base initializers");
+ $$ = begin_function_body ();
}
;
;
pending_inline:
- PRE_PARSED_FUNCTION_DECL maybe_return_init ctor_initializer_opt compstmt_or_error
+ PRE_PARSED_FUNCTION_DECL maybe_return_init function_body
{
- expand_body (finish_function ((int)$3 | 2));
+ expand_body (finish_function (2));
process_next_inline ($1);
}
| PRE_PARSED_FUNCTION_DECL maybe_return_init function_try_block
{
- expand_body (finish_function ((int)$3 | 2));
+ expand_body (finish_function (2));
process_next_inline ($1);
}
| PRE_PARSED_FUNCTION_DECL maybe_return_init error
}
;
-/* This is the body of a function definition.
- It causes syntax errors to ignore to the next openbrace. */
-compstmt_or_error:
- compstmt
- | error compstmt
- ;
-
compstmt:
save_lineno '{'
{ $<ttype>$ = begin_compound_stmt (0); }
function_try_block:
TRY
{ $<ttype>$ = begin_function_try_block (); }
- ctor_initializer_opt compstmt
+ function_body
{ finish_function_try_block ($<ttype>2); }
handler_seq
- {
- finish_function_handler_sequence ($<ttype>2);
- $$ = $3;
- }
+ { finish_function_handler_sequence ($<ttype>2); }
;
try_block:
case COMPOUND_STMT:
{
prep_stmt (t);
- stmt = begin_compound_stmt (COMPOUND_STMT_NO_SCOPE (t));
+ if (COMPOUND_STMT_BODY_BLOCK (t))
+ stmt = begin_function_body ();
+ else
+ stmt = begin_compound_stmt (COMPOUND_STMT_NO_SCOPE (t));
+
tsubst_expr (COMPOUND_BODY (t), args, complain, in_decl);
- finish_compound_stmt (COMPOUND_STMT_NO_SCOPE (t), stmt);
+
+ if (COMPOUND_STMT_BODY_BLOCK (t))
+ finish_function_body (stmt);
+ else
+ finish_compound_stmt (COMPOUND_STMT_NO_SCOPE (t), stmt);
}
break;
case CTOR_STMT:
add_stmt (copy_node (t));
break;
-
+
default:
abort ();
}
if (FN_TRY_BLOCK_P (t))
{
- end_protect_partials ();
expand_start_all_catch ();
in_function_try_handler = 1;
expand_stmt (TRY_HANDLERS (t));
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
finish_then_clause (if_stmt);
finish_if_stmt ();
+
+ /* And insert cleanups for our bases and members so that they
+ will be properly destroyed if we throw. */
+ push_base_cleanups ();
}
/* Always keep the BLOCK node associated with the outermost pair of
genrtl_start_function (fn)
tree fn;
{
- tree parm;
-
/* Tell everybody what function we're processing. */
current_function_decl = fn;
/* Get the RTL machinery going for this function. */