Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions clang-tools-extra/clang-tidy/modernize/DeprecatedHeadersCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 "
Expand Down Expand Up @@ -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"},
Expand All @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Comment on lines -7 to -8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we still mention "[depr.c.headers]" section somewhere?


This check replaces C standard library headers with their C++ alternatives and
removes redundant ones.
Comment on lines -10 to -11
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we leave this as first sentence in docs? But remove "This check" in favor of "Replaces ..."

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++

Expand All @@ -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.
Comment on lines -52 to -54
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we completely remove this part?


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++

Expand Down
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"