objective-c++, C++ exceptions, and objc_msgsend

Geoffrey Keating gkeating@apple.com
Fri Oct 21 01:28:00 GMT 2005


The objc_msgsend* builtins are marked as TREE_NOTHROW in C++ by
default, like all builtins, but because these functions can (in fact,
always do) call user functions, they can throw.

This testcase is a regression relative to gcc 3.4, because before then
the optimisers wouldn't notice that no exceptions were possible and
so wouldn't remove the try/catch statement.

Bootstrapped & tested on powerpc-darwin8.

-- 
- Geoffrey Keating <geoffk@apple.com>

===File ~/patches/gcc-4308031.patch=========================
Index: objc/ChangeLog
2005-10-20  Geoffrey Keating  <geoffk@apple.com>

	* objc-act.c (synth_module_prologue): Clear TREE_NOTHROW
	on objc_msgSend and like builtin functions.

Index: testsuite/ChangeLog
2005-10-20  Geoffrey Keating  <geoffk@apple.com>

	* obj-c++.dg/except-1.mm: New.

Index: objc/objc-act.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/objc/objc-act.c,v
retrieving revision 1.292
diff -u -p -u -p -r1.292 objc-act.c
--- objc/objc-act.c	17 Oct 2005 14:51:03 -0000	1.292
+++ objc/objc-act.c	21 Oct 2005 00:00:20 -0000
@@ -1597,6 +1597,10 @@ synth_module_prologue (void)
 		       (xref_tag (RECORD_TYPE,
 				  get_identifier (UTAG_IVAR_LIST)));
 
+  /* TREE_NOTHROW is cleared for the message-sending functions,
+     because the function that gets called can throw in Obj-C++, or
+     could itself call something that can throw even in Obj-C.  */
+
   if (flag_next_runtime)
     {
       /* NB: In order to call one of the ..._stret (struct-returning)
@@ -1626,12 +1630,21 @@ synth_module_prologue (void)
 						 type, 0, NOT_BUILT_IN,
 						 NULL, NULL_TREE);
 
+      /* These can throw, because the function that gets called can throw
+	 in Obj-C++, or could itself call something that can throw even
+	 in Obj-C.  */
+      TREE_NOTHROW (umsg_decl) = 0;
+      TREE_NOTHROW (umsg_nonnil_decl) = 0;
+      TREE_NOTHROW (umsg_stret_decl) = 0;
+      TREE_NOTHROW (umsg_nonnil_stret_decl) = 0;
+
       /* id objc_msgSend_Fast (id, SEL, ...)
 	   __attribute__ ((hard_coded_address (OFFS_MSGSEND_FAST))); */
 #ifdef OFFS_MSGSEND_FAST
       umsg_fast_decl = builtin_function (TAG_MSGSEND_FAST,
 					 type, 0, NOT_BUILT_IN,
 					 NULL, NULL_TREE);
+      TREE_NOTHROW (umsg_fast_decl) = 0;
       DECL_ATTRIBUTES (umsg_fast_decl) 
 	= tree_cons (get_identifier ("hard_coded_address"), 
 		     build_int_cst (NULL_TREE, OFFS_MSGSEND_FAST),
@@ -1654,6 +1667,8 @@ synth_module_prologue (void)
       umsg_super_stret_decl = builtin_function (TAG_MSGSENDSUPER_STRET,
 						type, 0, NOT_BUILT_IN, 0,
 						NULL_TREE);
+      TREE_NOTHROW (umsg_super_decl) = 0;
+      TREE_NOTHROW (umsg_super_stret_decl) = 0;
     }
   else
     {
@@ -1676,6 +1691,7 @@ synth_module_prologue (void)
       umsg_decl = builtin_function (TAG_MSGSEND,
 				    type, 0, NOT_BUILT_IN,
 				    NULL, NULL_TREE);
+      TREE_NOTHROW (umsg_decl) = 0;
 
       /* IMP objc_msg_lookup_super (struct objc_super *, SEL); */
       type
@@ -1686,6 +1702,7 @@ synth_module_prologue (void)
       umsg_super_decl = builtin_function (TAG_MSGSENDSUPER,
 					  type, 0, NOT_BUILT_IN,
 					  NULL, NULL_TREE);
+      TREE_NOTHROW (umsg_super_decl) = 0;
 
       /* The following GNU runtime entry point is called to initialize
 	 each module:
Index: testsuite/obj-c++.dg/except-1.mm
===================================================================
RCS file: testsuite/obj-c++.dg/except-1.mm
diff -N testsuite/obj-c++.dg/except-1.mm
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/obj-c++.dg/except-1.mm	21 Oct 2005 00:00:24 -0000
@@ -0,0 +1,65 @@
+/* { dg-do run { target "*-*-darwin*" } } */
+/* { dg-options "-framework Foundation" } */
+
+/* This tests that exceptions work.  It used to fail because
+   objc_msgSend was marked with DECL_NOTHROW. 
+   If you include objc/Object.h, the problem goes away, because
+   that file includes objc/objc-runtime.h which explicitly prototypes
+   objc_msgSend without 'nothrow'.  */
+
+#include <Foundation/Foundation.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// ObjectiveC class header
+@interface ObjCclass : NSObject {
+}
+-(void)method1;
+-(void)method2;
+@end
+
+// C++ class header
+class CPPclass {
+public:
+	void function1();
+};
+
+
+// Main
+int main(int argc, char *argv[])
+{
+	ObjCclass * foo = [[ObjCclass alloc] init];
+	[foo method1];
+	exit (0);
+}
+
+
+// ObjectiveC implementation
+@implementation ObjCclass
+
+-(void) method1
+{
+	try {
+		[self method2];
+	}
+	catch(...) {
+		return;
+	}
+}
+
+-(void) method2
+{
+	CPPclass foo;
+	foo.function1();
+}
+
+@end
+
+
+// C++ implementation
+void CPPclass::function1()
+{
+	throw (1);
+	/* Shouldn't be here because we threw.  */
+	abort ();
+}
============================================================



More information about the Gcc-patches mailing list