[Diagnostics] Handle tautological left shifts in boolean context
authorDavid Bolvansky <david.bolvansky@gmail.com>
Tue, 24 Sep 2019 13:14:18 +0000 (13:14 +0000)
committerDavid Bolvansky <david.bolvansky@gmail.com>
Tue, 24 Sep 2019 13:14:18 +0000 (13:14 +0000)
llvm-svn: 372749

clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Sema/SemaChecking.cpp
clang/test/Sema/warn-int-in-bool-context.c

index e7dacc8..08fe50c 100644 (file)
@@ -6155,6 +6155,10 @@ def warn_integer_constants_in_conditional_always_true : Warning<
   "converting the result of '?:' with integer constants to a boolean always "
   "evaluates to 'true'">,
   InGroup<TautologicalConstantCompare>;
+def warn_left_shift_always : Warning<
+  "converting the result of '<<' to a boolean always evaluates "
+  "to %select{false|true}0">,
+  InGroup<TautologicalConstantCompare>;
 def warn_comparison_of_mixed_enum_types : Warning<
   "comparison of two values with different enumeration types"
   "%diff{ ($ and $)|}0,1">,
index 59b875a..02c0d48 100644 (file)
@@ -11314,17 +11314,26 @@ static void DiagnoseIntInBoolContext(Sema &S, Expr *E) {
 
   if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
     BinaryOperator::Opcode Opc = BO->getOpcode();
+    Expr::EvalResult Result;
     // Do not diagnose unsigned shifts.
-    if (Opc == BO_Shl && E->getType()->isSignedIntegerType())
-      S.Diag(ExprLoc, diag::warn_left_shift_in_bool_context) << E;
+    if (Opc == BO_Shl) {
+      const auto *LHS = getIntegerLiteral(BO->getLHS());
+      const auto *RHS = getIntegerLiteral(BO->getRHS());
+      if (LHS && LHS->getValue() == 0)
+        S.Diag(ExprLoc, diag::warn_left_shift_always) << 0;
+      else if (RHS && RHS->getValue().isNonNegative() &&
+               E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects))
+        S.Diag(ExprLoc, diag::warn_left_shift_always)
+            << (Result.Val.getInt() != 0);
+      else if (E->getType()->isSignedIntegerType())
+        S.Diag(ExprLoc, diag::warn_left_shift_in_bool_context) << E;
+    }
   }
 
   if (const auto *CO = dyn_cast<ConditionalOperator>(E)) {
     const auto *LHS = getIntegerLiteral(CO->getTrueExpr());
-    if (!LHS)
-      return;
     const auto *RHS = getIntegerLiteral(CO->getFalseExpr());
-    if (!RHS)
+    if (!LHS || !RHS)
       return;
     if ((LHS->getValue() == 0 || LHS->getValue() == 1) &&
         (RHS->getValue() == 0 || RHS->getValue() == 1))
index ae35ca3..0c94ebb 100644 (file)
@@ -24,12 +24,17 @@ enum num {
 
 int test(int a, unsigned b, enum num n) {
   boolean r;
-  r = a << a; // expected-warning {{converting the result of '<<' to a boolean; did you mean '(a << a) != 0'?}}
-  r = MM; // expected-warning {{converting the result of '<<' to a boolean; did you mean '(a << a) != 0'?}}
-  r = (1 << 7); // expected-warning {{converting the result of '<<' to a boolean; did you mean '(1 << 7) != 0'?}}
-  r = 2UL << 2;
-  r = 2 << b; // expected-warning {{converting the result of '<<' to a boolean; did you mean '(2 << b) != 0'?}}
-  r = (unsigned)(2 << b); 
+  r = a << a;    // expected-warning {{converting the result of '<<' to a boolean; did you mean '(a << a) != 0'?}}
+  r = MM;        // expected-warning {{converting the result of '<<' to a boolean; did you mean '(a << a) != 0'?}}
+  r = (1 << 7);  // expected-warning {{converting the result of '<<' to a boolean always evaluates to true}}
+  r = 2UL << 2;  // expected-warning {{converting the result of '<<' to a boolean always evaluates to true}}
+  r = 0 << a;    // expected-warning {{converting the result of '<<' to a boolean always evaluates to false}}
+  r = 0 << 2;    // expected-warning {{converting the result of '<<' to a boolean always evaluates to false}}
+  r = 1 << 0;    // expected-warning {{converting the result of '<<' to a boolean always evaluates to true}}
+  r = 1 << 2;    // expected-warning {{converting the result of '<<' to a boolean always evaluates to true}}
+  r = 1ULL << 2; // expected-warning {{converting the result of '<<' to a boolean always evaluates to true}}
+  r = 2 << b;    // expected-warning {{converting the result of '<<' to a boolean; did you mean '(2 << b) != 0'?}}
+  r = (unsigned)(2 << b);
   r = b << 7;
   r = (1 << a); // expected-warning {{converting the result of '<<' to a boolean; did you mean '(1 << a) != 0'?}}
   r = TWO << a; // expected-warning {{converting the result of '<<' to a boolean; did you mean '(2 << a) != 0'?}}
@@ -39,7 +44,7 @@ int test(int a, unsigned b, enum num n) {
     return a;
 
   for (a = 0; 1 << a; a++) // expected-warning {{converting the result of '<<' to a boolean; did you mean '(1 << a) != 0'?}}
-    ; 
+    ;
 
   if (a << TWO) // expected-warning {{converting the result of '<<' to a boolean; did you mean '(a << 2) != 0'?}}
     return a;