/* Handle exceptional things in C++.
- Copyright (C) 1989-2015 Free Software Foundation, Inc.
+ Copyright (C) 1989-2019 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.
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "tm.h"
-#include "hash-set.h"
-#include "machmode.h"
-#include "vec.h"
-#include "double-int.h"
-#include "input.h"
-#include "alias.h"
-#include "symtab.h"
-#include "wide-int.h"
-#include "inchash.h"
-#include "tree.h"
+#include "cp-tree.h"
#include "stringpool.h"
#include "trans-mem.h"
#include "attribs.h"
-#include "cp-tree.h"
-#include "flags.h"
-#include "tree-inline.h"
#include "tree-iterator.h"
-#include "target.h"
static void push_eh_cleanup (tree);
static tree prepare_eh_type (tree);
static tree do_begin_catch (void);
static int dtor_nothrow (tree);
static tree do_end_catch (tree);
-static bool decl_is_java_type (tree decl, int err);
static void initialize_handler_parm (tree, tree);
static tree do_allocate_exception (tree);
static tree wrap_cleanups_r (tree *, int *, void *);
/* void std::terminate (); */
push_namespace (std_identifier);
tmp = build_function_type_list (void_type_node, NULL_TREE);
- terminate_node = build_cp_library_fn_ptr ("terminate", tmp,
- ECF_NOTHROW | ECF_NORETURN);
- TREE_THIS_VOLATILE (terminate_node) = 1;
- TREE_NOTHROW (terminate_node) = 1;
+ terminate_fn = build_cp_library_fn_ptr ("terminate", tmp,
+ ECF_NOTHROW | ECF_NORETURN
+ | ECF_COLD);
+ gcc_checking_assert (TREE_THIS_VOLATILE (terminate_fn)
+ && TREE_NOTHROW (terminate_fn));
pop_namespace ();
/* void __cxa_call_unexpected(void *); */
tmp = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
- call_unexpected_node
+ call_unexpected_fn
= push_throw_library_fn (get_identifier ("__cxa_call_unexpected"), tmp);
}
When the destruction of an object during stack unwinding exits
using an exception ... void terminate(); is called. */
- return terminate_node;
+ return terminate_fn;
}
static tree
tree
eh_type_info (tree type)
{
- tree exp;
-
if (type == NULL_TREE || type == error_mark_node)
return type;
- if (decl_is_java_type (type, 0))
- exp = build_java_class_ref (TREE_TYPE (type));
- else
- exp = get_tinfo_decl (type);
-
- return exp;
+ return get_tinfo_decl (type);
}
/* Build the address of a typeinfo decl for use in the runtime
1, integer_zero_node);
}
-/* Declare a function NAME, returning RETURN_TYPE, taking a single
- parameter PARM_TYPE, with an empty exception specification.
+/* Check that user declared function FN is a function and has return
+ type RTYPE and argument types ARG{1,2,3}TYPE. */
+
+static bool
+verify_library_fn (tree fn, const char *name, tree rtype,
+ tree arg1type, tree arg2type, tree arg3type)
+{
+ if (TREE_CODE (fn) != FUNCTION_DECL
+ || TREE_CODE (TREE_TYPE (fn)) != FUNCTION_TYPE)
+ {
+ bad:
+ error_at (DECL_SOURCE_LOCATION (fn), "%qs declared incorrectly", name);
+ return false;
+ }
+ tree fntype = TREE_TYPE (fn);
+ if (!same_type_p (TREE_TYPE (fntype), rtype))
+ goto bad;
+ tree targs = TYPE_ARG_TYPES (fntype);
+ tree args[3] = { arg1type, arg2type, arg3type };
+ for (int i = 0; i < 3 && args[i]; i++)
+ {
+ if (targs == NULL_TREE)
+ goto bad;
+ if (!same_type_p (TREE_VALUE (targs), args[i]))
+ {
+ if (i == 0)
+ goto bad;
+ /* Be less strict for second and following arguments, __cxa_throw
+ needs to be more permissive. */
+ if (TYPE_PTROBV_P (TREE_VALUE (targs)) && TYPE_PTROBV_P (args[i]))
+ /* Both object pointers. */;
+ else if (TYPE_PTRFN_P (TREE_VALUE (targs)) && TYPE_PTRFN_P (args[i]))
+ /* Both function pointers. */;
+ else
+ goto bad;
+ }
+ targs = TREE_CHAIN (targs);
+ }
+ if (targs != void_list_node)
+ goto bad;
+ return true;
+}
+
+/* Find or declare a function NAME, returning RTYPE, taking a single
+ parameter PTYPE, with an empty exception specification. ECF are the
+ library fn flags. If TM_ECF is non-zero, also find or create a
+ transaction variant and record it as a replacement, when flag_tm is
+ in effect.
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_library_fn (tree name, tree return_type, tree parm_type, int ecf_flags)
+declare_library_fn (const char *name, tree rtype, tree ptype,
+ int ecf, int tm_ecf)
{
- return push_library_fn (name, build_function_type_list (return_type,
- parm_type,
- NULL_TREE),
- empty_except_spec,
- ecf_flags);
+ tree ident = get_identifier (name);
+ tree res = get_global_binding (ident);
+ tree fntype = NULL_TREE;
+ tree except = NULL_TREE;
+ if (!res)
+ {
+ fntype = build_function_type_list (rtype, ptype, NULL_TREE);
+ if (ecf & ECF_NOTHROW)
+ except = empty_except_spec;
+ res = push_library_fn (ident, fntype, except, ecf);
+ }
+ else if (!verify_library_fn (res, name, rtype, ptype, NULL_TREE, NULL_TREE))
+ return error_mark_node;
+
+ if (tm_ecf && flag_tm)
+ {
+ char *tm_name = concat ("_ITM_", name + 2, NULL_TREE);
+ tree tm_ident = get_identifier (tm_name);
+ tree tm_fn = get_global_binding (tm_ident);
+ if (!tm_fn)
+ {
+ if (!fntype)
+ {
+ fntype = build_function_type_list (rtype, ptype, NULL_TREE);
+ if (ecf & ECF_NOTHROW)
+ except = empty_except_spec;
+ }
+ tm_fn = push_library_fn (tm_ident, fntype, except, ecf | tm_ecf);
+ }
+ else if (!verify_library_fn (tm_fn, tm_name, rtype, ptype,
+ NULL_TREE, NULL_TREE))
+ tm_fn = error_mark_node;
+ free (tm_name);
+ if (tm_fn != error_mark_node)
+ record_tm_replacement (res, tm_fn);
+ }
+ return res;
}
/* Build up a call to __cxa_get_exception_ptr so that we can build a
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_library_fn (fn, ptr_type_node, ptr_type_node,
- ECF_NOTHROW | ECF_PURE | ECF_LEAF | ECF_TM_PURE);
- }
-
- return cp_build_function_call_nary (fn, tf_warning_or_error,
+ if (!get_exception_ptr_fn)
+ /* Declare void* __cxa_get_exception_ptr (void *) throw(). */
+ get_exception_ptr_fn
+ = declare_library_fn ("__cxa_get_exception_ptr",
+ ptr_type_node, ptr_type_node,
+ ECF_NOTHROW | ECF_PURE | ECF_LEAF | ECF_TM_PURE,
+ 0);
+
+ return cp_build_function_call_nary (get_exception_ptr_fn,
+ tf_warning_or_error,
build_exc_ptr (), NULL_TREE);
}
static tree
do_begin_catch (void)
{
- tree fn;
-
- fn = get_identifier ("__cxa_begin_catch");
- if (!get_global_value_if_present (fn, &fn))
- {
- /* Declare void* __cxa_begin_catch (void *) throw(). */
- fn = declare_library_fn (fn, ptr_type_node, ptr_type_node, ECF_NOTHROW);
-
- /* Create its transactional-memory equivalent. */
- if (flag_tm)
- {
- tree fn2 = get_identifier ("_ITM_cxa_begin_catch");
- if (!get_global_value_if_present (fn2, &fn2))
- fn2 = declare_library_fn (fn2, ptr_type_node,
- ptr_type_node, ECF_NOTHROW | ECF_TM_PURE);
- record_tm_replacement (fn, fn2);
- }
- }
-
- return cp_build_function_call_nary (fn, tf_warning_or_error,
+ if (!begin_catch_fn)
+ /* Declare void* __cxa_begin_catch (void *) throw(). */
+ begin_catch_fn
+ = declare_library_fn ("__cxa_begin_catch",
+ ptr_type_node, ptr_type_node, ECF_NOTHROW,
+ ECF_TM_PURE);
+
+ return cp_build_function_call_nary (begin_catch_fn, tf_warning_or_error,
build_exc_ptr (), NULL_TREE);
}
if (CLASSTYPE_LAZY_DESTRUCTOR (type))
lazily_declare_fn (sfk_destructor, type);
- return TREE_NOTHROW (CLASSTYPE_DESTRUCTORS (type));
+ return TREE_NOTHROW (CLASSTYPE_DESTRUCTOR (type));
}
/* Build up a call to __cxa_end_catch, to destroy the exception object
static tree
do_end_catch (tree type)
{
- tree fn, cleanup;
-
- fn = get_identifier ("__cxa_end_catch");
- if (!get_global_value_if_present (fn, &fn))
- {
- /* Declare void __cxa_end_catch ().
- This can throw if the destructor for the exception throws. */
- fn = push_void_library_fn (fn, void_list_node, 0);
-
- /* Create its transactional-memory equivalent. */
- if (flag_tm)
- {
- tree fn2 = get_identifier ("_ITM_cxa_end_catch");
- if (!get_global_value_if_present (fn2, &fn2))
- fn2 = push_void_library_fn (fn2, void_list_node, ECF_TM_PURE);
- record_tm_replacement (fn, fn2);
- }
- }
-
- cleanup = cp_build_function_call_vec (fn, NULL, tf_warning_or_error);
- TREE_NOTHROW (cleanup) = dtor_nothrow (type);
+ if (!end_catch_fn)
+ /* Declare void __cxa_end_catch ().
+ This can throw if the destructor for the exception throws. */
+ end_catch_fn
+ = declare_library_fn ("__cxa_end_catch", void_type_node,
+ NULL_TREE, 0, ECF_TM_PURE);
+
+ tree cleanup = cp_build_function_call_vec (end_catch_fn,
+ NULL, tf_warning_or_error);
+ if (cleanup != error_mark_node)
+ TREE_NOTHROW (cleanup) = dtor_nothrow (type);
return cleanup;
}
finish_decl_cleanup (NULL_TREE, do_end_catch (type));
}
-/* Return nonzero value if DECL is a Java type suitable for catch or
- throw. */
-
-static bool
-decl_is_java_type (tree decl, int err)
-{
- bool r = (TYPE_PTR_P (decl)
- && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
- && TYPE_FOR_JAVA (TREE_TYPE (decl)));
-
- if (err)
- {
- if (TREE_CODE (decl) == REFERENCE_TYPE
- && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
- && TYPE_FOR_JAVA (TREE_TYPE (decl)))
- {
- /* Can't throw a reference. */
- error ("type %qT is disallowed in Java %<throw%> or %<catch%>",
- decl);
- }
-
- if (r)
- {
- tree jthrow_node
- = IDENTIFIER_GLOBAL_VALUE (get_identifier ("jthrowable"));
-
- if (jthrow_node == NULL_TREE)
- fatal_error
- (input_location,
- "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 %qT is not derived from %<java::lang::Throwable%>",
- TREE_TYPE (decl));
- }
- }
- }
-
- return r;
-}
-
-/* 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 DECL_FUNCTION_PERSONALITY is set via
- LANG_HOOKS_EH_PERSONALITY. Should it be done here instead? */
-void
-choose_personality_routine (enum languages lang)
-{
- static enum {
- chose_none,
- chose_cpp,
- chose_java,
- gave_error
- } state;
-
- switch (state)
- {
- case gave_error:
- return;
-
- case chose_cpp:
- if (lang != lang_cplusplus)
- goto give_error;
- return;
-
- case chose_java:
- if (lang != lang_java)
- goto give_error;
- return;
-
- case chose_none:
- ; /* Proceed to language selection. */
- }
-
- switch (lang)
- {
- case lang_cplusplus:
- state = chose_cpp;
- break;
-
- case lang_java:
- state = chose_java;
- terminate_node = builtin_decl_explicit (BUILT_IN_ABORT);
- pragma_java_exceptions = true;
- break;
-
- default:
- gcc_unreachable ();
- }
- return;
-
- give_error:
- error ("mixing C++ and Java catches in a single translation unit");
- state = gave_error;
-}
-
/* Wrap EXPR in a MUST_NOT_THROW_EXPR expressing that EXPR must
not throw any exceptions if COND is true. A condition of
NULL_TREE is treated as 'true'. */
if (!flag_exceptions)
return body;
- if (cond && !value_dependent_expression_p (cond))
+ if (!cond)
+ /* OK, unconditional. */;
+ else
{
- cond = cxx_constant_value (cond);
+ tree conv = NULL_TREE;
+ if (!type_dependent_expression_p (cond))
+ conv = perform_implicit_conversion_flags (boolean_type_node, cond,
+ tf_warning_or_error,
+ LOOKUP_NORMAL);
+ if (tree inst = instantiate_non_dependent_or_null (conv))
+ cond = cxx_constant_value (inst);
+ else
+ require_constant_expression (cond);
if (integer_zerop (cond))
return body;
else if (integer_onep (cond))
adjusted by value from __cxa_begin_catch. Others are returned by
reference. */
init_type = TREE_TYPE (decl);
- if (!POINTER_TYPE_P (init_type))
+ if (!INDIRECT_TYPE_P (init_type))
init_type = build_reference_type (init_type);
- choose_personality_routine (decl_is_java_type (init_type, 0)
- ? lang_java : lang_cplusplus);
-
/* Since pointers are passed by value, initialize a reference to
pointer catch parm with the address of the temporary. */
- if (TREE_CODE (init_type) == REFERENCE_TYPE
+ if (TYPE_REF_P (init_type)
&& TYPE_PTR_P (TREE_TYPE (init_type)))
exp = cp_build_addr_expr (exp, tf_warning_or_error);
static int warned = 0;
if (! warned)
{
- error ("exception handling disabled, use -fexceptions to enable");
+ error ("exception handling disabled, use %<-fexceptions%> to enable");
warned = 1;
}
return 0;
else
type = NULL_TREE;
- if (decl && 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. */
- exp = build_exc_ptr ();
- exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
- exp = fold_build_pointer_plus (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;
- }
-
/* Call __cxa_end_catch at the end of processing the exception. */
push_eh_cleanup (type);
&& TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
{
exp = do_get_exception_ptr ();
- initialize_handler_parm (decl, exp);
+ if (exp != error_mark_node)
+ initialize_handler_parm (decl, exp);
finish_expr_stmt (init);
}
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);
+ DECL_REGISTER (exp) = 1;
initialize_handler_parm (decl, exp);
}
if (in_function_try_handler
&& (DECL_CONSTRUCTOR_P (current_function_decl)
|| DECL_DESTRUCTOR_P (current_function_decl)))
- finish_expr_stmt (build_throw (NULL_TREE));
+ {
+ tree rethrow = build_throw (NULL_TREE);
+ TREE_NO_WARNING (rethrow) = true;
+ finish_expr_stmt (rethrow);
+ }
}
tree
static tree
do_allocate_exception (tree type)
{
- tree fn;
-
- fn = get_identifier ("__cxa_allocate_exception");
- if (!get_global_value_if_present (fn, &fn))
- {
- /* Declare void *__cxa_allocate_exception(size_t) throw(). */
- fn = declare_library_fn (fn, ptr_type_node, size_type_node,
- ECF_NOTHROW | ECF_MALLOC);
-
- if (flag_tm)
- {
- tree fn2 = get_identifier ("_ITM_cxa_allocate_exception");
- if (!get_global_value_if_present (fn2, &fn2))
- fn2 = declare_library_fn (fn2, ptr_type_node,
- size_type_node,
- ECF_NOTHROW | ECF_MALLOC | ECF_TM_PURE);
- record_tm_replacement (fn, fn2);
- }
- }
-
- return cp_build_function_call_nary (fn, tf_warning_or_error,
+ if (!allocate_exception_fn)
+ /* Declare void *__cxa_allocate_exception(size_t) throw(). */
+ allocate_exception_fn
+ = declare_library_fn ("__cxa_allocate_exception",
+ ptr_type_node, size_type_node,
+ ECF_NOTHROW | ECF_MALLOC | ECF_COLD, ECF_TM_PURE);
+
+ return cp_build_function_call_nary (allocate_exception_fn,
+ tf_warning_or_error,
size_in_bytes (type), NULL_TREE);
}
static tree
do_free_exception (tree ptr)
{
- tree fn;
-
- fn = get_identifier ("__cxa_free_exception");
- if (!get_global_value_if_present (fn, &fn))
- {
- /* Declare void __cxa_free_exception (void *) throw(). */
- fn = declare_library_fn (fn, void_type_node, ptr_type_node,
- ECF_NOTHROW | ECF_LEAF);
- }
-
- return cp_build_function_call_nary (fn, tf_warning_or_error, ptr, NULL_TREE);
+ if (!free_exception_fn)
+ /* Declare void __cxa_free_exception (void *) throw(). */
+ free_exception_fn
+ = declare_library_fn ("__cxa_free_exception",
+ void_type_node, ptr_type_node,
+ ECF_NOTHROW | ECF_LEAF, ECF_TM_PURE);
+
+ return cp_build_function_call_nary (free_exception_fn,
+ tf_warning_or_error, ptr, NULL_TREE);
}
/* Wrap all cleanups for TARGET_EXPRs in MUST_NOT_THROW_EXPR.
tree
build_throw (tree exp)
{
- tree fn;
-
if (exp == error_mark_node)
return exp;
return exp;
}
- if (exp == null_node)
+ if (exp && null_node_p (exp))
warning (0, "throwing NULL, which has integral, not pointer type");
if (exp != NULL_TREE)
if (! doing_eh ())
return error_mark_node;
- if (exp && decl_is_java_type (TREE_TYPE (exp), 1))
- {
- tree fn = get_identifier ("_Jv_Throw");
- if (!get_global_value_if_present (fn, &fn))
- {
- /* Declare void _Jv_Throw (void *). */
- tree tmp;
- tmp = build_function_type_list (ptr_type_node,
- ptr_type_node, NULL_TREE);
- fn = push_throw_library_fn (fn, tmp);
- }
- else if (really_overloaded_fn (fn))
- {
- error ("%qD should never be overloaded", fn);
- return error_mark_node;
- }
- fn = OVL_CURRENT (fn);
- exp = cp_build_function_call_nary (fn, tf_warning_or_error,
- exp, NULL_TREE);
- }
- else if (exp)
+ if (exp)
{
tree throw_type;
tree temp_type;
cleanup_type = build_pointer_type (tmp);
}
- fn = get_identifier ("__cxa_throw");
- if (!get_global_value_if_present (fn, &fn))
+ if (!throw_fn)
{
- /* Declare void __cxa_throw (void*, void*, void (*)(void*)). */
- /* ??? Second argument is supposed to be "std::type_info*". */
- tmp = build_function_type_list (void_type_node,
- ptr_type_node, ptr_type_node,
- cleanup_type, NULL_TREE);
- fn = push_throw_library_fn (fn, tmp);
+ const char *name = "__cxa_throw";
+ tree ident = get_identifier (name);
+ tree fntype = NULL_TREE;
+ throw_fn = get_global_binding (ident);
+ if (!throw_fn)
+ {
+ /* Declare void __cxa_throw (void*, void*, void (*)(void*)). */
+ /* ??? Second argument is supposed to be "std::type_info*". */
+ fntype = build_function_type_list (void_type_node,
+ ptr_type_node, ptr_type_node,
+ cleanup_type, NULL_TREE);
+ throw_fn = push_throw_library_fn (ident, fntype);
+ }
+ else if (!verify_library_fn (throw_fn, name, void_type_node,
+ ptr_type_node, ptr_type_node,
+ cleanup_type))
+ throw_fn = error_mark_node;
- if (flag_tm)
+ if (flag_tm && throw_fn != error_mark_node)
{
- tree fn2 = get_identifier ("_ITM_cxa_throw");
- if (!get_global_value_if_present (fn2, &fn2))
- fn2 = push_throw_library_fn (fn2, tmp);
- apply_tm_attr (fn2, get_identifier ("transaction_pure"));
- record_tm_replacement (fn, fn2);
+ const char *itm_name = "_ITM_cxa_throw";
+ tree itm_ident = get_identifier (itm_name);
+ tree itm_fn = get_global_binding (itm_ident);
+ if (!itm_fn)
+ {
+ if (!fntype)
+ fntype
+ = build_function_type_list (void_type_node,
+ ptr_type_node, ptr_type_node,
+ cleanup_type, NULL_TREE);
+ itm_fn = push_throw_library_fn (itm_ident, fntype);
+ }
+ else if (!verify_library_fn (itm_fn, itm_name, void_type_node,
+ ptr_type_node, ptr_type_node,
+ cleanup_type))
+ itm_fn = error_mark_node;
+ if (itm_fn != error_mark_node)
+ {
+ apply_tm_attr (itm_fn, get_identifier ("transaction_pure"));
+ record_tm_replacement (throw_fn, itm_fn);
+ }
}
}
/* Allocate the space for the exception. */
allocate_expr = do_allocate_exception (temp_type);
+ if (allocate_expr == error_mark_node)
+ return error_mark_node;
allocate_expr = get_target_expr (allocate_expr);
ptr = TARGET_EXPR_SLOT (allocate_expr);
TARGET_EXPR_CLEANUP (allocate_expr) = do_free_exception (ptr);
CLEANUP_EH_ONLY (allocate_expr) = 1;
object = build_nop (build_pointer_type (temp_type), ptr);
- object = cp_build_indirect_ref (object, RO_NULL, tf_warning_or_error);
+ object = cp_build_fold_indirect_ref (object);
/* And initialize the exception object. */
if (CLASS_TYPE_P (temp_type))
{
int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING;
vec<tree, va_gc> *exp_vec;
+ bool converted = false;
/* 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. */
- VAR_P (exp)
- && DECL_CONTEXT (exp) == current_function_decl
- && ! TREE_STATIC (exp)
+ if (treat_lvalue_as_rvalue_p (exp, /*parm_ok*/false)
/* The variable must not have the `volatile' qualifier. */
- && !(cp_type_quals (TREE_TYPE (exp)) & TYPE_QUAL_VOLATILE))
- flags = flags | LOOKUP_PREFER_RVALUE;
+ && !CP_TYPE_VOLATILE_P (TREE_TYPE (exp)))
+ {
+ tree moved = move (exp);
+ exp_vec = make_tree_vector_single (moved);
+ moved = (build_special_member_call
+ (object, complete_ctor_identifier, &exp_vec,
+ TREE_TYPE (object), flags|LOOKUP_PREFER_RVALUE,
+ tf_none));
+ release_tree_vector (exp_vec);
+ if (moved != error_mark_node)
+ {
+ exp = moved;
+ converted = true;
+ }
+ }
/* 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 (!converted)
+ {
+ 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");
cleanup = NULL_TREE;
if (type_build_dtor_call (TREE_TYPE (object)))
{
- tree fn = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
- complete_dtor_identifier, 0);
- fn = BASELINK_FUNCTIONS (fn);
- mark_used (fn);
+ tree dtor_fn = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
+ complete_dtor_identifier, 0);
+ dtor_fn = BASELINK_FUNCTIONS (dtor_fn);
+ mark_used (dtor_fn);
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (object)))
{
- cxx_mark_addressable (fn);
+ cxx_mark_addressable (dtor_fn);
/* Pretend it's a normal function. */
- cleanup = build1 (ADDR_EXPR, cleanup_type, fn);
+ cleanup = build1 (ADDR_EXPR, cleanup_type, dtor_fn);
}
}
if (cleanup == NULL_TREE)
cleanup = build_int_cst (cleanup_type, 0);
/* ??? Indicate that this function call throws throw_type. */
- tmp = cp_build_function_call_nary (fn, tf_warning_or_error,
+ tmp = cp_build_function_call_nary (throw_fn, tf_warning_or_error,
ptr, throw_type, cleanup, NULL_TREE);
/* Tack on the initialization stuff. */
else
{
/* Rethrow current exception. */
-
- tree fn = get_identifier ("__cxa_rethrow");
- if (!get_global_value_if_present (fn, &fn))
+ if (!rethrow_fn)
{
- /* Declare void __cxa_rethrow (void). */
- fn = push_throw_library_fn
- (fn, build_function_type_list (void_type_node, NULL_TREE));
- }
+ const char *name = "__cxa_rethrow";
+ tree ident = get_identifier (name);
+ rethrow_fn = get_global_binding (ident);
+ if (!rethrow_fn)
+ {
+ /* Declare void __cxa_rethrow (void). */
+ tree fntype
+ = build_function_type_list (void_type_node, NULL_TREE);
+ rethrow_fn = push_throw_library_fn (ident, fntype);
+ }
+ else if (!verify_library_fn (rethrow_fn, name, void_type_node,
+ NULL_TREE, NULL_TREE, NULL_TREE))
+ rethrow_fn = error_mark_node;
- if (flag_tm)
- apply_tm_attr (fn, get_identifier ("transaction_pure"));
+ if (flag_tm && rethrow_fn != error_mark_node)
+ apply_tm_attr (rethrow_fn, get_identifier ("transaction_pure"));
+ }
/* ??? Indicate that this function call allows exceptions of the type
of the enclosing catch block (if known). */
- exp = cp_build_function_call_vec (fn, NULL, tf_warning_or_error);
+ exp = cp_build_function_call_vec (rethrow_fn, NULL, tf_warning_or_error);
}
exp = build1 (THROW_EXPR, void_type_node, exp);
/* Or a pointer or ref to one, or cv void *. */
is_ptr = TYPE_PTR_P (type);
- if (is_ptr || TREE_CODE (type) == REFERENCE_TYPE)
+ if (is_ptr || TYPE_REF_P (type))
{
tree core = TREE_TYPE (type);
else if (abstract_virtuals_error (is_throw ? ACU_THROW : ACU_CATCH, type))
return false;
else if (!is_throw
- && TREE_CODE (type) == REFERENCE_TYPE
+ && TYPE_REF_P (type)
&& TYPE_REF_IS_RVALUE (type))
{
error ("cannot declare catch parameter to be of rvalue "
unless the system headers are playing rename tricks, and if
they are, we don't want to be confused by them. */
id = DECL_NAME (fn);
- return !!libc_name_p (IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
+ const struct libc_name_struct *s
+ = libc_name::libc_name_p (IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
+ if (s == NULL)
+ return 0;
+ switch (s->c_ver)
+ {
+ case 89: return 1;
+ case 99: return !flag_iso || flag_isoc99;
+ case 11: return !flag_iso || flag_isoc11;
+ default: gcc_unreachable ();
+ }
}
/* Returns nonzero if an exception of type FROM will be caught by a
translation unit, creating ODR problems.
We could use TREE_NOTHROW (t) for !TREE_PUBLIC fns, though... */
- tree fn = (code == AGGR_INIT_EXPR
- ? AGGR_INIT_EXPR_FN (t) : CALL_EXPR_FN (t));
- tree type = TREE_TYPE (TREE_TYPE (fn));
+ tree fn = cp_get_callee (t);
+ tree type = TREE_TYPE (fn);
+ gcc_assert (INDIRECT_TYPE_P (type));
+ type = TREE_TYPE (type);
STRIP_NOPS (fn);
if (TREE_CODE (fn) == ADDR_EXPR)
/* If a function that causes a noexcept-expression to be false isn't
defined yet, remember it and check it for TREE_NOTHROW again at EOF. */
-typedef struct GTY(()) pending_noexcept {
+struct GTY(()) pending_noexcept {
tree fn;
location_t loc;
-} pending_noexcept;
+};
static GTY(()) vec<pending_noexcept, va_gc> *pending_noexcept_checks;
/* FN is a FUNCTION_DECL that caused a noexcept-expr to be false. Warn if
{
warning (OPT_Wnoexcept, "noexcept-expression evaluates to %<false%> "
"because of a call to %qD", fn);
- warning (OPT_Wnoexcept, "but %q+D does not throw; perhaps "
- "it should be declared %<noexcept%>", fn);
+ warning_at (DECL_SOURCE_LOCATION (fn), OPT_Wnoexcept,
+ "but %qD does not throw; perhaps "
+ "it should be declared %<noexcept%>", fn);
}
}
nothrow_spec_p (const_tree spec)
{
gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (spec));
- if (spec == NULL_TREE
- || TREE_VALUE (spec) != NULL_TREE
- || spec == noexcept_false_spec)
- return false;
- if (TREE_PURPOSE (spec) == NULL_TREE
+
+ if (spec == empty_except_spec
|| spec == noexcept_true_spec)
return true;
- gcc_assert (processing_template_decl
- || TREE_PURPOSE (spec) == error_mark_node);
+
+ gcc_assert (!spec
+ || TREE_VALUE (spec)
+ || spec == noexcept_false_spec
+ || TREE_PURPOSE (spec) == error_mark_node
+ || processing_template_decl);
+
return false;
}
constant-expression of EXPR. COMPLAIN is as for tsubst. */
tree
-build_noexcept_spec (tree expr, int complain)
+build_noexcept_spec (tree expr, tsubst_flags_t complain)
{
- /* This isn't part of the signature, so don't bother trying to evaluate
- it until instantiation. */
- if (!processing_template_decl && TREE_CODE (expr) != DEFERRED_NOEXCEPT)
+ if (TREE_CODE (expr) != DEFERRED_NOEXCEPT
+ && !value_dependent_expression_p (expr))
{
expr = perform_implicit_conversion_flags (boolean_type_node, expr,
complain,
LOOKUP_NORMAL);
+ expr = instantiate_non_dependent_expr (expr);
expr = cxx_constant_value (expr);
}
if (TREE_CODE (expr) == INTEGER_CST)
{
gcc_assert (processing_template_decl
|| TREE_CODE (expr) == DEFERRED_NOEXCEPT);
+ if (TREE_CODE (expr) != DEFERRED_NOEXCEPT)
+ /* Avoid problems with a function type built with a dependent typedef
+ being reused in another scope (c++/84045). */
+ expr = strip_typedefs_expr (expr);
return build_tree_list (expr, NULL_TREE);
}
}
-/* Returns a noexcept-specifier to be evaluated later, for an
- implicitly-declared or explicitly defaulted special member function. */
-
-tree
-unevaluated_noexcept_spec (void)
-{
- static tree spec;
- if (spec == NULL_TREE)
- spec = build_noexcept_spec (make_node (DEFERRED_NOEXCEPT), tf_none);
- return spec;
-}
-
/* Returns a TRY_CATCH_EXPR that will put TRY_LIST and CATCH_LIST in the
TRY and CATCH locations. CATCH_LIST must be a STATEMENT_LIST */