diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Driver/Driver.cpp | 23 | ||||
-rw-r--r-- | clang/lib/Driver/ToolChains/Clang.cpp | 79 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInstance.cpp | 31 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Lex/PPDirectives.cpp | 35 | ||||
-rw-r--r-- | clang/lib/Lex/PPLexerChange.cpp | 27 | ||||
-rw-r--r-- | clang/lib/Lex/Preprocessor.cpp | 71 | ||||
-rw-r--r-- | clang/lib/Parse/ParseAST.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 11 |
9 files changed, 168 insertions, 117 deletions
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 7b890d80f0a..1fd7a6d718e 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -2991,22 +2991,6 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, Args.eraseArg(options::OPT__SLASH_Yu); YcArg = YuArg = nullptr; } - if (YcArg || YuArg) { - StringRef Val = YcArg ? YcArg->getValue() : YuArg->getValue(); - bool FoundMatchingInclude = false; - for (const Arg *Inc : Args.filtered(options::OPT_include)) { - // FIXME: Do case-insensitive matching and consider / and \ as equal. - if (Inc->getValue() == Val) - FoundMatchingInclude = true; - } - if (!FoundMatchingInclude) { - Diag(clang::diag::warn_drv_ycyu_no_fi_arg_clang_cl) - << (YcArg ? YcArg : YuArg)->getSpelling(); - Args.eraseArg(options::OPT__SLASH_Yc); - Args.eraseArg(options::OPT__SLASH_Yu); - YcArg = YuArg = nullptr; - } - } if (YcArg && Inputs.size() > 1) { Diag(clang::diag::warn_drv_yc_multiple_inputs_clang_cl); Args.eraseArg(options::OPT__SLASH_Yc); @@ -3076,11 +3060,9 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, const types::ID HeaderType = lookupHeaderTypeForSourceType(InputType); llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PCHPL; types::getCompilationPhases(HeaderType, PCHPL); - Arg *PchInputArg = MakeInputArg(Args, *Opts, YcArg->getValue()); - // Build the pipeline for the pch file. Action *ClangClPch = - C.MakeAction<InputAction>(*PchInputArg, HeaderType); + C.MakeAction<InputAction>(*InputArg, HeaderType); for (phases::ID Phase : PCHPL) ClangClPch = ConstructPhaseAction(C, Args, Phase, ClangClPch); assert(ClangClPch); @@ -4269,6 +4251,9 @@ std::string Driver::GetClPchPath(Compilation &C, StringRef BaseName) const { // extension of .pch is assumed. " if (!llvm::sys::path::has_extension(Output)) Output += ".pch"; + } else if (Arg *YcArg = C.getArgs().getLastArg(options::OPT__SLASH_Yc)) { + Output = YcArg->getValue(); + llvm::sys::path::replace_extension(Output, ".pch"); } else { Output = BaseName; llvm::sys::path::replace_extension(Output, ".pch"); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 5999d0b3f95..d7092801dfb 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -1060,77 +1060,28 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, // wonky, but we include looking for .gch so we can support seamless // replacement into a build system already set up to be generating // .gch files. - int YcIndex = -1, YuIndex = -1; - { - int AI = -1; + + if (getToolChain().getDriver().IsCLMode()) { const Arg *YcArg = Args.getLastArg(options::OPT__SLASH_Yc); const Arg *YuArg = Args.getLastArg(options::OPT__SLASH_Yu); - for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) { - // Walk the whole i_Group and skip non "-include" flags so that the index - // here matches the index in the next loop below. - ++AI; - if (!A->getOption().matches(options::OPT_include)) - continue; - if (YcArg && strcmp(A->getValue(), YcArg->getValue()) == 0) - YcIndex = AI; - if (YuArg && strcmp(A->getValue(), YuArg->getValue()) == 0) - YuIndex = AI; + if (YcArg && JA.getKind() >= Action::PrecompileJobClass && + JA.getKind() <= Action::AssembleJobClass) { + CmdArgs.push_back(Args.MakeArgString("-building-pch-with-obj")); + } + if (YcArg || YuArg) { + StringRef ThroughHeader = YcArg ? YcArg->getValue() : YuArg->getValue(); + if (!isa<PrecompileJobAction>(JA)) { + CmdArgs.push_back("-include-pch"); + CmdArgs.push_back(Args.MakeArgString(D.GetClPchPath(C, ThroughHeader))); + } + CmdArgs.push_back( + Args.MakeArgString(Twine("-pch-through-header=") + ThroughHeader)); } - } - if (isa<PrecompileJobAction>(JA) && YcIndex != -1) { - Driver::InputList Inputs; - D.BuildInputs(getToolChain(), C.getArgs(), Inputs); - assert(Inputs.size() == 1 && "Need one input when building pch"); - CmdArgs.push_back(Args.MakeArgString(Twine("-find-pch-source=") + - Inputs[0].second->getValue())); - } - if (YcIndex != -1 && JA.getKind() >= Action::PrecompileJobClass && - JA.getKind() <= Action::AssembleJobClass) { - CmdArgs.push_back(Args.MakeArgString("-building-pch-with-obj")); } bool RenderedImplicitInclude = false; - int AI = -1; for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) { - ++AI; - - if (getToolChain().getDriver().IsCLMode() && - A->getOption().matches(options::OPT_include)) { - // In clang-cl mode, /Ycfoo.h means that all code up to a foo.h - // include is compiled into foo.h, and everything after goes into - // the .obj file. /Yufoo.h means that all includes prior to and including - // foo.h are completely skipped and replaced with a use of the pch file - // for foo.h. (Each flag can have at most one value, multiple /Yc flags - // just mean that the last one wins.) If /Yc and /Yu are both present - // and refer to the same file, /Yc wins. - // Note that OPT__SLASH_FI gets mapped to OPT_include. - // FIXME: The code here assumes that /Yc and /Yu refer to the same file. - // cl.exe seems to support both flags with different values, but that - // seems strange (which flag does /Fp now refer to?), so don't implement - // that until someone needs it. - int PchIndex = YcIndex != -1 ? YcIndex : YuIndex; - if (PchIndex != -1) { - if (isa<PrecompileJobAction>(JA)) { - // When building the pch, skip all includes after the pch. - assert(YcIndex != -1 && PchIndex == YcIndex); - if (AI >= YcIndex) - continue; - } else { - // When using the pch, skip all includes prior to the pch. - if (AI < PchIndex) { - A->claim(); - continue; - } - if (AI == PchIndex) { - A->claim(); - CmdArgs.push_back("-include-pch"); - CmdArgs.push_back( - Args.MakeArgString(D.GetClPchPath(C, A->getValue()))); - continue; - } - } - } - } else if (A->getOption().matches(options::OPT_include)) { + if (A->getOption().matches(options::OPT_include)) { // Handling of gcc-style gch precompiled headers. bool IsFirstImplicitInclude = !RenderedImplicitInclude; RenderedImplicitInclude = true; diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index c4863d6c03d..5727aae5f14 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -853,36 +853,7 @@ bool CompilerInstance::InitializeSourceManager( // Figure out where to get and map in the main file. if (InputFile != "-") { - const FileEntry *File; - if (Opts.FindPchSource.empty()) { - File = FileMgr.getFile(InputFile, /*OpenFile=*/true); - } else { - // When building a pch file in clang-cl mode, the .h file is built as if - // it was included by a cc file. Since the driver doesn't know about - // all include search directories, the frontend must search the input - // file through HeaderSearch here, as if it had been included by the - // cc file at Opts.FindPchSource. - const FileEntry *FindFile = FileMgr.getFile(Opts.FindPchSource); - if (!FindFile) { - Diags.Report(diag::err_fe_error_reading) << Opts.FindPchSource; - return false; - } - const DirectoryLookup *UnusedCurDir; - SmallVector<std::pair<const FileEntry *, const DirectoryEntry *>, 16> - Includers; - Includers.push_back(std::make_pair(FindFile, FindFile->getDir())); - File = HS->LookupFile(InputFile, SourceLocation(), /*isAngled=*/false, - /*FromDir=*/nullptr, - /*CurDir=*/UnusedCurDir, Includers, - /*SearchPath=*/nullptr, - /*RelativePath=*/nullptr, - /*RequestingModule=*/nullptr, - /*SuggestedModule=*/nullptr, /*IsMapped=*/nullptr, - /*SkipCache=*/true); - // Also add the header to /showIncludes output. - if (File) - DepOpts.ShowIncludesPretendHeader = File->getName(); - } + const FileEntry *File = FileMgr.getFile(InputFile, /*OpenFile=*/true); if (!File) { Diags.Report(diag::err_fe_error_reading) << InputFile; return false; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 3335ccb4fce..f57f23a0d4c 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1546,7 +1546,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, = Args.getLastArgValue(OPT_foverride_record_layout_EQ); Opts.AuxTriple = llvm::Triple::normalize(Args.getLastArgValue(OPT_aux_triple)); - Opts.FindPchSource = Args.getLastArgValue(OPT_find_pch_source_EQ); Opts.StatsFile = Args.getLastArgValue(OPT_stats_file); if (const Arg *A = Args.getLastArg(OPT_arcmt_check, @@ -2828,6 +2827,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, frontend::ActionKind Action) { Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch); Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth); + Opts.PCHThroughHeader = Args.getLastArgValue(OPT_pch_through_header_EQ); if (const Arg *A = Args.getLastArg(OPT_token_cache)) Opts.TokenCache = A->getValue(); else diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 949dbf17563..4ea0f485d31 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -887,6 +887,22 @@ 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, + SourceLocation HashLoc) { + if (const IdentifierInfo *II = Result.getIdentifierInfo()) { + if (II->getPPKeywordID() == tok::pp_include) + return HandleIncludeDirective(HashLoc, Result); + if (II->getPPKeywordID() == tok::pp_define) + return HandleDefineDirective(Result, + /*ImmediatelyAfterHeaderGuard=*/false); + } + DiscardUntilEndOfDirective(); +} + /// HandleDirective - This callback is invoked when the lexer sees a # token /// at the start of a line. This consumes the directive, modifies the /// lexer/preprocessor state, and advances the lexer(s) so that the next token @@ -948,6 +964,9 @@ 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()); + switch (Result.getKind()) { case tok::eod: return; // null directive. @@ -1862,6 +1881,12 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, } } + if (usingPCHWithThroughHeader() && SkippingUntilPCHThroughHeader) { + if (isPCHThroughHeader(File)) + SkippingUntilPCHThroughHeader = false; + return; + } + // Should we enter the source file? Set to false if either the source file is // known to have no effect beyond its effect on module visibility -- that is, // if it's got an include guard that is already defined or is a modular header @@ -2587,7 +2612,15 @@ void Preprocessor::HandleDefineDirective( } } - + // When skipping just warn about macros that do not match. + if (SkippingUntilPCHThroughHeader) { + const MacroInfo *OtherMI = getMacroInfo(MacroNameTok.getIdentifierInfo()); + if (!OtherMI || !MI->isIdenticalTo(*OtherMI, *this, + /*Syntactic=*/LangOpts.MicrosoftExt)) + Diag(MI->getDefinitionLoc(), diag::warn_pp_macro_def_mismatch_with_pch) + << MacroNameTok.getIdentifierInfo(); + return; + } // Finally, if this identifier already had a macro defined for it, verify that // the macro bodies are identical, and issue diagnostics if they are not. diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp index c7e0d2c7c28..352814d715f 100644 --- a/clang/lib/Lex/PPLexerChange.cpp +++ b/clang/lib/Lex/PPLexerChange.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/HeaderSearch.h" @@ -425,6 +426,8 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { PragmaAssumeNonNullLoc = SourceLocation(); } + bool LeavingPCHThroughHeader = false; + // If this is a #include'd file, pop it off the include stack and continue // lexing the #includer file. if (!IncludeMacroStack.empty()) { @@ -481,6 +484,12 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { Result.setAnnotationValue(M); } + bool FoundPCHThroughHeader = false; + if (CurPPLexer && creatingPCHWithThroughHeader() && + isPCHThroughHeader( + SourceMgr.getFileEntryForID(CurPPLexer->getFileID()))) + FoundPCHThroughHeader = true; + // We're done with the #included file. RemoveTopOfLexerStack(); @@ -500,8 +509,16 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { if (ExitedFromPredefinesFile) replayPreambleConditionalStack(); - // Client should lex another token unless we generated an EOM. - return LeavingSubmodule; + if (!isEndOfMacro && CurPPLexer && FoundPCHThroughHeader && + (isInPrimaryFile() || + CurPPLexer->getFileID() == getPredefinesFileID())) { + // Leaving the through header. Continue directly to end of main file + // processing. + LeavingPCHThroughHeader = true; + } else { + // Client should lex another token unless we generated an EOM. + return LeavingSubmodule; + } } // If this is the end of the main file, form an EOF token. @@ -522,6 +539,12 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { Result.setLocation(Result.getLocation().getLocWithOffset(-1)); } + if (creatingPCHWithThroughHeader() && !LeavingPCHThroughHeader) { + // Reached the end of the compilation without finding the through header. + Diag(CurLexer->getFileLoc(), diag::err_pp_through_header_not_seen) + << PPOpts->PCHThroughHeader << 0; + } + if (!isIncrementalProcessingEnabled()) // We're done with lexing. CurLexer.reset(); diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 358103d43d3..0217a2e60ed 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -149,6 +149,11 @@ Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts, Ident_AbnormalTermination = nullptr; } + // If using a PCH with a through header, start skipping tokens. + if (!this->PPOpts->PCHThroughHeader.empty() && + !this->PPOpts->ImplicitPCHInclude.empty()) + SkippingUntilPCHThroughHeader = true; + if (this->PPOpts->GeneratePreamble) PreambleConditionalStack.startRecording(); } @@ -551,6 +556,72 @@ void Preprocessor::EnterMainSourceFile() { // Start parsing the predefines. EnterSourceFile(FID, nullptr, SourceLocation()); + + if (!PPOpts->PCHThroughHeader.empty()) { + // Lookup and save the FileID for the through header. If it isn't found + // in the search path, it's a fatal error. + const DirectoryLookup *CurDir; + const FileEntry *File = LookupFile( + SourceLocation(), PPOpts->PCHThroughHeader, + /*isAngled=*/false, /*FromDir=*/nullptr, /*FromFile=*/nullptr, CurDir, + /*SearchPath=*/nullptr, /*RelativePath=*/nullptr, + /*SuggestedModule=*/nullptr, /*IsMapped=*/nullptr); + if (!File) { + Diag(SourceLocation(), diag::err_pp_through_header_not_found) + << PPOpts->PCHThroughHeader; + return; + } + setPCHThroughHeaderFileID( + SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User)); + } + + // Skip tokens from the Predefines and if needed the main file. + if (usingPCHWithThroughHeader() && SkippingUntilPCHThroughHeader) + SkipTokensUntilPCHThroughHeader(); +} + +void Preprocessor::setPCHThroughHeaderFileID(FileID FID) { + assert(PCHThroughHeaderFileID.isInvalid() && + "PCHThroughHeaderFileID already set!"); + PCHThroughHeaderFileID = FID; +} + +bool Preprocessor::isPCHThroughHeader(const FileEntry *FE) { + assert(PCHThroughHeaderFileID.isValid() && + "Invalid PCH through header FileID"); + return FE == SourceMgr.getFileEntryForID(PCHThroughHeaderFileID); +} + +bool Preprocessor::creatingPCHWithThroughHeader() { + return TUKind == TU_Prefix && !PPOpts->PCHThroughHeader.empty() && + PCHThroughHeaderFileID.isValid(); +} + +bool Preprocessor::usingPCHWithThroughHeader() { + return TUKind != TU_Prefix && !PPOpts->PCHThroughHeader.empty() && + 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 ReachedMainFileEOF = false; + Token Tok; + while (true) { + bool InPredefines = (CurLexer->getFileID() == getPredefinesFileID()); + CurLexer->Lex(Tok); + if (Tok.is(tok::eof) && !InPredefines) { + ReachedMainFileEOF = true; + break; + } + if (!SkippingUntilPCHThroughHeader) + break; + } + if (ReachedMainFileEOF) + Diag(SourceLocation(), diag::err_pp_through_header_not_seen) + << PPOpts->PCHThroughHeader << 1; } void Preprocessor::replayPreambleConditionalStack() { diff --git a/clang/lib/Parse/ParseAST.cpp b/clang/lib/Parse/ParseAST.cpp index 354b3800791..696506099e5 100644 --- a/clang/lib/Parse/ParseAST.cpp +++ b/clang/lib/Parse/ParseAST.cpp @@ -141,6 +141,12 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { CleanupParser(ParseOP.get()); S.getPreprocessor().EnterMainSourceFile(); + if (!S.getPreprocessor().getCurrentLexer()) { + // If a PCH through header is specified that does not have an include in + // the source, there won't be any tokens or a Lexer. + return; + } + P.Initialize(); Parser::DeclGroupPtrTy ADecl; diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index f56afeb8923..84286ca3808 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -704,6 +704,17 @@ static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts, // Compute the #include and #include_macros lines we need. for (unsigned I = 0, N = ExistingPPOpts.Includes.size(); I != N; ++I) { StringRef File = ExistingPPOpts.Includes[I]; + + if (!ExistingPPOpts.ImplicitPCHInclude.empty() && + !ExistingPPOpts.PCHThroughHeader.empty()) { + // In case the through header is an include, we must add all the includes + // to the predefines so the start point can be determined. + SuggestedPredefines += "#include \""; + SuggestedPredefines += File; + SuggestedPredefines += "\"\n"; + continue; + } + if (File == ExistingPPOpts.ImplicitPCHInclude) continue; |