[clang] d1522d3 - [-Wcompletion-handler] Support checks with builtins

Valeriy Savchenko via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 9 00:35:46 PST 2021


Author: Valeriy Savchenko
Date: 2021-02-09T11:32:24+03:00
New Revision: d1522d349f4d4b960ff7a37303103e95aa535af3

URL: https://github.com/llvm/llvm-project/commit/d1522d349f4d4b960ff7a37303103e95aa535af3
DIFF: https://github.com/llvm/llvm-project/commit/d1522d349f4d4b960ff7a37303103e95aa535af3.diff

LOG: [-Wcompletion-handler] Support checks with builtins

It is very common to check callbacks and completion handlers for null.
This patch supports such checks using built-in functions:
  * __builtin_expect
  * __builtin_expect_with_probablity
  * __builtin_unpredictable

rdar://73455388

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

Added: 
    

Modified: 
    clang/lib/Analysis/CalledOnceCheck.cpp
    clang/test/SemaObjC/warn-called-once.m

Removed: 
    


################################################################################
diff  --git a/clang/lib/Analysis/CalledOnceCheck.cpp b/clang/lib/Analysis/CalledOnceCheck.cpp
index 883629a300dc..92d68d85fbc2 100644
--- a/clang/lib/Analysis/CalledOnceCheck.cpp
+++ b/clang/lib/Analysis/CalledOnceCheck.cpp
@@ -22,6 +22,7 @@
 #include "clang/Analysis/AnalysisDeclContext.h"
 #include "clang/Analysis/CFG.h"
 #include "clang/Analysis/FlowSensitive/DataflowWorklist.h"
+#include "clang/Basic/Builtins.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/BitVector.h"
@@ -330,6 +331,29 @@ class DeclRefFinder
     return Visit(OVE->getSourceExpr());
   }
 
+  const DeclRefExpr *VisitCallExpr(const CallExpr *CE) {
+    if (!ShouldRetrieveFromComparisons)
+      return nullptr;
+
+    // We want to see through some of the boolean builtin functions
+    // that we are likely to see in conditions.
+    switch (CE->getBuiltinCallee()) {
+    case Builtin::BI__builtin_expect:
+    case Builtin::BI__builtin_expect_with_probability: {
+      assert(CE->getNumArgs() >= 2);
+
+      const DeclRefExpr *Candidate = Visit(CE->getArg(0));
+      return Candidate != nullptr ? Candidate : Visit(CE->getArg(1));
+    }
+
+    case Builtin::BI__builtin_unpredictable:
+      return Visit(CE->getArg(0));
+
+    default:
+      return nullptr;
+    }
+  }
+
   const DeclRefExpr *VisitExpr(const Expr *E) {
     // It is a fallback method that gets called whenever the actual type
     // of the given expression is not covered.

diff  --git a/clang/test/SemaObjC/warn-called-once.m b/clang/test/SemaObjC/warn-called-once.m
index 094f92a49935..0c11d0e0a15b 100644
--- a/clang/test/SemaObjC/warn-called-once.m
+++ b/clang/test/SemaObjC/warn-called-once.m
@@ -4,6 +4,11 @@
 #define nil (id)0
 #define CALLED_ONCE __attribute__((called_once))
 #define NORETURN __attribute__((noreturn))
+#define LIKELY(X) __builtin_expect(!!(X), 1)
+#define UNLIKELY(X) __builtin_expect(!!(X), 0)
+#define LIKELY_WITH_PROBA(X, P) __builtin_expect_with_probability(!!(X), 1, P)
+#define UNLIKELY_WITH_PROBA(X, P) __builtin_expect_with_probability(!!(X), 0, P)
+#define UNPRED(X) __builtin_unpredictable((long)(X))
 
 @protocol NSObject
 @end
@@ -547,6 +552,70 @@ int call_with_check_7(int (^callback)(void) CALLED_ONCE) {
   // no-warning
 }
 
+void call_with_builtin_check_1(int (^callback)(void) CALLED_ONCE) {
+  if (LIKELY(callback))
+    callback();
+  // no-warning
+}
+
+void call_with_builtin_check_2(int (^callback)(void) CALLED_ONCE) {
+  if (!UNLIKELY(callback)) {
+  } else {
+    callback();
+  }
+  // no-warning
+}
+
+void call_with_builtin_check_3(int (^callback)(void) CALLED_ONCE) {
+  if (__builtin_expect((long)callback, 0L)) {
+  } else {
+    callback();
+  }
+  // no-warning
+}
+
+void call_with_builtin_check_4(int (^callback)(void) CALLED_ONCE) {
+  if (__builtin_expect(0L, (long)callback)) {
+  } else {
+    callback();
+  }
+  // no-warning
+}
+
+void call_with_builtin_check_5(int (^callback)(void) CALLED_ONCE) {
+  if (LIKELY_WITH_PROBA(callback, 0.9))
+    callback();
+  // no-warning
+}
+
+void call_with_builtin_check_6(int (^callback)(void) CALLED_ONCE) {
+  if (!UNLIKELY_WITH_PROBA(callback, 0.9)) {
+  } else {
+    callback();
+  }
+  // no-warning
+}
+
+void call_with_builtin_check_7(int (^callback)(void) CALLED_ONCE) {
+  if (UNPRED(callback)) {
+  } else {
+    callback();
+  }
+  // no-warning
+}
+
+void call_with_builtin_check_8(int (^callback)(void) CALLED_ONCE) {
+  if (LIKELY(callback != nil))
+    callback();
+  // no-warning
+}
+
+void call_with_builtin_check_9(int (^callback)(void) CALLED_ONCE) {
+  if (!UNLIKELY(callback == NULL))
+    callback();
+  // no-warning
+}
+
 void unreachable_true_branch(void (^callback)(void) CALLED_ONCE) {
   if (0) {
 


        


More information about the cfe-commits mailing list