diff mbox

[ObjC/C++] Recognize attributes on class, category and protocol declarations.

Message ID C97DAA0C-0D72-429A-A276-ADA2FE3090E1@sandoe-acoustics.co.uk
State New
Headers show

Commit Message

Iain Sandoe Sept. 26, 2010, 2:04 p.m. UTC
Hi,

The patch implements the parsing for the prefix attributes on class,  
category and protocol in both ObjC and ObjC++ FEs and hands off the  
result to the shared code in objc-act (which simply raises a warning  
that the attribute is currently ignored).

This is part of the support needed for (eventually) ObjC V1 and (as  
soon as possible) to parse Application/Foundation headers on NeXT  
platforms >= Darwin9.

Nicola came up with the approach and started the patch off - I tweaked  
the c parts and added the c++ , objc-act and testsuite bits.

We feel that this approach is useful in that:
  (a) the remainder of the implementation can be local to  objc/  and..
  (b) instead of a fatal syntax error, we now have a warning which may  
often be ignored safely on m32 NeXT (the main use in system headers is  
to warn of deprecated interfaces that become unavailable at m64).

The source locations shown in diagnostics could be better, but that's  
for a different patch.

Tested on i686-darwin9, x86_64-unknown-linux-gnu, and on a cross to  
mipsisa64-elf

We need approval for c, c-family, c++ and objc.
OK to apply?

Iain

gcc/c-family:

	* c-common.h (objc_start_class_interface): Adjust prototype.
	(objc_start_category_interface): Likewise.
	(objc_start_protocol): Likewise.
	* stub-objc.c (objc_start_protocol): Adjust for extra argument.
	(objc_start_class_interface): Likewise.
	(objc_start_category_interface): Likewise.

gcc/objc:

	* objc-act.c (objc_start_class_interface): Handle and ignore  
attributes.
	(objc_start_category_interface): Likewise.
	(objc_start_protocol): Likewise.

gcc/cp:

	* parser.c (objc_at_keyword_follows_attributes): New.
	(cp_parser_declaration): Parse prefix attributes for ObjC++.
	(cp_parser_objc_protocol_declaration): Handle attributes.
	(cp_parser_objc_class_interface): Likewise.
	(cp_parser_objc_declaration): Likewise.

gcc:

	* c-parser.c (c_parser_objc_class_definition): Adjust prototype.
	(c_parser_objc_protocol_definition): Likewise.
	(c_parser_external_declaration): Provide dummy attribute arguments.
	(c_parser_declaration_or_fndef): Parse prefix attributes for ObjC.
	(c_parser_objc_class_definition): Handle attributes.
	(c_parser_objc_protocol_definition): Likewise.

gcc/testsuite:

	* objc.dg/attributes: New.
	* objc.dg/attributes/attributes.exp: New.
	* objc.dg/attributes/class-attribute-1.m: New.
	* objc.dg/attributes/class-attribute-2.m: New
	* objc.dg/attributes/categ-attribute-1.m: New
	* objc.dg/attributes/categ-attribute-2.m: New
	* objc.dg/attributes/proto-attribute-1.m: New

	* obj-c++.dg/attributes: New.
	* obj-c++.dg/attributes/attributes.exp: New
	* obj-c++.dg/attributes/class-attribute-1.mm: New
	* obj-c++.dg/attributes/class-attribute-2.mm: New
	* obj-c++.dg/attributes/categ-attribute-1.mm: New
	* obj-c++.dg/attributes/categ-attribute-2.mm: New
	* obj-c++.dg/attributes/proto-attribute-1.mm: New

Comments

Nicola Pero Sept. 26, 2010, 2:26 p.m. UTC | #1
I haven't looked at the details, but the patch looks very cool :-)

I wonder about the warning messages though.  They mention "ObjC Version 1",
but I'm not even sure I know myself what "ObjC Version 1" is ;-)

I would suggest we use something more neutral (for now), such as

 class attributes are ignored (not supported by the compiler)

We'll need to classify and document the Objective-C features as we're going to be
adding all the new ones, so we may want to revisit the message once we have done
some classification (which should probably go in the gcc/doc/standards.texi).

Thanks

-----Original Message-----
From: "IainS" <developer@sandoe-acoustics.co.uk>
Sent: Sunday, 26 September, 2010 16:04
To: "GCC Patches" <gcc-patches@gcc.gnu.org>
Cc: "Mike Stump" <mrs@gcc.gnu.org>, "Joseph S. Myers" <joseph@codesourcery.com>, "Jason Merrill" <jason@redhat.com>, "Nicola Pero" <nicola.pero@meta-innovation.com>
Subject: [Patch, ObjC/C++] Recognize attributes on class, category and protocol declarations.

Hi,

The patch implements the parsing for the prefix attributes on class,  
category and protocol in both ObjC and ObjC++ FEs and hands off the  
result to the shared code in objc-act (which simply raises a warning  
that the attribute is currently ignored).

This is part of the support needed for (eventually) ObjC V1 and (as  
soon as possible) to parse Application/Foundation headers on NeXT  
platforms >= Darwin9.

Nicola came up with the approach and started the patch off - I tweaked  
the c parts and added the c++ , objc-act and testsuite bits.

We feel that this approach is useful in that:
  (a) the remainder of the implementation can be local to  objc/  and..
  (b) instead of a fatal syntax error, we now have a warning which may  
often be ignored safely on m32 NeXT (the main use in system headers is  
to warn of deprecated interfaces that become unavailable at m64).

The source locations shown in diagnostics could be better, but that's  
for a different patch.

Tested on i686-darwin9, x86_64-unknown-linux-gnu, and on a cross to  
mipsisa64-elf

We need approval for c, c-family, c++ and objc.
OK to apply?

Iain

gcc/c-family:

	* c-common.h (objc_start_class_interface): Adjust prototype.
	(objc_start_category_interface): Likewise.
	(objc_start_protocol): Likewise.
	* stub-objc.c (objc_start_protocol): Adjust for extra argument.
	(objc_start_class_interface): Likewise.
	(objc_start_category_interface): Likewise.

gcc/objc:

	* objc-act.c (objc_start_class_interface): Handle and ignore  
attributes.
	(objc_start_category_interface): Likewise.
	(objc_start_protocol): Likewise.

gcc/cp:

	* parser.c (objc_at_keyword_follows_attributes): New.
	(cp_parser_declaration): Parse prefix attributes for ObjC++.
	(cp_parser_objc_protocol_declaration): Handle attributes.
	(cp_parser_objc_class_interface): Likewise.
	(cp_parser_objc_declaration): Likewise.

gcc:

	* c-parser.c (c_parser_objc_class_definition): Adjust prototype.
	(c_parser_objc_protocol_definition): Likewise.
	(c_parser_external_declaration): Provide dummy attribute arguments.
	(c_parser_declaration_or_fndef): Parse prefix attributes for ObjC.
	(c_parser_objc_class_definition): Handle attributes.
	(c_parser_objc_protocol_definition): Likewise.

gcc/testsuite:

	* objc.dg/attributes: New.
	* objc.dg/attributes/attributes.exp: New.
	* objc.dg/attributes/class-attribute-1.m: New.
	* objc.dg/attributes/class-attribute-2.m: New
	* objc.dg/attributes/categ-attribute-1.m: New
	* objc.dg/attributes/categ-attribute-2.m: New
	* objc.dg/attributes/proto-attribute-1.m: New

	* obj-c++.dg/attributes: New.
	* obj-c++.dg/attributes/attributes.exp: New
	* obj-c++.dg/attributes/class-attribute-1.mm: New
	* obj-c++.dg/attributes/class-attribute-2.mm: New
	* obj-c++.dg/attributes/categ-attribute-1.mm: New
	* obj-c++.dg/attributes/categ-attribute-2.mm: New
	* obj-c++.dg/attributes/proto-attribute-1.mm: New
Iain Sandoe Sept. 26, 2010, 2:39 p.m. UTC | #2
On 26 Sep 2010, at 15:26, Nicola Pero wrote:
>
> I wonder about the warning messages though.  They mention "ObjC  
> Version 1",
> but I'm not even sure I know myself what "ObjC Version 1" is ;-)

Hm. I wonder if it was ever official
Perhaps we can only go by release dates (of XCode versions supporting  
additional features)
--- that will require a trawl through the release notes (see below).

> I would suggest we use something more neutral (for now), such as
>
> class attributes are ignored (not supported by the compiler)

fine by me - I intend that the 'unimplemented' phase will only last  
for a short time.

> We'll need to classify and document the Objective-C features as  
> we're going to be
> adding all the new ones, so we may want to revisit the message once  
> we have done
> some classification (which should probably go in the gcc/doc/ 
> standards.texi).

I would like to have (very soon) something equivalent to  the
-std= option (maybe -objc-std=  ) so that we can have  an enum (e.g.  
apple_200x ... or gnu_xxx ) so that we can provide decent diagnostics  
for compatibility.
I think this needs discussion on a separate thread tho.

Iain
Nicola Pero Sept. 26, 2010, 2:42 p.m. UTC | #3
>> We'll need to classify and document the Objective-C features as  
>> we're going to be
>> adding all the new ones, so we may want to revisit the message once  
>> we have done
>> some classification (which should probably go in the gcc/doc/ 
>> standards.texi).
>
> I would like to have (very soon) something equivalent to  the
> -std= option (maybe -objc-std=  ) so that we can have  an enum (e.g.  
> apple_200x ... or gnu_xxx ) so that we can provide decent diagnostics  
> for compatibility.
> I think this needs discussion on a separate thread tho.

Yes, I agree.

Thanks
diff mbox

Patch

Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	(revision 164620)
+++ gcc/c-family/c-common.h	(working copy)
@@ -963,9 +963,9 @@  extern tree objc_get_protocol_qualified_type (tree
 extern tree objc_get_class_reference (tree);
 extern tree objc_get_class_ivars (tree);
 extern tree objc_get_interface_ivars (tree);
-extern void objc_start_class_interface (tree, tree, tree);
-extern void objc_start_category_interface (tree, tree, tree);
-extern void objc_start_protocol (tree, tree);
+extern void objc_start_class_interface (tree, tree, tree, tree);
+extern void objc_start_category_interface (tree, tree, tree, tree);
+extern void objc_start_protocol (tree, tree, tree);
 extern void objc_continue_interface (void);
 extern void objc_finish_interface (void);
 extern void objc_start_class_implementation (tree, tree);
Index: gcc/c-family/stub-objc.c
===================================================================
--- gcc/c-family/stub-objc.c	(revision 164620)
+++ gcc/c-family/stub-objc.c	(working copy)
@@ -109,21 +109,24 @@  objc_declare_protocols (tree ARG_UNUSED (list))
 
 void
 objc_start_protocol (tree ARG_UNUSED (proto),
-		     tree ARG_UNUSED (protorefs))
+		     tree ARG_UNUSED (protorefs),
+		     tree ARG_UNUSED (attribs))
 {
 }
 
 void
 objc_start_class_interface (tree ARG_UNUSED (name),
 			    tree ARG_UNUSED (super),
-			    tree ARG_UNUSED (protos))
+			    tree ARG_UNUSED (protos),
+			    tree ARG_UNUSED (attribs))
 {
 }
 
 void
 objc_start_category_interface (tree ARG_UNUSED (name),
 			       tree ARG_UNUSED (categ),
-			       tree ARG_UNUSED (protos))
+			       tree ARG_UNUSED (protos),
+			       tree ARG_UNUSED (attribs))
 {
 }
 
Index: gcc/objc/objc-act.c
===================================================================
--- gcc/objc/objc-act.c	(revision 164620)
+++ gcc/objc/objc-act.c	(working copy)
@@ -670,8 +670,13 @@  lookup_protocol_in_reflist (tree rproto_list, tree
 }
 
 void
-objc_start_class_interface (tree klass, tree super_class, tree protos)
+objc_start_class_interface (tree klass, tree super_class,
+			    tree protos, tree attributes)
 {
+  if (attributes)
+    warning_at (input_location, OPT_Wattributes, 
+		"class attributes are only available in ObjC Version 1 "
+		"and higher, (ignored)");
   objc_interface_context
     = objc_ivar_context
     = start_class (CLASS_INTERFACE_TYPE, klass, super_class, protos);
@@ -679,8 +684,13 @@  void
 }
 
 void
-objc_start_category_interface (tree klass, tree categ, tree protos)
+objc_start_category_interface (tree klass, tree categ,
+			       tree protos, tree attributes)
 {
+  if (attributes)
+    warning_at (input_location, OPT_Wattributes, 
+		"category attributes are only available in ObjC Version 1 "
+		"and higher, (ignored)");
   objc_interface_context
     = start_class (CATEGORY_INTERFACE_TYPE, klass, categ, protos);
   objc_ivar_chain
@@ -688,8 +698,12 @@  void
 }
 
 void
-objc_start_protocol (tree name, tree protos)
+objc_start_protocol (tree name, tree protos, tree attributes)
 {
+  if (attributes)
+    warning_at (input_location, OPT_Wattributes, 
+		"protocol attributes are only available in ObjC Version 1 "
+		"and higher, (ignored)");
   objc_interface_context
     = start_protocol (PROTOCOL_INTERFACE_TYPE, name, protos);
 }
Index: gcc/testsuite/objc.dg/attributes/class-attribute-1.m
===================================================================
--- gcc/testsuite/objc.dg/attributes/class-attribute-1.m	(revision 0)
+++ gcc/testsuite/objc.dg/attributes/class-attribute-1.m	(revision 0)
@@ -0,0 +1,36 @@ 
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+#include "../../objc-obj-c++-shared/Object1.h"
+
+/* Normal deprecated func. */
+__attribute ((deprecated)) void f1();
+__attribute__ ((deprecated("use some new func"))) void f2();
+
+__attribute__ ((deprecated)) 
+@interface DEPRECATED : Object
+  { @public int ivar; } /* { dg-warning "class attributes are only available in ObjC Version 1" } */
+  - (int) instancemethod;
+@end
+
+@implementation DEPRECATED
+-(int) instancemethod {  return ivar; } 
+@end
+
+@interface DEPRECATED (Category) 
+@end /*  dg - warning "deprecated"  */
+
+@interface NS : DEPRECATED 
+@end /* dg - warning "deprecated"  */
+
+DEPRECATED * deprecated_obj; /*  dg - warning "deprecated"  */
+
+int foo (DEPRECATED *unavailable_obj) /*  dg - warning "deprecated"  */
+{
+    DEPRECATED *p = [DEPRECATED new];	/*  dg - warning "deprecated"   */ 
+
+    f1();	/* { dg-warning "'f1' is deprecated" } */
+    f2();	/* { dg-warning "'f2' is deprecated .declared at \[^\\)\]*.: use some new func" } */
+    int q = p->ivar;
+    return [p instancemethod];    
+}
Index: gcc/testsuite/objc.dg/attributes/class-attribute-2.m
===================================================================
--- gcc/testsuite/objc.dg/attributes/class-attribute-2.m	(revision 0)
+++ gcc/testsuite/objc.dg/attributes/class-attribute-2.m	(revision 0)
@@ -0,0 +1,25 @@ 
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+#include "../../objc-obj-c++-shared/Object1.h"
+
+__attribute ((deprecated)) 
+@interface depobj : Object { /* { dg-warning "class attributes are only available in " } */
+@public 
+  int ivar; 
+} 
+- (int) mth;
+@end
+
+__attribute ((deprecated)) 
+@implementation depobj /* { dg-error "attributes may not be" } */
+-(int) mth {  return ivar; } 
+@end
+
+int foo (void)
+{
+    depobj *p = [depobj new];	/*  dg - warning "deprecated"   */ 
+
+    int q = p->ivar;
+    return [p mth];    
+}
Index: gcc/testsuite/objc.dg/attributes/attributes.exp
===================================================================
--- gcc/testsuite/objc.dg/attributes/attributes.exp	(revision 0)
+++ gcc/testsuite/objc.dg/attributes/attributes.exp	(revision 0)
@@ -0,0 +1,44 @@ 
+# Copyright (C) 2010 Free Software Foundation, Inc.
+# 
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Load support procs.
+
+load_lib objc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS ""
+}
+
+# Initialize `dg'.
+dg-init
+
+# Gather a list of all tests.
+set tests [lsort [glob -nocomplain $srcdir/$subdir/*.m]]
+
+# Main loop.
+dg-runtest $tests "-fgnu-runtime" $DEFAULT_CFLAGS
+
+# darwin targets can also run code with the NeXT runtime.
+if [istarget "*-*-darwin*" ] {
+  dg-runtest $tests "-fnext-runtime" $DEFAULT_CFLAGS
+}
+
+# All done.
+dg-finish
Index: gcc/testsuite/objc.dg/attributes/categ-attribute-1.m
===================================================================
--- gcc/testsuite/objc.dg/attributes/categ-attribute-1.m	(revision 0)
+++ gcc/testsuite/objc.dg/attributes/categ-attribute-1.m	(revision 0)
@@ -0,0 +1,31 @@ 
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+#include "../../objc-obj-c++-shared/Object1.h"
+
+@interface obj : Object { 
+@public 
+  int var; 
+} 
+- (int) mth;
+@end
+
+@implementation obj
+- (int) mth {  return var; } 
+@end
+
+__attribute ((deprecated)) 
+@interface obj (dep_categ) 
+- (int) depmth;/* { dg-warning "category attributes are only available in " } */
+@end
+
+@implementation obj (dep_categ)
+- (int) depmth { return var + 1; }
+@end
+
+int foo (void)
+{
+    obj *p = [obj new];	 
+    int q = [p depmth];
+    return [p mth];    
+}
Index: gcc/testsuite/objc.dg/attributes/proto-attribute-1.m
===================================================================
--- gcc/testsuite/objc.dg/attributes/proto-attribute-1.m	(revision 0)
+++ gcc/testsuite/objc.dg/attributes/proto-attribute-1.m	(revision 0)
@@ -0,0 +1,29 @@ 
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+#include "../../objc-obj-c++-shared/Object1.h"
+
+__attribute ((deprecated)) 
+@protocol dep_proto 
+- (int) depprotomth; /* { dg-warning "protocol attributes are only available in " } */
+@end
+
+@interface obj : Object <dep_proto>
+{ 
+@public 
+  int var; 
+} 
+- (int) mth;
+@end
+
+@implementation obj
+- (int) mth {  return var; } 
+- (int) depprotomth { return var + 1; }
+@end
+
+int foo (void)
+{
+    obj *p = [obj new];	 
+    int q = [p depprotomth];
+    return [p mth];    
+}
Index: gcc/testsuite/objc.dg/attributes/categ-attribute-2.m
===================================================================
--- gcc/testsuite/objc.dg/attributes/categ-attribute-2.m	(revision 0)
+++ gcc/testsuite/objc.dg/attributes/categ-attribute-2.m	(revision 0)
@@ -0,0 +1,32 @@ 
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+#include "../../objc-obj-c++-shared/Object1.h"
+
+@interface obj : Object { 
+@public 
+  int var; 
+} 
+- (int) mth;
+@end
+
+@implementation obj
+- (int) mth {  return var; } 
+@end
+
+__attribute__ ((deprecated("no dep_categ")))
+@interface obj (dep_categ) 
+- (int) depmth;/* { dg-warning "category attributes are only available in " } */
+@end
+
+__attribute__ ((deprecated)) 
+@implementation obj (dep_categ) /* { dg-error "attributes may not be" } */
+- (int) depmth { return var + 1; }
+@end
+
+int foo (void)
+{
+    obj *p = [obj new];	 
+    int q = [p depmth];
+    return [p mth];    
+}
Index: gcc/testsuite/obj-c++.dg/attributes/attributes.exp
===================================================================
--- gcc/testsuite/obj-c++.dg/attributes/attributes.exp	(revision 0)
+++ gcc/testsuite/obj-c++.dg/attributes/attributes.exp	(revision 0)
@@ -0,0 +1,43 @@ 
+# Copyright (C) 2010 Free Software Foundation, Inc.
+# 
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Load support procs.
+load_lib obj-c++-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_OBJCXXFLAGS
+if ![info exists DEFAULT_OBJCXXFLAGS] then {
+    set DEFAULT_OBJCXXFLAGS " -ansi -pedantic-errors -Wno-long-long"
+}
+
+# Initialize `dg'.
+dg-init
+
+# Gather a list of all tests.
+set tests [lsort [glob -nocomplain $srcdir/$subdir/*.mm]]
+
+# Main loop.
+dg-runtest $tests "-fgnu-runtime" $DEFAULT_OBJCXXFLAGS
+
+# darwin targets can also run code with the NeXT runtime.
+if [istarget "*-*-darwin*" ] {
+  dg-runtest $tests "-fnext-runtime" $DEFAULT_OBJCXXFLAGS
+}
+
+# All done.
+dg-finish
Index: gcc/testsuite/obj-c++.dg/attributes/categ-attribute-1.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/attributes/categ-attribute-1.mm	(revision 0)
+++ gcc/testsuite/obj-c++.dg/attributes/categ-attribute-1.mm	(revision 0)
@@ -0,0 +1,31 @@ 
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+#include "../../objc-obj-c++-shared/Object1.h"
+
+@interface obj : Object { 
+@public 
+  int var; 
+} 
+- (int) mth;
+@end
+
+@implementation obj
+- (int) mth {  return var; } 
+@end
+
+__attribute ((deprecated)) 
+@interface obj (dep_categ) /* { dg-warning "category attributes are only available in " } */
+- (int) depmth;
+@end
+
+@implementation obj (dep_categ)
+- (int) depmth { return var + 1; }
+@end
+
+int foo (void)
+{
+    obj *p = [obj new];	 
+    int q = [p depmth];
+    return [p mth];    
+}
Index: gcc/testsuite/obj-c++.dg/attributes/proto-attribute-1.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/attributes/proto-attribute-1.mm	(revision 0)
+++ gcc/testsuite/obj-c++.dg/attributes/proto-attribute-1.mm	(revision 0)
@@ -0,0 +1,29 @@ 
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+#include "../../objc-obj-c++-shared/Object1.h"
+
+__attribute ((deprecated)) 
+@protocol dep_proto /* { dg-warning "protocol attributes are only available in " } */
+- (int) depprotomth; 
+@end
+
+@interface obj : Object <dep_proto>
+{ 
+@public 
+  int var; 
+} 
+- (int) mth;
+@end
+
+@implementation obj
+- (int) mth {  return var; } 
+- (int) depprotomth { return var + 1; }
+@end
+
+int foo (void)
+{
+    obj *p = [obj new];	 
+    int q = [p depprotomth];
+    return [p mth];    
+}
Index: gcc/testsuite/obj-c++.dg/attributes/categ-attribute-2.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/attributes/categ-attribute-2.mm	(revision 0)
+++ gcc/testsuite/obj-c++.dg/attributes/categ-attribute-2.mm	(revision 0)
@@ -0,0 +1,32 @@ 
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+#include "../../objc-obj-c++-shared/Object1.h"
+
+@interface obj : Object { 
+@public 
+  int var; 
+} 
+- (int) mth;
+@end
+
+@implementation obj
+- (int) mth {  return var; } 
+@end
+
+__attribute__ ((deprecated("no dep_categ")))
+@interface obj (dep_categ) /* { dg-warning "category attributes are only available in " } */ 
+- (int) depmth;
+@end
+
+__attribute__ ((deprecated)) 
+@implementation obj (dep_categ) /* { dg-error "attributes may not be" } */
+- (int) depmth { return var + 1; }
+@end
+
+int foo (void)
+{
+    obj *p = [obj new];	 
+    int q = [p depmth];
+    return [p mth];    
+}
Index: gcc/testsuite/obj-c++.dg/attributes/class-attribute-1.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/attributes/class-attribute-1.mm	(revision 0)
+++ gcc/testsuite/obj-c++.dg/attributes/class-attribute-1.mm	(revision 0)
@@ -0,0 +1,38 @@ 
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+#include "../../objc-obj-c++-shared/Object1.h"
+
+/* Normal deprecated func. */
+__attribute ((deprecated)) void f1();
+__attribute__ ((deprecated("use some new func"))) void f2();
+
+__attribute__ ((deprecated)) 
+@interface depobj : Object { /* { dg-warning "class attributes are only available in " } */
+@public 
+  int var; 
+} 
+- (int) mth;
+@end
+
+@implementation depobj
+-(int) mth {  return var; } 
+@end
+
+@interface depobj (ok_categ) 
+@end 
+
+@interface NS : depobj 
+@end 
+
+depobj * deprecated;
+
+int foo (depobj *dep_obj) /*  dg - warning "deprecated"  */
+{
+    depobj *p = [depobj new];	/*  dg - warning "deprecated"   */ 
+
+    f1();	/* { dg-warning "'void f1..' is deprecated .declared at" } */
+    f2();	/* { dg-warning "'void f2..' is deprecated .declared at \[^\\)\]*.: use some new func" } */
+    int q = p->var;
+    return [p mth];    
+}
Index: gcc/testsuite/obj-c++.dg/attributes/class-attribute-2.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/attributes/class-attribute-2.mm	(revision 0)
+++ gcc/testsuite/obj-c++.dg/attributes/class-attribute-2.mm	(revision 0)
@@ -0,0 +1,25 @@ 
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+#include "../../objc-obj-c++-shared/Object1.h"
+
+__attribute ((deprecated)) 
+@interface depobj : Object { /* { dg-warning "class attributes are only available in " } */
+@public 
+  int ivar; 
+} 
+- (int) mth;
+@end
+
+__attribute ((deprecated)) 
+@implementation depobj /* { dg-error "attributes may not be" } */
+-(int) mth {  return ivar; } 
+@end
+
+int foo (void)
+{
+    depobj *p = [depobj new];	/*  dg - warning "deprecated"   */ 
+
+    int q = p->ivar;
+    return [p mth];    
+}
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 164620)
+++ gcc/cp/parser.c	(working copy)
@@ -2086,7 +2086,7 @@  static tree cp_parser_objc_selector
 static tree cp_parser_objc_protocol_refs_opt
   (cp_parser *);
 static void cp_parser_objc_declaration
-  (cp_parser *);
+  (cp_parser *, tree);
 static tree cp_parser_objc_statement
   (cp_parser *);
 
@@ -9262,6 +9262,26 @@  cp_parser_declaration_seq_opt (cp_parser* parser)
     }
 }
 
+/* If we are compiling ObjC++ and we see an __attribute__ we neeed to 
+   look ahead to see if an objc keyword follows the attributes.  This
+   is to detect the use of prefix attributes on ObjC @interface and 
+   @protocol.  */
+
+static bool
+objc_at_keyword_follows_attributes (cp_parser* parser, tree *attrib)
+{
+  cp_lexer_save_tokens (parser->lexer);
+  *attrib = cp_parser_attributes_opt (parser);
+  gcc_assert (*attrib);
+  if (OBJC_IS_AT_KEYWORD (cp_lexer_peek_token (parser->lexer)->keyword))
+    {
+      cp_lexer_commit_tokens (parser->lexer);
+      return true;
+    }
+  cp_lexer_rollback_tokens (parser->lexer);
+  return false;  
+}
+
 /* Parse a declaration.
 
    declaration:
@@ -9285,6 +9305,7 @@  cp_parser_declaration (cp_parser* parser)
   cp_token token2;
   int saved_pedantic;
   void *p;
+  tree attributes = NULL_TREE;
 
   /* Check for the `__extension__' keyword.  */
   if (cp_parser_extension_opt (parser, &saved_pedantic))
@@ -9362,7 +9383,11 @@  cp_parser_declaration (cp_parser* parser)
     cp_parser_namespace_definition (parser);
   /* Objective-C++ declaration/definition.  */
   else if (c_dialect_objc () && OBJC_IS_AT_KEYWORD (token1.keyword))
-    cp_parser_objc_declaration (parser);
+    cp_parser_objc_declaration (parser, NULL_TREE);
+  else if (c_dialect_objc ()
+	   && token1.keyword == RID_ATTRIBUTE
+	   && objc_at_keyword_follows_attributes (parser, &attributes))
+    cp_parser_objc_declaration (parser, attributes);
   /* We must have either a block declaration or a function
      definition.  */
   else
@@ -21739,7 +21764,7 @@  cp_parser_objc_class_ivars (cp_parser* parser)
 /* Parse an Objective-C protocol declaration.  */
 
 static void
-cp_parser_objc_protocol_declaration (cp_parser* parser)
+cp_parser_objc_protocol_declaration (cp_parser* parser, tree attributes)
 {
   tree proto, protorefs;
   cp_token *tok;
@@ -21768,7 +21793,7 @@  static void
     {
       proto = cp_parser_identifier (parser);
       protorefs = cp_parser_objc_protocol_refs_opt (parser);
-      objc_start_protocol (proto, protorefs);
+      objc_start_protocol (proto, protorefs, attributes);
       cp_parser_objc_method_prototype_list (parser);
     }
 }
@@ -21798,7 +21823,7 @@  cp_parser_objc_superclass_or_category (cp_parser *
 /* Parse an Objective-C class interface.  */
 
 static void
-cp_parser_objc_class_interface (cp_parser* parser)
+cp_parser_objc_class_interface (cp_parser* parser, tree attributes)
 {
   tree name, super, categ, protos;
 
@@ -21809,10 +21834,10 @@  static void
 
   /* We have either a class or a category on our hands.  */
   if (categ)
-    objc_start_category_interface (name, categ, protos);
+    objc_start_category_interface (name, categ, protos, attributes);
   else
     {
-      objc_start_class_interface (name, super, protos);
+      objc_start_class_interface (name, super, protos, attributes);
       /* Handle instance variable declarations, if any.  */
       cp_parser_objc_class_ivars (parser);
       objc_continue_interface ();
@@ -21858,11 +21883,27 @@  cp_parser_objc_end_implementation (cp_parser* pars
 /* Parse an Objective-C declaration.  */
 
 static void
-cp_parser_objc_declaration (cp_parser* parser)
+cp_parser_objc_declaration (cp_parser* parser, tree attributes)
 {
   /* Try to figure out what kind of declaration is present.  */
   cp_token *kwd = cp_lexer_peek_token (parser->lexer);
 
+  if (attributes)
+    switch (kwd->keyword)
+      {
+	case RID_AT_ALIAS:
+	case RID_AT_CLASS:
+	case RID_AT_IMPLEMENTATION:
+	case RID_AT_END:
+	  error_at (kwd->location, "attributes may not be specified before"
+	            " the %<@%D%> Objective-C++ keyword",
+		    kwd->u.value);
+	  attributes = NULL;
+	  break;
+	default:
+	  break;
+      }
+
   switch (kwd->keyword)
     {
     case RID_AT_ALIAS:
@@ -21872,10 +21913,10 @@  static void
       cp_parser_objc_class_declaration (parser);
       break;
     case RID_AT_PROTOCOL:
-      cp_parser_objc_protocol_declaration (parser);
+      cp_parser_objc_protocol_declaration (parser, attributes);
       break;
     case RID_AT_INTERFACE:
-      cp_parser_objc_class_interface (parser);
+      cp_parser_objc_class_interface (parser, attributes);
       break;
     case RID_AT_IMPLEMENTATION:
       cp_parser_objc_class_implementation (parser);
Index: gcc/c-parser.c
===================================================================
--- gcc/c-parser.c	(revision 164620)
+++ gcc/c-parser.c	(working copy)
@@ -977,11 +977,11 @@  static bool c_parser_pragma (c_parser *, enum prag
 
 /* These Objective-C parser functions are only ever called when
    compiling Objective-C.  */
-static void c_parser_objc_class_definition (c_parser *);
+static void c_parser_objc_class_definition (c_parser *, tree);
 static void c_parser_objc_class_instance_variables (c_parser *);
 static void c_parser_objc_class_declaration (c_parser *);
 static void c_parser_objc_alias_declaration (c_parser *);
-static void c_parser_objc_protocol_definition (c_parser *);
+static void c_parser_objc_protocol_definition (c_parser *, tree);
 static enum tree_code c_parser_objc_method_type (c_parser *);
 static void c_parser_objc_method_definition (c_parser *);
 static void c_parser_objc_methodprotolist (c_parser *);
@@ -1079,7 +1079,7 @@  c_parser_external_declaration (c_parser *parser)
 	case RID_AT_INTERFACE:
 	case RID_AT_IMPLEMENTATION:
 	  gcc_assert (c_dialect_objc ());
-	  c_parser_objc_class_definition (parser);
+	  c_parser_objc_class_definition (parser, NULL_TREE);
 	  break;
 	case RID_CLASS:
 	  gcc_assert (c_dialect_objc ());
@@ -1091,7 +1091,7 @@  c_parser_external_declaration (c_parser *parser)
 	  break;
 	case RID_AT_PROTOCOL:
 	  gcc_assert (c_dialect_objc ());
-	  c_parser_objc_protocol_definition (parser);
+	  c_parser_objc_protocol_definition (parser, NULL_TREE);
 	  break;
 	case RID_AT_END:
 	  gcc_assert (c_dialect_objc ());
@@ -1123,9 +1123,10 @@  c_parser_external_declaration (c_parser *parser)
 	 as a declaration or function definition.  */
     default:
     decl_or_fndef:
-      /* A declaration or a function definition.  We can only tell
-	 which after parsing the declaration specifiers, if any, and
-	 the first declarator.  */
+      /* A declaration or a function definition (or, in Objective-C,
+	 an @interface or @protocol with prefix attributes).  We can
+	 only tell which after parsing the declaration specifiers, if
+	 any, and the first declarator.  */
       c_parser_declaration_or_fndef (parser, true, true, true, false, true);
       break;
     }
@@ -1173,6 +1174,11 @@  c_parser_external_declaration (c_parser *parser)
      declaration-specifiers declarator declaration-list[opt]
        compound-statement
 
+   Objective-C:
+     attributes objc-class-definition
+     attributes objc-category-definition
+     attributes objc-protocol-definition
+
    The simple-asm-expr and attributes are GNU extensions.
 
    This function does not handle __extension__; that is handled in its
@@ -1235,6 +1241,43 @@  c_parser_declaration_or_fndef (c_parser *parser, b
       c_parser_consume_token (parser);
       return;
     }
+  else if (c_dialect_objc ())
+    {
+      /* This is where we parse 'attributes @interface ...',
+	 'attributes @implementation ...', 'attributes @protocol ...'
+	 (where attributes could be, for example, __attribute__
+	 ((deprecated)).
+      */
+      switch (c_parser_peek_token (parser)->keyword)
+	{
+	case RID_AT_INTERFACE:
+	  {
+	    if (!specs->declspecs_seen_p || specs->type_seen_p || specs->non_sc_seen_p)
+	      c_parser_error (parser, "no type or storage class may be specified here");
+	    c_parser_objc_class_definition (parser, specs->attrs);
+	    return;
+	  }
+	  break;
+	case RID_AT_IMPLEMENTATION:
+	  {
+	    c_parser_error (parser, "attributes may not be specified here");
+	    c_parser_objc_class_definition (parser, NULL_TREE);	    
+	    return;
+	  }
+	  break;
+	case RID_AT_PROTOCOL:
+	  {
+	    if (!specs->declspecs_seen_p || specs->type_seen_p || specs->non_sc_seen_p)
+	      c_parser_error (parser, "no type or storage class may be specified here");
+	    c_parser_objc_protocol_definition (parser, specs->attrs);
+	    return;
+	  }
+	  break;
+	default:
+	  break;
+	}
+    }
+  
   pending_xref_error ();
   prefix_attrs = specs->attrs;
   all_prefix_attrs = prefix_attrs;
@@ -6254,7 +6297,7 @@  c_parser_expr_list (c_parser *parser, bool convert
    objc-protocol-refs and objc-class-instance-variables are omitted.  */
 
 static void
-c_parser_objc_class_definition (c_parser *parser)
+c_parser_objc_class_definition (c_parser *parser, tree attributes)
 {
   bool iface_p;
   tree id1;
@@ -6265,6 +6308,7 @@  static void
     iface_p = false;
   else
     gcc_unreachable ();
+
   c_parser_consume_token (parser);
   if (c_parser_next_token_is_not (parser, CPP_NAME))
     {
@@ -6294,7 +6338,7 @@  static void
 	}
       if (c_parser_next_token_is (parser, CPP_LESS))
 	proto = c_parser_objc_protocol_refs (parser);
-      objc_start_category_interface (id1, id2, proto);
+      objc_start_category_interface (id1, id2, proto, attributes);
       c_parser_objc_methodprotolist (parser);
       c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>");
       objc_finish_interface ();
@@ -6318,7 +6362,7 @@  static void
       tree proto = NULL_TREE;
       if (c_parser_next_token_is (parser, CPP_LESS))
 	proto = c_parser_objc_protocol_refs (parser);
-      objc_start_class_interface (id1, superclass, proto);
+      objc_start_class_interface (id1, superclass, proto, attributes);
     }
   else
     objc_start_class_implementation (id1, superclass);
@@ -6498,9 +6542,10 @@  c_parser_objc_alias_declaration (c_parser *parser)
    omitted.  */
 
 static void
-c_parser_objc_protocol_definition (c_parser *parser)
+c_parser_objc_protocol_definition (c_parser *parser, tree attributes)
 {
   gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROTOCOL));
+
   c_parser_consume_token (parser);
   if (c_parser_next_token_is_not (parser, CPP_NAME))
     {
@@ -6540,7 +6585,7 @@  static void
       if (c_parser_next_token_is (parser, CPP_LESS))
 	proto = c_parser_objc_protocol_refs (parser);
       parser->objc_pq_context = true;
-      objc_start_protocol (id, proto);
+      objc_start_protocol (id, proto, attributes);
       c_parser_objc_methodprotolist (parser);
       c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>");
       parser->objc_pq_context = false;