diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2012-12-02 13:20:44 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2012-12-02 13:20:44 +0000 |
commit | 13cc256e404620c1de0cbcc4e43ce1e2dbbc4898 (patch) | |
tree | 2732d02d7d51218d6eed98ac7fcfc5b8794896b5 /lib/Frontend/ASTUnit.cpp | |
parent | 657bc3d9848e3be92029b2416031340988cd0111 (diff) | |
download | src-13cc256e404620c1de0cbcc4e43ce1e2dbbc4898.tar.gz src-13cc256e404620c1de0cbcc4e43ce1e2dbbc4898.zip |
Notes
Diffstat (limited to 'lib/Frontend/ASTUnit.cpp')
-rw-r--r-- | lib/Frontend/ASTUnit.cpp | 306 |
1 files changed, 205 insertions, 101 deletions
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 42a67720c353..5576854a7d8b 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -27,6 +27,7 @@ #include "clang/Serialization/ASTWriter.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" #include "clang/Basic/TargetOptions.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Diagnostic.h" @@ -180,6 +181,14 @@ void OnDiskData::Cleanup() { CleanPreambleFile(); } +struct ASTUnit::ASTWriterData { + SmallString<128> Buffer; + llvm::BitstreamWriter Stream; + ASTWriter Writer; + + ASTWriterData() : Stream(Buffer), Writer(Stream) { } +}; + void ASTUnit::clearFileLevelDecls() { for (FileDeclsTy::iterator I = FileDecls.begin(), E = FileDecls.end(); I != E; ++I) @@ -495,8 +504,8 @@ class ASTInfoCollector : public ASTReaderListener { ASTContext &Context; LangOptions &LangOpt; HeaderSearch &HSI; + IntrusiveRefCntPtr<TargetOptions> &TargetOpts; IntrusiveRefCntPtr<TargetInfo> &Target; - std::string &Predefines; unsigned &Counter; unsigned NumHeaderInfos; @@ -504,54 +513,38 @@ class ASTInfoCollector : public ASTReaderListener { bool InitializedLanguage; public: ASTInfoCollector(Preprocessor &PP, ASTContext &Context, LangOptions &LangOpt, - HeaderSearch &HSI, + HeaderSearch &HSI, + IntrusiveRefCntPtr<TargetOptions> &TargetOpts, IntrusiveRefCntPtr<TargetInfo> &Target, - std::string &Predefines, unsigned &Counter) - : PP(PP), Context(Context), LangOpt(LangOpt), HSI(HSI), Target(Target), - Predefines(Predefines), Counter(Counter), NumHeaderInfos(0), + : PP(PP), Context(Context), LangOpt(LangOpt), HSI(HSI), + TargetOpts(TargetOpts), Target(Target), + Counter(Counter), NumHeaderInfos(0), InitializedLanguage(false) {} - virtual bool ReadLanguageOptions(const LangOptions &LangOpts) { + virtual bool ReadLanguageOptions(const LangOptions &LangOpts, + bool Complain) { if (InitializedLanguage) return false; LangOpt = LangOpts; - - // Initialize the preprocessor. - PP.Initialize(*Target); - - // Initialize the ASTContext - Context.InitBuiltinTypes(*Target); - InitializedLanguage = true; + + updated(); return false; } - virtual bool ReadTargetTriple(StringRef Triple) { + virtual bool ReadTargetOptions(const TargetOptions &TargetOpts, + bool Complain) { // If we've already initialized the target, don't do it again. if (Target) return false; - // FIXME: This is broken, we should store the TargetOptions in the AST file. - TargetOptions TargetOpts; - TargetOpts.ABI = ""; - TargetOpts.CXXABI = ""; - TargetOpts.CPU = ""; - TargetOpts.Features.clear(); - TargetOpts.Triple = Triple; - Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(), TargetOpts); - return false; - } + this->TargetOpts = new TargetOptions(TargetOpts); + Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(), + *this->TargetOpts); - virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, - StringRef OriginalFileName, - std::string &SuggestedPredefines, - FileManager &FileMgr) { - Predefines = Buffers[0].Data; - for (unsigned I = 1, N = Buffers.size(); I != N; ++I) { - Predefines += Buffers[I].Data; - } + updated(); return false; } @@ -559,9 +552,27 @@ public: HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++); } - virtual void ReadCounter(unsigned Value) { + virtual void ReadCounter(const serialization::ModuleFile &M, unsigned Value) { Counter = Value; } + +private: + void updated() { + if (!Target || !InitializedLanguage) + return; + + // 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. + Target->setForcedLangOptions(LangOpt); + + // Initialize the preprocessor. + PP.Initialize(*Target); + + // Initialize the ASTContext + Context.InitBuiltinTypes(*Target); + } }; class StoredDiagnosticConsumer : public DiagnosticConsumer { @@ -621,8 +632,10 @@ void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level, StoredDiags.push_back(StoredDiagnostic(Level, Info)); } -const std::string &ASTUnit::getOriginalSourceFileName() { - return OriginalSourceFile; +ASTDeserializationListener *ASTUnit::getDeserializationListener() { + if (WriterData) + return &WriterData->Writer; + return 0; } llvm::MemoryBuffer *ASTUnit::getBufferForFile(StringRef Filename, @@ -638,11 +651,11 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> &Diags, if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. - DiagnosticOptions DiagOpts; DiagnosticConsumer *Client = 0; if (CaptureDiagnostics) Client = new StoredDiagnosticConsumer(AST.StoredDiagnostics); - Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd-ArgBegin, + Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions(), + ArgEnd-ArgBegin, ArgBegin, Client, /*ShouldOwnClient=*/true, /*ShouldCloneClient=*/false); @@ -679,7 +692,10 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, AST->SourceMgr = new SourceManager(AST->getDiagnostics(), AST->getFileManager(), UserFilesAreVolatile); - AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager(), + AST->HSOpts = new HeaderSearchOptions(); + + AST->HeaderInfo.reset(new HeaderSearch(AST->HSOpts, + AST->getFileManager(), AST->getDiagnostics(), AST->ASTFileLangOpts, /*Target=*/0)); @@ -734,12 +750,12 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, // Gather Info for preprocessor construction later on. HeaderSearch &HeaderInfo = *AST->HeaderInfo.get(); - std::string Predefines; unsigned Counter; OwningPtr<ASTReader> Reader; - AST->PP = new Preprocessor(AST->getDiagnostics(), AST->ASTFileLangOpts, + AST->PP = new Preprocessor(new PreprocessorOptions(), + AST->getDiagnostics(), AST->ASTFileLangOpts, /*Target=*/0, AST->getSourceManager(), HeaderInfo, *AST, /*IILookup=*/0, @@ -757,10 +773,12 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, /*DelayInitialization=*/true); ASTContext &Context = *AST->Ctx; + bool disableValid = false; + if (::getenv("LIBCLANG_DISABLE_PCH_VALIDATION")) + disableValid = true; Reader.reset(new ASTReader(PP, Context, /*isysroot=*/"", - /*DisableValidation=*/false, - /*DisableStatCache=*/false, + /*DisableValidation=*/disableValid, AllowPCHWithCompilerErrors)); // Recover resources if we crash before exiting this method. @@ -769,21 +787,25 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, Reader->setListener(new ASTInfoCollector(*AST->PP, Context, AST->ASTFileLangOpts, HeaderInfo, - AST->Target, Predefines, Counter)); + AST->TargetOpts, AST->Target, + Counter)); - switch (Reader->ReadAST(Filename, serialization::MK_MainFile)) { + switch (Reader->ReadAST(Filename, serialization::MK_MainFile, + ASTReader::ARR_None)) { case ASTReader::Success: break; case ASTReader::Failure: - case ASTReader::IgnorePCH: + case ASTReader::OutOfDate: + case ASTReader::VersionMismatch: + case ASTReader::ConfigurationMismatch: + case ASTReader::HadErrors: AST->getDiagnostics().Report(diag::err_fe_unable_to_load_pch); return NULL; } AST->OriginalSourceFile = Reader->getOriginalSourceFile(); - PP.setPredefines(Reader->getSuggestedPredefines()); PP.setCounterValue(Counter); // Attach the AST reader to the AST context as an external AST @@ -897,6 +919,10 @@ public: for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) handleTopLevelDecl(*it); } + + virtual ASTDeserializationListener *GetASTDeserializationListener() { + return Unit.getDeserializationListener(); + } }; class TopLevelDeclTrackerAction : public ASTFrontendAction { @@ -1047,14 +1073,13 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { CCInvocation(new CompilerInvocation(*Invocation)); Clang->setInvocation(CCInvocation.getPtr()); - OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File; + OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile(); // Set up diagnostics, capturing any diagnostics that would // otherwise be dropped. Clang->setDiagnostics(&getDiagnostics()); // Create the target instance. - Clang->getTargetOpts().Features = TargetFeatures; Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), Clang->getTargetOpts())); if (!Clang->hasTarget()) { @@ -1070,9 +1095,9 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR && + assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && "IR inputs not support here!"); // Configure the various subsystems. @@ -1217,7 +1242,7 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation, // command line (to another file) or directly through the compiler invocation // (to a memory buffer). llvm::MemoryBuffer *Buffer = 0; - llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].File); + llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].getFile()); if (const llvm::sys::FileStatus *MainFileStatus = MainFilePath.getFileStatus()) { // Check whether there is a file-file remapping of the main file for (PreprocessorOptions::remapped_file_iterator @@ -1267,7 +1292,7 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation, // If the main source file was not remapped, load it now. if (!Buffer) { - Buffer = getBufferForFile(FrontendOpts.Inputs[0].File); + Buffer = getBufferForFile(FrontendOpts.Inputs[0].getFile()); if (!Buffer) return std::make_pair((llvm::MemoryBuffer*)0, std::make_pair(0, true)); @@ -1429,7 +1454,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // buffer size we reserved when creating the preamble. return CreatePaddedMainFileBuffer(NewPreamble.first, PreambleReservedSize, - FrontendOpts.Inputs[0].File); + FrontendOpts.Inputs[0].getFile()); } } @@ -1482,7 +1507,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // Save the preamble text for later; we'll need to compare against it for // subsequent reparses. - StringRef MainFilename = PreambleInvocation->getFrontendOpts().Inputs[0].File; + StringRef MainFilename = PreambleInvocation->getFrontendOpts().Inputs[0].getFile(); Preamble.assign(FileMgr->getFile(MainFilename), NewPreamble.first->getBufferStart(), NewPreamble.first->getBufferStart() @@ -1492,7 +1517,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( delete PreambleBuffer; PreambleBuffer = llvm::MemoryBuffer::getNewUninitMemBuffer(PreambleReservedSize, - FrontendOpts.Inputs[0].File); + FrontendOpts.Inputs[0].getFile()); memcpy(const_cast<char*>(PreambleBuffer->getBufferStart()), NewPreamble.first->getBufferStart(), Preamble.size()); memset(const_cast<char*>(PreambleBuffer->getBufferStart()) + Preamble.size(), @@ -1500,7 +1525,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( const_cast<char*>(PreambleBuffer->getBufferEnd())[-1] = '\n'; // Remap the main source file to the preamble buffer. - llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].File); + llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].getFile()); PreprocessorOpts.addRemappedFile(MainFilePath.str(), PreambleBuffer); // Tell the compiler invocation to generate a temporary precompiled header. @@ -1518,15 +1543,14 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( CICleanup(Clang.get()); Clang->setInvocation(&*PreambleInvocation); - OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File; + OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile(); // Set up diagnostics, capturing all of the diagnostics produced. Clang->setDiagnostics(&getDiagnostics()); // Create the target instance. - Clang->getTargetOpts().Features = TargetFeatures; Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), - Clang->getTargetOpts())); + Clang->getTargetOpts())); if (!Clang->hasTarget()) { llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk(); Preamble.clear(); @@ -1544,9 +1568,9 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR && + assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && "IR inputs not support here!"); // Clear out old caches and data. @@ -1633,7 +1657,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( return CreatePaddedMainFileBuffer(NewPreamble.first, PreambleReservedSize, - FrontendOpts.Inputs[0].File); + FrontendOpts.Inputs[0].getFile()); } void ASTUnit::RealizeTopLevelDeclsFromPreamble() { @@ -1664,7 +1688,7 @@ void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) { } StringRef ASTUnit::getMainFileName() const { - return Invocation->getFrontendOpts().Inputs[0].File; + return Invocation->getFrontendOpts().Inputs[0].getFile(); } ASTUnit *ASTUnit::create(CompilerInvocation *CI, @@ -1733,9 +1757,6 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, CI->getFrontendOpts().DisableFree = false; ProcessWarningOptions(AST->getDiagnostics(), CI->getDiagnosticOpts()); - // Save the target features. - AST->TargetFeatures = CI->getTargetOpts().Features; - // Create the compiler instance to use for building the AST. OwningPtr<CompilerInstance> Clang(new CompilerInstance()); @@ -1744,14 +1765,13 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, CICleanup(Clang.get()); Clang->setInvocation(CI); - AST->OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File; + AST->OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile(); // Set up diagnostics, capturing any diagnostics that would // otherwise be dropped. Clang->setDiagnostics(&AST->getDiagnostics()); // Create the target instance. - Clang->getTargetOpts().Features = AST->TargetFeatures; Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), Clang->getTargetOpts())); if (!Clang->hasTarget()) @@ -1765,9 +1785,9 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR && + assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && "IR inputs not supported here!"); // Configure the various subsystems. @@ -1840,9 +1860,6 @@ bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) { Invocation->getFrontendOpts().DisableFree = false; ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts()); - // Save the target features. - TargetFeatures = Invocation->getTargetOpts().Features; - llvm::MemoryBuffer *OverrideMainBuffer = 0; if (PrecompilePreamble) { PreambleRebuildCounter = 2; @@ -1909,12 +1926,13 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, bool AllowPCHWithCompilerErrors, bool SkipFunctionBodies, bool UserFilesAreVolatile, + bool ForSerialization, OwningPtr<ASTUnit> *ErrAST) { if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. - DiagnosticOptions DiagOpts; - Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd - ArgBegin, + Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions(), + ArgEnd - ArgBegin, ArgBegin); } @@ -1972,6 +1990,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size(); AST->StoredDiagnostics.swap(StoredDiagnostics); AST->Invocation = CI; + if (ForSerialization) + AST->WriterData.reset(new ASTWriterData()); CI = 0; // Zero out now to ease cleanup during crash recovery. // Recover resources if we crash before exiting this method. @@ -2002,7 +2022,6 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { // Remap files. PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts(); - PPOpts.DisableStatCache = true; for (PreprocessorOptions::remapped_file_buffer_iterator R = PPOpts.remapped_file_buffer_begin(), REnd = PPOpts.remapped_file_buffer_end(); @@ -2238,7 +2257,6 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, // Adjust priority based on similar type classes. unsigned Priority = C->Priority; - CXCursorKind CursorKind = C->Kind; CodeCompletionString *Completion = C->Completion; if (!Context.getPreferredType().isNull()) { if (C->Kind == CXCursor_MacroDefinition) { @@ -2272,12 +2290,11 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, CodeCompletionBuilder Builder(getAllocator(), getCodeCompletionTUInfo(), CCP_CodePattern, C->Availability); Builder.AddTypedTextChunk(C->Completion->getTypedText()); - CursorKind = CXCursor_NotImplemented; Priority = CCP_CodePattern; Completion = Builder.TakeString(); } - AllResults.push_back(Result(Completion, Priority, CursorKind, + AllResults.push_back(Result(Completion, Priority, C->Kind, C->Availability)); } @@ -2341,7 +2358,7 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, CICleanup(Clang.get()); Clang->setInvocation(&*CCInvocation); - OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File; + OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile(); // Set up diagnostics, capturing any diagnostics produced. Clang->setDiagnostics(&Diag); @@ -2351,7 +2368,6 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, StoredDiagnostics); // Create the target instance. - Clang->getTargetOpts().Features = TargetFeatures; Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), Clang->getTargetOpts())); if (!Clang->hasTarget()) { @@ -2367,9 +2383,9 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR && + assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && "IR inputs not support here!"); @@ -2398,8 +2414,6 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, = new AugmentedCodeCompleteConsumer(*this, Consumer, CodeCompleteOpts); Clang->setCodeCompletionConsumer(AugmentedConsumer); - Clang->getFrontendOpts().SkipFunctionBodies = true; - // If we have a precompiled preamble, try to use it. We only allow // the use of the precompiled preamble if we're if the completion // point is within the main file, after the end of the precompiled @@ -2420,7 +2434,6 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, // If the main file has been overridden due to the use of a preamble, // make that override happen and introduce the preamble. - PreprocessorOpts.DisableStatCache = true; StoredDiagnostics.insert(StoredDiagnostics.end(), stored_diag_begin(), stored_diag_afterDriver_begin()); @@ -2438,8 +2451,9 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, PreprocessorOpts.PrecompiledPreambleBytes.second = false; } - // Disable the preprocessing record - PreprocessorOpts.DetailedRecord = false; + // Disable the preprocessing record if modules are not enabled. + if (!Clang->getLangOpts().Modules) + PreprocessorOpts.DetailedRecord = false; OwningPtr<SyntaxOnlyAction> Act; Act.reset(new SyntaxOnlyAction); @@ -2457,7 +2471,7 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, checkAndSanitizeDiags(StoredDiagnostics, getSourceManager()); } -CXSaveError ASTUnit::Save(StringRef File) { +bool ASTUnit::Save(StringRef File) { // Write to a temporary file and later rename it to the actual file, to avoid // possible race conditions. SmallString<128> TempPath; @@ -2466,7 +2480,7 @@ CXSaveError ASTUnit::Save(StringRef File) { int fd; if (llvm::sys::fs::unique_file(TempPath.str(), fd, TempPath, /*makeAbsolute=*/false)) - return CXSaveError_Unknown; + return true; // FIXME: Can we somehow regenerate the stat cache here, or do we need to // unconditionally create a stat cache when we parse the file? @@ -2476,32 +2490,43 @@ CXSaveError ASTUnit::Save(StringRef File) { Out.close(); if (Out.has_error()) { Out.clear_error(); - return CXSaveError_Unknown; + return true; } if (llvm::sys::fs::rename(TempPath.str(), File)) { bool exists; llvm::sys::fs::remove(TempPath.str(), exists); - return CXSaveError_Unknown; + return true; } - return CXSaveError_None; + return false; +} + +static bool serializeUnit(ASTWriter &Writer, + SmallVectorImpl<char> &Buffer, + Sema &S, + bool hasErrors, + raw_ostream &OS) { + Writer.WriteAST(S, std::string(), 0, "", hasErrors); + + // Write the generated bitstream to "Out". + if (!Buffer.empty()) + OS.write(Buffer.data(), Buffer.size()); + + return false; } bool ASTUnit::serialize(raw_ostream &OS) { bool hasErrors = getDiagnostics().hasErrorOccurred(); + if (WriterData) + return serializeUnit(WriterData->Writer, WriterData->Buffer, + getSema(), hasErrors, OS); + SmallString<128> Buffer; llvm::BitstreamWriter Stream(Buffer); ASTWriter Writer(Stream); - // FIXME: Handle modules - Writer.WriteAST(getSema(), 0, std::string(), 0, "", hasErrors); - - // Write the generated bitstream to "Out". - if (!Buffer.empty()) - OS.write((char *)&Buffer.front(), Buffer.size()); - - return false; + return serializeUnit(Writer, Buffer, getSema(), hasErrors, OS); } typedef ContinuousRangeMap<unsigned, int, 2> SLocRemap; @@ -2761,6 +2786,85 @@ SourceLocation ASTUnit::getStartOfMainFileID() { return SourceMgr->getLocForStartOfFile(FID); } +std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator> +ASTUnit::getLocalPreprocessingEntities() const { + if (isMainFileAST()) { + serialization::ModuleFile & + Mod = Reader->getModuleManager().getPrimaryModule(); + return Reader->getModulePreprocessedEntities(Mod); + } + + if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord()) + return std::make_pair(PPRec->local_begin(), PPRec->local_end()); + + return std::make_pair(PreprocessingRecord::iterator(), + PreprocessingRecord::iterator()); +} + +bool ASTUnit::visitLocalTopLevelDecls(void *context, DeclVisitorFn Fn) { + if (isMainFileAST()) { + serialization::ModuleFile & + Mod = Reader->getModuleManager().getPrimaryModule(); + ASTReader::ModuleDeclIterator MDI, MDE; + llvm::tie(MDI, MDE) = Reader->getModuleFileLevelDecls(Mod); + for (; MDI != MDE; ++MDI) { + if (!Fn(context, *MDI)) + return false; + } + + return true; + } + + for (ASTUnit::top_level_iterator TL = top_level_begin(), + TLEnd = top_level_end(); + TL != TLEnd; ++TL) { + if (!Fn(context, *TL)) + return false; + } + + return true; +} + +namespace { +struct PCHLocatorInfo { + serialization::ModuleFile *Mod; + PCHLocatorInfo() : Mod(0) {} +}; +} + +static bool PCHLocator(serialization::ModuleFile &M, void *UserData) { + PCHLocatorInfo &Info = *static_cast<PCHLocatorInfo*>(UserData); + switch (M.Kind) { + case serialization::MK_Module: + return true; // skip dependencies. + case serialization::MK_PCH: + Info.Mod = &M; + return true; // found it. + case serialization::MK_Preamble: + return false; // look in dependencies. + case serialization::MK_MainFile: + return false; // look in dependencies. + } + + return true; +} + +const FileEntry *ASTUnit::getPCHFile() { + if (!Reader) + return 0; + + PCHLocatorInfo Info; + Reader->getModuleManager().visit(PCHLocator, &Info); + if (Info.Mod) + return Info.Mod->File; + + return 0; +} + +bool ASTUnit::isModuleFile() { + return isMainFileAST() && !ASTFileLangOpts.CurrentModule.empty(); +} + void ASTUnit::PreambleData::countLines() const { NumLines = 0; if (empty()) |