===================================================================
@@ -1,3 +1,9 @@
+2010-10-31 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-30 Nicola Pero <nicola.pero@meta-innovation.com>
Implemented Objective-C 2.0 @property, @synthesize and @dynamic.
===================================================================
@@ -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)
===================================================================
@@ -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
{
===================================================================
@@ -1,3 +1,19 @@
+2010-10-31 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-10-30 Nicola Pero <nicola.pero@meta-innovation.com>
Implemented Objective-C 2.0 @property, @synthesize and @dynamic.
===================================================================
@@ -1,3 +1,19 @@
+2010-10-31 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-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 <janus@gcc.gnu.org>
PR fortran/44917
===================================================================
@@ -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
===================================================================
@@ -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" } */
+}
===================================================================
@@ -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" } */
+}
===================================================================
@@ -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" } */
+}
===================================================================
@@ -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" } */
+}
===================================================================
@@ -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; }
===================================================================
@@ -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" } */
+}
===================================================================
@@ -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" } */
+}
===================================================================
@@ -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; }
===================================================================
@@ -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
===================================================================
@@ -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" } */
+}
===================================================================
@@ -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" } */
+}