]> granicus.if.org Git - clang/commitdiff
[Diagnostics] Warn if '<<' in bool context with -Wint-in-bool-context (GCC compatibility)
authorDavid Bolvansky <david.bolvansky@gmail.com>
Mon, 23 Sep 2019 14:21:08 +0000 (14:21 +0000)
committerDavid Bolvansky <david.bolvansky@gmail.com>
Mon, 23 Sep 2019 14:21:08 +0000 (14:21 +0000)
Extracted from D63082, addressed review comments related to a warning message.

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

include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaChecking.cpp
test/Sema/warn-int-in-bool-context.c [new file with mode: 0644]
test/SemaCXX/cxx2a-explicit-bool.cpp

index 4e2f85d4e7c520b0deec8fd58e57ad7669b3f9ce..4c7ea3d4ea20d93dc1476f57d9e13df165ce008b 100644 (file)
@@ -499,6 +499,7 @@ def StringCompare : DiagGroup<"string-compare">;
 def StringPlusInt : DiagGroup<"string-plus-int">;
 def StringPlusChar : DiagGroup<"string-plus-char">;
 def StrncatSize : DiagGroup<"strncat-size">;
+def IntInBoolContext : DiagGroup<"int-in-bool-context">;
 def TautologicalTypeLimitCompare : DiagGroup<"tautological-type-limit-compare">;
 def TautologicalUnsignedZeroCompare : DiagGroup<"tautological-unsigned-zero-compare">;
 def TautologicalUnsignedEnumZeroCompare : DiagGroup<"tautological-unsigned-enum-zero-compare">;
@@ -821,6 +822,7 @@ def Most : DiagGroup<"most", [
     Format,
     Implicit,
     InfiniteRecursion,
+    IntInBoolContext,
     MismatchedTags,
     MissingBraces,
     Move,
index 5f47da03338b29638104cafa9547494173672eb2..26b328b9990f545e2f79c61bb76830b928ff272c 100644 (file)
@@ -5720,6 +5720,9 @@ def warn_precedence_conditional : Warning<
 def note_precedence_conditional_first : Note<
   "place parentheses around the '?:' expression to evaluate it first">;
 
+def warn_left_shift_in_bool_context : Warning<
+  "converting the result of '<<' to a boolean; did you mean '(%0) != 0'?">,
+  InGroup<IntInBoolContext>;
 def warn_logical_instead_of_bitwise : Warning<
   "use of logical '%0' with constant operand">,
   InGroup<DiagGroup<"constant-logical-operand">>;
index 7aeace5c2a7d5dd0abfd1005bed9d5f9d23ffbb4..cbe7e9a82383015249e5cfe9d708bbfe5c4e7d6b 100644 (file)
@@ -11256,10 +11256,16 @@ static bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T,
   return true;
 }
 
-static void DiagnoseIntInBoolContext(Sema &S, const Expr *E) {
+static void DiagnoseIntInBoolContext(Sema &S, Expr *E) {
   E = E->IgnoreParenImpCasts();
   SourceLocation ExprLoc = E->getExprLoc();
 
+  if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
+    BinaryOperator::Opcode Opc = BO->getOpcode();
+    if (Opc == BO_Shl)
+      S.Diag(ExprLoc, diag::warn_left_shift_in_bool_context) << E;
+  }
+
   if (const auto *CO = dyn_cast<ConditionalOperator>(E)) {
     const auto *LHS = dyn_cast<IntegerLiteral>(CO->getTrueExpr());
     if (!LHS) {
@@ -11585,6 +11591,9 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
 
   S.DiscardMisalignedMemberAddress(Target, E);
 
+  if (Target->isBooleanType())
+    DiagnoseIntInBoolContext(S, E);
+
   if (!Source->isIntegerType() || !Target->isIntegerType())
     return;
 
diff --git a/test/Sema/warn-int-in-bool-context.c b/test/Sema/warn-int-in-bool-context.c
new file mode 100644 (file)
index 0000000..0a0d88f
--- /dev/null
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -x c -fsyntax-only -verify -Wint-in-bool-context %s
+// RUN: %clang_cc1 -x c -fsyntax-only -verify -Wall %s
+// RUN: %clang_cc1 -x c++ -fsyntax-only -verify -Wint-in-bool-context %s
+// RUN: %clang_cc1 -x c++ -fsyntax-only -verify -Wall %s
+
+#define ONE 1
+#define TWO 2
+
+#define SHIFT(l, r) l << r
+
+#ifdef __cplusplus
+typedef bool boolean;
+#else
+typedef _Bool boolean;
+#endif
+
+int test(int a) {
+  boolean r;
+  r = (1 << 3); // expected-warning {{converting the result of '<<' to a boolean; did you mean '(1 << 3) != 0'?}}
+  r = TWO << 7; // expected-warning {{converting the result of '<<' to a boolean; did you mean '(2 << 7) != 0'?}}
+  r = a << 7;   // expected-warning {{converting the result of '<<' to a boolean; did you mean '(a << 7) != 0'?}}
+  r = ONE << a; // expected-warning {{converting the result of '<<' to a boolean; did you mean '(1 << a) != 0'?}}
+  if (TWO << 4) // expected-warning {{converting the result of '<<' to a boolean; did you mean '(2 << 4) != 0'?}}
+    return a;
+
+  if (a << TWO) // expected-warning {{converting the result of '<<' to a boolean; did you mean '(a << 2) != 0'?}}
+    return a;
+
+  // Don't warn in macros.
+  return SHIFT(1, a);
+}
index 56fa76f0a8bd5b9078a2f6b5bc3bfc32cbc91177..bb62a25bdf196e4bcdc626dae94f9f4c44e034a1 100644 (file)
@@ -20,7 +20,7 @@ namespace special_cases
 template<int a>
 struct A {
 // expected-note@-1+ {{candidate constructor}}
-  explicit(1 << a)
+  explicit(1 << a)  // expected-warning {{converting the result of '<<' to a boolean; did you mean '(1 << -1) != 0'?}}
 // expected-note@-1 {{negative shift count -1}}
 // expected-error@-2 {{explicit specifier argument is not a constant expression}}
   A(int);