diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Frontend')
6 files changed, 235 insertions, 84 deletions
diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp index d3ebf48315e2..96854b8fbc1a 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp @@ -766,6 +766,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.SanitizeCoverageTracePC = Args.hasArg(OPT_fsanitize_coverage_trace_pc); Opts.SanitizeCoverageTracePCGuard = Args.hasArg(OPT_fsanitize_coverage_trace_pc_guard); + Opts.SanitizeCoverageNoPrune = Args.hasArg(OPT_fsanitize_coverage_no_prune); Opts.SanitizeMemoryTrackOrigins = getLastArgIntValue(Args, OPT_fsanitize_memory_track_origins_EQ, 0, Diags); Opts.SanitizeMemoryUseAfterDtor = diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp index d26b6937b851..1fbb2b054bad 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp @@ -136,6 +136,12 @@ void FrontendAction::setCurrentInput(const FrontendInputFile &CurrentInput, CurrentASTUnit = std::move(AST); } +Module *FrontendAction::getCurrentModule() const { + CompilerInstance &CI = getCompilerInstance(); + return CI.getPreprocessor().getHeaderSearchInfo().lookupModule( + CI.getLangOpts().CurrentModule, /*AllowSearch*/false); +} + std::unique_ptr<ASTConsumer> FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI, StringRef InFile) { @@ -188,16 +194,25 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI, return llvm::make_unique<MultiplexConsumer>(std::move(Consumers)); } -// For preprocessed files, if the first line is the linemarker and specifies -// the original source file name, use that name as the input file name. -static bool ReadOriginalFileName(CompilerInstance &CI, std::string &InputFile) -{ - bool Invalid = false; +/// For preprocessed files, if the first line is the linemarker and specifies +/// the original source file name, use that name as the input file name. +/// Returns the location of the first token after the line marker directive. +/// +/// \param CI The compiler instance. +/// \param InputFile Populated with the filename from the line marker. +/// \param AddLineNote If \c true, add a line note corresponding to this line +/// directive. Only use this if the directive will not actually be +/// visited by the preprocessor. +static SourceLocation ReadOriginalFileName(CompilerInstance &CI, + std::string &InputFile, + bool AddLineNote = false) { auto &SourceMgr = CI.getSourceManager(); auto MainFileID = SourceMgr.getMainFileID(); + + bool Invalid = false; const auto *MainFileBuf = SourceMgr.getBuffer(MainFileID, &Invalid); if (Invalid) - return false; + return SourceLocation(); std::unique_ptr<Lexer> RawLexer( new Lexer(MainFileID, MainFileBuf, SourceMgr, CI.getLangOpts())); @@ -209,19 +224,37 @@ static bool ReadOriginalFileName(CompilerInstance &CI, std::string &InputFile) // we use FILENAME as the input file name. Token T; if (RawLexer->LexFromRawLexer(T) || T.getKind() != tok::hash) - return false; + return SourceLocation(); if (RawLexer->LexFromRawLexer(T) || T.isAtStartOfLine() || T.getKind() != tok::numeric_constant) - return false; + return SourceLocation(); + + unsigned LineNo; + SourceLocation LineNoLoc = T.getLocation(); + if (AddLineNote) { + llvm::SmallString<16> Buffer; + if (Lexer::getSpelling(LineNoLoc, Buffer, SourceMgr, CI.getLangOpts()) + .getAsInteger(10, LineNo)) + return SourceLocation(); + } + RawLexer->LexFromRawLexer(T); if (T.isAtStartOfLine() || T.getKind() != tok::string_literal) - return false; + return SourceLocation(); StringLiteralParser Literal(T, CI.getPreprocessor()); if (Literal.hadError) - return false; + return SourceLocation(); + RawLexer->LexFromRawLexer(T); + if (T.isNot(tok::eof) && !T.isAtStartOfLine()) + return SourceLocation(); InputFile = Literal.GetString().str(); - return true; + + if (AddLineNote) + CI.getSourceManager().AddLineNote( + LineNoLoc, LineNo, SourceMgr.getLineTableFilenameID(InputFile)); + + return T.getLocation(); } static SmallVectorImpl<char> & @@ -339,42 +372,44 @@ collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr, return std::error_code(); } -/// Parse a module map and compute the corresponding real input buffer that -/// should be used to build the module described by that module map and the -/// current module name. -static std::unique_ptr<llvm::MemoryBuffer> -getInputBufferForModuleMap(CompilerInstance &CI, StringRef Filename, - bool IsSystem) { - // Find the module map file. - const FileEntry *ModuleMap = - CI.getFileManager().getFile(Filename, /*openFile*/true); - if (!ModuleMap) { - CI.getDiagnostics().Report(diag::err_module_map_not_found) - << Filename; - return nullptr; - } +static bool +loadModuleMapForModuleBuild(CompilerInstance &CI, StringRef Filename, + bool IsSystem, bool IsPreprocessed, + unsigned &Offset) { + auto &SrcMgr = CI.getSourceManager(); + HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); - // Find the module map file from which it was generated, if different. - const FileEntry *OriginalModuleMap = ModuleMap; - StringRef OriginalModuleMapName = CI.getFrontendOpts().OriginalModuleMap; - if (!OriginalModuleMapName.empty()) { - OriginalModuleMap = CI.getFileManager().getFile(OriginalModuleMapName, - /*openFile*/ true); - if (!OriginalModuleMap) { - CI.getDiagnostics().Report(diag::err_module_map_not_found) - << OriginalModuleMapName; - return nullptr; - } + // Map the current input to a file. + FileID ModuleMapID = SrcMgr.getMainFileID(); + const FileEntry *ModuleMap = SrcMgr.getFileEntryForID(ModuleMapID); + + // If the module map is preprocessed, handle the initial line marker; + // line directives are not part of the module map syntax in general. + Offset = 0; + if (IsPreprocessed) { + std::string PresumedModuleMapFile; + SourceLocation EndOfLineMarker = + ReadOriginalFileName(CI, PresumedModuleMapFile, /*AddLineNote*/true); + if (EndOfLineMarker.isValid()) + Offset = CI.getSourceManager().getDecomposedLoc(EndOfLineMarker).second; + // FIXME: Use PresumedModuleMapFile as the MODULE_MAP_FILE in the PCM. } - - // Parse the module map file. - HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); - if (HS.loadModuleMapFile(ModuleMap, IsSystem)) - return nullptr; - + + // Load the module map file. + if (HS.loadModuleMapFile(ModuleMap, IsSystem, ModuleMapID, &Offset)) + return true; + + if (SrcMgr.getBuffer(ModuleMapID)->getBufferSize() == Offset) + Offset = 0; + + return false; +} + +static Module *prepareToBuildModule(CompilerInstance &CI, + StringRef ModuleMapFilename) { if (CI.getLangOpts().CurrentModule.empty()) { CI.getDiagnostics().Report(diag::err_missing_module_name); - + // FIXME: Eventually, we could consider asking whether there was just // a single module described in the module map, and use that as a // default. Then it would be fairly trivial to just "compile" a module @@ -382,21 +417,14 @@ getInputBufferForModuleMap(CompilerInstance &CI, StringRef Filename, return nullptr; } - // If we're being run from the command-line, the module build stack will not - // have been filled in yet, so complete it now in order to allow us to detect - // module cycles. - SourceManager &SourceMgr = CI.getSourceManager(); - if (SourceMgr.getModuleBuildStack().empty()) - SourceMgr.pushModuleBuildStack(CI.getLangOpts().CurrentModule, - FullSourceLoc(SourceLocation(), SourceMgr)); - // Dig out the module definition. + HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); Module *M = HS.lookupModule(CI.getLangOpts().CurrentModule, /*AllowSearch=*/false); if (!M) { CI.getDiagnostics().Report(diag::err_missing_module) - << CI.getLangOpts().CurrentModule << Filename; - + << CI.getLangOpts().CurrentModule << ModuleMapFilename; + return nullptr; } @@ -417,11 +445,45 @@ getInputBufferForModuleMap(CompilerInstance &CI, StringRef Filename, return nullptr; } - if (OriginalModuleMap != ModuleMap) { - M->IsInferred = true; - HS.getModuleMap().setInferredModuleAllowedBy(M, OriginalModuleMap); + // Inform the preprocessor that includes from within the input buffer should + // be resolved relative to the build directory of the module map file. + CI.getPreprocessor().setMainFileDir(M->Directory); + + // If the module was inferred from a different module map (via an expanded + // umbrella module definition), track that fact. + // FIXME: It would be preferable to fill this in as part of processing + // the module map, rather than adding it after the fact. + StringRef OriginalModuleMapName = CI.getFrontendOpts().OriginalModuleMap; + if (!OriginalModuleMapName.empty()) { + auto *OriginalModuleMap = + CI.getFileManager().getFile(OriginalModuleMapName, + /*openFile*/ true); + if (!OriginalModuleMap) { + CI.getDiagnostics().Report(diag::err_module_map_not_found) + << OriginalModuleMapName; + return nullptr; + } + if (OriginalModuleMap != CI.getSourceManager().getFileEntryForID( + CI.getSourceManager().getMainFileID())) { + M->IsInferred = true; + CI.getPreprocessor().getHeaderSearchInfo().getModuleMap() + .setInferredModuleAllowedBy(M, OriginalModuleMap); + } } + // If we're being run from the command-line, the module build stack will not + // have been filled in yet, so complete it now in order to allow us to detect + // module cycles. + SourceManager &SourceMgr = CI.getSourceManager(); + if (SourceMgr.getModuleBuildStack().empty()) + SourceMgr.pushModuleBuildStack(CI.getLangOpts().CurrentModule, + FullSourceLoc(SourceLocation(), SourceMgr)); + return M; +} + +/// Compute the input buffer that should be used to build the specified module. +static std::unique_ptr<llvm::MemoryBuffer> +getInputBufferForModule(CompilerInstance &CI, Module *M) { FileManager &FileMgr = CI.getFileManager(); // Collect the set of #includes we need to build the module. @@ -441,10 +503,6 @@ getInputBufferForModuleMap(CompilerInstance &CI, StringRef Filename, return nullptr; } - // Inform the preprocessor that includes from within the input buffer should - // be resolved relative to the build directory of the module map file. - CI.getPreprocessor().setMainFileDir(M->Directory); - return llvm::MemoryBuffer::getMemBufferCopy( HeaderContents, Module::getModuleInputBufferName()); } @@ -457,7 +515,6 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, setCompilerInstance(&CI); StringRef InputFile = Input.getFile(); - FrontendInputFile FileToProcess = Input; bool HasBegunSourceFile = false; if (!BeginInvocation(CI)) goto failure; @@ -597,36 +654,45 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, &CI.getPreprocessor()); HasBegunSourceFile = true; + // Initialize the main file entry. + if (!CI.InitializeSourceManager(Input)) + goto failure; + // For module map files, we first parse the module map and synthesize a // "<module-includes>" buffer before more conventional processing. if (Input.getKind().getFormat() == InputKind::ModuleMap) { CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleMap); - auto Buffer = getInputBufferForModuleMap(CI, InputFile, Input.isSystem()); - if (!Buffer) + unsigned OffsetToContents; + if (loadModuleMapForModuleBuild(CI, Input.getFile(), Input.isSystem(), + Input.isPreprocessed(), OffsetToContents)) goto failure; - Module *CurrentModule = - CI.getPreprocessor().getHeaderSearchInfo().lookupModule( - CI.getLangOpts().CurrentModule, - /*AllowSearch=*/false); - assert(CurrentModule && "no module info for current module"); + auto *CurrentModule = prepareToBuildModule(CI, Input.getFile()); + if (!CurrentModule) + goto failure; + + if (OffsetToContents) + // If the module contents are in the same file, skip to them. + CI.getPreprocessor().setSkipMainFilePreamble(OffsetToContents, true); + else { + // Otherwise, convert the module description to a suitable input buffer. + auto Buffer = getInputBufferForModule(CI, CurrentModule); + if (!Buffer) + goto failure; - // The input that we end up processing is the generated buffer, not the - // module map file itself. - FileToProcess = FrontendInputFile( - Buffer.release(), Input.getKind().withFormat(InputKind::Source), - CurrentModule->IsSystem); + // Reinitialize the main file entry to refer to the new input. + if (!CI.InitializeSourceManager(FrontendInputFile( + Buffer.release(), Input.getKind().withFormat(InputKind::Source), + CurrentModule->IsSystem))) + goto failure; + } } // Initialize the action. if (!BeginSourceFileAction(CI, InputFile)) goto failure; - // Initialize the main file entry. - if (!CI.InitializeSourceManager(FileToProcess)) - goto failure; - // Create the AST context and consumer unless this is a preprocessor only // action. if (!usesPreprocessorOnly()) { @@ -636,13 +702,12 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // For preprocessed files, check if the first line specifies the original // source file name with a linemarker. - std::string OrigFile; + std::string PresumedInputFile = InputFile; if (Input.isPreprocessed()) - if (ReadOriginalFileName(CI, OrigFile)) - InputFile = OrigFile; + ReadOriginalFileName(CI, PresumedInputFile); std::unique_ptr<ASTConsumer> Consumer = - CreateWrappedASTConsumer(CI, InputFile); + CreateWrappedASTConsumer(CI, PresumedInputFile); if (!Consumer) goto failure; diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp index dd7c12f60f0e..baaf93b167bc 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp @@ -542,6 +542,18 @@ void PrintPreprocessedAction::ExecuteAction() { CI.createDefaultOutputFile(BinaryMode, getCurrentFile()); if (!OS) return; + // If we're preprocessing a module map, start by dumping the contents of the + // module itself before switching to the input buffer. + auto &Input = getCurrentInput(); + if (Input.getKind().getFormat() == InputKind::ModuleMap) { + if (Input.isFile()) + (*OS) << "# 1 \"" << Input.getFile() << "\"\n"; + // FIXME: Include additional information here so that we don't need the + // original source files to exist on disk. + getCurrentModule()->print(*OS); + (*OS) << "#pragma clang module contents\n"; + } + DoPrintPreprocessedInput(CI.getPreprocessor(), OS.get(), CI.getPreprocessorOutputOpts()); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp index ffedf3cac847..832eaf2926f0 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp @@ -174,6 +174,9 @@ public: void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD, const MacroDirective *Undef) override; + + void BeginModule(const Module *M); + void EndModule(const Module *M); }; } // end anonymous namespace @@ -372,6 +375,20 @@ void PrintPPOutputPPCallbacks::InclusionDirective(SourceLocation HashLoc, } } +/// Handle entering the scope of a module during a module compilation. +void PrintPPOutputPPCallbacks::BeginModule(const Module *M) { + startNewLineIfNeeded(); + OS << "#pragma clang module begin " << M->getFullModuleName(); + setEmittedDirectiveOnThisLine(); +} + +/// Handle leaving the scope of a module during a module compilation. +void PrintPPOutputPPCallbacks::EndModule(const Module *M) { + startNewLineIfNeeded(); + OS << "#pragma clang module end /*" << M->getFullModuleName() << "*/"; + setEmittedDirectiveOnThisLine(); +} + /// Ident - Handle #ident directives when read by the preprocessor. /// void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, StringRef S) { @@ -685,13 +702,27 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, // -traditional-cpp the lexer keeps /all/ whitespace, including comments. SourceLocation StartLoc = Tok.getLocation(); Callbacks->MoveToLine(StartLoc.getLocWithOffset(Tok.getLength())); - } else if (Tok.is(tok::annot_module_include) || - Tok.is(tok::annot_module_begin) || - Tok.is(tok::annot_module_end)) { + } else if (Tok.is(tok::annot_module_include)) { // PrintPPOutputPPCallbacks::InclusionDirective handles producing // appropriate output here. Ignore this token entirely. PP.Lex(Tok); continue; + } else if (Tok.is(tok::annot_module_begin)) { + // FIXME: We retrieve this token after the FileChanged callback, and + // retrieve the module_end token before the FileChanged callback, so + // we render this within the file and render the module end outside the + // file, but this is backwards from the token locations: the module_begin + // token is at the include location (outside the file) and the module_end + // token is at the EOF location (within the file). + Callbacks->BeginModule( + reinterpret_cast<Module *>(Tok.getAnnotationValue())); + PP.Lex(Tok); + continue; + } else if (Tok.is(tok::annot_module_end)) { + Callbacks->EndModule( + reinterpret_cast<Module *>(Tok.getAnnotationValue())); + PP.Lex(Tok); + continue; } else if (IdentifierInfo *II = Tok.getIdentifierInfo()) { OS << II->getName(); } else if (Tok.isLiteral() && !Tok.needsCleaning() && diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp index 2e76e2e3151e..8c5eb161b5ab 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp @@ -196,6 +196,18 @@ void RewriteIncludesAction::ExecuteAction() { CI.createDefaultOutputFile(true, getCurrentFile()); if (!OS) return; + // If we're preprocessing a module map, start by dumping the contents of the + // module itself before switching to the input buffer. + auto &Input = getCurrentInput(); + if (Input.getKind().getFormat() == InputKind::ModuleMap) { + if (Input.isFile()) + (*OS) << "# 1 \"" << Input.getFile() << "\"\n"; + // FIXME: Include additional information here so that we don't need the + // original source files to exist on disk. + getCurrentModule()->print(*OS); + (*OS) << "#pragma clang module contents\n"; + } + RewriteIncludesInInput(CI.getPreprocessor(), OS.get(), CI.getPreprocessorOutputOpts()); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp index ee61f76d029d..d45cbc01df8c 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp @@ -46,6 +46,8 @@ class InclusionRewriter : public PPCallbacks { std::map<unsigned, IncludedFile> FileIncludes; /// Tracks where inclusions that import modules are found. std::map<unsigned, const Module *> ModuleIncludes; + /// Tracks where inclusions that enter modules (in a module build) are found. + std::map<unsigned, const Module *> ModuleEntryIncludes; /// Used transitively for building up the FileIncludes mapping over the /// various \c PPCallbacks callbacks. SourceLocation LastInclusionLocation; @@ -57,6 +59,11 @@ public: PredefinesBuffer = Buf; } void detectMainFileEOL(); + void handleModuleBegin(Token &Tok) { + assert(Tok.getKind() == tok::annot_module_begin); + ModuleEntryIncludes.insert({Tok.getLocation().getRawEncoding(), + (Module *)Tok.getAnnotationValue()}); + } private: void FileChanged(SourceLocation Loc, FileChangeReason Reason, SrcMgr::CharacteristicKind FileType, @@ -84,6 +91,7 @@ private: bool &FileExists); const IncludedFile *FindIncludeAtLocation(SourceLocation Loc) const; const Module *FindModuleAtLocation(SourceLocation Loc) const; + const Module *FindEnteredModule(SourceLocation Loc) const; StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken); }; @@ -211,6 +219,16 @@ InclusionRewriter::FindModuleAtLocation(SourceLocation Loc) const { return nullptr; } +/// Simple lookup for a SourceLocation (specifically one denoting the hash in +/// an inclusion directive) in the map of module entry information. +const Module * +InclusionRewriter::FindEnteredModule(SourceLocation Loc) const { + const auto I = ModuleEntryIncludes.find(Loc.getRawEncoding()); + if (I != ModuleEntryIncludes.end()) + return I->second; + return nullptr; +} + /// Detect the likely line ending style of \p FromFile by examining the first /// newline found within it. static StringRef DetectEOL(const MemoryBuffer &FromFile) { @@ -452,8 +470,18 @@ void InclusionRewriter::Process(FileID FileId, if (const Module *Mod = FindModuleAtLocation(Loc)) WriteImplicitModuleImport(Mod); else if (const IncludedFile *Inc = FindIncludeAtLocation(Loc)) { + const Module *Mod = FindEnteredModule(Loc); + if (Mod) + OS << "#pragma clang module begin " << Mod->getFullModuleName() + << "\n"; + // Include and recursively process the file. Process(Inc->Id, Inc->FileType); + + if (Mod) + OS << "#pragma clang module end /*" << Mod->getFullModuleName() + << "*/\n"; + // Add line marker to indicate we're returning from an included // file. LineInfoExtra = " 2"; @@ -590,6 +618,8 @@ void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, PP.SetMacroExpansionOnlyInDirectives(); do { PP.Lex(Tok); + if (Tok.is(tok::annot_module_begin)) + Rewrite->handleModuleBegin(Tok); } while (Tok.isNot(tok::eof)); Rewrite->setPredefinesBuffer(SM.getBuffer(PP.getPredefinesFileID())); Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User); |
