diff options
author | dim <dim@FreeBSD.org> | 2012-12-02 13:20:44 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2012-12-02 13:20:44 +0000 |
commit | 056abd2059c65a3e908193aeae16fad98017437c (patch) | |
tree | 2732d02d7d51218d6eed98ac7fcfc5b8794896b5 /lib/Frontend | |
parent | cc73504950eb7b5dff2dded9bedd67bc36d64641 (diff) | |
download | FreeBSD-src-056abd2059c65a3e908193aeae16fad98017437c.zip FreeBSD-src-056abd2059c65a3e908193aeae16fad98017437c.tar.gz |
Vendor import of clang release_32 branch r168974 (effectively, 3.2 RC2):
http://llvm.org/svn/llvm-project/cfe/branches/release_32@168974
Diffstat (limited to 'lib/Frontend')
22 files changed, 1211 insertions, 1633 deletions
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index 0f0d835..882d400 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -58,7 +58,7 @@ namespace { bool shouldWalkTypesOfTypeLocs() const { return false; } bool TraverseDecl(Decl *D) { - if (filterMatches(D)) { + if (D != NULL && filterMatches(D)) { Out.changeColor(llvm::raw_ostream::BLUE) << (Dump ? "Dumping " : "Printing ") << getName(D) << ":\n"; Out.resetColor(); @@ -66,6 +66,7 @@ namespace { D->dump(Out); else D->print(Out, /*Indentation=*/0, /*PrintInstantiation=*/true); + Out << "\n"; // Don't traverse child nodes to avoid output duplication. return true; } @@ -89,8 +90,6 @@ namespace { class ASTDeclNodeLister : public ASTConsumer, public RecursiveASTVisitor<ASTDeclNodeLister> { - typedef RecursiveASTVisitor<ASTDeclNodeLister> base; - public: ASTDeclNodeLister(raw_ostream *Out = NULL) : Out(Out ? *Out : llvm::outs()) {} diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp index 9feb3de..31b1df4 100644 --- a/lib/Frontend/ASTMerge.cpp +++ b/lib/Frontend/ASTMerge.cpp @@ -41,8 +41,9 @@ void ASTMergeAction::ExecuteAction() { DiagIDs(CI.getDiagnostics().getDiagnosticIDs()); for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) { IntrusiveRefCntPtr<DiagnosticsEngine> - Diags(new DiagnosticsEngine(DiagIDs, CI.getDiagnostics().getClient(), - /*ShouldOwnClient=*/false)); + Diags(new DiagnosticsEngine(DiagIDs, &CI.getDiagnosticOpts(), + CI.getDiagnostics().getClient(), + /*ShouldOwnClient=*/false)); ASTUnit *Unit = ASTUnit::LoadFromASTFile(ASTFiles[I], Diags, CI.getFileSystemOpts(), false); if (!Unit) diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 42a6772..5576854 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()) diff --git a/lib/Frontend/ChainedDiagnosticConsumer.cpp b/lib/Frontend/ChainedDiagnosticConsumer.cpp index c1d3db8..d77fd18 100644 --- a/lib/Frontend/ChainedDiagnosticConsumer.cpp +++ b/lib/Frontend/ChainedDiagnosticConsumer.cpp @@ -1,4 +1,4 @@ -//===- ChainedDiagnosticConsumer.cpp - Chain Diagnostic Clients -*- C++ -*-===// +//===- ChainedDiagnosticConsumer.cpp - Chain Diagnostic Clients -----------===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Frontend/ChainedIncludesSource.cpp b/lib/Frontend/ChainedIncludesSource.cpp index dbb06bd..2d58640 100644 --- a/lib/Frontend/ChainedIncludesSource.cpp +++ b/lib/Frontend/ChainedIncludesSource.cpp @@ -39,14 +39,18 @@ static ASTReader *createASTReader(CompilerInstance &CI, Reader->addInMemoryBuffer(sr, memBufs[ti]); } Reader->setDeserializationListener(deserialListener); - switch (Reader->ReadAST(pchFile, serialization::MK_PCH)) { + switch (Reader->ReadAST(pchFile, serialization::MK_PCH, + ASTReader::ARR_None)) { case ASTReader::Success: // Set the predefines buffer as suggested by the PCH reader. PP.setPredefines(Reader->getSuggestedPredefines()); return Reader.take(); case ASTReader::Failure: - case ASTReader::IgnorePCH: + case ASTReader::OutOfDate: + case ASTReader::VersionMismatch: + case ASTReader::ConfigurationMismatch: + case ASTReader::HadErrors: break; } return 0; @@ -63,7 +67,7 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) { assert(!includes.empty() && "No '-chain-include' in options!"); OwningPtr<ChainedIncludesSource> source(new ChainedIncludesSource()); - InputKind IK = CI.getFrontendOpts().Inputs[0].Kind; + InputKind IK = CI.getFrontendOpts().Inputs[0].getKind(); SmallVector<llvm::MemoryBuffer *, 4> serialBufs; SmallVector<std::string, 4> serialBufNames; @@ -82,14 +86,14 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) { CInvok->getPreprocessorOpts().Macros.clear(); CInvok->getFrontendOpts().Inputs.clear(); - CInvok->getFrontendOpts().Inputs.push_back(FrontendInputFile(includes[i], - IK)); + FrontendInputFile InputFile(includes[i], IK); + CInvok->getFrontendOpts().Inputs.push_back(InputFile); TextDiagnosticPrinter *DiagClient = - new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions()); + new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions()); IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr<DiagnosticsEngine> Diags( - new DiagnosticsEngine(DiagID, DiagClient)); + new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient)); OwningPtr<CompilerInstance> Clang(new CompilerInstance()); Clang->setInvocation(CInvok.take()); @@ -108,6 +112,8 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) { OwningPtr<ASTConsumer> consumer; consumer.reset(new PCHGenerator(Clang->getPreprocessor(), "-", 0, /*isysroot=*/"", &OS)); + Clang->getPreprocessor().setPPMutationListener( + consumer->GetPPMutationListener()); Clang->getASTContext().setASTMutationListener( consumer->GetASTMutationListener()); Clang->setASTConsumer(consumer.take()); @@ -141,7 +147,7 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) { Clang->getASTContext().setExternalSource(Reader); } - if (!Clang->InitializeSourceManager(includes[i])) + if (!Clang->InitializeSourceManager(InputFile)) return 0; ParseAST(Clang->getSema()); diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 6de1531..22a74fc 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -52,6 +52,7 @@ CompilerInstance::CompilerInstance() } CompilerInstance::~CompilerInstance() { + assert(OutputFiles.empty() && "Still output files in flight?"); } void CompilerInstance::setInvocation(CompilerInvocation *Value) { @@ -88,19 +89,18 @@ void CompilerInstance::setASTConsumer(ASTConsumer *Value) { void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) { CompletionConsumer.reset(Value); - getFrontendOpts().SkipFunctionBodies = Value != 0; } // Diagnostics -static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, +static void SetUpBuildDumpLog(DiagnosticOptions *DiagOpts, unsigned argc, const char* const *argv, DiagnosticsEngine &Diags) { std::string ErrorInfo; OwningPtr<raw_ostream> OS( - new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo)); + new llvm::raw_fd_ostream(DiagOpts->DumpBuildInformation.c_str(),ErrorInfo)); if (!ErrorInfo.empty()) { Diags.Report(diag::err_fe_unable_to_open_logfile) - << DiagOpts.DumpBuildInformation << ErrorInfo; + << DiagOpts->DumpBuildInformation << ErrorInfo; return; } @@ -115,20 +115,20 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), Logger)); } -static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts, +static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts, const CodeGenOptions *CodeGenOpts, DiagnosticsEngine &Diags) { std::string ErrorInfo; bool OwnsStream = false; raw_ostream *OS = &llvm::errs(); - if (DiagOpts.DiagnosticLogFile != "-") { + if (DiagOpts->DiagnosticLogFile != "-") { // Create the output stream. llvm::raw_fd_ostream *FileOS( - new llvm::raw_fd_ostream(DiagOpts.DiagnosticLogFile.c_str(), + new llvm::raw_fd_ostream(DiagOpts->DiagnosticLogFile.c_str(), ErrorInfo, llvm::raw_fd_ostream::F_Append)); if (!ErrorInfo.empty()) { Diags.Report(diag::warn_fe_cc_log_diagnostics_failure) - << DiagOpts.DumpBuildInformation << ErrorInfo; + << DiagOpts->DumpBuildInformation << ErrorInfo; } else { FileOS->SetUnbuffered(); FileOS->SetUseAtomicWrites(true); @@ -145,7 +145,7 @@ static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts, Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), Logger)); } -static void SetupSerializedDiagnostics(const DiagnosticOptions &DiagOpts, +static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts, DiagnosticsEngine &Diags, StringRef OutputFile) { std::string ErrorInfo; @@ -171,13 +171,13 @@ void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv, DiagnosticConsumer *Client, bool ShouldOwnClient, bool ShouldCloneClient) { - Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv, Client, + Diagnostics = createDiagnostics(&getDiagnosticOpts(), Argc, Argv, Client, ShouldOwnClient, ShouldCloneClient, &getCodeGenOpts()); } IntrusiveRefCntPtr<DiagnosticsEngine> -CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, +CompilerInstance::createDiagnostics(DiagnosticOptions *Opts, int Argc, const char* const *Argv, DiagnosticConsumer *Client, bool ShouldOwnClient, @@ -185,7 +185,7 @@ CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, const CodeGenOptions *CodeGenOpts) { IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr<DiagnosticsEngine> - Diags(new DiagnosticsEngine(DiagID)); + Diags(new DiagnosticsEngine(DiagID, Opts)); // Create the diagnostic client for reporting errors or for // implementing -verify. @@ -198,22 +198,22 @@ CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts)); // Chain in -verify checker, if requested. - if (Opts.VerifyDiagnostics) + if (Opts->VerifyDiagnostics) Diags->setClient(new VerifyDiagnosticConsumer(*Diags)); // Chain in -diagnostic-log-file dumper, if requested. - if (!Opts.DiagnosticLogFile.empty()) + if (!Opts->DiagnosticLogFile.empty()) SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags); - if (!Opts.DumpBuildInformation.empty()) + if (!Opts->DumpBuildInformation.empty()) SetUpBuildDumpLog(Opts, Argc, Argv, *Diags); - if (!Opts.DiagnosticSerializationFile.empty()) + if (!Opts->DiagnosticSerializationFile.empty()) SetupSerializedDiagnostics(Opts, *Diags, - Opts.DiagnosticSerializationFile); + Opts->DiagnosticSerializationFile); // Configure our handling of diagnostics. - ProcessWarningOptions(*Diags, Opts); + ProcessWarningOptions(*Diags, *Opts); return Diags; } @@ -241,11 +241,13 @@ void CompilerInstance::createPreprocessor() { PTHMgr = PTHManager::Create(PPOpts.TokenCache, getDiagnostics()); // Create the Preprocessor. - HeaderSearch *HeaderInfo = new HeaderSearch(getFileManager(), + HeaderSearch *HeaderInfo = new HeaderSearch(&getHeaderSearchOpts(), + getFileManager(), getDiagnostics(), getLangOpts(), &getTarget()); - PP = new Preprocessor(getDiagnostics(), getLangOpts(), &getTarget(), + PP = new Preprocessor(&getPreprocessorOpts(), + getDiagnostics(), getLangOpts(), &getTarget(), getSourceManager(), *HeaderInfo, *this, PTHMgr, /*OwnsHeaderSearch=*/true); @@ -306,14 +308,12 @@ void CompilerInstance::createASTContext() { void CompilerInstance::createPCHExternalASTSource(StringRef Path, bool DisablePCHValidation, - bool DisableStatCache, bool AllowPCHWithCompilerErrors, void *DeserializationListener){ OwningPtr<ExternalASTSource> Source; bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0; Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot, DisablePCHValidation, - DisableStatCache, AllowPCHWithCompilerErrors, getPreprocessor(), getASTContext(), DeserializationListener, @@ -326,7 +326,6 @@ ExternalASTSource * CompilerInstance::createPCHExternalASTSource(StringRef Path, const std::string &Sysroot, bool DisablePCHValidation, - bool DisableStatCache, bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context, @@ -335,14 +334,15 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path, OwningPtr<ASTReader> Reader; Reader.reset(new ASTReader(PP, Context, Sysroot.empty() ? "" : Sysroot.c_str(), - DisablePCHValidation, DisableStatCache, + DisablePCHValidation, AllowPCHWithCompilerErrors)); Reader->setDeserializationListener( static_cast<ASTDeserializationListener *>(DeserializationListener)); switch (Reader->ReadAST(Path, Preamble ? serialization::MK_Preamble - : serialization::MK_PCH)) { + : serialization::MK_PCH, + ASTReader::ARR_None)) { case ASTReader::Success: // Set the predefines buffer as suggested by the PCH reader. Typically, the // predefines buffer will be empty. @@ -353,7 +353,10 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path, // Unrecoverable failure: don't even try to process the input file. break; - case ASTReader::IgnorePCH: + case ASTReader::OutOfDate: + case ASTReader::VersionMismatch: + case ASTReader::ConfigurationMismatch: + case ASTReader::HadErrors: // No suitable PCH file could be found. Return an error. break; } @@ -586,19 +589,29 @@ CompilerInstance::createOutputFile(StringRef OutputPath, // Initialization Utilities -bool CompilerInstance::InitializeSourceManager(StringRef InputFile, - SrcMgr::CharacteristicKind Kind){ - return InitializeSourceManager(InputFile, Kind, getDiagnostics(), +bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input){ + return InitializeSourceManager(Input, getDiagnostics(), getFileManager(), getSourceManager(), getFrontendOpts()); } -bool CompilerInstance::InitializeSourceManager(StringRef InputFile, - SrcMgr::CharacteristicKind Kind, +bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input, DiagnosticsEngine &Diags, FileManager &FileMgr, SourceManager &SourceMgr, const FrontendOptions &Opts) { + SrcMgr::CharacteristicKind + Kind = Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User; + + if (Input.isBuffer()) { + SourceMgr.createMainFileIDForMemBuffer(Input.getBuffer(), Kind); + assert(!SourceMgr.getMainFileID().isInvalid() && + "Couldn't establish MainFileID!"); + return true; + } + + StringRef InputFile = Input.getFile(); + // Figure out where to get and map in the main file. if (InputFile != "-") { const FileEntry *File = FileMgr.getFile(InputFile); @@ -607,6 +620,19 @@ bool CompilerInstance::InitializeSourceManager(StringRef InputFile, return false; } SourceMgr.createMainFileID(File, Kind); + + // The natural SourceManager infrastructure can't currently handle named + // pipes, but we would at least like to accept them for the main + // file. Detect them here, read them with the more generic MemoryBuffer + // function, and simply override their contents as we do for STDIN. + if (File->isNamedPipe()) { + OwningPtr<llvm::MemoryBuffer> MB; + if (llvm::error_code ec = llvm::MemoryBuffer::getFile(InputFile, MB)) { + Diags.Report(diag::err_cannot_open_file) << InputFile << ec.message(); + return false; + } + SourceMgr.overrideFileContents(File, MB.take()); + } } else { OwningPtr<llvm::MemoryBuffer> SB; if (llvm::MemoryBuffer::getSTDIN(SB)) { @@ -746,7 +772,7 @@ static void compileModule(CompilerInstance &ImportingInstance, // Someone else is responsible for building the module. Wait for them to // finish. Locked.waitForUnlock(); - break; + return; } ModuleMap &ModMap @@ -836,6 +862,7 @@ static void compileModule(CompilerInstance &ImportingInstance, // FIXME: Even though we're executing under crash protection, it would still // be nice to do this with RemoveFileOnSignal when we can. However, that // doesn't make sense for all clients, so clean this up manually. + Instance.clearOutputFiles(/*EraseFiles=*/true); if (!TempModuleMapFileName.empty()) llvm::sys::Path(TempModuleMapFileName).eraseFromDisk(); } @@ -939,13 +966,14 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc, const PreprocessorOptions &PPOpts = getPreprocessorOpts(); ModuleManager = new ASTReader(getPreprocessor(), *Context, Sysroot.empty() ? "" : Sysroot.c_str(), - PPOpts.DisablePCHValidation, - PPOpts.DisableStatCache); + PPOpts.DisablePCHValidation); if (hasASTConsumer()) { ModuleManager->setDeserializationListener( getASTConsumer().GetASTDeserializationListener()); getASTContext().setASTMutationListener( getASTConsumer().GetASTMutationListener()); + getPreprocessor().setPPMutationListener( + getASTConsumer().GetPPMutationListener()); } OwningPtr<ExternalASTSource> Source; Source.reset(ModuleManager); @@ -957,12 +985,39 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc, } // Try to load the module we found. + unsigned ARRFlags = ASTReader::ARR_None; + if (Module) + ARRFlags |= ASTReader::ARR_OutOfDate; switch (ModuleManager->ReadAST(ModuleFile->getName(), - serialization::MK_Module)) { + serialization::MK_Module, + ARRFlags)) { case ASTReader::Success: break; - case ASTReader::IgnorePCH: + case ASTReader::OutOfDate: { + // The module file is out-of-date. Rebuild it. + getFileManager().invalidateCache(ModuleFile); + bool Existed; + llvm::sys::fs::remove(ModuleFileName, Existed); + compileModule(*this, Module, ModuleFileName); + + // Try loading the module again. + ModuleFile = FileMgr->getFile(ModuleFileName); + if (!ModuleFile || + ModuleManager->ReadAST(ModuleFileName, + serialization::MK_Module, + ASTReader::ARR_None) != ASTReader::Success) { + KnownModules[Path[0].first] = 0; + return 0; + } + + // Okay, we've rebuilt and now loaded the module. + break; + } + + case ASTReader::VersionMismatch: + case ASTReader::ConfigurationMismatch: + case ASTReader::HadErrors: // FIXME: The ASTReader will already have complained, but can we showhorn // that diagnostic information into a more useful form? KnownModules[Path[0].first] = 0; @@ -980,6 +1035,9 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc, Module = PP->getHeaderSearchInfo().getModuleMap() .findModule((Path[0].first->getName())); } + + if (Module) + Module->setASTFile(ModuleFile); // Cache the result of this top-level module lookup for later. Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first; @@ -1079,9 +1137,12 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc, // implicit import declaration to capture it in the AST. if (IsInclusionDirective && hasASTContext()) { TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl(); - TU->addDecl(ImportDecl::CreateImplicit(getASTContext(), TU, - ImportLoc, Module, - Path.back().second)); + ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU, + ImportLoc, Module, + Path.back().second); + TU->addDecl(ImportD); + if (Consumer) + Consumer->HandleImplicitImportDecl(ImportD); } LastModuleImportLoc = ImportLoc; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index d39679c..b9c198b 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -11,6 +11,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/Version.h" #include "clang/Basic/FileManager.h" +#include "clang/Lex/HeaderSearchOptions.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/Options.h" @@ -20,6 +21,7 @@ #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/LangStandard.h" #include "clang/Serialization/ASTReader.h" +#include "llvm/ADT/Hashing.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" @@ -35,917 +37,21 @@ using namespace clang; //===----------------------------------------------------------------------===// CompilerInvocationBase::CompilerInvocationBase() - : LangOpts(new LangOptions()) {} + : LangOpts(new LangOptions()), TargetOpts(new TargetOptions()), + DiagnosticOpts(new DiagnosticOptions()), + HeaderSearchOpts(new HeaderSearchOptions()), + PreprocessorOpts(new PreprocessorOptions()) {} CompilerInvocationBase::CompilerInvocationBase(const CompilerInvocationBase &X) : RefCountedBase<CompilerInvocation>(), - LangOpts(new LangOptions(*X.getLangOpts())) {} + LangOpts(new LangOptions(*X.getLangOpts())), + TargetOpts(new TargetOptions(X.getTargetOpts())), + DiagnosticOpts(new DiagnosticOptions(X.getDiagnosticOpts())), + HeaderSearchOpts(new HeaderSearchOptions(X.getHeaderSearchOpts())), + PreprocessorOpts(new PreprocessorOptions(X.getPreprocessorOpts())) {} //===----------------------------------------------------------------------===// -// Utility functions. -//===----------------------------------------------------------------------===// - -static const char *getAnalysisStoreName(AnalysisStores Kind) { - switch (Kind) { - default: - llvm_unreachable("Unknown analysis store!"); -#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \ - case NAME##Model: return CMDFLAG; -#include "clang/Frontend/Analyses.def" - } -} - -static const char *getAnalysisConstraintName(AnalysisConstraints Kind) { - switch (Kind) { - default: - llvm_unreachable("Unknown analysis constraints!"); -#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \ - case NAME##Model: return CMDFLAG; -#include "clang/Frontend/Analyses.def" - } -} - -static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) { - switch (Kind) { - default: - llvm_unreachable("Unknown analysis client!"); -#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREATE) \ - case PD_##NAME: return CMDFLAG; -#include "clang/Frontend/Analyses.def" - } -} - -static const char *getAnalysisPurgeModeName(AnalysisPurgeMode Kind) { - switch (Kind) { - default: - llvm_unreachable("Unknown analysis purge mode!"); -#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \ - case NAME: return CMDFLAG; -#include "clang/Frontend/Analyses.def" - } -} - -static const char *getAnalysisIPAModeName(AnalysisIPAMode Kind) { - switch (Kind) { - default: - llvm_unreachable("Unknown analysis ipa mode!"); -#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) \ - case NAME: return CMDFLAG; -#include "clang/Frontend/Analyses.def" - } -} - -static const char * - getAnalysisInliningModeName(AnalysisInliningMode Kind) { - switch (Kind) { - default: - llvm_unreachable("Unknown analysis inlining mode!"); -#define ANALYSIS_INLINE_SELECTION(NAME, CMDFLAG, DESC) \ - case NAME: return CMDFLAG; -#include "clang/Frontend/Analyses.def" - } -} - -//===----------------------------------------------------------------------===// -// Serialization (to args) -//===----------------------------------------------------------------------===// - -namespace { - /// ToArgsList - Helper class to create a list of std::strings. - class ToArgsList { - std::vector<std::string> &Res; - public: - explicit ToArgsList(std::vector<std::string> &Res) : Res(Res) {} - - void push_back(StringRef Str) { - // Avoid creating a temporary string. - Res.push_back(std::string()); - Res.back().assign(Str.data(), Str.size()); - } - - void push_back(StringRef Str1, StringRef Str2) { - push_back(Str1); - push_back(Str2); - } - }; -} - -static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, ToArgsList &Res) { - if (Opts.ShowCheckerHelp) - Res.push_back("-analyzer-checker-help"); - if (Opts.AnalysisStoreOpt != RegionStoreModel) - Res.push_back("-analyzer-store", - getAnalysisStoreName(Opts.AnalysisStoreOpt)); - if (Opts.AnalysisConstraintsOpt != RangeConstraintsModel) - Res.push_back("-analyzer-constraints", - getAnalysisConstraintName(Opts.AnalysisConstraintsOpt)); - if (Opts.AnalysisDiagOpt != PD_HTML) - Res.push_back("-analyzer-output", - getAnalysisDiagClientName(Opts.AnalysisDiagOpt)); - if (Opts.AnalysisPurgeOpt != PurgeStmt) - Res.push_back("-analyzer-purge", - getAnalysisPurgeModeName(Opts.AnalysisPurgeOpt)); - if (!Opts.AnalyzeSpecificFunction.empty()) - Res.push_back("-analyze-function", Opts.AnalyzeSpecificFunction); - if (Opts.IPAMode != Inlining) - Res.push_back("-analyzer-ipa", getAnalysisIPAModeName(Opts.IPAMode)); - if (Opts.InliningMode != NoRedundancy) - Res.push_back("-analyzer-inlining-mode", - getAnalysisInliningModeName(Opts.InliningMode)); - - if (Opts.AnalyzeAll) - Res.push_back("-analyzer-opt-analyze-headers"); - if (Opts.AnalyzerDisplayProgress) - Res.push_back("-analyzer-display-progress"); - if (Opts.AnalyzeNestedBlocks) - Res.push_back("-analyzer-opt-analyze-nested-blocks"); - if (Opts.EagerlyAssume) - Res.push_back("-analyzer-eagerly-assume"); - if (Opts.TrimGraph) - Res.push_back("-trim-egraph"); - if (Opts.VisualizeEGDot) - Res.push_back("-analyzer-viz-egraph-graphviz"); - if (Opts.VisualizeEGUbi) - Res.push_back("-analyzer-viz-egraph-ubigraph"); - if (Opts.NoRetryExhausted) - Res.push_back("-analyzer-disable-retry-exhausted"); - - for (unsigned i = 0, e = Opts.CheckersControlList.size(); i != e; ++i) { - const std::pair<std::string, bool> &opt = Opts.CheckersControlList[i]; - if (opt.second) - Res.push_back("-analyzer-disable-checker"); - else - Res.push_back("-analyzer-checker"); - Res.push_back(opt.first); - } -} - -static void CodeGenOptsToArgs(const CodeGenOptions &Opts, ToArgsList &Res) { - switch (Opts.DebugInfo) { - case CodeGenOptions::NoDebugInfo: - break; - case CodeGenOptions::DebugLineTablesOnly: - Res.push_back("-gline-tables-only"); - break; - case CodeGenOptions::LimitedDebugInfo: - Res.push_back("-g"); - Res.push_back("-flimit-debug-info"); - break; - case CodeGenOptions::FullDebugInfo: - Res.push_back("-g"); - Res.push_back("-fno-limit-debug-info"); - break; - } - if (Opts.DisableLLVMOpts) - Res.push_back("-disable-llvm-optzns"); - if (Opts.DisableRedZone) - Res.push_back("-disable-red-zone"); - if (Opts.DisableTailCalls) - Res.push_back("-mdisable-tail-calls"); - if (!Opts.DebugCompilationDir.empty()) - Res.push_back("-fdebug-compilation-dir", Opts.DebugCompilationDir); - if (!Opts.DwarfDebugFlags.empty()) - Res.push_back("-dwarf-debug-flags", Opts.DwarfDebugFlags); - if (Opts.EmitGcovArcs) - Res.push_back("-femit-coverage-data"); - if (Opts.EmitGcovNotes) - Res.push_back("-femit-coverage-notes"); - if (Opts.EmitOpenCLArgMetadata) - Res.push_back("-cl-kernel-arg-info"); - if (!Opts.MergeAllConstants) - Res.push_back("-fno-merge-all-constants"); - if (Opts.NoCommon) - Res.push_back("-fno-common"); - if (Opts.ForbidGuardVariables) - Res.push_back("-fforbid-guard-variables"); - if (Opts.UseRegisterSizedBitfieldAccess) - Res.push_back("-fuse-register-sized-bitfield-access"); - if (Opts.NoImplicitFloat) - Res.push_back("-no-implicit-float"); - if (Opts.OmitLeafFramePointer) - Res.push_back("-momit-leaf-frame-pointer"); - if (Opts.OptimizeSize) { - assert(Opts.OptimizationLevel == 2 && "Invalid options!"); - Opts.OptimizeSize == 1 ? Res.push_back("-Os") : Res.push_back("-Oz"); - } else if (Opts.OptimizationLevel != 0) - Res.push_back("-O" + llvm::utostr(Opts.OptimizationLevel)); - if (!Opts.MainFileName.empty()) - Res.push_back("-main-file-name", Opts.MainFileName); - if (Opts.NoInfsFPMath) - Res.push_back("-menable-no-infinities"); - if (Opts.NoNaNsFPMath) - Res.push_back("-menable-no-nans"); - // SimplifyLibCalls is only derived. - // TimePasses is only derived. - // UnitAtATime is unused. - // Inlining is only derived. - - // UnrollLoops is derived, but also accepts an option, no - // harm in pushing it back here. - if (Opts.UnrollLoops) - Res.push_back("-funroll-loops"); - if (Opts.DataSections) - Res.push_back("-fdata-sections"); - if (Opts.FunctionSections) - Res.push_back("-ffunction-sections"); - if (Opts.AsmVerbose) - Res.push_back("-masm-verbose"); - if (!Opts.CodeModel.empty()) - Res.push_back("-mcode-model", Opts.CodeModel); - if (Opts.CUDAIsDevice) - Res.push_back("-fcuda-is-device"); - if (!Opts.CXAAtExit) - Res.push_back("-fno-use-cxa-atexit"); - if (Opts.CXXCtorDtorAliases) - Res.push_back("-mconstructor-aliases"); - if (Opts.ObjCAutoRefCountExceptions) - Res.push_back("-fobjc-arc-eh"); - if (!Opts.DebugPass.empty()) { - Res.push_back("-mdebug-pass", Opts.DebugPass); - } - if (Opts.DisableFPElim) - Res.push_back("-mdisable-fp-elim"); - if (!Opts.FloatABI.empty()) - Res.push_back("-mfloat-abi", Opts.FloatABI); - if (!Opts.LimitFloatPrecision.empty()) - Res.push_back("-mlimit-float-precision", Opts.LimitFloatPrecision); - if (Opts.NoZeroInitializedInBSS) - Res.push_back("-mno-zero-initialized-bss"); - switch (Opts.getObjCDispatchMethod()) { - case CodeGenOptions::Legacy: - break; - case CodeGenOptions::Mixed: - Res.push_back("-fobjc-dispatch-method=mixed"); - break; - case CodeGenOptions::NonLegacy: - Res.push_back("-fobjc-dispatch-method=non-legacy"); - break; - } - if (Opts.BoundsChecking > 0) - Res.push_back("-fbounds-checking=" + llvm::utostr(Opts.BoundsChecking)); - if (Opts.NumRegisterParameters) - Res.push_back("-mregparm", llvm::utostr(Opts.NumRegisterParameters)); - if (Opts.NoGlobalMerge) - Res.push_back("-mno-global-merge"); - if (Opts.NoExecStack) - Res.push_back("-mnoexecstack"); - if (Opts.RelaxAll) - Res.push_back("-mrelax-all"); - if (Opts.SaveTempLabels) - Res.push_back("-msave-temp-labels"); - if (Opts.NoDwarf2CFIAsm) - Res.push_back("-fno-dwarf2-cfi-asm"); - if (Opts.NoDwarfDirectoryAsm) - Res.push_back("-fno-dwarf-directory-asm"); - if (Opts.SoftFloat) - Res.push_back("-msoft-float"); - if (Opts.StrictEnums) - Res.push_back("-fstrict-enums"); - if (Opts.UnwindTables) - Res.push_back("-munwind-tables"); - if (Opts.RelocationModel != "pic") - Res.push_back("-mrelocation-model", Opts.RelocationModel); - if (!Opts.VerifyModule) - Res.push_back("-disable-llvm-verifier"); - for (unsigned i = 0, e = Opts.BackendOptions.size(); i != e; ++i) - Res.push_back("-backend-option", Opts.BackendOptions[i]); - - switch (Opts.DefaultTLSModel) { - case CodeGenOptions::GeneralDynamicTLSModel: - break; - case CodeGenOptions::LocalDynamicTLSModel: - Res.push_back("-ftls-model=local-dynamic"); - break; - case CodeGenOptions::InitialExecTLSModel: - Res.push_back("-ftls-model=initial-exec"); - break; - case CodeGenOptions::LocalExecTLSModel: - Res.push_back("-ftls-model=local-exec"); - break; - } -} - -static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts, - ToArgsList &Res) { - if (Opts.IncludeSystemHeaders) - Res.push_back("-sys-header-deps"); - if (Opts.ShowHeaderIncludes) - Res.push_back("-H"); - if (!Opts.HeaderIncludeOutputFile.empty()) - Res.push_back("-header-include-file", Opts.HeaderIncludeOutputFile); - if (Opts.UsePhonyTargets) - Res.push_back("-MP"); - if (!Opts.OutputFile.empty()) - Res.push_back("-dependency-file", Opts.OutputFile); - for (unsigned i = 0, e = Opts.Targets.size(); i != e; ++i) - Res.push_back("-MT", Opts.Targets[i]); -} - -static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts, - ToArgsList &Res) { - if (Opts.IgnoreWarnings) - Res.push_back("-w"); - if (Opts.NoRewriteMacros) - Res.push_back("-Wno-rewrite-macros"); - if (Opts.Pedantic) - Res.push_back("-pedantic"); - if (Opts.PedanticErrors) - Res.push_back("-pedantic-errors"); - if (!Opts.ShowColumn) - Res.push_back("-fno-show-column"); - if (!Opts.ShowLocation) - Res.push_back("-fno-show-source-location"); - if (!Opts.ShowCarets) - Res.push_back("-fno-caret-diagnostics"); - if (!Opts.ShowFixits) - Res.push_back("-fno-diagnostics-fixit-info"); - if (Opts.ShowSourceRanges) - Res.push_back("-fdiagnostics-print-source-range-info"); - if (Opts.ShowParseableFixits) - Res.push_back("-fdiagnostics-parseable-fixits"); - if (Opts.ShowColors) - Res.push_back("-fcolor-diagnostics"); - if (Opts.VerifyDiagnostics) - Res.push_back("-verify"); - if (Opts.ShowOptionNames) - Res.push_back("-fdiagnostics-show-option"); - if (Opts.ShowCategories == 1) - Res.push_back("-fdiagnostics-show-category=id"); - else if (Opts.ShowCategories == 2) - Res.push_back("-fdiagnostics-show-category=name"); - switch (Opts.Format) { - case DiagnosticOptions::Clang: - Res.push_back("-fdiagnostics-format=clang"); break; - case DiagnosticOptions::Msvc: - Res.push_back("-fdiagnostics-format=msvc"); break; - case DiagnosticOptions::Vi: - Res.push_back("-fdiagnostics-format=vi"); break; - } - if (Opts.ErrorLimit) - Res.push_back("-ferror-limit", llvm::utostr(Opts.ErrorLimit)); - if (!Opts.DiagnosticLogFile.empty()) - Res.push_back("-diagnostic-log-file", Opts.DiagnosticLogFile); - if (Opts.MacroBacktraceLimit - != DiagnosticOptions::DefaultMacroBacktraceLimit) - Res.push_back("-fmacro-backtrace-limit", - llvm::utostr(Opts.MacroBacktraceLimit)); - if (Opts.TemplateBacktraceLimit - != DiagnosticOptions::DefaultTemplateBacktraceLimit) - Res.push_back("-ftemplate-backtrace-limit", - llvm::utostr(Opts.TemplateBacktraceLimit)); - if (Opts.ConstexprBacktraceLimit - != DiagnosticOptions::DefaultConstexprBacktraceLimit) - Res.push_back("-fconstexpr-backtrace-limit", - llvm::utostr(Opts.ConstexprBacktraceLimit)); - - if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) - Res.push_back("-ftabstop", llvm::utostr(Opts.TabStop)); - if (Opts.MessageLength) - Res.push_back("-fmessage-length", llvm::utostr(Opts.MessageLength)); - if (!Opts.DumpBuildInformation.empty()) - Res.push_back("-dump-build-information", Opts.DumpBuildInformation); - for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) - Res.push_back("-W" + Opts.Warnings[i]); -} - -static const char *getInputKindName(InputKind Kind) { - switch (Kind) { - case IK_None: break; - case IK_AST: return "ast"; - case IK_Asm: return "assembler-with-cpp"; - case IK_C: return "c"; - case IK_CXX: return "c++"; - case IK_LLVM_IR: return "ir"; - case IK_ObjC: return "objective-c"; - case IK_ObjCXX: return "objective-c++"; - case IK_OpenCL: return "cl"; - case IK_CUDA: return "cuda"; - case IK_PreprocessedC: return "cpp-output"; - case IK_PreprocessedCXX: return "c++-cpp-output"; - case IK_PreprocessedObjC: return "objective-c-cpp-output"; - case IK_PreprocessedObjCXX:return "objective-c++-cpp-output"; - } - - llvm_unreachable("Unexpected language kind!"); -} - -static const char *getActionName(frontend::ActionKind Kind) { - switch (Kind) { - case frontend::PluginAction: - llvm_unreachable("Invalid kind!"); - - case frontend::ASTDeclList: return "-ast-list"; - case frontend::ASTDump: return "-ast-dump"; - case frontend::ASTDumpXML: return "-ast-dump-xml"; - case frontend::ASTPrint: return "-ast-print"; - case frontend::ASTView: return "-ast-view"; - case frontend::DumpRawTokens: return "-dump-raw-tokens"; - case frontend::DumpTokens: return "-dump-tokens"; - case frontend::EmitAssembly: return "-S"; - case frontend::EmitBC: return "-emit-llvm-bc"; - case frontend::EmitHTML: return "-emit-html"; - case frontend::EmitLLVM: return "-emit-llvm"; - case frontend::EmitLLVMOnly: return "-emit-llvm-only"; - case frontend::EmitCodeGenOnly: return "-emit-codegen-only"; - case frontend::EmitObj: return "-emit-obj"; - case frontend::FixIt: return "-fixit"; - case frontend::GenerateModule: return "-emit-module"; - case frontend::GeneratePCH: return "-emit-pch"; - case frontend::GeneratePTH: return "-emit-pth"; - case frontend::InitOnly: return "-init-only"; - case frontend::ParseSyntaxOnly: return "-fsyntax-only"; - case frontend::PrintDeclContext: return "-print-decl-contexts"; - case frontend::PrintPreamble: return "-print-preamble"; - case frontend::PrintPreprocessedInput: return "-E"; - case frontend::RewriteMacros: return "-rewrite-macros"; - case frontend::RewriteObjC: return "-rewrite-objc"; - case frontend::RewriteTest: return "-rewrite-test"; - case frontend::RunAnalysis: return "-analyze"; - case frontend::MigrateSource: return "-migrate"; - case frontend::RunPreprocessorOnly: return "-Eonly"; - } - - llvm_unreachable("Unexpected language kind!"); -} - -static void FileSystemOptsToArgs(const FileSystemOptions &Opts, ToArgsList &Res){ - if (!Opts.WorkingDir.empty()) - Res.push_back("-working-directory", Opts.WorkingDir); -} - -static void CodeCompleteOptionsToArgs(const CodeCompleteOptions &Opts, - ToArgsList &Res) { - if (Opts.IncludeMacros) - Res.push_back("-code-completion-macros"); - if (Opts.IncludeCodePatterns) - Res.push_back("-code-completion-patterns"); - if (!Opts.IncludeGlobals) - Res.push_back("-no-code-completion-globals"); - if (Opts.IncludeBriefComments) - Res.push_back("-code-completion-brief-comments"); -} - -static void FrontendOptsToArgs(const FrontendOptions &Opts, ToArgsList &Res) { - if (Opts.DisableFree) - Res.push_back("-disable-free"); - if (Opts.RelocatablePCH) - Res.push_back("-relocatable-pch"); - if (Opts.ShowHelp) - Res.push_back("-help"); - if (Opts.ShowStats) - Res.push_back("-print-stats"); - if (Opts.ShowTimers) - Res.push_back("-ftime-report"); - if (Opts.ShowVersion) - Res.push_back("-version"); - if (Opts.FixWhatYouCan) - Res.push_back("-fix-what-you-can"); - if (Opts.FixOnlyWarnings) - Res.push_back("-fix-only-warnings"); - if (Opts.FixAndRecompile) - Res.push_back("-fixit-recompile"); - if (Opts.FixToTemporaries) - Res.push_back("-fixit-to-temporary"); - switch (Opts.ARCMTAction) { - case FrontendOptions::ARCMT_None: - break; - case FrontendOptions::ARCMT_Check: - Res.push_back("-arcmt-check"); - break; - case FrontendOptions::ARCMT_Modify: - Res.push_back("-arcmt-modify"); - break; - case FrontendOptions::ARCMT_Migrate: - Res.push_back("-arcmt-migrate"); - break; - } - CodeCompleteOptionsToArgs(Opts.CodeCompleteOpts, Res); - if (!Opts.MTMigrateDir.empty()) - Res.push_back("-mt-migrate-directory", Opts.MTMigrateDir); - if (!Opts.ARCMTMigrateReportOut.empty()) - Res.push_back("-arcmt-migrate-report-output", Opts.ARCMTMigrateReportOut); - if (Opts.ARCMTMigrateEmitARCErrors) - Res.push_back("-arcmt-migrate-emit-errors"); - - if (Opts.ObjCMTAction & ~FrontendOptions::ObjCMT_Literals) - Res.push_back("-objcmt-migrate-literals"); - if (Opts.ObjCMTAction & ~FrontendOptions::ObjCMT_Subscripting) - Res.push_back("-objcmt-migrate-subscripting"); - - bool NeedLang = false; - for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) - if (FrontendOptions::getInputKindForExtension(Opts.Inputs[i].File) != - Opts.Inputs[i].Kind) - NeedLang = true; - if (NeedLang) - Res.push_back("-x", getInputKindName(Opts.Inputs[0].Kind)); - for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) { - assert((!NeedLang || Opts.Inputs[i].Kind == Opts.Inputs[0].Kind) && - "Unable to represent this input vector!"); - Res.push_back(Opts.Inputs[i].File); - } - - if (!Opts.OutputFile.empty()) - Res.push_back("-o", Opts.OutputFile); - if (!Opts.CodeCompletionAt.FileName.empty()) - Res.push_back("-code-completion-at", - Opts.CodeCompletionAt.FileName + ":" + - llvm::utostr(Opts.CodeCompletionAt.Line) + ":" + - llvm::utostr(Opts.CodeCompletionAt.Column)); - if (Opts.ProgramAction != frontend::PluginAction) - Res.push_back(getActionName(Opts.ProgramAction)); - if (!Opts.ActionName.empty()) { - Res.push_back("-plugin", Opts.ActionName); - for(unsigned i = 0, e = Opts.PluginArgs.size(); i != e; ++i) - Res.push_back("-plugin-arg-" + Opts.ActionName, Opts.PluginArgs[i]); - } - if (!Opts.ASTDumpFilter.empty()) - Res.push_back("-ast-dump-filter", Opts.ASTDumpFilter); - for (unsigned i = 0, e = Opts.Plugins.size(); i != e; ++i) - Res.push_back("-load", Opts.Plugins[i]); - for (unsigned i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) { - Res.push_back("-add-plugin", Opts.AddPluginActions[i]); - for(unsigned ai = 0, ae = Opts.AddPluginArgs.size(); ai != ae; ++ai) - Res.push_back("-plugin-arg-" + Opts.AddPluginActions[i], - Opts.AddPluginArgs[i][ai]); - } - for (unsigned i = 0, e = Opts.ASTMergeFiles.size(); i != e; ++i) - Res.push_back("-ast-merge", Opts.ASTMergeFiles[i]); - for (unsigned i = 0, e = Opts.LLVMArgs.size(); i != e; ++i) - Res.push_back("-mllvm", Opts.LLVMArgs[i]); - if (!Opts.OverrideRecordLayoutsFile.empty()) - Res.push_back("-foverride-record-layout=" + Opts.OverrideRecordLayoutsFile); -} - -static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, - ToArgsList &Res) { - if (Opts.Sysroot != "/") { - Res.push_back("-isysroot"); - Res.push_back(Opts.Sysroot); - } - - /// User specified include entries. - for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) { - const HeaderSearchOptions::Entry &E = Opts.UserEntries[i]; - if (E.IsFramework && (E.Group != frontend::Angled || !E.IsUserSupplied)) - llvm::report_fatal_error("Invalid option set!"); - if (E.IsUserSupplied) { - switch (E.Group) { - case frontend::After: - Res.push_back("-idirafter"); - break; - - case frontend::Quoted: - Res.push_back("-iquote"); - break; - - case frontend::System: - Res.push_back("-isystem"); - break; - - case frontend::IndexHeaderMap: - Res.push_back("-index-header-map"); - Res.push_back(E.IsFramework? "-F" : "-I"); - break; - - case frontend::CSystem: - Res.push_back("-c-isystem"); - break; - - case frontend::CXXSystem: - Res.push_back("-cxx-isystem"); - break; - - case frontend::ObjCSystem: - Res.push_back("-objc-isystem"); - break; - - case frontend::ObjCXXSystem: - Res.push_back("-objcxx-isystem"); - break; - - case frontend::Angled: - Res.push_back(E.IsFramework ? "-F" : "-I"); - break; - } - } else { - if (E.IsInternal) { - assert(E.Group == frontend::System && "Unexpected header search group"); - if (E.ImplicitExternC) - Res.push_back("-internal-externc-isystem"); - else - Res.push_back("-internal-isystem"); - } else { - if (E.Group != frontend::Angled && E.Group != frontend::System) - llvm::report_fatal_error("Invalid option set!"); - Res.push_back(E.Group == frontend::Angled ? "-iwithprefixbefore" : - "-iwithprefix"); - } - } - Res.push_back(E.Path); - } - - /// User-specified system header prefixes. - for (unsigned i = 0, e = Opts.SystemHeaderPrefixes.size(); i != e; ++i) { - if (Opts.SystemHeaderPrefixes[i].IsSystemHeader) - Res.push_back("-isystem-prefix"); - else - Res.push_back("-ino-system-prefix"); - - Res.push_back(Opts.SystemHeaderPrefixes[i].Prefix); - } - - if (!Opts.ResourceDir.empty()) - Res.push_back("-resource-dir", Opts.ResourceDir); - if (!Opts.ModuleCachePath.empty()) - Res.push_back("-fmodule-cache-path", Opts.ModuleCachePath); - if (!Opts.UseStandardSystemIncludes) - Res.push_back("-nostdsysteminc"); - if (!Opts.UseStandardCXXIncludes) - Res.push_back("-nostdinc++"); - if (Opts.UseLibcxx) - Res.push_back("-stdlib=libc++"); - if (Opts.Verbose) - Res.push_back("-v"); -} - -static void LangOptsToArgs(const LangOptions &Opts, ToArgsList &Res) { - LangOptions DefaultLangOpts; - - // FIXME: Need to set -std to get all the implicit options. - - // FIXME: We want to only pass options relative to the defaults, which - // requires constructing a target. :( - // - // It would be better to push the all target specific choices into the driver, - // so that everything below that was more uniform. - - if (Opts.Trigraphs) - Res.push_back("-trigraphs"); - // Implicit based on the input kind: - // AsmPreprocessor, CPlusPlus, ObjC1, ObjC2, OpenCL - // Implicit based on the input language standard: - // BCPLComment, C99, CPlusPlus0x, Digraphs, GNUInline, ImplicitInt, GNUMode - if (Opts.DollarIdents) - Res.push_back("-fdollars-in-identifiers"); - if (Opts.GNUMode && !Opts.GNUKeywords) - Res.push_back("-fno-gnu-keywords"); - if (!Opts.GNUMode && Opts.GNUKeywords) - Res.push_back("-fgnu-keywords"); - if (Opts.MicrosoftExt) - Res.push_back("-fms-extensions"); - if (Opts.MicrosoftMode) - Res.push_back("-fms-compatibility"); - if (Opts.MSCVersion != 0) - Res.push_back("-fmsc-version=" + llvm::utostr(Opts.MSCVersion)); - if (Opts.Borland) - Res.push_back("-fborland-extensions"); - if (Opts.ObjCDefaultSynthProperties) - Res.push_back("-fobjc-default-synthesize-properties"); - // NoInline is implicit. - if (!Opts.CXXOperatorNames) - Res.push_back("-fno-operator-names"); - if (Opts.PascalStrings) - Res.push_back("-fpascal-strings"); - if (Opts.CatchUndefined) - Res.push_back("-fcatch-undefined-behavior"); - if (Opts.AddressSanitizer) - Res.push_back("-faddress-sanitizer"); - if (Opts.ThreadSanitizer) - Res.push_back("-fthread-sanitizer"); - if (Opts.WritableStrings) - Res.push_back("-fwritable-strings"); - if (Opts.ConstStrings) - Res.push_back("-fconst-strings"); - if (!Opts.LaxVectorConversions) - Res.push_back("-fno-lax-vector-conversions"); - if (Opts.AltiVec) - Res.push_back("-faltivec"); - if (Opts.Exceptions) - Res.push_back("-fexceptions"); - if (Opts.ObjCExceptions) - Res.push_back("-fobjc-exceptions"); - if (Opts.CXXExceptions) - Res.push_back("-fcxx-exceptions"); - if (Opts.SjLjExceptions) - Res.push_back("-fsjlj-exceptions"); - if (Opts.TraditionalCPP) - Res.push_back("-traditional-cpp"); - if (!Opts.RTTI) - Res.push_back("-fno-rtti"); - if (Opts.MSBitfields) - Res.push_back("-mms-bitfields"); - if (Opts.Freestanding) - Res.push_back("-ffreestanding"); - if (Opts.NoBuiltin) - Res.push_back("-fno-builtin"); - if (!Opts.AssumeSaneOperatorNew) - Res.push_back("-fno-assume-sane-operator-new"); - if (!Opts.ThreadsafeStatics) - Res.push_back("-fno-threadsafe-statics"); - if (Opts.POSIXThreads) - Res.push_back("-pthread"); - if (Opts.Blocks) - Res.push_back("-fblocks"); - if (Opts.BlocksRuntimeOptional) - Res.push_back("-fblocks-runtime-optional"); - if (Opts.Modules) - Res.push_back("-fmodules"); - if (Opts.EmitAllDecls) - Res.push_back("-femit-all-decls"); - if (Opts.MathErrno) - Res.push_back("-fmath-errno"); - switch (Opts.getSignedOverflowBehavior()) { - case LangOptions::SOB_Undefined: break; - case LangOptions::SOB_Defined: Res.push_back("-fwrapv"); break; - case LangOptions::SOB_Trapping: - Res.push_back("-ftrapv"); - if (!Opts.OverflowHandler.empty()) - Res.push_back("-ftrapv-handler", Opts.OverflowHandler); - break; - } - switch (Opts.getFPContractMode()) { - case LangOptions::FPC_Off: Res.push_back("-ffp-contract=off"); break; - case LangOptions::FPC_On: Res.push_back("-ffp-contract=on"); break; - case LangOptions::FPC_Fast: Res.push_back("-ffp-contract=fast"); break; - } - if (Opts.HeinousExtensions) - Res.push_back("-fheinous-gnu-extensions"); - // Optimize is implicit. - // OptimizeSize is implicit. - if (Opts.FastMath) - Res.push_back("-ffast-math"); - if (Opts.Static) - Res.push_back("-static-define"); - if (Opts.DumpRecordLayoutsSimple) - Res.push_back("-fdump-record-layouts-simple"); - else if (Opts.DumpRecordLayouts) - Res.push_back("-fdump-record-layouts"); - if (Opts.DumpVTableLayouts) - Res.push_back("-fdump-vtable-layouts"); - if (Opts.NoBitFieldTypeAlign) - Res.push_back("-fno-bitfield-type-alignment"); - if (Opts.PICLevel) - Res.push_back("-pic-level", llvm::utostr(Opts.PICLevel)); - if (Opts.PIELevel) - Res.push_back("-pie-level", llvm::utostr(Opts.PIELevel)); - if (Opts.ObjCGCBitmapPrint) - Res.push_back("-print-ivar-layout"); - if (Opts.NoConstantCFStrings) - Res.push_back("-fno-constant-cfstrings"); - if (!Opts.AccessControl) - Res.push_back("-fno-access-control"); - if (!Opts.CharIsSigned) - Res.push_back("-fno-signed-char"); - if (Opts.ShortWChar) - Res.push_back("-fshort-wchar"); - if (!Opts.ElideConstructors) - Res.push_back("-fno-elide-constructors"); - if (Opts.getGC() != LangOptions::NonGC) { - if (Opts.getGC() == LangOptions::HybridGC) { - Res.push_back("-fobjc-gc"); - } else { - assert(Opts.getGC() == LangOptions::GCOnly && "Invalid GC mode!"); - Res.push_back("-fobjc-gc-only"); - } - } - Res.push_back("-fobjc-runtime=" + Opts.ObjCRuntime.getAsString()); - if (Opts.ObjCAutoRefCount) - Res.push_back("-fobjc-arc"); - if (Opts.ObjCRuntimeHasWeak) - Res.push_back("-fobjc-runtime-has-weak"); - if (!Opts.ObjCInferRelatedResultType) - Res.push_back("-fno-objc-infer-related-result-type"); - - if (Opts.AppleKext) - Res.push_back("-fapple-kext"); - - if (Opts.getVisibilityMode() != DefaultVisibility) { - Res.push_back("-fvisibility"); - if (Opts.getVisibilityMode() == HiddenVisibility) { - Res.push_back("hidden"); - } else { - assert(Opts.getVisibilityMode() == ProtectedVisibility && - "Invalid visibility!"); - Res.push_back("protected"); - } - } - if (Opts.InlineVisibilityHidden) - Res.push_back("-fvisibility-inlines-hidden"); - - if (Opts.getStackProtector() != 0) - Res.push_back("-stack-protector", llvm::utostr(Opts.getStackProtector())); - if (Opts.InstantiationDepth != DefaultLangOpts.InstantiationDepth) - Res.push_back("-ftemplate-depth", llvm::utostr(Opts.InstantiationDepth)); - if (Opts.ConstexprCallDepth != DefaultLangOpts.ConstexprCallDepth) - Res.push_back("-fconstexpr-depth", llvm::utostr(Opts.ConstexprCallDepth)); - if (!Opts.ObjCConstantStringClass.empty()) - Res.push_back("-fconstant-string-class", Opts.ObjCConstantStringClass); - if (Opts.FakeAddressSpaceMap) - Res.push_back("-ffake-address-space-map"); - if (Opts.ParseUnknownAnytype) - Res.push_back("-funknown-anytype"); - if (Opts.DebuggerSupport) - Res.push_back("-fdebugger-support"); - if (Opts.DebuggerCastResultToId) - Res.push_back("-fdebugger-cast-result-to-id"); - if (Opts.DebuggerObjCLiteral) - Res.push_back("-fdebugger-objc-literal"); - if (Opts.DelayedTemplateParsing) - Res.push_back("-fdelayed-template-parsing"); - if (Opts.Deprecated) - Res.push_back("-fdeprecated-macro"); - if (Opts.ApplePragmaPack) - Res.push_back("-fapple-pragma-pack"); - if (!Opts.CurrentModule.empty()) - Res.push_back("-fmodule-name=" + Opts.CurrentModule); -} - -static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts, - ToArgsList &Res) { - for (unsigned i = 0, e = Opts.Macros.size(); i != e; ++i) - Res.push_back(std::string(Opts.Macros[i].second ? "-U" : "-D") + - Opts.Macros[i].first); - for (unsigned i = 0, e = Opts.Includes.size(); i != e; ++i) { - // FIXME: We need to avoid reincluding the implicit PCH and PTH includes. - Res.push_back("-include", Opts.Includes[i]); - } - for (unsigned i = 0, e = Opts.MacroIncludes.size(); i != e; ++i) - Res.push_back("-imacros", Opts.MacroIncludes[i]); - if (!Opts.UsePredefines) - Res.push_back("-undef"); - if (Opts.DetailedRecord) - Res.push_back("-detailed-preprocessing-record"); - if (!Opts.ImplicitPCHInclude.empty()) - Res.push_back("-include-pch", Opts.ImplicitPCHInclude); - if (!Opts.ImplicitPTHInclude.empty()) - Res.push_back("-include-pth", Opts.ImplicitPTHInclude); - if (!Opts.TokenCache.empty()) { - if (Opts.ImplicitPTHInclude.empty()) - Res.push_back("-token-cache", Opts.TokenCache); - else - assert(Opts.ImplicitPTHInclude == Opts.TokenCache && - "Unsupported option combination!"); - } - for (unsigned i = 0, e = Opts.ChainedIncludes.size(); i != e; ++i) - Res.push_back("-chain-include", Opts.ChainedIncludes[i]); - for (unsigned i = 0, e = Opts.RemappedFiles.size(); i != e; ++i) { - Res.push_back("-remap-file", Opts.RemappedFiles[i].first + ";" + - Opts.RemappedFiles[i].second); - } -} - -static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts, - ToArgsList &Res) { - if (!Opts.ShowCPP && !Opts.ShowMacros) - llvm::report_fatal_error("Invalid option combination!"); - - if (Opts.ShowCPP && Opts.ShowMacros) - Res.push_back("-dD"); - else if (!Opts.ShowCPP && Opts.ShowMacros) - Res.push_back("-dM"); - - if (!Opts.ShowLineMarkers) - Res.push_back("-P"); - if (Opts.ShowComments) - Res.push_back("-C"); - if (Opts.ShowMacroComments) - Res.push_back("-CC"); -} - -static void TargetOptsToArgs(const TargetOptions &Opts, - ToArgsList &Res) { - Res.push_back("-triple"); - Res.push_back(Opts.Triple); - if (!Opts.CPU.empty()) - Res.push_back("-target-cpu", Opts.CPU); - if (!Opts.ABI.empty()) - Res.push_back("-target-abi", Opts.ABI); - if (!Opts.LinkerVersion.empty()) - Res.push_back("-target-linker-version", Opts.LinkerVersion); - if (!Opts.CXXABI.empty()) - Res.push_back("-cxx-abi", Opts.CXXABI); - for (unsigned i = 0, e = Opts.Features.size(); i != e; ++i) - Res.push_back("-target-feature", Opts.Features[i]); -} - -void CompilerInvocation::toArgs(std::vector<std::string> &Res) const { - ToArgsList List(Res); - AnalyzerOptsToArgs(getAnalyzerOpts(), List); - CodeGenOptsToArgs(getCodeGenOpts(), List); - DependencyOutputOptsToArgs(getDependencyOutputOpts(), List); - DiagnosticOptsToArgs(getDiagnosticOpts(), List); - FileSystemOptsToArgs(getFileSystemOpts(), List); - FrontendOptsToArgs(getFrontendOpts(), List); - HeaderSearchOptsToArgs(getHeaderSearchOpts(), List); - LangOptsToArgs(*getLangOpts(), List); - PreprocessorOptsToArgs(getPreprocessorOpts(), List); - PreprocessorOutputOptsToArgs(getPreprocessorOutputOpts(), List); - TargetOptsToArgs(getTargetOpts(), List); -} - -//===----------------------------------------------------------------------===// -// Deserialization (to args) +// Deserialization (from args) //===----------------------------------------------------------------------===// using namespace clang::driver; @@ -965,7 +71,7 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, assert (A->getOption().matches(options::OPT_O)); - llvm::StringRef S(A->getValue(Args)); + llvm::StringRef S(A->getValue()); if (S == "s" || S == "z" || S.empty()) return 2; @@ -979,7 +85,7 @@ static unsigned getOptimizationLevelSize(ArgList &Args, InputKind IK, DiagnosticsEngine &Diags) { if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { if (A->getOption().matches(options::OPT_O)) { - switch (A->getValue(Args)[0]) { + switch (A->getValue()[0]) { default: return 0; case 's': @@ -996,14 +102,14 @@ static void addWarningArgs(ArgList &Args, std::vector<std::string> &Warnings) { for (arg_iterator I = Args.filtered_begin(OPT_W_Group), E = Args.filtered_end(); I != E; ++I) { Arg *A = *I; - // If the argument is a pure flag, add its name (minus the "-W" at the beginning) + // If the argument is a pure flag, add its name (minus the "W" at the beginning) // to the warning list. Else, add its value (for the OPT_W case). if (A->getOption().getKind() == Option::FlagClass) { - Warnings.push_back(A->getOption().getName().substr(2)); + Warnings.push_back(A->getOption().getName().substr(1)); } else { for (unsigned Idx = 0, End = A->getNumValues(); Idx < End; ++Idx) { - StringRef V = A->getValue(Args, Idx); + StringRef V = A->getValue(Idx); // "-Wl," and such are not warning options. // FIXME: Should be handled by putting these in separate flags. if (V.startswith("l,") || V.startswith("a,") || V.startswith("p,")) @@ -1020,11 +126,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, using namespace options; bool Success = true; if (Arg *A = Args.getLastArg(OPT_analyzer_store)) { - StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(); AnalysisStores Value = llvm::StringSwitch<AnalysisStores>(Name) #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \ .Case(CMDFLAG, NAME##Model) -#include "clang/Frontend/Analyses.def" +#include "clang/StaticAnalyzer/Core/Analyses.def" .Default(NumStores); if (Value == NumStores) { Diags.Report(diag::err_drv_invalid_value) @@ -1036,11 +142,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } if (Arg *A = Args.getLastArg(OPT_analyzer_constraints)) { - StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(); AnalysisConstraints Value = llvm::StringSwitch<AnalysisConstraints>(Name) #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \ .Case(CMDFLAG, NAME##Model) -#include "clang/Frontend/Analyses.def" +#include "clang/StaticAnalyzer/Core/Analyses.def" .Default(NumConstraints); if (Value == NumConstraints) { Diags.Report(diag::err_drv_invalid_value) @@ -1052,11 +158,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } if (Arg *A = Args.getLastArg(OPT_analyzer_output)) { - StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(); AnalysisDiagClients Value = llvm::StringSwitch<AnalysisDiagClients>(Name) #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) \ .Case(CMDFLAG, PD_##NAME) -#include "clang/Frontend/Analyses.def" +#include "clang/StaticAnalyzer/Core/Analyses.def" .Default(NUM_ANALYSIS_DIAG_CLIENTS); if (Value == NUM_ANALYSIS_DIAG_CLIENTS) { Diags.Report(diag::err_drv_invalid_value) @@ -1068,11 +174,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } if (Arg *A = Args.getLastArg(OPT_analyzer_purge)) { - StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(); AnalysisPurgeMode Value = llvm::StringSwitch<AnalysisPurgeMode>(Name) #define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \ .Case(CMDFLAG, NAME) -#include "clang/Frontend/Analyses.def" +#include "clang/StaticAnalyzer/Core/Analyses.def" .Default(NumPurgeModes); if (Value == NumPurgeModes) { Diags.Report(diag::err_drv_invalid_value) @@ -1084,11 +190,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } if (Arg *A = Args.getLastArg(OPT_analyzer_ipa)) { - StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(); AnalysisIPAMode Value = llvm::StringSwitch<AnalysisIPAMode>(Name) #define ANALYSIS_IPA(NAME, CMDFLAG, DESC) \ .Case(CMDFLAG, NAME) -#include "clang/Frontend/Analyses.def" +#include "clang/StaticAnalyzer/Core/Analyses.def" .Default(NumIPAModes); if (Value == NumIPAModes) { Diags.Report(diag::err_drv_invalid_value) @@ -1100,11 +206,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } if (Arg *A = Args.getLastArg(OPT_analyzer_inlining_mode)) { - StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(); AnalysisInliningMode Value = llvm::StringSwitch<AnalysisInliningMode>(Name) #define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) \ .Case(CMDFLAG, NAME) -#include "clang/Frontend/Analyses.def" +#include "clang/StaticAnalyzer/Core/Analyses.def" .Default(NumInliningModes); if (Value == NumInliningModes) { Diags.Report(diag::err_drv_invalid_value) @@ -1116,21 +222,21 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } Opts.ShowCheckerHelp = Args.hasArg(OPT_analyzer_checker_help); - Opts.VisualizeEGDot = Args.hasArg(OPT_analyzer_viz_egraph_graphviz); - Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph); + Opts.visualizeExplodedGraphWithGraphViz = + Args.hasArg(OPT_analyzer_viz_egraph_graphviz); + Opts.visualizeExplodedGraphWithUbiGraph = + Args.hasArg(OPT_analyzer_viz_egraph_ubigraph); Opts.NoRetryExhausted = Args.hasArg(OPT_analyzer_disable_retry_exhausted); Opts.AnalyzeAll = Args.hasArg(OPT_analyzer_opt_analyze_headers); Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress); Opts.AnalyzeNestedBlocks = Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks); - Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume); + Opts.eagerlyAssumeBinOpBifurcation = Args.hasArg(OPT_analyzer_eagerly_assume); Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function); Opts.UnoptimizedCFG = Args.hasArg(OPT_analysis_UnoptimizedCFG); - Opts.CFGAddImplicitDtors = Args.hasArg(OPT_analysis_CFGAddImplicitDtors); Opts.TrimGraph = Args.hasArg(OPT_trim_egraph); Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags); - Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags); - Opts.EagerlyTrimEGraph = !Args.hasArg(OPT_analyzer_no_eagerly_trim_egraph); + Opts.maxBlockVisitOnPath = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags); Opts.PrintStats = Args.hasArg(OPT_analyzer_stats); Opts.InlineMaxStackDepth = Args.getLastArgIntValue(OPT_analyzer_inline_max_stack_depth, @@ -1148,12 +254,42 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, bool enable = (A->getOption().getID() == OPT_analyzer_checker); // We can have a list of comma separated checker names, e.g: // '-analyzer-checker=cocoa,unix' - StringRef checkerList = A->getValue(Args); + StringRef checkerList = A->getValue(); SmallVector<StringRef, 4> checkers; checkerList.split(checkers, ","); for (unsigned i = 0, e = checkers.size(); i != e; ++i) Opts.CheckersControlList.push_back(std::make_pair(checkers[i], enable)); } + + // Go through the analyzer configuration options. + for (arg_iterator it = Args.filtered_begin(OPT_analyzer_config), + ie = Args.filtered_end(); it != ie; ++it) { + const Arg *A = *it; + A->claim(); + // We can have a list of comma separated config names, e.g: + // '-analyzer-config key1=val1,key2=val2' + StringRef configList = A->getValue(); + SmallVector<StringRef, 4> configVals; + configList.split(configVals, ","); + for (unsigned i = 0, e = configVals.size(); i != e; ++i) { + StringRef key, val; + llvm::tie(key, val) = configVals[i].split("="); + if (val.empty()) { + Diags.Report(SourceLocation(), + diag::err_analyzer_config_no_value) << configVals[i]; + Success = false; + break; + } + if (val.find('=') != StringRef::npos) { + Diags.Report(SourceLocation(), + diag::err_analyzer_config_multiple_values) + << configVals[i]; + Success = false; + break; + } + Opts.Config[key] = val; + } + } return Success; } @@ -1179,21 +315,23 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.OptimizationLevel = OptLevel; // We must always run at least the always inlining pass. - Opts.Inlining = (Opts.OptimizationLevel > 1) ? CodeGenOptions::NormalInlining - : CodeGenOptions::OnlyAlwaysInlining; + Opts.setInlining( + (Opts.OptimizationLevel > 1) ? CodeGenOptions::NormalInlining + : CodeGenOptions::OnlyAlwaysInlining); // -fno-inline-functions overrides OptimizationLevel > 1. Opts.NoInline = Args.hasArg(OPT_fno_inline); - Opts.Inlining = Args.hasArg(OPT_fno_inline_functions) ? - CodeGenOptions::OnlyAlwaysInlining : Opts.Inlining; + Opts.setInlining(Args.hasArg(OPT_fno_inline_functions) ? + CodeGenOptions::OnlyAlwaysInlining : Opts.getInlining()); if (Args.hasArg(OPT_gline_tables_only)) { - Opts.DebugInfo = CodeGenOptions::DebugLineTablesOnly; + Opts.setDebugInfo(CodeGenOptions::DebugLineTablesOnly); } else if (Args.hasArg(OPT_g_Flag)) { if (Args.hasFlag(OPT_flimit_debug_info, OPT_fno_limit_debug_info, true)) - Opts.DebugInfo = CodeGenOptions::LimitedDebugInfo; + Opts.setDebugInfo(CodeGenOptions::LimitedDebugInfo); else - Opts.DebugInfo = CodeGenOptions::FullDebugInfo; + Opts.setDebugInfo(CodeGenOptions::FullDebugInfo); } + Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info); Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns); Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone); @@ -1263,18 +401,21 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data); Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes); Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info); - Opts.EmitMicrosoftInlineAsm = Args.hasArg(OPT_fenable_experimental_ms_inline_asm); Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file); Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir); Opts.LinkBitcodeFile = Args.getLastArgValue(OPT_mlink_bitcode_file); + Opts.SSPBufferSize = + Args.getLastArgIntValue(OPT_stack_protector_buffer_size, 8, Diags); Opts.StackRealignment = Args.hasArg(OPT_mstackrealign); if (Arg *A = Args.getLastArg(OPT_mstack_alignment)) { - StringRef Val = A->getValue(Args); - Val.getAsInteger(10, Opts.StackAlignment); + StringRef Val = A->getValue(); + unsigned StackAlignment = Opts.StackAlignment; + Val.getAsInteger(10, StackAlignment); + Opts.StackAlignment = StackAlignment; } if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) { - StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(); unsigned Method = llvm::StringSwitch<unsigned>(Name) .Case("legacy", CodeGenOptions::Legacy) .Case("non-legacy", CodeGenOptions::NonLegacy) @@ -1284,12 +425,13 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; Success = false; } else { - Opts.ObjCDispatchMethod = Method; + Opts.setObjCDispatchMethod( + static_cast<CodeGenOptions::ObjCDispatchMethodKind>(Method)); } } if (Arg *A = Args.getLastArg(OPT_ftlsmodel_EQ)) { - StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(); unsigned Model = llvm::StringSwitch<unsigned>(Name) .Case("global-dynamic", CodeGenOptions::GeneralDynamicTLSModel) .Case("local-dynamic", CodeGenOptions::LocalDynamicTLSModel) @@ -1300,7 +442,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; Success = false; } else { - Opts.DefaultTLSModel = static_cast<CodeGenOptions::TLSModel>(Model); + Opts.setDefaultTLSModel(static_cast<CodeGenOptions::TLSModel>(Model)); } } @@ -1351,9 +493,9 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, StringRef ShowOverloads = Args.getLastArgValue(OPT_fshow_overloads_EQ, "all"); if (ShowOverloads == "best") - Opts.ShowOverloads = DiagnosticsEngine::Ovl_Best; + Opts.setShowOverloads(Ovl_Best); else if (ShowOverloads == "all") - Opts.ShowOverloads = DiagnosticsEngine::Ovl_All; + Opts.setShowOverloads(Ovl_All); else { Success = false; if (Diags) @@ -1381,11 +523,11 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, StringRef Format = Args.getLastArgValue(OPT_fdiagnostics_format, "clang"); if (Format == "clang") - Opts.Format = DiagnosticOptions::Clang; + Opts.setFormat(DiagnosticOptions::Clang); else if (Format == "msvc") - Opts.Format = DiagnosticOptions::Msvc; + Opts.setFormat(DiagnosticOptions::Msvc); else if (Format == "vi") - Opts.Format = DiagnosticOptions::Vi; + Opts.setFormat(DiagnosticOptions::Vi); else { Success = false; if (Diags) @@ -1467,7 +609,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, case OPT_emit_obj: Opts.ProgramAction = frontend::EmitObj; break; case OPT_fixit_EQ: - Opts.FixItSuffix = A->getValue(Args); + Opts.FixItSuffix = A->getValue(); // fall-through! case OPT_fixit: Opts.ProgramAction = frontend::FixIt; break; @@ -1503,14 +645,14 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, } if (const Arg* A = Args.getLastArg(OPT_plugin)) { - Opts.Plugins.push_back(A->getValue(Args,0)); + Opts.Plugins.push_back(A->getValue(0)); Opts.ProgramAction = frontend::PluginAction; - Opts.ActionName = A->getValue(Args); + Opts.ActionName = A->getValue(); for (arg_iterator it = Args.filtered_begin(OPT_plugin_arg), end = Args.filtered_end(); it != end; ++it) { - if ((*it)->getValue(Args, 0) == Opts.ActionName) - Opts.PluginArgs.push_back((*it)->getValue(Args, 1)); + if ((*it)->getValue(0) == Opts.ActionName) + Opts.PluginArgs.push_back((*it)->getValue(1)); } } @@ -1519,17 +661,17 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, for (int i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) { for (arg_iterator it = Args.filtered_begin(OPT_plugin_arg), end = Args.filtered_end(); it != end; ++it) { - if ((*it)->getValue(Args, 0) == Opts.AddPluginActions[i]) - Opts.AddPluginArgs[i].push_back((*it)->getValue(Args, 1)); + if ((*it)->getValue(0) == Opts.AddPluginActions[i]) + Opts.AddPluginArgs[i].push_back((*it)->getValue(1)); } } if (const Arg *A = Args.getLastArg(OPT_code_completion_at)) { Opts.CodeCompletionAt = - ParsedSourceLocation::FromString(A->getValue(Args)); + ParsedSourceLocation::FromString(A->getValue()); if (Opts.CodeCompletionAt.FileName.empty()) Diags.Report(diag::err_drv_invalid_value) - << A->getAsString(Args) << A->getValue(Args); + << A->getAsString(Args) << A->getValue(); } Opts.DisableFree = Args.hasArg(OPT_disable_free); @@ -1595,7 +737,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, InputKind DashX = IK_None; if (const Arg *A = Args.getLastArg(OPT_x)) { - DashX = llvm::StringSwitch<InputKind>(A->getValue(Args)) + DashX = llvm::StringSwitch<InputKind>(A->getValue()) .Case("c", IK_C) .Case("cl", IK_OpenCL) .Case("cuda", IK_CUDA) @@ -1619,7 +761,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, .Default(IK_None); if (DashX == IK_None) Diags.Report(diag::err_drv_invalid_value) - << A->getAsString(Args) << A->getValue(Args); + << A->getAsString(Args) << A->getValue(); } // '-' is the default input if none is given. @@ -1667,7 +809,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { Opts.UseStandardSystemIncludes = !Args.hasArg(OPT_nostdsysteminc); Opts.UseStandardCXXIncludes = !Args.hasArg(OPT_nostdincxx); if (const Arg *A = Args.getLastArg(OPT_stdlib_EQ)) - Opts.UseLibcxx = (strcmp(A->getValue(Args), "libc++") == 0); + Opts.UseLibcxx = (strcmp(A->getValue(), "libc++") == 0); Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir); Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodule_cache_path); Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash); @@ -1686,7 +828,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { frontend::IncludeDirGroup Group = IsIndexHeaderMap? frontend::IndexHeaderMap : frontend::Angled; - Opts.AddPath((*it)->getValue(Args), Group, true, + Opts.AddPath((*it)->getValue(), Group, true, /*IsFramework=*/ (*it)->getOption().matches(OPT_F), false); IsIndexHeaderMap = false; } @@ -1698,43 +840,43 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; if (A->getOption().matches(OPT_iprefix)) - Prefix = A->getValue(Args); + Prefix = A->getValue(); else if (A->getOption().matches(OPT_iwithprefix)) - Opts.AddPath(Prefix.str() + A->getValue(Args), + Opts.AddPath(Prefix.str() + A->getValue(), frontend::System, false, false, false); else - Opts.AddPath(Prefix.str() + A->getValue(Args), + Opts.AddPath(Prefix.str() + A->getValue(), frontend::Angled, false, false, false); } for (arg_iterator it = Args.filtered_begin(OPT_idirafter), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::After, true, false, false); + Opts.AddPath((*it)->getValue(), frontend::After, true, false, false); for (arg_iterator it = Args.filtered_begin(OPT_iquote), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::Quoted, true, false, false); + Opts.AddPath((*it)->getValue(), frontend::Quoted, true, false, false); for (arg_iterator it = Args.filtered_begin(OPT_isystem, OPT_iwithsysroot), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::System, true, false, + Opts.AddPath((*it)->getValue(), frontend::System, true, false, !(*it)->getOption().matches(OPT_iwithsysroot)); for (arg_iterator it = Args.filtered_begin(OPT_iframework), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::System, true, true, + Opts.AddPath((*it)->getValue(), frontend::System, true, true, true); // Add the paths for the various language specific isystem flags. for (arg_iterator it = Args.filtered_begin(OPT_c_isystem), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::CSystem, true, false, true); + Opts.AddPath((*it)->getValue(), frontend::CSystem, true, false, true); for (arg_iterator it = Args.filtered_begin(OPT_cxx_isystem), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::CXXSystem, true, false, true); + Opts.AddPath((*it)->getValue(), frontend::CXXSystem, true, false, true); for (arg_iterator it = Args.filtered_begin(OPT_objc_isystem), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::ObjCSystem, true, false,true); + Opts.AddPath((*it)->getValue(), frontend::ObjCSystem, true, false,true); for (arg_iterator it = Args.filtered_begin(OPT_objcxx_isystem), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::ObjCXXSystem, true, false, + Opts.AddPath((*it)->getValue(), frontend::ObjCXXSystem, true, false, true); // Add the internal paths from a driver that detects standard include paths. @@ -1742,7 +884,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { OPT_internal_externc_isystem), E = Args.filtered_end(); I != E; ++I) - Opts.AddPath((*I)->getValue(Args), frontend::System, + Opts.AddPath((*I)->getValue(), frontend::System, false, false, /*IgnoreSysRoot=*/true, /*IsInternal=*/true, (*I)->getOption().matches(OPT_internal_externc_isystem)); @@ -1751,7 +893,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { OPT_ino_system_prefix), E = Args.filtered_end(); I != E; ++I) - Opts.AddSystemHeaderPrefix((*I)->getValue(Args), + Opts.AddSystemHeaderPrefix((*I)->getValue(), (*I)->getOption().matches(OPT_isystem_prefix)); } @@ -1799,11 +941,12 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, } const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); - Opts.BCPLComment = Std.hasBCPLComments(); + Opts.LineComment = Std.hasLineComments(); Opts.C99 = Std.isC99(); Opts.C11 = Std.isC11(); Opts.CPlusPlus = Std.isCPlusPlus(); Opts.CPlusPlus0x = Std.isCPlusPlus0x(); + Opts.CPlusPlus1y = Std.isCPlusPlus1y(); Opts.Digraphs = Std.hasDigraphs(); Opts.GNUMode = Std.isGNUMode(); Opts.GNUInline = !Std.isC99(); @@ -1838,6 +981,9 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, // OpenCL and C++ both have bool, true, false keywords. Opts.Bool = Opts.OpenCL || Opts.CPlusPlus; + // C++ has wchar_t keyword. + Opts.WChar = Opts.CPlusPlus; + Opts.GNUKeywords = Opts.GNUMode; Opts.CXXOperatorNames = Opts.CPlusPlus; @@ -1853,14 +999,14 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // FIXME: Cleanup per-file based stuff. LangStandard::Kind LangStd = LangStandard::lang_unspecified; if (const Arg *A = Args.getLastArg(OPT_std_EQ)) { - LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue(Args)) + LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue()) #define LANGSTANDARD(id, name, desc, features) \ .Case(name, LangStandard::lang_##id) #include "clang/Frontend/LangStandards.def" .Default(LangStandard::lang_unspecified); if (LangStd == LangStandard::lang_unspecified) Diags.Report(diag::err_drv_invalid_value) - << A->getAsString(Args) << A->getValue(Args); + << A->getAsString(Args) << A->getValue(); else { // Valid standard, check to make sure language and standard are compatable. const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); @@ -1901,7 +1047,7 @@ 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(Args)) + = llvm::StringSwitch<LangStandard::Kind>(A->getValue()) .Case("CL", LangStandard::lang_opencl) .Case("CL1.1", LangStandard::lang_opencl11) .Case("CL1.2", LangStandard::lang_opencl12) @@ -1909,7 +1055,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (OpenCLLangStd == LangStandard::lang_unspecified) { Diags.Report(diag::err_drv_invalid_value) - << A->getAsString(Args) << A->getValue(Args); + << A->getAsString(Args) << A->getValue(); } else LangStd = OpenCLLangStd; @@ -1930,7 +1076,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Opts.ObjC1) { if (Arg *arg = Args.getLastArg(OPT_fobjc_runtime_EQ)) { - StringRef value = arg->getValue(Args); + StringRef value = arg->getValue(); if (Opts.ObjCRuntime.tryParse(value)) Diags.Report(diag::err_drv_unknown_objc_runtime) << value; } @@ -1941,14 +1087,16 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.setGC(LangOptions::HybridGC); else if (Args.hasArg(OPT_fobjc_arc)) { Opts.ObjCAutoRefCount = 1; - if (!Opts.ObjCRuntime.isNonFragile()) - Diags.Report(diag::err_arc_nonfragile_abi); + if (!Opts.ObjCRuntime.allowsARC()) + Diags.Report(diag::err_arc_unsupported_on_runtime); + + // Only set ObjCARCWeak if ARC is enabled. + if (Args.hasArg(OPT_fobjc_runtime_has_weak)) + Opts.ObjCARCWeak = 1; + else + Opts.ObjCARCWeak = Opts.ObjCRuntime.allowsWeak(); } - Opts.ObjCRuntimeHasWeak = Opts.ObjCRuntime.hasWeak(); - if (Args.hasArg(OPT_fobjc_runtime_has_weak)) - Opts.ObjCRuntimeHasWeak = 1; - if (Args.hasArg(OPT_fno_objc_infer_related_result_type)) Opts.ObjCInferRelatedResultType = 0; } @@ -1990,7 +1138,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, << Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis; if (Arg *A = Args.getLastArg(OPT_ffp_contract)) { - StringRef Val = A->getValue(Args); + StringRef Val = A->getValue(); if (Val == "fast") Opts.setFPContractMode(LangOptions::FPC_Fast); else if (Val == "on") @@ -2043,6 +1191,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional); Opts.Modules = Args.hasArg(OPT_fmodules); Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char); + Opts.WChar = Opts.CPlusPlus && !Args.hasArg(OPT_fno_wchar); Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar); Opts.ShortEnums = Args.hasArg(OPT_fshort_enums); Opts.Freestanding = Args.hasArg(OPT_ffreestanding); @@ -2064,7 +1213,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Args.getLastArgValue(OPT_fconstant_string_class); Opts.ObjCDefaultSynthProperties = Args.hasArg(OPT_fobjc_default_synthesize_properties); - Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior); + Opts.EncodeExtendedBlockSig = + Args.hasArg(OPT_fencode_extended_block_signature); Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls); Opts.PackStruct = Args.getLastArgIntValue(OPT_fpack_struct_EQ, 0, Diags); Opts.PICLevel = Args.getLastArgIntValue(OPT_pic_level, 0, Diags); @@ -2085,8 +1235,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.DebuggerSupport = Args.hasArg(OPT_fdebugger_support); Opts.DebuggerCastResultToId = Args.hasArg(OPT_fdebugger_cast_result_to_id); Opts.DebuggerObjCLiteral = Args.hasArg(OPT_fdebugger_objc_literal); - Opts.AddressSanitizer = Args.hasArg(OPT_faddress_sanitizer); - Opts.ThreadSanitizer = Args.hasArg(OPT_fthread_sanitizer); Opts.ApplePragmaPack = Args.hasArg(OPT_fapple_pragma_pack); Opts.CurrentModule = Args.getLastArgValue(OPT_fmodule_name); @@ -2109,6 +1257,11 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.FastMath = Args.hasArg(OPT_ffast_math); Opts.FiniteMathOnly = Args.hasArg(OPT_ffinite_math_only); + Opts.EmitMicrosoftInlineAsm = Args.hasArg(OPT_fenable_experimental_ms_inline_asm); + + Opts.RetainCommentsFromSystemHeaders = + Args.hasArg(OPT_fretain_comments_from_system_headers); + unsigned SSP = Args.getLastArgIntValue(OPT_stack_protector, 0, Diags); switch (SSP) { default: @@ -2119,6 +1272,37 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, case 1: Opts.setStackProtector(LangOptions::SSPOn); break; case 2: Opts.setStackProtector(LangOptions::SSPReq); break; } + + // Parse -fsanitize= arguments. + std::vector<std::string> Sanitizers = Args.getAllArgValues(OPT_fsanitize_EQ); + for (unsigned I = 0, N = Sanitizers.size(); I != N; ++I) { + // Since the Opts.Sanitize* values are bitfields, it's a little tricky to + // efficiently map string values to them. Perform the mapping indirectly: + // convert strings to enumerated values, then switch over the enum to set + // the right bitfield value. + enum Sanitizer { +#define SANITIZER(NAME, ID) \ + ID, +#include "clang/Basic/Sanitizers.def" + Unknown + }; + switch (llvm::StringSwitch<unsigned>(Sanitizers[I]) +#define SANITIZER(NAME, ID) \ + .Case(NAME, ID) +#include "clang/Basic/Sanitizers.def" + .Default(Unknown)) { +#define SANITIZER(NAME, ID) \ + case ID: \ + Opts.Sanitize##ID = true; \ + break; +#include "clang/Basic/Sanitizers.def" + + case Unknown: + Diags.Report(diag::err_drv_invalid_value) + << "-fsanitize=" << Sanitizers[I]; + break; + } + } } static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, @@ -2128,7 +1312,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch); Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth); if (const Arg *A = Args.getLastArg(OPT_token_cache)) - Opts.TokenCache = A->getValue(Args); + Opts.TokenCache = A->getValue(); else Opts.TokenCache = Opts.ImplicitPTHInclude; Opts.UsePredefines = !Args.hasArg(OPT_undef); @@ -2139,11 +1323,11 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, for (arg_iterator it = Args.filtered_begin(OPT_error_on_deserialized_pch_decl), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; - Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue(Args)); + Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue()); } if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) { - StringRef Value(A->getValue(Args)); + StringRef Value(A->getValue()); size_t Comma = Value.find(','); unsigned Bytes = 0; unsigned EndOfLine = 0; @@ -2162,9 +1346,9 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, for (arg_iterator it = Args.filtered_begin(OPT_D, OPT_U), ie = Args.filtered_end(); it != ie; ++it) { if ((*it)->getOption().matches(OPT_D)) - Opts.addMacroDef((*it)->getValue(Args)); + Opts.addMacroDef((*it)->getValue()); else - Opts.addMacroUndef((*it)->getValue(Args)); + Opts.addMacroUndef((*it)->getValue()); } Opts.MacroIncludes = Args.getAllArgValues(OPT_imacros); @@ -2174,22 +1358,13 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, OPT_include_pth), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; - // PCH is handled specially, we need to extra the original include path. - if (A->getOption().matches(OPT_include_pch)) { - std::string OriginalFile = - ASTReader::getOriginalSourceFile(A->getValue(Args), FileMgr, Diags); - if (OriginalFile.empty()) - continue; - - Opts.Includes.push_back(OriginalFile); - } else - Opts.Includes.push_back(A->getValue(Args)); + Opts.Includes.push_back(A->getValue()); } for (arg_iterator it = Args.filtered_begin(OPT_chain_include), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; - Opts.ChainedIncludes.push_back(A->getValue(Args)); + Opts.ChainedIncludes.push_back(A->getValue()); } // Include 'altivec.h' if -faltivec option present @@ -2200,7 +1375,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; std::pair<StringRef,StringRef> Split = - StringRef(A->getValue(Args)).split(';'); + StringRef(A->getValue()).split(';'); if (Split.second.empty()) { Diags.Report(diag::err_drv_invalid_remap_file) << A->getAsString(Args); @@ -2211,7 +1386,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, } if (Arg *A = Args.getLastArg(OPT_fobjc_arc_cxxlib_EQ)) { - StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(); unsigned Library = llvm::StringSwitch<unsigned>(Name) .Case("libc++", ARCXX_libcxx) .Case("libstdc++", ARCXX_libstdcxx) @@ -2240,7 +1415,7 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { Opts.ABI = Args.getLastArgValue(OPT_target_abi); Opts.CXXABI = Args.getLastArgValue(OPT_cxx_abi); Opts.CPU = Args.getLastArgValue(OPT_target_cpu); - Opts.Features = Args.getAllArgValues(OPT_target_feature); + Opts.FeaturesAsWritten = Args.getAllArgValues(OPT_target_feature); Opts.LinkerVersion = Args.getLastArgValue(OPT_target_linker_version); Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple)); @@ -2280,13 +1455,13 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, // Issue errors on arguments that are not valid for CC1. for (ArgList::iterator I = Args->begin(), E = Args->end(); I != E; ++I) { - if (!(*I)->getOption().isCC1Option()) { + if (!(*I)->getOption().hasFlag(options::CC1Option)) { Diags.Report(diag::err_drv_unknown_argument) << (*I)->getAsString(*Args); Success = false; } } - Success = ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags) && Success; + Success = ParseAnalyzerArgs(*Res.getAnalyzerOpts(), *Args, Diags) && Success; Success = ParseMigratorArgs(Res.getMigratorOpts(), *Args) && Success; ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args); Success = ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, &Diags) @@ -2368,53 +1543,49 @@ llvm::APInt ModuleSignature::getAsInteger() const { } std::string CompilerInvocation::getModuleHash() const { - ModuleSignature Signature; - + using llvm::hash_code; + using llvm::hash_value; + using llvm::hash_combine; + // Start the signature with the compiler version. - // FIXME: The full version string can be quite long. Omit it from the - // module hash for now to avoid failures where the path name becomes too - // long. An MD5 or similar checksum would work well here. - // Signature.add(getClangFullRepositoryVersion()); - + // FIXME: We'd rather use something more cryptographically sound than + // CityHash, but this will do for now. + hash_code code = hash_value(getClangFullRepositoryVersion()); + // Extend the signature with the language options #define LANGOPT(Name, Bits, Default, Description) \ - Signature.add(LangOpts->Name, Bits); + code = hash_combine(code, LangOpts->Name); #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ - Signature.add(static_cast<unsigned>(LangOpts->get##Name()), Bits); + code = hash_combine(code, static_cast<unsigned>(LangOpts->get##Name())); #define BENIGN_LANGOPT(Name, Bits, Default, Description) #define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) #include "clang/Basic/LangOptions.def" - // Extend the signature with the target triple - llvm::Triple T(TargetOpts.Triple); - Signature.add((unsigned)T.getArch(), 5); - Signature.add((unsigned)T.getVendor(), 4); - Signature.add((unsigned)T.getOS(), 5); - Signature.add((unsigned)T.getEnvironment(), 4); + // Extend the signature with the target options. + code = hash_combine(code, TargetOpts->Triple, TargetOpts->CPU, + TargetOpts->ABI, TargetOpts->CXXABI, + TargetOpts->LinkerVersion); + for (unsigned i = 0, n = TargetOpts->FeaturesAsWritten.size(); i != n; ++i) + code = hash_combine(code, TargetOpts->FeaturesAsWritten[i]); // Extend the signature with preprocessor options. - Signature.add(getPreprocessorOpts().UsePredefines, 1); - Signature.add(getPreprocessorOpts().DetailedRecord, 1); - - // Hash the preprocessor defines. - // FIXME: This is terrible. Use an MD5 sum of the preprocessor defines. + const PreprocessorOptions &ppOpts = getPreprocessorOpts(); + code = hash_combine(code, ppOpts.UsePredefines, ppOpts.DetailedRecord); + std::vector<StringRef> MacroDefs; for (std::vector<std::pair<std::string, bool/*isUndef*/> >::const_iterator I = getPreprocessorOpts().Macros.begin(), IEnd = getPreprocessorOpts().Macros.end(); I != IEnd; ++I) { - if (!I->second) - MacroDefs.push_back(I->first); + code = hash_combine(code, I->first, I->second); } - llvm::array_pod_sort(MacroDefs.begin(), MacroDefs.end()); - - unsigned PPHashResult = 0; - for (unsigned I = 0, N = MacroDefs.size(); I != N; ++I) - PPHashResult = llvm::HashString(MacroDefs[I], PPHashResult); - Signature.add(PPHashResult, 32); - - // We've generated the signature. Treat it as one large APInt that we'll - // encode in base-36 and return. - Signature.flush(); - return Signature.getAsInteger().toString(36, /*Signed=*/false); + + // Extend the signature with the sysroot. + const HeaderSearchOptions &hsOpts = getHeaderSearchOpts(); + code = hash_combine(code, hsOpts.Sysroot, hsOpts.UseBuiltinIncludes, + hsOpts.UseStandardSystemIncludes, + hsOpts.UseStandardCXXIncludes, + hsOpts.UseLibcxx); + + return llvm::APInt(64, code).toString(36, /*Signed=*/false); } diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp index 0aca86e..d82cb6d 100644 --- a/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -11,9 +11,9 @@ // //===----------------------------------------------------------------------===// +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Frontend/Utils.h" #include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/DiagnosticOptions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" @@ -34,8 +34,8 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList, if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. - DiagnosticOptions DiagOpts; - Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgList.size(), + Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions, + ArgList.size(), ArgList.begin()); } @@ -49,11 +49,6 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList, // FIXME: We shouldn't have to pass in the path info. driver::Driver TheDriver("clang", llvm::sys::getDefaultTargetTriple(), "a.out", false, *Diags); - // Force driver to use clang. - // FIXME: This seems like a hack. Maybe the "Clang" tool subclass should be - // available for using it to get the arguments, thus avoiding the overkill - // of using the driver. - TheDriver.setForcedClangUse(); // Don't check that inputs exist, they may have been remapped. TheDriver.setCheckInputsExist(false); diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp index 21f5daa..53ea8be 100644 --- a/lib/Frontend/DependencyFile.cpp +++ b/lib/Frontend/DependencyFile.cpp @@ -59,10 +59,11 @@ public: const Token &IncludeTok, StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, const FileEntry *File, - SourceLocation EndLoc, StringRef SearchPath, - StringRef RelativePath); + StringRef RelativePath, + const Module *Imported); virtual void EndOfMainFile() { OutputDependencyFile(); @@ -132,10 +133,11 @@ void DependencyFileCallback::InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, const FileEntry *File, - SourceLocation EndLoc, StringRef SearchPath, - StringRef RelativePath) { + StringRef RelativePath, + const Module *Imported) { if (!File) { if (AddMissingHeaderDeps) AddFilename(FileName); diff --git a/lib/Frontend/DependencyGraph.cpp b/lib/Frontend/DependencyGraph.cpp index eebaf0c..28d9c5d 100644 --- a/lib/Frontend/DependencyGraph.cpp +++ b/lib/Frontend/DependencyGraph.cpp @@ -51,10 +51,11 @@ public: const Token &IncludeTok, StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, const FileEntry *File, - SourceLocation EndLoc, StringRef SearchPath, - StringRef RelativePath); + StringRef RelativePath, + const Module *Imported); virtual void EndOfMainFile() { OutputGraphFile(); @@ -72,10 +73,11 @@ void DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, const FileEntry *File, - SourceLocation EndLoc, StringRef SearchPath, - StringRef RelativePath) { + StringRef RelativePath, + const Module *Imported) { if (!File) return; diff --git a/lib/Frontend/DiagnosticRenderer.cpp b/lib/Frontend/DiagnosticRenderer.cpp index f052f90..359b82b 100644 --- a/lib/Frontend/DiagnosticRenderer.cpp +++ b/lib/Frontend/DiagnosticRenderer.cpp @@ -8,9 +8,9 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/DiagnosticRenderer.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" -#include "clang/Frontend/DiagnosticOptions.h" #include "clang/Lex/Lexer.h" #include "clang/Edit/EditedSource.h" #include "clang/Edit/Commit.h" @@ -18,6 +18,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include <algorithm> using namespace clang; @@ -60,8 +61,8 @@ static StringRef getImmediateMacroName(SourceLocation Loc, } DiagnosticRenderer::DiagnosticRenderer(const LangOptions &LangOpts, - const DiagnosticOptions &DiagOpts) -: LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {} + DiagnosticOptions *DiagOpts) + : LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {} DiagnosticRenderer::~DiagnosticRenderer() {} @@ -194,7 +195,7 @@ void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc, return; LastIncludeLoc = Loc; - if (!DiagOpts.ShowNoteIncludeStack && Level == DiagnosticsEngine::Note) + if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note) return; emitIncludeStackRecursively(Loc, SM); @@ -218,6 +219,53 @@ void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc, emitIncludeLocation(Loc, PLoc, SM); } +// Helper function to fix up source ranges. It takes in an array of ranges, +// and outputs an array of ranges where we want to draw the range highlighting +// around the location specified by CaretLoc. +// +// To find locations which correspond to the caret, we crawl the macro caller +// chain for the beginning and end of each range. If the caret location +// is in a macro expansion, we search each chain for a location +// 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, + const SmallVectorImpl<CharSourceRange>& Ranges, + SmallVectorImpl<CharSourceRange>& SpellingRanges, + const SourceManager *SM) { + FileID CaretLocFileID = SM->getFileID(CaretLoc); + + for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(), + E = Ranges.end(); + I != E; ++I) { + SourceLocation Begin = I->getBegin(), End = I->getEnd(); + bool IsTokenRange = I->isTokenRange(); + + // Search the macro caller chain for the beginning of the range. + while (Begin.isMacroID() && SM->getFileID(Begin) != CaretLocFileID) + Begin = SM->getImmediateMacroCallerLoc(Begin); + + // Search the macro caller chain for the beginning of the range. + while (End.isMacroID() && SM->getFileID(End) != CaretLocFileID) { + // The computation of the next End is an inlined version of + // getImmediateMacroCallerLoc, except it chooses the end of an + // expansion range. + if (SM->isMacroArgExpansion(End)) { + End = SM->getImmediateSpellingLoc(End); + } else { + End = SM->getImmediateExpansionRange(End).second; + } + } + + // Return the spelling location of the beginning and end of the range. + Begin = SM->getSpellingLoc(Begin); + End = SM->getSpellingLoc(End); + SpellingRanges.push_back(CharSourceRange(SourceRange(Begin, End), + IsTokenRange)); + } +} + /// \brief Recursively emit notes for each macro expansion and caret /// diagnostics where appropriate. /// @@ -245,9 +293,13 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets( // If this is a file source location, directly emit the source snippet and // caret line. Also record the macro depth reached. if (Loc.isFileID()) { + // Map the ranges. + SmallVector<CharSourceRange, 4> SpellingRanges; + mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM); + assert(MacroDepth == 0 && "We shouldn't hit a leaf node twice!"); MacroDepth = OnMacroInst; - emitCodeContext(Loc, Level, Ranges, Hints, SM); + emitCodeContext(Loc, Level, SpellingRanges, Hints, SM); return; } // Otherwise recurse through each macro expansion layer. @@ -257,8 +309,7 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets( Loc = SM.skipToMacroArgExpansion(Loc); SourceLocation OneLevelUp = SM.getImmediateMacroCallerLoc(Loc); - - // FIXME: Map ranges? + emitMacroExpansionsAndCarets(OneLevelUp, Level, Ranges, Hints, SM, MacroDepth, OnMacroInst + 1); @@ -269,28 +320,17 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets( Loc = SM.getImmediateMacroCalleeLoc(Loc); unsigned MacroSkipStart = 0, MacroSkipEnd = 0; - if (MacroDepth > DiagOpts.MacroBacktraceLimit && - DiagOpts.MacroBacktraceLimit != 0) { - MacroSkipStart = DiagOpts.MacroBacktraceLimit / 2 + - DiagOpts.MacroBacktraceLimit % 2; - MacroSkipEnd = MacroDepth - DiagOpts.MacroBacktraceLimit / 2; + if (MacroDepth > DiagOpts->MacroBacktraceLimit && + DiagOpts->MacroBacktraceLimit != 0) { + MacroSkipStart = DiagOpts->MacroBacktraceLimit / 2 + + DiagOpts->MacroBacktraceLimit % 2; + MacroSkipEnd = MacroDepth - DiagOpts->MacroBacktraceLimit / 2; } // Whether to suppress printing this macro expansion. bool Suppressed = (OnMacroInst >= MacroSkipStart && OnMacroInst < MacroSkipEnd); - // Map the ranges. - for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), - E = Ranges.end(); - I != E; ++I) { - SourceLocation Start = I->getBegin(), End = I->getEnd(); - if (Start.isMacroID()) - I->setBegin(SM.getImmediateMacroCalleeLoc(Start)); - if (End.isMacroID()) - I->setEnd(SM.getImmediateMacroCalleeLoc(End)); - } - if (Suppressed) { // Tell the user that we've skipped contexts. if (OnMacroInst == MacroSkipStart) { @@ -303,14 +343,18 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets( } return; } - + + // Map the ranges. + SmallVector<CharSourceRange, 4> SpellingRanges; + mapDiagnosticRanges(MacroLoc, Ranges, SpellingRanges, &SM); + SmallString<100> MessageStorage; llvm::raw_svector_ostream Message(MessageStorage); Message << "expanded from macro '" << getImmediateMacroName(MacroLoc, SM, LangOpts) << "'"; emitDiagnostic(SM.getSpellingLoc(Loc), DiagnosticsEngine::Note, Message.str(), - Ranges, ArrayRef<FixItHint>(), &SM); + SpellingRanges, ArrayRef<FixItHint>(), &SM); } DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {} diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index a4321e7..2e9a791 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -23,10 +23,12 @@ #include "clang/Parse/ParseAST.h" #include "clang/Serialization/ASTDeserializationListener.h" #include "clang/Serialization/ASTReader.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Timer.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" +#include "llvm/Support/Timer.h" using namespace clang; namespace { @@ -155,20 +157,22 @@ ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI, return new MultiplexConsumer(Consumers); } + bool FrontendAction::BeginSourceFile(CompilerInstance &CI, const FrontendInputFile &Input) { assert(!Instance && "Already processing a source file!"); - assert(!Input.File.empty() && "Unexpected empty filename!"); + assert(!Input.isEmpty() && "Unexpected empty filename!"); setCurrentInput(Input); setCompilerInstance(&CI); + StringRef InputFile = Input.getFile(); bool HasBegunSourceFile = false; if (!BeginInvocation(CI)) goto failure; // AST files follow a very different path, since they share objects via the // AST unit. - if (Input.Kind == IK_AST) { + if (Input.getKind() == IK_AST) { assert(!usesPreprocessorOnly() && "Attempt to pass AST file to preprocessor only action!"); assert(hasASTFileSupport() && @@ -176,7 +180,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics()); std::string Error; - ASTUnit *AST = ASTUnit::LoadFromASTFile(Input.File, Diags, + ASTUnit *AST = ASTUnit::LoadFromASTFile(InputFile, Diags, CI.getFileSystemOpts()); if (!AST) goto failure; @@ -191,11 +195,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, CI.setASTContext(&AST->getASTContext()); // Initialize the action. - if (!BeginSourceFileAction(CI, Input.File)) + if (!BeginSourceFileAction(CI, InputFile)) goto failure; /// Create the AST consumer. - CI.setASTConsumer(CreateWrappedASTConsumer(CI, Input.File)); + CI.setASTConsumer(CreateWrappedASTConsumer(CI, InputFile)); if (!CI.hasASTConsumer()) goto failure; @@ -209,7 +213,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, CI.createSourceManager(CI.getFileManager()); // IR files bypass the rest of initialization. - if (Input.Kind == IK_LLVM_IR) { + if (Input.getKind() == IK_LLVM_IR) { assert(hasIRSupport() && "This action does not have IR file support!"); @@ -218,12 +222,51 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, HasBegunSourceFile = true; // Initialize the action. - if (!BeginSourceFileAction(CI, Input.File)) + if (!BeginSourceFileAction(CI, InputFile)) goto failure; return true; } + // If the implicit PCH include is actually a directory, rather than + // a single file, search for a suitable PCH file in that directory. + if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { + FileManager &FileMgr = CI.getFileManager(); + PreprocessorOptions &PPOpts = CI.getPreprocessorOpts(); + StringRef PCHInclude = PPOpts.ImplicitPCHInclude; + if (const DirectoryEntry *PCHDir = FileMgr.getDirectory(PCHInclude)) { + llvm::error_code EC; + SmallString<128> DirNative; + llvm::sys::path::native(PCHDir->getName(), DirNative); + bool Found = false; + for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd; + Dir != DirEnd && !EC; Dir.increment(EC)) { + // Check whether this is an acceptable AST file. + if (ASTReader::isAcceptableASTFile(Dir->path(), FileMgr, + CI.getLangOpts(), + CI.getTargetOpts(), + CI.getPreprocessorOpts())) { + for (unsigned I = 0, N = PPOpts.Includes.size(); I != N; ++I) { + if (PPOpts.Includes[I] == PPOpts.ImplicitPCHInclude) { + PPOpts.Includes[I] = Dir->path(); + PPOpts.ImplicitPCHInclude = Dir->path(); + Found = true; + break; + } + } + + assert(Found && "Implicit PCH include not in includes list?"); + break; + } + } + + if (!Found) { + CI.getDiagnostics().Report(diag::err_fe_no_pch_in_dir) << PCHInclude; + return true; + } + } + } + // Set up the preprocessor. CI.createPreprocessor(); @@ -233,7 +276,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, HasBegunSourceFile = true; // Initialize the action. - if (!BeginSourceFileAction(CI, Input.File)) + if (!BeginSourceFileAction(CI, InputFile)) goto failure; /// Create the AST context and consumer unless this is a preprocessor only @@ -242,12 +285,14 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, CI.createASTContext(); OwningPtr<ASTConsumer> Consumer( - CreateWrappedASTConsumer(CI, Input.File)); + CreateWrappedASTConsumer(CI, InputFile)); if (!Consumer) goto failure; CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener()); - + CI.getPreprocessor().setPPMutationListener( + Consumer->GetPPMutationListener()); + if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) { // Convert headers to PCH and chain them. OwningPtr<ExternalASTSource> source; @@ -270,7 +315,6 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, CI.createPCHExternalASTSource( CI.getPreprocessorOpts().ImplicitPCHInclude, CI.getPreprocessorOpts().DisablePCHValidation, - CI.getPreprocessorOpts().DisableStatCache, CI.getPreprocessorOpts().AllowPCHWithCompilerErrors, DeserialListener); if (!CI.getASTContext().getExternalSource()) @@ -314,6 +358,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (HasBegunSourceFile) CI.getDiagnosticClient().EndSourceFile(); + CI.clearOutputFiles(/*EraseFiles=*/true); setCurrentInput(FrontendInputFile()); setCompilerInstance(0); return false; @@ -325,10 +370,7 @@ bool FrontendAction::Execute() { // Initialize the main file entry. This needs to be delayed until after PCH // has loaded. if (!isCurrentFileAST()) { - if (!CI.InitializeSourceManager(getCurrentFile(), - getCurrentInput().IsSystem - ? SrcMgr::C_System - : SrcMgr::C_User)) + if (!CI.InitializeSourceManager(getCurrentInput())) return false; } diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 24960cf..47063f7 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -131,8 +131,31 @@ ASTConsumer *GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI, Sysroot, OS); } +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) { + if (LangOpts.ObjC1) + Includes += "#import \""; + else + Includes += "#include \""; + Includes += HeaderName; + Includes += "\"\n"; +} + +static void addHeaderInclude(const FileEntry *Header, + SmallVectorImpl<char> &Includes, + const LangOptions &LangOpts) { + addHeaderInclude(Header->getName(), Includes, LangOpts); +} + /// \brief Collect the set of header includes needed to construct the given -/// module. +/// module and update the TopHeaders file set of the module. /// /// \param Module The module we're collecting includes from. /// @@ -142,30 +165,23 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr, ModuleMap &ModMap, clang::Module *Module, - SmallString<256> &Includes) { + SmallVectorImpl<char> &Includes) { // Don't collect any headers for unavailable modules. if (!Module->isAvailable()) return; // Add includes for each of these headers. for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) { - if (LangOpts.ObjC1) - Includes += "#import \""; - else - Includes += "#include \""; - Includes += Module->Headers[I]->getName(); - Includes += "\"\n"; + const FileEntry *Header = Module->Headers[I]; + Module->TopHeaders.insert(Header); + addHeaderInclude(Header, Includes, LangOpts); } if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) { + Module->TopHeaders.insert(UmbrellaHeader); if (Module->Parent) { // Include the umbrella header for submodules. - if (LangOpts.ObjC1) - Includes += "#import \""; - else - Includes += "#include \""; - Includes += UmbrellaHeader->getName(); - Includes += "\"\n"; + addHeaderInclude(UmbrellaHeader, Includes, LangOpts); } } else if (const DirectoryEntry *UmbrellaDir = Module->getUmbrellaDir()) { // Add all of the headers we find in this subdirectory. @@ -184,17 +200,14 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts, // If this header is marked 'unavailable' in this module, don't include // it. - if (const FileEntry *Header = FileMgr.getFile(Dir->path())) + if (const FileEntry *Header = FileMgr.getFile(Dir->path())) { if (ModMap.isHeaderInUnavailableModule(Header)) continue; + Module->TopHeaders.insert(Header); + } // Include this header umbrella header for submodules. - if (LangOpts.ObjC1) - Includes += "#import \""; - else - Includes += "#include \""; - Includes += Dir->path(); - Includes += "\"\n"; + addHeaderInclude(Dir->path(), Includes, LangOpts); } } @@ -250,77 +263,29 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI, return false; } - // Do we have an umbrella header for this module? - const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader(); - + FileManager &FileMgr = CI.getFileManager(); + // Collect the set of #includes we need to build the module. SmallString<256> HeaderContents; - collectModuleHeaderIncludes(CI.getLangOpts(), CI.getFileManager(), + if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) + addHeaderInclude(UmbrellaHeader, HeaderContents, CI.getLangOpts()); + collectModuleHeaderIncludes(CI.getLangOpts(), FileMgr, CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), Module, HeaderContents); - if (UmbrellaHeader && HeaderContents.empty()) { - // Simple case: we have an umbrella header and there are no additional - // includes, we can just parse the umbrella header directly. - setCurrentInput(FrontendInputFile(UmbrellaHeader->getName(), - getCurrentFileKind(), - Module->IsSystem)); - return true; - } - - FileManager &FileMgr = CI.getFileManager(); - SmallString<128> HeaderName; - time_t ModTime; - if (UmbrellaHeader) { - // Read in the umbrella header. - // FIXME: Go through the source manager; the umbrella header may have - // been overridden. - std::string ErrorStr; - llvm::MemoryBuffer *UmbrellaContents - = FileMgr.getBufferForFile(UmbrellaHeader, &ErrorStr); - if (!UmbrellaContents) { - CI.getDiagnostics().Report(diag::err_missing_umbrella_header) - << UmbrellaHeader->getName() << ErrorStr; - return false; - } - - // Combine the contents of the umbrella header with the automatically- - // generated includes. - SmallString<256> OldContents = HeaderContents; - HeaderContents = UmbrellaContents->getBuffer(); - HeaderContents += "\n\n"; - HeaderContents += "/* Module includes */\n"; - HeaderContents += OldContents; - - // Pretend that we're parsing the umbrella header. - HeaderName = UmbrellaHeader->getName(); - ModTime = UmbrellaHeader->getModificationTime(); - - delete UmbrellaContents; - } else { - // Pick an innocuous-sounding name for the umbrella header. - HeaderName = Module->Name + ".h"; - if (FileMgr.getFile(HeaderName, /*OpenFile=*/false, - /*CacheFailure=*/false)) { - // Try again! - HeaderName = Module->Name + "-module.h"; - if (FileMgr.getFile(HeaderName, /*OpenFile=*/false, - /*CacheFailure=*/false)) { - // Pick something ridiculous and go with it. - HeaderName = Module->Name + "-module.hmod"; - } - } - ModTime = time(0); - } - - // Remap the contents of the header name we're using to our synthesized - // buffer. - const FileEntry *HeaderFile = FileMgr.getVirtualFile(HeaderName, + + StringRef InputName = Module::getModuleInputBufferName(); + + // We consistently construct a buffer as input to build the module. + // This means the main file for modules will always be a virtual one. + // FIXME: Maybe allow using a memory buffer as input directly instead of + // messing with virtual files. + const FileEntry *HeaderFile = FileMgr.getVirtualFile(InputName, HeaderContents.size(), - ModTime); + time(0)); llvm::MemoryBuffer *HeaderContentsBuf = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents); CI.getSourceManager().overrideFileContents(HeaderFile, HeaderContentsBuf); - setCurrentInput(FrontendInputFile(HeaderName, getCurrentFileKind(), + setCurrentInput(FrontendInputFile(InputName, getCurrentFileKind(), Module->IsSystem)); return true; } diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index 8178f7a..4fddd11 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -14,7 +14,7 @@ #include "clang/Frontend/Utils.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LangOptions.h" -#include "clang/Frontend/HeaderSearchOptions.h" +#include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/HeaderSearch.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallPtrSet.h" @@ -320,7 +320,9 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, P.appendComponent("../../../include"); // <sysroot>/include AddPath(P.str(), System, true, false, false); AddPath("/mingw/include", System, true, false, false); +#if defined(_WIN32) AddPath("c:/mingw/include", System, true, false, false); +#endif } break; @@ -396,12 +398,14 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.7.0"); // mingw.org C++ include paths AddMinGWCPlusPlusIncludePaths("/mingw/lib/gcc", "mingw32", "4.5.2"); //MSYS +#if defined(_WIN32) AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.6.2"); AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.6.1"); AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.2"); AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.0"); AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0"); AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0"); +#endif break; case llvm::Triple::DragonFly: AddPath("/usr/include/c++/4.1", CXXSystem, true, false, false); diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 1440da6..4bbd033 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -17,11 +17,12 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/FrontendOptions.h" -#include "clang/Frontend/PreprocessorOptions.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" +#include "clang/Serialization/ASTReader.h" #include "llvm/ADT/APFloat.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" @@ -83,6 +84,19 @@ static void AddImplicitIncludePTH(MacroBuilder &Builder, Preprocessor &PP, AddImplicitInclude(Builder, OriginalFile, PP.getFileManager()); } +/// \brief Add an implicit \#include using the original file used to generate +/// a PCH file. +static void AddImplicitIncludePCH(MacroBuilder &Builder, Preprocessor &PP, + StringRef ImplicitIncludePCH) { + std::string OriginalFile = + ASTReader::getOriginalSourceFile(ImplicitIncludePCH, PP.getFileManager(), + PP.getDiagnostics()); + if (OriginalFile.empty()) + return; + + AddImplicitInclude(Builder, OriginalFile, PP.getFileManager()); +} + /// PickFP - This is used to pick a value based on the FP semantics of the /// specified FP model. template <typename T> @@ -102,51 +116,51 @@ static T PickFP(const llvm::fltSemantics *Sem, T IEEESingleVal, } static void DefineFloatMacros(MacroBuilder &Builder, StringRef Prefix, - const llvm::fltSemantics *Sem) { + const llvm::fltSemantics *Sem, StringRef Ext) { const char *DenormMin, *Epsilon, *Max, *Min; - DenormMin = PickFP(Sem, "1.40129846e-45F", "4.9406564584124654e-324", - "3.64519953188247460253e-4951L", - "4.94065645841246544176568792868221e-324L", - "6.47517511943802511092443895822764655e-4966L"); + DenormMin = PickFP(Sem, "1.40129846e-45", "4.9406564584124654e-324", + "3.64519953188247460253e-4951", + "4.94065645841246544176568792868221e-324", + "6.47517511943802511092443895822764655e-4966"); int Digits = PickFP(Sem, 6, 15, 18, 31, 33); - Epsilon = PickFP(Sem, "1.19209290e-7F", "2.2204460492503131e-16", - "1.08420217248550443401e-19L", - "4.94065645841246544176568792868221e-324L", - "1.92592994438723585305597794258492732e-34L"); + Epsilon = PickFP(Sem, "1.19209290e-7", "2.2204460492503131e-16", + "1.08420217248550443401e-19", + "4.94065645841246544176568792868221e-324", + "1.92592994438723585305597794258492732e-34"); int MantissaDigits = PickFP(Sem, 24, 53, 64, 106, 113); int Min10Exp = PickFP(Sem, -37, -307, -4931, -291, -4931); int Max10Exp = PickFP(Sem, 38, 308, 4932, 308, 4932); int MinExp = PickFP(Sem, -125, -1021, -16381, -968, -16381); int MaxExp = PickFP(Sem, 128, 1024, 16384, 1024, 16384); - Min = PickFP(Sem, "1.17549435e-38F", "2.2250738585072014e-308", - "3.36210314311209350626e-4932L", - "2.00416836000897277799610805135016e-292L", - "3.36210314311209350626267781732175260e-4932L"); - Max = PickFP(Sem, "3.40282347e+38F", "1.7976931348623157e+308", - "1.18973149535723176502e+4932L", - "1.79769313486231580793728971405301e+308L", - "1.18973149535723176508575932662800702e+4932L"); + Min = PickFP(Sem, "1.17549435e-38", "2.2250738585072014e-308", + "3.36210314311209350626e-4932", + "2.00416836000897277799610805135016e-292", + "3.36210314311209350626267781732175260e-4932"); + Max = PickFP(Sem, "3.40282347e+38", "1.7976931348623157e+308", + "1.18973149535723176502e+4932", + "1.79769313486231580793728971405301e+308", + "1.18973149535723176508575932662800702e+4932"); SmallString<32> DefPrefix; DefPrefix = "__"; DefPrefix += Prefix; DefPrefix += "_"; - Builder.defineMacro(DefPrefix + "DENORM_MIN__", DenormMin); + Builder.defineMacro(DefPrefix + "DENORM_MIN__", Twine(DenormMin)+Ext); Builder.defineMacro(DefPrefix + "HAS_DENORM__"); Builder.defineMacro(DefPrefix + "DIG__", Twine(Digits)); - Builder.defineMacro(DefPrefix + "EPSILON__", Twine(Epsilon)); + Builder.defineMacro(DefPrefix + "EPSILON__", Twine(Epsilon)+Ext); Builder.defineMacro(DefPrefix + "HAS_INFINITY__"); Builder.defineMacro(DefPrefix + "HAS_QUIET_NAN__"); Builder.defineMacro(DefPrefix + "MANT_DIG__", Twine(MantissaDigits)); Builder.defineMacro(DefPrefix + "MAX_10_EXP__", Twine(Max10Exp)); Builder.defineMacro(DefPrefix + "MAX_EXP__", Twine(MaxExp)); - Builder.defineMacro(DefPrefix + "MAX__", Twine(Max)); + Builder.defineMacro(DefPrefix + "MAX__", Twine(Max)+Ext); Builder.defineMacro(DefPrefix + "MIN_10_EXP__","("+Twine(Min10Exp)+")"); Builder.defineMacro(DefPrefix + "MIN_EXP__", "("+Twine(MinExp)+")"); - Builder.defineMacro(DefPrefix + "MIN__", Twine(Min)); + Builder.defineMacro(DefPrefix + "MIN__", Twine(Min)+Ext); } @@ -247,7 +261,7 @@ static void AddObjCXXARCLibstdcxxDefines(const LangOptions &LangOpts, << "};\n" << "\n"; - if (LangOpts.ObjCRuntimeHasWeak) { + if (LangOpts.ObjCARCWeak) { Out << "template<typename _Tp>\n" << "struct __is_scalar<__attribute__((objc_ownership(weak))) _Tp> {\n" << " enum { __value = 0 };\n" @@ -288,6 +302,8 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, else if (!LangOpts.GNUMode && LangOpts.Digraphs) Builder.defineMacro("__STDC_VERSION__", "199409L"); } else { + // FIXME: LangOpts.CPlusPlus1y + // C++11 [cpp.predefined]p1: // The name __cplusplus is defined to the value 201103L when compiling a // C++ translation unit. @@ -325,8 +341,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__clang_patchlevel__", "0"); #endif Builder.defineMacro("__clang_version__", - "\"" CLANG_VERSION_STRING " (" - + getClangFullRepositoryVersion() + ")\""); + "\"" CLANG_VERSION_STRING " " + + getClangFullRepositoryVersion() + "\""); #undef TOSTR #undef TOSTR2 if (!LangOpts.MicrosoftMode) { @@ -420,19 +436,17 @@ static void InitializePredefinedMacros(const TargetInfo &TI, // Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however // VC++ appears to only like __FUNCTION__. Builder.defineMacro("__PRETTY_FUNCTION__", "__FUNCTION__"); - // Work around some issues with Visual C++ headerws. - if (LangOpts.CPlusPlus) { - // Since we define wchar_t in C++ mode. + // Work around some issues with Visual C++ headers. + if (LangOpts.WChar) { + // wchar_t supported as a keyword. Builder.defineMacro("_WCHAR_T_DEFINED"); Builder.defineMacro("_NATIVE_WCHAR_T_DEFINED"); + } + if (LangOpts.CPlusPlus) { // FIXME: Support Microsoft's __identifier extension in the lexer. Builder.append("#define __identifier(x) x"); Builder.append("class type_info;"); } - - if (LangOpts.CPlusPlus0x) { - Builder.defineMacro("_HAS_CHAR16_T_LANGUAGE_SUPPORT", "1"); - } } if (LangOpts.Optimize) @@ -511,9 +525,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineType("__CHAR16_TYPE__", TI.getChar16Type(), Builder); DefineType("__CHAR32_TYPE__", TI.getChar32Type(), Builder); - DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat()); - DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat()); - DefineFloatMacros(Builder, "LDBL", &TI.getLongDoubleFormat()); + DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat(), "F"); + DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat(), ""); + DefineFloatMacros(Builder, "LDBL", &TI.getLongDoubleFormat(), "L"); // Define a __POINTER_WIDTH__ macro for stdint.h. Builder.defineMacro("__POINTER_WIDTH__", @@ -763,6 +777,8 @@ void clang::InitializePreprocessor(Preprocessor &PP, const std::string &Path = InitOpts.Includes[i]; if (Path == InitOpts.ImplicitPTHInclude) AddImplicitIncludePTH(Builder, PP, Path); + else if (Path == InitOpts.ImplicitPCHInclude) + AddImplicitIncludePCH(Builder, PP, Path); else AddImplicitInclude(Builder, Path, PP.getFileManager()); } diff --git a/lib/Frontend/LogDiagnosticPrinter.cpp b/lib/Frontend/LogDiagnosticPrinter.cpp index 3fee957..3a04f18 100644 --- a/lib/Frontend/LogDiagnosticPrinter.cpp +++ b/lib/Frontend/LogDiagnosticPrinter.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/LogDiagnosticPrinter.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallString.h" @@ -16,9 +17,9 @@ using namespace clang; LogDiagnosticPrinter::LogDiagnosticPrinter(raw_ostream &os, - const DiagnosticOptions &diags, + DiagnosticOptions *diags, bool _OwnsOutputStream) - : OS(os), LangOpts(0), DiagOpts(&diags), + : OS(os), LangOpts(0), DiagOpts(diags), OwnsOutputStream(_OwnsOutputStream) { } @@ -172,6 +173,6 @@ void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, DiagnosticConsumer * LogDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const { - return new LogDiagnosticPrinter(OS, *DiagOpts, /*OwnsOutputStream=*/false); + return new LogDiagnosticPrinter(OS, &*DiagOpts, /*OwnsOutputStream=*/false); } diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index 5311ed5..30707dc 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -570,8 +570,12 @@ static void DoPrintMacros(Preprocessor &PP, raw_ostream *OS) { do PP.Lex(Tok); while (Tok.isNot(tok::eof)); - SmallVector<id_macro_pair, 128> - MacrosByID(PP.macro_begin(), PP.macro_end()); + SmallVector<id_macro_pair, 128> MacrosByID; + for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end(); + I != E; ++I) { + if (I->first->hasMacroDefinition()) + MacrosByID.push_back(id_macro_pair(I->first, I->second)); + } llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(), MacroIDCompare); for (unsigned i = 0, e = MacrosByID.size(); i != e; ++i) { diff --git a/lib/Frontend/SerializedDiagnosticPrinter.cpp b/lib/Frontend/SerializedDiagnosticPrinter.cpp index a20f30d..5f8fc1e 100644 --- a/lib/Frontend/SerializedDiagnosticPrinter.cpp +++ b/lib/Frontend/SerializedDiagnosticPrinter.cpp @@ -12,6 +12,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/DenseSet.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/Diagnostic.h" @@ -50,13 +51,10 @@ class SDiagsWriter; class SDiagsRenderer : public DiagnosticNoteRenderer { SDiagsWriter &Writer; - RecordData &Record; public: - SDiagsRenderer(SDiagsWriter &Writer, RecordData &Record, - const LangOptions &LangOpts, - const DiagnosticOptions &DiagOpts) - : DiagnosticNoteRenderer(LangOpts, DiagOpts), - Writer(Writer), Record(Record){} + SDiagsRenderer(SDiagsWriter &Writer, const LangOptions &LangOpts, + DiagnosticOptions *DiagOpts) + : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {} virtual ~SDiagsRenderer() {} @@ -73,15 +71,16 @@ protected: DiagnosticsEngine::Level Level, ArrayRef<CharSourceRange> Ranges, const SourceManager &SM) {} - - void emitNote(SourceLocation Loc, StringRef Message, const SourceManager *SM); - + + virtual void emitNote(SourceLocation Loc, StringRef Message, + const SourceManager *SM); + virtual void emitCodeContext(SourceLocation Loc, DiagnosticsEngine::Level Level, SmallVectorImpl<CharSourceRange>& Ranges, ArrayRef<FixItHint> Hints, const SourceManager &SM); - + virtual void beginDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level); virtual void endDiagnostic(DiagOrStoredDiag D, @@ -91,13 +90,12 @@ protected: class SDiagsWriter : public DiagnosticConsumer { friend class SDiagsRenderer; public: - explicit SDiagsWriter(llvm::raw_ostream *os, const DiagnosticOptions &diags) - : LangOpts(0), DiagOpts(diags), - Stream(Buffer), OS(os), inNonNoteDiagnostic(false) - { + explicit SDiagsWriter(llvm::raw_ostream *os, DiagnosticOptions *diags) + : LangOpts(0), DiagOpts(diags), Stream(Buffer), OS(os), + EmittedAnyDiagBlocks(false) { EmitPreamble(); } - + ~SDiagsWriter() {} void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, @@ -124,7 +122,26 @@ private: /// \brief Emit the META data block. void EmitMetaBlock(); - + + /// \brief Start a DIAG block. + void EnterDiagBlock(); + + /// \brief End a DIAG block. + void ExitDiagBlock(); + + /// \brief Emit a DIAG record. + void EmitDiagnosticMessage(SourceLocation Loc, + PresumedLoc PLoc, + DiagnosticsEngine::Level Level, + StringRef Message, + const SourceManager *SM, + DiagOrStoredDiag D); + + /// \brief Emit FIXIT and SOURCE_RANGE records for a diagnostic. + void EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges, + ArrayRef<FixItHint> Hints, + const SourceManager &SM); + /// \brief Emit a record for a CharSourceRange. void EmitCharSourceRange(CharSourceRange R, const SourceManager &SM); @@ -159,7 +176,7 @@ private: enum { Version = 1 }; const LangOptions *LangOpts; - const DiagnosticOptions &DiagOpts; + llvm::IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; /// \brief The byte buffer for the serialized content. SmallString<1024> Buffer; @@ -190,17 +207,18 @@ private: /// \brief Map for uniquing strings. DiagFlagsTy DiagFlags; - - /// \brief Flag indicating whether or not we are in the process of - /// emitting a non-note diagnostic. - bool inNonNoteDiagnostic; + + /// \brief Whether we have already started emission of any DIAG blocks. Once + /// this becomes \c true, we never close a DIAG block until we know that we're + /// starting another one or we're done. + bool EmittedAnyDiagBlocks; }; } // end anonymous namespace namespace clang { namespace serialized_diags { DiagnosticConsumer *create(llvm::raw_ostream *OS, - const DiagnosticOptions &diags) { + DiagnosticOptions *diags) { return new SDiagsWriter(OS, diags); } } // end namespace serialized_diags @@ -474,31 +492,69 @@ unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel, void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { + // Enter the block for a non-note diagnostic immediately, rather than waiting + // for beginDiagnostic, in case associated notes are emitted before we get + // there. if (DiagLevel != DiagnosticsEngine::Note) { - if (inNonNoteDiagnostic) { - // We have encountered a non-note diagnostic. Finish up the previous - // diagnostic block before starting a new one. - Stream.ExitBlock(); - } - inNonNoteDiagnostic = true; + if (EmittedAnyDiagBlocks) + ExitDiagBlock(); + + EnterDiagBlock(); + EmittedAnyDiagBlocks = true; } // Compute the diagnostic text. - diagBuf.clear(); + diagBuf.clear(); Info.FormatDiagnostic(diagBuf); - const SourceManager * - SM = Info.hasSourceManager() ? &Info.getSourceManager() : 0; - SDiagsRenderer Renderer(*this, Record, *LangOpts, DiagOpts); + if (Info.getLocation().isInvalid()) { + // Special-case diagnostics with no location. We may not have entered a + // source file in this case, so we can't use the normal DiagnosticsRenderer + // machinery. + EmitDiagnosticMessage(SourceLocation(), PresumedLoc(), DiagLevel, + diagBuf, 0, &Info); + return; + } + + assert(Info.hasSourceManager() && LangOpts && + "Unexpected diagnostic with valid location outside of a source file"); + SDiagsRenderer Renderer(*this, *LangOpts, &*DiagOpts); Renderer.emitDiagnostic(Info.getLocation(), DiagLevel, diagBuf.str(), Info.getRanges(), llvm::makeArrayRef(Info.getFixItHints(), Info.getNumFixItHints()), - SM, + &Info.getSourceManager(), &Info); } +void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc, + PresumedLoc PLoc, + DiagnosticsEngine::Level Level, + StringRef Message, + const SourceManager *SM, + DiagOrStoredDiag D) { + // Emit the RECORD_DIAG record. + Record.clear(); + Record.push_back(RECORD_DIAG); + Record.push_back(Level); + AddLocToRecord(Loc, SM, PLoc, Record); + + if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) { + // Emit the category string lazily and get the category ID. + unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID()); + Record.push_back(getEmitCategory(DiagID)); + // Emit the diagnostic flag string lazily and get the mapped ID. + Record.push_back(getEmitDiagnosticFlag(Level, Info->getID())); + } else { + Record.push_back(getEmitCategory()); + Record.push_back(getEmitDiagnosticFlag(Level)); + } + + Record.push_back(Message.size()); + Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, Message); +} + void SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc, PresumedLoc PLoc, @@ -507,94 +563,80 @@ SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc, ArrayRef<clang::CharSourceRange> Ranges, const SourceManager *SM, DiagOrStoredDiag D) { - // Emit the RECORD_DIAG record. - Writer.Record.clear(); - Writer.Record.push_back(RECORD_DIAG); - Writer.Record.push_back(Level); - Writer.AddLocToRecord(Loc, SM, PLoc, Record); + Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, SM, D); +} - if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) { - // Emit the category string lazily and get the category ID. - unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID()); - Writer.Record.push_back(Writer.getEmitCategory(DiagID)); - // Emit the diagnostic flag string lazily and get the mapped ID. - Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level, Info->getID())); - } - else { - Writer.Record.push_back(Writer.getEmitCategory()); - Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level)); - } +void SDiagsWriter::EnterDiagBlock() { + Stream.EnterSubblock(BLOCK_DIAG, 4); +} - Writer.Record.push_back(Message.size()); - Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG), - Writer.Record, Message); +void SDiagsWriter::ExitDiagBlock() { + Stream.ExitBlock(); } void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level) { - Writer.Stream.EnterSubblock(BLOCK_DIAG, 4); + if (Level == DiagnosticsEngine::Note) + Writer.EnterDiagBlock(); } void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level) { - if (D && Level != DiagnosticsEngine::Note) - return; - Writer.Stream.ExitBlock(); + // Only end note diagnostics here, because we can't be sure when we've seen + // the last note associated with a non-note diagnostic. + if (Level == DiagnosticsEngine::Note) + Writer.ExitDiagBlock(); } -void SDiagsRenderer::emitCodeContext(SourceLocation Loc, - DiagnosticsEngine::Level Level, - SmallVectorImpl<CharSourceRange> &Ranges, - ArrayRef<FixItHint> Hints, - const SourceManager &SM) { +void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges, + ArrayRef<FixItHint> Hints, + const SourceManager &SM) { // Emit Source Ranges. - for (ArrayRef<CharSourceRange>::iterator it=Ranges.begin(), ei=Ranges.end(); - it != ei; ++it) { - if (it->isValid()) - Writer.EmitCharSourceRange(*it, SM); - } - + for (ArrayRef<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); + I != E; ++I) + if (I->isValid()) + EmitCharSourceRange(*I, SM); + // Emit FixIts. - for (ArrayRef<FixItHint>::iterator it = Hints.begin(), et = Hints.end(); - it != et; ++it) { - const FixItHint &fix = *it; - if (fix.isNull()) + for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); + I != E; ++I) { + const FixItHint &Fix = *I; + if (Fix.isNull()) continue; - Writer.Record.clear(); - Writer.Record.push_back(RECORD_FIXIT); - Writer.AddCharSourceRangeToRecord(fix.RemoveRange, Record, SM); - Writer.Record.push_back(fix.CodeToInsert.size()); - Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_FIXIT), Record, - fix.CodeToInsert); + Record.clear(); + Record.push_back(RECORD_FIXIT); + AddCharSourceRangeToRecord(Fix.RemoveRange, Record, SM); + Record.push_back(Fix.CodeToInsert.size()); + Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FIXIT), Record, + Fix.CodeToInsert); } } +void SDiagsRenderer::emitCodeContext(SourceLocation Loc, + DiagnosticsEngine::Level Level, + SmallVectorImpl<CharSourceRange> &Ranges, + ArrayRef<FixItHint> Hints, + const SourceManager &SM) { + Writer.EmitCodeContext(Ranges, Hints, SM); +} + void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message, const SourceManager *SM) { - Writer.Stream.EnterSubblock(BLOCK_DIAG, 4); - RecordData Record; - Record.push_back(RECORD_DIAG); - Record.push_back(DiagnosticsEngine::Note); - Writer.AddLocToRecord(Loc, Record, SM); - Record.push_back(Writer.getEmitCategory()); - Record.push_back(Writer.getEmitDiagnosticFlag(DiagnosticsEngine::Note)); - Record.push_back(Message.size()); - Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG), - Record, Message); - Writer.Stream.ExitBlock(); + Writer.EnterDiagBlock(); + PresumedLoc PLoc = SM ? SM->getPresumedLoc(Loc) : PresumedLoc(); + Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note, + Message, SM, DiagOrStoredDiag()); + Writer.ExitDiagBlock(); } void SDiagsWriter::finish() { - if (inNonNoteDiagnostic) { - // Finish off any diagnostics we were in the process of emitting. - Stream.ExitBlock(); - inNonNoteDiagnostic = false; - } + // Finish off any diagnostic we were in the process of emitting. + if (EmittedAnyDiagBlocks) + ExitDiagBlock(); // Write the generated bitstream to "Out". OS->write((char *)&Buffer.front(), Buffer.size()); OS->flush(); - + OS.reset(0); } - diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp index 9bb3e1d..35dabad 100644 --- a/lib/Frontend/TextDiagnostic.cpp +++ b/lib/Frontend/TextDiagnostic.cpp @@ -11,7 +11,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/ConvertUTF.h" -#include "clang/Frontend/DiagnosticOptions.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Lex/Lexer.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" @@ -43,19 +43,22 @@ static const enum raw_ostream::Colors savedColor = /// \brief Add highlights to differences in template strings. static void applyTemplateHighlighting(raw_ostream &OS, StringRef Str, bool &Normal, bool Bold) { - for (unsigned i = 0, e = Str.size(); i < e; ++i) - if (Str[i] != ToggleHighlight) { - OS << Str[i]; - } else { - if (Normal) - OS.changeColor(templateColor, true); - else { - OS.resetColor(); - if (Bold) - OS.changeColor(savedColor, true); - } - Normal = !Normal; + while (1) { + size_t Pos = Str.find(ToggleHighlight); + OS << Str.slice(0, Pos); + if (Pos == StringRef::npos) + break; + + Str = Str.substr(Pos + 1); + if (Normal) + OS.changeColor(templateColor, true); + else { + OS.resetColor(); + if (Bold) + OS.changeColor(savedColor, true); } + Normal = !Normal; + } } /// \brief Number of spaces to indent when word-wrapping. @@ -110,28 +113,15 @@ printableTextForNextCharacter(StringRef SourceLine, size_t *i, return std::make_pair(expandedTab, true); } - // FIXME: this data is copied from the private implementation of ConvertUTF.h - static const char trailingBytesForUTF8[256] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 - }; - unsigned char const *begin, *end; begin = reinterpret_cast<unsigned char const *>(&*(SourceLine.begin() + *i)); - end = begin + SourceLine.size(); + end = begin + (SourceLine.size() - *i); if (isLegalUTF8Sequence(begin, end)) { UTF32 c; UTF32 *cptr = &c; unsigned char const *original_begin = begin; - char trailingBytes = trailingBytesForUTF8[(unsigned char)SourceLine[*i]]; - unsigned char const *cp_end = begin+trailingBytes+1; + unsigned char const *cp_end = begin+getNumBytesForUTF8(SourceLine[*i]); ConversionResult res = ConvertUTF8toUTF32(&begin, cp_end, &cptr, cptr+1, strictConversion); @@ -274,14 +264,44 @@ struct SourceColumnMap { } int columns() const { return m_byteToColumn.back(); } int bytes() const { return m_columnToByte.back(); } + + /// \brief Map a byte to the column which it is at the start of, or return -1 + /// if it is not at the start of a column (for a UTF-8 trailing byte). int byteToColumn(int n) const { assert(0<=n && n<static_cast<int>(m_byteToColumn.size())); return m_byteToColumn[n]; } + + /// \brief Map a byte to the first column which contains it. + int byteToContainingColumn(int N) const { + assert(0 <= N && N < static_cast<int>(m_byteToColumn.size())); + while (m_byteToColumn[N] == -1) + --N; + return m_byteToColumn[N]; + } + + /// \brief Map a column to the byte which starts the column, or return -1 if + /// the column the second or subsequent column of an expanded tab or similar + /// multi-column entity. int columnToByte(int n) const { assert(0<=n && n<static_cast<int>(m_columnToByte.size())); return m_columnToByte[n]; } + + /// \brief Map from a byte index to the next byte which starts a column. + int startOfNextColumn(int N) const { + assert(0 <= N && N < static_cast<int>(m_columnToByte.size() - 1)); + while (byteToColumn(++N) == -1) {} + return N; + } + + /// \brief Map from a byte index to the previous byte which starts a column. + int startOfPreviousColumn(int N) const { + assert(0 < N && N < static_cast<int>(m_columnToByte.size())); + while (byteToColumn(--N) == -1) {} + return N; + } + StringRef getSourceLine() const { return m_SourceLine; } @@ -398,25 +418,24 @@ static void selectInterestingSourceRegion(std::string &SourceLine, bool ExpandedRegion = false; if (SourceStart>0) { - unsigned NewStart = SourceStart-1; + unsigned NewStart = map.startOfPreviousColumn(SourceStart); // Skip over any whitespace we see here; we're looking for // another bit of interesting text. + // FIXME: Detect non-ASCII whitespace characters too. while (NewStart && - (map.byteToColumn(NewStart)==-1 || - isspace(static_cast<unsigned char>(SourceLine[NewStart])))) - --NewStart; + isspace(static_cast<unsigned char>(SourceLine[NewStart]))) + NewStart = map.startOfPreviousColumn(NewStart); // Skip over this bit of "interesting" text. - while (NewStart && - (map.byteToColumn(NewStart)!=-1 && - !isspace(static_cast<unsigned char>(SourceLine[NewStart])))) - --NewStart; - - // Move up to the non-whitespace character we just saw. - if (NewStart) - ++NewStart; + while (NewStart) { + unsigned Prev = map.startOfPreviousColumn(NewStart); + if (isspace(static_cast<unsigned char>(SourceLine[Prev]))) + break; + NewStart = Prev; + } + assert(map.byteToColumn(NewStart) != -1); unsigned NewColumns = map.byteToColumn(SourceEnd) - map.byteToColumn(NewStart); if (NewColumns <= TargetColumns) { @@ -426,21 +445,21 @@ static void selectInterestingSourceRegion(std::string &SourceLine, } if (SourceEnd<SourceLine.size()) { - unsigned NewEnd = SourceEnd+1; + unsigned NewEnd = map.startOfNextColumn(SourceEnd); // Skip over any whitespace we see here; we're looking for // another bit of interesting text. - while (NewEnd<SourceLine.size() && - (map.byteToColumn(NewEnd)==-1 || - isspace(static_cast<unsigned char>(SourceLine[NewEnd])))) - ++NewEnd; + // FIXME: Detect non-ASCII whitespace characters too. + while (NewEnd < SourceLine.size() && + isspace(static_cast<unsigned char>(SourceLine[NewEnd]))) + NewEnd = map.startOfNextColumn(NewEnd); // Skip over this bit of "interesting" text. - while (NewEnd<SourceLine.size() && - (map.byteToColumn(NewEnd)!=-1 && - !isspace(static_cast<unsigned char>(SourceLine[NewEnd])))) - ++NewEnd; + while (NewEnd < SourceLine.size() && + !isspace(static_cast<unsigned char>(SourceLine[NewEnd]))) + NewEnd = map.startOfNextColumn(NewEnd); + assert(map.byteToColumn(NewEnd) != -1); unsigned NewColumns = map.byteToColumn(NewEnd) - map.byteToColumn(SourceStart); if (NewColumns <= TargetColumns) { @@ -475,7 +494,7 @@ static void selectInterestingSourceRegion(std::string &SourceLine, // The line needs some trunctiona, and we'd prefer to keep the front // if possible, so remove the back - if (BackColumnsRemoved) + if (BackColumnsRemoved > strlen(back_ellipse)) SourceLine.replace(SourceEnd, std::string::npos, back_ellipse); // If that's enough then we're done @@ -483,7 +502,7 @@ static void selectInterestingSourceRegion(std::string &SourceLine, return; // Otherwise remove the front as well - if (FrontColumnsRemoved) { + if (FrontColumnsRemoved > strlen(front_ellipse)) { SourceLine.replace(0, SourceStart, front_ellipse); CaretLine.replace(0, CaretStart, front_space); if (!FixItInsertionLine.empty()) @@ -651,7 +670,7 @@ static bool printWordWrapped(raw_ostream &OS, StringRef Str, TextDiagnostic::TextDiagnostic(raw_ostream &OS, const LangOptions &LangOpts, - const DiagnosticOptions &DiagOpts) + DiagnosticOptions *DiagOpts) : DiagnosticRenderer(LangOpts, DiagOpts), OS(OS) {} TextDiagnostic::~TextDiagnostic() {} @@ -670,13 +689,13 @@ TextDiagnostic::emitDiagnosticMessage(SourceLocation Loc, if (Loc.isValid()) emitDiagnosticLoc(Loc, PLoc, Level, Ranges, *SM); - if (DiagOpts.ShowColors) + if (DiagOpts->ShowColors) OS.resetColor(); - printDiagnosticLevel(OS, Level, DiagOpts.ShowColors); + printDiagnosticLevel(OS, Level, DiagOpts->ShowColors); printDiagnosticMessage(OS, Level, Message, OS.tell() - StartOfLocationInfo, - DiagOpts.MessageLength, DiagOpts.ShowColors); + DiagOpts->MessageLength, DiagOpts->ShowColors); } /*static*/ void @@ -770,36 +789,36 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, } unsigned LineNo = PLoc.getLine(); - if (!DiagOpts.ShowLocation) + if (!DiagOpts->ShowLocation) return; - if (DiagOpts.ShowColors) + if (DiagOpts->ShowColors) OS.changeColor(savedColor, true); OS << PLoc.getFilename(); - switch (DiagOpts.Format) { + switch (DiagOpts->getFormat()) { case DiagnosticOptions::Clang: OS << ':' << LineNo; break; case DiagnosticOptions::Msvc: OS << '(' << LineNo; break; case DiagnosticOptions::Vi: OS << " +" << LineNo; break; } - if (DiagOpts.ShowColumn) + if (DiagOpts->ShowColumn) // Compute the column number. if (unsigned ColNo = PLoc.getColumn()) { - if (DiagOpts.Format == DiagnosticOptions::Msvc) { + if (DiagOpts->getFormat() == DiagnosticOptions::Msvc) { OS << ','; ColNo--; } else OS << ':'; OS << ColNo; } - switch (DiagOpts.Format) { + switch (DiagOpts->getFormat()) { case DiagnosticOptions::Clang: case DiagnosticOptions::Vi: OS << ':'; break; case DiagnosticOptions::Msvc: OS << ") : "; break; } - if (DiagOpts.ShowSourceRanges && !Ranges.empty()) { + if (DiagOpts->ShowSourceRanges && !Ranges.empty()) { FileID CaretFileID = SM.getFileID(SM.getExpansionLoc(Loc)); bool PrintedRange = false; @@ -858,7 +877,7 @@ void TextDiagnostic::emitBasicNote(StringRef Message) { void TextDiagnostic::emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc, const SourceManager &SM) { - if (DiagOpts.ShowLocation) + if (DiagOpts->ShowLocation) OS << "In file included from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; else @@ -886,7 +905,7 @@ void TextDiagnostic::emitSnippetAndCaret( // was part of a different warning or error diagnostic, or if the // diagnostic has ranges. We don't want to emit the same caret // multiple times if one loc has multiple diagnostics. - if (!DiagOpts.ShowCarets) + if (!DiagOpts->ShowCarets) return; if (Loc == LastLoc && Ranges.empty() && Hints.empty() && (LastLevel != DiagnosticsEngine::Note || Level == LastLevel)) @@ -924,7 +943,7 @@ void TextDiagnostic::emitSnippetAndCaret( // length as the line of source code. std::string CaretLine(LineEnd-LineStart, ' '); - const SourceColumnMap sourceColMap(SourceLine, DiagOpts.TabStop); + const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop); // Highlight all of the characters covered by Ranges with ~ characters. for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), @@ -933,7 +952,7 @@ void TextDiagnostic::emitSnippetAndCaret( highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM); // Next, insert the caret itself. - ColNo = sourceColMap.byteToColumn(ColNo-1); + ColNo = sourceColMap.byteToContainingColumn(ColNo-1); if (CaretLine.size()<ColNo+1) CaretLine.resize(ColNo+1, ' '); CaretLine[ColNo] = '^'; @@ -944,7 +963,7 @@ void TextDiagnostic::emitSnippetAndCaret( // If the source line is too long for our terminal, select only the // "interesting" source region within that line. - unsigned Columns = DiagOpts.MessageLength; + unsigned Columns = DiagOpts->MessageLength; if (Columns) selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine, Columns, sourceColMap); @@ -953,7 +972,7 @@ void TextDiagnostic::emitSnippetAndCaret( // 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) { + if (DiagOpts->ShowSourceRanges) { SourceLine = ' ' + SourceLine; CaretLine = ' ' + CaretLine; } @@ -965,20 +984,20 @@ void TextDiagnostic::emitSnippetAndCaret( // Emit what we have computed. emitSnippet(SourceLine); - if (DiagOpts.ShowColors) + if (DiagOpts->ShowColors) OS.changeColor(caretColor, true); OS << CaretLine << '\n'; - if (DiagOpts.ShowColors) + if (DiagOpts->ShowColors) OS.resetColor(); if (!FixItInsertionLine.empty()) { - if (DiagOpts.ShowColors) + if (DiagOpts->ShowColors) // Print fixit line in color OS.changeColor(fixitColor, false); - if (DiagOpts.ShowSourceRanges) + if (DiagOpts->ShowSourceRanges) OS << ' '; OS << FixItInsertionLine << '\n'; - if (DiagOpts.ShowColors) + if (DiagOpts->ShowColors) OS.resetColor(); } @@ -997,15 +1016,15 @@ void TextDiagnostic::emitSnippet(StringRef line) { while (i<line.size()) { std::pair<SmallString<16>,bool> res - = printableTextForNextCharacter(line, &i, DiagOpts.TabStop); + = printableTextForNextCharacter(line, &i, DiagOpts->TabStop); bool was_printable = res.second; - if (DiagOpts.ShowColors && was_printable == print_reversed) { + if (DiagOpts->ShowColors && was_printable == print_reversed) { if (print_reversed) OS.reverseColor(); OS << to_print; to_print.clear(); - if (DiagOpts.ShowColors) + if (DiagOpts->ShowColors) OS.resetColor(); } @@ -1013,10 +1032,10 @@ void TextDiagnostic::emitSnippet(StringRef line) { to_print += res.first.str(); } - if (print_reversed && DiagOpts.ShowColors) + if (print_reversed && DiagOpts->ShowColors) OS.reverseColor(); OS << to_print; - if (print_reversed && DiagOpts.ShowColors) + if (print_reversed && DiagOpts->ShowColors) OS.resetColor(); OS << '\n'; @@ -1030,16 +1049,8 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R, const SourceManager &SM) { if (!R.isValid()) return; - SourceLocation Begin = SM.getExpansionLoc(R.getBegin()); - SourceLocation End = SM.getExpansionLoc(R.getEnd()); - - // 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 macro expansion - // or _Pragma. If this is an object-like macro, the 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 (Begin == End && R.getEnd().isMacroID()) - End = SM.getExpansionRange(R.getEnd()).second; + SourceLocation Begin = R.getBegin(); + SourceLocation End = R.getEnd(); unsigned StartLineNo = SM.getExpansionLineNumber(Begin); if (StartLineNo > LineNo || SM.getFileID(Begin) != FID) @@ -1080,7 +1091,7 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R, while (StartColNo < map.getSourceLine().size() && (map.getSourceLine()[StartColNo] == ' ' || map.getSourceLine()[StartColNo] == '\t')) - ++StartColNo; + StartColNo = map.startOfNextColumn(StartColNo); // Pick the last non-whitespace column. if (EndColNo > map.getSourceLine().size()) @@ -1088,7 +1099,7 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R, while (EndColNo-1 && (map.getSourceLine()[EndColNo-1] == ' ' || map.getSourceLine()[EndColNo-1] == '\t')) - --EndColNo; + 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 @@ -1100,8 +1111,8 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R, assert(EndColNo <= map.getSourceLine().size() && "Invalid range!"); // Fill the range with ~'s. - StartColNo = map.byteToColumn(StartColNo); - EndColNo = map.byteToColumn(EndColNo); + StartColNo = map.byteToContainingColumn(StartColNo); + EndColNo = map.byteToContainingColumn(EndColNo); assert(StartColNo <= EndColNo && "Invalid range!"); if (CaretLine.size() < EndColNo) @@ -1116,7 +1127,7 @@ std::string TextDiagnostic::buildFixItInsertionLine( const SourceManager &SM) { std::string FixItInsertionLine; - if (Hints.empty() || !DiagOpts.ShowFixits) + if (Hints.empty() || !DiagOpts->ShowFixits) return FixItInsertionLine; unsigned PrevHintEndCol = 0; @@ -1139,7 +1150,7 @@ std::string TextDiagnostic::buildFixItInsertionLine( // The hint must start inside the source or right at the end assert(HintByteOffset < static_cast<unsigned>(map.bytes())+1); - unsigned HintCol = map.byteToColumn(HintByteOffset); + unsigned HintCol = map.byteToContainingColumn(HintByteOffset); // If we inserted a long previous hint, push this one forwards, and add // an extra space to show that this is not part of the previous @@ -1176,14 +1187,14 @@ std::string TextDiagnostic::buildFixItInsertionLine( } } - expandTabs(FixItInsertionLine, DiagOpts.TabStop); + expandTabs(FixItInsertionLine, DiagOpts->TabStop); return FixItInsertionLine; } void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints, const SourceManager &SM) { - if (!DiagOpts.ShowParseableFixits) + if (!DiagOpts->ShowParseableFixits) return; // We follow FixItRewriter's example in not (yet) handling diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 382e156..aa7a61a 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -12,9 +12,9 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" -#include "clang/Frontend/DiagnosticOptions.h" #include "clang/Frontend/TextDiagnostic.h" #include "clang/Lex/Lexer.h" #include "llvm/Support/MemoryBuffer.h" @@ -25,9 +25,9 @@ using namespace clang; TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &os, - const DiagnosticOptions &diags, + DiagnosticOptions *diags, bool _OwnsOutputStream) - : OS(os), DiagOpts(&diags), + : OS(os), DiagOpts(diags), OwnsOutputStream(_OwnsOutputStream) { } @@ -39,7 +39,7 @@ TextDiagnosticPrinter::~TextDiagnosticPrinter() { void TextDiagnosticPrinter::BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) { // Build the TextDiagnostic utility. - TextDiag.reset(new TextDiagnostic(OS, LO, *DiagOpts)); + TextDiag.reset(new TextDiagnostic(OS, LO, &*DiagOpts)); } void TextDiagnosticPrinter::EndSourceFile() { @@ -158,5 +158,5 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, DiagnosticConsumer * TextDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const { - return new TextDiagnosticPrinter(OS, *DiagOpts, /*OwnsOutputStream=*/false); + return new TextDiagnosticPrinter(OS, &*DiagOpts, /*OwnsOutputStream=*/false); } diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp index a9378a1..1750946 100644 --- a/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -31,14 +31,17 @@ VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &_Diags) : Diags(_Diags), PrimaryClient(Diags.getClient()), OwnsPrimaryClient(Diags.ownsClient()), Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0), - ActiveSourceFiles(0) + LangOpts(0), SrcManager(0), ActiveSourceFiles(0), Status(HasNoDirectives) { Diags.takeClient(); + if (Diags.hasSourceManager()) + setSourceManager(Diags.getSourceManager()); } VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() { assert(!ActiveSourceFiles && "Incomplete parsing of source files!"); assert(!CurrentPreprocessor && "CurrentPreprocessor should be invalid!"); + SrcManager = 0; CheckDiagnostics(); Diags.takeClient(); if (OwnsPrimaryClient) @@ -48,21 +51,20 @@ VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() { #ifndef NDEBUG namespace { class VerifyFileTracker : public PPCallbacks { - typedef VerifyDiagnosticConsumer::FilesParsedForDirectivesSet ListType; - ListType &FilesList; + VerifyDiagnosticConsumer &Verify; SourceManager &SM; public: - VerifyFileTracker(ListType &FilesList, SourceManager &SM) - : FilesList(FilesList), SM(SM) { } + VerifyFileTracker(VerifyDiagnosticConsumer &Verify, SourceManager &SM) + : Verify(Verify), SM(SM) { } /// \brief Hook into the preprocessor and update the list of parsed /// files when the preprocessor indicates a new file is entered. virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, SrcMgr::CharacteristicKind FileType, FileID PrevFID) { - if (const FileEntry *E = SM.getFileEntryForID(SM.getFileID(Loc))) - FilesList.insert(E); + Verify.UpdateParsedFileStatus(SM, SM.getFileID(Loc), + VerifyDiagnosticConsumer::IsParsed); } }; } // End anonymous namespace. @@ -76,10 +78,12 @@ void VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts, if (++ActiveSourceFiles == 1) { if (PP) { CurrentPreprocessor = PP; + this->LangOpts = &LangOpts; + setSourceManager(PP->getSourceManager()); const_cast<Preprocessor*>(PP)->addCommentHandler(this); #ifndef NDEBUG - VerifyFileTracker *V = new VerifyFileTracker(FilesParsedForDirectives, - PP->getSourceManager()); + // Debug build tracks parsed files. + VerifyFileTracker *V = new VerifyFileTracker(*this, *SrcManager); const_cast<Preprocessor*>(PP)->addPPCallbacks(V); #endif } @@ -101,18 +105,40 @@ void VerifyDiagnosticConsumer::EndSourceFile() { // Check diagnostics once last file completed. CheckDiagnostics(); CurrentPreprocessor = 0; + LangOpts = 0; } } void VerifyDiagnosticConsumer::HandleDiagnostic( DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { + if (Info.hasSourceManager()) + setSourceManager(Info.getSourceManager()); + #ifndef NDEBUG - if (Info.hasSourceManager()) { - FileID FID = Info.getSourceManager().getFileID(Info.getLocation()); - if (!FID.isInvalid()) - FilesWithDiagnostics.insert(FID); + // Debug build tracks unparsed files for possible + // unparsed expected-* directives. + if (SrcManager) { + SourceLocation Loc = Info.getLocation(); + if (Loc.isValid()) { + ParsedStatus PS = IsUnparsed; + + Loc = SrcManager->getExpansionLoc(Loc); + FileID FID = SrcManager->getFileID(Loc); + + const FileEntry *FE = SrcManager->getFileEntryForID(FID); + if (FE && CurrentPreprocessor && SrcManager->isLoadedFileID(FID)) { + // If the file is a modules header file it shall not be parsed + // for expected-* directives. + HeaderSearch &HS = CurrentPreprocessor->getHeaderSearchInfo(); + if (HS.findModuleForHeader(FE)) + PS = IsUnparsedNoDirectives; + } + + UpdateParsedFileStatus(*SrcManager, FID, PS); + } } #endif + // Send the diagnostic to the buffer, we will check it once we reach the end // of the source file (or are destructed). Buffer->HandleDiagnostic(DiagLevel, Info); @@ -200,10 +226,22 @@ public: // Return true if string literal is found. // When true, P marks begin-position of S in content. - bool Search(StringRef S) { - P = std::search(C, End, S.begin(), S.end()); - PEnd = P + S.size(); - return P != End; + bool Search(StringRef S, bool EnsureStartOfWord = false) { + do { + P = std::search(C, End, S.begin(), S.end()); + PEnd = P + S.size(); + if (P == End) + break; + if (!EnsureStartOfWord + // Check if string literal starts a new word. + || P == Begin || isspace(P[-1]) + // Or it could be preceeded by the start of a comment. + || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*') + && P[-2] == '/')) + return true; + // Otherwise, skip and search again. + } while (Advance()); + return false; } // Advance 1-past previous next/search. @@ -240,12 +278,13 @@ private: /// /// Returns true if any valid directives were found. static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, - SourceLocation Pos, DiagnosticsEngine &Diags) { + SourceLocation Pos, DiagnosticsEngine &Diags, + VerifyDiagnosticConsumer::DirectiveStatus &Status) { // A single comment may contain multiple directives. bool FoundDirective = false; for (ParseHelper PH(S); !PH.Done();) { // Search for token: expected - if (!PH.Search("expected")) + if (!PH.Search("expected", true)) break; PH.Advance(); @@ -262,10 +301,24 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, DL = ED ? &ED->Warnings : NULL; else if (PH.Next("note")) DL = ED ? &ED->Notes : NULL; - else + else if (PH.Next("no-diagnostics")) { + if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives) + Diags.Report(Pos, diag::err_verify_invalid_no_diags) + << /*IsExpectedNoDiagnostics=*/true; + else + Status = VerifyDiagnosticConsumer::HasExpectedNoDiagnostics; + continue; + } else continue; PH.Advance(); + if (Status == VerifyDiagnosticConsumer::HasExpectedNoDiagnostics) { + Diags.Report(Pos, diag::err_verify_invalid_no_diags) + << /*IsExpectedNoDiagnostics=*/false; + continue; + } + Status = VerifyDiagnosticConsumer::HasOtherExpectedDirectives; + // If a directive has been found but we're not interested // in storing the directive information, return now. if (!DL) @@ -412,7 +465,7 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP, // Fold any "\<EOL>" sequences size_t loc = C.find('\\'); if (loc == StringRef::npos) { - ParseDirective(C, &ED, SM, CommentBegin, PP.getDiagnostics()); + ParseDirective(C, &ED, SM, CommentBegin, PP.getDiagnostics(), Status); return false; } @@ -442,7 +495,7 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP, } if (!C2.empty()) - ParseDirective(C2, &ED, SM, CommentBegin, PP.getDiagnostics()); + ParseDirective(C2, &ED, SM, CommentBegin, PP.getDiagnostics(), Status); return false; } @@ -452,34 +505,36 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP, /// Preprocessor, directives inside skipped #if blocks will still be found. /// /// \return true if any directives were found. -static bool findDirectives(const Preprocessor &PP, FileID FID) { +static bool findDirectives(SourceManager &SM, FileID FID, + const LangOptions &LangOpts) { // Create a raw lexer to pull all the comments out of FID. if (FID.isInvalid()) return false; - SourceManager& SM = PP.getSourceManager(); // Create a lexer to lex all the tokens of the main file in raw mode. const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); - Lexer RawLex(FID, FromFile, SM, PP.getLangOpts()); + Lexer RawLex(FID, FromFile, SM, LangOpts); // Return comments as tokens, this is how we find expected diagnostics. RawLex.SetCommentRetentionState(true); Token Tok; Tok.setKind(tok::comment); - bool Found = false; + VerifyDiagnosticConsumer::DirectiveStatus Status = + VerifyDiagnosticConsumer::HasNoDirectives; while (Tok.isNot(tok::eof)) { RawLex.Lex(Tok); if (!Tok.is(tok::comment)) continue; - std::string Comment = PP.getSpelling(Tok); + std::string Comment = RawLex.getSpelling(Tok, SM, LangOpts); if (Comment.empty()) continue; - // Find all expected errors/warnings/notes. - Found |= ParseDirective(Comment, 0, SM, Tok.getLocation(), - PP.getDiagnostics()); + // Find first directive. + if (ParseDirective(Comment, 0, SM, Tok.getLocation(), + SM.getDiagnostics(), Status)) + return true; } - return Found; + return false; } #endif // !NDEBUG @@ -601,41 +656,95 @@ static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr, return NumProblems; } +void VerifyDiagnosticConsumer::UpdateParsedFileStatus(SourceManager &SM, + FileID FID, + ParsedStatus PS) { + // Check SourceManager hasn't changed. + setSourceManager(SM); + +#ifndef NDEBUG + if (FID.isInvalid()) + return; + + const FileEntry *FE = SM.getFileEntryForID(FID); + + if (PS == IsParsed) { + // Move the FileID from the unparsed set to the parsed set. + UnparsedFiles.erase(FID); + ParsedFiles.insert(std::make_pair(FID, FE)); + } else if (!ParsedFiles.count(FID) && !UnparsedFiles.count(FID)) { + // Add the FileID to the unparsed set if we haven't seen it before. + + // Check for directives. + bool FoundDirectives; + if (PS == IsUnparsedNoDirectives) + FoundDirectives = false; + else + FoundDirectives = !LangOpts || findDirectives(SM, FID, *LangOpts); + + // Add the FileID to the unparsed set. + UnparsedFiles.insert(std::make_pair(FID, + UnparsedFileStatus(FE, FoundDirectives))); + } +#endif +} + void VerifyDiagnosticConsumer::CheckDiagnostics() { // Ensure any diagnostics go to the primary client. bool OwnsCurClient = Diags.ownsClient(); DiagnosticConsumer *CurClient = Diags.takeClient(); Diags.setClient(PrimaryClient, false); - // If we have a preprocessor, scan the source for expected diagnostic - // markers. If not then any diagnostics are unexpected. - if (CurrentPreprocessor) { - SourceManager &SM = CurrentPreprocessor->getSourceManager(); - #ifndef NDEBUG - // In a debug build, scan through any files that may have been missed - // during parsing and issue a fatal error if directives are contained - // within these files. If a fatal error occurs, this suggests that - // this file is being parsed separately from the main file. - HeaderSearch &HS = CurrentPreprocessor->getHeaderSearchInfo(); - for (FilesWithDiagnosticsSet::iterator I = FilesWithDiagnostics.begin(), - End = FilesWithDiagnostics.end(); - I != End; ++I) { - const FileEntry *E = SM.getFileEntryForID(*I); - // Don't check files already parsed or those handled as modules. - if (E && (FilesParsedForDirectives.count(E) - || HS.findModuleForHeader(E))) + // In a debug build, scan through any files that may have been missed + // during parsing and issue a fatal error if directives are contained + // within these files. If a fatal error occurs, this suggests that + // this file is being parsed separately from the main file, in which + // case consider moving the directives to the correct place, if this + // is applicable. + if (UnparsedFiles.size() > 0) { + // Generate a cache of parsed FileEntry pointers for alias lookups. + llvm::SmallPtrSet<const FileEntry *, 8> ParsedFileCache; + for (ParsedFilesMap::iterator I = ParsedFiles.begin(), + End = ParsedFiles.end(); I != End; ++I) { + if (const FileEntry *FE = I->second) + ParsedFileCache.insert(FE); + } + + // Iterate through list of unparsed files. + for (UnparsedFilesMap::iterator I = UnparsedFiles.begin(), + End = UnparsedFiles.end(); I != End; ++I) { + const UnparsedFileStatus &Status = I->second; + const FileEntry *FE = Status.getFile(); + + // Skip files that have been parsed via an alias. + if (FE && ParsedFileCache.count(FE)) continue; - if (findDirectives(*CurrentPreprocessor, *I)) + // Report a fatal error if this file contained directives. + if (Status.foundDirectives()) { llvm::report_fatal_error(Twine("-verify directives found after rather" " than during normal parsing of ", - StringRef(E ? E->getName() : "(unknown)"))); + StringRef(FE ? FE->getName() : "(unknown)"))); + } + } + + // UnparsedFiles has been processed now, so clear it. + UnparsedFiles.clear(); + } +#endif // !NDEBUG + + if (SrcManager) { + // Produce an error if no expected-* directives could be found in the + // source file(s) processed. + if (Status == HasNoDirectives) { + Diags.Report(diag::err_verify_no_directives).setForceEmit(); + ++NumErrors; + Status = HasNoDirectivesReported; } -#endif // Check that the expected diagnostics occurred. - NumErrors += CheckResults(Diags, SM, *Buffer, ED); + NumErrors += CheckResults(Diags, *SrcManager, *Buffer, ED); } else { NumErrors += (PrintUnexpected(Diags, 0, Buffer->err_begin(), Buffer->err_end(), "error") + diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp index b7d4a3b..f789b7f 100644 --- a/lib/Frontend/Warnings.cpp +++ b/lib/Frontend/Warnings.cpp @@ -24,7 +24,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Lex/LexDiagnostic.h" -#include "clang/Frontend/DiagnosticOptions.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include <cstring> #include <utility> @@ -51,8 +51,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, const DiagnosticOptions &Opts) { Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings); - Diags.setShowOverloads( - static_cast<DiagnosticsEngine::OverloadsShown>(Opts.ShowOverloads)); + Diags.setShowOverloads(Opts.getShowOverloads()); Diags.setElideType(Opts.ElideType); Diags.setPrintTemplateTree(Opts.ShowTemplateTree); |