[clang-tools-extra] [libcxx] [clang-tools-extra]: Check for static in constexpr (PR #175814)
Prabhu Rajasekaran via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 13 11:03:53 PST 2026
https://github.com/Prabhuk updated https://github.com/llvm/llvm-project/pull/175814
>From dbaa2b79b8251c9a9045b51180c3830b23633395 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Tue, 13 Jan 2026 19:00:52 +0000
Subject: [PATCH] [clang-tools-extra]: Check for static in constexpr
Static variables in constexpr functions create a warning in Clang and is
currently an error in GCC. Add a clang tidy check to catch such cases to
prevent these cases slipping through in libcxx code.
---
.../clang-tidy/misc/CMakeLists.txt | 1 +
.../clang-tidy/misc/MiscTidyModule.cpp | 3 ++
.../misc/StaticInConstexprCheck.cpp | 39 ++++++++++++++++++
.../clang-tidy/misc/StaticInConstexprCheck.h | 33 +++++++++++++++
.../checks/misc/static-in-constexpr.rst | 6 +++
.../checkers/misc/static-in-constexpr.cpp | 41 +++++++++++++++++++
libcxx/.clang-tidy | 1 +
7 files changed, 124 insertions(+)
create mode 100644 clang-tools-extra/clang-tidy/misc/StaticInConstexprCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/misc/StaticInConstexprCheck.h
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/misc/static-in-constexpr.rst
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/static-in-constexpr.cpp
diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
index e34b0cf687be3..bb11f5c5836e1 100644
--- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
@@ -38,6 +38,7 @@ add_clang_library(clangTidyMiscModule STATIC
PredictableRandCheck.cpp
RedundantExpressionCheck.cpp
StaticAssertCheck.cpp
+ StaticInConstexprCheck.cpp
ThrowByValueCatchByReferenceCheck.cpp
UnconventionalAssignOperatorCheck.cpp
UniqueptrResetReleaseCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
index f8550b30b9789..3918c70f4fb9a 100644
--- a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
@@ -27,6 +27,7 @@
#include "PredictableRandCheck.h"
#include "RedundantExpressionCheck.h"
#include "StaticAssertCheck.h"
+#include "StaticInConstexprCheck.h"
#include "ThrowByValueCatchByReferenceCheck.h"
#include "UnconventionalAssignOperatorCheck.h"
#include "UniqueptrResetReleaseCheck.h"
@@ -76,6 +77,8 @@ class MiscModule : public ClangTidyModule {
CheckFactories.registerCheck<RedundantExpressionCheck>(
"misc-redundant-expression");
CheckFactories.registerCheck<StaticAssertCheck>("misc-static-assert");
+ CheckFactories.registerCheck<StaticInConstexprCheck>(
+ "misc-static-in-constexpr");
CheckFactories.registerCheck<ThrowByValueCatchByReferenceCheck>(
"misc-throw-by-value-catch-by-reference");
CheckFactories.registerCheck<UnconventionalAssignOperatorCheck>(
diff --git a/clang-tools-extra/clang-tidy/misc/StaticInConstexprCheck.cpp b/clang-tools-extra/clang-tidy/misc/StaticInConstexprCheck.cpp
new file mode 100644
index 0000000000000..5427f7e80cd33
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/misc/StaticInConstexprCheck.cpp
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "StaticInConstexprCheck.h"
+#include "clang/AST/Decl.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::misc {
+
+void StaticInConstexprCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(varDecl(isStaticLocal()).bind("var"), this);
+}
+
+void StaticInConstexprCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var");
+ const DeclContext *DC = Var->getDeclContext();
+
+ while (DC && !DC->isFunctionOrMethod())
+ DC = DC->getParent();
+
+ const auto *FD = dyn_cast_or_null<FunctionDecl>(DC);
+ if (!FD)
+ return;
+
+ if (FD->isConstexpr()) {
+ diag(Var->getLocation(),
+ "variable of static or thread storage duration inside constexpr "
+ "function");
+ }
+}
+
+} // namespace clang::tidy::misc
\ No newline at end of file
diff --git a/clang-tools-extra/clang-tidy/misc/StaticInConstexprCheck.h b/clang-tools-extra/clang-tidy/misc/StaticInConstexprCheck.h
new file mode 100644
index 0000000000000..862255c9eeb1d
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/misc/StaticInConstexprCheck.h
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_MISC_STATICINCONSTEXPRCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_STATICINCONSTEXPRCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::misc {
+
+/// Checks for static variables declared inside constexpr functions.
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/misc/static-in-constexpr.html
+class StaticInConstexprCheck : public ClangTidyCheck {
+public:
+ StaticInConstexprCheck(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.CPlusPlus;
+ }
+};
+
+} // namespace clang::tidy::misc
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_STATICINCONSTEXPRCHECK_H
diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/static-in-constexpr.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/static-in-constexpr.rst
new file mode 100644
index 0000000000000..4aeaa4e661866
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/misc/static-in-constexpr.rst
@@ -0,0 +1,6 @@
+.. title:: clang-tidy - misc-static-in-constexpr
+
+misc-static-in-constexpr
+========================
+
+FIXME: Describe what patterns does the check detect and why. Give examples.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/static-in-constexpr.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/static-in-constexpr.cpp
new file mode 100644
index 0000000000000..9b6c38a4cabfe
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/static-in-constexpr.cpp
@@ -0,0 +1,41 @@
+// RUN: %check_clang_tidy -std=c++20 %s misc-static-in-constexpr %t
+// RUN: %check_clang_tidy -std=c++23 %s misc-static-in-constexpr %t
+
+void normal_func() {
+ static int x = 0;
+ thread_local int y = 0;
+}
+
+constexpr void constexpr_func() {
+ static int x = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: variable of static or thread storage duration inside constexpr function [misc-static-in-constexpr]
+
+ thread_local int y = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: variable of static or thread storage duration inside constexpr function [misc-static-in-constexpr]
+}
+
+consteval void consteval_func() {
+ static int x = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: variable of static or thread storage duration inside constexpr function [misc-static-in-constexpr]
+}
+
+constexpr void constexpr_with_lambda() {
+ auto l = []() {
+ static int x = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: variable of static or thread storage duration inside constexpr function [misc-static-in-constexpr]
+ };
+}
+
+constexpr void constexpr_with_constexpr_lambda() {
+ auto l = []() constexpr {
+ static int x = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: variable of static or thread storage duration inside constexpr function [misc-static-in-constexpr]
+ };
+}
+
+struct S {
+ static constexpr void static_member_func() {
+ static int x = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: variable of static or thread storage duration inside constexpr function [misc-static-in-constexpr]
+ }
+};
\ No newline at end of file
diff --git a/libcxx/.clang-tidy b/libcxx/.clang-tidy
index ebbfab0379265..685773e4095cd 100644
--- a/libcxx/.clang-tidy
+++ b/libcxx/.clang-tidy
@@ -13,6 +13,7 @@ Checks: >
misc-definitions-in-headers,
misc-misplaced-const,
misc-non-copyable-objects,
+ misc-static-in-constexpr,
misc-uniqueptr-reset-release,
modernize-loop-convert,
More information about the cfe-commits
mailing list