[PATCH] Remove NOTHROW from {,v}{,f}{print,scan}f, {,f}printf_unlocked and __{,v}{,f}printf_chk builtins

Jakub Jelinek jakub@redhat.com
Tue Sep 4 20:23:00 GMT 2007


On Tue, Sep 04, 2007 at 10:07:00AM -0700, Mark Mitchell wrote:
> > What we could do is when we see a prototype, update the NOTHROW state
> > not only of the DECL_ANTICIPATED builtin, but also its __builtin_* variant.
> 
> That seems like it might be an improvement.  I guess the problem is if
> __builtin_printf decides to go call "puts", and "puts" is declared to
> throw exceptions, even though "printf" is not.  So, presumably we don't
> set the bit on the builtin because we can't be sure it's safe.

Well, TREE_NOTHROW __builtin_printf and __builtin_puts with !TREE_NOTHROW
is what we had for the last 3 years, I don't remember any ICEs with it.
I tried e.g.:
struct A { A (); ~A (); };

inline int foo (const char *f)
{
  A a;
  __builtin_printf (f);
  return 0;
}

int bar ()
{
  return foo ("foo\n");
}

or just
int bar ()
{
  A a;
  __builtin_printf ("foo\n");
  return 0;
}

As long as we don't ICE here, I think we are fine, libraries that
have puts that can throw and printf that can't are IMHO broken.
Either both of them can throw, or neither can.

> > BTW, several other functions are already not NOTHROW for years:
> > http://gcc.gnu.org/ml/gcc-patches/2004-09/msg02897.html
> > it is just that the NOTHROW for the *printf has been not explicit
> > in builtins.def and therefore missed in the above patch.
> 
> Yes, I understand.  It might mean that we should do your patch, just to
> get everything into a consistent state -- but we still have a
> longer-term problem: how to avoid pessimizing code on all systems
> because, on some systems, thread cancellation is implemented as an
> exception.  I'd like to at least have a strategy here, unless it's the
> case that the builtins being nothrow doesn't offer us any advantage.

Ok, so how about following patch together with the earlier posted
builtins.def fix (http://gcc.gnu.org/ml/gcc-patches/2007-09/msg00103.html).

	Jakub
-------------- next part --------------
2007-09-04  Jakub Jelinek  <jakub@redhat.com>

	* decl.c (duplicate_decls): Set TREE_NOTHROW on __builtin_XX
	decl if a prototype for XX is provided with throw().

	PR c++/33289
	* decl.c (builtin_function_1): Set DECL_ANTICIPATED also
	on __*_chk non-__builtin_* decls.

	* g++.dg/eh/builtin1.C: New test.
	* g++.dg/eh/builtin2.C: New test.
	* g++.dg/eh/builtin3.C: New test.

	PR c++/33289
	* g++.dg/eh/builtin4.C: New test.

--- gcc/cp/decl.c.jj	2007-08-31 14:28:19.000000000 +0200
+++ gcc/cp/decl.c	2007-09-04 21:28:06.000000000 +0200
@@ -1280,6 +1280,18 @@ duplicate_decls (tree newdecl, tree oldd
 	  TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = type;
 	}
 
+      /* When there is explicit declaration of builtin with throw(),
+	 say printf, propagate TREE_NOTHROW even to the __builtin
+	 variant (__builtin_printf in this case).  */
+      if (DECL_BUILT_IN_CLASS (olddecl) == BUILT_IN_NORMAL
+	  && DECL_ANTICIPATED (olddecl)
+	  && TREE_NOTHROW (newdecl)
+	  && !TREE_NOTHROW (olddecl)
+	  && built_in_decls [DECL_FUNCTION_CODE (olddecl)] != NULL_TREE
+	  && built_in_decls [DECL_FUNCTION_CODE (olddecl)] != olddecl
+	  && types_match)
+	TREE_NOTHROW (built_in_decls [DECL_FUNCTION_CODE (olddecl)]) = 1;
+
       /* Whether or not the builtin can throw exceptions has no
 	 bearing on this declarator.  */
       TREE_NOTHROW (olddecl) = 0;
@@ -3517,6 +3529,17 @@ builtin_function_1 (tree decl, tree cont
      anticipated but not actually declared.  */
   if (name[0] != '_' || name[1] != '_')
     DECL_ANTICIPATED (decl) = 1;
+  else if (strncmp (name + 2, "builtin_", sizeof ("builtin_") - 1) != 0)
+    {
+      size_t len = strlen (name);
+
+      /* Treat __*_chk fortification functions as anticipated as well,
+	 unless they are __builtin_*.  */
+      if (len >= sizeof ("___chk")
+	  && memcmp (name + len - sizeof ("_chk") + 1,
+		     "_chk", sizeof ("_chk")) == 0)
+	DECL_ANTICIPATED (decl) = 1;
+    }
 
   return decl;
 }
--- gcc/testsuite/g++.dg/eh/builtin1.C.jj	2007-09-04 22:02:08.000000000 +0200
+++ gcc/testsuite/g++.dg/eh/builtin1.C	2007-09-04 22:02:04.000000000 +0200
@@ -0,0 +1,26 @@
+// Verify that if explicit prototype for builtin is present without throw(),
+// both the normal builtin and __builtin_* variant are expected to be
+// able to throw exceptions.
+// { dg-do compile }
+// { dg-options "-fdump-tree-eh" }
+
+extern "C" int printf (const char *, ...);
+
+struct A { A (); ~A (); int i; };
+
+int
+foo ()
+{
+  A a;
+  printf ("foo %d\n", a.i);
+}
+
+int
+bar ()
+{
+  A a;
+  __builtin_printf ("foo %d\n", a.i);
+}
+
+/* { dg-final { scan-tree-dump-times "resx 1" 2 "eh" } } */
+/* { dg-final { cleanup-tree-dump "eh" } } */
--- gcc/testsuite/g++.dg/eh/builtin2.C.jj	2007-09-04 22:02:59.000000000 +0200
+++ gcc/testsuite/g++.dg/eh/builtin2.C	2007-09-04 22:04:07.000000000 +0200
@@ -0,0 +1,25 @@
+// Verify that if explicit prototype for builtin is present with throw(),
+// neither the normal builtin nor __builtin_* variant can throw exceptions.
+// { dg-do compile }
+// { dg-options "-fdump-tree-eh" }
+
+extern "C" int printf (const char *, ...) throw();
+
+struct A { A (); ~A (); int i; };
+
+int
+foo ()
+{
+  A a;
+  printf ("foo %d\n", a.i);
+}
+
+int
+bar ()
+{
+  A a;
+  __builtin_printf ("foo %d\n", a.i);
+}
+
+/* { dg-final { scan-tree-dump-times "resx 1" 0 "eh" } } */
+/* { dg-final { cleanup-tree-dump "eh" } } */
--- gcc/testsuite/g++.dg/eh/builtin3.C.jj	2007-09-04 22:03:07.000000000 +0200
+++ gcc/testsuite/g++.dg/eh/builtin3.C	2007-09-04 22:03:56.000000000 +0200
@@ -0,0 +1,16 @@
+// Without explicit prototype, we need to assume the builtin can
+// throw for builtins that at least on one platform can throw.
+// { dg-do compile }
+// { dg-options "-fdump-tree-eh" }
+
+struct A { A (); ~A (); int i; };
+
+int
+bar ()
+{
+  A a;
+  __builtin_printf ("foo %d\n", a.i);
+}
+
+/* { dg-final { scan-tree-dump-times "resx 1" 1 "eh" } } */
+/* { dg-final { cleanup-tree-dump "eh" } } */
--- gcc/testsuite/g++.dg/eh/builtin4.C.jj	2007-09-04 22:06:06.000000000 +0200
+++ gcc/testsuite/g++.dg/eh/builtin4.C	2007-09-04 22:07:03.000000000 +0200
@@ -0,0 +1,6 @@
+// PR c++/33289
+// { dg-do compile }
+
+typedef __SIZE_TYPE__ size_t;
+extern "C" int __sprintf_chk (char *__restrict, int, size_t, const char *, ...) throw ();
+extern "C" int __sprintf_chk (char *__restrict, int, size_t, const char *, ...) throw ();


More information about the Gcc-patches mailing list