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 <[email protected]> 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" _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
