[clang-tools-extra] [clang-tidy] Add `modernize-use-if-consteval` check (PR #189743)
Daniil Dudkin via cfe-commits
cfe-commits at lists.llvm.org
Sun Apr 19 11:04:04 PDT 2026
https://github.com/unterumarmung updated https://github.com/llvm/llvm-project/pull/189743
>From adc5c175575f18e587c87808dcad94823e635009 Mon Sep 17 00:00:00 2001
From: Daniil Dudkin <unterumarmung at yandex.ru>
Date: Tue, 31 Mar 2026 22:56:57 +0300
Subject: [PATCH 1/5] [clang-tidy] Add modernize-use-if-consteval check
---
.../clang-tidy/modernize/CMakeLists.txt | 1 +
.../modernize/ModernizeTidyModule.cpp | 3 +
.../modernize/UseIfConstevalCheck.cpp | 136 +++++++++
.../modernize/UseIfConstevalCheck.h | 36 +++
clang-tools-extra/docs/ReleaseNotes.rst | 5 +
.../docs/clang-tidy/checks/list.rst | 1 +
.../checks/modernize/use-if-consteval.rst | 47 ++++
.../checkers/modernize/use-if-consteval.cpp | 263 ++++++++++++++++++
8 files changed, 492 insertions(+)
create mode 100644 clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.h
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/modernize/use-if-consteval.rst
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index 2c5c44db587fe..9e15c9ae13123 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -39,6 +39,7 @@ add_clang_library(clangTidyModernizeModule STATIC
UseEmplaceCheck.cpp
UseEqualsDefaultCheck.cpp
UseEqualsDeleteCheck.cpp
+ UseIfConstevalCheck.cpp
UseIntegerSignComparisonCheck.cpp
UseNodiscardCheck.cpp
UseNoexceptCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index cc13da7535bcb..6c786c9b9f596 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -39,6 +39,7 @@
#include "UseEmplaceCheck.h"
#include "UseEqualsDefaultCheck.h"
#include "UseEqualsDeleteCheck.h"
+#include "UseIfConstevalCheck.h"
#include "UseIntegerSignComparisonCheck.h"
#include "UseNodiscardCheck.h"
#include "UseNoexceptCheck.h"
@@ -90,6 +91,8 @@ class ModernizeModule : public ClangTidyModule {
CheckFactories.registerCheck<PassByValueCheck>("modernize-pass-by-value");
CheckFactories.registerCheck<UseDesignatedInitializersCheck>(
"modernize-use-designated-initializers");
+ CheckFactories.registerCheck<UseIfConstevalCheck>(
+ "modernize-use-if-consteval");
CheckFactories.registerCheck<UseIntegerSignComparisonCheck>(
"modernize-use-integer-sign-comparison");
CheckFactories.registerCheck<UseRangesCheck>("modernize-use-ranges");
diff --git a/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp
new file mode 100644
index 0000000000000..b31a4b97a01ff
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp
@@ -0,0 +1,136 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "UseIfConstevalCheck.h"
+
+#include "../utils/BracesAroundStatement.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+namespace {
+
+struct BraceFix {
+ bool NeedsBraces = false;
+ utils::BraceInsertionHints Hints;
+};
+
+} // namespace
+
+static const Stmt *ignoreAttributedStmt(const Stmt *S) {
+ while (const auto *AS = dyn_cast_or_null<AttributedStmt>(S))
+ S = AS->getSubStmt();
+ return S;
+}
+
+static std::optional<CharSourceRange>
+getHeaderRange(const IfStmt *If, const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ if (If->getIfLoc().isMacroID() || If->getRParenLoc().isMacroID())
+ return std::nullopt;
+
+ const CharSourceRange HeaderRange = Lexer::makeFileCharRange(
+ CharSourceRange::getTokenRange(If->getIfLoc(), If->getRParenLoc()), SM,
+ LangOpts);
+ if (HeaderRange.isInvalid())
+ return std::nullopt;
+ return HeaderRange;
+}
+
+static std::optional<BraceFix>
+getBraceFix(const Stmt *S, const LangOptions &LangOpts, const SourceManager &SM,
+ SourceLocation StartLoc,
+ SourceLocation EndLocHint = SourceLocation()) {
+ S = ignoreAttributedStmt(S);
+ if (!S || isa<CompoundStmt>(S))
+ return BraceFix();
+
+ const auto Hints =
+ utils::getBraceInsertionsHints(S, LangOpts, SM, StartLoc, EndLocHint);
+ if (!Hints || !Hints.offersFixIts())
+ return std::nullopt;
+
+ return BraceFix{true, Hints};
+}
+void UseIfConstevalCheck::registerMatchers(MatchFinder *Finder) {
+ const auto IsConstantEvaluatedCall =
+ callExpr(callee(functionDecl(hasName("is_constant_evaluated"),
+ isInStdNamespace())))
+ .bind("call");
+ const auto IsNegatedConstantEvaluatedExpr =
+ unaryOperator(hasOperatorName("!"), hasUnaryOperand(ignoringParenImpCasts(
+ IsConstantEvaluatedCall)))
+ .bind("negation");
+ const auto IsConstantEvaluatedExpr =
+ expr(anyOf(ignoringParenImpCasts(IsConstantEvaluatedCall),
+ ignoringParenImpCasts(IsNegatedConstantEvaluatedExpr)));
+
+ Finder->addMatcher(
+ ifStmt(unless(anyOf(isConstexpr(), isConsteval())),
+ anyOf(hasCondition(IsConstantEvaluatedExpr),
+ hasConditionVariableStatement(declStmt(hasSingleDecl(
+ varDecl(hasInitializer(IsConstantEvaluatedExpr)))))))
+ .bind("if"),
+ this);
+}
+
+void UseIfConstevalCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *If = Result.Nodes.getNodeAs<IfStmt>("if");
+ const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
+ assert(If && Call && "expected to match an if statement and its call");
+
+ const bool IsNegated = Result.Nodes.getNodeAs<UnaryOperator>("negation");
+ const char *Replacement = IsNegated ? "if !consteval" : "if consteval";
+ const SourceLocation DiagLoc =
+ Result.SourceManager->getExpansionLoc(Call->getExprLoc());
+
+ auto Diag =
+ diag(
+ DiagLoc,
+ "use '%0' instead of checking 'std::is_constant_evaluated()' in this "
+ "'if' statement")
+ << Replacement;
+
+ if (If->hasInitStorage() || If->hasVarStorage())
+ return;
+
+ std::optional<CharSourceRange> HeaderRange =
+ getHeaderRange(If, *Result.SourceManager, getLangOpts());
+ if (!HeaderRange)
+ return;
+
+ std::optional<BraceFix> ThenBraceFix =
+ getBraceFix(If->getThen(), getLangOpts(), *Result.SourceManager,
+ If->getRParenLoc(), If->getElseLoc());
+ if (!ThenBraceFix)
+ return;
+
+ std::optional<BraceFix> ElseBraceFix = BraceFix();
+ const Stmt *Else = ignoreAttributedStmt(If->getElse());
+ if (Else && !isa<IfStmt>(Else)) {
+ ElseBraceFix = getBraceFix(If->getElse(), getLangOpts(),
+ *Result.SourceManager, If->getElseLoc());
+ }
+
+ std::string HeaderReplacement(Replacement);
+ if (ThenBraceFix->NeedsBraces)
+ HeaderReplacement += " {";
+ Diag << FixItHint::CreateReplacement(*HeaderRange, HeaderReplacement);
+
+ if (ThenBraceFix->NeedsBraces)
+ Diag << ThenBraceFix->Hints.closingBraceFixIt();
+
+ if (ElseBraceFix && ElseBraceFix->NeedsBraces)
+ Diag << ElseBraceFix->Hints.openingBraceFixIt()
+ << ElseBraceFix->Hints.closingBraceFixIt();
+}
+
+} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.h b/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.h
new file mode 100644
index 0000000000000..a87c9e6c5c8df
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.h
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_USEIFCONSTEVALCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEIFCONSTEVALCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::modernize {
+
+/// Use if consteval instead of std::is_constant_evaluated in if statements.
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/modernize/use-if-consteval.html
+class UseIfConstevalCheck : public ClangTidyCheck {
+public:
+ UseIfConstevalCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, 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.CPlusPlus23;
+ }
+ std::optional<TraversalKind> getCheckTraversalKind() const override {
+ return TK_IgnoreUnlessSpelledInSource;
+ }
+};
+
+} // namespace clang::tidy::modernize
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEIFCONSTEVALCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 95ed0061d654c..1d49967337b43 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -145,6 +145,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-if-consteval
+ <clang-tidy/checks/modernize/use-if-consteval>` check.
+
+ Use ``if consteval`` instead of ``std::is_constant_evaluated`` in if statements.
+
- New :doc:`modernize-use-std-bit
<clang-tidy/checks/modernize/use-std-bit>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 71b312a7112ee..e437bfa54d1fb 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -319,6 +319,7 @@ Clang-Tidy Checks
:doc:`modernize-use-emplace <modernize/use-emplace>`, "Yes"
:doc:`modernize-use-equals-default <modernize/use-equals-default>`, "Yes"
:doc:`modernize-use-equals-delete <modernize/use-equals-delete>`, "Yes"
+ :doc:`modernize-use-if-consteval <modernize/use-if-consteval>`, "Yes"
:doc:`modernize-use-integer-sign-comparison <modernize/use-integer-sign-comparison>`, "Yes"
:doc:`modernize-use-nodiscard <modernize/use-nodiscard>`, "Yes"
:doc:`modernize-use-noexcept <modernize/use-noexcept>`, "Yes"
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-if-consteval.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-if-consteval.rst
new file mode 100644
index 0000000000000..6875b54025bc7
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-if-consteval.rst
@@ -0,0 +1,47 @@
+.. title:: clang-tidy - modernize-use-if-consteval
+
+modernize-use-if-consteval
+==========================
+
+Replaces direct ``std::is_constant_evaluated()`` checks in ``if`` statements
+with C++23's ``if consteval`` syntax.
+
+In C++20, code often spells constant-evaluation branches as:
+
+.. code-block:: c++
+
+ if (std::is_constant_evaluated()) {
+ return slow_but_constexpr_path();
+ } else {
+ return fast_runtime_path();
+ }
+
+In C++23, the language has a dedicated spelling for the same idea:
+
+.. code-block:: c++
+
+ if consteval {
+ return slow_but_constexpr_path();
+ } else {
+ return fast_runtime_path();
+ }
+
+The check also recognizes the direct negated form and rewrites it to
+``if !consteval``.
+
+The check only diagnoses direct uses in ``if`` statements whose condition is a
+call to ``std::is_constant_evaluated()`` or a direct negation of that call.
+Lookup through ``using`` declarations, ``using namespace`` directives, and
+namespace aliases is handled.
+
+When the rewrite is source-safe, fix-its are provided. This includes inserting
+braces around unbraced ``then`` and ``else`` branches because ``if consteval``
+always requires compound statements.
+
+The check still diagnoses, but does not provide fix-its for:
+
+- ``if`` statements with an init-statement
+- ``if`` statements with a condition variable
+- cases where the necessary edits would cross unsafe macro or source ranges
+
+``if constexpr`` and existing ``if consteval`` statements are ignored.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp
new file mode 100644
index 0000000000000..95047d119b4f8
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp
@@ -0,0 +1,263 @@
+// RUN: %check_clang_tidy -std=c++23-or-later %s modernize-use-if-consteval %t
+
+namespace std {
+constexpr bool is_constant_evaluated() noexcept {
+ return __builtin_is_constant_evaluated();
+}
+}
+
+namespace mine {
+constexpr bool is_constant_evaluated() noexcept {
+ return __builtin_is_constant_evaluated();
+}
+}
+
+namespace alias = std;
+
+#define ICE_CALL() std::is_constant_evaluated()
+#define IF_ICE_HEADER if (std::is_constant_evaluated())
+#define RETURN_ONE() return 1;
+#define RETURN_THREE() return 3;
+
+bool runtime_predicate();
+
+int direct() {
+ if (std::is_constant_evaluated())
+ return 1;
+ else
+ return 2;
+ // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
+ // CHECK-FIXES-NEXT: return 1;
+ // CHECK-FIXES-NEXT: } else {
+ // CHECK-FIXES-NEXT: return 2;
+ // CHECK-FIXES-NEXT: }
+}
+
+int direct_global() {
+ if (::std::is_constant_evaluated()) {
+ return 1;
+ }
+ return 2;
+ // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
+}
+
+int using_decl() {
+ using std::is_constant_evaluated;
+ if (is_constant_evaluated()) {
+ return 1;
+ }
+ return 2;
+ // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
+}
+
+int using_namespace() {
+ using namespace std;
+ if (is_constant_evaluated()) {
+ return 1;
+ }
+ return 2;
+ // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
+}
+
+int namespace_alias() {
+ if (alias::is_constant_evaluated()) {
+ return 1;
+ }
+ return 2;
+ // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
+}
+
+int negated() {
+ if (!std::is_constant_evaluated())
+ return 1;
+ return 2;
+ // CHECK-MESSAGES: :[[@LINE-3]]:8: warning: use 'if !consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-FIXES: if !consteval {
+ // CHECK-FIXES-NEXT: return 1;
+ // CHECK-FIXES-NEXT: }
+ // CHECK-FIXES-NEXT: return 2;
+}
+
+int negated_alternative_token() {
+ if (not std::is_constant_evaluated())
+ return 1;
+ return 2;
+ // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: use 'if !consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-FIXES: if !consteval {
+ // CHECK-FIXES-NEXT: return 1;
+ // CHECK-FIXES-NEXT: }
+ // CHECK-FIXES-NEXT: return 2;
+}
+
+int extra_parens() {
+ if ((((std::is_constant_evaluated())))) {
+ return 1;
+ }
+ return 2;
+ // CHECK-MESSAGES: :[[@LINE-4]]:10: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
+}
+
+template <typename T>
+int templated() {
+ if (std::is_constant_evaluated()) {
+ return sizeof(T);
+ }
+ return 0;
+ // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
+}
+
+template int templated<int>();
+template int templated<long>();
+
+auto Lambda = [] {
+ if (std::is_constant_evaluated())
+ return 1;
+ return 2;
+ // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
+ // CHECK-FIXES-NEXT: return 1;
+ // CHECK-FIXES-NEXT: }
+ // CHECK-FIXES-NEXT: return 2;
+};
+
+int else_if_chain(int Value) {
+ if (Value == 0)
+ return 0;
+ else if (std::is_constant_evaluated())
+ return 1;
+ else
+ return 2;
+ // CHECK-MESSAGES: :[[@LINE-4]]:12: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-FIXES: else if consteval {
+ // CHECK-FIXES-NEXT: return 1;
+ // CHECK-FIXES-NEXT: } else {
+ // CHECK-FIXES-NEXT: return 2;
+ // CHECK-FIXES-NEXT: }
+}
+
+int macro_header_safe() {
+ if (ICE_CALL()) {
+ return 1;
+ } else {
+ return 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
+}
+
+int with_init() {
+ if (int X = 0; std::is_constant_evaluated()) {
+ return X + 1;
+ }
+ return 0;
+ // CHECK-MESSAGES: :[[@LINE-4]]:18: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-FIXES: if (int X = 0; std::is_constant_evaluated()) {
+}
+
+int with_condition_variable() {
+ if (bool B = std::is_constant_evaluated())
+ return B ? 1 : 2;
+ else
+ return 3;
+ // CHECK-MESSAGES: :[[@LINE-4]]:16: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-FIXES: if (bool B = std::is_constant_evaluated())
+ // CHECK-FIXES-NEXT: return B ? 1 : 2;
+ // CHECK-FIXES-NEXT: else
+ // CHECK-FIXES-NEXT: return 3;
+}
+
+int macro_header_unsafe() {
+ IF_ICE_HEADER {
+ return 1;
+ }
+ return 0;
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-FIXES: IF_ICE_HEADER {
+}
+
+int macro_body_unsafe() {
+ if (std::is_constant_evaluated())
+ RETURN_ONE()
+ return 2;
+ // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-FIXES: if (std::is_constant_evaluated())
+ // CHECK-FIXES-NEXT: RETURN_ONE()
+ // CHECK-FIXES-NEXT: return 2;
+}
+
+int macro_else_unsafe() {
+ if (std::is_constant_evaluated())
+ return 1;
+ else
+ RETURN_THREE()
+ return 4;
+ // CHECK-MESSAGES: :[[@LINE-5]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
+ // CHECK-FIXES-NEXT: return 1;
+ // CHECK-FIXES-NEXT: } else
+ // CHECK-FIXES-NEXT: RETURN_THREE()
+ // CHECK-FIXES-NEXT: return 4;
+}
+
+int not_std() {
+ if (mine::is_constant_evaluated()) {
+ return 1;
+ }
+ return 0;
+ // CHECK-MESSAGES-NOT: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+}
+
+int composite_conditions() {
+ if (std::is_constant_evaluated() && runtime_predicate()) {
+ return 1;
+ }
+ if (!!std::is_constant_evaluated()) {
+ return 2;
+ }
+ return 0;
+ // CHECK-MESSAGES-NOT: :[[@LINE-7]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-MESSAGES-NOT: :[[@LINE-5]]:9: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+}
+
+int if_constexpr() {
+ if constexpr (std::is_constant_evaluated()) {
+ return 1;
+ }
+ return 2;
+ // CHECK-MESSAGES-NOT: :[[@LINE-4]]:17: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+}
+
+int already_if_consteval() {
+ if consteval {
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]] warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ return 1;
+ } else {
+ return 2;
+ }
+}
+
+int already_if_not_consteval() {
+ if !consteval {
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]] warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ return 1;
+ } else {
+ return 2;
+ }
+}
+
+template <typename T>
+concept HasICE = requires {
+ std::is_constant_evaluated();
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]] warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+};
+
+using ICEPtr = decltype(std::is_constant_evaluated()) *;
+ICEPtr Ptr = nullptr;
+// CHECK-MESSAGES-NOT: :[[@LINE-2]] warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
>From ffc8a2aedd01d93ccad7793457b189eb998476b9 Mon Sep 17 00:00:00 2001
From: Daniil Dudkin <unterumarmung at yandex.ru>
Date: Thu, 2 Apr 2026 20:04:36 +0300
Subject: [PATCH 2/5] Fix review comment
---
.../modernize/UseIfConstevalCheck.cpp | 41 +++++++++++++------
.../checkers/modernize/use-if-consteval.cpp | 19 +++++++++
2 files changed, 47 insertions(+), 13 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp
index b31a4b97a01ff..859bda8294b79 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp
@@ -10,6 +10,7 @@
#include "../utils/BracesAroundStatement.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Lex/Lexer.h"
using namespace clang::ast_matchers;
@@ -34,12 +35,12 @@ static const Stmt *ignoreAttributedStmt(const Stmt *S) {
static std::optional<CharSourceRange>
getHeaderRange(const IfStmt *If, const SourceManager &SM,
const LangOptions &LangOpts) {
- if (If->getIfLoc().isMacroID() || If->getRParenLoc().isMacroID())
+ if (If->getLParenLoc().isMacroID() || If->getRParenLoc().isMacroID())
return std::nullopt;
const CharSourceRange HeaderRange = Lexer::makeFileCharRange(
- CharSourceRange::getTokenRange(If->getIfLoc(), If->getRParenLoc()), SM,
- LangOpts);
+ CharSourceRange::getTokenRange(If->getLParenLoc(), If->getRParenLoc()),
+ SM, LangOpts);
if (HeaderRange.isInvalid())
return std::nullopt;
return HeaderRange;
@@ -60,6 +61,14 @@ getBraceFix(const Stmt *S, const LangOptions &LangOpts, const SourceManager &SM,
return BraceFix{true, Hints};
}
+
+static bool needsLeadingSpaceBeforeConsteval(SourceLocation LParenLoc,
+ const SourceManager &SM) {
+ bool Invalid = false;
+ const char *LParen = SM.getCharacterData(LParenLoc, &Invalid);
+ return Invalid || !isWhitespace(LParen[-1]);
+}
+
void UseIfConstevalCheck::registerMatchers(MatchFinder *Finder) {
const auto IsConstantEvaluatedCall =
callExpr(callee(functionDecl(hasName("is_constant_evaluated"),
@@ -88,16 +97,15 @@ void UseIfConstevalCheck::check(const MatchFinder::MatchResult &Result) {
assert(If && Call && "expected to match an if statement and its call");
const bool IsNegated = Result.Nodes.getNodeAs<UnaryOperator>("negation");
- const char *Replacement = IsNegated ? "if !consteval" : "if consteval";
+ const llvm::StringRef ConstevalClause =
+ IsNegated ? "!consteval" : "consteval";
const SourceLocation DiagLoc =
Result.SourceManager->getExpansionLoc(Call->getExprLoc());
- auto Diag =
- diag(
- DiagLoc,
- "use '%0' instead of checking 'std::is_constant_evaluated()' in this "
- "'if' statement")
- << Replacement;
+ auto Diag = diag(DiagLoc, "use 'if %0' instead of checking "
+ "'std::is_constant_evaluated()' in this "
+ "'if' statement")
+ << ConstevalClause;
if (If->hasInitStorage() || If->hasVarStorage())
return;
@@ -120,9 +128,16 @@ void UseIfConstevalCheck::check(const MatchFinder::MatchResult &Result) {
*Result.SourceManager, If->getElseLoc());
}
- std::string HeaderReplacement(Replacement);
- if (ThenBraceFix->NeedsBraces)
- HeaderReplacement += " {";
+ const bool NeedsLeadingSpace = needsLeadingSpaceBeforeConsteval(
+ If->getLParenLoc(), *Result.SourceManager);
+ const std::string HeaderReplacement = [&] {
+ std::string Replacement = ConstevalClause.str();
+ if (NeedsLeadingSpace)
+ Replacement.insert(0, 1, ' ');
+ if (ThenBraceFix->NeedsBraces)
+ Replacement += " {";
+ return Replacement;
+ }();
Diag << FixItHint::CreateReplacement(*HeaderRange, HeaderReplacement);
if (ThenBraceFix->NeedsBraces)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp
index 95047d119b4f8..d3e9084776477 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp
@@ -16,6 +16,7 @@ namespace alias = std;
#define ICE_CALL() std::is_constant_evaluated()
#define IF_ICE_HEADER if (std::is_constant_evaluated())
+#define IF_ONLY if
#define RETURN_ONE() return 1;
#define RETURN_THREE() return 3;
@@ -43,6 +44,15 @@ int direct_global() {
// CHECK-FIXES: if consteval {
}
+int compact_spacing() {
+ if(std::is_constant_evaluated()) {
+ return 1;
+ }
+ return 2;
+ // CHECK-MESSAGES: :[[@LINE-4]]:6: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
+}
+
int using_decl() {
using std::is_constant_evaluated;
if (is_constant_evaluated()) {
@@ -182,6 +192,15 @@ int macro_header_unsafe() {
// CHECK-FIXES: IF_ICE_HEADER {
}
+int macro_if_token_unsafe() {
+ IF_ONLY (std::is_constant_evaluated()) {
+ return 1;
+ }
+ return 0;
+ // CHECK-MESSAGES: :[[@LINE-4]]:12: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-FIXES: IF_ONLY consteval {
+}
+
int macro_body_unsafe() {
if (std::is_constant_evaluated())
RETURN_ONE()
>From 551cb3890db74725ed8ddb8fdb20d6a9619b9481 Mon Sep 17 00:00:00 2001
From: Daniil Dudkin <unterumarmung at yandex.ru>
Date: Thu, 2 Apr 2026 20:06:47 +0300
Subject: [PATCH 3/5] Fix review comment
---
clang-tools-extra/docs/ReleaseNotes.rst | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 1d49967337b43..56c9077c24902 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -148,7 +148,8 @@ New checks
- New :doc:`modernize-use-if-consteval
<clang-tidy/checks/modernize/use-if-consteval>` check.
- Use ``if consteval`` instead of ``std::is_constant_evaluated`` in if statements.
+ Replaces direct ``std::is_constant_evaluated()`` checks in ``if`` statements
+ with C++23's ``if consteval`` syntax.
- New :doc:`modernize-use-std-bit
<clang-tidy/checks/modernize/use-std-bit>` check.
>From 17f80affd8b8cee8c2b25ece3d7b8b06666a76d2 Mon Sep 17 00:00:00 2001
From: Daniil Dudkin <unterumarmung at yandex.ru>
Date: Fri, 3 Apr 2026 22:37:19 +0300
Subject: [PATCH 4/5] fix review comments
---
.../modernize/UseIfConstevalCheck.cpp | 5 +-
.../checkers/modernize/use-if-consteval.cpp | 92 +++++++++----------
2 files changed, 48 insertions(+), 49 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp
index 859bda8294b79..1724558d13159 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp
@@ -83,7 +83,7 @@ void UseIfConstevalCheck::registerMatchers(MatchFinder *Finder) {
ignoringParenImpCasts(IsNegatedConstantEvaluatedExpr)));
Finder->addMatcher(
- ifStmt(unless(anyOf(isConstexpr(), isConsteval())),
+ ifStmt(unless(isConstexpr()),
anyOf(hasCondition(IsConstantEvaluatedExpr),
hasConditionVariableStatement(declStmt(hasSingleDecl(
varDecl(hasInitializer(IsConstantEvaluatedExpr)))))))
@@ -103,8 +103,7 @@ void UseIfConstevalCheck::check(const MatchFinder::MatchResult &Result) {
Result.SourceManager->getExpansionLoc(Call->getExprLoc());
auto Diag = diag(DiagLoc, "use 'if %0' instead of checking "
- "'std::is_constant_evaluated()' in this "
- "'if' statement")
+ "'std::is_constant_evaluated()'")
<< ConstevalClause;
if (If->hasInitStorage() || If->hasVarStorage())
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp
index d3e9084776477..1fa2f7f113e45 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp
@@ -27,8 +27,8 @@ int direct() {
return 1;
else
return 2;
- // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-FIXES: if consteval {
+ // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
// CHECK-FIXES-NEXT: return 1;
// CHECK-FIXES-NEXT: } else {
// CHECK-FIXES-NEXT: return 2;
@@ -40,8 +40,8 @@ int direct_global() {
return 1;
}
return 2;
- // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-FIXES: if consteval {
+ // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
}
int compact_spacing() {
@@ -49,8 +49,8 @@ int compact_spacing() {
return 1;
}
return 2;
- // CHECK-MESSAGES: :[[@LINE-4]]:6: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-FIXES: if consteval {
+ // CHECK-MESSAGES: :[[@LINE-4]]:6: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
}
int using_decl() {
@@ -59,8 +59,8 @@ int using_decl() {
return 1;
}
return 2;
- // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-FIXES: if consteval {
+ // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
}
int using_namespace() {
@@ -69,8 +69,8 @@ int using_namespace() {
return 1;
}
return 2;
- // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-FIXES: if consteval {
+ // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
}
int namespace_alias() {
@@ -78,16 +78,16 @@ int namespace_alias() {
return 1;
}
return 2;
- // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-FIXES: if consteval {
+ // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
}
int negated() {
if (!std::is_constant_evaluated())
return 1;
return 2;
- // CHECK-MESSAGES: :[[@LINE-3]]:8: warning: use 'if !consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-FIXES: if !consteval {
+ // CHECK-MESSAGES: :[[@LINE-3]]:8: warning: use 'if !consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: if !consteval {
// CHECK-FIXES-NEXT: return 1;
// CHECK-FIXES-NEXT: }
// CHECK-FIXES-NEXT: return 2;
@@ -97,8 +97,8 @@ int negated_alternative_token() {
if (not std::is_constant_evaluated())
return 1;
return 2;
- // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: use 'if !consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-FIXES: if !consteval {
+ // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: use 'if !consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: if !consteval {
// CHECK-FIXES-NEXT: return 1;
// CHECK-FIXES-NEXT: }
// CHECK-FIXES-NEXT: return 2;
@@ -109,8 +109,8 @@ int extra_parens() {
return 1;
}
return 2;
- // CHECK-MESSAGES: :[[@LINE-4]]:10: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-FIXES: if consteval {
+ // CHECK-MESSAGES: :[[@LINE-4]]:10: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
}
template <typename T>
@@ -119,8 +119,8 @@ int templated() {
return sizeof(T);
}
return 0;
- // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-FIXES: if consteval {
+ // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
}
template int templated<int>();
@@ -130,8 +130,8 @@ auto Lambda = [] {
if (std::is_constant_evaluated())
return 1;
return 2;
- // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-FIXES: if consteval {
+ // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
// CHECK-FIXES-NEXT: return 1;
// CHECK-FIXES-NEXT: }
// CHECK-FIXES-NEXT: return 2;
@@ -144,8 +144,8 @@ int else_if_chain(int Value) {
return 1;
else
return 2;
- // CHECK-MESSAGES: :[[@LINE-4]]:12: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-FIXES: else if consteval {
+ // CHECK-MESSAGES: :[[@LINE-4]]:12: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: else if consteval {
// CHECK-FIXES-NEXT: return 1;
// CHECK-FIXES-NEXT: } else {
// CHECK-FIXES-NEXT: return 2;
@@ -158,8 +158,8 @@ int macro_header_safe() {
} else {
return 2;
}
- // CHECK-MESSAGES: :[[@LINE-5]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-FIXES: if consteval {
+ // CHECK-MESSAGES: :[[@LINE-5]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
}
int with_init() {
@@ -167,8 +167,8 @@ int with_init() {
return X + 1;
}
return 0;
- // CHECK-MESSAGES: :[[@LINE-4]]:18: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-FIXES: if (int X = 0; std::is_constant_evaluated()) {
+ // CHECK-MESSAGES: :[[@LINE-4]]:18: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: if (int X = 0; std::is_constant_evaluated()) {
}
int with_condition_variable() {
@@ -176,8 +176,8 @@ int with_condition_variable() {
return B ? 1 : 2;
else
return 3;
- // CHECK-MESSAGES: :[[@LINE-4]]:16: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-FIXES: if (bool B = std::is_constant_evaluated())
+ // CHECK-MESSAGES: :[[@LINE-4]]:16: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: if (bool B = std::is_constant_evaluated())
// CHECK-FIXES-NEXT: return B ? 1 : 2;
// CHECK-FIXES-NEXT: else
// CHECK-FIXES-NEXT: return 3;
@@ -188,8 +188,8 @@ int macro_header_unsafe() {
return 1;
}
return 0;
- // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-FIXES: IF_ICE_HEADER {
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: IF_ICE_HEADER {
}
int macro_if_token_unsafe() {
@@ -197,16 +197,16 @@ int macro_if_token_unsafe() {
return 1;
}
return 0;
- // CHECK-MESSAGES: :[[@LINE-4]]:12: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-FIXES: IF_ONLY consteval {
+ // CHECK-MESSAGES: :[[@LINE-4]]:12: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: IF_ONLY consteval {
}
int macro_body_unsafe() {
if (std::is_constant_evaluated())
RETURN_ONE()
return 2;
- // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-FIXES: if (std::is_constant_evaluated())
+ // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: if (std::is_constant_evaluated())
// CHECK-FIXES-NEXT: RETURN_ONE()
// CHECK-FIXES-NEXT: return 2;
}
@@ -217,8 +217,8 @@ int macro_else_unsafe() {
else
RETURN_THREE()
return 4;
- // CHECK-MESSAGES: :[[@LINE-5]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-FIXES: if consteval {
+ // CHECK-MESSAGES: :[[@LINE-5]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
// CHECK-FIXES-NEXT: return 1;
// CHECK-FIXES-NEXT: } else
// CHECK-FIXES-NEXT: RETURN_THREE()
@@ -230,7 +230,7 @@ int not_std() {
return 1;
}
return 0;
- // CHECK-MESSAGES-NOT: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-MESSAGES-NOT: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
}
int composite_conditions() {
@@ -241,8 +241,8 @@ int composite_conditions() {
return 2;
}
return 0;
- // CHECK-MESSAGES-NOT: :[[@LINE-7]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
- // CHECK-MESSAGES-NOT: :[[@LINE-5]]:9: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-MESSAGES-NOT: :[[@LINE-7]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-MESSAGES-NOT: :[[@LINE-5]]:9: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
}
int if_constexpr() {
@@ -250,12 +250,12 @@ int if_constexpr() {
return 1;
}
return 2;
- // CHECK-MESSAGES-NOT: :[[@LINE-4]]:17: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-MESSAGES-NOT: :[[@LINE-4]]:17: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
}
int already_if_consteval() {
if consteval {
- // CHECK-MESSAGES-NOT: :[[@LINE-1]] warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]] warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
return 1;
} else {
return 2;
@@ -264,7 +264,7 @@ int already_if_consteval() {
int already_if_not_consteval() {
if !consteval {
- // CHECK-MESSAGES-NOT: :[[@LINE-1]] warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]] warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
return 1;
} else {
return 2;
@@ -274,9 +274,9 @@ int already_if_not_consteval() {
template <typename T>
concept HasICE = requires {
std::is_constant_evaluated();
- // CHECK-MESSAGES-NOT: :[[@LINE-1]] warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]] warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
};
using ICEPtr = decltype(std::is_constant_evaluated()) *;
ICEPtr Ptr = nullptr;
-// CHECK-MESSAGES-NOT: :[[@LINE-2]] warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' in this 'if' statement [modernize-use-if-consteval]
+// CHECK-MESSAGES-NOT: :[[@LINE-2]] warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
>From 6079f68821bd8a766d7324c45fcd050a0f3f14c6 Mon Sep 17 00:00:00 2001
From: Daniil Dudkin <unterumarmung at yandex.ru>
Date: Sun, 19 Apr 2026 21:03:46 +0300
Subject: [PATCH 5/5] Fix review comments
---
.../modernize/UseIfConstevalCheck.cpp | 31 +++++++++----------
.../checkers/modernize/use-if-consteval.cpp | 24 ++++++++++++++
2 files changed, 39 insertions(+), 16 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp
index 1724558d13159..e31902a7d8e74 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseIfConstevalCheck.cpp
@@ -26,22 +26,18 @@ struct BraceFix {
} // namespace
-static const Stmt *ignoreAttributedStmt(const Stmt *S) {
- while (const auto *AS = dyn_cast_or_null<AttributedStmt>(S))
- S = AS->getSubStmt();
- return S;
-}
-
-static std::optional<CharSourceRange>
-getHeaderRange(const IfStmt *If, const SourceManager &SM,
- const LangOptions &LangOpts) {
+static std::optional<SourceRange> getHeaderRange(const IfStmt *If,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
if (If->getLParenLoc().isMacroID() || If->getRParenLoc().isMacroID())
return std::nullopt;
- const CharSourceRange HeaderRange = Lexer::makeFileCharRange(
- CharSourceRange::getTokenRange(If->getLParenLoc(), If->getRParenLoc()),
- SM, LangOpts);
- if (HeaderRange.isInvalid())
+ const SourceRange HeaderRange(If->getLParenLoc(), If->getRParenLoc());
+ // Validate that the token range is safely rewriteable in file source before
+ // offering a fix-it.
+ if (Lexer::makeFileCharRange(CharSourceRange::getTokenRange(HeaderRange), SM,
+ LangOpts)
+ .isInvalid())
return std::nullopt;
return HeaderRange;
}
@@ -50,7 +46,8 @@ static std::optional<BraceFix>
getBraceFix(const Stmt *S, const LangOptions &LangOpts, const SourceManager &SM,
SourceLocation StartLoc,
SourceLocation EndLocHint = SourceLocation()) {
- S = ignoreAttributedStmt(S);
+ if (S)
+ S = S->stripLabelLikeStatements();
if (!S || isa<CompoundStmt>(S))
return BraceFix();
@@ -109,7 +106,7 @@ void UseIfConstevalCheck::check(const MatchFinder::MatchResult &Result) {
if (If->hasInitStorage() || If->hasVarStorage())
return;
- std::optional<CharSourceRange> HeaderRange =
+ std::optional<SourceRange> HeaderRange =
getHeaderRange(If, *Result.SourceManager, getLangOpts());
if (!HeaderRange)
return;
@@ -121,7 +118,9 @@ void UseIfConstevalCheck::check(const MatchFinder::MatchResult &Result) {
return;
std::optional<BraceFix> ElseBraceFix = BraceFix();
- const Stmt *Else = ignoreAttributedStmt(If->getElse());
+ const Stmt *Else = If->getElse();
+ if (Else)
+ Else = Else->stripLabelLikeStatements();
if (Else && !isa<IfStmt>(Else)) {
ElseBraceFix = getBraceFix(If->getElse(), getLangOpts(),
*Result.SourceManager, If->getElseLoc());
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp
index 1fa2f7f113e45..b822b0753595c 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-if-consteval.cpp
@@ -137,6 +137,30 @@ auto Lambda = [] {
// CHECK-FIXES-NEXT: return 2;
};
+int attributed_then() {
+ if (std::is_constant_evaluated())
+ [[likely]] return 1;
+ return 0;
+ // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
+ // CHECK-FIXES-NEXT: {{[[][[]}}likely{{[]][]]}} return 1;
+ // CHECK-FIXES-NEXT: }
+ // CHECK-FIXES-NEXT: return 0;
+}
+
+int labeled_then() {
+ if (std::is_constant_evaluated())
+ labeled_then:
+ return 1;
+ return 0;
+ // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use 'if consteval' instead of checking 'std::is_constant_evaluated()' [modernize-use-if-consteval]
+ // CHECK-FIXES: if consteval {
+ // CHECK-FIXES-NEXT: labeled_then:
+ // CHECK-FIXES-NEXT: return 1;
+ // CHECK-FIXES-NEXT: }
+ // CHECK-FIXES-NEXT: return 0;
+}
+
int else_if_chain(int Value) {
if (Value == 0)
return 0;
More information about the cfe-commits
mailing list