decl.c (store_parm_decls): Remove parms_have_cleanups cruft.
* decl.c (store_parm_decls): Remove parms_have_cleanups cruft. * semantics.c (genrtl_start_function): Don't pass parms_have_cleanups or push an extra binding level. (genrtl_finish_function): Lose cleanup_label cruft. * cp-tree.h (struct cp_language_function): Remove x_ctor_label. (ctor_label): Remove. * semantics.c (finish_return_stmt): Lose ctor_label support. * decl.c (finish_constructor_body, mark_lang_function): Likewise. * typeck.c (check_return_expr): Check DECL_DESTRUCTOR_P, not dtor_label. * call.c (build_new_method_call): Let resolves_to_fixed_type_p check for [cd]tors. * class.c (fixed_type_or_null, case INDIRECT_REF): Fix. * decl.c (finish_function): Check VMS_TARGET, not VMS. * decl.c (start_cleanup_fn): Remove redundant pushlevel. (end_cleanup_fn): And poplevel. * semantics.c (setup_vtbl_ptr): Always build a CTOR_INITIALIZER if we're in a template. From-SVN: r47962
This commit is contained in:
parent
aff8a8d52b
commit
a0de9d2025
8 changed files with 67 additions and 137 deletions
|
@ -1,3 +1,29 @@
|
||||||
|
2001-12-12 Jason Merrill <jason@redhat.com>
|
||||||
|
|
||||||
|
* decl.c (store_parm_decls): Remove parms_have_cleanups cruft.
|
||||||
|
* semantics.c (genrtl_start_function): Don't pass
|
||||||
|
parms_have_cleanups or push an extra binding level.
|
||||||
|
(genrtl_finish_function): Lose cleanup_label cruft.
|
||||||
|
|
||||||
|
* cp-tree.h (struct cp_language_function): Remove x_ctor_label.
|
||||||
|
(ctor_label): Remove.
|
||||||
|
* semantics.c (finish_return_stmt): Lose ctor_label support.
|
||||||
|
* decl.c (finish_constructor_body, mark_lang_function): Likewise.
|
||||||
|
* typeck.c (check_return_expr): Check DECL_DESTRUCTOR_P, not
|
||||||
|
dtor_label.
|
||||||
|
|
||||||
|
* call.c (build_new_method_call): Let resolves_to_fixed_type_p
|
||||||
|
check for [cd]tors.
|
||||||
|
* class.c (fixed_type_or_null, case INDIRECT_REF): Fix.
|
||||||
|
|
||||||
|
* decl.c (finish_function): Check VMS_TARGET, not VMS.
|
||||||
|
|
||||||
|
* decl.c (start_cleanup_fn): Remove redundant pushlevel.
|
||||||
|
(end_cleanup_fn): And poplevel.
|
||||||
|
|
||||||
|
* semantics.c (setup_vtbl_ptr): Always build a CTOR_INITIALIZER
|
||||||
|
if we're in a template.
|
||||||
|
|
||||||
2001-12-12 Jakub Jelinek <jakub@redhat.com>
|
2001-12-12 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
* cp-tree.h (DESTRUCTOR_DECL_PREFIX, DESTRUCTOR_NAME_P,
|
* cp-tree.h (DESTRUCTOR_DECL_PREFIX, DESTRUCTOR_NAME_P,
|
||||||
|
|
|
@ -4660,8 +4660,7 @@ build_new_method_call (instance, name, args, basetype_path, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DECL_VINDEX (cand->fn) && ! (flags & LOOKUP_NONVIRTUAL)
|
if (DECL_VINDEX (cand->fn) && ! (flags & LOOKUP_NONVIRTUAL)
|
||||||
&& ((instance == current_class_ref && (dtor_label || ctor_label))
|
&& resolves_to_fixed_type_p (instance, 0))
|
||||||
|| resolves_to_fixed_type_p (instance, 0)))
|
|
||||||
flags |= LOOKUP_NONVIRTUAL;
|
flags |= LOOKUP_NONVIRTUAL;
|
||||||
|
|
||||||
if (TREE_CODE (TREE_TYPE (cand->fn)) == METHOD_TYPE)
|
if (TREE_CODE (TREE_TYPE (cand->fn)) == METHOD_TYPE)
|
||||||
|
|
|
@ -5287,11 +5287,12 @@ fixed_type_or_null (instance, nonnull, cdtorp)
|
||||||
switch (TREE_CODE (instance))
|
switch (TREE_CODE (instance))
|
||||||
{
|
{
|
||||||
case INDIRECT_REF:
|
case INDIRECT_REF:
|
||||||
/* Check that we are not going through a cast of some sort. */
|
if (POINTER_TYPE_P (instance))
|
||||||
if (TREE_TYPE (instance)
|
return NULL_TREE;
|
||||||
== TREE_TYPE (TREE_TYPE (TREE_OPERAND (instance, 0))))
|
else
|
||||||
instance = TREE_OPERAND (instance, 0);
|
return fixed_type_or_null (TREE_OPERAND (instance, 0),
|
||||||
/* fall through... */
|
nonnull, cdtorp);
|
||||||
|
|
||||||
case CALL_EXPR:
|
case CALL_EXPR:
|
||||||
/* This is a call to a constructor, hence it's never zero. */
|
/* This is a call to a constructor, hence it's never zero. */
|
||||||
if (TREE_HAS_CONSTRUCTOR (instance))
|
if (TREE_HAS_CONSTRUCTOR (instance))
|
||||||
|
|
|
@ -801,7 +801,6 @@ struct cp_language_function
|
||||||
{
|
{
|
||||||
struct language_function base;
|
struct language_function base;
|
||||||
|
|
||||||
tree x_ctor_label;
|
|
||||||
tree x_dtor_label;
|
tree x_dtor_label;
|
||||||
tree x_current_class_ptr;
|
tree x_current_class_ptr;
|
||||||
tree x_current_class_ref;
|
tree x_current_class_ref;
|
||||||
|
@ -836,11 +835,6 @@ struct cp_language_function
|
||||||
|
|
||||||
#define dtor_label cp_function_chain->x_dtor_label
|
#define dtor_label cp_function_chain->x_dtor_label
|
||||||
|
|
||||||
/* In a constructor, the point at which we are ready to return
|
|
||||||
the pointer to the initialized object. */
|
|
||||||
|
|
||||||
#define ctor_label cp_function_chain->x_ctor_label
|
|
||||||
|
|
||||||
/* When we're processing a member function, current_class_ptr is the
|
/* When we're processing a member function, current_class_ptr is the
|
||||||
PARM_DECL for the `this' pointer. The current_class_ref is an
|
PARM_DECL for the `this' pointer. The current_class_ref is an
|
||||||
expression for `*this'. */
|
expression for `*this'. */
|
||||||
|
|
|
@ -8418,7 +8418,6 @@ start_cleanup_fn ()
|
||||||
|
|
||||||
pushdecl (fndecl);
|
pushdecl (fndecl);
|
||||||
start_function (/*specs=*/NULL_TREE, fndecl, NULL_TREE, SF_PRE_PARSED);
|
start_function (/*specs=*/NULL_TREE, fndecl, NULL_TREE, SF_PRE_PARSED);
|
||||||
do_pushlevel ();
|
|
||||||
|
|
||||||
interface_unknown = old_interface_unknown;
|
interface_unknown = old_interface_unknown;
|
||||||
|
|
||||||
|
@ -8432,8 +8431,6 @@ start_cleanup_fn ()
|
||||||
static void
|
static void
|
||||||
end_cleanup_fn ()
|
end_cleanup_fn ()
|
||||||
{
|
{
|
||||||
do_poplevel ();
|
|
||||||
|
|
||||||
expand_body (finish_function (0));
|
expand_body (finish_function (0));
|
||||||
|
|
||||||
pop_from_top_level ();
|
pop_from_top_level ();
|
||||||
|
@ -13794,7 +13791,6 @@ store_parm_decls (current_function_parms)
|
||||||
{
|
{
|
||||||
register tree fndecl = current_function_decl;
|
register tree fndecl = current_function_decl;
|
||||||
register tree parm;
|
register tree parm;
|
||||||
int parms_have_cleanups = 0;
|
|
||||||
tree cleanups = NULL_TREE;
|
tree cleanups = NULL_TREE;
|
||||||
|
|
||||||
/* This is a chain of any other decls that came in among the parm
|
/* This is a chain of any other decls that came in among the parm
|
||||||
|
@ -13875,11 +13871,6 @@ store_parm_decls (current_function_parms)
|
||||||
cleanups = TREE_CHAIN (cleanups);
|
cleanups = TREE_CHAIN (cleanups);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a binding contour which can be used to catch
|
|
||||||
cleanup-generated temporaries. */
|
|
||||||
if (parms_have_cleanups)
|
|
||||||
pushlevel (0);
|
|
||||||
|
|
||||||
/* Do the starting of the exception specifications, if we have any. */
|
/* Do the starting of the exception specifications, if we have any. */
|
||||||
if (flag_exceptions && !processing_template_decl
|
if (flag_exceptions && !processing_template_decl
|
||||||
&& flag_enforce_eh_specs
|
&& flag_enforce_eh_specs
|
||||||
|
@ -13935,16 +13926,6 @@ save_function_data (decl)
|
||||||
static void
|
static void
|
||||||
finish_constructor_body ()
|
finish_constructor_body ()
|
||||||
{
|
{
|
||||||
/* Any return from a constructor will end up here. */
|
|
||||||
if (ctor_label)
|
|
||||||
add_stmt (build_stmt (LABEL_STMT, ctor_label));
|
|
||||||
|
|
||||||
/* Clear CTOR_LABEL so that finish_return_stmt knows to really
|
|
||||||
generate the return, rather than a goto to CTOR_LABEL. */
|
|
||||||
ctor_label = NULL_TREE;
|
|
||||||
/* In check_return_expr we translate an empty return from a
|
|
||||||
constructor to a return of `this'. */
|
|
||||||
finish_return_stmt (NULL_TREE);
|
|
||||||
/* Mark the end of the constructor. */
|
/* Mark the end of the constructor. */
|
||||||
add_stmt (build_stmt (CTOR_STMT));
|
add_stmt (build_stmt (CTOR_STMT));
|
||||||
}
|
}
|
||||||
|
@ -14124,7 +14105,7 @@ finish_function (flags)
|
||||||
else if (DECL_MAIN_P (fndecl))
|
else if (DECL_MAIN_P (fndecl))
|
||||||
{
|
{
|
||||||
/* Make it so that `main' always returns 0 by default. */
|
/* Make it so that `main' always returns 0 by default. */
|
||||||
#ifdef VMS
|
#ifdef VMS_TARGET
|
||||||
finish_return_stmt (integer_one_node);
|
finish_return_stmt (integer_one_node);
|
||||||
#else
|
#else
|
||||||
finish_return_stmt (integer_zero_node);
|
finish_return_stmt (integer_zero_node);
|
||||||
|
@ -14575,7 +14556,6 @@ mark_lang_function (p)
|
||||||
|
|
||||||
mark_c_language_function (&p->base);
|
mark_c_language_function (&p->base);
|
||||||
|
|
||||||
ggc_mark_tree (p->x_ctor_label);
|
|
||||||
ggc_mark_tree (p->x_dtor_label);
|
ggc_mark_tree (p->x_dtor_label);
|
||||||
ggc_mark_tree (p->x_current_class_ptr);
|
ggc_mark_tree (p->x_current_class_ptr);
|
||||||
ggc_mark_tree (p->x_current_class_ref);
|
ggc_mark_tree (p->x_current_class_ref);
|
||||||
|
|
|
@ -462,6 +462,7 @@ use_thunk (thunk_fndecl, emit_p)
|
||||||
DECL_RESULT (thunk_fndecl) = NULL_TREE;
|
DECL_RESULT (thunk_fndecl) = NULL_TREE;
|
||||||
|
|
||||||
start_function (NULL_TREE, thunk_fndecl, NULL_TREE, SF_PRE_PARSED);
|
start_function (NULL_TREE, thunk_fndecl, NULL_TREE, SF_PRE_PARSED);
|
||||||
|
/* We don't bother with a body block for thunks. */
|
||||||
|
|
||||||
/* Adjust the this pointer by the constant. */
|
/* Adjust the this pointer by the constant. */
|
||||||
t = ssize_int (delta);
|
t = ssize_int (delta);
|
||||||
|
|
|
@ -390,17 +390,7 @@ finish_return_stmt (expr)
|
||||||
expr = check_return_expr (expr);
|
expr = check_return_expr (expr);
|
||||||
if (!processing_template_decl)
|
if (!processing_template_decl)
|
||||||
{
|
{
|
||||||
if (DECL_CONSTRUCTOR_P (current_function_decl) && ctor_label)
|
if (DECL_DESTRUCTOR_P (current_function_decl))
|
||||||
{
|
|
||||||
/* Even returns without a value in a constructor must return
|
|
||||||
`this'. We accomplish this by sending all returns in a
|
|
||||||
constructor to the CTOR_LABEL; finish_function emits code to
|
|
||||||
return a value there. When we finally generate the real
|
|
||||||
return statement, CTOR_LABEL is no longer set, and we fall
|
|
||||||
through into the normal return-processing code below. */
|
|
||||||
return finish_goto_stmt (ctor_label);
|
|
||||||
}
|
|
||||||
else if (DECL_DESTRUCTOR_P (current_function_decl))
|
|
||||||
{
|
{
|
||||||
/* Similarly, all destructors must run destructors for
|
/* Similarly, all destructors must run destructors for
|
||||||
base-classes before returning. So, all returns in a
|
base-classes before returning. So, all returns in a
|
||||||
|
@ -678,7 +668,7 @@ finish_cleanup (cleanup, try_block)
|
||||||
|
|
||||||
void
|
void
|
||||||
finish_function_try_block (try_block)
|
finish_function_try_block (try_block)
|
||||||
tree try_block;
|
tree try_block;
|
||||||
{
|
{
|
||||||
if (TREE_CHAIN (try_block)
|
if (TREE_CHAIN (try_block)
|
||||||
&& TREE_CODE (TREE_CHAIN (try_block)) == CTOR_INITIALIZER)
|
&& TREE_CODE (TREE_CHAIN (try_block)) == CTOR_INITIALIZER)
|
||||||
|
@ -1155,9 +1145,12 @@ finish_mem_initializers (init_list)
|
||||||
setup_vtbl_ptr (member_init_list, base_init_list);
|
setup_vtbl_ptr (member_init_list, base_init_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cache the value of this class's main virtual function table pointer
|
/* Do the initialization work necessary at the beginning of a constructor
|
||||||
in a register variable. This will save one indirection if a
|
or destructor. This means processing member initializers and setting
|
||||||
more than one virtual function call is made this function. */
|
vtable pointers.
|
||||||
|
|
||||||
|
??? The call to keep_next_level at the end applies to all functions, but
|
||||||
|
should probably go somewhere else. */
|
||||||
|
|
||||||
void
|
void
|
||||||
setup_vtbl_ptr (member_init_list, base_init_list)
|
setup_vtbl_ptr (member_init_list, base_init_list)
|
||||||
|
@ -1166,31 +1159,26 @@ setup_vtbl_ptr (member_init_list, base_init_list)
|
||||||
{
|
{
|
||||||
my_friendly_assert (doing_semantic_analysis_p (), 19990919);
|
my_friendly_assert (doing_semantic_analysis_p (), 19990919);
|
||||||
|
|
||||||
/* If we've already done this, there's no need to do it again. */
|
/* If we've already done this, break. */
|
||||||
if (vtbls_set_up_p)
|
if (vtbls_set_up_p)
|
||||||
return;
|
abort ();
|
||||||
|
|
||||||
if (DECL_CONSTRUCTOR_P (current_function_decl))
|
if (processing_template_decl)
|
||||||
|
add_stmt (build_min_nt (CTOR_INITIALIZER,
|
||||||
|
member_init_list, base_init_list));
|
||||||
|
else if (DECL_CONSTRUCTOR_P (current_function_decl))
|
||||||
{
|
{
|
||||||
if (processing_template_decl)
|
tree ctor_stmt;
|
||||||
add_stmt (build_min_nt
|
|
||||||
(CTOR_INITIALIZER,
|
|
||||||
member_init_list, base_init_list));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tree ctor_stmt;
|
|
||||||
|
|
||||||
/* Mark the beginning of the constructor. */
|
/* Mark the beginning of the constructor. */
|
||||||
ctor_stmt = build_stmt (CTOR_STMT);
|
ctor_stmt = build_stmt (CTOR_STMT);
|
||||||
CTOR_BEGIN_P (ctor_stmt) = 1;
|
CTOR_BEGIN_P (ctor_stmt) = 1;
|
||||||
add_stmt (ctor_stmt);
|
add_stmt (ctor_stmt);
|
||||||
|
|
||||||
/* And actually initialize the base-classes and members. */
|
/* And actually initialize the base-classes and members. */
|
||||||
emit_base_init (member_init_list, base_init_list);
|
emit_base_init (member_init_list, base_init_list);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (DECL_DESTRUCTOR_P (current_function_decl)
|
else if (DECL_DESTRUCTOR_P (current_function_decl))
|
||||||
&& !processing_template_decl)
|
|
||||||
{
|
{
|
||||||
tree if_stmt;
|
tree if_stmt;
|
||||||
tree compound_stmt;
|
tree compound_stmt;
|
||||||
|
@ -1203,7 +1191,11 @@ setup_vtbl_ptr (member_init_list, base_init_list)
|
||||||
virtual dispatch to an overridden function that would need to
|
virtual dispatch to an overridden function that would need to
|
||||||
have a non-related vtable set up, we cannot avoid setting up
|
have a non-related vtable set up, we cannot avoid setting up
|
||||||
vtables in that case. We could change this to see if there
|
vtables in that case. We could change this to see if there
|
||||||
is just one vtable. */
|
is just one vtable.
|
||||||
|
|
||||||
|
??? In the destructor for a class, the vtables are set
|
||||||
|
appropriately for that class. There will be no non-related
|
||||||
|
vtables. jason 2001-12-11. */
|
||||||
if_stmt = begin_if_stmt ();
|
if_stmt = begin_if_stmt ();
|
||||||
|
|
||||||
/* If it is not safe to avoid setting up the vtables, then
|
/* If it is not safe to avoid setting up the vtables, then
|
||||||
|
@ -2618,23 +2610,10 @@ genrtl_start_function (fn)
|
||||||
|
|
||||||
/* Create a binding level for the parameters. */
|
/* Create a binding level for the parameters. */
|
||||||
expand_start_bindings (2);
|
expand_start_bindings (2);
|
||||||
/* Go through the PARM_DECLs for this function to see if any need
|
expand_function_start (fn, /*parms_have_cleanups=*/0);
|
||||||
cleanups. */
|
|
||||||
for (parm = DECL_ARGUMENTS (fn); parm; parm = TREE_CHAIN (parm))
|
|
||||||
if (TREE_TYPE (parm) != error_mark_node
|
|
||||||
&& TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (parm)))
|
|
||||||
{
|
|
||||||
expand_function_start (fn, /*parms_have_cleanups=*/1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!parm)
|
|
||||||
expand_function_start (fn, /*parms_have_cleanups=*/0);
|
|
||||||
/* If this function is `main'. */
|
/* If this function is `main'. */
|
||||||
if (DECL_MAIN_P (fn))
|
if (DECL_MAIN_P (fn))
|
||||||
expand_main_function ();
|
expand_main_function ();
|
||||||
/* Create a binding contour which can be used to catch
|
|
||||||
cleanup-generated temporaries. */
|
|
||||||
expand_start_bindings (2);
|
|
||||||
|
|
||||||
/* Give our named return value the same RTL as our RESULT_DECL. */
|
/* Give our named return value the same RTL as our RESULT_DECL. */
|
||||||
if (current_function_return_value)
|
if (current_function_return_value)
|
||||||
|
@ -2647,7 +2626,6 @@ static void
|
||||||
genrtl_finish_function (fn)
|
genrtl_finish_function (fn)
|
||||||
tree fn;
|
tree fn;
|
||||||
{
|
{
|
||||||
tree no_return_label = NULL_TREE;
|
|
||||||
tree t;
|
tree t;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -2676,59 +2654,10 @@ genrtl_finish_function (fn)
|
||||||
/* Clean house because we will need to reorder insns here. */
|
/* Clean house because we will need to reorder insns here. */
|
||||||
do_pending_stack_adjust ();
|
do_pending_stack_adjust ();
|
||||||
|
|
||||||
if (!dtor_label && !DECL_CONSTRUCTOR_P (fn)
|
/* If we have a named return value, we need to force a return so that
|
||||||
&& return_label != NULL_RTX
|
the return register is USEd. */
|
||||||
&& ! DECL_NAME (DECL_RESULT (current_function_decl)))
|
if (DECL_NAME (DECL_RESULT (fn)))
|
||||||
no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
|
|
||||||
|
|
||||||
/* If this function is supposed to return a value, ensure that
|
|
||||||
we do not fall into the cleanups by mistake. The end of our
|
|
||||||
function will look like this:
|
|
||||||
|
|
||||||
user code (may have return stmt somewhere)
|
|
||||||
goto no_return_label
|
|
||||||
cleanup_label:
|
|
||||||
cleanups
|
|
||||||
goto return_label
|
|
||||||
no_return_label:
|
|
||||||
NOTE_INSN_FUNCTION_END
|
|
||||||
return_label:
|
|
||||||
things for return
|
|
||||||
|
|
||||||
If the user omits a return stmt in the USER CODE section, we
|
|
||||||
will have a control path which reaches NOTE_INSN_FUNCTION_END.
|
|
||||||
Otherwise, we won't. */
|
|
||||||
if (no_return_label)
|
|
||||||
{
|
|
||||||
DECL_CONTEXT (no_return_label) = fn;
|
|
||||||
DECL_INITIAL (no_return_label) = error_mark_node;
|
|
||||||
DECL_SOURCE_FILE (no_return_label) = input_filename;
|
|
||||||
DECL_SOURCE_LINE (no_return_label) = lineno;
|
|
||||||
expand_goto (no_return_label);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cleanup_label)
|
|
||||||
{
|
|
||||||
/* Remove the binding contour which is used to catch
|
|
||||||
cleanup-generated temporaries. */
|
|
||||||
expand_end_bindings (0, 0, 0);
|
|
||||||
poplevel (0, 0, 0);
|
|
||||||
|
|
||||||
/* Emit label at beginning of cleanup code for parameters. */
|
|
||||||
emit_label (cleanup_label);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finish building code that will trigger warnings if users forget
|
|
||||||
to make their functions return values. */
|
|
||||||
if (return_label)
|
|
||||||
emit_jump (return_label);
|
emit_jump (return_label);
|
||||||
if (no_return_label)
|
|
||||||
{
|
|
||||||
/* We don't need to call `expand_*_return' here because we don't
|
|
||||||
need any cleanups here--this path of code is only for error
|
|
||||||
checking purposes. */
|
|
||||||
expand_label (no_return_label);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We hard-wired immediate_size_expand to zero in start_function.
|
/* We hard-wired immediate_size_expand to zero in start_function.
|
||||||
Expand_function_end will decrement this variable. So, we set the
|
Expand_function_end will decrement this variable. So, we set the
|
||||||
|
|
|
@ -6585,7 +6585,7 @@ check_return_expr (retval)
|
||||||
warning ("function declared `noreturn' has a `return' statement");
|
warning ("function declared `noreturn' has a `return' statement");
|
||||||
|
|
||||||
/* Check for various simple errors. */
|
/* Check for various simple errors. */
|
||||||
if (dtor_label)
|
if (DECL_DESTRUCTOR_P (current_function_decl))
|
||||||
{
|
{
|
||||||
if (retval)
|
if (retval)
|
||||||
error ("returning a value from a destructor");
|
error ("returning a value from a destructor");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue