Commit b2dd096b by Mark Mitchell Committed by Mark Mitchell

Makefile.in (calls.o): Depend on except.h.

	* Makefile.in (calls.o): Depend on except.h.
	* calls.c: Include except.h.
	(emit_call_1): Call note_eh_region_may_contain_throw if
	appropriate.
	* except.c (eh_region): Add may_contain_throw.
	(expand_eh_region_end_cleanup): Do not include handler code when
	it cannot be reached.
	(note_eh_region_may_contain_throw): New function.
	* except.h (note_eh_region_may_contain_throw): New function.

	* call.c (build_over_call): Use build_cxx_call.
	(build_cxx_call): New method, split out of build_over_call.
	* cp-tree.h (language_function): Add can_throw.
	(build_cxx_call): Declare it.
	* decl.c (finish_function): If a function does not contain any
	calls to functions that can throw an exception, indicate that
	fact.
	* decl2.c (mark_used): Do not defer the instantiation of
	functions, if the current function does not throw.
	* optimize.c (maybe_clone_body): Copy TREE_NOTHROW to the clones.
	* pt.c (instantiate_decl): Make sure import_export_decl is called
	before emitting things.
	* rtti.c (throw_bad_cast): Use build_cxx_call.
	(build_dynamic_cast_1): Likewise.
	* typeck.c (build_function_call): Likewise.

	* g++.dg/template/recurse.C: Adjust location of error messages.

From-SVN: r65929
parent f71c1255
2003-04-21 Mark Mitchell <mark@codesourcery.com> 2003-04-21 Mark Mitchell <mark@codesourcery.com>
* Makefile.in (calls.o): Depend on except.h.
* calls.c: Include except.h.
(emit_call_1): Call note_eh_region_may_contain_throw if
appropriate.
* except.c (eh_region): Add may_contain_throw.
(expand_eh_region_end_cleanup): Do not include handler code when
it cannot be reached.
(note_eh_region_may_contain_throw): New function.
* except.h (note_eh_region_may_contain_throw): New function.
2003-04-21 Mark Mitchell <mark@codesourcery.com>
* config/i386/winnt.c (i386_pe_mark_dllimport): Revert previous * config/i386/winnt.c (i386_pe_mark_dllimport): Revert previous
changes. changes.
......
...@@ -1532,7 +1532,7 @@ builtins.o : builtins.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(T ...@@ -1532,7 +1532,7 @@ builtins.o : builtins.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(T
except.h $(TM_P_H) $(PREDICT_H) libfuncs.h real.h langhooks.h except.h $(TM_P_H) $(PREDICT_H) libfuncs.h real.h langhooks.h
calls.o : calls.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) flags.h \ calls.o : calls.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) flags.h \
$(EXPR_H) langhooks.h $(TARGET_H) \ $(EXPR_H) langhooks.h $(TARGET_H) \
libfuncs.h $(REGS_H) toplev.h output.h function.h $(TIMEVAR_H) $(TM_P_H) cgraph.h libfuncs.h $(REGS_H) toplev.h output.h function.h $(TIMEVAR_H) $(TM_P_H) cgraph.h except.h
expmed.o : expmed.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ expmed.o : expmed.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
flags.h insn-config.h $(EXPR_H) $(OPTABS_H) $(RECOG_H) real.h \ flags.h insn-config.h $(EXPR_H) $(OPTABS_H) $(RECOG_H) real.h \
toplev.h $(TM_P_H) langhooks.h toplev.h $(TM_P_H) langhooks.h
......
...@@ -38,6 +38,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -38,6 +38,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "langhooks.h" #include "langhooks.h"
#include "target.h" #include "target.h"
#include "cgraph.h" #include "cgraph.h"
#include "except.h"
/* Decide whether a function's arguments should be processed /* Decide whether a function's arguments should be processed
from first to last or from last to first. from first to last or from last to first.
...@@ -588,6 +589,8 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size, ...@@ -588,6 +589,8 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
if (ecf_flags & ECF_NOTHROW) if (ecf_flags & ECF_NOTHROW)
REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, const0_rtx, REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, const0_rtx,
REG_NOTES (call_insn)); REG_NOTES (call_insn));
else
note_eh_region_may_contain_throw ();
if (ecf_flags & ECF_NORETURN) if (ecf_flags & ECF_NORETURN)
REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_NORETURN, const0_rtx, REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_NORETURN, const0_rtx,
......
2003-04-21 Mark Mitchell <mark@codesourcery.com>
* call.c (build_over_call): Use build_cxx_call.
(build_cxx_call): New method, split out of build_over_call.
* cp-tree.h (language_function): Add can_throw.
(build_cxx_call): Declare it.
* decl.c (finish_function): If a function does not contain any
calls to functions that can throw an exception, indicate that
fact.
* decl2.c (mark_used): Do not defer the instantiation of
functions, if the current function does not throw.
* optimize.c (maybe_clone_body): Copy TREE_NOTHROW to the clones.
* pt.c (instantiate_decl): Make sure import_export_decl is called
before emitting things.
* rtti.c (throw_bad_cast): Use build_cxx_call.
(build_dynamic_cast_1): Likewise.
* typeck.c (build_function_call): Likewise.
2003-04-21 Nathan Sidwell <nathan@codesourcery.com> 2003-04-21 Nathan Sidwell <nathan@codesourcery.com>
PR c++/9881 PR c++/9881
......
...@@ -4707,10 +4707,22 @@ build_over_call (struct z_candidate *cand, int flags) ...@@ -4707,10 +4707,22 @@ build_over_call (struct z_candidate *cand, int flags)
else else
fn = build_addr_func (fn); fn = build_addr_func (fn);
return build_cxx_call (fn, args, converted_args);
}
/* Build and return a call to FN, using the the CONVERTED_ARGS. ARGS
gives the original form of the arguments. This function performs
no overload resolution, conversion, or other high-level
operations. */
tree
build_cxx_call(tree fn, tree args, tree converted_args)
{
tree fndecl;
/* Recognize certain built-in functions so we can make tree-codes /* Recognize certain built-in functions so we can make tree-codes
other than CALL_EXPR. We do this when it enables fold-const.c other than CALL_EXPR. We do this when it enables fold-const.c
to do something useful. */ to do something useful. */
if (TREE_CODE (fn) == ADDR_EXPR if (TREE_CODE (fn) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL
&& DECL_BUILT_IN (TREE_OPERAND (fn, 0))) && DECL_BUILT_IN (TREE_OPERAND (fn, 0)))
...@@ -4721,14 +4733,24 @@ build_over_call (struct z_candidate *cand, int flags) ...@@ -4721,14 +4733,24 @@ build_over_call (struct z_candidate *cand, int flags)
return exp; return exp;
} }
/* Some built-in function calls will be evaluated at fn = build_call (fn, converted_args);
compile-time in fold (). */
fn = fold (build_call (fn, converted_args)); /* If this call might throw an exception, note that fact. */
fndecl = get_callee_fndecl (fn);
if ((!fndecl || !TREE_NOTHROW (fndecl)) && at_function_scope_p ())
cp_function_chain->can_throw = 1;
/* Some built-in function calls will be evaluated at compile-time in
fold (). */
fn = fold (fn);
if (VOID_TYPE_P (TREE_TYPE (fn))) if (VOID_TYPE_P (TREE_TYPE (fn)))
return fn; return fn;
fn = require_complete_type (fn); fn = require_complete_type (fn);
if (fn == error_mark_node) if (fn == error_mark_node)
return error_mark_node; return error_mark_node;
if (IS_AGGR_TYPE (TREE_TYPE (fn))) if (IS_AGGR_TYPE (TREE_TYPE (fn)))
fn = build_cplus_new (TREE_TYPE (fn), fn); fn = build_cplus_new (TREE_TYPE (fn), fn);
return convert_from_reference (fn); return convert_from_reference (fn);
......
...@@ -794,6 +794,9 @@ struct language_function GTY(()) ...@@ -794,6 +794,9 @@ struct language_function GTY(())
int in_base_initializer; int in_base_initializer;
int x_expanding_p; int x_expanding_p;
/* True if this function can throw an exception. */
bool can_throw : 1;
struct named_label_use_list *x_named_label_uses; struct named_label_use_list *x_named_label_uses;
struct named_label_list *x_named_labels; struct named_label_list *x_named_labels;
struct cp_binding_level *bindings; struct cp_binding_level *bindings;
...@@ -3522,6 +3525,7 @@ extern tree make_temporary_var_for_ref_to_temp (tree, tree); ...@@ -3522,6 +3525,7 @@ extern tree make_temporary_var_for_ref_to_temp (tree, tree);
extern tree strip_top_quals (tree); extern tree strip_top_quals (tree);
extern tree perform_implicit_conversion (tree, tree); extern tree perform_implicit_conversion (tree, tree);
extern tree in_charge_arg_for_name (tree); extern tree in_charge_arg_for_name (tree);
extern tree build_cxx_call (tree, tree, tree);
/* in class.c */ /* in class.c */
extern tree build_base_path (enum tree_code, tree, tree, int); extern tree build_base_path (enum tree_code, tree, tree, int);
......
...@@ -13961,6 +13961,12 @@ finish_function (int flags) ...@@ -13961,6 +13961,12 @@ finish_function (int flags)
/* If we're saving up tree structure, tie off the function now. */ /* If we're saving up tree structure, tie off the function now. */
finish_stmt_tree (&DECL_SAVED_TREE (fndecl)); finish_stmt_tree (&DECL_SAVED_TREE (fndecl));
/* If this function can't throw any exceptions, remember that. */
if (!processing_template_decl
&& !cp_function_chain->can_throw
&& !flag_non_call_exceptions)
TREE_NOTHROW (fndecl) = 1;
/* This must come after expand_function_end because cleanups might /* This must come after expand_function_end because cleanups might
have declarations (from inline functions) that need to go into have declarations (from inline functions) that need to go into
this function's blocks. */ this function's blocks. */
......
...@@ -4581,7 +4581,33 @@ mark_used (tree decl) ...@@ -4581,7 +4581,33 @@ mark_used (tree decl)
&& DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl) && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)
&& (!DECL_EXPLICIT_INSTANTIATION (decl) && (!DECL_EXPLICIT_INSTANTIATION (decl)
|| (TREE_CODE (decl) == FUNCTION_DECL && DECL_INLINE (decl)))) || (TREE_CODE (decl) == FUNCTION_DECL && DECL_INLINE (decl))))
instantiate_decl (decl, /*defer_ok=*/1); {
bool defer;
/* Normally, we put off instantiating functions in order to
improve compile times. Maintaining a stack of active
functions is expensive, and the inliner knows to
instantiate any functions it might need.
However, if instantiating this function might help us mark
the current function TREE_NOTHROW, we go ahead and
instantiate it now. */
defer = (!flag_exceptions
|| TREE_CODE (decl) != FUNCTION_DECL
/* If the called function can't throw, we don't need to
generate its body to find that out. */
|| TREE_NOTHROW (decl)
|| !cfun
/* If we already know the current function can't throw,
then we don't need to work hard to prove it. */
|| TREE_NOTHROW (current_function_decl)
/* If we already know that the current function *can*
throw, there's no point in gathering more
information. */
|| cp_function_chain->can_throw);
instantiate_decl (decl, defer);
}
} }
/* Called when a class-head is encountered. TAG_KIND is the class-key /* Called when a class-head is encountered. TAG_KIND is the class-key
......
...@@ -259,6 +259,9 @@ maybe_clone_body (tree fn) ...@@ -259,6 +259,9 @@ maybe_clone_body (tree fn)
/* Clean up. */ /* Clean up. */
splay_tree_delete (decl_map); splay_tree_delete (decl_map);
/* The clone can throw iff the original function can throw. */
cp_function_chain->can_throw = !TREE_NOTHROW (fn);
/* Now, expand this function into RTL, if appropriate. */ /* Now, expand this function into RTL, if appropriate. */
finish_function (0); finish_function (0);
BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn); BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn);
......
...@@ -10948,13 +10948,8 @@ instantiate_decl (d, defer_ok) ...@@ -10948,13 +10948,8 @@ instantiate_decl (d, defer_ok)
SET_DECL_RTL (d, NULL_RTX); SET_DECL_RTL (d, NULL_RTX);
DECL_IN_AGGR_P (d) = 0; DECL_IN_AGGR_P (d) = 0;
if (DECL_INTERFACE_KNOWN (d)) import_export_decl (d);
DECL_EXTERNAL (d) = ! DECL_NOT_REALLY_EXTERN (d); DECL_EXTERNAL (d) = ! DECL_NOT_REALLY_EXTERN (d);
else
{
DECL_EXTERNAL (d) = 1;
DECL_NOT_REALLY_EXTERN (d) = 1;
}
cp_finish_decl (d, cp_finish_decl (d,
(!DECL_INITIALIZED_IN_CLASS_P (d) (!DECL_INITIALIZED_IN_CLASS_P (d)
? DECL_INITIAL (d) : NULL_TREE), ? DECL_INITIAL (d) : NULL_TREE),
...@@ -11007,7 +11002,9 @@ instantiate_decl (d, defer_ok) ...@@ -11007,7 +11002,9 @@ instantiate_decl (d, defer_ok)
local_specializations = saved_local_specializations; local_specializations = saved_local_specializations;
/* Finish the function. */ /* Finish the function. */
expand_body (finish_function (0)); d = finish_function (0);
import_export_decl (d);
expand_body (d);
} }
/* We're not deferring instantiation any more. */ /* We're not deferring instantiation any more. */
......
...@@ -177,7 +177,7 @@ throw_bad_cast (void) ...@@ -177,7 +177,7 @@ throw_bad_cast (void)
fn = push_throw_library_fn (fn, build_function_type (ptr_type_node, fn = push_throw_library_fn (fn, build_function_type (ptr_type_node,
void_list_node)); void_list_node));
return build_call (fn, NULL_TREE); return build_cxx_call (fn, NULL_TREE, NULL_TREE);
} }
/* Return an expression for "__cxa_bad_typeid()". The expression /* Return an expression for "__cxa_bad_typeid()". The expression
...@@ -660,7 +660,7 @@ build_dynamic_cast_1 (tree type, tree expr) ...@@ -660,7 +660,7 @@ build_dynamic_cast_1 (tree type, tree expr)
pop_nested_namespace (ns); pop_nested_namespace (ns);
dynamic_cast_node = dcast_fn; dynamic_cast_node = dcast_fn;
} }
result = build_call (dcast_fn, elems); result = build_cxx_call (dcast_fn, elems, elems);
if (tc == REFERENCE_TYPE) if (tc == REFERENCE_TYPE)
{ {
......
...@@ -2660,7 +2660,6 @@ build_function_call (function, params) ...@@ -2660,7 +2660,6 @@ build_function_call (function, params)
tree function, params; tree function, params;
{ {
register tree fntype, fndecl; register tree fntype, fndecl;
register tree value_type;
register tree coerced_params; register tree coerced_params;
tree result; tree result;
tree name = NULL_TREE, assembler_name = NULL_TREE; tree name = NULL_TREE, assembler_name = NULL_TREE;
...@@ -2755,17 +2754,7 @@ build_function_call (function, params) ...@@ -2755,17 +2754,7 @@ build_function_call (function, params)
return result; return result;
} }
/* Some built-in function calls will be evaluated at return build_cxx_call (function, params, coerced_params);
compile-time in fold (). */
result = fold (build_call (function, coerced_params));
value_type = TREE_TYPE (result);
if (TREE_CODE (value_type) == VOID_TYPE)
return result;
result = require_complete_type (result);
if (IS_AGGR_TYPE (value_type))
result = build_cplus_new (value_type, result);
return convert_from_reference (result);
} }
/* Convert the actual parameter expressions in the list VALUES /* Convert the actual parameter expressions in the list VALUES
......
...@@ -209,6 +209,9 @@ struct eh_region GTY(()) ...@@ -209,6 +209,9 @@ struct eh_region GTY(())
/* The RESX insn for handing off control to the next outermost handler, /* The RESX insn for handing off control to the next outermost handler,
if appropriate. */ if appropriate. */
rtx resume; rtx resume;
/* True if something in this region may throw. */
unsigned may_contain_throw : 1;
}; };
struct call_site_record GTY(()) struct call_site_record GTY(())
...@@ -561,33 +564,38 @@ expand_eh_region_end_cleanup (handler) ...@@ -561,33 +564,38 @@ expand_eh_region_end_cleanup (handler)
emit_label (region->label); emit_label (region->label);
/* Give the language a chance to specify an action to be taken if an if (flag_non_call_exceptions
exception is thrown that would propagate out of the HANDLER. */ || flag_forced_unwind_exceptions
protect_cleanup_actions || region->may_contain_throw)
= (lang_protect_cleanup_actions {
? (*lang_protect_cleanup_actions) () /* Give the language a chance to specify an action to be taken if an
: NULL_TREE); exception is thrown that would propagate out of the HANDLER. */
protect_cleanup_actions
= (lang_protect_cleanup_actions
? (*lang_protect_cleanup_actions) ()
: NULL_TREE);
if (protect_cleanup_actions) if (protect_cleanup_actions)
expand_eh_region_start (); expand_eh_region_start ();
/* In case this cleanup involves an inline destructor with a try block in /* In case this cleanup involves an inline destructor with a try block in
it, we need to save the EH return data registers around it. */ it, we need to save the EH return data registers around it. */
data_save[0] = gen_reg_rtx (ptr_mode); data_save[0] = gen_reg_rtx (ptr_mode);
emit_move_insn (data_save[0], get_exception_pointer (cfun)); emit_move_insn (data_save[0], get_exception_pointer (cfun));
data_save[1] = gen_reg_rtx (word_mode); data_save[1] = gen_reg_rtx (word_mode);
emit_move_insn (data_save[1], get_exception_filter (cfun)); emit_move_insn (data_save[1], get_exception_filter (cfun));
expand_expr (handler, const0_rtx, VOIDmode, 0); expand_expr (handler, const0_rtx, VOIDmode, 0);
emit_move_insn (cfun->eh->exc_ptr, data_save[0]); emit_move_insn (cfun->eh->exc_ptr, data_save[0]);
emit_move_insn (cfun->eh->filter, data_save[1]); emit_move_insn (cfun->eh->filter, data_save[1]);
if (protect_cleanup_actions) if (protect_cleanup_actions)
expand_eh_region_end_must_not_throw (protect_cleanup_actions); expand_eh_region_end_must_not_throw (protect_cleanup_actions);
/* We need any stack adjustment complete before the around_label. */ /* We need any stack adjustment complete before the around_label. */
do_pending_stack_adjust (); do_pending_stack_adjust ();
}
/* We delay the generation of the _Unwind_Resume until we generate /* We delay the generation of the _Unwind_Resume until we generate
landing pads. We emit a marker here so as to get good control landing pads. We emit a marker here so as to get good control
...@@ -823,6 +831,22 @@ expand_eh_region_end_fixup (handler) ...@@ -823,6 +831,22 @@ expand_eh_region_end_fixup (handler)
fixup->u.fixup.cleanup_exp = handler; fixup->u.fixup.cleanup_exp = handler;
} }
/* Note that the current EH region (if any) may contain a throw, or a
call to a function which itself may contain a throw. */
void
note_eh_region_may_contain_throw ()
{
struct eh_region *region;
region = cfun->eh->cur_region;
while (region && !region->may_contain_throw)
{
region->may_contain_throw = 1;
region = region->outer;
}
}
/* Return an rtl expression for a pointer to the exception object /* Return an rtl expression for a pointer to the exception object
within a handler. */ within a handler. */
......
...@@ -78,6 +78,10 @@ extern void expand_eh_region_end_throw PARAMS ((tree)); ...@@ -78,6 +78,10 @@ extern void expand_eh_region_end_throw PARAMS ((tree));
destroying an object twice. */ destroying an object twice. */
extern void expand_eh_region_end_fixup PARAMS ((tree)); extern void expand_eh_region_end_fixup PARAMS ((tree));
/* Note that the current EH region (if any) may contain a throw, or a
call to a function which itself may contain a throw. */
extern void note_eh_region_may_contain_throw PARAMS ((void));
/* Invokes CALLBACK for every exception handler label. Only used by old /* Invokes CALLBACK for every exception handler label. Only used by old
loop hackery; should not be used by new code. */ loop hackery; should not be used by new code. */
extern void for_each_eh_label PARAMS ((void (*) (rtx))); extern void for_each_eh_label PARAMS ((void (*) (rtx)));
......
2003-04-21 Mark Mitchell <mark@codesourcery.com>
* g++.dg/template/recurse.C: Adjust location of error messages.
2003-04-21 Nathan Sidwell <nathan@codesourcery.com> 2003-04-21 Nathan Sidwell <nathan@codesourcery.com>
PR c++/9881 PR c++/9881
......
...@@ -6,7 +6,7 @@ template <int I> struct F ...@@ -6,7 +6,7 @@ template <int I> struct F
int operator()() int operator()()
{ {
F<I+1> f; // { dg-error "" "" } F<I+1> f; // { dg-error "" "" }
return f()*I; return f()*I; // { dg-error "" "" }
} }
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment