diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Frontend')
28 files changed, 2919 insertions, 1801 deletions
diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp index d8118cb..7dc475e 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp @@ -34,10 +34,11 @@ namespace { typedef RecursiveASTVisitor<ASTPrinter> base; public: - ASTPrinter(std::unique_ptr<raw_ostream> Out = nullptr, bool Dump = false, - StringRef FilterString = "", bool DumpLookups = false) - : Out(Out ? *Out : llvm::outs()), OwnedOut(std::move(Out)), Dump(Dump), - FilterString(FilterString), DumpLookups(DumpLookups) {} + enum Kind { DumpFull, Dump, Print, None }; + ASTPrinter(std::unique_ptr<raw_ostream> Out, Kind K, StringRef FilterString, + bool DumpLookups = false) + : Out(Out ? *Out : llvm::outs()), OwnedOut(std::move(Out)), + OutputKind(K), FilterString(FilterString), DumpLookups(DumpLookups) {} void HandleTranslationUnit(ASTContext &Context) override { TranslationUnitDecl *D = Context.getTranslationUnitDecl(); @@ -55,7 +56,7 @@ namespace { bool ShowColors = Out.has_colors(); if (ShowColors) Out.changeColor(raw_ostream::BLUE); - Out << ((Dump || DumpLookups) ? "Dumping " : "Printing ") << getName(D) + Out << (OutputKind != Print ? "Dumping " : "Printing ") << getName(D) << ":\n"; if (ShowColors) Out.resetColor(); @@ -80,22 +81,30 @@ namespace { if (DumpLookups) { if (DeclContext *DC = dyn_cast<DeclContext>(D)) { if (DC == DC->getPrimaryContext()) - DC->dumpLookups(Out, Dump); + DC->dumpLookups(Out, OutputKind != None, OutputKind == DumpFull); else Out << "Lookup map is in primary DeclContext " << DC->getPrimaryContext() << "\n"; } else Out << "Not a DeclContext\n"; - } else if (Dump) - D->dump(Out); - else + } else if (OutputKind == Print) D->print(Out, /*Indentation=*/0, /*PrintInstantiation=*/true); + else if (OutputKind != None) + D->dump(Out, OutputKind == DumpFull); } raw_ostream &Out; std::unique_ptr<raw_ostream> OwnedOut; - bool Dump; + + /// How to output individual declarations. + Kind OutputKind; + + /// Which declarations or DeclContexts to display. std::string FilterString; + + /// Whether the primary output is lookup results or declarations. Individual + /// results will be output with a format determined by OutputKind. This is + /// incompatible with OutputKind == Print. bool DumpLookups; }; @@ -125,16 +134,20 @@ namespace { std::unique_ptr<ASTConsumer> clang::CreateASTPrinter(std::unique_ptr<raw_ostream> Out, StringRef FilterString) { - return llvm::make_unique<ASTPrinter>(std::move(Out), /*Dump=*/false, + return llvm::make_unique<ASTPrinter>(std::move(Out), ASTPrinter::Print, FilterString); } std::unique_ptr<ASTConsumer> clang::CreateASTDumper(StringRef FilterString, bool DumpDecls, + bool Deserialize, bool DumpLookups) { - assert((DumpDecls || DumpLookups) && "nothing to dump"); - return llvm::make_unique<ASTPrinter>(nullptr, DumpDecls, FilterString, - DumpLookups); + assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump"); + return llvm::make_unique<ASTPrinter>(nullptr, + Deserialize ? ASTPrinter::DumpFull : + DumpDecls ? ASTPrinter::Dump : + ASTPrinter::None, + FilterString, DumpLookups); } std::unique_ptr<ASTConsumer> clang::CreateASTDeclNodeLister() { diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp index 51064da..354527d 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp @@ -21,14 +21,13 @@ ASTMergeAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { return AdaptedAction->CreateASTConsumer(CI, InFile); } -bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI, - StringRef Filename) { +bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI) { // FIXME: This is a hack. We need a better way to communicate the // AST file, compiler instance, and file name than member variables // of FrontendAction. AdaptedAction->setCurrentInput(getCurrentInput(), takeCurrentASTUnit()); AdaptedAction->setCompilerInstance(&CI); - return AdaptedAction->BeginSourceFileAction(CI, Filename); + return AdaptedAction->BeginSourceFileAction(CI); } void ASTMergeAction::ExecuteAction() { @@ -45,9 +44,9 @@ void ASTMergeAction::ExecuteAction() { new ForwardingDiagnosticConsumer( *CI.getDiagnostics().getClient()), /*ShouldOwnClient=*/true)); - std::unique_ptr<ASTUnit> Unit = - ASTUnit::LoadFromASTFile(ASTFiles[I], CI.getPCHContainerReader(), - Diags, CI.getFileSystemOpts(), false); + std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile( + ASTFiles[I], CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags, + CI.getFileSystemOpts(), false); if (!Unit) continue; diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp index d892996..1094e6d 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp @@ -18,6 +18,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeOrdering.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/MemoryBufferCache.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" #include "clang/Basic/VirtualFileSystem.h" @@ -78,106 +79,83 @@ namespace { } } }; - - struct OnDiskData { - /// \brief The file in which the precompiled preamble is stored. - std::string PreambleFile; - - /// \brief Temporary files that should be removed when the ASTUnit is - /// destroyed. - SmallVector<std::string, 4> TemporaryFiles; - - /// \brief Erase temporary files. - void CleanTemporaryFiles(); - - /// \brief Erase the preamble file. - void CleanPreambleFile(); - - /// \brief Erase temporary files and the preamble file. - void Cleanup(); - }; -} - -static llvm::sys::SmartMutex<false> &getOnDiskMutex() { - static llvm::sys::SmartMutex<false> M(/* recursive = */ true); - return M; -} - -static void cleanupOnDiskMapAtExit(); -typedef llvm::DenseMap<const ASTUnit *, - std::unique_ptr<OnDiskData>> OnDiskDataMap; -static OnDiskDataMap &getOnDiskDataMap() { - static OnDiskDataMap M; - static bool hasRegisteredAtExit = false; - if (!hasRegisteredAtExit) { - hasRegisteredAtExit = true; - atexit(cleanupOnDiskMapAtExit); + template <class T> + std::unique_ptr<T> valueOrNull(llvm::ErrorOr<std::unique_ptr<T>> Val) { + if (!Val) + return nullptr; + return std::move(*Val); } - return M; -} -static void cleanupOnDiskMapAtExit() { - // Use the mutex because there can be an alive thread destroying an ASTUnit. - llvm::MutexGuard Guard(getOnDiskMutex()); - for (const auto &I : getOnDiskDataMap()) { - // We don't worry about freeing the memory associated with OnDiskDataMap. - // All we care about is erasing stale files. - I.second->Cleanup(); + template <class T> + bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) { + if (!Val) + return false; + Output = std::move(*Val); + return true; } -} -static OnDiskData &getOnDiskData(const ASTUnit *AU) { - // We require the mutex since we are modifying the structure of the - // DenseMap. - llvm::MutexGuard Guard(getOnDiskMutex()); - OnDiskDataMap &M = getOnDiskDataMap(); - auto &D = M[AU]; - if (!D) - D = llvm::make_unique<OnDiskData>(); - return *D; -} - -static void erasePreambleFile(const ASTUnit *AU) { - getOnDiskData(AU).CleanPreambleFile(); -} +/// \brief Get a source buffer for \p MainFilePath, handling all file-to-file +/// and file-to-buffer remappings inside \p Invocation. +static std::unique_ptr<llvm::MemoryBuffer> +getBufferForFileHandlingRemapping(const CompilerInvocation &Invocation, + vfs::FileSystem *VFS, + StringRef FilePath) { + const auto &PreprocessorOpts = Invocation.getPreprocessorOpts(); -static void removeOnDiskEntry(const ASTUnit *AU) { - // We require the mutex since we are modifying the structure of the - // DenseMap. - llvm::MutexGuard Guard(getOnDiskMutex()); - OnDiskDataMap &M = getOnDiskDataMap(); - OnDiskDataMap::iterator I = M.find(AU); - if (I != M.end()) { - I->second->Cleanup(); - M.erase(I); - } -} - -static void setPreambleFile(const ASTUnit *AU, StringRef preambleFile) { - getOnDiskData(AU).PreambleFile = preambleFile; -} + // Try to determine if the main file has been remapped, either from the + // command line (to another file) or directly through the compiler + // invocation (to a memory buffer). + llvm::MemoryBuffer *Buffer = nullptr; + std::unique_ptr<llvm::MemoryBuffer> BufferOwner; + auto FileStatus = VFS->status(FilePath); + if (FileStatus) { + llvm::sys::fs::UniqueID MainFileID = FileStatus->getUniqueID(); -static const std::string &getPreambleFile(const ASTUnit *AU) { - return getOnDiskData(AU).PreambleFile; -} + // Check whether there is a file-file remapping of the main file + for (const auto &RF : PreprocessorOpts.RemappedFiles) { + std::string MPath(RF.first); + auto MPathStatus = VFS->status(MPath); + if (MPathStatus) { + llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID(); + if (MainFileID == MID) { + // We found a remapping. Try to load the resulting, remapped source. + BufferOwner = valueOrNull(VFS->getBufferForFile(RF.second)); + if (!BufferOwner) + return nullptr; + } + } + } -void OnDiskData::CleanTemporaryFiles() { - for (StringRef File : TemporaryFiles) - llvm::sys::fs::remove(File); - TemporaryFiles.clear(); -} + // Check whether there is a file-buffer remapping. It supercedes the + // file-file remapping. + for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) { + std::string MPath(RB.first); + auto MPathStatus = VFS->status(MPath); + if (MPathStatus) { + llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID(); + if (MainFileID == MID) { + // We found a remapping. + BufferOwner.reset(); + Buffer = const_cast<llvm::MemoryBuffer *>(RB.second); + } + } + } + } -void OnDiskData::CleanPreambleFile() { - if (!PreambleFile.empty()) { - llvm::sys::fs::remove(PreambleFile); - PreambleFile.clear(); + // If the main source file was not remapped, load it now. + if (!Buffer && !BufferOwner) { + BufferOwner = valueOrNull(VFS->getBufferForFile(FilePath)); + if (!BufferOwner) + return nullptr; } -} -void OnDiskData::Cleanup() { - CleanTemporaryFiles(); - CleanPreambleFile(); + if (BufferOwner) + return BufferOwner; + if (!Buffer) + return nullptr; + return llvm::MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(), FilePath); +} } struct ASTUnit::ASTWriterData { @@ -185,21 +163,14 @@ struct ASTUnit::ASTWriterData { llvm::BitstreamWriter Stream; ASTWriter Writer; - ASTWriterData() : Stream(Buffer), Writer(Stream, { }) { } + ASTWriterData(MemoryBufferCache &PCMCache) + : Stream(Buffer), Writer(Stream, Buffer, PCMCache, {}) {} }; void ASTUnit::clearFileLevelDecls() { llvm::DeleteContainerSeconds(FileDecls); } -void ASTUnit::CleanTemporaryFiles() { - getOnDiskData(this).CleanTemporaryFiles(); -} - -void ASTUnit::addTemporaryFile(StringRef TempFile) { - getOnDiskData(this).TemporaryFiles.push_back(TempFile); -} - /// \brief After failing to build a precompiled preamble (due to /// errors in the source that occurs in the preamble), the number of /// reparses during which we'll skip even trying to precompile the @@ -238,9 +209,6 @@ ASTUnit::~ASTUnit() { clearFileLevelDecls(); - // Clean up the temporary files and the preamble file. - removeOnDiskEntry(this); - // Free the buffers associated with remapped files. We are required to // perform this operation here because we explicitly request that the // compiler instance *not* free these buffers for each invocation of the @@ -490,7 +458,9 @@ namespace { /// a Preprocessor. class ASTInfoCollector : public ASTReaderListener { Preprocessor &PP; - ASTContext &Context; + ASTContext *Context; + HeaderSearchOptions &HSOpts; + PreprocessorOptions &PPOpts; LangOptions &LangOpt; std::shared_ptr<TargetOptions> &TargetOpts; IntrusiveRefCntPtr<TargetInfo> &Target; @@ -498,11 +468,14 @@ class ASTInfoCollector : public ASTReaderListener { bool InitializedLanguage; public: - ASTInfoCollector(Preprocessor &PP, ASTContext &Context, LangOptions &LangOpt, + ASTInfoCollector(Preprocessor &PP, ASTContext *Context, + HeaderSearchOptions &HSOpts, PreprocessorOptions &PPOpts, + LangOptions &LangOpt, std::shared_ptr<TargetOptions> &TargetOpts, IntrusiveRefCntPtr<TargetInfo> &Target, unsigned &Counter) - : PP(PP), Context(Context), LangOpt(LangOpt), TargetOpts(TargetOpts), - Target(Target), Counter(Counter), InitializedLanguage(false) {} + : PP(PP), Context(Context), HSOpts(HSOpts), PPOpts(PPOpts), + LangOpt(LangOpt), TargetOpts(TargetOpts), Target(Target), + Counter(Counter), InitializedLanguage(false) {} bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, bool AllowCompatibleDifferences) override { @@ -516,6 +489,20 @@ public: return false; } + virtual bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, + StringRef SpecificModuleCachePath, + bool Complain) override { + this->HSOpts = HSOpts; + return false; + } + + virtual bool + ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool Complain, + std::string &SuggestedPredefines) override { + this->PPOpts = PPOpts; + return false; + } + bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain, bool AllowCompatibleDifferences) override { // If we've already initialized the target, don't do it again. @@ -549,28 +536,39 @@ private: // Initialize the preprocessor. PP.Initialize(*Target); + if (!Context) + return; + // Initialize the ASTContext - Context.InitBuiltinTypes(*Target); + Context->InitBuiltinTypes(*Target); // We didn't have access to the comment options when the ASTContext was // constructed, so register them now. - Context.getCommentCommandTraits().registerCommentOptions( + Context->getCommentCommandTraits().registerCommentOptions( LangOpt.CommentOpts); } }; /// \brief Diagnostic consumer that saves each diagnostic it is given. class StoredDiagnosticConsumer : public DiagnosticConsumer { - SmallVectorImpl<StoredDiagnostic> &StoredDiags; + SmallVectorImpl<StoredDiagnostic> *StoredDiags; + SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags; + const LangOptions *LangOpts; SourceManager *SourceMgr; public: - explicit StoredDiagnosticConsumer( - SmallVectorImpl<StoredDiagnostic> &StoredDiags) - : StoredDiags(StoredDiags), SourceMgr(nullptr) {} + StoredDiagnosticConsumer( + SmallVectorImpl<StoredDiagnostic> *StoredDiags, + SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags) + : StoredDiags(StoredDiags), StandaloneDiags(StandaloneDiags), + LangOpts(nullptr), SourceMgr(nullptr) { + assert((StoredDiags || StandaloneDiags) && + "No output collections were passed to StoredDiagnosticConsumer."); + } void BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP = nullptr) override { + this->LangOpts = &LangOpts; if (PP) SourceMgr = &PP->getSourceManager(); } @@ -589,8 +587,9 @@ class CaptureDroppedDiagnostics { public: CaptureDroppedDiagnostics(bool RequestCapture, DiagnosticsEngine &Diags, - SmallVectorImpl<StoredDiagnostic> &StoredDiags) - : Diags(Diags), Client(StoredDiags), PreviousClient(nullptr) + SmallVectorImpl<StoredDiagnostic> *StoredDiags, + SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags) + : Diags(Diags), Client(StoredDiags, StandaloneDiags), PreviousClient(nullptr) { if (RequestCapture || Diags.getClient() == nullptr) { OwningPreviousClient = Diags.takeClient(); @@ -607,16 +606,39 @@ public: } // anonymous namespace +static ASTUnit::StandaloneDiagnostic +makeStandaloneDiagnostic(const LangOptions &LangOpts, + const StoredDiagnostic &InDiag); + void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level, - const Diagnostic &Info) { + const Diagnostic &Info) { // Default implementation (Warnings/errors count). DiagnosticConsumer::HandleDiagnostic(Level, Info); // Only record the diagnostic if it's part of the source manager we know // about. This effectively drops diagnostics from modules we're building. // FIXME: In the long run, ee don't want to drop source managers from modules. - if (!Info.hasSourceManager() || &Info.getSourceManager() == SourceMgr) - StoredDiags.emplace_back(Level, Info); + if (!Info.hasSourceManager() || &Info.getSourceManager() == SourceMgr) { + StoredDiagnostic *ResultDiag = nullptr; + if (StoredDiags) { + StoredDiags->emplace_back(Level, Info); + ResultDiag = &StoredDiags->back(); + } + + if (StandaloneDiags) { + llvm::Optional<StoredDiagnostic> StoredDiag = llvm::None; + if (!ResultDiag) { + StoredDiag.emplace(Level, Info); + ResultDiag = StoredDiag.getPointer(); + } + StandaloneDiags->push_back( + makeStandaloneDiagnostic(*LangOpts, *ResultDiag)); + } + } +} + +IntrusiveRefCntPtr<ASTReader> ASTUnit::getASTReader() const { + return Reader; } ASTMutationListener *ASTUnit::getASTMutationListener() { @@ -647,12 +669,12 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> Diags, ASTUnit &AST, bool CaptureDiagnostics) { assert(Diags.get() && "no DiagnosticsEngine was provided"); if (CaptureDiagnostics) - Diags->setClient(new StoredDiagnosticConsumer(AST.StoredDiagnostics)); + Diags->setClient(new StoredDiagnosticConsumer(&AST.StoredDiagnostics, nullptr)); } std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( const std::string &Filename, const PCHContainerReader &PCHContainerRdr, - IntrusiveRefCntPtr<DiagnosticsEngine> Diags, + WhatToLoad ToLoad, IntrusiveRefCntPtr<DiagnosticsEngine> Diags, const FileSystemOptions &FileSystemOpts, bool UseDebugInfo, bool OnlyLocalDecls, ArrayRef<RemappedFile> RemappedFiles, bool CaptureDiagnostics, bool AllowPCHWithCompilerErrors, @@ -668,6 +690,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( ConfigureDiags(Diags, *AST, CaptureDiagnostics); + AST->LangOpts = std::make_shared<LangOptions>(); AST->OnlyLocalDecls = OnlyLocalDecls; AST->CaptureDiagnostics = CaptureDiagnostics; AST->Diagnostics = Diags; @@ -677,18 +700,18 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( AST->SourceMgr = new SourceManager(AST->getDiagnostics(), AST->getFileManager(), UserFilesAreVolatile); + AST->PCMCache = new MemoryBufferCache; AST->HSOpts = std::make_shared<HeaderSearchOptions>(); AST->HSOpts->ModuleFormat = PCHContainerRdr.getFormat(); AST->HeaderInfo.reset(new HeaderSearch(AST->HSOpts, AST->getSourceManager(), AST->getDiagnostics(), - AST->ASTFileLangOpts, + AST->getLangOpts(), /*Target=*/nullptr)); - - auto PPOpts = std::make_shared<PreprocessorOptions>(); + AST->PPOpts = std::make_shared<PreprocessorOptions>(); for (const auto &RemappedFile : RemappedFiles) - PPOpts->addRemappedFile(RemappedFile.first, RemappedFile.second); + AST->PPOpts->addRemappedFile(RemappedFile.first, RemappedFile.second); // Gather Info for preprocessor construction later on. @@ -696,35 +719,36 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( unsigned Counter; AST->PP = std::make_shared<Preprocessor>( - std::move(PPOpts), AST->getDiagnostics(), AST->ASTFileLangOpts, - AST->getSourceManager(), HeaderInfo, *AST, + AST->PPOpts, AST->getDiagnostics(), *AST->LangOpts, + AST->getSourceManager(), *AST->PCMCache, HeaderInfo, AST->ModuleLoader, /*IILookup=*/nullptr, /*OwnsHeaderSearch=*/false); Preprocessor &PP = *AST->PP; - AST->Ctx = new ASTContext(AST->ASTFileLangOpts, AST->getSourceManager(), - PP.getIdentifierTable(), PP.getSelectorTable(), - PP.getBuiltinInfo()); - ASTContext &Context = *AST->Ctx; + if (ToLoad >= LoadASTOnly) + AST->Ctx = new ASTContext(*AST->LangOpts, AST->getSourceManager(), + PP.getIdentifierTable(), PP.getSelectorTable(), + PP.getBuiltinInfo()); bool disableValid = false; if (::getenv("LIBCLANG_DISABLE_PCH_VALIDATION")) disableValid = true; - AST->Reader = new ASTReader(PP, Context, PCHContainerRdr, { }, + AST->Reader = new ASTReader(PP, AST->Ctx.get(), PCHContainerRdr, { }, /*isysroot=*/"", /*DisableValidation=*/disableValid, AllowPCHWithCompilerErrors); AST->Reader->setListener(llvm::make_unique<ASTInfoCollector>( - *AST->PP, Context, AST->ASTFileLangOpts, AST->TargetOpts, AST->Target, - Counter)); + *AST->PP, AST->Ctx.get(), *AST->HSOpts, *AST->PPOpts, *AST->LangOpts, + AST->TargetOpts, AST->Target, Counter)); // Attach the AST reader to the AST context as an external AST // source, so that declarations will be deserialized from the // AST file as needed. // We need the external source to be set up before we read the AST, because // eagerly-deserialized declarations may use it. - Context.setExternalSource(AST->Reader); + if (AST->Ctx) + AST->Ctx->setExternalSource(AST->Reader); switch (AST->Reader->ReadAST(Filename, serialization::MK_MainFile, SourceLocation(), ASTReader::ARR_None)) { @@ -746,21 +770,29 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( PP.setCounterValue(Counter); // Create an AST consumer, even though it isn't used. - AST->Consumer.reset(new ASTConsumer); - + if (ToLoad >= LoadASTOnly) + AST->Consumer.reset(new ASTConsumer); + // Create a semantic analysis object and tell the AST reader about it. - AST->TheSema.reset(new Sema(PP, Context, *AST->Consumer)); - AST->TheSema->Initialize(); - AST->Reader->InitializeSema(*AST->TheSema); + if (ToLoad >= LoadEverything) { + AST->TheSema.reset(new Sema(PP, *AST->Ctx, *AST->Consumer)); + AST->TheSema->Initialize(); + AST->Reader->InitializeSema(*AST->TheSema); + } // Tell the diagnostic client that we have started a source file. - AST->getDiagnostics().getClient()->BeginSourceFile(Context.getLangOpts(),&PP); + AST->getDiagnostics().getClient()->BeginSourceFile(PP.getLangOpts(), &PP); return AST; } namespace { +/// \brief Add the given macro to the hash of all top-level entities. +void AddDefinedMacroToHash(const Token &MacroNameTok, unsigned &Hash) { + Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash); +} + /// \brief Preprocessor callback class that updates a hash value with the names /// of all macros that have been defined by the translation unit. class MacroDefinitionTrackerPPCallbacks : public PPCallbacks { @@ -771,7 +803,7 @@ public: void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD) override { - Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash); + AddDefinedMacroToHash(MacroNameTok, Hash); } }; @@ -897,45 +929,27 @@ public: } }; -class PrecompilePreambleAction : public ASTFrontendAction { - ASTUnit &Unit; - bool HasEmittedPreamblePCH; - +class ASTUnitPreambleCallbacks : public PreambleCallbacks { public: - explicit PrecompilePreambleAction(ASTUnit &Unit) - : Unit(Unit), HasEmittedPreamblePCH(false) {} + unsigned getHash() const { return Hash; } - std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) override; - bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; } - void setHasEmittedPreamblePCH() { HasEmittedPreamblePCH = true; } - bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); } - - bool hasCodeCompletionSupport() const override { return false; } - bool hasASTFileSupport() const override { return false; } - TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; } -}; + std::vector<Decl *> takeTopLevelDecls() { return std::move(TopLevelDecls); } -class PrecompilePreambleConsumer : public PCHGenerator { - ASTUnit &Unit; - unsigned &Hash; - std::vector<Decl *> TopLevelDecls; - PrecompilePreambleAction *Action; - std::unique_ptr<raw_ostream> Out; + std::vector<serialization::DeclID> takeTopLevelDeclIDs() { + return std::move(TopLevelDeclIDs); + } -public: - PrecompilePreambleConsumer(ASTUnit &Unit, PrecompilePreambleAction *Action, - const Preprocessor &PP, StringRef isysroot, - std::unique_ptr<raw_ostream> Out) - : PCHGenerator(PP, "", isysroot, std::make_shared<PCHBuffer>(), - ArrayRef<std::shared_ptr<ModuleFileExtension>>(), - /*AllowASTWithErrors=*/true), - Unit(Unit), Hash(Unit.getCurrentTopLevelHashValue()), Action(Action), - Out(std::move(Out)) { - Hash = 0; + void AfterPCHEmitted(ASTWriter &Writer) override { + TopLevelDeclIDs.reserve(TopLevelDecls.size()); + for (Decl *D : TopLevelDecls) { + // Invalid top-level decls may not have been serialized. + if (D->isInvalidDecl()) + continue; + TopLevelDeclIDs.push_back(Writer.getDeclID(D)); + } } - bool HandleTopLevelDecl(DeclGroupRef DG) override { + void HandleTopLevelDecl(DeclGroupRef DG) override { for (Decl *D : DG) { // FIXME: Currently ObjC method declarations are incorrectly being // reported as top-level declarations, even though their DeclContext @@ -946,59 +960,22 @@ public: AddTopLevelDeclarationToHash(D, Hash); TopLevelDecls.push_back(D); } - return true; } - void HandleTranslationUnit(ASTContext &Ctx) override { - PCHGenerator::HandleTranslationUnit(Ctx); - if (hasEmittedPCH()) { - // Write the generated bitstream to "Out". - *Out << getPCH(); - // Make sure it hits disk now. - Out->flush(); - // Free the buffer. - llvm::SmallVector<char, 0> Empty; - getPCH() = std::move(Empty); - - // Translate the top-level declarations we captured during - // parsing into declaration IDs in the precompiled - // preamble. This will allow us to deserialize those top-level - // declarations when requested. - for (Decl *D : TopLevelDecls) { - // Invalid top-level decls may not have been serialized. - if (D->isInvalidDecl()) - continue; - Unit.addTopLevelDeclFromPreamble(getWriter().getDeclID(D)); - } - - Action->setHasEmittedPreamblePCH(); - } + void HandleMacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override { + AddDefinedMacroToHash(MacroNameTok, Hash); } + +private: + unsigned Hash = 0; + std::vector<Decl *> TopLevelDecls; + std::vector<serialization::DeclID> TopLevelDeclIDs; + llvm::SmallVector<ASTUnit::StandaloneDiagnostic, 4> PreambleDiags; }; } // anonymous namespace -std::unique_ptr<ASTConsumer> -PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) { - std::string Sysroot; - std::string OutputFile; - std::unique_ptr<raw_ostream> OS = - GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot, - OutputFile); - if (!OS) - return nullptr; - - if (!CI.getFrontendOpts().RelocatablePCH) - Sysroot.clear(); - - CI.getPreprocessor().addPPCallbacks( - llvm::make_unique<MacroDefinitionTrackerPPCallbacks>( - Unit.getCurrentTopLevelHashValue())); - return llvm::make_unique<PrecompilePreambleConsumer>( - Unit, this, CI.getPreprocessor(), Sysroot, std::move(OS)); -} - static bool isNonDriverDiag(const StoredDiagnostic &StoredDiag) { return StoredDiag.getLocation().isValid(); } @@ -1034,15 +1011,20 @@ static void checkAndSanitizeDiags(SmallVectorImpl<StoredDiagnostic> & /// \returns True if a failure occurred that causes the ASTUnit not to /// contain any translation-unit information, false otherwise. bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, - std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer) { - SavedMainFileBuffer.reset(); - + std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer, + IntrusiveRefCntPtr<vfs::FileSystem> VFS) { if (!Invocation) return true; // Create the compiler instance to use for building the AST. std::unique_ptr<CompilerInstance> Clang( new CompilerInstance(std::move(PCHContainerOps))); + if (FileMgr && VFS) { + assert(VFS == FileMgr->getVirtualFileSystem() && + "VFS passed to Parse and VFS in FileMgr are different"); + } else if (VFS) { + Clang->setVirtualFileSystem(VFS); + } // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> @@ -1069,9 +1051,11 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() == + InputKind::Source && "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && + assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() != + InputKind::LLVM_IR && "IR inputs not support here!"); // Configure the various subsystems. @@ -1081,18 +1065,11 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, Clang->createFileManager(); FileMgr = &Clang->getFileManager(); } - SourceMgr = new SourceManager(getDiagnostics(), *FileMgr, - UserFilesAreVolatile); - TheSema.reset(); - Ctx = nullptr; - PP = nullptr; - Reader = nullptr; - // Clear out old caches and data. - TopLevelDecls.clear(); - clearFileLevelDecls(); - CleanTemporaryFiles(); + ResetForParse(); + SourceMgr = new SourceManager(getDiagnostics(), *FileMgr, + UserFilesAreVolatile); if (!OverrideMainBuffer) { checkAndRemoveNonDriverDiags(StoredDiagnostics); TopLevelDeclsInPreamble.clear(); @@ -1106,15 +1083,9 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, // If the main file has been overridden due to the use of a preamble, // make that override happen and introduce the preamble. - PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts(); if (OverrideMainBuffer) { - PreprocessorOpts.addRemappedFile(OriginalSourceFile, - OverrideMainBuffer.get()); - PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size(); - PreprocessorOpts.PrecompiledPreambleBytes.second - = PreambleEndsAtStartOfLine; - PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this); - PreprocessorOpts.DisablePCHValidation = true; + assert(Preamble && "No preamble was built, but OverrideMainBuffer is not null"); + Preamble->AddImplicitPreamble(Clang->getInvocation(), OverrideMainBuffer.get()); // The stored diagnostic has the old source manager in it; update // the locations to refer into the new source manager. Since we've @@ -1140,6 +1111,8 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, if (SavedMainFileBuffer) TranslateStoredDiagnostics(getFileManager(), getSourceManager(), PreambleDiagnostics, StoredDiagnostics); + else + PreambleSrcLocCache.clear(); if (!Act->Execute()) goto error; @@ -1165,111 +1138,6 @@ error: return true; } -/// \brief Simple function to retrieve a path for a preamble precompiled header. -static std::string GetPreamblePCHPath() { - // FIXME: This is a hack so that we can override the preamble file during - // crash-recovery testing, which is the only case where the preamble files - // are not necessarily cleaned up. - const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE"); - if (TmpFile) - return TmpFile; - - SmallString<128> Path; - llvm::sys::fs::createTemporaryFile("preamble", "pch", Path); - - return Path.str(); -} - -/// \brief Compute the preamble for the main file, providing the source buffer -/// that corresponds to the main file along with a pair (bytes, start-of-line) -/// that describes the preamble. -ASTUnit::ComputedPreamble -ASTUnit::ComputePreamble(CompilerInvocation &Invocation, unsigned MaxLines) { - FrontendOptions &FrontendOpts = Invocation.getFrontendOpts(); - PreprocessorOptions &PreprocessorOpts = Invocation.getPreprocessorOpts(); - - // Try to determine if the main file has been remapped, either from the - // command line (to another file) or directly through the compiler invocation - // (to a memory buffer). - llvm::MemoryBuffer *Buffer = nullptr; - std::unique_ptr<llvm::MemoryBuffer> BufferOwner; - std::string MainFilePath(FrontendOpts.Inputs[0].getFile()); - llvm::sys::fs::UniqueID MainFileID; - if (!llvm::sys::fs::getUniqueID(MainFilePath, MainFileID)) { - // Check whether there is a file-file remapping of the main file - for (const auto &RF : PreprocessorOpts.RemappedFiles) { - std::string MPath(RF.first); - llvm::sys::fs::UniqueID MID; - if (!llvm::sys::fs::getUniqueID(MPath, MID)) { - if (MainFileID == MID) { - // We found a remapping. Try to load the resulting, remapped source. - BufferOwner = getBufferForFile(RF.second); - if (!BufferOwner) - return ComputedPreamble(nullptr, nullptr, 0, true); - } - } - } - - // Check whether there is a file-buffer remapping. It supercedes the - // file-file remapping. - for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) { - std::string MPath(RB.first); - llvm::sys::fs::UniqueID MID; - if (!llvm::sys::fs::getUniqueID(MPath, MID)) { - if (MainFileID == MID) { - // We found a remapping. - BufferOwner.reset(); - Buffer = const_cast<llvm::MemoryBuffer *>(RB.second); - } - } - } - } - - // If the main source file was not remapped, load it now. - if (!Buffer && !BufferOwner) { - BufferOwner = getBufferForFile(FrontendOpts.Inputs[0].getFile()); - if (!BufferOwner) - return ComputedPreamble(nullptr, nullptr, 0, true); - } - - if (!Buffer) - Buffer = BufferOwner.get(); - auto Pre = Lexer::ComputePreamble(Buffer->getBuffer(), - *Invocation.getLangOpts(), MaxLines); - return ComputedPreamble(Buffer, std::move(BufferOwner), Pre.first, - Pre.second); -} - -ASTUnit::PreambleFileHash -ASTUnit::PreambleFileHash::createForFile(off_t Size, time_t ModTime) { - PreambleFileHash Result; - Result.Size = Size; - Result.ModTime = ModTime; - memset(Result.MD5, 0, sizeof(Result.MD5)); - return Result; -} - -ASTUnit::PreambleFileHash ASTUnit::PreambleFileHash::createForMemoryBuffer( - const llvm::MemoryBuffer *Buffer) { - PreambleFileHash Result; - Result.Size = Buffer->getBufferSize(); - Result.ModTime = 0; - - llvm::MD5 MD5Ctx; - MD5Ctx.update(Buffer->getBuffer().data()); - MD5Ctx.final(Result.MD5); - - return Result; -} - -namespace clang { -bool operator==(const ASTUnit::PreambleFileHash &LHS, - const ASTUnit::PreambleFileHash &RHS) { - return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime && - memcmp(LHS.MD5, RHS.MD5, sizeof(LHS.MD5)) == 0; -} -} // namespace clang - static std::pair<unsigned, unsigned> makeStandaloneRange(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts) { @@ -1338,135 +1206,44 @@ makeStandaloneDiagnostic(const LangOptions &LangOpts, std::unique_ptr<llvm::MemoryBuffer> ASTUnit::getMainBufferWithPrecompiledPreamble( std::shared_ptr<PCHContainerOperations> PCHContainerOps, - const CompilerInvocation &PreambleInvocationIn, bool AllowRebuild, + const CompilerInvocation &PreambleInvocationIn, + IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool AllowRebuild, unsigned MaxLines) { - auto PreambleInvocation = - std::make_shared<CompilerInvocation>(PreambleInvocationIn); - FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts(); - PreprocessorOptions &PreprocessorOpts - = PreambleInvocation->getPreprocessorOpts(); - - ComputedPreamble NewPreamble = ComputePreamble(*PreambleInvocation, MaxLines); - - if (!NewPreamble.Size) { - // We couldn't find a preamble in the main source. Clear out the current - // preamble, if we have one. It's obviously no good any more. - Preamble.clear(); - erasePreambleFile(this); - - // The next time we actually see a preamble, precompile it. - PreambleRebuildCounter = 1; + auto MainFilePath = + PreambleInvocationIn.getFrontendOpts().Inputs[0].getFile(); + std::unique_ptr<llvm::MemoryBuffer> MainFileBuffer = + getBufferForFileHandlingRemapping(PreambleInvocationIn, VFS.get(), + MainFilePath); + if (!MainFileBuffer) return nullptr; - } - - if (!Preamble.empty()) { - // We've previously computed a preamble. Check whether we have the same - // preamble now that we did before, and that there's enough space in - // the main-file buffer within the precompiled preamble to fit the - // new main file. - if (Preamble.size() == NewPreamble.Size && - PreambleEndsAtStartOfLine == NewPreamble.PreambleEndsAtStartOfLine && - memcmp(Preamble.getBufferStart(), NewPreamble.Buffer->getBufferStart(), - NewPreamble.Size) == 0) { - // The preamble has not changed. We may be able to re-use the precompiled - // preamble. - - // Check that none of the files used by the preamble have changed. - bool AnyFileChanged = false; - - // First, make a record of those files that have been overridden via - // remapping or unsaved_files. - std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles; - for (const auto &R : PreprocessorOpts.RemappedFiles) { - if (AnyFileChanged) - break; - - vfs::Status Status; - if (FileMgr->getNoncachedStatValue(R.second, Status)) { - // If we can't stat the file we're remapping to, assume that something - // horrible happened. - AnyFileChanged = true; - break; - } - OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile( - Status.getSize(), - llvm::sys::toTimeT(Status.getLastModificationTime())); - } + PreambleBounds Bounds = + ComputePreambleBounds(*PreambleInvocationIn.getLangOpts(), + MainFileBuffer.get(), MaxLines); + if (!Bounds.Size) + return nullptr; - for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) { - if (AnyFileChanged) - break; + if (Preamble) { + if (Preamble->CanReuse(PreambleInvocationIn, MainFileBuffer.get(), Bounds, + VFS.get())) { + // Okay! We can re-use the precompiled preamble. - vfs::Status Status; - if (FileMgr->getNoncachedStatValue(RB.first, Status)) { - AnyFileChanged = true; - break; - } + // Set the state of the diagnostic object to mimic its state + // after parsing the preamble. + getDiagnostics().Reset(); + ProcessWarningOptions(getDiagnostics(), + PreambleInvocationIn.getDiagnosticOpts()); + getDiagnostics().setNumWarnings(NumWarningsInPreamble); - OverriddenFiles[Status.getUniqueID()] = - PreambleFileHash::createForMemoryBuffer(RB.second); - } - - // Check whether anything has changed. - for (llvm::StringMap<PreambleFileHash>::iterator - F = FilesInPreamble.begin(), FEnd = FilesInPreamble.end(); - !AnyFileChanged && F != FEnd; - ++F) { - vfs::Status Status; - if (FileMgr->getNoncachedStatValue(F->first(), Status)) { - // If we can't stat the file, assume that something horrible happened. - AnyFileChanged = true; - break; - } - - std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden - = OverriddenFiles.find(Status.getUniqueID()); - if (Overridden != OverriddenFiles.end()) { - // This file was remapped; check whether the newly-mapped file - // matches up with the previous mapping. - if (Overridden->second != F->second) - AnyFileChanged = true; - continue; - } - - // The file was not remapped; check whether it has changed on disk. - if (Status.getSize() != uint64_t(F->second.Size) || - llvm::sys::toTimeT(Status.getLastModificationTime()) != - F->second.ModTime) - AnyFileChanged = true; - } - - if (!AnyFileChanged) { - // Okay! We can re-use the precompiled preamble. - - // Set the state of the diagnostic object to mimic its state - // after parsing the preamble. - getDiagnostics().Reset(); - ProcessWarningOptions(getDiagnostics(), - PreambleInvocation->getDiagnosticOpts()); - getDiagnostics().setNumWarnings(NumWarningsInPreamble); - - return llvm::MemoryBuffer::getMemBufferCopy( - NewPreamble.Buffer->getBuffer(), FrontendOpts.Inputs[0].getFile()); - } + PreambleRebuildCounter = 1; + return MainFileBuffer; + } else { + Preamble.reset(); + PreambleDiagnostics.clear(); + TopLevelDeclsInPreamble.clear(); + PreambleRebuildCounter = 1; } - - // If we aren't allowed to rebuild the precompiled preamble, just - // return now. - if (!AllowRebuild) - return nullptr; - - // We can't reuse the previously-computed preamble. Build a new one. - Preamble.clear(); - PreambleDiagnostics.clear(); - erasePreambleFile(this); - PreambleRebuildCounter = 1; - } else if (!AllowRebuild) { - // We aren't allowed to rebuild the precompiled preamble; just - // return now. - return nullptr; } // If the preamble rebuild counter > 1, it's because we previously @@ -1477,162 +1254,61 @@ ASTUnit::getMainBufferWithPrecompiledPreamble( return nullptr; } - // Create a temporary file for the precompiled preamble. In rare - // circumstances, this can fail. - std::string PreamblePCHPath = GetPreamblePCHPath(); - if (PreamblePCHPath.empty()) { - // Try again next time. - PreambleRebuildCounter = 1; - return nullptr; - } - - // We did not previously compute a preamble, or it can't be reused anyway. - SimpleTimer PreambleTimer(WantTiming); - PreambleTimer.setOutput("Precompiling preamble"); - - // Save the preamble text for later; we'll need to compare against it for - // subsequent reparses. - StringRef MainFilename = FrontendOpts.Inputs[0].getFile(); - Preamble.assign(FileMgr->getFile(MainFilename), - NewPreamble.Buffer->getBufferStart(), - NewPreamble.Buffer->getBufferStart() + NewPreamble.Size); - PreambleEndsAtStartOfLine = NewPreamble.PreambleEndsAtStartOfLine; - - PreambleBuffer = llvm::MemoryBuffer::getMemBufferCopy( - NewPreamble.Buffer->getBuffer().slice(0, Preamble.size()), MainFilename); - - // Remap the main source file to the preamble buffer. - StringRef MainFilePath = FrontendOpts.Inputs[0].getFile(); - PreprocessorOpts.addRemappedFile(MainFilePath, PreambleBuffer.get()); - - // Tell the compiler invocation to generate a temporary precompiled header. - FrontendOpts.ProgramAction = frontend::GeneratePCH; - // FIXME: Generate the precompiled header into memory? - FrontendOpts.OutputFile = PreamblePCHPath; - PreprocessorOpts.PrecompiledPreambleBytes.first = 0; - PreprocessorOpts.PrecompiledPreambleBytes.second = false; - - // Create the compiler instance to use for building the precompiled preamble. - std::unique_ptr<CompilerInstance> Clang( - new CompilerInstance(std::move(PCHContainerOps))); - - // Recover resources if we crash before exiting this method. - llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> - CICleanup(Clang.get()); - - Clang->setInvocation(std::move(PreambleInvocation)); - OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile(); - - // Set up diagnostics, capturing all of the diagnostics produced. - Clang->setDiagnostics(&getDiagnostics()); - - // Create the target instance. - Clang->setTarget(TargetInfo::CreateTargetInfo( - Clang->getDiagnostics(), Clang->getInvocation().TargetOpts)); - if (!Clang->hasTarget()) { - llvm::sys::fs::remove(FrontendOpts.OutputFile); - Preamble.clear(); - PreambleRebuildCounter = DefaultPreambleRebuildInterval; - PreprocessorOpts.RemappedFileBuffers.pop_back(); - return nullptr; - } - - // Inform the target of the language options. - // - // FIXME: We shouldn't need to do this, the target should be immutable once - // created. This complexity should be lifted elsewhere. - Clang->getTarget().adjust(Clang->getLangOpts()); - - assert(Clang->getFrontendOpts().Inputs.size() == 1 && - "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && - "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && - "IR inputs not support here!"); - - // Clear out old caches and data. - getDiagnostics().Reset(); - ProcessWarningOptions(getDiagnostics(), Clang->getDiagnosticOpts()); - checkAndRemoveNonDriverDiags(StoredDiagnostics); - TopLevelDecls.clear(); - TopLevelDeclsInPreamble.clear(); - PreambleDiagnostics.clear(); - - IntrusiveRefCntPtr<vfs::FileSystem> VFS = - createVFSFromCompilerInvocation(Clang->getInvocation(), getDiagnostics()); - if (!VFS) + assert(!Preamble && "No Preamble should be stored at that point"); + // If we aren't allowed to rebuild the precompiled preamble, just + // return now. + if (!AllowRebuild) return nullptr; - // Create a file manager object to provide access to and cache the filesystem. - Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS)); - - // Create the source manager. - Clang->setSourceManager(new SourceManager(getDiagnostics(), - Clang->getFileManager())); - - auto PreambleDepCollector = std::make_shared<DependencyCollector>(); - Clang->addDependencyCollector(PreambleDepCollector); - - std::unique_ptr<PrecompilePreambleAction> Act; - Act.reset(new PrecompilePreambleAction(*this)); - if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) { - llvm::sys::fs::remove(FrontendOpts.OutputFile); - Preamble.clear(); - PreambleRebuildCounter = DefaultPreambleRebuildInterval; - PreprocessorOpts.RemappedFileBuffers.pop_back(); - return nullptr; + SmallVector<StandaloneDiagnostic, 4> NewPreambleDiagsStandalone; + SmallVector<StoredDiagnostic, 4> NewPreambleDiags; + ASTUnitPreambleCallbacks Callbacks; + { + llvm::Optional<CaptureDroppedDiagnostics> Capture; + if (CaptureDiagnostics) + Capture.emplace(/*RequestCapture=*/true, *Diagnostics, &NewPreambleDiags, + &NewPreambleDiagsStandalone); + + // We did not previously compute a preamble, or it can't be reused anyway. + SimpleTimer PreambleTimer(WantTiming); + PreambleTimer.setOutput("Precompiling preamble"); + + llvm::ErrorOr<PrecompiledPreamble> NewPreamble = PrecompiledPreamble::Build( + PreambleInvocationIn, MainFileBuffer.get(), Bounds, *Diagnostics, VFS, + PCHContainerOps, Callbacks); + if (NewPreamble) { + Preamble = std::move(*NewPreamble); + PreambleRebuildCounter = 1; + } else { + switch (static_cast<BuildPreambleError>(NewPreamble.getError().value())) { + case BuildPreambleError::CouldntCreateTempFile: + case BuildPreambleError::PreambleIsEmpty: + // Try again next time. + PreambleRebuildCounter = 1; + return nullptr; + case BuildPreambleError::CouldntCreateTargetInfo: + case BuildPreambleError::BeginSourceFileFailed: + case BuildPreambleError::CouldntEmitPCH: + case BuildPreambleError::CouldntCreateVFSOverlay: + // These erros are more likely to repeat, retry after some period. + PreambleRebuildCounter = DefaultPreambleRebuildInterval; + return nullptr; + } + llvm_unreachable("unexpected BuildPreambleError"); + } } - - Act->Execute(); - - // Transfer any diagnostics generated when parsing the preamble into the set - // of preamble diagnostics. - for (stored_diag_iterator I = stored_diag_afterDriver_begin(), - E = stored_diag_end(); - I != E; ++I) - PreambleDiagnostics.push_back( - makeStandaloneDiagnostic(Clang->getLangOpts(), *I)); - Act->EndSourceFile(); + assert(Preamble && "Preamble wasn't built"); - checkAndRemoveNonDriverDiags(StoredDiagnostics); + TopLevelDecls.clear(); + TopLevelDeclsInPreamble = Callbacks.takeTopLevelDeclIDs(); + PreambleTopLevelHashValue = Callbacks.getHash(); - if (!Act->hasEmittedPreamblePCH()) { - // The preamble PCH failed (e.g. there was a module loading fatal error), - // so no precompiled header was generated. Forget that we even tried. - // FIXME: Should we leave a note for ourselves to try again? - llvm::sys::fs::remove(FrontendOpts.OutputFile); - Preamble.clear(); - TopLevelDeclsInPreamble.clear(); - PreambleRebuildCounter = DefaultPreambleRebuildInterval; - PreprocessorOpts.RemappedFileBuffers.pop_back(); - return nullptr; - } - - // Keep track of the preamble we precompiled. - setPreambleFile(this, FrontendOpts.OutputFile); NumWarningsInPreamble = getDiagnostics().getNumWarnings(); - - // Keep track of all of the files that the source manager knows about, - // so we can verify whether they have changed or not. - FilesInPreamble.clear(); - SourceManager &SourceMgr = Clang->getSourceManager(); - for (auto &Filename : PreambleDepCollector->getDependencies()) { - const FileEntry *File = Clang->getFileManager().getFile(Filename); - if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID())) - continue; - if (time_t ModTime = File->getModificationTime()) { - FilesInPreamble[File->getName()] = PreambleFileHash::createForFile( - File->getSize(), ModTime); - } else { - llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File); - FilesInPreamble[File->getName()] = - PreambleFileHash::createForMemoryBuffer(Buffer); - } - } - PreambleRebuildCounter = 1; - PreprocessorOpts.RemappedFileBuffers.pop_back(); + checkAndRemoveNonDriverDiags(NewPreambleDiags); + StoredDiagnostics = std::move(NewPreambleDiags); + PreambleDiagnostics = std::move(NewPreambleDiagsStandalone); // If the hash of top-level entities differs from the hash of the top-level // entities the last time we rebuilt the preamble, clear out the completion @@ -1642,11 +1318,12 @@ ASTUnit::getMainBufferWithPrecompiledPreamble( PreambleTopLevelHashValue = CurrentTopLevelHashValue; } - return llvm::MemoryBuffer::getMemBufferCopy(NewPreamble.Buffer->getBuffer(), - MainFilename); + return MainFileBuffer; } void ASTUnit::RealizeTopLevelDeclsFromPreamble() { + assert(Preamble && "Should only be called when preamble was built"); + std::vector<Decl *> Resolved; Resolved.reserve(TopLevelDeclsInPreamble.size()); ExternalASTSource &Source = *getASTContext().getExternalSource(); @@ -1723,6 +1400,7 @@ ASTUnit::create(std::shared_ptr<CompilerInvocation> CI, AST->UserFilesAreVolatile = UserFilesAreVolatile; AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr, UserFilesAreVolatile); + AST->PCMCache = new MemoryBufferCache; return AST; } @@ -1802,10 +1480,12 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction( assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() == + InputKind::Source && "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && - "IR inputs not supported here!"); + assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() != + InputKind::LLVM_IR && + "IR inputs not support here!"); // Configure the various subsystems. AST->TheSema.reset(); @@ -1872,30 +1552,36 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction( bool ASTUnit::LoadFromCompilerInvocation( std::shared_ptr<PCHContainerOperations> PCHContainerOps, - unsigned PrecompilePreambleAfterNParses) { + unsigned PrecompilePreambleAfterNParses, + IntrusiveRefCntPtr<vfs::FileSystem> VFS) { if (!Invocation) return true; - + + assert(VFS && "VFS is null"); + // We'll manage file buffers ourselves. Invocation->getPreprocessorOpts().RetainRemappedFileBuffers = true; Invocation->getFrontendOpts().DisableFree = false; + getDiagnostics().Reset(); ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts()); std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer; if (PrecompilePreambleAfterNParses > 0) { PreambleRebuildCounter = PrecompilePreambleAfterNParses; OverrideMainBuffer = - getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation); + getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS); + getDiagnostics().Reset(); + ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts()); } - + SimpleTimer ParsingTimer(WantTiming); ParsingTimer.setOutput("Parsing " + getMainFileName()); - + // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<llvm::MemoryBuffer> MemBufferCleanup(OverrideMainBuffer.get()); - return Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer)); + return Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer), VFS); } std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation( @@ -1929,7 +1615,8 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation( DiagCleanup(Diags.get()); if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps), - PrecompilePreambleAfterNParses)) + PrecompilePreambleAfterNParses, + AST->FileMgr->getVirtualFileSystem())) return nullptr; return AST; } @@ -1943,8 +1630,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine( unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, bool AllowPCHWithCompilerErrors, bool SkipFunctionBodies, - bool UserFilesAreVolatile, bool ForSerialization, - llvm::Optional<StringRef> ModuleFormat, std::unique_ptr<ASTUnit> *ErrAST) { + bool SingleFileParse, bool UserFilesAreVolatile, bool ForSerialization, + llvm::Optional<StringRef> ModuleFormat, std::unique_ptr<ASTUnit> *ErrAST, + IntrusiveRefCntPtr<vfs::FileSystem> VFS) { assert(Diags.get() && "no DiagnosticsEngine was provided"); SmallVector<StoredDiagnostic, 4> StoredDiagnostics; @@ -1953,11 +1641,11 @@ ASTUnit *ASTUnit::LoadFromCommandLine( { - CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags, - StoredDiagnostics); + CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags, + &StoredDiagnostics, nullptr); CI = clang::createInvocationFromCommandLine( - llvm::makeArrayRef(ArgBegin, ArgEnd), Diags); + llvm::makeArrayRef(ArgBegin, ArgEnd), Diags, VFS); if (!CI) return nullptr; } @@ -1970,6 +1658,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine( PreprocessorOptions &PPOpts = CI->getPreprocessorOpts(); PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName; PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors; + PPOpts.GeneratePreamble = PrecompilePreambleAfterNParses != 0; + PPOpts.SingleFileParseMode = SingleFileParse; // Override the resources path. CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath; @@ -1985,11 +1675,13 @@ ASTUnit *ASTUnit::LoadFromCommandLine( ConfigureDiags(Diags, *AST, CaptureDiagnostics); AST->Diagnostics = Diags; AST->FileSystemOpts = CI->getFileSystemOpts(); - IntrusiveRefCntPtr<vfs::FileSystem> VFS = - createVFSFromCompilerInvocation(*CI, *Diags); + if (!VFS) + VFS = vfs::getRealFileSystem(); + VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS); if (!VFS) return nullptr; AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS); + AST->PCMCache = new MemoryBufferCache; AST->OnlyLocalDecls = OnlyLocalDecls; AST->CaptureDiagnostics = CaptureDiagnostics; AST->TUKind = TUKind; @@ -2001,7 +1693,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine( AST->StoredDiagnostics.swap(StoredDiagnostics); AST->Invocation = CI; if (ForSerialization) - AST->WriterData.reset(new ASTWriterData()); + AST->WriterData.reset(new ASTWriterData(*AST->PCMCache)); // Zero out now to ease cleanup during crash recovery. CI = nullptr; Diags = nullptr; @@ -2011,7 +1703,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine( ASTUnitCleanup(AST.get()); if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps), - PrecompilePreambleAfterNParses)) { + PrecompilePreambleAfterNParses, + VFS)) { // Some error occurred, if caller wants to examine diagnostics, pass it the // ASTUnit. if (ErrAST) { @@ -2025,10 +1718,16 @@ ASTUnit *ASTUnit::LoadFromCommandLine( } bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, - ArrayRef<RemappedFile> RemappedFiles) { + ArrayRef<RemappedFile> RemappedFiles, + IntrusiveRefCntPtr<vfs::FileSystem> VFS) { if (!Invocation) return true; + if (!VFS) { + assert(FileMgr && "FileMgr is null on Reparse call"); + VFS = FileMgr->getVirtualFileSystem(); + } + clearFileLevelDecls(); SimpleTimer ParsingTimer(WantTiming); @@ -2048,9 +1747,10 @@ bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, // If we have a preamble file lying around, or if we might try to // build a precompiled preamble, do so now. std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer; - if (!getPreambleFile(this).empty() || PreambleRebuildCounter > 0) + if (Preamble || PreambleRebuildCounter > 0) OverrideMainBuffer = - getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation); + getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS); + // Clear out the diagnostics state. FileMgr.reset(); @@ -2061,7 +1761,7 @@ bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, // Parse the sources bool Result = - Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer)); + Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer), VFS); // If we're caching global code-completion results, and the top-level // declarations have changed, clear out the code-completion cache. @@ -2076,6 +1776,19 @@ bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, return Result; } +void ASTUnit::ResetForParse() { + SavedMainFileBuffer.reset(); + + SourceMgr.reset(); + TheSema.reset(); + Ctx.reset(); + PP.reset(); + Reader.reset(); + + TopLevelDecls.clear(); + clearFileLevelDecls(); +} + //----------------------------------------------------------------------------// // Code completion //----------------------------------------------------------------------------// @@ -2368,7 +2081,7 @@ void ASTUnit::CodeComplete( Clang->setDiagnostics(&Diag); CaptureDroppedDiagnostics Capture(true, Clang->getDiagnostics(), - StoredDiagnostics); + &StoredDiagnostics, nullptr); ProcessWarningOptions(Diag, Inv.getDiagnosticOpts()); // Create the target instance. @@ -2387,11 +2100,12 @@ void ASTUnit::CodeComplete( assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() == + InputKind::Source && "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && + assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() != + InputKind::LLVM_IR && "IR inputs not support here!"); - // Use the source and file managers that we were given. Clang->setFileManager(&FileMgr); @@ -2416,17 +2130,21 @@ void ASTUnit::CodeComplete( // point is within the main file, after the end of the precompiled // preamble. std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer; - if (!getPreambleFile(this).empty()) { + if (Preamble) { std::string CompleteFilePath(File); - llvm::sys::fs::UniqueID CompleteFileID; - if (!llvm::sys::fs::getUniqueID(CompleteFilePath, CompleteFileID)) { + auto VFS = FileMgr.getVirtualFileSystem(); + auto CompleteFileStatus = VFS->status(CompleteFilePath); + if (CompleteFileStatus) { + llvm::sys::fs::UniqueID CompleteFileID = CompleteFileStatus->getUniqueID(); + std::string MainPath(OriginalSourceFile); - llvm::sys::fs::UniqueID MainID; - if (!llvm::sys::fs::getUniqueID(MainPath, MainID)) { + auto MainStatus = VFS->status(MainPath); + if (MainStatus) { + llvm::sys::fs::UniqueID MainID = MainStatus->getUniqueID(); if (CompleteFileID == MainID && Line > 1) OverrideMainBuffer = getMainBufferWithPrecompiledPreamble( - PCHContainerOps, Inv, false, Line - 1); + PCHContainerOps, Inv, VFS, false, Line - 1); } } } @@ -2434,14 +2152,8 @@ void ASTUnit::CodeComplete( // If the main file has been overridden due to the use of a preamble, // make that override happen and introduce the preamble. if (OverrideMainBuffer) { - PreprocessorOpts.addRemappedFile(OriginalSourceFile, - OverrideMainBuffer.get()); - PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size(); - PreprocessorOpts.PrecompiledPreambleBytes.second - = PreambleEndsAtStartOfLine; - PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this); - PreprocessorOpts.DisablePCHValidation = true; - + assert(Preamble && "No preamble was built, but OverrideMainBuffer is not null"); + Preamble->AddImplicitPreamble(Clang->getInvocation(), OverrideMainBuffer.get()); OwnedBuffers.push_back(OverrideMainBuffer.release()); } else { PreprocessorOpts.PrecompiledPreambleBytes.first = 0; @@ -2516,7 +2228,8 @@ bool ASTUnit::serialize(raw_ostream &OS) { SmallString<128> Buffer; llvm::BitstreamWriter Stream(Buffer); - ASTWriter Writer(Stream, { }); + MemoryBufferCache PCMCache; + ASTWriter Writer(Stream, Buffer, PCMCache, {}); return serializeUnit(Writer, Buffer, getSema(), hasErrors, OS); } @@ -2531,9 +2244,9 @@ void ASTUnit::TranslateStoredDiagnostics( // remap all the locations to the new view. This includes the diag location, // any associated source ranges, and the source ranges of associated fix-its. // FIXME: There should be a cleaner way to do this. - SmallVector<StoredDiagnostic, 4> Result; Result.reserve(Diags.size()); + for (const StandaloneDiagnostic &SD : Diags) { // Rebuild the StoredDiagnostic. if (SD.Filename.empty()) @@ -2541,8 +2254,16 @@ void ASTUnit::TranslateStoredDiagnostics( const FileEntry *FE = FileMgr.getFile(SD.Filename); if (!FE) continue; - FileID FID = SrcMgr.translateFile(FE); - SourceLocation FileLoc = SrcMgr.getLocForStartOfFile(FID); + SourceLocation FileLoc; + auto ItFileID = PreambleSrcLocCache.find(SD.Filename); + if (ItFileID == PreambleSrcLocCache.end()) { + FileID FID = SrcMgr.translateFile(FE); + FileLoc = SrcMgr.getLocForStartOfFile(FID); + PreambleSrcLocCache[SD.Filename] = FileLoc; + } else { + FileLoc = ItFileID->getValue(); + } + if (FileLoc.isInvalid()) continue; SourceLocation L = FileLoc.getLocWithOffset(SD.LocOffset); @@ -2679,11 +2400,11 @@ SourceLocation ASTUnit::mapLocationFromPreamble(SourceLocation Loc) { if (SourceMgr) PreambleID = SourceMgr->getPreambleFileID(); - if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid()) + if (Loc.isInvalid() || !Preamble || PreambleID.isInvalid()) return Loc; unsigned Offs; - if (SourceMgr->isInFileID(Loc, PreambleID, &Offs) && Offs < Preamble.size()) { + if (SourceMgr->isInFileID(Loc, PreambleID, &Offs) && Offs < Preamble->getBounds().Size) { SourceLocation FileLoc = SourceMgr->getLocForStartOfFile(SourceMgr->getMainFileID()); return FileLoc.getLocWithOffset(Offs); @@ -2700,12 +2421,12 @@ SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) { if (SourceMgr) PreambleID = SourceMgr->getPreambleFileID(); - if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid()) + if (Loc.isInvalid() || !Preamble || PreambleID.isInvalid()) return Loc; unsigned Offs; if (SourceMgr->isInFileID(Loc, SourceMgr->getMainFileID(), &Offs) && - Offs < Preamble.size()) { + Offs < Preamble->getBounds().Size) { SourceLocation FileLoc = SourceMgr->getLocForStartOfFile(PreambleID); return FileLoc.getLocWithOffset(Offs); } @@ -2823,18 +2544,32 @@ const FileEntry *ASTUnit::getPCHFile() { } bool ASTUnit::isModuleFile() { - return isMainFileAST() && ASTFileLangOpts.isCompilingModule(); + return isMainFileAST() && getLangOpts().isCompilingModule(); } -void ASTUnit::PreambleData::countLines() const { - NumLines = 0; - if (empty()) - return; +InputKind ASTUnit::getInputKind() const { + auto &LangOpts = getLangOpts(); + + InputKind::Language Lang; + if (LangOpts.OpenCL) + Lang = InputKind::OpenCL; + else if (LangOpts.CUDA) + Lang = InputKind::CUDA; + else if (LangOpts.RenderScript) + Lang = InputKind::RenderScript; + else if (LangOpts.CPlusPlus) + Lang = LangOpts.ObjC1 ? InputKind::ObjCXX : InputKind::CXX; + else + Lang = LangOpts.ObjC1 ? InputKind::ObjC : InputKind::C; + + InputKind::Format Fmt = InputKind::Source; + if (LangOpts.getCompilingModule() == LangOptions::CMK_ModuleMap) + Fmt = InputKind::ModuleMap; - NumLines = std::count(Buffer.begin(), Buffer.end(), '\n'); + // We don't know if input was preprocessed. Assume not. + bool PP = false; - if (Buffer.back() != '\n') - ++NumLines; + return InputKind(Lang, Fmt, PP); } #ifndef NDEBUG diff --git a/contrib/llvm/tools/clang/lib/Frontend/ChainedIncludesSource.cpp b/contrib/llvm/tools/clang/lib/Frontend/ChainedIncludesSource.cpp index b984c2e..534c758 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/ChainedIncludesSource.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/ChainedIncludesSource.cpp @@ -83,7 +83,7 @@ createASTReader(CompilerInstance &CI, StringRef pchFile, ASTDeserializationListener *deserialListener = nullptr) { Preprocessor &PP = CI.getPreprocessor(); std::unique_ptr<ASTReader> Reader; - Reader.reset(new ASTReader(PP, CI.getASTContext(), + Reader.reset(new ASTReader(PP, &CI.getASTContext(), CI.getPCHContainerReader(), /*Extensions=*/{ }, /*isysroot=*/"", /*DisableValidation=*/true)); diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp index afcaa6e..bb6a665 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp @@ -11,8 +11,10 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" +#include "clang/Basic/CharInfo.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" +#include "clang/Basic/MemoryBufferCache.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" @@ -55,12 +57,15 @@ using namespace clang; CompilerInstance::CompilerInstance( std::shared_ptr<PCHContainerOperations> PCHContainerOps, - bool BuildingModule) - : ModuleLoader(BuildingModule), Invocation(new CompilerInvocation()), - ModuleManager(nullptr), - ThePCHContainerOperations(std::move(PCHContainerOps)), - BuildGlobalModuleIndex(false), HaveFullGlobalModuleIndex(false), - ModuleBuildFailed(false) {} + MemoryBufferCache *SharedPCMCache) + : ModuleLoader(/* BuildingModule = */ SharedPCMCache), + Invocation(new CompilerInvocation()), + PCMCache(SharedPCMCache ? SharedPCMCache : new MemoryBufferCache), + ThePCHContainerOperations(std::move(PCHContainerOps)) { + // Don't allow this to invalidate buffers in use by others. + if (SharedPCMCache) + getPCMCache().finalizeCurrentBuffers(); +} CompilerInstance::~CompilerInstance() { assert(OutputFiles.empty() && "Still output files in flight?"); @@ -131,6 +136,8 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::getModuleManager() const { return ModuleManager; } void CompilerInstance::setModuleManager(IntrusiveRefCntPtr<ASTReader> Reader) { + assert(PCMCache.get() == &Reader->getModuleManager().getPCMCache() && + "Expected ASTReader to use the same PCM cache"); ModuleManager = std::move(Reader); } @@ -373,7 +380,7 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) { getDiagnostics(), getLangOpts(), &getTarget()); PP = std::make_shared<Preprocessor>( Invocation->getPreprocessorOptsPtr(), getDiagnostics(), getLangOpts(), - getSourceManager(), *HeaderInfo, *this, PTHMgr, + getSourceManager(), getPCMCache(), *HeaderInfo, *this, PTHMgr, /*OwnsHeaderSearch=*/true, TUKind); PP->Initialize(getTarget(), getAuxTarget()); @@ -491,6 +498,8 @@ void CompilerInstance::createPCHExternalASTSource( AllowPCHWithCompilerErrors, getPreprocessor(), getASTContext(), getPCHContainerReader(), getFrontendOpts().ModuleFileExtensions, + TheDependencyFileGenerator.get(), + DependencyCollectors, DeserializationListener, OwnDeserializationListener, Preamble, getFrontendOpts().UseGlobalModuleIndex); @@ -501,12 +510,14 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource( bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context, const PCHContainerReader &PCHContainerRdr, ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions, + DependencyFileGenerator *DependencyFile, + ArrayRef<std::shared_ptr<DependencyCollector>> DependencyCollectors, void *DeserializationListener, bool OwnDeserializationListener, bool Preamble, bool UseGlobalModuleIndex) { HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); IntrusiveRefCntPtr<ASTReader> Reader(new ASTReader( - PP, Context, PCHContainerRdr, Extensions, + PP, &Context, PCHContainerRdr, Extensions, Sysroot.empty() ? "" : Sysroot.data(), DisablePCHValidation, AllowPCHWithCompilerErrors, /*AllowConfigurationMismatch*/ false, HSOpts.ModulesValidateSystemHeaders, UseGlobalModuleIndex)); @@ -518,6 +529,12 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource( Reader->setDeserializationListener( static_cast<ASTDeserializationListener *>(DeserializationListener), /*TakeOwnership=*/OwnDeserializationListener); + + if (DependencyFile) + DependencyFile->AttachToASTReader(*Reader); + for (auto &Listener : DependencyCollectors) + Listener->attachToASTReader(*Reader); + switch (Reader->ReadAST(Path, Preamble ? serialization::MK_Preamble : serialization::MK_PCH, @@ -651,6 +668,11 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) { llvm::sys::fs::remove(OF.Filename); } OutputFiles.clear(); + if (DeleteBuiltModules) { + for (auto &Module : BuiltModules) + llvm::sys::fs::remove(Module.second); + BuiltModules.clear(); + } NonSeekStream.reset(); } @@ -803,8 +825,11 @@ bool CompilerInstance::InitializeSourceManager( const FrontendInputFile &Input, DiagnosticsEngine &Diags, FileManager &FileMgr, SourceManager &SourceMgr, HeaderSearch *HS, DependencyOutputOptions &DepOpts, const FrontendOptions &Opts) { - SrcMgr::CharacteristicKind - Kind = Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User; + SrcMgr::CharacteristicKind Kind = + Input.getKind().getFormat() == InputKind::ModuleMap + ? Input.isSystem() ? SrcMgr::C_System_ModuleMap + : SrcMgr::C_User_ModuleMap + : Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User; if (Input.isBuffer()) { SourceMgr.setMainFileID(SourceMgr.createFileID( @@ -842,7 +867,8 @@ bool CompilerInstance::InitializeSourceManager( /*SearchPath=*/nullptr, /*RelativePath=*/nullptr, /*RequestingModule=*/nullptr, - /*SuggestedModule=*/nullptr, /*SkipCache=*/true); + /*SuggestedModule=*/nullptr, /*IsMapped=*/nullptr, + /*SkipCache=*/true); // Also add the header to /showIncludes output. if (File) DepOpts.ShowIncludesPretendHeader = File->getName(); @@ -910,8 +936,9 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { if (!hasTarget()) return false; - // Create TargetInfo for the other side of CUDA compilation. - if (getLangOpts().CUDA && !getFrontendOpts().AuxTriple.empty()) { + // Create TargetInfo for the other side of CUDA and OpenMP compilation. + if ((getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) && + !getFrontendOpts().AuxTriple.empty()) { auto TO = std::make_shared<TargetOptions>(); TO->Triple = getFrontendOpts().AuxTriple; TO->HostTriple = getTarget().getTriple().str(); @@ -999,26 +1026,27 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { /// \brief Determine the appropriate source input kind based on language /// options. -static InputKind getSourceInputKindFromOptions(const LangOptions &LangOpts) { +static InputKind::Language getLanguageFromOptions(const LangOptions &LangOpts) { if (LangOpts.OpenCL) - return IK_OpenCL; + return InputKind::OpenCL; if (LangOpts.CUDA) - return IK_CUDA; + return InputKind::CUDA; if (LangOpts.ObjC1) - return LangOpts.CPlusPlus? IK_ObjCXX : IK_ObjC; - return LangOpts.CPlusPlus? IK_CXX : IK_C; + return LangOpts.CPlusPlus ? InputKind::ObjCXX : InputKind::ObjC; + return LangOpts.CPlusPlus ? InputKind::CXX : InputKind::C; } /// \brief Compile a module file for the given module, using the options /// provided by the importing compiler instance. Returns true if the module /// was built without errors. -static bool compileModuleImpl(CompilerInstance &ImportingInstance, - SourceLocation ImportLoc, - Module *Module, - StringRef ModuleFileName) { - ModuleMap &ModMap - = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); - +static bool +compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, + StringRef ModuleName, FrontendInputFile Input, + StringRef OriginalModuleMapFile, StringRef ModuleFileName, + llvm::function_ref<void(CompilerInstance &)> PreBuildStep = + [](CompilerInstance &) {}, + llvm::function_ref<void(CompilerInstance &)> PostBuildStep = + [](CompilerInstance &) {}) { // Construct a compiler invocation for creating this module. auto Invocation = std::make_shared<CompilerInvocation>(ImportingInstance.getInvocation()); @@ -1032,7 +1060,7 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance, // Remove any macro definitions that are explicitly ignored by the module. // They aren't supposed to affect how the module is built anyway. - const HeaderSearchOptions &HSOpts = Invocation->getHeaderSearchOpts(); + HeaderSearchOptions &HSOpts = Invocation->getHeaderSearchOpts(); PPOpts.Macros.erase( std::remove_if(PPOpts.Macros.begin(), PPOpts.Macros.end(), [&HSOpts](const std::pair<std::string, bool> &def) { @@ -1043,7 +1071,7 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance, PPOpts.Macros.end()); // Note the name of the module we're building. - Invocation->getLangOpts()->CurrentModule = Module->getTopLevelModuleName(); + Invocation->getLangOpts()->CurrentModule = ModuleName; // Make sure that the failed-module structure has been allocated in // the importing instance, and propagate the pointer to the newly-created @@ -1063,8 +1091,10 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance, FrontendOpts.DisableFree = false; FrontendOpts.GenerateGlobalModuleIndex = false; FrontendOpts.BuildingImplicitModule = true; - FrontendOpts.Inputs.clear(); - InputKind IK = getSourceInputKindFromOptions(*Invocation->getLangOpts()); + FrontendOpts.OriginalModuleMap = OriginalModuleMapFile; + // Force implicitly-built modules to hash the content of the module file. + HSOpts.ModulesHashContent = true; + FrontendOpts.Inputs = {Input}; // Don't free the remapped file buffers; they are owned by our caller. PPOpts.RetainRemappedFileBuffers = true; @@ -1074,9 +1104,11 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance, Invocation->getModuleHash() && "Module hash mismatch!"); // Construct a compiler instance that will be used to actually create the - // module. + // module. Since we're sharing a PCMCache, + // CompilerInstance::CompilerInstance is responsible for finalizing the + // buffers to prevent use-after-frees. CompilerInstance Instance(ImportingInstance.getPCHContainerOperations(), - /*BuildingModule=*/true); + &ImportingInstance.getPreprocessor().getPCMCache()); auto &Inv = *Invocation; Instance.setInvocation(std::move(Invocation)); @@ -1093,7 +1125,7 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance, SourceManager &SourceMgr = Instance.getSourceManager(); SourceMgr.setModuleBuildStack( ImportingInstance.getSourceManager().getModuleBuildStack()); - SourceMgr.pushModuleBuildStack(Module->getTopLevelModuleName(), + SourceMgr.pushModuleBuildStack(ModuleName, FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager())); // If we're collecting module dependencies, we need to share a collector @@ -1102,47 +1134,28 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance, Instance.setModuleDepCollector(ImportingInstance.getModuleDepCollector()); Inv.getDependencyOutputOpts() = DependencyOutputOptions(); - // Get or create the module map that we'll use to build this module. - std::string InferredModuleMapContent; - if (const FileEntry *ModuleMapFile = - ModMap.getContainingModuleMapFile(Module)) { - // Use the module map where this module resides. - FrontendOpts.Inputs.emplace_back(ModuleMapFile->getName(), IK); - } else { - SmallString<128> FakeModuleMapFile(Module->Directory->getName()); - llvm::sys::path::append(FakeModuleMapFile, "__inferred_module.map"); - FrontendOpts.Inputs.emplace_back(FakeModuleMapFile, IK); - - llvm::raw_string_ostream OS(InferredModuleMapContent); - Module->print(OS); - OS.flush(); - - std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer = - llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent); - ModuleMapFile = Instance.getFileManager().getVirtualFile( - FakeModuleMapFile, InferredModuleMapContent.size(), 0); - SourceMgr.overrideFileContents(ModuleMapFile, std::move(ModuleMapBuffer)); - } - - // Construct a module-generating action. Passing through the module map is - // safe because the FileManager is shared between the compiler instances. - GenerateModuleFromModuleMapAction CreateModuleAction( - ModMap.getModuleMapFileForUniquing(Module), Module->IsSystem); - ImportingInstance.getDiagnostics().Report(ImportLoc, diag::remark_module_build) - << Module->Name << ModuleFileName; + << ModuleName << ModuleFileName; + + PreBuildStep(Instance); // Execute the action to actually build the module in-place. Use a separate // thread so that we get a stack large enough. const unsigned ThreadStackSize = 8 << 20; llvm::CrashRecoveryContext CRC; - CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(CreateModuleAction); }, - ThreadStackSize); + CRC.RunSafelyOnThread( + [&]() { + GenerateModuleFromModuleMapAction Action; + Instance.ExecuteAction(Action); + }, + ThreadStackSize); + + PostBuildStep(Instance); ImportingInstance.getDiagnostics().Report(ImportLoc, diag::remark_module_build_done) - << Module->Name; + << ModuleName; // Delete the temporary module map file. // FIXME: Even though we're executing under crash protection, it would still @@ -1150,13 +1163,66 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance, // doesn't make sense for all clients, so clean this up manually. Instance.clearOutputFiles(/*EraseFiles=*/true); + return !Instance.getDiagnostics().hasErrorOccurred(); +} + +/// \brief Compile a module file for the given module, using the options +/// provided by the importing compiler instance. Returns true if the module +/// was built without errors. +static bool compileModuleImpl(CompilerInstance &ImportingInstance, + SourceLocation ImportLoc, + Module *Module, + StringRef ModuleFileName) { + InputKind IK(getLanguageFromOptions(ImportingInstance.getLangOpts()), + InputKind::ModuleMap); + + // Get or create the module map that we'll use to build this module. + ModuleMap &ModMap + = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); + bool Result; + if (const FileEntry *ModuleMapFile = + ModMap.getContainingModuleMapFile(Module)) { + // Use the module map where this module resides. + Result = compileModuleImpl( + ImportingInstance, ImportLoc, Module->getTopLevelModuleName(), + FrontendInputFile(ModuleMapFile->getName(), IK, +Module->IsSystem), + ModMap.getModuleMapFileForUniquing(Module)->getName(), + ModuleFileName); + } else { + // FIXME: We only need to fake up an input file here as a way of + // transporting the module's directory to the module map parser. We should + // be able to do that more directly, and parse from a memory buffer without + // inventing this file. + SmallString<128> FakeModuleMapFile(Module->Directory->getName()); + llvm::sys::path::append(FakeModuleMapFile, "__inferred_module.map"); + + std::string InferredModuleMapContent; + llvm::raw_string_ostream OS(InferredModuleMapContent); + Module->print(OS); + OS.flush(); + + Result = compileModuleImpl( + ImportingInstance, ImportLoc, Module->getTopLevelModuleName(), + FrontendInputFile(FakeModuleMapFile, IK, +Module->IsSystem), + ModMap.getModuleMapFileForUniquing(Module)->getName(), + ModuleFileName, + [&](CompilerInstance &Instance) { + std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer = + llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent); + ModuleMapFile = Instance.getFileManager().getVirtualFile( + FakeModuleMapFile, InferredModuleMapContent.size(), 0); + Instance.getSourceManager().overrideFileContents( + ModuleMapFile, std::move(ModuleMapBuffer)); + }); + } + // We've rebuilt a module. If we're allowed to generate or update the global // module index, record that fact in the importing compiler instance. if (ImportingInstance.getFrontendOpts().GenerateGlobalModuleIndex) { ImportingInstance.setBuildGlobalModuleIndex(true); } - return !Instance.getDiagnostics().hasErrorOccurred(); + return Result; } static bool compileAndLoadModule(CompilerInstance &ImportingInstance, @@ -1180,10 +1246,14 @@ static bool compileAndLoadModule(CompilerInstance &ImportingInstance, llvm::LockFileManager Locked(ModuleFileName); switch (Locked) { case llvm::LockFileManager::LFS_Error: - Diags.Report(ModuleNameLoc, diag::err_module_lock_failure) + // PCMCache takes care of correctness and locks are only necessary for + // performance. Fallback to building the module in case of any lock + // related errors. + Diags.Report(ModuleNameLoc, diag::remark_module_lock_failure) << Module->Name << Locked.getErrorMessage(); - return false; - + // Clear out any potential leftover. + Locked.unsafeRemoveLockFile(); + // FALLTHROUGH case llvm::LockFileManager::LFS_Owned: // We're responsible for building the module ourselves. if (!compileModuleImpl(ImportingInstance, ModuleNameLoc, Module, @@ -1203,11 +1273,14 @@ static bool compileAndLoadModule(CompilerInstance &ImportingInstance, case llvm::LockFileManager::Res_OwnerDied: continue; // try again to get the lock. case llvm::LockFileManager::Res_Timeout: - Diags.Report(ModuleNameLoc, diag::err_module_lock_timeout) + // Since PCMCache takes care of correctness, we try waiting for another + // process to complete the build so clang does not do it done twice. If + // case of timeout, build it ourselves. + Diags.Report(ModuleNameLoc, diag::remark_module_lock_timeout) << Module->Name; // Clear the lock file so that future invokations can make progress. Locked.unsafeRemoveLockFile(); - return false; + continue; } break; } @@ -1400,7 +1473,7 @@ void CompilerInstance::createModuleManager() { "Reading modules", *FrontendTimerGroup); ModuleManager = new ASTReader( - getPreprocessor(), getASTContext(), getPCHContainerReader(), + getPreprocessor(), &getASTContext(), getPCHContainerReader(), getFrontendOpts().ModuleFileExtensions, Sysroot.empty() ? "" : Sysroot.c_str(), PPOpts.DisablePCHValidation, /*AllowASTWithCompilerErrors=*/false, @@ -1555,24 +1628,36 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, PP->getHeaderSearchInfo().getHeaderSearchOpts(); std::string ModuleFileName; - bool LoadFromPrebuiltModulePath = false; - // We try to load the module from the prebuilt module paths. If not - // successful, we then try to find it in the module cache. - if (!HSOpts.PrebuiltModulePaths.empty()) { - // Load the module from the prebuilt module path. + enum ModuleSource { + ModuleNotFound, ModuleCache, PrebuiltModulePath, ModuleBuildPragma + } Source = ModuleNotFound; + + // Check to see if the module has been built as part of this compilation + // via a module build pragma. + auto BuiltModuleIt = BuiltModules.find(ModuleName); + if (BuiltModuleIt != BuiltModules.end()) { + ModuleFileName = BuiltModuleIt->second; + Source = ModuleBuildPragma; + } + + // Try to load the module from the prebuilt module path. + if (Source == ModuleNotFound && !HSOpts.PrebuiltModulePaths.empty()) { ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName( ModuleName, "", /*UsePrebuiltPath*/ true); if (!ModuleFileName.empty()) - LoadFromPrebuiltModulePath = true; + Source = PrebuiltModulePath; } - if (!LoadFromPrebuiltModulePath && Module) { - // Load the module from the module cache. + + // Try to load the module from the module cache. + if (Source == ModuleNotFound && Module) { ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(Module); - } else if (!LoadFromPrebuiltModulePath) { + Source = ModuleCache; + } + + if (Source == ModuleNotFound) { // We can't find a module, error out here. getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found) - << ModuleName - << SourceRange(ImportLoc, ModuleNameLoc); + << ModuleName << SourceRange(ImportLoc, ModuleNameLoc); ModuleBuildFailed = true; return ModuleLoadResult(); } @@ -1600,20 +1685,20 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, *FrontendTimerGroup); llvm::TimeRegion TimeLoading(FrontendTimerGroup ? &Timer : nullptr); - // Try to load the module file. If we are trying to load from the prebuilt - // module path, we don't have the module map files and don't know how to - // rebuild modules. - unsigned ARRFlags = LoadFromPrebuiltModulePath ? - ASTReader::ARR_ConfigurationMismatch : - ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing; + // Try to load the module file. If we are not trying to load from the + // module cache, we don't know how to rebuild modules. + unsigned ARRFlags = Source == ModuleCache ? + ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing : + ASTReader::ARR_ConfigurationMismatch; switch (ModuleManager->ReadAST(ModuleFileName, - LoadFromPrebuiltModulePath ? - serialization::MK_PrebuiltModule : - serialization::MK_ImplicitModule, - ImportLoc, - ARRFlags)) { + Source == PrebuiltModulePath + ? serialization::MK_PrebuiltModule + : Source == ModuleBuildPragma + ? serialization::MK_ExplicitModule + : serialization::MK_ImplicitModule, + ImportLoc, ARRFlags)) { case ASTReader::Success: { - if (LoadFromPrebuiltModulePath && !Module) { + if (Source != ModuleCache && !Module) { Module = PP->getHeaderSearchInfo().lookupModule(ModuleName); if (!Module || !Module->getASTFile() || FileMgr->getFile(ModuleFileName) != Module->getASTFile()) { @@ -1631,10 +1716,10 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, case ASTReader::OutOfDate: case ASTReader::Missing: { - if (LoadFromPrebuiltModulePath) { - // We can't rebuild the module without a module map. Since ReadAST - // already produces diagnostics for these two cases, we simply - // error out here. + if (Source != ModuleCache) { + // We don't know the desired configuration for this module and don't + // necessarily even have a module map. Since ReadAST already produces + // diagnostics for these two cases, we simply error out here. ModuleBuildFailed = true; KnownModules[Path[0].first] = nullptr; return ModuleLoadResult(); @@ -1691,11 +1776,14 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, } case ASTReader::ConfigurationMismatch: - if (LoadFromPrebuiltModulePath) + if (Source == PrebuiltModulePath) + // FIXME: We shouldn't be setting HadFatalFailure below if we only + // produce a warning here! getDiagnostics().Report(SourceLocation(), diag::warn_module_config_mismatch) << ModuleFileName; // Fall through to error out. + LLVM_FALLTHROUGH; case ASTReader::VersionMismatch: case ASTReader::HadErrors: ModuleLoader::HadFatalFailure = true; @@ -1719,7 +1807,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, // If we never found the module, fail. if (!Module) return ModuleLoadResult(); - + // Verify that the rest of the module path actually corresponds to // a submodule. if (Path.size() > 1) { @@ -1792,20 +1880,10 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, } // Check whether this module is available. - clang::Module::Requirement Requirement; - clang::Module::UnresolvedHeaderDirective MissingHeader; - if (!Module->isAvailable(getLangOpts(), getTarget(), Requirement, - MissingHeader)) { - if (MissingHeader.FileNameLoc.isValid()) { - getDiagnostics().Report(MissingHeader.FileNameLoc, - diag::err_module_header_missing) - << MissingHeader.IsUmbrella << MissingHeader.FileName; - } else { - getDiagnostics().Report(ImportLoc, diag::err_module_unavailable) - << Module->getFullModuleName() - << Requirement.second << Requirement.first - << SourceRange(Path.front().second, Path.back().second); - } + if (Preprocessor::checkModuleIsAvailable(getLangOpts(), getTarget(), + getDiagnostics(), Module)) { + getDiagnostics().Report(ImportLoc, diag::note_module_import_here) + << SourceRange(Path.front().second, Path.back().second); LastModuleImportLoc = ImportLoc; LastModuleImportResult = ModuleLoadResult(); return ModuleLoadResult(); @@ -1826,6 +1904,59 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, return LastModuleImportResult; } +void CompilerInstance::loadModuleFromSource(SourceLocation ImportLoc, + StringRef ModuleName, + StringRef Source) { + // Avoid creating filenames with special characters. + SmallString<128> CleanModuleName(ModuleName); + for (auto &C : CleanModuleName) + if (!isAlphanumeric(C)) + C = '_'; + + // FIXME: Using a randomized filename here means that our intermediate .pcm + // output is nondeterministic (as .pcm files refer to each other by name). + // Can this affect the output in any way? + SmallString<128> ModuleFileName; + if (std::error_code EC = llvm::sys::fs::createTemporaryFile( + CleanModuleName, "pcm", ModuleFileName)) { + getDiagnostics().Report(ImportLoc, diag::err_fe_unable_to_open_output) + << ModuleFileName << EC.message(); + return; + } + std::string ModuleMapFileName = (CleanModuleName + ".map").str(); + + FrontendInputFile Input( + ModuleMapFileName, + InputKind(getLanguageFromOptions(*Invocation->getLangOpts()), + InputKind::ModuleMap, /*Preprocessed*/true)); + + std::string NullTerminatedSource(Source.str()); + + auto PreBuildStep = [&](CompilerInstance &Other) { + // Create a virtual file containing our desired source. + // FIXME: We shouldn't need to do this. + const FileEntry *ModuleMapFile = Other.getFileManager().getVirtualFile( + ModuleMapFileName, NullTerminatedSource.size(), 0); + Other.getSourceManager().overrideFileContents( + ModuleMapFile, + llvm::MemoryBuffer::getMemBuffer(NullTerminatedSource.c_str())); + + Other.BuiltModules = std::move(BuiltModules); + Other.DeleteBuiltModules = false; + }; + + auto PostBuildStep = [this](CompilerInstance &Other) { + BuiltModules = std::move(Other.BuiltModules); + }; + + // Build the module, inheriting any modules that we've built locally. + if (compileModuleImpl(*this, ImportLoc, ModuleName, Input, StringRef(), + ModuleFileName, PreBuildStep, PostBuildStep)) { + BuiltModules[ModuleName] = ModuleFileName.str(); + llvm::sys::RemoveFileOnSignal(ModuleFileName); + } +} + void CompilerInstance::makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility, SourceLocation ImportLoc) { diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp index 36f6b0a..0d0869c 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp @@ -81,7 +81,7 @@ using namespace llvm::opt; static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, DiagnosticsEngine &Diags) { unsigned DefaultOpt = 0; - if (IK == IK_OpenCL && !Args.hasArg(OPT_cl_opt_disable)) + if (IK.getLanguage() == InputKind::OpenCL && !Args.hasArg(OPT_cl_opt_disable)) DefaultOpt = 2; if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { @@ -330,6 +330,17 @@ static StringRef getCodeModel(ArgList &Args, DiagnosticsEngine &Diags) { return "default"; } +static StringRef getRelocModel(ArgList &Args, DiagnosticsEngine &Diags) { + if (Arg *A = Args.getLastArg(OPT_mrelocation_model)) { + StringRef Value = A->getValue(); + if (Value == "static" || Value == "pic" || Value == "ropi" || + Value == "rwpi" || Value == "ropi-rwpi" || Value == "dynamic-no-pic") + return Value; + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Value; + } + return "pic"; +} + /// \brief Create a new Regex instance out of the string value in \p RpassArg. /// It returns a pointer to the newly generated Regex instance. static std::shared_ptr<llvm::Regex> @@ -465,6 +476,10 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, OPT_fexperimental_new_pass_manager, OPT_fno_experimental_new_pass_manager, /* Default */ false); + Opts.DebugPassManager = + Args.hasFlag(OPT_fdebug_pass_manager, OPT_fno_debug_pass_manager, + /* Default */ false); + if (Arg *A = Args.getLastArg(OPT_fveclib)) { StringRef Name = A->getValue(); if (Name == "Accelerate") @@ -505,8 +520,10 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 0, Diags); Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info); Opts.EmitCodeView = Args.hasArg(OPT_gcodeview); + Opts.MacroDebugInfo = Args.hasArg(OPT_debug_info_macro); Opts.WholeProgramVTables = Args.hasArg(OPT_fwhole_program_vtables); Opts.LTOVisibilityPublicStd = Args.hasArg(OPT_flto_visibility_public_std); + Opts.EnableSplitDwarf = Args.hasArg(OPT_enable_split_dwarf); Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file); Opts.SplitDwarfInlining = !Args.hasArg(OPT_fno_split_dwarf_inlining); Opts.DebugTypeExtRefs = Args.hasArg(OPT_dwarf_ext_refs); @@ -521,6 +538,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.DisableLLVMPasses = Args.hasArg(OPT_disable_llvm_passes); Opts.DisableLifetimeMarkers = Args.hasArg(OPT_disable_lifetimemarkers); + Opts.DisableO0ImplyOptNone = Args.hasArg(OPT_disable_O0_optnone); Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone); Opts.ForbidGuardVariables = Args.hasArg(OPT_fforbid_guard_variables); Opts.UseRegisterSizedBitfieldAccess = Args.hasArg( @@ -544,6 +562,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.DisableIntegratedAS = Args.hasArg(OPT_fno_integrated_as); Opts.Autolink = !Args.hasArg(OPT_fno_autolink); Opts.SampleProfileFile = Args.getLastArgValue(OPT_fprofile_sample_use_EQ); + Opts.DebugInfoForProfiling = Args.hasFlag( + OPT_fdebug_info_for_profiling, OPT_fno_debug_info_for_profiling, false); setPGOInstrumentor(Opts, Args, Diags); Opts.InstrProfileOutput = @@ -553,6 +573,33 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, if (!Opts.ProfileInstrumentUsePath.empty()) setPGOUseInstrumentor(Opts, Opts.ProfileInstrumentUsePath); + if (Arg *A = Args.getLastArg(OPT_fclang_abi_compat_EQ)) { + Opts.setClangABICompat(CodeGenOptions::ClangABI::Latest); + + StringRef Ver = A->getValue(); + std::pair<StringRef, StringRef> VerParts = Ver.split('.'); + unsigned Major, Minor = 0; + + // Check the version number is valid: either 3.x (0 <= x <= 9) or + // y or y.0 (4 <= y <= current version). + if (!VerParts.first.startswith("0") && + !VerParts.first.getAsInteger(10, Major) && + 3 <= Major && Major <= CLANG_VERSION_MAJOR && + (Major == 3 ? VerParts.second.size() == 1 && + !VerParts.second.getAsInteger(10, Minor) + : VerParts.first.size() == Ver.size() || + VerParts.second == "0")) { + // Got a valid version number. + if (Major == 3 && Minor <= 8) + Opts.setClangABICompat(CodeGenOptions::ClangABI::Ver3_8); + else if (Major <= 4) + Opts.setClangABICompat(CodeGenOptions::ClangABI::Ver4); + } else if (Ver != "latest") { + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(); + } + } + Opts.CoverageMapping = Args.hasFlag(OPT_fcoverage_mapping, OPT_fno_coverage_mapping, false); Opts.DumpCoverageMapping = Args.hasArg(OPT_dump_coverage_mapping); @@ -570,7 +617,9 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.DiscardValueNames = Args.hasArg(OPT_discard_value_names); Opts.DisableTailCalls = Args.hasArg(OPT_mdisable_tail_calls); Opts.FloatABI = Args.getLastArgValue(OPT_mfloat_abi); - Opts.LessPreciseFPMAD = Args.hasArg(OPT_cl_mad_enable); + Opts.LessPreciseFPMAD = Args.hasArg(OPT_cl_mad_enable) || + Args.hasArg(OPT_cl_unsafe_math_optimizations) || + Args.hasArg(OPT_cl_fast_relaxed_math); Opts.LimitFloatPrecision = Args.getLastArgValue(OPT_mlimit_float_precision); Opts.NoInfsFPMath = (Args.hasArg(OPT_menable_no_infinities) || Args.hasArg(OPT_cl_finite_math_only) || @@ -580,7 +629,9 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Args.hasArg(OPT_cl_finite_math_only) || Args.hasArg(OPT_cl_fast_relaxed_math)); Opts.NoSignedZeros = (Args.hasArg(OPT_fno_signed_zeros) || - Args.hasArg(OPT_cl_no_signed_zeros)); + Args.hasArg(OPT_cl_no_signed_zeros) || + Args.hasArg(OPT_cl_unsafe_math_optimizations) || + Args.hasArg(OPT_cl_fast_relaxed_math)); Opts.FlushDenorm = Args.hasArg(OPT_cl_denorms_are_zero); Opts.CorrectlyRoundedDivSqrt = Args.hasArg(OPT_cl_fp32_correctly_rounded_divide_sqrt); @@ -608,7 +659,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Args.hasArg(OPT_cl_unsafe_math_optimizations) || Args.hasArg(OPT_cl_fast_relaxed_math); Opts.UnwindTables = Args.hasArg(OPT_munwind_tables); - Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic"); + Opts.RelocationModel = getRelocModel(Args, Diags); Opts.ThreadModel = Args.getLastArgValue(OPT_mthread_model, "posix"); if (Opts.ThreadModel != "posix" && Opts.ThreadModel != "single") Diags.Report(diag::err_drv_invalid_value) @@ -629,18 +680,25 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.NoUseJumpTables = Args.hasArg(OPT_fno_jump_tables); Opts.PrepareForLTO = Args.hasArg(OPT_flto, OPT_flto_EQ); - const Arg *A = Args.getLastArg(OPT_flto, OPT_flto_EQ); - Opts.EmitSummaryIndex = A && A->containsValue("thin"); + Opts.EmitSummaryIndex = false; + if (Arg *A = Args.getLastArg(OPT_flto_EQ)) { + StringRef S = A->getValue(); + if (S == "thin") + Opts.EmitSummaryIndex = true; + else if (S != "full") + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << S; + } + Opts.LTOUnit = Args.hasFlag(OPT_flto_unit, OPT_fno_lto_unit, false); if (Arg *A = Args.getLastArg(OPT_fthinlto_index_EQ)) { - if (IK != IK_LLVM_IR) + if (IK.getLanguage() != InputKind::LLVM_IR) Diags.Report(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) << "-x ir"; Opts.ThinLTOIndexFile = Args.getLastArgValue(OPT_fthinlto_index_EQ); } + Opts.ThinLinkBitcodeFile = Args.getLastArgValue(OPT_fthin_link_bitcode_EQ); Opts.MSVolatile = Args.hasArg(OPT_fms_volatile); - Opts.VectorizeBB = Args.hasArg(OPT_vectorize_slp_aggressive); Opts.VectorizeLoop = Args.hasArg(OPT_vectorize_loops); Opts.VectorizeSLP = Args.hasArg(OPT_vectorize_slp); @@ -709,21 +767,43 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, } } + Opts.PreserveVec3Type = Args.hasArg(OPT_fpreserve_vec3_type); Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions); Opts.XRayInstrumentFunctions = Args.hasArg(OPT_fxray_instrument); Opts.XRayInstructionThreshold = - getLastArgIntValue(Args, OPT_fxray_instruction_threshold_, 200, Diags); + getLastArgIntValue(Args, OPT_fxray_instruction_threshold_EQ, 200, Diags); Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); + Opts.CallFEntry = Args.hasArg(OPT_mfentry); Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info); - Opts.CompressDebugSections = Args.hasArg(OPT_compress_debug_sections); + + if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections, + OPT_compress_debug_sections_EQ)) { + if (A->getOption().getID() == OPT_compress_debug_sections) { + // TODO: be more clever about the compression type auto-detection + Opts.setCompressDebugSections(llvm::DebugCompressionType::GNU); + } else { + auto DCT = llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue()) + .Case("none", llvm::DebugCompressionType::None) + .Case("zlib", llvm::DebugCompressionType::Z) + .Case("zlib-gnu", llvm::DebugCompressionType::GNU) + .Default(llvm::DebugCompressionType::None); + Opts.setCompressDebugSections(DCT); + } + } + Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations); Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir); for (auto A : Args.filtered(OPT_mlink_bitcode_file, OPT_mlink_cuda_bitcode)) { - unsigned LinkFlags = llvm::Linker::Flags::None; - if (A->getOption().matches(OPT_mlink_cuda_bitcode)) - LinkFlags = llvm::Linker::Flags::LinkOnlyNeeded | - llvm::Linker::Flags::InternalizeLinkedSymbols; - Opts.LinkBitcodeFiles.push_back(std::make_pair(LinkFlags, A->getValue())); + CodeGenOptions::BitcodeFileToLink F; + F.Filename = A->getValue(); + if (A->getOption().matches(OPT_mlink_cuda_bitcode)) { + F.LinkFlags = llvm::Linker::Flags::LinkOnlyNeeded; + // When linking CUDA bitcode, propagate function attributes so that + // e.g. libdevice gets fast-math attrs if we're building with fast-math. + F.PropagateAttrs = true; + F.Internalize = true; + } + Opts.LinkBitcodeFiles.push_back(F); } Opts.SanitizeCoverageType = getLastArgIntValue(Args, OPT_fsanitize_coverage_type, 0, Diags); @@ -738,6 +818,9 @@ 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.SanitizeCoverageInline8bitCounters = + Args.hasArg(OPT_fsanitize_coverage_inline_8bit_counters); Opts.SanitizeMemoryTrackOrigins = getLastArgIntValue(Args, OPT_fsanitize_memory_track_origins_EQ, 0, Diags); Opts.SanitizeMemoryUseAfterDtor = @@ -749,6 +832,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.SanitizeAddressUseAfterScope = A->getOption().getID() == OPT_fsanitize_address_use_after_scope; } + Opts.SanitizeAddressGlobalsDeadStripping = + Args.hasArg(OPT_fsanitize_address_globals_dead_stripping); Opts.SSPBufferSize = getLastArgIntValue(Args, OPT_stack_protector_buffer_size, 8, Diags); Opts.StackRealignment = Args.hasArg(OPT_mstackrealign); @@ -801,18 +886,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, } } - if (Arg *A = Args.getLastArg(OPT_ffp_contract)) { - StringRef Val = A->getValue(); - if (Val == "fast") - Opts.setFPContractMode(CodeGenOptions::FPC_Fast); - else if (Val == "on") - Opts.setFPContractMode(CodeGenOptions::FPC_On); - else if (Val == "off") - Opts.setFPContractMode(CodeGenOptions::FPC_Off); - else - Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; - } - if (Arg *A = Args.getLastArg(OPT_fdenormal_fp_math_EQ)) { StringRef Val = A->getValue(); if (Val == "ieee") @@ -862,14 +935,24 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.DiagnosticsWithHotness = Args.hasArg(options::OPT_fdiagnostics_show_hotness); - if (Opts.DiagnosticsWithHotness && - Opts.getProfileUse() == CodeGenOptions::ProfileNone) - Diags.Report(diag::warn_drv_fdiagnostics_show_hotness_requires_pgo); + bool UsingSampleProfile = !Opts.SampleProfileFile.empty(); + bool UsingProfile = UsingSampleProfile || + (Opts.getProfileUse() != CodeGenOptions::ProfileNone); + + if (Opts.DiagnosticsWithHotness && !UsingProfile) + Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo) + << "-fdiagnostics-show-hotness"; + + Opts.DiagnosticsHotnessThreshold = getLastArgUInt64Value( + Args, options::OPT_fdiagnostics_hotness_threshold_EQ, 0); + if (Opts.DiagnosticsHotnessThreshold > 0 && !UsingProfile) + Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo) + << "-fdiagnostics-hotness-threshold="; // If the user requested to use a sample profile for PGO, then the // backend will need to track source location information so the profile // can be incorporated into the IR. - if (!Opts.SampleProfileFile.empty()) + if (UsingSampleProfile) NeedLocTracking = true; // If the user requested a flag that requires source locations available in @@ -1068,6 +1151,9 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.SpellCheckingLimit = getLastArgIntValue( Args, OPT_fspell_checking_limit, DiagnosticOptions::DefaultSpellCheckingLimit, Diags); + Opts.SnippetLineLimit = getLastArgIntValue( + Args, OPT_fcaret_diagnostics_max_lines, + DiagnosticOptions::DefaultSnippetLineLimit, Diags); Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop, DiagnosticOptions::DefaultTabStop, Diags); if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) { @@ -1123,6 +1209,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, case OPT_ast_list: Opts.ProgramAction = frontend::ASTDeclList; break; case OPT_ast_dump: + case OPT_ast_dump_all: case OPT_ast_dump_lookups: Opts.ProgramAction = frontend::ASTDump; break; case OPT_ast_print: @@ -1241,6 +1328,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.FixAndRecompile = Args.hasArg(OPT_fixit_recompile); Opts.FixToTemporaries = Args.hasArg(OPT_fixit_to_temp); Opts.ASTDumpDecls = Args.hasArg(OPT_ast_dump); + Opts.ASTDumpAll = Args.hasArg(OPT_ast_dump_all); Opts.ASTDumpFilter = Args.getLastArgValue(OPT_ast_dump_filter); Opts.ASTDumpLookups = Args.hasArg(OPT_ast_dump_lookups); Opts.UseGlobalModuleIndex = !Args.hasArg(OPT_fno_modules_global_index); @@ -1329,44 +1417,54 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, << "ARC migration" << "ObjC migration"; } - InputKind DashX = IK_None; + InputKind DashX(InputKind::Unknown); if (const Arg *A = Args.getLastArg(OPT_x)) { - DashX = llvm::StringSwitch<InputKind>(A->getValue()) - .Case("c", IK_C) - .Case("cl", IK_OpenCL) - .Case("cuda", IK_CUDA) - .Case("c++", IK_CXX) - .Case("c++-module", IK_CXX) - .Case("objective-c", IK_ObjC) - .Case("objective-c++", IK_ObjCXX) - .Case("cpp-output", IK_PreprocessedC) - .Case("assembler-with-cpp", IK_Asm) - .Case("c++-cpp-output", IK_PreprocessedCXX) - .Case("c++-module-cpp-output", IK_PreprocessedCXX) - .Case("cuda-cpp-output", IK_PreprocessedCuda) - .Case("objective-c-cpp-output", IK_PreprocessedObjC) - .Case("objc-cpp-output", IK_PreprocessedObjC) - .Case("objective-c++-cpp-output", IK_PreprocessedObjCXX) - .Case("objc++-cpp-output", IK_PreprocessedObjCXX) - .Case("c-header", IK_C) - .Case("cl-header", IK_OpenCL) - .Case("objective-c-header", IK_ObjC) - .Case("c++-header", IK_CXX) - .Case("objective-c++-header", IK_ObjCXX) - .Cases("ast", "pcm", IK_AST) - .Case("ir", IK_LLVM_IR) - .Case("renderscript", IK_RenderScript) - .Default(IK_None); - if (DashX == IK_None) + StringRef XValue = A->getValue(); + + // Parse suffixes: '<lang>(-header|[-module-map][-cpp-output])'. + // FIXME: Supporting '<lang>-header-cpp-output' would be useful. + bool Preprocessed = XValue.consume_back("-cpp-output"); + bool ModuleMap = XValue.consume_back("-module-map"); + IsHeaderFile = + !Preprocessed && !ModuleMap && XValue.consume_back("-header"); + + // Principal languages. + DashX = llvm::StringSwitch<InputKind>(XValue) + .Case("c", InputKind::C) + .Case("cl", InputKind::OpenCL) + .Case("cuda", InputKind::CUDA) + .Case("c++", InputKind::CXX) + .Case("objective-c", InputKind::ObjC) + .Case("objective-c++", InputKind::ObjCXX) + .Case("renderscript", InputKind::RenderScript) + .Default(InputKind::Unknown); + + // "objc[++]-cpp-output" is an acceptable synonym for + // "objective-c[++]-cpp-output". + if (DashX.isUnknown() && Preprocessed && !IsHeaderFile && !ModuleMap) + DashX = llvm::StringSwitch<InputKind>(XValue) + .Case("objc", InputKind::ObjC) + .Case("objc++", InputKind::ObjCXX) + .Default(InputKind::Unknown); + + // Some special cases cannot be combined with suffixes. + if (DashX.isUnknown() && !Preprocessed && !ModuleMap && !IsHeaderFile) + DashX = llvm::StringSwitch<InputKind>(XValue) + .Case("cpp-output", InputKind(InputKind::C).getPreprocessed()) + .Case("assembler-with-cpp", InputKind::Asm) + .Cases("ast", "pcm", + InputKind(InputKind::Unknown, InputKind::Precompiled)) + .Case("ir", InputKind::LLVM_IR) + .Default(InputKind::Unknown); + + if (DashX.isUnknown()) Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(); - IsHeaderFile = llvm::StringSwitch<bool>(A->getValue()) - .Case("c-header", true) - .Case("cl-header", true) - .Case("objective-c-header", true) - .Case("c++-header", true) - .Case("objective-c++-header", true) - .Default(false); + + if (Preprocessed) + DashX = DashX.getPreprocessed(); + if (ModuleMap) + DashX = DashX.withFormat(InputKind::ModuleMap); } // '-' is the default input if none is given. @@ -1376,13 +1474,22 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Inputs.push_back("-"); for (unsigned i = 0, e = Inputs.size(); i != e; ++i) { InputKind IK = DashX; - if (IK == IK_None) { + if (IK.isUnknown()) { IK = FrontendOptions::getInputKindForExtension( StringRef(Inputs[i]).rsplit('.').second); + // FIXME: Warn on this? + if (IK.isUnknown()) + IK = InputKind::C; // FIXME: Remove this hack. if (i == 0) DashX = IK; } + + // The -emit-module action implicitly takes a module map. + if (Opts.ProgramAction == frontend::GenerateModule && + IK.getFormat() == InputKind::Source) + IK = IK.withFormat(InputKind::ModuleMap); + Opts.Inputs.emplace_back(std::move(Inputs[i]), IK); } @@ -1407,7 +1514,8 @@ std::string CompilerInvocation::GetResourcesPath(const char *Argv0, return P.str(); } -static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { +static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, + const std::string &WorkingDir) { using namespace options; Opts.Sysroot = Args.getLastArgValue(OPT_isysroot, "/"); Opts.Verbose = Args.hasArg(OPT_v); @@ -1417,11 +1525,23 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { if (const Arg *A = Args.getLastArg(OPT_stdlib_EQ)) Opts.UseLibcxx = (strcmp(A->getValue(), "libc++") == 0); Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir); - Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodules_cache_path); + + // Canonicalize -fmodules-cache-path before storing it. + SmallString<128> P(Args.getLastArgValue(OPT_fmodules_cache_path)); + if (!(P.empty() || llvm::sys::path::is_absolute(P))) { + if (WorkingDir.empty()) + llvm::sys::fs::make_absolute(P); + else + llvm::sys::fs::make_absolute(WorkingDir, P); + } + llvm::sys::path::remove_dots(P); + Opts.ModuleCachePath = P.str(); + Opts.ModuleUserBuildPath = Args.getLastArgValue(OPT_fmodules_user_build_path); for (const Arg *A : Args.filtered(OPT_fprebuilt_module_path)) Opts.AddPrebuiltModulePath(A->getValue()); Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash); + Opts.ModulesHashContent = Args.hasArg(OPT_fmodules_hash_content); Opts.ModulesValidateDiagnosticOptions = !Args.hasArg(OPT_fmodules_disable_diagnostic_validation); Opts.ImplicitModuleMaps = Args.hasArg(OPT_fimplicit_module_maps); @@ -1495,6 +1615,9 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { !A->getOption().matches(OPT_iwithsysroot)); for (const Arg *A : Args.filtered(OPT_iframework)) Opts.AddPath(A->getValue(), frontend::System, true, true); + for (const Arg *A : Args.filtered(OPT_iframeworkwithsysroot)) + Opts.AddPath(A->getValue(), frontend::System, /*IsFramework=*/true, + /*IgnoreSysRoot=*/false); // Add the paths for the various language specific isystem flags. for (const Arg *A : Args.filtered(OPT_c_isystem)) @@ -1525,13 +1648,6 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { Opts.AddVFSOverlayFile(A->getValue()); } -static bool isOpenCL(LangStandard::Kind LangStd) { - return LangStd == LangStandard::lang_opencl || - LangStd == LangStandard::lang_opencl11 || - LangStd == LangStandard::lang_opencl12 || - LangStd == LangStandard::lang_opencl20; -} - void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, const llvm::Triple &T, PreprocessorOptions &PPOpts, @@ -1539,49 +1655,48 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, // Set some properties which depend solely on the input kind; it would be nice // to move these to the language standard, and have the driver resolve the // input kind + language standard. - if (IK == IK_Asm) { + // + // FIXME: Perhaps a better model would be for a single source file to have + // multiple language standards (C / C++ std, ObjC std, OpenCL std, OpenMP std) + // simultaneously active? + if (IK.getLanguage() == InputKind::Asm) { Opts.AsmPreprocessor = 1; - } else if (IK == IK_ObjC || - IK == IK_ObjCXX || - IK == IK_PreprocessedObjC || - IK == IK_PreprocessedObjCXX) { + } else if (IK.isObjectiveC()) { Opts.ObjC1 = Opts.ObjC2 = 1; } if (LangStd == LangStandard::lang_unspecified) { // Based on the base language, pick one. - switch (IK) { - case IK_None: - case IK_AST: - case IK_LLVM_IR: + switch (IK.getLanguage()) { + case InputKind::Unknown: + case InputKind::LLVM_IR: llvm_unreachable("Invalid input kind!"); - case IK_OpenCL: - LangStd = LangStandard::lang_opencl; + case InputKind::OpenCL: + LangStd = LangStandard::lang_opencl10; break; - case IK_CUDA: - case IK_PreprocessedCuda: + case InputKind::CUDA: LangStd = LangStandard::lang_cuda; break; - case IK_Asm: - case IK_C: - case IK_PreprocessedC: + case InputKind::Asm: + case InputKind::C: // The PS4 uses C99 as the default C standard. if (T.isPS4()) LangStd = LangStandard::lang_gnu99; else LangStd = LangStandard::lang_gnu11; break; - case IK_ObjC: - case IK_PreprocessedObjC: + case InputKind::ObjC: LangStd = LangStandard::lang_gnu11; break; - case IK_CXX: - case IK_PreprocessedCXX: - case IK_ObjCXX: - case IK_PreprocessedObjCXX: - LangStd = LangStandard::lang_gnucxx98; + case InputKind::CXX: + case InputKind::ObjCXX: + // The PS4 uses C++11 as the default C++ standard. + if (T.isPS4()) + LangStd = LangStandard::lang_gnucxx11; + else + LangStd = LangStandard::lang_gnucxx98; break; - case IK_RenderScript: + case InputKind::RenderScript: LangStd = LangStandard::lang_c99; break; } @@ -1595,15 +1710,16 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, Opts.CPlusPlus11 = Std.isCPlusPlus11(); Opts.CPlusPlus14 = Std.isCPlusPlus14(); Opts.CPlusPlus1z = Std.isCPlusPlus1z(); + Opts.CPlusPlus2a = Std.isCPlusPlus2a(); Opts.Digraphs = Std.hasDigraphs(); Opts.GNUMode = Std.isGNUMode(); - Opts.GNUInline = Std.isC89(); + Opts.GNUInline = !Opts.C99 && !Opts.CPlusPlus; Opts.HexFloats = Std.hasHexFloats(); Opts.ImplicitInt = Std.hasImplicitInt(); // Set OpenCL Version. - Opts.OpenCL = isOpenCL(LangStd) || IK == IK_OpenCL; - if (LangStd == LangStandard::lang_opencl) + Opts.OpenCL = Std.isOpenCL(); + if (LangStd == LangStandard::lang_opencl10) Opts.OpenCLVersion = 100; else if (LangStd == LangStandard::lang_opencl11) Opts.OpenCLVersion = 110; @@ -1616,9 +1732,8 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, if (Opts.OpenCL) { Opts.AltiVec = 0; Opts.ZVector = 0; - Opts.CXXOperatorNames = 1; Opts.LaxVectorConversions = 0; - Opts.DefaultFPContract = 1; + Opts.setDefaultFPContractMode(LangOptions::FPC_On); Opts.NativeHalfType = 1; Opts.NativeHalfArgsAndReturns = 1; // Include default header file for OpenCL. @@ -1627,10 +1742,12 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, } } - Opts.CUDA = IK == IK_CUDA || IK == IK_PreprocessedCuda || - LangStd == LangStandard::lang_cuda; + Opts.CUDA = IK.getLanguage() == InputKind::CUDA; + if (Opts.CUDA) + // Set default FP_CONTRACT to FAST. + Opts.setDefaultFPContractMode(LangOptions::FPC_Fast); - Opts.RenderScript = IK == IK_RenderScript; + Opts.RenderScript = IK.getLanguage() == InputKind::RenderScript; if (Opts.RenderScript) { Opts.NativeHalfType = 1; Opts.NativeHalfArgsAndReturns = 1; @@ -1671,6 +1788,70 @@ static Visibility parseVisibility(Arg *arg, ArgList &args, return DefaultVisibility; } +/// Check if input file kind and language standard are compatible. +static bool IsInputCompatibleWithStandard(InputKind IK, + const LangStandard &S) { + switch (IK.getLanguage()) { + case InputKind::Unknown: + case InputKind::LLVM_IR: + llvm_unreachable("should not parse language flags for this input"); + + case InputKind::C: + case InputKind::ObjC: + case InputKind::RenderScript: + return S.getLanguage() == InputKind::C; + + case InputKind::OpenCL: + return S.getLanguage() == InputKind::OpenCL; + + case InputKind::CXX: + case InputKind::ObjCXX: + return S.getLanguage() == InputKind::CXX; + + case InputKind::CUDA: + // FIXME: What -std= values should be permitted for CUDA compilations? + return S.getLanguage() == InputKind::CUDA || + S.getLanguage() == InputKind::CXX; + + case InputKind::Asm: + // Accept (and ignore) all -std= values. + // FIXME: The -std= value is not ignored; it affects the tokenization + // and preprocessing rules if we're preprocessing this asm input. + return true; + } + + llvm_unreachable("unexpected input language"); +} + +/// Get language name for given input kind. +static const StringRef GetInputKindName(InputKind IK) { + switch (IK.getLanguage()) { + case InputKind::C: + return "C"; + case InputKind::ObjC: + return "Objective-C"; + case InputKind::CXX: + return "C++"; + case InputKind::ObjCXX: + return "Objective-C++"; + case InputKind::OpenCL: + return "OpenCL"; + case InputKind::CUDA: + return "CUDA"; + case InputKind::RenderScript: + return "RenderScript"; + + case InputKind::Asm: + return "Asm"; + case InputKind::LLVM_IR: + return "LLVM IR"; + + case InputKind::Unknown: + break; + } + llvm_unreachable("unknown input language"); +} + static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, const TargetOptions &TargetOpts, PreprocessorOptions &PPOpts, @@ -1679,49 +1860,45 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, LangStandard::Kind LangStd = LangStandard::lang_unspecified; if (const Arg *A = Args.getLastArg(OPT_std_EQ)) { LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue()) -#define LANGSTANDARD(id, name, desc, features) \ +#define LANGSTANDARD(id, name, lang, desc, features) \ .Case(name, LangStandard::lang_##id) #define LANGSTANDARD_ALIAS(id, alias) \ .Case(alias, LangStandard::lang_##id) #include "clang/Frontend/LangStandards.def" .Default(LangStandard::lang_unspecified); - if (LangStd == LangStandard::lang_unspecified) + if (LangStd == LangStandard::lang_unspecified) { Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(); - else { + // Report supported standards with short description. + for (unsigned KindValue = 0; + KindValue != LangStandard::lang_unspecified; + ++KindValue) { + const LangStandard &Std = LangStandard::getLangStandardForKind( + static_cast<LangStandard::Kind>(KindValue)); + if (IsInputCompatibleWithStandard(IK, Std)) { + auto Diag = Diags.Report(diag::note_drv_use_standard); + Diag << Std.getName() << Std.getDescription(); + unsigned NumAliases = 0; +#define LANGSTANDARD(id, name, lang, desc, features) +#define LANGSTANDARD_ALIAS(id, alias) \ + if (KindValue == LangStandard::lang_##id) ++NumAliases; +#define LANGSTANDARD_ALIAS_DEPR(id, alias) +#include "clang/Frontend/LangStandards.def" + Diag << NumAliases; +#define LANGSTANDARD(id, name, lang, desc, features) +#define LANGSTANDARD_ALIAS(id, alias) \ + if (KindValue == LangStandard::lang_##id) Diag << alias; +#define LANGSTANDARD_ALIAS_DEPR(id, alias) +#include "clang/Frontend/LangStandards.def" + } + } + } else { // Valid standard, check to make sure language and standard are // compatible. const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); - switch (IK) { - case IK_C: - case IK_ObjC: - case IK_PreprocessedC: - case IK_PreprocessedObjC: - if (!(Std.isC89() || Std.isC99())) - Diags.Report(diag::err_drv_argument_not_allowed_with) - << A->getAsString(Args) << "C/ObjC"; - break; - case IK_CXX: - case IK_ObjCXX: - case IK_PreprocessedCXX: - case IK_PreprocessedObjCXX: - if (!Std.isCPlusPlus()) - Diags.Report(diag::err_drv_argument_not_allowed_with) - << A->getAsString(Args) << "C++/ObjC++"; - break; - case IK_OpenCL: - if (!isOpenCL(LangStd)) - Diags.Report(diag::err_drv_argument_not_allowed_with) - << A->getAsString(Args) << "OpenCL"; - break; - case IK_CUDA: - case IK_PreprocessedCuda: - if (!Std.isCPlusPlus()) - Diags.Report(diag::err_drv_argument_not_allowed_with) - << A->getAsString(Args) << "CUDA"; - break; - default: - break; + if (!IsInputCompatibleWithStandard(IK, Std)) { + Diags.Report(diag::err_drv_argument_not_allowed_with) + << A->getAsString(Args) << GetInputKindName(IK); } } } @@ -1730,16 +1907,16 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // Override the -std option in this case. if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) { LangStandard::Kind OpenCLLangStd - = llvm::StringSwitch<LangStandard::Kind>(A->getValue()) - .Cases("cl", "CL", LangStandard::lang_opencl) - .Cases("cl1.1", "CL1.1", LangStandard::lang_opencl11) - .Cases("cl1.2", "CL1.2", LangStandard::lang_opencl12) - .Cases("cl2.0", "CL2.0", LangStandard::lang_opencl20) - .Default(LangStandard::lang_unspecified); + = llvm::StringSwitch<LangStandard::Kind>(A->getValue()) + .Cases("cl", "CL", LangStandard::lang_opencl10) + .Cases("cl1.1", "CL1.1", LangStandard::lang_opencl11) + .Cases("cl1.2", "CL1.2", LangStandard::lang_opencl12) + .Cases("cl2.0", "CL2.0", LangStandard::lang_opencl20) + .Default(LangStandard::lang_unspecified); if (OpenCLLangStd == LangStandard::lang_unspecified) { Diags.Report(diag::err_drv_invalid_value) - << A->getAsString(Args) << A->getValue(); + << A->getAsString(Args) << A->getValue(); } else LangStd = OpenCLLangStd; @@ -1840,8 +2017,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Args.hasArg(OPT_fgnu89_inline)) { if (Opts.CPlusPlus) - Diags.Report(diag::err_drv_argument_not_allowed_with) << "-fgnu89-inline" - << "C++/ObjC++"; + Diags.Report(diag::err_drv_argument_not_allowed_with) + << "-fgnu89-inline" << GetInputKindName(IK); else Opts.GNUInline = 1; } @@ -1858,9 +2035,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Args.hasArg(OPT_fno_constant_cfstrings)) Opts.NoConstantCFStrings = 1; - if (Args.hasArg(OPT_faltivec)) - Opts.AltiVec = 1; - if (Args.hasArg(OPT_fzvector)) Opts.ZVector = 1; @@ -1947,6 +2121,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Args.hasArg(OPT_fmodules_decluse) || Opts.ModulesStrictDeclUse; Opts.ModulesLocalVisibility = Args.hasArg(OPT_fmodules_local_submodule_visibility) || Opts.ModulesTS; + Opts.ModulesCodegen = Args.hasArg(OPT_fmodules_codegen); + Opts.ModulesDebugInfo = Args.hasArg(OPT_fmodules_debuginfo); Opts.ModulesSearchAll = Opts.Modules && !Args.hasArg(OPT_fno_modules_search_all) && Args.hasArg(OPT_fmodules_search_all); @@ -1967,6 +2143,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.AlignedAllocation = Args.hasFlag(OPT_faligned_allocation, OPT_fno_aligned_allocation, Opts.AlignedAllocation); + Opts.AlignedAllocationUnavailable = + Opts.AlignedAllocation && Args.hasArg(OPT_aligned_alloc_unavailable); Opts.NewAlignOverride = getLastArgIntValue(Args, OPT_fnew_alignment_EQ, 0, Diags); if (Opts.NewAlignOverride && !llvm::isPowerOf2_32(Opts.NewAlignOverride)) { @@ -2045,12 +2223,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Args.hasFlag(OPT_fdeclspec, OPT_fno_declspec, (Opts.MicrosoftExt || Opts.Borland || Opts.CUDA)); - // For now, we only support local submodule visibility in C++ (because we - // heavily depend on the ODR for merging redefinitions). - if (Opts.ModulesLocalVisibility && !Opts.CPlusPlus) - Diags.Report(diag::err_drv_argument_not_allowed_with) - << "-fmodules-local-submodule-visibility" << "C"; - if (Arg *A = Args.getLastArg(OPT_faddress_space_map_mangling_EQ)) { switch (llvm::StringSwitch<unsigned>(A->getValue()) .Case("target", LangOptions::ASMM_Target) @@ -2108,8 +2280,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, llvm::Triple T(TargetOpts.Triple); llvm::Triple::ArchType Arch = T.getArch(); bool emitError = (DefaultCC == LangOptions::DCC_FastCall || - DefaultCC == LangOptions::DCC_StdCall) && - Arch != llvm::Triple::x86; + DefaultCC == LangOptions::DCC_StdCall) && + Arch != llvm::Triple::x86; emitError |= DefaultCC == LangOptions::DCC_VectorCall && !(Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64); if (emitError) @@ -2214,6 +2386,18 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Args.hasArg(OPT_cl_unsafe_math_optimizations) || Args.hasArg(OPT_cl_fast_relaxed_math); + if (Arg *A = Args.getLastArg(OPT_ffp_contract)) { + StringRef Val = A->getValue(); + if (Val == "fast") + Opts.setDefaultFPContractMode(LangOptions::FPC_Fast); + else if (Val == "on") + Opts.setDefaultFPContractMode(LangOptions::FPC_On); + else if (Val == "off") + Opts.setDefaultFPContractMode(LangOptions::FPC_Off); + else + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; + } + Opts.RetainCommentsFromSystemHeaders = Args.hasArg(OPT_fretain_comments_from_system_headers); @@ -2236,11 +2420,66 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.SanitizeAddressFieldPadding = getLastArgIntValue(Args, OPT_fsanitize_address_field_padding, 0, Diags); Opts.SanitizerBlacklistFiles = Args.getAllArgValues(OPT_fsanitize_blacklist); + + // -fxray-instrument + Opts.XRayInstrument = + Args.hasFlag(OPT_fxray_instrument, OPT_fnoxray_instrument, false); + + // -fxray-{always,never}-instrument= filenames. + Opts.XRayAlwaysInstrumentFiles = + Args.getAllArgValues(OPT_fxray_always_instrument); + Opts.XRayNeverInstrumentFiles = + Args.getAllArgValues(OPT_fxray_never_instrument); + + // -fallow-editor-placeholders + Opts.AllowEditorPlaceholders = Args.hasArg(OPT_fallow_editor_placeholders); +} + +static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { + switch (Action) { + case frontend::ASTDeclList: + case frontend::ASTDump: + case frontend::ASTPrint: + case frontend::ASTView: + case frontend::EmitAssembly: + case frontend::EmitBC: + case frontend::EmitHTML: + case frontend::EmitLLVM: + case frontend::EmitLLVMOnly: + case frontend::EmitCodeGenOnly: + case frontend::EmitObj: + case frontend::FixIt: + case frontend::GenerateModule: + case frontend::GenerateModuleInterface: + case frontend::GeneratePCH: + case frontend::GeneratePTH: + case frontend::ParseSyntaxOnly: + case frontend::ModuleFileInfo: + case frontend::VerifyPCH: + case frontend::PluginAction: + case frontend::PrintDeclContext: + case frontend::RewriteObjC: + case frontend::RewriteTest: + case frontend::RunAnalysis: + case frontend::MigrateSource: + return false; + + case frontend::DumpRawTokens: + case frontend::DumpTokens: + case frontend::InitOnly: + case frontend::PrintPreamble: + case frontend::PrintPreprocessedInput: + case frontend::RewriteMacros: + case frontend::RunPreprocessorOnly: + return true; + } + llvm_unreachable("invalid frontend action"); } static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, FileManager &FileMgr, - DiagnosticsEngine &Diags) { + DiagnosticsEngine &Diags, + frontend::ActionKind Action) { using namespace options; Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch); Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth); @@ -2251,6 +2490,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Opts.UsePredefines = !Args.hasArg(OPT_undef); Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record); Opts.DisablePCHValidation = Args.hasArg(OPT_fno_validate_pch); + Opts.AllowPCHWithCompilerErrors = Args.hasArg(OPT_fallow_pch_with_errors); Opts.DumpDeserializedPCHDecls = Args.hasArg(OPT_dump_deserialized_pch_decls); for (const Arg *A : Args.filtered(OPT_error_on_deserialized_pch_decl)) @@ -2312,6 +2552,12 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, else Opts.ObjCXXARCStandardLibrary = (ObjCXXARCStandardLibraryKind)Library; } + + // Always avoid lexing editor placeholders when we're just running the + // preprocessor as we never want to emit the + // "editor placeholder in source file" error in PP only mode. + if (isStrictlyPreprocessorAction(Action)) + Opts.LexEditorPlaceholders = false; } static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, @@ -2319,45 +2565,10 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, frontend::ActionKind Action) { using namespace options; - switch (Action) { - case frontend::ASTDeclList: - case frontend::ASTDump: - case frontend::ASTPrint: - case frontend::ASTView: - case frontend::EmitAssembly: - case frontend::EmitBC: - case frontend::EmitHTML: - case frontend::EmitLLVM: - case frontend::EmitLLVMOnly: - case frontend::EmitCodeGenOnly: - case frontend::EmitObj: - case frontend::FixIt: - case frontend::GenerateModule: - case frontend::GenerateModuleInterface: - case frontend::GeneratePCH: - case frontend::GeneratePTH: - case frontend::ParseSyntaxOnly: - case frontend::ModuleFileInfo: - case frontend::VerifyPCH: - case frontend::PluginAction: - case frontend::PrintDeclContext: - case frontend::RewriteObjC: - case frontend::RewriteTest: - case frontend::RunAnalysis: - case frontend::MigrateSource: - Opts.ShowCPP = 0; - break; - - case frontend::DumpRawTokens: - case frontend::DumpTokens: - case frontend::InitOnly: - case frontend::PrintPreamble: - case frontend::PrintPreprocessedInput: - case frontend::RewriteMacros: - case frontend::RunPreprocessorOnly: + if (isStrictlyPreprocessorAction(Action)) Opts.ShowCPP = !Args.hasArg(OPT_dM); - break; - } + else + Opts.ShowCPP = 0; Opts.ShowComments = Args.hasArg(OPT_C); Opts.ShowLineMarkers = !Args.hasArg(OPT_P); @@ -2365,6 +2576,7 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD); Opts.ShowIncludeDirectives = Args.hasArg(OPT_dI); Opts.RewriteIncludes = Args.hasArg(OPT_frewrite_includes); + Opts.RewriteImports = Args.hasArg(OPT_frewrite_imports); Opts.UseLineDirectives = Args.hasArg(OPT_fuse_line_directives); } @@ -2384,7 +2596,7 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args, Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Value; else - Opts.EABIVersion = Value; + Opts.EABIVersion = EABIVersion; } Opts.CPU = Args.getLastArgValue(OPT_target_cpu); Opts.FPMath = Args.getLastArgValue(OPT_mfpmath); @@ -2405,7 +2617,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, bool Success = true; // Parse the arguments. - std::unique_ptr<OptTable> Opts(createDriverOptTable()); + std::unique_ptr<OptTable> Opts = createDriverOptTable(); const unsigned IncludedFlagsBitmask = options::CC1Option; unsigned MissingArgIndex, MissingArgCount; InputArgList Args = @@ -2440,8 +2652,10 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, ParseTargetArgs(Res.getTargetOpts(), Args, Diags); Success &= ParseCodeGenArgs(Res.getCodeGenOpts(), Args, DashX, Diags, Res.getTargetOpts()); - ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args); - if (DashX == IK_AST || DashX == IK_LLVM_IR) { + ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args, + Res.getFileSystemOpts().WorkingDir); + if (DashX.getFormat() == InputKind::Precompiled || + DashX.getLanguage() == InputKind::LLVM_IR) { // ObjCAAutoRefCount and Sanitize LangOpts are used to setup the // PassManager in BackendUtil.cpp. They need to be initializd no matter // what the input type is. @@ -2455,8 +2669,9 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, Diags, LangOpts.Sanitize); } else { // Other LangOpts are only initialzed when the input is not AST or LLVM IR. + // FIXME: Should we really be calling this for an InputKind::Asm input? ParseLangArgs(LangOpts, Args, DashX, Res.getTargetOpts(), - Res.getPreprocessorOpts(), Diags); + Res.getPreprocessorOpts(), Diags); if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC) LangOpts.ObjCExceptions = 1; } @@ -2466,12 +2681,12 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, // triple used for host compilation. if (LangOpts.CUDAIsDevice) Res.getTargetOpts().HostTriple = Res.getFrontendOpts().AuxTriple; - - // Set default FP_CONTRACT to FAST. - if (!Args.hasArg(OPT_ffp_contract)) - Res.getCodeGenOpts().setFPContractMode(CodeGenOptions::FPC_Fast); } + // Set the triple of the host for OpenMP device compile. + if (LangOpts.OpenMPIsDevice) + Res.getTargetOpts().HostTriple = Res.getFrontendOpts().AuxTriple; + // FIXME: Override value name discarding when asan or msan is used because the // backend passes depend on the name of the alloca in order to print out // names. @@ -2484,7 +2699,8 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, // ParsePreprocessorArgs and remove the FileManager // parameters from the function and the "FileManager.h" #include. FileManager FileMgr(Res.getFileSystemOpts()); - ParsePreprocessorArgs(Res.getPreprocessorOpts(), Args, FileMgr, Diags); + ParsePreprocessorArgs(Res.getPreprocessorOpts(), Args, FileMgr, Diags, + Res.getFrontendOpts().ProgramAction); ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), Args, Res.getFrontendOpts().ProgramAction); @@ -2569,28 +2785,12 @@ std::string CompilerInvocation::getModuleHash() const { code = ext->hashExtension(code); } - // Darwin-specific hack: if we have a sysroot, use the contents and - // modification time of - // $sysroot/System/Library/CoreServices/SystemVersion.plist - // as part of the module hash. - if (!hsOpts.Sysroot.empty()) { - SmallString<128> systemVersionFile; - systemVersionFile += hsOpts.Sysroot; - llvm::sys::path::append(systemVersionFile, "System"); - llvm::sys::path::append(systemVersionFile, "Library"); - llvm::sys::path::append(systemVersionFile, "CoreServices"); - llvm::sys::path::append(systemVersionFile, "SystemVersion.plist"); - - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer = - llvm::MemoryBuffer::getFile(systemVersionFile); - if (buffer) { - code = hash_combine(code, buffer.get()->getBuffer()); - - struct stat statBuf; - if (stat(systemVersionFile.c_str(), &statBuf) == 0) - code = hash_combine(code, statBuf.st_mtime); - } - } + // Extend the signature with the enabled sanitizers, if at least one is + // enabled. Sanitizers which cannot affect AST generation aren't hashed. + SanitizerSet SanHash = LangOpts->Sanitize; + SanHash.clear(getPPTransparentSanitizers()); + if (!SanHash.empty()) + code = hash_combine(code, SanHash.Mask); return llvm::APInt(64, code).toString(36, /*Signed=*/false); } @@ -2643,15 +2843,22 @@ void BuryPointer(const void *Ptr) { IntrusiveRefCntPtr<vfs::FileSystem> createVFSFromCompilerInvocation(const CompilerInvocation &CI, DiagnosticsEngine &Diags) { + return createVFSFromCompilerInvocation(CI, Diags, vfs::getRealFileSystem()); +} + +IntrusiveRefCntPtr<vfs::FileSystem> +createVFSFromCompilerInvocation(const CompilerInvocation &CI, + DiagnosticsEngine &Diags, + IntrusiveRefCntPtr<vfs::FileSystem> BaseFS) { if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty()) - return vfs::getRealFileSystem(); + return BaseFS; - IntrusiveRefCntPtr<vfs::OverlayFileSystem> - Overlay(new vfs::OverlayFileSystem(vfs::getRealFileSystem())); + IntrusiveRefCntPtr<vfs::OverlayFileSystem> Overlay( + new vfs::OverlayFileSystem(BaseFS)); // earlier vfs files are on the bottom for (const std::string &File : CI.getHeaderSearchOpts().VFSOverlayFiles) { llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer = - llvm::MemoryBuffer::getFile(File); + BaseFS->getBufferForFile(File); if (!Buffer) { Diags.Report(diag::err_missing_vfs_overlay_file) << File; return IntrusiveRefCntPtr<vfs::FileSystem>(); diff --git a/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp index 1626906..c3ce7ce 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -31,8 +31,8 @@ using namespace llvm::opt; /// \return A CompilerInvocation, or 0 if none was built for the given /// argument vector. std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine( - ArrayRef<const char *> ArgList, - IntrusiveRefCntPtr<DiagnosticsEngine> Diags) { + ArrayRef<const char *> ArgList, IntrusiveRefCntPtr<DiagnosticsEngine> Diags, + IntrusiveRefCntPtr<vfs::FileSystem> VFS) { if (!Diags.get()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. @@ -46,12 +46,14 @@ std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine( // FIXME: We shouldn't have to pass in the path info. driver::Driver TheDriver(Args[0], llvm::sys::getDefaultTargetTriple(), - *Diags); + *Diags, VFS); // Don't check that inputs exist, they may have been remapped. TheDriver.setCheckInputsExist(false); std::unique_ptr<driver::Compilation> C(TheDriver.BuildCompilation(Args)); + if (!C) + return nullptr; // Just print the cc1 options if -### was present. if (C->getArgs().hasArg(driver::options::OPT__HASH_HASH_HASH)) { diff --git a/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp b/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp index bd14c53..561eb9c 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp @@ -55,8 +55,8 @@ struct DepCollectorPPCallbacks : public PPCallbacks { llvm::sys::path::remove_leading_dotslash(FE->getName()); DepCollector.maybeAddDependency(Filename, /*FromModule*/false, - FileType != SrcMgr::C_User, - /*IsModuleFile*/false, /*IsMissing*/false); + isSystem(FileType), + /*IsModuleFile*/false, /*IsMissing*/false); } void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, @@ -265,7 +265,7 @@ bool DFGImpl::FileMatchesDepCriteria(const char *Filename, if (IncludeSystemHeaders) return true; - return FileType == SrcMgr::C_User; + return !isSystem(FileType); } void DFGImpl::FileChanged(SourceLocation Loc, diff --git a/contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp b/contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp index 177feac..e326384 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp @@ -76,20 +76,19 @@ static void mergeFixits(ArrayRef<FixItHint> FixItHints, } } -void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, +void DiagnosticRenderer::emitDiagnostic(FullSourceLoc Loc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> FixItHints, - const SourceManager *SM, DiagOrStoredDiag D) { - assert(SM || Loc.isInvalid()); + assert(Loc.hasManager() || Loc.isInvalid()); beginDiagnostic(D, Level); if (!Loc.isValid()) // If we have no source location, just emit the diagnostic message. - emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, SM, D); + emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, D); else { // Get the ranges into a local array we can hack on. SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(), @@ -97,7 +96,7 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, SmallVector<FixItHint, 8> MergedFixits; if (!FixItHints.empty()) { - mergeFixits(FixItHints, *SM, LangOpts, MergedFixits); + mergeFixits(FixItHints, Loc.getManager(), LangOpts, MergedFixits); FixItHints = MergedFixits; } @@ -107,25 +106,25 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, if (I->RemoveRange.isValid()) MutableRanges.push_back(I->RemoveRange); - SourceLocation UnexpandedLoc = Loc; + FullSourceLoc UnexpandedLoc = Loc; // Find the ultimate expansion location for the diagnostic. - Loc = SM->getFileLoc(Loc); + Loc = Loc.getFileLoc(); - PresumedLoc PLoc = SM->getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc); + PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc); // First, if this diagnostic is not in the main file, print out the // "included from" lines. - emitIncludeStack(Loc, PLoc, Level, *SM); + emitIncludeStack(Loc, PLoc, Level); // Next, emit the actual diagnostic message and caret. - emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, SM, D); - emitCaret(Loc, Level, MutableRanges, FixItHints, *SM); + emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, D); + emitCaret(Loc, Level, MutableRanges, FixItHints); // If this location is within a macro, walk from UnexpandedLoc up to Loc // and produce a macro backtrace. if (UnexpandedLoc.isValid() && UnexpandedLoc.isMacroID()) { - emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints, *SM); + emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints); } } @@ -139,15 +138,12 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) { emitDiagnostic(Diag.getLocation(), Diag.getLevel(), Diag.getMessage(), Diag.getRanges(), Diag.getFixIts(), - Diag.getLocation().isValid() ? &Diag.getLocation().getManager() - : nullptr, &Diag); } void DiagnosticRenderer::emitBasicNote(StringRef Message) { - emitDiagnosticMessage( - SourceLocation(), PresumedLoc(), DiagnosticsEngine::Note, Message, - None, nullptr, DiagOrStoredDiag()); + emitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagnosticsEngine::Note, + Message, None, DiagOrStoredDiag()); } /// \brief Prints an include stack when appropriate for a particular @@ -161,12 +157,11 @@ void DiagnosticRenderer::emitBasicNote(StringRef Message) { /// \param Loc The diagnostic location. /// \param PLoc The presumed location of the diagnostic location. /// \param Level The diagnostic level of the message this stack pertains to. -void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc, - PresumedLoc PLoc, - DiagnosticsEngine::Level Level, - const SourceManager &SM) { - SourceLocation IncludeLoc = - PLoc.isInvalid() ? SourceLocation() : PLoc.getIncludeLoc(); +void DiagnosticRenderer::emitIncludeStack(FullSourceLoc Loc, PresumedLoc PLoc, + DiagnosticsEngine::Level Level) { + FullSourceLoc IncludeLoc = + PLoc.isInvalid() ? FullSourceLoc() + : FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager()); // Skip redundant include stacks altogether. if (LastIncludeLoc == IncludeLoc) @@ -178,74 +173,70 @@ void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc, return; if (IncludeLoc.isValid()) - emitIncludeStackRecursively(IncludeLoc, SM); + emitIncludeStackRecursively(IncludeLoc); else { - emitModuleBuildStack(SM); - emitImportStack(Loc, SM); + emitModuleBuildStack(Loc.getManager()); + emitImportStack(Loc); } } /// \brief Helper to recursivly walk up the include stack and print each layer /// on the way back down. -void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc, - const SourceManager &SM) { +void DiagnosticRenderer::emitIncludeStackRecursively(FullSourceLoc Loc) { if (Loc.isInvalid()) { - emitModuleBuildStack(SM); + emitModuleBuildStack(Loc.getManager()); return; } - - PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc); + + PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc); if (PLoc.isInvalid()) return; // If this source location was imported from a module, print the module // import stack rather than the // FIXME: We want submodule granularity here. - std::pair<SourceLocation, StringRef> Imported = SM.getModuleImportLoc(Loc); + std::pair<FullSourceLoc, StringRef> Imported = Loc.getModuleImportLoc(); if (!Imported.second.empty()) { // This location was imported by a module. Emit the module import stack. - emitImportStackRecursively(Imported.first, Imported.second, SM); + emitImportStackRecursively(Imported.first, Imported.second); return; } // Emit the other include frames first. - emitIncludeStackRecursively(PLoc.getIncludeLoc(), SM); - + emitIncludeStackRecursively( + FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager())); + // Emit the inclusion text/note. - emitIncludeLocation(Loc, PLoc, SM); + emitIncludeLocation(Loc, PLoc); } /// \brief Emit the module import stack associated with the current location. -void DiagnosticRenderer::emitImportStack(SourceLocation Loc, - const SourceManager &SM) { +void DiagnosticRenderer::emitImportStack(FullSourceLoc Loc) { if (Loc.isInvalid()) { - emitModuleBuildStack(SM); + emitModuleBuildStack(Loc.getManager()); return; } - std::pair<SourceLocation, StringRef> NextImportLoc - = SM.getModuleImportLoc(Loc); - emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM); + std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc(); + emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second); } /// \brief Helper to recursivly walk up the import stack and print each layer /// on the way back down. -void DiagnosticRenderer::emitImportStackRecursively(SourceLocation Loc, - StringRef ModuleName, - const SourceManager &SM) { +void DiagnosticRenderer::emitImportStackRecursively(FullSourceLoc Loc, + StringRef ModuleName) { if (ModuleName.empty()) { return; } - PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc); + PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc); // Emit the other import frames first. - std::pair<SourceLocation, StringRef> NextImportLoc - = SM.getModuleImportLoc(Loc); - emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM); + std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc(); + emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second); // Emit the inclusion text/note. - emitImportLocation(Loc, PLoc, ModuleName, SM); + emitImportLocation(Loc, PLoc, ModuleName); } /// \brief Emit the module build stack, for cases where a module is (re-)built @@ -253,13 +244,9 @@ void DiagnosticRenderer::emitImportStackRecursively(SourceLocation Loc, void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) { ModuleBuildStack Stack = SM.getModuleBuildStack(); for (unsigned I = 0, N = Stack.size(); I != N; ++I) { - const SourceManager &CurSM = Stack[I].second.getManager(); - SourceLocation CurLoc = Stack[I].second; - emitBuildingModuleLocation(CurLoc, - CurSM.getPresumedLoc(CurLoc, + emitBuildingModuleLocation(Stack[I].second, Stack[I].second.getPresumedLoc( DiagOpts->ShowPresumedLoc), - Stack[I].first, - CurSM); + Stack[I].first); } } @@ -348,12 +335,12 @@ static void computeCommonMacroArgExpansionFileIDs( // in the same expansion as the caret; otherwise, we crawl to the top of // each chain. Two locations are part of the same macro expansion // iff the FileID is the same. -static void mapDiagnosticRanges( - SourceLocation CaretLoc, - ArrayRef<CharSourceRange> Ranges, - SmallVectorImpl<CharSourceRange> &SpellingRanges, - const SourceManager *SM) { - FileID CaretLocFileID = SM->getFileID(CaretLoc); +static void +mapDiagnosticRanges(FullSourceLoc CaretLoc, ArrayRef<CharSourceRange> Ranges, + SmallVectorImpl<CharSourceRange> &SpellingRanges) { + FileID CaretLocFileID = CaretLoc.getFileID(); + + const SourceManager *SM = &CaretLoc.getManager(); for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { if (I->isInvalid()) continue; @@ -404,42 +391,39 @@ static void mapDiagnosticRanges( } } -void DiagnosticRenderer::emitCaret(SourceLocation Loc, +void DiagnosticRenderer::emitCaret(FullSourceLoc Loc, DiagnosticsEngine::Level Level, ArrayRef<CharSourceRange> Ranges, - ArrayRef<FixItHint> Hints, - const SourceManager &SM) { + ArrayRef<FixItHint> Hints) { SmallVector<CharSourceRange, 4> SpellingRanges; - mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM); - emitCodeContext(Loc, Level, SpellingRanges, Hints, SM); + mapDiagnosticRanges(Loc, Ranges, SpellingRanges); + emitCodeContext(Loc, Level, SpellingRanges, Hints); } /// \brief A helper function for emitMacroExpansion to print the /// macro expansion message void DiagnosticRenderer::emitSingleMacroExpansion( - SourceLocation Loc, - DiagnosticsEngine::Level Level, - ArrayRef<CharSourceRange> Ranges, - const SourceManager &SM) { + FullSourceLoc Loc, DiagnosticsEngine::Level Level, + ArrayRef<CharSourceRange> Ranges) { // Find the spelling location for the macro definition. We must use the // spelling location here to avoid emitting a macro backtrace for the note. - SourceLocation SpellingLoc = SM.getSpellingLoc(Loc); + FullSourceLoc SpellingLoc = Loc.getSpellingLoc(); // Map the ranges into the FileID of the diagnostic location. SmallVector<CharSourceRange, 4> SpellingRanges; - mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM); + mapDiagnosticRanges(Loc, Ranges, SpellingRanges); SmallString<100> MessageStorage; llvm::raw_svector_ostream Message(MessageStorage); - StringRef MacroName = - Lexer::getImmediateMacroNameForDiagnostics(Loc, SM, LangOpts); + StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics( + Loc, Loc.getManager(), LangOpts); if (MacroName.empty()) Message << "expanded from here"; else Message << "expanded from macro '" << MacroName << "'"; emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(), - SpellingRanges, None, &SM); + SpellingRanges, None); } /// Check that the macro argument location of Loc starts with ArgumentLoc. @@ -473,13 +457,12 @@ static bool checkRangeForMacroArgExpansion(CharSourceRange Range, /// A helper function to check if the current ranges are all inside the same /// macro argument expansion as Loc. -static bool checkRangesForMacroArgExpansion(SourceLocation Loc, - ArrayRef<CharSourceRange> Ranges, - const SourceManager &SM) { +static bool checkRangesForMacroArgExpansion(FullSourceLoc Loc, + ArrayRef<CharSourceRange> Ranges) { assert(Loc.isMacroID() && "Must be a macro expansion!"); SmallVector<CharSourceRange, 4> SpellingRanges; - mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM); + mapDiagnosticRanges(Loc, Ranges, SpellingRanges); /// Count all valid ranges. unsigned ValidCount = 0; @@ -490,15 +473,15 @@ static bool checkRangesForMacroArgExpansion(SourceLocation Loc, return false; /// To store the source location of the argument location. - SourceLocation ArgumentLoc; + FullSourceLoc ArgumentLoc; /// Set the ArgumentLoc to the beginning location of the expansion of Loc /// so to check if the ranges expands to the same beginning location. - if (!SM.isMacroArgExpansion(Loc,&ArgumentLoc)) + if (!Loc.isMacroArgExpansion(&ArgumentLoc)) return false; for (auto I = SpellingRanges.begin(), E = SpellingRanges.end(); I != E; ++I) { - if (!checkRangeForMacroArgExpansion(*I, SM, ArgumentLoc)) + if (!checkRangeForMacroArgExpansion(*I, Loc.getManager(), ArgumentLoc)) return false; } @@ -516,34 +499,33 @@ static bool checkRangesForMacroArgExpansion(SourceLocation Loc, /// \param Level The diagnostic level currently being emitted. /// \param Ranges The underlined ranges for this code snippet. /// \param Hints The FixIt hints active for this diagnostic. -void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc, +void DiagnosticRenderer::emitMacroExpansions(FullSourceLoc Loc, DiagnosticsEngine::Level Level, ArrayRef<CharSourceRange> Ranges, - ArrayRef<FixItHint> Hints, - const SourceManager &SM) { + ArrayRef<FixItHint> Hints) { assert(Loc.isValid() && "must have a valid source location here"); // Produce a stack of macro backtraces. - SmallVector<SourceLocation, 8> LocationStack; + SmallVector<FullSourceLoc, 8> LocationStack; unsigned IgnoredEnd = 0; while (Loc.isMacroID()) { // If this is the expansion of a macro argument, point the caret at the // use of the argument in the definition of the macro, not the expansion. - if (SM.isMacroArgExpansion(Loc)) - LocationStack.push_back(SM.getImmediateExpansionRange(Loc).first); + if (Loc.isMacroArgExpansion()) + LocationStack.push_back(Loc.getImmediateExpansionRange().first); else LocationStack.push_back(Loc); - if (checkRangesForMacroArgExpansion(Loc, Ranges, SM)) + if (checkRangesForMacroArgExpansion(Loc, Ranges)) IgnoredEnd = LocationStack.size(); - Loc = SM.getImmediateMacroCallerLoc(Loc); + Loc = Loc.getImmediateMacroCallerLoc(); // Once the location no longer points into a macro, try stepping through // the last found location. This sometimes produces additional useful // backtraces. if (Loc.isFileID()) - Loc = SM.getImmediateMacroCallerLoc(LocationStack.back()); + Loc = LocationStack.back().getImmediateMacroCallerLoc(); assert(Loc.isValid() && "must have a valid source location here"); } @@ -555,7 +537,7 @@ void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc, if (MacroDepth <= MacroLimit || MacroLimit == 0) { for (auto I = LocationStack.rbegin(), E = LocationStack.rend(); I != E; ++I) - emitSingleMacroExpansion(*I, Level, Ranges, SM); + emitSingleMacroExpansion(*I, Level, Ranges); return; } @@ -565,7 +547,7 @@ void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc, for (auto I = LocationStack.rbegin(), E = LocationStack.rbegin() + MacroStartMessages; I != E; ++I) - emitSingleMacroExpansion(*I, Level, Ranges, SM); + emitSingleMacroExpansion(*I, Level, Ranges); SmallString<200> MessageStorage; llvm::raw_svector_ostream Message(MessageStorage); @@ -577,26 +559,24 @@ void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc, for (auto I = LocationStack.rend() - MacroEndMessages, E = LocationStack.rend(); I != E; ++I) - emitSingleMacroExpansion(*I, Level, Ranges, SM); + emitSingleMacroExpansion(*I, Level, Ranges); } DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {} -void DiagnosticNoteRenderer::emitIncludeLocation(SourceLocation Loc, - PresumedLoc PLoc, - const SourceManager &SM) { +void DiagnosticNoteRenderer::emitIncludeLocation(FullSourceLoc Loc, + PresumedLoc PLoc) { // Generate a note indicating the include location. SmallString<200> MessageStorage; llvm::raw_svector_ostream Message(MessageStorage); Message << "in file included from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":"; - emitNote(Loc, Message.str(), &SM); + emitNote(Loc, Message.str()); } -void DiagnosticNoteRenderer::emitImportLocation(SourceLocation Loc, +void DiagnosticNoteRenderer::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, - StringRef ModuleName, - const SourceManager &SM) { + StringRef ModuleName) { // Generate a note indicating the include location. SmallString<200> MessageStorage; llvm::raw_svector_ostream Message(MessageStorage); @@ -605,14 +585,12 @@ void DiagnosticNoteRenderer::emitImportLocation(SourceLocation Loc, Message << "' imported from " << PLoc.getFilename() << ':' << PLoc.getLine(); Message << ":"; - emitNote(Loc, Message.str(), &SM); + emitNote(Loc, Message.str()); } -void -DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc, - PresumedLoc PLoc, - StringRef ModuleName, - const SourceManager &SM) { +void DiagnosticNoteRenderer::emitBuildingModuleLocation(FullSourceLoc Loc, + PresumedLoc PLoc, + StringRef ModuleName) { // Generate a note indicating the include location. SmallString<200> MessageStorage; llvm::raw_svector_ostream Message(MessageStorage); @@ -621,5 +599,5 @@ DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc, << PLoc.getFilename() << ':' << PLoc.getLine() << ":"; else Message << "while building module '" << ModuleName << "':"; - emitNote(Loc, Message.str(), &SM); + emitNote(Loc, Message.str()); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp index 39fc137..704d5150 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp @@ -19,6 +19,7 @@ #include "clang/Frontend/MultiplexConsumer.h" #include "clang/Frontend/Utils.h" #include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/LiteralSupport.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Parse/ParseAST.h" @@ -135,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) { @@ -187,8 +194,324 @@ 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. +/// 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 IsModuleMap If \c true, add a line note corresponding to this line +/// directive. (We need to do this because the directive will not be +/// visited by the preprocessor.) +static SourceLocation ReadOriginalFileName(CompilerInstance &CI, + std::string &InputFile, + bool IsModuleMap = false) { + auto &SourceMgr = CI.getSourceManager(); + auto MainFileID = SourceMgr.getMainFileID(); + + bool Invalid = false; + const auto *MainFileBuf = SourceMgr.getBuffer(MainFileID, &Invalid); + if (Invalid) + return SourceLocation(); + + std::unique_ptr<Lexer> RawLexer( + new Lexer(MainFileID, MainFileBuf, SourceMgr, CI.getLangOpts())); + + // If the first line has the syntax of + // + // # NUM "FILENAME" + // + // we use FILENAME as the input file name. + Token T; + if (RawLexer->LexFromRawLexer(T) || T.getKind() != tok::hash) + return SourceLocation(); + if (RawLexer->LexFromRawLexer(T) || T.isAtStartOfLine() || + T.getKind() != tok::numeric_constant) + return SourceLocation(); + + unsigned LineNo; + SourceLocation LineNoLoc = T.getLocation(); + if (IsModuleMap) { + 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 SourceLocation(); + + StringLiteralParser Literal(T, CI.getPreprocessor()); + if (Literal.hadError) + return SourceLocation(); + RawLexer->LexFromRawLexer(T); + if (T.isNot(tok::eof) && !T.isAtStartOfLine()) + return SourceLocation(); + InputFile = Literal.GetString().str(); + + if (IsModuleMap) + CI.getSourceManager().AddLineNote( + LineNoLoc, LineNo, SourceMgr.getLineTableFilenameID(InputFile), false, + false, SrcMgr::C_User_ModuleMap); + + return T.getLocation(); +} + +static SmallVectorImpl<char> & +operator+=(SmallVectorImpl<char> &Includes, StringRef RHS) { + Includes.append(RHS.begin(), RHS.end()); + return Includes; +} + +static void addHeaderInclude(StringRef HeaderName, + SmallVectorImpl<char> &Includes, + const LangOptions &LangOpts, + bool IsExternC) { + if (IsExternC && LangOpts.CPlusPlus) + Includes += "extern \"C\" {\n"; + if (LangOpts.ObjC1) + Includes += "#import \""; + else + Includes += "#include \""; + + Includes += HeaderName; + + Includes += "\"\n"; + if (IsExternC && LangOpts.CPlusPlus) + Includes += "}\n"; +} + +/// \brief Collect the set of header includes needed to construct the given +/// module and update the TopHeaders file set of the module. +/// +/// \param Module The module we're collecting includes from. +/// +/// \param Includes Will be augmented with the set of \#includes or \#imports +/// needed to load all of the named headers. +static std::error_code collectModuleHeaderIncludes( + const LangOptions &LangOpts, FileManager &FileMgr, DiagnosticsEngine &Diag, + ModuleMap &ModMap, clang::Module *Module, SmallVectorImpl<char> &Includes) { + // Don't collect any headers for unavailable modules. + if (!Module->isAvailable()) + return std::error_code(); + + // Resolve all lazy header directives to header files. + ModMap.resolveHeaderDirectives(Module); + + // If any headers are missing, we can't build this module. In most cases, + // diagnostics for this should have already been produced; we only get here + // if explicit stat information was provided. + // FIXME: If the name resolves to a file with different stat information, + // produce a better diagnostic. + if (!Module->MissingHeaders.empty()) { + auto &MissingHeader = Module->MissingHeaders.front(); + Diag.Report(MissingHeader.FileNameLoc, diag::err_module_header_missing) + << MissingHeader.IsUmbrella << MissingHeader.FileName; + return std::error_code(); + } + + // Add includes for each of these headers. + for (auto HK : {Module::HK_Normal, Module::HK_Private}) { + for (Module::Header &H : Module->Headers[HK]) { + Module->addTopHeader(H.Entry); + // Use the path as specified in the module map file. We'll look for this + // file relative to the module build directory (the directory containing + // the module map file) so this will find the same file that we found + // while parsing the module map. + addHeaderInclude(H.NameAsWritten, Includes, LangOpts, Module->IsExternC); + } + } + // Note that Module->PrivateHeaders will not be a TopHeader. + + if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader()) { + Module->addTopHeader(UmbrellaHeader.Entry); + if (Module->Parent) + // Include the umbrella header for submodules. + addHeaderInclude(UmbrellaHeader.NameAsWritten, Includes, LangOpts, + Module->IsExternC); + } else if (Module::DirectoryName UmbrellaDir = Module->getUmbrellaDir()) { + // Add all of the headers we find in this subdirectory. + std::error_code EC; + SmallString<128> DirNative; + llvm::sys::path::native(UmbrellaDir.Entry->getName(), DirNative); + + vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem(); + for (vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End; + Dir != End && !EC; Dir.increment(EC)) { + // Check whether this entry has an extension typically associated with + // headers. + if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->getName())) + .Cases(".h", ".H", ".hh", ".hpp", true) + .Default(false)) + continue; + + const FileEntry *Header = FileMgr.getFile(Dir->getName()); + // FIXME: This shouldn't happen unless there is a file system race. Is + // that worth diagnosing? + if (!Header) + continue; + + // If this header is marked 'unavailable' in this module, don't include + // it. + if (ModMap.isHeaderUnavailableInModule(Header, Module)) + continue; + + // Compute the relative path from the directory to this file. + SmallVector<StringRef, 16> Components; + auto PathIt = llvm::sys::path::rbegin(Dir->getName()); + for (int I = 0; I != Dir.level() + 1; ++I, ++PathIt) + Components.push_back(*PathIt); + SmallString<128> RelativeHeader(UmbrellaDir.NameAsWritten); + for (auto It = Components.rbegin(), End = Components.rend(); It != End; + ++It) + llvm::sys::path::append(RelativeHeader, *It); + + // Include this header as part of the umbrella directory. + Module->addTopHeader(Header); + addHeaderInclude(RelativeHeader, Includes, LangOpts, Module->IsExternC); + } + + if (EC) + return EC; + } + + // Recurse into submodules. + for (clang::Module::submodule_iterator Sub = Module->submodule_begin(), + SubEnd = Module->submodule_end(); + Sub != SubEnd; ++Sub) + if (std::error_code Err = collectModuleHeaderIncludes( + LangOpts, FileMgr, Diag, ModMap, *Sub, Includes)) + return Err; + + return std::error_code(); +} + +static bool loadModuleMapForModuleBuild(CompilerInstance &CI, bool IsSystem, + bool IsPreprocessed, + std::string &PresumedModuleMapFile, + unsigned &Offset) { + auto &SrcMgr = CI.getSourceManager(); + HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); + + // 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) { + SourceLocation EndOfLineMarker = + ReadOriginalFileName(CI, PresumedModuleMapFile, /*IsModuleMap*/ true); + if (EndOfLineMarker.isValid()) + Offset = CI.getSourceManager().getDecomposedLoc(EndOfLineMarker).second; + } + + // Load the module map file. + if (HS.loadModuleMapFile(ModuleMap, IsSystem, ModuleMapID, &Offset, + PresumedModuleMapFile)) + 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 + // map with a single module (the common case). + return nullptr; + } + + // 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 << ModuleMapFilename; + + return nullptr; + } + + // Check whether we can build this module at all. + if (Preprocessor::checkModuleIsAvailable(CI.getLangOpts(), CI.getTarget(), + CI.getDiagnostics(), M)) + 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); + + // 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. + SmallString<256> HeaderContents; + std::error_code Err = std::error_code(); + if (Module::Header UmbrellaHeader = M->getUmbrellaHeader()) + addHeaderInclude(UmbrellaHeader.NameAsWritten, HeaderContents, + CI.getLangOpts(), M->IsExternC); + Err = collectModuleHeaderIncludes( + CI.getLangOpts(), FileMgr, CI.getDiagnostics(), + CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), M, + HeaderContents); + + if (Err) { + CI.getDiagnostics().Report(diag::err_module_cannot_create_includes) + << M->getFullModuleName() << Err.message(); + return nullptr; + } + + return llvm::MemoryBuffer::getMemBufferCopy( + HeaderContents, Module::getModuleInputBufferName()); +} + bool FrontendAction::BeginSourceFile(CompilerInstance &CI, - const FrontendInputFile &Input) { + const FrontendInputFile &RealInput) { + FrontendInputFile Input(RealInput); assert(!Instance && "Already processing a source file!"); assert(!Input.isEmpty() && "Unexpected empty filename!"); setCurrentInput(Input); @@ -196,22 +519,88 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, StringRef InputFile = Input.getFile(); bool HasBegunSourceFile = false; + bool ReplayASTFile = Input.getKind().getFormat() == InputKind::Precompiled && + usesPreprocessorOnly(); if (!BeginInvocation(CI)) goto failure; + // If we're replaying the build of an AST file, import it and set up + // the initial state from its build. + if (ReplayASTFile) { + IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics()); + + // The AST unit populates its own diagnostics engine rather than ours. + IntrusiveRefCntPtr<DiagnosticsEngine> ASTDiags( + new DiagnosticsEngine(Diags->getDiagnosticIDs(), + &Diags->getDiagnosticOptions())); + ASTDiags->setClient(Diags->getClient(), /*OwnsClient*/false); + + std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile( + InputFile, CI.getPCHContainerReader(), ASTUnit::LoadPreprocessorOnly, + ASTDiags, CI.getFileSystemOpts(), CI.getCodeGenOpts().DebugTypeExtRefs); + if (!AST) + goto failure; + + // Options relating to how we treat the input (but not what we do with it) + // are inherited from the AST unit. + CI.getHeaderSearchOpts() = AST->getHeaderSearchOpts(); + CI.getPreprocessorOpts() = AST->getPreprocessorOpts(); + CI.getLangOpts() = AST->getLangOpts(); + + // Set the shared objects, these are reset when we finish processing the + // file, otherwise the CompilerInstance will happily destroy them. + CI.setFileManager(&AST->getFileManager()); + CI.createSourceManager(CI.getFileManager()); + CI.getSourceManager().initializeForReplay(AST->getSourceManager()); + + // Preload all the module files loaded transitively by the AST unit. Also + // load all module map files that were parsed as part of building the AST + // unit. + if (auto ASTReader = AST->getASTReader()) { + auto &MM = ASTReader->getModuleManager(); + auto &PrimaryModule = MM.getPrimaryModule(); + + for (ModuleFile &MF : MM) + if (&MF != &PrimaryModule) + CI.getFrontendOpts().ModuleFiles.push_back(MF.FileName); + + ASTReader->visitTopLevelModuleMaps(PrimaryModule, + [&](const FileEntry *FE) { + CI.getFrontendOpts().ModuleMapFiles.push_back(FE->getName()); + }); + } + + // Set up the input file for replay purposes. + auto Kind = AST->getInputKind(); + if (Kind.getFormat() == InputKind::ModuleMap) { + Module *ASTModule = + AST->getPreprocessor().getHeaderSearchInfo().lookupModule( + AST->getLangOpts().CurrentModule, /*AllowSearch*/ false); + assert(ASTModule && "module file does not define its own module"); + Input = FrontendInputFile(ASTModule->PresumedModuleMapFile, Kind); + } else { + auto &SM = CI.getSourceManager(); + FileID ID = SM.getMainFileID(); + if (auto *File = SM.getFileEntryForID(ID)) + Input = FrontendInputFile(File->getName(), Kind); + else + Input = FrontendInputFile(SM.getBuffer(ID), Kind); + } + setCurrentInput(Input, std::move(AST)); + } + // AST files follow a very different path, since they share objects via the // AST unit. - if (Input.getKind() == IK_AST) { - assert(!usesPreprocessorOnly() && - "Attempt to pass AST file to preprocessor only action!"); + if (Input.getKind().getFormat() == InputKind::Precompiled) { + assert(!usesPreprocessorOnly() && "this case was handled above"); assert(hasASTFileSupport() && "This action does not have AST file support!"); IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics()); std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile( - InputFile, CI.getPCHContainerReader(), Diags, CI.getFileSystemOpts(), - CI.getCodeGenOpts().DebugTypeExtRefs); + InputFile, CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags, + CI.getFileSystemOpts(), CI.getCodeGenOpts().DebugTypeExtRefs); if (!AST) goto failure; @@ -225,12 +614,15 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, CI.setFileManager(&AST->getFileManager()); CI.setSourceManager(&AST->getSourceManager()); CI.setPreprocessor(AST->getPreprocessorPtr()); + Preprocessor &PP = CI.getPreprocessor(); + PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(), + PP.getLangOpts()); CI.setASTContext(&AST->getASTContext()); setCurrentInput(Input, std::move(AST)); // Initialize the action. - if (!BeginSourceFileAction(CI, InputFile)) + if (!BeginSourceFileAction(CI)) goto failure; // Create the AST consumer. @@ -256,8 +648,19 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (!CI.hasSourceManager()) CI.createSourceManager(CI.getFileManager()); + // Set up embedding for any specified files. Do this before we load any + // source files, including the primary module map for the compilation. + for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) { + if (const auto *FE = CI.getFileManager().getFile(F, /*openFile*/true)) + CI.getSourceManager().setFileIsTransient(FE); + else + CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F; + } + if (CI.getFrontendOpts().ModulesEmbedAllFiles) + CI.getSourceManager().setAllFilesAreTransient(true); + // IR files bypass the rest of initialization. - if (Input.getKind() == IK_LLVM_IR) { + if (Input.getKind().getLanguage() == InputKind::LLVM_IR) { assert(hasIRSupport() && "This action does not have IR file support!"); @@ -266,7 +669,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, HasBegunSourceFile = true; // Initialize the action. - if (!BeginSourceFileAction(CI, InputFile)) + if (!BeginSourceFileAction(CI)) goto failure; // Initialize the main file entry. @@ -319,13 +722,47 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, &CI.getPreprocessor()); HasBegunSourceFile = true; - // Initialize the action. - if (!BeginSourceFileAction(CI, InputFile)) + // Initialize the main file entry. + if (!CI.InitializeSourceManager(Input)) goto failure; - // Initialize the main file entry. It is important that this occurs after - // BeginSourceFileAction, which may change CurrentInput during module builds. - if (!CI.InitializeSourceManager(CurrentInput)) + // 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); + + std::string PresumedModuleMapFile; + unsigned OffsetToContents; + if (loadModuleMapForModuleBuild(CI, Input.isSystem(), + Input.isPreprocessed(), + PresumedModuleMapFile, OffsetToContents)) + goto failure; + + auto *CurrentModule = prepareToBuildModule(CI, Input.getFile()); + if (!CurrentModule) + goto failure; + + CurrentModule->PresumedModuleMapFile = PresumedModuleMapFile; + + 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; + + // 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)) goto failure; // Create the AST context and consumer unless this is a preprocessor only @@ -335,8 +772,14 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (!isModelParsingAction()) CI.createASTContext(); + // For preprocessed files, check if the first line specifies the original + // source file name with a linemarker. + std::string PresumedInputFile = InputFile; + if (Input.isPreprocessed()) + ReadOriginalFileName(CI, PresumedInputFile); + std::unique_ptr<ASTConsumer> Consumer = - CreateWrappedASTConsumer(CI, InputFile); + CreateWrappedASTConsumer(CI, PresumedInputFile); if (!Consumer) goto failure; @@ -352,8 +795,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, goto failure; CI.setModuleManager(static_cast<ASTReader *>(FinalReader.get())); CI.getASTContext().setExternalSource(source); - } else if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { - // Use PCH. + } else if (CI.getLangOpts().Modules || + !CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { + // Use PCM or PCH. assert(hasPCHSupport() && "This action does not have PCH support!"); ASTDeserializationListener *DeserialListener = Consumer->GetASTDeserializationListener(); @@ -370,13 +814,24 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, DeserialListener, DeleteDeserialListener); DeleteDeserialListener = true; } - CI.createPCHExternalASTSource( - CI.getPreprocessorOpts().ImplicitPCHInclude, - CI.getPreprocessorOpts().DisablePCHValidation, + if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { + CI.createPCHExternalASTSource( + CI.getPreprocessorOpts().ImplicitPCHInclude, + CI.getPreprocessorOpts().DisablePCHValidation, CI.getPreprocessorOpts().AllowPCHWithCompilerErrors, DeserialListener, - DeleteDeserialListener); - if (!CI.getASTContext().getExternalSource()) - goto failure; + DeleteDeserialListener); + if (!CI.getASTContext().getExternalSource()) + goto failure; + } + // If modules are enabled, create the module manager before creating + // any builtins, so that all declarations know that they might be + // extended by an external source. + if (CI.getLangOpts().Modules || !CI.hasASTContext() || + !CI.getASTContext().getExternalSource()) { + CI.createModuleManager(); + CI.getModuleManager()->setDeserializationListener(DeserialListener, + DeleteDeserialListener); + } } CI.setASTConsumer(std::move(Consumer)); @@ -386,15 +841,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // Initialize built-in info as long as we aren't using an external AST // source. - if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) { + if (CI.getLangOpts().Modules || !CI.hasASTContext() || + !CI.getASTContext().getExternalSource()) { Preprocessor &PP = CI.getPreprocessor(); - - // If modules are enabled, create the module manager before creating - // any builtins, so that all declarations know that they might be - // extended by an external source. - if (CI.getLangOpts().Modules) - CI.createModuleManager(); - PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(), PP.getLangOpts()); } else { @@ -421,9 +870,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // If there is a layout overrides file, attach an external AST source that // provides the layouts from that file. - if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() && + if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() && CI.hasASTContext() && !CI.getASTContext().getExternalSource()) { - IntrusiveRefCntPtr<ExternalASTSource> + IntrusiveRefCntPtr<ExternalASTSource> Override(new LayoutOverrideSource( CI.getFrontendOpts().OverrideRecordLayoutsFile)); CI.getASTContext().setExternalSource(Override); @@ -433,17 +882,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // If we failed, reset state since the client will not end up calling the // matching EndSourceFile(). - failure: - if (isCurrentFileAST()) { - CI.setASTContext(nullptr); - CI.setPreprocessor(nullptr); - CI.setSourceManager(nullptr); - CI.setFileManager(nullptr); - } - +failure: if (HasBegunSourceFile) CI.getDiagnosticClient().EndSourceFile(); CI.clearOutputFiles(/*EraseFiles=*/true); + CI.getLangOpts().setCompilingModule(LangOptions::CMK_None); setCurrentInput(FrontendInputFile()); setCompilerInstance(nullptr); return false; @@ -517,6 +960,7 @@ void FrontendAction::EndSourceFile() { CI.resetAndLeakPreprocessor(); CI.resetAndLeakSourceManager(); CI.resetAndLeakFileManager(); + BuryPointer(CurrentASTUnit.release()); } else { CI.setPreprocessor(nullptr); CI.setSourceManager(nullptr); @@ -526,6 +970,7 @@ void FrontendAction::EndSourceFile() { setCompilerInstance(nullptr); setCurrentInput(FrontendInputFile()); + CI.getLangOpts().setCompilingModule(LangOptions::CMK_None); } bool FrontendAction::shouldEraseOutputFiles() { @@ -575,11 +1020,10 @@ WrapperFrontendAction::CreateASTConsumer(CompilerInstance &CI, bool WrapperFrontendAction::BeginInvocation(CompilerInstance &CI) { return WrappedAction->BeginInvocation(CI); } -bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI, - StringRef Filename) { +bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI) { WrappedAction->setCurrentInput(getCurrentInput()); WrappedAction->setCompilerInstance(&CI); - auto Ret = WrappedAction->BeginSourceFileAction(CI, Filename); + auto Ret = WrappedAction->BeginSourceFileAction(CI); // BeginSourceFileAction may change CurrentInput, e.g. during module builds. setCurrentInput(WrappedAction->getCurrentInput()); return Ret; diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp index f795a1d..d424001 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp @@ -57,6 +57,7 @@ std::unique_ptr<ASTConsumer> ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { return CreateASTDumper(CI.getFrontendOpts().ASTDumpFilter, CI.getFrontendOpts().ASTDumpDecls, + CI.getFrontendOpts().ASTDumpAll, CI.getFrontendOpts().ASTDumpLookups); } @@ -93,7 +94,7 @@ GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { Consumers.push_back(llvm::make_unique<PCHGenerator>( CI.getPreprocessor(), OutputFile, Sysroot, Buffer, CI.getFrontendOpts().ModuleFileExtensions, - /*AllowASTWithErrors*/false, + /*AllowASTWithErrors*/CI.getPreprocessorOpts().AllowPCHWithCompilerErrors, /*IncludeTimestamps*/ +CI.getFrontendOpts().IncludeTimestamps)); Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator( @@ -127,8 +128,13 @@ GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI, return OS; } -bool GeneratePCHAction::BeginSourceFileAction(CompilerInstance &CI, - StringRef Filename) { +bool GeneratePCHAction::shouldEraseOutputFiles() { + if (getCompilerInstance().getPreprocessorOpts().AllowPCHWithCompilerErrors) + return false; + return ASTFrontendAction::shouldEraseOutputFiles(); +} + +bool GeneratePCHAction::BeginSourceFileAction(CompilerInstance &CI) { CI.getLangOpts().CompilingPCH = true; return true; } @@ -157,242 +163,14 @@ GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI, return llvm::make_unique<MultiplexConsumer>(std::move(Consumers)); } -bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI, - StringRef Filename) { - // Set up embedding for any specified files. Do this before we load any - // source files, including the primary module map for the compilation. - for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) { - if (const auto *FE = CI.getFileManager().getFile(F, /*openFile*/true)) - CI.getSourceManager().setFileIsTransient(FE); - else - CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F; - } - if (CI.getFrontendOpts().ModulesEmbedAllFiles) - CI.getSourceManager().setAllFilesAreTransient(true); - - return true; -} - - -static SmallVectorImpl<char> & -operator+=(SmallVectorImpl<char> &Includes, StringRef RHS) { - Includes.append(RHS.begin(), RHS.end()); - return Includes; -} - -static void addHeaderInclude(StringRef HeaderName, - SmallVectorImpl<char> &Includes, - const LangOptions &LangOpts, - bool IsExternC) { - if (IsExternC && LangOpts.CPlusPlus) - Includes += "extern \"C\" {\n"; - if (LangOpts.ObjC1) - Includes += "#import \""; - else - Includes += "#include \""; - - Includes += HeaderName; - - Includes += "\"\n"; - if (IsExternC && LangOpts.CPlusPlus) - Includes += "}\n"; -} - -/// \brief Collect the set of header includes needed to construct the given -/// module and update the TopHeaders file set of the module. -/// -/// \param Module The module we're collecting includes from. -/// -/// \param Includes Will be augmented with the set of \#includes or \#imports -/// needed to load all of the named headers. -static std::error_code -collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr, - ModuleMap &ModMap, clang::Module *Module, - SmallVectorImpl<char> &Includes) { - // Don't collect any headers for unavailable modules. - if (!Module->isAvailable()) - return std::error_code(); - - // Add includes for each of these headers. - for (auto HK : {Module::HK_Normal, Module::HK_Private}) { - for (Module::Header &H : Module->Headers[HK]) { - Module->addTopHeader(H.Entry); - // Use the path as specified in the module map file. We'll look for this - // file relative to the module build directory (the directory containing - // the module map file) so this will find the same file that we found - // while parsing the module map. - addHeaderInclude(H.NameAsWritten, Includes, LangOpts, Module->IsExternC); - } - } - // Note that Module->PrivateHeaders will not be a TopHeader. - - if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader()) { - Module->addTopHeader(UmbrellaHeader.Entry); - if (Module->Parent) - // Include the umbrella header for submodules. - addHeaderInclude(UmbrellaHeader.NameAsWritten, Includes, LangOpts, - Module->IsExternC); - } else if (Module::DirectoryName UmbrellaDir = Module->getUmbrellaDir()) { - // Add all of the headers we find in this subdirectory. - std::error_code EC; - SmallString<128> DirNative; - llvm::sys::path::native(UmbrellaDir.Entry->getName(), DirNative); - - vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem(); - for (vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End; - Dir != End && !EC; Dir.increment(EC)) { - // Check whether this entry has an extension typically associated with - // headers. - if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->getName())) - .Cases(".h", ".H", ".hh", ".hpp", true) - .Default(false)) - continue; - - const FileEntry *Header = FileMgr.getFile(Dir->getName()); - // FIXME: This shouldn't happen unless there is a file system race. Is - // that worth diagnosing? - if (!Header) - continue; - - // If this header is marked 'unavailable' in this module, don't include - // it. - if (ModMap.isHeaderUnavailableInModule(Header, Module)) - continue; - - // Compute the relative path from the directory to this file. - SmallVector<StringRef, 16> Components; - auto PathIt = llvm::sys::path::rbegin(Dir->getName()); - for (int I = 0; I != Dir.level() + 1; ++I, ++PathIt) - Components.push_back(*PathIt); - SmallString<128> RelativeHeader(UmbrellaDir.NameAsWritten); - for (auto It = Components.rbegin(), End = Components.rend(); It != End; - ++It) - llvm::sys::path::append(RelativeHeader, *It); - - // Include this header as part of the umbrella directory. - Module->addTopHeader(Header); - addHeaderInclude(RelativeHeader, Includes, LangOpts, Module->IsExternC); - } - - if (EC) - return EC; - } - - // Recurse into submodules. - for (clang::Module::submodule_iterator Sub = Module->submodule_begin(), - SubEnd = Module->submodule_end(); - Sub != SubEnd; ++Sub) - if (std::error_code Err = collectModuleHeaderIncludes( - LangOpts, FileMgr, ModMap, *Sub, Includes)) - return Err; - - return std::error_code(); -} - bool GenerateModuleFromModuleMapAction::BeginSourceFileAction( - CompilerInstance &CI, StringRef Filename) { - CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleMap); - - if (!GenerateModuleAction::BeginSourceFileAction(CI, Filename)) - return false; - - // 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; + CompilerInstance &CI) { + if (!CI.getLangOpts().Modules) { + CI.getDiagnostics().Report(diag::err_module_build_requires_fmodules); return false; } - - // Parse the module map file. - HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); - if (HS.loadModuleMapFile(ModuleMap, IsSystem)) - return false; - - 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 - // map with a single module (the common case). - return false; - } - - // 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. - Module = HS.lookupModule(CI.getLangOpts().CurrentModule, - /*AllowSearch=*/false); - if (!Module) { - CI.getDiagnostics().Report(diag::err_missing_module) - << CI.getLangOpts().CurrentModule << Filename; - - return false; - } - - // Check whether we can build this module at all. - clang::Module::Requirement Requirement; - clang::Module::UnresolvedHeaderDirective MissingHeader; - if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement, - MissingHeader)) { - if (MissingHeader.FileNameLoc.isValid()) { - CI.getDiagnostics().Report(MissingHeader.FileNameLoc, - diag::err_module_header_missing) - << MissingHeader.IsUmbrella << MissingHeader.FileName; - } else { - CI.getDiagnostics().Report(diag::err_module_unavailable) - << Module->getFullModuleName() - << Requirement.second << Requirement.first; - } - - return false; - } - - if (ModuleMapForUniquing && ModuleMapForUniquing != ModuleMap) { - Module->IsInferred = true; - HS.getModuleMap().setInferredModuleAllowedBy(Module, ModuleMapForUniquing); - } else { - ModuleMapForUniquing = ModuleMap; - } - FileManager &FileMgr = CI.getFileManager(); - - // Collect the set of #includes we need to build the module. - SmallString<256> HeaderContents; - std::error_code Err = std::error_code(); - if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader()) - addHeaderInclude(UmbrellaHeader.NameAsWritten, HeaderContents, - CI.getLangOpts(), Module->IsExternC); - Err = collectModuleHeaderIncludes( - CI.getLangOpts(), FileMgr, - CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), Module, - HeaderContents); - - if (Err) { - CI.getDiagnostics().Report(diag::err_module_cannot_create_includes) - << Module->getFullModuleName() << Err.message(); - return false; - } - - // 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(Module->Directory); - - std::unique_ptr<llvm::MemoryBuffer> InputBuffer = - llvm::MemoryBuffer::getMemBufferCopy(HeaderContents, - Module::getModuleInputBufferName()); - // Ownership of InputBuffer will be transferred to the SourceManager. - setCurrentInput(FrontendInputFile(InputBuffer.release(), getCurrentFileKind(), - Module->IsSystem)); - return true; + return GenerateModuleAction::BeginSourceFileAction(CI); } std::unique_ptr<raw_pwrite_stream> @@ -401,10 +179,13 @@ GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI, // If no output file was provided, figure out where this module would go // in the module cache. if (CI.getFrontendOpts().OutputFile.empty()) { + StringRef ModuleMapFile = CI.getFrontendOpts().OriginalModuleMap; + if (ModuleMapFile.empty()) + ModuleMapFile = InFile; + HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); CI.getFrontendOpts().OutputFile = - HS.getModuleFileName(CI.getLangOpts().CurrentModule, - ModuleMapForUniquing->getName(), + HS.getModuleFileName(CI.getLangOpts().CurrentModule, ModuleMapFile, /*UsePrebuiltPath=*/false); } @@ -417,8 +198,8 @@ GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI, /*CreateMissingDirectories=*/true); } -bool GenerateModuleInterfaceAction::BeginSourceFileAction(CompilerInstance &CI, - StringRef Filename) { +bool GenerateModuleInterfaceAction::BeginSourceFileAction( + CompilerInstance &CI) { if (!CI.getLangOpts().ModulesTS) { CI.getDiagnostics().Report(diag::err_module_interface_requires_modules_ts); return false; @@ -426,7 +207,7 @@ bool GenerateModuleInterfaceAction::BeginSourceFileAction(CompilerInstance &CI, CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface); - return GenerateModuleAction::BeginSourceFileAction(CI, Filename); + return GenerateModuleAction::BeginSourceFileAction(CI); } std::unique_ptr<raw_pwrite_stream> @@ -459,7 +240,7 @@ void VerifyPCHAction::ExecuteAction() { bool Preamble = CI.getPreprocessorOpts().PrecompiledPreambleBytes.first != 0; const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot; std::unique_ptr<ASTReader> Reader(new ASTReader( - CI.getPreprocessor(), CI.getASTContext(), CI.getPCHContainerReader(), + CI.getPreprocessor(), &CI.getASTContext(), CI.getPCHContainerReader(), CI.getFrontendOpts().ModuleFileExtensions, Sysroot.empty() ? "" : Sysroot.c_str(), /*DisableValidation*/ false, @@ -567,6 +348,7 @@ namespace { bool Complain) override { Out.indent(2) << "Header search options:\n"; Out.indent(4) << "System root [-isysroot=]: '" << HSOpts.Sysroot << "'\n"; + Out.indent(4) << "Resource dir [ -resource-dir=]: '" << HSOpts.ResourceDir << "'\n"; Out.indent(4) << "Module Cache: '" << SpecificModuleCachePath << "'\n"; DUMP_BOOLEAN(HSOpts.UseBuiltinIncludes, "Use builtin include directories [-nobuiltininc]"); @@ -745,7 +527,7 @@ void PrintPreprocessedAction::ExecuteAction() { // file. This is mostly a sanity check in case the file has no // newlines whatsoever. if (end - cur > 256) end = cur + 256; - + while (next < end) { if (*cur == 0x0D) { // CR if (*next == 0x0A) // CRLF @@ -764,34 +546,47 @@ 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 \""; + OS->write_escaped(Input.getFile()); + (*OS) << "\"\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()); } void PrintPreambleAction::ExecuteAction() { - switch (getCurrentFileKind()) { - case IK_C: - case IK_CXX: - case IK_ObjC: - case IK_ObjCXX: - case IK_OpenCL: - case IK_CUDA: + switch (getCurrentFileKind().getLanguage()) { + case InputKind::C: + case InputKind::CXX: + case InputKind::ObjC: + case InputKind::ObjCXX: + case InputKind::OpenCL: + case InputKind::CUDA: break; - case IK_None: - case IK_Asm: - case IK_PreprocessedC: - case IK_PreprocessedCuda: - case IK_PreprocessedCXX: - case IK_PreprocessedObjC: - case IK_PreprocessedObjCXX: - case IK_AST: - case IK_LLVM_IR: - case IK_RenderScript: + case InputKind::Unknown: + case InputKind::Asm: + case InputKind::LLVM_IR: + case InputKind::RenderScript: // We can't do anything with these. return; } + // We don't expect to find any #include directives in a preprocessed input. + if (getCurrentFileKind().isPreprocessed()) + return; + CompilerInstance &CI = getCompilerInstance(); auto Buffer = CI.getFileManager().getBufferForFile(getCurrentFile()); if (Buffer) { diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp index 6a82084..dca4345 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp @@ -13,22 +13,22 @@ using namespace clang; InputKind FrontendOptions::getInputKindForExtension(StringRef Extension) { return llvm::StringSwitch<InputKind>(Extension) - .Cases("ast", "pcm", IK_AST) - .Case("c", IK_C) - .Cases("S", "s", IK_Asm) - .Case("i", IK_PreprocessedC) - .Case("ii", IK_PreprocessedCXX) - .Case("cui", IK_PreprocessedCuda) - .Case("m", IK_ObjC) - .Case("mi", IK_PreprocessedObjC) - .Cases("mm", "M", IK_ObjCXX) - .Case("mii", IK_PreprocessedObjCXX) - .Cases("C", "cc", "cp", IK_CXX) - .Cases("cpp", "CPP", "c++", "cxx", "hpp", IK_CXX) - .Case("cppm", IK_CXX) - .Case("iim", IK_PreprocessedCXX) - .Case("cl", IK_OpenCL) - .Case("cu", IK_CUDA) - .Cases("ll", "bc", IK_LLVM_IR) - .Default(IK_C); + .Cases("ast", "pcm", InputKind(InputKind::Unknown, InputKind::Precompiled)) + .Case("c", InputKind::C) + .Cases("S", "s", InputKind::Asm) + .Case("i", InputKind(InputKind::C).getPreprocessed()) + .Case("ii", InputKind(InputKind::CXX).getPreprocessed()) + .Case("cui", InputKind(InputKind::CUDA).getPreprocessed()) + .Case("m", InputKind::ObjC) + .Case("mi", InputKind(InputKind::ObjC).getPreprocessed()) + .Cases("mm", "M", InputKind::ObjCXX) + .Case("mii", InputKind(InputKind::ObjCXX).getPreprocessed()) + .Cases("C", "cc", "cp", InputKind::CXX) + .Cases("cpp", "CPP", "c++", "cxx", "hpp", InputKind::CXX) + .Case("cppm", InputKind::CXX) + .Case("iim", InputKind(InputKind::CXX).getPreprocessed()) + .Case("cl", InputKind::OpenCL) + .Case("cu", InputKind::CUDA) + .Cases("ll", "bc", InputKind::LLVM_IR) + .Default(InputKind::Unknown); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp index d50fb6d..1d7c8a0 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp @@ -221,6 +221,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, case llvm::Triple::Win32: if (triple.getEnvironment() != llvm::Triple::Cygnus) break; + LLVM_FALLTHROUGH; default: // FIXME: temporary hack: hard-coded paths. AddPath("/usr/local/include", System, false); @@ -343,6 +344,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, AddPath(BaseSDKPath + "/target/include", System, false); if (triple.isPS4CPU()) AddPath(BaseSDKPath + "/target/include_common", System, false); + LLVM_FALLTHROUGH; } default: AddPath("/usr/include", ExternCSystem, false); diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp index 17603ad..92d6136 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp @@ -374,9 +374,14 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, else if (!LangOpts.GNUMode && LangOpts.Digraphs) Builder.defineMacro("__STDC_VERSION__", "199409L"); } else { - // FIXME: Use correct value for C++17. - if (LangOpts.CPlusPlus1z) - Builder.defineMacro("__cplusplus", "201406L"); + // FIXME: Use correct value for C++20. + if (LangOpts.CPlusPlus2a) + Builder.defineMacro("__cplusplus", "201707L"); + // C++17 [cpp.predefined]p1: + // The name __cplusplus is defined to the value 201703L when compiling a + // C++ translation unit. + else if (LangOpts.CPlusPlus1z) + Builder.defineMacro("__cplusplus", "201703L"); // C++1y [cpp.predefined]p1: // The name __cplusplus is defined to the value 201402L when compiling a // C++ translation unit. @@ -475,6 +480,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, Builder.defineMacro("__cpp_user_defined_literals", "200809"); Builder.defineMacro("__cpp_lambdas", "200907"); Builder.defineMacro("__cpp_constexpr", + LangOpts.CPlusPlus1z ? "201603" : LangOpts.CPlusPlus14 ? "201304" : "200704"); Builder.defineMacro("__cpp_range_based_for", LangOpts.CPlusPlus1z ? "201603" : "200907"); @@ -491,6 +497,8 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, Builder.defineMacro("__cpp_ref_qualifiers", "200710"); Builder.defineMacro("__cpp_alias_templates", "200704"); } + if (LangOpts.ThreadsafeStatics) + Builder.defineMacro("__cpp_threadsafe_static_init", "200806"); // C++14 features. if (LangOpts.CPlusPlus14) { @@ -513,6 +521,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, Builder.defineMacro("__cpp_noexcept_function_type", "201510"); Builder.defineMacro("__cpp_capture_star_this", "201603"); Builder.defineMacro("__cpp_if_constexpr", "201606"); + Builder.defineMacro("__cpp_deduction_guides", "201611"); Builder.defineMacro("__cpp_template_auto", "201606"); Builder.defineMacro("__cpp_namespace_attributes", "201411"); Builder.defineMacro("__cpp_enumerator_attributes", "201411"); @@ -530,7 +539,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, if (LangOpts.ConceptsTS) Builder.defineMacro("__cpp_experimental_concepts", "1"); if (LangOpts.CoroutinesTS) - Builder.defineMacro("__cpp_coroutines", "1"); + Builder.defineMacro("__cpp_coroutines", "201703L"); } static void InitializePredefinedMacros(const TargetInfo &TI, @@ -593,9 +602,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("OBJC_ZEROCOST_EXCEPTIONS"); } - Builder.defineMacro("__OBJC_BOOL_IS_BOOL", - Twine(TI.useSignedCharForObjCBool() ? "0" : "1")); - if (LangOpts.getGC() != LangOptions::NonGC) Builder.defineMacro("__OBJC_GC__"); @@ -626,6 +632,11 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("IB_DESIGNABLE", ""); } + // Define a macro that describes the Objective-C boolean type even for C + // and C++ since BOOL can be used from non Objective-C code. + Builder.defineMacro("__OBJC_BOOL_IS_BOOL", + Twine(TI.useSignedCharForObjCBool() ? "0" : "1")); + if (LangOpts.CPlusPlus) InitializeCPlusPlusFeatureTestMacros(LangOpts, Builder); @@ -875,14 +886,16 @@ static void InitializePredefinedMacros(const TargetInfo &TI, // The value written by __atomic_test_and_set. // FIXME: This is target-dependent. Builder.defineMacro("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL", "1"); + } + auto addLockFreeMacros = [&](const llvm::Twine &Prefix) { // Used by libc++ and libstdc++ to implement ATOMIC_<foo>_LOCK_FREE. unsigned InlineWidthBits = TI.getMaxAtomicInlineWidth(); -#define DEFINE_LOCK_FREE_MACRO(TYPE, Type) \ - Builder.defineMacro("__GCC_ATOMIC_" #TYPE "_LOCK_FREE", \ - getLockFreeValue(TI.get##Type##Width(), \ - TI.get##Type##Align(), \ - InlineWidthBits)); +#define DEFINE_LOCK_FREE_MACRO(TYPE, Type) \ + Builder.defineMacro(Prefix + #TYPE "_LOCK_FREE", \ + getLockFreeValue(TI.get##Type##Width(), \ + TI.get##Type##Align(), \ + InlineWidthBits)); DEFINE_LOCK_FREE_MACRO(BOOL, Bool); DEFINE_LOCK_FREE_MACRO(CHAR, Char); DEFINE_LOCK_FREE_MACRO(CHAR16_T, Char16); @@ -892,12 +905,15 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DEFINE_LOCK_FREE_MACRO(INT, Int); DEFINE_LOCK_FREE_MACRO(LONG, Long); DEFINE_LOCK_FREE_MACRO(LLONG, LongLong); - Builder.defineMacro("__GCC_ATOMIC_POINTER_LOCK_FREE", + Builder.defineMacro(Prefix + "POINTER_LOCK_FREE", getLockFreeValue(TI.getPointerWidth(0), TI.getPointerAlign(0), InlineWidthBits)); #undef DEFINE_LOCK_FREE_MACRO - } + }; + addLockFreeMacros("__CLANG_ATOMIC_"); + if (!LangOpts.MSVCCompat) + addLockFreeMacros("__GCC_ATOMIC_"); if (LangOpts.NoInlineDefine) Builder.defineMacro("__NO_INLINE__"); @@ -1029,7 +1045,9 @@ void clang::InitializePreprocessor( // Install things like __POWERPC__, __GNUC__, etc into the macro table. if (InitOpts.UsePredefines) { - if (LangOpts.CUDA && PP.getAuxTargetInfo()) + // FIXME: This will create multiple definitions for most of the predefined + // macros. This is not the right way to handle this. + if ((LangOpts.CUDA || LangOpts.OpenMPIsDevice) && PP.getAuxTargetInfo()) InitializePredefinedMacros(*PP.getAuxTargetInfo(), LangOpts, FEOpts, Builder); diff --git a/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp b/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp index f133327..47023e5 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp @@ -13,15 +13,15 @@ using namespace clang; using namespace clang::frontend; -#define LANGSTANDARD(id, name, desc, features) \ - static const LangStandard Lang_##id = { name, desc, features }; +#define LANGSTANDARD(id, name, lang, desc, features) \ +static const LangStandard Lang_##id = { name, desc, features, InputKind::lang }; #include "clang/Frontend/LangStandards.def" const LangStandard &LangStandard::getLangStandardForKind(Kind K) { switch (K) { case lang_unspecified: llvm::report_fatal_error("getLangStandardForKind() on unspecified kind"); -#define LANGSTANDARD(id, name, desc, features) \ +#define LANGSTANDARD(id, name, lang, desc, features) \ case lang_##id: return Lang_##id; #include "clang/Frontend/LangStandards.def" } @@ -30,7 +30,7 @@ const LangStandard &LangStandard::getLangStandardForKind(Kind K) { const LangStandard *LangStandard::getLangStandardForName(StringRef Name) { Kind K = llvm::StringSwitch<Kind>(Name) -#define LANGSTANDARD(id, name, desc, features) \ +#define LANGSTANDARD(id, name, lang, desc, features) \ .Case(name, lang_##id) #include "clang/Frontend/LangStandards.def" .Default(lang_unspecified); diff --git a/contrib/llvm/tools/clang/lib/Frontend/ModuleDependencyCollector.cpp b/contrib/llvm/tools/clang/lib/Frontend/ModuleDependencyCollector.cpp index 9b34d42..ede12aa 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/ModuleDependencyCollector.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/ModuleDependencyCollector.cpp @@ -248,7 +248,7 @@ std::error_code ModuleDependencyCollector::copyToRoot(StringRef Src, // Always map a canonical src path to its real path into the YAML, by doing // this we map different virtual src paths to the same entry in the VFS // overlay, which is a way to emulate symlink inside the VFS; this is also - // needed for correctness, not doing that can lead to module redifinition + // needed for correctness, not doing that can lead to module redefinition // errors. addFileMapping(VirtualPath, CacheDst); return std::error_code(); diff --git a/contrib/llvm/tools/clang/lib/Frontend/PrecompiledPreamble.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrecompiledPreamble.cpp new file mode 100644 index 0000000..15b24cb --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/PrecompiledPreamble.cpp @@ -0,0 +1,563 @@ +//===--- PrecompiledPreamble.cpp - Build precompiled preambles --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Helper class to build precompiled preamble. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/PrecompiledPreamble.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/FrontendOptions.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/PreprocessorOptions.h" +#include "clang/Serialization/ASTWriter.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Support/CrashRecoveryContext.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/MutexGuard.h" + +using namespace clang; + +namespace { + +/// Keeps a track of files to be deleted in destructor. +class TemporaryFiles { +public: + // A static instance to be used by all clients. + static TemporaryFiles &getInstance(); + +private: + // Disallow constructing the class directly. + TemporaryFiles() = default; + // Disallow copy. + TemporaryFiles(const TemporaryFiles &) = delete; + +public: + ~TemporaryFiles(); + + /// Adds \p File to a set of tracked files. + void addFile(StringRef File); + + /// Remove \p File from disk and from the set of tracked files. + void removeFile(StringRef File); + +private: + llvm::sys::SmartMutex<false> Mutex; + llvm::StringSet<> Files; +}; + +TemporaryFiles &TemporaryFiles::getInstance() { + static TemporaryFiles Instance; + return Instance; +} + +TemporaryFiles::~TemporaryFiles() { + llvm::MutexGuard Guard(Mutex); + for (const auto &File : Files) + llvm::sys::fs::remove(File.getKey()); +} + +void TemporaryFiles::addFile(StringRef File) { + llvm::MutexGuard Guard(Mutex); + auto IsInserted = Files.insert(File).second; + (void)IsInserted; + assert(IsInserted && "File has already been added"); +} + +void TemporaryFiles::removeFile(StringRef File) { + llvm::MutexGuard Guard(Mutex); + auto WasPresent = Files.erase(File); + (void)WasPresent; + assert(WasPresent && "File was not tracked"); + llvm::sys::fs::remove(File); +} + +class PreambleMacroCallbacks : public PPCallbacks { +public: + PreambleMacroCallbacks(PreambleCallbacks &Callbacks) : Callbacks(Callbacks) {} + + void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override { + Callbacks.HandleMacroDefined(MacroNameTok, MD); + } + +private: + PreambleCallbacks &Callbacks; +}; + +class PrecompilePreambleAction : public ASTFrontendAction { +public: + PrecompilePreambleAction(PreambleCallbacks &Callbacks) + : Callbacks(Callbacks) {} + + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; + + bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; } + + void setEmittedPreamblePCH(ASTWriter &Writer) { + this->HasEmittedPreamblePCH = true; + Callbacks.AfterPCHEmitted(Writer); + } + + bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); } + bool hasCodeCompletionSupport() const override { return false; } + bool hasASTFileSupport() const override { return false; } + TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; } + +private: + friend class PrecompilePreambleConsumer; + + bool HasEmittedPreamblePCH = false; + PreambleCallbacks &Callbacks; +}; + +class PrecompilePreambleConsumer : public PCHGenerator { +public: + PrecompilePreambleConsumer(PrecompilePreambleAction &Action, + const Preprocessor &PP, StringRef isysroot, + std::unique_ptr<raw_ostream> Out) + : PCHGenerator(PP, "", isysroot, std::make_shared<PCHBuffer>(), + ArrayRef<std::shared_ptr<ModuleFileExtension>>(), + /*AllowASTWithErrors=*/true), + Action(Action), Out(std::move(Out)) {} + + bool HandleTopLevelDecl(DeclGroupRef DG) override { + Action.Callbacks.HandleTopLevelDecl(DG); + return true; + } + + void HandleTranslationUnit(ASTContext &Ctx) override { + PCHGenerator::HandleTranslationUnit(Ctx); + if (!hasEmittedPCH()) + return; + + // Write the generated bitstream to "Out". + *Out << getPCH(); + // Make sure it hits disk now. + Out->flush(); + // Free the buffer. + llvm::SmallVector<char, 0> Empty; + getPCH() = std::move(Empty); + + Action.setEmittedPreamblePCH(getWriter()); + } + +private: + PrecompilePreambleAction &Action; + std::unique_ptr<raw_ostream> Out; +}; + +std::unique_ptr<ASTConsumer> +PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI, + + StringRef InFile) { + std::string Sysroot; + std::string OutputFile; + std::unique_ptr<raw_ostream> OS = + GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot, + OutputFile); + if (!OS) + return nullptr; + + if (!CI.getFrontendOpts().RelocatablePCH) + Sysroot.clear(); + + CI.getPreprocessor().addPPCallbacks( + llvm::make_unique<PreambleMacroCallbacks>(Callbacks)); + return llvm::make_unique<PrecompilePreambleConsumer>( + *this, CI.getPreprocessor(), Sysroot, std::move(OS)); +} + +template <class T> bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) { + if (!Val) + return false; + Output = std::move(*Val); + return true; +} + +} // namespace + +PreambleBounds clang::ComputePreambleBounds(const LangOptions &LangOpts, + llvm::MemoryBuffer *Buffer, + unsigned MaxLines) { + auto Pre = Lexer::ComputePreamble(Buffer->getBuffer(), LangOpts, MaxLines); + return PreambleBounds(Pre.first, Pre.second); +} + +llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build( + const CompilerInvocation &Invocation, + const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, + DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr<vfs::FileSystem> VFS, + std::shared_ptr<PCHContainerOperations> PCHContainerOps, + PreambleCallbacks &Callbacks) { + assert(VFS && "VFS is null"); + + if (!Bounds.Size) + return BuildPreambleError::PreambleIsEmpty; + + auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation); + FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts(); + PreprocessorOptions &PreprocessorOpts = + PreambleInvocation->getPreprocessorOpts(); + + // Create a temporary file for the precompiled preamble. In rare + // circumstances, this can fail. + llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> PreamblePCHFile = + PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile(); + if (!PreamblePCHFile) + return BuildPreambleError::CouldntCreateTempFile; + + // Save the preamble text for later; we'll need to compare against it for + // subsequent reparses. + std::vector<char> PreambleBytes(MainFileBuffer->getBufferStart(), + MainFileBuffer->getBufferStart() + + Bounds.Size); + bool PreambleEndsAtStartOfLine = Bounds.PreambleEndsAtStartOfLine; + + // Tell the compiler invocation to generate a temporary precompiled header. + FrontendOpts.ProgramAction = frontend::GeneratePCH; + // FIXME: Generate the precompiled header into memory? + FrontendOpts.OutputFile = PreamblePCHFile->getFilePath(); + PreprocessorOpts.PrecompiledPreambleBytes.first = 0; + PreprocessorOpts.PrecompiledPreambleBytes.second = false; + + // Create the compiler instance to use for building the precompiled preamble. + std::unique_ptr<CompilerInstance> Clang( + new CompilerInstance(std::move(PCHContainerOps))); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup( + Clang.get()); + + Clang->setInvocation(std::move(PreambleInvocation)); + Clang->setDiagnostics(&Diagnostics); + + // Create the target instance. + Clang->setTarget(TargetInfo::CreateTargetInfo( + Clang->getDiagnostics(), Clang->getInvocation().TargetOpts)); + if (!Clang->hasTarget()) + return BuildPreambleError::CouldntCreateTargetInfo; + + // Inform the target of the language options. + // + // FIXME: We shouldn't need to do this, the target should be immutable once + // created. This complexity should be lifted elsewhere. + Clang->getTarget().adjust(Clang->getLangOpts()); + + assert(Clang->getFrontendOpts().Inputs.size() == 1 && + "Invocation must have exactly one source file!"); + assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() == + InputKind::Source && + "FIXME: AST inputs not yet supported here!"); + assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() != + InputKind::LLVM_IR && + "IR inputs not support here!"); + + // Clear out old caches and data. + Diagnostics.Reset(); + ProcessWarningOptions(Diagnostics, Clang->getDiagnosticOpts()); + + VFS = + createVFSFromCompilerInvocation(Clang->getInvocation(), Diagnostics, VFS); + if (!VFS) + return BuildPreambleError::CouldntCreateVFSOverlay; + + // Create a file manager object to provide access to and cache the filesystem. + Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS)); + + // Create the source manager. + Clang->setSourceManager( + new SourceManager(Diagnostics, Clang->getFileManager())); + + auto PreambleDepCollector = std::make_shared<DependencyCollector>(); + Clang->addDependencyCollector(PreambleDepCollector); + + // Remap the main source file to the preamble buffer. + StringRef MainFilePath = FrontendOpts.Inputs[0].getFile(); + auto PreambleInputBuffer = llvm::MemoryBuffer::getMemBufferCopy( + MainFileBuffer->getBuffer().slice(0, Bounds.Size), MainFilePath); + if (PreprocessorOpts.RetainRemappedFileBuffers) { + // MainFileBuffer will be deleted by unique_ptr after leaving the method. + PreprocessorOpts.addRemappedFile(MainFilePath, PreambleInputBuffer.get()); + } else { + // In that case, remapped buffer will be deleted by CompilerInstance on + // BeginSourceFile, so we call release() to avoid double deletion. + PreprocessorOpts.addRemappedFile(MainFilePath, + PreambleInputBuffer.release()); + } + + std::unique_ptr<PrecompilePreambleAction> Act; + Act.reset(new PrecompilePreambleAction(Callbacks)); + if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) + return BuildPreambleError::BeginSourceFileFailed; + + Act->Execute(); + + // Run the callbacks. + Callbacks.AfterExecute(*Clang); + + Act->EndSourceFile(); + + if (!Act->hasEmittedPreamblePCH()) + return BuildPreambleError::CouldntEmitPCH; + + // Keep track of all of the files that the source manager knows about, + // so we can verify whether they have changed or not. + llvm::StringMap<PrecompiledPreamble::PreambleFileHash> FilesInPreamble; + + SourceManager &SourceMgr = Clang->getSourceManager(); + for (auto &Filename : PreambleDepCollector->getDependencies()) { + const FileEntry *File = Clang->getFileManager().getFile(Filename); + if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID())) + continue; + if (time_t ModTime = File->getModificationTime()) { + FilesInPreamble[File->getName()] = + PrecompiledPreamble::PreambleFileHash::createForFile(File->getSize(), + ModTime); + } else { + llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File); + FilesInPreamble[File->getName()] = + PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer); + } + } + + return PrecompiledPreamble( + std::move(*PreamblePCHFile), std::move(PreambleBytes), + PreambleEndsAtStartOfLine, std::move(FilesInPreamble)); +} + +PreambleBounds PrecompiledPreamble::getBounds() const { + return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine); +} + +bool PrecompiledPreamble::CanReuse(const CompilerInvocation &Invocation, + const llvm::MemoryBuffer *MainFileBuffer, + PreambleBounds Bounds, + vfs::FileSystem *VFS) const { + + assert( + Bounds.Size <= MainFileBuffer->getBufferSize() && + "Buffer is too large. Bounds were calculated from a different buffer?"); + + auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation); + PreprocessorOptions &PreprocessorOpts = + PreambleInvocation->getPreprocessorOpts(); + + if (!Bounds.Size) + return false; + + // We've previously computed a preamble. Check whether we have the same + // preamble now that we did before, and that there's enough space in + // the main-file buffer within the precompiled preamble to fit the + // new main file. + if (PreambleBytes.size() != Bounds.Size || + PreambleEndsAtStartOfLine != Bounds.PreambleEndsAtStartOfLine || + memcmp(PreambleBytes.data(), MainFileBuffer->getBufferStart(), + Bounds.Size) != 0) + return false; + // The preamble has not changed. We may be able to re-use the precompiled + // preamble. + + // Check that none of the files used by the preamble have changed. + // First, make a record of those files that have been overridden via + // remapping or unsaved_files. + std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles; + for (const auto &R : PreprocessorOpts.RemappedFiles) { + vfs::Status Status; + if (!moveOnNoError(VFS->status(R.second), Status)) { + // If we can't stat the file we're remapping to, assume that something + // horrible happened. + return false; + } + + OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile( + Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime())); + } + + for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) { + vfs::Status Status; + if (!moveOnNoError(VFS->status(RB.first), Status)) + return false; + + OverriddenFiles[Status.getUniqueID()] = + PreambleFileHash::createForMemoryBuffer(RB.second); + } + + // Check whether anything has changed. + for (const auto &F : FilesInPreamble) { + vfs::Status Status; + if (!moveOnNoError(VFS->status(F.first()), Status)) { + // If we can't stat the file, assume that something horrible happened. + return false; + } + + std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden = + OverriddenFiles.find(Status.getUniqueID()); + if (Overridden != OverriddenFiles.end()) { + // This file was remapped; check whether the newly-mapped file + // matches up with the previous mapping. + if (Overridden->second != F.second) + return false; + continue; + } + + // The file was not remapped; check whether it has changed on disk. + if (Status.getSize() != uint64_t(F.second.Size) || + llvm::sys::toTimeT(Status.getLastModificationTime()) != + F.second.ModTime) + return false; + } + return true; +} + +void PrecompiledPreamble::AddImplicitPreamble( + CompilerInvocation &CI, llvm::MemoryBuffer *MainFileBuffer) const { + auto &PreprocessorOpts = CI.getPreprocessorOpts(); + + // Configure ImpicitPCHInclude. + PreprocessorOpts.PrecompiledPreambleBytes.first = PreambleBytes.size(); + PreprocessorOpts.PrecompiledPreambleBytes.second = PreambleEndsAtStartOfLine; + PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath(); + PreprocessorOpts.DisablePCHValidation = true; + + // Remap main file to point to MainFileBuffer. + auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile(); + PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer); +} + +PrecompiledPreamble::PrecompiledPreamble( + TempPCHFile PCHFile, std::vector<char> PreambleBytes, + bool PreambleEndsAtStartOfLine, + llvm::StringMap<PreambleFileHash> FilesInPreamble) + : PCHFile(std::move(PCHFile)), FilesInPreamble(FilesInPreamble), + PreambleBytes(std::move(PreambleBytes)), + PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {} + +llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> +PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() { + // FIXME: This is a hack so that we can override the preamble file during + // crash-recovery testing, which is the only case where the preamble files + // are not necessarily cleaned up. + const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE"); + if (TmpFile) + return TempPCHFile::createFromCustomPath(TmpFile); + return TempPCHFile::createInSystemTempDir("preamble", "pch"); +} + +llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> +PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix, + StringRef Suffix) { + llvm::SmallString<64> File; + auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, /*ref*/ File); + if (EC) + return EC; + return TempPCHFile(std::move(File).str()); +} + +llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> +PrecompiledPreamble::TempPCHFile::createFromCustomPath(const Twine &Path) { + return TempPCHFile(Path.str()); +} + +PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath) + : FilePath(std::move(FilePath)) { + TemporaryFiles::getInstance().addFile(*this->FilePath); +} + +PrecompiledPreamble::TempPCHFile::TempPCHFile(TempPCHFile &&Other) { + FilePath = std::move(Other.FilePath); + Other.FilePath = None; +} + +PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::TempPCHFile:: +operator=(TempPCHFile &&Other) { + RemoveFileIfPresent(); + + FilePath = std::move(Other.FilePath); + Other.FilePath = None; + return *this; +} + +PrecompiledPreamble::TempPCHFile::~TempPCHFile() { RemoveFileIfPresent(); } + +void PrecompiledPreamble::TempPCHFile::RemoveFileIfPresent() { + if (FilePath) { + TemporaryFiles::getInstance().removeFile(*FilePath); + FilePath = None; + } +} + +llvm::StringRef PrecompiledPreamble::TempPCHFile::getFilePath() const { + assert(FilePath && "TempPCHFile doesn't have a FilePath. Had it been moved?"); + return *FilePath; +} + +PrecompiledPreamble::PreambleFileHash +PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size, + time_t ModTime) { + PreambleFileHash Result; + Result.Size = Size; + Result.ModTime = ModTime; + Result.MD5 = {}; + return Result; +} + +PrecompiledPreamble::PreambleFileHash +PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer( + const llvm::MemoryBuffer *Buffer) { + PreambleFileHash Result; + Result.Size = Buffer->getBufferSize(); + Result.ModTime = 0; + + llvm::MD5 MD5Ctx; + MD5Ctx.update(Buffer->getBuffer().data()); + MD5Ctx.final(Result.MD5); + + return Result; +} + +void PreambleCallbacks::AfterExecute(CompilerInstance &CI) {} +void PreambleCallbacks::AfterPCHEmitted(ASTWriter &Writer) {} +void PreambleCallbacks::HandleTopLevelDecl(DeclGroupRef DG) {} +void PreambleCallbacks::HandleMacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) {} + +std::error_code clang::make_error_code(BuildPreambleError Error) { + return std::error_code(static_cast<int>(Error), BuildPreambleErrorCategory()); +} + +const char *BuildPreambleErrorCategory::name() const noexcept { + return "build-preamble.error"; +} + +std::string BuildPreambleErrorCategory::message(int condition) const { + switch (static_cast<BuildPreambleError>(condition)) { + case BuildPreambleError::PreambleIsEmpty: + return "Preamble is empty"; + case BuildPreambleError::CouldntCreateTempFile: + return "Could not create temporary file for PCH"; + case BuildPreambleError::CouldntCreateTargetInfo: + return "CreateTargetInfo() return null"; + case BuildPreambleError::CouldntCreateVFSOverlay: + return "Could not create VFS Overlay"; + case BuildPreambleError::BeginSourceFileFailed: + return "BeginSourceFile() return an error"; + case BuildPreambleError::CouldntEmitPCH: + return "Could not emit PCH"; + } + llvm_unreachable("unexpected BuildPreambleError"); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp index d48b952..914039a 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp @@ -38,8 +38,8 @@ static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI, if (MI.isFunctionLike()) { OS << '('; - if (!MI.arg_empty()) { - MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end(); + if (!MI.param_empty()) { + MacroInfo::param_iterator AI = MI.param_begin(), E = MI.param_end(); for (; AI+1 != E; ++AI) { OS << (*AI)->getName(); OS << ','; @@ -172,7 +172,11 @@ public: /// MacroUndefined - This hook is called whenever a macro #undef is seen. void MacroUndefined(const Token &MacroNameTok, - const MacroDefinition &MD) override; + const MacroDefinition &MD, + const MacroDirective *Undef) override; + + void BeginModule(const Module *M); + void EndModule(const Module *M); }; } // end anonymous namespace @@ -323,47 +327,68 @@ void PrintPPOutputPPCallbacks::InclusionDirective(SourceLocation HashLoc, StringRef SearchPath, StringRef RelativePath, const Module *Imported) { - if (Imported) { - // When preprocessing, turn implicit imports into @imports. - // FIXME: This is a stop-gap until a more comprehensive "preprocessing with - // modules" solution is introduced. + // In -dI mode, dump #include directives prior to dumping their content or + // interpretation. + if (DumpIncludeDirectives) { startNewLineIfNeeded(); MoveToLine(HashLoc); - if (PP.getLangOpts().ObjC2) { - OS << "@import " << Imported->getFullModuleName() << ";" - << " /* clang -E: implicit import for \"" << File->getName() - << "\" */"; - } else { - const std::string TokenText = PP.getSpelling(IncludeTok); - assert(!TokenText.empty()); - OS << "#" << TokenText << " " - << (IsAngled ? '<' : '"') - << FileName - << (IsAngled ? '>' : '"') - << " /* clang -E: implicit import for module " - << Imported->getFullModuleName() << " */"; - } - // Since we want a newline after the @import, but not a #<line>, start a new - // line immediately. - EmittedTokensOnThisLine = true; + const std::string TokenText = PP.getSpelling(IncludeTok); + assert(!TokenText.empty()); + OS << "#" << TokenText << " " + << (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"') + << " /* clang -E -dI */"; + setEmittedDirectiveOnThisLine(); startNewLineIfNeeded(); - } else { - // Not a module import; it's a more vanilla inclusion of some file using one - // of: #include, #import, #include_next, #include_macros. - if (DumpIncludeDirectives) { + } + + // When preprocessing, turn implicit imports into module import pragmas. + if (Imported) { + switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) { + case tok::pp_include: + case tok::pp_import: + case tok::pp_include_next: startNewLineIfNeeded(); MoveToLine(HashLoc); - const std::string TokenText = PP.getSpelling(IncludeTok); - assert(!TokenText.empty()); - OS << "#" << TokenText << " " + OS << "#pragma clang module import " << Imported->getFullModuleName(true) + << " /* clang -E: implicit import for " + << "#" << PP.getSpelling(IncludeTok) << " " << (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"') - << " /* clang -E -dI */"; - setEmittedDirectiveOnThisLine(); + << " */"; + // Since we want a newline after the pragma, but not a #<line>, start a + // new line immediately. + EmittedTokensOnThisLine = true; startNewLineIfNeeded(); + break; + + case tok::pp___include_macros: + // #__include_macros has no effect on a user of a preprocessed source + // file; the only effect is on preprocessing. + // + // FIXME: That's not *quite* true: it causes the module in question to + // be loaded, which can affect downstream diagnostics. + break; + + default: + llvm_unreachable("unknown include directive kind"); + break; } } } +/// 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(true); + 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(true) << "*/"; + setEmittedDirectiveOnThisLine(); +} + /// Ident - Handle #ident directives when read by the preprocessor. /// void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, StringRef S) { @@ -389,7 +414,8 @@ void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok, } void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok, - const MacroDefinition &MD) { + const MacroDefinition &MD, + const MacroDirective *Undef) { // Only print out macro definitions in -dD mode. if (!DumpDefines) return; @@ -676,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() && @@ -773,26 +813,33 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS, // Expand macros in pragmas with -fms-extensions. The assumption is that // the majority of pragmas in such a file will be Microsoft pragmas. - PP.AddPragmaHandler(new UnknownPragmaHandler( - "#pragma", Callbacks, + // Remember the handlers we will add so that we can remove them later. + std::unique_ptr<UnknownPragmaHandler> MicrosoftExtHandler( + new UnknownPragmaHandler( + "#pragma", Callbacks, + /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); + + std::unique_ptr<UnknownPragmaHandler> GCCHandler(new UnknownPragmaHandler( + "#pragma GCC", Callbacks, /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); - PP.AddPragmaHandler( - "GCC", new UnknownPragmaHandler( - "#pragma GCC", Callbacks, - /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); - PP.AddPragmaHandler( - "clang", new UnknownPragmaHandler( - "#pragma clang", Callbacks, - /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); + + std::unique_ptr<UnknownPragmaHandler> ClangHandler(new UnknownPragmaHandler( + "#pragma clang", Callbacks, + /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); + + PP.AddPragmaHandler(MicrosoftExtHandler.get()); + PP.AddPragmaHandler("GCC", GCCHandler.get()); + PP.AddPragmaHandler("clang", ClangHandler.get()); // The tokens after pragma omp need to be expanded. // // OpenMP [2.1, Directive format] // Preprocessing tokens following the #pragma omp are subject to macro // replacement. - PP.AddPragmaHandler("omp", - new UnknownPragmaHandler("#pragma omp", Callbacks, - /*RequireTokenExpansion=*/true)); + std::unique_ptr<UnknownPragmaHandler> OpenMPHandler( + new UnknownPragmaHandler("#pragma omp", Callbacks, + /*RequireTokenExpansion=*/true)); + PP.AddPragmaHandler("omp", OpenMPHandler.get()); PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks)); @@ -820,4 +867,11 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS, // Read all the preprocessed tokens, printing them out to the stream. PrintPreprocessedTokens(PP, Tok, Callbacks, *OS); *OS << '\n'; + + // Remove the handlers we just added to leave the preprocessor in a sane state + // so that it can be reused (for example by a clang::Parser instance). + PP.RemovePragmaHandler(MicrosoftExtHandler.get()); + PP.RemovePragmaHandler("GCC", GCCHandler.get()); + PP.RemovePragmaHandler("clang", ClangHandler.get()); + PP.RemovePragmaHandler("omp", OpenMPHandler.get()); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp index 2e76e2e..5efa6ae 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp @@ -9,6 +9,8 @@ #include "clang/Rewrite/Frontend/FrontendActions.h" #include "clang/AST/ASTConsumer.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Config/config.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" @@ -18,6 +20,11 @@ #include "clang/Rewrite/Frontend/ASTConsumers.h" #include "clang/Rewrite/Frontend/FixItRewriter.h" #include "clang/Rewrite/Frontend/Rewriters.h" +#include "clang/Serialization/ASTReader.h" +#include "clang/Serialization/Module.h" +#include "clang/Serialization/ModuleManager.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" @@ -86,8 +93,7 @@ public: }; } // end anonymous namespace -bool FixItAction::BeginSourceFileAction(CompilerInstance &CI, - StringRef Filename) { +bool FixItAction::BeginSourceFileAction(CompilerInstance &CI) { const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts(); if (!FEOpts.FixItSuffix.empty()) { FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix, @@ -190,12 +196,123 @@ void RewriteTestAction::ExecuteAction() { DoRewriteTest(CI.getPreprocessor(), OS.get()); } +class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener { + CompilerInstance &CI; + std::weak_ptr<raw_ostream> Out; + + llvm::DenseSet<const FileEntry*> Rewritten; + +public: + RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out) + : CI(CI), Out(Out) {} + + void visitModuleFile(StringRef Filename, + serialization::ModuleKind Kind) override { + auto *File = CI.getFileManager().getFile(Filename); + assert(File && "missing file for loaded module?"); + + // Only rewrite each module file once. + if (!Rewritten.insert(File).second) + return; + + serialization::ModuleFile *MF = + CI.getModuleManager()->getModuleManager().lookup(File); + assert(File && "missing module file for loaded module?"); + + // Not interested in PCH / preambles. + if (!MF->isModule()) + return; + + auto OS = Out.lock(); + assert(OS && "loaded module file after finishing rewrite action?"); + + (*OS) << "#pragma clang module build "; + if (isValidIdentifier(MF->ModuleName)) + (*OS) << MF->ModuleName; + else { + (*OS) << '"'; + OS->write_escaped(MF->ModuleName); + (*OS) << '"'; + } + (*OS) << '\n'; + + // Rewrite the contents of the module in a separate compiler instance. + CompilerInstance Instance(CI.getPCHContainerOperations(), + &CI.getPreprocessor().getPCMCache()); + Instance.setInvocation( + std::make_shared<CompilerInvocation>(CI.getInvocation())); + Instance.createDiagnostics( + new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()), + /*ShouldOwnClient=*/true); + Instance.getFrontendOpts().DisableFree = false; + Instance.getFrontendOpts().Inputs.clear(); + Instance.getFrontendOpts().Inputs.emplace_back( + Filename, InputKind(InputKind::Unknown, InputKind::Precompiled)); + Instance.getFrontendOpts().ModuleFiles.clear(); + Instance.getFrontendOpts().ModuleMapFiles.clear(); + // Don't recursively rewrite imports. We handle them all at the top level. + Instance.getPreprocessorOutputOpts().RewriteImports = false; + + llvm::CrashRecoveryContext().RunSafelyOnThread([&]() { + RewriteIncludesAction Action; + Action.OutputStream = OS; + Instance.ExecuteAction(Action); + }); + + (*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n"; + } +}; + +bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) { + if (!OutputStream) { + OutputStream = CI.createDefaultOutputFile(true, getCurrentFile()); + if (!OutputStream) + return false; + } + + auto &OS = *OutputStream; + + // 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 \""; + OS.write_escaped(Input.getFile()); + OS << "\"\n"; + } + getCurrentModule()->print(OS); + OS << "#pragma clang module contents\n"; + } + + // If we're rewriting imports, set up a listener to track when we import + // module files. + if (CI.getPreprocessorOutputOpts().RewriteImports) { + CI.createModuleManager(); + CI.getModuleManager()->addListener( + llvm::make_unique<RewriteImportsListener>(CI, OutputStream)); + } + + return true; +} + void RewriteIncludesAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); - std::unique_ptr<raw_ostream> OS = - CI.createDefaultOutputFile(true, getCurrentFile()); - if (!OS) return; - RewriteIncludesInInput(CI.getPreprocessor(), OS.get(), - CI.getPreprocessorOutputOpts()); + // If we're rewriting imports, emit the module build output first rather + // than switching back and forth (potentially in the middle of a line). + if (CI.getPreprocessorOutputOpts().RewriteImports) { + std::string Buffer; + llvm::raw_string_ostream OS(Buffer); + + RewriteIncludesInInput(CI.getPreprocessor(), &OS, + CI.getPreprocessorOutputOpts()); + + (*OutputStream) << OS.str(); + } else { + RewriteIncludesInInput(CI.getPreprocessor(), OutputStream.get(), + CI.getPreprocessorOutputOpts()); + } + + OutputStream.reset(); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp index d953da2..e047706 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp @@ -46,17 +46,24 @@ 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; public: InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers, bool UseLineDirectives); - bool Process(FileID FileId, SrcMgr::CharacteristicKind FileType); + void Process(FileID FileId, SrcMgr::CharacteristicKind FileType); void setPredefinesBuffer(const llvm::MemoryBuffer *Buf) { 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); }; @@ -132,7 +140,7 @@ void InclusionRewriter::WriteLineInfo(StringRef Filename, int Line, } void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod) { - OS << "@import " << Mod->getFullModuleName() << ";" + OS << "#pragma clang module import " << Mod->getFullModuleName(true) << " /* clang -frewrite-includes: implicit import */" << MainEOL; } @@ -169,7 +177,9 @@ void InclusionRewriter::FileSkipped(const FileEntry &/*SkippedFile*/, /// directives. It does not say whether the file has been included, but it /// provides more information about the directive (hash location instead /// of location inside the included file). It is assumed that the matching -/// FileChanged() or FileSkipped() is called after this. +/// FileChanged() or FileSkipped() is called after this (or neither is +/// called if this #include results in an error or does not textually include +/// anything). void InclusionRewriter::InclusionDirective(SourceLocation HashLoc, const Token &/*IncludeTok*/, StringRef /*FileName*/, @@ -179,9 +189,6 @@ void InclusionRewriter::InclusionDirective(SourceLocation HashLoc, StringRef /*SearchPath*/, StringRef /*RelativePath*/, const Module *Imported) { - assert(LastInclusionLocation.isInvalid() && - "Another inclusion directive was found before the previous one " - "was processed"); if (Imported) { auto P = ModuleIncludes.insert( std::make_pair(HashLoc.getRawEncoding(), Imported)); @@ -211,6 +218,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) { @@ -392,7 +409,7 @@ bool InclusionRewriter::HandleHasInclude( // FIXME: Why don't we call PP.LookupFile here? const FileEntry *File = PP.getHeaderSearchInfo().LookupFile( Filename, SourceLocation(), isAngled, nullptr, CurDir, Includers, nullptr, - nullptr, nullptr, nullptr, false); + nullptr, nullptr, nullptr, nullptr); FileExists = File != nullptr; return true; @@ -400,9 +417,8 @@ bool InclusionRewriter::HandleHasInclude( /// Use a raw lexer to analyze \p FileId, incrementally copying parts of it /// and including content of included files recursively. -bool InclusionRewriter::Process(FileID FileId, - SrcMgr::CharacteristicKind FileType) -{ +void InclusionRewriter::Process(FileID FileId, + SrcMgr::CharacteristicKind FileType) { bool Invalid; const MemoryBuffer &FromFile = *SM.getBuffer(FileId, &Invalid); assert(!Invalid && "Attempting to process invalid inclusion"); @@ -419,7 +435,7 @@ bool InclusionRewriter::Process(FileID FileId, WriteLineInfo(FileName, 1, FileType, " 1"); if (SM.getFileIDSize(FileId) == 0) - return false; + return; // The next byte to be copied from the source file, which may be non-zero if // the lexer handled a BOM. @@ -450,19 +466,24 @@ bool InclusionRewriter::Process(FileID FileId, WriteLineInfo(FileName, Line - 1, FileType, ""); StringRef LineInfoExtra; SourceLocation Loc = HashToken.getLocation(); - if (const Module *Mod = PP.getLangOpts().ObjC2 - ? FindModuleAtLocation(Loc) - : nullptr) + if (const Module *Mod = FindModuleAtLocation(Loc)) WriteImplicitModuleImport(Mod); else if (const IncludedFile *Inc = FindIncludeAtLocation(Loc)) { - // include and recursively process the file - if (Process(Inc->Id, Inc->FileType)) { - // and set lineinfo back to this file, if the nested one was - // actually included - // `2' indicates returning to a file (after having included - // another file. - LineInfoExtra = " 2"; - } + const Module *Mod = FindEnteredModule(Loc); + if (Mod) + OS << "#pragma clang module begin " + << Mod->getFullModuleName(true) << "\n"; + + // Include and recursively process the file. + Process(Inc->Id, Inc->FileType); + + if (Mod) + OS << "#pragma clang module end /*" + << Mod->getFullModuleName(true) << "*/\n"; + + // Add line marker to indicate we're returning from an included + // file. + LineInfoExtra = " 2"; } // fix up lineinfo (since commented out directive changed line // numbers) for inclusions that were skipped due to header guards @@ -571,7 +592,6 @@ bool InclusionRewriter::Process(FileID FileId, OutputContentUpTo(FromFile, NextToWrite, SM.getFileOffset(SM.getLocForEndOfFile(FileId)), LocalEOL, Line, /*EnsureNewline=*/true); - return true; } /// InclusionRewriterInInput - Implement -frewrite-includes mode. @@ -597,6 +617,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); diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteMacros.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteMacros.cpp index 0d0a991..ae6b51b 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteMacros.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteMacros.cpp @@ -76,7 +76,7 @@ static void LexRawTokensFromMainFile(Preprocessor &PP, RawLex.LexFromRawLexer(RawTok); // If we have an identifier with no identifier info for our raw token, look - // up the indentifier info. This is important for equality comparison of + // up the identifier info. This is important for equality comparison of // identifier tokens. if (RawTok.is(tok::raw_identifier)) PP.LookUpIdentifierInfo(RawTok); diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp index e7bfced..21686b8 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -21,6 +21,7 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Config/config.h" #include "clang/Lex/Lexer.h" #include "clang/Rewrite/Core/Rewriter.h" #include "llvm/ADT/DenseSet.h" @@ -146,7 +147,7 @@ namespace { llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs; llvm::DenseMap<ObjCInterfaceDecl *, - llvm::SmallPtrSet<ObjCIvarDecl *, 8> > ReferencedIvars; + llvm::SmallSetVector<ObjCIvarDecl *, 8> > ReferencedIvars; // ivar bitfield grouping containers llvm::DenseSet<const ObjCInterfaceDecl *> ObjCInterefaceHasBitfieldGroups; @@ -1013,7 +1014,7 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, Setr = "\nextern \"C\" __declspec(dllimport) " "void objc_setProperty (id, SEL, long, id, bool, bool);\n"; } - + RewriteObjCMethodDecl(OID->getContainingInterface(), PD->getSetterMethodDecl(), Setr); Setr += "{ "; @@ -3965,10 +3966,11 @@ void RewriteModernObjC::RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl, std::string &Result) { // write out ivar offset symbols which have been referenced in an ivar // access expression. - llvm::SmallPtrSet<ObjCIvarDecl *, 8> Ivars = ReferencedIvars[CDecl]; + llvm::SmallSetVector<ObjCIvarDecl *, 8> Ivars = ReferencedIvars[CDecl]; + if (Ivars.empty()) return; - + llvm::DenseSet<std::pair<const ObjCInterfaceDecl*, unsigned> > GroupSymbolOutput; for (ObjCIvarDecl *IvarDecl : Ivars) { const ObjCInterfaceDecl *IDecl = IvarDecl->getContainingInterface(); @@ -4454,7 +4456,7 @@ static void BuildUniqueMethodName(std::string &Name, Name += "__" + MD->getSelector().getAsString(); // Convert colons to underscores. std::string::size_type loc = 0; - while ((loc = Name.find(":", loc)) != std::string::npos) + while ((loc = Name.find(':', loc)) != std::string::npos) Name.replace(loc, 1, "_"); } @@ -5141,7 +5143,7 @@ void RewriteModernObjC::RewriteByRefVar(VarDecl *ND, bool firstDecl, if (!hasInit) { ByrefType += "};\n"; unsigned nameSize = Name.size(); - // for block or function pointer declaration. Name is aleady + // for block or function pointer declaration. Name is already // part of the declaration. if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) nameSize = 1; @@ -6068,7 +6070,7 @@ void RewriteModernObjC::Initialize(ASTContext &context) { Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n"; } -/// RewriteIvarOffsetComputation - This rutine synthesizes computation of +/// RewriteIvarOffsetComputation - This routine synthesizes computation of /// ivar offset. void RewriteModernObjC::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, std::string &Result) { @@ -7500,7 +7502,7 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) { BinaryOperator *addExpr = new (Context) BinaryOperator(castExpr, DRE, BO_Add, Context->getPointerType(Context->CharTy), - VK_RValue, OK_Ordinary, SourceLocation(), false); + VK_RValue, OK_Ordinary, SourceLocation(), FPOptions()); // Don't forget the parens to enforce the proper binding. ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteObjC.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteObjC.cpp index e842e59..e0d813d 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteObjC.cpp @@ -20,6 +20,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/SourceManager.h" +#include "clang/Config/config.h" #include "clang/Lex/Lexer.h" #include "clang/Rewrite/Core/Rewriter.h" #include "llvm/ADT/DenseSet.h" @@ -2992,7 +2993,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, BinaryOperator *lessThanExpr = new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy, VK_RValue, OK_Ordinary, SourceLocation(), - false); + FPOptions()); // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) ConditionalOperator *CondExpr = new (Context) ConditionalOperator(lessThanExpr, @@ -3629,7 +3630,7 @@ static void BuildUniqueMethodName(std::string &Name, Name += "__" + MD->getSelector().getAsString(); // Convert colons to underscores. std::string::size_type loc = 0; - while ((loc = Name.find(":", loc)) != std::string::npos) + while ((loc = Name.find(':', loc)) != std::string::npos) Name.replace(loc, 1, "_"); } @@ -4261,7 +4262,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { } ByrefType += "};\n"; unsigned nameSize = Name.size(); - // for block or function pointer declaration. Name is aleady + // for block or function pointer declaration. Name is already // part of the declaration. if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) nameSize = 1; @@ -5052,7 +5053,7 @@ void RewriteObjCFragileABI::Initialize(ASTContext &context) { Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n"; } -/// RewriteIvarOffsetComputation - This rutine synthesizes computation of +/// RewriteIvarOffsetComputation - This routine synthesizes computation of /// ivar offset. void RewriteObjCFragileABI::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, std::string &Result) { diff --git a/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp b/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp index 7f88c91..7666fe1 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp @@ -63,27 +63,20 @@ public: ~SDiagsRenderer() override {} protected: - void emitDiagnosticMessage(SourceLocation Loc, - PresumedLoc PLoc, - DiagnosticsEngine::Level Level, - StringRef Message, + void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, + DiagnosticsEngine::Level Level, StringRef Message, ArrayRef<CharSourceRange> Ranges, - const SourceManager *SM, DiagOrStoredDiag D) override; - void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, + void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, - ArrayRef<CharSourceRange> Ranges, - const SourceManager &SM) override {} + ArrayRef<CharSourceRange> Ranges) override {} - void emitNote(SourceLocation Loc, StringRef Message, - const SourceManager *SM) override; + void emitNote(FullSourceLoc Loc, StringRef Message) override; - void emitCodeContext(SourceLocation Loc, - DiagnosticsEngine::Level Level, - SmallVectorImpl<CharSourceRange>& Ranges, - ArrayRef<FixItHint> Hints, - const SourceManager &SM) override; + void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level, + SmallVectorImpl<CharSourceRange> &Ranges, + ArrayRef<FixItHint> Hints) override; void beginDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level) override; @@ -193,11 +186,8 @@ private: void ExitDiagBlock(); /// \brief Emit a DIAG record. - void EmitDiagnosticMessage(SourceLocation Loc, - PresumedLoc PLoc, - DiagnosticsEngine::Level Level, - StringRef Message, - const SourceManager *SM, + void EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, + DiagnosticsEngine::Level Level, StringRef Message, DiagOrStoredDiag D); /// \brief Emit FIXIT and SOURCE_RANGE records for a diagnostic. @@ -220,16 +210,14 @@ private: /// \brief Emit (lazily) the file string and retrieved the file identifier. unsigned getEmitFile(const char *Filename); - /// \brief Add SourceLocation information the specified record. - void AddLocToRecord(SourceLocation Loc, const SourceManager *SM, - PresumedLoc PLoc, RecordDataImpl &Record, - unsigned TokSize = 0); + /// \brief Add SourceLocation information the specified record. + void AddLocToRecord(FullSourceLoc Loc, PresumedLoc PLoc, + RecordDataImpl &Record, unsigned TokSize = 0); /// \brief Add SourceLocation information the specified record. - void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record, - const SourceManager *SM, + void AddLocToRecord(FullSourceLoc Loc, RecordDataImpl &Record, unsigned TokSize = 0) { - AddLocToRecord(Loc, SM, SM ? SM->getPresumedLoc(Loc) : PresumedLoc(), + AddLocToRecord(Loc, Loc.hasManager() ? Loc.getPresumedLoc() : PresumedLoc(), Record, TokSize); } @@ -350,11 +338,8 @@ static void EmitRecordID(unsigned ID, const char *Name, Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record); } -void SDiagsWriter::AddLocToRecord(SourceLocation Loc, - const SourceManager *SM, - PresumedLoc PLoc, - RecordDataImpl &Record, - unsigned TokSize) { +void SDiagsWriter::AddLocToRecord(FullSourceLoc Loc, PresumedLoc PLoc, + RecordDataImpl &Record, unsigned TokSize) { if (PLoc.isInvalid()) { // Emit a "sentinel" location. Record.push_back((unsigned)0); // File. @@ -367,19 +352,19 @@ void SDiagsWriter::AddLocToRecord(SourceLocation Loc, Record.push_back(getEmitFile(PLoc.getFilename())); Record.push_back(PLoc.getLine()); Record.push_back(PLoc.getColumn()+TokSize); - Record.push_back(SM->getFileOffset(Loc)); + Record.push_back(Loc.getFileOffset()); } void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range, RecordDataImpl &Record, const SourceManager &SM) { - AddLocToRecord(Range.getBegin(), Record, &SM); + AddLocToRecord(FullSourceLoc(Range.getBegin(), SM), Record); unsigned TokSize = 0; if (Range.isTokenRange()) TokSize = Lexer::MeasureTokenLength(Range.getEnd(), SM, *LangOpts); - - AddLocToRecord(Range.getEnd(), Record, &SM, TokSize); + + AddLocToRecord(FullSourceLoc(Range.getEnd(), SM), Record, TokSize); } unsigned SDiagsWriter::getEmitFile(const char *FileName){ @@ -506,7 +491,7 @@ void SDiagsWriter::EmitBlockInfoBlock() { Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size. - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time. + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modification time. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text. Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, @@ -606,8 +591,8 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, if (DiagLevel == DiagnosticsEngine::Note) EnterDiagBlock(); - EmitDiagnosticMessage(SourceLocation(), PresumedLoc(), DiagLevel, - State->diagBuf, nullptr, &Info); + EmitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagLevel, + State->diagBuf, &Info); if (DiagLevel == DiagnosticsEngine::Note) ExitDiagBlock(); @@ -618,12 +603,9 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, assert(Info.hasSourceManager() && LangOpts && "Unexpected diagnostic with valid location outside of a source file"); SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts); - Renderer.emitDiagnostic(Info.getLocation(), DiagLevel, - State->diagBuf, - Info.getRanges(), - Info.getFixItHints(), - &Info.getSourceManager(), - &Info); + Renderer.emitDiagnostic( + FullSourceLoc(Info.getLocation(), Info.getSourceManager()), DiagLevel, + State->diagBuf, Info.getRanges(), Info.getFixItHints(), &Info); } static serialized_diags::Level getStableLevel(DiagnosticsEngine::Level Level) { @@ -641,11 +623,9 @@ static serialized_diags::Level getStableLevel(DiagnosticsEngine::Level Level) { llvm_unreachable("invalid diagnostic level"); } -void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc, - PresumedLoc PLoc, +void SDiagsWriter::EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, StringRef Message, - const SourceManager *SM, DiagOrStoredDiag D) { llvm::BitstreamWriter &Stream = State->Stream; RecordData &Record = State->Record; @@ -655,7 +635,7 @@ void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc, Record.clear(); Record.push_back(RECORD_DIAG); Record.push_back(getStableLevel(Level)); - AddLocToRecord(Loc, SM, PLoc, Record); + AddLocToRecord(Loc, PLoc, Record); if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) { // Emit the category string lazily and get the category ID. @@ -672,15 +652,11 @@ void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc, Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, Message); } -void -SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc, - PresumedLoc PLoc, - DiagnosticsEngine::Level Level, - StringRef Message, - ArrayRef<clang::CharSourceRange> Ranges, - const SourceManager *SM, - DiagOrStoredDiag D) { - Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, SM, D); +void SDiagsRenderer::emitDiagnosticMessage( + FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, + StringRef Message, ArrayRef<clang::CharSourceRange> Ranges, + DiagOrStoredDiag D) { + Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, D); } void SDiagsWriter::EnterDiagBlock() { @@ -733,20 +709,18 @@ void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges, } } -void SDiagsRenderer::emitCodeContext(SourceLocation Loc, +void SDiagsRenderer::emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level, SmallVectorImpl<CharSourceRange> &Ranges, - ArrayRef<FixItHint> Hints, - const SourceManager &SM) { - Writer.EmitCodeContext(Ranges, Hints, SM); + ArrayRef<FixItHint> Hints) { + Writer.EmitCodeContext(Ranges, Hints, Loc.getManager()); } -void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message, - const SourceManager *SM) { +void SDiagsRenderer::emitNote(FullSourceLoc Loc, StringRef Message) { Writer.EnterDiagBlock(); - PresumedLoc PLoc = SM ? SM->getPresumedLoc(Loc) : PresumedLoc(); - Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note, - Message, SM, DiagOrStoredDiag()); + PresumedLoc PLoc = Loc.hasManager() ? Loc.getPresumedLoc() : PresumedLoc(); + Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note, Message, + DiagOrStoredDiag()); Writer.ExitDiagBlock(); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticReader.cpp b/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticReader.cpp index c4461d4..08b7087 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticReader.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticReader.cpp @@ -27,6 +27,9 @@ std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) { llvm::BitstreamCursor Stream(**Buffer); Optional<llvm::BitstreamBlockInfo> BlockInfo; + if (Stream.AtEndOfStream()) + return SDError::InvalidSignature; + // Sniff for the signature. if (Stream.Read(8) != 'D' || Stream.Read(8) != 'I' || @@ -125,6 +128,7 @@ SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) { case Cursor::BlockBegin: if (Stream.SkipBlock()) return SDError::MalformedMetadataBlock; + LLVM_FALLTHROUGH; case Cursor::BlockEnd: if (!VersionChecked) return SDError::MissingVersion; diff --git a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnostic.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnostic.cpp index a493738..6a72b00 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnostic.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnostic.cpp @@ -672,20 +672,16 @@ TextDiagnostic::TextDiagnostic(raw_ostream &OS, TextDiagnostic::~TextDiagnostic() {} -void -TextDiagnostic::emitDiagnosticMessage(SourceLocation Loc, - PresumedLoc PLoc, - DiagnosticsEngine::Level Level, - StringRef Message, - ArrayRef<clang::CharSourceRange> Ranges, - const SourceManager *SM, - DiagOrStoredDiag D) { +void TextDiagnostic::emitDiagnosticMessage( + FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, + StringRef Message, ArrayRef<clang::CharSourceRange> Ranges, + DiagOrStoredDiag D) { uint64_t StartOfLocationInfo = OS.tell(); // Emit the location of this particular diagnostic. if (Loc.isValid()) - emitDiagnosticLoc(Loc, PLoc, Level, Ranges, *SM); - + emitDiagnosticLoc(Loc, PLoc, Level, Ranges); + if (DiagOpts->ShowColors) OS.resetColor(); @@ -787,17 +783,16 @@ void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) { /// This includes extracting as much location information as is present for /// the diagnostic and printing it, as well as any include stack or source /// ranges necessary. -void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, +void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, - ArrayRef<CharSourceRange> Ranges, - const SourceManager &SM) { + ArrayRef<CharSourceRange> Ranges) { if (PLoc.isInvalid()) { // At least print the file name if available: - FileID FID = SM.getFileID(Loc); + FileID FID = Loc.getFileID(); if (FID.isValid()) { - const FileEntry* FE = SM.getFileEntryForID(FID); + const FileEntry *FE = Loc.getFileEntry(); if (FE && FE->isValid()) { - emitFilename(FE->getName(), SM); + emitFilename(FE->getName(), Loc.getManager()); if (FE->isInPCH()) OS << " (in PCH)"; OS << ": "; @@ -813,7 +808,7 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, if (DiagOpts->ShowColors) OS.changeColor(savedColor, true); - emitFilename(PLoc.getFilename(), SM); + emitFilename(PLoc.getFilename(), Loc.getManager()); switch (DiagOpts->getFormat()) { case DiagnosticOptions::Clang: OS << ':' << LineNo; break; case DiagnosticOptions::MSVC: OS << '(' << LineNo; break; @@ -848,8 +843,7 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, } if (DiagOpts->ShowSourceRanges && !Ranges.empty()) { - FileID CaretFileID = - SM.getFileID(SM.getExpansionLoc(Loc)); + FileID CaretFileID = Loc.getExpansionLoc().getFileID(); bool PrintedRange = false; for (ArrayRef<CharSourceRange>::const_iterator RI = Ranges.begin(), @@ -858,8 +852,10 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, // Ignore invalid ranges. if (!RI->isValid()) continue; - SourceLocation B = SM.getExpansionLoc(RI->getBegin()); - SourceLocation E = SM.getExpansionLoc(RI->getEnd()); + FullSourceLoc B = + FullSourceLoc(RI->getBegin(), Loc.getManager()).getExpansionLoc(); + FullSourceLoc E = + FullSourceLoc(RI->getEnd(), Loc.getManager()).getExpansionLoc(); // If the End location and the start location are the same and are a // macro location, then the range was something that came from a @@ -867,10 +863,12 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, // best we can do is to highlight the range. If this is a // function-like macro, we'd also like to highlight the arguments. if (B == E && RI->getEnd().isMacroID()) - E = SM.getExpansionRange(RI->getEnd()).second; + E = FullSourceLoc(RI->getEnd(), Loc.getManager()) + .getExpansionRange() + .second; - std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B); - std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E); + std::pair<FileID, unsigned> BInfo = B.getDecomposedLoc(); + std::pair<FileID, unsigned> EInfo = E.getDecomposedLoc(); // If the start or end of the range is in another file, just discard // it. @@ -881,13 +879,10 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, // tokens. unsigned TokSize = 0; if (RI->isTokenRange()) - TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts); + TokSize = Lexer::MeasureTokenLength(E, E.getManager(), LangOpts); - OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':' - << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' - << SM.getLineNumber(EInfo.first, EInfo.second) << ':' - << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) - << '}'; + OS << '{' << B.getLineNumber() << ':' << B.getColumnNumber() << '-' + << E.getLineNumber() << ':' << (E.getColumnNumber() + TokSize) << '}'; PrintedRange = true; } @@ -897,9 +892,7 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, OS << ' '; } -void TextDiagnostic::emitIncludeLocation(SourceLocation Loc, - PresumedLoc PLoc, - const SourceManager &SM) { +void TextDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) { if (DiagOpts->ShowLocation && PLoc.isValid()) OS << "In file included from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; @@ -907,9 +900,8 @@ void TextDiagnostic::emitIncludeLocation(SourceLocation Loc, OS << "In included file:\n"; } -void TextDiagnostic::emitImportLocation(SourceLocation Loc, PresumedLoc PLoc, - StringRef ModuleName, - const SourceManager &SM) { +void TextDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, + StringRef ModuleName) { if (DiagOpts->ShowLocation && PLoc.isValid()) OS << "In module '" << ModuleName << "' imported from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; @@ -917,10 +909,9 @@ void TextDiagnostic::emitImportLocation(SourceLocation Loc, PresumedLoc PLoc, OS << "In module '" << ModuleName << "':\n"; } -void TextDiagnostic::emitBuildingModuleLocation(SourceLocation Loc, +void TextDiagnostic::emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc, - StringRef ModuleName, - const SourceManager &SM) { + StringRef ModuleName) { if (DiagOpts->ShowLocation && PLoc.isValid()) OS << "While building module '" << ModuleName << "' imported from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; @@ -928,6 +919,56 @@ void TextDiagnostic::emitBuildingModuleLocation(SourceLocation Loc, OS << "While building module '" << ModuleName << "':\n"; } +/// \brief Find the suitable set of lines to show to include a set of ranges. +static llvm::Optional<std::pair<unsigned, unsigned>> +findLinesForRange(const CharSourceRange &R, FileID FID, + const SourceManager &SM) { + if (!R.isValid()) return None; + + SourceLocation Begin = R.getBegin(); + SourceLocation End = R.getEnd(); + if (SM.getFileID(Begin) != FID || SM.getFileID(End) != FID) + return None; + + return std::make_pair(SM.getExpansionLineNumber(Begin), + SM.getExpansionLineNumber(End)); +} + +/// Add as much of range B into range A as possible without exceeding a maximum +/// size of MaxRange. Ranges are inclusive. +static std::pair<unsigned, unsigned> +maybeAddRange(std::pair<unsigned, unsigned> A, std::pair<unsigned, unsigned> B, + unsigned MaxRange) { + // If A is already the maximum size, we're done. + unsigned Slack = MaxRange - (A.second - A.first + 1); + if (Slack == 0) + return A; + + // Easy case: merge succeeds within MaxRange. + unsigned Min = std::min(A.first, B.first); + unsigned Max = std::max(A.second, B.second); + if (Max - Min + 1 <= MaxRange) + return {Min, Max}; + + // If we can't reach B from A within MaxRange, there's nothing to do. + // Don't add lines to the range that contain nothing interesting. + if ((B.first > A.first && B.first - A.first + 1 > MaxRange) || + (B.second < A.second && A.second - B.second + 1 > MaxRange)) + return A; + + // Otherwise, expand A towards B to produce a range of size MaxRange. We + // attempt to expand by the same amount in both directions if B strictly + // contains A. + + // Expand downwards by up to half the available amount, then upwards as + // much as possible, then downwards as much as possible. + A.second = std::min(A.second + (Slack + 1) / 2, Max); + Slack = MaxRange - (A.second - A.first + 1); + A.first = std::max(Min + Slack, A.first) - Slack; + A.second = std::min(A.first + MaxRange - 1, Max); + return A; +} + /// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo. static void highlightRange(const CharSourceRange &R, unsigned LineNo, FileID FID, @@ -990,9 +1031,12 @@ static void highlightRange(const CharSourceRange &R, EndColNo = map.startOfPreviousColumn(EndColNo); // If the start/end passed each other, then we are trying to highlight a - // range that just exists in whitespace, which must be some sort of other - // bug. - assert(StartColNo <= EndColNo && "Trying to highlight whitespace??"); + // range that just exists in whitespace. That most likely means we have + // a multi-line highlighting range that covers a blank line. + if (StartColNo > EndColNo) { + assert(StartLineNo != EndLineNo && "trying to highlight whitespace"); + StartColNo = EndColNo; + } } assert(StartColNo <= map.getSourceLine().size() && "Invalid range!"); @@ -1008,7 +1052,8 @@ static void highlightRange(const CharSourceRange &R, std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~'); } -static std::string buildFixItInsertionLine(unsigned LineNo, +static std::string buildFixItInsertionLine(FileID FID, + unsigned LineNo, const SourceColumnMap &map, ArrayRef<FixItHint> Hints, const SourceManager &SM, @@ -1025,7 +1070,8 @@ static std::string buildFixItInsertionLine(unsigned LineNo, // code contains no newlines and is on the same line as the caret. std::pair<FileID, unsigned> HintLocInfo = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin()); - if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) && + if (FID == HintLocInfo.first && + LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) && StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos) { // Insert the new code into the line just below the code // that the user wrote. @@ -1061,9 +1107,6 @@ static std::string buildFixItInsertionLine(unsigned LineNo, PrevHintEndCol = HintCol + llvm::sys::locale::columnWidth(I->CodeToInsert); - } else { - FixItInsertionLine.clear(); - break; } } } @@ -1081,10 +1124,8 @@ static std::string buildFixItInsertionLine(unsigned LineNo, /// \param Ranges The underlined ranges for this code snippet. /// \param Hints The FixIt hints active for this diagnostic. void TextDiagnostic::emitSnippetAndCaret( - SourceLocation Loc, DiagnosticsEngine::Level Level, - SmallVectorImpl<CharSourceRange>& Ranges, - ArrayRef<FixItHint> Hints, - const SourceManager &SM) { + FullSourceLoc Loc, DiagnosticsEngine::Level Level, + SmallVectorImpl<CharSourceRange> &Ranges, ArrayRef<FixItHint> Hints) { assert(Loc.isValid() && "must have a valid source location here"); assert(Loc.isFileID() && "must have a file location here"); @@ -1101,111 +1142,128 @@ void TextDiagnostic::emitSnippetAndCaret( return; // Decompose the location into a FID/Offset pair. - std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); + std::pair<FileID, unsigned> LocInfo = Loc.getDecomposedLoc(); FileID FID = LocInfo.first; - unsigned FileOffset = LocInfo.second; + const SourceManager &SM = Loc.getManager(); // Get information about the buffer it points into. bool Invalid = false; - StringRef BufData = SM.getBufferData(FID, &Invalid); + StringRef BufData = Loc.getBufferData(&Invalid); if (Invalid) return; - const char *BufStart = BufData.data(); - const char *BufEnd = BufStart + BufData.size(); + unsigned CaretLineNo = Loc.getLineNumber(); + unsigned CaretColNo = Loc.getColumnNumber(); - unsigned LineNo = SM.getLineNumber(FID, FileOffset); - unsigned ColNo = SM.getColumnNumber(FID, FileOffset); - // Arbitrarily stop showing snippets when the line is too long. static const size_t MaxLineLengthToPrint = 4096; - if (ColNo > MaxLineLengthToPrint) + if (CaretColNo > MaxLineLengthToPrint) return; - // Rewind from the current position to the start of the line. - const char *TokPtr = BufStart+FileOffset; - const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based. - - // Compute the line end. Scan forward from the error position to the end of - // the line. - const char *LineEnd = TokPtr; - while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd) - ++LineEnd; - - // Arbitrarily stop showing snippets when the line is too long. - if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint) - return; - - // Trim trailing null-bytes. - StringRef Line(LineStart, LineEnd - LineStart); - while (Line.size() > ColNo && Line.back() == '\0') - Line = Line.drop_back(); + // Find the set of lines to include. + const unsigned MaxLines = DiagOpts->SnippetLineLimit; + std::pair<unsigned, unsigned> Lines = {CaretLineNo, CaretLineNo}; + for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), + E = Ranges.end(); + I != E; ++I) + if (auto OptionalRange = findLinesForRange(*I, FID, SM)) + Lines = maybeAddRange(Lines, *OptionalRange, MaxLines); + + for (unsigned LineNo = Lines.first; LineNo != Lines.second + 1; ++LineNo) { + const char *BufStart = BufData.data(); + const char *BufEnd = BufStart + BufData.size(); + + // Rewind from the current position to the start of the line. + const char *LineStart = + BufStart + + SM.getDecomposedLoc(SM.translateLineCol(FID, LineNo, 1)).second; + if (LineStart == BufEnd) + break; - // Copy the line of code into an std::string for ease of manipulation. - std::string SourceLine(Line.begin(), Line.end()); + // Compute the line end. + const char *LineEnd = LineStart; + while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd) + ++LineEnd; - // Build the byte to column map. - const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop); + // Arbitrarily stop showing snippets when the line is too long. + // FIXME: Don't print any lines in this case. + if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint) + return; - // Create a line for the caret that is filled with spaces that is the same - // number of columns as the line of source code. - std::string CaretLine(sourceColMap.columns(), ' '); + // Trim trailing null-bytes. + StringRef Line(LineStart, LineEnd - LineStart); + while (!Line.empty() && Line.back() == '\0' && + (LineNo != CaretLineNo || Line.size() > CaretColNo)) + Line = Line.drop_back(); + + // Copy the line of code into an std::string for ease of manipulation. + std::string SourceLine(Line.begin(), Line.end()); + + // Build the byte to column map. + const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop); + + // Create a line for the caret that is filled with spaces that is the same + // number of columns as the line of source code. + std::string CaretLine(sourceColMap.columns(), ' '); + + // Highlight all of the characters covered by Ranges with ~ characters. + for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), + E = Ranges.end(); + I != E; ++I) + highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts); + + // Next, insert the caret itself. + if (CaretLineNo == LineNo) { + CaretColNo = sourceColMap.byteToContainingColumn(CaretColNo - 1); + if (CaretLine.size() < CaretColNo + 1) + CaretLine.resize(CaretColNo + 1, ' '); + CaretLine[CaretColNo] = '^'; + } - // Highlight all of the characters covered by Ranges with ~ characters. - for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), - E = Ranges.end(); - I != E; ++I) - highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts); - - // Next, insert the caret itself. - ColNo = sourceColMap.byteToContainingColumn(ColNo-1); - if (CaretLine.size()<ColNo+1) - CaretLine.resize(ColNo+1, ' '); - CaretLine[ColNo] = '^'; - - std::string FixItInsertionLine = buildFixItInsertionLine(LineNo, - sourceColMap, - Hints, SM, - DiagOpts.get()); - - // If the source line is too long for our terminal, select only the - // "interesting" source region within that line. - unsigned Columns = DiagOpts->MessageLength; - if (Columns) - selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine, - Columns, sourceColMap); - - // If we are in -fdiagnostics-print-source-range-info mode, we are trying - // to produce easily machine parsable output. Add a space before the - // source line and the caret to make it trivial to tell the main diagnostic - // line from what the user is intended to see. - if (DiagOpts->ShowSourceRanges) { - SourceLine = ' ' + SourceLine; - CaretLine = ' ' + CaretLine; - } + std::string FixItInsertionLine = buildFixItInsertionLine( + FID, LineNo, sourceColMap, Hints, SM, DiagOpts.get()); + + // If the source line is too long for our terminal, select only the + // "interesting" source region within that line. + unsigned Columns = DiagOpts->MessageLength; + if (Columns) + selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine, + Columns, sourceColMap); + + // If we are in -fdiagnostics-print-source-range-info mode, we are trying + // to produce easily machine parsable output. Add a space before the + // source line and the caret to make it trivial to tell the main diagnostic + // line from what the user is intended to see. + if (DiagOpts->ShowSourceRanges) { + SourceLine = ' ' + SourceLine; + CaretLine = ' ' + CaretLine; + } - // Finally, remove any blank spaces from the end of CaretLine. - while (CaretLine[CaretLine.size()-1] == ' ') - CaretLine.erase(CaretLine.end()-1); + // Finally, remove any blank spaces from the end of CaretLine. + while (!CaretLine.empty() && CaretLine[CaretLine.size() - 1] == ' ') + CaretLine.erase(CaretLine.end() - 1); - // Emit what we have computed. - emitSnippet(SourceLine); + // Emit what we have computed. + emitSnippet(SourceLine); - if (DiagOpts->ShowColors) - OS.changeColor(caretColor, true); - OS << CaretLine << '\n'; - if (DiagOpts->ShowColors) - OS.resetColor(); + if (!CaretLine.empty()) { + if (DiagOpts->ShowColors) + OS.changeColor(caretColor, true); + OS << CaretLine << '\n'; + if (DiagOpts->ShowColors) + OS.resetColor(); + } - if (!FixItInsertionLine.empty()) { - if (DiagOpts->ShowColors) - // Print fixit line in color - OS.changeColor(fixitColor, false); - if (DiagOpts->ShowSourceRanges) - OS << ' '; - OS << FixItInsertionLine << '\n'; - if (DiagOpts->ShowColors) - OS.resetColor(); + if (!FixItInsertionLine.empty()) { + if (DiagOpts->ShowColors) + // Print fixit line in color + OS.changeColor(fixitColor, false); + if (DiagOpts->ShowSourceRanges) + OS << ' '; + OS << FixItInsertionLine << '\n'; + if (DiagOpts->ShowColors) + OS.resetColor(); + } } // Print out any parseable fixit information requested by the options. diff --git a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp index 17646b4..5dd3252 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp @@ -150,10 +150,9 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, "Unexpected diagnostic with no source manager"); assert(TextDiag && "Unexpected diagnostic outside source file processing"); - TextDiag->emitDiagnostic(Info.getLocation(), Level, DiagMessageStream.str(), - Info.getRanges(), - Info.getFixItHints(), - &Info.getSourceManager()); + TextDiag->emitDiagnostic( + FullSourceLoc(Info.getLocation(), Info.getSourceManager()), Level, + DiagMessageStream.str(), Info.getRanges(), Info.getFixItHints()); OS.flush(); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp index ae16ea1..427d15e 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -400,7 +400,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, const DirectoryLookup *CurDir; const FileEntry *FE = PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir, - nullptr, nullptr, nullptr); + nullptr, nullptr, nullptr, nullptr); if (!FE) { Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_file) << Filename << KindStr; |