summaryrefslogtreecommitdiffstats
path: root/lib/Lex
diff options
context:
space:
mode:
authorMike Rice <michael.p.rice@intel.com>2018-09-11 17:10:44 +0000
committerMike Rice <michael.p.rice@intel.com>2018-09-11 17:10:44 +0000
commit3886719cbbfb304f2eb93fba42b904959a8e77c3 (patch)
tree9f43b1ea80ad36a744d8179a60271e184b2e043c /lib/Lex
parent0a8a76da18b28bea9500c5f4539fe9c65075b4ac (diff)
[clang-cl, PCH] Support for /Yc and /Yu without filename and #pragma hdrstop
With clang-cl, when the user specifies /Yc or /Yu without a filename the compiler uses a #pragma hdrstop in the main source file to determine the end of the PCH. If a header is specified with /Yc or /Yu #pragma hdrstop has no effect. The optional #pragma hdrstop filename argument is not yet supported. Differential Revision: https://reviews.llvm.org/D51391 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@341963 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Lex')
-rw-r--r--lib/Lex/PPDirectives.cpp31
-rw-r--r--lib/Lex/Pragma.cpp41
-rw-r--r--lib/Lex/Preprocessor.cpp44
3 files changed, 95 insertions, 21 deletions
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 66a9faa6e6..2bb96c1f15 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -887,18 +887,29 @@ private:
bool save;
};
-/// Process a directive while looking for the through header.
-/// Only #include (to check if it is the through header) and #define (to warn
-/// about macros that don't match the PCH) are handled. All other directives
-/// are completely discarded.
-void Preprocessor::HandleSkippedThroughHeaderDirective(Token &Result,
+/// Process a directive while looking for the through header or a #pragma
+/// hdrstop. The following directives are handled:
+/// #include (to check if it is the through header)
+/// #define (to warn about macros that don't match the PCH)
+/// #pragma (to check for pragma hdrstop).
+/// All other directives are completely discarded.
+void Preprocessor::HandleSkippedDirectiveWhileUsingPCH(Token &Result,
SourceLocation HashLoc) {
if (const IdentifierInfo *II = Result.getIdentifierInfo()) {
- if (II->getPPKeywordID() == tok::pp_include)
- return HandleIncludeDirective(HashLoc, Result);
- if (II->getPPKeywordID() == tok::pp_define)
+ if (II->getPPKeywordID() == tok::pp_define) {
return HandleDefineDirective(Result,
/*ImmediatelyAfterHeaderGuard=*/false);
+ }
+ if (SkippingUntilPCHThroughHeader &&
+ II->getPPKeywordID() == tok::pp_include) {
+ return HandleIncludeDirective(HashLoc, Result);
+ }
+ if (SkippingUntilPragmaHdrStop && II->getPPKeywordID() == tok::pp_pragma) {
+ Token P = LookAhead(0);
+ auto *II = P.getIdentifierInfo();
+ if (II && II->getName() == "hdrstop")
+ return HandlePragmaDirective(HashLoc, PIK_HashPragma);
+ }
}
DiscardUntilEndOfDirective();
}
@@ -964,8 +975,8 @@ void Preprocessor::HandleDirective(Token &Result) {
// and reset to previous state when returning from this function.
ResetMacroExpansionHelper helper(this);
- if (SkippingUntilPCHThroughHeader)
- return HandleSkippedThroughHeaderDirective(Result, SavedHash.getLocation());
+ if (SkippingUntilPCHThroughHeader || SkippingUntilPragmaHdrStop)
+ return HandleSkippedDirectiveWhileUsingPCH(Result, SavedHash.getLocation());
switch (Result.getKind()) {
case tok::eod:
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 37c0a23646..0a63ed724c 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -876,6 +876,37 @@ void Preprocessor::HandlePragmaModuleBuild(Token &Tok) {
StringRef(Start, End - Start));
}
+void Preprocessor::HandlePragmaHdrstop(Token &Tok) {
+ Lex(Tok);
+ if (Tok.is(tok::l_paren)) {
+ Diag(Tok.getLocation(), diag::warn_pp_hdrstop_filename_ignored);
+
+ std::string FileName;
+ if (!LexStringLiteral(Tok, FileName, "pragma hdrstop", false))
+ return;
+
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_expected) << tok::r_paren;
+ return;
+ }
+ Lex(Tok);
+ }
+ if (Tok.isNot(tok::eod))
+ Diag(Tok.getLocation(), diag::ext_pp_extra_tokens_at_eol)
+ << "pragma hdrstop";
+
+ if (creatingPCHWithPragmaHdrStop() &&
+ SourceMgr.isInMainFile(Tok.getLocation())) {
+ assert(CurLexer && "no lexer for #pragma hdrstop processing");
+ Token &Result = Tok;
+ Result.startToken();
+ CurLexer->FormTokenWithChars(Result, CurLexer->BufferEnd, tok::eof);
+ CurLexer->cutOffLexing();
+ }
+ if (usingPCHWithPragmaHdrStop())
+ SkippingUntilPragmaHdrStop = false;
+}
+
/// AddPragmaHandler - Add the specified pragma handler to the preprocessor.
/// If 'Namespace' is non-null, then it is a token required to exist on the
/// pragma line before the pragma string starts, e.g. "STDC" or "GCC".
@@ -1220,6 +1251,15 @@ public:
}
};
+/// "\#pragma hdrstop [<header-name-string>]"
+struct PragmaHdrstopHandler : public PragmaHandler {
+ PragmaHdrstopHandler() : PragmaHandler("hdrstop") {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &DepToken) override {
+ PP.HandlePragmaHdrstop(DepToken);
+ }
+};
+
/// "\#pragma warning(...)". MSVC's diagnostics do not map cleanly to clang's
/// diagnostics, so we don't really implement this pragma. We parse it and
/// ignore it to avoid -Wunknown-pragma warnings.
@@ -1799,6 +1839,7 @@ void Preprocessor::RegisterBuiltinPragmas() {
if (LangOpts.MicrosoftExt) {
AddPragmaHandler(new PragmaWarningHandler());
AddPragmaHandler(new PragmaIncludeAliasHandler());
+ AddPragmaHandler(new PragmaHdrstopHandler());
}
// Pragmas added by plugins
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index c7da41172f..dcff51ad61 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -149,6 +149,10 @@ Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts,
Ident_AbnormalTermination = nullptr;
}
+ // If using a PCH where a #pragma hdrstop is expected, start skipping tokens.
+ if (usingPCHWithPragmaHdrStop())
+ SkippingUntilPragmaHdrStop = true;
+
// If using a PCH with a through header, start skipping tokens.
if (!this->PPOpts->PCHThroughHeader.empty() &&
!this->PPOpts->ImplicitPCHInclude.empty())
@@ -576,8 +580,9 @@ void Preprocessor::EnterMainSourceFile() {
}
// Skip tokens from the Predefines and if needed the main file.
- if (usingPCHWithThroughHeader() && SkippingUntilPCHThroughHeader)
- SkipTokensUntilPCHThroughHeader();
+ if ((usingPCHWithThroughHeader() && SkippingUntilPCHThroughHeader) ||
+ (usingPCHWithPragmaHdrStop() && SkippingUntilPragmaHdrStop))
+ SkipTokensWhileUsingPCH();
}
void Preprocessor::setPCHThroughHeaderFileID(FileID FID) {
@@ -602,12 +607,23 @@ bool Preprocessor::usingPCHWithThroughHeader() {
PCHThroughHeaderFileID.isValid();
}
-/// Skip tokens until after the #include of the through header.
-/// Tokens in the predefines file and the main file may be skipped. If the end
-/// of the predefines file is reached, skipping continues into the main file.
-/// If the end of the main file is reached, it's a fatal error.
-void Preprocessor::SkipTokensUntilPCHThroughHeader() {
+bool Preprocessor::creatingPCHWithPragmaHdrStop() {
+ return TUKind == TU_Prefix && PPOpts->PCHWithHdrStop;
+}
+
+bool Preprocessor::usingPCHWithPragmaHdrStop() {
+ return TUKind != TU_Prefix && PPOpts->PCHWithHdrStop;
+}
+
+/// Skip tokens until after the #include of the through header or
+/// until after a #pragma hdrstop is seen. Tokens in the predefines file
+/// and the main file may be skipped. If the end of the predefines file
+/// is reached, skipping continues into the main file. If the end of the
+/// main file is reached, it's a fatal error.
+void Preprocessor::SkipTokensWhileUsingPCH() {
bool ReachedMainFileEOF = false;
+ bool UsingPCHThroughHeader = SkippingUntilPCHThroughHeader;
+ bool UsingPragmaHdrStop = SkippingUntilPragmaHdrStop;
Token Tok;
while (true) {
bool InPredefines = (CurLexer->getFileID() == getPredefinesFileID());
@@ -616,12 +632,18 @@ void Preprocessor::SkipTokensUntilPCHThroughHeader() {
ReachedMainFileEOF = true;
break;
}
- if (!SkippingUntilPCHThroughHeader)
+ if (UsingPCHThroughHeader && !SkippingUntilPCHThroughHeader)
+ break;
+ if (UsingPragmaHdrStop && !SkippingUntilPragmaHdrStop)
break;
}
- if (ReachedMainFileEOF)
- Diag(SourceLocation(), diag::err_pp_through_header_not_seen)
- << PPOpts->PCHThroughHeader << 1;
+ if (ReachedMainFileEOF) {
+ if (UsingPCHThroughHeader)
+ Diag(SourceLocation(), diag::err_pp_through_header_not_seen)
+ << PPOpts->PCHThroughHeader << 1;
+ else if (!PPOpts->PCHWithHdrStopCreate)
+ Diag(SourceLocation(), diag::err_pp_pragma_hdrstop_not_seen);
+ }
}
void Preprocessor::replayPreambleConditionalStack() {