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.