From a693d3a8f55ffcf432401f5890fa1a55fc86eaf1 Mon Sep 17 00:00:00 2001 From: Nicola Pero Date: Sat, 27 Nov 2010 09:53:43 +0000 Subject: [PATCH] In gcc/objc/: 2010-11-27 Nicola Pero In gcc/objc/: 2010-11-27 Nicola Pero * objc-act.c (objc_build_struct): Fixed loops that save and restore TYPE_OBJC_INFO to iterate over all variants of the type; a special case for the current type is then no longer required. Duplicate TYPE_LANG_SPECIFIC for each type before restoring TYPE_OBJC_INFO. (objc_get_protocol_qualified_type): Updated comments. In gcc/testsuite/: 2010-11-27 Nicola Pero * objc.dg/protocol-qualifier-1.m: New. * objc.dg/protocol-qualifier-2.m: New. * obj-c++.dg/protocol-qualifier-1.mm: New. * obj-c++.dg/protocol-qualifier-2.mm: New. From-SVN: r167195 --- gcc/objc/ChangeLog | 9 +++ gcc/objc/objc-act.c | 75 ++++++++++++------- gcc/testsuite/ChangeLog | 7 ++ .../obj-c++.dg/protocol-qualifier-1.mm | 33 ++++++++ .../obj-c++.dg/protocol-qualifier-2.mm | 31 ++++++++ gcc/testsuite/objc.dg/protocol-qualifier-1.m | 33 ++++++++ gcc/testsuite/objc.dg/protocol-qualifier-2.m | 31 ++++++++ 7 files changed, 191 insertions(+), 28 deletions(-) create mode 100644 gcc/testsuite/obj-c++.dg/protocol-qualifier-1.mm create mode 100644 gcc/testsuite/obj-c++.dg/protocol-qualifier-2.mm create mode 100644 gcc/testsuite/objc.dg/protocol-qualifier-1.m create mode 100644 gcc/testsuite/objc.dg/protocol-qualifier-2.m diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index fb1ee6a4de3..7c890ce7e2e 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,12 @@ +2010-11-27 Nicola Pero + + * objc-act.c (objc_build_struct): Fixed loops that save and + restore TYPE_OBJC_INFO to iterate over all variants of the type; a + special case for the current type is then no longer required. + Duplicate TYPE_LANG_SPECIFIC for each type before restoring + TYPE_OBJC_INFO. + (objc_get_protocol_qualified_type): Updated comments. + 2010-11-25 Nicola Pero * objc-act.c (objc_build_struct): Install TYPE_OBJC_INTERFACE diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 042fa359a4f..232708f6dbb 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -2137,41 +2137,54 @@ objc_build_struct (tree klass, tree fields, tree super_name) fields = base; } - /* NB: Calling finish_struct() may cause type TYPE_LANG_SPECIFIC - fields in all variants of this RECORD_TYPE to be clobbered (this - is because the C frontend stores a sorted version of the list of - fields in lang_type if it deems appropriate, and will update and - propagate that list to all variants ignoring the fact that we use - lang_type for something else and that such propagation will wipe - the objc_info away), but it is therein that we store protocol - conformance info (e.g., 'NSObject '). Hence, we must - squirrel away the ObjC-specific information before calling + /* NB: Calling finish_struct() may cause type TYPE_OBJC_INFO + information in all variants of this RECORD_TYPE to be destroyed + (this is because the C frontend manipulates TYPE_LANG_SPECIFIC + for something else and then will change all variants to use the + same resulting TYPE_LANG_SPECIFIC, ignoring the fact that we use + it for ObjC protocols and that such propagation will make all + variants use the same objc_info), but it is therein that we store + protocol conformance info (e.g., 'NSObject '). + Hence, we must save the ObjC-specific information before calling finish_struct(), and then reinstate it afterwards. */ - for (t = TYPE_NEXT_VARIANT (s); t; t = TYPE_NEXT_VARIANT (t)) + for (t = TYPE_MAIN_VARIANT (s); t; t = TYPE_NEXT_VARIANT (t)) { - if (!TYPE_HAS_OBJC_INFO (t)) - { - INIT_TYPE_OBJC_INFO (t); - TYPE_OBJC_INTERFACE (t) = klass; - } + INIT_TYPE_OBJC_INFO (t); VEC_safe_push (tree, heap, objc_info, TYPE_OBJC_INFO (t)); } s = objc_finish_struct (s, fields); - /* Point the struct at its related Objective-C class. We do this - after calling finish_struct() because otherwise finish_struct() - would wipe TYPE_OBJC_INTERFACE() out. */ - if (!TYPE_HAS_OBJC_INFO (s)) - INIT_TYPE_OBJC_INFO (s); - - TYPE_OBJC_INTERFACE (s) = klass; - - for (i = 0, t = TYPE_NEXT_VARIANT (s); t; t = TYPE_NEXT_VARIANT (t), i++) + for (i = 0, t = TYPE_MAIN_VARIANT (s); t; t = TYPE_NEXT_VARIANT (t), i++) { + /* We now want to restore the different TYPE_OBJC_INFO, but we + have the additional problem that the C frontend doesn't just + copy TYPE_LANG_SPECIFIC from one variant to the other; it + actually makes all of them the *same* TYPE_LANG_SPECIFIC. As + we need a different TYPE_OBJC_INFO for each (and + TYPE_OBJC_INFO is a field in TYPE_LANG_SPECIFIC), we need to + make a copy of each TYPE_LANG_SPECIFIC before we modify + TYPE_OBJC_INFO. */ + if (TYPE_LANG_SPECIFIC (t)) + { + /* Create a copy of TYPE_LANG_SPECIFIC. */ + struct lang_type *old_lang_type = TYPE_LANG_SPECIFIC (t); + ALLOC_OBJC_TYPE_LANG_SPECIFIC (t); + memcpy (TYPE_LANG_SPECIFIC (t), old_lang_type, + SIZEOF_OBJC_TYPE_LANG_SPECIFIC); + } + else + { + /* Just create a new one. */ + ALLOC_OBJC_TYPE_LANG_SPECIFIC (t); + } + /* Replace TYPE_OBJC_INFO with the saved one. This restores any + protocol information that may have been associated with the + type. */ TYPE_OBJC_INFO (t) = VEC_index (tree, objc_info, i); - /* Replace the IDENTIFIER_NODE with an actual @interface. */ + /* Replace the IDENTIFIER_NODE with an actual @interface now + that we have it. */ TYPE_OBJC_INTERFACE (t) = klass; } VEC_free (tree, heap, objc_info); @@ -2766,9 +2779,12 @@ objc_non_volatilized_type (tree type) return type; } -/* Construct a PROTOCOLS-qualified variant of INTERFACE, where INTERFACE may - either name an Objective-C class, or refer to the special 'id' or 'Class' - types. If INTERFACE is not a valid ObjC type, just return it unchanged. */ +/* Construct a PROTOCOLS-qualified variant of INTERFACE, where + INTERFACE may either name an Objective-C class, or refer to the + special 'id' or 'Class' types. If INTERFACE is not a valid ObjC + type, just return it unchanged. This function is often called when + PROTOCOLS is NULL_TREE, in which case we simply look up the + appropriate INTERFACE. */ tree objc_get_protocol_qualified_type (tree interface, tree protocols) @@ -4422,6 +4438,9 @@ objc_declare_class (tree ident_list) record = xref_tag (RECORD_TYPE, ident); INIT_TYPE_OBJC_INFO (record); + /* In the case of a @class declaration, we store the ident + in the TYPE_OBJC_INTERFACE. If later an @interface is + found, we'll replace the ident with the interface. */ TYPE_OBJC_INTERFACE (record) = ident; hash_class_name_enter (cls_name_hash_list, ident, NULL_TREE); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index bc402c4453f..d0b568a735e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2010-11-27 Nicola Pero + + * objc.dg/protocol-qualifier-1.m: New. + * objc.dg/protocol-qualifier-2.m: New. + * obj-c++.dg/protocol-qualifier-1.mm: New. + * obj-c++.dg/protocol-qualifier-2.mm: New. + 2010-11-26 Rainer Orth * lib/gnat.exp: Load gcc.exp. diff --git a/gcc/testsuite/obj-c++.dg/protocol-qualifier-1.mm b/gcc/testsuite/obj-c++.dg/protocol-qualifier-1.mm new file mode 100644 index 00000000000..c84bfbfa208 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/protocol-qualifier-1.mm @@ -0,0 +1,33 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +/* Test that protocol qualifiers work in the same way with @class and @interface. */ + +#include + +@protocol MyProtocol +- (void) method; +@end + + +/* This first snippet gives no warnings, which is correct as 'object' + implements and hence responds to 'method'. Note how + the details of the class 'MyClass' are never used. */ +@interface MyClass +@end + +void test (MyClass *object) +{ + [object method]; +} + + +/* This second snippet should behave identically. 'object' still implements + the same protocol and responds to 'method'. The details of MyClass or + MyClass2 are irrelevant. */ +@class MyClass2; + +void test2 (MyClass2 *object) +{ + [object method]; +} diff --git a/gcc/testsuite/obj-c++.dg/protocol-qualifier-2.mm b/gcc/testsuite/obj-c++.dg/protocol-qualifier-2.mm new file mode 100644 index 00000000000..fd25d8ff606 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/protocol-qualifier-2.mm @@ -0,0 +1,31 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +/* Test that protocol qualifiers are maintained correctly when a + @class is replaced by its @interface. */ + +#include + +@protocol MyProtocol +- (void) method; +@end + +@class MyClass; + +static MyClass *object1; +static MyClass *object2; + +/* Declarating the @interface now will need to update all the existing + ObjC types referring to MyClass with the new information. We need + to test that protocol information is not lost in the process. */ +@interface MyClass +@end + +void test1 (void) +{ + [object1 method]; /* Ok */ + [object2 method]; /* { dg-warning ".MyClass. may not respond to ..method." } */ + /* { dg-warning "without a matching method" "" { target *-*-* } 27 } */ + /* { dg-warning "will be assumed to return" "" { target *-*-* } 27 } */ + /* { dg-warning "as arguments" "" { target *-*-* } 27 } */ +} diff --git a/gcc/testsuite/objc.dg/protocol-qualifier-1.m b/gcc/testsuite/objc.dg/protocol-qualifier-1.m new file mode 100644 index 00000000000..c84bfbfa208 --- /dev/null +++ b/gcc/testsuite/objc.dg/protocol-qualifier-1.m @@ -0,0 +1,33 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +/* Test that protocol qualifiers work in the same way with @class and @interface. */ + +#include + +@protocol MyProtocol +- (void) method; +@end + + +/* This first snippet gives no warnings, which is correct as 'object' + implements and hence responds to 'method'. Note how + the details of the class 'MyClass' are never used. */ +@interface MyClass +@end + +void test (MyClass *object) +{ + [object method]; +} + + +/* This second snippet should behave identically. 'object' still implements + the same protocol and responds to 'method'. The details of MyClass or + MyClass2 are irrelevant. */ +@class MyClass2; + +void test2 (MyClass2 *object) +{ + [object method]; +} diff --git a/gcc/testsuite/objc.dg/protocol-qualifier-2.m b/gcc/testsuite/objc.dg/protocol-qualifier-2.m new file mode 100644 index 00000000000..fd25d8ff606 --- /dev/null +++ b/gcc/testsuite/objc.dg/protocol-qualifier-2.m @@ -0,0 +1,31 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +/* Test that protocol qualifiers are maintained correctly when a + @class is replaced by its @interface. */ + +#include + +@protocol MyProtocol +- (void) method; +@end + +@class MyClass; + +static MyClass *object1; +static MyClass *object2; + +/* Declarating the @interface now will need to update all the existing + ObjC types referring to MyClass with the new information. We need + to test that protocol information is not lost in the process. */ +@interface MyClass +@end + +void test1 (void) +{ + [object1 method]; /* Ok */ + [object2 method]; /* { dg-warning ".MyClass. may not respond to ..method." } */ + /* { dg-warning "without a matching method" "" { target *-*-* } 27 } */ + /* { dg-warning "will be assumed to return" "" { target *-*-* } 27 } */ + /* { dg-warning "as arguments" "" { target *-*-* } 27 } */ +}