diff options
author | Mike Rice <michael.p.rice@intel.com> | 2018-09-11 17:10:44 +0000 |
---|---|---|
committer | Mike Rice <michael.p.rice@intel.com> | 2018-09-11 17:10:44 +0000 |
commit | 3886719cbbfb304f2eb93fba42b904959a8e77c3 (patch) | |
tree | 9f43b1ea80ad36a744d8179a60271e184b2e043c /lib/Lex | |
parent | 0a8a76da18b28bea9500c5f4539fe9c65075b4ac (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.cpp | 31 | ||||
-rw-r--r-- | lib/Lex/Pragma.cpp | 41 | ||||
-rw-r--r-- | lib/Lex/Preprocessor.cpp | 44 |
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() { |