[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