diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index 43ef65d6ec9..3edb54edb82 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,10 @@ +2010-12-30 Nicola Pero + + * objc-act.c (objc_types_are_equivalent): Fixed comparing protocol + lists. Check them two-ways to fix comparisons when one protocol + implements the other one, or when one list contains duplicated + protocols. + 2010-12-30 Nicola Pero * objc-act.c (objc_add_method): When emitting an error because a diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index ec7fea59dd3..a37f3d91457 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -11925,9 +11925,8 @@ start_method_def (tree method) really_start_method (objc_method_context, parm_info); } -/* Return 1 if TYPE1 is equivalent to TYPE2 - for purposes of method overloading. */ - +/* Return 1 if TYPE1 is equivalent to TYPE2 for purposes of method + overloading. */ static int objc_types_are_equivalent (tree type1, tree type2) { @@ -11941,6 +11940,7 @@ objc_types_are_equivalent (tree type1, tree type2) if (TYPE_MAIN_VARIANT (type1) != TYPE_MAIN_VARIANT (type2)) return 0; + /* Compare the protocol lists. */ type1 = (TYPE_HAS_OBJC_INFO (type1) ? TYPE_OBJC_PROTOCOL_LIST (type1) : NULL_TREE); @@ -11948,14 +11948,34 @@ objc_types_are_equivalent (tree type1, tree type2) ? TYPE_OBJC_PROTOCOL_LIST (type2) : NULL_TREE); - if (list_length (type1) == list_length (type2)) + /* If there are no protocols (most common case), the types are + identical. */ + if (type1 == NULL_TREE && type2 == NULL_TREE) + return 1; + + /* If one has protocols, and the other one hasn't, they are not + identical. */ + if ((type1 == NULL_TREE && type2 != NULL_TREE) + || (type1 != NULL_TREE && type2 == NULL_TREE)) + return 0; + else { - for (; type2; type2 = TREE_CHAIN (type2)) - if (!lookup_protocol_in_reflist (type1, TREE_VALUE (type2))) + /* Else, both have protocols, and we need to do the full + comparison. It is possible that either type1 or type2 + contain some duplicate protocols in the list, so we can't + even just compare list_length as a first check. */ + tree t; + + for (t = type2; t; t = TREE_CHAIN (t)) + if (!lookup_protocol_in_reflist (type1, TREE_VALUE (t))) return 0; + + for (t = type1; t; t = TREE_CHAIN (t)) + if (!lookup_protocol_in_reflist (type2, TREE_VALUE (t))) + return 0; + return 1; } - return 0; } /* Return 1 if TYPE1 has the same size and alignment as TYPE2. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 681c27ef679..26bcf8c83b2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2010-12-30 Nicola Pero + + * objc.dg/method-conflict-3.m: New. + * objc.dg/method-conflict-4.m: New. + * obj-c++.dg/method-conflict-3.m: New. + * obj-c++.dg/method-conflict-4.mm: New. + 2010-12-30 Nicola Pero * objc.dg/class-extension-3.m: Updated. diff --git a/gcc/testsuite/obj-c++.dg/method-conflict-3.mm b/gcc/testsuite/obj-c++.dg/method-conflict-3.mm new file mode 100644 index 00000000000..d4b6fbfd526 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-conflict-3.mm @@ -0,0 +1,65 @@ +/* Contributed by Nicola Pero , December 2010. */ +/* { dg-do compile } */ + +#include + +/* Test that the compiler can correctly compare protocols in types of + method signatures. */ + +@protocol A, B, C; + +@interface MyClass +- (void) method1: (id)x; +- (void) method1: (id)x; /* Ok */ + +- (void) method2: (id )x; +- (void) method2: (id )x; /* Ok */ + +- (void) method3: (id )x; +- (void) method3: (id )x; /* Ok */ + +- (void) method4: (id )x; +- (void) method4: (id )x; /* Ok */ + +- (void) method5: (id )x; +- (void) method5: (id )x; /* Ok */ + +- (void) method6: (id )x; +- (void) method6: (id )x; /* Ok */ + +- (void) method7: (id)x; /* { dg-warning "previous declaration" } */ +- (void) method7: (id )x; /* { dg-error "duplicate declaration" } */ + +- (void) method8: (id )x; /* { dg-warning "previous declaration" } */ +- (void) method8: (id)x; /* { dg-error "duplicate declaration" } */ + +- (void) method9: (id )x; /* { dg-warning "previous declaration" } */ +- (void) method9: (id )x; /* { dg-error "duplicate declaration" } */ + +- (void) methodA: (id )x; /* { dg-warning "previous declaration" } */ +- (void) methodA: (id )x; /* { dg-error "duplicate declaration" } */ + +/* FIXME: Bug in the testsuite - the following are done Ok by the compiler, but + the testsuite barfs so we have to comment out the tests. */ +/* - (void) methodB: (id )x; dg-warning "previous declaration" */ +/* - (void) methodB: (id )x; dg-error "duplicate declaration" */ + +/* - (void) methodC: (id )x; dg-warning "previous declaration" */ +/* - (void) methodC: (id )x; dg-error "duplicate declaration" */ + +/* - (void) methodD: (id )x; dg-warning "previous declaration" */ +/* - (void) methodD: (id )x; dg-error "duplicate declaration" */ + +/* - (void) methodE: (MyClass *)x; dg-warning "previous declaration" */ +/* - (void) methodE: (MyClass *)x; dg-error "duplicate declaration" */ + +- (void) methodF: (MyClass *)x; +- (void) methodF: (MyClass *)x; /* Ok */ + +/* - (void) methodG: (MyClass *)x; dg-warning "previous declaration" */ +/* - (void) methodG: (MyClass *)x; dg-error "duplicate declaration" */ + +/* - (void) methodH: (MyClass *)x; dg-warning "previous declaration" */ +/* - (void) methodH: (MyClass *)x; dg-error "duplicate declaration" */ + +@end diff --git a/gcc/testsuite/obj-c++.dg/method-conflict-4.mm b/gcc/testsuite/obj-c++.dg/method-conflict-4.mm new file mode 100644 index 00000000000..103134116e2 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/method-conflict-4.mm @@ -0,0 +1,48 @@ +/* Contributed by Nicola Pero , December 2010. */ +/* { dg-do compile } */ + +#include + +/* Test that the compiler can correctly compare protocols in types of + method signatures. In this test we look at protocols implementing + other protocols. The fact that one protocol implements another one + doesn't mean that they are identical. */ + +@protocol A +- (void) doSomething; +@end + +@protocol B +- (void) doSomethingElse; +@end + +@protocol C +- (void) doYetSomethingElse; +@end + +@interface MyClass2 +- (void) aMethod: (id )x; /* { dg-error "previous declaration" } */ +- (void) aMethod: (id )x; /* { dg-error "duplicate declaration" } */ + +- (void) bMethod: (id )x; /* { dg-error "previous declaration" } */ +- (void) bMethod: (id )x; /* { dg-error "duplicate declaration" } */ + +- (void) cMethod: (id )x; +- (void) cMethod: (id )x; /* Ok - because if you implement B, then you also implement A, so == */ + +- (void) dMethod: (id )x; +- (void) dMethod: (id )x; /* Ok */ + +/* FIXME: The compiler works, but the testsuite produces errors anyway. */ +/* - (void) eMethod: (id )x; dg-error "previous declaration" */ +/* - (void) eMethod: (id )x; dg-error "duplicate declaration" */ + +/*- (void) fMethod: (id )x; dg-error "previous declaration" */ +/*- (void) fMethod: (id )x; dg-error "duplicate declaration" */ + +/* - (void) gMethod: (id )x; dg-error "previous declaration" */ +/* - (void) gMethod: (id )x; dg-error "duplicate declaration" */ + +/* - (void) hMethod: (id )x; dg-error "previous declaration" */ +/* - (void) hMethod: (id )x; dg-error "duplicate declaration" */ +@end diff --git a/gcc/testsuite/objc.dg/method-conflict-3.m b/gcc/testsuite/objc.dg/method-conflict-3.m new file mode 100644 index 00000000000..cc4d2631fa2 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-conflict-3.m @@ -0,0 +1,63 @@ +/* Contributed by Nicola Pero , December 2010. */ +/* { dg-do compile } */ + +#include + +/* Test that the compiler can correctly compare protocols in types of + method signatures. */ + +@protocol A, B, C; + +@interface MyClass +- (void) method1: (id)x; +- (void) method1: (id)x; /* Ok */ + +- (void) method2: (id )x; +- (void) method2: (id )x; /* Ok */ + +- (void) method3: (id )x; +- (void) method3: (id )x; /* Ok */ + +- (void) method4: (id )x; +- (void) method4: (id )x; /* Ok */ + +- (void) method5: (id )x; +- (void) method5: (id )x; /* Ok */ + +- (void) method6: (id )x; +- (void) method6: (id )x; /* Ok */ + +- (void) method7: (id)x; /* { dg-message "previous declaration" } */ +- (void) method7: (id )x; /* { dg-error "duplicate declaration" } */ + +- (void) method8: (id )x; /* { dg-message "previous declaration" } */ +- (void) method8: (id)x; /* { dg-error "duplicate declaration" } */ + +- (void) method9: (id )x; /* { dg-message "previous declaration" } */ +- (void) method9: (id )x; /* { dg-error "duplicate declaration" } */ + +- (void) methodA: (id )x; /* { dg-message "previous declaration" } */ +- (void) methodA: (id )x; /* { dg-error "duplicate declaration" } */ + +- (void) methodB: (id )x; /* { dg-message "previous declaration" } */ +- (void) methodB: (id )x; /* { dg-error "duplicate declaration" } */ + +- (void) methodC: (id )x; /* { dg-message "previous declaration" } */ +- (void) methodC: (id )x; /* { dg-error "duplicate declaration" } */ + +- (void) methodD: (id )x; /* { dg-message "previous declaration" } */ +- (void) methodD: (id )x; /* { dg-error "duplicate declaration" } */ + +- (void) methodE: (MyClass *)x; /* { dg-message "previous declaration" } */ +- (void) methodE: (MyClass *)x; /* { dg-error "duplicate declaration" } */ + +- (void) methodF: (MyClass *)x; +- (void) methodF: (MyClass *)x; /* Ok */ + +- (void) methodG: (MyClass *)x; /* { dg-message "previous declaration" } */ +- (void) methodG: (MyClass *)x; /* { dg-error "duplicate declaration" } */ + +- (void) methodH: (MyClass *)x; /* { dg-message "previous declaration" } */ +- (void) methodH: (MyClass *)x; /* { dg-error "duplicate declaration" } */ + +@end diff --git a/gcc/testsuite/objc.dg/method-conflict-4.m b/gcc/testsuite/objc.dg/method-conflict-4.m new file mode 100644 index 00000000000..a0c278294d8 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-conflict-4.m @@ -0,0 +1,47 @@ +/* Contributed by Nicola Pero , December 2010. */ +/* { dg-do compile } */ + +#include + +/* Test that the compiler can correctly compare protocols in types of + method signatures. In this test we look at protocols implementing + other protocols. The fact that one protocol implements another one + doesn't mean that they are identical. */ + +@protocol A +- (void) doSomething; +@end + +@protocol B +- (void) doSomethingElse; +@end + +@protocol C +- (void) doYetSomethingElse; +@end + +@interface MyClass2 +- (void) aMethod: (id )x; /* { dg-message "previous declaration" } */ +- (void) aMethod: (id )x; /* { dg-error "duplicate declaration" } */ + +- (void) bMethod: (id )x; /* { dg-message "previous declaration" } */ +- (void) bMethod: (id )x; /* { dg-error "duplicate declaration" } */ + +- (void) cMethod: (id )x; +- (void) cMethod: (id )x; /* Ok - because if you implement B, then you also implement A, so == */ + +- (void) dMethod: (id )x; +- (void) dMethod: (id )x; /* Ok */ + +- (void) eMethod: (id )x; /* { dg-message "previous declaration" } */ +- (void) eMethod: (id )x; /* { dg-error "duplicate declaration" } */ + +- (void) fMethod: (id )x; /* { dg-message "previous declaration" } */ +- (void) fMethod: (id )x; /* { dg-error "duplicate declaration" } */ + +- (void) gMethod: (id )x; /* { dg-message "previous declaration" } */ +- (void) gMethod: (id )x; /* { dg-error "duplicate declaration" } */ + +- (void) hMethod: (id )x; /* { dg-message "previous declaration" } */ +- (void) hMethod: (id )x; /* { dg-error "duplicate declaration" } */ +@end