/* Handle exceptional things in C++.
Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
+ Free Software Foundation, Inc.
Contributed by Michael Tiemann <tiemann@cygnus.com>
Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
initial re-implementation courtesy Tad Hunt.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "toplev.h"
#include "tree-inline.h"
#include "tree-iterator.h"
+#include "target.h"
+#include "gimple.h"
static void push_eh_cleanup (tree);
static tree prepare_eh_type (tree);
-static tree build_eh_type_type (tree);
static tree do_begin_catch (void);
static int dtor_nothrow (tree);
static tree do_end_catch (tree);
call_unexpected_node
= push_throw_library_fn (get_identifier ("__cxa_call_unexpected"), tmp);
- eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
- ? "__gxx_personality_sj0"
- : "__gxx_personality_v0");
-
- lang_eh_runtime_type = build_eh_type_type;
lang_protect_cleanup_actions = &cp_protect_cleanup_actions;
}
When the destruction of an object during stack unwinding exits
using an exception ... void terminate(); is called. */
- return build_call (terminate_node, NULL_TREE);
-}
+ return terminate_node;
+}
static tree
prepare_eh_type (tree type)
/* Peel off cv qualifiers. */
type = TYPE_MAIN_VARIANT (type);
+ /* Functions and arrays decay to pointers. */
+ type = type_decays_to (type);
+
return type;
}
/* Build the address of a typeinfo decl for use in the runtime
matching field of the exception model. */
-static tree
+tree
build_eh_type_type (tree type)
{
tree exp = eh_type_info (type);
tree
build_exc_ptr (void)
{
- return build0 (EXC_PTR_EXPR, ptr_type_node);
+ return build_call_n (built_in_decls [BUILT_IN_EH_POINTER],
+ 1, integer_zero_node);
+}
+
+/* Declare a function NAME, returning RETURN_TYPE, taking a single
+ parameter PARM_TYPE, with an empty exception specification.
+
+ Note that the C++ ABI document does not have a throw-specifier on
+ the routines declared below via this function. The declarations
+ are consistent with the actual implementations in libsupc++. */
+
+static tree
+declare_nothrow_library_fn (tree name, tree return_type, tree parm_type)
+{
+ tree tmp = tree_cons (NULL_TREE, parm_type, void_list_node);
+ return push_library_fn (name, build_function_type (return_type, tmp),
+ empty_except_spec);
+}
+
+/* Build up a call to __cxa_get_exception_ptr so that we can build a
+ copy constructor for the thrown object. */
+
+static tree
+do_get_exception_ptr (void)
+{
+ tree fn;
+
+ fn = get_identifier ("__cxa_get_exception_ptr");
+ if (!get_global_value_if_present (fn, &fn))
+ {
+ /* Declare void* __cxa_get_exception_ptr (void *) throw(). */
+ fn = declare_nothrow_library_fn (fn, ptr_type_node, ptr_type_node);
+ }
+
+ return cp_build_function_call (fn, tree_cons (NULL_TREE, build_exc_ptr (),
+ NULL_TREE),
+ tf_warning_or_error);
}
/* Build up a call to __cxa_begin_catch, to tell the runtime that the
fn = get_identifier ("__cxa_begin_catch");
if (!get_global_value_if_present (fn, &fn))
{
- /* Declare void* __cxa_begin_catch (void *). */
- tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
- fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp));
+ /* Declare void* __cxa_begin_catch (void *) throw(). */
+ fn = declare_nothrow_library_fn (fn, ptr_type_node, ptr_type_node);
}
- return build_function_call (fn, tree_cons (NULL_TREE, build_exc_ptr (),
- NULL_TREE));
+ return cp_build_function_call (fn, tree_cons (NULL_TREE, build_exc_ptr (),
+ NULL_TREE),
+ tf_warning_or_error);
}
/* Returns nonzero if cleaning up an exception of type TYPE (which can be
static int
dtor_nothrow (tree type)
{
- if (type == NULL_TREE)
+ if (type == NULL_TREE || type == error_mark_node)
return 0;
- if (! TYPE_HAS_DESTRUCTOR (type))
+ if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
return 1;
+ if (CLASSTYPE_LAZY_DESTRUCTOR (type))
+ lazily_declare_fn (sfk_destructor, type);
+
return TREE_NOTHROW (CLASSTYPE_DESTRUCTORS (type));
}
TREE_NOTHROW (fn) = 0;
}
- cleanup = build_function_call (fn, NULL_TREE);
+ cleanup = cp_build_function_call (fn, NULL_TREE, tf_warning_or_error);
TREE_NOTHROW (cleanup) = dtor_nothrow (type);
return cleanup;
&& TYPE_FOR_JAVA (TREE_TYPE (decl)))
{
/* Can't throw a reference. */
- error ("type `%T' is disallowed in Java `throw' or `catch'",
- decl);
+ error ("type %qT is disallowed in Java %<throw%> or %<catch%>",
+ decl);
}
if (r)
if (jthrow_node == NULL_TREE)
fatal_error
- ("call to Java `catch' or `throw' with `jthrowable' undefined");
+ ("call to Java %<catch%> or %<throw%> with %<jthrowable%> undefined");
jthrow_node = TREE_TYPE (TREE_TYPE (jthrow_node));
if (! DERIVED_FROM_P (jthrow_node, TREE_TYPE (decl)))
{
/* Thrown object must be a Throwable. */
- error ("type `%T' is not derived from `java::lang::Throwable'",
- TREE_TYPE (decl));
+ error ("type %qT is not derived from %<java::lang::Throwable%>",
+ TREE_TYPE (decl));
}
}
}
/* Select the personality routine to be used for exception handling,
or issue an error if we need two different ones in the same
translation unit.
- ??? At present eh_personality_libfunc is set to
+ ??? At present eh_personality_decl is set to
__gxx_personality_(sj|v)0 in init_exception_processing - should it
be done here instead? */
void
case lang_java:
state = chose_java;
- eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
- ? "__gcj_personality_sj0"
- : "__gcj_personality_v0");
+ terminate_node = built_in_decls [BUILT_IN_ABORT];
+ pragma_java_exceptions = true;
break;
default:
- abort ();
+ gcc_unreachable ();
}
return;
/* Initialize the catch parameter DECL. */
-static void
+static void
initialize_handler_parm (tree decl, tree exp)
{
tree init;
/* Make sure we mark the catch param as used, otherwise we'll get a
warning about an unused ((anonymous)). */
TREE_USED (decl) = 1;
+ DECL_READ_P (decl) = 1;
/* Figure out the type that the initializer is. Pointers are returned
- adjusted by value from __cxa_begin_catch. Others are returned by
+ adjusted by value from __cxa_begin_catch. Others are returned by
reference. */
init_type = TREE_TYPE (decl);
- if (! TYPE_PTR_P (init_type)
- && TREE_CODE (init_type) != REFERENCE_TYPE)
+ if (!POINTER_TYPE_P (init_type))
init_type = build_reference_type (init_type);
choose_personality_routine (decl_is_java_type (init_type, 0)
pointer catch parm with the address of the temporary. */
if (TREE_CODE (init_type) == REFERENCE_TYPE
&& TYPE_PTR_P (TREE_TYPE (init_type)))
- exp = build_unary_op (ADDR_EXPR, exp, 1);
+ exp = cp_build_unary_op (ADDR_EXPR, exp, 1, tf_warning_or_error);
exp = ocp_convert (init_type, exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
See also expand_default_init. */
init = ocp_convert (TREE_TYPE (decl), init,
CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
+ /* Force cleanups now to avoid nesting problems with the
+ MUST_NOT_THROW_EXPR. */
+ init = fold_build_cleanup_point_expr (TREE_TYPE (init), init);
init = build1 (MUST_NOT_THROW_EXPR, TREE_TYPE (init), init);
}
- /* Let `cp_finish_decl' know that this initializer is ok. */
- DECL_INITIAL (decl) = error_mark_node;
decl = pushdecl (decl);
- start_decl_1 (decl);
- cp_finish_decl (decl, init, NULL_TREE,
+ start_decl_1 (decl, true);
+ cp_finish_decl (decl, init, /*init_const_expr_p=*/false, NULL_TREE,
LOOKUP_ONLYCONVERTING|DIRECT_BIND);
}
tree
expand_start_catch_block (tree decl)
{
- tree exp = NULL_TREE;
- tree type;
- bool is_java;
+ tree exp;
+ tree type, init;
if (! doing_eh (1))
return NULL_TREE;
/* Make sure this declaration is reasonable. */
if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE))
- decl = NULL_TREE;
+ decl = error_mark_node;
if (decl)
type = prepare_eh_type (TREE_TYPE (decl));
else
type = NULL_TREE;
- is_java = false;
- if (decl)
+ if (decl && decl_is_java_type (type, 1))
{
- tree init;
-
- if (decl_is_java_type (type, 1))
- {
- /* Java only passes object via pointer and doesn't require
- adjusting. The java object is immediately before the
- generic exception header. */
- init = build_exc_ptr ();
- init = build1 (NOP_EXPR, build_pointer_type (type), init);
- init = build2 (MINUS_EXPR, TREE_TYPE (init), init,
- TYPE_SIZE_UNIT (TREE_TYPE (init)));
- init = build_indirect_ref (init, NULL);
- is_java = true;
- }
- else
- {
- /* C++ requires that we call __cxa_begin_catch to get the
- pointer to the actual object. */
- init = do_begin_catch ();
- }
-
- exp = create_temporary_var (ptr_type_node);
- DECL_REGISTER (exp) = 1;
- cp_finish_decl (exp, init, NULL_TREE, LOOKUP_ONLYCONVERTING);
- finish_expr_stmt (build_modify_expr (exp, INIT_EXPR, init));
+ /* Java only passes object via pointer and doesn't require
+ adjusting. The java object is immediately before the
+ generic exception header. */
+ exp = build_exc_ptr ();
+ exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
+ exp = build2 (POINTER_PLUS_EXPR, TREE_TYPE (exp), exp,
+ fold_build1_loc (input_location,
+ NEGATE_EXPR, sizetype,
+ TYPE_SIZE_UNIT (TREE_TYPE (exp))));
+ exp = cp_build_indirect_ref (exp, RO_NULL, tf_warning_or_error);
+ initialize_handler_parm (decl, exp);
+ return type;
}
- else
- finish_expr_stmt (do_begin_catch ());
- /* C++ requires that we call __cxa_end_catch at the end of
- processing the exception. */
- if (! is_java)
- push_eh_cleanup (type);
+ /* Call __cxa_end_catch at the end of processing the exception. */
+ push_eh_cleanup (type);
- if (decl)
- initialize_handler_parm (decl, exp);
+ init = do_begin_catch ();
+
+ /* If there's no decl at all, then all we need to do is make sure
+ to tell the runtime that we've begun handling the exception. */
+ if (decl == NULL || decl == error_mark_node || init == error_mark_node)
+ finish_expr_stmt (init);
+
+ /* If the C++ object needs constructing, we need to do that before
+ calling __cxa_begin_catch, so that std::uncaught_exception gets
+ the right value during the copy constructor. */
+ else if (flag_use_cxa_get_exception_ptr
+ && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
+ {
+ exp = do_get_exception_ptr ();
+ initialize_handler_parm (decl, exp);
+ finish_expr_stmt (init);
+ }
+
+ /* Otherwise the type uses a bitwise copy, and we don't have to worry
+ about the value of std::uncaught_exception and therefore can do the
+ copy with the return value of __cxa_end_catch instead. */
+ else
+ {
+ tree init_type = type;
+
+ /* Pointers are passed by values, everything else by reference. */
+ if (!TYPE_PTR_P (type))
+ init_type = build_pointer_type (type);
+ if (init_type != TREE_TYPE (init))
+ init = build1 (NOP_EXPR, init_type, init);
+ exp = create_temporary_var (init_type);
+ DECL_REGISTER (exp) = 1;
+ cp_finish_decl (exp, init, /*init_const_expr=*/false,
+ NULL_TREE, LOOKUP_ONLYCONVERTING);
+ initialize_handler_parm (decl, exp);
+ }
return type;
}
tree
begin_eh_spec_block (void)
{
- tree r = build_stmt (EH_SPEC_BLOCK, NULL_TREE, NULL_TREE);
+ tree r;
+ /* A noexcept specification (or throw() with -fnothrow-opt) is a
+ MUST_NOT_THROW_EXPR. */
+ if (TYPE_NOEXCEPT_P (TREE_TYPE (current_function_decl)))
+ {
+ r = build_stmt (input_location, MUST_NOT_THROW_EXPR, NULL_TREE);
+ TREE_SIDE_EFFECTS (r) = 1;
+ }
+ else
+ r = build_stmt (input_location, EH_SPEC_BLOCK, NULL_TREE, NULL_TREE);
add_stmt (r);
- EH_SPEC_STMTS (r) = push_stmt_list ();
+ TREE_OPERAND (r, 0) = push_stmt_list ();
return r;
}
{
tree raises;
- EH_SPEC_STMTS (eh_spec_block) = pop_stmt_list (EH_SPEC_STMTS (eh_spec_block));
+ TREE_OPERAND (eh_spec_block, 0)
+ = pop_stmt_list (TREE_OPERAND (eh_spec_block, 0));
+
+ if (TREE_CODE (eh_spec_block) == MUST_NOT_THROW_EXPR)
+ return;
/* Strip cv quals, etc, from the specification types. */
for (raises = NULL_TREE;
fn = get_identifier ("__cxa_allocate_exception");
if (!get_global_value_if_present (fn, &fn))
{
- /* Declare void *__cxa_allocate_exception(size_t). */
- tree tmp = tree_cons (NULL_TREE, size_type_node, void_list_node);
- fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp));
+ /* Declare void *__cxa_allocate_exception(size_t) throw(). */
+ fn = declare_nothrow_library_fn (fn, ptr_type_node, size_type_node);
}
-
- return build_function_call (fn, tree_cons (NULL_TREE, size_in_bytes (type),
- NULL_TREE));
+
+ return cp_build_function_call (fn,
+ tree_cons (NULL_TREE, size_in_bytes (type),
+ NULL_TREE),
+ tf_warning_or_error);
}
/* Call __cxa_free_exception from a cleanup. This is never invoked
fn = get_identifier ("__cxa_free_exception");
if (!get_global_value_if_present (fn, &fn))
{
- /* Declare void __cxa_free_exception (void *). */
- fn = push_void_library_fn (fn, tree_cons (NULL_TREE, ptr_type_node,
- void_list_node));
+ /* Declare void __cxa_free_exception (void *) throw(). */
+ fn = declare_nothrow_library_fn (fn, void_type_node, ptr_type_node);
}
- return build_function_call (fn, tree_cons (NULL_TREE, ptr, NULL_TREE));
+ return cp_build_function_call (fn, tree_cons (NULL_TREE, ptr, NULL_TREE),
+ tf_warning_or_error);
}
/* Wrap all cleanups for TARGET_EXPRs in MUST_NOT_THROW_EXPR.
static tree
wrap_cleanups_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
- void *data ATTRIBUTE_UNUSED)
+ void *data ATTRIBUTE_UNUSED)
{
tree exp = *tp;
tree cleanup;
if (processing_template_decl)
{
- current_function_returns_abnormally = 1;
+ if (cfun)
+ current_function_returns_abnormally = 1;
return build_min (THROW_EXPR, void_type_node, exp);
}
if (exp == null_node)
- warning ("throwing NULL, which has integral, not pointer type");
-
+ warning (0, "throwing NULL, which has integral, not pointer type");
+
if (exp != NULL_TREE)
{
if (!is_admissible_throw_operand (exp))
- return error_mark_node;
+ return error_mark_node;
}
if (! doing_eh (1))
}
else if (really_overloaded_fn (fn))
{
- error ("`%D' should never be overloaded", fn);
+ error ("%qD should never be overloaded", fn);
return error_mark_node;
}
fn = OVL_CURRENT (fn);
- exp = build_function_call (fn, tree_cons (NULL_TREE, exp, NULL_TREE));
+ exp = cp_build_function_call (fn, tree_cons (NULL_TREE, exp, NULL_TREE),
+ tf_warning_or_error);
}
else if (exp)
{
tree throw_type;
+ tree temp_type;
tree cleanup;
tree object, ptr;
tree tmp;
- tree temp_expr, allocate_expr;
- bool elided;
+ tree allocate_expr;
/* The CLEANUP_TYPE is the internal type of a destructor. */
if (!cleanup_type)
tmp = build_function_type (void_type_node, tmp);
cleanup_type = build_pointer_type (tmp);
}
-
+
fn = get_identifier ("__cxa_throw");
if (!get_global_value_if_present (fn, &fn))
{
tmp = build_function_type (void_type_node, tmp);
fn = push_throw_library_fn (fn, tmp);
}
-
- /* throw expression */
- /* First, decay it. */
- exp = decay_conversion (exp);
+
+ /* [except.throw]
+
+ A throw-expression initializes a temporary object, the type
+ of which is determined by removing any top-level
+ cv-qualifiers from the static type of the operand of throw
+ and adjusting the type from "array of T" or "function return
+ T" to "pointer to T" or "pointer to function returning T"
+ respectively. */
+ temp_type = is_bitfield_expr_with_lowered_type (exp);
+ if (!temp_type)
+ temp_type = type_decays_to (TREE_TYPE (exp));
/* OK, this is kind of wacky. The standard says that we call
terminate when the exception handling mechanism, after
matter, since it can't throw). */
/* Allocate the space for the exception. */
- allocate_expr = do_allocate_exception (TREE_TYPE (exp));
+ allocate_expr = do_allocate_exception (temp_type);
allocate_expr = get_target_expr (allocate_expr);
ptr = TARGET_EXPR_SLOT (allocate_expr);
- object = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (exp)), ptr);
- object = build_indirect_ref (object, NULL);
+ TARGET_EXPR_CLEANUP (allocate_expr) = do_free_exception (ptr);
+ CLEANUP_EH_ONLY (allocate_expr) = 1;
- elided = (TREE_CODE (exp) == TARGET_EXPR);
+ object = build_nop (build_pointer_type (temp_type), ptr);
+ object = cp_build_indirect_ref (object, RO_NULL, tf_warning_or_error);
/* And initialize the exception object. */
- exp = build_init (object, exp, LOOKUP_ONLYCONVERTING);
- if (exp == error_mark_node)
+ if (CLASS_TYPE_P (temp_type))
{
- error (" in thrown expression");
- return error_mark_node;
+ int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING;
+ VEC(tree,gc) *exp_vec;
+
+ /* Under C++0x [12.8/16 class.copy], a thrown lvalue is sometimes
+ treated as an rvalue for the purposes of overload resolution
+ to favor move constructors over copy constructors. */
+ if (/* Must be a local, automatic variable. */
+ TREE_CODE (exp) == VAR_DECL
+ && DECL_CONTEXT (exp) == current_function_decl
+ && ! TREE_STATIC (exp)
+ /* The variable must not have the `volatile' qualifier. */
+ && !(cp_type_quals (TREE_TYPE (exp)) & TYPE_QUAL_VOLATILE))
+ flags = flags | LOOKUP_PREFER_RVALUE;
+
+ /* Call the copy constructor. */
+ exp_vec = make_tree_vector_single (exp);
+ exp = (build_special_member_call
+ (object, complete_ctor_identifier, &exp_vec,
+ TREE_TYPE (object), flags, tf_warning_or_error));
+ release_tree_vector (exp_vec);
+ if (exp == error_mark_node)
+ {
+ error (" in thrown expression");
+ return error_mark_node;
+ }
}
-
- /* Pre-evaluate the thrown expression first, since if we allocated
- the space first we would have to deal with cleaning it up if
- evaluating this expression throws.
-
- The case where EXP the initializer is a call to a constructor or a
- function returning a class is a bit of a grey area in the
- standard; it's unclear whether or not it should be allowed to
- throw. We used to say no, as that allowed us to optimize this
- case without worrying about deallocating the exception object if
- it does. But that conflicted with expectations (PR 13944) and the
- EDG compiler; now we wrap the initialization in a TRY_CATCH_EXPR
- to call do_free_exception rather than in a MUST_NOT_THROW_EXPR,
- for this case only.
-
- Note that we don't check the return value from stabilize_init
- because it will only return false in cases where elided is true,
- and therefore we don't need to work around the failure to
- preevaluate. */
- temp_expr = NULL_TREE;
- stabilize_init (exp, &temp_expr);
-
- if (elided)
- exp = build2 (TRY_CATCH_EXPR, void_type_node, exp,
- do_free_exception (ptr));
else
- exp = build1 (MUST_NOT_THROW_EXPR, void_type_node, exp);
+ {
+ tmp = decay_conversion (exp);
+ if (tmp == error_mark_node)
+ return error_mark_node;
+ exp = build2 (INIT_EXPR, temp_type, object, tmp);
+ }
+
+ /* Mark any cleanups from the initialization as MUST_NOT_THROW, since
+ they are run after the exception object is initialized. */
+ cp_walk_tree_without_duplicates (&exp, wrap_cleanups_r, 0);
/* Prepend the allocation. */
exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp);
- if (temp_expr)
- {
- /* Prepend the calculation of the throw expression. Also, force
- any cleanups from the expression to be evaluated here so that
- we don't have to do them during unwinding. But first wrap
- them in MUST_NOT_THROW_EXPR, since they are run after the
- exception object is initialized. */
- walk_tree_without_duplicates (&temp_expr, wrap_cleanups_r, 0);
- exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), temp_expr, exp);
- exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp);
- }
+
+ /* Force all the cleanups to be evaluated here so that we don't have
+ to do them during unwinding. */
+ exp = build1 (CLEANUP_POINT_EXPR, void_type_node, exp);
throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object)));
- if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
+ if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (object)))
{
cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
complete_dtor_identifier, 0);
}
else
cleanup = build_int_cst (cleanup_type, 0);
-
+
tmp = tree_cons (NULL_TREE, cleanup, NULL_TREE);
tmp = tree_cons (NULL_TREE, throw_type, tmp);
tmp = tree_cons (NULL_TREE, ptr, tmp);
/* ??? Indicate that this function call throws throw_type. */
- tmp = build_function_call (fn, tmp);
+ tmp = cp_build_function_call (fn, tmp, tf_warning_or_error);
/* Tack on the initialization stuff. */
exp = build2 (COMPOUND_EXPR, TREE_TYPE (tmp), exp, tmp);
}
/* ??? Indicate that this function call allows exceptions of the type
- of the enclosing catch block (if known). */
- exp = build_function_call (fn, NULL_TREE);
+ of the enclosing catch block (if known). */
+ exp = cp_build_function_call (fn, NULL_TREE, tf_warning_or_error);
}
exp = build1 (THROW_EXPR, void_type_node, exp);
complete_ptr_ref_or_void_ptr_p (tree type, tree from)
{
int is_ptr;
-
+
/* Check complete. */
type = complete_type_or_else (type, from);
if (!type)
return 0;
-
+
/* Or a pointer or ref to one, or cv void *. */
is_ptr = TREE_CODE (type) == POINTER_TYPE;
if (is_ptr || TREE_CODE (type) == REFERENCE_TYPE)
{
tree core = TREE_TYPE (type);
-
+
if (is_ptr && VOID_TYPE_P (core))
- /* OK */;
+ /* OK */;
else if (!complete_type_or_else (core, from))
- return 0;
+ return 0;
}
return 1;
}
tree type = TREE_TYPE (expr);
/* 15.1/4 [...] The type of the throw-expression shall not be an
- incomplete type, or a pointer or a reference to an incomplete
- type, other than void*, const void*, volatile void*, or
- const volatile void*. Except for these restriction and the
- restrictions on type matching mentioned in 15.3, the operand
- of throw is treated exactly as a function argument in a call
- (5.2.2) or the operand of a return statement. */
+ incomplete type, or a pointer or a reference to an incomplete
+ type, other than void*, const void*, volatile void*, or
+ const volatile void*. Except for these restriction and the
+ restrictions on type matching mentioned in 15.3, the operand
+ of throw is treated exactly as a function argument in a call
+ (5.2.2) or the operand of a return statement. */
if (!complete_ptr_ref_or_void_ptr_p (type, expr))
return false;
/* 10.4/3 An abstract class shall not be used as a parameter type,
- as a function return type or as type of an explicit
- conversion. */
+ as a function return type or as type of an explicit
+ conversion. */
else if (CLASS_TYPE_P (type) && CLASSTYPE_PURE_VIRTUALS (type))
{
- error ("expression '%E' of abstract class type '%T' cannot be used in throw-expression", expr, type);
+ error ("expression %qE of abstract class type %qT cannot "
+ "be used in throw-expression", expr, type);
return false;
}
#include "cfns.h"
int
-nothrow_libfn_p (tree fn)
+nothrow_libfn_p (const_tree fn)
{
tree id;
tree handler = tsi_stmt (i);
if (TREE_TYPE (handler) && can_convert_eh (type, TREE_TYPE (handler)))
{
- warning ("%Hexception of type `%T' will be caught",
- EXPR_LOCUS (handler), TREE_TYPE (handler));
- warning ("%H by earlier handler for `%T'",
- EXPR_LOCUS (master), type);
+ warning_at (EXPR_LOCATION (handler), 0,
+ "exception of type %qT will be caught",
+ TREE_TYPE (handler));
+ warning_at (EXPR_LOCATION (master), 0,
+ " by earlier handler for %qT", type);
break;
- }
+ }
}
}
if (!tsi_end_p (i))
while (1)
{
- tree handler = tsi_stmt (i);
+ tree handler = tsi_stmt (i);
tsi_next (&i);
/* No more handlers; nothing to shadow. */
if (tsi_end_p (i))
break;
if (TREE_TYPE (handler) == NULL_TREE)
- pedwarn ("%H`...' handler must be the last handler for"
- " its try block", EXPR_LOCUS (handler));
+ permerror (EXPR_LOCATION (handler), "%<...%>"
+ " handler must be the last handler for its try block");
else
check_handlers_1 (handler, i);
}