r205629 - 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.

Aaron Ballman aaron at aaronballman.com
Fri Apr 4 08:13:57 PDT 2014


Author: aaronballman
Date: Fri Apr  4 10:13:57 2014
New Revision: 205629

URL: http://llvm.org/viewvc/llvm-project?rev=205629&view=rev
Log:
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.

Modified:
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp
    cfe/trunk/test/Sema/attr-capabilities.c

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=205629&r1=205628&r2=205629&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Fri Apr  4 10:13:57 2014
@@ -363,8 +363,7 @@ static const RecordType *getRecordType(Q
   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
   return false;
 }
 
-static bool checkTypedefTypeForCapability(Sema &S, const AttributeList &Attr,
-                                          QualType Ty) {
+static bool checkTypedefTypeForCapability(QualType Ty) {
   const auto *TD = Ty->getAs<TypedefType>();
   if (!TD)
     return false;
@@ -410,18 +408,40 @@ static bool checkTypedefTypeForCapabilit
   return TN->hasAttr<CapabilityAttr>();
 }
 
-/// \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, Ty))
+    return true;
+
+  return false;
+}
 
-  if (checkRecordTypeForCapability(S, Attr, Ty))
-    return;
+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<DeclRefExpr>(Ex))
+    return typeHasCapability(S, E->getType());
+  else if (const auto *E = dyn_cast<CastExpr>(Ex))
+    return isCapabilityExpr(S, E->getSubExpr());
+  else if (const auto *E = dyn_cast<ParenExpr>(Ex))
+    return isCapabilityExpr(S, E->getSubExpr());
+  else if (const auto *E = dyn_cast<UnaryOperator>(Ex)) {
+    if (E->getOpcode() == UO_LNot)
+      return isCapabilityExpr(S, E->getSubExpr());
+    return false;
+  } else if (const auto *E = dyn_cast<BinaryOperator>(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 checkAttrArgsAreCapabilityOb
       }
     }
 
-    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);
   }

Modified: cfe/trunk/test/Sema/attr-capabilities.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-capabilities.c?rev=205629&r1=205628&r2=205629&view=diff
==============================================================================
--- cfe/trunk/test/Sema/attr-capabilities.c (original)
+++ cfe/trunk/test/Sema/attr-capabilities.c Fri Apr  4 10:13:57 2014
@@ -50,4 +50,13 @@ void Func23(void) __attribute__((try_acq
 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'}}





More information about the cfe-commits mailing list