aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDeclAttr.cpp
diff options
context:
space:
mode:
authorCaitlin Sadowski <supertri@google.com>2011-07-28 20:12:35 +0000
committerCaitlin Sadowski <supertri@google.com>2011-07-28 20:12:35 +0000
commitdb33e14661c7a118a2d9a777ae69c0ecaa036e1e (patch)
tree3219ced3e13e9ecd7fd11db0acde3327bd622bff /lib/Sema/SemaDeclAttr.cpp
parent1d05d424cb2be0e3f369ec27d8fb8be20e9ba5ae (diff)
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
Diffstat (limited to 'lib/Sema/SemaDeclAttr.cpp')
-rw-r--r--lib/Sema/SemaDeclAttr.cpp230
1 files changed, 227 insertions, 3 deletions
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 694d38b4a1..0f02ed31df 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -27,7 +27,7 @@ using namespace sema;
/// 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 @@ enum {
ExpectedClassMember,
ExpectedVariable,
ExpectedMethod,
- ExpectedVariableFunctionOrLabel
+ ExpectedVariableFunctionOrLabel,
+ ExpectedFieldOrGlobalVar
};
//===----------------------------------------------------------------------===//
@@ -205,6 +206,34 @@ static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr,
}
///
+/// \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 @@ static bool mayBeSharedVariable(Decl *D) {
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 @@ static void handleGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr,
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 @@ static void handleNoThreadSafetyAttr(Sema &S, Decl *D,
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 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
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.