]> granicus.if.org Git - clang/commitdiff
Substitute for arguments in method calls -- functionality
authorDeLesley Hutchins <delesley@google.com>
Mon, 17 Oct 2011 21:38:02 +0000 (21:38 +0000)
committerDeLesley Hutchins <delesley@google.com>
Mon, 17 Oct 2011 21:38:02 +0000 (21:38 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142267 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/ThreadSafety.cpp
test/SemaCXX/warn-thread-safety-analysis.cpp

index b01ca51dfe60e78fb2b1aafb62309c9f7e7372f0..a03e5a699407fd94f82f82aa109783ad1551c659 100644 (file)
@@ -156,23 +156,31 @@ class MutexID {
 
   /// Build a Decl sequence representing the lock from the given expression.
   /// Recursive function that bottoms out when the final DeclRefExpr is reached.
-  // FIXME: Lock expressions that involve array indices or function calls.
-  // FIXME: Deal with LockReturned attribute.
-  void buildMutexID(Expr *Exp, Expr *Parent) {
+  void buildMutexID(Expr *Exp, Expr *Parent, int NumArgs,
+                    const NamedDecl **FunArgDecls, Expr **FunArgs) {
     if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp)) {
+      if (FunArgDecls) {
+        // Substitute call arguments for references to function parameters
+        for (int i = 0; i < NumArgs; ++i) {
+          if (DRE->getDecl() == FunArgDecls[i]) {
+            buildMutexID(FunArgs[i], 0, 0, 0, 0);
+            return;
+          }
+        }
+      }
       NamedDecl *ND = cast<NamedDecl>(DRE->getDecl()->getCanonicalDecl());
       DeclSeq.push_back(ND);
     } else if (MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
       NamedDecl *ND = ME->getMemberDecl();
       DeclSeq.push_back(ND);
-      buildMutexID(ME->getBase(), Parent);
+      buildMutexID(ME->getBase(), Parent, NumArgs, FunArgDecls, FunArgs);
     } else if (isa<CXXThisExpr>(Exp)) {
       if (Parent)
-        buildMutexID(Parent, 0);
+        buildMutexID(Parent, 0, 0, 0, 0);
       else
         return;  // mutexID is still valid in this case
     } else if (CastExpr *CE = dyn_cast<CastExpr>(Exp))
-      buildMutexID(CE->getSubExpr(), Parent);
+      buildMutexID(CE->getSubExpr(), Parent, NumArgs, FunArgDecls, FunArgs);
     else
       DeclSeq.clear(); // Mark as invalid lock expression.
   }
@@ -184,23 +192,36 @@ class MutexID {
   /// \param D  The declaration to which the lock/unlock attribute is attached.
   void buildMutexIDFromExp(Expr *MutexExp, Expr *DeclExp, const NamedDecl *D) {
     Expr *Parent = 0;
+    unsigned NumArgs = 0;
+    Expr **FunArgs = 0;
+    SmallVector<const NamedDecl*, 8> FunArgDecls;
 
     if (DeclExp == 0) {
-      buildMutexID(MutexExp, 0);
+      buildMutexID(MutexExp, 0, 0, 0, 0);
       return;
     }
 
-    if (MemberExpr *ME = dyn_cast<MemberExpr>(DeclExp))
+    if (MemberExpr *ME = dyn_cast<MemberExpr>(DeclExp)) {
       Parent = ME->getBase();
-    else if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(DeclExp))
+    } else if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(DeclExp)) {
       Parent = CE->getImplicitObjectArgument();
+      NumArgs = CE->getNumArgs();
+      FunArgs = CE->getArgs();
+    }
 
     // If the attribute has no arguments, then assume the argument is "this".
     if (MutexExp == 0) {
-      buildMutexID(Parent, 0);
+      buildMutexID(Parent, 0, 0, 0, 0);
       return;
     }
-    buildMutexID(MutexExp, Parent);
+
+    // FIXME: handle default arguments
+    if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+      for (unsigned i = 0, ni = FD->getNumParams(); i < ni && i < NumArgs; ++i) {
+        FunArgDecls.push_back(FD->getParamDecl(i));
+      }
+    }
+    buildMutexID(MutexExp, Parent, NumArgs, &FunArgDecls.front(), FunArgs);
   }
 
 public:
index 90a8933150ac477736b7375cf6d9e437a70013d6..efa19fdcf7eb2178678788dc513285126948d637 100644 (file)
@@ -740,6 +740,7 @@ void es_bad_7() {
   sls_mu.Unlock();
 }
 
+
 //-----------------------------------------------//
 // Unparseable lock expressions
 // ----------------------------------------------//
@@ -1420,3 +1421,57 @@ void main()
 } // end namespace thread_annot_lock_67_modified
 
 
+namespace substitution_test {
+  class MyData  {
+  public:
+    Mutex mu;
+
+    void lockData()    __attribute__((exclusive_lock_function(mu)))   { }
+    void unlockData()  __attribute__((unlock_function(mu)))           { }
+
+    void doSomething() __attribute__((exclusive_locks_required(mu)))  { }
+  };
+
+
+  class DataLocker {
+  public:
+    void lockData  (MyData *d) __attribute__((exclusive_lock_function(d->mu))) { }
+    void unlockData(MyData *d) __attribute__((unlock_function(d->mu)))         { }
+  };
+
+
+  class Foo {
+  public:
+    void foo(MyData* d) __attribute__((exclusive_locks_required(d->mu))) { }
+
+    void bar1(MyData* d) {
+      d->lockData();
+      foo(d);
+      d->unlockData();
+    }
+
+    void bar2(MyData* d) {
+      DataLocker dlr;
+      dlr.lockData(d);
+      foo(d);
+      dlr.unlockData(d);
+    }
+
+    void bar3(MyData* d1, MyData* d2) {
+      DataLocker dlr;
+      dlr.lockData(d1);   // \
+        // expected-warning {{mutex 'mu' is still locked at the end of function}}
+      dlr.unlockData(d2); // \
+        // expected-warning {{unlocking 'mu' that was not locked}}
+    }
+
+    void bar4(MyData* d1, MyData* d2) {
+      DataLocker dlr;
+      dlr.lockData(d1);
+      foo(d2); // \
+        // expected-warning {{calling function 'foo' requires exclusive lock on 'mu'}}
+      dlr.unlockData(d1);
+    }
+  };
+} // end namespace substituation_test
+