Added basic parsing for all remaining attributes, thread safety
analysis. This includes checking that the attributes are applied in the
correct contexts and with the correct number of arguments.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@136383 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 694d38b..0f02ed3 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -27,7 +27,7 @@
 
 /// These constants match the enumerated choices of
 /// warn_attribute_wrong_decl_type and err_attribute_wrong_decl_type.
-enum {
+enum AttributeDeclType {
   ExpectedFunction,
   ExpectedUnion,
   ExpectedVariableOrFunction,
@@ -42,7 +42,8 @@
   ExpectedClassMember,
   ExpectedVariable,
   ExpectedMethod,
-  ExpectedVariableFunctionOrLabel
+  ExpectedVariableFunctionOrLabel,
+  ExpectedFieldOrGlobalVar
 };
 
 //===----------------------------------------------------------------------===//
@@ -205,6 +206,34 @@
 }
 
 ///
+/// \brief Check the total number of argumenation, whether parsed by clang
+/// as arguments or parameters. Outputs a warning.
+/// \return false if the number of argumenation units does not match expectation
+///
+static bool checkAttributeNumArgsPlusParams(Sema &S, const AttributeList &Attr,
+                                             unsigned int Num,
+                                             bool moreok = false) {
+  unsigned int numArgsPlusParams = 0;
+
+  if (Attr.getParameterName())
+    numArgsPlusParams++;
+
+  numArgsPlusParams += Attr.getNumArgs();
+
+  if (moreok && numArgsPlusParams < Num) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_too_few_arguments) << Num;
+    return false;
+  }
+
+  if (!moreok && numArgsPlusParams != Num) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << Num;
+    return false;
+  }
+
+  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
 ///
@@ -225,7 +254,7 @@
 bool checkIsPointer(Sema & S, Decl * D, const AttributeList & Attr) {
   if(ValueDecl * vd = dyn_cast <ValueDecl>(D)) {
     QualType QT = vd->getType();
-    if(QT->isAnyPointerType()){
+    if(QT->isAnyPointerType()) {
       return true;
     }
     S.Diag(Attr.getLoc(), diag::warn_pointer_attribute_wrong_type)
@@ -268,6 +297,30 @@
     D->addAttr(::new (S.Context) GuardedVarAttr(Attr.getLoc(), S.Context));
 }
 
+static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr,
+                                 bool pointer = false) {
+  assert(!Attr.isInvalid());
+
+  if (!checkAttributeNumArgsPlusParams(S, Attr, 1))
+    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) PtGuardedByAttr(Attr.getLoc(), S.Context));
+  else
+    D->addAttr(::new (S.Context) GuardedByAttr(Attr.getLoc(), S.Context));
+}
+
+
 static void handleLockableAttr(Sema &S, Decl *D, const AttributeList &Attr,
                                bool scoped = false) {
   assert(!Attr.isInvalid());
@@ -304,6 +357,138 @@
                                                           S.Context));
 }
 
+static void handleAcquireOrderAttr(Sema &S, Decl *D, const AttributeList &Attr,
+                                   bool before) {
+  assert(!Attr.isInvalid());
+
+  if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true))
+    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 (before)
+    D->addAttr(::new (S.Context) AcquiredBeforeAttr(Attr.getLoc(), S.Context));
+  else
+    D->addAttr(::new (S.Context) AcquiredAfterAttr(Attr.getLoc(), S.Context));
+}
+
+static void handleLockFunAttr(Sema &S, Decl *D, const AttributeList &Attr,
+                                   bool exclusive = false) {
+  assert(!Attr.isInvalid());
+
+  // zero or more arguments ok
+
+  if (!isFunction(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << ExpectedFunctionOrMethod;
+    return;
+  }
+
+  if (exclusive)
+    D->addAttr(::new (S.Context) ExclusiveLockFunctionAttr(Attr.getLoc(),
+                                                           S.Context));
+  else
+    D->addAttr(::new (S.Context) SharedLockFunctionAttr(Attr.getLoc(),
+                                                        S.Context));
+}
+
+static void handleTrylockFunAttr(Sema &S, Decl *D, const AttributeList &Attr,
+                                      bool exclusive = false) {
+  assert(!Attr.isInvalid());
+
+  if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true))
+    return;
+
+  if (!isFunction(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << ExpectedFunctionOrMethod;
+    return;
+  }
+
+  if (exclusive)
+    D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(Attr.getLoc(),
+                                                           S.Context));
+  else
+    D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(Attr.getLoc(),
+                                                        S.Context));
+
+}
+
+static void handleLocksRequiredAttr(Sema &S, Decl *D, const AttributeList &Attr,
+                                   bool exclusive = false) {
+  assert(!Attr.isInvalid());
+
+  if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true))
+    return;
+
+  if (!isFunction(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << ExpectedFunctionOrMethod;
+    return;
+  }
+
+  if (exclusive)
+    D->addAttr(::new (S.Context) ExclusiveLocksRequiredAttr(Attr.getLoc(),
+                                                           S.Context));
+  else
+    D->addAttr(::new (S.Context) SharedLocksRequiredAttr(Attr.getLoc(),
+                                                        S.Context));
+}
+
+
+static void handleUnlockFunAttr(Sema &S, Decl *D,
+                                     const AttributeList &Attr) {
+  assert(!Attr.isInvalid());
+
+  // zero or more arguments ok
+
+  if (!isFunction(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << ExpectedFunctionOrMethod;
+    return;
+  }
+
+  D->addAttr(::new (S.Context) UnlockFunctionAttr(Attr.getLoc(), S.Context));
+}
+
+static void handleLockReturnedAttr(Sema &S, Decl *D,
+                                     const AttributeList &Attr) {
+  assert(!Attr.isInvalid());
+
+  if (!checkAttributeNumArgsPlusParams(S, Attr, 1))
+    return;
+
+  if (!isFunction(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << ExpectedFunctionOrMethod;
+    return;
+  }
+
+  D->addAttr(::new (S.Context) LockReturnedAttr(Attr.getLoc(), S.Context));
+}
+
+static void handleLocksExcludedAttr(Sema &S, Decl *D,
+                                     const AttributeList &Attr) {
+  assert(!Attr.isInvalid());
+
+  if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true))
+    return;
+
+  if (!isFunction(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << ExpectedFunctionOrMethod;
+    return;
+  }
+
+  D->addAttr(::new (S.Context) LocksExcludedAttr(Attr.getLoc(), S.Context));
+}
+
+
 static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,
                                     const AttributeList &Attr) {
   TypedefNameDecl *tDecl = dyn_cast<TypedefNameDecl>(D);
@@ -3180,6 +3365,45 @@
   case AttributeList::AT_lockable:
     handleLockableAttr(S, D, Attr);
     break;
+  case AttributeList::AT_guarded_by:
+    handleGuardedByAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_pt_guarded_by:
+    handleGuardedByAttr(S, D, Attr, /*pointer = */true);
+    break;
+  case AttributeList::AT_exclusive_lock_function:
+    handleLockFunAttr(S, D, Attr, /*exclusive = */true);
+    break;
+  case AttributeList::AT_exclusive_locks_required:
+    handleLocksRequiredAttr(S, D, Attr, /*exclusive = */true);
+    break;
+  case AttributeList::AT_exclusive_trylock_function:
+    handleTrylockFunAttr(S, D, Attr, /*exclusive = */true);
+    break;
+  case AttributeList::AT_lock_returned:
+    handleLockReturnedAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_locks_excluded:
+    handleLocksExcludedAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_shared_lock_function:
+    handleLockFunAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_shared_locks_required:
+    handleLocksRequiredAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_shared_trylock_function:
+    handleTrylockFunAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_unlock_function:
+    handleUnlockFunAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_acquired_before:
+    handleAcquireOrderAttr(S, D, Attr, /*before = */true);
+    break;
+  case AttributeList::AT_acquired_after:
+    handleAcquireOrderAttr(S, D, Attr, /*before = */false);
+    break;
 
   default:
     // Ask target about the attribute.