[clang-tools-extra] [clang-tidy] Fix a crash in bugprone-std-namespace-modification (PR #214704)
Zeyi Xu via cfe-commits
cfe-commits at lists.llvm.org
Sat Aug 8 04:05:12 PDT 2026
https://github.com/zeyi2 updated https://github.com/llvm/llvm-project/pull/214704
>From abf535a2e3d9e977f81d56de99e974299cd58b9a Mon Sep 17 00:00:00 2001
From: Zeyi Xu <mitchell.xu2 at gmail.com>
Date: Fri, 7 Aug 2026 19:11:14 +0800
Subject: [PATCH 1/3] [clang-tidy] Fix a crash in
bugprone-std-namespace-modification
---
.../StdNamespaceModificationCheck.cpp | 19 +++++++++++++++----
clang-tools-extra/docs/ReleaseNotes.rst | 4 ++++
.../std-namespace-modification-no-crash.cpp | 10 ++++++++++
3 files changed, 29 insertions(+), 4 deletions(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/std-namespace-modification-no-crash.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/StdNamespaceModificationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/StdNamespaceModificationCheck.cpp
index a623ed690697b..85ea32f3e7b4f 100644
--- a/clang-tools-extra/clang-tidy/bugprone/StdNamespaceModificationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/StdNamespaceModificationCheck.cpp
@@ -34,6 +34,19 @@ AST_POLYMORPHIC_MATCHER_P(
Builder) != Args.end();
}
+AST_MATCHER(NamedDecl, isInStdOrPosixNamespace) {
+ for (const DeclContext *DC = Node.getDeclContext(); DC;
+ DC = DC->getParent()) {
+ if (DC->isStdNamespace())
+ return true;
+
+ if (const auto *NS = dyn_cast<NamespaceDecl>(DC);
+ NS && NS->getName() == "posix" && NS->getParent()->isTranslationUnit())
+ return true;
+ }
+ return false;
+}
+
} // namespace
namespace clang::tidy::bugprone {
@@ -43,10 +56,8 @@ void StdNamespaceModificationCheck::registerMatchers(MatchFinder *Finder) {
hasDeclContext(namespaceDecl(hasAnyName("std", "posix"),
unless(hasParent(namespaceDecl())))
.bind("nmspc"));
- const auto UserDefinedDecl =
- namedDecl(anyOf(classTemplateDecl(), tagDecl()),
- hasAncestor(namespaceDecl(hasAnyName("std", "posix"),
- unless(hasParent(namespaceDecl())))));
+ const auto UserDefinedDecl = namedDecl(anyOf(classTemplateDecl(), tagDecl()),
+ isInStdOrPosixNamespace());
const auto UserDefinedType = qualType(hasUnqualifiedDesugaredType(anyOf(
tagType(unless(hasDeclaration(UserDefinedDecl))),
templateSpecializationType(unless(hasDeclaration(UserDefinedDecl))))));
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 0dcf2ea1f21c7..ed462bc7339fc 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -113,6 +113,10 @@ New check aliases
Changes in existing checks
^^^^^^^^^^^^^^^^^^^^^^^^^^
+- Fixed a crash in :doc:`bugprone-std-namespace-modification
+ <clang-tidy/checks/bugprone/std-namespace-modification>` when checking
+ lambda closure types used as template arguments.
+
- Improved :doc:`cppcoreguidelines-pro-type-member-init
<clang-tidy/checks/cppcoreguidelines/pro-type-member-init>` check by treating
``std::array`` the same as built-in arrays when `IgnoreArrays` option is enabled.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/std-namespace-modification-no-crash.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/std-namespace-modification-no-crash.cpp
new file mode 100644
index 0000000000000..7921e8a40605a
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/std-namespace-modification-no-crash.cpp
@@ -0,0 +1,10 @@
+// RUN: %check_clang_tidy -std=c++20-or-later -expect-clang-tidy-error %s bugprone-std-namespace-modification %t
+
+template <class A, class B> struct O : A, B {};
+template <class T> void f() {
+ auto a = [](auto) {};
+ auto b = [](auto) -> decltype(({ })) {};
+ O(a, b)(T{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: error: member 'operator()' found in multiple base classes of different types
+}
+template void f<int>();
>From d0f9040d53b814c3a45b65952370d5dcd73467be Mon Sep 17 00:00:00 2001
From: Zeyi Xu <mitchell.xu2 at gmail.com>
Date: Sat, 8 Aug 2026 18:54:16 +0800
Subject: [PATCH 2/3] ~
---
.../bugprone/StdNamespaceModificationCheck.cpp | 11 +++++++----
.../bugprone/std-namespace-modification-no-crash.cpp | 6 +++---
2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/StdNamespaceModificationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/StdNamespaceModificationCheck.cpp
index 85ea32f3e7b4f..07edd911e714c 100644
--- a/clang-tools-extra/clang-tidy/bugprone/StdNamespaceModificationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/StdNamespaceModificationCheck.cpp
@@ -34,8 +34,8 @@ AST_POLYMORPHIC_MATCHER_P(
Builder) != Args.end();
}
-AST_MATCHER(NamedDecl, isInStdOrPosixNamespace) {
- for (const DeclContext *DC = Node.getDeclContext(); DC;
+AST_MATCHER(Decl, isInStdOrPosixNamespace) {
+ for (const DeclContext *DC = dyn_cast<DeclContext>(&Node); DC;
DC = DC->getParent()) {
if (DC->isStdNamespace())
return true;
@@ -56,8 +56,11 @@ void StdNamespaceModificationCheck::registerMatchers(MatchFinder *Finder) {
hasDeclContext(namespaceDecl(hasAnyName("std", "posix"),
unless(hasParent(namespaceDecl())))
.bind("nmspc"));
- const auto UserDefinedDecl = namedDecl(anyOf(classTemplateDecl(), tagDecl()),
- isInStdOrPosixNamespace());
+ // FIXME: Investigate why lambda closure declarations can be absent from the
+ // AST parent map.
+ const auto UserDefinedDecl =
+ namedDecl(anyOf(classTemplateDecl(), tagDecl()),
+ hasDeclContext(isInStdOrPosixNamespace()));
const auto UserDefinedType = qualType(hasUnqualifiedDesugaredType(anyOf(
tagType(unless(hasDeclaration(UserDefinedDecl))),
templateSpecializationType(unless(hasDeclaration(UserDefinedDecl))))));
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/std-namespace-modification-no-crash.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/std-namespace-modification-no-crash.cpp
index 7921e8a40605a..bb2bf0eefeebb 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/std-namespace-modification-no-crash.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/std-namespace-modification-no-crash.cpp
@@ -2,9 +2,9 @@
template <class A, class B> struct O : A, B {};
template <class T> void f() {
- auto a = [](auto) {};
- auto b = [](auto) -> decltype(({ })) {};
- O(a, b)(T{});
+ auto a = [] {};
+ auto b = [] {};
+ O(a, b)();
// CHECK-MESSAGES: :[[@LINE-1]]:3: error: member 'operator()' found in multiple base classes of different types
}
template void f<int>();
>From 5ad08e28394878e2be23542a3bcf165cfd16c7bf Mon Sep 17 00:00:00 2001
From: Zeyi Xu <mitchell.xu2 at gmail.com>
Date: Sat, 8 Aug 2026 19:04:47 +0800
Subject: [PATCH 3/3] make clang-tidy happy
---
.../clang-tidy/bugprone/StdNamespaceModificationCheck.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/StdNamespaceModificationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/StdNamespaceModificationCheck.cpp
index 07edd911e714c..709de88a71f48 100644
--- a/clang-tools-extra/clang-tidy/bugprone/StdNamespaceModificationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/StdNamespaceModificationCheck.cpp
@@ -35,7 +35,7 @@ AST_POLYMORPHIC_MATCHER_P(
}
AST_MATCHER(Decl, isInStdOrPosixNamespace) {
- for (const DeclContext *DC = dyn_cast<DeclContext>(&Node); DC;
+ for (const auto *DC = dyn_cast<DeclContext>(&Node); DC;
DC = DC->getParent()) {
if (DC->isStdNamespace())
return true;
More information about the cfe-commits
mailing list