This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: preliminary patch for objc_comptypes() fixes
- From: Nicola Pero <nicola at brainstorm dot co dot uk>
- To: Stan Shebs <shebs at apple dot com>
- Cc: Nicola Pero <n dot pero at mi dot flashnet dot it>, gcc-patches at gcc dot gnu dot org
- Date: Thu, 12 Sep 2002 11:26:34 +0100 (BST)
- Subject: Re: preliminary patch for objc_comptypes() fixes
Hi Stan,
sorry for having been a few days late with this.
I've now updated the patch for Zem's changes, double checked it, fixed a
bug in it, then written a whole bunch of testcases mechanically mixing all
ObjC types in assignments and comparisons (quite boring but it had to be
done), and tested my patch against it (I also added an extensive test that
ObjC casts are not ignored for all types, which is really more about Zem's
patch than mine).
I think it's ready to be applied. It does fix a lot of missing (or
excess) warnings in a variety of situations, but all pretty obscure :-)
usually involving id<MyProtocol> (or the even more obscure
MyClass<MyProtocol> *).
To test it a bit more extensively than just a bootstrap and testcases, I
compiled gnustep-base and gnustep-gui with the patched compiler, and it
didn't generate any new ObjC warnings, except for a new warning for
NSMenuItem *i = [anObject aMethod];
where -aMethod returns id<NSMenuItem>. It now warns that the assignment
requires a cast. Which is correct.
Of course, the original PR/7014 tstcase which started all this :-)
id<MyProtocol> obj = nil;
if (nil == obj) ;
now compiles correctly without warnings.
Ok to apply ?
Thu Sep 12 12:09:12 2002 Nicola Pero <n.pero@mi.flashnet.it>
Fix PR/7014 and related objc typechecking bugs:
* c-typeck.c (comp_target_types): Added a reflexive argument.
Pass it to ObjC when/if calling objc_comptypes(). Updated all
callers to provide the appropriate reflexive argument.
* objc/objc-act.c (objc_comptypes): Carefully checked and fixed
typechecking for all cases of comparisons and assignments,
particularly the obscure and less common ones involving protocols.
Index: c-typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v
retrieving revision 1.206
diff -u -r1.206 c-typeck.c
--- c-typeck.c 8 Sep 2002 03:20:34 -0000 1.206
+++ c-typeck.c 12 Sep 2002 10:01:03 -0000
@@ -51,7 +51,7 @@
static int undeclared_variable_notice;
static tree qualify_type PARAMS ((tree, tree));
-static int comp_target_types PARAMS ((tree, tree));
+static int comp_target_types PARAMS ((tree, tree, int));
static int function_types_compatible_p PARAMS ((tree, tree));
static int type_lists_compatible_p PARAMS ((tree, tree));
static tree decl_constant_value_for_broken_optimization PARAMS ((tree));
@@ -579,16 +579,21 @@
}
/* Return 1 if TTL and TTR are pointers to types that are equivalent,
- ignoring their qualifiers. */
+ ignoring their qualifiers. REFLEXIVE is only used by ObjC - set it
+ to 1 or 0 depending if the check of the pointer types is meant to
+ be reflexive or not (typically, assignments are not reflexive,
+ while comparisons are reflexive).
+*/
static int
-comp_target_types (ttl, ttr)
+comp_target_types (ttl, ttr, reflexive)
tree ttl, ttr;
+ int reflexive;
{
int val;
/* Give objc_comptypes a crack at letting these types through. */
- if ((val = objc_comptypes (ttl, ttr, 1)) >= 0)
+ if ((val = objc_comptypes (ttl, ttr, reflexive)) >= 0)
return val;
val = comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (ttl)),
@@ -1958,7 +1963,7 @@
/* Subtraction of two similar pointers.
We must subtract them as integers, then divide by object size. */
if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
- && comp_target_types (type0, type1))
+ && comp_target_types (type0, type1, 1))
return pointer_diff (op0, op1);
/* Handle pointer minus int. Just like pointer plus int. */
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
@@ -2148,7 +2153,7 @@
/* Anything compares with void *. void * compares with anything.
Otherwise, the targets must be compatible
and both must be object or both incomplete. */
- if (comp_target_types (type0, type1))
+ if (comp_target_types (type0, type1, 1))
result_type = common_type (type0, type1);
else if (VOID_TYPE_P (tt0))
{
@@ -2195,7 +2200,7 @@
shorten = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
- if (comp_target_types (type0, type1))
+ if (comp_target_types (type0, type1, 1))
{
result_type = common_type (type0, type1);
if (pedantic
@@ -2220,7 +2225,7 @@
short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
- if (comp_target_types (type0, type1))
+ if (comp_target_types (type0, type1, 1))
{
result_type = common_type (type0, type1);
if (!COMPLETE_TYPE_P (TREE_TYPE (type0))
@@ -3443,7 +3448,7 @@
}
else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
{
- if (comp_target_types (type1, type2))
+ if (comp_target_types (type1, type2, 1))
result_type = common_type (type1, type2);
else if (integer_zerop (op1) && TREE_TYPE (type1) == void_type_node
&& TREE_CODE (orig_op1) != NOP_EXPR)
@@ -4010,13 +4015,12 @@
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
{
overflow_warning (rhs);
- /* Check for Objective-C protocols. This will issue a warning if
- there are protocol violations. No need to use the return value. */
+ /* Check for Objective-C protocols. This will automatically
+ issue a warning if there are protocol violations. */
if (flag_objc)
objc_comptypes (type, rhstype, 0);
return rhs;
}
-
if (coder == VOID_TYPE)
{
error ("void value not ignored as it ought to be");
@@ -4086,7 +4090,7 @@
Meanwhile, the lhs target must have all the qualifiers of
the rhs. */
if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
- || comp_target_types (memb_type, rhstype))
+ || comp_target_types (memb_type, rhstype, 0))
{
/* If this type won't generate any warnings, use it. */
if (TYPE_QUALS (ttl) == TYPE_QUALS (ttr)
@@ -4161,7 +4165,7 @@
and vice versa; otherwise, targets must be the same.
Meanwhile, the lhs target must have all the qualifiers of the rhs. */
if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
- || comp_target_types (type, rhstype)
+ || comp_target_types (type, rhstype, 0)
|| (c_common_unsigned_type (TYPE_MAIN_VARIANT (ttl))
== c_common_unsigned_type (TYPE_MAIN_VARIANT (ttr))))
{
@@ -4186,7 +4190,7 @@
/* If this is not a case of ignoring a mismatch in signedness,
no warning. */
else if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
- || comp_target_types (type, rhstype))
+ || comp_target_types (type, rhstype, 0))
;
/* If there is a mismatch, do warn. */
else if (pedantic)
Index: objc/objc-act.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/objc/objc-act.c,v
retrieving revision 1.158
diff -u -r1.158 objc-act.c
--- objc/objc-act.c 6 Sep 2002 23:32:12 -0000 1.158
+++ objc/objc-act.c 12 Sep 2002 10:01:03 -0000
@@ -587,10 +587,24 @@
return 0;
}
-/* Return 1 if LHS and RHS are compatible types for assignment
- or various other operations. Return 0 if they are incompatible,
- and return -1 if we choose to not decide. When the operation
- is REFLEXIVE, check for compatibility in either direction. */
+/* Return 1 if LHS and RHS are compatible types for assignment or
+ various other operations. Return 0 if they are incompatible, and
+ return -1 if we choose to not decide (because the types are really
+ just C types, not ObjC specific ones). When the operation is
+ REFLEXIVE (typically comparisons), check for compatibility in
+ either direction; when it's not (typically assignments), don't.
+
+ This function is called in two cases: when both lhs and rhs are
+ pointers to records (in which case we check protocols too), and
+ when both lhs and rhs are records (in which case we check class
+ inheritance only).
+
+ Warnings about classes/protocols not implementing a protocol are
+ emitted here (multiple of those warnings might be emitted for a
+ single line!); generic warnings about incompatible assignments and
+ lacks of casts in comparisons are/must be emitted by the caller if
+ we return 0.
+*/
int
objc_comptypes (lhs, rhs, reflexive)
@@ -600,6 +614,8 @@
{
/* New clause for protocols. */
+ /* Here we manage the case of a POINTER_TYPE = POINTER_TYPE. We only
+ manage the ObjC ones, and leave the rest to the C code. */
if (TREE_CODE (lhs) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (lhs)) == RECORD_TYPE
&& TREE_CODE (rhs) == POINTER_TYPE
@@ -614,44 +630,90 @@
tree rproto, rproto_list;
tree p;
+ /* <Protocol> = <Protocol> */
if (rhs_is_proto)
{
rproto_list = TYPE_PROTOCOL_LIST (rhs);
-
- /* Make sure the protocol is supported by the object
- on the rhs. */
- for (lproto = lproto_list; lproto; lproto = TREE_CHAIN (lproto))
+
+ if (!reflexive)
{
- p = TREE_VALUE (lproto);
- rproto = lookup_protocol_in_reflist (rproto_list, p);
-
- if (!rproto)
- warning ("object does not conform to the `%s' protocol",
- IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
+ /* An assignment between objects of type 'id
+ <Protocol>'; make sure the protocol on the lhs is
+ supported by the object on the rhs. */
+ for (lproto = lproto_list; lproto;
+ lproto = TREE_CHAIN (lproto))
+ {
+ p = TREE_VALUE (lproto);
+ rproto = lookup_protocol_in_reflist (rproto_list, p);
+
+ if (!rproto)
+ warning
+ ("object does not conform to the `%s' protocol",
+ IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
+ }
+ return 1;
+ }
+ else
+ {
+ /* Obscure case - a comparison between two objects
+ of type 'id <Protocol>'. Check that either the
+ protocol on the lhs is supported by the object on
+ the rhs, or viceversa. */
+
+ /* Check if the protocol on the lhs is supported by the
+ object on the rhs. */
+ for (lproto = lproto_list; lproto;
+ lproto = TREE_CHAIN (lproto))
+ {
+ p = TREE_VALUE (lproto);
+ rproto = lookup_protocol_in_reflist (rproto_list, p);
+
+ if (!rproto)
+ {
+ /* Check failed - check if the protocol on the rhs
+ is supported by the object on the lhs. */
+ for (rproto = rproto_list; rproto;
+ rproto = TREE_CHAIN (rproto))
+ {
+ p = TREE_VALUE (rproto);
+ lproto = lookup_protocol_in_reflist (lproto_list,
+ p);
+
+ if (!lproto)
+ {
+ /* This check failed too: incompatible */
+ return 0;
+ }
+ }
+ return 1;
+ }
+ }
+ return 1;
}
}
+ /* <Protocol> = <class> * */
else if (TYPED_OBJECT (TREE_TYPE (rhs)))
{
tree rname = TYPE_NAME (TREE_TYPE (rhs));
tree rinter;
-
- /* Make sure the protocol is supported by the object
- on the rhs. */
+
+ /* Make sure the protocol is supported by the object on
+ the rhs. */
for (lproto = lproto_list; lproto; lproto = TREE_CHAIN (lproto))
{
p = TREE_VALUE (lproto);
rproto = 0;
rinter = lookup_interface (rname);
-
+
while (rinter && !rproto)
{
tree cat;
-
+
rproto_list = CLASS_PROTOCOL_LIST (rinter);
rproto = lookup_protocol_in_reflist (rproto_list, p);
/* If the underlying ObjC class does not have
the protocol we're looking for, check for "one-off"
- protocols (e.g., `NSObject<MyProt> foo;') attached
+ protocols (e.g., `NSObject<MyProt> *foo;') attached
to the rhs. */
if (!rproto)
{
@@ -665,40 +727,135 @@
{
rproto_list = CLASS_PROTOCOL_LIST (cat);
rproto = lookup_protocol_in_reflist (rproto_list, p);
-
cat = CLASS_CATEGORY_LIST (cat);
}
-
+
rinter = lookup_interface (CLASS_SUPER_NAME (rinter));
}
-
+
if (!rproto)
warning ("class `%s' does not implement the `%s' protocol",
- IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (rhs))),
- IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
+ IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (rhs))),
+ IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
}
+ return 1;
}
-
- /* May change...based on whether there was any mismatch */
- return 1;
+ /* <Protocol> = id */
+ else if (TYPE_NAME (TREE_TYPE (rhs)) == objc_object_id)
+ {
+ return 1;
+ }
+ /* <Protocol> = Class */
+ else if (TYPE_NAME (TREE_TYPE (rhs)) == objc_class_id)
+ {
+ return 0;
+ }
+ /* <Protocol> = ?? : let comptypes decide. */
+ return -1;
}
else if (rhs_is_proto)
- /* Lhs is not a protocol...warn if it is statically typed */
- return (TYPED_OBJECT (TREE_TYPE (lhs)) != 0);
-
+ {
+ /* <class> * = <Protocol> */
+ if (TYPED_OBJECT (TREE_TYPE (lhs)))
+ {
+ if (reflexive)
+ {
+ tree rname = TYPE_NAME (TREE_TYPE (lhs));
+ tree rinter;
+ tree rproto, rproto_list = TYPE_PROTOCOL_LIST (rhs);
+
+ /* Make sure the protocol is supported by the object on
+ the lhs. */
+ for (rproto = rproto_list; rproto;
+ rproto = TREE_CHAIN (rproto))
+ {
+ tree p = TREE_VALUE (rproto);
+ tree lproto = 0;
+ rinter = lookup_interface (rname);
+
+ while (rinter && !lproto)
+ {
+ tree cat;
+
+ tree lproto_list = CLASS_PROTOCOL_LIST (rinter);
+ lproto = lookup_protocol_in_reflist (lproto_list, p);
+ /* If the underlying ObjC class does not
+ have the protocol we're looking for,
+ check for "one-off" protocols (e.g.,
+ `NSObject<MyProt> *foo;') attached to the
+ lhs. */
+ if (!lproto)
+ {
+ lproto_list = TYPE_PROTOCOL_LIST
+ (TREE_TYPE (lhs));
+ lproto = lookup_protocol_in_reflist
+ (lproto_list, p);
+ }
+
+ /* Check for protocols adopted by categories. */
+ cat = CLASS_CATEGORY_LIST (rinter);
+ while (cat && !lproto)
+ {
+ lproto_list = CLASS_PROTOCOL_LIST (cat);
+ lproto = lookup_protocol_in_reflist (lproto_list,
+ p);
+ cat = CLASS_CATEGORY_LIST (cat);
+ }
+
+ rinter = lookup_interface (CLASS_SUPER_NAME
+ (rinter));
+ }
+
+ if (!lproto)
+ warning ("class `%s' does not implement the `%s' protocol",
+ IDENTIFIER_POINTER (TYPE_NAME
+ (TREE_TYPE (lhs))),
+ IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
+ }
+ return 1;
+ }
+ else
+ return 0;
+ }
+ /* id = <Protocol> */
+ else if (TYPE_NAME (TREE_TYPE (lhs)) == objc_object_id)
+ {
+ return 1;
+ }
+ /* Class = <Protocol> */
+ else if (TYPE_NAME (TREE_TYPE (lhs)) == objc_class_id)
+ {
+ return 0;
+ }
+ /* ??? = <Protocol> : let comptypes decide */
+ else
+ {
+ return -1;
+ }
+ }
else
- /* Defer to comptypes. */
- return -1;
+ {
+ /* Attention: we shouldn't defer to comptypes here. One bad
+ side effect would be that we might loose the REFLEXIVE
+ information.
+ */
+ lhs = TREE_TYPE (lhs);
+ rhs = TREE_TYPE (rhs);
+ }
}
- else if (TREE_CODE (lhs) == RECORD_TYPE && TREE_CODE (rhs) == RECORD_TYPE)
- ; /* Fall thru. This is the case we have been handling all along */
- else
- /* Defer to comptypes. */
- return -1;
-
- /* `id' = `<class> *', `<class> *' = `id' */
+ if (TREE_CODE (lhs) != RECORD_TYPE || TREE_CODE (rhs) != RECORD_TYPE)
+ {
+ /* Nothing to do with ObjC - let immediately comptypes take
+ responsibility for checking. */
+ return -1;
+ }
+ /* `id' = `<class> *' `<class> *' = `id': always allow it.
+ Please note that
+ 'Object *o = [[Object alloc] init]; falls
+ in the case <class> * = `id'.
+ */
if ((TYPE_NAME (lhs) == objc_object_id && TYPED_OBJECT (rhs))
|| (TYPE_NAME (rhs) == objc_object_id && TYPED_OBJECT (lhs)))
return 1;
@@ -739,7 +896,7 @@
return 0;
}
else
- /* Defer to comptypes. */
+ /* Not an ObjC type - let comptypes do the check. */
return -1;
}
=== Now the testcases ===
/* Test various ObjC types assignments and comparisons. */
/* Author: Nicola Pero <nicola@brainstorm.co.uk>. */
/* { dg-do compile } */
#include <objc/objc.h>
@protocol MyProtocol
- (void) foo;
@end
@interface MyClass
@end
@interface MyOtherClass <MyProtocol>
- (void) foo;
@end
int main()
{
id obj = nil;
id<MyProtocol> obj_p = nil;
MyClass *obj_c = nil;
MyOtherClass *obj_cp = nil;
Class obj_C = Nil;
/* Assigning to an 'id' variable should never
generate a warning. */
obj = obj_p; /* Ok */
obj = obj_c; /* Ok */
obj = obj_cp; /* Ok */
obj = obj_C; /* Ok */
/* Assigning to a 'MyClass *' variable should always generate a
warning, unless done from an 'id'. */
obj_c = obj; /* Ok */
obj_c = obj_p; /* { dg-warning "incompatible pointer type" } */
obj_c = obj_cp; /* { dg-warning "incompatible pointer type" } */
obj_c = obj_C; /* { dg-warning "incompatible pointer type" } */
/* Assigning to an 'id<MyProtocol>' variable should generate a
warning if done from a 'MyClass *' (which doesn't implement
MyProtocol), but not from an 'id' or from a 'MyOtherClass *'
(which implements MyProtocol). */
obj_p = obj; /* Ok */
obj_p = obj_c; /* { dg-warning "does not implement" } */ /*FIXME: Duplicated*/
obj_p = obj_cp; /* Ok */
obj_p = obj_C; /* { dg-warning "incompatible pointer type" } */
/* Assigning to a 'MyOtherClass *' variable should always generate
a warning, unless done from an 'id' */
obj_cp = obj; /* Ok */
obj_cp = obj_c; /* { dg-warning "incompatible pointer type" } */
obj_cp = obj_p; /* { dg-warning "incompatible pointer type" } */
obj_cp = obj_C; /* { dg-warning "incompatible pointer type" } */
/* Any comparison involving an 'id' must be without warnings. */
if (obj == obj_p) ; /* Ok */ /*Bogus warning here in 2.95.4*/
if (obj_p == obj) ; /* Ok */
if (obj == obj_c) ; /* Ok */
if (obj_c == obj) ; /* Ok */
if (obj == obj_cp) ; /* Ok */
if (obj_cp == obj) ; /* Ok */
if (obj == obj_C) ; /* Ok */
if (obj_C == obj) ; /* Ok */
/* Any comparison between 'MyClass *' and anything which is not an 'id'
must generate a warning. */
if (obj_c == obj_p) ; /* { dg-warning "does not implement" } */
if (obj_p == obj_c) ; /* { dg-warning "does not implement" } */
if (obj_c == obj_cp) ; /* { dg-warning "lacks a cast" } */
if (obj_cp == obj_c) ; /* { dg-warning "lacks a cast" } */
if (obj_c == obj_C) ; /* { dg-warning "lacks a cast" } */
if (obj_C == obj_c) ; /* { dg-warning "lacks a cast" } */
/* Any comparison between 'MyOtherClass *' (which implements
MyProtocol) and an 'id' implementing MyProtocol are Ok. */
if (obj_cp == obj_p) ; /* Ok */
if (obj_p == obj_cp) ; /* Ok */
if (obj_p == obj_C) ; /* { dg-warning "lacks a cast" } */
if (obj_C == obj_p) ; /* { dg-warning "lacks a cast" } */
if (obj_cp == obj_C) ; /* { dg-warning "lacks a cast" } */
if (obj_C == obj_cp) ; /* { dg-warning "lacks a cast" } */
return 0;
}
/* Test simple ObjC types casts. */
/* Author: Nicola Pero <nicola@brainstorm.co.uk>. */
/* { dg-do compile } */
#include <objc/objc.h>
@protocol MyProtocol
- (void) foo;
@end
@interface MyClass
@end
int main()
{
id obj = nil;
id<MyProtocol> obj_p = nil;
MyClass *obj_c = nil;
Class obj_C = Nil;
/* All these casts should generate no warnings. */
obj = (id)obj_p;
obj = (id)obj_c;
obj = (id)obj_C;
obj_c = (MyClass *)obj;
obj_c = (MyClass *)obj_p;
obj_c = (MyClass *)obj_C;
obj_p = (id<MyProtocol>)obj;
obj_p = (id<MyProtocol>)obj_c;
obj_p = (id<MyProtocol>)obj_C;
obj_C = (Class)obj;
obj_C = (Class)obj_p;
obj_C = (Class)obj_c;
return 0;
}
/* Test assignments and comparisons between protocols (obscure case). */
/* Author: Nicola Pero <nicola@brainstorm.co.uk>. */
/* { dg-do compile } */
#include <objc/objc.h>
@protocol MyProtocolA
- (void) methodA;
@end
@protocol MyProtocolB
- (void) methodB;
@end
@protocol MyProtocolAB <MyProtocolA, MyProtocolB>
@end
@protocol MyProtocolAC <MyProtocolA>
- (void) methodC;
@end
int main()
{
id<MyProtocolA> obj_a = nil;
id<MyProtocolB> obj_b = nil;
id<MyProtocolAB> obj_ab = nil;
id<MyProtocolAC> obj_ac = nil;
obj_a = obj_b; /* { dg-warning "does not conform" } */
obj_a = obj_ab; /* Ok */
obj_a = obj_ac; /* Ok */
obj_b = obj_a; /* { dg-warning "does not conform" } */
obj_b = obj_ab; /* Ok */
obj_b = obj_ac; /* { dg-warning "does not conform" } */
obj_ab = obj_a; /* { dg-warning "does not conform" } */
obj_ab = obj_b; /* { dg-warning "does not conform" } */
obj_ab = obj_ac; /* { dg-warning "does not conform" } */
obj_ac = obj_a; /* { dg-warning "does not conform" } */
obj_ac = obj_b; /* { dg-warning "does not conform" } */
obj_ac = obj_ab; /* { dg-warning "does not conform" } */
if (obj_a == obj_b) ; /* { dg-warning "lacks a cast" } */
if (obj_b == obj_a) ; /* { dg-warning "lacks a cast" } */
if (obj_a == obj_ab) ; /* Ok */
if (obj_ab == obj_a) ; /* Ok */ /* Spurious 2.95.4 warning here */
if (obj_a == obj_ac) ; /* Ok */
if (obj_ac == obj_a) ; /* Ok */ /* Spurious 2.95.4 warning here */
if (obj_b == obj_ab) ; /* Ok */
if (obj_ab == obj_b) ; /* Ok */ /* Spurious 2.95.4 warning here */
if (obj_b == obj_ac) ; /* { dg-warning "lacks a cast" } */
if (obj_ac == obj_b) ; /* { dg-warning "lacks a cast" } */
if (obj_ab == obj_ac) ; /* { dg-warning "lacks a cast" } */
if (obj_ac == obj_ab) ; /* { dg-warning "lacks a cast" } */
return 0;
}
/* Test warnings for assignments and comparisons between ObjC and C types. */
/* Author: Nicola Pero <nicola@brainstorm.co.uk>. */
/* { dg-do compile } */
#include <objc/objc.h>
@protocol MyProtocol
- (void) method;
@end
@interface MyClass
@end
int main()
{
id obj = nil;
id <MyProtocol> obj_p = nil;
MyClass *obj_c = nil;
Class obj_C = Nil;
int i = 0;
int *j = NULL;
/* These should all generate warnings. */
obj = i; /* { dg-warning "pointer from integer without a cast" } */
obj = j; /* { dg-warning "incompatible pointer type" } */
obj_p = i; /* { dg-warning "pointer from integer without a cast" } */
obj_p = j; /* { dg-warning "incompatible pointer type" } */
obj_c = i; /* { dg-warning "pointer from integer without a cast" } */
obj_c = j; /* { dg-warning "incompatible pointer type" } */
obj_C = i; /* { dg-warning "pointer from integer without a cast" } */
obj_C = j; /* { dg-warning "incompatible pointer type" } */
i = obj; /* { dg-warning "integer from pointer without a cast" } */
i = obj_p; /* { dg-warning "integer from pointer without a cast" } */
i = obj_c; /* { dg-warning "integer from pointer without a cast" } */
i = obj_C; /* { dg-warning "integer from pointer without a cast" } */
j = obj; /* { dg-warning "incompatible pointer type" } */
j = obj_p; /* { dg-warning "incompatible pointer type" } */
j = obj_c; /* { dg-warning "incompatible pointer type" } */
j = obj_C; /* { dg-warning "incompatible pointer type" } */
if (obj == i) ; /* { dg-warning "comparison between pointer and integer" } */
if (i == obj) ; /* { dg-warning "comparison between pointer and integer" } */
if (obj == j) ; /* { dg-warning "lacks a cast" } */
if (j == obj) ; /* { dg-warning "lacks a cast" } */
if (obj_c == i) ; /*{ dg-warning "comparison between pointer and integer" }*/
if (i == obj_c) ; /*{ dg-warning "comparison between pointer and integer" }*/
if (obj_c == j) ; /* { dg-warning "lacks a cast" } */
if (j == obj_c) ; /* { dg-warning "lacks a cast" } */
if (obj_p == i) ; /*{ dg-warning "comparison between pointer and integer" }*/
if (i == obj_p) ; /*{ dg-warning "comparison between pointer and integer" }*/
if (obj_p == j) ; /* { dg-warning "lacks a cast" } */
if (j == obj_p) ; /* { dg-warning "lacks a cast" } */
if (obj_C == i) ; /*{ dg-warning "comparison between pointer and integer" }*/
if (i == obj_C) ; /*{ dg-warning "comparison between pointer and integer" }*/
if (obj_C == j) ; /* { dg-warning "lacks a cast" } */
if (j == obj_C) ; /* { dg-warning "lacks a cast" } */
return 0;
}
/* Test assignments and comparisons involving `one-off' protocols. */
/* Author: Nicola Pero <nicola@brainstorm.co.uk>. */
/* { dg-do compile } */
#include <objc/objc.h>
@protocol MyProtocol
- (void) method;
@end
@interface MyClass
@end
int main()
{
id obj = nil;
id <MyProtocol> obj_p = nil;
MyClass<MyProtocol> *obj_cp = nil;
obj_cp = obj; /* Ok */
obj = obj_cp; /* Ok */
obj_cp = obj_p; /* { dg-warning "incompatible pointer type" } */
obj_p = obj_cp; /* Ok */ /* Spurious 2.95.4 warning here. */
if (obj_cp == obj) ; /* Ok */
if (obj == obj_cp) ; /* Ok */
if (obj_cp == obj_p) ; /* Ok */
if (obj_p == obj_cp) ; /* Ok */
return 0;
}
/* Test assignments and comparisons involving category protocols. */
/* Author: Nicola Pero <nicola@brainstorm.co.uk>. */
/* { dg-do compile } */
#include <objc/objc.h>
@protocol MyProtocol
- (void) method;
@end
@interface MyClass
@end
@interface MyClass (Addition) <MyProtocol>
- (void) method;
@end
@interface MyOtherClass : MyClass
@end
int main()
{
id <MyProtocol> obj_p = nil;
MyClass *obj_cp = nil;
MyOtherClass *obj_cp2 = nil;
obj_cp = obj_p; /* { dg-warning "incompatible pointer type" } */
obj_cp2 = obj_p; /* { dg-warning "incompatible pointer type" } */
obj_p = obj_cp; /* Ok */
obj_p = obj_cp2; /* Ok */
if (obj_cp == obj_p) ; /* Ok */
if (obj_cp2 == obj_p) ; /* Ok */
if (obj_p == obj_cp) ; /* Ok */
if (obj_p == obj_cp2) ; /* Ok */
return 0;
}