Index: clang/include/clang/Basic/DiagnosticGroups.td =================================================================== --- clang/include/clang/Basic/DiagnosticGroups.td +++ 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">; Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ 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 boolean expressions; 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 " Index: clang/lib/Sema/SemaChecking.cpp =================================================================== --- clang/lib/Sema/SemaChecking.cpp +++ 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)) { Index: clang/test/Sema/warn-bitwise-and-bool.c =================================================================== --- /dev/null +++ clang/test/Sema/warn-bitwise-and-bool.c @@ -0,0 +1,52 @@ +// 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)); +void sink(boolean); + +#define FOO foo() + +void test(boolean a, boolean b, int *p, volatile int *q, int i) { + b = a & b; + b = foo() & a; + b = (p != 0) & (*p == 42); + b = (q != 0) & (*q == 42); // expected-warning {{bitwise and of boolean expressions; did you mean logical and?}} + b = a & foo(); // expected-warning {{bitwise and of boolean expressions; did you mean logical and?}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:10}:"&&" + b = foo() & bar(); // expected-warning {{bitwise and of boolean expressions; did you mean logical and?}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:14}:"&&" + b = foo() & !bar(); // expected-warning {{bitwise and of boolean expressions; 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 boolean expressions; did you mean logical and?}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:10}:"&&" + b = !b & foo(); // expected-warning {{bitwise and of boolean expressions; 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 boolean expressions; did you mean logical and?}} +#ifdef __cplusplus + b = a bitand foo(); // expected-warning {{bitwise and of boolean expressions; did you mean logical and?}} +#endif + + if (foo() & bar()) // expected-warning {{bitwise and of boolean expressions; did you mean logical and?}} + ; + + sink(a & b); + sink(a & foo()); // expected-warning {{bitwise and of boolean expressions; did you mean logical and?}} + sink(foo() & bar()); // expected-warning {{bitwise and of boolean expressions; did you mean logical and?}} + + int n = i + 10; + b = (n & (n-1)); +}