Author: mitchell
Date: 2025-12-29T20:22:10+08:00
New Revision: 843ebcbb24758996279f9a8018bb765f1ae4a293

URL: 
https://github.com/llvm/llvm-project/commit/843ebcbb24758996279f9a8018bb765f1ae4a293
DIFF: 
https://github.com/llvm/llvm-project/commit/843ebcbb24758996279f9a8018bb765f1ae4a293.diff

LOG: [clang-tidy] Enable C99 in `implicit-bool-conversion` and avoid FP with 
`bool` operands in C23 (#171070)

Closes [#170596](https://github.com/llvm/llvm-project/issues/170596)

---------

Co-authored-by: EugeneZelenko <[email protected]>
Co-authored-by: Baranov Victor <[email protected]>

Added: 
    
clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-c99.c

Modified: 
    clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
    clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.h
    clang-tools-extra/docs/ReleaseNotes.rst
    
clang-tools-extra/docs/clang-tidy/checks/readability/implicit-bool-conversion.rst
    
clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion.c

Removed: 
    


################################################################################
diff  --git 
a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp 
b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
index de77cde3a201c..a0b15603b36e8 100644
--- a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
@@ -27,7 +27,7 @@ AST_MATCHER(Stmt, isMacroExpansion) {
   return SM.isMacroBodyExpansion(Loc) || SM.isMacroArgExpansion(Loc);
 }
 
-AST_MATCHER(Stmt, isC23) { return Finder->getASTContext().getLangOpts().C23; }
+AST_MATCHER(Stmt, isC) { return Finder->getASTContext().getLangOpts().C99; }
 
 // Preserve same name as AST_MATCHER(isNULLMacroExpansion)
 // NOLINTNEXTLINE(llvm-prefer-static-over-anonymous-namespace)
@@ -293,8 +293,8 @@ void 
ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) {
                          hasCastKind(CK_FloatingToBoolean),
                          hasCastKind(CK_PointerToBoolean),
                          hasCastKind(CK_MemberPointerToBoolean)),
-                   // Exclude cases of C23 comparison result.
-                   unless(allOf(isC23(),
+                   // Exclude cases of C comparison result.
+                   unless(allOf(isC(),
                                 hasSourceExpression(ignoringParens(
                                     binaryOperator(hasAnyOperatorName(
                                         ">", ">=", "==", "!=", "<", "<=")))))),
@@ -337,6 +337,9 @@ void 
ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) {
               unless(hasParent(
                   binaryOperator(anyOf(BoolComparison, BoolXor,
                                        BoolOpAssignment, 
BitfieldAssignment)))),
+              // Exclude logical operators in C
+              unless(allOf(isC(), hasParent(binaryOperator(
+                                      hasAnyOperatorName("&&", "||"))))),
               implicitCastExpr().bind("implicitCastFromBool"),
               unless(hasParent(BitfieldConstruct)),
               // Check also for nested casts, for example: bool -> int -> 
float.

diff  --git 
a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.h 
b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.h
index 101089ccfb2e9..6ae15a9e19fe2 100644
--- a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.h
@@ -21,7 +21,7 @@ class ImplicitBoolConversionCheck : public ClangTidyCheck {
 public:
   ImplicitBoolConversionCheck(StringRef Name, ClangTidyContext *Context);
   bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
-    return LangOpts.Bool;
+    return LangOpts.Bool || LangOpts.C99;
   }
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;

diff  --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index ce16f94816aa3..7d878f7d28386 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -630,8 +630,10 @@ Changes in existing checks
 
 - Improved :doc:`readability-implicit-bool-conversion
   <clang-tidy/checks/readability/implicit-bool-conversion>` check by correctly
-  adding parentheses when the inner expression are implicitly converted
-  multiple times.
+  adding parentheses when inner expressions are implicitly converted multiple
+  times, enabling the check for C99 and later standards, and allowing implicit
+  conversions from ``bool`` to integer when used as operands of logical
+  operators (``&&``, ``||``) in C.
 
 - Improved :doc:`readability-inconsistent-declaration-parameter-name
   <clang-tidy/checks/readability/inconsistent-declaration-parameter-name>` 
check

diff  --git 
a/clang-tools-extra/docs/clang-tidy/checks/readability/implicit-bool-conversion.rst
 
b/clang-tools-extra/docs/clang-tidy/checks/readability/implicit-bool-conversion.rst
index 3a37b25023129..66e2fd0beaea1 100644
--- 
a/clang-tools-extra/docs/clang-tidy/checks/readability/implicit-bool-conversion.rst
+++ 
b/clang-tools-extra/docs/clang-tidy/checks/readability/implicit-bool-conversion.rst
@@ -118,6 +118,11 @@ Some additional accommodations are made for pre-C++11 
dialects:
 
 - instead of ``nullptr`` literal, ``0`` is proposed as replacement.
 
+Some additional accommodations are made for C:
+
+- ``bool`` (or ``_Bool``) operands in logical operators (``&&``, ``||``) are
+  ignored.
+
 Occurrences of implicit conversions inside macros and template instantiations
 are deliberately ignored, as it is not clear how to deal with such cases.
 

diff  --git 
a/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-c99.c
 
b/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-c99.c
new file mode 100644
index 0000000000000..c06235cbf0847
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-c99.c
@@ -0,0 +1,43 @@
+// RUN: %check_clang_tidy -std=c99,c11,c17 %s 
readability-implicit-bool-conversion %t
+
+#define true 1
+#define false 0
+
+_Bool returns_bool(void) { return true; }
+int returns_int(void) { return 1; }
+
+void test_c99_logical_ops(void) {
+  _Bool b1 = true;
+  _Bool b2 = false;
+
+  if (b1 && b2) {}
+  if (b1 && returns_int()) {}
+}
+
+void test_c99_comparison(void) {
+  int x = 1;
+  int y = 2;
+  _Bool b = x > y;
+}
+
+void test_c99_native_keyword(void) {
+  _Bool raw_bool = 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit conversion 'int' -> 
'bool' [readability-implicit-bool-conversion]
+  // CHECK-FIXES: _Bool raw_bool = true;
+  int i = raw_bool;
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: implicit conversion 'bool' -> 
'int'
+  // CHECK-FIXES: int i = (int)raw_bool;
+}
+
+void test_c99_macro_behavior(void) {
+  _Bool b = true;
+  int i = b + 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: implicit conversion 'bool' -> 
'int'
+  // CHECK-FIXES: int i = (int)b + 1;
+}
+
+void test_c99_pointer_conversion(int *p) {
+  _Bool b = p;
+  // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: implicit conversion 'int *' -> 
'bool'
+  // CHECK-FIXES: _Bool b = p != 0;
+}

diff  --git 
a/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion.c
 
b/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion.c
index 7f82b95f41799..e6f8eb451f67a 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion.c
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion.c
@@ -75,20 +75,8 @@ void implicitConversionFromBoolInComplexBoolExpressions() {
   bool anotherBoolean = false;
 
   int integer = boolean && anotherBoolean;
-  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: implicit conversion 'bool' -> 
'int'
-  // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: implicit conversion 'bool' -> 
'int'
-  // CHECK-FIXES: int integer = (int)boolean && (int)anotherBoolean;
-
   float floating = (boolean || anotherBoolean) * 0.3f;
-  // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: implicit conversion 'bool' -> 
'int'
-  // CHECK-MESSAGES: :[[@LINE-2]]:32: warning: implicit conversion 'bool' -> 
'int'
-  // CHECK-FIXES: float floating = ((int)boolean || (int)anotherBoolean) * 
0.3f;
-
   double doubleFloating = (boolean && (anotherBoolean || boolean)) * 0.3;
-  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: implicit conversion 'bool' -> 
'int'
-  // CHECK-MESSAGES: :[[@LINE-2]]:40: warning: implicit conversion 'bool' -> 
'int'
-  // CHECK-MESSAGES: :[[@LINE-3]]:58: warning: implicit conversion 'bool' -> 
'int'
-  // CHECK-FIXES: double doubleFloating = ((int)boolean && 
((int)anotherBoolean || (int)boolean)) * 0.3;
 }
 
 void implicitConversionFromBoolLiterals() {
@@ -371,3 +359,29 @@ int keepCompactReturnInC_PR71848() {
 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: implicit conversion 'bool' -> 
'int' [readability-implicit-bool-conversion]
 // CHECK-FIXES: return(int)( foo );
 }
+
+bool returns_bool(void) { return true; }
+
+void implicitConversionFromBoolInLogicalOps(int len) {
+  while (returns_bool()) {}
+  while ((len > 0) && returns_bool()) {}
+  while (returns_bool() && (len > 0)) {}
+  while ((len > 0) || returns_bool()) {}
+  while (returns_bool() || (len > 0)) {}
+}
+
+void checkResultAssignment(void) {
+  int a = returns_bool() || returns_bool();
+  bool b = returns_bool() && returns_bool();
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: implicit conversion 'int' -> 
'bool'
+  // CHECK-FIXES: bool b = (returns_bool() && returns_bool()) != 0;
+}
+
+void checkNestedLogic(void) {
+  bool a = true;
+  bool b = false;
+  bool c = true;
+
+  if ((a && b) || c) {}
+  if (c && (a || b)) {}
+}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to