From 98ab0248600687a1a0df95fa2eed84ed170c405e Mon Sep 17 00:00:00 2001
From: Nicola Pero <nicola.pero@meta-innovation.com>
Date: Wed, 1 Jun 2011 09:30:18 +0000
Subject: [PATCH] In gcc/objc/: 2011-06-01 Nicola Pero
 <nicola.pero@meta-innovation.com>

In gcc/objc/:
2011-06-01  Nicola Pero  <nicola.pero@meta-innovation.com>

	* objc-act.c (objc_decl_method_attributes): Implement nonnull
	attribute for Objective-C methods.

In gcc/testsuite/:
2011-06-01  Nicola Pero  <nicola.pero@meta-innovation.com>

	* objc.dg/attributes/method-nonnull-1.m: New test.
	* obj-c++.dg/attributes/method-nonnull-1.mm: New test.

From-SVN: r174520
---
 gcc/objc/ChangeLog                            |  5 ++
 gcc/objc/objc-act.c                           | 42 +++++++++++++++++
 gcc/testsuite/ChangeLog                       |  5 ++
 .../obj-c++.dg/attributes/method-nonnull-1.mm | 46 +++++++++++++++++++
 .../objc.dg/attributes/method-nonnull-1.m     | 46 +++++++++++++++++++
 5 files changed, 144 insertions(+)
 create mode 100644 gcc/testsuite/obj-c++.dg/attributes/method-nonnull-1.mm
 create mode 100644 gcc/testsuite/objc.dg/attributes/method-nonnull-1.m

diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog
index 0b8b595e63cb..c52fcc3ff980 100644
--- a/gcc/objc/ChangeLog
+++ b/gcc/objc/ChangeLog
@@ -1,3 +1,8 @@
+2011-06-01  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+	* objc-act.c (objc_decl_method_attributes): Implement nonnull
+	attribute for Objective-C methods.
+
 2011-05-21  Nicola Pero  <nicola.pero@meta-innovation.com>
 
 	* config-lang.in (gtfiles): Updated order of files to fix building
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index 0e15fe55aa79..be65a534f1bd 100644
--- a/gcc/objc/objc-act.c
+++ b/gcc/objc/objc-act.c
@@ -5042,6 +5042,48 @@ objc_decl_method_attributes (tree *node, tree attributes, int flags)
 	      filtered_attributes = chainon (filtered_attributes,
 					     new_attribute);
 	    }
+	  else if (is_attribute_p ("nonnull", name))
+	    {
+	      /* We need to fixup all the argument indexes by adding 2
+		 for the two hidden arguments of an Objective-C method
+		 invocation, similat to what we do above for the
+		 "format" attribute.  */
+	      /* FIXME: This works great in terms of implementing the
+		 functionality, but the warnings that are produced by
+		 nonnull do mention the argument index (while the
+		 format ones don't).  For example, you could get
+		 "warning: null argument where non-null required
+		 (argument 3)".  Now in that message, "argument 3"
+		 includes the 2 hidden arguments; it would be much
+		 more friendly to call it "argument 1", as that would
+		 be consistent with __attribute__ ((nonnnull (1))).
+		 To do this, we'd need to have the C family code that
+		 checks the arguments know about adding/removing 2 to
+		 the argument index ... or alternatively we could
+		 maybe store the "printable" argument index in
+		 addition to the actual argument index ?  Some
+		 refactoring is needed to do this elegantly.  */
+	      tree new_attribute = copy_node (attribute);
+	      tree argument = TREE_VALUE (attribute);
+	      while (argument != NULL_TREE)
+		{
+		  /* Get the value of the argument and add 2.  */
+		  tree number = TREE_VALUE (argument);
+		  if (number
+		      && TREE_CODE (number) == INTEGER_CST
+		      && TREE_INT_CST_HIGH (number) == 0
+		      && TREE_INT_CST_LOW (number) != 0)
+		    {
+		      TREE_VALUE (argument)
+			= build_int_cst (integer_type_node,
+					 TREE_INT_CST_LOW (number) + 2);
+		    }
+		  argument = TREE_CHAIN (argument);
+		}
+
+	      filtered_attributes = chainon (filtered_attributes,
+					     new_attribute);
+	    }
 	  else
 	    warning (OPT_Wattributes, "%qE attribute directive ignored", name);
 	}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f8eea2b32e69..3a0371bb4869 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2011-06-01  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+	* objc.dg/attributes/method-nonnull-1.m: New test.
+	* obj-c++.dg/attributes/method-nonnull-1.mm: New test.	
+
 2011-05-31  Tobias Burnus  <burnus@net-b.de>
 
 	PR fortran/18918
diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-nonnull-1.mm b/gcc/testsuite/obj-c++.dg/attributes/method-nonnull-1.mm
new file mode 100644
index 000000000000..c554894b228e
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/attributes/method-nonnull-1.mm
@@ -0,0 +1,46 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, May 2011.  */
+/* { dg-do compile } */
+/* { dg-options "-Wall" } */
+
+#include <objc/objc.h>
+#include <stdlib.h>
+
+@interface MyArray
+{
+  Class isa;
+} 
++ (void) addObject: (id)object __attribute__ ((nonnull));
+- (void) addObject: (id)object __attribute__ ((nonnull));
+
++ (void) insertObject: (id)object  atIndex: (size_t)index __attribute__ ((nonnull (1)));
+- (void) insertObject: (id)object  atIndex: (size_t)index __attribute__ ((nonnull (1)));
+
++ (void) insertObject: (id)object  atIndex: (size_t)index  andObject: (id)anotherObject  atIndex: (size_t)anotherIndex __attribute__ ((nonnull (1, 3)));
+- (void) insertObject: (id)object  atIndex: (size_t)index  andObject: (id)anotherObject  atIndex: (size_t)anotherIndex __attribute__ ((nonnull (1, 3)));
+
+/* Test the behaviour with invalid code.  */
++ (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-error "out-of-range" } */
+- (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-error "out-of-range" } */
+
++ (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-error "out-of-range" } */
+- (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-error "out-of-range" } */
+
++ (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-error "non-pointer operand" } */
+- (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-error "non-pointer operand" } */
+
++ (void) removeObject: (id)object __attribute__ ((nonnull (MyArray))); /* { dg-error "" } */
+- (void) removeObject: (id)object __attribute__ ((nonnull (MyArray))); /* { dg-error "" } */
+@end
+
+void test (MyArray *object)
+{
+  [object addObject: object];
+  [object addObject: nil]; /* { dg-warning "null argument where non-null required" } */
+
+  [object insertObject: object atIndex: 4];
+  [object insertObject: nil    atIndex: 4]; /* { dg-warning "null argument where non-null required" } */
+
+  [object insertObject: object atIndex: 2 andObject: object atIndex: 3];
+  [object insertObject: nil    atIndex: 2 andObject: object atIndex: 3]; /* { dg-warning "null argument where non-null required" } */
+  [object insertObject: object atIndex: 2 andObject: nil    atIndex: 3]; /* { dg-warning "null argument where non-null required" } */
+}
diff --git a/gcc/testsuite/objc.dg/attributes/method-nonnull-1.m b/gcc/testsuite/objc.dg/attributes/method-nonnull-1.m
new file mode 100644
index 000000000000..49003242d761
--- /dev/null
+++ b/gcc/testsuite/objc.dg/attributes/method-nonnull-1.m
@@ -0,0 +1,46 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, May 2011.  */
+/* { dg-do compile } */
+/* { dg-options "-Wall" } */
+
+#include <objc/objc.h>
+#include <stdlib.h>
+
+@interface MyArray
+{
+  Class isa;
+} 
++ (void) addObject: (id)object __attribute__ ((nonnull));
+- (void) addObject: (id)object __attribute__ ((nonnull));
+
++ (void) insertObject: (id)object  atIndex: (size_t)index __attribute__ ((nonnull (1)));
+- (void) insertObject: (id)object  atIndex: (size_t)index __attribute__ ((nonnull (1)));
+
++ (void) insertObject: (id)object  atIndex: (size_t)index  andObject: (id)anotherObject  atIndex: (size_t)anotherIndex __attribute__ ((nonnull (1, 3)));
+- (void) insertObject: (id)object  atIndex: (size_t)index  andObject: (id)anotherObject  atIndex: (size_t)anotherIndex __attribute__ ((nonnull (1, 3)));
+
+/* Test the behaviour with invalid code.  */
++ (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-error "out-of-range" } */
+- (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-error "out-of-range" } */
+
++ (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-error "out-of-range" } */
+- (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-error "out-of-range" } */
+
++ (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-error "non-pointer operand" } */
+- (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-error "non-pointer operand" } */
+
++ (void) removeObject: (id)object __attribute__ ((nonnull (MyArray))); /* { dg-error "invalid operand" } */
+- (void) removeObject: (id)object __attribute__ ((nonnull (MyArray))); /* { dg-error "invalid operand" } */
+@end
+
+void test (MyArray *object)
+{
+  [object addObject: object];
+  [object addObject: nil]; /* { dg-warning "null argument where non-null required" } */
+
+  [object insertObject: object atIndex: 4];
+  [object insertObject: nil    atIndex: 4]; /* { dg-warning "null argument where non-null required" } */
+
+  [object insertObject: object atIndex: 2 andObject: object atIndex: 3];
+  [object insertObject: nil    atIndex: 2 andObject: object atIndex: 3]; /* { dg-warning "null argument where non-null required" } */
+  [object insertObject: object atIndex: 2 andObject: nil    atIndex: 3]; /* { dg-warning "null argument where non-null required" } */
+}
-- 
GitLab