[clang-tools-extra] [clang-tidy] Teach `modernize-deprecated-headers` about more no-op headers (PR #165674)
Victor Chernyakin via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 30 01:14:03 PDT 2025
https://github.com/localspook created https://github.com/llvm/llvm-project/pull/165674
First, this PR adds some more no-op C++ headers: `<cstdbool>`, `<cstdalign>`, and `<ciso646>`. Second, it adds some headers that are no-ops in C23: `<stdbool.h>`, `<stdnoreturn.h>`, and `<stdalign.h>`. Up until now, this was a C++-only check, so adding support for C headers required somewhat invasive changes. In particular, the current docs are written from a C++ point of view, so I had to rework them to make it clear that the check is relevant for C as well.
>From 030982462f365563135b881e2770da82222b039a Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Thu, 30 Oct 2025 01:08:37 -0700
Subject: [PATCH] [clang-tidy] Teach `modernize-deprecated-headers` about more
no-op headers
---
.../modernize/DeprecatedHeadersCheck.cpp | 23 +++--
.../modernize/DeprecatedHeadersCheck.h | 2 +-
clang-tools-extra/docs/ReleaseNotes.rst | 4 +
.../checks/modernize/deprecated-headers.rst | 98 ++++++++++---------
.../Inputs/deprecated-headers/ciso646 | 0
.../Inputs/deprecated-headers/cstdalign | 0
.../Inputs/deprecated-headers/cstdbool | 0
.../Inputs/deprecated-headers/stdnoreturn.h | 0
.../modernize/deprecated-headers-c23.c | 25 +++++
.../modernize/deprecated-headers-cxx03.cpp | 18 ++++
.../modernize/deprecated-headers-cxx11.cpp | 18 ++++
11 files changed, 134 insertions(+), 54 deletions(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/deprecated-headers/ciso646
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/deprecated-headers/cstdalign
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/deprecated-headers/cstdbool
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/deprecated-headers/stdnoreturn.h
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/deprecated-headers-c23.c
diff --git a/clang-tools-extra/clang-tidy/modernize/DeprecatedHeadersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/DeprecatedHeadersCheck.cpp
index 1de9e136c5719..aa27cfd5ce81d 100644
--- a/clang-tools-extra/clang-tidy/modernize/DeprecatedHeadersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/DeprecatedHeadersCheck.cpp
@@ -115,9 +115,9 @@ void DeprecatedHeadersCheck::check(
// Emit all the remaining reports.
for (const IncludeMarker &Marker : IncludesToBeProcessed) {
if (Marker.Replacement.empty()) {
- diag(Marker.DiagLoc,
- "including '%0' has no effect in C++; consider removing it")
- << Marker.FileName
+ diag(Marker.DiagLoc, "including '%0' has no effect %select{since C23|in "
+ "C++}1; consider removing it")
+ << Marker.FileName << getLangOpts().CPlusPlus
<< FixItHint::CreateRemoval(Marker.ReplacementRange);
} else {
diag(Marker.DiagLoc, "inclusion of deprecated C++ header "
@@ -147,7 +147,9 @@ IncludeModernizePPCallbacks::IncludeModernizePPCallbacks(
{"string.h", "cstring"}, {"time.h", "ctime"},
{"wchar.h", "cwchar"}, {"wctype.h", "cwctype"},
};
- CStyledHeaderToCxx.insert(std::begin(CXX98Headers), std::end(CXX98Headers));
+
+ if (LangOpts.CPlusPlus)
+ CStyledHeaderToCxx.insert(std::begin(CXX98Headers), std::end(CXX98Headers));
static constexpr std::pair<StringRef, StringRef> CXX11Headers[] = {
{"fenv.h", "cfenv"}, {"stdint.h", "cstdint"},
@@ -157,9 +159,16 @@ IncludeModernizePPCallbacks::IncludeModernizePPCallbacks(
if (LangOpts.CPlusPlus11)
CStyledHeaderToCxx.insert(std::begin(CXX11Headers), std::end(CXX11Headers));
- static constexpr StringRef HeadersToDelete[] = {"stdalign.h", "stdbool.h",
- "iso646.h"};
- DeleteHeaders.insert_range(HeadersToDelete);
+ static constexpr StringRef CXXHeadersToDelete[] = {"stdalign.h", "cstdalign",
+ "stdbool.h", "cstdbool",
+ "iso646.h", "ciso646"};
+ if (LangOpts.CPlusPlus)
+ DeleteHeaders.insert_range(CXXHeadersToDelete);
+
+ static constexpr StringRef C23HeadersToDelete[] = {"stdalign.h", "stdbool.h",
+ "stdnoreturn.h"};
+ if (LangOpts.C23)
+ DeleteHeaders.insert_range(C23HeadersToDelete);
}
void IncludeModernizePPCallbacks::InclusionDirective(
diff --git a/clang-tools-extra/clang-tidy/modernize/DeprecatedHeadersCheck.h b/clang-tools-extra/clang-tidy/modernize/DeprecatedHeadersCheck.h
index badb2b41f164f..1b7c1821fb19c 100644
--- a/clang-tools-extra/clang-tidy/modernize/DeprecatedHeadersCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/DeprecatedHeadersCheck.h
@@ -34,7 +34,7 @@ class DeprecatedHeadersCheck : public ClangTidyCheck {
public:
DeprecatedHeadersCheck(StringRef Name, ClangTidyContext *Context);
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
- return LangOpts.CPlusPlus;
+ return LangOpts.CPlusPlus || LangOpts.C23;
}
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 33cc401bcb78f..c2ed8b643c590 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -346,6 +346,10 @@ Changes in existing checks
<clang-tidy/checks/modernize/avoid-c-arrays>` to not diagnose array types
which are part of an implicit instantiation of a template.
+- Improved :doc:`modernize-deprecated-headers
+ <clang-tidy/checks/modernize/deprecated-headers>` to diagnose more
+ deprecated headers, in both C++ and (for the first time) in C.
+
- Improved :doc:`modernize-use-constraints
<clang-tidy/checks/modernize/use-constraints>` check by fixing a crash on
uses of non-standard ``enable_if`` with a signature different from
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/deprecated-headers.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/deprecated-headers.rst
index 6c35cd4e53d87..8dcc8580b2ccc 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/deprecated-headers.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/deprecated-headers.rst
@@ -3,12 +3,55 @@
modernize-deprecated-headers
============================
-Some headers from C library were deprecated in C++ and are no longer welcome in
-C++ codebases. Some have no effect in C++. For more details refer to the C++14
-Standard [depr.c.headers] section.
-
-This check replaces C standard library headers with their C++ alternatives and
-removes redundant ones.
+There exist headers that produce no effect when included, which are there
+solely to ease migrating code. The check will suggest removing them.
+In C++, they are:
+
+* ``stdalign.h`` / ``cstdalign``
+* ``stdbool.h`` / ``cstdbool``
+* ``iso646.h`` / ``ciso646``
+
+And in C they are:
+
+* ``stdalign.h`` // No-op since C23
+* ``stdbool.h`` // No-op since C23
+* ``stdnoreturn.h`` // No-op since C23
+
+In C++, there is additionally a number of headers intended for
+interoperability with C, which should not be used in pure C++ code.
+The check will suggest replacing them with their C++ counterparts
+(e.g. replacing ``<signal.h>`` with ``<csignal>``). These headers are:
+
+* ``<assert.h>``
+* ``<complex.h>``
+* ``<ctype.h>``
+* ``<errno.h>``
+* ``<fenv.h>`` // deprecated since C++11
+* ``<float.h>``
+* ``<inttypes.h>``
+* ``<limits.h>``
+* ``<locale.h>``
+* ``<math.h>``
+* ``<setjmp.h>``
+* ``<signal.h>``
+* ``<stdarg.h>``
+* ``<stddef.h>``
+* ``<stdint.h>``
+* ``<stdio.h>``
+* ``<stdlib.h>``
+* ``<string.h>``
+* ``<tgmath.h>`` // deprecated since C++11
+* ``<time.h>``
+* ``<uchar.h>`` // deprecated since C++11
+* ``<wchar.h>``
+* ``<wctype.h>``
+
+Important note: the C++ headers are not identical to their C counterparts.
+The C headers provide names in the global namespace (e.g. ``<stdio.h>``
+provides ``printf``), but the C++ headers might provide them only in the
+``std`` namespace (e.g. ``<cstdio>`` provides ``std::printf``, but not
+necessarily ``printf``). The check can break code that uses the unqualified
+names.
.. code-block:: c++
@@ -21,46 +64,9 @@ removes redundant ones.
#include <cassert>
// No 'stdbool.h' here.
-Important note: the Standard doesn't guarantee that the C++ headers declare all
-the same functions in the global namespace. The check in its current form can
-break the code that uses library symbols from the global namespace.
-
-* `<assert.h>`
-* `<complex.h>`
-* `<ctype.h>`
-* `<errno.h>`
-* `<fenv.h>` // deprecated since C++11
-* `<float.h>`
-* `<inttypes.h>`
-* `<limits.h>`
-* `<locale.h>`
-* `<math.h>`
-* `<setjmp.h>`
-* `<signal.h>`
-* `<stdarg.h>`
-* `<stddef.h>`
-* `<stdint.h>`
-* `<stdio.h>`
-* `<stdlib.h>`
-* `<string.h>`
-* `<tgmath.h>` // deprecated since C++11
-* `<time.h>`
-* `<uchar.h>` // deprecated since C++11
-* `<wchar.h>`
-* `<wctype.h>`
-
-If the specified standard is older than C++11 the check will only replace
-headers deprecated before C++11, otherwise -- every header that appeared in
-the previous list.
-
-These headers don't have effect in C++:
-
-* `<iso646.h>`
-* `<stdalign.h>`
-* `<stdbool.h>`
-
-The checker ignores `include` directives within `extern "C" { ... }` blocks,
-since a library might want to expose some API for C and C++ libraries.
+The check will ignore `include` directives within `extern "C" { ... }`
+blocks, under the assumption that such code is an API meant to compile as
+both C and C++:
.. code-block:: c++
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/deprecated-headers/ciso646 b/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/deprecated-headers/ciso646
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/deprecated-headers/cstdalign b/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/deprecated-headers/cstdalign
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/deprecated-headers/cstdbool b/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/deprecated-headers/cstdbool
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/deprecated-headers/stdnoreturn.h b/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/deprecated-headers/stdnoreturn.h
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/deprecated-headers-c23.c b/clang-tools-extra/test/clang-tidy/checkers/modernize/deprecated-headers-c23.c
new file mode 100644
index 0000000000000..f81f9981abaa6
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/deprecated-headers-c23.c
@@ -0,0 +1,25 @@
+// RUN: %check_clang_tidy -std=c23-or-later %s modernize-deprecated-headers %t -- -extra-arg-before=-isystem%S/Inputs/deprecated-headers
+
+#include <stdalign.h> // <stdalign.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdalign.h' has no effect since C23; consider removing it
+// CHECK-FIXES: // <stdalign.h>
+#include <stdbool.h> // <stdbool.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdbool.h' has no effect since C23; consider removing it
+// CHECK-FIXES: // <stdbool.h>
+#include <stdnoreturn.h> // <stdnoreturn.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdnoreturn.h' has no effect since C23; consider removing it
+// CHECK-FIXES: // <stdnoreturn.h>
+
+#include <stdio.h> // OK, not deprecated
+
+#include "stdalign.h" // "stdalign.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdalign.h' has no effect since C23; consider removing it
+// CHECK-FIXES: // "stdalign.h"
+#include "stdbool.h" // "stdbool.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdbool.h' has no effect since C23; consider removing it
+// CHECK-FIXES: // "stdbool.h"
+#include "stdnoreturn.h" // "stdnoreturn.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdnoreturn.h' has no effect since C23; consider removing it
+// CHECK-FIXES: // "stdnoreturn.h"
+
+#include "stdio.h" // OK, not deprecated
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/deprecated-headers-cxx03.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/deprecated-headers-cxx03.cpp
index b02dfd1ce976f..01bb62e99f16f 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/deprecated-headers-cxx03.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/deprecated-headers-cxx03.cpp
@@ -59,12 +59,21 @@
#include <stdalign.h> // <stdalign.h>
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdalign.h' has no effect in C++; consider removing it
// CHECK-FIXES: // <stdalign.h>
+#include <cstdalign> // <cstdalign>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'cstdalign' has no effect in C++; consider removing it
+// CHECK-FIXES: // <cstdalign>
#include <stdbool.h> // <stdbool.h>
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdbool.h' has no effect in C++; consider removing it
// CHECK-FIXES: // <stdbool.h>
+#include <cstdbool> // <cstdbool>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'cstdbool' has no effect in C++; consider removing it
+// CHECK-FIXES: // <cstdbool>
#include <iso646.h> // <iso646.h>
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'iso646.h' has no effect in C++; consider removing it
// CHECK-FIXES: // <iso646.h>
+#include <ciso646> // <ciso646>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'ciso646' has no effect in C++; consider removing it
+// CHECK-FIXES: // <ciso646>
// Headers deprecated since C++11: expect no diagnostics.
#include <fenv.h>
@@ -133,12 +142,21 @@
#include "stdalign.h" // "stdalign.h"
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdalign.h' has no effect in C++; consider removing it
// CHECK-FIXES: // "stdalign.h"
+#include "cstdalign" // "cstdalign"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'cstdalign' has no effect in C++; consider removing it
+// CHECK-FIXES: // "cstdalign"
#include "stdbool.h" // "stdbool.h"
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdbool.h' has no effect in C++; consider removing it
// CHECK-FIXES: // "stdbool.h"
+#include "cstdbool" // "cstdbool"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'cstdbool' has no effect in C++; consider removing it
+// CHECK-FIXES: // "cstdbool"
#include "iso646.h" // "iso646.h"
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'iso646.h' has no effect in C++; consider removing it
// CHECK-FIXES: // "iso646.h"
+#include "ciso646" // "ciso646"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'ciso646' has no effect in C++; consider removing it
+// CHECK-FIXES: // "ciso646"
// Headers deprecated since C++11; expect no diagnostics
#include "fenv.h"
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/deprecated-headers-cxx11.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/deprecated-headers-cxx11.cpp
index 99ef506276a66..d4af364f0a844 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/deprecated-headers-cxx11.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/deprecated-headers-cxx11.cpp
@@ -74,12 +74,21 @@
#include <stdalign.h> // <stdalign.h>
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdalign.h' has no effect in C++; consider removing it
// CHECK-FIXES: // <stdalign.h>
+#include <cstdalign> // <cstdalign>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'cstdalign' has no effect in C++; consider removing it
+// CHECK-FIXES: // <cstdalign>
#include <stdbool.h> // <stdbool.h>
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdbool.h' has no effect in C++; consider removing it
// CHECK-FIXES: // <stdbool.h>
+#include <cstdbool> // <cstdbool>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'cstdbool' has no effect in C++; consider removing it
+// CHECK-FIXES: // <cstdbool>
#include <iso646.h> // <iso646.h>
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'iso646.h' has no effect in C++; consider removing it
// CHECK-FIXES: // <iso646.h>
+#include <ciso646> // <ciso646>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'ciso646' has no effect in C++; consider removing it
+// CHECK-FIXES: // <ciso646>
#include "assert.h"
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'assert.h'; consider using 'cassert' instead
@@ -155,9 +164,18 @@
#include "stdalign.h" // "stdalign.h"
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdalign.h' has no effect in C++; consider removing it
// CHECK-FIXES: // "stdalign.h"
+#include "cstdalign" // "cstdalign"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'cstdalign' has no effect in C++; consider removing it
+// CHECK-FIXES: // "cstdalign"
#include "stdbool.h" // "stdbool.h"
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdbool.h' has no effect in C++; consider removing it
// CHECK-FIXES: // "stdbool.h"
+#include "cstdbool" // "cstdbool"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'cstdbool' has no effect in C++; consider removing it
+// CHECK-FIXES: // "cstdbool"
#include "iso646.h" // "iso646.h"
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'iso646.h' has no effect in C++; consider removing it
// CHECK-FIXES: // "iso646.h"
+#include "ciso646" // "ciso646"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'ciso646' has no effect in C++; consider removing it
+// CHECK-FIXES: // "ciso646"
More information about the cfe-commits
mailing list