From patchwork Mon Oct 25 19:37:57 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicola Pero X-Patchwork-Id: 69172 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 3CBCCB70A8 for ; Tue, 26 Oct 2010 15:38:17 +1100 (EST) Received: (qmail 21038 invoked by alias); 26 Oct 2010 04:38:14 -0000 Received: (qmail 20240 invoked by uid 22791); 26 Oct 2010 04:38:08 -0000 X-SWARE-Spam-Status: No, hits=-1.3 required=5.0 tests=AWL, BAYES_00, TW_BJ, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from eggs.gnu.org (HELO eggs.gnu.org) (140.186.70.92) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 26 Oct 2010 04:37:57 +0000 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PASs6-0007SU-M8 for gcc-patches@gcc.gnu.org; Mon, 25 Oct 2010 15:38:21 -0400 Received: from fencepost.gnu.org ([140.186.70.10]:38513) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PASs6-0007SI-K0 for gcc-patches@gcc.gnu.org; Mon, 25 Oct 2010 15:38:18 -0400 Received: from eggs.gnu.org ([140.186.70.92]:33958) by fencepost.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from ) id 1PASrp-00036y-Qq for gcc-patches@gnu.org; Mon, 25 Oct 2010 15:38:01 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PASrm-0007OM-Dx for gcc-patches@gnu.org; Mon, 25 Oct 2010 15:38:01 -0400 Received: from smtp131.iad.emailsrvr.com ([207.97.245.131]:60976) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PASrm-0007OB-9l for gcc-patches@gnu.org; Mon, 25 Oct 2010 15:37:58 -0400 Received: from localhost (localhost.localdomain [127.0.0.1]) by smtp33.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id 83CDA3062F for ; Mon, 25 Oct 2010 15:37:57 -0400 (EDT) Received: from dynamic10.wm-web.iad.mlsrvr.com (dynamic10.wm-web.iad1a.rsapps.net [192.168.2.217]) by smtp33.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id 6C71330690 for ; Mon, 25 Oct 2010 15:37:57 -0400 (EDT) Received: from meta-innovation.com (localhost [127.0.0.1]) by dynamic10.wm-web.iad.mlsrvr.com (Postfix) with ESMTP id 5D5DD478807F for ; Mon, 25 Oct 2010 15:37:57 -0400 (EDT) Received: by www2.webmail.us (Authenticated sender: nicola.pero@meta-innovation.com, from: nicola.pero@meta-innovation.com) with HTTP; Mon, 25 Oct 2010 21:37:57 +0200 (CEST) Date: Mon, 25 Oct 2010 21:37:57 +0200 (CEST) Subject: ObjC/ObjC++ - @property parsing From: "Nicola Pero" To: "gcc-patches@gnu.org" MIME-Version: 1.0 X-Type: plain Message-ID: <1288035477.37978763@192.168.2.227> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) 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 This patch is a first chunk of work on the parsing of @property in Objective-C. It's a first patch of a series as I'm updating the @property support in the compiler. Hopefully I'll manage to finish the standard Objective-C 2.0 @property/@synthesized/@dynamic features in time for 4.6.0 (at least, ignoring the new ABI and garbage collection). Unfortunately, there's nothing left to merge from FSF apple/trunk, so I'm on my own, but don't mind. This patch partially rewrites the parsing of @property in Objective-C/Objective-C++, accomplishing the following: * it documents the syntax of @property before c_parser_objc_at_property_declaration and cp_parser_objc_at_property_declaration. * it makes parsing of @property in Objective-C and Objective-C++ much more robust; all the common syntax errors are now processed in a satisfactorily way (6 included testcases contain a zoology of cases where the previous parser would get really confused because of a syntax error while the new one manages to produce reasonable error messages and keep going) ;-) * it makes the parsing of @property in Objective-C and Objective-C++ almost identical (as opposed to having two different implementations as we used to have); parsing is done in c_parser_objc_at_property_declaration() and cp_parser_objc_at_property_declaration() which are now almost identical (modulo replacing c_parser_peek_next_token with cp_lexer_peek_next_token etc). This means I have to maintain one parsing code instead of two (eg, it should immediately help with the follow-up patches, since work on @property parsing is not finished yet!) ;-) * it implements __attribute__s for @property in Objective-C++ (eg __attribute__((deprecated))). A fallout of syncing ObjC and ObjC++ is that I noticed these were missing in Objective-C++. Testcase at-property-2.mm shows this is now working (they are also working for Objective-C, as tested in at-property-2.m). * it improves parsing of properties and instance variables in Objective-C++; 'extern', 'static', 'typedef', '__thread' etc are invalid for properties and instance variables, but the compiler wasn't checking in Objective-C++. Testcases (ivars-invalid-type-1.mm, at-property-3.mm) included showing it now works (and corresponding ObjC testcase shows that ObjC parses them in the same way and emits similar errors [and always has]). As a note, the patch also merges two @property parsing functions. This is a bit of a no-op at this stage, but it allows me to remove the global (to objc-act.c) static property_readonly etc. variables in the next patch. Finally, a couple of ObjC++ testcases have a line or two where the compiler seems to be generating the right messages, but I couldn't get the testsuite to PASS. It seems to be a bug in the testsuite (is it because they are on the last line ?); I don't want to spend time on that right now [as I need to rush to finish @property! :-)] so I added FIXMEs there and left these to be fixed in stage 3. :-) Ok to commit to trunk ? Thanks In gcc/: 2010-10-25 Nicola Pero * c-parser.c (c_parser_objc_at_property): Renamed to c_parser_objc_at_property_declaration. Updated calls to objc_add_property_variable, now objc_add_property_declaration. Code rewritten to be much more robust in recovering from syntax errors. Added comments. (c_parser_objc_property_attrlist): Removed. (c_parser_external_declaration): Updated calls to c_parser_objc_at_property, now c_parser_objc_at_property_declaration. (c_parser_objc_methodprotolist): Same change. In gcc/c-family/: 2010-10-25 Nicola Pero * c-common.h (objc_add_property_variable): Renamed to objc_add_property_declaration. Added location argument. * stub-objc.c (objc_add_property_variable): Same change. In gcc/cp/: 2010-10-25 Nicola Pero * parser.c (cp_parser_objc_property_decl): Renamed to cp_parser_objc_struct_declaration. Return the parsed trees instead of calling objc_add_property_variable directly. Detect missing or invalid declspecs. Implemented attributes. Do not eat the ';' at the end. Exit loop whenever a non-comma is parsed, not just EOF. (cp_parser_objc_at_property): Renamed to cp_parser_objc_at_property_declaration. Updated calls to objc_add_property_variable, now objc_add_property_declaration, and to cp_parser_objc_property_decl, now cp_parser_objc_struct_declaration. Rewritten all code to be more robust in dealing with syntax errors, and almost identical to the one in c_parser_objc_at_property_declaration. (cp_parser_objc_property_attrlist): Removed. (cp_parser_objc_method_prototype_list): Updated call to cp_parser_objc_at_property. (cp_parser_objc_method_definition_list): Same change. (cp_parser_objc_class_ivars): Detect a number of invalid declarations of instance variables and produce errors when they are found. In gcc/objc/: 2010-10-25 Nicola Pero * objc-act.c (objc_add_property_variable): Renamed to objc_add_property_declaration. Added location argument. Updated warnings and errors to use it. Use error, not fatal_error, if a property declaration is found outside an interface or implementation context. In gcc/testsuite/: 2010-10-25 Nicola Pero * objc.dg/property/at-property-1.m: New. * objc.dg/property/at-property-2.m: New. * objc.dg/property/at-property-3.m: New. * objc.dg/ivar-invalid-type-1.m: New. * obj-c++.dg/property/at-property-1.mm: New. * obj-c++.dg/property/at-property-2.mm: New. * obj-c++.dg/property/at-property-3.mm: New. * obj-c++.dg/ivar-invalid-type-1.mm: New. * objc.dg/property/property-neg-6.m: Updated testcase for updates in error reporting. Index: c-family/ChangeLog =================================================================== --- c-family/ChangeLog (revision 165924) +++ c-family/ChangeLog (working copy) @@ -1,3 +1,9 @@ +2010-10-25 Nicola Pero + + * c-common.h (objc_add_property_variable): Renamed to + objc_add_property_declaration. Added location argument. + * stub-objc.c (objc_add_property_variable): Same change. + 2010-10-23 Nicola Pero * c-common.h (objc_maybe_printable_name): New. Index: c-family/c-common.h =================================================================== --- c-family/c-common.h (revision 165924) +++ c-family/c-common.h (working copy) @@ -1043,7 +1043,7 @@ extern void objc_finish_foreach_loop (location_t, extern void objc_set_property_attr (location_t, objc_property_attribute_kind, tree); extern bool objc_method_decl (enum tree_code); -extern void objc_add_property_variable (tree); +extern void objc_add_property_declaration (location_t, tree); extern tree objc_build_getter_call (tree, tree); extern tree objc_build_setter_call (tree, tree); extern void objc_add_synthesize_declaration (location_t, tree); Index: c-family/stub-objc.c =================================================================== --- c-family/stub-objc.c (revision 165924) +++ c-family/stub-objc.c (working copy) @@ -331,7 +331,7 @@ objc_set_property_attr (location_t ARG_UNUSED (loc } void -objc_add_property_variable (tree ARG_UNUSED (prop)) +objc_add_property_declaration (location_t ARG_UNUSED (loc), tree ARG_UNUSED (prop)) { } Index: objc/objc-act.c =================================================================== --- objc/objc-act.c (revision 165924) +++ objc/objc-act.c (working copy) @@ -871,7 +871,7 @@ objc_set_property_attr (location_t loc, objc_prope */ void -objc_add_property_variable (tree decl) +objc_add_property_declaration (location_t location, tree decl) { tree property_decl; tree x; @@ -882,7 +882,7 @@ void interface = lookup_interface (CLASS_NAME (objc_implementation_context)); if (!interface) { - error ("no class property can be implemented without an interface"); + error_at (location, "no class property can be implemented without an interface"); return; } if (TREE_CODE (objc_implementation_context) == CATEGORY_IMPLEMENTATION_TYPE) @@ -891,14 +891,14 @@ void CLASS_SUPER_NAME (objc_implementation_context)); if (!interface) { - error ("no category property can be implemented without an interface"); + error_at (location, "no category property can be implemented without an interface"); return; } } } else if (!objc_interface_context) { - fatal_error ("property declaration not in @interface or @implementation context"); + error_at (location, "property declaration not in @interface or @implementation context"); return; } @@ -923,13 +923,13 @@ void /* Issue error if property and an ivar name match. */ if (TREE_CODE (objc_interface_context) == CLASS_INTERFACE_TYPE && is_ivar (CLASS_IVARS (objc_interface_context), DECL_NAME (decl))) - error ("property %qD may not have the same name as an ivar in the class", decl); + error_at (location, "property %qD may not have the same name as an ivar in the class", decl); /* must check for duplicate property declarations. */ for (x = CLASS_PROPERTY_DECL (objc_interface_context); x; x = TREE_CHAIN (x)) { if (PROPERTY_NAME (x) == DECL_NAME (decl)) { - error ("duplicate property declaration %qD", decl); + error_at (location, "duplicate property declaration %qD", decl); return; } } @@ -945,26 +945,26 @@ void break; if (!x) { - error ("no declaration of property %qD found in the interface", decl); + error_at (location, "no declaration of property %qD found in the interface", decl); return; } /* readonlys must also match. */ if (PROPERTY_READONLY (x) != PROPERTY_READONLY (property_decl)) { - error ("property %qD % attribute conflicts with its" - " interface version", decl); + error_at (location, "property %qD % attribute conflicts with its" + " interface version", decl); } /* copies must also match. */ if (PROPERTY_COPIES (x) != PROPERTY_COPIES (property_decl)) { - error ("property %qD % attribute conflicts with its" - " interface version", decl); + error_at (location, "property %qD % attribute conflicts with its" + " interface version", decl); } /* Cannot have readonly and setter attribute for the same property. */ if (PROPERTY_READONLY (property_decl) == boolean_true_node && PROPERTY_SETTER_NAME (property_decl)) { - warning (0, "a % property cannot have a setter (ignored)"); + warning_at (location, 0, "a % property cannot have a setter (ignored)"); PROPERTY_SETTER_NAME (property_decl) = NULL_TREE; } /* Add the property to the list of properties for current implementation. */ Index: objc/ChangeLog =================================================================== --- objc/ChangeLog (revision 165924) +++ objc/ChangeLog (working copy) @@ -1,3 +1,11 @@ +2010-10-25 Nicola Pero + + * objc-act.c (objc_add_property_variable): Renamed to + objc_add_property_declaration. Added location argument. Updated + warnings and errors to use it. Use error, not fatal_error, if a + property declaration is found outside an interface or + implementation context. + 2010-10-24 Nicola Pero * objc-act.c (objc_build_keyword_decl): Updated comments. Do not Index: ChangeLog =================================================================== --- ChangeLog (revision 165924) +++ ChangeLog (working copy) @@ -1,3 +1,16 @@ +2010-10-25 Nicola Pero + + * c-parser.c (c_parser_objc_at_property): Renamed to + c_parser_objc_at_property_declaration. Updated calls to + objc_add_property_variable, now objc_add_property_declaration. + Code rewritten to be much more robust in recovering from syntax + errors. Added comments. + (c_parser_objc_property_attrlist): Removed. + (c_parser_external_declaration): Updated calls to + c_parser_objc_at_property, now + c_parser_objc_at_property_declaration. + (c_parser_objc_methodprotolist): Same change. + 2010-10-25 Eric Botcazou * configure.ac: Use $cpu_type instead of $target to define the nop. Index: testsuite/ChangeLog =================================================================== --- testsuite/ChangeLog (revision 165924) +++ testsuite/ChangeLog (working copy) @@ -1,3 +1,16 @@ +2010-10-25 Nicola Pero + + * objc.dg/property/at-property-1.m: New. + * objc.dg/property/at-property-2.m: New. + * objc.dg/property/at-property-3.m: New. + * objc.dg/ivar-invalid-type-1.m: New. + * obj-c++.dg/property/at-property-1.mm: New. + * obj-c++.dg/property/at-property-2.mm: New. + * obj-c++.dg/property/at-property-3.mm: New. + * obj-c++.dg/ivar-invalid-type-1.mm: New. + * objc.dg/property/property-neg-6.m: Updated testcase for updates + in error reporting. + 2010-10-25 Eric Botcazou * gnat.dg/in_out_parameter2.adb: New test. Index: testsuite/objc.dg/property/at-property-1.m =================================================================== --- testsuite/objc.dg/property/at-property-1.m (revision 0) +++ testsuite/objc.dg/property/at-property-1.m (revision 0) @@ -0,0 +1,21 @@ +/* { dg-do compile } */ + +#include + +@interface MyRootClass +{ + Class isa; +} +@property; /* { dg-error "expected" } */ +@property int; /* { dg-error "expected identifier" } */ + /* { dg-warning "declaration does not declare anything" "" { target *-*-* } 10 } */ +@property int a; +@property int b, c; +@property () int d; /* { dg-error "expected identifier" } */ +@property (readonly) int e; +@property (readonly,) int f; /* { dg-error "expected identifier" } */ +@property (xxx) int g; /* { dg-error "unknown property attribute" } */ +@property (readonly,xxx) int h; /* { dg-error "unknown property attribute" } */ +@property ( int i; /* { dg-error "unknown property attribute" } */ +/* Because the last syntax error opens a '(' and never closes it, we get to the end of input. */ +@end /* { dg-error "expected ..end. at end of input" } */ Index: testsuite/objc.dg/property/at-property-2.m =================================================================== --- testsuite/objc.dg/property/at-property-2.m (revision 0) +++ testsuite/objc.dg/property/at-property-2.m (revision 0) @@ -0,0 +1,13 @@ +/* { dg-do compile } */ + +#include + +@interface MyRootClass +{ + Class isa; +} +@property id name __attribute__((deprecated)); +@property id table __attribute__((xxx)); /* { dg-warning ".xxx. attribute directive ignored" } */ +@property void function (void); /* { dg-error "declared as a function" } */ +@property typedef int j; /* { dg-error "expected" } */ +@end Index: testsuite/objc.dg/property/at-property-3.m =================================================================== --- testsuite/objc.dg/property/at-property-3.m (revision 0) +++ testsuite/objc.dg/property/at-property-3.m (revision 0) @@ -0,0 +1,15 @@ +/* { dg-do compile } */ + +#include + +@interface MyRootClass +{ + Class isa; +} +@property volatile int a; /* This is allowed */ +@property extern int b; /* { dg-error "expected" } */ +@property static int c; /* { dg-error "expected" } */ +@property inline int d; /* { dg-error "expected" } */ +@property typedef int e; /* { dg-error "expected" } */ +@property __thread int f; /* { dg-error "expected" } */ +@end Index: testsuite/objc.dg/property/property-neg-6.m =================================================================== --- testsuite/objc.dg/property/property-neg-6.m (revision 165924) +++ testsuite/objc.dg/property/property-neg-6.m (working copy) @@ -6,3 +6,4 @@ int iVar; } @property int FooBar /* { dg-error "expected ':', ',', ';', '\}' or '__attribute__' at end of input" } */ +/* { dg-error "expected ..end. at end of input" "" { target *-*-* } 8 } */ Index: testsuite/objc.dg/ivar-invalid-type-1.m =================================================================== --- testsuite/objc.dg/ivar-invalid-type-1.m (revision 0) +++ testsuite/objc.dg/ivar-invalid-type-1.m (revision 0) @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +#include + +@interface MyRootClass +{ + Class isa; +} +@end + +@interface MySubClass +{ + volatile int a; /* This is allowed */ + extern int b; /* { dg-error "expected" } */ + static int c; /* { dg-error "expected" } */ + inline int d; /* { dg-error "expected" } */ + typedef int e; /* { dg-error "expected" } */ + __thread int f; /* { dg-error "expected" } */ +} +@end Index: testsuite/obj-c++.dg/property/at-property-1.mm =================================================================== --- testsuite/obj-c++.dg/property/at-property-1.mm (revision 0) +++ testsuite/obj-c++.dg/property/at-property-1.mm (revision 0) @@ -0,0 +1,23 @@ +/* { dg-do compile } */ + +#include + +@interface MyRootClass +{ + Class isa; +} +@property; /* { dg-error "expected identifier" } */ +@property int; /* { dg-error "expected identifier" } */ +@property int a; +@property int b, c; +@property () int d; /* { dg-error "expected identifier" } */ +@property (readonly) int e; +@property (readonly,) int f; /* { dg-error "expected identifier" } */ +@property (xxx) int g; /* { dg-error "unknown property attribute" } */ +@property (readonly,xxx) int h; /* { dg-error "unknown property attribute" } */ +/* FIXME - there is a problem with the testuite in running the following test. The compiler + generates the messages, but the testsuite still complains. */ +/*@property ( int i;*/ /* dg-error "unknown property attribute" */ + /* dg-error "expected ... " "" { target *-*-* } 18 */ + /* dg-error "expected identfier " "" { target *-*-* } 18 */ +@end Index: testsuite/obj-c++.dg/property/at-property-2.mm =================================================================== --- testsuite/obj-c++.dg/property/at-property-2.mm (revision 0) +++ testsuite/obj-c++.dg/property/at-property-2.mm (revision 0) @@ -0,0 +1,13 @@ +/* { dg-do compile } */ + +#include + +@interface MyRootClass +{ + Class isa; +} +@property id name __attribute__((deprecated)); +@property id table __attribute__((xxx)); /* { dg-warning ".xxx. attribute directive ignored" } */ +@property void function (void); /* { dg-error "can.t make .function. into a method" } */ +@property typedef int j; /* { dg-error "invalid type for property" } */ +@end Index: testsuite/obj-c++.dg/property/at-property-3.mm =================================================================== --- testsuite/obj-c++.dg/property/at-property-3.mm (revision 0) +++ testsuite/obj-c++.dg/property/at-property-3.mm (revision 0) @@ -0,0 +1,15 @@ +/* { dg-do compile } */ + +#include + +@interface MyRootClass +{ + Class isa; +} +@property volatile int a; /* This is allowed */ +@property extern int b; /* { dg-error "invalid type" } */ +@property static int c; /* { dg-error "invalid type" } */ +@property inline int d; /* { dg-error "declared as an .inline." } */ +@property typedef int e; /* { dg-error "invalid type" } */ +@property __thread int f; /* { dg-error "invalid type" } */ +@end Index: testsuite/obj-c++.dg/ivar-invalid-type-1.mm =================================================================== --- testsuite/obj-c++.dg/ivar-invalid-type-1.mm (revision 0) +++ testsuite/obj-c++.dg/ivar-invalid-type-1.mm (revision 0) @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +#include + +@interface MyRootClass +{ + Class isa; +} +@end + +@interface MySubClass +{ + volatile int a; /* This is allowed */ + extern int b; /* { dg-error "invalid type" } */ + static int c; /* { dg-error "invalid type" } */ + inline int d; /* { dg-error "declared as an .inline." } */ + typedef int e; /* { dg-error "invalid type" } */ + __thread int f; /* dg-error "invalid type" */ /* FIXME: The compiler generates this message, but the testsuite does not match it. */ +} +@end Index: cp/ChangeLog =================================================================== --- cp/ChangeLog (revision 165924) +++ cp/ChangeLog (working copy) @@ -1,3 +1,26 @@ +2010-10-25 Nicola Pero + + * parser.c (cp_parser_objc_property_decl): Renamed to + cp_parser_objc_struct_declaration. Return the parsed trees + instead of calling objc_add_property_variable directly. Detect + missing or invalid declspecs. Implemented attributes. Do not eat + the ';' at the end. Exit loop whenever a non-comma is parsed, not + just EOF. + (cp_parser_objc_at_property): Renamed to + cp_parser_objc_at_property_declaration. Updated calls to + objc_add_property_variable, now objc_add_property_declaration, and + to cp_parser_objc_property_decl, now + cp_parser_objc_struct_declaration. Rewritten all code to be more + robust in dealing with syntax errors, and almost identical to the + one in c_parser_objc_at_property_declaration. + (cp_parser_objc_property_attrlist): Removed. + (cp_parser_objc_method_prototype_list): Updated call to + cp_parser_objc_at_property. + (cp_parser_objc_method_definition_list): Same change. + (cp_parser_objc_class_ivars): Detect a number of invalid + declarations of instance variables and produce errors when they + are found. + 2010-10-24 Nicola Pero Removed Objective-C++ specific replacement of cxx_printable_name. Index: cp/parser.c =================================================================== --- cp/parser.c (revision 165924) +++ cp/parser.c (working copy) @@ -2098,13 +2098,13 @@ static tree cp_parser_objc_statement (cp_parser *); static bool cp_parser_objc_valid_prefix_attributes (cp_parser *, tree *); -static void cp_parser_objc_at_property +static void cp_parser_objc_at_property_declaration (cp_parser *) ; static void cp_parser_objc_at_synthesize_declaration (cp_parser *) ; static void cp_parser_objc_at_dynamic_declaration (cp_parser *) ; -static void cp_parser_objc_property_decl +static tree cp_parser_objc_struct_declaration (cp_parser *) ; /* Utility Routines */ @@ -21752,7 +21752,7 @@ cp_parser_objc_method_prototype_list (cp_parser* p cp_parser_consume_semicolon_at_end_of_statement (parser); } else if (token->keyword == RID_AT_PROPERTY) - cp_parser_objc_at_property (parser); + cp_parser_objc_at_property_declaration (parser); else if (token->keyword == RID_ATTRIBUTE && cp_parser_objc_method_maybe_bad_prefix_attributes(parser)) warning_at (cp_lexer_peek_token (parser->lexer)->location, @@ -21819,8 +21819,10 @@ cp_parser_objc_method_definition_list (cp_parser* objc_finish_method_definition (meth); } } + /* The following case will be removed once @synthesize is + completely implemented. */ else if (token->keyword == RID_AT_PROPERTY) - cp_parser_objc_at_property (parser); + cp_parser_objc_at_property_declaration (parser); else if (token->keyword == RID_AT_SYNTHESIZE) cp_parser_objc_at_synthesize_declaration (parser); else if (token->keyword == RID_AT_DYNAMIC) @@ -21873,6 +21875,28 @@ cp_parser_objc_class_ivars (cp_parser* parser) CP_PARSER_FLAGS_OPTIONAL, &declspecs, &decl_class_or_enum_p); + + /* auto, register, static, extern, mutable. */ + if (declspecs.storage_class != sc_none) + { + cp_parser_error (parser, "invalid type for instance variable"); + declspecs.storage_class = sc_none; + } + + /* __thread. */ + if (declspecs.specs[(int) ds_thread]) + { + cp_parser_error (parser, "invalid type for instance variable"); + declspecs.specs[(int) ds_thread] = 0; + } + + /* typedef. */ + if (declspecs.specs[(int) ds_typedef]) + { + cp_parser_error (parser, "invalid type for instance variable"); + declspecs.specs[(int) ds_typedef] = 0; + } + prefix_attributes = declspecs.attributes; declspecs.attributes = NULL_TREE; @@ -22318,146 +22342,277 @@ cp_parser_objc_valid_prefix_attributes (cp_parser* return false; } -/* This routine parses the propery declarations. */ +/* This routine is a minimal replacement for + c_parser_struct_declaration () used when parsing the list of + types/names or ObjC++ properties. For example, when parsing the + code -static void -cp_parser_objc_property_decl (cp_parser *parser) + @property (readonly) int a, b, c; + + this function is responsible for parsing "int a, int b, int c" and + returning the declarations as CHAIN of DECLs. + + TODO: Share this code with cp_parser_objc_class_ivars. It's very + similar parsing. */ +static tree +cp_parser_objc_struct_declaration (cp_parser *parser) { - int declares_class_or_enum; + tree decls = NULL_TREE; cp_decl_specifier_seq declspecs; + int decl_class_or_enum_p; + tree prefix_attributes; cp_parser_decl_specifier_seq (parser, - CP_PARSER_FLAGS_NONE, - &declspecs, - &declares_class_or_enum); + CP_PARSER_FLAGS_NONE, + &declspecs, + &decl_class_or_enum_p); + + if (declspecs.type == error_mark_node) + return error_mark_node; + + /* auto, register, static, extern, mutable. */ + if (declspecs.storage_class != sc_none) + { + cp_parser_error (parser, "invalid type for property"); + declspecs.storage_class = sc_none; + } + + /* __thread. */ + if (declspecs.specs[(int) ds_thread]) + { + cp_parser_error (parser, "invalid type for property"); + declspecs.specs[(int) ds_thread] = 0; + } + + /* typedef. */ + if (declspecs.specs[(int) ds_typedef]) + { + cp_parser_error (parser, "invalid type for property"); + declspecs.specs[(int) ds_typedef] = 0; + } + + prefix_attributes = declspecs.attributes; + declspecs.attributes = NULL_TREE; + /* Keep going until we hit the `;' at the end of the declaration. */ while (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) { - tree property; + tree attributes, first_attribute, decl; + cp_declarator *declarator; cp_token *token; - cp_declarator *declarator - = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, - NULL, NULL, false); - property = grokdeclarator (declarator, &declspecs, NORMAL,0, NULL); - /* Recover from any kind of error in property declaration. */ - if (property == error_mark_node || property == NULL_TREE) - return; - /* Add to property list. */ - objc_add_property_variable (copy_node (property)); + /* Parse the declarator. */ + declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, + NULL, NULL, false); + + /* Look for attributes that apply to the ivar. */ + attributes = cp_parser_attributes_opt (parser); + /* Remember which attributes are prefix attributes and + which are not. */ + first_attribute = attributes; + /* Combine the attributes. */ + attributes = chainon (prefix_attributes, attributes); + + decl = grokfield (declarator, &declspecs, + NULL_TREE, /*init_const_expr_p=*/false, + NULL_TREE, attributes); + + if (decl == error_mark_node || decl == NULL_TREE) + return error_mark_node; + + /* Reset PREFIX_ATTRIBUTES. */ + while (attributes && TREE_CHAIN (attributes) != first_attribute) + attributes = TREE_CHAIN (attributes); + if (attributes) + TREE_CHAIN (attributes) = NULL_TREE; + + DECL_CHAIN (decl) = decls; + decls = decl; + token = cp_lexer_peek_token (parser->lexer); if (token->type == CPP_COMMA) { cp_lexer_consume_token (parser->lexer); /* Eat ','. */ continue; } - else if (token->type == CPP_EOF) + else break; } - /* Eat ';' if present, or issue an error. */ - cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); + return decls; } -/* ObjC @property. */ -/* Parse a comma-separated list of property attributes. - The lexer does not recognize */ +/* Parse an Objective-C @property declaration. The syntax is: + objc-property-declaration: + '@property' objc-property-attributes[opt] struct-declaration ; + + objc-property-attributes: + '(' objc-property-attribute-list ')' + + objc-property-attribute-list: + objc-property-attribute + objc-property-attribute-list, objc-property-attribute + + objc-property-attribute + 'getter' = identifier + 'setter' = identifier + 'readonly' + 'readwrite' + 'assign' + 'retain' + 'copy' + 'nonatomic' + + For example: + @property NSString *name; + @property (readonly) id object; + @property (retain, nonatomic, getter=getTheName) id name; + @property int a, b, c; + + PS: This function is identical to + c_parser_objc_at_property_declaration for C. Keep them in sync. + + WORK IN PROGRESS: At the moment, the list of attributes that are + parsed is different from the above list. It will be updated to use + the above list at the same time as @synthesize is implemented. */ static void -cp_parser_objc_property_attrlist (cp_parser *parser) +cp_parser_objc_at_property_declaration (cp_parser *parser) { - cp_token *token; - /* Initialize to an empty list. */ - objc_set_property_attr (cp_lexer_peek_token (parser->lexer)->location, - OBJC_PATTR_INIT, NULL_TREE); + tree properties; + location_t loc; + loc = cp_lexer_peek_token (parser->lexer)->location; - /* The list is optional. */ - if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)) - return; + cp_lexer_consume_token (parser->lexer); /* Eat '@property'. */ - /* Eat the '('. */ - cp_lexer_consume_token (parser->lexer); + /* Initialize attributes to an empty list. */ + objc_set_property_attr (loc, OBJC_PATTR_INIT, NULL_TREE); - token = cp_lexer_peek_token (parser->lexer); - while (token->type != CPP_CLOSE_PAREN && token->type != CPP_EOF) + /* Parse the optional attribute list... */ + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) { - location_t loc = token->location; - tree node = cp_parser_identifier (parser); - if (node == ridpointers [(int) RID_READONLY]) - objc_set_property_attr (loc, OBJC_PATTR_READONLY, NULL_TREE); - else if (node == ridpointers [(int) RID_GETTER] - || node == ridpointers [(int) RID_SETTER] - || node == ridpointers [(int) RID_IVAR]) + /* Eat the '('. */ + cp_lexer_consume_token (parser->lexer); + + while (true) { - /* Do the getter/setter/ivar attribute. */ - token = cp_lexer_consume_token (parser->lexer); - if (token->type == CPP_EQ) + bool syntax_error = false; + cp_token *token = cp_lexer_peek_token (parser->lexer); + enum rid keyword; + + if (token->type != CPP_NAME) { - tree attr_ident = cp_parser_identifier (parser); + cp_parser_error (parser, "expected identifier"); + break; + } + keyword = C_RID_CODE (token->u.value); + switch (keyword) + { + tree ident; objc_property_attribute_kind pkind; - if (node == ridpointers [(int) RID_GETTER]) - pkind = OBJC_PATTR_GETTER; - else if (node == ridpointers [(int) RID_SETTER]) + case RID_READONLY: + cp_lexer_consume_token (parser->lexer); + objc_set_property_attr (loc, OBJC_PATTR_READONLY, NULL_TREE); + break; + case RID_GETTER: + case RID_SETTER: + case RID_IVAR: + cp_lexer_consume_token (parser->lexer); + if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)) { + cp_parser_error (parser, + "getter/setter/ivar attribute must be followed by %<=%>"); + syntax_error = true; + break; + } + cp_lexer_consume_token (parser->lexer); /* eat the = */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME)) + { + cp_parser_error (parser, "expected identifier"); + syntax_error = true; + break; + } + ident = cp_lexer_peek_token (parser->lexer)->u.value; + cp_lexer_consume_token (parser->lexer); + if (keyword == RID_SETTER) + { pkind = OBJC_PATTR_SETTER; - /* Consume the ':' which must always follow the setter name. */ - if (cp_lexer_next_token_is (parser->lexer, CPP_COLON)) - cp_lexer_consume_token (parser->lexer); - else + /* Eat the identifier, and look for the following : */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON)) { - error_at (token->location, - "setter name must be followed by %<:%>"); + cp_parser_error (parser, + "setter name must be followed by %<:%>"); + syntax_error = true; break; } + cp_lexer_consume_token (parser->lexer); } - else + else if (keyword == RID_GETTER) + pkind = OBJC_PATTR_GETTER; + else pkind = OBJC_PATTR_IVAR; - objc_set_property_attr (loc, pkind, attr_ident); + objc_set_property_attr (loc, pkind, ident); + break; + case RID_COPIES: + cp_lexer_consume_token (parser->lexer); + objc_set_property_attr (loc, OBJC_PATTR_COPIES, NULL_TREE); + break; + default: + if (token->type == CPP_CLOSE_PAREN) + cp_parser_error (parser, "expected identifier"); + else + { + cp_lexer_consume_token (parser->lexer); + cp_parser_error (parser, "unknown property attribute"); + } + syntax_error = true; + break; } + + if (syntax_error) + break; + + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); else - { - error_at (token->location, - "getter/setter/ivar attribute must be followed by %<=%>"); - break; - } + break; } - else if (node == ridpointers [(int) RID_COPIES]) - objc_set_property_attr (loc, OBJC_PATTR_COPIES, NULL_TREE); - else + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) { - error_at (token->location,"unknown property attribute"); - break; + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); } - if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + } + + /* ... and the property declaration(s). */ + properties = cp_parser_objc_struct_declaration (parser); + + if (properties == error_mark_node) + { + cp_parser_skip_to_end_of_statement (parser); + /* If the next token is now a `;', consume it. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) cp_lexer_consume_token (parser->lexer); - else if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)) - warning_at (token->location, 0, - "property attributes should be separated by a %<,%>"); - token = cp_lexer_peek_token (parser->lexer); + return; } - if (token->type != CPP_CLOSE_PAREN) - error_at (token->location, - "syntax error in @property's attribute declaration"); + if (properties == NULL_TREE) + cp_parser_error (parser, "expected identifier"); else - /* Consume ')' */ - cp_lexer_consume_token (parser->lexer); + { + /* Comma-separated properties are chained together in + reverse order; add them one by one. */ + properties = nreverse (properties); + + for (; properties; properties = TREE_CHAIN (properties)) + objc_add_property_declaration (loc, copy_node (properties)); + } + + cp_parser_consume_semicolon_at_end_of_statement (parser); } -/* This function parses a @property declaration inside an objective class - or its implementation. */ - -static void -cp_parser_objc_at_property (cp_parser *parser) -{ - /* Consume @property */ - cp_lexer_consume_token (parser->lexer); - - /* Parse optional attributes list... */ - cp_parser_objc_property_attrlist (parser); - /* ... and the property declaration(s). */ - cp_parser_objc_property_decl (parser); -} - /* Parse an Objective-C++ @synthesize declaration. The syntax is: objc-synthesize-declaration: Index: c-parser.c =================================================================== --- c-parser.c (revision 165924) +++ c-parser.c (working copy) @@ -1081,7 +1081,7 @@ static tree c_parser_objc_selector_arg (c_parser * static tree c_parser_objc_receiver (c_parser *); static tree c_parser_objc_message_args (c_parser *); static tree c_parser_objc_keywordexpr (c_parser *); -static void c_parser_objc_at_property (c_parser *) ; +static void c_parser_objc_at_property_declaration (c_parser *); static void c_parser_objc_at_synthesize_declaration (c_parser *); static void c_parser_objc_at_dynamic_declaration (c_parser *); static bool c_parser_objc_diagnose_bad_element_prefix @@ -1185,7 +1185,7 @@ c_parser_external_declaration (c_parser *parser) break; case RID_AT_PROPERTY: gcc_assert (c_dialect_objc ()); - c_parser_objc_at_property (parser); + c_parser_objc_at_property_declaration (parser); break; case RID_AT_SYNTHESIZE: gcc_assert (c_dialect_objc ()); @@ -6997,7 +6997,7 @@ c_parser_objc_methodprotolist (c_parser *parser) if (c_parser_next_token_is_keyword (parser, RID_AT_END)) return; else if (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY)) - c_parser_objc_at_property (parser); + c_parser_objc_at_property_declaration (parser); else if (c_parser_next_token_is_keyword (parser, RID_AT_OPTIONAL)) { objc_set_method_opt (true); @@ -7574,132 +7574,178 @@ c_parser_objc_diagnose_bad_element_prefix (c_parse return false; } -/* ObjC @property. */ +/* Parse an Objective-C @property declaration. The syntax is: -/* Parse a comma-separated list of property attributes. */ + objc-property-declaration: + '@property' objc-property-attributes[opt] struct-declaration ; + objc-property-attributes: + '(' objc-property-attribute-list ')' + + objc-property-attribute-list: + objc-property-attribute + objc-property-attribute-list, objc-property-attribute + + objc-property-attribute + 'getter' = identifier + 'setter' = identifier + 'readonly' + 'readwrite' + 'assign' + 'retain' + 'copy' + 'nonatomic' + + For example: + @property NSString *name; + @property (readonly) id object; + @property (retain, nonatomic, getter=getTheName) id name; + @property int a, b, c; + + PS: This function is identical to cp_parser_objc_at_propery_declaration + for C++. Keep them in sync. + + WORK IN PROGRESS: At the moment, the list of attributes that are + parsed is different from the above list. It will be updated to use + the above list at the same time as @synthesize is implemented. */ static void -c_parser_objc_property_attrlist (c_parser *parser) +c_parser_objc_at_property_declaration (c_parser *parser) { - bool err = false; - /* Initialize to an empty list. */ - objc_set_property_attr (c_parser_peek_token (parser)->location, - OBJC_PATTR_INIT, NULL_TREE); + tree properties; + location_t loc; + loc = c_parser_peek_token (parser)->location; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY)); - if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN)) - return; + c_parser_consume_token (parser); /* Eat '@property'. */ - /* Eat the '(' */ - c_parser_consume_token (parser); - - /* Property attribute keywords are valid now. */ - parser->objc_property_attr_context = true; - while (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN) - && c_parser_next_token_is_not (parser, CPP_EOF) - && !err) + /* Initialize attributes to an empty list. */ + objc_set_property_attr (loc, OBJC_PATTR_INIT, NULL_TREE); + + /* Parse the optional attribute list... */ + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) { - enum rid keywd; - location_t loc; - if (c_parser_peek_token (parser)->type != CPP_KEYWORD) + /* Eat the '(' */ + c_parser_consume_token (parser); + + /* Property attribute keywords are valid now. */ + parser->objc_property_attr_context = true; + + while (true) { - c_parser_error (parser, "expected a property attribute"); - c_parser_consume_token (parser); - err = true; - break; - } - keywd = c_parser_peek_token (parser)->keyword; - /* Initially, make diagnostics point to the attribute. */ - loc = c_parser_peek_token (parser)->location; - switch (keywd) - { - tree ident; - objc_property_attribute_kind pkind; - case RID_READONLY: - objc_set_property_attr (loc, OBJC_PATTR_READONLY, NULL_TREE); + bool syntax_error = false; + c_token *token = c_parser_peek_token (parser); + enum rid keyword; + + if (token->type != CPP_KEYWORD) + { + if (token->type == CPP_CLOSE_PAREN) + c_parser_error (parser, "expected identifier"); + else + { + c_parser_consume_token (parser); + c_parser_error (parser, "unknown property attribute"); + } + break; + } + keyword = token->keyword; + switch (keyword) + { + tree ident; + objc_property_attribute_kind pkind; + case RID_READONLY: + c_parser_consume_token (parser); + objc_set_property_attr (loc, OBJC_PATTR_READONLY, NULL_TREE); + break; + case RID_GETTER: + case RID_SETTER: + case RID_IVAR: + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_EQ)) + { + c_parser_error (parser, + "getter/setter/ivar attribute must be followed by %<=%>"); + syntax_error = true; + break; + } + c_parser_consume_token (parser); /* eat the = */ + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + syntax_error = true; + break; + } + ident = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + if (keyword == RID_SETTER) + { + pkind = OBJC_PATTR_SETTER; + /* Eat the identifier, and look for the following : */ + if (c_parser_next_token_is_not (parser, CPP_COLON)) + { + c_parser_error (parser, + "setter name must be followed by %<:%>"); + syntax_error = true; + break; + } + c_parser_consume_token (parser); + } + else if (keyword == RID_GETTER) + pkind = OBJC_PATTR_GETTER; + else + pkind = OBJC_PATTR_IVAR; + objc_set_property_attr (loc, pkind, ident); + break; + case RID_COPIES: + c_parser_consume_token (parser); + objc_set_property_attr (loc, OBJC_PATTR_COPIES, NULL_TREE); + break; + default: + if (token->type == CPP_CLOSE_PAREN) + c_parser_error (parser, "expected identifier"); + else + { + c_parser_consume_token (parser); + c_parser_error (parser, "unknown property attribute"); + } + syntax_error = true; + break; + } + + if (syntax_error) break; - case RID_GETTER: - case RID_SETTER: - case RID_IVAR: + + if (c_parser_next_token_is (parser, CPP_COMMA)) c_parser_consume_token (parser); - if (c_parser_next_token_is_not (parser, CPP_EQ)) - { - c_parser_error (parser, - "getter/setter/ivar attribute must be followed by %<=%>"); - err = true; - break; - } - c_parser_consume_token (parser); /* eat the = */ - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - c_parser_error (parser, "expected an identifier"); - err = true; - break; - } - ident = c_parser_peek_token (parser)->value; - if (keywd == RID_SETTER) - { - pkind = OBJC_PATTR_SETTER; - /* Eat the identifier, and look for the following : */ - c_parser_consume_token (parser); - if (c_parser_next_token_is_not (parser, CPP_COLON)) - { - c_parser_error (parser, - "setter name must be followed by %<:%>"); - err = true; - } - } - else if (keywd == RID_GETTER) - pkind = OBJC_PATTR_GETTER; - else - pkind = OBJC_PATTR_IVAR; - - objc_set_property_attr (loc, pkind, ident); + else break; - case RID_COPIES: - objc_set_property_attr (loc, OBJC_PATTR_COPIES, NULL_TREE); - break; - default: - c_parser_error (parser, "unknown property attribute"); - err = true; - break; } - /* Eat the attribute,identifier or colon that's been used. */ - c_parser_consume_token (parser); - if (err) - break; + parser->objc_property_attr_context = false; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + /* ... and the property declaration(s). */ + properties = c_parser_struct_declaration (parser); - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); - else if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) - warning_at (c_parser_peek_token (parser)->location, 0, - "property attributes should be separated by a %<,%>"); - } - parser->objc_property_attr_context = false; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); -} + if (properties == error_mark_node) + { + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + parser->error = false; + return; + } -/* Parse property attributes and then the definition. */ + if (properties == NULL_TREE) + c_parser_error (parser, "expected identifier"); + else + { + /* Comma-separated properties are chained together in + reverse order; add them one by one. */ + properties = nreverse (properties); + + for (; properties; properties = TREE_CHAIN (properties)) + objc_add_property_declaration (loc, copy_node (properties)); + } -static void -c_parser_objc_at_property (c_parser *parser) -{ - tree props; - /* We should only arrive here with the property keyword. */ - c_parser_require_keyword (parser, RID_AT_PROPERTY, "expected %<@property%>"); - - /* Process the optional attribute list... */ - c_parser_objc_property_attrlist (parser) ; - /* ... and the property var decls. */ - props = c_parser_struct_declaration (parser); - - /* Comma-separated properties are chained together in - reverse order; add them one by one. */ - props = nreverse (props); - - for (; props; props = TREE_CHAIN (props)) - objc_add_property_variable (copy_node (props)); - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + parser->error = false; } /* Parse an Objective-C @synthesize declaration. The syntax is: