[Sema/Attribute] Check for noderef attribute

This patch adds the noderef attribute in clang and checks for dereferences of
types that have this attribute. This attribute is currently used by sparse and
would like to be ported to clang.

Differential Revision: https://reviews.llvm.org/D49511

llvm-svn: 348442
diff --git a/clang/test/Frontend/noderef.c b/clang/test/Frontend/noderef.c
new file mode 100644
index 0000000..b072b99
--- /dev/null
+++ b/clang/test/Frontend/noderef.c
@@ -0,0 +1,209 @@
+// RUN: %clang_cc1 -Wno-unused-value -verify %s
+
+#define NODEREF __attribute__((noderef))
+
+struct S {
+  int a;
+  int b;
+};
+
+struct S2 {
+  int a[2];
+  int NODEREF a2[2];
+  int *b;
+  int NODEREF *b2;
+  struct S *s;
+  struct S NODEREF *s2;
+};
+
+int NODEREF *func(int NODEREF *arg) {  // expected-note{{arg declared here}}
+  int y = *arg; // expected-warning{{dereferencing arg; was declared with a 'noderef' type}}
+  return arg;
+}
+
+void func2(int x) {}
+
+int test() {
+  int NODEREF *p; // expected-note 34 {{p declared here}}
+  int *p2;
+
+  int x = *p;               // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+  x = *((int NODEREF *)p2); // expected-warning{{dereferencing expression marked as 'noderef'}}
+
+  int NODEREF **q;
+  int *NODEREF *q2; // expected-note 4 {{q2 declared here}}
+
+  // Indirection
+  x = **q;  // expected-warning{{dereferencing expression marked as 'noderef'}}
+  p2 = *q2; // expected-warning{{dereferencing q2; was declared with a 'noderef' type}}
+
+  **q; // expected-warning{{dereferencing expression marked as 'noderef'}}
+
+  p = *&*q;
+  p = **&q;
+  q = &**&q;
+  p = &*p;
+  p = *&p;
+  p = &(*p);
+  p = *(&p);
+  x = **&p; // expected-warning{{dereferencing expression marked as 'noderef'}}
+
+  *p = 2;   // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+  *q = p;   // ok
+  **q = 2;  // expected-warning{{dereferencing expression marked as 'noderef'}}
+  *q2 = p2; // expected-warning{{dereferencing q2; was declared with a 'noderef' type}}
+
+  p = p + 1;
+  p = &*(p + 1);
+
+  // Struct member access
+  struct S NODEREF *s;  // expected-note 2 {{s declared here}}
+  x = s->a;   // expected-warning{{dereferencing s; was declared with a 'noderef' type}}
+  x = (*s).b; // expected-warning{{dereferencing s; was declared with a 'noderef' type}}
+  p = &s->a;
+  p = &(*s).b;
+
+  // Nested struct access
+  struct S2 NODEREF *s2_noderef;    // expected-note 5 {{s2_noderef declared here}}
+  p = s2_noderef->a;  // ok since result is an array in a struct
+  p = s2_noderef->a2; // ok
+  p = s2_noderef->b;  // expected-warning{{dereferencing s2_noderef; was declared with a 'noderef' type}}
+  p = s2_noderef->b2; // expected-warning{{dereferencing s2_noderef; was declared with a 'noderef' type}}
+  s = s2_noderef->s;  // expected-warning{{dereferencing s2_noderef; was declared with a 'noderef' type}}
+  s = s2_noderef->s2; // expected-warning{{dereferencing s2_noderef; was declared with a 'noderef' type}}
+  p = s2_noderef->a + 1;
+
+  struct S2 *s2;
+  p = s2->a;
+  p = s2->a2;
+  p = s2->b;
+  p = s2->b2;
+  s = s2->s;
+  s = s2->s2;
+  &(*(*s2).s2).b;
+
+  // Subscript access
+  x = p[1];    // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+  x = q[0][0]; // expected-warning{{dereferencing expression marked as 'noderef'}}
+  p2 = q2[0];  // expected-warning{{dereferencing q2; was declared with a 'noderef' type}}
+  p = q[*p];   // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+  x = p[*p];   // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+               // expected-warning@-1{{dereferencing p; was declared with a 'noderef' type}}
+
+  int NODEREF arr[10];    // expected-note 1 {{arr declared here}}
+  x = arr[1]; // expected-warning{{dereferencing arr; was declared with a 'noderef' type}}
+
+  int NODEREF *(arr2[10]);
+  int NODEREF *elem = *arr2;
+
+  int NODEREF(*arr3)[10];
+  elem = *arr3;
+
+  // Combinations between indirection, subscript, and member access
+  struct S2 NODEREF *s2_arr[10];
+  struct S2 NODEREF *s2_arr2[10][10];
+
+  p = s2_arr[1]->a;
+  p = s2_arr[1]->b; // expected-warning{{dereferencing expression marked as 'noderef'}}
+  int **bptr = &s2_arr[1]->b;
+
+  x = s2->s2->a;        // expected-warning{{dereferencing expression marked as 'noderef'}}
+  x = s2_noderef->a[1]; // expected-warning{{dereferencing s2_noderef; was declared with a 'noderef' type}}
+  p = &s2_noderef->a[1];
+
+  // Casting to dereferenceable pointer
+  p2 = p;             // expected-warning{{casting to dereferenceable pointer removes 'noderef' attribute}}
+  p2 = *q;            // expected-warning{{casting to dereferenceable pointer removes 'noderef' attribute}}
+  p2 = q[0];          // expected-warning{{casting to dereferenceable pointer removes 'noderef' attribute}}
+  s2 = s2_arr[1];     // expected-warning{{casting to dereferenceable pointer removes 'noderef' attribute}}
+  s2 = s2_arr2[1][1]; // expected-warning{{casting to dereferenceable pointer removes 'noderef' attribute}}
+  p2 = p, p2 = *q;    // expected-warning 2 {{casting to dereferenceable pointer removes 'noderef' attribute}}
+
+  // typedefs
+  typedef int NODEREF *ptr_t;
+  ptr_t ptr; // expected-note 2 {{ptr declared here}}
+  ptr_t *ptr2;
+  *ptr; // expected-warning{{dereferencing ptr; was declared with a 'noderef' type}}
+  *ptr2;
+  **ptr2; // expected-warning{{dereferencing expression marked as 'noderef'}}
+
+  typedef struct S2 NODEREF *s2_ptr_t;
+  s2_ptr_t s2_ptr; // expected-note 4 {{s2_ptr declared here}}
+  s2_ptr->a;       // ok since result is an array in a struct
+  s2_ptr->a2;      // ok
+  s2_ptr->b;       // expected-warning{{dereferencing s2_ptr; was declared with a 'noderef' type}}
+  s2_ptr->b2;      // expected-warning{{dereferencing s2_ptr; was declared with a 'noderef' type}}
+  s2_ptr->s;       // expected-warning{{dereferencing s2_ptr; was declared with a 'noderef' type}}
+  s2_ptr->s2;      // expected-warning{{dereferencing s2_ptr; was declared with a 'noderef' type}}
+  s2_ptr->a + 1;
+
+  typedef int(int_t);
+  typedef int_t NODEREF *(noderef_int_t);
+  typedef noderef_int_t *noderef_int_nested_t;
+  noderef_int_nested_t noderef_int_nested_ptr;
+  *noderef_int_nested_ptr;
+  **noderef_int_nested_ptr; // expected-warning{{dereferencing expression marked as 'noderef'}}
+
+  typedef int_t *(NODEREF noderef_int2_t);
+  typedef noderef_int2_t *noderef_int2_nested_t;
+  noderef_int2_nested_t noderef_int2_nested_ptr; // expected-note{{noderef_int2_nested_ptr declared here}}
+  *noderef_int2_nested_ptr;                      // expected-warning{{dereferencing noderef_int2_nested_ptr; was declared with a 'noderef' type}}
+
+  typedef int_t *(noderef_int3_t);
+  typedef noderef_int3_t(NODEREF(*(noderef_int3_nested_t)));
+  noderef_int3_nested_t noderef_int3_nested_ptr; // expected-note{{noderef_int3_nested_ptr declared here}}
+  *noderef_int3_nested_ptr;                      // expected-warning{{dereferencing noderef_int3_nested_ptr; was declared with a 'noderef' type}}
+
+  // Parentheses
+  (((*((p))))); // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+  (*(*(&(p)))); // expected-warning{{dereferencing expression marked as 'noderef'}}
+
+  (p[1]);      // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+  (q[0]);      // ok
+  (q[0][0]);   // expected-warning{{dereferencing expression marked as 'noderef'}}
+  (q2[0]);     // expected-warning{{dereferencing q2; was declared with a 'noderef' type}}
+  (q[(*(p))]); // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+  (p[(*(p))]); // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+               // expected-warning@-1{{dereferencing p; was declared with a 'noderef' type}}
+
+  (*(ptr)); // expected-warning{{dereferencing ptr; was declared with a 'noderef' type}}
+  (*(ptr2));
+  (*(*(ptr2))); // expected-warning{{dereferencing expression marked as 'noderef'}}
+
+  // Functions
+  x = *(func(p)); // expected-warning{{dereferencing expression marked as 'noderef'}}
+
+  // Casting is ok
+  q = (int NODEREF **)&p;
+  q = (int NODEREF **)&p2;
+  q = &p;
+  q = &p2;
+  x = s2->s2->a; // expected-warning{{dereferencing expression marked as 'noderef'}}
+
+  // Other expressions
+  func2(*p);         // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+  func2(*p + 1);     // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+  func2(!*p);        // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+  func2((x = *p));   // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+  func2((char)(*p)); // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+
+  // Other statements
+  if (*p) {}          // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+  else if (*p) {}     // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+  switch (*p){}       // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+  for (*p; *p; *p){}  // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+                      // expected-warning@-1{{dereferencing p; was declared with a 'noderef' type}}
+                      // expected-warning@-2{{dereferencing p; was declared with a 'noderef' type}}
+  for (*p; *p;){}     // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+                      // expected-warning@-1{{dereferencing p; was declared with a 'noderef' type}}
+  for (*p;; *p){}     // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+                      // expected-warning@-1{{dereferencing p; was declared with a 'noderef' type}}
+  for (; *p; *p){}    // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+                      // expected-warning@-1{{dereferencing p; was declared with a 'noderef' type}}
+  for (*p;;){}        // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+  for (;*p;){}        // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+  for (;;*p){}        // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+  while (*p){}        // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+  do {} while (*p);   // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+  return *p;          // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
+}
diff --git a/clang/test/Frontend/noderef.cpp b/clang/test/Frontend/noderef.cpp
new file mode 100644
index 0000000..15eb4e4
--- /dev/null
+++ b/clang/test/Frontend/noderef.cpp
@@ -0,0 +1,102 @@
+// RUN: %clang_cc1 -fblocks -verify %s
+
+/**
+ * Test 'noderef' attribute with c++ constructs.
+ */
+
+#define NODEREF __attribute__((noderef))
+
+void Normal() {
+  int NODEREF i;        // expected-warning{{'noderef' can only be used on an array or pointer type}}
+  int NODEREF *i_ptr;   // expected-note 2 {{i_ptr declared here}}
+  int NODEREF **i_ptr2; // ok
+  int *NODEREF i_ptr3;  // expected-warning{{'noderef' can only be used on an array or pointer type}}
+  int *NODEREF *i_ptr4; // ok
+
+  auto NODEREF *auto_i_ptr = i_ptr;
+  auto NODEREF auto_i = i; // expected-warning{{'noderef' can only be used on an array or pointer type}}
+
+  struct {
+    int x;
+    int y;
+  } NODEREF *s;
+
+  int __attribute__((noderef(10))) * no_args; // expected-error{{'noderef' attribute takes no arguments}}
+
+  int i2 = *i_ptr;     // expected-warning{{dereferencing i_ptr; was declared with a 'noderef' type}}
+  int &i3 = *i_ptr;    // expected-warning{{dereferencing i_ptr; was declared with a 'noderef' type}}
+  int *i_ptr5 = i_ptr; // expected-warning{{casting to dereferenceable pointer removes 'noderef' attribute}}
+  int *i_ptr6(i_ptr);  // expected-warning{{casting to dereferenceable pointer removes 'noderef' attribute}}
+}
+
+const int NODEREF *const_i_ptr;
+static int NODEREF *static_i_ptr;
+
+void ParenTypes() {
+  int NODEREF(*i_ptr);    // ok (same as `int NODEREF *`)
+  int NODEREF *(*i_ptr2); // ok (same as `int NODEREF **`)
+}
+
+// Function declarations
+int NODEREF func();   // expected-warning{{'noderef' can only be used on an array or pointer type}}
+int NODEREF *func2(); // ok (returning pointer)
+
+typedef int NODEREF (*func3)(int); // expected-warning{{'noderef' can only be used on an array or pointer type}}
+typedef int NODEREF *(*func4)(int);
+
+void Arrays() {
+  int NODEREF i_arr[10];      // ok
+  int NODEREF i_arr2[10][10]; // ok
+  int NODEREF *i_arr3[10];    // ok
+  int NODEREF i_arr4[] = {1, 2};
+}
+
+void ParenArrays() {
+  int NODEREF(i_ptr[10]);
+  int NODEREF(i_ptr2[10])[10];
+}
+
+typedef int NODEREF *(*func5[10])(int);
+
+// Arguments
+void func6(int NODEREF x); // expected-warning{{'noderef' can only be used on an array or pointer type}}
+void func7(int NODEREF *x);
+void func8() NODEREF;
+
+void References() {
+  int x = 2;
+  int NODEREF &y = x; // expected-warning{{'noderef' can only be used on an array or pointer type}}
+  int *xp = &x;
+  int NODEREF *&a = xp; // ok (reference to a NODEREF *)
+  int *NODEREF &b = xp; // expected-warning{{'noderef' can only be used on an array or pointer type}}
+}
+
+void BlockPointers() {
+  typedef int NODEREF (^IntBlock)(); // expected-warning{{'noderef' can only be used on an array or pointer type}}
+}
+
+class A {
+public:
+  int member;
+  int NODEREF *member2;
+  int NODEREF member3; // expected-warning{{'noderef' can only be used on an array or pointer type}}
+};
+
+void MemberPointer() {
+  int NODEREF A::*var = &A::member; // expected-warning{{'noderef' can only be used on an array or pointer type}}
+}
+
+template <class Ty>
+class B {
+  Ty NODEREF *member;
+  Ty NODEREF member2; // expected-warning{{'noderef' can only be used on an array or pointer type}}
+};
+
+void test_lambdas() {
+  auto l = [](int NODEREF *x){  // expected-note{{x declared here}}
+    return *x;  // expected-warning{{dereferencing x; was declared with a 'noderef' type}}
+  };
+}
+
+int NODEREF *glob_ptr;  // expected-note{{glob_ptr declared here}}
+int glob_int = *glob_ptr;  // expected-warning{{dereferencing glob_ptr; was declared with a 'noderef' type}}
diff --git a/clang/test/Frontend/noderef_on_non_pointers.m b/clang/test/Frontend/noderef_on_non_pointers.m
new file mode 100644
index 0000000..ced7627
--- /dev/null
+++ b/clang/test/Frontend/noderef_on_non_pointers.m
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -verify %s
+
+#define NODEREF __attribute__((noderef))
+
+@interface NSObject
++ (id)new;
+@end
+
+void func() {
+  id NODEREF obj = [NSObject new]; // expected-warning{{'noderef' can only be used on an array or pointer type}}
+}
diff --git a/clang/test/Frontend/noderef_templates.cpp b/clang/test/Frontend/noderef_templates.cpp
new file mode 100644
index 0000000..5fde6ef
--- /dev/null
+++ b/clang/test/Frontend/noderef_templates.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -verify %s
+
+#define NODEREF __attribute__((noderef))
+
+template <typename T>
+int func(T NODEREF *a) { // expected-note 2 {{a declared here}}
+  return *a + 1;         // expected-warning 2 {{dereferencing a; was declared with a 'noderef' type}}
+}
+
+void func() {
+  float NODEREF *f;
+  int NODEREF *i;
+  func(f); // expected-note{{in instantiation of function template specialization 'func<float>' requested here}}
+  func(i); // expected-note{{in instantiation of function template specialization 'func<int>' requested here}}
+}