https://github.com/shivaansharma created 
https://github.com/llvm/llvm-project/pull/208162

Fixes #208078.

The `bugprone-misplaced-widening-cast` check currently warns on casts like 
`static_cast<std::size_t>(x * 2)` even when `x` is a `constexpr` variable and 
the multiplication provably does not overflow the narrower type. This is 
pointless churn, since the compiler can prove the cast is safe as written.

This PR teaches `getMaxCalculationWidth` to evaluate `constexpr` operands at 
compile time and use their actual bit-width instead of the declared type's full 
width, when the value is non-negative (so overflow cases still warn). 
Non-`constexpr` `const` values are unaffected and still warn, matching existing 
check semantics.

See the linked issue for the original discussion, including the 
counter-examples this PR is designed to preserve (non-constexpr const, and 
constexpr values that do overflow).

>From d890f389a887393e78330f948ba4111b613f22d3 Mon Sep 17 00:00:00 2001
From: shivaan sharma <[email protected]>
Date: Wed, 8 Jul 2026 13:01:01 +0530
Subject: [PATCH] [clang-tidy] Don't warn on misplaced-widening-cast for
 provably non-overflowing constexpr values

The check now evaluates constexpr operands at compile time and skips
the diagnostic when the value provably does not overflow the narrower
type. Non-constexpr const values and constexpr values that do overflow
still warn as before.

Fixes #208078
---
 .../bugprone/MisplacedWideningCastCheck.cpp   |  9 ++++++
 clang-tools-extra/docs/ReleaseNotes.rst       |  7 +++++
 .../bugprone/misplaced-widening-cast.rst      | 28 +++++++++++++++++++
 .../misplaced-widening-cast-explicit-only.cpp | 24 ++++++++++++++++
 4 files changed, 68 insertions(+)

diff --git 
a/clang-tools-extra/clang-tidy/bugprone/MisplacedWideningCastCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/MisplacedWideningCastCheck.cpp
index 61bbbf8af2abd..9b405cf80bdff 100644
--- a/clang-tools-extra/clang-tidy/bugprone/MisplacedWideningCastCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/MisplacedWideningCastCheck.cpp
@@ -90,6 +90,15 @@ static unsigned getMaxCalculationWidth(const ASTContext 
&Context,
     return T->isIntegerType() ? Context.getIntWidth(T) : 1024U;
   } else if (const auto *I = dyn_cast<IntegerLiteral>(E)) {
     return I->getValue().getActiveBits();
+  } else if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
+    if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+      if (VD->isConstexpr()) {
+        Expr::EvalResult Result;
+        if (E->EvaluateAsInt(Result, Context) &&
+            !Result.Val.getInt().isNegative())
+          return Result.Val.getInt().getActiveBits();
+      }
+    }
   }
 
   return Context.getIntWidth(E->getType());
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index b85ece288881e..e29dfa3c926cd 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -417,6 +417,13 @@ Changes in existing checks
   positive on bit field assignments when the `CheckImplicitCasts` option is
   enabled. The check now uses the actual bit field width instead of the
   declared type to determine if widening occurs.
+  
+- Improved :doc:`bugprone-misplaced-widening-cast
+  <clang-tidy/checks/bugprone/misplaced-widening-cast>` check by fixing a false
+  positive when the calculation operand is a ``constexpr`` variable whose
+  compile-time value provably fits without overflow in the narrower type. The
+  check still warns when the operand is a non-``constexpr`` ``const`` or when
+  the ``constexpr`` value does overflow.
 
 - Improved :doc:`bugprone-move-forwarding-reference
   <clang-tidy/checks/bugprone/move-forwarding-reference>` check by fixing some
diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/bugprone/misplaced-widening-cast.rst 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/misplaced-widening-cast.rst
index cec49c55309ad..dedb1662ec8a7 100644
--- 
a/clang-tools-extra/docs/clang-tidy/checks/bugprone/misplaced-widening-cast.rst
+++ 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/misplaced-widening-cast.rst
@@ -57,6 +57,34 @@ written for this code:
         return (double)(x * 10.0f);
     }
 
+Constexpr operands
+------------------
+
+If the calculation operand is a ``constexpr`` variable, the check evaluates
+its compile-time value. If the value provably does not overflow the narrower
+type, no warning is issued, since the cast is then not actually masking any
+loss of precision:
+
+.. code-block:: c++
+
+    void f(std::size_t (*bar)(std::size_t)) {
+        constexpr int x = 256;
+        bar(static_cast<std::size_t>(x * 2)); // No warning: x * 2 == 512,
+                                               // which fits in int.
+    }
+
+A plain ``const`` (not ``constexpr``) variable does not get this exception,
+since the check does not attempt to prove non-``constexpr`` values are
+compile-time constants. A ``constexpr`` value that does overflow the narrower
+type is still diagnosed as before:
+
+.. code-block:: c++
+
+    void f(std::size_t (*bar)(std::size_t)) {
+        constexpr int x = -1;
+        bar(static_cast<std::size_t>(x * 2)); // Still warns: overflows int.
+    }
+
 Options
 -------
 
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/misplaced-widening-cast-explicit-only.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/misplaced-widening-cast-explicit-only.cpp
index 56eba15f2cd0e..d5cd43de67bb7 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/misplaced-widening-cast-explicit-only.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/misplaced-widening-cast-explicit-only.cpp
@@ -80,3 +80,27 @@ void nextDay(DaysEnum day) {
   if (day < SUN)
     day = static_cast<DaysEnum>(day + 1);
 }
+
+// Constexpr values that are provably non-overflowing should not warn,
+// even though the cast is technically "misplaced" relative to the
+// multiplication. See https://github.com/llvm/llvm-project/issues/208078
+void constexprNoOverflow() {
+  constexpr int x = 256;
+  long l = static_cast<long>(x * 2);
+}
+
+// A non-constexpr const does NOT get this exception: 'const' alone does not
+// prove the compiler evaluated it as a compile-time constant expression from
+// the check's point of view, and this mirrors clang's own narrowing checks.
+void constNotConstexprStillWarns() {
+  const int x = 256;
+  long l = static_cast<long>(x * 2);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: either cast from 'int' to 'long'
+}
+
+// A constexpr value that DOES overflow the narrow type must still warn.
+void constexprOverflowStillWarns() {
+  constexpr int x = -1;
+  long l = static_cast<long>(x * 2);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: either cast from 'int' to 'long'
+}

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

Reply via email to