From: Aaron Ballman Date: Fri, 4 Apr 2014 15:13:57 +0000 (+0000) Subject: In preparation for being able to use simple Boolean logic expressions involving capab... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=117df18867d16299c5d7a1920e3112297cc66de7;p=clang In preparation for being able to use simple Boolean logic expressions involving capabilities, the semantics for attributes now looks through the types of the constituent parts of a capability expression instead of at the aggregate expression type. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@205629 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 5f607834b7..1920182ce2 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -363,8 +363,7 @@ static const RecordType *getRecordType(QualType QT) { return 0; } -static bool checkRecordTypeForCapability(Sema &S, const AttributeList &Attr, - QualType Ty) { +static bool checkRecordTypeForCapability(Sema &S, QualType Ty) { const RecordType *RT = getRecordType(Ty); if (!RT) @@ -397,8 +396,7 @@ static bool checkRecordTypeForCapability(Sema &S, const AttributeList &Attr, return false; } -static bool checkTypedefTypeForCapability(Sema &S, const AttributeList &Attr, - QualType Ty) { +static bool checkTypedefTypeForCapability(QualType Ty) { const auto *TD = Ty->getAs(); if (!TD) return false; @@ -410,18 +408,40 @@ static bool checkTypedefTypeForCapability(Sema &S, const AttributeList &Attr, return TN->hasAttr(); } -/// \brief Checks that the passed in type is qualified as a capability. This -/// type can either be a struct, or a typedef to a built-in type (such as int). -static void checkForCapability(Sema &S, const AttributeList &Attr, - QualType Ty) { - if (checkTypedefTypeForCapability(S, Attr, Ty)) - return; +static bool typeHasCapability(Sema &S, QualType Ty) { + if (checkTypedefTypeForCapability(Ty)) + return true; - if (checkRecordTypeForCapability(S, Attr, Ty)) - return; + if (checkRecordTypeForCapability(S, Ty)) + return true; + + return false; +} + +static bool isCapabilityExpr(Sema &S, const Expr *Ex) { + // Capability expressions are simple expressions involving the boolean logic + // operators &&, || or !, a simple DeclRefExpr, CastExpr or a ParenExpr. Once + // a DeclRefExpr is found, its type should be checked to determine whether it + // is a capability or not. + + if (const auto *E = dyn_cast(Ex)) + return typeHasCapability(S, E->getType()); + else if (const auto *E = dyn_cast(Ex)) + return isCapabilityExpr(S, E->getSubExpr()); + else if (const auto *E = dyn_cast(Ex)) + return isCapabilityExpr(S, E->getSubExpr()); + else if (const auto *E = dyn_cast(Ex)) { + if (E->getOpcode() == UO_LNot) + return isCapabilityExpr(S, E->getSubExpr()); + return false; + } else if (const auto *E = dyn_cast(Ex)) { + if (E->getOpcode() == BO_LAnd || E->getOpcode() == BO_LOr) + return isCapabilityExpr(S, E->getLHS()) && + isCapabilityExpr(S, E->getRHS()); + return false; + } - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_lockable) - << Attr.getName() << Ty; + return false; } /// \brief Checks that all attribute arguments, starting from Sidx, resolve to @@ -491,7 +511,13 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, } } - checkForCapability(S, Attr, ArgTy); + // If the type does not have a capability, see if the components of the + // expression have capabilities. This allows for writing C code where the + // capability may be on the type, and the expression is a capability + // boolean logic expression. Eg) requires_capability(A || B && !C) + if (!typeHasCapability(S, ArgTy) && !isCapabilityExpr(S, ArgExp)) + S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_lockable) + << Attr.getName() << ArgTy; Args.push_back(ArgExp); } diff --git a/test/Sema/attr-capabilities.c b/test/Sema/attr-capabilities.c index e6f123f25a..cdbd2f3b2d 100644 --- a/test/Sema/attr-capabilities.c +++ b/test/Sema/attr-capabilities.c @@ -50,4 +50,13 @@ void Func23(void) __attribute__((try_acquire_capability(1, GUI))) {} void Func24(void) __attribute__((try_acquire_shared_capability(1, GUI))) {} void Func25(void) __attribute__((try_acquire_capability())) {} // expected-error {{'try_acquire_capability' attribute takes at least 1 argument}} -void Func26(void) __attribute__((try_acquire_shared_capability())) {} // expected-error {{'try_acquire_shared_capability' attribute takes at least 1 argument}} \ No newline at end of file +void Func26(void) __attribute__((try_acquire_shared_capability())) {} // expected-error {{'try_acquire_shared_capability' attribute takes at least 1 argument}} + +// Test that boolean logic works with capability attributes +void Func27(void) __attribute__((requires_capability(!GUI))); +void Func28(void) __attribute__((requires_capability(GUI && Worker))); +void Func29(void) __attribute__((requires_capability(GUI || Worker))); +void Func30(void) __attribute__((requires_capability((Worker || Worker) && !GUI))); + +int AlsoNotACapability; +void Func31(void) __attribute__((requires_capability(GUI && AlsoNotACapability))); // expected-warning {{'requires_capability' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'int'}}