[clang] [Clang] add -Wshift-bool warning to handle shifting of bool (PR #127336)

Oleksandr T. via cfe-commits cfe-commits at lists.llvm.org
Sat Feb 15 08:21:55 PST 2025


https://github.com/a-tarasyuk created https://github.com/llvm/llvm-project/pull/127336

Fixes #28334

--- 

This PR introduces the `-Wshift-bool` warning to detect and warn against shifting `bool` values using the `<<` or `>>` operators. Shifting a `bool` implicitly converts it to an `int`, which can lead to unintended behavior. 

>From 272385df25b791b50472b92e12157477d021a26f Mon Sep 17 00:00:00 2001
From: Oleksandr T <oleksandr.tarasiuk at outlook.com>
Date: Sat, 15 Feb 2025 18:19:44 +0200
Subject: [PATCH] [Clang] add -Wshift-bool warning to handle shifting of bool

---
 clang/docs/ReleaseNotes.rst                   |  1 +
 clang/include/clang/Basic/DiagnosticGroups.td |  2 ++
 .../clang/Basic/DiagnosticSemaKinds.td        |  3 +++
 clang/lib/Sema/SemaExpr.cpp                   |  6 ++++++
 clang/test/Sema/shift-bool.cpp                | 21 +++++++++++++++++++
 5 files changed, 33 insertions(+)
 create mode 100644 clang/test/Sema/shift-bool.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 6056a6964fbcc..d623d7daf05ea 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -138,6 +138,7 @@ Improvements to Clang's diagnostics
 - Fixed a bug where Clang's Analysis did not correctly model the destructor behavior of ``union`` members (#GH119415).
 - A statement attribute applied to a ``case`` label no longer suppresses
   'bypassing variable initialization' diagnostics (#84072).
+- The ``-Wshift-bool`` warning has been added to warn about shifting a ``boolean``. (#GH28334)
 
 Improvements to Clang's time-trace
 ----------------------------------
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 05e39899e6f25..193aea3a8dfc3 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -461,6 +461,8 @@ def DanglingField : DiagGroup<"dangling-field">;
 def DanglingInitializerList : DiagGroup<"dangling-initializer-list">;
 def DanglingGsl : DiagGroup<"dangling-gsl">;
 def ReturnStackAddress : DiagGroup<"return-stack-address">;
+def ShiftBool: DiagGroup<"shift-bool">;
+
 // Name of this warning in GCC
 def : DiagGroup<"return-local-addr", [ReturnStackAddress]>;
 def Dangling : DiagGroup<"dangling", [DanglingAssignment,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index c4f0fc55b4a38..754cf1e14799b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7115,6 +7115,9 @@ def warn_shift_result_sets_sign_bit : Warning<
   "signed shift result (%0) sets the sign bit of the shift expression's "
   "type (%1) and becomes negative">,
   InGroup<DiagGroup<"shift-sign-overflow">>, DefaultIgnore;
+def warn_shift_bool : Warning<
+  "%select{left|right}0 shifting a `bool` implicitly converts it to 'int'">,
+  InGroup<ShiftBool>, DefaultIgnore;
 
 def warn_precedence_bitwise_rel : Warning<
   "%0 has lower precedence than %1; %1 will be evaluated first">,
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 3cd4010740d19..0816403b2df2a 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -11246,6 +11246,12 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS,
   if (S.getLangOpts().OpenCL)
     return;
 
+  if (LHS.get()->IgnoreParenImpCasts()->getType()->isBooleanType()) {
+    S.Diag(Loc, diag::warn_shift_bool)
+        << (Opc == BO_Shr) /*left|right*/ << LHS.get()->getSourceRange();
+    return;
+  }
+
   // Check right/shifter operand
   Expr::EvalResult RHSResult;
   if (RHS.get()->isValueDependent() ||
diff --git a/clang/test/Sema/shift-bool.cpp b/clang/test/Sema/shift-bool.cpp
new file mode 100644
index 0000000000000..dfbc1a1e73307
--- /dev/null
+++ b/clang/test/Sema/shift-bool.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -Wshift-bool -verify %s
+
+void t() {
+  int x = 10;
+  bool y = true;
+
+  bool a = y << x; // expected-warning {{left shifting a `bool` implicitly converts it to 'int'}}
+  bool b = y >> x; // expected-warning {{right shifting a `bool` implicitly converts it to 'int'}}
+
+  bool c = false << x; // expected-warning {{left shifting a `bool` implicitly converts it to 'int'}}
+  bool d = false >> x; // expected-warning {{right shifting a `bool` implicitly converts it to 'int'}}
+
+  bool e = y << 5; // expected-warning {{left shifting a `bool` implicitly converts it to 'int'}}
+  bool f = y >> 5; // expected-warning {{right shifting a `bool` implicitly converts it to 'int'}}
+
+  bool g = y << -1; // expected-warning {{left shifting a `bool` implicitly converts it to 'int'}}
+  bool h = y >> -1; // expected-warning {{right shifting a `bool` implicitly converts it to 'int'}}
+
+  bool i = y << 0; // expected-warning {{left shifting a `bool` implicitly converts it to 'int'}}
+  bool j = y >> 0; // expected-warning {{right shifting a `bool` implicitly converts it to 'int'}}
+}



More information about the cfe-commits mailing list