]> granicus.if.org Git - clang/commitdiff
Implement -Wshift-op-parentheses for: a << b + c
authorDavid Blaikie <dblaikie@gmail.com>
Fri, 5 Oct 2012 00:41:03 +0000 (00:41 +0000)
committerDavid Blaikie <dblaikie@gmail.com>
Fri, 5 Oct 2012 00:41:03 +0000 (00:41 +0000)
This appears to be consistent with GCC's implementation of the same warning
under -Wparentheses. Suppressing a << b + c for cases where 'a' is a user
defined type for compatibility with C++ stream IO. Otherwise suggest
parentheses around the addition or subtraction subexpression.

(this came up when MSVC was complaining (incorrectly, so far as I can tell)
about a perceived violation of this within the LLVM codebase, PR14001)

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@165283 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaExpr.cpp
test/Sema/parentheses.cpp

index 156cf54d706a30d007a09304f1a17ade1e542856..e5e9021e65324fa96116548dafd6f46e74d5a0fc 100644 (file)
@@ -119,6 +119,7 @@ def GlobalConstructors : DiagGroup<"global-constructors">;
 def : DiagGroup<"idiomatic-parentheses">;
 def BitwiseOpParentheses: DiagGroup<"bitwise-op-parentheses">;
 def LogicalOpParentheses: DiagGroup<"logical-op-parentheses">;
+def ShiftOpParentheses: DiagGroup<"shift-op-parentheses">;
 def DanglingElse: DiagGroup<"dangling-else">;
 def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">;
 def : DiagGroup<"import">;
index 0f0f4f13ebe4e0f9e4e2f233ad118c66dce59240..d88933115216b12d7bbf491ca95ccd556933f8f6 100644 (file)
@@ -3863,6 +3863,11 @@ def warn_logical_and_in_logical_or : Warning<
 def note_logical_and_in_logical_or_silence : Note<
   "place parentheses around the '&&' expression to silence this warning">;
 
+def warn_addition_in_bitshift : Warning<
+  "'%0' within '%1'">, InGroup<ShiftOpParentheses>;
+def note_addition_in_bitshift_silence : Note<
+  "place parentheses around the '%0' expression to silence this warning">;
+
 def warn_self_assignment : Warning<
   "explicitly assigning a variable of type %0 to itself">,
   InGroup<SelfAssignment>, DefaultIgnore;
index bbae55b5980c6ca0d26bdceff7e1f072f2cf7c5e..d40818b83b0d6a36a2bd9a9dd29647a07669a82b 100644 (file)
@@ -8570,6 +8570,20 @@ static void DiagnoseBitwiseAndInBitwiseOr(Sema &S, SourceLocation OpLoc,
   }
 }
 
+static void DiagnoseAdditionInShift(Sema &S, SourceLocation OpLoc,
+                                    Expr *SubExpr, StringRef shift) {
+  if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(SubExpr)) {
+    if (Bop->getOpcode() == BO_Add || Bop->getOpcode() == BO_Sub) {
+      StringRef op = Bop->getOpcode() == BO_Add ? "+" : "-";
+      S.Diag(Bop->getOperatorLoc(), diag::warn_addition_in_bitshift)
+          << Bop->getSourceRange() << OpLoc << op << shift;
+      SuggestParentheses(S, Bop->getOperatorLoc(),
+          S.PDiag(diag::note_addition_in_bitshift_silence) << op,
+          Bop->getSourceRange());
+    }
+  }
+}
+
 /// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky
 /// precedence.
 static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc,
@@ -8591,6 +8605,13 @@ static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc,
     DiagnoseLogicalAndInLogicalOrLHS(Self, OpLoc, LHSExpr, RHSExpr);
     DiagnoseLogicalAndInLogicalOrRHS(Self, OpLoc, LHSExpr, RHSExpr);
   }
+
+  if ((Opc == BO_Shl && LHSExpr->getType()->isIntegralType(Self.getASTContext()))
+      || Opc == BO_Shr) {
+    StringRef shift = Opc == BO_Shl ? "<<" : ">>";
+    DiagnoseAdditionInShift(Self, OpLoc, LHSExpr, shift);
+    DiagnoseAdditionInShift(Self, OpLoc, RHSExpr, shift);
+  }
 }
 
 // Binary Operators.  'Tok' is the token for the operator.
index 767416677e00f4d5d4c2fd5315f569ddf361031e..d0dcdda0bf3b21ef957b19119de2e36033aa3566 100644 (file)
@@ -22,6 +22,8 @@ public:
   operator int();
   Stream &operator<<(int);
   Stream &operator<<(const char*);
+  Stream &operator>>(int);
+  Stream &operator>>(const char*);
 };
 
 void f(Stream& s, bool b) {
@@ -45,3 +47,13 @@ void test(S *s, bool (S::*m_ptr)()) {
   // Don't crash on unusual member call expressions.
   (void)((s->*m_ptr)() ? "foo" : "bar");
 }
+
+void test(int a, int b, int c) {
+  (void)(a >> b + c); // expected-warning {{'+' within '>>'}} \
+                         expected-note {{place parentheses around the '+' expression to silence this warning}}
+  (void)(a - b << c); // expected-warning {{'-' within '<<'}} \
+                         expected-note {{place parentheses around the '-' expression to silence this warning}}
+  Stream() << b + c;
+  Stream() >> b + c; // expected-warning {{'+' within '>>'}} \
+                        expected-note {{place parentheses around the '+' expression to silence this warning}}
+}