[clang-tools-extra] 843ebcb - [clang-tidy] Enable C99 in `implicit-bool-conversion` and avoid FP with `bool` operands in C23 (#171070)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Dec 29 04:22:15 PST 2025
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 <eugene.zelenko at gmail.com>
Co-authored-by: Baranov Victor <bar.victor.2002 at gmail.com>
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)) {}
+}
More information about the cfe-commits
mailing list