From patchwork Sun Sep 26 14:04:59 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Iain Sandoe X-Patchwork-Id: 65784 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 8992DB70E6 for ; Mon, 27 Sep 2010 00:05:30 +1000 (EST) Received: (qmail 25677 invoked by alias); 26 Sep 2010 14:05:29 -0000 Received: (qmail 25661 invoked by uid 22791); 26 Sep 2010 14:05:25 -0000 X-SWARE-Spam-Status: No, hits=-1.9 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_NONE, TW_BJ, TW_KW X-Spam-Check-By: sourceware.org Received: from c2beaomr07.btconnect.com (HELO mail.btconnect.com) (213.123.26.185) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sun, 26 Sep 2010 14:05:16 +0000 Received: from host81-138-1-83.in-addr.btopenworld.com (EHLO thor.office) ([81.138.1.83]) by c2beaomr07.btconnect.com with ESMTP id ACI78089; Sun, 26 Sep 2010 15:05:12 +0100 (BST) Message-Id: From: IainS To: GCC Patches Mime-Version: 1.0 (Apple Message framework v936) Subject: [Patch, ObjC/C++] Recognize attributes on class, category and protocol declarations. Date: Sun, 26 Sep 2010 15:04:59 +0100 Cc: Mike Stump , "Joseph S. Myers" , Jason Merrill , Nicola Pero X-Mirapoint-IP-Reputation: reputation=Fair-1, source=Queried, refid=tid=0001.0A0B0301.4C9F530B.0208, actions=tag X-Junkmail-Signature-Raw: score=unknown, refid=str=0001.0A0B0201.4C9F5319.001D, ss=1, fgs=0, ip=0.0.0.0, so=2010-07-22 22:03:31, dmn=2009-09-10 00:05:08, mode=single engine X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org 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 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 +#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 +#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 +# . + +# 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 +#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 +#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 +{ +@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 +#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 +# . + +# 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 +#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 +#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 +{ +@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 +#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 +#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 +#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;