Skip to content

Commit c64e4db

Browse files
committed
[Clang] Add #pragma deprecated_header
1 parent f969c86 commit c64e4db

File tree

9 files changed

+115
-3
lines changed

9 files changed

+115
-3
lines changed

clang/include/clang/Basic/DiagnosticLexKinds.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,11 @@ def warn_pragma_deprecated_macro_use :
666666
ExtWarn<"macro %0 has been marked as deprecated%select{|: %2}1">,
667667
InGroup<DeprecatedPragma>;
668668

669+
// - #pragma depcreated_header
670+
def warn_pragma_deprecated_header : Warning<
671+
"header is deprecated%select{|: %1}0">,
672+
InGroup<Deprecated>;
673+
669674
// - #pragma clang restrict_expansion(...)
670675
def warn_pragma_restrict_expansion_macro_use :
671676
ExtWarn<"macro %0 has been marked as unsafe for use in headers"

clang/include/clang/Lex/HeaderSearch.h

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ struct HeaderFileInfo {
8080
LLVM_PREFERRED_TYPE(SrcMgr::CharacteristicKind)
8181
unsigned DirInfo : 3;
8282

83+
LLVM_PREFERRED_TYPE(bool)
84+
unsigned IsDeprecated : 1;
85+
8386
/// Whether this header file info was supplied by an external source,
8487
/// and has not changed since.
8588
LLVM_PREFERRED_TYPE(bool)
@@ -124,9 +127,9 @@ struct HeaderFileInfo {
124127

125128
HeaderFileInfo()
126129
: IsLocallyIncluded(false), isImport(false), isPragmaOnce(false),
127-
DirInfo(SrcMgr::C_User), External(false), isModuleHeader(false),
128-
isTextualModuleHeader(false), isCompilingModuleHeader(false),
129-
Resolved(false), IsValid(false) {}
130+
DirInfo(SrcMgr::C_User), IsDeprecated(false), External(false),
131+
isModuleHeader(false), isTextualModuleHeader(false),
132+
isCompilingModuleHeader(false), Resolved(false), IsValid(false) {}
130133

131134
/// Retrieve the controlling macro for this header file, if
132135
/// any.
@@ -356,6 +359,9 @@ class HeaderSearch {
356359
// A map of discovered headers with their associated include file name.
357360
llvm::DenseMap<const FileEntry *, llvm::SmallString<64>> IncludeNames;
358361

362+
// A map from a file to its deprecation message
363+
llvm::DenseMap<const FileEntry *, std::string> DeprecationMessages;
364+
359365
/// Uniqued set of framework names, which is used to track which
360366
/// headers were included as framework headers.
361367
llvm::StringSet<llvm::BumpPtrAllocator> FrameworkNames;
@@ -563,6 +569,12 @@ class HeaderSearch {
563569
getFileInfo(File).DirInfo = SrcMgr::C_System;
564570
}
565571

572+
void MarkFileDeprecated(FileEntryRef File, std::string DeprecationMessage) {
573+
getFileInfo(File).IsDeprecated = true;
574+
DeprecationMessages.emplace_or_assign(&File.getFileEntry(),
575+
std::move(DeprecationMessage));
576+
}
577+
566578
/// Mark the specified file as part of a module.
567579
void MarkFileModuleHeader(FileEntryRef FE, ModuleMap::ModuleHeaderRole Role,
568580
bool isCompilingModuleHeader);
@@ -652,6 +664,13 @@ class HeaderSearch {
652664
std::string getCachedModuleFileName(StringRef ModuleName,
653665
StringRef ModuleMapPath);
654666

667+
std::optional<std::string_view>
668+
getHeaderDeprecationMessage(FileEntryRef File) {
669+
if (!getFileInfo(File).IsDeprecated)
670+
return std::nullopt;
671+
return DeprecationMessages.at(File);
672+
}
673+
655674
/// Lookup a module Search for a module with the given name.
656675
///
657676
/// \param ModuleName The name of the module we're looking for.

clang/include/clang/Lex/Preprocessor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2943,6 +2943,7 @@ class Preprocessor {
29432943
void HandlePragmaMark(Token &MarkTok);
29442944
void HandlePragmaPoison();
29452945
void HandlePragmaSystemHeader(Token &SysHeaderTok);
2946+
void HandlePragmaDeprecatedHeader(Token &Tok, std::string DeprecationMessage);
29462947
void HandlePragmaDependency(Token &DependencyTok);
29472948
void HandlePragmaPushMacro(Token &Tok);
29482949
void HandlePragmaPopMacro(Token &Tok);

clang/lib/Lex/PPDirectives.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2509,6 +2509,15 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
25092509
Action = TrackGMFState.inGMF() ? Import : Skip;
25102510
else
25112511
Action = (ModuleToImport && !getLangOpts().CompilingPCH) ? Import : Skip;
2512+
2513+
// If we're not entering the header, it might have been marked deprecated
2514+
// the first time it was included.
2515+
if (auto MaybeMessage = HeaderInfo.getHeaderDeprecationMessage(*File);
2516+
MaybeMessage) {
2517+
std::string_view Message = *MaybeMessage;
2518+
Diag(FilenameTok, diag::warn_pragma_deprecated_header)
2519+
<< !Message.empty() << Message;
2520+
}
25122521
}
25132522

25142523
// Check for circular inclusion of the main file.

clang/lib/Lex/PPLexerChange.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,18 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
490490
SourceMgr.getFileEntryForID(CurPPLexer->getFileID())))
491491
FoundPCHThroughHeader = true;
492492

493+
if (CurPPLexer) {
494+
if (OptionalFileEntryRef File = CurPPLexer->getFileEntry()) {
495+
if (auto MaybeMessage = HeaderInfo.getHeaderDeprecationMessage(*File);
496+
MaybeMessage) {
497+
std::string_view Message = *MaybeMessage;
498+
Diag(SourceMgr.getIncludeLoc(CurPPLexer->getFileID()),
499+
diag::warn_pragma_deprecated_header)
500+
<< !Message.empty() << Message;
501+
}
502+
}
503+
}
504+
493505
// We're done with the #included file.
494506
RemoveTopOfLexerStack();
495507

clang/lib/Lex/Pragma.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,13 @@ void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) {
508508
SrcMgr::C_System);
509509
}
510510

511+
void Preprocessor::HandlePragmaDeprecatedHeader(
512+
Token &Tok, std::string DeprecationMessage) {
513+
PreprocessorLexer *TheLexer = getCurrentFileLexer();
514+
HeaderInfo.MarkFileDeprecated(*TheLexer->getFileEntry(),
515+
std::move(DeprecationMessage));
516+
}
517+
511518
/// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah.
512519
void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
513520
Token FilenameTok;
@@ -2084,6 +2091,39 @@ struct PragmaDeprecatedHandler : public PragmaHandler {
20842091
}
20852092
};
20862093

2094+
/// "\#pragma clang deprecated_header"
2095+
struct PragmaDeprecatedHeaderHandler : PragmaHandler {
2096+
PragmaDeprecatedHeaderHandler() : PragmaHandler("deprecated_header") {}
2097+
2098+
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
2099+
Token &Tok) override {
2100+
std::string MessageString;
2101+
2102+
PP.Lex(Tok);
2103+
if (!Tok.is(tok::eod)) {
2104+
if (!Tok.is(tok::l_paren)) {
2105+
PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol)
2106+
<< "pragma clang deprecated_header";
2107+
} else {
2108+
PP.Lex(Tok);
2109+
if (PP.FinishLexStringLiteral(Tok, MessageString,
2110+
"#pragma clang deprecated_header",
2111+
/*AllowMacroExpansion=*/true)) {
2112+
if (Tok.isNot(tok::r_paren)) {
2113+
PP.Diag(Tok, diag::err_expected) << ")";
2114+
} else {
2115+
PP.Lex(Tok);
2116+
if (!Tok.is(tok::eod))
2117+
PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol)
2118+
<< "pragma clang deprecated_header";
2119+
}
2120+
}
2121+
}
2122+
}
2123+
PP.HandlePragmaDeprecatedHeader(Tok, MessageString);
2124+
}
2125+
};
2126+
20872127
/// "\#pragma clang restrict_expansion(...)"
20882128
///
20892129
/// The syntax is
@@ -2174,6 +2214,7 @@ void Preprocessor::RegisterBuiltinPragmas() {
21742214
AddPragmaHandler("clang", new PragmaARCCFCodeAuditedHandler());
21752215
AddPragmaHandler("clang", new PragmaAssumeNonNullHandler());
21762216
AddPragmaHandler("clang", new PragmaDeprecatedHandler());
2217+
AddPragmaHandler("clang", new PragmaDeprecatedHeaderHandler());
21772218
AddPragmaHandler("clang", new PragmaRestrictExpansionHandler());
21782219
AddPragmaHandler("clang", new PragmaFinalHandler());
21792220

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef DEPRECATED_HEADER_MSG_H
2+
#define DEPRECATED_HEADER_MSG_H
3+
4+
#pragma clang deprecated_header("This is a shitty header")
5+
6+
#endif // DEPRECATED_HEADER_MSG_H
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %clang_cc1 -Wdeprecated %s -fsyntax-only -verify -Wunknown-pragmas -Wextra-tokens
2+
3+
#pragma clang deprecated_header( // expected-error {{expected string literal in #pragma clang deprecated_header}}
4+
#pragma clang deprecated_header() // expected-error {{expected string literal in #pragma clang deprecated_header}}
5+
#pragma clang deprecated_header("" // expected-error {{expected )}}
6+
#pragma clang deprecated_header something // expected-warning {{extra tokens at end of #pragma clang deprecated_header directive}}
7+
#pragma clang deprecated_header("") something // expected-warning {{extra tokens at end of #pragma clang deprecated_header directive}}
8+
9+
#include "deprecated-header.h" // expected-warning {{header is deprecated}}
10+
#include "deprecated-header.h" // expected-warning {{header is deprecated}}
11+
12+
#include "deprecated-header-msg.h" // expected-warning {{header is deprecated: This is a shitty header}}
13+
#include "deprecated-header-msg.h" // expected-warning {{header is deprecated: This is a shitty header}}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef DEPRECATED_HEADER_H
2+
#define DEPRECATED_HEADER_H
3+
4+
#pragma clang deprecated_header
5+
6+
#endif // DEPRECATED_HEADER_H

0 commit comments

Comments
 (0)