diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -64,6 +64,10 @@ def SignConversion : DiagGroup<"sign-conversion">; def PointerBoolConversion : DiagGroup<"pointer-bool-conversion">; def UndefinedBoolConversion : DiagGroup<"undefined-bool-conversion">; +def BoolOperationNegation : DiagGroup<"bool-operation-negation">; +def BoolOperationAnd : DiagGroup<"bool-operation-and">; +def BoolOperation : DiagGroup<"bool-operation", [BoolOperationNegation, + BoolOperationAnd]>; def BoolConversion : DiagGroup<"bool-conversion", [PointerBoolConversion, UndefinedBoolConversion]>; def IntConversion : DiagGroup<"int-conversion">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7424,7 +7424,10 @@ def warn_bitwise_negation_bool : Warning< "bitwise negation of a boolean expression%select{;| always evaluates to 'true';}0 " "did you mean logical negation?">, - InGroup>; + InGroup; +def warn_bitwise_and_bool : Warning< + "bitwise and of a boolean expression; did you mean logical and?">, + InGroup; def err_decrement_bool : Error<"cannot decrement expression of type bool">; def warn_increment_bool : Warning< "incrementing expression of type bool is deprecated and " diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -13073,6 +13073,15 @@ << OrigE->getSourceRange() << T->isBooleanType() << FixItHint::CreateReplacement(UO->getBeginLoc(), "!"); + if (const auto *BO = dyn_cast(SourceExpr)) + if (BO->getOpcode() == BO_And && + BO->getLHS()->isKnownToHaveBooleanValue() && + BO->getRHS()->isKnownToHaveBooleanValue() && + BO->getRHS()->HasSideEffects(S.Context)) + S.Diag(BO->getBeginLoc(), diag::warn_bitwise_and_bool) + << OrigE->getSourceRange() + << FixItHint::CreateReplacement(BO->getOperatorLoc(), "&&"); + // For conditional operators, we analyze the arguments as if they // were being fed directly into the output. if (auto *CO = dyn_cast(SourceExpr)) { diff --git a/clang/test/Sema/warn-bitwise-and-bool.c b/clang/test/Sema/warn-bitwise-and-bool.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/warn-bitwise-and-bool.c @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 -x c -fsyntax-only -verify -Wbool-operation %s +// RUN: %clang_cc1 -x c -fsyntax-only -verify %s +// RUN: %clang_cc1 -x c -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -x c++ -fsyntax-only -verify -Wbool-operation %s +// RUN: %clang_cc1 -x c++ -fsyntax-only -verify %s +// RUN: %clang_cc1 -x c++ -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s + +#ifdef __cplusplus +typedef bool boolean; +#else +typedef _Bool boolean; +#endif + +boolean foo(void); +boolean bar(void); +boolean baz(void) __attribute__((const)); + +#define FOO foo(); + +void test(boolean a, boolean b, int i) { + b = a & b; + b = a & foo(); // expected-warning {{bitwise and of a boolean expression; did you mean logical and?}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:10}:"&&" + b = foo() & bar(); // expected-warning {{bitwise and of a boolean expression; did you mean logical and?}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:14}:"&&" + b = foo() & !bar(); // expected-warning {{bitwise and of a boolean expression; did you mean logical and?}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:14}:"&&" + b = a & baz(); + b = a & FOO; // expected-warning {{bitwise and of a boolean expression; did you mean logical and?}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:10}:"&&" + i = !b & foo(); // expected-warning {{bitwise and of a boolean expression; did you mean logical and?}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:10-[[@LINE-1]]:11}:"&&" + b = bar() & (i > 4); + b = (i == 7) & foo(); // expected-warning {{bitwise and of a boolean expression; did you mean logical and?}} +#ifdef __cplusplus + b = a and foo(); +#endif +}