diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 92db68ec263..62e7a43ee37 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2005-02-18 Richard Henderson + + PR libstdc++/10606 + * except.c (do_get_exception_ptr): New. + (expand_start_catch_block): Use it. + 2005-02-19 Jakub Jelinek * decl.c (start_decl_1): Only check TYPE_NEEDS_CONSTRUCTING diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 4a0ccb913b9..ef4fb2193b5 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -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; } diff --git a/gcc/testsuite/g++.dg/eh/uncaught1.C b/gcc/testsuite/g++.dg/eh/uncaught1.C new file mode 100644 index 00000000000..2aa1068b090 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/uncaught1.C @@ -0,0 +1,83 @@ +// PR libstdc++/10606 +// { dg-do run } + +#include +#include + + +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; +} diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index e54c43b3930..9b27b0b65e9 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,4 +1,17 @@ +2005-02-18 Richard Henderson + + 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 + * 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. diff --git a/libstdc++-v3/config/linker-map.gnu b/libstdc++-v3/config/linker-map.gnu index df3c674f96f..d7d291485b6 100644 --- a/libstdc++-v3/config/linker-map.gnu +++ b/libstdc++-v3/config/linker-map.gnu @@ -410,3 +410,9 @@ CXXABI_1.3 { local: *; }; + +CXXABI_1.3.1 { + + __cxa_get_exception_ptr; + +} CXXABI_1.3; diff --git a/libstdc++-v3/libsupc++/eh_alloc.cc b/libstdc++-v3/libsupc++/eh_alloc.cc index 4728bcbf380..3b7319ea235 100644 --- a/libstdc++-v3/libsupc++/eh_alloc.cc +++ b/libstdc++-v3/libsupc++/eh_alloc.cc @@ -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)); diff --git a/libstdc++-v3/libsupc++/eh_catch.cc b/libstdc++-v3/libsupc++/eh_catch.cc index bdcbd7e085c..88060d9f9cd 100644 --- a/libstdc++-v3/libsupc++/eh_catch.cc +++ b/libstdc++-v3/libsupc++/eh_catch.cc @@ -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) { diff --git a/libstdc++-v3/libsupc++/eh_throw.cc b/libstdc++-v3/libsupc++/eh_throw.cc index b02efdad6dc..0807c5e1df7 100644 --- a/libstdc++-v3/libsupc++/eh_throw.cc +++ b/libstdc++-v3/libsupc++/eh_throw.cc @@ -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) { diff --git a/libstdc++-v3/libsupc++/unwind-cxx.h b/libstdc++-v3/libsupc++/unwind-cxx.h index 67ea5cc2110..e79dd83628e 100644 --- a/libstdc++-v3/libsupc++/unwind-cxx.h +++ b/libstdc++-v3/libsupc++/unwind-cxx.h @@ -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));