Allow thread safety attributes on function definitions.
For compatibility with gcc, clang will now parse gcc attributes on
function definitions, but issue a warning if the attribute is not a
thread safety attribute.  Warning controlled by -Wgcc-compat.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150698 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/Parser/attributes.c b/test/Parser/attributes.c
index 36bd807..347cb9c 100644
--- a/test/Parser/attributes.c
+++ b/test/Parser/attributes.c
@@ -61,3 +61,38 @@
 int __attribute__((vec_type_hint(char, aligned(16) )) missing_rparen_1; // expected-error {{expected ')'}}
 int __attribute__((mode(x aligned(16) )) missing_rparen_2; // expected-error {{expected ')'}}
 int __attribute__((format(printf, 0 aligned(16) )) missing_rparen_3; // expected-error {{expected ')'}}
+
+
+
+int testFundef1(int *a) __attribute__((nonnull(1))) { // \
+    // expected-warning {{GCC does not allow nonnull attribute in this position on a function definition}}
+  return *a;
+}
+
+// noreturn is lifted to type qualifier
+void testFundef2() __attribute__((noreturn)) { // \
+    // expected-warning {{GCC does not allow noreturn attribute in this position on a function definition}}
+  testFundef2();
+}
+
+int testFundef3(int *a) __attribute__((nonnull(1), // \
+    // expected-warning {{GCC does not allow nonnull attribute in this position on a function definition}}
+                                     pure)) { // \
+    // expected-warning {{GCC does not allow pure attribute in this position on a function definition}}
+  return *a;
+}
+
+int testFundef4(int *a) __attribute__((nonnull(1))) // \
+    // expected-warning {{GCC does not allow nonnull attribute in this position on a function definition}}
+                      __attribute((pure)) { // \
+    // expected-warning {{GCC does not allow pure attribute in this position on a function definition}}
+  return *a;
+}
+
+// GCC allows these
+void testFundef5() __attribute__(()) { }
+
+__attribute__((pure)) int testFundef6(int a) { return a; }
+
+
+
diff --git a/test/SemaCXX/cxx0x-cursory-default-delete.cpp b/test/SemaCXX/cxx0x-cursory-default-delete.cpp
index 17933c2..3290595 100644
--- a/test/SemaCXX/cxx0x-cursory-default-delete.cpp
+++ b/test/SemaCXX/cxx0x-cursory-default-delete.cpp
@@ -67,3 +67,9 @@
 struct except_spec_d_match : except_spec_a, except_spec_b {
   except_spec_d_match() throw(A, B) = default;
 };  
+
+// gcc-compatibility: allow attributes on default definitions
+// (but not normal definitions)
+struct S { S(); };
+S::S() __attribute((pure)) = default;
+
diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp
index 54e5795..e0fde6b 100644
--- a/test/SemaCXX/warn-thread-safety-analysis.cpp
+++ b/test/SemaCXX/warn-thread-safety-analysis.cpp
@@ -1936,3 +1936,118 @@
   }
 
 }
+
+
+
+namespace FunctionDefinitionTest {
+
+class Foo {
+public:
+  void foo1();
+  void foo2();
+  void foo3(Foo *other);
+
+  template<class T>
+  void fooT1(const T& dummy1);
+
+  template<class T>
+  void fooT2(const T& dummy2) EXCLUSIVE_LOCKS_REQUIRED(mu_);
+
+  Mutex mu_;
+  int a GUARDED_BY(mu_);
+};
+
+template<class T>
+class FooT {
+public:
+  void foo();
+
+  Mutex mu_;
+  T a GUARDED_BY(mu_);
+};
+
+
+void Foo::foo1() NO_THREAD_SAFETY_ANALYSIS {
+  a = 1;
+}
+
+void Foo::foo2() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
+  a = 2;
+}
+
+void Foo::foo3(Foo *other) EXCLUSIVE_LOCKS_REQUIRED(other->mu_) {
+  other->a = 3;
+}
+
+template<class T>
+void Foo::fooT1(const T& dummy1) EXCLUSIVE_LOCKS_REQUIRED(mu_) {
+  a = dummy1;
+}
+
+/* TODO -- uncomment with template instantiation of attributes.
+template<class T>
+void Foo::fooT2(const T& dummy2) {
+  a = dummy2;
+}
+*/
+
+void fooF1(Foo *f) EXCLUSIVE_LOCKS_REQUIRED(f->mu_) {
+  f->a = 1;
+}
+
+void fooF2(Foo *f);
+void fooF2(Foo *f) EXCLUSIVE_LOCKS_REQUIRED(f->mu_) {
+  f->a = 2;
+}
+
+void fooF3(Foo *f) EXCLUSIVE_LOCKS_REQUIRED(f->mu_);
+void fooF3(Foo *f) {
+  f->a = 3;
+}
+
+template<class T>
+void FooT<T>::foo() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
+  a = 0;
+}
+
+void test() {
+  int dummy = 0;
+  Foo myFoo;
+
+  myFoo.foo2();        // \
+    // expected-warning {{calling function 'foo2' requires exclusive lock on 'mu_'}}
+  myFoo.foo3(&myFoo);  // \
+    // expected-warning {{calling function 'foo3' requires exclusive lock on 'mu_'}}
+  myFoo.fooT1(dummy);  // \
+    // expected-warning {{calling function 'fooT1' requires exclusive lock on 'mu_'}}
+
+  // FIXME: uncomment with template instantiation of attributes patch
+  // myFoo.fooT2(dummy);  // expected warning
+
+  fooF1(&myFoo);  // \
+    // expected-warning {{calling function 'fooF1' requires exclusive lock on 'mu_'}}
+  fooF2(&myFoo);  // \
+    // expected-warning {{calling function 'fooF2' requires exclusive lock on 'mu_'}}
+  fooF3(&myFoo);  // \
+    // expected-warning {{calling function 'fooF3' requires exclusive lock on 'mu_'}}
+
+  myFoo.mu_.Lock();
+  myFoo.foo2();
+  myFoo.foo3(&myFoo);
+  myFoo.fooT1(dummy);
+
+  // FIXME: uncomment with template instantiation of attributes patch
+  // myFoo.fooT2(dummy);
+
+  fooF1(&myFoo);
+  fooF2(&myFoo);
+  fooF3(&myFoo);
+  myFoo.mu_.Unlock();
+
+  FooT<int> myFooT;
+  myFooT.foo();  // \
+    // expected-warning {{calling function 'foo' requires exclusive lock on 'mu_'}}
+}
+
+};
+
diff --git a/test/SemaCXX/warn-thread-safety-parsing.cpp b/test/SemaCXX/warn-thread-safety-parsing.cpp
index 6eacc76..c58ff93 100644
--- a/test/SemaCXX/warn-thread-safety-parsing.cpp
+++ b/test/SemaCXX/warn-thread-safety-parsing.cpp
@@ -1262,3 +1262,30 @@
   void unlock() __attribute__((unlock_function())) { }
 };
 
+
+namespace FunctionDefinitionParseTest {
+// Test parsing of attributes on function definitions.
+
+class Foo {
+public:
+  Mu mu_;
+  void foo1();
+  void foo2(Foo *f);
+};
+
+template <class T>
+class Bar {
+public:
+  Mu mu_;
+  void bar();
+};
+
+void Foo::foo1()       __attribute__((exclusive_locks_required(mu_))) { }
+void Foo::foo2(Foo *f) __attribute__((exclusive_locks_required(f->mu_))) { }
+
+template <class T>
+void Bar<T>::bar() __attribute__((exclusive_locks_required(mu_))) { }
+
+void baz(Foo *f) __attribute__((exclusive_locks_required(f->mu_))) { }
+};
+