mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-10 03:46:45 +08:00
c-common.h (COMPOUND_STMT_BODY_BLOCK): New macro.
* 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
This commit is contained in:
parent
466eb3e085
commit
ade3dc07d5
@ -1,3 +1,7 @@
|
||||
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
|
||||
@ -20,10 +24,10 @@ Thu Dec 13 20:30:08 2001 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
|
||||
|
||||
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.
|
||||
|
||||
|
@ -37,6 +37,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
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)
|
||||
*/
|
||||
|
||||
@ -762,6 +763,10 @@ extern tree build_return_stmt PARAMS ((tree));
|
||||
|
||||
#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
|
||||
|
@ -1,5 +1,28 @@
|
||||
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>
|
||||
|
@ -118,8 +118,9 @@ $(srcdir)/cp/cfns.h: $(srcdir)/cp/cfns.gperf
|
||||
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
|
||||
|
@ -234,6 +234,8 @@ DEFTREECODE (CTOR_STMT, "ctor_stmt", 'e', 0)
|
||||
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)
|
||||
|
@ -3677,6 +3677,8 @@ extern tree start_enum PARAMS ((tree));
|
||||
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));
|
||||
@ -3849,6 +3851,7 @@ extern tree build_new PARAMS ((tree, tree, tree, int));
|
||||
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));
|
||||
|
172
gcc/cp/decl.c
172
gcc/cp/decl.c
@ -4188,8 +4188,8 @@ pushdecl (x)
|
||||
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)
|
||||
@ -13920,106 +13920,29 @@ save_function_data (decl)
|
||||
}
|
||||
}
|
||||
|
||||
/* 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))
|
||||
{
|
||||
@ -14028,10 +13951,10 @@ finish_destructor_body ()
|
||||
|
||||
/* [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);
|
||||
@ -14045,20 +13968,58 @@ finish_destructor_body ()
|
||||
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
|
||||
@ -14070,7 +14031,6 @@ finish_function (flags)
|
||||
{
|
||||
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;
|
||||
|
||||
@ -14094,15 +14054,7 @@ finish_function (flags)
|
||||
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
|
||||
|
139
gcc/cp/init.c
139
gcc/cp/init.c
@ -3078,9 +3078,7 @@ build_dtor_call (exp, dtor_kind, flags)
|
||||
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)
|
||||
@ -3089,7 +3087,6 @@ 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)
|
||||
@ -3157,15 +3154,13 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
|
||||
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'. */
|
||||
@ -3215,56 +3210,98 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
|
||||
|
||||
return expr;
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
/* At the beginning of a destructor, push cleanups that will call the
|
||||
destructors for our base classes and members.
|
||||
|
||||
Called from setup_vtbl_ptr. */
|
||||
|
||||
void
|
||||
push_base_cleanups ()
|
||||
{
|
||||
tree binfos;
|
||||
int i, n_baseclasses;
|
||||
tree member;
|
||||
tree expr;
|
||||
|
||||
/* Run destructors for all virtual baseclasses. */
|
||||
if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
|
||||
{
|
||||
/* 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);
|
||||
tree vbases;
|
||||
tree cond = (condition_conversion
|
||||
(build (BIT_AND_EXPR, integer_type_node,
|
||||
current_in_charge_parm,
|
||||
integer_two_node)));
|
||||
|
||||
/* Set this again before we call anything, as we might get called
|
||||
recursively. */
|
||||
TYPE_HAS_DESTRUCTOR (type) = 1;
|
||||
|
||||
/* If we have member delete or vbases, we call delete in
|
||||
finish_function. */
|
||||
my_friendly_assert (auto_delete == sfk_base_destructor, 20000411);
|
||||
|
||||
/* Take care of the remaining baseclasses. */
|
||||
for (i = 0; i < n_baseclasses; i++)
|
||||
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))
|
||||
{
|
||||
base_binfo = TREE_VEC_ELT (binfos, i);
|
||||
if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo))
|
||||
|| TREE_VIA_VIRTUAL (base_binfo))
|
||||
continue;
|
||||
tree vbase = TREE_VALUE (vbases);
|
||||
tree base_type = BINFO_TYPE (vbase);
|
||||
|
||||
expr = build_scoped_method_call (ref, base_binfo,
|
||||
base_dtor_identifier,
|
||||
NULL_TREE);
|
||||
|
||||
exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
|
||||
}
|
||||
|
||||
for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member))
|
||||
{
|
||||
if (TREE_CODE (member) != FIELD_DECL)
|
||||
continue;
|
||||
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (member)))
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exprstmt)
|
||||
return build_compound_expr (exprstmt);
|
||||
/* Virtual base classes make this function do nothing. */
|
||||
return void_zero_node;
|
||||
binfos = BINFO_BASETYPES (TYPE_BINFO (current_class_type));
|
||||
n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -727,6 +727,7 @@ synthesize_method (fndecl)
|
||||
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);
|
||||
@ -757,6 +758,7 @@ synthesize_method (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)
|
||||
{
|
||||
@ -783,6 +785,7 @@ synthesize_method (fndecl)
|
||||
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
|
||||
}
|
||||
|
||||
finish_function_body (stmt);
|
||||
expand_body (finish_function (0));
|
||||
|
||||
extract_interface_info ();
|
||||
|
@ -385,7 +385,7 @@ cp_parse_init ()
|
||||
%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
|
||||
@ -747,9 +747,7 @@ datadef:
|
||||
|
||||
ctor_initializer_opt:
|
||||
nodecls
|
||||
{ $$ = 0; }
|
||||
| base_init
|
||||
{ $$ = 1; }
|
||||
;
|
||||
|
||||
maybe_return_init:
|
||||
@ -763,11 +761,18 @@ eat_saved_input:
|
||||
| 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
|
||||
{ }
|
||||
;
|
||||
@ -890,25 +895,21 @@ return_init:
|
||||
;
|
||||
|
||||
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 ();
|
||||
}
|
||||
;
|
||||
|
||||
@ -2208,14 +2209,14 @@ initlist:
|
||||
;
|
||||
|
||||
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
|
||||
@ -3328,13 +3329,6 @@ label_decl:
|
||||
}
|
||||
;
|
||||
|
||||
/* 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); }
|
||||
@ -3499,13 +3493,10 @@ simple_stmt:
|
||||
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:
|
||||
|
14
gcc/cp/pt.c
14
gcc/cp/pt.c
@ -7389,9 +7389,17 @@ tsubst_expr (t, args, complain, in_decl)
|
||||
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;
|
||||
|
||||
@ -7517,7 +7525,7 @@ tsubst_expr (t, args, complain, in_decl)
|
||||
case CTOR_STMT:
|
||||
add_stmt (copy_node (t));
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
@ -580,7 +580,6 @@ genrtl_try_block (t)
|
||||
|
||||
if (FN_TRY_BLOCK_P (t))
|
||||
{
|
||||
end_protect_partials ();
|
||||
expand_start_all_catch ();
|
||||
in_function_try_handler = 1;
|
||||
expand_stmt (TRY_HANDLERS (t));
|
||||
@ -1216,6 +1215,10 @@ setup_vtbl_ptr (member_init_list, base_init_list)
|
||||
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
|
||||
@ -2559,8 +2562,6 @@ static void
|
||||
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. */
|
||||
|
Loading…
Reference in New Issue
Block a user