diff options
19 files changed, 577 insertions, 19 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index cb5b5dc..b2c9011 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2010-11-01 Nicola Pero <nicola.pero@meta-innovation.com> + + Implemented format and noreturn attributes for Objective-C methods. + * c-common.c (handle_noreturn_attribute): Recognize 'noreturn' + attribute for Objective-C methods. + 2010-10-31 Jason Merrill <jason@redhat.com> * c-common.c (conversion_warning, warn_for_collisions_1): Use diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 923c63a..ab050ab 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -5729,7 +5729,8 @@ handle_noreturn_attribute (tree *node, tree name, tree ARG_UNUSED (args), tree type = TREE_TYPE (*node); /* See FIXME comment in c_common_attribute_table. */ - if (TREE_CODE (*node) == FUNCTION_DECL) + if (TREE_CODE (*node) == FUNCTION_DECL + || objc_method_decl (TREE_CODE (*node))) TREE_THIS_VOLATILE (*node) = 1; else if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index 1e61291..e9e5592 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,5 +1,21 @@ 2010-11-01 Nicola Pero <nicola.pero@meta-innovation.com> + Implemented format and noreturn attributes for Objective-C methods. + * objc-act.c (objc_start_method_definition): If method attributes + are specified emit a warning and ignore them. + (build_objc_method_call): Moved deprecation warnings from here ... + (objc_finish_message_expr): to here. Do not emit deprecation + warnings if the receiver is of type 'id'. + (really_start_method): Install 'deprecation' and 'noreturn' + attributes. + (objc_decl_method_attributes): Carefully filter out the list of + attributes, allowing only "noreturn", "format", "sentinel" and + "deprecated". In the case of "format", adjust the arguments. + Always process the attributes in the same way no matter if + "sentinel" is in the list or not. + +2010-11-01 Nicola Pero <nicola.pero@meta-innovation.com> + * objc-act.c (objc_maybe_build_component_ref): Warn about using deprecated properties. (objc_maybe_printable_name): Support PROPERTY_DECL. diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 68639ce..768215e 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -1261,7 +1261,11 @@ objc_start_method_definition (bool is_class_method, tree decl, tree attributes) c_break_label = c_cont_label = size_zero_node; #endif - objc_decl_method_attributes (&decl, attributes, 0); + if (attributes) + warning_at (input_location, 0, "method attributes can not be specified in @implementation context"); + else + objc_decl_method_attributes (&decl, attributes, 0); + objc_add_method (objc_implementation_context, decl, is_class_method, @@ -6598,6 +6602,11 @@ build_method_decl (enum tree_code code, tree ret_type, tree selector, /* If no type is specified, default to "id". */ ret_type = adjust_type_for_id_default (ret_type); + /* Note how a method_decl has a TREE_TYPE which is not the function + type of the function implementing the method, but only the return + type of the method. We may want to change this, and store the + entire function type in there (eg, it may be used to simplify + dealing with attributes below). */ method_decl = make_node (code); TREE_TYPE (method_decl) = ret_type; @@ -6628,19 +6637,119 @@ build_method_decl (enum tree_code code, tree ret_type, tree selector, static void objc_decl_method_attributes (tree *node, tree attributes, int flags) { - tree sentinel_attr = lookup_attribute ("sentinel", attributes); - if (sentinel_attr) + /* TODO: Replace the hackery below. An idea would be to store the + full function type in the method declaration (for example in + TREE_TYPE) and then expose ObjC method declarations to c-family + and they could deal with them by simply treating them as + functions. */ + + /* Because of the dangers in the hackery below, we filter out any + attribute that we do not know about. For the ones we know about, + we know that they work with the hackery. For the other ones, + there is no guarantee, so we have to filter them out. */ + tree filtered_attributes = NULL_TREE; + + if (attributes) { - /* hackery to make an obj method look like a function type. */ - tree rettype = TREE_TYPE (*node); - TREE_TYPE (*node) = build_function_type (TREE_VALUE (rettype), - get_arg_type_list (*node, METHOD_REF, 0)); - decl_attributes (node, attributes, flags); + tree attribute; + for (attribute = attributes; attribute; attribute = TREE_CHAIN (attribute)) + { + tree name = TREE_PURPOSE (attribute); + + if (is_attribute_p ("deprecated", name) + || is_attribute_p ("sentinel", name) + || is_attribute_p ("noreturn", name)) + { + /* An attribute that we support; add it to the filtered + attributes. */ + filtered_attributes = chainon (filtered_attributes, + copy_node (attribute)); + } + else if (is_attribute_p ("format", name)) + { + /* "format" is special because before adding it to the + filtered attributes we need to adjust the specified + format by adding the hidden function parameters for + an Objective-C method (self, _cmd). */ + tree new_attribute = copy_node (attribute); + + /* Check the arguments specified with the attribute, and + modify them adding 2 for the two hidden arguments. + Note how this differs from C++; according to the + specs, C++ does not do it so you have to add the +1 + yourself. For Objective-C, instead, the compiler + adds the +2 for you. */ + + /* The attribute arguments have not been checked yet, so + we need to be careful as they could be missing or + invalid. If anything looks wrong, we skip the + process and the compiler will complain about it later + when it validates the attribute. */ + /* Check that we have at least three arguments. */ + if (TREE_VALUE (new_attribute) + && TREE_CHAIN (TREE_VALUE (new_attribute)) + && TREE_CHAIN (TREE_CHAIN (TREE_VALUE (new_attribute)))) + { + tree second_argument = TREE_CHAIN (TREE_VALUE (new_attribute)); + tree third_argument = TREE_CHAIN (second_argument); + tree number; + + /* This is the second argument, the "string-index", + which specifies the index of the format string + argument. Add 2. */ + number = TREE_VALUE (second_argument); + if (number + && TREE_CODE (number) == INTEGER_CST + && TREE_INT_CST_HIGH (number) == 0) + { + TREE_VALUE (second_argument) + = build_int_cst (integer_type_node, + TREE_INT_CST_LOW (number) + 2); + } + + /* This is the third argument, the "first-to-check", + which specifies the index of the first argument to + check. This could be 0, meaning it is not available, + in which case we don't need to add 2. Add 2 if not + 0. */ + number = TREE_VALUE (third_argument); + if (number + && TREE_CODE (number) == INTEGER_CST + && TREE_INT_CST_HIGH (number) == 0 + && TREE_INT_CST_LOW (number) != 0) + { + TREE_VALUE (third_argument) + = build_int_cst (integer_type_node, + TREE_INT_CST_LOW (number) + 2); + } + } + filtered_attributes = chainon (filtered_attributes, + new_attribute); + } + else + warning (OPT_Wattributes, "%qE attribute directive ignored", name); + } + } + + if (filtered_attributes) + { + /* This hackery changes the TREE_TYPE of the ObjC method + declaration to be a function type, so that decl_attributes + will treat the ObjC method as if it was a function. Some + attributes (sentinel, format) will be applied to the function + type, changing it in place; so after calling decl_attributes, + we extract the function type attributes and store them in + METHOD_TYPE_ATTRIBUTES. Some other attributes (noreturn, + deprecated) are applied directly to the method declaration + (by setting TREE_DEPRECATED and TREE_THIS_VOLATILE) so there + is nothing to do. */ + tree saved_type = TREE_TYPE (*node); + TREE_TYPE (*node) = build_function_type + (TREE_VALUE (saved_type), get_arg_type_list (*node, METHOD_REF, 0)); + decl_attributes (node, filtered_attributes, flags); METHOD_TYPE_ATTRIBUTES (*node) = TYPE_ATTRIBUTES (TREE_TYPE (*node)); - TREE_TYPE (*node) = rettype; + TREE_TYPE (*node) = saved_type; } - else - decl_attributes (node, attributes, flags); } bool @@ -7149,6 +7258,26 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params) warn_missing_methods = true; } } + else + { + /* Warn if the method is deprecated, but not if the receiver is + a generic 'id'. 'id' is used to cast an object to a generic + object of an unspecified class; in that case, we'll use + whatever method prototype we can find to get the method + argument and return types, but it is not appropriate to + produce deprecation warnings since we don't know the class + that the object will be of at runtime. The @interface(s) for + that class may not even be available to the compiler right + now, and it is perfectly possible that the method is marked + as non-deprecated in such @interface(s). + + In practice this makes sense since casting an object to 'id' + is often used precisely to turn off warnings associated with + the object being of a particular class. */ + if (TREE_DEPRECATED (method_prototype) && rtype != NULL_TREE) + warn_deprecated_use (method_prototype, NULL_TREE); + } + /* Save the selector name for printing error messages. */ current_objc_message_selector = sel_name; @@ -7209,14 +7338,12 @@ build_objc_method_call (location_t loc, int super_flag, tree method_prototype, tree method, t; if (method_prototype && METHOD_TYPE_ATTRIBUTES (method_prototype)) - ftype = build_type_attribute_variant ( - ftype, METHOD_TYPE_ATTRIBUTES (method_prototype)); + ftype = build_type_attribute_variant (ftype, + METHOD_TYPE_ATTRIBUTES + (method_prototype)); sender_cast = build_pointer_type (ftype); - if (method_prototype && TREE_DEPRECATED (method_prototype)) - warn_deprecated_use (method_prototype, NULL_TREE); - lookup_object = build_c_cast (loc, rcv_p, lookup_object); /* Use SAVE_EXPR to avoid evaluating the receiver twice. */ @@ -10636,6 +10763,20 @@ really_start_method (tree method, (type ? '-' : '+'), identifier_to_locale (gen_method_decl (proto))); } + else + { + /* If the method in the @interface was deprecated, mark + the implemented method as deprecated too. It should + never be used for messaging (when the deprecation + warnings are produced), but just in case. */ + if (TREE_DEPRECATED (proto)) + TREE_DEPRECATED (method) = 1; + + /* If the method in the @interface was marked as + 'noreturn', mark the function implementing the method + as 'noreturn' too. */ + TREE_THIS_VOLATILE (current_function_decl) = TREE_THIS_VOLATILE (proto); + } } else { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ccace6f..ea07278 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,23 @@ 2010-11-01 Nicola Pero <nicola.pero@meta-innovation.com> + Implemented format and noreturn attributes for Objective-C methods. + * objc.dg/attributes/method-attribute-2.m: Updated warnings. + * objc.dg/attributes/method-deprecated-1.m: New. + * objc.dg/attributes/method-deprecated-2.m: New. + * objc.dg/attributes/method-deprecated-3.m: New. + * objc.dg/attributes/method-noreturn-1.m: New. + * objc.dg/attributes/method-sentinel-1.m: New. + * objc.dg/attributes/method-format-1.m: New. + * obj-c++.dg/attributes/method-attribute-2.mm: Updated warnings. + * obj-c++.dg/attributes/method-deprecated-1.mm: New. + * obj-c++.dg/attributes/method-deprecated-2.mm: New. + * obj-c++.dg/attributes/method-deprecated-3.mm: New. + * obj-c++.dg/attributes/method-noreturn-1.mm: New. + * obj-c++.dg/attributes/method-sentinel-1.mm: New. + * obj-c++.dg/attributes/method-format-1.mm: New. + +2010-11-01 Nicola Pero <nicola.pero@meta-innovation.com> + * objc.dg/property/at-property-deprecated-1.m: New. * obj-c++.dg/property/at-property-deprecated-1.mm: New. diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-attribute-2.mm b/gcc/testsuite/obj-c++.dg/attributes/method-attribute-2.mm index f9a184c..4a56b3a 100644 --- a/gcc/testsuite/obj-c++.dg/attributes/method-attribute-2.mm +++ b/gcc/testsuite/obj-c++.dg/attributes/method-attribute-2.mm @@ -14,7 +14,7 @@ @end @implementation obj -- (int) depmth __attribute__((deprecated)) { return var; } +- (int) depmth __attribute__((deprecated)) { return var; } /* { dg-warning "method attributes can not be specified in @implementation context" } */ - (int) depmtharg:(int) iarg { return var + iarg ; } - (int) unusedarg:(int) __attribute__((unused)) uarg { return var; } - (int) depunusedarg:(int) __attribute__((unused)) uarg { return var; } diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-1.mm b/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-1.mm new file mode 100644 index 0000000..8343856 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-1.mm @@ -0,0 +1,33 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyClass +{ + Class isa; +} ++ (int) method; +- (int) method; ++ (int) deprecatedClassMethod __attribute__((deprecated)); +- (int) deprecatedInstanceMethod __attribute__((deprecated)); +@end + +/* Test that deprecation warnings are produced, but not if the + receiver is of type 'id'. */ +void foo (void) +{ + Class c; + id object; + MyClass *another_object; + + [c method]; + [object method]; + [c deprecatedClassMethod]; + [object deprecatedInstanceMethod]; + + [object method]; + [another_object method]; + [MyClass deprecatedClassMethod]; /* { dg-warning "is deprecated" } */ + [another_object deprecatedInstanceMethod]; /* { dg-warning "is deprecated" } */ +} diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-2.mm b/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-2.mm new file mode 100644 index 0000000..1e5d87f --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-2.mm @@ -0,0 +1,23 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyClass +{ + Class isa; +} ++ (int) deprecatedClassMethod: (id)firstObject, ... __attribute__((sentinel)) __attribute__((deprecated)); +- (int) deprecatedInstanceMethod: (id)firstobject, ... __attribute__((sentinel)) __attribute__((deprecated)); +@end + +/* Test that deprecation warnings are produced even if the method is + also marked with another attribute too (this is to test the + processing of multiple attributes). */ +void foo (void) +{ + MyClass *object = nil; + + [MyClass deprecatedClassMethod: object, nil]; /* { dg-warning "is deprecated" } */ + [object deprecatedInstanceMethod: object, nil]; /* { dg-warning "is deprecated" } */ +} diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-3.mm b/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-3.mm new file mode 100644 index 0000000..5c715a2 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-3.mm @@ -0,0 +1,21 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +/* Test that __attribute__ ((__deprecated__)) works as well as __attribute__ ((deprecated)). */ +@interface MyClass +{ + Class isa; +} ++ (int) deprecatedClassMethod: (id)firstObject, ... __attribute__((__deprecated__)); +- (int) deprecatedInstanceMethod: (id)firstobject, ... __attribute__((__deprecated__)); +@end + +void foo (void) +{ + MyClass *object = nil; + + [MyClass deprecatedClassMethod: object, nil]; /* { dg-warning "is deprecated" } */ + [object deprecatedInstanceMethod: object, nil]; /* { dg-warning "is deprecated" } */ +} diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-format-1.mm b/gcc/testsuite/obj-c++.dg/attributes/method-format-1.mm new file mode 100644 index 0000000..0a078ff --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/method-format-1.mm @@ -0,0 +1,43 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +#include <objc/objc.h> +#include <stdlib.h> + +@interface LogObject +{ + Class isa; +} ++ (void) log: (int)level message: (const char *) my_format, ... __attribute__ ((format (printf, 2, 3))); +- (void) log: (int)level message: (const char *) my_format, ... __attribute__ ((format (printf, 2, 3))); + ++ (void) debug: (const char *) my_format, ... __attribute__ ((format (printf, 1, 2))); +- (void) debug: (const char *) my_format, ... __attribute__ ((format (printf, 1, 2))); + +/* Just make sure a missing or invalid attribute won't crash the compiler. */ +- (void) log2: (int)level message: (const char *) my_format, ... __attribute__ ((format (printf, 2))); /* { dg-error "wrong" } */ ++ (void) debug2: (const char *) my_format, ... __attribute__ ((format (printf))); /* { dg-error "wrong" } */ +- (void) debug2: (const char *) my_format, ... __attribute__ ((format (printf))); /* { dg-error "wrong" } */ ++ (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "args to be formatted is not ..." } */ +- (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "args to be formatted is not ..." } */ +@end + +void test (LogObject *object) +{ + [object log: 2 message: "attribute only applies to variadic functions"]; + [object log: 2 message: "attribute %s only applies to variadic functions", "'format'"]; + [object log: 2 message: "attribute %s only applies to variadic functions"]; /* { dg-warning "too few arguments for format" } */ + + [object debug: "attribute only applies to variadic functions"]; + [object debug: "attribute %s only applies to variadic functions", "'format'"]; + [object debug: "attribute %s only applies to variadic functions"]; /* { dg-warning "too few arguments for format" } */ + + [LogObject log: 2 message: "attribute only applies to variadic functions"]; + [LogObject log: 2 message: "attribute %s only applies to variadic functions", "'format'"]; + [LogObject log: 2 message: "attribute %s only applies to variadic functions"]; /* { dg-warning "too few arguments for format" } */ + + [LogObject debug: "attribute only applies to variadic functions"]; + [LogObject debug: "attribute %s only applies to variadic functions", "'format'"]; + [LogObject debug: "attribute %s only applies to variadic functions"]; /* { dg-warning "too few arguments for format" } */ +} diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-noreturn-1.mm b/gcc/testsuite/obj-c++.dg/attributes/method-noreturn-1.mm new file mode 100644 index 0000000..af051a6 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/method-noreturn-1.mm @@ -0,0 +1,34 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> +#include <stdlib.h> + +@interface MyClass +{ + Class isa; +} ++ (id) method1 __attribute__ ((noreturn)); +- (id) method2 __attribute__ ((noreturn)); ++ (id) method3 __attribute__ ((noreturn)); +- (id) method4 __attribute__ ((noreturn)); +@end + +@implementation MyClass ++ (id) method1 +{ + return self; /* { dg-warning "function declared .noreturn. has a .return. statement" } */ +} /* { dg-warning ".noreturn. function does return" } */ +- (id) method2 +{ + return self; /* { dg-warning "function declared .noreturn. has a .return. statement" } */ +} /* { dg-warning ".noreturn. function does return" } */ ++ (id) method3 +{ + abort (); +} +- (id) method4 +{ + abort (); +} +@end diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-sentinel-1.mm b/gcc/testsuite/obj-c++.dg/attributes/method-sentinel-1.mm new file mode 100644 index 0000000..ecaa36c2 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/method-sentinel-1.mm @@ -0,0 +1,34 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +#include <objc/objc.h> +#include <stdlib.h> + +@interface NSArray +{ + Class isa; +} ++ (id) arrayWithObject: (id)object __attribute__ ((sentinel)); /* { dg-warning "attribute only applies to variadic functions" } */ ++ (id) arrayWithObjects: (id)firstObject, ... __attribute__ ((sentinel)); + +- (id) initWithObject: (id)object __attribute__ ((sentinel)); /* { dg-warning "attribute only applies to variadic functions" } */ +- (id) initWithObjects: (id)firstObject, ... __attribute__ ((sentinel)); +@end + +void test (id object) +{ + NSArray *array; + + array = [NSArray arrayWithObject: object]; + array = [NSArray arrayWithObjects: object, nil]; + array = [NSArray arrayWithObjects: object, object, nil]; + array = [NSArray arrayWithObjects: object]; /* { dg-warning "not enough variable arguments" } */ + array = [NSArray arrayWithObjects: object, object]; /* { dg-warning "missing sentinel" } */ + + [array initWithObject: object]; + [array initWithObjects: object, nil]; + [array initWithObjects: object, object, nil]; + [array initWithObjects: object]; /* { dg-warning "not enough variable arguments" } */ + [array initWithObjects: object, object]; /* { dg-warning "missing sentinel" } */ +} diff --git a/gcc/testsuite/objc.dg/attributes/method-attribute-2.m b/gcc/testsuite/objc.dg/attributes/method-attribute-2.m index f9a184c..4a56b3a 100644 --- a/gcc/testsuite/objc.dg/attributes/method-attribute-2.m +++ b/gcc/testsuite/objc.dg/attributes/method-attribute-2.m @@ -14,7 +14,7 @@ @end @implementation obj -- (int) depmth __attribute__((deprecated)) { return var; } +- (int) depmth __attribute__((deprecated)) { return var; } /* { dg-warning "method attributes can not be specified in @implementation context" } */ - (int) depmtharg:(int) iarg { return var + iarg ; } - (int) unusedarg:(int) __attribute__((unused)) uarg { return var; } - (int) depunusedarg:(int) __attribute__((unused)) uarg { return var; } diff --git a/gcc/testsuite/objc.dg/attributes/method-deprecated-1.m b/gcc/testsuite/objc.dg/attributes/method-deprecated-1.m new file mode 100644 index 0000000..8343856 --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/method-deprecated-1.m @@ -0,0 +1,33 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyClass +{ + Class isa; +} ++ (int) method; +- (int) method; ++ (int) deprecatedClassMethod __attribute__((deprecated)); +- (int) deprecatedInstanceMethod __attribute__((deprecated)); +@end + +/* Test that deprecation warnings are produced, but not if the + receiver is of type 'id'. */ +void foo (void) +{ + Class c; + id object; + MyClass *another_object; + + [c method]; + [object method]; + [c deprecatedClassMethod]; + [object deprecatedInstanceMethod]; + + [object method]; + [another_object method]; + [MyClass deprecatedClassMethod]; /* { dg-warning "is deprecated" } */ + [another_object deprecatedInstanceMethod]; /* { dg-warning "is deprecated" } */ +} diff --git a/gcc/testsuite/objc.dg/attributes/method-deprecated-2.m b/gcc/testsuite/objc.dg/attributes/method-deprecated-2.m new file mode 100644 index 0000000..1e5d87f --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/method-deprecated-2.m @@ -0,0 +1,23 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface MyClass +{ + Class isa; +} ++ (int) deprecatedClassMethod: (id)firstObject, ... __attribute__((sentinel)) __attribute__((deprecated)); +- (int) deprecatedInstanceMethod: (id)firstobject, ... __attribute__((sentinel)) __attribute__((deprecated)); +@end + +/* Test that deprecation warnings are produced even if the method is + also marked with another attribute too (this is to test the + processing of multiple attributes). */ +void foo (void) +{ + MyClass *object = nil; + + [MyClass deprecatedClassMethod: object, nil]; /* { dg-warning "is deprecated" } */ + [object deprecatedInstanceMethod: object, nil]; /* { dg-warning "is deprecated" } */ +} diff --git a/gcc/testsuite/objc.dg/attributes/method-deprecated-3.m b/gcc/testsuite/objc.dg/attributes/method-deprecated-3.m new file mode 100644 index 0000000..5c715a2 --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/method-deprecated-3.m @@ -0,0 +1,21 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +/* Test that __attribute__ ((__deprecated__)) works as well as __attribute__ ((deprecated)). */ +@interface MyClass +{ + Class isa; +} ++ (int) deprecatedClassMethod: (id)firstObject, ... __attribute__((__deprecated__)); +- (int) deprecatedInstanceMethod: (id)firstobject, ... __attribute__((__deprecated__)); +@end + +void foo (void) +{ + MyClass *object = nil; + + [MyClass deprecatedClassMethod: object, nil]; /* { dg-warning "is deprecated" } */ + [object deprecatedInstanceMethod: object, nil]; /* { dg-warning "is deprecated" } */ +} diff --git a/gcc/testsuite/objc.dg/attributes/method-format-1.m b/gcc/testsuite/objc.dg/attributes/method-format-1.m new file mode 100644 index 0000000..0a078ff --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/method-format-1.m @@ -0,0 +1,43 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +#include <objc/objc.h> +#include <stdlib.h> + +@interface LogObject +{ + Class isa; +} ++ (void) log: (int)level message: (const char *) my_format, ... __attribute__ ((format (printf, 2, 3))); +- (void) log: (int)level message: (const char *) my_format, ... __attribute__ ((format (printf, 2, 3))); + ++ (void) debug: (const char *) my_format, ... __attribute__ ((format (printf, 1, 2))); +- (void) debug: (const char *) my_format, ... __attribute__ ((format (printf, 1, 2))); + +/* Just make sure a missing or invalid attribute won't crash the compiler. */ +- (void) log2: (int)level message: (const char *) my_format, ... __attribute__ ((format (printf, 2))); /* { dg-error "wrong" } */ ++ (void) debug2: (const char *) my_format, ... __attribute__ ((format (printf))); /* { dg-error "wrong" } */ +- (void) debug2: (const char *) my_format, ... __attribute__ ((format (printf))); /* { dg-error "wrong" } */ ++ (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "args to be formatted is not ..." } */ +- (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "args to be formatted is not ..." } */ +@end + +void test (LogObject *object) +{ + [object log: 2 message: "attribute only applies to variadic functions"]; + [object log: 2 message: "attribute %s only applies to variadic functions", "'format'"]; + [object log: 2 message: "attribute %s only applies to variadic functions"]; /* { dg-warning "too few arguments for format" } */ + + [object debug: "attribute only applies to variadic functions"]; + [object debug: "attribute %s only applies to variadic functions", "'format'"]; + [object debug: "attribute %s only applies to variadic functions"]; /* { dg-warning "too few arguments for format" } */ + + [LogObject log: 2 message: "attribute only applies to variadic functions"]; + [LogObject log: 2 message: "attribute %s only applies to variadic functions", "'format'"]; + [LogObject log: 2 message: "attribute %s only applies to variadic functions"]; /* { dg-warning "too few arguments for format" } */ + + [LogObject debug: "attribute only applies to variadic functions"]; + [LogObject debug: "attribute %s only applies to variadic functions", "'format'"]; + [LogObject debug: "attribute %s only applies to variadic functions"]; /* { dg-warning "too few arguments for format" } */ +} diff --git a/gcc/testsuite/objc.dg/attributes/method-noreturn-1.m b/gcc/testsuite/objc.dg/attributes/method-noreturn-1.m new file mode 100644 index 0000000..af051a6 --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/method-noreturn-1.m @@ -0,0 +1,34 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ + +#include <objc/objc.h> +#include <stdlib.h> + +@interface MyClass +{ + Class isa; +} ++ (id) method1 __attribute__ ((noreturn)); +- (id) method2 __attribute__ ((noreturn)); ++ (id) method3 __attribute__ ((noreturn)); +- (id) method4 __attribute__ ((noreturn)); +@end + +@implementation MyClass ++ (id) method1 +{ + return self; /* { dg-warning "function declared .noreturn. has a .return. statement" } */ +} /* { dg-warning ".noreturn. function does return" } */ +- (id) method2 +{ + return self; /* { dg-warning "function declared .noreturn. has a .return. statement" } */ +} /* { dg-warning ".noreturn. function does return" } */ ++ (id) method3 +{ + abort (); +} +- (id) method4 +{ + abort (); +} +@end diff --git a/gcc/testsuite/objc.dg/attributes/method-sentinel-1.m b/gcc/testsuite/objc.dg/attributes/method-sentinel-1.m new file mode 100644 index 0000000..ecaa36c2 --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/method-sentinel-1.m @@ -0,0 +1,34 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +#include <objc/objc.h> +#include <stdlib.h> + +@interface NSArray +{ + Class isa; +} ++ (id) arrayWithObject: (id)object __attribute__ ((sentinel)); /* { dg-warning "attribute only applies to variadic functions" } */ ++ (id) arrayWithObjects: (id)firstObject, ... __attribute__ ((sentinel)); + +- (id) initWithObject: (id)object __attribute__ ((sentinel)); /* { dg-warning "attribute only applies to variadic functions" } */ +- (id) initWithObjects: (id)firstObject, ... __attribute__ ((sentinel)); +@end + +void test (id object) +{ + NSArray *array; + + array = [NSArray arrayWithObject: object]; + array = [NSArray arrayWithObjects: object, nil]; + array = [NSArray arrayWithObjects: object, object, nil]; + array = [NSArray arrayWithObjects: object]; /* { dg-warning "not enough variable arguments" } */ + array = [NSArray arrayWithObjects: object, object]; /* { dg-warning "missing sentinel" } */ + + [array initWithObject: object]; + [array initWithObjects: object, nil]; + [array initWithObjects: object, object, nil]; + [array initWithObjects: object]; /* { dg-warning "not enough variable arguments" } */ + [array initWithObjects: object, object]; /* { dg-warning "missing sentinel" } */ +} |