aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@acm.org>2020-07-06 09:54:40 -0700
committerNathan Sidwell <nathan@acm.org>2020-07-06 10:02:46 -0700
commite88218fd5a21e44c77c10dec87af4b11c76f34a0 (patch)
treeee1cbca72c47e5a0af0ae3e8193b043751aea610
parentf2151227dfe90a5fe73297c370786be98b0b090f (diff)
downloadgcc-e88218fd5a21e44c77c10dec87af4b11c76f34a0.zip
gcc-e88218fd5a21e44c77c10dec87af4b11c76f34a0.tar.gz
gcc-e88218fd5a21e44c77c10dec87af4b11c76f34a0.tar.bz2
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.
-rw-r--r--gcc/cp/decl.c7
-rw-r--r--gcc/cp/except.c162
-rw-r--r--gcc/testsuite/g++.dg/eh/builtin10.C12
-rw-r--r--gcc/testsuite/g++.dg/eh/builtin11.C20
-rw-r--r--gcc/testsuite/g++.dg/eh/builtin5.C8
-rw-r--r--gcc/testsuite/g++.dg/eh/builtin6.C16
-rw-r--r--gcc/testsuite/g++.dg/eh/builtin7.C12
-rw-r--r--gcc/testsuite/g++.dg/eh/builtin9.C20
-rw-r--r--gcc/testsuite/g++.dg/parse/crash55.C4
9 files changed, 90 insertions, 171 deletions
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 1eb5c2a..60a09e9 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 9e1aa50..aca54f1 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 8c48e3d..6c34f1f 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 fb1d4f3..abc8c1a 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 eec6f25..1ab9c74 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 a70b406..c05abdc 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 ad9c7f6..0ef279d 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 acd1a5e..591a622 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 23ce203..2e88c47 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" }
}