[clang-tools-extra] [clang-tidy] New checker: modernize-use-std-bit to detect std::has_one_bit idiom (PR #185435)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 10 10:23:18 PDT 2026
https://github.com/serge-sans-paille updated https://github.com/llvm/llvm-project/pull/185435
>From 309550019fdac9a0d283350ef180dd457a9f0df4 Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguelton at mozilla.com>
Date: Mon, 9 Mar 2026 09:52:19 +0100
Subject: [PATCH 1/8] [clang-tidy] New checker: modernize.use-std-bit to detect
std::has_one_bit idiom
>From https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2
---
.../clang-tidy/modernize/CMakeLists.txt | 1 +
.../modernize/ModernizeTidyModule.cpp | 2 +
.../clang-tidy/modernize/UseStdBitCheck.cpp | 84 +++++++++++++++++++
.../clang-tidy/modernize/UseStdBitCheck.h | 43 ++++++++++
clang-tools-extra/docs/ReleaseNotes.rst | 5 ++
.../docs/clang-tidy/checks/list.rst | 1 +
.../checkers/modernize/use-std-bit.cpp | 50 +++++++++++
7 files changed, 186 insertions(+)
create mode 100644 clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.h
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index cc4cc7a02b594..2c5c44db587fe 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -47,6 +47,7 @@ add_clang_library(clangTidyModernizeModule STATIC
UseRangesCheck.cpp
UseScopedLockCheck.cpp
UseStartsEndsWithCheck.cpp
+ UseStdBitCheck.cpp
UseStdFormatCheck.cpp
UseStdNumbersCheck.cpp
UseStdPrintCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index fcb860d8c5298..cc13da7535bcb 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -47,6 +47,7 @@
#include "UseRangesCheck.h"
#include "UseScopedLockCheck.h"
#include "UseStartsEndsWithCheck.h"
+#include "UseStdBitCheck.h"
#include "UseStdFormatCheck.h"
#include "UseStdNumbersCheck.h"
#include "UseStdPrintCheck.h"
@@ -96,6 +97,7 @@ class ModernizeModule : public ClangTidyModule {
"modernize-use-scoped-lock");
CheckFactories.registerCheck<UseStartsEndsWithCheck>(
"modernize-use-starts-ends-with");
+ CheckFactories.registerCheck<UseStdBitCheck>("modernize-use-std-bit");
CheckFactories.registerCheck<UseStdFormatCheck>("modernize-use-std-format");
CheckFactories.registerCheck<UseStdNumbersCheck>(
"modernize-use-std-numbers");
diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp
new file mode 100644
index 0000000000000..57014ab88a094
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp
@@ -0,0 +1,84 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseStdBitCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void UseStdBitCheck::registerMatchers(MatchFinder *Finder) {
+ const auto makeBinaryOperatorMatcher = [](auto Op) {
+ return [=](auto LHS, auto RHS) {
+ return binaryOperator(
+ hasOperatorName(Op),
+ hasOperands(ignoringParenImpCasts(LHS), ignoringParenImpCasts(RHS)));
+ };
+ };
+
+ const auto logicalAnd = makeBinaryOperatorMatcher("&&");
+ const auto sub = makeBinaryOperatorMatcher("-");
+ const auto bitwiseAnd = makeBinaryOperatorMatcher("&");
+ const auto cmpNot = makeBinaryOperatorMatcher("!=");
+ const auto cmpGt = makeBinaryOperatorMatcher(">");
+
+ const auto logicalNot = [](auto Expr) {
+ return unaryOperator(hasOperatorName("!"),
+ hasUnaryOperand(ignoringParenImpCasts(Expr)));
+ };
+
+ const auto isNonNull = [=](auto Expr) {
+ return anyOf(Expr, cmpNot(Expr, integerLiteral(equals(0))),
+ cmpGt(Expr, integerLiteral(equals(0))));
+ };
+ const auto bindDeclRef = [](auto Name) {
+ return declRefExpr(to(varDecl(hasType(isUnsignedInteger())).bind(Name)));
+ };
+ const auto boundDeclRef = [](auto Name) {
+ return declRefExpr(to(varDecl(equalsBoundNode(Name))));
+ };
+
+ // https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2
+ // has_one_bit(v) = v && !(v & (v - 1));
+ Finder->addMatcher(
+ logicalAnd(isNonNull(bindDeclRef("v")),
+ logicalNot(bitwiseAnd(
+ boundDeclRef("v"),
+ sub(boundDeclRef("v"), integerLiteral(equals(1))))))
+ .bind("expr"),
+ this);
+}
+
+void UseStdBitCheck::registerPPCallbacks(const SourceManager &SM,
+ Preprocessor *PP,
+ Preprocessor *ModuleExpanderPP) {
+ IncludeInserter.registerPreprocessor(PP);
+}
+
+void UseStdBitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+}
+
+void UseStdBitCheck::check(const MatchFinder::MatchResult &Result) {
+ const ASTContext &Context = *Result.Context;
+ const SourceManager &Source = Context.getSourceManager();
+
+ const auto *MatchedVarDecl = Result.Nodes.getNodeAs<VarDecl>("v");
+ const auto *MatchedExpr = Result.Nodes.getNodeAs<BinaryOperator>("expr");
+
+ diag(MatchedExpr->getBeginLoc(), "use std::has_one_bit instead")
+ << MatchedVarDecl->getName()
+ << FixItHint::CreateReplacement(
+ MatchedExpr->getSourceRange(),
+ ("std::has_one_bit(" + MatchedVarDecl->getName() + ")").str())
+ << IncludeInserter.createIncludeInsertion(
+ Source.getFileID(MatchedExpr->getBeginLoc()), "<bit>");
+}
+
+} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.h b/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.h
new file mode 100644
index 0000000000000..e09a3cf35fe18
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.h
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTDBITCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTDBITCHECK_H
+
+#include "../ClangTidyCheck.h"
+#include "../utils/IncludeInserter.h"
+
+namespace clang::tidy::modernize {
+
+/// use function from <bit> instead of common idioms.
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/modernize/use-std-bit.html
+class UseStdBitCheck : public ClangTidyCheck {
+public:
+ UseStdBitCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+ utils::IncludeSorter::IS_LLVM),
+ areDiagsSelfContained()) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus20;
+ }
+ void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
+ Preprocessor *ModuleExpanderPP) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+ utils::IncludeInserter IncludeInserter;
+};
+
+} // namespace clang::tidy::modernize
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTDBITCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 9f4d7e6923fa0..9fdf0c93a4e3f 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -124,6 +124,11 @@ New checks
``llvm::to_vector(llvm::make_filter_range(...))`` that can be replaced with
``llvm::map_to_vector`` and ``llvm::filter_to_vector``.
+- New :doc:`modernize-use-std-bit
+ <clang-tidy/checks/modernize/use-std-bit>` check.
+
+ Use functions from ``<bit>`` instead of common idioms.
+
- New :doc:`modernize-use-string-view
<clang-tidy/checks/modernize/use-string-view>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 068431fb5c94c..956e495eb4645 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -326,6 +326,7 @@ Clang-Tidy Checks
:doc:`modernize-use-ranges <modernize/use-ranges>`, "Yes"
:doc:`modernize-use-scoped-lock <modernize/use-scoped-lock>`, "Yes"
:doc:`modernize-use-starts-ends-with <modernize/use-starts-ends-with>`, "Yes"
+ :doc:`modernize-use-std-bit <modernize/use-std-bit>`, "Yes"
:doc:`modernize-use-std-format <modernize/use-std-format>`, "Yes"
:doc:`modernize-use-std-numbers <modernize/use-std-numbers>`, "Yes"
:doc:`modernize-use-std-print <modernize/use-std-print>`, "Yes"
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp
new file mode 100644
index 0000000000000..0ef978ff386ce
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp
@@ -0,0 +1,50 @@
+// RUN: %check_clang_tidy -std=c++20-or-later %s modernize-use-std-bit %t
+// CHECK-FIXES: #include <bit>
+
+unsigned bithacks(unsigned x) {
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // CHECK-FIXES: return std::has_one_bit(x);
+ return x && !(x & (x - 1));
+}
+
+unsigned long bithacks(unsigned long x) {
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // CHECK-FIXES: return std::has_one_bit(x);
+ return x && !(x & (x - 1));
+}
+
+unsigned short bithacks(unsigned short x) {
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // CHECK-FIXES: return std::has_one_bit(x);
+ return x && !(x & (x - 1));
+}
+
+unsigned bithacks_perm(unsigned x) {
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // CHECK-FIXES: return std::has_one_bit(x);
+ return x && !((x - 1) & (x));
+}
+
+unsigned bithacks_variant_neq(unsigned x) {
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // CHECK-FIXES: return std::has_one_bit(x);
+ return (x != 0) && !(x & (x - 1));
+}
+
+unsigned bithacks_variant_neq_perm(unsigned x) {
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // CHECK-FIXES: return std::has_one_bit(x);
+ return (x != 0) && !(x & (x - 1));
+}
+
+unsigned bithacks_variant_gt(unsigned x) {
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // CHECK-FIXES: return std::has_one_bit(x);
+ return (x > 0) && !(x & (x - 1));
+}
+
+unsigned bithacks_variant_gt_perm(unsigned x) {
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // CHECK-FIXES: return std::has_one_bit(x);
+ return (x > 0) && !(x & (x - 1));
+}
>From 161cf4c0cda084172bafa417ecaa927f17797afa Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguelton at mozilla.com>
Date: Mon, 9 Mar 2026 16:21:26 +0100
Subject: [PATCH 2/8] fixup! [clang-tidy] New checker: modernize.use-std-bit to
detect std::has_one_bit idiom
---
.../clang-tidy/modernize/UseStdBitCheck.cpp | 34 +++++++++----------
.../checks/modernize/use-std-bit.rst | 17 ++++++++++
2 files changed, 34 insertions(+), 17 deletions(-)
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-bit.rst
diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp
index 57014ab88a094..463def0a89a81 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp
@@ -14,43 +14,43 @@ using namespace clang::ast_matchers;
namespace clang::tidy::modernize {
void UseStdBitCheck::registerMatchers(MatchFinder *Finder) {
- const auto makeBinaryOperatorMatcher = [](auto Op) {
- return [=](auto LHS, auto RHS) {
+ const auto MakeBinaryOperatorMatcher = [](auto Op) {
+ return [=](const auto &LHS, const auto &RHS) {
return binaryOperator(
hasOperatorName(Op),
hasOperands(ignoringParenImpCasts(LHS), ignoringParenImpCasts(RHS)));
};
};
- const auto logicalAnd = makeBinaryOperatorMatcher("&&");
- const auto sub = makeBinaryOperatorMatcher("-");
- const auto bitwiseAnd = makeBinaryOperatorMatcher("&");
- const auto cmpNot = makeBinaryOperatorMatcher("!=");
- const auto cmpGt = makeBinaryOperatorMatcher(">");
+ const auto LogicalAnd = MakeBinaryOperatorMatcher("&&");
+ const auto Sub = MakeBinaryOperatorMatcher("-");
+ const auto BitwiseAnd = MakeBinaryOperatorMatcher("&");
+ const auto CmpNot = MakeBinaryOperatorMatcher("!=");
+ const auto CmpGt = MakeBinaryOperatorMatcher(">");
- const auto logicalNot = [](auto Expr) {
+ const auto LogicalNot = [](const auto &Expr) {
return unaryOperator(hasOperatorName("!"),
hasUnaryOperand(ignoringParenImpCasts(Expr)));
};
- const auto isNonNull = [=](auto Expr) {
- return anyOf(Expr, cmpNot(Expr, integerLiteral(equals(0))),
- cmpGt(Expr, integerLiteral(equals(0))));
+ const auto IsNonNull = [=](const auto &Expr) {
+ return anyOf(Expr, CmpNot(Expr, integerLiteral(equals(0))),
+ CmpGt(Expr, integerLiteral(equals(0))));
};
- const auto bindDeclRef = [](auto Name) {
+ const auto BindDeclRef = [](auto Name) {
return declRefExpr(to(varDecl(hasType(isUnsignedInteger())).bind(Name)));
};
- const auto boundDeclRef = [](auto Name) {
+ const auto BoundDeclRef = [](auto Name) {
return declRefExpr(to(varDecl(equalsBoundNode(Name))));
};
// https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2
// has_one_bit(v) = v && !(v & (v - 1));
Finder->addMatcher(
- logicalAnd(isNonNull(bindDeclRef("v")),
- logicalNot(bitwiseAnd(
- boundDeclRef("v"),
- sub(boundDeclRef("v"), integerLiteral(equals(1))))))
+ LogicalAnd(IsNonNull(BindDeclRef("v")),
+ LogicalNot(BitwiseAnd(
+ BoundDeclRef("v"),
+ Sub(BoundDeclRef("v"), integerLiteral(equals(1))))))
.bind("expr"),
this);
}
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-bit.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-bit.rst
new file mode 100644
index 0000000000000..1d59e3a485cf9
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-bit.rst
@@ -0,0 +1,17 @@
+.. title:: clang-tidy - modernize-use-std-bit
+
+modernize-use-std-bit
+=====================
+
+Find common idioms which can be replaced by standrad functions from the
+``<bit>`` C++20 header.
+
+.. code-block:: c++
+
+ bool has_one_bit = x && !(x & (x - 1));
+
+ // transforms to
+
+ #include <bit>
+
+ bool has_one_bit = std::has_one_bit(x);
>From 6539705a5a940c3af206c1cfa647319e936eb4c5 Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguelton at mozilla.com>
Date: Mon, 9 Mar 2026 17:36:44 +0100
Subject: [PATCH 3/8] fixup! fixup! [clang-tidy] New checker:
modernize.use-std-bit to detect std::has_one_bit idiom
---
clang-tools-extra/docs/ReleaseNotes.rst | 3 ++-
.../docs/clang-tidy/checks/modernize/use-std-bit.rst | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 9fdf0c93a4e3f..050811eea1149 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -127,7 +127,8 @@ New checks
- New :doc:`modernize-use-std-bit
<clang-tidy/checks/modernize/use-std-bit>` check.
- Use functions from ``<bit>`` instead of common idioms.
+ Find common idioms which can be replaced by standard functions from the
+ ``<bit>`` C++20 header.
- New :doc:`modernize-use-string-view
<clang-tidy/checks/modernize/use-string-view>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-bit.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-bit.rst
index 1d59e3a485cf9..f68c29f203144 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-bit.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-bit.rst
@@ -3,7 +3,7 @@
modernize-use-std-bit
=====================
-Find common idioms which can be replaced by standrad functions from the
+Find common idioms which can be replaced by standard functions from the
``<bit>`` C++20 header.
.. code-block:: c++
>From 2323f8687510a45aa7299b25a8ab3074511f1613 Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguelton at mozilla.com>
Date: Tue, 10 Mar 2026 00:23:49 +0100
Subject: [PATCH 4/8] fixup! fixup! fixup! [clang-tidy] New checker:
modernize.use-std-bit to detect std::has_one_bit idiom
---
.../clang-tidy/modernize/UseStdBitCheck.cpp | 29 +++++++++++----
.../clang-tidy/modernize/UseStdBitCheck.h | 19 +++++-----
clang-tools-extra/docs/ReleaseNotes.rst | 2 +-
.../checks/modernize/use-std-bit.rst | 18 ++++-----
.../checkers/modernize/use-std-bit.cpp | 37 +++++++++++++++++++
5 files changed, 78 insertions(+), 27 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp
index 463def0a89a81..4611a48078ffb 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp
@@ -13,8 +13,21 @@ using namespace clang::ast_matchers;
namespace clang::tidy::modernize {
+UseStdBitCheck::UseStdBitCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+ utils::IncludeSorter::IS_LLVM),
+ areDiagsSelfContained()) {}
+
void UseStdBitCheck::registerMatchers(MatchFinder *Finder) {
const auto MakeBinaryOperatorMatcher = [](auto Op) {
+ return [=](const auto &LHS, const auto &RHS) {
+ return binaryOperator(hasOperatorName(Op),
+ hasLHS(ignoringParenImpCasts(LHS)),
+ hasRHS(ignoringParenImpCasts(RHS)));
+ };
+ };
+ const auto MakeCommutativeBinaryOperatorMatcher = [](auto Op) {
return [=](const auto &LHS, const auto &RHS) {
return binaryOperator(
hasOperatorName(Op),
@@ -22,10 +35,10 @@ void UseStdBitCheck::registerMatchers(MatchFinder *Finder) {
};
};
- const auto LogicalAnd = MakeBinaryOperatorMatcher("&&");
+ const auto LogicalAnd = MakeCommutativeBinaryOperatorMatcher("&&");
const auto Sub = MakeBinaryOperatorMatcher("-");
- const auto BitwiseAnd = MakeBinaryOperatorMatcher("&");
- const auto CmpNot = MakeBinaryOperatorMatcher("!=");
+ const auto BitwiseAnd = MakeCommutativeBinaryOperatorMatcher("&");
+ const auto CmpNot = MakeCommutativeBinaryOperatorMatcher("!=");
const auto CmpGt = MakeBinaryOperatorMatcher(">");
const auto LogicalNot = [](const auto &Expr) {
@@ -37,11 +50,12 @@ void UseStdBitCheck::registerMatchers(MatchFinder *Finder) {
return anyOf(Expr, CmpNot(Expr, integerLiteral(equals(0))),
CmpGt(Expr, integerLiteral(equals(0))));
};
- const auto BindDeclRef = [](auto Name) {
- return declRefExpr(to(varDecl(hasType(isUnsignedInteger())).bind(Name)));
+ const auto BindDeclRef = [](StringRef Name) {
+ return declRefExpr(
+ to(varDecl(hasType(isUnsignedInteger())).bind(Name.str())));
};
- const auto BoundDeclRef = [](auto Name) {
- return declRefExpr(to(varDecl(equalsBoundNode(Name))));
+ const auto BoundDeclRef = [](StringRef Name) {
+ return declRefExpr(to(varDecl(equalsBoundNode(Name.str()))));
};
// https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2
@@ -73,7 +87,6 @@ void UseStdBitCheck::check(const MatchFinder::MatchResult &Result) {
const auto *MatchedExpr = Result.Nodes.getNodeAs<BinaryOperator>("expr");
diag(MatchedExpr->getBeginLoc(), "use std::has_one_bit instead")
- << MatchedVarDecl->getName()
<< FixItHint::CreateReplacement(
MatchedExpr->getSourceRange(),
("std::has_one_bit(" + MatchedVarDecl->getName() + ")").str())
diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.h b/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.h
index e09a3cf35fe18..6dd455d4286c4 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.h
@@ -14,26 +14,27 @@
namespace clang::tidy::modernize {
-/// use function from <bit> instead of common idioms.
+/// Finds common idioms which can be replaced by standard functions from the
+/// <bit> C++20 header.
///
/// For the user-facing documentation see:
/// https://clang.llvm.org/extra/clang-tidy/checks/modernize/use-std-bit.html
class UseStdBitCheck : public ClangTidyCheck {
public:
- UseStdBitCheck(StringRef Name, ClangTidyContext *Context)
- : ClangTidyCheck(Name, Context),
- IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
- utils::IncludeSorter::IS_LLVM),
- areDiagsSelfContained()) {}
+ UseStdBitCheck(StringRef Name, ClangTidyContext *Context);
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
- bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
- return LangOpts.CPlusPlus20;
- }
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
Preprocessor *ModuleExpanderPP) override;
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus20;
+ }
+ std::optional<TraversalKind> getCheckTraversalKind() const override {
+ return TK_IgnoreUnlessSpelledInSource;
+ }
+
private:
utils::IncludeInserter IncludeInserter;
};
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 050811eea1149..3c2ea6d2f6fe0 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -127,7 +127,7 @@ New checks
- New :doc:`modernize-use-std-bit
<clang-tidy/checks/modernize/use-std-bit>` check.
- Find common idioms which can be replaced by standard functions from the
+ Finds common idioms which can be replaced by standard functions from the
``<bit>`` C++20 header.
- New :doc:`modernize-use-string-view
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-bit.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-bit.rst
index f68c29f203144..15c3ee6ccecb1 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-bit.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-bit.rst
@@ -3,15 +3,15 @@
modernize-use-std-bit
=====================
-Find common idioms which can be replaced by standard functions from the
+Finds common idioms which can be replaced by standard functions from the
``<bit>`` C++20 header.
-.. code-block:: c++
+Covered scenarios:
- bool has_one_bit = x && !(x & (x - 1));
-
- // transforms to
-
- #include <bit>
-
- bool has_one_bit = std::has_one_bit(x);
+==================================================== =======================
+Expression Replacement
+---------------------------------------------------- -----------------------
+``x && !(x & (x - 1))`` ``std::has_one_bit(x)``
+``(x != 0) && !(x & (x - 1))`` ``std::has_one_bit(x)``
+``(x > 0) && !(x & (x - 1))`` ``std::has_one_bit(x)``
+==================================================== =======================
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp
index 0ef978ff386ce..13d820e894a84 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp
@@ -25,6 +25,12 @@ unsigned bithacks_perm(unsigned x) {
return x && !((x - 1) & (x));
}
+unsigned bithacks_otherperm(unsigned x) {
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // CHECK-FIXES: return std::has_one_bit(x);
+ return !((x - 1) & (x)) && x;
+}
+
unsigned bithacks_variant_neq(unsigned x) {
// CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
// CHECK-FIXES: return std::has_one_bit(x);
@@ -48,3 +54,34 @@ unsigned bithacks_variant_gt_perm(unsigned x) {
// CHECK-FIXES: return std::has_one_bit(x);
return (x > 0) && !(x & (x - 1));
}
+
+/*
+ * Invalid patterns
+ */
+struct integer_like {
+ integer_like operator!() const;
+ bool operator&&(integer_like) const;
+ integer_like operator&(integer_like) const;
+ friend integer_like operator-(integer_like, unsigned);
+};
+
+unsigned invalid_bithacks(integer_like w, unsigned x, signed y, unsigned z) {
+ bool patterns[] = {
+ // non commutative operators
+ x && !(x & (1 - x)),
+ x < 0 && !(x & (x - 1)),
+ x >= 0 && !(x & (x - 1)),
+ // unsupported combinations
+ x && !(x & (z - 1)),
+ z && !(x & (x - 1)),
+ x && !(z & (x - 1)),
+ // unsupported types
+ y && !(y & (y - 1)),
+ w && !(w & (w - 1)),
+ };
+}
+
+template <class T>
+T bithacks_generic(T x) {
+ return x && !(x & (x - 1));
+}
>From 17cb9a3b169dec5cc1e9a1bb0afec3e68df1c0e2 Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguelton at mozilla.com>
Date: Tue, 10 Mar 2026 08:24:16 +0100
Subject: [PATCH 5/8] fixup! fixup! fixup! fixup! [clang-tidy] New checker:
modernize.use-std-bit to detect std::has_one_bit idiom
---
.../clang-tidy/checks/modernize/use-std-bit.rst | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-bit.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-bit.rst
index 15c3ee6ccecb1..87d102d1f6ff8 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-bit.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-bit.rst
@@ -8,10 +8,10 @@ Finds common idioms which can be replaced by standard functions from the
Covered scenarios:
-==================================================== =======================
-Expression Replacement
----------------------------------------------------- -----------------------
-``x && !(x & (x - 1))`` ``std::has_one_bit(x)``
-``(x != 0) && !(x & (x - 1))`` ``std::has_one_bit(x)``
-``(x > 0) && !(x & (x - 1))`` ``std::has_one_bit(x)``
-==================================================== =======================
+============================== =======================
+Expression Replacement
+------------------------------ -----------------------
+``x && !(x & (x - 1))`` ``std::has_one_bit(x)``
+``(x != 0) && !(x & (x - 1))`` ``std::has_one_bit(x)``
+``(x > 0) && !(x & (x - 1))`` ``std::has_one_bit(x)``
+============================== =======================
>From ddec67455654fdda707a86e9a750a11de64e80bf Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguelton at mozilla.com>
Date: Tue, 10 Mar 2026 08:58:32 +0100
Subject: [PATCH 6/8] fixup! fixup! fixup! fixup! fixup! [clang-tidy] New
checker: modernize.use-std-bit to detect std::has_one_bit idiom
---
.../clang-tidy/modernize/UseStdBitCheck.cpp | 14 ++++++++------
.../clang-tidy/checkers/modernize/use-std-bit.cpp | 8 ++++++++
2 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp
index 4611a48078ffb..4b06357395cef 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp
@@ -86,12 +86,14 @@ void UseStdBitCheck::check(const MatchFinder::MatchResult &Result) {
const auto *MatchedVarDecl = Result.Nodes.getNodeAs<VarDecl>("v");
const auto *MatchedExpr = Result.Nodes.getNodeAs<BinaryOperator>("expr");
- diag(MatchedExpr->getBeginLoc(), "use std::has_one_bit instead")
- << FixItHint::CreateReplacement(
- MatchedExpr->getSourceRange(),
- ("std::has_one_bit(" + MatchedVarDecl->getName() + ")").str())
- << IncludeInserter.createIncludeInsertion(
- Source.getFileID(MatchedExpr->getBeginLoc()), "<bit>");
+ auto Diag = diag(MatchedExpr->getBeginLoc(), "use std::has_one_bit instead");
+ if (!MatchedExpr->getSourceRange().getBegin().isMacroID()) {
+ Diag << FixItHint::CreateReplacement(
+ MatchedExpr->getSourceRange(),
+ ("std::has_one_bit(" + MatchedVarDecl->getName() + ")").str())
+ << IncludeInserter.createIncludeInsertion(
+ Source.getFileID(MatchedExpr->getBeginLoc()), "<bit>");
+ }
}
} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp
index 13d820e894a84..b929f76403dc6 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp
@@ -55,6 +55,13 @@ unsigned bithacks_variant_gt_perm(unsigned x) {
return (x > 0) && !(x & (x - 1));
}
+#define HAS_ONE_BIT v && !(v & (v - 1))
+unsigned bithacks_macro(unsigned v) {
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // No fixes, it comes from macro expansion.
+ return HAS_ONE_BIT;
+}
+
/*
* Invalid patterns
*/
@@ -83,5 +90,6 @@ unsigned invalid_bithacks(integer_like w, unsigned x, signed y, unsigned z) {
template <class T>
T bithacks_generic(T x) {
+ // substitution only valid for some instantiation of bithacks_generic
return x && !(x & (x - 1));
}
>From 27053e50715d7366bdcd46fddb4fbed19c7a86db Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguelton at mozilla.com>
Date: Tue, 10 Mar 2026 09:10:59 +0100
Subject: [PATCH 7/8] fixup! fixup! fixup! fixup! fixup! fixup! [clang-tidy]
New checker: modernize.use-std-bit to detect std::has_one_bit idiom
---
.../clang-tidy/modernize/UseStdBitCheck.cpp | 5 ++--
.../checkers/modernize/use-std-bit.cpp | 24 +++++++++++--------
2 files changed, 17 insertions(+), 12 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp
index 4b06357395cef..08bc80d1f8a23 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp
@@ -58,7 +58,7 @@ void UseStdBitCheck::registerMatchers(MatchFinder *Finder) {
return declRefExpr(to(varDecl(equalsBoundNode(Name.str()))));
};
- // https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2
+ // Determining if an integer is a power of 2 with following pattern:
// has_one_bit(v) = v && !(v & (v - 1));
Finder->addMatcher(
LogicalAnd(IsNonNull(BindDeclRef("v")),
@@ -86,7 +86,8 @@ void UseStdBitCheck::check(const MatchFinder::MatchResult &Result) {
const auto *MatchedVarDecl = Result.Nodes.getNodeAs<VarDecl>("v");
const auto *MatchedExpr = Result.Nodes.getNodeAs<BinaryOperator>("expr");
- auto Diag = diag(MatchedExpr->getBeginLoc(), "use std::has_one_bit instead");
+ auto Diag =
+ diag(MatchedExpr->getBeginLoc(), "use 'std::has_one_bit' instead");
if (!MatchedExpr->getSourceRange().getBegin().isMacroID()) {
Diag << FixItHint::CreateReplacement(
MatchedExpr->getSourceRange(),
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp
index b929f76403dc6..0ec08b22cd0f6 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp
@@ -2,62 +2,62 @@
// CHECK-FIXES: #include <bit>
unsigned bithacks(unsigned x) {
- // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use 'std::has_one_bit' instead [modernize-use-std-bit]
// CHECK-FIXES: return std::has_one_bit(x);
return x && !(x & (x - 1));
}
unsigned long bithacks(unsigned long x) {
- // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use 'std::has_one_bit' instead [modernize-use-std-bit]
// CHECK-FIXES: return std::has_one_bit(x);
return x && !(x & (x - 1));
}
unsigned short bithacks(unsigned short x) {
- // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use 'std::has_one_bit' instead [modernize-use-std-bit]
// CHECK-FIXES: return std::has_one_bit(x);
return x && !(x & (x - 1));
}
unsigned bithacks_perm(unsigned x) {
- // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use 'std::has_one_bit' instead [modernize-use-std-bit]
// CHECK-FIXES: return std::has_one_bit(x);
return x && !((x - 1) & (x));
}
unsigned bithacks_otherperm(unsigned x) {
- // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use 'std::has_one_bit' instead [modernize-use-std-bit]
// CHECK-FIXES: return std::has_one_bit(x);
return !((x - 1) & (x)) && x;
}
unsigned bithacks_variant_neq(unsigned x) {
- // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use 'std::has_one_bit' instead [modernize-use-std-bit]
// CHECK-FIXES: return std::has_one_bit(x);
return (x != 0) && !(x & (x - 1));
}
unsigned bithacks_variant_neq_perm(unsigned x) {
- // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use 'std::has_one_bit' instead [modernize-use-std-bit]
// CHECK-FIXES: return std::has_one_bit(x);
return (x != 0) && !(x & (x - 1));
}
unsigned bithacks_variant_gt(unsigned x) {
- // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use 'std::has_one_bit' instead [modernize-use-std-bit]
// CHECK-FIXES: return std::has_one_bit(x);
return (x > 0) && !(x & (x - 1));
}
unsigned bithacks_variant_gt_perm(unsigned x) {
- // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use 'std::has_one_bit' instead [modernize-use-std-bit]
// CHECK-FIXES: return std::has_one_bit(x);
return (x > 0) && !(x & (x - 1));
}
#define HAS_ONE_BIT v && !(v & (v - 1))
unsigned bithacks_macro(unsigned v) {
- // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use std::has_one_bit instead [modernize-use-std-bit]
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use 'std::has_one_bit' instead [modernize-use-std-bit]
// No fixes, it comes from macro expansion.
return HAS_ONE_BIT;
}
@@ -82,6 +82,10 @@ unsigned invalid_bithacks(integer_like w, unsigned x, signed y, unsigned z) {
x && !(x & (z - 1)),
z && !(x & (x - 1)),
x && !(z & (x - 1)),
+ // invalid operators
+ x && !(x | (x - 1)),
+ (bool)(x & !(x & (x - 1))),
+ x && (x & (x - 1)),
// unsupported types
y && !(y & (y - 1)),
w && !(w & (w - 1)),
>From 4266a4abd7eff9d035c0c24e6d5f08f93f51d2db Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguelton at mozilla.com>
Date: Tue, 10 Mar 2026 18:22:41 +0100
Subject: [PATCH 8/8] fixup! fixup! fixup! fixup! fixup! fixup! fixup!
[clang-tidy] New checker: modernize.use-std-bit to detect std::has_one_bit
idiom
---
.../clang-tidy/modernize/UseStdBitCheck.cpp | 14 +++++++++++---
.../checkers/modernize/use-std-bit.cpp | 18 ++++++++++++++++++
2 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp
index 08bc80d1f8a23..ff43f707a867b 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStdBitCheck.cpp
@@ -40,6 +40,12 @@ void UseStdBitCheck::registerMatchers(MatchFinder *Finder) {
const auto BitwiseAnd = MakeCommutativeBinaryOperatorMatcher("&");
const auto CmpNot = MakeCommutativeBinaryOperatorMatcher("!=");
const auto CmpGt = MakeBinaryOperatorMatcher(">");
+ const auto CmpGte = MakeBinaryOperatorMatcher(">=");
+ const auto CmpLt = MakeBinaryOperatorMatcher("<");
+ const auto CmpLte = MakeBinaryOperatorMatcher("<=");
+
+ const auto Literal0 = integerLiteral(equals(0));
+ const auto Literal1 = integerLiteral(equals(1));
const auto LogicalNot = [](const auto &Expr) {
return unaryOperator(hasOperatorName("!"),
@@ -47,8 +53,9 @@ void UseStdBitCheck::registerMatchers(MatchFinder *Finder) {
};
const auto IsNonNull = [=](const auto &Expr) {
- return anyOf(Expr, CmpNot(Expr, integerLiteral(equals(0))),
- CmpGt(Expr, integerLiteral(equals(0))));
+ return anyOf(Expr, CmpNot(Expr, Literal0), CmpGt(Expr, Literal0),
+ CmpGte(Expr, Literal1), CmpLt(Literal0, Expr),
+ CmpLte(Literal1, Expr));
};
const auto BindDeclRef = [](StringRef Name) {
return declRefExpr(
@@ -88,7 +95,8 @@ void UseStdBitCheck::check(const MatchFinder::MatchResult &Result) {
auto Diag =
diag(MatchedExpr->getBeginLoc(), "use 'std::has_one_bit' instead");
- if (!MatchedExpr->getSourceRange().getBegin().isMacroID()) {
+ if (auto R = MatchedExpr->getSourceRange();
+ !R.getBegin().isMacroID() && !R.getEnd().isMacroID()) {
Diag << FixItHint::CreateReplacement(
MatchedExpr->getSourceRange(),
("std::has_one_bit(" + MatchedVarDecl->getName() + ")").str())
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp
index 0ec08b22cd0f6..51f9d3485fc26 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-bit.cpp
@@ -49,6 +49,24 @@ unsigned bithacks_variant_gt(unsigned x) {
return (x > 0) && !(x & (x - 1));
}
+unsigned bithacks_variant_gte(unsigned x) {
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use 'std::has_one_bit' instead [modernize-use-std-bit]
+ // CHECK-FIXES: return std::has_one_bit(x);
+ return (x >= 1) && !(x & (x - 1));
+}
+
+unsigned bithacks_variant_lt(unsigned x) {
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use 'std::has_one_bit' instead [modernize-use-std-bit]
+ // CHECK-FIXES: return std::has_one_bit(x);
+ return (0 < x) && !(x & (x - 1));
+}
+
+unsigned bithacks_variant_lte(unsigned x) {
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use 'std::has_one_bit' instead [modernize-use-std-bit]
+ // CHECK-FIXES: return std::has_one_bit(x);
+ return (1 <= x) && !(x & (x - 1));
+}
+
unsigned bithacks_variant_gt_perm(unsigned x) {
// CHECK-MESSAGES: :[[@LINE+2]]:10: warning: use 'std::has_one_bit' instead [modernize-use-std-bit]
// CHECK-FIXES: return std::has_one_bit(x);
More information about the cfe-commits
mailing list