Commit bf79cedb by Nicola Pero Committed by Nicola Pero

In gcc/objc/: 2011-06-02 Nicola Pero <nicola.pero@meta-innovation.com>

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.

From-SVN: r174575
parent ae9982ec
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
......
......@@ -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)
......
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.
2011-06-02 DJ Delorie <dj@redhat.com>
* lib/timeout.exp (timeout): Add board_info support.
......
/* The following should NOT generate "may not respond to" warnings,
since a forward-declared @class (instance) should be treated like a
'Class') ('id'). */
/* The following should NOT generate "may not respond to" warnings, since a forward-declared
@class (instance) should be treated like a 'Class') ('id'). */
/* { dg-do compile } */
......@@ -9,11 +8,11 @@
@class NotKnown;
void foo(NotKnown *n) {
[NotKnown new];
[n nonexistent_method]; /* { dg-warning "no .\\-nonexistent_method. method found" } */
[NotKnown new]; /* { dg-warning ".interface of class .NotKnown. not found" } */
[n nonexistent_method]; /* { dg-warning ".interface of class .NotKnown. not found" } */
/* { dg-warning "no .\\-nonexistent_method. method found" "" { target *-*-* } 12 } */
}
/* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 0 } */
/* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 0 } */
/* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 0 } */
/* Check if sending messages to "underspecified" objects is handled gracefully. */
/* Author: Ziemowit Laski <zlaski@apple.com>. */
/* { dg-do compile } */
@class UnderSpecified;
......@@ -10,10 +9,12 @@ typedef struct NotAClass {
void foo(UnderSpecified *u, NotAClass *n) {
[n nonexistent_method]; /* { dg-warning "invalid receiver type" } */
/* { dg-warning "no .\\-nonexistent_method. method found" "" { target *-*-* } 12 } */
/* { dg-warning "no .\\-nonexistent_method. method found" "" { target *-*-* } 11 } */
[NotAClass nonexistent_method]; /* { dg-error ".NotAClass. is not an Objective\\-C class name or alias" } */
[u nonexistent_method]; /* { dg-warning "no .\\-nonexistent_method. method found" } */
[UnderSpecified nonexistent_method]; /* { dg-warning "no .\\+nonexistent_method. method found" } */
[u nonexistent_method]; /* { dg-warning ".interface of class .UnderSpecified. not found" } */
/* { dg-warning "no .\\-nonexistent_method. method found" "" { target *-*-* } 14 } */
[UnderSpecified nonexistent_method]; /* { dg-warning ".interface of class .UnderSpecified. not found" } */
/* { dg-warning "no .\\+nonexistent_method. method found" "" { target *-*-* } 16 } */
}
/* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 0 } */
......
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, June 2011. */
/* { dg-do compile } */
@class NotKnown;
@protocol MyProtocol
+ (id) classMethod;
- (id) instanceMethod;
@end
@protocol MyProtocol2
+ (id) classMethod2;
- (id) instanceMethod2;
@end
void test (Class x, Class <MyProtocol> y, id w, id <MyProtocol> z, NotKnown *a, NotKnown <MyProtocol> *b)
{
/* "Class x" means that "x" responds to any class methods, and may
also respond to instance methods because instance methods of the
root class are class methods. */
[x classMethod]; /* No warning here. */
[x instanceMethod]; /* No warning here. */
/* "Class <MyProtocol> y" means that "y" responds to any class
methods specified in the protocol MyProtocol, but not to other
class or instance methods. If a class method is not found, an
instance method from the protocol may be used instead but that is
suspicious and gets a warning. */
[y classMethod]; /* No warning here. */
[y instanceMethod]; /* { dg-warning "found .\\-instanceMethod. instead of .\\+instanceMethod. in protocol" } */
[y classMethod2]; /* { dg-warning ".\\+classMethod2. not found in protocol" } */
[y instanceMethod2]; /* { dg-warning ".\\+instanceMethod2. not found in protocol" } */
/* If a class is specified by name, the @interface must be available
to check what it responds to. */
[NotKnown classMethod]; /* { dg-warning ".interface of class .NotKnown. not found" } */
/* "id w" means that "w" responds to anything, both class and
instance methods. */
[w instanceMethod]; /* No warning here. */
[w instanceMethod2]; /* No warning here. */
[w classMethod]; /* No warning here. */
[w classMethod2]; /* No warning here. */
/* "id <MyProtocol> z" means that "z" responds to any instance
methods in the protocol, but not class methods. To select class
methods, you use "Class <MyProtocol> z". */
[z instanceMethod]; /* No warning here. */
[z instanceMethod2]; /* { dg-warning ".\\-instanceMethod2. not found in protocol" } */
[z classMethod]; /* { dg-warning ".\\-classMethod. not found in protocol" } */
[z classMethod2]; /* { dg-warning ".\\-classMethod2. not found in protocol" } */
/* "NotKnown *a" means that "a" is an instance of NotKnown. Since
the programmer explicitly specified the class name, it must be
because they expect the compiler to do type-checking; the
@interface must be available to do this check, otherwise the
compiler does not know what "a" responds to. */
[a instanceMethod]; /* { dg-warning ".interface of class .NotKnown. not found" } */
/* But, if you cast it to "id", then you're disabling type-checking
and the warnings should go away. */
[(id)a instanceMethod]; /* No warning here. */
/* "NotKnown <MyProtocol> *b" means that "a" is an instance of
NotKnown, and also implements protocol <MyProtocol>. If you send
a message that is part of the protocol, then the compiler can do
type-checking and all is fine. */
[b instanceMethod];
/* But if you send a message that is not part of the protocol, then
you'll get a warning that the method can not be found in the
protocol. */
[b instanceMethod2]; /* { dg-warning ".\\-instanceMethod2. not found in protocol" } */
/* But, if you cast it to "id", then you're disabling type-checking
and the warnings should go away. */
[(id)b instanceMethod2]; /* No warning here. */
}
......@@ -8,8 +8,9 @@
@class NotKnown;
void foo(NotKnown *n) {
[NotKnown new];
[n nonexistent_method]; /* { dg-warning "no .\\-nonexistent_method. method found" } */
[NotKnown new]; /* { dg-warning ".interface of class .NotKnown. not found" } */
[n nonexistent_method]; /* { dg-warning ".interface of class .NotKnown. not found" } */
/* { dg-warning "no .\\-nonexistent_method. method found" "" { target *-*-* } 12 } */
}
/* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 0 } */
......
......@@ -11,8 +11,10 @@ void foo(UnderSpecified *u, NotAClass *n) {
[n nonexistent_method]; /* { dg-warning "invalid receiver type" } */
/* { dg-warning "no .\\-nonexistent_method. method found" "" { target *-*-* } 11 } */
[NotAClass nonexistent_method]; /* { dg-error ".NotAClass. is not an Objective\\-C class name or alias" } */
[u nonexistent_method]; /* { dg-warning "no .\\-nonexistent_method. method found" } */
[UnderSpecified nonexistent_method]; /* { dg-warning "no .\\+nonexistent_method. method found" } */
[u nonexistent_method]; /* { dg-warning ".interface of class .UnderSpecified. not found" } */
/* { dg-warning "no .\\-nonexistent_method. method found" "" { target *-*-* } 14 } */
[UnderSpecified nonexistent_method]; /* { dg-warning ".interface of class .UnderSpecified. not found" } */
/* { dg-warning "no .\\+nonexistent_method. method found" "" { target *-*-* } 16 } */
}
/* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 0 } */
......
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, June 2011. */
/* { dg-do compile } */
@class NotKnown;
@protocol MyProtocol
+ (id) classMethod;
- (id) instanceMethod;
@end
@protocol MyProtocol2
+ (id) classMethod2;
- (id) instanceMethod2;
@end
void test (Class x, Class <MyProtocol> y, id w, id <MyProtocol> z, NotKnown *a, NotKnown <MyProtocol> *b)
{
/* "Class x" means that "x" responds to any class methods, and may
also respond to instance methods because instance methods of the
root class are class methods. */
[x classMethod]; /* No warning here. */
[x instanceMethod]; /* No warning here. */
/* "Class <MyProtocol> y" means that "y" responds to any class
methods specified in the protocol MyProtocol, but not to other
class or instance methods. If a class method is not found, an
instance method from the protocol may be used instead but that is
suspicious and gets a warning. */
[y classMethod]; /* No warning here. */
[y instanceMethod]; /* { dg-warning "found .\\-instanceMethod. instead of .\\+instanceMethod. in protocol" } */
[y classMethod2]; /* { dg-warning ".\\+classMethod2. not found in protocol" } */
[y instanceMethod2]; /* { dg-warning ".\\+instanceMethod2. not found in protocol" } */
/* If a class is specified by name, the @interface must be available
to check what it responds to. */
[NotKnown classMethod]; /* { dg-warning ".interface of class .NotKnown. not found" } */
/* "id w" means that "w" responds to anything, both class and
instance methods. */
[w instanceMethod]; /* No warning here. */
[w instanceMethod2]; /* No warning here. */
[w classMethod]; /* No warning here. */
[w classMethod2]; /* No warning here. */
/* "id <MyProtocol> z" means that "z" responds to any instance
methods in the protocol, but not class methods. To select class
methods, you use "Class <MyProtocol> z". */
[z instanceMethod]; /* No warning here. */
[z instanceMethod2]; /* { dg-warning ".\\-instanceMethod2. not found in protocol" } */
[z classMethod]; /* { dg-warning ".\\-classMethod. not found in protocol" } */
[z classMethod2]; /* { dg-warning ".\\-classMethod2. not found in protocol" } */
/* "NotKnown *a" means that "a" is an instance of NotKnown. Since
the programmer explicitly specified the class name, it must be
because they expect the compiler to do type-checking; the
@interface must be available to do this check, otherwise the
compiler does not know what "a" responds to. */
[a instanceMethod]; /* { dg-warning ".interface of class .NotKnown. not found" } */
/* But, if you cast it to "id", then you're disabling type-checking
and the warnings should go away. */
[(id)a instanceMethod]; /* No warning here. */
/* "NotKnown <MyProtocol> *b" means that "a" is an instance of
NotKnown, and also implements protocol <MyProtocol>. If you send
a message that is part of the protocol, then the compiler can do
type-checking and all is fine. */
[b instanceMethod];
/* But if you send a message that is not part of the protocol, then
you'll get a warning that the method can not be found in the
protocol. */
[b instanceMethod2]; /* { dg-warning ".\\-instanceMethod2. not found in protocol" } */
/* But, if you cast it to "id", then you're disabling type-checking
and the warnings should go away. */
[(id)b instanceMethod2]; /* No warning here. */
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment