[clang-tools-extra] [clang-tidy] Improve redundant-casting check for binary operation (PR #191386)

Gaurav Dhingra via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 16 03:04:42 PDT 2026


https://github.com/gxyd updated https://github.com/llvm/llvm-project/pull/191386

>From f9ad8da3a37ba112600503e6bfe179b2948449a8 Mon Sep 17 00:00:00 2001
From: Gaurav Dhingra <gauravdhingra.gxyd at gmail.com>
Date: Fri, 10 Apr 2026 16:14:58 +0530
Subject: [PATCH 01/11] [clang-tidy] Improve redundant-casting check for binary
 operation

Mark explicit casting as readabily redundant for a
BinaryOperation with atleast one operand of the same
type as the cast type in `RedundantCastingCheck`

E.g.; `static<float>(1 + 2.0f)`  // redundant cast

Fixes #182132
---
 .../readability/RedundantCastingCheck.cpp       | 17 ++++++++++-------
 .../checkers/readability/redundant-casting.cpp  | 16 ++++++++++++++++
 2 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp
index eae0b3f6d0e7d..9dc4cef139125 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp
@@ -50,7 +50,7 @@ static bool areTypesEqual(QualType TypeS, QualType TypeD,
                                             TypeD.getLocalUnqualifiedType());
 }
 
-static bool areBinaryOperatorOperandsTypesEqualToOperatorResultType(
+static bool anyBinaryOperatorOperandsTypesEqualToOperatorResultType(
     const Expr *E, bool IgnoreTypeAliases) {
   if (!E)
     return true;
@@ -64,12 +64,15 @@ static bool areBinaryOperatorOperandsTypesEqualToOperatorResultType(
 
     const QualType NonReferenceType = Type.getNonReferenceType();
     const QualType LHSType = B->getLHS()->IgnoreImplicit()->getType();
-    if (LHSType.isNull() || !areTypesEqual(LHSType.getNonReferenceType(),
-                                           NonReferenceType, IgnoreTypeAliases))
-      return false;
     const QualType RHSType = B->getRHS()->IgnoreImplicit()->getType();
-    if (RHSType.isNull() || !areTypesEqual(RHSType.getNonReferenceType(),
-                                           NonReferenceType, IgnoreTypeAliases))
+    const bool LHSMatches =
+        !LHSType.isNull() && areTypesEqual(LHSType.getNonReferenceType(),
+                                           NonReferenceType, IgnoreTypeAliases);
+    const bool RHSMatches =
+        !RHSType.isNull() && areTypesEqual(RHSType.getNonReferenceType(),
+                                           NonReferenceType, IgnoreTypeAliases);
+    if (!LHSMatches && !RHSMatches)
+      // neither of the operand matches => casting is needed for readability
       return false;
   }
   return true;
@@ -145,7 +148,7 @@ void RedundantCastingCheck::check(const MatchFinder::MatchResult &Result) {
   if (!areTypesEqual(TypeS, TypeD, IgnoreTypeAliases))
     return;
 
-  if (!areBinaryOperatorOperandsTypesEqualToOperatorResultType(
+  if (!anyBinaryOperatorOperandsTypesEqualToOperatorResultType(
           SourceExpr, IgnoreTypeAliases))
     return;
 
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
index 001057aeaa495..8a0f271d55e29 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
@@ -14,6 +14,8 @@
 // RUN:   -config='{CheckOptions: { readability-redundant-casting.IgnoreTypeAliases: true }}' \
 // RUN:   -- -fno-delayed-template-parsing -D CXX_20=1
 
+#include <cstdint>
+
 struct A {};
 struct B : A {};
 A getA();
@@ -168,6 +170,20 @@ void testFunctionalCastWithInitExpr(unsigned a) {
   unsigned c = unsigned{0};
 }
 
+void testBinaryOperatorRedundantCasting() {
+  const auto diff_types_operands1 { static_cast<float>(1.0f + 1) };
+  // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant explicit casting to the same type 'float' as the sub-expression, remove this casting [readability-redundant-casting]
+  // CHECK-FIXES: const auto diff_types_operands1 { (1.0f + 1) };
+
+  const auto diff_types_operands2 { static_cast<float>(2 + 3.0f) };
+  // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant explicit casting to the same type 'float' as the sub-expression, remove this casting [readability-redundant-casting]
+  // CHECK-FIXES: const auto diff_types_operands2 { (2 + 3.0f) };
+
+  const auto diff_types_operands3 { static_cast<int>(1 + static_cast<uint8_t>(1)) };
+  // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant explicit casting to the same type 'int' as the sub-expression, remove this casting [readability-redundant-casting]
+  // CHECK-FIXES: const auto diff_types_operands3 { (1 + static_cast<uint8_t>(1)) };
+}
+
 void testBinaryOperator(char c) {
   int a = int(c - 'C');
 }

>From 92011b394b551f53df2997d48f1a76f152ab791a Mon Sep 17 00:00:00 2001
From: Gaurav Dhingra <gauravdhingra.gxyd at gmail.com>
Date: Sat, 11 Apr 2026 12:47:51 +0530
Subject: [PATCH 02/11] add ReleaseNotes entry for the fixed issue

---
 clang-tools-extra/docs/ReleaseNotes.rst | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 3d126910d2e2e..4e645384f5caa 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -509,6 +509,12 @@ Changes in existing checks
     implicit conversions of logical operator results (``&&``, ``||``, ``!``)
     to ``bool`` in C.
 
+- Improved :doc:`readability-redundant-casting
+  <clang-tidy/checks/readability/redundant-casting>` check by fixing a false
+  negative where casts were not flagged as redundant when at least one operand
+  of a binary operation had the same type as the cast result type. For example,
+  ``static_cast<float>(1.0f + 1)`` is now correctly identified as redundant.
+
 - Improved :doc:`readability-non-const-parameter
   <clang-tidy/checks/readability/non-const-parameter>` check:
 

>From 9757878bcf7992c641c24046eb624a776249ddec Mon Sep 17 00:00:00 2001
From: Gaurav Dhingra <gauravdhingra.gxyd at gmail.com>
Date: Sat, 11 Apr 2026 15:45:10 +0530
Subject: [PATCH 03/11] add more test cases

add test cases for: ``int`` & ``unsigned`` , ``size_t`` & ``int``
---
 .../checkers/readability/redundant-casting.cpp     | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
index 8a0f271d55e29..336d17c7d69ef 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
@@ -15,6 +15,7 @@
 // RUN:   -- -fno-delayed-template-parsing -D CXX_20=1
 
 #include <cstdint>
+#include <cstddef>
 
 struct A {};
 struct B : A {};
@@ -182,6 +183,19 @@ void testBinaryOperatorRedundantCasting() {
   const auto diff_types_operands3 { static_cast<int>(1 + static_cast<uint8_t>(1)) };
   // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant explicit casting to the same type 'int' as the sub-expression, remove this casting [readability-redundant-casting]
   // CHECK-FIXES: const auto diff_types_operands3 { (1 + static_cast<uint8_t>(1)) };
+
+  const auto diff_types_operands4 {
+    static_cast<size_t>(static_cast<size_t>(3) + 2)
+  };
+  // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: redundant explicit casting to the same type 'size_t' (aka 'unsigned long') as the sub-expression, remove this casting [readability-redundant-casting]
+  // CHECK-FIXES: (static_cast<size_t>(3) + 2)
+
+  const auto diff_types_operands5 { unsigned(7 + unsigned(4)) };
+  // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant explicit casting to the same type 'unsigned int' as the sub-expression, remove this casting [readability-redundant-casting]
+  // CHECK-FIXES: const auto diff_types_operands5 { (7 + unsigned(4)) };
+
+  // casting isn't redundant here
+  const auto diff_types_operands6 { (int)(-7 + unsigned(4)) };
 }
 
 void testBinaryOperator(char c) {

>From e795dd269eb8b638dfb732ae7f2c9c88f4503248 Mon Sep 17 00:00:00 2001
From: Gaurav Dhingra <gauravdhingra.gxyd at gmail.com>
Date: Sat, 11 Apr 2026 16:28:18 +0530
Subject: [PATCH 04/11] fix alphabetic order of the added ReleaseNotes entry

---
 clang-tools-extra/docs/ReleaseNotes.rst | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 4e645384f5caa..f06b2e3354774 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -509,12 +509,6 @@ Changes in existing checks
     implicit conversions of logical operator results (``&&``, ``||``, ``!``)
     to ``bool`` in C.
 
-- Improved :doc:`readability-redundant-casting
-  <clang-tidy/checks/readability/redundant-casting>` check by fixing a false
-  negative where casts were not flagged as redundant when at least one operand
-  of a binary operation had the same type as the cast result type. For example,
-  ``static_cast<float>(1.0f + 1)`` is now correctly identified as redundant.
-
 - Improved :doc:`readability-non-const-parameter
   <clang-tidy/checks/readability/non-const-parameter>` check:
 
@@ -534,6 +528,12 @@ Changes in existing checks
   false positive for nested ``#if`` directives using different builtin
   expressions such as ``__has_builtin`` and ``__has_cpp_attribute``.
 
+- Improved :doc:`readability-redundant-casting
+  <clang-tidy/checks/readability/redundant-casting>` check by fixing a false
+  negative where casts were not flagged as redundant when at least one operand
+  of a binary operation had the same type as the cast result type. For example,
+  ``static_cast<float>(1.0f + 1)`` is now correctly identified as redundant.
+
 - Improved :doc:`readability-simplify-boolean-expr
   <clang-tidy/checks/readability/simplify-boolean-expr>` check to provide valid
   fix suggestions for C23 and later by not using ``static_cast``.

>From ac00ab62406915873d555931cd749f494047e27b Mon Sep 17 00:00:00 2001
From: Gaurav Dhingra <gauravdhingra.gxyd at gmail.com>
Date: Sat, 11 Apr 2026 16:28:41 +0530
Subject: [PATCH 05/11] use optional CHECK-MESSAGE string for Windows platforma

---
 .../test/clang-tidy/checkers/readability/redundant-casting.cpp  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
index 336d17c7d69ef..9e49e599af6f3 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
@@ -187,7 +187,7 @@ void testBinaryOperatorRedundantCasting() {
   const auto diff_types_operands4 {
     static_cast<size_t>(static_cast<size_t>(3) + 2)
   };
-  // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: redundant explicit casting to the same type 'size_t' (aka 'unsigned long') as the sub-expression, remove this casting [readability-redundant-casting]
+  // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: redundant explicit casting to the same type 'size_t' (aka 'unsigned long{{( long)?}}') as the sub-expression, remove this casting [readability-redundant-casting]
   // CHECK-FIXES: (static_cast<size_t>(3) + 2)
 
   const auto diff_types_operands5 { unsigned(7 + unsigned(4)) };

>From 4d4f6f4f01a14a8e6e98c72b7d780dc5c62c9d7e Mon Sep 17 00:00:00 2001
From: Gaurav Dhingra <gauravdhingra.gxyd at gmail.com>
Date: Sat, 11 Apr 2026 16:36:11 +0530
Subject: [PATCH 06/11] fix the order of ReleaseNotes entry again

---
 clang-tools-extra/docs/ReleaseNotes.rst | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index f06b2e3354774..2da76b8994971 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -523,17 +523,17 @@ Changes in existing checks
   `IgnoreMacros` option to suppress warnings when the initializer involves
   macros that may expand differently in other configurations.
 
-- Improved :doc:`readability-redundant-preprocessor
-  <clang-tidy/checks/readability/redundant-preprocessor>` check by fixing a
-  false positive for nested ``#if`` directives using different builtin
-  expressions such as ``__has_builtin`` and ``__has_cpp_attribute``.
-
 - Improved :doc:`readability-redundant-casting
   <clang-tidy/checks/readability/redundant-casting>` check by fixing a false
   negative where casts were not flagged as redundant when at least one operand
   of a binary operation had the same type as the cast result type. For example,
   ``static_cast<float>(1.0f + 1)`` is now correctly identified as redundant.
 
+- Improved :doc:`readability-redundant-preprocessor
+  <clang-tidy/checks/readability/redundant-preprocessor>` check by fixing a
+  false positive for nested ``#if`` directives using different builtin
+  expressions such as ``__has_builtin`` and ``__has_cpp_attribute``.
+
 - Improved :doc:`readability-simplify-boolean-expr
   <clang-tidy/checks/readability/simplify-boolean-expr>` check to provide valid
   fix suggestions for C23 and later by not using ``static_cast``.

>From b18088853d319a98b219eb0f23219a6ae57da090 Mon Sep 17 00:00:00 2001
From: Gaurav Dhingra <gauravdhingra.gxyd at gmail.com>
Date: Thu, 16 Apr 2026 13:08:28 +0530
Subject: [PATCH 07/11] add option IgnoreImplicitCasts to Redundant Casting
 check

---
 .../readability/RedundantCastingCheck.cpp     | 20 ++++++++++------
 .../readability/RedundantCastingCheck.h       |  1 +
 .../checks/readability/redundant-casting.rst  | 23 +++++++++++++++----
 3 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp
index 9dc4cef139125..7d634e67add9c 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp
@@ -50,8 +50,8 @@ static bool areTypesEqual(QualType TypeS, QualType TypeD,
                                             TypeD.getLocalUnqualifiedType());
 }
 
-static bool anyBinaryOperatorOperandsTypesEqualToOperatorResultType(
-    const Expr *E, bool IgnoreTypeAliases) {
+static bool BinaryOperatorOperandsTypesEqualToOperatorResultType(
+    const Expr *E, bool IgnoreTypeAliases, bool IgnoreImplicitCasts) {
   if (!E)
     return true;
   const Expr *WithoutImplicitAndParen = E->IgnoreParenImpCasts();
@@ -71,9 +71,13 @@ static bool anyBinaryOperatorOperandsTypesEqualToOperatorResultType(
     const bool RHSMatches =
         !RHSType.isNull() && areTypesEqual(RHSType.getNonReferenceType(),
                                            NonReferenceType, IgnoreTypeAliases);
-    if (!LHSMatches && !RHSMatches)
-      // neither of the operand matches => casting is needed for readability
+    if (!IgnoreImplicitCasts) {
+      if (!LHSMatches && !RHSMatches)
+        // neither of the operand matches => casting is needed for readability
+        return false;
+    } else if (!LHSMatches || !RHSMatches) {
       return false;
+    }
   }
   return true;
 }
@@ -95,11 +99,13 @@ RedundantCastingCheck::RedundantCastingCheck(StringRef Name,
                                              ClangTidyContext *Context)
     : ClangTidyCheck(Name, Context),
       IgnoreMacros(Options.get("IgnoreMacros", true)),
-      IgnoreTypeAliases(Options.get("IgnoreTypeAliases", false)) {}
+      IgnoreTypeAliases(Options.get("IgnoreTypeAliases", false)),
+      IgnoreImplicitCasts(Options.get("IgnoreImplicitCasts", false)) {}
 
 void RedundantCastingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "IgnoreMacros", IgnoreMacros);
   Options.store(Opts, "IgnoreTypeAliases", IgnoreTypeAliases);
+  Options.store(Opts, "IgnoreImplicitCasts", IgnoreImplicitCasts);
 }
 
 void RedundantCastingCheck::registerMatchers(MatchFinder *Finder) {
@@ -148,8 +154,8 @@ void RedundantCastingCheck::check(const MatchFinder::MatchResult &Result) {
   if (!areTypesEqual(TypeS, TypeD, IgnoreTypeAliases))
     return;
 
-  if (!anyBinaryOperatorOperandsTypesEqualToOperatorResultType(
-          SourceExpr, IgnoreTypeAliases))
+  if (!BinaryOperatorOperandsTypesEqualToOperatorResultType(
+          SourceExpr, IgnoreTypeAliases, IgnoreImplicitCasts))
     return;
 
   const auto *CastExpr = Result.Nodes.getNodeAs<ExplicitCastExpr>("cast");
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.h
index c09767d0cda2b..25bfb4410a27f 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.h
@@ -31,6 +31,7 @@ class RedundantCastingCheck : public ClangTidyCheck {
 private:
   const bool IgnoreMacros;
   const bool IgnoreTypeAliases;
+  const bool IgnoreImplicitCasts;
 };
 
 } // namespace clang::tidy::readability
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-casting.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-casting.rst
index 4b6c14ba1cf87..cd9ef09bcaf81 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-casting.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-casting.rst
@@ -27,11 +27,24 @@ Options
 
 .. option:: IgnoreMacros
 
-   If set to `true`, the check will not give warnings inside macros. Default
-   is `true`.
+  If set to `true`, the check will not give warnings inside macros. Default
+  is `true`.
 
 .. option:: IgnoreTypeAliases
 
-   When set to `false`, the check will consider type aliases, and when set to
-   `true`, it will resolve all type aliases and operate on the underlying
-   types. Default is `false`.
+  When set to `false`, the check will consider type aliases, and when set to
+  `true`, it will resolve all type aliases and operate on the underlying types.
+  Default is `false`.
+
+.. option:: IgnoreImplicitCasts
+
+  When set to `false`, the check will flag casts as redundant when atleast one
+  operand in an expression is implicitly cast to match the result type of the
+  explicit cast. When set to `true` the casts will not be flagged. Default is
+  `false`.
+
+  For example, with `IgnoreImplicitCasts = false`:
+
+  .. code-block:: c++
+
+    static_cast<float>(2.0f + 1);  // redundant (1 implicitly converts to float)

>From 0a6d0ca7f82b9742018ac0cbf1c6f7e7b361b775 Mon Sep 17 00:00:00 2001
From: Gaurav Dhingra <gauravdhingra.gxyd at gmail.com>
Date: Thu, 16 Apr 2026 14:14:32 +0530
Subject: [PATCH 08/11] add testing for "IgnoreImplicitCasts" when set to to
 true

---
 .../checkers/readability/redundant-casting.cpp        | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
index 9e49e599af6f3..13be4192f49d1 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
@@ -5,6 +5,9 @@
 // RUN: %check_clang_tidy -std=c++11,c++14,c++17 -check-suffix=,ALIASES %s readability-redundant-casting %t -- \
 // RUN:   -config='{CheckOptions: { readability-redundant-casting.IgnoreTypeAliases: true }}' \
 // RUN:   -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++11,c++14,c++17 -check-suffix=IMPLICIT %s readability-redundant-casting %t -- \
+// RUN:   -config='{CheckOptions: { readability-redundant-casting.IgnoreImplicitCasts: true }}' \
+// RUN:   -- -fno-delayed-template-parsing
 // RUN: %check_clang_tidy -std=c++20-or-later %s readability-redundant-casting %t -- \
 // RUN:   -- -fno-delayed-template-parsing -D CXX_20=1
 // RUN: %check_clang_tidy -std=c++20-or-later -check-suffix=,MACROS %s readability-redundant-casting %t -- \
@@ -13,6 +16,9 @@
 // RUN: %check_clang_tidy -std=c++20-or-later -check-suffix=,ALIASES %s readability-redundant-casting %t -- \
 // RUN:   -config='{CheckOptions: { readability-redundant-casting.IgnoreTypeAliases: true }}' \
 // RUN:   -- -fno-delayed-template-parsing -D CXX_20=1
+// RUN: %check_clang_tidy -std=c++20-or-later -check-suffix=IMPLICIT %s readability-redundant-casting %t -- \
+// RUN:   -config='{CheckOptions: { readability-redundant-casting.IgnoreImplicitCasts: true }}' \
+// RUN:   -- -fno-delayed-template-parsing -D CXX_20=1
 
 #include <cstdint>
 #include <cstddef>
@@ -175,24 +181,29 @@ void testBinaryOperatorRedundantCasting() {
   const auto diff_types_operands1 { static_cast<float>(1.0f + 1) };
   // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant explicit casting to the same type 'float' as the sub-expression, remove this casting [readability-redundant-casting]
   // CHECK-FIXES: const auto diff_types_operands1 { (1.0f + 1) };
+  // CHECK-FIXES-IMPLICIT: const auto diff_types_operands1 { static_cast<float>(1.0f + 1) };
 
   const auto diff_types_operands2 { static_cast<float>(2 + 3.0f) };
   // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant explicit casting to the same type 'float' as the sub-expression, remove this casting [readability-redundant-casting]
   // CHECK-FIXES: const auto diff_types_operands2 { (2 + 3.0f) };
+  // CHECK-FIXES-IMPLICIT: const auto diff_types_operands2 { static_cast<float>(2 + 3.0f) };
 
   const auto diff_types_operands3 { static_cast<int>(1 + static_cast<uint8_t>(1)) };
   // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant explicit casting to the same type 'int' as the sub-expression, remove this casting [readability-redundant-casting]
   // CHECK-FIXES: const auto diff_types_operands3 { (1 + static_cast<uint8_t>(1)) };
+  // CHECK-FIXES-IMPLICIT: const auto diff_types_operands3 { static_cast<int>(1 + static_cast<uint8_t>(1)) };
 
   const auto diff_types_operands4 {
     static_cast<size_t>(static_cast<size_t>(3) + 2)
   };
   // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: redundant explicit casting to the same type 'size_t' (aka 'unsigned long{{( long)?}}') as the sub-expression, remove this casting [readability-redundant-casting]
   // CHECK-FIXES: (static_cast<size_t>(3) + 2)
+  // CHECK-FIXES-IMPLICIT: static_cast<size_t>(static_cast<size_t>(3) + 2)
 
   const auto diff_types_operands5 { unsigned(7 + unsigned(4)) };
   // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant explicit casting to the same type 'unsigned int' as the sub-expression, remove this casting [readability-redundant-casting]
   // CHECK-FIXES: const auto diff_types_operands5 { (7 + unsigned(4)) };
+  // CHECK-FIXES-IMPLICIT: const auto diff_types_operands5 { unsigned(7 + unsigned(4)) };
 
   // casting isn't redundant here
   const auto diff_types_operands6 { (int)(-7 + unsigned(4)) };

>From 6b1c3ad9da99846de836d18eca7604c17242899e Mon Sep 17 00:00:00 2001
From: Gaurav Dhingra <gauravdhingra.gxyd at gmail.com>
Date: Thu, 16 Apr 2026 15:12:06 +0530
Subject: [PATCH 09/11] use simpler logic to check whether casting is needed

---
 .../readability/RedundantCastingCheck.cpp       | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp
index 7d634e67add9c..8cd943ceb76fd 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp
@@ -50,7 +50,7 @@ static bool areTypesEqual(QualType TypeS, QualType TypeD,
                                             TypeD.getLocalUnqualifiedType());
 }
 
-static bool BinaryOperatorOperandsTypesEqualToOperatorResultType(
+static bool binaryOperatorOperandsTypesEqualToOperatorResultType(
     const Expr *E, bool IgnoreTypeAliases, bool IgnoreImplicitCasts) {
   if (!E)
     return true;
@@ -71,13 +71,14 @@ static bool BinaryOperatorOperandsTypesEqualToOperatorResultType(
     const bool RHSMatches =
         !RHSType.isNull() && areTypesEqual(RHSType.getNonReferenceType(),
                                            NonReferenceType, IgnoreTypeAliases);
-    if (!IgnoreImplicitCasts) {
-      if (!LHSMatches && !RHSMatches)
-        // neither of the operand matches => casting is needed for readability
-        return false;
-    } else if (!LHSMatches || !RHSMatches) {
+    // Explicit Cast is needed if:
+    // IgnoreImplicitCasts = false: neither of operands type matches cast type
+    // IgnoreImplicitCasts = true: at least one operand type doesn't match cast
+    //                             type
+    const bool castIsNeeded = IgnoreImplicitCasts ? (!LHSMatches || !RHSMatches)
+                                                  : (!LHSMatches && !RHSMatches);
+    if (castIsNeeded)
       return false;
-    }
   }
   return true;
 }
@@ -154,7 +155,7 @@ void RedundantCastingCheck::check(const MatchFinder::MatchResult &Result) {
   if (!areTypesEqual(TypeS, TypeD, IgnoreTypeAliases))
     return;
 
-  if (!BinaryOperatorOperandsTypesEqualToOperatorResultType(
+  if (!binaryOperatorOperandsTypesEqualToOperatorResultType(
           SourceExpr, IgnoreTypeAliases, IgnoreImplicitCasts))
     return;
 

>From e7b65ac67eeb65704e4c6c11b43010ba06ef5c8e Mon Sep 17 00:00:00 2001
From: Gaurav Dhingra <gauravdhingra.gxyd at gmail.com>
Date: Thu, 16 Apr 2026 15:21:57 +0530
Subject: [PATCH 10/11] reorder release notes entry to fix alphabetical order

---
 clang-tools-extra/docs/ReleaseNotes.rst | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 2da76b8994971..ebbfd4c6bd185 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -518,17 +518,17 @@ Changes in existing checks
   - Fixed a false positive in array subscript expressions where the types are
     not yet resolved.
 
-- Improved :doc:`readability-redundant-member-init
-  <clang-tidy/checks/readability/redundant-member-init>` check by adding an
-  `IgnoreMacros` option to suppress warnings when the initializer involves
-  macros that may expand differently in other configurations.
-
 - Improved :doc:`readability-redundant-casting
   <clang-tidy/checks/readability/redundant-casting>` check by fixing a false
   negative where casts were not flagged as redundant when at least one operand
   of a binary operation had the same type as the cast result type. For example,
   ``static_cast<float>(1.0f + 1)`` is now correctly identified as redundant.
 
+- Improved :doc:`readability-redundant-member-init
+  <clang-tidy/checks/readability/redundant-member-init>` check by adding an
+  `IgnoreMacros` option to suppress warnings when the initializer involves
+  macros that may expand differently in other configurations.
+
 - Improved :doc:`readability-redundant-preprocessor
   <clang-tidy/checks/readability/redundant-preprocessor>` check by fixing a
   false positive for nested ``#if`` directives using different builtin

>From 9f1dca04b8569a3dd7c6a15d058283a34ec12b1d Mon Sep 17 00:00:00 2001
From: Gaurav Dhingra <gauravdhingra.gxyd at gmail.com>
Date: Thu, 16 Apr 2026 15:33:37 +0530
Subject: [PATCH 11/11] update release notes entry to reflect newly added
 option

---
 clang-tools-extra/docs/ReleaseNotes.rst | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index ebbfd4c6bd185..3510b926fc0cb 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -519,10 +519,15 @@ Changes in existing checks
     not yet resolved.
 
 - Improved :doc:`readability-redundant-casting
-  <clang-tidy/checks/readability/redundant-casting>` check by fixing a false
-  negative where casts were not flagged as redundant when at least one operand
-  of a binary operation had the same type as the cast result type. For example,
-  ``static_cast<float>(1.0f + 1)`` is now correctly identified as redundant.
+  <clang-tidy/checks/readability/redundant-casting>` check
+
+  - Fixed a false negative where casts were not flagged as redundant when
+  atleast one operand of a binary operation had the same type as the cast result
+  type. For example, ``static_cast<float>(1.0f + 1)`` is now correctly
+  identified as redundant.
+
+  - Added `IgnoreImplicitCasts` option to control this, which can be opted-out
+  by setting it to ``true``, default is ``false``.
 
 - Improved :doc:`readability-redundant-member-init
   <clang-tidy/checks/readability/redundant-member-init>` check by adding an



More information about the cfe-commits mailing list