Update to newer base revision.

http://reviews.llvm.org/D5765

Files:
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaExpr.cpp
  test/SemaCXX/warn-mismatch.cpp

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
Index: include/clang/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -233,6 +233,7 @@
 def CXX11LongLong : DiagGroup<"c++11-long-long">;
 def LongLong : DiagGroup<"long-long", [CXX11LongLong]>;
 def MethodSignatures : DiagGroup<"method-signatures">;
+def MismatchedOperators : DiagGroup<"mismatched-operators">;
 def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">;
 def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">;
 def MismatchedTags : DiagGroup<"mismatched-tags">;
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -36,6 +36,15 @@
   "been assigned">, InGroup<DiagGroup<"duplicate-enum">>, DefaultIgnore;
 def note_duplicate_element : Note<"element %0 also has value %1">;
 
+def warn_wrong_binary_operator : Warning<
+  "using %select{bitwise|logical}0 operator when both operands are "
+  "%select{logical|bitwise}0">, InGroup<MismatchedOperators>, DefaultIgnore;
+def warn_mismatch_operators : Warning<
+  "using %select{bitwise|logical}0 %select{and|or}1 operator with "
+  "%select{logical|bitwise}0 not">, InGroup<MismatchedOperators>, DefaultIgnore;
+def note_suggest_operator : Note<
+  "did you mean to use %select{bitwise|logical}0 %select{and|or|not}1?">;
+
 // Absolute value functions
 def warn_unsigned_abs : Warning<
   "taking the absolute value of unsigned type %0 has no effect">,
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -10097,6 +10097,154 @@
     DiagnoseShiftCompare(Self, OpLoc, LHSExpr, RHSExpr);
 }
 
+namespace {
+
+enum OperatorKind { Other, Bitwise, Logical };
+
+// Determine if the operator is a logical or bitwise type.
+OperatorKind getOperatorKind(BinaryOperatorKind Opc) {
+  switch (Opc) {
+  default:
+    return Other;
+  case BO_Or:
+  case BO_And:
+    return Bitwise;
+  case BO_LOr:
+  case BO_LAnd:
+    return Logical;
+  }
+}
+
+// Determine if the operator is a logical or bitwise type.
+OperatorKind getOperatorKind(UnaryOperator *UO) {
+  if (!UO)
+    return Other;
+  switch (UO->getOpcode()) {
+  default:
+    return Other;
+  case UO_LNot:
+    return Logical;
+  case UO_Not:
+    return Bitwise;
+  }
+}
+
+// Switch between bitwise and logical operators.
+BinaryOperatorKind getOppositeOpcode(BinaryOperatorKind Opc) {
+  switch (Opc) {
+  default:
+    llvm_unreachable("Unexpected opcode");
+  case BO_LAnd:
+    return BO_And;
+  case BO_LOr:
+    return BO_Or;
+  case BO_And:
+    return BO_LAnd;
+  case BO_Or:
+    return BO_LOr;
+  }
+}
+
+// Switch between bitwise and logical operators.
+UnaryOperatorKind getOppositeOpcode(UnaryOperatorKind Opc) {
+  switch (Opc) {
+  default:
+    llvm_unreachable("Unexpected opcode");
+  case UO_LNot:
+    return UO_Not;
+  case UO_Not:
+    return UO_LNot;
+  }
+}
+
+static void DiagnoseIncorrectNot(Sema &Self, BinaryOperatorKind Opc,
+                                 SourceLocation OpLoc, Expr *LHSExpr,
+                                 Expr *RHSExpr) {
+  const OperatorKind BinOpKind = getOperatorKind(Opc);
+  if (BinOpKind == Other)
+    return;
+
+  UnaryOperator *LHS_UO = dyn_cast<UnaryOperator>(LHSExpr);
+  OperatorKind LHSKind = getOperatorKind(LHS_UO);
+
+  UnaryOperator *RHS_UO = dyn_cast<UnaryOperator>(RHSExpr);
+  OperatorKind RHSKind = getOperatorKind(RHS_UO);
+
+  if (RHSKind == LHSKind) {
+    // LHS and RHS have same type, possible suggest to change binary operator.
+    if (RHSKind == Other) {
+      // No not operators.
+      return;
+    }
+    if (LHSKind == BinOpKind) {
+      // Operands and binary operator are the same type.
+      return;
+    }
+
+    const BinaryOperatorKind NewOpcode = getOppositeOpcode(Opc);
+    const StringRef NewOperator = BinaryOperator::getOpcodeStr(NewOpcode);
+    const bool BinaryOrOperator = Opc == BO_Or || Opc == BO_LOr;
+
+    Self.Diag(OpLoc, diag::warn_wrong_binary_operator)
+        << (BinOpKind == Logical);
+    Self.Diag(OpLoc, diag::note_suggest_operator)
+        << (BinOpKind != Logical) << BinaryOrOperator
+        << FixItHint::CreateReplacement(SourceRange(OpLoc), NewOperator);
+    return;
+  }
+
+  if (RHSKind == Other || LHSKind == Other) {
+    // Either LHS or RHS do not use a not operator.  Possible suggest either
+    // switching the not operator or switching the binary operator.
+    OperatorKind Kind = (RHSKind != Other) ? RHSKind : LHSKind;
+    if (Kind == BinOpKind)
+      return;
+
+    UnaryOperator *NotExpr = (RHSKind != Other) ? RHS_UO : LHS_UO;
+
+    const BinaryOperatorKind NewBinOpcode = getOppositeOpcode(Opc);
+    const StringRef NewBinaryOperator =
+        BinaryOperator::getOpcodeStr(NewBinOpcode);
+    const UnaryOperatorKind NewUnaryOpcode =
+        getOppositeOpcode(NotExpr->getOpcode());
+    const StringRef NewUnaryOperator =
+        UnaryOperator::getOpcodeStr(NewUnaryOpcode);
+    const bool BinaryOrOperator = Opc == BO_Or || Opc == BO_LOr;
+
+    Self.Diag(OpLoc, diag::warn_mismatch_operators) << (BinOpKind == Logical)
+                                                    << BinaryOrOperator
+                                                    << NotExpr->getExprLoc();
+    Self.Diag(OpLoc, diag::note_suggest_operator)
+        << (BinOpKind == Logical) << BinaryOrOperator
+        << FixItHint::CreateReplacement(SourceRange(OpLoc), NewBinaryOperator);
+    Self.Diag(OpLoc, diag::note_suggest_operator)
+        << (Kind == Logical) << 2 /*not*/
+        << FixItHint::CreateReplacement(SourceRange(NotExpr->getOperatorLoc()),
+                                        NewUnaryOperator);
+    return;
+  }
+
+  if (RHSKind == BinOpKind || LHSKind == BinOpKind) {
+    // RHS and LHS are different kinds of not operators.  Suggest switching one
+    // of them to match the binary operator.
+    UnaryOperator *UO = (RHSKind != BinOpKind) ? RHS_UO : LHS_UO;
+    const bool BinaryOrOperator = Opc == BO_Or || Opc == BO_LOr;
+    const UnaryOperatorKind NewUnaryOpcode = getOppositeOpcode(UO->getOpcode());
+    const StringRef NewUnaryOperator =
+        UnaryOperator::getOpcodeStr(NewUnaryOpcode);
+    Self.Diag(OpLoc, diag::warn_mismatch_operators)
+        << (BinOpKind == Logical) << BinaryOrOperator << UO->getExprLoc();
+    Self.Diag(OpLoc, diag::note_suggest_operator)
+        << (BinOpKind == Logical) << 2 /*not*/
+        << FixItHint::CreateReplacement(SourceRange(UO->getOperatorLoc()),
+                                        NewUnaryOperator);
+    return;
+  }
+
+  llvm_unreachable("unable to process BinaryOperator");
+}
+}
+
 // Binary Operators.  'Tok' is the token for the operator.
 ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
                             tok::TokenKind Kind,
@@ -10108,6 +10256,8 @@
   // Emit warnings for tricky precedence issues, e.g. "bitfield & 0x4 == 0"
   DiagnoseBinOpPrecedence(*this, Opc, TokLoc, LHSExpr, RHSExpr);
 
+  DiagnoseIncorrectNot(*this, Opc, TokLoc, LHSExpr, RHSExpr);
+
   return BuildBinOp(S, TokLoc, Opc, LHSExpr, RHSExpr);
 }
 
Index: test/SemaCXX/warn-mismatch.cpp
===================================================================
--- test/SemaCXX/warn-mismatch.cpp
+++ test/SemaCXX/warn-mismatch.cpp
@@ -0,0 +1,100 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wmismatched-operators %s
+
+void test_negative(int x, int y, int z) {
+  z = x | y;
+  z = x & y;
+  z = ~x | y;
+  z = ~x & y;
+  z = x | ~y;
+  z = x & ~y;
+  z = ~x | ~y;
+  z = ~x & ~y;
+
+  z = x || y;
+  z = x && y;
+  z = !x || y;
+  z = !x && y;
+  z = x || !y;
+  z = x && !y;
+  z = !x || !y;
+  z = !x && !y;
+}
+
+void test_same_operand(int x, int y, int z) {
+  z = !x | !y;
+  // expected-warning@-1 {{using bitwise operator when both operands are logical}}
+  // expected-note@-2 {{did you mean to use logical or?}}
+  z = !x & !y;
+  // expected-warning@-1 {{using bitwise operator when both operands are logical}}
+  // expected-note@-2 {{did you mean to use logical and?}}
+  z = ~x || ~y;
+  // expected-warning@-1 {{using logical operator when both operands are bitwise}}
+  // expected-note@-2 {{did you mean to use bitwise or?}}
+  z = ~x && ~y;
+  // expected-warning@-1 {{using logical operator when both operands are bitwise}}
+  // expected-note@-2 {{did you mean to use bitwise and?}}
+}
+
+void test_different_operand(int x, int y, int z) {
+  z = !x | ~y;
+  // expected-warning@-1 {{using bitwise or operator with logical not}}
+  // expected-note@-2 {{did you mean to use bitwise not?}}
+  z = !x & ~y;
+  // expected-warning@-1 {{using bitwise and operator with logical not}}
+  // expected-note@-2 {{did you mean to use bitwise not?}}
+  z = !x || ~y;
+  // expected-warning@-1 {{using logical or operator with bitwise not}}
+  // expected-note@-2 {{did you mean to use logical not?}}
+  z = !x && ~y;
+  // expected-warning@-1 {{using logical and operator with bitwise not}}
+  // expected-note@-2 {{did you mean to use logical not?}}
+
+  z = ~x | !y;
+  // expected-warning@-1 {{using bitwise or operator with logical not}}
+  // expected-note@-2 {{did you mean to use bitwise not?}}
+  z = ~x & !y;
+  // expected-warning@-1 {{using bitwise and operator with logical not}}
+  // expected-note@-2 {{did you mean to use bitwise not?}}
+  z = ~x || !y;
+  // expected-warning@-1 {{using logical or operator with bitwise not}}
+  // expected-note@-2 {{did you mean to use logical not?}}
+  z = ~x && !y;
+  // expected-warning@-1 {{using logical and operator with bitwise not}}
+  // expected-note@-2 {{did you mean to use logical not?}}
+}
+
+void test_one_operand(int x, int y, int z) {
+  z = !x | y;
+  // expected-warning@-1 {{using bitwise or operator with logical not}}
+  // expected-note@-2 {{did you mean to use bitwise or?}}
+  // expected-note@-3 {{did you mean to use logical not?}}
+  z = !x & y;
+  // expected-warning@-1 {{using bitwise and operator with logical not}}
+  // expected-note@-2 {{did you mean to use bitwise and?}}
+  // expected-note@-3 {{did you mean to use logical not?}}
+  z = ~x || y;
+  // expected-warning@-1 {{using logical or operator with bitwise not}}
+  // expected-note@-2 {{did you mean to use logical or?}}
+  // expected-note@-3 {{did you mean to use bitwise not?}}
+  z = ~x && y;
+  // expected-warning@-1 {{using logical and operator with bitwise not}}
+  // expected-note@-2 {{did you mean to use logical and?}}
+  // expected-note@-3 {{did you mean to use bitwise not?}}
+
+  z = x | !y;
+  // expected-warning@-1 {{using bitwise or operator with logical not}}
+  // expected-note@-2 {{did you mean to use bitwise or?}}
+  // expected-note@-3 {{did you mean to use logical not?}}
+  z = x & !y;
+  // expected-warning@-1 {{using bitwise and operator with logical not}}
+  // expected-note@-2 {{did you mean to use bitwise and?}}
+  // expected-note@-3 {{did you mean to use logical not?}}
+  z = x || ~y;
+  // expected-warning@-1 {{using logical or operator with bitwise not}}
+  // expected-note@-2 {{did you mean to use logical or?}}
+  // expected-note@-3 {{did you mean to use bitwise not?}}
+  z = x && ~y;
+  // expected-warning@-1 {{using logical and operator with bitwise not}}
+  // expected-note@-2 {{did you mean to use logical and?}}
+  // expected-note@-3 {{did you mean to use bitwise not?}}
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to