aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticGroups.td4
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td5
-rw-r--r--lib/Sema/SemaExpr.cpp31
-rw-r--r--test/Sema/parentheses.c6
4 files changed, 44 insertions, 2 deletions
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<DiagGroup<"constant-logical-operand">>;
+def warn_bitwise_and_in_bitwise_or : Warning<
+ "'&' within '|'">, InGroup<BitwiseOpParentheses>;
+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<LogicalOpParentheses>;
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<BinaryOperator>(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}}