From patchwork Sat Nov 6 23:39:32 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicola Pero X-Patchwork-Id: 70338 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 70E5EB70FB for ; Sun, 7 Nov 2010 10:40:07 +1100 (EST) Received: (qmail 26793 invoked by alias); 6 Nov 2010 23:40:04 -0000 Received: (qmail 26708 invoked by uid 22791); 6 Nov 2010 23:39:55 -0000 X-SWARE-Spam-Status: No, hits=0.0 required=5.0 tests=AWL, BAYES_50, TW_BJ, TW_CP, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from fencepost.gnu.org (HELO fencepost.gnu.org) (140.186.70.10) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sat, 06 Nov 2010 23:39:41 +0000 Received: from eggs.gnu.org ([140.186.70.92]:42796) by fencepost.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from ) id 1PEsMD-0004Nf-Sj for gcc-patches@gnu.org; Sat, 06 Nov 2010 19:39:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PEsMA-000435-BX for gcc-patches@gnu.org; Sat, 06 Nov 2010 19:39:38 -0400 Received: from smtp141.iad.emailsrvr.com ([207.97.245.141]:57421) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PEsMA-00042w-5K for gcc-patches@gnu.org; Sat, 06 Nov 2010 19:39:34 -0400 Received: from localhost (localhost.localdomain [127.0.0.1]) by smtp34.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id 113B63800B5 for ; Sat, 6 Nov 2010 19:39:33 -0400 (EDT) Received: from dynamic8.wm-web.iad.mlsrvr.com (dynamic8.wm-web.iad1a.rsapps.net [192.168.2.149]) by smtp34.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id E9A163800B1 for ; Sat, 6 Nov 2010 19:39:32 -0400 (EDT) Received: from meta-innovation.com (localhost [127.0.0.1]) by dynamic8.wm-web.iad.mlsrvr.com (Postfix) with ESMTP id D587C305006C for ; Sat, 6 Nov 2010 19:39:32 -0400 (EDT) Received: by www2.webmail.us (Authenticated sender: nicola.pero@meta-innovation.com, from: nicola.pero@meta-innovation.com) with HTTP; Sun, 7 Nov 2010 00:39:32 +0100 (CET) Date: Sun, 7 Nov 2010 00:39:32 +0100 (CET) Subject: ObjC/ObjC++ - yet another bunch of @property fixes From: "Nicola Pero" To: "gcc-patches@gnu.org" MIME-Version: 1.0 X-Type: plain Message-ID: <1289086772.87318910@192.168.2.229> 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 fixes a bunch of missing (or incorrect) warnings and checks for @properties -- * adds some missing checks for a @property declaration. When a @property is declared, with this patch we now check for existing @property declarations that would be inherited, and check that the attributes are compatible. In particular, nonatomic / assign semantics / setter / getter attributes must be identical; readonly can be overridden with readwrite (but not vice versa). * removes warnings when a setter/getter for a @property is inherited instead of being implemented directly. In particular, this is useful when you have a readonly property and want to override it with a readwrite one; you may want to implement only the setter, while inheriting the getter as it is (and that should generate no warnings). * it adds some testcases for a similar situation with protocols; in that case, though, there was nothing to implement as we already have the -Wno-protocol switch that allows you to decide if you want a warning or not when a method in a class conforming to a protocol is inherited as opposed to directly implemented in the class. The two testcases show that this works exactly as documented (and still works as documented after my changes to method lookup) with both the -Wno-protocol and the -Wprotocol switches (turning the warnings on or off). * it fixes looking up a @property in a protocol attached to a category of a superclass. Testcases for all the above are included. Ok to commit to trunk ? Thanks In gcc/objc/: 2010-11-07 Nicola Pero * objc-act.c (lookup_property): When checking categories, also check the protocols attached to each. (objc_add_property_declaration): Determine the PROPERTY_SETTER_NAME and PROPERTY_GETTER_NAME here. Tidied up error message. Search for an existing property declaration with the same name which would be inherited from the class hiearchy, and produce an error if it has incompatible attributes. (check_methods): Changed second parameter. If the method is a getter or setter for a property, do not warn if it is inherited as opposed to implemented directly in the class. (check_protocol): Updated calls to check_methods. (finish_class): Do not determine the PROPERTY_SETTER_NAME and PROPERTY_GETTER_NAME here; this is now done earlier, in objc_add_property_declaration. * objc-act.h (CLASS_NAME, CLASS_SUPER_NAME): Added comments. In gcc/testsuite/: 2010-11-07 Nicola Pero * objc.dg/property/at-property-5.m: Updated test. * objc.dg/property/at-property-16.m: New. * objc.dg/property/at-property-17.m: New. * objc.dg/property/at-property-18.m: New. * objc.dg/property/at-property-19.m: New. * objc.dg/property/dotsyntax-12.m: New * objc.dg/protocol-inheritance-1.m: New. * objc.dg/protocol-inheritance-2.m: New. * obj-c++.dg/property/at-property-5.mm: Updated test. * obj-c++.dg/property/at-property-16.mm: New. * obj-c++.dg/property/at-property-17.mm: New. * obj-c++.dg/property/at-property-18.mm: New. * obj-c++.dg/property/at-property-19.mm: New. * obj-c++.dg/protocol-inheritance-1.mm: New. * obj-c++.dg/protocol-inheritance-2.mm: New. * obj-c++.dg/property/dotsyntax-12.mm: New. Index: gcc/objc/objc-act.c =================================================================== --- gcc/objc/objc-act.c (revision 166402) +++ gcc/objc/objc-act.c (working copy) @@ -829,6 +829,78 @@ objc_set_method_opt (bool optional) } } +/* This routine looks for a given PROPERTY in a list of CLASS, CATEGORY, or + PROTOCOL. */ +static tree +lookup_property_in_list (tree chain, tree property) +{ + tree x; + for (x = CLASS_PROPERTY_DECL (chain); x; x = TREE_CHAIN (x)) + if (PROPERTY_NAME (x) == property) + return x; + return NULL_TREE; +} + +/* This routine looks for a given PROPERTY in the tree chain of RPROTO_LIST. */ +static tree lookup_property_in_protocol_list (tree rproto_list, tree property) +{ + tree rproto, x; + for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto)) + { + tree p = TREE_VALUE (rproto); + if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) + { + if ((x = lookup_property_in_list (p, property))) + return x; + if (PROTOCOL_LIST (p)) + return lookup_property_in_protocol_list (PROTOCOL_LIST (p), property); + } + else + { + ; /* An identifier...if we could not find a protocol. */ + } + } + return NULL_TREE; +} + +/* This routine looks up the PROPERTY in current INTERFACE, its categories and up the + chain of interface hierarchy. */ +static tree +lookup_property (tree interface_type, tree property) +{ + tree inter = interface_type; + while (inter) + { + tree x, category; + if ((x = lookup_property_in_list (inter, property))) + return x; + /* Failing that, look for the property in each category of the class. */ + category = inter; + while ((category = CLASS_CATEGORY_LIST (category))) + { + if ((x = lookup_property_in_list (category, property))) + return x; + + /* When checking a category, also check the protocols + attached with the category itself. */ + if (CLASS_PROTOCOL_LIST (category) + && (x = lookup_property_in_protocol_list + (CLASS_PROTOCOL_LIST (category), property))) + return x; + } + + /* Failing to find in categories, look for property in protocol list. */ + if (CLASS_PROTOCOL_LIST (inter) + && (x = lookup_property_in_protocol_list + (CLASS_PROTOCOL_LIST (inter), property))) + return x; + + /* Failing that, climb up the inheritance hierarchy. */ + inter = lookup_interface (CLASS_SUPER_NAME (inter)); + } + return inter; +} + /* This routine is called by the parser when a @property... declaration is found. 'decl' is the declaration of the property (type/identifier), and the other arguments represent @@ -920,19 +992,6 @@ objc_add_property_declaration (location_t location /* At this point we know that we are either in an interface, a category, or a protocol. */ - if (parsed_property_setter_ident) - { - /* The setter should be terminated by ':', but the parser only - gives us an identifier without ':'. So, we need to add ':' - at the end. */ - const char *parsed_setter = IDENTIFIER_POINTER (parsed_property_setter_ident); - size_t length = strlen (parsed_setter); - char *final_setter = (char *)alloca (length + 2); - - sprintf (final_setter, "%s:", parsed_setter); - parsed_property_setter_ident = get_identifier (final_setter); - } - /* Check that the property does not have an initial value specified. This should never happen as the parser doesn't allow this, but it's just in case. */ @@ -984,8 +1043,39 @@ objc_add_property_declaration (location_t location && !objc_type_valid_for_messaging (TREE_TYPE (decl), true)) error_at (location, "% attribute is only valid for Objective-C objects"); + /* Now determine the final property getter and setter names. They + will be stored in the PROPERTY_DECL, from which they'll always be + extracted and used. */ + + /* Adjust, or fill in, setter and getter names. We overwrite the + parsed_property_setter_ident and parsed_property_getter_ident + with the final setter and getter identifiers that will be + used. */ + if (parsed_property_setter_ident) + { + /* The setter should be terminated by ':', but the parser only + gives us an identifier without ':'. So, we need to add ':' + at the end. */ + const char *parsed_setter = IDENTIFIER_POINTER (parsed_property_setter_ident); + size_t length = strlen (parsed_setter); + char *final_setter = (char *)alloca (length + 2); + + sprintf (final_setter, "%s:", parsed_setter); + parsed_property_setter_ident = get_identifier (final_setter); + } + else + { + if (!property_readonly) + parsed_property_setter_ident = get_identifier (objc_build_property_setter_name + (DECL_NAME (decl))); + } + + if (!parsed_property_getter_ident) + parsed_property_getter_ident = DECL_NAME (decl); + /* Check for duplicate property declarations. We first check the - immediate context for a property with the same name. */ + immediate context for a property with the same name. Any such + declarations are an error. */ for (x = CLASS_PROPERTY_DECL (objc_interface_context); x; x = TREE_CHAIN (x)) { if (PROPERTY_NAME (x) == DECL_NAME (decl)) @@ -995,15 +1085,127 @@ objc_add_property_declaration (location_t location error_at (location, "redeclaration of property %qD", decl); if (original_location != UNKNOWN_LOCATION) - inform (original_location, "originally declared here"); + inform (original_location, "originally specified here"); return; } } - /* TODO: Shall we check here for other property declaractions (in - the superclass, other categories or protocols) with the same name - and conflicting types ? */ + /* We now need to check for existing property declarations (in the + superclass, other categories or protocols) and check that the new + declaration is not in conflict with existing ones. */ + /* Search for a previous, existing declaration of a property with + the same name in superclasses, protocols etc. If one is found, + it will be in the 'x' variable. */ + x = NULL_TREE; + + /* Note that, for simplicity, the following may search again the + local context. That's Ok as nothing will be found (else we'd + have thrown an error above); it's only a little inefficient, but + the code is simpler. */ + switch (TREE_CODE (objc_interface_context)) + { + case CLASS_INTERFACE_TYPE: + /* Look up the property in the current @interface (which will + find nothing), then its protocols and categories and + superclasses. */ + x = lookup_property (objc_interface_context, DECL_NAME (decl)); + break; + case CATEGORY_INTERFACE_TYPE: + /* Look up the property in the main @interface, then protocols + and categories (one of them is ours, and will find nothing) + and superclasses. */ + x = lookup_property (lookup_interface (CLASS_NAME (objc_interface_context)), + DECL_NAME (decl)); + break; + case PROTOCOL_INTERFACE_TYPE: + /* Looks up the property in any protocols attached to the + current protocol. */ + if (PROTOCOL_LIST (objc_interface_context)) + { + x = lookup_property_in_protocol_list (PROTOCOL_LIST (objc_interface_context), + DECL_NAME (decl)); + } + break; + default: + gcc_unreachable (); + } + + if (x != NULL_TREE) + { + /* An existing property was found; check that it has the same + types, or it is compatible. */ + location_t original_location = DECL_SOURCE_LOCATION (x); + + if (PROPERTY_NONATOMIC (x) != parsed_property_nonatomic) + { + error_at (location, "'nonatomic' attribute of property %qD conflicts with previous declaration", decl); + + if (original_location != UNKNOWN_LOCATION) + inform (original_location, "originally specified here"); + return; + } + + if (PROPERTY_GETTER_NAME (x) != parsed_property_getter_ident) + { + error_at (location, "'getter' attribute of property %qD conflicts with previous declaration", decl); + + if (original_location != UNKNOWN_LOCATION) + inform (original_location, "originally specified here"); + return; + } + + /* We can only compare the setter names if both the old and new property have a setter. */ + if (!property_readonly && !PROPERTY_READONLY(x)) + { + if (PROPERTY_SETTER_NAME (x) != parsed_property_setter_ident) + { + error_at (location, "'setter' attribute of property %qD conflicts with previous declaration", decl); + + if (original_location != UNKNOWN_LOCATION) + inform (original_location, "originally specified here"); + return; + } + } + + if (PROPERTY_ASSIGN_SEMANTICS (x) != property_assign_semantics) + { + error_at (location, "assign semantics attributes of property %qD conflict with previous declaration", decl); + + if (original_location != UNKNOWN_LOCATION) + inform (original_location, "originally specified here"); + return; + } + + /* It's ok to have a readonly property that becomes a readwrite, but not vice versa. */ + if (PROPERTY_READONLY (x) == 0 && property_readonly == 1) + { + error_at (location, "'readonly' attribute of property %qD conflicts with previous declaration", decl); + + if (original_location != UNKNOWN_LOCATION) + inform (original_location, "originally specified here"); + return; + } + + if (property_readonly) + { + /* If the property is readonly, it is Ok if the property + type is a specialization of the previously declared one. + Eg, the superclass returns 'NSArray' while the subclass + returns 'NSMutableArray'. */ + + /* TODO: Check that the types are the same, or more specialized. */ + ; + } + else + { + /* Else, the types must match exactly. */ + + /* TODO: Check that property types are identical. */ + ; + } + } + /* Create a PROPERTY_DECL node. */ property_decl = make_node (PROPERTY_DECL); @@ -1022,74 +1224,18 @@ objc_add_property_declaration (location_t location PROPERTY_IVAR_NAME (property_decl) = NULL_TREE; PROPERTY_DYNAMIC (property_decl) = 0; + /* Note that PROPERTY_GETTER_NAME is always set for all + PROPERTY_DECLs, and PROPERTY_SETTER_NAME is always set for all + PROPERTY_DECLs where PROPERTY_READONLY == 0. Any time we deal + with a getter or setter, we should get the PROPERTY_DECL and use + PROPERTY_GETTER_NAME and PROPERTY_SETTER_NAME to know the correct + names. */ + /* Add the PROPERTY_DECL to the list of properties for the class. */ TREE_CHAIN (property_decl) = CLASS_PROPERTY_DECL (objc_interface_context); CLASS_PROPERTY_DECL (objc_interface_context) = property_decl; } -/* This routine looks for a given PROPERTY in a list of CLASS, CATEGORY, or - PROTOCOL. */ -static tree -lookup_property_in_list (tree chain, tree property) -{ - tree x; - for (x = CLASS_PROPERTY_DECL (chain); x; x = TREE_CHAIN (x)) - if (PROPERTY_NAME (x) == property) - return x; - return NULL_TREE; -} - -/* This routine looks for a given PROPERTY in the tree chain of RPROTO_LIST. */ -static tree lookup_property_in_protocol_list (tree rproto_list, tree property) -{ - tree rproto, x; - for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto)) - { - tree p = TREE_VALUE (rproto); - if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) - { - if ((x = lookup_property_in_list (p, property))) - return x; - if (PROTOCOL_LIST (p)) - return lookup_property_in_protocol_list (PROTOCOL_LIST (p), property); - } - else - { - ; /* An identifier...if we could not find a protocol. */ - } - } - return NULL_TREE; -} - -/* This routine looks up the PROPERTY in current INTERFACE, its categories and up the - chain of interface hierarchy. */ -static tree -lookup_property (tree interface_type, tree property) -{ - tree inter = interface_type; - while (inter) - { - tree x, category; - if ((x = lookup_property_in_list (inter, property))) - return x; - /* Failing that, look for the property in each category of the class. */ - category = inter; - while ((category = CLASS_CATEGORY_LIST (category))) - if ((x = lookup_property_in_list (category, property))) - return x; - - /* Failing to find in categories, look for property in protocol list. */ - if (CLASS_PROTOCOL_LIST (inter) - && (x = lookup_property_in_protocol_list ( - CLASS_PROTOCOL_LIST (inter), property))) - return x; - - /* Failing that, climb up the inheritance hierarchy. */ - inter = lookup_interface (CLASS_SUPER_NAME (inter)); - } - return inter; -} - /* This is a subroutine of objc_maybe_build_component_ref. Search the list of methods in the interface (and, failing that, the local list in the implementation, and failing that, the protocol list) @@ -1295,7 +1441,10 @@ objc_maybe_build_component_ref (tree object, tree t = TREE_OPERAND (t, 0); if (t == UOBJC_SUPER_decl) - interface_type = lookup_interface (CLASS_SUPER_NAME (implementation_template)); + { + /* TODO: Check if this is correct also for 'super' in categories. */ + interface_type = lookup_interface (CLASS_SUPER_NAME (implementation_template)); + } else if (t == self_decl) interface_type = lookup_interface (CLASS_NAME (implementation_template)); @@ -8564,20 +8713,34 @@ objc_is_public (tree expr, tree identifier) return 1; } -/* Make sure all entries in CHAIN are also in LIST. */ +/* Make sure all methods in CHAIN (a list of method declarations from + an @interface or a @protocol) are in IMPLEMENTATION (the + implementation context). This is used to check for example that + all methods declared in an @interface were implemented in an + @implementation. + Some special methods (property setters/getters) are special and if + they are not found in IMPLEMENTATION, we look them up in its + superclasses. */ + static int -check_methods (tree chain, tree list, int mtype) +check_methods (tree chain, tree implementation, int mtype) { int first = 1; + tree list; + if (mtype == (int)'+') + list = CLASS_CLS_METHODS (implementation); + else + list = CLASS_NST_METHODS (implementation); + while (chain) { /* If the method is associated with a dynamic property, then it is Ok not to have the method implementation, as it will be generated dynamically at runtime. */ tree property = METHOD_PROPERTY_CONTEXT (chain); - if (property != NULL_TREE && PROPERTY_DYNAMIC (property)) + if (property != NULL_TREE && PROPERTY_DYNAMIC (property)) { chain = TREE_CHAIN (chain); /* next method... */ continue; @@ -8585,17 +8748,66 @@ static int if (!lookup_method (list, chain)) { + /* If the method is a property setter/getter, we'll still + allow it to be missing if it is implemented by + 'interface' or any of its superclasses. */ + if (property) + { + /* Note that since this is a property getter/setter, it + is obviously an instance method. */ + tree interface = NULL_TREE; + + /* For a category, first check the main class + @interface. */ + if (TREE_CODE (implementation) == CATEGORY_IMPLEMENTATION_TYPE) + { + interface = lookup_interface (CLASS_NAME (implementation)); + + /* If the method is found in the main class, it's Ok. */ + if (lookup_method (CLASS_NST_METHODS (interface), chain)) + { + chain = DECL_CHAIN (chain); + continue; + } + + /* Else, get the superclass. */ + if (CLASS_SUPER_NAME (interface)) + interface = lookup_interface (CLASS_SUPER_NAME (interface)); + else + interface = NULL_TREE; + } + + /* Get the superclass for classes. */ + if (TREE_CODE (implementation) == CLASS_IMPLEMENTATION_TYPE) + { + if (CLASS_SUPER_NAME (implementation)) + interface = lookup_interface (CLASS_SUPER_NAME (implementation)); + else + interface = NULL_TREE; + } + + /* Now, interface is the superclass, if any; go check it. */ + if (interface) + { + if (lookup_method_static (interface, chain, 0)) + { + chain = DECL_CHAIN (chain); + continue; + } + } + /* Else, fall through - warn. */ + } if (first) { - switch (TREE_CODE (objc_implementation_context)) + switch (TREE_CODE (implementation)) { case CLASS_IMPLEMENTATION_TYPE: warning (0, "incomplete implementation of class %qE", - CLASS_NAME (objc_implementation_context)); + CLASS_NAME (implementation)); break; case CATEGORY_IMPLEMENTATION_TYPE: warning (0, "incomplete implementation of category %qE", - CLASS_SUPER_NAME (objc_implementation_context)); + CLASS_SUPER_NAME (implementation)); break; default: gcc_unreachable (); @@ -8733,10 +8945,10 @@ check_protocol (tree p, const char *type, tree nam if (warn_protocol) { f1 = check_methods (PROTOCOL_CLS_METHODS (p), - CLASS_CLS_METHODS (objc_implementation_context), + objc_implementation_context, '+'); f2 = check_methods (PROTOCOL_NST_METHODS (p), - CLASS_NST_METHODS (objc_implementation_context), + objc_implementation_context, '-'); } else @@ -9829,9 +10041,9 @@ finish_class (tree klass) { /* Ensure that all method listed in the interface contain bodies. */ check_methods (CLASS_CLS_METHODS (implementation_template), - CLASS_CLS_METHODS (objc_implementation_context), '+'); + objc_implementation_context, '+'); check_methods (CLASS_NST_METHODS (implementation_template), - CLASS_NST_METHODS (objc_implementation_context), '-'); + objc_implementation_context, '-'); if (CLASS_PROTOCOL_LIST (implementation_template)) check_protocols (CLASS_PROTOCOL_LIST (implementation_template), @@ -9848,12 +10060,12 @@ finish_class (tree klass) { /* Generate what needed for property; setters, getters, etc. */ objc_gen_property_data (implementation_template, category); - + /* Ensure all method listed in the interface contain bodies. */ check_methods (CLASS_CLS_METHODS (category), - CLASS_CLS_METHODS (objc_implementation_context), '+'); + objc_implementation_context, '+'); check_methods (CLASS_NST_METHODS (category), - CLASS_NST_METHODS (objc_implementation_context), '-'); + objc_implementation_context, '-'); if (CLASS_PROTOCOL_LIST (category)) check_protocols (CLASS_PROTOCOL_LIST (category), @@ -9870,104 +10082,69 @@ finish_class (tree klass) tree x; for (x = CLASS_PROPERTY_DECL (objc_interface_context); x; x = TREE_CHAIN (x)) { - /* Store the getter name that we used into the property. - It is used to generate the right getter calls; - moreover, when a @synthesize is processed, it copies - everything from the property, including the - PROPERTY_GETTER_NAME. We want to be sure that - @synthesize will get exactly the right - PROPERTY_GETTER_NAME. */ - if (PROPERTY_GETTER_NAME (x) == NULL_TREE) - PROPERTY_GETTER_NAME (x) = PROPERTY_NAME (x); - /* Now we check that the appropriate getter is declared, and if not, we declare one ourselves. */ - { - tree getter_decl = lookup_method (CLASS_NST_METHODS (klass), - PROPERTY_GETTER_NAME (x)); - - if (getter_decl) - { - /* TODO: Check that the declaration is consistent with the property. */ - ; - } - else - { - /* Generate an instance method declaration for the - getter; for example "- (id) name;". In general - it will be of the form - -(type)property_getter_name; */ - tree rettype = build_tree_list (NULL_TREE, TREE_TYPE (x)); - getter_decl = build_method_decl (INSTANCE_METHOD_DECL, - rettype, PROPERTY_GETTER_NAME (x), - NULL_TREE, false); - objc_add_method (objc_interface_context, getter_decl, false, false); - METHOD_PROPERTY_CONTEXT (getter_decl) = x; - } - } + tree getter_decl = lookup_method (CLASS_NST_METHODS (klass), + PROPERTY_GETTER_NAME (x)); + + if (getter_decl) + { + /* TODO: Check that the declaration is consistent with the property. */ + ; + } + else + { + /* Generate an instance method declaration for the + getter; for example "- (id) name;". In general it + will be of the form + -(type)property_getter_name; */ + tree rettype = build_tree_list (NULL_TREE, TREE_TYPE (x)); + getter_decl = build_method_decl (INSTANCE_METHOD_DECL, + rettype, PROPERTY_GETTER_NAME (x), + NULL_TREE, false); + objc_add_method (objc_interface_context, getter_decl, false, false); + METHOD_PROPERTY_CONTEXT (getter_decl) = x; + } if (PROPERTY_READONLY (x) == 0) { - /* Store the setter name that we used into the - property. It is used when generating setter calls; - moreover, when a @synthesize is processed, it - copies everything from the property, including the - PROPERTY_SETTER_NAME. We want to be sure that - @synthesize will get exactly the right - PROPERTY_SETTER_NAME. */ - if (PROPERTY_SETTER_NAME (x) == NULL_TREE) - PROPERTY_SETTER_NAME (x) = get_identifier (objc_build_property_setter_name - (PROPERTY_NAME (x))); - /* Now we check that the appropriate setter is declared, and if not, we declare on ourselves. */ - { - tree setter_decl = lookup_method (CLASS_NST_METHODS (klass), - PROPERTY_SETTER_NAME (x)); - - if (setter_decl) - { - /* TODO: Check that the declaration is consistent with the property. */ - ; - } - else - { - /* The setter name is something like 'setName:'. - We need the substring 'setName' to build the - method declaration due to how the declaration - works. TODO: build_method_decl() will then - generate back 'setName:' from 'setName'; it - would be more efficient to hook into - there. */ - const char *full_setter_name = IDENTIFIER_POINTER (PROPERTY_SETTER_NAME (x)); - size_t length = strlen (full_setter_name); - char *setter_name = (char *) alloca (length); - tree ret_type, selector, arg_type, arg_name; - - strcpy (setter_name, full_setter_name); - setter_name[length - 1] = '\0'; - ret_type = build_tree_list (NULL_TREE, void_type_node); - arg_type = build_tree_list (NULL_TREE, TREE_TYPE (x)); - arg_name = get_identifier ("_value"); - selector = objc_build_keyword_decl (get_identifier (setter_name), - arg_type, arg_name, NULL); - setter_decl = build_method_decl (INSTANCE_METHOD_DECL, - ret_type, selector, - build_tree_list (NULL_TREE, NULL_TREE), - false); - objc_add_method (objc_interface_context, setter_decl, false, false); - METHOD_PROPERTY_CONTEXT (setter_decl) = x; - } - } - - /* Note how at this point (once an @interface or @protocol - have been processed), PROPERTY_GETTER_NAME is always - set for all PROPERTY_DECLs, and PROPERTY_SETTER_NAME is - always set for all PROPERTY_DECLs where - PROPERTY_READONLY == 0. Any time we deal with a getter - or setter, we should get the PROPERTY_DECL and use - PROPERTY_GETTER_NAME and PROPERTY_SETTER_NAME to know - the correct names. */ + tree setter_decl = lookup_method (CLASS_NST_METHODS (klass), + PROPERTY_SETTER_NAME (x)); + + if (setter_decl) + { + /* TODO: Check that the declaration is consistent with the property. */ + ; + } + else + { + /* The setter name is something like 'setName:'. + We need the substring 'setName' to build the + method declaration due to how the declaration + works. TODO: build_method_decl() will then + generate back 'setName:' from 'setName'; it + would be more efficient to hook into there. */ + const char *full_setter_name = IDENTIFIER_POINTER (PROPERTY_SETTER_NAME (x)); + size_t length = strlen (full_setter_name); + char *setter_name = (char *) alloca (length); + tree ret_type, selector, arg_type, arg_name; + + strcpy (setter_name, full_setter_name); + setter_name[length - 1] = '\0'; + ret_type = build_tree_list (NULL_TREE, void_type_node); + arg_type = build_tree_list (NULL_TREE, TREE_TYPE (x)); + arg_name = get_identifier ("_value"); + selector = objc_build_keyword_decl (get_identifier (setter_name), + arg_type, arg_name, NULL); + setter_decl = build_method_decl (INSTANCE_METHOD_DECL, + ret_type, selector, + build_tree_list (NULL_TREE, NULL_TREE), + false); + objc_add_method (objc_interface_context, setter_decl, false, false); + METHOD_PROPERTY_CONTEXT (setter_decl) = x; + } } } break; Index: gcc/objc/ChangeLog =================================================================== --- gcc/objc/ChangeLog (revision 166402) +++ gcc/objc/ChangeLog (working copy) @@ -1,3 +1,21 @@ +2010-11-07 Nicola Pero + + * objc-act.c (lookup_property): When checking categories, also + check the protocols attached to each. + (objc_add_property_declaration): Determine the + PROPERTY_SETTER_NAME and PROPERTY_GETTER_NAME here. Tidied up + error message. Search for an existing property declaration with + the same name which would be inherited from the class hiearchy, + and produce an error if it has incompatible attributes. + (check_methods): Changed second parameter. If the method is a + getter or setter for a property, do not warn if it is inherited as + opposed to implemented directly in the class. + (check_protocol): Updated calls to check_methods. + (finish_class): Do not determine the PROPERTY_SETTER_NAME and + PROPERTY_GETTER_NAME here; this is now done earlier, in + objc_add_property_declaration. + * objc-act.h (CLASS_NAME, CLASS_SUPER_NAME): Added comments. + 2010-11-06 Nicola Pero Fixed using the Objective-C 2.0 syntax with self and super. Index: gcc/objc/objc-act.h =================================================================== --- gcc/objc/objc-act.h (revision 166402) +++ gcc/objc/objc-act.h (working copy) @@ -144,7 +144,10 @@ typedef enum objc_property_assign_semantics { /* CLASS_INTERFACE_TYPE, CLASS_IMPLEMENTATION_TYPE, CATEGORY_INTERFACE_TYPE, CATEGORY_IMPLEMENTATION_TYPE, PROTOCOL_INTERFACE_TYPE */ +/* CLASS_NAME is the name of the class. */ #define CLASS_NAME(CLASS) ((CLASS)->type.name) +/* CLASS_SUPER_NAME is the name of the superclass, or, in the case of + categories, it is the name of the category itself. */ #define CLASS_SUPER_NAME(CLASS) (TYPE_CHECK (CLASS)->type.context) #define CLASS_IVARS(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 0) #define CLASS_RAW_IVARS(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 1) Index: gcc/testsuite/ChangeLog =================================================================== --- gcc/testsuite/ChangeLog (revision 166402) +++ gcc/testsuite/ChangeLog (working copy) @@ -1,3 +1,22 @@ +2010-11-07 Nicola Pero + + * objc.dg/property/at-property-5.m: Updated test. + * objc.dg/property/at-property-16.m: New. + * objc.dg/property/at-property-17.m: New. + * objc.dg/property/at-property-18.m: New. + * objc.dg/property/at-property-19.m: New. + * objc.dg/property/dotsyntax-12.m: New. + * objc.dg/protocol-inheritance-1.m: New. + * objc.dg/protocol-inheritance-2.m: New. + * obj-c++.dg/property/at-property-5.mm: Updated test. + * obj-c++.dg/property/at-property-16.mm: New. + * obj-c++.dg/property/at-property-17.mm: New. + * obj-c++.dg/property/at-property-18.mm: New. + * obj-c++.dg/property/at-property-19.mm: New. + * obj-c++.dg/protocol-inheritance-1.mm: New. + * obj-c++.dg/protocol-inheritance-2.mm: New. + * obj-c++.dg/property/dotsyntax-12.mm: New. + 2010-11-06 Nicola Pero Fixed using the Objective-C 2.0 dot-syntax with self and super. Index: gcc/testsuite/objc.dg/protocol-inheritance-1.m =================================================================== --- gcc/testsuite/objc.dg/protocol-inheritance-1.m (revision 0) +++ gcc/testsuite/objc.dg/protocol-inheritance-1.m (revision 0) @@ -0,0 +1,54 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ +/* { dg-options "-Wno-protocol" } */ + +#include + +/* Test the -Wno-protocol flag. With this, at a class is accepted + (with no warnings) as conforming to a protocol even if some + protocol methods are implemented in the superclass. */ + +@protocol MyProtocol +- (int)method; +@end + +@protocol MyProtocol2 +- (int)method2; +@end + +/* The superclass implements the method required by the protocol. */ +@interface MyRootClass +{ + Class isa; +} +- (int)method; +@end + +@implementation MyRootClass +- (int)method +{ + return 23; +} +@end + +/* The subclass inherits the method (does not implement it directly) + but that still makes it conform to the protocol. No warnings. */ +@interface MySubClass : MyRootClass +@end + +@implementation MySubClass +@end /* No warnings here. */ + + +/* The subclass instead does not inherit the method method2 (and does + not implement it directly) so it does not conform to the + protocol MyProtocol2. */ +@interface MySubClass2 : MyRootClass +@end + +@implementation MySubClass2 +@end /* Warnings here, below. */ + +/* { dg-warning "incomplete implementation of class .MySubClass2." "" { target *-*-* } 50 } */ +/* { dg-warning "method definition for .\\-method2. not found" "" { target *-*-* } 50 } */ +/* { dg-warning "class .MySubClass2. does not fully implement the .MyProtocol2. protocol" "" { target *-*-* } 50 } */ Index: gcc/testsuite/objc.dg/property/dotsyntax-12.m =================================================================== --- gcc/testsuite/objc.dg/property/dotsyntax-12.m (revision 0) +++ gcc/testsuite/objc.dg/property/dotsyntax-12.m (revision 0) @@ -0,0 +1,105 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test looking up a setter or getter which are in a protocol attached + to a category of a superclass. */ + +#include +#include +#include + +static int c; + +@interface MyRootClass +{ + Class isa; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@end + +@protocol count +- (int) count; +- (void) setCount: (int)count; +@end + +@protocol classCount ++ (int) classCount; ++ (void) setClassCount: (int)count; +@end + +@interface MyRootClass (Category) +@end + +@implementation MyRootClass (Category) +- (int) count +{ + return a; +} +- (void) setCount: (int)count +{ + a = count; +} ++ (int) classCount +{ + return c; +} ++ (void) setClassCount: (int)count +{ + c = count; +} +@end + +@interface MySubClass : MyRootClass ++ (int) testMe; +- (int) testMe; +@end + +@implementation MySubClass +- (int) testMe +{ + self.count = 400; + if (self.count != 400) + abort (); + + return self.count; +} ++ (int) testMe +{ + self.classCount = 4000; + if (self.classCount != 4000) + abort (); + + return self.classCount; +} +@end + +int main (void) +{ + MySubClass *object = [[MySubClass alloc] init]; + + object.count = 44; + if (object.count != 44) + abort (); + + MySubClass.classCount = 40; + if (MySubClass.classCount != 40) + abort (); + + if ([object testMe] != 400) + abort (); + + if ([MySubClass testMe] != 4000) + abort (); + + return 0; +} Index: gcc/testsuite/objc.dg/property/at-property-5.m =================================================================== --- gcc/testsuite/objc.dg/property/at-property-5.m (revision 166401) +++ gcc/testsuite/objc.dg/property/at-property-5.m (working copy) @@ -28,7 +28,7 @@ @property (retain) id property_g; @property (retain) id property_h; @property (retain) id property_e; /* { dg-error "redeclaration of property .property_e." } */ - /* { dg-message "originally declared here" "" { target *-*-* } 26 } */ + /* { dg-message "originally specified here" "" { target *-*-* } 26 } */ @end @property id test; /* { dg-error "property declaration not in .interface or .protocol context" } */ Index: gcc/testsuite/objc.dg/property/at-property-16.m =================================================================== --- gcc/testsuite/objc.dg/property/at-property-16.m (revision 0) +++ gcc/testsuite/objc.dg/property/at-property-16.m (revision 0) @@ -0,0 +1,55 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +#include + +/* Test that if you have a property declared in a class and a + sub-class, the attributes match. */ + +@interface MyRootClass +{ + Class isa; +} +@property (assign) id a; +@property (retain) id b; +@property int c; +@property (nonatomic) int d; +@property int e; +@property int f; +@property int g; +@property (readonly) int h; +@property (readonly,getter=getMe) int i; +@end + +@interface MyClass : MyRootClass +@property (assign) id a; +@property (retain) id b; +@property int c; +@property (nonatomic) int d; +@property int e; +@property int f; +@property int g; +@property (readonly) int h; +@property (readonly,getter=getMe) int i; +@end + +@interface MyClass2 : MyRootClass +@property (retain) id a; /* { dg-error "assign semantics attributes of property .a. conflict with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 13 } */ +@property (assign) id b; /* { dg-error "assign semantics attributes of property .b. conflict with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 14 } */ +@property (nonatomic) int c; /* { dg-error ".nonatomic. attribute of property .c. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 15 } */ +@property int d; /* { dg-error ".nonatomic. attribute of property .d. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 16 } */ +@property (setter=setX:) int e; /* { dg-error ".setter. attribute of property .e. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 17 } */ +@property (getter=x) int f; /* { dg-error ".getter. attribute of property .f. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 18 } */ +@property (readonly) int g; /* { dg-error ".readonly. attribute of property .g. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 19 } */ +@property (readwrite) int h; /* Ok */ +@property (readonly) int i; /* { dg-error ".getter. attribute of property .i. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 21 } */ +@end + Index: gcc/testsuite/objc.dg/property/at-property-17.m =================================================================== --- gcc/testsuite/objc.dg/property/at-property-17.m (revision 0) +++ gcc/testsuite/objc.dg/property/at-property-17.m (revision 0) @@ -0,0 +1,98 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +#include + +/* Test that if you have a property declared in a class, with + getters/setters in the superclass, there are no warnings. */ + +@interface MyRootClass +{ + Class isa; + int myCount; + int myCount2; + int myCount3; +} +- (int)count; +- (void)setCount: (int)number; +- (int)count2; +- (void)setCount2: (int)number; +- (int)count3; +@end + +@implementation MyRootClass +- (int) count +{ + return myCount; +} +- (void) setCount: (int)number +{ + myCount = number; +} +- (int) count2 +{ + return myCount2; +} +- (void) setCount2: (int)number +{ + myCount2 = number; +} +- (int) count3 +{ + return myCount3; +} +@end + + + +/* Try with a subclass. */ +@interface MyClass : MyRootClass +@property int count; +@end + +@implementation MyClass +@end /* No warnings. */ + + + +/* Try with a category. */ +@interface MyRootClass (count) +@property int count; +@end + +@implementation MyRootClass (count) +@end /* No warnings. */ + + + +/* Try with a category of a subclass. */ +@interface MyClass2 : MyClass +@end + +@implementation MyClass2 +@end + +@interface MyClass2 (count2) +@property int count2; +@end + +@implementation MyClass2 (count2) +@end /* No warnings. */ + + + +/* Now, try with a category of a subclass, but with a missing setter, + which should generate a warning. */ +@interface MyClass3 : MyClass +@end + +@implementation MyClass3 +@end + +@interface MyClass3 (count3) +@property int count3; +@end + +@implementation MyClass3 (count3) +@end /* { dg-warning "incomplete implementation" } */ +/* { dg-warning "method definition for .-setCount3:. not found" "" { target *-*-* } 97 } */ Index: gcc/testsuite/objc.dg/property/at-property-18.m =================================================================== --- gcc/testsuite/objc.dg/property/at-property-18.m (revision 0) +++ gcc/testsuite/objc.dg/property/at-property-18.m (revision 0) @@ -0,0 +1,47 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +#include + +/* Test that if you have a property declared in a class and a + category, the attributes match. This is almost the same as + at-property-16.m, but for a category. It is a separate file + because it is difficult to test multiple messages for the same + line. */ + +@interface MyRootClass +{ + Class isa; +} +@property (assign) id a; +@property (retain) id b; +@property int c; +@property (nonatomic) int d; +@property int e; +@property int f; +@property int g; +@property (readonly) int h; +@property (readonly,getter=getMe) int i; +@property (nonatomic) float j; +@end + +@interface MyRootClass (Category) +@property (retain) id a; /* { dg-error "assign semantics attributes of property .a. conflict with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 16 } */ +@property (assign) id b; /* { dg-error "assign semantics attributes of property .b. conflict with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 17 } */ +@property (nonatomic) int c; /* { dg-error ".nonatomic. attribute of property .c. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 18 } */ +@property int d; /* { dg-error ".nonatomic. attribute of property .d. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 19 } */ +@property (setter=setX:) int e; /* { dg-error ".setter. attribute of property .e. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 20 } */ +@property (getter=x) int f; /* { dg-error ".getter. attribute of property .f. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 21 } */ +@property (readonly) int g; /* { dg-error ".readonly. attribute of property .g. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 22 } */ +@property (readwrite) int h; /* Ok */ +@property (readonly) int i; /* { dg-error ".getter. attribute of property .i. conflicts with previous declaration" } */ + /* { dg-message "originally specified here" "" { target *-*-* } 24 } */ +@property (nonatomic) float j; /* Ok */ +@end Index: gcc/testsuite/objc.dg/property/at-property-19.m =================================================================== --- gcc/testsuite/objc.dg/property/at-property-19.m (revision 0) +++ gcc/testsuite/objc.dg/property/at-property-19.m (revision 0) @@ -0,0 +1,74 @@ +/* Contributed by Nicola Pero , October 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test looking up a @property in a protocol of a category of a superclass. */ + +#include +#include +#include + +@interface MyRootClass +{ + Class isa; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@end + +/* Use a different getter/setter, so that the only way to compile + object.count is to find the actual @property. */ +@protocol count +@property (getter=number, setter=setNumber:) int count; +@end + +@interface MySubClass : MyRootClass +- (int) testMe; +@end + +@interface MySubClass (Category) +@end + +@implementation MySubClass (Category) +- (int) number +{ + return a; +} +- (void) setNumber: (int)count +{ + a = count; +} +@end + +@implementation MySubClass +- (int) testMe +{ + self.count = 400; + if (self.count != 400) + abort (); + + return self.count; +} +@end + +int main (void) +{ + MySubClass *object = [[MySubClass alloc] init]; + + object.count = 44; + if (object.count != 44) + abort (); + + if ([object testMe] != 400) + abort (); + + return 0; +} Index: gcc/testsuite/objc.dg/protocol-inheritance-2.m =================================================================== --- gcc/testsuite/objc.dg/protocol-inheritance-2.m (revision 0) +++ gcc/testsuite/objc.dg/protocol-inheritance-2.m (revision 0) @@ -0,0 +1,57 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +#include + +/* Test standard warnings when a class conforms to a protocol but some + methods are implemented in the superclass. Use -Wno-protocol to + turn these off. */ + +@protocol MyProtocol +- (int)method; +@end + +@protocol MyProtocol2 +- (int)method2; +@end + +/* The superclass implements the method required by the protocol. */ +@interface MyRootClass +{ + Class isa; +} +- (int)method; +@end + +@implementation MyRootClass +- (int)method +{ + return 23; +} +@end + +/* The subclass inherits the method (does not implement it directly) + and unless -Wno-protocol is used, we emit a warning. */ +@interface MySubClass : MyRootClass +@end + +@implementation MySubClass +@end + +/* { dg-warning "incomplete implementation of class .MySubClass." "" { target *-*-* } 39 } */ +/* { dg-warning "method definition for .\\-method. not found" "" { target *-*-* } 39 } */ +/* { dg-warning "class .MySubClass. does not fully implement the .MyProtocol. protocol" "" { target *-*-* } 39 } */ + + +/* The subclass instead does not inherit the method method2 (and does + not implement it directly) so it does not conform to the + protocol MyProtocol2. */ +@interface MySubClass2 : MyRootClass +@end + +@implementation MySubClass2 +@end /* Warnings here, below. */ + +/* { dg-warning "incomplete implementation of class .MySubClass2." "" { target *-*-* } 53 } */ +/* { dg-warning "method definition for .\\-method2. not found" "" { target *-*-* } 53 } */ +/* { dg-warning "class .MySubClass2. does not fully implement the .MyProtocol2. protocol" "" { target *-*-* } 53 } */ Index: gcc/testsuite/obj-c++.dg/property/at-property-17.mm =================================================================== --- gcc/testsuite/obj-c++.dg/property/at-property-17.mm (revision 0) +++ gcc/testsuite/obj-c++.dg/property/at-property-17.mm (revision 0) @@ -0,0 +1,98 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +#include + +/* Test that if you have a property declared in a class, with + getters/setters in the superclass, there are no warnings. */ + +@interface MyRootClass +{ + Class isa; + int myCount; + int myCount2; + int myCount3; +} +- (int)count; +- (void)setCount: (int)number; +- (int)count2; +- (void)setCount2: (int)number; +- (int)count3; +@end + +@implementation MyRootClass +- (int) count +{ + return myCount; +} +- (void) setCount: (int)number +{ + myCount = number; +} +- (int) count2 +{ + return myCount2; +} +- (void) setCount2: (int)number +{ + myCount2 = number; +} +- (int) count3 +{ + return myCount3; +} +@end + + + +/* Try with a subclass. */ +@interface MyClass : MyRootClass +@property int count; +@end + +@implementation MyClass +@end /* No warnings. */ + + + +/* Try with a category. */ +@interface MyRootClass (count) +@property int count; +@end + +@implementation MyRootClass (count) +@end /* No warnings. */ + + + +/* Try with a category of a subclass. */ +@interface MyClass2 : MyClass +@end + +@implementation MyClass2 +@end + +@interface MyClass2 (count2) +@property int count2; +@end + +@implementation MyClass2 (count2) +@end /* No warnings. */ + + + +/* Now, try with a category of a subclass, but with a missing setter, + which should generate a warning. */ +@interface MyClass3 : MyClass +@end + +@implementation MyClass3 +@end + +@interface MyClass3 (count3) +@property int count3; +@end + +@implementation MyClass3 (count3) +@end /* { dg-warning "incomplete implementation" } */ +/* { dg-warning "method definition for .-setCount3:. not found" "" { target *-*-* } 97 } */ Index: gcc/testsuite/obj-c++.dg/property/at-property-19.mm =================================================================== --- gcc/testsuite/obj-c++.dg/property/at-property-19.mm (revision 0) +++ gcc/testsuite/obj-c++.dg/property/at-property-19.mm (revision 0) @@ -0,0 +1,74 @@ +/* Contributed by Nicola Pero , October 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test looking up a @property in a protocol of a category of a superclass. */ + +#include +#include +#include + +@interface MyRootClass +{ + Class isa; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@end + +/* Use a different getter/setter, so that the only way to compile + object.count is to find the actual @property. */ +@protocol count +@property (getter=number, setter=setNumber:) int count; +@end + +@interface MySubClass : MyRootClass +- (int) testMe; +@end + +@interface MySubClass (Category) +@end + +@implementation MySubClass (Category) +- (int) number +{ + return a; +} +- (void) setNumber: (int)count +{ + a = count; +} +@end + +@implementation MySubClass +- (int) testMe +{ + self.count = 400; + if (self.count != 400) + abort (); + + return self.count; +} +@end + +int main (void) +{ + MySubClass *object = [[MySubClass alloc] init]; + + object.count = 44; + if (object.count != 44) + abort (); + + if ([object testMe] != 400) + abort (); + + return 0; +} Index: gcc/testsuite/obj-c++.dg/property/at-property-5.mm =================================================================== --- gcc/testsuite/obj-c++.dg/property/at-property-5.mm (revision 166401) +++ gcc/testsuite/obj-c++.dg/property/at-property-5.mm (working copy) @@ -32,7 +32,7 @@ /* FIXME - there is a problem with the testuite in running the following test. The compiler generates the messages, but the testsuite still complains. */ /*@property (retain) id property_e;*/ /* dg-error "redeclaration of property .property_e." */ - /* dg-message "originally declared here" "" { target *-*-* } 26 */ + /* dg-message "originally specified here" "" { target *-*-* } 26 */ @end @property id test; /* { dg-error "misplaced .@property. Objective-C.. construct" } */ Index: gcc/testsuite/obj-c++.dg/property/at-property-16.mm =================================================================== --- gcc/testsuite/obj-c++.dg/property/at-property-16.mm (revision 0) +++ gcc/testsuite/obj-c++.dg/property/at-property-16.mm (revision 0) @@ -0,0 +1,54 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +#include + +/* Test that if you have a property declared in a class and a + sub-class, the attributes match. */ + +@interface MyRootClass +{ + Class isa; +} +@property (assign) id a; +@property (retain) id b; +@property int c; +@property (nonatomic) int d; +@property int e; +@property int f; +@property int g; +@property (readonly) int h; +@property (readonly,getter=getMe) int i; +@end + +@interface MyClass : MyRootClass +@property (assign) id a; +@property (retain) id b; +@property int c; +@property (nonatomic) int d; +@property int e; +@property int f; +@property int g; +@property (readonly) int h; +@property (readonly,getter=getMe) int i; +@end +/* FIXME - there is a problem with the testuite in running the following test. The compiler generates the messages, but the testsuite still complains. */ +@interface MyClass2 : MyRootClass +/* @property (retain) id a; */ /* dg-error "assign semantics attributes of property .a. conflict with previous declaration" */ + /* dg-message "originally specified here" "" { target *-*-* } 13 */ +/* @property (assign) id b; */ /* dg-error "assign semantics attributes of property .b. conflict with previous declaration" */ + /* dg-message "originally specified here" "" { target *-*-* } 14 */ +/* @property (nonatomic) int c; */ /* dg-error ".nonatomic. attribute of property .c. conflicts with previous declaration" */ + /* dg-message "originally specified here" "" { target *-*-* } 15 */ +/* @property int d; */ /* dg-error ".nonatomic. attribute of property .d. conflicts with previous declaration" */ + /* dg-message "originally specified here" "" { target *-*-* } 16 */ +/* @property (setter=setX:) int e; */ /* dg-error ".setter. attribute of property .e. conflicts with previous declaration" */ + /* dg-message "originally specified here" "" { target *-*-* } 17 */ +/* @property (getter=x) int f; */ /* dg-error ".getter. attribute of property .f. conflicts with previous declaration" */ + /* dg-message "originally specified here" "" { target *-*-* } 18 */ +/* @property (readonly) int g; */ /* dg-error ".readonly. attribute of property .g. conflicts with previous declaration" */ + /* dg-message "originally specified here" "" { target *-*-* } 19 */ +@property (readwrite) int h; /* Ok */ +/* @property (readonly) int i; */ /* dg-error ".getter. attribute of property .i. conflicts with previous declaration" */ + /* dg-message "originally specified here" "" { target *-*-* } 21 */ +@end Index: gcc/testsuite/obj-c++.dg/property/at-property-18.mm =================================================================== --- gcc/testsuite/obj-c++.dg/property/at-property-18.mm (revision 0) +++ gcc/testsuite/obj-c++.dg/property/at-property-18.mm (revision 0) @@ -0,0 +1,47 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +#include + +/* Test that if you have a property declared in a class and a + category, the attributes match. This is almost the same as + at-property-16.m, but for a category. It is a separate file + because it is difficult to test multiple messages for the same + line. */ + +@interface MyRootClass +{ + Class isa; +} +@property (assign) id a; +@property (retain) id b; +@property int c; +@property (nonatomic) int d; +@property int e; +@property int f; +@property int g; +@property (readonly) int h; +@property (readonly,getter=getMe) int i; +@property (nonatomic) float j; +@end +/* FIXME - there is a problem with the testuite in running the following test. The compiler generates the messages, but the testsuite still complains. */ +@interface MyRootClass (Category) +/*@property (retain) id a; */ /* dg-error "assign semantics attributes of property .a. conflict with previous declaration" */ + /* dg-message "originally specified here" "" { target *-*-* } 16 */ +/*@property (assign) id b; */ /* dg-error "assign semantics attributes of property .b. conflict with previous declaration" */ + /* dg-message "originally specified here" "" { target *-*-* } 17 */ +/*@property (nonatomic) int c; */ /* dg-error ".nonatomic. attribute of property .c. conflicts with previous declaration" */ + /* dg-message "originally specified here" "" { target *-*-* } 18 */ +/*@property int d; */ /* dg-error ".nonatomic. attribute of property .d. conflicts with previous declaration" */ + /* dg-message "originally specified here" "" { target *-*-* } 19 */ +/*@property (setter=setX:) int e; */ /* dg-error ".setter. attribute of property .e. conflicts with previous declaration" */ + /* dg-message "originally specified here" "" { target *-*-* } 20 */ +/*@property (getter=x) int f; */ /* dg-error ".getter. attribute of property .f. conflicts with previous declaration" */ + /* dg-message "originally specified here" "" { target *-*-* } 21 */ +/*@property (readonly) int g; */ /* dg-error ".readonly. attribute of property .g. conflicts with previous declaration" */ + /* dg-message "originally specified here" "" { target *-*-* } 22 */ +@property (readwrite) int h; /* Ok */ +/*@property (readonly) int i; */ /* dg-error ".getter. attribute of property .i. conflicts with previous declaration" */ + /* dg-message "originally specified here" "" { target *-*-* } 24 */ +@property (nonatomic) float j; /* Ok */ +@end Index: gcc/testsuite/obj-c++.dg/property/dotsyntax-12.mm =================================================================== --- gcc/testsuite/obj-c++.dg/property/dotsyntax-12.mm (revision 0) +++ gcc/testsuite/obj-c++.dg/property/dotsyntax-12.mm (revision 0) @@ -0,0 +1,105 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test looking up a setter or getter which are in a protocol attached + to a category of a superclass. */ + +#include +#include +#include + +static int c; + +@interface MyRootClass +{ + Class isa; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@end + +@protocol count +- (int) count; +- (void) setCount: (int)count; +@end + +@protocol classCount ++ (int) classCount; ++ (void) setClassCount: (int)count; +@end + +@interface MyRootClass (Category) +@end + +@implementation MyRootClass (Category) +- (int) count +{ + return a; +} +- (void) setCount: (int)count +{ + a = count; +} ++ (int) classCount +{ + return c; +} ++ (void) setClassCount: (int)count +{ + c = count; +} +@end + +@interface MySubClass : MyRootClass ++ (int) testMe; +- (int) testMe; +@end + +@implementation MySubClass +- (int) testMe +{ + self.count = 400; + if (self.count != 400) + abort (); + + return self.count; +} ++ (int) testMe +{ + self.classCount = 4000; + if (self.classCount != 4000) + abort (); + + return self.classCount; +} +@end + +int main (void) +{ + MySubClass *object = [[MySubClass alloc] init]; + + object.count = 44; + if (object.count != 44) + abort (); + + MySubClass.classCount = 40; + if (MySubClass.classCount != 40) + abort (); + + if ([object testMe] != 400) + abort (); + + if ([MySubClass testMe] != 4000) + abort (); + + return 0; +} Index: gcc/testsuite/obj-c++.dg/protocol-inheritance-2.mm =================================================================== --- gcc/testsuite/obj-c++.dg/protocol-inheritance-2.mm (revision 0) +++ gcc/testsuite/obj-c++.dg/protocol-inheritance-2.mm (revision 0) @@ -0,0 +1,57 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +#include + +/* Test standard warnings when a class conforms to a protocol but some + methods are implemented in the superclass. Use -Wno-protocol to + turn these off. */ + +@protocol MyProtocol +- (int)method; +@end + +@protocol MyProtocol2 +- (int)method2; +@end + +/* The superclass implements the method required by the protocol. */ +@interface MyRootClass +{ + Class isa; +} +- (int)method; +@end + +@implementation MyRootClass +- (int)method +{ + return 23; +} +@end + +/* The subclass inherits the method (does not implement it directly) + and unless -Wno-protocol is used, we emit a warning. */ +@interface MySubClass : MyRootClass +@end + +@implementation MySubClass +@end + +/* { dg-warning "incomplete implementation of class .MySubClass." "" { target *-*-* } 39 } */ +/* { dg-warning "method definition for .\\-method. not found" "" { target *-*-* } 39 } */ +/* { dg-warning "class .MySubClass. does not fully implement the .MyProtocol. protocol" "" { target *-*-* } 39 } */ + + +/* The subclass instead does not inherit the method method2 (and does + not implement it directly) so it does not conform to the + protocol MyProtocol2. */ +@interface MySubClass2 : MyRootClass +@end + +@implementation MySubClass2 +@end /* Warnings here, below. */ + +/* { dg-warning "incomplete implementation of class .MySubClass2." "" { target *-*-* } 53 } */ +/* { dg-warning "method definition for .\\-method2. not found" "" { target *-*-* } 53 } */ +/* { dg-warning "class .MySubClass2. does not fully implement the .MyProtocol2. protocol" "" { target *-*-* } 53 } */ Index: gcc/testsuite/obj-c++.dg/protocol-inheritance-1.mm =================================================================== --- gcc/testsuite/obj-c++.dg/protocol-inheritance-1.mm (revision 0) +++ gcc/testsuite/obj-c++.dg/protocol-inheritance-1.mm (revision 0) @@ -0,0 +1,54 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ +/* { dg-options "-Wno-protocol" } */ + +#include + +/* Test the -Wno-protocol flag. With this, at a class is accepted + (with no warnings) as conforming to a protocol even if some + protocol methods are implemented in the superclass. */ + +@protocol MyProtocol +- (int)method; +@end + +@protocol MyProtocol2 +- (int)method2; +@end + +/* The superclass implements the method required by the protocol. */ +@interface MyRootClass +{ + Class isa; +} +- (int)method; +@end + +@implementation MyRootClass +- (int)method +{ + return 23; +} +@end + +/* The subclass inherits the method (does not implement it directly) + but that still makes it conform to the protocol. No warnings. */ +@interface MySubClass : MyRootClass +@end + +@implementation MySubClass +@end /* No warnings here. */ + + +/* The subclass instead does not inherit the method method2 (and does + not implement it directly) so it does not conform to the + protocol MyProtocol2. */ +@interface MySubClass2 : MyRootClass +@end + +@implementation MySubClass2 +@end /* Warnings here, below. */ + +/* { dg-warning "incomplete implementation of class .MySubClass2." "" { target *-*-* } 50 } */ +/* { dg-warning "method definition for .\\-method2. not found" "" { target *-*-* } 50 } */ +/* { dg-warning "class .MySubClass2. does not fully implement the .MyProtocol2. protocol" "" { target *-*-* } 50 } */