diff options
author | nicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-06-02 18:54:32 +0000 |
---|---|---|
committer | nicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-06-02 18:54:32 +0000 |
commit | a53aa046850c0271a5729af9f258dcc1b947b3b2 (patch) | |
tree | c5eb3b5146458a81edad3cd5ef6d4467cb3fd01c /gcc/objc | |
parent | 5a2e53487f615d5896ea3b827adc3cb43c3744e8 (diff) | |
download | gcc-a53aa046850c0271a5729af9f258dcc1b947b3b2.tar.gz |
In gcc/objc/:
2011-06-02 Nicola Pero <nicola.pero@meta-innovation.com>
PR objc/48539
* objc-act.c (objc_finish_message_expr): Warn if messaging a class
that was only declared using @class without an @interface. Warn
if messaging an instance of a class that was only declared using
@class without an @interface, unless the receiver was also typed
with a protocol list.
In gcc/testsuite/:
2011-06-02 Nicola Pero <nicola.pero@meta-innovation.com>
PR objc/48539
* objc.dg/method-5.m: Updated.
* objc.dg/method-19.m: Updated.
* objc.dg/method-lookup-1.m: New.
* obj-c++.dg/method-6.mm: Updated.
* obj-c++.dg/method-7.mm: Updated.
* obj-c++.dg/method-lookup-1.mm: New.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@174575 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/objc')
-rw-r--r-- | gcc/objc/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/objc/objc-act.c | 150 |
2 files changed, 130 insertions, 29 deletions
diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index c52fcc3ff98..50c80b5c7cb 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,12 @@ +2011-06-02 Nicola Pero <nicola.pero@meta-innovation.com> + + PR objc/48539 + * objc-act.c (objc_finish_message_expr): Warn if messaging a class + that was only declared using @class without an @interface. Warn + if messaging an instance of a class that was only declared using + @class without an @interface, unless the receiver was also typed + with a protocol list. + 2011-06-01 Nicola Pero <nicola.pero@meta-innovation.com> * objc-act.c (objc_decl_method_attributes): Implement nonnull diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index be65a534f1b..e7acb7f05b1 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -5432,15 +5432,21 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params, from the implementation context). */ rtype = receiver; while (TREE_CODE (rtype) == COMPOUND_EXPR - || TREE_CODE (rtype) == MODIFY_EXPR - || CONVERT_EXPR_P (rtype) - || TREE_CODE (rtype) == COMPONENT_REF) + || TREE_CODE (rtype) == MODIFY_EXPR + || CONVERT_EXPR_P (rtype) + || TREE_CODE (rtype) == COMPONENT_REF) rtype = TREE_OPERAND (rtype, 0); + /* self is 1 if this is a message to self, 0 otherwise */ self = (rtype == self_decl); + + /* super is 1 if this is a message to super, 0 otherwise. */ super = (rtype == UOBJC_SUPER_decl); + + /* rtype is the type of the receiver. */ rtype = TREE_TYPE (receiver); + /* have_cast is 1 if the receiver is casted. */ have_cast = (TREE_CODE (receiver) == NOP_EXPR || (TREE_CODE (receiver) == COMPOUND_EXPR && !IS_SUPER (rtype))); @@ -5450,7 +5456,10 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params, should_call_super_dealloc = 0; /* If the receiver is a class object, retrieve the corresponding - @interface, if one exists. */ + @interface, if one exists. class_tree is the class name + identifier, or NULL_TREE if this is not a class method or the + class name could not be determined (as in the case "Class c; [c + method];"). */ class_tree = receiver_is_class_object (receiver, self, super); /* Now determine the receiver type (if an explicit cast has not been @@ -5458,7 +5467,27 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params, if (!have_cast) { if (class_tree) - rtype = lookup_interface (class_tree); + { + /* We are here when we have no cast, and we have a class + name. So, this is a plain method to a class object, as + in [NSObject alloc]. Find the interface corresponding to + the class name. */ + rtype = lookup_interface (class_tree); + + if (rtype == NULL_TREE) + { + /* If 'rtype' is NULL_TREE at this point it means that + we have seen no @interface corresponding to that + class name, only a @class declaration. So, we have a + class name (class_tree) but no actual details of the + class methods. We won't be able to check that the + class responds to the method, and we will have to + guess the method prototype. Emit a warning, then + keep going (this will use any method with a matching + name, as if the receiver was of type 'Class'). */ + warning (0, "@interface of class %qE not found", class_tree); + } + } /* Handle `self' and `super'. */ else if (super) { @@ -5474,28 +5503,41 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params, rtype = lookup_interface (CLASS_NAME (implementation_template)); } - /* If receiver is of type `id' or `Class' (or if the @interface for a - class is not visible), we shall be satisfied with the existence of - any instance or class method. */ if (objc_is_id (rtype)) { + /* The receiver is of type 'id' or 'Class' (with or without some + protocols attached to it). */ + + /* We set class_tree to the identifier for 'Class' if this is a + class method, and to NULL_TREE if not. */ class_tree = (IS_CLASS (rtype) ? objc_class_name : NULL_TREE); + + /* 'rprotos' is the list of protocols that the receiver + supports. */ rprotos = (TYPE_HAS_OBJC_INFO (TREE_TYPE (rtype)) ? TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (rtype)) : NULL_TREE); + + /* We have no information on the type, and we set it to + NULL_TREE. */ rtype = NULL_TREE; + /* If there are any protocols, check that the method we are + calling appears in the protocol list. If there are no + protocols, this is a message to 'id' or 'Class' and we accept + any method that exists. */ if (rprotos) { - /* If messaging 'id <Protos>' or 'Class <Proto>', first search - in protocols themselves for the method prototype. */ + /* If messaging 'id <Protos>' or 'Class <Proto>', first + search in protocols themselves for the method + prototype. */ method_prototype = lookup_method_in_protocol_list (rprotos, sel_name, class_tree != NULL_TREE); - /* If messaging 'Class <Proto>' but did not find a class method - prototype, search for an instance method instead, and warn - about having done so. */ + /* If messaging 'Class <Proto>' but did not find a class + method prototype, search for an instance method instead, + and warn about having done so. */ if (!method_prototype && !rtype && class_tree != NULL_TREE) { method_prototype @@ -5509,6 +5551,8 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params, } else if (rtype) { + /* We have a receiver type which is more specific than 'id' or + 'Class'. */ tree orig_rtype = rtype; if (TREE_CODE (rtype) == POINTER_TYPE) @@ -5523,25 +5567,70 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params, rprotos = TYPE_OBJC_PROTOCOL_LIST (rtype); rtype = TYPE_OBJC_INTERFACE (rtype); } - /* If we could not find an @interface declaration, we must have - only seen a @class declaration; so, we cannot say anything - more intelligent about which methods the receiver will - understand. */ if (!rtype || TREE_CODE (rtype) == IDENTIFIER_NODE) { + /* If we could not find an @interface declaration, we must + have only seen a @class declaration; so, we cannot say + anything more intelligent about which methods the + receiver will understand. Note that this only happens + for instance methods; for class methods to a class where + we have only seen a @class declaration, + lookup_interface() above would have set rtype to + NULL_TREE. */ + if (rprotos) + { + /* We could not find an @interface declaration, yet, if + there are protocols attached to the type, we can + still look up the method in the protocols. Ie, we + are in the following case: + + @class MyClass; + MyClass<MyProtocol> *x; + [x method]; + + If 'MyProtocol' has the method 'method', we can check + and retrieve the method prototype. */ + method_prototype + = lookup_method_in_protocol_list (rprotos, sel_name, 0); + + /* At this point, if we have found the method_prototype, + we are quite happy. The details of the class are + irrelevant. If we haven't found it, a warning will + have been produced that the method could not be found + in the protocol, and we won't produce further + warnings (please note that this means that "@class + MyClass; MyClass <MyProtocol> *x;" is exactly + equivalent to "id <MyProtocol> x", which isn't too + satisfactory but it's not easy to see how to do + better). */ + } + else + { + if (rtype) + { + /* We could not find an @interface declaration, and + there are no protocols attached to the receiver, + so we can't complete the check that the receiver + responds to the method, and we can't retrieve the + method prototype. But, because the receiver has + a well-specified class, the programmer did want + this check to be performed. Emit a warning, then + keep going as if it was an 'id'. To remove the + warning, either include an @interface for the + class, or cast the receiver to 'id'. Note that + rtype is an IDENTIFIER_NODE at this point. */ + warning (0, "@interface of class %qE not found", rtype); + } + } + rtype = NULL_TREE; - /* We could not find an @interface declaration, yet Message maybe in a - @class's protocol. */ - if (!method_prototype && rprotos) - method_prototype - = lookup_method_in_protocol_list (rprotos, sel_name, 0); } else if (TREE_CODE (rtype) == CLASS_INTERFACE_TYPE || TREE_CODE (rtype) == CLASS_IMPLEMENTATION_TYPE) { - /* We have a valid ObjC class name. Look up the method name - in the published @interface for the class (and its - superclasses). */ + /* We have a valid ObjC class name with an associated + @interface. Look up the method name in the published + @interface for the class (and its superclasses). */ method_prototype = lookup_method_static (rtype, sel_name, class_tree != NULL_TREE); @@ -5566,6 +5655,7 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params, } else { + /* We have a type, but it's not an Objective-C type (!). */ warning (0, "invalid receiver type %qs", identifier_to_locale (gen_type_name (orig_rtype))); /* After issuing the "invalid receiver" warning, perform method @@ -5573,11 +5663,13 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params, rtype = rprotos = NULL_TREE; } } + /* Note that rtype could also be NULL_TREE. This happens if we are + messaging a class by name, but the class was only + forward-declared using @class. */ - - /* For 'id' or 'Class' receivers, search in the global hash table - as a last resort. For all receivers, warn if protocol searches - have failed. */ + /* For 'id' or 'Class' receivers, search in the global hash table as + a last resort. For all receivers, warn if protocol searches have + failed. */ if (!method_prototype) { if (rprotos) |