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
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/DiagnosticLexKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
25 changes: 22 additions & 3 deletions clang/include/clang/Lex/HeaderSearch.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Lex/Preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/Lex/PPDirectives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/Lex/PPLexerChange.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
41 changes: 41 additions & 0 deletions clang/lib/Lex/Pragma.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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());

Expand Down
6 changes: 6 additions & 0 deletions clang/test/Lexer/deprecated-header-msg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef DEPRECATED_HEADER_MSG_H
#define DEPRECATED_HEADER_MSG_H

#pragma clang deprecated_header("This is a shitty header")
Copy link
Collaborator

Choose a reason for hiding this comment

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

That's not acceptable for us to commit.


#endif // DEPRECATED_HEADER_MSG_H
13 changes: 13 additions & 0 deletions clang/test/Lexer/deprecated-header.c
Original file line number Diff line number Diff line change
@@ -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}}
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should also have a test that we reject writing this in a source file.


#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}}
6 changes: 6 additions & 0 deletions clang/test/Lexer/deprecated-header.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef DEPRECATED_HEADER_H
#define DEPRECATED_HEADER_H

#pragma clang deprecated_header

#endif // DEPRECATED_HEADER_H
Loading