Thread safety analysis: Unwrap __builtin_expect in getTrylockCallExpr

Summary:
When people are really sure they'll get the lock they sometimes use
__builtin_expect. It's also used by some assertion implementations.
Asserting that try-lock succeeded is basically the same as asserting
that the lock is not held by anyone else (and acquiring it).

Reviewers: aaron.ballman, delesley

Reviewed By: aaron.ballman

Subscribers: kristina, cfe-commits

Differential Revision: https://reviews.llvm.org/D52398

llvm-svn: 343681
diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp
index 65904fd..be1f8b8 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -33,6 +33,7 @@
 #include "clang/Analysis/Analyses/ThreadSafetyUtil.h"
 #include "clang/Analysis/AnalysisDeclContext.h"
 #include "clang/Analysis/CFG.h"
+#include "clang/Basic/Builtins.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/OperatorKinds.h"
 #include "clang/Basic/SourceLocation.h"
@@ -1388,8 +1389,11 @@
   if (!Cond)
     return nullptr;
 
-  if (const auto *CallExp = dyn_cast<CallExpr>(Cond))
+  if (const auto *CallExp = dyn_cast<CallExpr>(Cond)) {
+    if (CallExp->getBuiltinCallee() == Builtin::BI__builtin_expect)
+      return getTrylockCallExpr(CallExp->getArg(0), C, Negate);
     return CallExp;
+  }
   else if (const auto *PE = dyn_cast<ParenExpr>(Cond))
     return getTrylockCallExpr(PE->getSubExpr(), C, Negate);
   else if (const auto *CE = dyn_cast<ImplicitCastExpr>(Cond))
diff --git a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp
index 057fd17..ce3c6b9 100644
--- a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp
+++ b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp
@@ -1754,6 +1754,13 @@
     mu.Unlock();
   }
 
+  void foo2_builtin_expect() {
+    if (__builtin_expect(!mu.TryLock(), false))
+      return;
+    a = 2;
+    mu.Unlock();
+  }
+
   void foo3() {
     bool b = mu.TryLock();
     if (b) {
@@ -1762,6 +1769,14 @@
     }
   }
 
+  void foo3_builtin_expect() {
+    bool b = mu.TryLock();
+    if (__builtin_expect(b, true)) {
+      a = 3;
+      mu.Unlock();
+    }
+  }
+
   void foo4() {
     bool b = mu.TryLock();
     if (!b) return;