re PR libstdc++/10606 (uncaught_exception() returns false too early)
PR libstdc++/10606 gcc/cp/ * except.c (do_get_exception_ptr): New. (expand_start_catch_block): Use it. libstdc++/ * config/linker-map.gnu (CXXABI_1.3.1): Add __cxa_get_exception_ptr. * libsupc++/eh_alloc.cc (__cxa_allocate_exception): Increment uncaughtExceptions here instead of ... * libsupc++/eh_throw.cc (__cxa_throw) ... here. (__cxa_rethrow): Increment uncaughtExceptions here instead of ... * libsupc++/eh_catch.cc (__cxa_end_catch): ... here. (__cxa_get_exception_ptr): New. * libsupc++/unwind-cxx.h (__cxa_get_exception_ptr): Declare. From-SVN: r95262
This commit is contained in:
parent
5ff489f15b
commit
396090773c
9 changed files with 185 additions and 41 deletions
|
@ -1,3 +1,9 @@
|
|||
2005-02-18 Richard Henderson <rth@redhat.com>
|
||||
|
||||
PR libstdc++/10606
|
||||
* except.c (do_get_exception_ptr): New.
|
||||
(expand_start_catch_block): Use it.
|
||||
|
||||
2005-02-19 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* decl.c (start_decl_1): Only check TYPE_NEEDS_CONSTRUCTING
|
||||
|
|
|
@ -153,6 +153,26 @@ build_exc_ptr (void)
|
|||
return build0 (EXC_PTR_EXPR, ptr_type_node);
|
||||
}
|
||||
|
||||
/* 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 *). */
|
||||
tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
|
||||
fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp));
|
||||
}
|
||||
|
||||
return build_function_call (fn, tree_cons (NULL_TREE, build_exc_ptr (),
|
||||
NULL_TREE));
|
||||
}
|
||||
|
||||
/* Build up a call to __cxa_begin_catch, to tell the runtime that the
|
||||
exception has been handled. */
|
||||
|
||||
|
@ -381,9 +401,8 @@ initialize_handler_parm (tree decl, tree exp)
|
|||
tree
|
||||
expand_start_catch_block (tree decl)
|
||||
{
|
||||
tree exp = NULL_TREE;
|
||||
tree exp;
|
||||
tree type;
|
||||
bool is_java;
|
||||
|
||||
if (! doing_eh (1))
|
||||
return NULL_TREE;
|
||||
|
@ -397,45 +416,50 @@ expand_start_catch_block (tree decl)
|
|||
else
|
||||
type = NULL_TREE;
|
||||
|
||||
is_java = false;
|
||||
if (decl)
|
||||
if (decl && decl_is_java_type (type, 1))
|
||||
{
|
||||
tree 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 (MINUS_EXPR, TREE_TYPE (exp), exp,
|
||||
TYPE_SIZE_UNIT (TREE_TYPE (exp)));
|
||||
exp = build_indirect_ref (exp, NULL);
|
||||
initialize_handler_parm (decl, exp);
|
||||
return type;
|
||||
}
|
||||
|
||||
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 ();
|
||||
}
|
||||
|
||||
/* Call __cxa_end_catch at the end of processing the exception. */
|
||||
push_eh_cleanup (type);
|
||||
|
||||
/* 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)
|
||||
finish_expr_stmt (do_begin_catch ());
|
||||
|
||||
/* 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 (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
|
||||
{
|
||||
exp = do_get_exception_ptr ();
|
||||
initialize_handler_parm (decl, exp);
|
||||
finish_expr_stmt (do_begin_catch ());
|
||||
}
|
||||
|
||||
/* 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 = 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));
|
||||
initialize_handler_parm (decl, exp);
|
||||
}
|
||||
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);
|
||||
|
||||
if (decl)
|
||||
initialize_handler_parm (decl, exp);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
|
83
gcc/testsuite/g++.dg/eh/uncaught1.C
Normal file
83
gcc/testsuite/g++.dg/eh/uncaught1.C
Normal file
|
@ -0,0 +1,83 @@
|
|||
// PR libstdc++/10606
|
||||
// { dg-do run }
|
||||
|
||||
#include <exception>
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
struct Check {
|
||||
int obj1, obj2;
|
||||
bool state;
|
||||
};
|
||||
|
||||
static Check const data[] = {
|
||||
{ 0, 0, false }, // construct [0]
|
||||
{ 1, 0, true }, // [1] = [0]
|
||||
{ 0, 0, true }, // destruct [0]
|
||||
{ 2, 1, true }, // [2] = [1]
|
||||
{ 2, 2, true }, // destruct [2]
|
||||
{ 3, 1, true }, // [3] = [1]
|
||||
{ 3, 3, false }, // destruct [3]
|
||||
{ 1, 1, false }, // destruct [1]
|
||||
{ 9, 9, false } // end-of-data
|
||||
};
|
||||
|
||||
static int pos = 0;
|
||||
|
||||
static void test(int obj1, int obj2, bool state)
|
||||
{
|
||||
if (obj1 != data[pos].obj1) abort ();
|
||||
if (obj2 != data[pos].obj2) abort ();
|
||||
if (state != data[pos].state) abort ();
|
||||
pos++;
|
||||
}
|
||||
|
||||
|
||||
struct S {
|
||||
int id;
|
||||
S ();
|
||||
S (const S &);
|
||||
~S ();
|
||||
};
|
||||
|
||||
static int next_id = 0;
|
||||
|
||||
S::S()
|
||||
: id (next_id++)
|
||||
{
|
||||
test (id, id, std::uncaught_exception ());
|
||||
}
|
||||
|
||||
S::S(const S &x)
|
||||
: id (next_id++)
|
||||
{
|
||||
test (id, x.id, std::uncaught_exception ());
|
||||
}
|
||||
|
||||
S::~S()
|
||||
{
|
||||
test (id, id, std::uncaught_exception ());
|
||||
}
|
||||
|
||||
extern void foo (S *);
|
||||
|
||||
int main()
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
S s0;
|
||||
throw s0; // s1 is the exception object
|
||||
}
|
||||
catch (S s2)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (S s3)
|
||||
{
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,4 +1,17 @@
|
|||
2005-02-18 Richard Henderson <rth@redhat.com>
|
||||
|
||||
PR libstdc++/10606
|
||||
* config/linker-map.gnu (CXXABI_1.3.1): Add __cxa_get_exception_ptr.
|
||||
* libsupc++/eh_alloc.cc (__cxa_allocate_exception): Increment
|
||||
uncaughtExceptions here instead of ...
|
||||
* libsupc++/eh_throw.cc (__cxa_throw) ... here.
|
||||
(__cxa_rethrow): Increment uncaughtExceptions here instead of ...
|
||||
* libsupc++/eh_catch.cc (__cxa_end_catch): ... here.
|
||||
(__cxa_get_exception_ptr): New.
|
||||
* libsupc++/unwind-cxx.h (__cxa_get_exception_ptr): Declare.
|
||||
|
||||
2005-02-18 Matt Austern <austern@apple.com>
|
||||
|
||||
* testsuite/tr1/6_containers/unordered/insert/array_syntax.cc: Fix
|
||||
test case to use assignment instead of ==
|
||||
* testsuite/tr1/6_containers/unordered/insert/map_range.cc: New test.
|
||||
|
|
|
@ -410,3 +410,9 @@ CXXABI_1.3 {
|
|||
local:
|
||||
*;
|
||||
};
|
||||
|
||||
CXXABI_1.3.1 {
|
||||
|
||||
__cxa_get_exception_ptr;
|
||||
|
||||
} CXXABI_1.3;
|
||||
|
|
|
@ -147,6 +147,12 @@ __cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) throw()
|
|||
std::terminate ();
|
||||
}
|
||||
|
||||
// We have an uncaught exception as soon as we allocate memory. This
|
||||
// yields uncaught_exception() true during the copy-constructor that
|
||||
// initializes the exception object. See Issue 475.
|
||||
__cxa_eh_globals *globals = __cxa_get_globals ();
|
||||
globals->uncaughtExceptions += 1;
|
||||
|
||||
memset (ret, 0, sizeof (__cxa_exception));
|
||||
|
||||
return (void *)((char *)ret + sizeof (__cxa_exception));
|
||||
|
|
|
@ -33,6 +33,15 @@
|
|||
|
||||
using namespace __cxxabiv1;
|
||||
|
||||
extern "C" void *
|
||||
__cxxabiv1::__cxa_get_exception_ptr(void *exc_obj_in) throw()
|
||||
{
|
||||
_Unwind_Exception *exceptionObject
|
||||
= reinterpret_cast <_Unwind_Exception *>(exc_obj_in);
|
||||
__cxa_exception *header = __get_exception_header_from_ue (exceptionObject);
|
||||
|
||||
return header->adjustedPtr;
|
||||
}
|
||||
|
||||
extern "C" void *
|
||||
__cxxabiv1::__cxa_begin_catch (void *exc_obj_in) throw()
|
||||
|
@ -107,10 +116,7 @@ __cxxabiv1::__cxa_end_catch ()
|
|||
// This exception was rethrown. Decrement the (inverted) catch
|
||||
// count and remove it from the chain when it reaches zero.
|
||||
if (++count == 0)
|
||||
{
|
||||
globals->uncaughtExceptions += 1;
|
||||
globals->caughtExceptions = header->nextException;
|
||||
}
|
||||
globals->caughtExceptions = header->nextException;
|
||||
}
|
||||
else if (--count == 0)
|
||||
{
|
||||
|
|
|
@ -66,9 +66,6 @@ __cxxabiv1::__cxa_throw (void *obj, std::type_info *tinfo,
|
|||
header->unwindHeader.exception_class = __gxx_exception_class;
|
||||
header->unwindHeader.exception_cleanup = __gxx_exception_cleanup;
|
||||
|
||||
__cxa_eh_globals *globals = __cxa_get_globals ();
|
||||
globals->uncaughtExceptions += 1;
|
||||
|
||||
#ifdef _GLIBCXX_SJLJ_EXCEPTIONS
|
||||
_Unwind_SjLj_RaiseException (&header->unwindHeader);
|
||||
#else
|
||||
|
@ -86,6 +83,8 @@ __cxxabiv1::__cxa_rethrow ()
|
|||
__cxa_eh_globals *globals = __cxa_get_globals ();
|
||||
__cxa_exception *header = globals->caughtExceptions;
|
||||
|
||||
globals->uncaughtExceptions += 1;
|
||||
|
||||
// Watch for luser rethrowing with no active exception.
|
||||
if (header)
|
||||
{
|
||||
|
|
|
@ -107,6 +107,7 @@ extern "C" void __cxa_throw (void *thrown_exception,
|
|||
__attribute__((noreturn));
|
||||
|
||||
// Used to implement exception handlers.
|
||||
extern "C" void *__cxa_get_exception_ptr (void *) throw();
|
||||
extern "C" void *__cxa_begin_catch (void *) throw();
|
||||
extern "C" void __cxa_end_catch ();
|
||||
extern "C" void __cxa_rethrow () __attribute__((noreturn));
|
||||
|
|
Loading…
Add table
Reference in a new issue