https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/168041
>From c64e4dbf78300fb0021ddbad976f13237d4b2870 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser <[email protected]> Date: Fri, 14 Nov 2025 11:54:12 +0100 Subject: [PATCH] [Clang] Add #pragma deprecated_header --- .../include/clang/Basic/DiagnosticLexKinds.td | 5 +++ clang/include/clang/Lex/HeaderSearch.h | 25 +++++++++-- clang/include/clang/Lex/Preprocessor.h | 1 + clang/lib/Lex/PPDirectives.cpp | 9 ++++ clang/lib/Lex/PPLexerChange.cpp | 12 ++++++ clang/lib/Lex/Pragma.cpp | 41 +++++++++++++++++++ clang/test/Lexer/deprecated-header-msg.h | 6 +++ clang/test/Lexer/deprecated-header.c | 13 ++++++ clang/test/Lexer/deprecated-header.h | 6 +++ 9 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 clang/test/Lexer/deprecated-header-msg.h create mode 100644 clang/test/Lexer/deprecated-header.c create mode 100644 clang/test/Lexer/deprecated-header.h diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index 417187222e448..c587a0e861949 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -666,6 +666,11 @@ def warn_pragma_deprecated_macro_use : ExtWarn<"macro %0 has been marked as deprecated%select{|: %2}1">, InGroup<DeprecatedPragma>; +// - #pragma depcreated_header +def warn_pragma_deprecated_header : Warning< + "header is deprecated%select{|: %1}0">, + InGroup<Deprecated>; + // - #pragma clang restrict_expansion(...) def warn_pragma_restrict_expansion_macro_use : ExtWarn<"macro %0 has been marked as unsafe for use in headers" diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h index 850aea41c4c3b..3a3d5498a2d44 100644 --- a/clang/include/clang/Lex/HeaderSearch.h +++ b/clang/include/clang/Lex/HeaderSearch.h @@ -80,6 +80,9 @@ struct HeaderFileInfo { LLVM_PREFERRED_TYPE(SrcMgr::CharacteristicKind) unsigned DirInfo : 3; + LLVM_PREFERRED_TYPE(bool) + unsigned IsDeprecated : 1; + /// Whether this header file info was supplied by an external source, /// and has not changed since. LLVM_PREFERRED_TYPE(bool) @@ -124,9 +127,9 @@ struct HeaderFileInfo { HeaderFileInfo() : IsLocallyIncluded(false), isImport(false), isPragmaOnce(false), - DirInfo(SrcMgr::C_User), External(false), isModuleHeader(false), - isTextualModuleHeader(false), isCompilingModuleHeader(false), - Resolved(false), IsValid(false) {} + DirInfo(SrcMgr::C_User), IsDeprecated(false), External(false), + isModuleHeader(false), isTextualModuleHeader(false), + isCompilingModuleHeader(false), Resolved(false), IsValid(false) {} /// Retrieve the controlling macro for this header file, if /// any. @@ -356,6 +359,9 @@ class HeaderSearch { // A map of discovered headers with their associated include file name. llvm::DenseMap<const FileEntry *, llvm::SmallString<64>> IncludeNames; + // A map from a file to its deprecation message + llvm::DenseMap<const FileEntry *, std::string> DeprecationMessages; + /// Uniqued set of framework names, which is used to track which /// headers were included as framework headers. llvm::StringSet<llvm::BumpPtrAllocator> FrameworkNames; @@ -563,6 +569,12 @@ class HeaderSearch { getFileInfo(File).DirInfo = SrcMgr::C_System; } + void MarkFileDeprecated(FileEntryRef File, std::string DeprecationMessage) { + getFileInfo(File).IsDeprecated = true; + DeprecationMessages.emplace_or_assign(&File.getFileEntry(), + std::move(DeprecationMessage)); + } + /// Mark the specified file as part of a module. void MarkFileModuleHeader(FileEntryRef FE, ModuleMap::ModuleHeaderRole Role, bool isCompilingModuleHeader); @@ -652,6 +664,13 @@ class HeaderSearch { std::string getCachedModuleFileName(StringRef ModuleName, StringRef ModuleMapPath); + std::optional<std::string_view> + getHeaderDeprecationMessage(FileEntryRef File) { + if (!getFileInfo(File).IsDeprecated) + return std::nullopt; + return DeprecationMessages.at(File); + } + /// Lookup a module Search for a module with the given name. /// /// \param ModuleName The name of the module we're looking for. diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index b1c648e647f41..3324996c59554 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -2943,6 +2943,7 @@ class Preprocessor { void HandlePragmaMark(Token &MarkTok); void HandlePragmaPoison(); void HandlePragmaSystemHeader(Token &SysHeaderTok); + void HandlePragmaDeprecatedHeader(Token &Tok, std::string DeprecationMessage); void HandlePragmaDependency(Token &DependencyTok); void HandlePragmaPushMacro(Token &Tok); void HandlePragmaPopMacro(Token &Tok); diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 891c8ab7f3155..0ea2b412502c2 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -2509,6 +2509,15 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( Action = TrackGMFState.inGMF() ? Import : Skip; else Action = (ModuleToImport && !getLangOpts().CompilingPCH) ? Import : Skip; + + // If we're not entering the header, it might have been marked deprecated + // the first time it was included. + if (auto MaybeMessage = HeaderInfo.getHeaderDeprecationMessage(*File); + MaybeMessage) { + std::string_view Message = *MaybeMessage; + Diag(FilenameTok, diag::warn_pragma_deprecated_header) + << !Message.empty() << Message; + } } // Check for circular inclusion of the main file. diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp index b014124153c83..52a19d1a3428a 100644 --- a/clang/lib/Lex/PPLexerChange.cpp +++ b/clang/lib/Lex/PPLexerChange.cpp @@ -490,6 +490,18 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { SourceMgr.getFileEntryForID(CurPPLexer->getFileID()))) FoundPCHThroughHeader = true; + if (CurPPLexer) { + if (OptionalFileEntryRef File = CurPPLexer->getFileEntry()) { + if (auto MaybeMessage = HeaderInfo.getHeaderDeprecationMessage(*File); + MaybeMessage) { + std::string_view Message = *MaybeMessage; + Diag(SourceMgr.getIncludeLoc(CurPPLexer->getFileID()), + diag::warn_pragma_deprecated_header) + << !Message.empty() << Message; + } + } + } + // We're done with the #included file. RemoveTopOfLexerStack(); diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index bba3c89bed38f..47f0974d3aeef 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -508,6 +508,13 @@ void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) { SrcMgr::C_System); } +void Preprocessor::HandlePragmaDeprecatedHeader( + Token &Tok, std::string DeprecationMessage) { + PreprocessorLexer *TheLexer = getCurrentFileLexer(); + HeaderInfo.MarkFileDeprecated(*TheLexer->getFileEntry(), + std::move(DeprecationMessage)); +} + /// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah. void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { Token FilenameTok; @@ -2084,6 +2091,39 @@ struct PragmaDeprecatedHandler : public PragmaHandler { } }; +/// "\#pragma clang deprecated_header" +struct PragmaDeprecatedHeaderHandler : PragmaHandler { + PragmaDeprecatedHeaderHandler() : PragmaHandler("deprecated_header") {} + + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, + Token &Tok) override { + std::string MessageString; + + PP.Lex(Tok); + if (!Tok.is(tok::eod)) { + if (!Tok.is(tok::l_paren)) { + PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) + << "pragma clang deprecated_header"; + } else { + PP.Lex(Tok); + if (PP.FinishLexStringLiteral(Tok, MessageString, + "#pragma clang deprecated_header", + /*AllowMacroExpansion=*/true)) { + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok, diag::err_expected) << ")"; + } else { + PP.Lex(Tok); + if (!Tok.is(tok::eod)) + PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) + << "pragma clang deprecated_header"; + } + } + } + } + PP.HandlePragmaDeprecatedHeader(Tok, MessageString); + } +}; + /// "\#pragma clang restrict_expansion(...)" /// /// The syntax is @@ -2174,6 +2214,7 @@ void Preprocessor::RegisterBuiltinPragmas() { AddPragmaHandler("clang", new PragmaARCCFCodeAuditedHandler()); AddPragmaHandler("clang", new PragmaAssumeNonNullHandler()); AddPragmaHandler("clang", new PragmaDeprecatedHandler()); + AddPragmaHandler("clang", new PragmaDeprecatedHeaderHandler()); AddPragmaHandler("clang", new PragmaRestrictExpansionHandler()); AddPragmaHandler("clang", new PragmaFinalHandler()); diff --git a/clang/test/Lexer/deprecated-header-msg.h b/clang/test/Lexer/deprecated-header-msg.h new file mode 100644 index 0000000000000..6295affba3f7b --- /dev/null +++ b/clang/test/Lexer/deprecated-header-msg.h @@ -0,0 +1,6 @@ +#ifndef DEPRECATED_HEADER_MSG_H +#define DEPRECATED_HEADER_MSG_H + +#pragma clang deprecated_header("This is a shitty header") + +#endif // DEPRECATED_HEADER_MSG_H diff --git a/clang/test/Lexer/deprecated-header.c b/clang/test/Lexer/deprecated-header.c new file mode 100644 index 0000000000000..caff6b2d09345 --- /dev/null +++ b/clang/test/Lexer/deprecated-header.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -Wdeprecated %s -fsyntax-only -verify -Wunknown-pragmas -Wextra-tokens + +#pragma clang deprecated_header( // expected-error {{expected string literal in #pragma clang deprecated_header}} +#pragma clang deprecated_header() // expected-error {{expected string literal in #pragma clang deprecated_header}} +#pragma clang deprecated_header("" // expected-error {{expected )}} +#pragma clang deprecated_header something // expected-warning {{extra tokens at end of #pragma clang deprecated_header directive}} +#pragma clang deprecated_header("") something // expected-warning {{extra tokens at end of #pragma clang deprecated_header directive}} + +#include "deprecated-header.h" // expected-warning {{header is deprecated}} +#include "deprecated-header.h" // expected-warning {{header is deprecated}} + +#include "deprecated-header-msg.h" // expected-warning {{header is deprecated: This is a shitty header}} +#include "deprecated-header-msg.h" // expected-warning {{header is deprecated: This is a shitty header}} diff --git a/clang/test/Lexer/deprecated-header.h b/clang/test/Lexer/deprecated-header.h new file mode 100644 index 0000000000000..81884b5630b9c --- /dev/null +++ b/clang/test/Lexer/deprecated-header.h @@ -0,0 +1,6 @@ +#ifndef DEPRECATED_HEADER_H +#define DEPRECATED_HEADER_H + +#pragma clang deprecated_header + +#endif // DEPRECATED_HEADER_H _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
