Added parsing for guarded_var, pt_guarded_var, lockable,
scoped_lockable, and no_thread_safety_analysis attributes, all for thread safety analysis

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@136364 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html
index 528315b..877217f 100644
--- a/docs/LanguageExtensions.html
+++ b/docs/LanguageExtensions.html
@@ -87,6 +87,14 @@
   </ul>
 </li>
 <li><a href="#analyzerspecific">Static Analysis-Specific Extensions</a></li>
+<li><a href="#threadsafety">Thread Safety Annotation Checking</a></li>
+    <ul>
+    <li><a href="#ts_guardedvar"><tt>guarded_var</tt></a></li>
+    <li><a href="#ts_ptguardedvar"><tt>pt_guarded_var</tt></a></li>
+    <li><a href="#ts_lockable"><tt>lockable</tt></a></li>  
+    <li><a href="#ts_scopedlockable"><tt>scoped_lockable</tt></a></li>   
+    <li><a href="#ts_noanal"><tt>no_thread_safety_analysis</tt></a></li>    
+    </ul>
 </ul>
 
 <!-- ======================================================================= -->
@@ -1088,6 +1096,50 @@
 <p>Query for these features with <tt>__has_attribute(ns_consumed)</tt>,
 <tt>__has_attribute(ns_returns_retained)</tt>, etc.</p>
 
+
+<!-- ======================================================================= -->
+<h2 id="analyzerspecific">Thread-Safety Annotation Checking</h2>
+<!-- ======================================================================= -->
+
+<p>Clang supports additional attributes for checking basic locking policies in 
+multithreaded programs.
+Clang currently parses the following list of attributes, although 
+<b>the implementation for these annotations is currently in development.</b> 
+For more details, see the
+<a href="http://gcc.gnu.org/wiki/ThreadSafetyAnnotation">GCC implementation</a>.
+</p>
+
+<h4 id="ts_guardedvar">guarded_var</h4>
+
+<p>Use <tt>__attribute__((guarded_var))</tt> on a variable declaration to 
+specify that the variable must be accessed while holding some lock.</p>
+
+<h4 id="ts_ptguardedvar">pt_guarded_var</h4>
+
+<p>Use <tt>__attribute__((pt_guarded_var))</tt> on a pointer declaration to 
+specify that the pointer must be dereferenced while holding some lock.</p>
+
+<h4 id="ts_lockable">lockable</h4>
+
+<p>Use <tt>__attribute__((lockable))</tt> on a class definition to specify 
+that it has a lockable type (e.g. a Mutex class). This annotation is primarily 
+used to check consistency.</p> 
+
+<h4 id="ts_scopedlockable">scoped_lockable</h4>
+
+<p>Use <tt>__attribute__((scoped_lockable))</tt> on a class definition to 
+specify that it has a "scoped" lockable type. Objects of this type will acquire 
+the lock upon construction and release it upon going out of scope.
+ This annotation is primarily used to check 
+consistency.</p> 
+
+<h4 id="ts_noanal">no_thread_safety_analysis</h4>
+
+<p>Use <tt>__attribute__((no_thread_safety_analysis))</tt> on a function 
+declaration to specify that the thread safety analysis should not be run on that 
+function. This attribute provides an escape hatch (e.g. for situations when it
+is difficult to annotate the locking policy). </p> 
+
 </div>
 </body>
 </html>
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 094ccb1..8f52a5b 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -538,3 +538,26 @@
 def X86ForceAlignArgPointer : InheritableAttr {
   let Spellings = [];
 }
+
+
+// C/C++ Thread safety attributes (e.g. for deadlock, data race checking)
+
+def GuardedVar : InheritableAttr {
+  let Spellings = ["guarded_var"];
+}
+
+def PtGuardedVar : InheritableAttr {
+  let Spellings = ["pt_guarded_var"];
+}
+
+def Lockable : InheritableAttr {
+  let Spellings = ["lockable"];
+}
+
+def ScopedLockable : InheritableAttr {
+  let Spellings = ["scoped_lockable"];
+}
+
+def NoThreadSafetyAnalysis : InheritableAttr {
+  let Spellings = ["no_thread_safety_analysis"];
+}
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 239bd45..98f7583 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1249,7 +1249,7 @@
   "parameters and methods|functions, methods and blocks|"
   "classes and virtual methods|functions, methods, and parameters|"
   "classes|virtual methods|class members|variables|methods|"
-  "variables, functions and labels}1">;
+  "variables, functions and labels|fields and global variables}1">;
 def err_attribute_wrong_decl_type : Error<
   "%0 attribute only applies to %select{functions|unions|"
   "variables and functions|functions and methods|parameters|"
@@ -1287,6 +1287,9 @@
 def warn_label_attribute_not_unused : Warning<
   "The only valid attribute for labels is 'unused'">;
 def err_invalid_pcs : Error<"Invalid PCS type">;
+def err_attribute_can_be_applied_only_to_value_decl : Error<
+  "%0 attribute can only be applied to value declarations">;
+
 
 // Availability attribute
 def warn_availability_unknown_platform : Warning<
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index 5b4c7d4..d741e89 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -184,12 +184,14 @@
     AT_format_arg,
     AT_global,
     AT_gnu_inline,
+    AT_guarded_var,
     AT_host,
     AT_IBAction,          // Clang-specific.
     AT_IBOutlet,          // Clang-specific.
     AT_IBOutletCollection, // Clang-specific.
     AT_init_priority,
     AT_launch_bounds,
+    AT_lockable,
     AT_malloc,
     AT_may_alias,
     AT_mode,
@@ -198,6 +200,7 @@
     AT_neon_polyvector_type,    // Clang-specific.
     AT_neon_vector_type,        // Clang-specific.
     AT_no_instrument_function,
+    AT_no_thread_safety_analysis,
     AT_nocommon,
     AT_nodebug,
     AT_noinline,
@@ -225,9 +228,11 @@
     AT_packed,
     AT_pascal,
     AT_pcs,  // ARM specific
+    AT_pt_guarded_var,
     AT_pure,
     AT_regparm,
     AT_reqd_wg_size,
+    AT_scoped_lockable,
     AT_section,
     AT_sentinel,
     AT_shared,
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index f90c6dc..babf491 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -210,5 +210,10 @@
     .Case("uuid", AT_uuid)
     .Case("pcs", AT_pcs)
     .Case("ms_struct", AT_MsStruct)
+    .Case("guarded_var", AT_guarded_var)
+    .Case("pt_guarded_var", AT_pt_guarded_var)
+    .Case("scoped_lockable", AT_scoped_lockable)
+    .Case("lockable", AT_lockable)
+    .Case("no_thread_safety_analysis", AT_no_thread_safety_analysis)
     .Default(UnknownAttribute);
 }
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 2cbd83a..2294c0e 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -204,6 +204,39 @@
   return true;
 }
 
+///
+/// \brief Check if passed in Decl is a field or potentially shared global var
+/// \return true if the Decl is a field or potentially shared global variable
+///
+static bool mayBeSharedVariable(Decl *D) {
+  if (isa<FieldDecl>(D))
+    return true;
+  if(VarDecl *vd = dyn_cast<VarDecl>(D))
+    return (vd->hasGlobalStorage() && !(vd->isThreadSpecified()));
+
+  return false;
+}
+
+///
+/// \brief Check if passed in Decl is a pointer type.
+/// Note that this function may produce an error message.
+/// \return true if the Decl is a pointer type; false otherwise
+///
+bool checkIsPointer(Sema & S, Decl * D, const AttributeList & Attr) {
+  if(ValueDecl * vd = dyn_cast <ValueDecl>(D)) {
+    QualType QT = vd->getType();
+    if(QT->isAnyPointerType()){
+      return true;
+    }
+    S.Diag(Attr.getLoc(), diag::warn_pointer_attribute_wrong_type)
+      << Attr.getName()->getName() << QT;
+  } else {
+    S.Diag(Attr.getLoc(), diag::err_attribute_can_be_applied_only_to_value_decl)
+      << Attr.getName();
+  }
+  return false;
+}
+
 //===----------------------------------------------------------------------===//
 // Attribute Implementations
 //===----------------------------------------------------------------------===//
@@ -212,6 +245,65 @@
 // least add some helper functions to check most argument patterns (#
 // and types of args).
 
+static void handleGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr,
+                                 bool pointer = false) {
+  assert(!Attr.isInvalid());
+
+  if (!checkAttributeNumArgs(S, Attr, 0))
+    return;
+
+  // D must be either a member field or global (potentially shared) variable.
+  if (!mayBeSharedVariable(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << 15; /*fields and global vars*/;
+    return;
+  }
+
+  if (pointer && !checkIsPointer(S, D, Attr))
+    return;
+
+  if (pointer)
+    D->addAttr(::new (S.Context) PtGuardedVarAttr(Attr.getLoc(), S.Context));
+  else
+    D->addAttr(::new (S.Context) GuardedVarAttr(Attr.getLoc(), S.Context));
+}
+
+static void handleLockableAttr(Sema &S, Decl *D, const AttributeList &Attr,
+                               bool scoped = false) {
+  assert(!Attr.isInvalid());
+
+  if (!checkAttributeNumArgs(S, Attr, 0))
+    return;
+
+  if (!isa<CXXRecordDecl>(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << ExpectedClass;
+    return;
+  }
+
+  if (scoped)
+    D->addAttr(::new (S.Context) ScopedLockableAttr(Attr.getLoc(), S.Context));
+  else
+    D->addAttr(::new (S.Context) LockableAttr(Attr.getLoc(), S.Context));
+}
+
+static void handleNoThreadSafetyAttr(Sema &S, Decl *D,
+                                     const AttributeList &Attr) {
+  assert(!Attr.isInvalid());
+
+  if (!checkAttributeNumArgs(S, Attr, 0))
+    return;
+
+  if (!isFunction(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << ExpectedFunctionOrMethod;
+    return;
+  }
+
+  D->addAttr(::new (S.Context) NoThreadSafetyAnalysisAttr(Attr.getLoc(),
+                                                          S.Context));
+}
+
 static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,
                                     const AttributeList &Attr) {
   TypedefNameDecl *tDecl = dyn_cast<TypedefNameDecl>(D);
@@ -3071,6 +3163,24 @@
   case AttributeList::AT_uuid:
     handleUuidAttr(S, D, Attr);
     break;
+
+  // Thread safety attributes:
+  case AttributeList::AT_guarded_var:
+    handleGuardedVarAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_pt_guarded_var:
+    handleGuardedVarAttr(S, D, Attr, /*pointer = */true);
+    break;
+  case AttributeList::AT_scoped_lockable:
+    handleLockableAttr(S, D, Attr, /*scoped = */true);
+    break;
+  case AttributeList::AT_no_thread_safety_analysis:
+    handleNoThreadSafetyAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_lockable:
+    handleLockableAttr(S, D, Attr);
+    break;
+
   default:
     // Ask target about the attribute.
     const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema();
diff --git a/test/SemaCXX/warn-thread-safety.cpp b/test/SemaCXX/warn-thread-safety.cpp
new file mode 100644
index 0000000..39a3fa2
--- /dev/null
+++ b/test/SemaCXX/warn-thread-safety.cpp
@@ -0,0 +1,204 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+/***********************************
+ *  No Thread Safety Analysis (noanal)
+ ***********************************/
+
+// FIXME: Right now we cannot parse attributes put on function definitions
+// We would like to patch this at some point.
+
+#if !__has_attribute(no_thread_safety_analysis)
+#error "Should support no_thread_safety_analysis attribute"
+#endif
+
+void noanal_function() __attribute__((no_thread_safety_analysis));
+
+void noanal_function() __attribute__((no_thread_safety_analysis(1))); // \
+  expected-error {{attribute takes no arguments}}
+
+int noanal_testfn(int y) __attribute__((no_thread_safety_analysis));
+
+int noanal_testfn(int y) {
+  int x __attribute__((no_thread_safety_analysis)) = y; // \
+    expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}}
+  return x;
+};
+
+int noanal_test_var __attribute__((no_thread_safety_analysis)); // \
+  expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}}
+
+class NoanalFoo {
+ private:
+  int test_field __attribute__((no_thread_safety_analysis)); // \
+    expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}}
+  void test_method() __attribute__((no_thread_safety_analysis));
+};
+
+class __attribute__((no_thread_safety_analysis)) NoanalTestClass { // \
+    expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}}
+};
+
+void noanal_fun_params(int lvar __attribute__((no_thread_safety_analysis))); // \
+  expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}}
+
+
+/***********************************
+ *  Guarded Var Attribute (gv)
+ ***********************************/
+
+#if !__has_attribute(guarded_var)
+#error "Should support guarded_var attribute"
+#endif
+
+int gv_var_noargs __attribute__((guarded_var));
+
+int gv_var_args __attribute__((guarded_var(1))); // \
+    expected-error {{attribute takes no arguments}}
+
+class GVFoo {
+ private:
+  int gv_field_noargs __attribute__((guarded_var));
+  int gv_field_args __attribute__((guarded_var(1))); // \
+      expected-error {{attribute takes no arguments}}
+};
+
+class __attribute__((guarded_var)) GV { // \
+      expected-warning {{'guarded_var' attribute only applies to fields and global variables}}
+};
+
+void gv_function() __attribute__((guarded_var)); // \
+    expected-warning {{'guarded_var' attribute only applies to fields and global variables}}
+
+void gv_function_params(int gv_lvar __attribute__((guarded_var))); // \
+    expected-warning {{'guarded_var' attribute only applies to fields and global variables}}
+
+int gv_testfn(int y){
+  int x __attribute__((guarded_var)) = y; // \
+      expected-warning {{'guarded_var' attribute only applies to fields and global variables}}
+  return x;
+}
+
+/***********************************
+ *  Pt Guarded Var Attribute (pgv)
+ ***********************************/
+
+//FIXME: add support for boost::scoped_ptr<int> fancyptr  and references
+
+#if !__has_attribute(pt_guarded_var)
+#error "Should support pt_guarded_var attribute"
+#endif
+
+int *pgv_pt_var_noargs __attribute__((pt_guarded_var));
+
+int pgv_var_noargs __attribute__((pt_guarded_var)); // \
+    expected-warning {{'pt_guarded_var' only applies to pointer types; type here is 'int'}}
+
+class PGVFoo {
+ private:
+  int *pt_field_noargs __attribute__((pt_guarded_var));
+  int field_noargs __attribute__((pt_guarded_var)); // \
+    expected-warning {{'pt_guarded_var' only applies to pointer types; type here is 'int'}}
+  int *gv_field_args __attribute__((pt_guarded_var(1))); // \
+    expected-error {{attribute takes no arguments}}
+};
+
+class __attribute__((pt_guarded_var)) PGV { // \
+    expected-warning {{'pt_guarded_var' attribute only applies to fields and global variables}}
+};
+
+int *pgv_var_args __attribute__((pt_guarded_var(1))); // \
+  expected-error {{attribute takes no arguments}}
+
+
+void pgv_function() __attribute__((pt_guarded_var)); // \
+  expected-warning {{'pt_guarded_var' attribute only applies to fields and global variables}}
+
+void pgv_function_params(int *gv_lvar __attribute__((pt_guarded_var))); // \
+  expected-warning {{'pt_guarded_var' attribute only applies to fields and global variables}}
+
+void pgv_testfn(int y){
+  int *x __attribute__((pt_guarded_var)) = new int(0); // \
+    expected-warning {{'pt_guarded_var' attribute only applies to fields and global variables}}
+  delete x;
+}
+
+/***********************************
+ *  Lockable Attribute (l)
+ ***********************************/
+
+//FIXME: In future we may want to add support for structs, ObjC classes, etc.
+
+#if !__has_attribute(lockable)
+#error "Should support lockable attribute"
+#endif
+
+class __attribute__((lockable)) LTestClass {
+};
+
+class __attribute__((lockable (1))) LTestClass_args { // \
+    expected-error {{attribute takes no arguments}}
+};
+
+void l_test_function() __attribute__((lockable));  // \
+  expected-warning {{'lockable' attribute only applies to classes}}
+
+int l_testfn(int y) {
+  int x __attribute__((lockable)) = y; // \
+    expected-warning {{'lockable' attribute only applies to classes}}
+  return x;
+}
+
+int l_test_var __attribute__((lockable)); // \
+  expected-warning {{'lockable' attribute only applies to classes}}
+
+class LFoo {
+ private:
+  int test_field __attribute__((lockable)); // \
+    expected-warning {{'lockable' attribute only applies to classes}}
+  void test_method() __attribute__((lockable)); // \
+    expected-warning {{'lockable' attribute only applies to classes}}
+};
+
+
+void l_function_params(int lvar __attribute__((lockable))); // \
+  expected-warning {{'lockable' attribute only applies to classes}}
+
+
+/***********************************
+ *  Scoped Lockable Attribute (sl)
+ ***********************************/
+
+#if !__has_attribute(scoped_lockable)
+#error "Should support scoped_lockable attribute"
+#endif
+
+class __attribute__((scoped_lockable)) SLTestClass {
+};
+
+class __attribute__((scoped_lockable (1))) SLTestClass_args { // \
+    expected-error {{attribute takes no arguments}}
+};
+
+void sl_test_function() __attribute__((scoped_lockable));  // \
+  expected-warning {{'scoped_lockable' attribute only applies to classes}}
+
+int sl_testfn(int y) {
+  int x __attribute__((scoped_lockable)) = y; // \
+    expected-warning {{'scoped_lockable' attribute only applies to classes}}
+  return x;
+}
+
+int sl_test_var __attribute__((scoped_lockable)); // \
+  expected-warning {{'scoped_lockable' attribute only applies to classes}}
+
+class SLFoo {
+ private:
+  int test_field __attribute__((scoped_lockable)); // \
+    expected-warning {{'scoped_lockable' attribute only applies to classes}}
+  void test_method() __attribute__((scoped_lockable)); // \
+    expected-warning {{'scoped_lockable' attribute only applies to classes}}
+};
+
+
+void sl_function_params(int lvar __attribute__((scoped_lockable))); // \
+  expected-warning {{'scoped_lockable' attribute only applies to classes}}