Skip to content

fix unnecessary warning when using bitand with boolean operators #81976

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,10 @@ Improvements to Clang's diagnostics
such as attempting to call ``free`` on an unallocated object. Fixes
`#79443 <https://github.com/llvm/llvm-project/issues/79443>`_.

- Clang no longer warns when the ``bitand`` operator is used with boolean
operands, distinguishing it from potential typographical errors or unintended
bitwise operations. Fixes #GH77601.

Improvements to Clang's time-trace
----------------------------------

Expand Down
26 changes: 20 additions & 6 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16602,12 +16602,26 @@ static void AnalyzeImplicitConversions(
BO->getRHS()->isKnownToHaveBooleanValue() &&
BO->getLHS()->HasSideEffects(S.Context) &&
BO->getRHS()->HasSideEffects(S.Context)) {
S.Diag(BO->getBeginLoc(), diag::warn_bitwise_instead_of_logical)
<< (BO->getOpcode() == BO_And ? "&" : "|") << OrigE->getSourceRange()
<< FixItHint::CreateReplacement(
BO->getOperatorLoc(),
(BO->getOpcode() == BO_And ? "&&" : "||"));
S.Diag(BO->getBeginLoc(), diag::note_cast_operand_to_int);
SourceManager &SM = S.getSourceManager();
const LangOptions &LO = S.getLangOpts();
SourceLocation BLoc = BO->getOperatorLoc();
SourceLocation ELoc = Lexer::getLocForEndOfToken(BLoc, 0, SM, LO);
StringRef SR = clang::Lexer::getSourceText(
clang::CharSourceRange::getTokenRange(BLoc, ELoc), SM, LO);
// To reduce false positives, only issue the diagnostic if the operator
// is explicitly spelled as a punctuator. This suppresses the diagnostic
// when using 'bitand' or 'bitor' either as keywords in C++ or as macros
// in C, along with other macro spellings the user might invent.
if (SR.str() == "&" || SR.str() == "|") {

S.Diag(BO->getBeginLoc(), diag::warn_bitwise_instead_of_logical)
<< (BO->getOpcode() == BO_And ? "&" : "|")
<< OrigE->getSourceRange()
<< FixItHint::CreateReplacement(
BO->getOperatorLoc(),
(BO->getOpcode() == BO_And ? "&&" : "||"));
S.Diag(BO->getBeginLoc(), diag::note_cast_operand_to_int);
}
}

// For conditional operators, we analyze the arguments as if they
Expand Down
10 changes: 8 additions & 2 deletions clang/test/Sema/warn-bitwise-and-bool.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ boolean baz(void) __attribute__((const));
void sink(boolean);

#define FOO foo()
#define MY_AND &
#define My_BITAND bitand

void test(boolean a, boolean b, int *p, volatile int *q, int i) {
b = a & b;
Expand All @@ -44,9 +46,12 @@ void test(boolean a, boolean b, int *p, volatile int *q, int i) {
b = b & foo();
b = bar() & (i > 4);
b = (i == 7) & foo();
b = b MY_AND foo(); // OK, no warning expected

#ifdef __cplusplus
b = foo() bitand bar(); // expected-warning {{use of bitwise '&' with boolean operands}}
// expected-note@-1 {{cast one or both operands to int to silence this warning}}
b = foo() bitand bar(); // Ok, no warning expected
b = foo() My_BITAND bar(); // Ok, no warning expected

#endif

if (foo() & bar()) // expected-warning {{use of bitwise '&' with boolean operands}}
Expand All @@ -60,4 +65,5 @@ void test(boolean a, boolean b, int *p, volatile int *q, int i) {

int n = i + 10;
b = (n & (n - 1));

}
8 changes: 6 additions & 2 deletions clang/test/Sema/warn-bitwise-or-bool.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ boolean baz(void) __attribute__((const));
void sink(boolean);

#define FOO foo()
#define MY_OR |
#define My_BITOR bitor

void test(boolean a, boolean b, int *p, volatile int *q, int i) {
b = a | b;
Expand All @@ -44,9 +46,11 @@ void test(boolean a, boolean b, int *p, volatile int *q, int i) {
b = b | foo();
b = bar() | (i > 4);
b = (i == 7) | foo();
b = b MY_OR foo(); // OK, no warning expected
#ifdef __cplusplus
b = foo() bitor bar(); // expected-warning {{use of bitwise '|' with boolean operands}}
// expected-note@-1 {{cast one or both operands to int to silence this warning}}
b = foo() bitor bar(); //Ok, no warning expected
b = foo() My_BITOR bar(); // Ok, no warning expected

#endif

if (foo() | bar()) // expected-warning {{use of bitwise '|' with boolean operands}}
Expand Down