From 4ca5d2a7bdc3cd7182cbf0e1261a6df44d362d87 Mon Sep 17 00:00:00 2001 From: Nicola Pero Date: Mon, 8 Nov 2010 21:47:59 +0000 Subject: [PATCH] In gcc/objc/: 2010-11-08 Nicola Pero In gcc/objc/: 2010-11-08 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-08 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. From-SVN: r166455 --- gcc/objc/ChangeLog | 18 + gcc/objc/objc-act.c | 549 ++++++++++++++------- gcc/objc/objc-act.h | 3 + gcc/testsuite/ChangeLog | 19 + .../obj-c++.dg/property/at-property-16.mm | 54 ++ .../obj-c++.dg/property/at-property-17.mm | 98 ++++ .../obj-c++.dg/property/at-property-18.mm | 47 ++ .../obj-c++.dg/property/at-property-19.mm | 74 +++ gcc/testsuite/obj-c++.dg/property/at-property-5.mm | 2 +- gcc/testsuite/obj-c++.dg/property/dotsyntax-12.mm | 105 ++++ gcc/testsuite/obj-c++.dg/protocol-inheritance-1.mm | 54 ++ gcc/testsuite/obj-c++.dg/protocol-inheritance-2.mm | 57 +++ gcc/testsuite/objc.dg/property/at-property-16.m | 55 +++ gcc/testsuite/objc.dg/property/at-property-17.m | 98 ++++ gcc/testsuite/objc.dg/property/at-property-18.m | 47 ++ gcc/testsuite/objc.dg/property/at-property-19.m | 74 +++ gcc/testsuite/objc.dg/property/at-property-5.m | 2 +- gcc/testsuite/objc.dg/property/dotsyntax-12.m | 105 ++++ gcc/testsuite/objc.dg/protocol-inheritance-1.m | 54 ++ gcc/testsuite/objc.dg/protocol-inheritance-2.m | 57 +++ 20 files changed, 1384 insertions(+), 188 deletions(-) create mode 100644 gcc/testsuite/obj-c++.dg/property/at-property-16.mm create mode 100644 gcc/testsuite/obj-c++.dg/property/at-property-17.mm create mode 100644 gcc/testsuite/obj-c++.dg/property/at-property-18.mm create mode 100644 gcc/testsuite/obj-c++.dg/property/at-property-19.mm create mode 100644 gcc/testsuite/obj-c++.dg/property/dotsyntax-12.mm create mode 100644 gcc/testsuite/obj-c++.dg/protocol-inheritance-1.mm create mode 100644 gcc/testsuite/obj-c++.dg/protocol-inheritance-2.mm create mode 100644 gcc/testsuite/objc.dg/property/at-property-16.m create mode 100644 gcc/testsuite/objc.dg/property/at-property-17.m create mode 100644 gcc/testsuite/objc.dg/property/at-property-18.m create mode 100644 gcc/testsuite/objc.dg/property/at-property-19.m create mode 100644 gcc/testsuite/objc.dg/property/dotsyntax-12.m create mode 100644 gcc/testsuite/objc.dg/protocol-inheritance-1.m create mode 100644 gcc/testsuite/objc.dg/protocol-inheritance-2.m diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index 9bde682663a..93c9f3e544a 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,21 @@ +2010-11-08 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. diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index fd5244e389a..db41dcab0ac 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -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, tree decl, /* 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, tree decl, && !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,14 +1085,126 @@ objc_add_property_declaration (location_t location, tree decl, 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, tree decl, 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 property_ident) 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,12 +8713,26 @@ 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) { @@ -8577,7 +8740,7 @@ check_methods (tree chain, tree list, int mtype) 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 @@ check_methods (tree chain, tree list, int mtype) 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 name) 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; diff --git a/gcc/objc/objc-act.h b/gcc/objc/objc-act.h index 9a9cacd668f..91717081ff8 100644 --- a/gcc/objc/objc-act.h +++ b/gcc/objc/objc-act.h @@ -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) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7d2688e3547..97b3f51ddd4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,22 @@ +2010-11-08 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-08 Jason Merrill * g++.dg/expr/overflow1.C: New. diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-16.mm b/gcc/testsuite/obj-c++.dg/property/at-property-16.mm new file mode 100644 index 00000000000..ca8a68c373d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-16.mm @@ -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 diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-17.mm b/gcc/testsuite/obj-c++.dg/property/at-property-17.mm new file mode 100644 index 00000000000..efb62d6f70d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-17.mm @@ -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 } */ diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-18.mm b/gcc/testsuite/obj-c++.dg/property/at-property-18.mm new file mode 100644 index 00000000000..482e1ff759d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-18.mm @@ -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 diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-19.mm b/gcc/testsuite/obj-c++.dg/property/at-property-19.mm new file mode 100644 index 00000000000..be898e21815 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-19.mm @@ -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; +} diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-5.mm b/gcc/testsuite/obj-c++.dg/property/at-property-5.mm index 1e604e90b16..7ccf4c974d2 100644 --- a/gcc/testsuite/obj-c++.dg/property/at-property-5.mm +++ b/gcc/testsuite/obj-c++.dg/property/at-property-5.mm @@ -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" } */ diff --git a/gcc/testsuite/obj-c++.dg/property/dotsyntax-12.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-12.mm new file mode 100644 index 00000000000..20882f909ae --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-12.mm @@ -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; +} diff --git a/gcc/testsuite/obj-c++.dg/protocol-inheritance-1.mm b/gcc/testsuite/obj-c++.dg/protocol-inheritance-1.mm new file mode 100644 index 00000000000..6c23a4663df --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/protocol-inheritance-1.mm @@ -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 } */ diff --git a/gcc/testsuite/obj-c++.dg/protocol-inheritance-2.mm b/gcc/testsuite/obj-c++.dg/protocol-inheritance-2.mm new file mode 100644 index 00000000000..d769949451e --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/protocol-inheritance-2.mm @@ -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 } */ diff --git a/gcc/testsuite/objc.dg/property/at-property-16.m b/gcc/testsuite/objc.dg/property/at-property-16.m new file mode 100644 index 00000000000..f40225dea67 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-16.m @@ -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 + diff --git a/gcc/testsuite/objc.dg/property/at-property-17.m b/gcc/testsuite/objc.dg/property/at-property-17.m new file mode 100644 index 00000000000..efb62d6f70d --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-17.m @@ -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 } */ diff --git a/gcc/testsuite/objc.dg/property/at-property-18.m b/gcc/testsuite/objc.dg/property/at-property-18.m new file mode 100644 index 00000000000..58b1d6a07cc --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-18.m @@ -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 diff --git a/gcc/testsuite/objc.dg/property/at-property-19.m b/gcc/testsuite/objc.dg/property/at-property-19.m new file mode 100644 index 00000000000..be898e21815 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-19.m @@ -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; +} diff --git a/gcc/testsuite/objc.dg/property/at-property-5.m b/gcc/testsuite/objc.dg/property/at-property-5.m index e4abd27c284..bd8949b7f58 100644 --- a/gcc/testsuite/objc.dg/property/at-property-5.m +++ b/gcc/testsuite/objc.dg/property/at-property-5.m @@ -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" } */ diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-12.m b/gcc/testsuite/objc.dg/property/dotsyntax-12.m new file mode 100644 index 00000000000..20882f909ae --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-12.m @@ -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; +} diff --git a/gcc/testsuite/objc.dg/protocol-inheritance-1.m b/gcc/testsuite/objc.dg/protocol-inheritance-1.m new file mode 100644 index 00000000000..6c23a4663df --- /dev/null +++ b/gcc/testsuite/objc.dg/protocol-inheritance-1.m @@ -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 } */ diff --git a/gcc/testsuite/objc.dg/protocol-inheritance-2.m b/gcc/testsuite/objc.dg/protocol-inheritance-2.m new file mode 100644 index 00000000000..d769949451e --- /dev/null +++ b/gcc/testsuite/objc.dg/protocol-inheritance-2.m @@ -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 } */ -- 2.11.4.GIT