c++: Always use pushdecl for exception library helpers
authorNathan Sidwell <nathan@acm.org>
Mon, 6 Jul 2020 16:54:40 +0000 (09:54 -0700)
committerNathan Sidwell <nathan@acm.org>
Mon, 6 Jul 2020 17:02:46 +0000 (10:02 -0700)
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
gcc/cp/except.c
gcc/testsuite/g++.dg/eh/builtin10.C
gcc/testsuite/g++.dg/eh/builtin11.C
gcc/testsuite/g++.dg/eh/builtin5.C
gcc/testsuite/g++.dg/eh/builtin6.C
gcc/testsuite/g++.dg/eh/builtin7.C
gcc/testsuite/g++.dg/eh/builtin9.C
gcc/testsuite/g++.dg/parse/crash55.C

index 1eb5c2a29ac48998d81a64fb3aa55478442311f5..60a09e9497a6f4741992d0fa0c47a7d0e62620ae 100644 (file)
@@ -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
index 9e1aa5085d492ce5a2bfcaabd8998bc6de7e1b13..aca54f136ba1e5095b6cbd1f5d3fec83f5846615 100644 (file)
@@ -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"));
        }
index 8c48e3de6d3892691cdeb0e727e27423e3cc5cf2..6c34f1f6d5cd5bddcbf687a2fd56137ea533c31b 100644 (file)
@@ -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;
     }
index fb1d4f38ab302e7ca3363353a808280307a35a84..abc8c1af535aa4ea4c05b3411b21e10fe8d94fec 100644 (file)
@@ -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;
 }
index eec6f2509a59f680ce3f3048867ff2d4f81d7edb..1ab9c7498671267071dbc803748d370282035326 100644 (file)
@@ -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 (); };
 
index a70b406cf848784c72dcc69f0fec242bdde34cb3..c05abdc8f51b6672a629405d84a944f0a96fd6ee 100644 (file)
@@ -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;
 }
index ad9c7f6802db44d9586aa742c220dbff5f3cb0c2..0ef279d09c1b39e0514dbdeab75e29a4f2da2b0c 100644 (file)
@@ -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;
     }
index acd1a5e7dd63ba501bb539ca301e4ac3d630af3d..591a622630ce2dc3176eb9edcb5b0f7cf86fa95b 100644 (file)
@@ -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;
 }
index 23ce203b3b5ef6bf316d0ea89efe186f843d754c..2e88c476fc7aafd2bc00ad655c01c483d26d03db 100644 (file)
@@ -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"  }
 }