diff options
author | Nicola Pero <n.pero@mi.flashnet.it> | 2002-09-17 15:59:30 +0200 |
---|---|---|
committer | Nicola Pero <nicola@gcc.gnu.org> | 2002-09-17 13:59:30 +0000 |
commit | 1074d9d4926fe3c5302527fb8a1e152d532ec13a (patch) | |
tree | 23ab0a5793dddd08ab57f35855174dd146bea0f9 /gcc | |
parent | 256e9fd21abe2cbebfb52396a47ecfd06412d144 (diff) | |
download | gcc-1074d9d4926fe3c5302527fb8a1e152d532ec13a.tar.gz |
Fixed ObjC typechecking, particularly case with protocols
From-SVN: r57250
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/c-typeck.c | 34 | ||||
-rw-r--r-- | gcc/objc/objc-act.c | 225 |
3 files changed, 221 insertions, 48 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a7a68f494fe..da1aed19f34 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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. diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 4c6c8bacdf8..3595cff496c 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -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) diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 42861685b11..3b5b75c7e7a 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -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; } |