OSDN Git Service

In gcc/objc/:
authornicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 29 Nov 2010 03:15:40 +0000 (03:15 +0000)
committernicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 29 Nov 2010 03:15:40 +0000 (03:15 +0000)
2010-11-29  Nicola Pero  <nicola.pero@meta-innovation.com>

* objc-act.c (objc_eh_runtime_type): Avoid ICE if error_mark_node
is passed as argument.
(objc_begin_catch_clause): Added code to deal with an
error_mark_node or NULL_TREE argument.  Improved checks for
invalid arguments.  Added code to traverse typedefs.

In gcc/testsuite/:
2010-11-29  Nicola Pero  <nicola.pero@meta-innovation.com>

* objc.dg/exceptions-1.m: New.
* objc.dg/exceptions-2.m: New.
* objc.dg/exceptions-3.m: New.
* objc.dg/exceptions-4.m: New.
* objc.dg/exceptions-5.m: New.
* obj-c++.dg/exceptions-1.mm: New.
* obj-c++.dg/exceptions-2.mm: New.
* obj-c++.dg/exceptions-3.mm: New.
* obj-c++.dg/exceptions-4.mm: New.
* obj-c++.dg/exceptions-5.mm: New.

In gcc/cp/:
2010-11-29  Nicola Pero  <nicola.pero@meta-innovation.com>

* parser.c (cp_parser_objc_try_catch_finally_statement): Parse
@catch(...)  and pass NULL_TREE to objc_begin_catch_clause() in
that case.  Improved error recovery.  Reorganized code to be
almost identical to c_parser_objc_try_catch_finally_statement.

In gcc/:
2010-11-29  Nicola Pero  <nicola.pero@meta-innovation.com>

* c-parser.c (c_parser_objc_try_catch_statement): Renamed to
c_parser_objc_try_catch_finally_statement for consistency with the
C++ parser.  Parse @catch(...) and pass NULL_TREE to
objc_begin_catch_clause() in that case.  Improved error recovery.
Reorganized code to be almost identical to
cp_parser_objc_try_catch_finally_statement.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@167233 138bc75d-0d04-0410-961f-82ee72b054a4

17 files changed:
gcc/ChangeLog
gcc/c-parser.c
gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/objc/ChangeLog
gcc/objc/objc-act.c
gcc/testsuite/ChangeLog
gcc/testsuite/obj-c++.dg/exceptions-1.mm [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/exceptions-2.mm [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/exceptions-3.mm [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/exceptions-4.mm [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/exceptions-5.mm [new file with mode: 0644]
gcc/testsuite/objc.dg/exceptions-1.m [new file with mode: 0644]
gcc/testsuite/objc.dg/exceptions-2.m [new file with mode: 0644]
gcc/testsuite/objc.dg/exceptions-3.m [new file with mode: 0644]
gcc/testsuite/objc.dg/exceptions-4.m [new file with mode: 0644]
gcc/testsuite/objc.dg/exceptions-5.m [new file with mode: 0644]

index bf82ac9..c20e57e 100644 (file)
@@ -1,3 +1,12 @@
+2010-11-29  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+       * c-parser.c (c_parser_objc_try_catch_statement): Renamed to
+       c_parser_objc_try_catch_finally_statement for consistency with the
+       C++ parser.  Parse @catch(...) and pass NULL_TREE to
+       objc_begin_catch_clause() in that case.  Improved error recovery.
+       Reorganized code to be almost identical to
+       cp_parser_objc_try_catch_finally_statement.
+       
 2010-11-29  Joern Rennecke  <amylaar@spamcop.net>
 
        PR tree-optimization/46621
index c63f001..879e106 100644 (file)
@@ -1155,7 +1155,7 @@ static void c_parser_objc_methodproto (c_parser *);
 static tree c_parser_objc_method_decl (c_parser *, bool, tree *);
 static tree c_parser_objc_type_name (c_parser *);
 static tree c_parser_objc_protocol_refs (c_parser *);
-static void c_parser_objc_try_catch_statement (c_parser *);
+static void c_parser_objc_try_catch_finally_statement (c_parser *);
 static void c_parser_objc_synchronized_statement (c_parser *);
 static tree c_parser_objc_selector (c_parser *);
 static tree c_parser_objc_selector_arg (c_parser *);
@@ -4371,7 +4371,7 @@ c_parser_statement_after_labels (c_parser *parser)
          break;
        case RID_AT_TRY:
          gcc_assert (c_dialect_objc ());
-         c_parser_objc_try_catch_statement (parser);
+         c_parser_objc_try_catch_finally_statement (parser);
          break;
        case RID_AT_SYNCHRONIZED:
          gcc_assert (c_dialect_objc ());
@@ -7468,53 +7468,97 @@ c_parser_objc_protocol_refs (c_parser *parser)
   return list;
 }
 
-/* Parse an objc-try-catch-statement.
+/* Parse an objc-try-catch-finally-statement.
 
-   objc-try-catch-statement:
+   objc-try-catch-finally-statement:
      @try compound-statement objc-catch-list[opt]
      @try compound-statement objc-catch-list[opt] @finally compound-statement
 
    objc-catch-list:
-     @catch ( parameter-declaration ) compound-statement
-     objc-catch-list @catch ( parameter-declaration ) compound-statement
-*/
+     @catch ( objc-catch-parameter-declaration ) compound-statement
+     objc-catch-list @catch ( objc-catch-parameter-declaration ) compound-statement
+
+   objc-catch-parameter-declaration:
+     parameter-declaration
+     '...'
+
+   where '...' is to be interpreted literally, that is, it means CPP_ELLIPSIS.
+
+   PS: This function is identical to cp_parser_objc_try_catch_finally_statement
+   for C++.  Keep them in sync.  */   
 
 static void
-c_parser_objc_try_catch_statement (c_parser *parser)
+c_parser_objc_try_catch_finally_statement (c_parser *parser)
 {
-  location_t loc;
+  location_t location;
   tree stmt;
+
   gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_TRY));
   c_parser_consume_token (parser);
-  loc = c_parser_peek_token (parser)->location;
+  location = c_parser_peek_token (parser)->location;
   stmt = c_parser_compound_statement (parser);
-  objc_begin_try_stmt (loc, stmt);
+  objc_begin_try_stmt (location, stmt);
+
   while (c_parser_next_token_is_keyword (parser, RID_AT_CATCH))
     {
       struct c_parm *parm;
+      tree parameter_declaration = error_mark_node;
+      bool seen_open_paren = false;
+
       c_parser_consume_token (parser);
       if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
-       break;
-      parm = c_parser_parameter_declaration (parser, NULL_TREE);
-      if (parm == NULL)
+       seen_open_paren = true;
+      if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
        {
-         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
-         break;
+         /* We have "@catch (...)" (where the '...' are literally
+            what is in the code).  Skip the '...'.
+            parameter_declaration is set to NULL_TREE, and
+            objc_being_catch_clauses() knows that that means
+            '...'.  */
+         c_parser_consume_token (parser);
+         parameter_declaration = NULL_TREE;
        }
-      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
-      objc_begin_catch_clause (grokparm (parm));
+      else
+       {
+         /* We have "@catch (NSException *exception)" or something
+            like that.  Parse the parameter declaration.  */
+         parm = c_parser_parameter_declaration (parser, NULL_TREE);
+         if (parm == NULL)
+           parameter_declaration = error_mark_node;
+         else
+           parameter_declaration = grokparm (parm);
+       }
+      if (seen_open_paren)
+       c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+      else
+       {
+         /* If there was no open parenthesis, we are recovering from
+            an error, and we are trying to figure out what mistake
+            the user has made.  */
+
+         /* If there is an immediate closing parenthesis, the user
+            probably forgot the opening one (ie, they typed "@catch
+            NSException *e)".  Parse the closing parenthesis and keep
+            going.  */
+         if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+           c_parser_consume_token (parser);
+         
+         /* If these is no immediate closing parenthesis, the user
+            probably doesn't know that parenthesis are required at
+            all (ie, they typed "@catch NSException *e").  So, just
+            forget about the closing parenthesis and keep going.  */
+       }
+      objc_begin_catch_clause (parameter_declaration);
       if (c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
        c_parser_compound_statement_nostart (parser);
       objc_finish_catch_clause ();
     }
   if (c_parser_next_token_is_keyword (parser, RID_AT_FINALLY))
     {
-      location_t finloc;
-      tree finstmt;
       c_parser_consume_token (parser);
-      finloc = c_parser_peek_token (parser)->location;
-      finstmt = c_parser_compound_statement (parser);
-      objc_build_finally_clause (finloc, finstmt);
+      location = c_parser_peek_token (parser)->location;
+      stmt = c_parser_compound_statement (parser);
+      objc_build_finally_clause (location, stmt);
     }
   objc_finish_try_stmt ();
 }
index 6422401..6e3bbbe 100644 (file)
@@ -1,3 +1,10 @@
+2010-11-29  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+       * parser.c (cp_parser_objc_try_catch_finally_statement): Parse
+       @catch(...)  and pass NULL_TREE to objc_begin_catch_clause() in
+       that case.  Improved error recovery.  Reorganized code to be
+       almost identical to c_parser_objc_try_catch_finally_statement.
+
 2010-11-27  Nicola Pero  <nicola.pero@meta-innovation.com>
 
        PR objc++/46222
index 3ed0579..917f750 100644 (file)
@@ -22598,15 +22598,25 @@ cp_parser_objc_declaration (cp_parser* parser, tree attributes)
      objc-catch-clause objc-catch-clause-seq [opt]
 
    objc-catch-clause:
-     @catch ( exception-declaration ) compound-statement
+     @catch ( objc-exception-declaration ) compound-statement
 
-   objc-finally-clause
+   objc-finally-clause:
      @finally compound-statement
 
-   Returns NULL_TREE.  */
+   objc-exception-declaration:
+     parameter-declaration
+     '...'
+
+   where '...' is to be interpreted literally, that is, it means CPP_ELLIPSIS.
+
+   Returns NULL_TREE.
+
+   PS: This function is identical to c_parser_objc_try_catch_finally_statement
+   for C.  Keep them in sync.  */   
 
 static tree
-cp_parser_objc_try_catch_finally_statement (cp_parser *parser) {
+cp_parser_objc_try_catch_finally_statement (cp_parser *parser)
+{
   location_t location;
   tree stmt;
 
@@ -22620,22 +22630,60 @@ cp_parser_objc_try_catch_finally_statement (cp_parser *parser) {
 
   while (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_CATCH))
     {
-      cp_parameter_declarator *parmdecl;
-      tree parm;
+      cp_parameter_declarator *parm;
+      tree parameter_declaration = error_mark_node;
+      bool seen_open_paren = false;
 
       cp_lexer_consume_token (parser->lexer);
-      cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
-      parmdecl = cp_parser_parameter_declaration (parser, false, NULL);
-      parm = grokdeclarator (parmdecl->declarator,
-                            &parmdecl->decl_specifiers,
-                            PARM, /*initialized=*/0,
-                            /*attrlist=*/NULL);
-      cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
-      objc_begin_catch_clause (parm);
+      if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+       seen_open_paren = true;
+      if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+       {
+         /* We have "@catch (...)" (where the '...' are literally
+            what is in the code).  Skip the '...'.
+            parameter_declaration is set to NULL_TREE, and
+            objc_being_catch_clauses() knows that that means
+            '...'.  */
+         cp_lexer_consume_token (parser->lexer);
+         parameter_declaration = NULL_TREE;
+       }
+      else
+       {
+         /* We have "@catch (NSException *exception)" or something
+            like that.  Parse the parameter declaration.  */
+         parm = cp_parser_parameter_declaration (parser, false, NULL);
+         if (parm == NULL)
+           parameter_declaration = error_mark_node;
+         else
+           parameter_declaration = grokdeclarator (parm->declarator,
+                                                   &parm->decl_specifiers,
+                                                   PARM, /*initialized=*/0,
+                                                   /*attrlist=*/NULL);
+       }
+      if (seen_open_paren)
+       cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
+      else
+       {
+         /* If there was no open parenthesis, we are recovering from
+            an error, and we are trying to figure out what mistake
+            the user has made.  */
+
+         /* If there is an immediate closing parenthesis, the user
+            probably forgot the opening one (ie, they typed "@catch
+            NSException *e)".  Parse the closing parenthesis and keep
+            going.  */
+         if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
+           cp_lexer_consume_token (parser->lexer);
+         
+         /* If these is no immediate closing parenthesis, the user
+            probably doesn't know that parenthesis are required at
+            all (ie, they typed "@catch NSException *e").  So, just
+            forget about the closing parenthesis and keep going.  */
+       }
+      objc_begin_catch_clause (parameter_declaration);
       cp_parser_compound_statement (parser, NULL, false);
       objc_finish_catch_clause ();
     }
-
   if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_FINALLY))
     {
       cp_lexer_consume_token (parser->lexer);
index ca2833c..644129b 100644 (file)
@@ -1,5 +1,13 @@
 2010-11-29  Nicola Pero  <nicola.pero@meta-innovation.com>
 
+       * objc-act.c (objc_eh_runtime_type): Avoid ICE if error_mark_node
+       is passed as argument.
+       (objc_begin_catch_clause): Added code to deal with an
+       error_mark_node or NULL_TREE argument.  Improved checks for
+       invalid arguments.  Added code to traverse typedefs.
+
+2010-11-29  Nicola Pero  <nicola.pero@meta-innovation.com>
+
        * objc-act.c (objc_demangle): Return immediately if the string is
        too short.  Detect names that do not need demangling, and return
        them unchanged.
index 09f4e6f..810a53a 100644 (file)
@@ -5024,7 +5024,14 @@ static GTY(()) tree objc_eh_personality_decl;
 tree
 objc_eh_runtime_type (tree type)
 {
-  return add_objc_string (OBJC_TYPE_NAME (TREE_TYPE (type)), class_names);
+  /* Use 'ErrorMarkNode' as class name when error_mark_node is found
+     to prevent an ICE.  Note that we know that the compiler will
+     terminate with an error and this 'ErrorMarkNode' class name will
+     never be actually used.  */
+  if (type == error_mark_node)
+    return add_objc_string (get_identifier ("ErrorMarkNode"), class_names);
+  else
+    return add_objc_string (OBJC_TYPE_NAME (TREE_TYPE (type)), class_names);
 }
 
 tree
@@ -5355,7 +5362,9 @@ objc_begin_try_stmt (location_t try_locus, tree body)
 
 /* Called just after parsing "@catch (parm)".  Open a binding level,
    enter DECL into the binding level, and initialize it.  Leave the
-   binding level open while the body of the compound statement is parsed.  */
+   binding level open while the body of the compound statement is
+   parsed.  If DECL is NULL_TREE, then we are compiling "@catch(...)"
+   which we compile as "@catch(id tmp_variable)".  */
 
 void
 objc_begin_catch_clause (tree decl)
@@ -5365,46 +5374,99 @@ objc_begin_catch_clause (tree decl)
   /* Begin a new scope that the entire catch clause will live in.  */
   compound = c_begin_compound_stmt (true);
 
-  /* The parser passed in a PARM_DECL, but what we really want is a VAR_DECL.  */
-  decl = build_decl (input_location,
-                    VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
-  lang_hooks.decls.pushdecl (decl);
+  /* Create the appropriate declaration for the argument.  */
+ if (decl == error_mark_node)
+   type = error_mark_node;
+ else
+   {
+     if (decl == NULL_TREE)
+       {
+        /* If @catch(...) was specified, create a temporary variable of
+           type 'id' and use it.  */
+        decl = objc_create_temporary_var (objc_object_type, "__objc_generic_catch_var");
+        DECL_SOURCE_LOCATION (decl) = input_location;
+       }
+     else
+       {
+        /* The parser passed in a PARM_DECL, but what we really want is a VAR_DECL.  */
+        decl = build_decl (input_location,
+                           VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
+       }
+     lang_hooks.decls.pushdecl (decl);
 
-  /* Since a decl is required here by syntax, don't warn if its unused.  */
-  /* ??? As opposed to __attribute__((unused))?  Anyway, this appears to
-     be what the previous objc implementation did.  */
-  TREE_USED (decl) = 1;
-  DECL_READ_P (decl) = 1;
+     /* Mark the declaration as used so you never any warnings whether
+       you use the exception argument or not.  TODO: Implement a
+       -Wunused-exception-parameter flag, which would cause warnings
+       if exception parameter is not used.  */
+     TREE_USED (decl) = 1;
+     DECL_READ_P (decl) = 1;
 
-  /* Verify that the type of the catch is valid.  It must be a pointer
-     to an Objective-C class, or "id" (which is catch-all).  */
-  type = TREE_TYPE (decl);
+     type = TREE_TYPE (decl);
+   }
 
-  if (POINTER_TYPE_P (type) && objc_is_object_id (TREE_TYPE (type)))
-    type = NULL;
-  else if (!POINTER_TYPE_P (type) || !TYPED_OBJECT (TREE_TYPE (type)))
+ /* Verify that the type of the catch is valid.  It must be a pointer
+    to an Objective-C class, or "id" (which is catch-all).  */
+ if (type == error_mark_node)
+   {
+     ;/* Just keep going.  */
+   }
+ else if (!objc_type_valid_for_messaging (type, false))
     {
       error ("@catch parameter is not a known Objective-C class type");
       type = error_mark_node;
     }
-  else if (cur_try_context->catch_list)
+  else if (TYPE_HAS_OBJC_INFO (TREE_TYPE (type))
+          && TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (type)))
     {
-      /* Examine previous @catch clauses and see if we've already
-        caught the type in question.  */
-      tree_stmt_iterator i = tsi_start (cur_try_context->catch_list);
-      for (; !tsi_end_p (i); tsi_next (&i))
+      error ("@catch parameter can not be protocol-qualified");
+      type = error_mark_node;      
+    }
+  else if (objc_is_object_id (TREE_TYPE (type)))
+    type = NULL;
+  else
+    {
+      /* If 'type' was built using typedefs, we need to get rid of
+        them and get a simple pointer to the class.  */
+      bool is_typedef = false;
+      tree x = TYPE_MAIN_VARIANT (type);
+      
+      /* Skip from the pointer to the pointee.  */
+      if (TREE_CODE (x) == POINTER_TYPE)
+       x = TREE_TYPE (x);
+      
+      /* Traverse typedef aliases */
+      while (TREE_CODE (x) == RECORD_TYPE && OBJC_TYPE_NAME (x)
+            && TREE_CODE (OBJC_TYPE_NAME (x)) == TYPE_DECL
+            && DECL_ORIGINAL_TYPE (OBJC_TYPE_NAME (x)))
        {
-         tree stmt = tsi_stmt (i);
-         t = CATCH_TYPES (stmt);
-         if (t == error_mark_node)
-           continue;
-         if (!t || DERIVED_FROM_P (TREE_TYPE (t), TREE_TYPE (type)))
+         is_typedef = true;
+         x = DECL_ORIGINAL_TYPE (OBJC_TYPE_NAME (x));
+       }
+
+      /* If it was a typedef, build a pointer to the final, original
+        class.  */
+      if (is_typedef)
+       type = build_pointer_type (x);
+
+      if (cur_try_context->catch_list)
+       {
+         /* Examine previous @catch clauses and see if we've already
+            caught the type in question.  */
+         tree_stmt_iterator i = tsi_start (cur_try_context->catch_list);
+         for (; !tsi_end_p (i); tsi_next (&i))
            {
-             warning (0, "exception of type %<%T%> will be caught",
-                      TREE_TYPE (type));
-             warning_at  (EXPR_LOCATION (stmt), 0, "   by earlier handler for %<%T%>",
-                          TREE_TYPE (t ? t : objc_object_type));
-             break;
+             tree stmt = tsi_stmt (i);
+             t = CATCH_TYPES (stmt);
+             if (t == error_mark_node)
+               continue;
+             if (!t || DERIVED_FROM_P (TREE_TYPE (t), TREE_TYPE (type)))
+               {
+                 warning (0, "exception of type %<%T%> will be caught",
+                          TREE_TYPE (type));
+                 warning_at  (EXPR_LOCATION (stmt), 0, "   by earlier handler for %<%T%>",
+                              TREE_TYPE (t ? t : objc_object_type));
+                 break;
+               }
            }
        }
     }
index c7830eb..6185f59 100644 (file)
@@ -1,5 +1,18 @@
 2010-11-29  Nicola Pero  <nicola.pero@meta-innovation.com>
 
+       * objc.dg/exceptions-1.m: New.
+       * objc.dg/exceptions-2.m: New.
+       * objc.dg/exceptions-3.m: New.
+       * objc.dg/exceptions-4.m: New.
+       * objc.dg/exceptions-5.m: New.
+       * obj-c++.dg/exceptions-1.mm: New.
+       * obj-c++.dg/exceptions-2.mm: New.
+       * obj-c++.dg/exceptions-3.mm: New.
+       * obj-c++.dg/exceptions-4.mm: New.
+       * obj-c++.dg/exceptions-5.mm: New.
+
+2010-11-29  Nicola Pero  <nicola.pero@meta-innovation.com>
+
        * obj-c++.dg/property/at-property-1.mm: Fixed testcase.
        * obj-c++.dg/property/at-property-16.mm: Fixed testcase.
        * obj-c++.dg/property/at-property-20.mm: Fixed testcase.
diff --git a/gcc/testsuite/obj-c++.dg/exceptions-1.mm b/gcc/testsuite/obj-c++.dg/exceptions-1.mm
new file mode 100644 (file)
index 0000000..0f3b7e8
--- /dev/null
@@ -0,0 +1,42 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-options "-fobjc-exceptions" } */
+/* { dg-do compile } */
+
+/* This test checks the syntax @catch (...) which catches any
+   exceptions.  At the moment, @catch (...) is identical to @catch (id
+   exception).  */
+
+#include <objc/objc.h>
+
+@interface MyObject
+{
+  Class isa;
+}
+@end
+
+@implementation MyObject
+@end
+
+int test (id object)
+{
+  int i = 0;
+
+  @try
+    {
+      @throw object;
+    }
+  @catch (MyObject *o)
+    {
+      i += 1;
+    }
+  @catch (...)
+    {
+      i += 2;
+    }
+  @finally
+    {
+      i += 4;
+    }
+
+  return i;
+}
diff --git a/gcc/testsuite/obj-c++.dg/exceptions-2.mm b/gcc/testsuite/obj-c++.dg/exceptions-2.mm
new file mode 100644 (file)
index 0000000..ce85b73
--- /dev/null
@@ -0,0 +1,54 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-options "-fobjc-exceptions" } */
+
+/* FIXME: This does not test running the code, because Objective-C exceptions at the moment
+   do not execute correctly in Objective-C++.  See PR objc++/23616.  Once that is fixed,
+   this test should be changed to use 'dg-run' instead of just 'dg-compile'.  */
+/* { dg-compile } */
+
+/* This test checks the syntax @catch (...) which catches any
+   exceptions.  Check that code using it runs correctly.  */
+
+#include "../objc-obj-c++-shared/Object1.h"
+#include <stdlib.h>
+
+@interface MyObject : Object
+@end
+
+@implementation MyObject
+@end
+
+int test (id object)
+{
+  int i = 0;
+
+  @try
+    {
+      @throw object;
+    }
+  @catch (MyObject *o)
+    {
+      i += 1;
+    }
+  @catch (...)
+    {
+      i += 2;
+    }
+  @finally
+    {
+      i += 4;
+    }
+
+  return i;
+}
+
+int main (void)
+{
+  if (test ([MyObject new]) != 5)
+    abort ();
+
+  if (test ([Object new]) != 6)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/obj-c++.dg/exceptions-3.mm b/gcc/testsuite/obj-c++.dg/exceptions-3.mm
new file mode 100644 (file)
index 0000000..b1ba185
--- /dev/null
@@ -0,0 +1,114 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-options "-fobjc-exceptions" } */
+/* { dg-do compile } */
+
+/* Test that the compiler is checking the argument of @catch(), and
+   produce errors when invalid types are used.  */
+
+#include <objc/objc.h>
+
+@interface MyObject
+{
+  Class isa;
+}
+@end
+
+@implementation MyObject
+@end
+
+@protocol MyProtocol;
+
+typedef MyObject MyObjectTypedef;
+typedef MyObject *MyObjectPtrTypedef;
+typedef int intTypedef;
+
+int test (id object)
+{
+  int dummy = 0;
+
+  @try { @throw object; }
+  @catch (int x)          /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (intTypedef x)   /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (int *x)         /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {
+      dummy++;
+    }  
+
+  @try { @throw object; }
+  @catch (id x)           /* Ok */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (id <MyProtocol> x) /* { dg-error "@catch parameter can not be protocol-qualified" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObject *x)    /* Ok */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObject <MyProtocol> *x)  /* { dg-error "@catch parameter can not be protocol-qualified" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObject x)     /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {                     /* { dg-error "no matching function" "" { target *-*-* } 72 } */
+      dummy++;            /* { dg-warning "MyObject" "" { target *-*-* } 13 } */
+    }
+
+  @try { @throw object; }
+  @catch (static MyObject *x) /* { dg-error "storage class" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObjectTypedef *x) /* Ok */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObjectTypedef <MyProtocol> *x) /* { dg-error "@catch parameter can not be protocol-qualified" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObjectPtrTypedef x) /* Ok */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (Class x)   /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (...)            /* Ok */
+    {
+      dummy++;
+    }
+
+  return dummy;
+}
diff --git a/gcc/testsuite/obj-c++.dg/exceptions-4.mm b/gcc/testsuite/obj-c++.dg/exceptions-4.mm
new file mode 100644 (file)
index 0000000..85debe4
--- /dev/null
@@ -0,0 +1,64 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-options "-fobjc-exceptions" } */
+/* { dg-do compile } */
+
+/* Test warnings when parsing syntax errors in @catch().  */
+
+#include <objc/objc.h>
+
+@interface MyObject
+{
+  Class isa;
+}
+@end
+
+@implementation MyObject
+@end
+
+@interface MyObject2
+{
+  Class isa;
+}
+@end
+
+@implementation MyObject2
+@end
+
+@protocol MyProtocol;
+
+int test (id object)
+{
+  int dummy = 0;
+
+  @try { @throw object; }
+  @catch
+    {          /* { dg-error "expected" } */
+      dummy++; /* { dg-error "@catch parameter is not a known Objective-C class type" "" { target *-*-* } 35 } */
+    }
+  @catch ()  /* { dg-error "expected identifier before" } */
+    {        /* { dg-error "@catch parameter is not a known Objective-C class type" "" { target *-*-* } 38 } */
+      dummy++;
+    }
+  @catch (i) /* { dg-error ".i. has not been declared" } */
+    {        /* { dg-error "@catch parameter is not a known Objective-C class type" "" { target *-*-* } 42 } */
+      dummy++;
+    }
+  @catch (id <MyProtocol x) /* { dg-error "expected ... before .x." } */
+    {                       /* { dg-error "@catch parameter can not be protocol-qualified" "" { target *-*-* } 46 } */
+      dummy++;
+    }
+  @catch MyObject *x       /* { dg-error "expected ... before .MyObject." } */
+    {
+      dummy++;
+    }
+  @catch MyObject2 *x)     /* { dg-error "expected ... before .MyObject2." } */
+   {
+     dummy++;
+   }
+
+  @try { @throw object; }
+  @catch (MyObject *x)
+  @catch (MyObject2 *y)    /* { dg-error "expected ... before .catch." } */
+
+  return dummy;            /* { dg-error "expected ... before .return." } */
+}
diff --git a/gcc/testsuite/obj-c++.dg/exceptions-5.mm b/gcc/testsuite/obj-c++.dg/exceptions-5.mm
new file mode 100644 (file)
index 0000000..f740496
--- /dev/null
@@ -0,0 +1,114 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-options "-fobjc-exceptions" } */
+/* { dg-do compile } */
+
+/* Test that you can use an unnamed argument with @catch.  This test is the same
+   as exceptions-3.mm, but with no name for @catch arguments.  */
+
+#include <objc/objc.h>
+
+@interface MyObject
+{
+  Class isa;
+}
+@end
+
+@implementation MyObject
+@end
+
+@protocol MyProtocol;
+
+typedef MyObject MyObjectTypedef;
+typedef MyObject *MyObjectPtrTypedef;
+typedef int intTypedef;
+
+int test (id object)
+{
+  int dummy = 0;
+
+  @try { @throw object; }
+  @catch (int)          /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (intTypedef)   /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (int *)         /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {
+      dummy++;
+    }  
+
+  @try { @throw object; }
+  @catch (id)           /* Ok */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (id <MyProtocol>) /* { dg-error "@catch parameter can not be protocol-qualified" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObject *)    /* Ok */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObject <MyProtocol> *)  /* { dg-error "@catch parameter can not be protocol-qualified" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObject)     /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {                     /* { dg-error "no matching function" "" { target *-*-* } 72 } */
+      dummy++;            /* { dg-warning "MyObject" "" { target *-*-* } 13 } */
+    }
+
+  @try { @throw object; }
+  @catch (static MyObject *) /* { dg-error "storage class" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObjectTypedef *) /* Ok */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObjectTypedef <MyProtocol> *) /* { dg-error "@catch parameter can not be protocol-qualified" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObjectPtrTypedef) /* Ok */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (Class)   /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (...)            /* Ok */
+    {
+      dummy++;
+    }
+
+  return dummy;
+}
diff --git a/gcc/testsuite/objc.dg/exceptions-1.m b/gcc/testsuite/objc.dg/exceptions-1.m
new file mode 100644 (file)
index 0000000..0f3b7e8
--- /dev/null
@@ -0,0 +1,42 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-options "-fobjc-exceptions" } */
+/* { dg-do compile } */
+
+/* This test checks the syntax @catch (...) which catches any
+   exceptions.  At the moment, @catch (...) is identical to @catch (id
+   exception).  */
+
+#include <objc/objc.h>
+
+@interface MyObject
+{
+  Class isa;
+}
+@end
+
+@implementation MyObject
+@end
+
+int test (id object)
+{
+  int i = 0;
+
+  @try
+    {
+      @throw object;
+    }
+  @catch (MyObject *o)
+    {
+      i += 1;
+    }
+  @catch (...)
+    {
+      i += 2;
+    }
+  @finally
+    {
+      i += 4;
+    }
+
+  return i;
+}
diff --git a/gcc/testsuite/objc.dg/exceptions-2.m b/gcc/testsuite/objc.dg/exceptions-2.m
new file mode 100644 (file)
index 0000000..3e4227c
--- /dev/null
@@ -0,0 +1,52 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-do run } */
+/* { dg-options "-fobjc-exceptions" } */
+/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
+/* { dg-additional-sources "../objc-obj-c++-shared/Object1.m" } */
+
+/* This test checks the syntax @catch (...) which catches any
+   exceptions.  Check that code using it runs correctly.  */
+
+#include "../objc-obj-c++-shared/Object1.h"
+#include <stdlib.h>
+
+@interface MyObject : Object
+@end
+
+@implementation MyObject
+@end
+
+int test (id object)
+{
+  int i = 0;
+
+  @try
+    {
+      @throw object;
+    }
+  @catch (MyObject *o)
+    {
+      i += 1;
+    }
+  @catch (...)
+    {
+      i += 2;
+    }
+  @finally
+    {
+      i += 4;
+    }
+
+  return i;
+}
+
+int main (void)
+{
+  if (test ([MyObject new]) != 5)
+    abort ();
+
+  if (test ([Object new]) != 6)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/objc.dg/exceptions-3.m b/gcc/testsuite/objc.dg/exceptions-3.m
new file mode 100644 (file)
index 0000000..fe9dbfb
--- /dev/null
@@ -0,0 +1,114 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-options "-fobjc-exceptions" } */
+/* { dg-do compile } */
+
+/* Test that the compiler is checking the argument of @catch(), and
+   produce errors when invalid types are used.  */
+
+#include <objc/objc.h>
+
+@interface MyObject
+{
+  Class isa;
+}
+@end
+
+@implementation MyObject
+@end
+
+@protocol MyProtocol;
+
+typedef MyObject MyObjectTypedef;
+typedef MyObject *MyObjectPtrTypedef;
+typedef int intTypedef;
+
+int test (id object)
+{
+  int dummy = 0;
+
+  @try { @throw object; }
+  @catch (int x)          /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (intTypedef x)   /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (int *x)         /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {
+      dummy++;
+    }  
+
+  @try { @throw object; }
+  @catch (id x)           /* Ok */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (id <MyProtocol> x) /* { dg-error "@catch parameter can not be protocol-qualified" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObject *x)    /* Ok */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObject <MyProtocol> *x)  /* { dg-error "@catch parameter can not be protocol-qualified" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObject x)     /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {                     /* { dg-error "conversion to non-scalar type requested" "" { target *-*-* } 72 } */
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (static MyObject *x) /* { dg-error "storage class specified for" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObjectTypedef *x) /* Ok */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObjectTypedef <MyProtocol> *x) /* { dg-error "@catch parameter can not be protocol-qualified" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObjectPtrTypedef x) /* Ok */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (Class x)   /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (...)            /* Ok */
+    {
+      dummy++;
+    }
+
+  return dummy;
+}
diff --git a/gcc/testsuite/objc.dg/exceptions-4.m b/gcc/testsuite/objc.dg/exceptions-4.m
new file mode 100644 (file)
index 0000000..a8a26ec
--- /dev/null
@@ -0,0 +1,64 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-options "-fobjc-exceptions" } */
+/* { dg-do compile } */
+
+/* Test warnings when parsing syntax errors in @catch().  */
+
+#include <objc/objc.h>
+
+@interface MyObject
+{
+  Class isa;
+}
+@end
+
+@implementation MyObject
+@end
+
+@interface MyObject2
+{
+  Class isa;
+}
+@end
+
+@implementation MyObject2
+@end
+
+@protocol MyProtocol;
+
+int test (id object)
+{
+  int dummy = 0;
+
+  @try { @throw object; }
+  @catch
+    { /* { dg-error "expected ... before ... token" } */
+      dummy++;
+    }
+  @catch ()  /* { dg-error "expected declaration specifiers or ..... before ..." } */
+    {
+      dummy++;
+    }
+  @catch (i) /* { dg-error "expected declaration specifiers or ..... before .i." } */
+    {
+      dummy++;
+    }
+  @catch (id <MyProtocol x) /* { dg-error "expected ... before .x." } */
+    {                       /* { dg-error "@catch parameter can not be protocol-qualified" "" { target *-*-* } 46 } */
+      dummy++;
+    }
+  @catch MyObject *x       /* { dg-error "expected ... before .MyObject." } */
+    {
+      dummy++;
+    }
+  @catch MyObject2 *x)      /* { dg-error "expected ... before .MyObject2." } */
+   {
+     dummy++;
+   }
+
+  @try { @throw object; }
+  @catch (MyObject *x)
+  @catch (MyObject2 *y)    /* { dg-error "expected ... before .catch." } */
+
+  return dummy;
+}
diff --git a/gcc/testsuite/objc.dg/exceptions-5.m b/gcc/testsuite/objc.dg/exceptions-5.m
new file mode 100644 (file)
index 0000000..d89ad29
--- /dev/null
@@ -0,0 +1,114 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-options "-fobjc-exceptions" } */
+/* { dg-do compile } */
+
+/* Test that you can use an unnamed argument with @catch.  This test is the same
+   as exceptions-3.m, but with no name for @catch arguments.  */
+
+#include <objc/objc.h>
+
+@interface MyObject
+{
+  Class isa;
+}
+@end
+
+@implementation MyObject
+@end
+
+@protocol MyProtocol;
+
+typedef MyObject MyObjectTypedef;
+typedef MyObject *MyObjectPtrTypedef;
+typedef int intTypedef;
+
+int test (id object)
+{
+  int dummy = 0;
+
+  @try { @throw object; }
+  @catch (int)          /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (intTypedef)   /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (int *)         /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {
+      dummy++;
+    }  
+
+  @try { @throw object; }
+  @catch (id)           /* Ok */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (id <MyProtocol>) /* { dg-error "@catch parameter can not be protocol-qualified" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObject *)    /* Ok */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObject <MyProtocol> *)  /* { dg-error "@catch parameter can not be protocol-qualified" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObject)     /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {                     /* { dg-error "conversion to non-scalar type requested" "" { target *-*-* } 72 } */
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (static MyObject *) /* { dg-error "storage class specified for" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObjectTypedef *) /* Ok */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObjectTypedef <MyProtocol> *) /* { dg-error "@catch parameter can not be protocol-qualified" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (MyObjectPtrTypedef) /* Ok */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (Class)   /* { dg-error "@catch parameter is not a known Objective-C class type" } */
+    {
+      dummy++;
+    }
+
+  @try { @throw object; }
+  @catch (...)            /* Ok */
+    {
+      dummy++;
+    }
+
+  return dummy;
+}