Fixed ObjC typechecking, particularly case with protocols
From-SVN: r57250
This commit is contained in:
parent
256e9fd21a
commit
1074d9d492
3 changed files with 221 additions and 48 deletions
|
@ -1,3 +1,13 @@
|
|||
Tue Sep 17 13:58:04 2002 Nicola Pero <n.pero@mi.flashnet.it>
|
||||
|
||||
Fix PR/7014 and related objc 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.
|
||||
|
||||
2002-09-17 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
* machmode.def (V1DImode): New mode. A single element vector.
|
||||
|
|
|
@ -51,7 +51,7 @@ static int missing_braces_mentioned;
|
|||
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 @@ comptypes (type1, type2)
|
|||
}
|
||||
|
||||
/* 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 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
|
|||
/* 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 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
|
|||
/* 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 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
|
|||
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 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
|
|||
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 @@ build_conditional_expr (ifexp, op1, op2)
|
|||
}
|
||||
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,8 +4015,9 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
|
|||
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. No need to
|
||||
use the return value. */
|
||||
if (flag_objc)
|
||||
objc_comptypes (type, rhstype, 0);
|
||||
return rhs;
|
||||
|
@ -4086,7 +4092,7 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
|
|||
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 +4167,7 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
|
|||
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 +4192,7 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
|
|||
/* 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)
|
||||
|
|
|
@ -587,10 +587,24 @@ lookup_protocol_in_reflist (rproto_list, lproto)
|
|||
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 @@ objc_comptypes (lhs, rhs, reflexive)
|
|||
{
|
||||
/* 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,29 +630,75 @@ objc_comptypes (lhs, rhs, reflexive)
|
|||
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);
|
||||
/* 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)));
|
||||
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);
|
||||
|
@ -651,7 +713,7 @@ objc_comptypes (lhs, rhs, reflexive)
|
|||
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,7 +727,6 @@ objc_comptypes (lhs, rhs, reflexive)
|
|||
{
|
||||
rproto_list = CLASS_PROTOCOL_LIST (cat);
|
||||
rproto = lookup_protocol_in_reflist (rproto_list, p);
|
||||
|
||||
cat = CLASS_CATEGORY_LIST (cat);
|
||||
}
|
||||
|
||||
|
@ -674,31 +735,127 @@ objc_comptypes (lhs, rhs, reflexive)
|
|||
|
||||
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 @@ objc_comptypes (lhs, rhs, reflexive)
|
|||
return 0;
|
||||
}
|
||||
else
|
||||
/* Defer to comptypes. */
|
||||
/* Not an ObjC type - let comptypes do the check. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue