From e88218fd5a21e44c77c10dec87af4b11c76f34a0 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Mon, 6 Jul 2020 09:54:40 -0700 Subject: [PATCH] c++: Always use pushdecl for exception library helpers The ABI exception helpers like __throw were being created by first looking for them, and then adding if not found. Primarily because libitm wasn't declaring them with the correct exception specifiers. I fixed libitm a while back, so let's just use push_library_fn and let the symbol table machinery deal with duplicates. push_library_fn was making the assumtion there wasn't already a decl available, by always returning the new decl. Bad things would happen if there was a duplicate, because duplicate_decls explicitly gcc_frees the new decl. Fixed by having it return whatever pushdecl returns. gcc/cp/ * decl.c (push_library_fn): Return the decl pushdecl_toplevel returns. * except.c (verify_library_fn): Replace with ... (declare_library_fn_1): ... this fn. Always push the fn. (declare_library_fn): Call it. (build_throw): Call declare_library_fn_1. gcc/testsuite/ * g++.dg/eh/builtin10.C: Adjust expected errors. * g++.dg/eh/builtin11.C: Likewise. * g++.dg/eh/builtin5.C: Likewise. * g++.dg/eh/builtin6.C: Likewise. * g++.dg/eh/builtin7.C: Likewise. * g++.dg/eh/builtin9.C: Likewise. * g++.dg/parse/crash55.C: Likewise. --- gcc/cp/decl.c | 7 +- gcc/cp/except.c | 162 +++++++-------------------- gcc/testsuite/g++.dg/eh/builtin10.C | 12 +- gcc/testsuite/g++.dg/eh/builtin11.C | 20 ++-- gcc/testsuite/g++.dg/eh/builtin5.C | 8 +- gcc/testsuite/g++.dg/eh/builtin6.C | 16 +-- gcc/testsuite/g++.dg/eh/builtin7.C | 12 +- gcc/testsuite/g++.dg/eh/builtin9.C | 20 ++-- gcc/testsuite/g++.dg/parse/crash55.C | 4 +- 9 files changed, 90 insertions(+), 171 deletions(-) diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 1eb5c2a29ac..60a09e9497a 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4819,14 +4819,11 @@ build_cp_library_fn_ptr (const char* name, tree type, int ecf_flags) tree push_library_fn (tree name, tree type, tree raises, int ecf_flags) { - tree fn; - if (raises) type = build_exception_variant (type, raises); - fn = build_library_fn (name, ERROR_MARK, type, ecf_flags); - pushdecl_top_level (fn); - return fn; + tree fn = build_library_fn (name, ERROR_MARK, type, ecf_flags); + return pushdecl_top_level (fn); } /* Like build_cp_library_fn, but also pushes the function so that it diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 9e1aa5085d4..aca54f136ba 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -133,47 +133,27 @@ build_exc_ptr (void) 1, integer_zero_node); } -/* Check that user declared function FN is a function and has return - type RTYPE and argument types ARG{1,2,3}TYPE. */ +/* Declare an exception ABI entry point called NAME. + ECF are the library flags, RTYPE the return type and ARGS[NARGS] + the parameter types. We return the DECL -- which might be one + found via the symbol table pushing, if the user already declared + it. If we pushed a new decl, the user will see it. */ -static bool -verify_library_fn (tree fn, const char *name, tree rtype, - tree arg1type, tree arg2type, tree arg3type) +static tree +declare_library_fn_1 (const char *name, int ecf, + tree rtype, int nargs, tree args[]) { - 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; + tree ident = get_identifier (name); + tree except = ecf & ECF_NOTHROW ? empty_except_spec : NULL_TREE; + + /* Make a new decl. */ + tree arg_list = void_list_node; + for (unsigned ix = nargs; ix--;) + arg_list = tree_cons (NULL_TREE, args[ix], arg_list); + tree fntype = build_function_type (rtype, arg_list); + tree res = push_library_fn (ident, fntype, except, ecf); + + return res; } /* Find or declare a function NAME, returning RTYPE, taking a single @@ -190,42 +170,21 @@ static tree declare_library_fn (const char *name, tree rtype, tree ptype, int ecf, int tm_ecf) { - 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; + tree res = declare_library_fn_1 (name, ecf, rtype, ptype ? 1 : 0, &ptype); + if (res == error_mark_node) + return res; 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; + + tree tm_fn = declare_library_fn_1 (tm_name, ecf | tm_ecf, rtype, + ptype ? 1 : 0, &ptype); free (tm_name); if (tm_fn != error_mark_node) record_tm_replacement (res, tm_fn); } + return res; } @@ -660,55 +619,28 @@ build_throw (location_t loc, tree exp) tree temp_type; tree cleanup; tree object, ptr; - tree tmp; tree allocate_expr; /* The CLEANUP_TYPE is the internal type of a destructor. */ if (!cleanup_type) { - tmp = build_function_type_list (void_type_node, - ptr_type_node, NULL_TREE); + tree tmp = build_function_type_list (void_type_node, + ptr_type_node, NULL_TREE); cleanup_type = build_pointer_type (tmp); } if (!throw_fn) { - 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; + tree args[3] = {ptr_type_node, ptr_type_node, cleanup_type}; + throw_fn = declare_library_fn_1 ("__cxa_throw", + ECF_NORETURN | ECF_COLD, + void_type_node, 3, args); if (flag_tm && throw_fn != error_mark_node) { - 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; + tree itm_fn = declare_library_fn_1 ("_ITM_cxa_throw", + ECF_NORETURN | ECF_COLD, + void_type_node, 3, args); if (itm_fn != error_mark_node) { apply_tm_attr (itm_fn, get_identifier ("transaction_pure")); @@ -798,7 +730,7 @@ build_throw (location_t loc, tree exp) } else { - tmp = decay_conversion (exp, tf_warning_or_error); + tree tmp = decay_conversion (exp, tf_warning_or_error); if (tmp == error_mark_node) return error_mark_node; exp = build2 (INIT_EXPR, temp_type, object, tmp); @@ -836,8 +768,9 @@ build_throw (location_t loc, tree exp) cleanup = build_int_cst (cleanup_type, 0); /* ??? Indicate that this function call throws throw_type. */ - tmp = cp_build_function_call_nary (throw_fn, tf_warning_or_error, - ptr, throw_type, cleanup, NULL_TREE); + tree tmp = cp_build_function_call_nary (throw_fn, tf_warning_or_error, + ptr, throw_type, cleanup, + NULL_TREE); /* Tack on the initialization stuff. */ exp = build2 (COMPOUND_EXPR, TREE_TYPE (tmp), exp, tmp); @@ -847,20 +780,9 @@ build_throw (location_t loc, tree exp) /* Rethrow current exception. */ if (!rethrow_fn) { - 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; - + rethrow_fn = declare_library_fn_1 ("__cxa_rethrow", + ECF_NORETURN | ECF_COLD, + void_type_node, 0, NULL); if (flag_tm && rethrow_fn != error_mark_node) apply_tm_attr (rethrow_fn, get_identifier ("transaction_pure")); } diff --git a/gcc/testsuite/g++.dg/eh/builtin10.C b/gcc/testsuite/g++.dg/eh/builtin10.C index 8c48e3de6d3..6c34f1f6d5c 100644 --- a/gcc/testsuite/g++.dg/eh/builtin10.C +++ b/gcc/testsuite/g++.dg/eh/builtin10.C @@ -2,12 +2,12 @@ // { dg-do compile } extern "C" void __cxa_throw (void *, void *, void (*) (void *)); -extern "C" float __cxa_get_exception_ptr (void *); // { dg-error "declared incorrectly" } -extern "C" void *__cxa_begin_catch (void *); +extern "C" float __cxa_get_exception_ptr (void *) throw (); // { dg-message "previous declaration" } +extern "C" void *__cxa_begin_catch (void *) throw (); extern "C" void __cxa_end_catch (); extern "C" void __cxa_rethrow (); -extern "C" void *__cxa_allocate_exception (__SIZE_TYPE__); -extern "C" int __cxa_free_exception (void *); // { dg-error "declared incorrectly" } +extern "C" void *__cxa_allocate_exception (__SIZE_TYPE__) throw (); +extern "C" int __cxa_free_exception (void *) throw (); // { dg-message "previous declaration" } struct S { S (); S (const S &); ~S (); }; @@ -15,13 +15,13 @@ int foo (int x) { if (x > 27) - throw 19; + throw 19; // { dg-error "conflicting" } try { if (x > 15) throw S (); } - catch (S s) + catch (S s) // { dg-error "conflicting" } { throw; } diff --git a/gcc/testsuite/g++.dg/eh/builtin11.C b/gcc/testsuite/g++.dg/eh/builtin11.C index fb1d4f38ab3..abc8c1af535 100644 --- a/gcc/testsuite/g++.dg/eh/builtin11.C +++ b/gcc/testsuite/g++.dg/eh/builtin11.C @@ -1,13 +1,13 @@ // PR c++/88482 // { dg-do compile } -extern "C" void __cxa_throw (float, void *, void (*) (void *)); // { dg-error "declared incorrectly" } -extern "C" void *__cxa_get_exception_ptr (void *); -extern "C" void *__cxa_begin_catch (int); // { dg-error "declared incorrectly" } -extern "C" void __cxa_end_catch (long long); // { dg-error "declared incorrectly" } -extern "C" void __cxa_rethrow (int); // { dg-error "declared incorrectly" } -extern "C" void *__cxa_allocate_exception (void *); // { dg-error "declared incorrectly" } -extern "C" void __cxa_free_exception (void *); +extern "C" void __cxa_throw (float, void *, void (*) (void *)); // { dg-message "previous declaration" } +extern "C" void *__cxa_get_exception_ptr (void *) throw (); +extern "C" void *__cxa_begin_catch (int) throw (); // { dg-message "previous declaration" } +extern "C" void __cxa_end_catch (long long) throw (); // { dg-message "previous declaration" } +extern "C" void __cxa_rethrow (int); // { dg-message "previous declaration" } +extern "C" void *__cxa_allocate_exception (void *) throw (); // { dg-message "previous declaration" } +extern "C" void __cxa_free_exception (void *) throw (); struct S { S (); S (const S &); ~S (); }; @@ -15,15 +15,15 @@ int foo (int x) { if (x > 27) - throw 19; + throw 19; // { dg-error "conflicting" } try { if (x > 15) throw S (); } - catch (S s) + catch (S s) // { dg-error "conflicting" } { - throw; + throw; // { dg-error "conflicting" } } return x + 3; } diff --git a/gcc/testsuite/g++.dg/eh/builtin5.C b/gcc/testsuite/g++.dg/eh/builtin5.C index eec6f2509a5..1ab9c749867 100644 --- a/gcc/testsuite/g++.dg/eh/builtin5.C +++ b/gcc/testsuite/g++.dg/eh/builtin5.C @@ -2,12 +2,12 @@ // { dg-do compile } extern "C" void __cxa_throw (void *, void *, void (*) (void *)); -extern "C" void *__cxa_get_exception_ptr (void *); -extern "C" void *__cxa_begin_catch (void *); +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 (); -extern "C" void *__cxa_allocate_exception (__SIZE_TYPE__); -extern "C" void __cxa_free_exception (void *); +extern "C" void *__cxa_allocate_exception (__SIZE_TYPE__) throw (); +extern "C" void __cxa_free_exception (void *) throw (); struct S { S (); S (const S &); ~S (); }; diff --git a/gcc/testsuite/g++.dg/eh/builtin6.C b/gcc/testsuite/g++.dg/eh/builtin6.C index a70b406cf84..c05abdc8f51 100644 --- a/gcc/testsuite/g++.dg/eh/builtin6.C +++ b/gcc/testsuite/g++.dg/eh/builtin6.C @@ -1,12 +1,12 @@ // PR c++/88482 // { dg-do compile } -float __cxa_throw; // { dg-error "declared incorrectly" } +float __cxa_throw; // { dg-message "previous declaration" } extern "C" void *__cxa_get_exception_ptr (void *); -float __cxa_begin_catch; // { dg-error "declared incorrectly" } -float __cxa_end_catch; // { dg-error "declared incorrectly" } -float __cxa_rethrow; // { dg-error "declared incorrectly" } -float __cxa_allocate_exception; // { dg-error "declared incorrectly" } +float __cxa_begin_catch; // { dg-message "previous declaration" } +float __cxa_end_catch; // { dg-message "previous declaration" } +float __cxa_rethrow; // { dg-message "previous declaration" } +float __cxa_allocate_exception; // { dg-message "previous declaration" } extern "C" void __cxa_free_exception (void *); struct S { S (); S (const S &); ~S (); }; @@ -15,15 +15,15 @@ int foo (int x) { if (x > 27) - throw 19; + throw 19; // { dg-error "redeclared" } try { if (x > 15) throw S (); } - catch (S s) + catch (S s) // { dg-error "redeclared" } { - throw; + throw; // { dg-error "redeclared" } } return x + 3; } diff --git a/gcc/testsuite/g++.dg/eh/builtin7.C b/gcc/testsuite/g++.dg/eh/builtin7.C index ad9c7f6802d..0ef279d09c1 100644 --- a/gcc/testsuite/g++.dg/eh/builtin7.C +++ b/gcc/testsuite/g++.dg/eh/builtin7.C @@ -2,12 +2,12 @@ // { dg-do compile } extern "C" void __cxa_throw (void *, void *, void (*) (void *)); -int __cxa_get_exception_ptr; // { dg-error "declared incorrectly" } -extern "C" void *__cxa_begin_catch (void *); +int __cxa_get_exception_ptr; // { dg-message "previous declaration" } +extern "C" void *__cxa_begin_catch (void *) throw (); extern "C" void __cxa_end_catch (); extern "C" void __cxa_rethrow (); -extern "C" void *__cxa_allocate_exception (__SIZE_TYPE__); -int __cxa_free_exception; // { dg-error "declared incorrectly" } +extern "C" void *__cxa_allocate_exception (__SIZE_TYPE__) throw (); +int __cxa_free_exception; // { dg-message "previous declaration" } struct S { S (); S (const S &); ~S (); }; @@ -15,13 +15,13 @@ int foo (int x) { if (x > 27) - throw 19; + throw 19; // { dg-error "redeclared" } try { if (x > 15) throw S (); } - catch (S s) + catch (S s) // { dg-error "redeclared" } { throw; } diff --git a/gcc/testsuite/g++.dg/eh/builtin9.C b/gcc/testsuite/g++.dg/eh/builtin9.C index acd1a5e7dd6..591a622630c 100644 --- a/gcc/testsuite/g++.dg/eh/builtin9.C +++ b/gcc/testsuite/g++.dg/eh/builtin9.C @@ -1,13 +1,13 @@ // PR c++/88482 // { dg-do compile } -extern "C" int __cxa_throw (void *, void *, void (*) (void *)); // { dg-error "declared incorrectly" } -extern "C" void *__cxa_get_exception_ptr (void *); -extern "C" double __cxa_begin_catch (void *); // { dg-error "declared incorrectly" } -extern "C" long *__cxa_end_catch (); // { dg-error "declared incorrectly" } -extern "C" char __cxa_rethrow (); // { dg-error "declared incorrectly" } -extern "C" void __cxa_allocate_exception (__SIZE_TYPE__); // { dg-error "declared incorrectly" } -extern "C" void __cxa_free_exception (void *); +extern "C" int __cxa_throw (void *, void *, void (*) (void *)); // { dg-message "previous declaration" } +extern "C" void *__cxa_get_exception_ptr (void *) throw (); +extern "C" double __cxa_begin_catch (void *) throw (); // { dg-message "previous declaration" } +extern "C" long *__cxa_end_catch () throw (); // { dg-message "previous declaration" } +extern "C" char __cxa_rethrow (); // { dg-message "previous declaration" } +extern "C" void __cxa_allocate_exception (__SIZE_TYPE__) throw ();// { dg-message "previous declaration" } +extern "C" void __cxa_free_exception (void *) throw (); struct S { S (); S (const S &); ~S (); }; @@ -15,15 +15,15 @@ int foo (int x) { if (x > 27) - throw 19; + throw 19; // { dg-error "conflicting" } try { if (x > 15) throw S (); } - catch (S s) + catch (S s) // { dg-error "conflicting" } { - throw; + throw; // { dg-error "conflicting" } } return x + 3; } diff --git a/gcc/testsuite/g++.dg/parse/crash55.C b/gcc/testsuite/g++.dg/parse/crash55.C index 23ce203b3b5..2e88c476fc7 100644 --- a/gcc/testsuite/g++.dg/parse/crash55.C +++ b/gcc/testsuite/g++.dg/parse/crash55.C @@ -1,8 +1,8 @@ // PR c++/42038 -extern int __cxa_begin_catch; // { dg-error "declared incorrectly" } +extern int __cxa_begin_catch; // { dg-message "previous declaration" } void f(void) { - try { } catch (int) { } + try { } catch (int) { } // { dg-error "redeclared" } } -- 2.30.2