From: Argyrios Kyrtzidis Date: Mon, 20 Jun 2011 18:41:26 +0000 (+0000) Subject: Warn for un-parenthesized '&' inside '|' (a & b | c), rdar://9553326. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=33f46e22b7fc3b75c34b6d892790f80869da0300;p=clang Warn for un-parenthesized '&' inside '|' (a & b | c), rdar://9553326. Patch by Henry Mason with tweaks by me. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133453 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 7444ca44ad..6b348d4308 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -62,6 +62,7 @@ def ExitTimeDestructors : DiagGroup<"exit-time-destructors">; def FourByteMultiChar : DiagGroup<"four-char-constants">; def GlobalConstructors : DiagGroup<"global-constructors">; def : DiagGroup<"idiomatic-parentheses">; +def BitwiseOpParentheses: DiagGroup<"bitwise-op-parentheses">; def LogicalOpParentheses: DiagGroup<"logical-op-parentheses">; def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">; def : DiagGroup<"import">; @@ -195,7 +196,8 @@ def DuplicateArgDecl : DiagGroup<"duplicate-method-arg">; // in -Wparentheses because most users who use -Wparentheses explicitly // do not want these warnings. def Parentheses : DiagGroup<"parentheses", - [LogicalOpParentheses]>; + [LogicalOpParentheses, + BitwiseOpParentheses]>; // -Wconversion has its own warnings, but we split a few out for // legacy reasons: diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index ebcf8238c6..6b38d9f9fe 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2777,6 +2777,11 @@ def warn_logical_instead_of_bitwise : Warning< "use of logical %0 with constant operand; switch to bitwise %1 or " "remove constant">, InGroup>; +def warn_bitwise_and_in_bitwise_or : Warning< + "'&' within '|'">, InGroup; +def note_bitwise_and_in_bitwise_or_silence : Note< + "place parentheses around the '&' expression to silence this warning">; + def warn_logical_and_in_logical_or : Warning< "'&&' within '||'">, InGroup; def note_logical_and_in_logical_or_silence : Note< diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index a00877622d..21b3468ab3 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9147,6 +9147,20 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc, } } +/// \brief It accepts a '&' expr that is inside a '|' one. +/// Emit a diagnostic together with a fixit hint that wraps the '&' expression +/// in parentheses. +static void +EmitDiagnosticForBitwiseAndInBitwiseOr(Sema &Self, SourceLocation OpLoc, + BinaryOperator *Bop) { + assert(Bop->getOpcode() == BO_And); + Self.Diag(Bop->getOperatorLoc(), diag::warn_bitwise_and_in_bitwise_or) + << Bop->getSourceRange() << OpLoc; + SuggestParentheses(Self, Bop->getOperatorLoc(), + Self.PDiag(diag::note_bitwise_and_in_bitwise_or_silence), + Bop->getSourceRange()); +} + /// \brief It accepts a '&&' expr that is inside a '||' one. /// Emit a diagnostic together with a fixit hint that wraps the '&&' expression /// in parentheses. @@ -9212,13 +9226,28 @@ static void DiagnoseLogicalAndInLogicalOrRHS(Sema &S, SourceLocation OpLoc, } } +/// \brief Look for '&' in the left or right hand of a '|' expr. +static void DiagnoseBitwiseAndInBitwiseOr(Sema &S, SourceLocation OpLoc, + Expr *OrArg) { + if (BinaryOperator *Bop = dyn_cast(OrArg)) { + if (Bop->getOpcode() == BO_And) + return EmitDiagnosticForBitwiseAndInBitwiseOr(S, OpLoc, Bop); + } +} + /// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky /// precedence. static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc, SourceLocation OpLoc, Expr *lhs, Expr *rhs){ // Diagnose "arg1 'bitwise' arg2 'eq' arg3". if (BinaryOperator::isBitwiseOp(Opc)) - return DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs); + DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs); + + // Diagnose "arg1 & arg2 | arg3" + if (Opc == BO_Or && !OpLoc.isMacroID()/* Don't warn in macros. */) { + DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, lhs); + DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, rhs); + } // Warn about arg1 || arg2 && arg3, as GCC 4.3+ does. // We don't warn for 'assert(a || b && "bad")' since this is safe. diff --git a/test/Sema/parentheses.c b/test/Sema/parentheses.c index 95e0a930fe..13ea3ecbe1 100644 --- a/test/Sema/parentheses.c +++ b/test/Sema/parentheses.c @@ -26,6 +26,12 @@ void bitwise_rel(unsigned i) { (void)(i == 1 | i == 2 | i == 3); (void)(i != 1 & i != 2 & i != 3); + (void)(i & i | i); // expected-warning {{'&' within '|'}} \ + // expected-note {{place parentheses around the '&' expression to silence this warning}} + + (void)(i | i & i); // expected-warning {{'&' within '|'}} \ + // expected-note {{place parentheses around the '&' expression to silence this warning}} + (void)(i || i && i); // expected-warning {{'&&' within '||'}} \ // expected-note {{place parentheses around the '&&' expression to silence this warning}}