From patchwork Sun Oct 31 17:42:40 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicola Pero X-Patchwork-Id: 69727 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 15A3FB70D4 for ; Mon, 1 Nov 2010 04:43:07 +1100 (EST) Received: (qmail 21215 invoked by alias); 31 Oct 2010 17:43:04 -0000 Received: (qmail 21161 invoked by uid 22791); 31 Oct 2010 17:43:00 -0000 X-SWARE-Spam-Status: No, hits=-1.3 required=5.0 tests=AWL, BAYES_00, TW_BJ, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from fencepost.gnu.org (HELO fencepost.gnu.org) (140.186.70.10) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sun, 31 Oct 2010 17:42:52 +0000 Received: from eggs.gnu.org ([140.186.70.92]:35888) by fencepost.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from ) id 1PCbvd-00042i-8X for gcc-patches@gnu.org; Sun, 31 Oct 2010 13:42:49 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PCbvX-0006jo-9t for gcc-patches@gnu.org; Sun, 31 Oct 2010 13:42:49 -0400 Received: from smtp141.iad.emailsrvr.com ([207.97.245.141]:36226) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PCbvX-0006jV-4R for gcc-patches@gnu.org; Sun, 31 Oct 2010 13:42:43 -0400 Received: from localhost (localhost.localdomain [127.0.0.1]) by smtp44.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id 60C58128264 for ; Sun, 31 Oct 2010 13:42:40 -0400 (EDT) Received: from dynamic6.wm-web.iad.mlsrvr.com (dynamic6.wm-web.iad1a.rsapps.net [192.168.2.147]) by smtp44.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id 4D1C41281BA for ; Sun, 31 Oct 2010 13:42:40 -0400 (EDT) Received: from meta-innovation.com (localhost [127.0.0.1]) by dynamic6.wm-web.iad.mlsrvr.com (Postfix) with ESMTP id 39CCF3F0054 for ; Sun, 31 Oct 2010 13:42:40 -0400 (EDT) Received: by www2.webmail.us (Authenticated sender: nicola.pero@meta-innovation.com, from: nicola.pero@meta-innovation.com) with HTTP; Sun, 31 Oct 2010 18:42:40 +0100 (CET) Date: Sun, 31 Oct 2010 18:42:40 +0100 (CET) Subject: ObjC/ObjC++ - finish off method attributes From: "Nicola Pero" To: "gcc-patches@gnu.org" MIME-Version: 1.0 X-Type: plain Message-ID: <1288546960.234428318@192.168.2.229> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This patch implements the "format" and "noreturn" method attributes for Objective-C and Objective-C++ methods. It also fixes some warnings for "deprecated" attributes and adds testcases for all the method attributes that we now support (deprecated, format, noreturn and sentinel). Ok to commit to trunk ? Thanks In gcc/c-family/: 2010-10-31 Nicola Pero Implemented format and noreturn attributes for Objective-C methods. * c-common.c (handle_noreturn_attribute): Recognize 'noreturn' attribute for Objective-C methods. In gcc/objc/: 2010-10-31 Nicola Pero 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. In gcc/testsuite/: 2010-10-31 Nicola Pero 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-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-noreturn-1.mm: New. * obj-c++.dg/attributes/method-sentinel-1.mm: New. * obj-c++.dg/attributes/method-format-1.mm: New. Index: c-family/ChangeLog =================================================================== --- c-family/ChangeLog (revision 166103) +++ c-family/ChangeLog (working copy) @@ -1,3 +1,9 @@ +2010-10-31 Nicola Pero + + Implemented format and noreturn attributes for Objective-C methods. + * c-common.c (handle_noreturn_attribute): Recognize 'noreturn' + attribute for Objective-C methods. + 2010-10-30 Nicola Pero Implemented Objective-C 2.0 @property, @synthesize and @dynamic. Index: c-family/c-common.c =================================================================== --- c-family/c-common.c (revision 166103) +++ c-family/c-common.c (working copy) @@ -5731,7 +5731,8 @@ handle_noreturn_attribute (tree *node, tree name, 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) Index: objc/objc-act.c =================================================================== --- objc/objc-act.c (revision 166103) +++ objc/objc-act.c (working copy) @@ -1257,7 +1257,11 @@ objc_start_method_definition (bool is_class_method 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, @@ -6590,6 +6594,11 @@ build_method_decl (enum tree_code code, tree ret_t /* 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; @@ -6620,19 +6629,119 @@ build_method_decl (enum tree_code code, tree ret_t 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)) + { + const char *name = IDENTIFIER_POINTER (TREE_PURPOSE (attribute)); + + if (strcmp (name, "deprecated") == 0 + || strcmp (name, "sentinel") == 0 + || strcmp (name, "noreturn") == 0) + { + /* An attribute that we support; add it to the filtered + attributes. */ + filtered_attributes = chainon (filtered_attributes, + copy_node (attribute)); + } + else if (strcmp (name, "format") == 0) + { + /* "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, "%qs 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 @@ -7141,7 +7250,27 @@ objc_finish_message_expr (tree receiver, tree sel_ 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; @@ -7201,14 +7330,12 @@ build_objc_method_call (location_t loc, int super_ 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. */ @@ -10282,6 +10409,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 { Index: objc/ChangeLog =================================================================== --- objc/ChangeLog (revision 166103) +++ objc/ChangeLog (working copy) @@ -1,3 +1,19 @@ +2010-10-31 Nicola Pero + + 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-10-30 Nicola Pero Implemented Objective-C 2.0 @property, @synthesize and @dynamic. Index: testsuite/ChangeLog =================================================================== --- testsuite/ChangeLog (revision 166103) +++ testsuite/ChangeLog (working copy) @@ -1,3 +1,19 @@ +2010-10-31 Nicola Pero + + 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-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-noreturn-1.mm: New. + * obj-c++.dg/attributes/method-sentinel-1.mm: New. + * obj-c++.dg/attributes/method-format-1.mm: New. + 2010-10-30 Janus Weil PR fortran/44917 Index: testsuite/objc.dg/attributes/method-noreturn-1.m =================================================================== --- testsuite/objc.dg/attributes/method-noreturn-1.m (revision 0) +++ testsuite/objc.dg/attributes/method-noreturn-1.m (revision 0) @@ -0,0 +1,34 @@ +/* Contributed by Nicola Pero , October 2010. */ +/* { dg-do compile } */ + +#include +#include + +@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 Index: testsuite/objc.dg/attributes/method-sentinel-1.m =================================================================== --- testsuite/objc.dg/attributes/method-sentinel-1.m (revision 0) +++ testsuite/objc.dg/attributes/method-sentinel-1.m (revision 0) @@ -0,0 +1,34 @@ +/* Contributed by Nicola Pero , October 2010. */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +#include +#include + +@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" } */ +} Index: testsuite/objc.dg/attributes/method-format-1.m =================================================================== --- testsuite/objc.dg/attributes/method-format-1.m (revision 0) +++ testsuite/objc.dg/attributes/method-format-1.m (revision 0) @@ -0,0 +1,43 @@ +/* Contributed by Nicola Pero , October 2010. */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +#include +#include + +@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" } */ +} Index: testsuite/objc.dg/attributes/method-deprecated-1.m =================================================================== --- testsuite/objc.dg/attributes/method-deprecated-1.m (revision 0) +++ testsuite/objc.dg/attributes/method-deprecated-1.m (revision 0) @@ -0,0 +1,33 @@ +/* Contributed by Nicola Pero , October 2010. */ +/* { dg-do compile } */ + +#include + +@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" } */ +} Index: testsuite/objc.dg/attributes/method-deprecated-2.m =================================================================== --- testsuite/objc.dg/attributes/method-deprecated-2.m (revision 0) +++ testsuite/objc.dg/attributes/method-deprecated-2.m (revision 0) @@ -0,0 +1,23 @@ +/* Contributed by Nicola Pero , October 2010. */ +/* { dg-do compile } */ + +#include + +@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" } */ +} Index: testsuite/objc.dg/attributes/method-attribute-2.m =================================================================== --- testsuite/objc.dg/attributes/method-attribute-2.m (revision 166103) +++ testsuite/objc.dg/attributes/method-attribute-2.m (working copy) @@ -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; } Index: testsuite/obj-c++.dg/attributes/method-deprecated-1.mm =================================================================== --- testsuite/obj-c++.dg/attributes/method-deprecated-1.mm (revision 0) +++ testsuite/obj-c++.dg/attributes/method-deprecated-1.mm (revision 0) @@ -0,0 +1,33 @@ +/* Contributed by Nicola Pero , October 2010. */ +/* { dg-do compile } */ + +#include + +@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" } */ +} Index: testsuite/obj-c++.dg/attributes/method-deprecated-2.mm =================================================================== --- testsuite/obj-c++.dg/attributes/method-deprecated-2.mm (revision 0) +++ testsuite/obj-c++.dg/attributes/method-deprecated-2.mm (revision 0) @@ -0,0 +1,23 @@ +/* Contributed by Nicola Pero , October 2010. */ +/* { dg-do compile } */ + +#include + +@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" } */ +} Index: testsuite/obj-c++.dg/attributes/method-attribute-2.mm =================================================================== --- testsuite/obj-c++.dg/attributes/method-attribute-2.mm (revision 166103) +++ testsuite/obj-c++.dg/attributes/method-attribute-2.mm (working copy) @@ -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; } Index: testsuite/obj-c++.dg/attributes/method-noreturn-1.mm =================================================================== --- testsuite/obj-c++.dg/attributes/method-noreturn-1.mm (revision 0) +++ testsuite/obj-c++.dg/attributes/method-noreturn-1.mm (revision 0) @@ -0,0 +1,34 @@ +/* Contributed by Nicola Pero , October 2010. */ +/* { dg-do compile } */ + +#include +#include + +@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 Index: testsuite/obj-c++.dg/attributes/method-sentinel-1.mm =================================================================== --- testsuite/obj-c++.dg/attributes/method-sentinel-1.mm (revision 0) +++ testsuite/obj-c++.dg/attributes/method-sentinel-1.mm (revision 0) @@ -0,0 +1,34 @@ +/* Contributed by Nicola Pero , October 2010. */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +#include +#include + +@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" } */ +} Index: testsuite/obj-c++.dg/attributes/method-format-1.mm =================================================================== --- testsuite/obj-c++.dg/attributes/method-format-1.mm (revision 0) +++ testsuite/obj-c++.dg/attributes/method-format-1.mm (revision 0) @@ -0,0 +1,43 @@ +/* Contributed by Nicola Pero , October 2010. */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +#include +#include + +@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" } */ +}